応用情報技術者 2023年 秋期 午前2 問05
問題文
双方向リストを三つの一次元配列 elem[i]、next[i]、prev[i]の組で実現する。双方向リストが図の状態のとき、要素 Dの次に要素 C を挿入した後のnext[6]、prev[6]の値の組合せはどれか。ここで、双方向リストは次のように表現する。
・双方向リストの要素は、elem[i]に値、next[i] に次の要素の要素番号、prev[i]に前の要素の要素番号を設定
・双方向リストの先頭、末尾の要素番号は、それぞれ変数 Head, Tail に設定
・next[i]、prev[i]の値が0である要素は、それぞれ双方向リストの末尾、先頭を表す。
・双方向リストへの要素の追加は、一次元配列の末尾に追加


選択肢
ア:
イ:
ウ:(正解)
エ:
🔒 解説は解答すると表示されます
配列実装の双方向リスト【午前2解説】
正解の理由
図の状態で要素 D は要素番号 3 にあり、その次に要素 C(新規要素、配列末尾の要素番号 6)を挿入する操作では、挿入位置の前後のつながりを正しく更新する必要があります。具体的には、挿入する要素 6 の前は D(要素番号 3)なので prev[6]=3、挿入後に 6 の次は元の D の次であった E(要素番号 5)なので next[6]=5 になります。以上から、選択肢の ウ が正しい組合せです。
解法ステップ
- 現在の状態を把握する
- D の要素番号は 3、D の現在の next[3]=5(D の次は E)、prev[3]=4(D の前は B)であることを確認する。
- 新規要素は配列末尾の添字 6 に入る。
- 新規要素 6 のリンク設定(挿入位置に合わせる)
- prev[6] = 挿入位置(D)の要素番号 = 3
- next[6] = D が元々指していた次の要素番号 = next[3] = 5
- 周囲要素のリンク更新
- D の next を新規要素 6 に更新: next[3] = 6
- 元の次要素 E の prev を新規要素 6 に更新: prev[5] = 6
- Head/Tail の更新は不要(今回は末尾でない位置への挿入のため)
この手順で最終的に next[6]=5、prev[6]=3 が得られます。
選択肢別の誤答解説
- ア(next[6]=2, prev[6]=3)
誤りです。next[6]=2 とすると要素 6 の次が要素番号 2(elem[2]=F)を指すことになり、D の直後に来る要素としては誤りです。もともと D の次は E(要素番号 5)であり、挿入後に 6 の次が 5 でなければなりません。従って next[6] が 2 である選択肢は不正です。 - イ(next[6]=3, prev[6]=4)
誤りです。next[6]=3 では 6 の次が D 自身を指すことになり、循環や自己参照を生じます。挿入は D の「直後」に行うため、prev[6] は 3(D)であるべきで、prev[6]=4(B を指す)は不適切です。 - ウ(next[6]=5, prev[6]=3)
正しいです。上で述べた通り、挿入要素の前は D(3)、挿入要素の次は元の D の次である E(5)になるため、next[6]=5、prev[6]=3 が正しい組合せです。 - エ(next[6]=5, prev[6]=4)
誤りです。next[6]=5 は正しい方向(6 の次が E)ですが、prev[6]=4 とすると 6 の前が B(4)になってしまい、挿入位置が D(3)の直後という条件に反します。したがって不正です。
よくある誤解
- 「挿入後の next/prev は片方だけ更新すればよい」
→ 片方だけ更新するとリストの整合性が崩れ、要素が辿れなくなります。挿入時は挿入要素自身と周囲(挿入前の前要素と次要素)の両方を更新する必要があります。 - 「配列の末尾に追加=Tail の次にしか入らない」
→ 問題の「一次元配列の末尾に追加」は物理的な配列位置(添字)に関する説明であり、論理的なリスト上での挿入位置(ここでは D の直後)とは別です。配列の物理末尾(添字 6)に置いても、リンクの設定次第でリスト中の任意の位置に挿入できます。
補足コラム
配列で双方向リストを実装する際、操作の順序に注意すると安全です。挿入の一般的な安全順序は次のとおりです(挿入要素を X、挿入前の要素を P、元の次要素を N とした場合)。
- next[X] = next[P](X の次を P の元の次に設定)
- prev[X] = P(X の前を P に設定)
- next[P] = X(P の次を X に更新)
- もし N が存在すれば prev[N] = X(N の前を X に更新)
この順序だと途中で参照を失うリスクが低くなります。配列実装では添字 0 を「外部(NULL 相当)」として使う慣例が多い点も覚えておきましょう。
例:今回の更新(Python による簡易シミュレーション)
elem = [None, 'A','F','D','B','E', None]
next = [None, 4,0,5,3,2, None]
prev = [None, 0,5,4,1,3, None]
# 挿入位置: P = 3 (D), 新規添字 X = 6 (C)
elem[6] = 'C'
next[6] = next[3] # 5
prev[6] = 3
next[3] = 6
prev[5] = 6
FAQ
Q1. 挿入がリストの末尾(Tail の直後)ならどう変わる?
A1. Tail の直後に挿入する場合、next[new]=0(末尾を表す)に設定し、prev[new]=oldTail、さらに Tail を new に更新します。
A1. Tail の直後に挿入する場合、next[new]=0(末尾を表す)に設定し、prev[new]=oldTail、さらに Tail を new に更新します。
Q2. 削除操作は挿入と逆順で更新すればよい?
A2. 基本は逆順で構いません。削除では周囲のリンクをつなぎ直した後、削除要素の next/prev をクリア(0 にするなど)すると安全です。
A2. 基本は逆順で構いません。削除では周囲のリンクをつなぎ直した後、削除要素の next/prev をクリア(0 にするなど)すると安全です。
Q3. 添字があふれたらどうする?
A3. 配列が固定長で満杯の場合は拡張(再確保)か、フリーノード管理(空きリスト)を用いて空き添字を再利用します。
A3. 配列が固定長で満杯の場合は拡張(再確保)か、フリーノード管理(空きリスト)を用いて空き添字を再利用します。
関連キーワード: 双方向リスト、連結リスト、配列実装、挿入操作、next配列、prev配列、添字管理

\ せっかくなら /
応用情報技術者を
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

