本次学习除了基本内容之外主要思考三个问题:why(为什么)、what(原理是什么)、which(同类中还有哪些类似的东西,相比有什么区别)。

由于我对 java 比较熟悉,并且 java 中也有字符串和链表。所以本篇暂拿 redis 中的字符串和链表与 java 进行对比。

字符串

先看几个问题:

  • redis 中有没有使用 C 语言的字符数组作为字符串? 答案:没有
  • 那么 C 语言的字符数组有着什么局限性以至于java和redis都重新定义了自己的字符串呢?
  • redis 定义的字符串结构是什么?java的呢?
  • java 和 redis 的字符串结构有什么区别?为什么会形成这样的区别?两者哪一个更好呢?

C 语言数组的局限性

  1. 取字符串长度不方便,c语言的字符数组没有存储字符串的长度,所以需要遍历。Time(时间复杂度):O(n)
  2. 不安全,两个字符数组进行拼接时可能会造成缓存区溢出,导致别的数据受损。
  3. 每次增删字符串都会导致重新分配或者回收内存,影响效率。
  4. 以\0判断是否结尾,只能存储文本数据。
  5. 比较两个字符串是否相等,需要循环比较每个字符,Time:O(n)。

由于 C 语言的字符数组有着以上的局限性,所以 redis 和 java 都重新定义了自己的字符串结构。

redis 定义的字符串结构是什么?java 的呢?

redis 中的字符串是自己构建了一种叫做简单动态字符串(SDS)的抽象类型标识的。它的具体结构如下:

struct sdshdr {
//字符串长度
int len;
// buf中未使用的字节数
int free;
// 字节数组,用于保存字符串
char buf[];
}

redis 的这个数据结构,很好的解决了 C 语言字符数组的第1、2、3、4点局限性。而且值得注意的是 sdshdr 中的 buf 数组,也是以“\0”结尾的,所以buf的总长度为:len + free + 1。那么为什么要浪费这一个字节呢?主要是想重用 C 语言对于字符串的一些函数,比如连接、输出等等。

这里有一个点需要注意一下,就是 redis 不会对存储的字符串进行编码,存储和获取都是直接通过二进制进行传输的,所以理论上来说只要客户端的编码和解码方式一样,是不会出现乱码的。这也是上面 buf 的注释里写字节数组的原因。

java 的字符串呢?则是直接把字符串搞成了一个常量。如下:

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[]; /** Cache the hash code for the string */
private int hash; // Default to 0
......
}

java 的字符串也解决了c语言字符数组的第 1/2/3/4 点。

  • 因为 java 中数组直接存储了长度,所以规避了 C 语言数组的第 1/4 点局限性。
  • 因为 String 是常量,所以c语言字符数组的第 2/3 点局限性不存在。
  • 为了解决第 5 点局限性,所以java中的字符串引入了 hashCode 的概念。

    正是因为 hash 直接存储在字符串中,所以才把字符串设置成常量(否则,每改一次字符串的值,都需要重新计算 hashcode 的值,太浪费效率)。正因为字符串是常量,所以才有了 StringBuilder、StringBuffer 的可变字符串。。。。。。

现在我们再回去看一下 redis 中字符串的结构,有一个数组,有数组中存储数据的长度。想到了什么?Java中 StringBuilder、StringBuffer、ArrayList 是不是都是这个结构?他们的共同点呢?是不是都是可变的数组( StringBuilder、StringBuffer 可以看成可变的字符数组)?说到可变,这里遗留一个问题:redis中的SDS、Java中的 (StringBuilder、StringBuffer、ArrayList ),他们的扩容规则分别是什么呢?

java 和 redis 的字符串比较

  1. redis 字符串中的字符数组(buf)是以“\0”结尾的,Java 中的不是。为什么呢?

    因为 redis 的设计之初就是效率高、运行快的缓存。所以才会选择以 C 语言实现(因为c是所有结构化语言中运行最快的),并且和c的字符数组一样的结尾,以便可以直接使用c的函数而不重复造轮子。

    java 的设计之初就是一门跨平台的语言,所以字符串的所有函数都是自己实现的,所以不需要额外浪费一个字节的空间。
  2. redis 定义了一个 sds 的字符串,但也是基于 C 的字符数组。而java直接把c的数组都重新定义了( C 的数组不能直接获得数组长度)。
  3. 关于字符串比较是否相等的问题:

    java 中有 hashcode 的概念来提升字符串比较是否相等的速度。redis 中又是如何做的呢?比如 get key 时,如何定位的一个具体的 key,而得到的 value 呢? 这个问题,暂时还不知道。

造成这些差异的原因,主要就是其定位不一样。redis 的定位是缓存、要求快。java 的定位是语言,最重要的是跨平台及扩展性。

链表

也同样看三个问题:

  1. 链表为什么产生?
  2. 原理是什么,和别的数据结构再来个对比。
  3. 和 java 的链表有什么不一样?

链表为什么产生?

链表的产生主要是因为数组的局限性。

比如:插入、删除慢。不能动态增加元素。

原理是什么

redis 的链表结构如下:

typedef struct listNode {
struct listNode *prev; //前驱节点,如果是list的头结点,则prev指向NULL
struct listNode *next;//后继节点,如果是list尾部结点,则next指向NULL
void *value; //万能指针,能够存放任何信息
} listNode; 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;

