Redis數據結構——SDS,鏈表

簡單動態字符串數組

struct sdshdr {
    unsigned int len; //記錄buf數組中已使用字節的數量 等於SDS所保存字符串的長度
    unsigned int free; // 記錄buf數組中未使用字節的數量
    char buf[];    //字節數組,用於保存字符串
};

SDS在len屬性中記錄了SDS自己的長度,因此獲取一個SDS長度的複雜度僅爲O(1)。安全

SDS的空間分配策略徹底杜絕了發生緩衝區溢出的可能性。當SDS API須要對SDS進行修改時,API會先檢查SDS的空間是否知足修改所須要的要求,若是不知足的話,API會自動將SDS的空間擴展至執行修改所需的大小,而後才執行實際的修改操做,因此函數

SDS 既不須要手動修改SDS的空間大小,也不會出現緩衝區溢出問題。優化

SDS經過free 未使用空間解除了字符串長度和底層數組長度之間的關聯;在SDS中,buf數組的長度不必定就是字符串數量加1,數組中可包含未使用的字節,而這些字節的數組就有SDS的free屬性記錄。指針

使用未使用空間,SDS實現了空間預分配惰性空間釋放兩種優化策略。code

Redis 只會使用C字符串做爲字面量,在大多數狀況下,Redis 使用SDS(Simple Dynamic String, 簡單動態字符串)做爲字符串表示。內存

比起C字符串,SDS具備如下優勢:字符串

  1. 常數複雜度獲取字符串長度。
    io

  2. 杜絕緩衝區溢出。class

  3. 減小修改字符串長度使所需的內存重分配次數。

  4. 二進制安全

  5. 兼容部分C字符串函數


鏈表

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;

Redis的鏈表實現的特性能夠總結以下:

雙端:鏈表節點帶有prev和next指針,獲取某個節點的前置節點和後置節點的複雜度都是O(1)

無環: 表頭節點的prev指針和表尾節點的next指針都指向NULL, 對鏈表的訪問以NULL爲終點。

帶表頭指針和表尾指針:經過list結構的head指針和tail指針,程序獲取鏈表的表頭節點和表尾節點的複雜度爲O(1).

帶鏈表長度計數器:程序使用list結構的len屬性來對list持有的鏈表節點進行計數,程序獲取鏈表中節點數量的複雜度爲O(1)。

多態: 鏈表節點使用void *指針來保存節點值,而且能夠經過list結構的dup,free,match三個屬性爲節點值設置類型特定函數,因此鏈表能夠用於保存各類不一樣類型的值。

相關文章
相關標籤/搜索