
【オブジェクト指向】単方向リストの削除(FEBサンプル問題1問10, 基本情報技術者試験, 科目B, 午後, 擬似言語)擬似言語⑬Aの2
このNoteでは「単方向リスト」をオブジェクト指向で実現した擬似言語問題をガチでトレースします。>【FEB】サンプル問題1問10のNote
下図のようにリストから要素を削除するdelNode()関数をトレースします。

なおリストを作成するappend()関数は公開問題に出ており、前回のNoteで解説済みです。
>【擬似言語⑬A1】単方向リストの作成/追加Note
>【FEB】サンプル問題2問03のNote
下図は、今回トレースするdelNode()関数の擬似言語。

まずはdelNode(2)をトレースし(青)、実行されなかった部分の動作確認のためにdelNode(1)とdelNode(3)のトレースも追加学習します。
公開問題に出た以上、しっかり深く復習したいですね。
それでは始めましょう!
>全Noteへのリンク(FE節)
※科目Aのテーマ別対策、科目B対策、旧FE午後(セキュリティ)など沢山作りました!
【NOTICE】著作権を侵害には即座に法的措置をしています。人格否定もブロックなどの自衛手段を行います。私は1個人であり、公人ではありません。プライベート時間の全てを費やして作成してきました。ご理解頂ける方のみ、ご活用されると嬉しいです🫠
今回の全体像
delNode(2)関数で、リストの2番目要素を削除をします。
下記がメイン処理。大域宣言~append関数3回で、リスト(A→K→T)を作ります。トレースは前回のNote。>【擬似言語⑬A1】単方向リストの作成/追加Note

delNode関数は、リスト内の引数番目の要素を削除します。例えばdelNode(2)なら2番目の要素(K)が削除され、元(A→K→T)が(A→T)になります。
下図が今回の全擬似言語。
〔プログラム〕
大域: ListElement: listHead // リストの先頭要素が格納されている
append("A")
append("K")
append("T")
delNode(2)
○delNode(整数型: pos) /* posは,リストの要素数以下の正の整数 */
ListElement: prev
整数型: i
if (pos が 1 と等しい)
listHead ← listHead.next
else
prev ← listHead
/* posが2と等しいときは繰返し処理を実行しない */
for (i を 2 から pos - 1 まで 1 ずつ増やす)
prev ← prev.next
endfor
prev.next ← prev.next.next
endif事前準備
append関数でリストを作ります。前回のNoteでトレース済みなので結論のみ。>【擬似言語⑬A1】単方向リストの作成/追加Note
listHeadにリスト先頭のアドレス値(メモリでの保存場所)が記録され、.nextで紐づけられリストが構築されます。

青文字の擬似言語を実行したら、下青図の状況になります。残りの黒字delNode(2)のトレースを次節からします。
delNode(2)のトレース
色表現は 前回のNoteと同じ。>【擬似言語⑬A1】単方向リストの作成/追加Note
擬似言語1行1行で変化した部分に色を付け(青, 緑, 水色)。注目/注意すべき点も(緑, 赤)。最初の1~2行が擬似言語、3行目以降に、変数/メモリ(データ)の作成状況。アドレス値を記録したポインタ変数は値と矢印で表現。
1行目は、prevを作るだけ。prevはListElement型データのアドレスを記録するポインタ変数。まだどこも指していません(未定義)。

上図の下。2行目のif文の判定。delNode(2)で引数pos=2、判定はFalse。次からelse文の実行をトレースします。
下図。else文の1行目。prevにアドレスが代入され、prevは”A”があるデータを指すようになりました。つまりリストの1番目を指す。

else文2行目はfor文。
delNode(2)よりpos=2なので、for文は「iを2から1まで1ずつ増やす」。for文内は実行されません。

for文を実行せずスルーして、for文直後/else文最後の1行。
今回最難関「prev.next←prev.next.next」を解釈します。
「←」で上書きされるので、❶❷❸と順を追って理解して下さいね。一気にやろうとすると混乱するかも。

❶prev.nextは、prevの属性値nextを指します。上図上よりprevはアドレス100のオブジェクトを指し、属性値next=300。
ただし、今回のクラス定義では「.next」もポインタ変数。値(アドレス)であると同時に、ListElement型データも指しています。
つまり、prev.nextは「300」であると同時に、アドレス300にある「ListElement型データ=Kのやつ」でもあります。
❷「prev.next.next」は「次の次のモノ」を意味します。prev.nextで300/"K"があるオブジェクト。prev.next.nextは200/"T"があるオブジェクトを指します。
❸「prev.next←prev.next.next」で、「"A"オブジェクトのnext」に「"T"オブジェクト」のアドレスで上書きしてます。AからKへの繋がりが、AからTへの繋がりに変更されます。
❶❷❸を経て、delNode関数は終了。
delNode()関数が終了したら、局所なprevは喪失します。大域なlistHeadは残ります。

listHeadからA→Tと辿れるようになりました。Kの200からも紐づいてますが、K(アドレス300)に行くことはないので問題ありません。
なお。追うのは沼ですが。アドレス300も200もappend関数内で作成したので喪失しそうですが、プログラム言語がうまいことします。まだ必要な200を残し、不要になった300を消す(他データで上書き)など。
全体フローと見たい処理
delNode(2)で辿ったルートを青線で描きました。

実行されなかったのは、緑と橙。
発動条件を考えます。
緑:pos=1で発動。delNode(1)なら実行される。
橙:for文はdelNode(3)なら1回実行される。
次節で見ます。