列表(list)用來存儲多個有序的元素; 一個列表可以存儲2^32-1個元素。
Redis中的列表支持兩端插入和彈出,并可以獲得指定位置(或范圍)的元素,可以充當數組、隊列、棧等。
1 內部編碼
列表的內部編碼可以是壓縮列表(ziplist)或雙端鏈表(linkedlist)
-
雙端鏈表
與雙鏈表定義一致,引入了鏈表節點,并在此基礎上增加頭尾節點構建雙端鏈表
鏈表節點listNode如下定義:
/* Node, List, and Iterator are the only data structures used currently. */
/*
* 鏈表節點
*/
typedef struct listNode {
// 前驅節點
struct listNode *prev;
// 后繼節點
struct listNode *next;
// 值
void *value;
} listNode;
鏈表如下定義:
/*
* 鏈表
*/
typedef struct list {
// 表頭指針
listNode *head;
// 表尾指針
listNode *tail;
// 節點數量
unsigned long len;
// 復制函數
void *(*dup)(void *ptr);
// 釋放函數
void (*free)(void *ptr);
// 比對函數
int (*match)(void *ptr, void *key);
} list;
雙端鏈表結構如下圖所示:
在這里插入圖片描述
通過圖中可以看出,雙端鏈表同時保存了表頭指針和表尾指針,并且每個節點都有指向前和指向后的指針;鏈表中保存了列表的長度;dup、free和match為節點值設置類型特定函數,所以鏈表可以用于保存各種不同類型的值。而鏈表中每個節點指向的是type為字符串的redisObject。
-
壓縮列表
壓縮列表是Redis為了節約內存而開發的,是由一系列特殊編碼的連續內存塊(而不是像雙端鏈表一樣每個節點是指針)組成的順序型數據結構。
壓縮列表的結構 -
zlbytes
記錄整個壓縮列表占用的內存字節數,在對壓縮列表進行內存重分配或計算 -
zlend
的位置時使用 -
zltail
記錄壓縮列表尾節點距離壓縮列表的起始地址有多少字節,通過這個偏移量,可以直接確定尾節點的位置 -
zllen
記錄壓縮列表包含的節點數量 -
entryX
表示各種節點,數量和長度不一定 -
zlend
用于標記壓縮列表的末端。
如圖,如果有一個指針p指向該壓縮列表,則尾巴節點的長度就是指針加上偏移量179(十六進制0xb3=16*11+3=179),列表的長度zllen為5,表示壓縮列表包含5個節點。zlbytes為0xd2表示壓縮列表的總長為210字節。
在這里插入圖片描述
由上可知,每個壓縮列表的節點可以保存一個字節數組或者一個整數值,那么每個節點肯定也有自己的結構。
與雙端鏈表相比,壓縮列表可以節省內存空間,但是進行修改或增刪操作時,復雜度較高
因此當節點數量較少時,可以使用壓縮列表;但是節點數量多時,還是使用雙端鏈表劃算
壓縮列表不僅用于實現列表,也用于實現哈希、有序列表;使用非常廣泛。