常見的三種快取淘汰策略:先進先出策略fifo,最少使用策略lfu,最近最少使用策略lru。
1. 陣列與鍊錶的區別
先從底層的儲存結構來看
陣列需要的是一組連續的記憶體空間開儲存,而鍊錶不需要,鍊錶通過指標將一組零散的記憶體空間串聯起來使用。
陣列使用的是連續的記憶體空間,所以可以借用cpu的快取機制,預讀陣列中的資料,訪問效率更高,而鍊錶在記憶體中不是連續儲存,所以對cpu的快取機制不是很友好。
陣列的缺點是大小固定,一經宣告就要占用整塊連續的記憶體空間。如果宣告的陣列過大,可能會導致「記憶體不足」,如果宣告的陣列太小,不夠用時只能再申請乙個更大的記憶體空間,把原陣列拷貝過去,比較耗時。而鍊錶本身沒有太大的限制,天然的支援動態擴容。
如果**對於記憶體的要求十分苛刻,那麼陣列更合適。因為鍊錶中的每個結點都需要消耗額外的記憶體空間去儲存乙份指向下乙個結點的指標,所以記憶體消耗會翻倍,而且對於鍊錶頻繁的插入、刪除操作,會導致頻繁的記憶體申請和釋放,容易造成記憶體碎片。
2. 三種鍊錶結構
1. 單鏈表
鍊錶通過指標將一組零散的記憶體塊串聯起來使用,其中的記憶體塊為結點,每個鍊錶的結點除了儲存資料外,還要記錄鏈上的下乙個結點的位址。我們把這個記錄下個結點的位址的指標稱為後繼指標。
我們把第乙個結點稱為頭結點,用來記錄鍊錶的基位址,有了它,我們可以遍歷得到整個鍊錶。
最後乙個結點稱為尾結點,尾結點的指標指向乙個空位址null。
插入與刪除:因為鍊錶的儲存空間本身就不是連續的,所以在鍊錶中插入和刪除資料是十分快速的,時間複雜度為o(1),我們只需要考慮相鄰結點的變化。
舉個栗子查詢:鍊錶的查詢十分複雜,不能像陣列一樣用定址公式計算位址,只能根據結點乙個乙個地依次遍歷,直到找到相應的結點,時間複雜度為o(n)。
2. 迴圈鍊錶
迴圈鍊錶是一種特殊的單鏈表,它把尾結點的指標指向頭結點。
和單鏈表相比,迴圈鍊錶的優點是從鏈頭到鏈尾比較方便。當要處理的資料具有環形結構特點時,可以使用迴圈鍊錶。
3. 雙鏈表
單鏈表只有乙個方向,結點只有乙個後繼指標指向下乙個結點。雙鏈表支援兩個方向,每個結點有前驅指標prev指向前乙個結點,也有後繼指標next指向下乙個結點。
與單鏈表相比,儲存同樣多的資料,雙鏈表占用更多的記憶體空間,而且支援雙向遍歷,比較靈活。
關於刪除和插入操作
從鍊錶中刪除資料一般有兩種情況:
刪除結點中「值等於給定值」的結點
刪除給定指標指向的結點
對於第一種情況,不管是單鏈表還是雙鏈表,都要從頭結點開始乙個乙個遍歷查詢,直到找到值等於給定值的結點,再進行刪除操作。查詢操作的時間複雜度為o(n),刪除操作的時間複雜度是o(1),所以總時間複雜度為o(n)。
對於第二種情況,我們已經找到了要刪除的結點,但是想要刪除結點,得知道這個結點的前驅結點,對於單鏈表而言,只能從頭結點開始遍歷,直到q->next = q,q為要刪除的結點,p是q的前驅結點,時間複雜度為o(n),但是對於雙鏈表而言,可以直接獲取到前驅結點,時間複雜度為o(1)。插入資料同理。
關於查詢操作
雙向鍊錶比單鏈表的查詢高效,因為我們可以記錄上次查詢的位置p,每次查詢時,比較p與要查詢的值,決定往前還是往後查詢,所以平均只需要查詢一半的資料。
3. 其他
當記憶體足夠,我們追求**的執行速度時,採用用空間換時間的設計思想。當記憶體比較緊缺時,採用用時間換空間的設計思路。
快取實際上利用了用空間換時間的設計思想,如果我們把資料儲存在硬碟上,會比較節省記憶體,但是每次查詢資料都要訪問一次硬碟,比較耗費時間,但是如果通過快取技術,事先把資料載入在記憶體中,雖然比較耗費記憶體空間,但是提高了資料查詢的速度。
對於執行比較慢的程式,可以通過消耗更多的記憶體進行優化(以空間換時間),對於消耗過多記憶體的程式,可以通過消耗更多的時間進行優化(以時間換空間)。
關於鍊錶 回顧
帶頭結點的單鏈表 倒置鍊錶 悲劇 折騰了n久 記錄一下 釋放鍊錶 注意下 倒置鍊錶方法二種 第一種,採用插入節點式,每次插入的位置都是head next的位置。第二種,採用遞迴方式,需要注意的是傳入應該為left 如head 1 2 3 4 呼叫時傳入reverse list head next 呼...
關於鍊錶追趕 鍊錶中環的問題
關於環的問題,介紹幾個個經典的題目 1.求鍊錶倒數第k個結點 最經典,最常見的解法就是,設定兩個指標p1,p2,一開始分別指向頭結點,首先p2先移動k個節點,之後開始p1,p2每次移動1個節點,直到p2達到最後乙個節點位置,那麼p1指向的就是倒數第k個節點。不過這種解法主要是針對單鏈表,且鍊錶中不存...
資料結構 鍊錶 上
本來說要放假認認真真的學習演算法和計算機基礎,但是看到安卓華麗麗的介面還是義無反顧的奔入了android入門大軍中 主要是懶的看演算法 不過在android學習中發現想要成為乙個合格的開發者 掙更多的錢 光是會呼叫函式是遠遠不夠的,還是需要有乙個深厚的計算機基礎。所以決定沉下心來認真學習計算機基礎。...