単方向リストは以前結構学んで、大分自信がついてきたので色々といてみたのですが、
サンプル問題のこちらの問題の動きがいまいちわからず、動きをしっかり追ってみました。
python での記述です。
問題:問題なので、こちらのコードは実行できません。
太文字が問題です。
class ListElement:
def __init__(self, val):
self.val = val
self.next = None
# 大域変数の初期化
ListHead = None
curr = None
#current現在地
prev = None
#previosひとつ前
def append(qval):
global ListHead # 大域変数を参照するためのキーワード
curr = List(qval) # 新しいリストの要素を作成
if **<問題A:ListHeadが未定義 or 未定義でない>** :
ListHead = curr
else:
prev = ListHead
while prev.next is not None:
prev = prev.next
prev.next = **<問題B:ここに何が入るかな?>**
回答:
問題A:未定義
問題B:curr
なんとなく解けるのではないでしょうか。
ただコードをの動きがいまいちわかりませんね。
疑問:
- if ListHead is None:は実行されるのか?
2.while prev.next is not None:はループに入るのか?
3.while prev.next is not None:は何回実行されるのか?
4.curr,prev,prev.nextの動き
そのため実際にコードを修正し、実行できるようにしてみました。
A,B,Cの順番でリストに入れます。
実行用コード:
class ListElement:
def __init__(self, val):
self.val = val
self.next = None
# 大域変数の初期化
ListHead = None
curr = None
prev = None
def append(qval):
global ListHead, curr, prev # 大域変数を参照するためのキーワード
curr = ListElement(qval) # 新しいリストの要素を作成
if ListHead is None: # リストが空の場合
ListHead = curr#ここで初めてリストの参照ができる。
else:
prev = ListHead
while prev.next is not None:
prev = prev.next
prev.next = curr
# A, B, Cをリストに追加
append("A")
append("B")
append("C")
# 確認のためにリストの内容を表示
def print_list():
global ListHead
temp = ListHead
while temp:
print(temp.val)
temp = temp.next
print_list()
実行できたのではないでしょうか。
動きを考えてみよう!
Aの参照を1とするまた、B:2,C:3とする!
1. if ListHead is None:は実行されるのか?
1**.Aを追加するとき**
- 初めて**
append
関数が呼び出されると、curr
は新しいList
**オブジェクト(A)の参照(1)を保持します。 - **
ListHead
はまだNone
なので、ListHead
にcurr
**の参照(1)が設定されます。 - if ListHead is None:ここで実行される
- **
prev
**はまだ使用されていません。
状態:
-
ListHead
= 1(Aの参照) -
curr
= 1(Aの参照) -
prev
= 未使用
while prev.next is not None:のループには入るのか?
2.Bを追加するとき
- **
append
関数が再度呼び出され、curr
は新しいList
**オブジェクト(B)の参照(2)を保持します。 - **
ListHead
**はAの参照(1)なので、elseブロックに進みます。 - **
prev
にListHead
**の参照(1、Aの参照)が設定されます。 -
prev.next
はNone
(Aの次の要素はまだない)なので、whileループは実行されず、直接**prev.next
にcurr
**(Bの参照、2)が設定されます。 - while prev.next is not None:には今回はループに入らない。
状態:
-
ListHead
= 1(Aの参照) -
curr
= 2(Bの参照) -
prev
= 1(Aの参照) -
prev.next
= 2(Bの参照)
3.Cを追加するとき
- **
append
関数が再度呼び出され、curr
は新しいList
**オブジェクト(C)の参照(3)を保持します。 - **
ListHead
**はAの参照(1)なので、elseブロックに進みます。 - **
prev
にListHead
**の参照(1、Aの参照)が設定されます。 - **
prev.next
**はBの参照(2)なので、whileループに入ります。 -
prev
はBの参照(2)に更新され、そのprev.next
(Bの次の要素)は**None
です。ループは終了し、prev.next
にcurr
**(Cの参照、3)が設定されます。
状態:
-
ListHead
= 1(Aの参照) -
curr
= 3(Cの参照) -
prev
= 2(Bの参照) -
prev.next
= 3(Cの参照)
最終的に、**ListHead
がAを指し、Aのnext
がBを指し、Bのnext
**がCを指す形の単方向リンクドリストが完成します。
結果:
何か問題によって考え方が結構違うので、問題解きまくるしかないなあ。
prev.next.nextを最後に使う、どこに使うかわからないコードよりはだいぶましな問題だとは思う。