1. 程式人生 > 實用技巧 >面試題24:反轉單鏈表(解法二:遞迴法)

面試題24:反轉單鏈表(解法二:遞迴法)

反轉單鏈表的兩種方法

今天看了帥地的第二版資料,突然發現單鏈表的反轉居然還可以用遞迴來做,太妙了吧!

  直接上程式碼,目前只有C++版的(用指標寫連結串列它不香嗎?):

// 遞迴法反轉單鏈表
ListNode* reverseListPlus(ListNode* pHead){
    if(pHead == nullptr || pHead->next == nullptr)
        return pHead;

    ListNode* reverseNode = reverseListPlus(pHead->next);
    pHead->next->next = pHead;
    pHead->next = nullptr;

    return reverseNode;
}

int main()
{
    ListNode* pNode1 = createListNode(1);
    ListNode* pNode2 = createListNode(2);
    ListNode* pNode3 = createListNode(3);
    ListNode* pNode4 = createListNode(4);
    ListNode* pNode5 = createListNode(5);

    connectListNodes(pNode1, pNode2);
    connectListNodes(pNode2, pNode3);
    connectListNodes(pNode3, pNode4);
    connectListNodes(pNode4, pNode5);

    PrintListNodes(pNode1);
    // 遞迴法反轉連結串列
    reverseListPlus(reverseList(pNode1));

    // 測試反轉是否成功
    PrintListNodes(pNode5);
    return 0;
}

  程式碼解釋:

  1、ListNode* reverseNode = reverseListPlus(pHead->next);

  • 遞迴法的目的是要返回一個新的頭節點,這個新的頭節點是原來連結串列的尾節點。

  • 遞迴是方法自己呼叫自己,棧的特性是先進後出、後進先出。所以這段程式碼的作用是不斷的去壓棧。

  2、pHead->next->next = pHead;把當前節點指向的下一個節點的指向變為自己。(不要慌,這段程式碼的解釋,下面有圖有真相);

  3、pHead->next = nullptr; 當前節點指向的下一個節點變為空。

  是不是看了上面的解釋還有點不理解,別急,我第一次看這段程式碼的時候也是懵逼的(內心wc:這寫了個啥,怎麼就反轉連結串列了),要理解這段程式碼首先,我們得去壓幾個棧:

  ListNode* reverseNode = reverseListPlus(pHead->next);這段程式碼會執行四次,壓棧四次,如圖:


  if(pHead == nullptr || pHead->next == nullptr) return pHead;這段程式碼會讓 reverseListPlus(pHead(4)) 發生彈棧,然而連結串列沒有發生任何變化。。。方法繼續執行。


  接著 reverseRecursion(head(3)) 彈棧執行下面這段程式碼
  head.next.next = head;
  head.next = null;
  reverseRecursion(head(3))

執行之後連結串列發生瞭如下變化:


  持續到最後reverseRecursion(head(1))出棧:連結串列反轉完成,撒花
  head.next.next = head;
  head.next = null;