1、Redis是什么?
Redis是一个数据库,不过与传统的数据库不同的是Redis数据库是工作在内存中,所以读写数据非常快,因此Redis广泛应用于缓存方面。
2、Redis的五种数据结构整理
简单动态字符串、list、字典、哈希表、跳跃表、压缩列表
简单动态字符串(Simple Dynamic String, SDS)
Redis没有直接使用C语言传统的字符串,而是使用自己构建的一个简单动态字符串(SDS)的抽象类型,并将SDS用作Redis的默认字符串表示。
简单来说,SDS其实类似C语言的char*,但是它可以存储任意的二进制数据,不需要像C语言那样,使用'\0'标识字符串结束。而是采用一个len表示字符串的大小。
代码如下:
struct sdshdr {
// 记录buf数组中已使用字节的数量
// 等于sds所保存字符串的长度
int len;
// 记录buf数组中未使用字节的数量
int free;
// 字节数组,用于保存字符串
char buf[];
}
优点:
- 获取字符串长度的复杂度为O(1)。
- 杜绝缓冲区溢出。
- 二进制安全
- 兼容部分C语言字符串函数。
链表(不是循环链表)
代码如下:
节点底层结构
typedef struct listNode {
// 前置节点
struct listNode *prev;
// 后置节点
struct listNode *next;
// 节点的值
void *value;
} listNode;
list底层结构:
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;
特性:
- 链表被广泛用于实现Redis的各种功能,比如订阅、发布等。
- 每个链表节点使用listNode来表示,每个节点都是有一个指向前置节点和后置节点的指针,所以Redis的链表实现是双端链表。
- 每个链表使用一个list结构表示,这个结构带有头结点指针和尾结点指针,以及链表长度等信息。
- 因为链表表头的头结点和链表表尾的尾结点都是指向NULL,所以Redis链表是无环链表。
- 通过为链表设置不同类型的特定函数,Redis的链表可以用于保存各种不同类型的值。
字典:
类似c++里面的map。
哈希表:
typedef struct dictht {
// 哈希表数组
dictEntry **table;
// 哈希表大小
unsigned long size;
// 哈希表大小掩码,用于计算索引值
// 总是等于size-1
unsigned long sizemark;
// 该哈希表已有节点的数量
unsigned long used;
} dichht;
当字典或者哈希表作为底层实现时候,Redis使用murmurhash算法,该算法的好处是能够把有些的key映射到随机的地址上面(hash冲突的概率比较小),并且算法计算非常快。
如果hash冲突了,如何解决,?
使用链地址法解决问题。简单来说就是让hash冲突的key形成一个链表连接起来。
特性:
- 字典被广泛用于实现Redis的各种功能,其中包括数据库和哈希键。
- Redis中字典使用哈希表作为底层结构实现,每个字典带有两个哈希表,一个平时使用,另一个仅在进行rehash的时候使用。
- Redis使用murmurhash计算hash值。
- 哈希表使用链地址法来解决冲突问题。
跳跃表:
首先看看单链表
由上图可以看到,如果要找某个值,只能顺序遍历过去,时间复杂度在o(n)级别的,这个效率是非常低的。
而跳跃表就是说把这个单链表,变成多个单链表,每次走的步长都不一样,从而可以很容易的查找到数据的范围,加速查找。
跳跃节点
typedef struct zskiplistNode {
// 后退指针
struct zskiplistNode *backward;
// 分值 权重
double score;
// 成员对象
robj *obj;
// 层
struct zskiplistLevel {
// 前进指针
struct zskiplistNode *forward;
// 跨度
unsigned int span;
} leval[];
} zskiplistNode;
一般来说,跳跃表的层数越大,查询的速度就越快。
跳跃表节点
typedef struct zskiplist {
// 表头节点和表尾节点
struct zskiplistNode *header, *tail;
// 表中节点的数量
unsigned long length;
// 表中层数最大的节点的层数
int leval;
} zskiplist;
特性:
- 跳跃表本身是有序集合的底层实现之一。
- Redis的跳跃表是由zskiplist和zskiplistNode两个结构组成,其中zskiplist用于保存跳跃表信息(比如表头节点、表尾节点、长度),而zskiplistNode则用于表示跳跃表节点。
- 每个跳跃表节点的层高都是1到32之间的随机数
- 跳跃表中的节点都是按照分值大小进行排序,当分值相同时,节点按照成员对象的大小进行排序。
- 跳跃表是一种实现起来简单,单层多指针的链表,它的查找效率很高,堪比优化过的二叉平衡树。
压缩列表
特性:节省内存