Redis学习笔记(一)底层数据结构

109 阅读2分钟

数据结构

SDS

定义

struct sdshdr{
    int len;    
    int free;   
    char buf[];
}

image.png

SDS与C字符串的区别

(1)常数复杂度获取字符串长度。C字符串需要遍历,以'\0'为结尾。

(2)杜绝缓冲区溢出。C字符串分配的内存可能不够,strcat操作时可能溢出。而SDS可以动态地扩展空间。

(3)减少修改字符串带来的内存重分配次数。C字符串在append或trim时,总要对这个C字符串进行一次内存重分配操作。而SDS采用空间预分配和惰性空间释放保留一部分空间,以免引起频繁重分配。

(4)二进制安全。C字符串会因为'\0'意外终止。

LinkedList

定义

image.png

Dict

定义

//哈希表
typedef struct dictht {
    dictEntry **table;
    unsigned long size;
    unsigned long sizemark;
    unsigned long used;
} dictht;
//哈希表节点
typedef struct dictEntry {
    void *key;
    union{
        void *val;
        ...
    } v;
   struct dictEntry *next;
} dictEntry;

字典是一种保存键值对的抽象数据结构。

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    int rehashidx;
} dict;

image.png

哈希算法

image.png

解决键冲突

使用链接地址法来解决键冲突。

image.png

rehash

(1)为字典的ht[1]哈希表分配空间。

(2)将保存在ht[0]中的所有键值对rehash到ht[1]上(重新计算哈希值和索引值)。要注意到ht[0]和ht[1]里的sizemark哈希掩码是不一样的。

(3)释放ht[0],将ht[1]设置为ht[0],并在ht[1]上新建一个空白哈希表。

扩展或收缩的条件

image.png

渐进式rehash

哈希表渐进式rehash的详细步骤:

image.png

将rehash键值对的计算量均摊到每个增删改查操作中,避免了集中rehash带来的工作量。

SkipList

定义

跳表是一种有序数据结构,通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问的目的。平均O(logN),最坏O(N)。

我们知道链表是无法二分查找的,跳表就是加了很多指向其他节点的指针后,在链表上实现二分查找。

一个跳跃表节点结构如下

//跳跃表节点
typedef struct zskiplistNode {
	struct zskiplistLevel {
		struct zskiplistNode *forward;	//前进指针
		unsigned int span;	//跨度
	} level[];
	struct zskiplistNode *backward;	//后退指针
	double score;	//分值,节点按各自所保存的分值从小到大排列
        robj *obj;    // 成员对象 
} zskiplistNode;

//跳跃表
typedef struct zskiplist {
	structz skiplistNode *header, *tail;	//表头节点和表尾节点
	unsigned long length;	//表中节点的数量
	int level;	//层数最大节点的层数
} zskiplist;

image.png

跳表和B+树的区别与选择:www.51cto.com/article/706…

image.png

IntSet

ZipList