鍊錶(linked list)是一種常見的基礎資料結構,是一種線性表,但是並不會按線性的順序儲存資料,而是在每乙個節點裡存到下乙個節點的指標(pointer)
由於不必須按順序儲存,鍊錶在插入的時候可以達到 o(1) 的複雜度,比另一種線性表 —— 順序表快得多,但是查詢乙個節點或者訪問特定編號的節點則需要 o(n)o(n) 的時間,而順序表相應的時間複雜度分別是 o(log n)o(log n) 和 o(1)o(1)。
使用鍊錶結構可以克服陣列鍊錶需要預先知道資料大小的缺點,鍊錶結構可以充分利用計算機記憶體空間,實現靈活的記憶體動態管理。但是鍊錶失去了陣列隨機讀取的優點,同時鍊錶由於增加了結點的指標域,空間開銷比較大。
在電腦科學中,鍊錶作為一種基礎的資料結構可以用來生成其它型別的資料結構。鍊錶通常由一連串節點組成,每個節點包含任意的例項資料(data fields)和一或兩個用來指向上乙個/或下乙個節點的位置的鏈結(links)。鍊錶最明顯的好處就是,常規陣列排列關聯專案的方式可能不同於這些資料專案在記憶體或磁碟上順序,資料的訪問往往要在不同的排列順序中轉換。而鍊錶是一種自我指示資料型別,因為它包含指向另乙個相同型別的資料的指標(鏈結)。
鍊錶允許插入和移除表上任意位置上的節點,但是不允許隨機訪問。鍊錶有很多種不同的型別:單向鍊錶,雙向鍊錶以及迴圈鍊錶。鍊錶通常可以衍生出迴圈鍊錶,靜態鍊錶,雙鏈表等。對於鍊錶使用,需要注意頭結點的使用。
涉及到鍊錶的操作,一定要在紙上把過程先畫出來,再寫程式。
由於乙個節點只通過next指標儲存了它的下乙個節點,失去了它的前驅節點資訊,而且單鏈表資料結構通常長度未知,因此幾乎所有單鏈表題目都是在前驅節點和長度上做文章。
常見煉表面試演算法,可以使用雙指標迭代的方式以及遞迴的方式。
鍊錶中最簡單的一種是單向鍊錶,它包含兩個域,乙個資訊域和乙個指標域。這個指標域指向列表中的下乙個節點,而最後乙個節點則指向乙個空值。
如何迭代?雙指標迭代。
使用雙指標迭代方式反轉單鏈表的中心思想:
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+1 步,而第二個指標將從列表的開頭出發。現在,這兩個指標被 n 個結點分開。我們通過同時移動兩個指標向前來保持這個恆定的間隔,直到第乙個指標到達最後乙個結點。此時第二個指標將指向從最後乙個結點數起的第 n 個結點。我們重新鏈結第二個指標所引用的結點的 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 else
curr = curr.next;
}curr.next = l1==null?l2:l1;
return dummyhead.next;}}
這道題可以使用遞迴實現,新鍊錶也不需要構造新節點,列舉遞迴三個要素 終止條件:兩條鍊錶分別名為 l1 和 l2,當 l1 為空或 l2 為空時結束 返回值:每一層呼叫都返回排序好的煉表頭 本級遞迴內容:如果 l1 的 val 值更小,則將 l1.next 與排序好的煉表頭相接,l2 同理 o(m+n),m 為 l1的長度,n 為 l2 的長度
class solution
if(l2 == null)
if(l1.val l1.next = mergetwolists(l1.next, l2);
return l1;
} 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;}}
鍊錶涉及題型太多,剩下的題型後續再總結,不過很多都可以雙指標和遞迴思想解決,但是看了會,動手會不會就兩說了,還是要學會動手寫,最好嘗試用筆在白紙上寫,先畫畫鍊錶圖,再寫下演算法**……
在IBM的第二個星期
從9號到今天,正好工作兩個星期了,這兩個星期裡我在工作日每天都能夠堅持在6點前起床,基本上每天都是第乙個到辦公室 這兩個星期我過得很開心,很充實,也很順利,每天從早到晚都不累。第乙個星期對abap學習有了個總體的把握。第二個星期繼續學習,而且順利完成manager交給我的第乙個任務。對我影響很大的兩...
Scala練習題02 列表中找出倒數第二個元素
find the last but one element of a list.list列表中找出倒數第二個元素 package com.yl.problem object pro02 02 模式匹配解決 def method02 a ls list a a ls match 03 稍作修改內建方法...
在鍊錶中查詢倒數第k個元素
第一種思路 第二種思路 注意 檔名 listnode.h pragma once ifndef listnode h define listnode h include using namespace std 定義鍊錶結構體 templatet struct listnode listnode t ...