単方向リストの挿入と削除|next をつなぎ替える順番【基本情報技術者試験 科目B】

基本情報技術者試験

現行FE シラバス Ver9.2 準拠擬似言語の記述形式は2022年から変更なし最終更新 2026-10-17

単方向リストは、要素の1つ1つが「値」と「次の要素」を持ち、先頭の要素から「次の要素」を順にたどって読む並びです。要素を途中に入れるときも、途中から外すときも、要素は動かしません。「次の要素」を書き換えて、つなぎ先を替えるだけです。

期間限定クーポンPR|Udemy の講座科目B オリジナル模試 3回分・60問42%OFF 1,500円2,600円中身を見る ›

つなぎ替え ── 書き換えるのは next だけ

科目Bでは、リストの要素をクラス ListElement で表すことがあります。メンバ変数は2つで、val が値、next が次の要素です。次の要素が無い末尾の要素では、next は未定義です。変数 listHead が、先頭の要素を指しています(たどり方は A10-1)。

A → B → D とつながったリストと、まだつながっていない C

上の段=要素の値(val) / 下の段=その要素の next が指している要素 / 緑の矢印=next が指している先 / 網掛け=未定義 / 下の箱=変数が指している要素

val

A

B

C

D

next

B

D

未定義

未定義

listHeadA の要素

prevB の要素

nodeC の要素

先頭からたどると A → B → D。C の要素は、どの next からも指されていないので、まだリストに入っていません。

図の A・B・C・D は val の値で、ここでは要素の呼び名にも使います。prev と node は、つなぎ替えに使う変数です。いまは prev が B の要素を、node が C の要素を指しています。

リストの順番は next だけで決まっています。だから、next を書き換えれば順番が変わります。配列の途中に入れるときのように、うしろの要素を1つずつずらす必要はありません。

つなぎ替えの行では、← の左に「どれかの要素の next」が来ます。たとえば次の行です。

prev.next ← node

prev.next は、prev が指している要素の next です。上の図なら prev は B の要素を指しているので、B の next のこと。この行は、B の next を、node が指している要素(C)へ書き換えます。prev と node が指す先は変わりません。ただし、この1行だけでは D を指す next が無くなってしまいます。正しい手順は、次の節の2行です。

挿入 ── 2行。新しい要素の next を先に書く

prev が指している要素のうしろに、node が指している要素を入れる手続です。

○sounyuu(ListElement: prev, ListElement: node)
  node.next ← prev.next
  prev.next ← node

当サイトで作った例です。

B と D のあいだに C を入れるので、prev に B の要素、node に C の要素を渡して呼び出します。手続の中の prev は、渡された B の要素そのものを指しているので、prev.next を書き換えると、リストの中の B の next が変わります。

B と D のあいだに C を入れる ── next を2か所、この順に書き換える

上の段=要素の値(val) / 下の段=その要素の next が指している要素 / 緑の矢印=next が指している先 / 網掛け=未定義 / 下の箱=変数が指している要素 / 琥珀の枡=その行で読んだ next / 緑の枡=その行で書き換えた next

① node.next ← prev.next C の next に、B の next の中身を写す

val

A

B

C

D

next

B

D

D

未定義

listHeadA の要素

prevB の要素

nodeC の要素

prev.next(B の next)は D を指しています。同じ D を、C の next にも入れました。これで C のうしろが D につながりました。先頭からたどると、まだ A → B → D です。

② prev.next ← node B の next を、C へ向ける

val

A

B

C

D

next

B

C

D

未定義

listHeadA の要素

prevB の要素

nodeC の要素

B の next が D から C に変わりました。先頭からたどると A → B → C → D。

どの要素も動いていません。書き換えたのは、C の next と B の next の2か所だけです。

呼び出したあと、先頭からたどると A → B → C → D になります。

行の順番 ── 逆にすると、うしろが切れる

2行の順番を入れ替えると、同じ呼び出しでも結果が変わります。

○sounyuu(ListElement: prev, ListElement: node)
  prev.next ← node
  node.next ← prev.next

当サイトで作った、誤った順の例です。

2行を逆にすると、D へたどり着けなくなる

