今回は《線形リストの基礎を学ぼう》というテーマで記事をまとめます。
「線形リスト」は配列同様、複数の要素をひとまとめにするデータ構造です。「線形リスト」を習得すると、効率的なプログラムを作成することができます。
強力な技術であり、開発者としては必須の技術の1つなのでしっかり学んでいきましょう!
尚、現在執筆中のC言語入門記事は以下の人を対象としています。
- プログラミング未経験の人
- C言語プログラミングの学習をこれから始めたい人
- C言語プログラミングの学習を始めたばかりの人
線形リストの基礎を学ぼう
線形リストとは
線形リストとは、「データ部とポインタを持つ構造体」を用いてリスト形状に連結するデータ構造です(単に「リスト」と呼ぶこともあります)。配列は固定長でしたが、線形リストは可変長という特性を持ちます。
そして、線形リストにおける構造体のオブジェクト1つのことを『ノード』と呼びます。
実際のプログラムコードとそれに対応したノードのイメージは次のようになります。
そして、複数のノードを連結した線形リストのイメージは次のようになります。
まずはベタ書きで線形リストを作ってみよう!
まずは細かいことを考えずにベタ書きで下図のようなイメージを作成してみましょう。
1.先頭ポインタを用意
struct mydata* root = NULL;
2.ノード①を生成、先頭ポインタにアドレスを代入
struct mydata* pdata1 = NULL; pdata1 = (struct mydata*)malloc( sizeof(struct mydata) ); pdata1->data = 1; pdata1->next = NULL; /* 生成時に必ずNULLを代入しましょう */ root = pdata1; /* 先頭ポインタに代入 */
3.ノード②を生成、ノード①の次ポインタ(next)にアドレスを代入
struct mydata* pdata2 = NULL; pdata2 = (struct mydata*)malloc( sizeof(struct mydata) ); pdata2->data = 1; pdata2->next = NULL; /* 生成時に必ずNULLを代入しましょう */ pdata1->next = pdata2; /* ノード①の次ポインタに代入 */
▽まとめ
ここまでのお話をまとめました。
struct mydata* root = NULL; struct mydata* pdata1 = NULL; struct mydata* pdata2 = NULL; pdata1 = (struct mydata*)malloc( sizeof(struct mydata) ); pdata1->data = 1; pdata1->next = NULL; /* 生成時に必ずNULLを代入しましょう */ pdata2 = (struct mydata*)malloc( sizeof(struct mydata) ); pdata2->data = 2; pdata2->next = NULL; /* 生成時に必ずNULLを代入しましょう */ root = pdata1; /* 先頭ポインタに代入 */ pdata1->next = pdata2; /* ノード①の次ポインタに代入 */
線形リストのノード表示
次に、作成済みの線形リストに対して各ノードを表示する方法を解説します。
1.参照用ポインタを用意
struct mydata* ptr = NULL; /* 参照用ポインタ */
2.参照用ポインタに先頭ポインタ(ノード①のアドレス)を代入
ptr = root;
3.参照用ポインタ(ノード①)の情報を表示
printf( "data : %d\n", ptr->data );
4.参照用ポインタに次ポインタ(ノード②)を代入
ptr = ptr->next;
5.参照用ポインタ(ノード②)の情報を表示
printf( "data : %d\n", ptr->data );
まとめ
struct mydata* root = NULL; /* 先頭ポインタ */ /* ~線形リスト作成処理(割愛)~ */ struct mydata* ptr = NULL; /* 参照用ポインタ */ /* 参照用ポインタに先頭ポインタ(ノード①のアドレス)を代入 */ ptr = root; /* 参照用ポインタ(ノード①)のノードを表示 */ printf( "data : %d\n", ptr->data ); /* 参照用ポインタに、次ポインタ(ノード②のアドレス)を代入 */ ptr = ptr->next; /* 参照用ポインタ(ノード②)のノードを表示 */ printf( "data : %d\n", ptr->data );
【更に向こうへ】線形リストの全ノード表示
上記まとめの書き方では、線形リストに追加されているノードの数だけプログラムコードを書く必要があります。これでは不便でしょうがありませんね。
そこで、線形リストの全ノードを表示するサンプルを用意しました。
線形リストにノードを複数個追加した上で実行してみてください。全てのノードが表示されるハズです。
struct mydata* root = NULL; /* 先頭ポインタ */ /* ~線形リスト作成処理(割愛)~ */ struct mydata* ptr = NULL; /* 参照用ポインタ */ ptr = root; while( ptr != NULL ){ printf( "data : %d\n", ptr->data ); ptr = ptr->next; }
サンプル
それでは、サンプルを用意したので実行してみてください。
尚、本来であれば、malloc関数で確保したメモリを解放する必要がありますが、今回は省略します。
メモリの解放は、次回解説予定の『ノードの削除』を学習したあとにメジャーな実装方法を解説したいと思います。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> /* 構造体の定義 */ struct person_info_node { char name[10]; int age; struct person_info_node* next; }; /* ノードの追加関数 */ void addNode(struct person_info_node** root, struct person_info_node* tgtNode, struct person_info_node* newNode) { struct person_info_node* tmp = NULL; if (*root == NULL) { /* 線形リストが空(先頭ポインタがNULL)の場合、先頭に追加 */ *root = newNode; } else { /* 対象ノードの後ろに追加 */ tgtNode->next = newNode; } } /* 全てのノード情報を表示 */ void dispAll(struct person_info_node* root) { struct person_info_node* node = NULL; printf( "## 全情報表示\n" ); node = root; while (node != NULL) { printf( "name = \"%s\"\n", node->name ); printf( "age = %d\n", node->age ); printf( "\n" ); node = node->next; } } void main() { int i = 0; int num = 0; struct person_info_node* root = NULL; struct person_info_node* node = NULL; struct person_info_node* nodePre = NULL; printf( "登録する人数を入力してエンターキーを押してください。:" ); scanf( "%d", &num ); printf( "\n" ); for( i = 0; i < num; i++ ){ /* 新規登録するノードを作成 */ node = (struct person_info_node*)malloc(sizeof(struct person_info_node)); printf( "登録データ No.%d\n", i + 1 ); printf( "名前:" ); scanf( "%s", node->name ); printf( "年齢:" ); scanf( "%d", &(node->age) ); node->next = NULL; printf( "\n" ); /* 追加 */ addNode( &root, nodePre, node ); /* 前回追加したノード(末尾のノード)を保存しておく */ nodePre = node; } /* 全データ表示 */ dispAll( root ); /* 本来はmallocで確保したメモリをここで解放する必要がある */ /* (今回は省略します) */ }
まとめと次回予告
今回、線形リストの基礎として次の内容を学んでもらいました。
- 線形リストの基本構造
- ノードの追加
- ノードの表示
次回以降は線形リスト基礎編の続編として、次の2つを予定しています。
- ノードの挿入
- ノードの削除
上記を習得できれば、「線形リストは習得済み」と胸を張って言えるでしょう!
ご期待ください。