0Pricing
C Academy · レッスン

単方向連結リスト

ノードとポインターです。

「単方向連結リスト」はCoddyKit上の無料C Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。

連結リストとは

連結リストは、ノードと呼ばれる小さな構造体が連なったものです。各ノードには値と、次のノードへのポインターが格納されます。

配列とは異なり、要素はメモリ上で連続している必要がなく、リストの拡張や縮小も簡単です。

#include <stdio.h>

struct Node {
    int value;
    struct Node *next;
};

int main(void) {
    printf("A node holds a value and a next pointer\n");
    return 0;
}

ノードを定義する

ノードの struct にはデータと、次のノードを指す struct Node *next が含まれます。

ポインター型が同じ struct を参照することで、ノード同士を連結できます。

#include <stdio.h>

struct Node {
    int value;
    struct Node *next;
};

int main(void) {
    struct Node n;
    n.value = 42;
    n.next = NULL;
    printf("value=%d, next is NULL: %d\n", n.value, n.next == NULL);
    return 0;
}

先頭ポインター

リストは、最初のノードを指す単一のポインターで識別します。これを先頭(head)と呼びます。

空のリストは、先頭が NULL になっているだけです。

#include <stdio.h>

struct Node { int value; struct Node *next; };

int main(void) {
    struct Node *head = NULL;
    printf("List is empty: %d\n", head == NULL);
    return 0;
}

ノードを確保する

ノードは通常、作成した関数が終了しても存在し続けるように、malloc でヒープ上に作成します。

必ず戻り値をチェックし、後でノードを解放することも忘れないでください。

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *next; };

int main(void) {
    struct Node *n = malloc(sizeof(struct Node));
    n->value = 7;
    n->next = NULL;
    printf("%d\n", n->value);
    free(n);
    return 0;
}

アロー演算子

構造体へのポインターがある場合は、-> を使ってメンバーにアクセスします。n->value は (*n).value と同じ意味です。

連結リストでは、アロー演算子を何度も使うことになります。

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *next; };

int main(void) {
    struct Node *n = malloc(sizeof(struct Node));
    n->value = 99;
    printf("%d\n", n->value);
    free(n);
    return 0;
}

2つのノードを連結する

ノードを接続するには、1つ目のノードの next が2つ目のノードを指すように設定します。最後のノードの next は終端を示すために NULL のままにします。

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *next; };

int main(void) {
    struct Node *a = malloc(sizeof(struct Node));
    struct Node *b = malloc(sizeof(struct Node));
    a->value = 1; a->next = b;
    b->value = 2; b->next = NULL;
    printf("%d -> %d\n", a->value, a->next->value);
    free(a); free(b);
    return 0;
}

ノードを作成するヘルパー

毎回メモリを確保するのは面倒なので、メモリの確保、初期化、新しいノードの返却を行うヘルパー関数にまとめます。

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *next; };

struct Node *make(int v) {
    struct Node *n = malloc(sizeof(struct Node));
    n->value = v;
    n->next = NULL;
    return n;
}

int main(void) {
    struct Node *n = make(5);
    printf("%d\n", n->value);
    free(n);
    return 0;
}

小さなリストを作る

ヘルパーを使い、next ポインターをつないで 1 -> 2 -> 3 の3ノードのリストを作ります。

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->next=NULL;return n;}

int main(void) {
    struct Node *head = make(1);
    head->next = make(2);
    head->next->next = make(3);
    printf("%d %d %d\n", head->value, head->next->value, head->next->next->value);
    return 0;
}

リストを出力する

すべての値を出力するには、先頭から始め、NULL に到達するまで next ポインターをたどります。

この走査パターンは、ほぼすべてのリスト操作の基礎となります。

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->next=NULL;return n;}

int main(void) {
    struct Node *head = make(1);
    head->next = make(2);
    for (struct Node *p = head; p; p = p->next)
        printf("%d ", p->value);
    printf("\n");
    return 0;
}

配列と連結リストの比較

配列はインデックスによるアクセスが高速ですが、サイズが固定です。連結リストは要素の挿入や削除が簡単ですが、アクセスは遅くなります(要素に到達するまでたどる必要があるためです)。

プログラムでどの操作が中心になるかに応じて選択してください。

#include <stdio.h>

int main(void) {
    printf("Array: O(1) index, costly resize\n");
    printf("List:  O(n) index, cheap insert/delete\n");
    return 0;
}

リスト全体を解放する

mallocで確保したすべてのノードを解放する必要があります。リストをたどる際は、各ノードを解放する前に次のポインターを保存してください。そうしないと、チェーンの残りにアクセスできなくなります。

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->next=NULL;return n;}

int main(void) {
    struct Node *head = make(1);
    head->next = make(2);
    struct Node *p = head;
    while (p) {
        struct Node *nxt = p->next;
        free(p);
        p = nxt;
    }
    printf("freed all nodes\n");
    return 0;
}

クイックチェック

連結リストの構造についての理解度を確認しましょう。

まとめ

単方向連結リストの基本を学びました。

  • ノードは値とnextポインターを保持し、headは最初のノードを指します。
  • mallocでノードを確保し、->でメンバーにアクセスします。
  • 最後のノードのnextはNULLです。ポインターをたどって走査します。
  • すべてのノードを必ずfreeし、解放する前にnextを保存します。

よくある質問

「単方向連結リスト」レッスンは無料ですか?

はい。「単方向連結リスト」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。

「単方向連結リスト」で何を学びますか?

ノードとポインターです。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「単方向連結リスト」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC Academyレッスンでコードを書いて実行できますか?

はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 単方向連結リスト
  2. 挿入と削除
  3. 走査と検索
  4. 双方向連結リスト
← C Academyに戻る