【独学C言語入門 番外編】線形リストの基礎を学ぼう【ポインタ応用②】

今回は《線形リストの基礎を学ぼう》というテーマで記事をまとめます。

「線形リスト」は配列同様、複数の要素をひとまとめにするデータ構造です。「線形リスト」を習得すると、効率的なプログラムを作成することができます。

強力な技術であり、開発者としては必須の技術の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つを予定しています。

  • ノードの挿入
  • ノードの削除

上記を習得できれば、「線形リストは習得済み」と胸を張って言えるでしょう!

ご期待ください。

タイトルとURLをコピーしました