題目:定義一個函數,輸入鏈表的頭結點,反轉該鏈表並輸出反轉後鏈表的頭結點,鏈表結點結構定義如下:
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
解決與鏈表相關的問題總是有大量的指針操作,而指針操作的代碼總是很容易出錯。很多面試官喜歡出鏈表相關的問題,就是想通過指針操作來考察應聘者的編碼功底。爲了避免出錯,我們最好先進行全面的分析,在實際軟件開發週期中,設計的時間總不會比編碼的時間短。在面試的時候我們不要急於動手寫代碼,而是一開始仔細分析和設計,這將會給面試官留下很好的印象。與其很快的寫出一段漏洞百出的代碼,倒不如仔細分析再寫出魯棒的代碼。
爲了正確的反轉一個鏈表,需要調整鏈表中指針的方向。爲了將調整指針的這個複雜過程分析清楚,我們可以藉助畫圖來直觀的分析,具體圖如下:
反轉前:所示的鏈表 H、I、J 是三個相鄰的結點。
反轉中:經過若干操作,我們已經把結點 H 之前的指針調整完畢,這些節點的next都指向前面一個結點。
我們可以看到,上圖所示的鏈表 I 結點的next指向 H ,此時的鏈表結構爲結點 I 和 J 之間發生斷裂。
不難注意到,由於結點 I 的next指向了它的前一個結點,導致我們無法在鏈表中遍歷到結點 J ,爲了避免鏈表在結點 I 處斷裂,我們需要在調整結點 I 的next之前,把結點 J 保存下來。
也就是說我們在調整結點 I 的next指針時,除了需要知道結點 I 本身,還要知道結點 I 的前一個結點 H ,因爲我們需要把結點 I 的next指向結點 H 。同時,我們還需要保存 I 的下一個節點 J ,以防止鏈表斷裂。
爲此,我們需要定義三個指針,分別指向當前遍歷的結點、它的前一個結點、它的後一個結點。
最後我們試着找到反轉鏈表的頭結點。不難分析出,反轉之後的鏈表的頭結點爲原始鏈表的尾節點。
爲此,我們給出代碼如下:
ListNode* ReverseList(ListNode* pHead) {
ListNode* ReversepHead = NULL;
ListNode* pNode = pHead;
ListNode* pPrev = NULL;
while(pHead != NULL)
{
ListNode* pNext = pHead->next;
if(pHead->next == NULL)
ReversepHead = pHead;
pHead->next = pPrev;
pPrev = pHead;
pHead = pNext;
}
return ReversepHead;
}