🇯🇵 日本語

STEP 7 総合復習 ― データ構造・ソート・探索

第43〜44回までの要点を チートシート でおさらいし、コード読み取り6問「よくあるミス」チェックリスト で定着度を確認します。

① 要点チートシート

STEP 7 で押さえておきたい要点を、表で一気に 見直しましょう。

📚 データ構造の使い分け

構造特徴典型用途
配列添字で即アクセス固定長データ
連結リスト挿入・削除が速い長さが伸縮するデータ
スタック後入れ先出し (LIFO)関数呼出・undo
キュー先入れ先出し (FIFO)順番待ち・BFS
  • 何が速く・何が遅い」かで使い分ける

🔗 連結リストのノード

struct Node {
    int value;
    struct Node *next; // 次のノードへの矢印
};

// 末尾は next が NULL
  • 各ノードが 次のノードへのポインタ を持つ
  • 挿入・削除は ポインタの繋ぎ替え だけで済む
  • 添字アクセスは遅い(先頭から辿る)

📥 スタック / 📤 キュー

// スタック (LIFO): push / pop
push(1); push(2); push(3);
pop(); // → 3 (最後に入れた)

// キュー (FIFO): enqueue / dequeue
enqueue(1); enqueue(2); enqueue(3);
dequeue(); // → 1 (最初に入れた)
  • スタック: 皿の山。後入れ先出し
  • キュー: レジの行列。先入れ先出し

🔀 主要なソートアルゴリズム

名前方針計算量
バブル隣同士を比較交換O(N²)
選択最小値を選んで先頭へO(N²)
挿入整列済みに正しい位置で挿入O(N²)
  • どれも基本は O(N²)。N が増えると急に遅くなる
  • 本格的に速いのはクイックソートやマージソート(O(N log N))

🔍 線形探索 vs 二分探索

方法必要な前提計算量
線形探索なしO(N)
二分探索整列済みであることO(log N)
  • 二分探索は 毎回半分に絞る(中央と比較)
  • N=1000 なら線形 1000 回 vs 二分 約 10 回
  • 整列されていないデータには 使えない

② コード読み取り 6問

頭の中で実行 してから選択肢をクリック。間違えても解説を読めば必ず腑に落ちます。

Q1. スタックの動き

// スタックに push して、最後に 1 回 pop すると?
push(10);
push(20);
push(30);
int v = pop();
printf("%d\n", v);

出力は?

10
20
30
不定
解説: スタックは 後入れ先出し(LIFO)
最後に push した 30 が最初に pop で取り出される。
30
皿の山と同じ:上に積んだものを上から取る。

Q2. キューの動き

enqueue(10);
enqueue(20);
enqueue(30);
int v = dequeue();
printf("%d\n", v);

出力は?

10
20
30
不定
解説: キューは 先入れ先出し(FIFO)
最初に enqueue した 10 が最初に dequeue で取り出される。
10
レジの行列と同じ:先に並んだ人から会計される。

Q3. バブルソートのループ回数

int a[] = {5, 2, 8, 1, 9}; // N=5
for (int i = 0; i < N - 1; i++) {
    for (int j = 0; j < N - 1 - i; j++) {
        if (a[j] > a[j+1]) /* swap */;
    }
}

内側ループの比較は合計何回?

25 回
10 回
5 回
15 回
解説: i=0 で 4 回、i=1 で 3 回、i=2 で 2 回、i=3 で 1 回。
合計 4+3+2+1 = 10 回
※ N=5 のとき N(N-1)/2 = 10。N が増えると急速に増える(O(N²))。

Q4. 二分探索の比較回数

// 整列された 1024 個のデータから 1 つ探す
// 二分探索を使うと、最悪何回の比較で見つかる?

最悪の比較回数は?

約 1024 回
約 512 回
約 10 回
約 1 回
解説: 二分探索は 毎回半分に絞る
1024 → 512 → 256 → 128 → ... → 1 まで 10 回 で 1 つに絞れる(2¹⁰ = 1024)。
計算量は O(log N)。線形探索(最悪 1024 回)に比べて圧倒的に速い。
ただし 整列済み が前提。

Q5. 連結リストの末尾

struct Node *cur = head;
while (cur->next != NULL) {
    cur = cur->next;
}
// この時 cur は何を指している?

cur が指すのは?

先頭ノード
2 番目のノード
末尾ノード(next が NULL のノード)
NULL
解説: ループ条件は cur->next != NULL。next が NULL になった瞬間、ループを抜ける。
その時点の cur は 末尾ノード(next が NULL のノード自身)。
※ 条件を cur != NULL にしてしまうと、最後に cur 自身が NULL を指したところで止まる(cur が NULL になる)。

Q6. 選択ソート 1 周目

int a[] = {5, 2, 8, 1, 9};
// 選択ソートを 1 周(最小値を見つけて先頭へ)すると?

1 周目の終了時、配列はどうなる?

{1, 2, 5, 8, 9}(全部整列)
{1, 2, 8, 5, 9}(先頭だけ最小、残りそのまま)
{1, 5, 8, 2, 9}
{2, 5, 8, 1, 9}
解説: 選択ソートは 「最小値を見つけて先頭と交換」を繰り返す
1 周目: 最小値 1(添字 3)を見つけ、先頭 5 と交換 → {1, 2, 8, 5, 9}
2 周目以降は a[1] 以降で同じことを繰り返す。

③ よくあるミス・難所チェックリスト

読みながら「やったことある…」と思ったら、その項目はもう一度元のページに戻って確認しておきましょう。
  1. 1
    スタックとキューの順序を取り違えた
    push/pop は LIFO、enqueue/dequeue は FIFO。用途で覚える(皿の山 vs レジ列)。
  2. 2
    連結リストの末尾判定で cur != NULLcur->next != NULL を取り違えた
    前者は「ノードを全部辿る」、後者は「末尾ノードで止まる」。目的に応じて使い分け。
  3. 3
    連結リストのノードを free し忘れた
    ノードを使い終わったら free しないと メモリリーク。先に next を別の変数に保存してから自分を解放。
  4. 4
    整列されていない配列に二分探索を使った
    二分探索は 整列済み が大前提。未整列なら結果は嘘になる。
  5. 5
    バブル/選択/挿入ソートの内側ループ範囲を間違えた
    j < N - 1 - ij >= 1 など、境界を 1 つズレるだけで 範囲外アクセス
  6. 6
    計算量 O(N²) の重さを軽く見た
    N=10 なら 100 回、N=10000 なら 1 億回。大きな N では速いアルゴリズム(O(N log N) 系)が必要。
  7. 7
    swap で 一時変数 を使い忘れて値が消えた
    a = b; b = a; は両方 b になってしまう。int t = a; a = b; b = t; と一時変数経由で。

④ 戻るページ ― つまずいたらここに戻る

特定の項目で迷ったら、対応する元ページにすぐ戻れるよう一覧にしました。
第43回 データ構造入門連結リスト・スタック・キューの仕組みを再確認 第44回 ソートアルゴリズムバブル/選択/挿入と二分探索の動きを再確認 ポインタの基礎連結リストで next が曖昧になった時に 動的メモリノードを動的に確保/解放する時に チートシート(早見表)計算量・データ構造を1ページで確認