本文所引用的源碼全部來自Redis2.8.2版本。
Redis中linkedlist數據結構與API相關文件是adlist.c, adlist.h。
本文主要講解Redis中對雙向鏈表的詳細實現,以及相關API的分析,對於雙向鏈表本身可以從任意一本數據結構書本中得到詳解。
轉載請註明,來自:http://blog.csdn.net/acceptedxukai/article/details/17467373
一、雙向鏈表簡介
雙向鏈表作爲一種常見的數據結構,在嚴蔚敏數據結構書裏有詳細的講解,雙向鏈表的每個數據節點都有兩個指針,分別指向後繼與前驅節點,因此從雙向鏈表中的任意一個節點開始都可以很方便地訪問其前驅與後繼節點。
二、Redis中雙向鏈表數據結構以及相關宏定義
typedef struct listNode {
struct listNode *prev;//前驅指針
struct listNode *next;//後繼指針
void *value; //節點的值
} listNode;
typedef struct listIter {//鏈表迭代器
listNode *next;
int direction;//遍歷方向
} listIter;
typedef struct list {//鏈表
listNode *head;//鏈表頭
listNode *tail;//鏈表尾
void *(*dup)(void *ptr); //複製函數指針
void (*free)(void *ptr); //釋放內存函數指針
int (*match)(void *ptr, void *key); //比較函數指針
unsigned long len; //鏈表長度
} list;
宏名稱 |
作用 |
listLength |
獲取鏈表的長度值 |
listFirst |
獲取鏈表的首指針 |
listLast |
獲取鏈表的尾指針 |
listPrevNode |
獲取當前節點的前驅節點指針 |
listNextNode |
獲取當前節點的後繼節點指針 |
listNodeValue |
獲取當前節點所存儲的值 |
listSetDupMethod |
設置鏈表節點value的複製函數 |
listSetFreeMethod |
設置鏈表節點value的釋放內存函數 |
listSetMatchMethod |
設置鏈表節點value的比較函數 |
listGetDupMethod |
獲取鏈表節點value的複製函數 |
listGetFree |
獲取鏈表節點value的釋放內存函數 |
listGetMatchMethod |
獲取鏈表節點value的比較函數 |
三、Redis中雙向鏈表API介紹
名稱 |
作用 |
複雜度 |
listCreate |
創建一個新雙向鏈表 |
O(1) |
listRelease |
釋放一個雙向鏈表以及包含的節點內存 |
O(N) |
listAddNodeHead |
將一個節點添加到鏈表的表頭 |
O(1) |
listAddNodeTail |
將一個節點添加到鏈表的表尾 |
O(1) |
listInsertNode |
將一個節點添加到給定節點的之後或之前 |
O(1) |
listDelNode |
刪除給定的節點 |
O(1) |
listGetIterator |
生成雙向鏈表的迭代器 |
O(1) |
listReleaseIterator |
釋放雙向鏈表的迭代器 |
O(1) |
listNext |
通過迭代器獲取下一個節點 |
O(1) |
listDup |
創建給定鏈表的副本 |
O(N) |
listSearchKey |
查找與給定key相同值的節點 |
O(N) |
listIndex |
根據給定的索引值,返回相應的節點 |
O(N) |
listRewind |
重新初始化迭代器,迭代方向從頭至尾 |
O(1) |
listRewindTail |
重新初始化迭代器,迭代方向從尾至頭 |
O(1) |
listRotate |
取出鏈表尾節點並插入到頭部 |
O(1) |
四、Redis雙向鏈表性能分析
Redis中的雙向鏈表也許是Redis中最簡單最容易實現的數據結構,對於API就不多說了,都很簡單,也沒啥可以說的,下面簡單分析一下雙向鏈表的性能。
listNode擁有prev前驅指針和next後繼指針,因此通過迭代器可以很方便的對鏈表從從頭至尾或從尾至頭遍歷;
list擁有header頭指針和tail爲指針,對於在鏈表的頭部或尾部進行插入節點的時間複雜度全部爲O(1),高效地實現了Redis中一些指令的操作;
list自帶保存鏈表長度的字段len,使得計算鏈表長度的時間複雜度爲O(1)。
五、小結
雙向鏈表主要有兩個作用:作爲Redis列表數據類型的底層實現方法之一;作爲通用數據結構可以被其他功能模塊使用。
雙向鏈表實現簡單,Redis對雙向鏈表加以改造,添加保存節點長度的字段,以及實現自己的迭代指針,使得一些數據操作變得簡單。
最後感謝黃健宏(huangz1990)的Redis設計與實現及其他對Redis2.6源碼的相關注釋對我在研究Redis2.8源碼方面的幫助。