リスト : 要素が順序付けされながら幾つか ( 0 個を含む.. ) 並んだもの # 同じ要素が含まれてていてもよい <-> 集合 考える対象 整数のリスト : 整数の要素をもつリスト 例 [] 空リスト ( 要素が一つも含まれていない ) [1,2,3] 1, 2, 3 の三つの整数からなるリスト [3,1,2] 上と同じ要素からなるが、順序が違うので、異なるリスト [1,2,2,3,3,3] 同じ要素が含まれてもいてもよい し、それらが含まれているので、更に上と異なるリスト [1,2,3.0] これは、実数(3.0)が含まれているので、整数リストでない 実装(連結片方向リンクリスト) # リストの実装方法は、色々あり、これは一つの(最も単純な..)実装例 # => 他の実装方法は、Web Page の Link先 を参照 連結片方向リンクリストを利用した実装 [1,2,3] を連結片方向リンクリストで表現する LIST +-------+ | * | <= [1,2,3] +---|---+ Link | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> なし(NULL) +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ CELL 連結: リストを実現している要素をいれるセルが、リンク(連結)されている 片方向リンク: リンク(連結)の方向が片方だけである。 イメージ : 列車のイメージ ( データは客車に入る 0 〜 ) リストは、それを引く牽引車両 参考(配列のイメージ) +-------+-------+-------+ | 1 | 2 | 3 | +-------+-------+-------+ 参考(双方リンクリスト) LIST +-------+ | * | <= [1,2,3] +---|---+ Link | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> なし(NULL) +-------+ +-------+ +-------+ NULL <------* | <-------* | <-------* | <== 双方向の場合は逆がある +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ CELL === List の実装は、 データを保持する Cell と、それを繋げたものを扱う List の二つの データ構造の協力で実現する icell.h ICell : integer Cell +-------+ 次 | *--------> : 次の Cell への「ポインター値」を保持する +-------+ int | | +-------+ なので、第一感は、 typedef struct { ICell *next; /* 次の ICell の要素を指すポインター値 */ int data; /* この CELL がもつ整数値を保持 */ } ICell; となる。 これは、残念ながらうまくゆかない なぜなら、ICell が、利用さた後(のち)に定義されている。 typedef struct icell { struct icell *next; /* struct icell は頭で定義されている.. */ int data; /* 関数の再帰呼び出しと良くにている.. */ } ICell; cf. 関数の再帰呼び出し int fact ( int n ) { if ( n < 2 ) { return 1; } else { return fact ( n - 1 ) * n; /* fact の定義の中に fact が参照されている */ } } icell.c ICell *new_ICell ( int value ) : 新しい ICell を作る void free_ICell ( ICell *object ) : ICell を開放する void print_ICell ( ICell *object ) : ICell の中身を出力 ilist.h IList +-------+ top : 先頭の要素 | * | +---|---+ | +---> ICell があるはず.. typedef struct { ICell *top; } IList; /* typedef ICell *IList; という考えかたもある LIST +-------+ | *-----------------------------------------+ +-------+ | | * | <= [1,2,3] | +---|---+ Link v | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> なし(NULL) +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ CELL 片方向リストでも、最後の要素も保持するようなパターンがあるので、まあ、 構造体にしておこう.. */ ilist.c IList *new_IList () : 新しい List を作る 空リストに初期化される void free_IList ( IList *object ) : List を開放する List を開放する場合は、List の中身を表現している ICell の並びも開放しなければならない LIST +-------+ | * | <= [1,2,3] +---|---+ Link | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> なし(NULL) +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ CELL ^ ^ | | cp nx 最初 cp は 1 を要素とする Cell を指す nx は cp の次を指す void printf_IList ( char *format, IList *object ) リストの出力 *insert_IList ( IList *object, int data ) リストの先頭に新しい要素を挿入する。 +-------+ | * | <= [1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> なし(NULL) +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ CELL insert_IList ( object, 10 ); +-------+ | * | <= [10,1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> | *--------> NULL +-------+ +-------+ +-------+ +-------+ | 10 | | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ +-------+ CELL (1) +-------+ | * | <= [1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> なし(NULL) +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ CELL cp = new_ICell ( data ); cp --> +-------+ | *--------> NULL +-------+ | 10 | +-------+ (2) cp -> next = object -> top +-------+ | * | <= [1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> なし(NULL) +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ CELL ^ | +-------+ | cp -> +-------+ | | *-------+ +-------+ | 10 | +-------+ (2) object -> top = cp; +-------+ | * | <= [10,1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ | | *--------> | *--------> | *--------> なし(NULL) | +-------+ +-------+ +-------+ | | 1 | | 2 | | 3 | | +-------+ +-------+ +-------+ | CELL | ^ | | | +-------+ | | +-------+ | | | v | cp -> +-------+ | | *-------+ +-------+ | 10 | +-------+ これは、 +-------+ | * | <= [10,1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> | *--------> NULL +-------+ +-------+ +-------+ +-------+ | 10 | | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ +-------+ とおなじ void delete_top_IList ( IList *object ) 先頭の要素を削除する つまり、 +-------+ | * | <= [10,1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> | *--------> NULL +-------+ +-------+ +-------+ +-------+ | 10 | | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ +-------+ を +-------+ | * | <= [1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> なし(NULL) +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ にしたい。 +-------+ | * | <= [10,1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> | *--------> NULL +-------+ +-------+ +-------+ +-------+ | 10 | | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ +-------+ +-------+ | * | <= [1,2,3] ; object +---|---+ Link +-----------------------+ | v +-------+ +-------+ +-------+ +-------+ | *--------> | *--------> | *--------> | *--------> NULL +-------+ +-------+ +-------+ +-------+ | 10 | | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ +-------+ 基本は object -> top = object -> top -> next; とすればよい。 ただし、問題は、10 を保持する CELL が迷子になる ということで、 10 を保持する CELL の情報を、保存し、後で、開放する (1) ICell *cp = object -> top; /* 先頭の要素 */ +-------+ | * | <= [10,1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> | *--------> NULL +-------+ +-------+ +-------+ +-------+ | 10 | | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ +-------+ ^ | cp (2) object -> top = cp -> next +-------+ | * | <= [1,2,3] ; object +---|---+ Link +-----------------------+ | v +-------+ +-------+ +-------+ +-------+ | *--------> | *--------> | *--------> | *--------> NULL +-------+ +-------+ +-------+ +-------+ | 10 | | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ +-------+ ^ | cp (3) free_ICell ( cp ) いらなくなった 10 のセルを開放 +-------+ | * | <= [1,2,3] ; object +---|---+ Link +-----------------------+ | v +-------+ +-------+ +-------+ | *--------> | *--------> | *--------> NULL +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ ^ | cp IList *append_IList ( IList *object, int data ) 要素を最後に追加する +-------+ | * | <= [1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> なし(NULL) +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ を +-------+ | * | <= [1,2,3,10] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> | *--------> NULL +-------+ +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | | 10 | +-------+ +-------+ +-------+ +-------+ 基本的な考え方は、最後の要素の next を書き換える (1) +-------+ | * | <= [1,2,3] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> なし(NULL) +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | +-------+ +-------+ +-------+ cp --> +-------+ | *--------> NULL +-------+ | 10 | +-------+ (2) +-------+ | * | <= [1,2,3,10] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *-------+ <= この最後の要素の CELL ? +-------+ +-------+ +-------+ | | 1 | | 2 | | 3 | | +-------+ +-------+ +-------+ | | +---------------------------------------+ v cp --> +-------+ | *--------> NULL +-------+ | 10 | +-------+ (0) 最後の要素を搜す void delete_end_IList ( IList *object ) 最後の要素を削除する ポイント : 最後の要素の一つ手前を知る必要がある +-------+ | * | <= [1,2,3,10] ; object +---|---+ Link | +-------+ +-------+ +-------+ +-------+ +-> | *--------> | *--------> | *--------> | *--------> NULL +-------+ +-------+ +-------+ +-------+ | 1 | | 2 | | 3 | | 10 | +-------+ +-------+ +-------+ +-------+ +-------+ | * | <= [1,2,3] ; object +--> NULL +---|---+ Link | | +-------+ +-------+ +-------+ | +-------+ +-> | *--------> | *--------> | *-----+ | *--------> NULL +-------+ +-------+ +-------+ +-------+ ^ | 1 | | 2 | | 3 | | 10 | | +-------+ +-------+ +-------+ +-------+ | ^ ^ | | | | pre last cp sample-001.c