上の段=要素の値(val) / 下の段=その要素の next が指している要素 / 緑の矢印=next が指している先 / 網掛け=未定義 / 下の箱=変数が指している要素 / 琥珀の枡=その行で読んだ next / 赤=誤った書き換え / 灰=先頭からたどり着けなくなった要素

① prev.next ← node 先に、B の next を C へ向けた

val

A

B

C

D

next

B

C

未定義

未定義

listHeadA の要素

prevB の要素

nodeC の要素

B の next は D を指していましたが、C で上書きしました。D の要素は残っていますが、D を指している next が、もうどこにもありません。先頭からたどると A → B → C で止まります。

② node.next ← prev.next C の next に、B の next の中身を写した

val

A

B

C

D

next

B

C

C

未定義

listHeadA の要素

prevB の要素

nodeC の要素

prev.next は、①で C に変わっています。だから C の next に入るのは C 自身です。先頭からたどると A → B → C → C → C … と、C から先へ進めません。

D の要素は残っていますが、先頭からたどり着く道がありません。

うしろの要素 D を指していたのは、B の next だけでした。B の next を書き換える前に、その中身を新しい要素の next へ写しておく。これが、正しい順で1行目に node.next ← prev.next を置く理由です。

削除 ── 1行。前の要素の next を、1つ先へ向ける

prev が指している要素の次の要素を、リストから外す手続です。

○sakujo(ListElement: prev)
  prev.next ← prev.next.next

当サイトで作った例です。

さきほど C を入れた A → B → C → D から、B を外します。prev に渡すのは、外す要素そのものではなく、その1つ前の要素です。B の1つ前は A なので、A の要素を渡して呼び出します。.next が2つ続くところは、左から1つずつ読みます。

A → B → C → D から B を外す ── A の next を、1つ先の C へ向ける

上の段=要素の値(val) / 下の段=その要素の next が指している要素 / 緑の矢印=next が指している先 / 網掛け=未定義 / 下の箱=変数が指している要素 / 琥珀の枡=その行で読んだ next / 緑の枡=その行で書き換えた next / 灰=先頭からたどり着けなくなった要素

実行する前 prev.next.next が指しているのは、どの要素か

val

A

B

C

D

next

B

C

D

未定義

listHeadA の要素

prevA の要素

prev.next は A の next なので B。prev.next.next は、その B の next なので C です。

prev.next ← prev.next.next のあと

val

A

B

C

D

next

C

C

D

未定義

listHeadA の要素

prevA の要素

A の next が B から C に変わりました。先頭からたどると A → C → D。B の要素も、B の next も、そのまま残っています。

B を指している next が無くなったので、先頭からたどっても B には着きません。これが「外れた」状態です。

呼び出したあと、先頭からたどると A → C → D になります。削除は、外す要素を飛び越すように、1つ前の要素の next を1つ先へ向けます。外す要素そのものを書き換える行はありません。

先頭の要素を外すとき

先頭の要素には、1つ前の要素がありません。先頭を指しているのは listHead なので、listHead を1つ先へ向けます。実際の出題でも、先頭を外す行はこう書かれています。

(基本情報技術者試験 科目B サンプル問題 問10)

    listHead ← listHead.next

先頭に入れるときも、書き換える相手が listHead になります。次の2行を、この順で書きます。

    node.next ← listHead
    listHead ← node

先に listHead の中身(いまの先頭)を node.next へ写してから、listHead を node へ向けます。prev のうしろに入れるときと同じ順番です。

次に読む

A11 木構造 ─ 根・葉・親子・深さ
A10-1 リストを読む ─ next をたどって、未定義で止まる
サンプル問題 問10 単方向リストから、指定された位置の要素を削除する問題の解説
G12 オブジェクト ─ 変数.メンバ変数 の読み方
目次 基本情報技術者試験 科目B 攻略ガイド

この記事で引用した資料

いずれも独立行政法人情報処理推進機構(IPA)が公表したものです。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では、引用した箇所の文言を改変していません(省略や補いがある場合は、その場に明記しています)。

本文の例題は当サイトのオリジナルです。

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