これを考える 1 つの方法は、小さな例を使用することです。まず、2 つのエッジ ケース:
- リストが空の場合は、すでに逆になっています (簡単に)
curr
が単一のノードである場合、それはそれ自身の反転です (繰り返しますが、自明です) 。したがって、現在のリストの先頭を に設定しcurr
ます。
これらのどちらも当てはまらないと仮定すると、最後のコード ブロックがどのように機能するかを理解するのが難しいことになります。おそらく、プロセス全体は を呼び出すことによって開始されreverse(head)
ます。2 要素リストで何が起こるか見てみましょう。
head = curr(0)
|
V
+---+ +---+
| 0 |->| 1 |->null
+---+ +---+
再帰呼び出しごとに新しい が作成されるため、適用される再帰のレベルを示すインデックスでcurr
注釈を付けました。curr
への呼び出しがありreverse(curr.next)
ます。その呼び出し中、メソッドの開始時の画像は次のようになります。
head curr(1)
| |
V V
+---+ +---+
| 0 |->| 1 |->null
+---+ +---+
これは 2 番目のエッジ ケースを満たすため、メソッドは図を次のように変更します。
head = curr(1)
|
V
+---+ +---+
| 0 |->| 1 |->null
+---+ +---+
curr
(要素が 1 つのリストでしたが、その要素は ではなかったことに注意してくださいhead
。これが、すべてが機能する理由の鍵です!) メソッドが戻り、最初の呼び出しに戻ります。写真は次のようになります。
curr(0) head
| |
V V
+---+ +---+
| 0 |->| 1 |->null
+---+ +---+
コードの 2 行目 (3 番目のブロック内) はcurr.next.next = curr;
. これにより、画像が次のように変更されます。
curr(0) head
| |
V V
+---+ +---+
| 0 |->| 1 |--\
+---+ +---+ |
^ |
| |
\-----------/
最後に、次のように設定しますcurr.next = null;
。
curr(0) head
| |
V V
+---+ +---+
| 0 |->null | 1 |--\
+---+ +---+ |
^ |
| |
\------------------/
それを少し見つめてみると、実際にはリストが逆になっていることがわかります。
同じ手法を使用して、これが長いリストを逆にする方法を確認できます。これについて考える最も簡単な方法は、呼び出すreverse(curr.next)
とリストの末尾が逆になり、次の 2 行がcurr
リストの末尾に追加されるということです。