這裏使用兩種方式,
一個是直接從頭日後遍歷 -------> 迭代
一個是從最後一個往前遍歷 -----> 遞歸指針
定義三個變量: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