三、链表(Linked List)(原理)
前言
經典的鏈表應用場景:LRU 緩存淘汰算法
緩存是一種提高數據讀取性能的技術,由于緩存的大小有限,當緩存被用滿時,哪些數據應該被清理出去,哪些數據應該被保留?這就需要緩存淘汰策略來決定。
- 常見的策略有三種:
- 先進先出策略 FIFO(First In,First Out)
- 最少使用策略 LFU(Least Frequently Used)
- 最近最少使用策略 LRU(Least Recently Used)
==》如何用鏈表來實現 LRU 緩存淘汰策略呢? ==》詳見 五 的解答
一、鏈表
鏈表:不需要一塊連續的內存空間,它通過“指針”將一組零散的內存塊串聯起來使用.
內存分布:
最常用的鏈表結構:單鏈表、雙向鏈表和循環鏈表
二、單鏈表
1、基本概念
結點(Node):單鏈表的結點結構
鏈表中的每一個數據元素稱為 “結點” ,每個結點都由兩部分組成:數據域 + 指針域。其中,數據域存儲數據元素信息,指針域存儲鏈表的下一個結點的位置信息,是一個指針。
單鏈表:當一個序列中只含有指向它的后繼結點的鏈接時,就稱該鏈表為單鏈表。
- 非空表(有頭結點):
- 空表:
頭指針:是指鏈表指向第一個結點的指針,若鏈表有頭結點,則是指向頭結點的指針。頭指針具有標識作用。任何情況下,頭指針都存在,無論鏈表是否為空。
頭結點:為了操作的統一和方便(插入/刪除首元結點)設立的,放在首元結點(第一元素結點)之前,其數據域一般無意義(也可以 存放鏈表的長度)。非必需要素。
最后一個結點:最后一個結點指針為“空”(通常用NULL或“^”符號表示),是鏈表的結束標志,表示它沒有后繼結點。
2、查找操作
目標:隨機訪問第 k 個元素 ==》依次遍歷 ==》時間復雜度:O(n)
3、插入操作
插入 x 結點: ==》時間復雜度:O(1)
① x->next = a2 -> next
② a2 -> next = x
4、刪除操作
刪除 a2 結點: ==》時間復雜度:O(1)
① p = a1->next
② a1->next = p->next
三、循環鏈表
循環鏈表:與單鏈表的唯一區別就是最后一個結點的指針指向鏈表的頭結點。
優點: 從鏈尾到鏈頭比較方便。當要處理的數據具有環型結構特點時,就特別適合采用循環鏈表。eg: 約瑟夫問題
四、雙向鏈表
雙向鏈表:每個結點不止有一個后繼指針 next 指向后面的結點,還有一個前驅指針 prev 指向前面的結點。
特點:支持雙向遍歷,更具靈活性;O(1) 時間復雜度的情況下前驅結點
結點:
2、雙向鏈表的優勢
(1)刪除
刪除的兩種情況:
- 刪除結點中“值等于某個給定值”的結點
- 刪除給定指針指向的結點
第一種情況
無論單鏈表還是雙向鏈表,均需要從頭開始遍歷對比,直至找到值等于給定值的結點,然后再執行刪除操作。==》時間復雜度:O(n)
第二種情況
已找到需刪除的結點,但是刪除某個結點 q 需要得到其前驅結點,雙向鏈表可以不用遍歷就得到前驅結點。 ==》時間復雜度:O(1)
(2)有序鏈表的查找操作
對于有序鏈表,雙向鏈表的按值查詢的效率要比單鏈表高一些。具體來說,可以記錄上次查找的位置 p ,每次查找時,根據查詢值與 p 的大小關系,決定向前還是向后查找。
五、設計思想:空間 <-> 時間
- 當內存足夠時,若追求代碼的執行速度 ==》選擇空間復雜度高、時間復雜度相對較低的算法或者數據結構
- 當內存比較緊張 ==》時間換空間
鏈表實現LRU緩存淘汰算法:越靠近鏈表尾部的結點是越早之前訪問的
- 若此時緩存未滿 ==》此結點直接插入到鏈表的頭部;
- 若此時緩存已滿,則鏈表的最后一個結點刪除,并將新的數據結點插入鏈表的頭部
總結
以上是生活随笔為你收集整理的三、链表(Linked List)(原理)的全部內容,希望文章能夠幫你解決所遇到的問題。