redis数据结构


redis放弃了很多c语言内置的数据结构,自己实现了很多自己的数据结构,这些数据结构很优质,提供了很多内置的指令都是常数复杂度的。从中可以体会到一个优秀的数据结构是多么的赏心悦目。


简单动态字符串

       C语言中的字符串使用的长度为N+1的字符数组来表达长度为N的字符串,
       而且字符数组的最后一个元素总是ascll码表中的空字符'\0'
 下面来介绍redis中字符串的实现
       redis的字符串的优点有
        1.常数复杂度获取字符串长度
        2.缓冲区不会溢出
        3.字符串修改内存分配次数少
        4.保证二进制安全
        5.兼容部分C字符串函数

概述reids中字符串的实现以及数据结构。
        reids中的字符串确切的来说全称为"简单动态字符串(SDS)"。他除了可以保存数据库中的字符串之外,还可以被用作缓冲区:如AOF缓冲区(持久化指令)等。

redis的字符串的数据结构定义如下,这也是为什么可以做到字符串长度为常数时间复杂度的原因

struct sds.h/sdshdr{
   int len;//用来记录保存的字符串长度,也就是用来记录buf数组中已使用字节数量
   int free;//用来保存数组中未使用字节的数量
   char buf[];//保存字符串数组
}
sds.jpg

如上图
♦ free属性值为0,表示sds没有可分配的剩余空间
♦ len属性为5,表示sds保存一个长度为5字节的字符串
♦ buf则表示记录了这个存放字符串的字符数组,最后一个字节保存了空字符'\0'
♦ sds也遵循C语言中字符串定义标准,以空字符串结尾,保存的空字符不记录进字符串长度也就是len属性中,而且为字符串分配额外的1字节空间。为什么遵循以空字符结尾,好处在于可以重用C语言的部分代码,而不用去写单独的实现。

1.如何实现了以常数复杂度获取字符串长度

  在c语言中获取一个字符串的长度是遍历整个字符数组,扫到空字符时为止,整个操作的时间复杂度为O(N)

  redis的数据结构,因为存储了存储的字符串长度的属性,所以时间复杂度为O(1),
  那么在redis中STRLEN命令的复杂度复杂度为O(1)

2.如何杜绝缓冲区溢出

  c语言中字符串不记录自身长度,由于数据的内存空间是一定的,当在使用/strcat函数时,
可以将源字符串拼接到目的字符串末尾。但是c语言中字符数组内存容纳不了如此多的字符串,那么就会
缓冲区溢出。造成源字符串的内容溢出到目的字符串,导致目的字符串内容被修改

   但是在redis的数据结构中,redis的api会去检查sds空间是否满足修改的要求,如果不满足自动进行扩容

3.如何减少修改字符串带来内存重分配次数

  c语言字符串并不记录自身长度,对于一个包含N个字符的字符串来说,总是需要一个长度为N+1的字符数组来承载他
所以在每次改变字符串长度的时候总会重新分配地址。 
   如果程序是增长字符串操作,如果数组空间不够,就要扩容,如果忘记就会缓冲区溢出
   如果执行缩短字符串操作,在执行之后,多余的内存要释放,如果忘记释放,就会内存泄露。
 一般程序下修改字符串长度操作不经常出现,那么修改一次耗费资源是可以接受的。
   redis的使用场景经常是对速度要求严格,数据频繁修改,如果经常重新分配内存会造成性能问题。
   在redis中SDS实现了空间预分配和惰性空间释放两种优化策略。
1.空间预分配
2.惰性空间释放

链表

字典

跳跃表

整数集合

压缩列表

对象


字符串对象
列表对象
哈希对象
集合对象

你可能感兴趣的:(redis数据结构)