注意事項:
- 在做指針的時候一定要明確指向的內容,如list_entry需要某個變量的地址,那就定義一個結構體,指向的時候,指向這個結構體的地址。內核在做hash_list的時候就是這麼做的。
- 代碼最好具有通用性,list.h的代碼插入任何結構體中,均可以保證結構體具有鏈表的屬性和功能
- 表頭很重要,有表頭邏輯更清晰。有表頭不用擔心鏈表的第一項和最後一項的插入和刪除,整體上方便的多。而且多數鏈表代碼是有表頭的
struct hlist_node {
struct hlist_node *next, **pprev;
};
棧、隊列本身就是鏈表的一種表現形式,其實也可以說沒有區別。算法的時間主要取決於使用數組還是指針,這些管理
內存的方式。
1、所有關於鏈表、棧、隊列都可以用數組和指針實現,但是處理過程中各有優劣
數組:數組本身是隻內存中,某種類型的結構大小,以連續的空間在內存中分佈,所以在使用的時候,要先估算出需求參數的大小,選擇一個合適的數值。
a)鏈表:需要對錶的大小進行估算
i、插入:時間是O(N)
在點M插入數值,這個點後面的數都要平移。需要平移N-M次,所以時間是O(N)
ii)刪除:時間是O(N)
同上
iii)查找某個值所在位置O(N)
需要遍歷數組
iv)查找某個位置的值O(1)
數組是以固定大小連續分佈在內存中的,要查找某個位置,能立刻知道該地址的位置。CPU通過地址總線,一個週期就
可以訪問完成。
b)棧:棧的大小也要提前定義,通常典型的應用程序,棧元素實際個數不會太大
i)push:時間是O(1)
ii) pop:時間是O(1)
直接對數組的最後一位賦值或獲取,時間必然是O(1)
因爲棧操作時間是常數時間,所以檢測花的時間相對較多。
c)隊列:
i )enqueue:O(1)
ii)dequeue:O(1)
同上
指針實現:指針需要malloc和free人爲的申請和釋放空間。指針指向的下一個地址不確定,可以發生變化,因此插入和刪除只需要malloc一片內存,改變position的前後指針指向就可以插入了。
鏈表:
i)插入:時間是O(1)
申請內存,改變position的前後單元的指針,就可以插入節點了。
2)刪除O(1):
同上
3)查找某個值所在位置O(N)
遍歷鏈表
4)查找某個位置的值O(N)
鏈表後面一項所在位置不明確,需要next指向,共需要位置次數的next指向。
棧:
push和pop均花費常數時間,但是每次push均需要malloc,pop需要free,相對於數組來說這種開銷是昂貴的,因爲操作
花費時間本身是常數
隊列:
同上