Redis設計與實現讀書筆記(二) 鍊錶

2022-05-30 16:06:14 字數 1271 閱讀 2307

鍊錶作為最基礎的資料結構,在許多高階語言上已經有了很好的實現。由於redis採用c語言編寫,需要自己實現鍊錶,於是redis在adlist.h定義了鍊錶型別。作者對於這部分沒什麼好說,原始碼比較簡單,如果這方面沒有接觸過的話,作者也耐心地推薦了幾本書供參考。為了提高效率,這裡的鍊錶指的是雙向鍊錶,使得某乙個元素訪問它的前驅與後繼的時間複雜度均為o(1)。

不多說,進入正題,首先可以看到節點的資料結構的**如下:

typedef structlistnode  listnode;

c語言沒有泛型,但是鍊錶又要儲存各種型別的資料,所以這裡使用了void指標。由於指標只在編譯器級別進行檢查,在指令級別是沒有型別的,所以這裡是ok的。這裡的value*指向真正的值儲存空間。

按理說使用上面的結構已經可以實現乙個簡單的鍊錶,redis為了更加簡便的使用鍊錶,使用list結構體對節點進行了封裝。

typedef structlist  list;

使用c語言實現物件導向程式設計的關鍵是定義函式指標作為介面,在使用時進行實現,這裡定義了三種方法指標,分別用於型別的拷貝(在鍊錶拷貝時呼叫),型別的釋放(在鍊錶釋放時呼叫),型別的比較(類似於c++的運算子過載,用於比較類似的大小),這裡的鍊錶定義的寫法值得好好學習一下。

使用以上結構,redis儲存乙個簡單的煉表示意圖如下:

這裡可以看到,redis實現的是無環鏈表,因為首元素的前驅是null。這樣設計的理由是list已經持有了首元素和尾元素的指標,無需另外在首尾之間組成迴路。這張圖已經很明顯的展示了鍊錶的工作狀態,下面對鍊錶的操作的討論僅以鍊錶插入為例子來進行分析:

list *listaddnodetail(list *list, void *value)

else

list->len++;

return

list;

}

進行插入的過程比較容易,先定義出節點元素,然後根據鍊錶的當前節點數進行不同的操作:當鍊表為空時,將list對應域指向node,而當鍊表不為空時,先完成新節點的成員賦值,然後再更改list的tail域等等,這裡一定要注意的是雙向列表的節點改變,要留心prev與next的值是否改變,而且新舊節點改變的順序一定不能錯,這個雖然簡單,但是還是比較考驗基本功的。

總結:可以看出,一些知名的軟體,底層還是最基礎的東西,並沒有什麼黑科技,所以掌握好基礎真的很重要。作者對這一章描述的比較簡單,也就沒什麼好講的了。希望以後可以繼續堅持寫部落格。

《redis設計與實現》讀書筆記

sds dynamic string 比起 c 字串,sds 具有以下優點 len屬性維護字串長度,常數複雜度即可獲取。預先檢查長度是否滿足需求,如果不滿足自動拓展,杜絕緩衝區溢位。空間預分配 惰性空間釋放會減少修改字串長度時所需的記憶體重分配次數。二進位制安全。相容部分 c 字串函式。list 鍊...

redis設計與實現讀書筆記二 SDS

redis字串並沒有使用以空字元為結尾的字元陣列來構建,而是實現了一套自身的字串模式,也叫簡單動態字串 sds,dynamic string sds在sds.h sdshdr中如下表示 struct sdshdrsds遵循c字串的已空字元結尾的慣例,這樣sds便可以復用c字串函式庫的一些函式.無須為...

redis設計與實現 讀書筆記1

乙個業務模型引出對redis的好奇 提出問題 1.redis 的五種資料型別分別由什麼資料結構實現?2.redis 的字串型別既可以儲存字串,也可以儲存整數和浮點數,甚至是二進位制位 使用setbit redis 內部是如何實現儲存這些值?3.redis的一部分命令只能對特定的資料型別執行 而另一部...