在之前對redis的介紹中,可以看到鍊錶的使用頻率非常高。
鍊錶可以作為單獨的儲存結構,比如客戶端的監視鍊錶記錄該客戶端監視的所有鍵,伺服器的模式訂閱鍊錶記錄所有客戶端和它的模式訂閱。
鍊錶也可以內嵌到字典中作為字典的值型別,比如資料庫的監視字典使用鍊錶儲存監視某個鍵的所有客戶端,伺服器的訂閱字典使用鍊錶儲存訂閱某個頻道的所有客戶端。
redis中的鍊錶是雙向鍊錶,即每乙個節點都儲存了它的前驅節點和後繼節點,用於提高操作效率。節點定義如下
/* 鍊錶節點 */
typedef struct listnode listnode;
鍊錶結構主要記錄了表頭節點和表尾節點,節點個數以及一些函式指標,定義如下
/* 鍊錶 */
typedef struct list list;
函式指標主要是對節點值的操作,包括複製,析構,判斷是否相等
此外,redis還為鍊錶提供迭代器的功能,主要是對鍊錶節點的封裝,另外通過鍊錶節點的前驅節點和後繼節點,可以輕鬆的完成向前移動和向後移動
/* 迭代器 */
typedef struct listiter listiter;
direction的值有兩個,向前和向後,由巨集定義指出
#define al_start_head 0 /* 從頭到尾(向後) */
#define al_start_tail 1 /* 從尾到頭(向前) */
鍊錶的建立工作由listcreate函式完成,實際上就是申請鍊錶記憶體然後初始化成員變數
/* 建立乙個空鍊錶 */
list *listcreate(void)
刪除乙個鍊錶比建立稍微麻煩一點,因為需要釋放每個節點中儲存的值,沒錯,它正是呼叫free函式完成的
/* 釋放鍊錶的記憶體空間 */
void listrelease(list *list)
/* 因為list* 也是動態申請的,所以也需要釋放 */
zfree(list);
}
在其他模組的實現上,經常會看到向鍊錶尾部新增節點的操作,它的實現由listaddnodetail完成。函式首先為新節點申請記憶體,然後將節點新增到鍊錶中,這裡需要根據鍊錶之前是否為空執行不同操作
/* 在鍊錶尾部新增節點 */
list *listaddnodetail(list *list, void *value)
else
/* 節點個數加一 */
list->len++;
return list;
}
迭代器主要用於遍歷鍊錶,而迭代器的重點在移動上,通過direction變數,可以得知迭代器移動的方向,又通過鍊錶節點的前驅後繼節點,可以輕鬆實現移動操作
/* 移動迭代器,同時返回下乙個節點 */
listnode *listnext(listiter *iter)
/* 返回之前迭代器指向的節點 */
return current;
}
此外,redis提供了重置迭代器的操作,分別由listrewind和listrewindtail函式完成
/* 重置迭代器方向為從頭到尾,使迭代器指向頭節點 */
void listrewind(list *list, listiter *li)
/* 重置迭代器方向為從尾到頭,使迭代器指向尾節點 */
void listrewindtail(list *list, listiter *li)
有了迭代器的基礎,就可以實現鍊錶搜尋功能,即在鍊錶中查詢與某個值匹配的節點,需要利用迭代器遍歷鍊錶
/* 查詢值key,返回鍊錶節點 */
listnode *listsearchkey(list *list, void *key)
} else }}
return null;
}
除了上面提到的函式外,redis還提供了一些巨集定義函式,比如返回節點值,返回節點的前驅後繼節點等
/* 返回鍊錶節點個數 */
#define listlength(l) ((l)->len)
/* 返回頭節點 */
#define listfirst(l) ((l)->head)
/* 返回尾節點 */
#define listlast(l) ((l)->tail)
/* 返回前驅節點 */
#define listprevnode(n) ((n)->prev)
/* 返回後繼節點 */
#define listnextnode(n) ((n)->next)
/* 返回節點值 */
#define listnodevalue(n) ((n)->value)
/* 設定鍊錶的值複製,值析構,值匹配函式 */
#define listsetdupmethod(l,m) ((l)->dup = (m))
#define listsetfreemethod(l,m) ((l)->free = (m))
#define listsetmatchmethod(l,m) ((l)->match = (m))
/* 獲取鍊錶的值賦值,值析構,值匹配函式 */
#define listgetdupmethod(l) ((l)->dup)
#define listgetfree(l) ((l)->free)
#define listgetmatchmethod(l) ((l)->match)
由於鍊錶結構簡單,所以在實現上還是非常容易理解的。當然redis中與鍊錶有關的函式還有很多很多,這裡僅僅介紹了一些常用操作,有興趣可以深入原始碼檢視 Redis原始碼剖析 雙端鍊錶Sdlist
redis為雙端鍊錶的每乙個節點定義了如下的結構體。鍊錶節點定義 typedef struct listnode listnode 與一般的雙端鍊錶無異,定義了鍊錶節點的結構體之後,下面就定義鍊錶的結構體,用來方便管理鍊錶節點,其結構體定義如下 typedef struct list list re...
redis原始碼剖析 skiplist
試想乙個業務場景 遊戲需要實現乙個實時更新的排行榜應該如何實現 首先想到使用有序的雙端鍊錶,因為插入的時間複雜度為o 1 但是定位的平均時間複雜度為o n 當頻繁更新排行榜的時候效率比較低 有沒有乙個結構 能夠滿足快速定位到相應的位置並插入?跳躍表就能滿足這個需求 跳躍表的思想是給資料結點建立索引 ...
redis原始碼剖析 dict
typedef struct dictentry v struct dictentry next dictentry typedef struct dicttype dicttype this is our hash table structure.every dictionary has two ...