鍊錶翻轉的方法

2021-09-12 16:30:04 字數 1515 閱讀 8751

鍊錶的翻轉是程式設計師面試**現頻度最高的問題之一,常見的解決方法分為遞迴和迭代兩種。最近在複習的時候,發現網上的資料都只告訴了怎麼做,但是根本沒有好好介紹兩種方法的實現過程與原理。所以我覺得有必要好好的整理一篇博文,來幫忙大家一步步理解其中的實現細節。 

我們知道迭代是從前往後依次處理,直到迴圈到鏈尾;而遞迴恰恰相反,首先一直迭代到鏈尾也就是遞迴基判斷的準則,然後再逐層返回處理到開頭。總結來說,鍊錶翻轉操作的順序對於迭代來說是從鏈頭往鏈尾,而對於遞迴是從鏈尾往鏈頭。下面我會用詳細的**來剖析其中實現的細節。 

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)

#include

using namespace std;

struct node

};/***非遞迴方式***/

node* reverselist(node* h)

return newh;

}/***遞迴方式***/

node* in_reverselist(node* h)

int main()

後面敲黑板,論壇中很多對這句話有議論。

h->next = null;

作者給的注釋是防止鍊錶錯亂,個人和罈子裡的人想法一致,也是覺得沒必要。

鍊錶的翻轉

如何快速的實現鍊錶的翻轉,比如鍊錶a資料為 str1,str2,str3,str4,str5,str6 翻轉後則變為 str6,str5,str4,str3,str2,str1 針對上述問題我能想到的一種辦法就是以壓棧的方式來實現,其實現思路相對較為簡單,通過定義乙個鍊錶資料結構的資料棧,遍歷鍊錶,...

鍊錶的翻轉

輸入乙個鍊錶,反轉鍊錶後,輸出鍊錶的所有元素。struct listnode 方法一 建立節點指標型別堆疊,遍歷鍊錶,將指標壓棧,順次出棧,實現反轉。這個占用記憶體空間較大。listnode reverselist listnode phead 建立鍊錶list list phead if list...

分析鍊錶翻轉

鍊錶翻轉分兩部分,鍊錶整表翻轉和鍊錶部分翻轉。下面討論非遞迴的做法,遞迴的做法以後有空再說。先說鍊錶整表翻轉,核心四句話 next p.next p.next pre pre p p next 顧名思義,pre是p前面的節點,next是p後面的節點。舉個例子,下圖是乙個鍊錶節點翻轉前的狀態 上面的 ...