就地鍊錶反轉 鍊錶常見問題總結 一

2021-10-14 06:22:01 字數 3229 閱讀 3205

鍊錶(linked list)是一種常見的基礎資料結構,是一種線性表,但是並不會按線性的順序儲存資料,而是在每乙個節點裡存到下乙個節點的指標(pointer)

由於不必須按順序儲存,鍊錶在插入的時候可以達到 o(1)o(1) 的複雜度,比另一種線性表 —— 順序表快得多,但是查詢乙個節點或者訪問特定編號的節點則需要 o(n)o(n) 的時間,而順序表相應的時間複雜度分別是 o(log n)o(log n) 和 o(1)o(1)。

使用鍊錶結構可以克服陣列鍊錶需要預先知道資料大小的缺點,鍊錶結構可以充分利用計算機記憶體空間,實現靈活的記憶體動態管理。但是鍊錶失去了陣列隨機讀取的優點,同時鍊錶由於增加了結點的指標域,空間開銷比較大。

在電腦科學中,鍊錶作為一種基礎的資料結構可以用來生成其它型別的資料結構。鍊錶通常由一連串節點組成,每個節點包含任意的例項資料(data fields)和一或兩個用來指向上乙個/或下乙個節點的位置的鏈結(links)。鍊錶最明顯的好處就是,常規陣列排列關聯專案的方式可能不同於這些資料專案在記憶體或磁碟上順序,資料的訪問往往要在不同的排列順序中轉換。而鍊錶是一種自我指示資料型別,因為它包含指向另乙個相同型別的資料的指標(鏈結)。

鍊錶允許插入和移除表上任意位置上的節點,但是不允許隨機訪問。鍊錶有很多種不同的型別:單向鍊錶,雙向鍊錶以及迴圈鍊錶。鍊錶通常可以衍生出迴圈鍊錶,靜態鍊錶,雙鏈表等。對於鍊錶使用,需要注意頭結點的使用。

涉及到鍊錶的操作,一定要在紙上把過程先畫出來,再寫程式。

常見煉表面試演算法,可以使用雙指標迭代的方式以及遞迴的方式。

鍊錶中最簡單的一種是單向鍊錶,它包含兩個域,乙個資訊域和乙個指標域。這個指標域指向列表中的下乙個節點,而最後乙個節點則指向乙個空值。

如何迭代?雙指標迭代。

使用雙指標迭代方式反轉單鏈表的中心思想:

1、雙指標分別指向鍊錶中的相鄰節點,初始狀態為當前指標指向頭節點,前指標指向null; 2、修改當前指標指向的節點的指向為前乙個節點,然後當前指標和前指標同時指向下乙個節點; 3、迴圈往復,直到當前指標指向的節點為null,返回前指標指向的節點。

具體步驟: 1.申請兩個指標,第乙個指標叫 pre,最初是指向 null 的,意指 cur 指標的前乙個指標。 2.第二個指標 cur 指向 head,然後不斷遍歷 cur。 3.每次迭代到 cur,都將 cur 的 next 指向 pre,然後 pre 和 cur 前進一位。 4.都迭代完了,cur 變成 null 了,pre 就是最後乙個節點了。

class solution 

return pre;

}}

終止條件是當前節點或者下乙個節點==null。

在函式內部,改變節點的指向,也就是 head 的下乙個節點指向 head。

class solution 

//這裡的cur就是最後乙個節點

listnode cur = reverselist(head.next);

//這裡請配合動畫演示理解

//如果鍊錶是 1->2->3->4->5,那麼此時的cur就是5

//而head是4,head的下乙個是5,下下乙個是空

//所以head.next.next 就是5->4

head.next.next = head;

//防止鍊錶迴圈,需要將head.next設定為空

head.next = null;

//每層遞迴函式都返回cur,也就是最後乙個節點

return cur;

}}

