鍊錶的翻轉是程式設計師面試中出現頻度最高的問題之一,常見的解決方法分為遞迴和迭代兩種。
我們知道迭代是從前往後依次處理,直到迴圈到鏈尾;而遞迴恰恰相反,首先一直迭代到鏈尾也就是遞迴基判斷的準則,然後再逐層返回處理到開頭。
總結來說,鍊錶翻轉操作的順序對於迭代來說是從鏈頭往鏈尾,而對於遞迴是從鏈尾往鏈頭。下面我會用詳細的**來剖析其中實現的細節。
1、非遞迴(迭代)方式
迭代的方式是從鏈頭開始處理,如下圖給定乙個存放5個數的鍊錶。
首先對於鍊錶設定兩個指標:
然後依次將舊鍊錶上每一項新增在新鍊錶的後面,然後新鍊錶的頭指標newh移向新的煉表頭,如下圖所示。此處需要注意,不可以上來立即將上圖中p->next直接指向newh,這樣存放2的位址就會被丟棄,後續鍊錶儲存的資料也隨之無法訪問。而是應該設定乙個臨時指標tmp,先暫時指向p->next指向的位址空間,儲存原鍊錶後續資料。然後再讓p->next指向newh,最後p=tmp就可以取回原鍊錶的資料了,所有迴圈訪問也可以繼續展開下去。
指標繼續向後移動,直到p指標指向null停止迭代。
最後一步:
2、非遞迴實現的程式
node* reverselist(node* h)
return newh;
}
3、遞迴方式
我們再來看看遞迴實現鍊錶翻轉的實現,前面非遞迴方式是從前面數1開始往後依次處理,而遞迴方式則恰恰相反,它先迴圈找到最後面指向的數5,然後從5開始處理依次翻轉整個鍊錶。
首先指標h迭代到底如下圖所示,並且設定乙個新的指標作為翻轉後的鍊錶的頭。由於整個鍊錶翻轉之後的頭就是最後乙個數,所以整個過程newh指標一直指向存放5的位址空間。
然後h指標逐層返回的時候依次做下圖的處理,將h指向的位址賦值給h->next->next指標,並且一定要記得讓h->next =null,也就是斷開現在指標的鏈結,否則新的鍊錶形成了環,下一層h->next->next賦值的時候會覆蓋後續的值。
繼續返回操作:
上圖第一次如果沒有將存放4空間的next指標賦值指向null,第二次h->next->next=h,就會將存放5的位址空間覆蓋為3,這樣鍊錶一切都大亂了。接著逐層返回下去,直到對存放1的位址空間處理。
返回到頭:
4、迭代實現的程式
node* in_reverselist(node* h)
5、整體實現的程式:
#includeusing namespace std;
struct node
};/***非遞迴方式***/
node* reverselist(node* h)
return newh;
}/***遞迴方式***/
node* in_reverselist(node* h)
int main()
面試題 鍊錶的 部分 翻轉
2016年08月09日 21 43 37 問題 給出乙個單鏈表 不帶頭節點 和乙個數k,請翻轉此單鏈表?例如 1 2 3 4 5 k 0 翻轉過後 1 2 3 4 5 1 2 3 4 5 k 2 翻轉過後 2 1 4 3 5 1 2 3 4 5 k 10 翻轉過後 5 4 3 2 1 在討論鍊錶的 ...
鍊錶的翻轉
如何快速的實現鍊錶的翻轉,比如鍊錶a資料為 str1,str2,str3,str4,str5,str6 翻轉後則變為 str6,str5,str4,str3,str2,str1 針對上述問題我能想到的一種辦法就是以壓棧的方式來實現,其實現思路相對較為簡單,通過定義乙個鍊錶資料結構的資料棧,遍歷鍊錶,...
分析鍊錶翻轉
鍊錶翻轉分兩部分,鍊錶整表翻轉和鍊錶部分翻轉。下面討論非遞迴的做法,遞迴的做法以後有空再說。先說鍊錶整表翻轉,核心四句話 next p.next p.next pre pre p p next 顧名思義,pre是p前面的節點,next是p後面的節點。舉個例子,下圖是乙個鍊錶節點翻轉前的狀態 上面的 ...