leadcode的Hot100系列--206. 反轉鏈表

這裏使用兩種方式,
一個是直接從頭日後遍歷 -------> 迭代
一個是從最後一個往前遍歷 -----> 遞歸指針

迭代

定義三個變量:pPre pNext pNow
pPre表示當前節點的前一個地址,pNext表示當前節點的下一個地址,pNow表示當前節點的地址。code

反轉的核心:就是把 pNow的next指針,指向 pPre遞歸

由於反轉以後,pNow的next原來的值會丟,因此在反轉以前,要用pNext把原來的值保存一下。
反轉以後,要處理下一個節點,而本節點就是下一個節點的前一個節點,因此用pPre把當前節點地址保存一下。變量

struct ListNode* reverseList(struct ListNode* head){
    struct ListNode *pstPre = NULL;
    struct ListNode *pstNow = head;
    struct ListNode *pstNext = NULL;
    
    while (NULL != pstNow)
    {
        pstNext = pstNow->next;  // 先保存一下當前節點的next指針
        pstNow->next = pstPre;    // 作反轉
        pstPre = pstNow;              // 更新pstPre指針
        pstNow = pstNext;            // 繼續作下一個節點的反轉
    }
    return pstPre;
}

遞歸

遞歸的話,不太好理解,先上代碼,看着代碼來理解:List

struct ListNode* reverseList(struct ListNode* head){
    struct ListHode *pstNewHead = NULL;
    if (head == NULL || head->next == NULL)   // 若是鏈表爲空,或者是最末端節點,則直接返回當前節點地址
    {
        return head;
    }
    else
    {
        pstNewHead = reverseList(head->next);  // 返回新鏈表頭節點
        head->next->next = head;  // 這裏完成反轉
        head->next = NULL;
        
        return pstNewHead;
    }
}

遞歸寫法的關鍵是:head->next->next = head 這句代碼中,
head 是誰,head->next 是誰,head->next->next 又是誰!遍歷

能夠從後往前理解,假設有三個節點,爲 1 -> 2 -> 3,鏈表

最後一次:當head爲節點2時,入參爲傳入節點3,節點3的next爲NULL,返回節點3的地址。next

此時:head指向節點2,pstNewHead指向節點3,
-----> 獲得:head->next 指向節點3,head->next->next 就至關於節點3的next,
因此:執行完 "head->next->next = head"以後,就至關於把節點3的next指向了節點2,完成一個反轉。
而節點2的next指針已經沒用了(本來節點2的next指向了節點3),直接指向NULL。
上面部分實現了節點3與節點2的反轉,並此時pstNewHead指向了節點3。while

再繼續。
上面返回pstNewHead爲節點3的地址,此時入參的head爲1(由於以前head爲節點2,返回調用者的時候,是head->next爲節點2,因此這裏調用者爲節點1),
因此,head->next爲2,head->next->next 就至關因而節點2的next,因此執行完 "head->next->next = head"以後,就至關於把節點2的next指向了節點1
而節點1原來的next沒用了(本來節點1的next指向了節點2),直接指向NULL,這裏就至關因而鏈表尾部。
而後返回pstNewHead。
其實這裏pstNewHead只賦值過一次,以後從未改變,一直指向了最一開始的節點3。co

相關文章
相關標籤/搜索