鍊錶不需要一塊連續的記憶體空間,它是通過"指標"將一組零散的記憶體塊串聯起來使用。
假如現在申請100m的陣列,如果沒有連續的記憶體空間,會申請失敗,但是申請100m的鍊錶,是可以成功的,說明鍊錶的儲存結構不需要連續的記憶體空間,只要記憶體滿足需求就可以。
1.單向鍊錶
鍊錶是通過指標將自足零散的記憶體塊串聯起來,每個記憶體塊稱為鍊錶的「結點」,每個「結點」除了儲存資料以外,還要記錄鏈的下乙個結點的位址。這個記錄下個結點的指標叫做後繼指標next
第乙個結點叫頭結點,頭結點記錄鍊錶的基位址。
最後乙個結點叫做尾結點,尾結點指向空值null,表示鍊錶的終點
鍊錶的插入和刪除操作,只需要考慮相鄰結點的指標改變,時間複雜度為o(1);
鍊錶的查詢操作,需要根據指標乙個結點乙個結點的遍歷,直到找到對應的結點,時間複雜度o(n)。
2.迴圈鍊錶
迴圈鍊錶是一種特殊的單鏈表。它跟單鏈表的區別在於尾結點,它的尾結點指標指向鍊錶的頭結點,像乙個環一樣首尾相連,所以叫迴圈鍊錶。
3.雙向鍊錶
支援雙向遍歷,更加靈活。
從結構上看,雙向鍊錶支援o(1)時間複雜度的情況下找到前驅結點,這個特點使得雙向鍊錶在某些情況下的插入、刪除操作逗比單向鍊錶更加高效、簡單。
鍊錶的刪除操作
第一種刪除,無論是單向鍊錶還是雙向鍊錶,都需要從頭結點開始乙個個的遍歷,直到找到給定值的結點,然後將其刪除。
單純刪除操作的時間複雜度為o(1),但是遍歷查詢的時間複雜度為o(n),所以執行該刪除操作的時間複雜度為o(n),這個很容易理解。
第二種刪除操作
這種情況下已經知道了要刪除的結點,但是要刪除該結點,需要知道其前驅結點,這時候雙向鍊錶優勢就體現出來了。
單向鍊錶是無法知道前驅結點的,要想知道,就得重新遍歷一遍,時間複雜度為o(n)
雙向鍊錶結點中已經儲存了前驅結點的指標,不需去重新遍歷一遍了,時間複雜度為o(1)
同理,如果插入乙個結點的話,雙向鍊錶時間複雜度為o(1),單向鍊錶為o(n)。
時間軟體開發中,雙向鍊錶比單向鍊錶更耗記憶體,但是應用卻比較廣泛,這裡有乙個用空間換時間的設計思想。
在記憶體空間相對較充足的情況下,如果更加追求**的執行速度,就可以選擇空間複雜度相對較高,但是時間複雜度相對很低的演算法或者資料結構。
相反,如果記憶體吃緊,例如**在手機或者微控制器,這時候就反過來用時間換空間的設計思路。
快取是一種提高資料讀取效能的技術,在硬體設計、軟體開發中廣泛應用,例如cpu快取、資料庫快取、瀏覽器快取等。
快取的大小有限,當快取被用滿時,哪些資料應該被清除,哪些應該被保留?需要快取的淘汰策略來決定。
快取淘汰策略
快取是假上就是用空間換時間設計思想。如果把資料放到硬碟上,會比較節省記憶體,但是每次查詢都需要詢問一次硬碟,比較慢。
如果通過快取技術,實現把資料載入到快取,雖然耗費記憶體空間,但是可以大大提高資料查詢的速度。
雙向鍊錶 + 迴圈鍊錶
時間複雜度
陣列鍊錶
插入和刪除
o(n)
o(1)
隨機訪問
o(1)
o(n)
陣列和鍊錶的對比不能只看時間複雜度
知識擴充套件:
1.arraylist的源**實現?
2.linkedlist的源**實現?
3.如何基於鍊錶實現lru快取淘汰演算法
思路:維護乙個單向鍊錶,越靠近鍊錶尾部的結點是越早之前訪問的,當乙個新的資料被訪問,從煉表頭遍歷鍊錶。
1.如果資料已經被鍊錶快取了,遍歷到這個結點後,將其從原來的位置刪除,再插入到鍊錶頭部。
2.如果不存在鍊錶中,分兩種情況:快取未滿,直接插入到頭結點;快取已滿,則刪除鍊錶尾結點,新的資料結點插入頭部。
可以看出該思路的時間複雜度為o(n)
資料結構 鍊錶
鍊錶 what 就是一張鏈式儲存的表,是一種資料結構,是基礎,所以還是不要想有什麼用。具體呢?在c中就用結構體實現物件描述,然後通過函式來實現各個基本操作 c 則用類來表述,c中的結構體就可以看成c 中的類,然後通過類封裝各個操作步驟。這些操作實現後就需要 來測試,號稱demo,就是main函式裡面...
資料結構 鍊錶
鍊錶中的資料是以節點來表示的,每個結點的構成 元素 資料元素的映象 指標 指示後繼元素儲存位置 元素就是儲存資料的儲存單元,指標就是連線每個結點的位址資料。鍊錶的結點結構 data next data域 存放結點值的資料域 next域 存放結點的直接後繼的位址 位置 的指標域 鏈域 以 結點的序列 ...
資料結構 鍊錶
一般的建立線性鍊錶有兩種 1.正序法 需要三個指標,head作為頭指標,pre作為前乙個指標,cur作為當前指標用來建立空間 2.倒序法,利用指標的插入,只需要兩個指標,不斷的往頭指標後插入新空間,不過插入的越早,離頭指標越遠,也就越後面輸出 1.線性鍊錶的建立及查詢刪除 include inclu...