第乙個指標從列表的開頭向前移動 n+1n+1 步,而第二個指標將從列表的開頭出發。現在,這兩個指標被 nn 個結點分開。我們通過同時移動兩個指標向前來保持這個恆定的間隔,直到第乙個指標到達最後乙個結點。此時第二個指標將指向從最後乙個結點數起的第 nn 個結點。我們重新鏈結第二個指標所引用的結點的 next 指標指向該結點的下下個結點。

class solution 

// move first to the end, maintaining the gap

while (first != null)

second.next = second.next.next;

return dummy.next;}}

將兩個公升序鍊錶合併為乙個新的公升序鍊錶並返回。新煉表是通過拼接給定的兩個鍊錶的所有節點組成的。

首先,設定乙個哨兵節點 dummyhead ,這可以在最後比較容易地返回合併後的鍊錶。我們維護乙個 curr 指標,我們需要做的是調整它的 next 指標。然後,我們重複以下過程,直到 l1 或者 l2 指向了 null :如果 l1 當前節點的值小於等於 l2 ,我們就把 l1 當前的節點接在 curr 節點的後面同時將 l1 指標往後移一位。否則,我們對 l2 做同樣的操作。不管我們將哪乙個元素接在了後面,我們都需要把 curr 向後移一位。

在迴圈終止的時候, l1 和 l2 至多有乙個是非空的。由於輸入的兩個鍊錶都是有序的,所以不管哪個鍊錶是非空的,它包含的所有元素都比前面已經合併鍊錶中的所有元素都要大。這意味著我們只需要簡單地將非空鍊錶接在合併鍊錶的後面,並返回合併鍊錶即可。

class solution 

if(l2 == null)

if(l1.val < l2.val) else }}

解法:雙指標,快指標和滿指標

設煉表共有 a+b 個節點,其中 鍊錶頭部到鍊錶入口 有a 個節點(不計鍊錶入口節點), 鍊錶環 有 b 個節點。 設兩指標分別走了 f,s 步,則有: fast 走的步數是slow步數的 2 倍,即 f=2s;(解析: fast 每輪走 22 步) fast 比 slow多走了 n 個環的長度,即 f=s+nb;( 解析: 雙指標都走過 a 步,然後在環內繞圈直到重合,重合時 fast 比 slow 多走 環的長度整數倍 )

解法重點思想:

走a+nb步一定是在環入口

第一次相遇時慢指標已經走了nb步

public class solution 

fast = head;

while (slow != fast)

return fast;}}

鍊錶涉及題型太多,剩下的題型後續再總結,不過很多都可以雙指標和遞迴思想解決,但是看了會,動手會不會就兩說了,還是要學會動手寫,最好嘗試用筆在白紙上寫,先畫畫鍊錶圖,再寫下演算法**……

就地鍊錶反轉 常見程式設計模式之就地反轉鍊錶

在很多問題中,我們需要對乙個鍊錶中的節點連線進行反轉,且通常需要原地進行,即不能使用額外的儲存空間。這時我們可以使用就地反轉鍊錶模式,該模式本質上是一種迭代解法,流程如下圖所示。首先設定乙個變數current指向鍊錶頭部,以及另乙個變數previous指向當前處理節點的前乙個節點。下一步我們需要將當...

鍊錶常見問題

思路 快慢指標,慢指標每次移動一步,快指標每次移動兩步,如果存在環,那麼兩個指標一定會在環內相遇 把第二個煉表頭節點的頭接到第乙個鍊錶尾部,然後就轉換成判斷單鏈表是否有環的問題了 當快慢指標相遇後,將乙個指標固定在相遇點,另乙個指標回到鍊錶起始位置,然後兩指標每次都移動乙個node,當兩指標再次相遇...

就地鍊錶反轉 單鏈表反轉總結篇

單鏈表的反轉是常見的面試題目。本文總結了2種方法。1 定義 單鏈表node的資料結構定義如下 class listnode 15 return dummy.next 16 2.4 總結 1個頭結點,2個指標,4行 注意初始狀態和結束狀態,體會中間的 過程。3 方法2 新建鍊錶,頭節點插入法 3.1 ...