java 的链表结构如下:

public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
transient int size = 0; /**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first; /**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
.......
}

redis 的链表和 java 的链表有什么不一样?

基本一致,都是双向不循环链表。

双向的优点就是可以向前遍历,也可以向后遍历。缺点就是每个节点都需要浪费一个指针去指向前一个节点。

Redis 学习笔记(篇一):字符串和链表的更多相关文章

  1. redis学习笔记(详细)——高级篇

    redis学习笔记(详细)--初级篇 redis学习笔记(详细)--高级篇 redis配置文件介绍 linux环境下配置大于编程 redis 的配置文件位于 Redis 安装目录下,文件名为 redi ...

  2. Redis学习笔记~目录

    回到占占推荐博客索引 百度百科 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合). ...

  3. Redis学习笔记一:数据结构与对象

    1. String(SDS) Redis使用自定义的一种字符串结构SDS来作为字符串的表示. 127.0.0.1:6379> set name liushijie OK 在如上操作中,name( ...

  4. Redis学习笔记(二)-key相关命令【转载】

    转自 Redis学习笔记(二)-key相关命令 - 点解 - 博客园http://www.cnblogs.com/leny/p/5638764.html Redis支持的各种数据类型包括string, ...

  5. Redis学习笔记(三)Redis支持的5种数据类型的总结

    继续Redis学习笔记(二)来说说剩余的三种数据类型. 三.列表类型(List) 1.介绍 列表类型可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的一段片段.列表类型内部是 ...

  6. Redis学习笔记(1)——Redis简介

    一.Redis是什么? Remote Dictionary Server(Redis) 是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Value ...

  7. Redis学习笔记4-Redis配置详解

    在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server   xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...

  8. Redis学习笔记之ABC

    Redis学习笔记之ABC Redis命令速查 官方帮助文档 中文版本1 中文版本2(反应速度比较慢) 基本操作 字符串操作 set key value get key 哈希 HMSET user:1 ...

  9. Redis学习笔记(二)Redis支持的5种数据类型的总结之String和Hash

    引言 在Redis学习笔记(一)中我们已经会安装并且简单使用Redis了,接下来我们一起来学习下Redis支持的5大数据类型. 简介 Redis是REmote DIctionary Server(远程 ...

  10. Redis学习笔记(2)——Redis的下载安装部署

    一.下载Redis Redis的官网下载页上有各种各样的版本,如图 但是官网下载的Redis项目不正式支持Windows.如果需要再windows系统上部署,要去GitHub上下载.我下载的是Redi ...

随机推荐

  1. PL/SQL Developer跑在Oracle 64位数据库上初始化错误

    安装完Oracle(64位).PL/SQL Developer后执行PL/SQL出现例如以下的错误: 网上查资料说,我的PL/SQL Developer与ORACLE不兼容,即PL/SQL不支持64位 ...

  2. 衡量镜头解像能力性能的指标-MTF曲线

    MTF(Modulation Transfer Function,模量传递函数),是目前分析镜头解像能力的方法,可以用来评判镜头还原物体对比度的能力.说到MTF,不得不先提一下衡量镜头性能的两在重要指 ...

  3. c语言学习笔记(13)——链表

    链表 算法: 1.通俗定义: 解题的方法和步骤 2.狭义定义: 对存储数据的操作 3.广义定义: 广义的算法也叫泛型 无论数据是如何存储的,对数据的操作都是一样的 我们至少可以通过两种结构来存储数据 ...

  4. 半监督学习(semi-supervised learning)

    P(x)P(x,y)}⇒P(y|x) 自 P(x) 生成的无标签样本: 自 P(x,y) 生成的标记样本:

  5. Python 内置函数 —— format

    科学计数法: >> format(2**20, '.2e') '1.05e+06' 小数 ⇒ 百分数 >> format(.1234, '.1%') 12.3%

  6. IOC学习1

    学习蒋金楠的 ASP.NET Core中的依赖注入(1):控制反转(IoC) 而来,这篇文章经典异常.一定要多读.反复读. 这篇文章举了一个例子,就是所谓的mvc框架,一开始介绍mvc的思想,由一个d ...

  7. NLP(paper + code)

    0. 开源的库 genism keras wrapper of theano/TensorFlow 1. CNN for NLP Convolutional Neural Networks for S ...

  8. HTML5 随手记(4)

    新中国 chrome 不支持 -webkit-text-size-adjust 设定.可以小于 12px.为了尺寸小于 12px 和清晰的显示效果,现在无解(scale 不清楚) 版权声明:本文博客原 ...

  9. JAVA学习第三十三课(经常使用对象API) —迭代器

    数字有非常多用数组存,对象有非常多就要用集合存 可是数组是固定长度的,集合是可变长度的 集合的由来: 对象用来封装特有数据,对象多了须要存储,假设对象个数不确定,就须要使用集合容器来存储 集合的特点: ...

  10. NPM切换源

    可以试试切换下你的NPM源.看是否能得到解决.国内的NPM有CNPM和淘宝的NPM源比较稳定.npm源切换和工具可参照站内贴 nrm工具的使用或者是直接用命令切换   npm config set r ...