第4回では,以下の項目に関して学ぶ.
単純な線形リストでは後続する要素を容易に見つけられるものの,先行する要素を見つけることは面倒である.そこで,後続する要素だけでなく,先行する要素へポインタを保持する双方向連結リストを考える.
ここでは,以下に示す構造体を用いて,整数の値を格納する双方向連結リストを構築するソースコード prog4-1.c
を作成する.
struct element { int value; struct element *prev; struct element *next; };この構造体は,後続する要素を指すポインタ
next
だけでなく,先行する要素を指すポインタ prev
を持つ.要素が末尾の場合,next
は NULL
とする.また,要素が先頭の場合,prev
は NULL
とする.
双方向連結リストは以下に示す構造体で表現する.
struct list { struct element *top; struct element *rear; };
top
は双方向連結リストの先頭,rear
は双方向連結リストの末尾を指すポインタである.リストが空の場合,top
と rear
は NULL
とする.
双方向連結リストの例を図4.1に示す.
図4.1: 双方向連結リストの例
いま,双方向連結リストを構築するために,以下に示す4つの関数を用意する.
struct list *create_list();
value
を格納した双方向連結リストの要素を生成する.struct element *create_element(int value);
list
に格納されている整数の値を先頭から順番に画面に表示する.void print_list(struct list *list);
list
に格納されている整数の値を末尾から順番に画面に表示する.void print_reverse_list(struct list *list);
上記の4つの関数とテストコードを含むprog4-1.c
を作成せよ.
本課題では,図4.1の線形リストに対して,テスト関数test1()
がすでに用意されている.空のリスト,要素を3つ持つリストなど,さまざまな線形リストの構築を検査するテストコードをprog4-1.c
に追加せよ.
課題1で作成したソースコード prog4-1.c
に対して,以下に示す4つの関数を追加したソースコード prog4-2.c
を作成する.
list
の先頭に要素 elem
を挿入する.void insert_front(struct list *list, struct element *elem);
list
の末尾に要素 elem
を挿入する.void insert_rear(struct list *list, struct element *elem);
list
の先頭の要素を削除する.void delete_front(struct list *list);
list
の末尾の要素を削除する.void delete_rear(struct list *list);
上記の4つの関数とテストコードを含むprog4-2.c
を作成せよ.
課題2で作成したソースコード prog4-2.c
を,リストから任意の位置の要素を取得できるように改良する.このために,双方向連結リストに格納されている要素の数を表す変数 size
を追加した,以下の構造体を用意する.
struct list { struct element *top; struct element *rear; int size; };
上記の構造体を用いて,以下に示す2つの関数を追加したソースコード prog4-3.c
を作成する.
list
に格納されている要素の数を返す.int size_of_list(struct list *list);
list
の index
番目の要素を取得する.index
番目の要素が存在しない場合は,NULL
を返す.struct element *get_from_list(struct list *list, int index);
上記の2つの関数とテストコードを含むprog4-3.c
を作成せよ.
課題3で作成したソースコード prog4-3.c
に対して,以下に示す3つの関数を追加したソースコード prog4-4.c
を作成する.
list
の index
番目の要素の前に要素 elem
を挿入する.void insert_at(struct list *list, int index, struct element *elem);
list
の index
番目の要素を削除する.void delete_at(struct list *list, int index);
first
の末尾に線形リスト second
を付け加える.いいかえると,second
に格納されている要素をそれらの順番を維持したまま,first
の末尾に挿入する.struct list *append(struct list *first, struct list *second);
上記の3つの関数とテストコードを含むprog4-4.c
を作成せよ.
線形リストの末尾の要素に,先頭の要素を指すポインタを保持したリストを循環リストという.
ここでは,以下に示す構造体を用いて,整数の値を格納する循環リストを構築するソースコード prog4-5.c
を作成する.
struct element { int value; struct element *next; };この構造体は,後続する要素を指すポインタ
next
を持つ.
循環リストは以下に示す構造体で表現する.
struct list { struct element *top; };
top
は循環リストの先頭を指すポインタである.リストが空の場合,top
は NULL
とする.
循環リストの例を図4.4に示す.
図4.4: 循環リストの例
いま,循環リストを構築するために,以下に示す3つの関数を用意する.
struct list *create_list();
value
を格納した双方向連結リストの要素を生成する.struct element *create_element(int value);
list
に格納されている整数の値を先頭から順番に画面に表示する.void print_list(struct list *list);
さらに,循環リストを操作する以下に示す3つの関数を用意する.
list
の先頭に要素 elem
を挿入する.void insert_front(struct list *list, struct element *elem);
list
において,要素 pos
の直後に要素 elem
を挿入する.void insert_after(struct list *list, struct element *pos, struct element *elem);
list
において,要素 pos
を削除する.void delete(struct list *list, struct element *pos);
上記の6つの関数とテストコードを含むprog4-5.c
を作成せよ.