数组在内存空间是连续的.
链表(linked List)的储存空间可以是不连续的,每个数据之间是通过指针来联系起来的,
链表分为单链表,双链表,循环链表(单向循环,双向循环)
链表核心操作 插入,删除,遍历
单链表中的内存结构是通过next指针链接在一起组成,next指针指向下一个数据域,(节点)内存结构由数据data和next指针两部分区块组成.链尾的next指针设为null[指向空],遍历方向单一从头到尾
双向链表由next指针和prew指针和数据三个区块组成,next指针指向下一个数据域,指向的内存结构叫做后继,链尾next指针设为null[指为空], prew指针指向上个数据域,指向的内存结构叫做前驱,连头prew指针设为null[指为空],一般情况下next方向是头到尾,这篇说的都是在next方向是头到尾的情况下.
循环链表单向循环 链尾next指针指向链头,形成闭环,其实没有链头和链尾
双向循环链表链尾next指针指向链头,链头prew指针指向链尾,形成闭环,其实没有链头和链尾
指针其实是下一个数据域的地址
红黑树(平衡二叉树的一种变体,不是严格意义上的平衡二叉树,左右子树高差可能大于1 )
一种特殊的二叉树,通过左右子树节点左移右移来维持平衡.
hashmap 中当链表元素个数大于8时(当整个散列桶(数组)的大小已经超过64),转成红黑树,低于6时转回链表,为了解决hash冲突和map元素过多
散列类型(hash类型)(redis中hash ,这与Java中的hashmap本质相同)
散列是<k,v>对的集合,不过KV都只能是字符串类型的,不能嵌套
不区分插入和更新,当设置一个field的时候如果不存在的话就是新增返回1,存在的话就视为更新,会覆盖原始数据返回0
<使用hmset可以一次付多个值
使用hsetnx只有当指定的field不存在时才赋值,为了比年覆盖已有的值
hget单个取值 hmget取多个值
hgetall取出全部的field和value
hkeys....获取hash表中的field集合
hvals.....获取value表中的value集合
hash冲突简单的说就是通过hash函数计算时,不同的key值,有相同的value>
以上中的field字段值就是指KV中 的k,key指的是表名
每个hash表名存储的最大是2的32次方减一的键值对
散列桶(分离链表法)
哈希桶就是为了解决哈希冲突
哈希桶算法其实就是链地址解决冲突的方法
哈希桶的每个桶由一个链表来存储数据
每个桶储存的是此格里链表的一个数据的key(地址值)
hashmap的几种方法
hash表的底层结构是一个数组,数组长度即哈希表的长度,数组中方的每个空间(桶)存放一个链表,链表每个节点存放元素
hash查找 是通过一种hash函数(如 value=key % 3)进行计算方便查找的方法
直接定址法 除留取余法 平均取余法 平均取中法 折叠法 随机数法 数据分析法 分离链接法和开放定址法 其中最后两个解决哈希冲突
一致性哈希(哈希圆环(虚拟圆环)0-2^32)(优点是即使缓存服务器的数量发生改变,部分的服务器还是可以能正常使用)(一致性哈希使用的32个bits,4个bytes,肯定也会有哈希碰撞的问题存在)解决分布式缓存问题
key或节点数值,ip ---hash()---->值----取余---->余数_
hash(节点(服务器或服务)特有数据或者ip)%机器数=余数,余数对应哈希环上的对数值的点,分布在圆环上,其为节点.
hash(处理的数据的值(key))%机器数=余数,余数对应哈希环上的对应数值的点,分布在圆环上,顺时针差找第一个节点,为该数据的存储节点.
哈希倾斜,是因为节点因为计算可能会分布不均,导致各个节点的存储数据不均匀
虚拟节点有效的缓解可以说解决哈希倾斜,通过服务器的物理真实节点,映射出多个虚拟节点,将这些虚拟节点映射到哈希环上,增加均匀缓存的概率,通过上面的顺时针查找,,找到第一个虚拟节点,通过这个虚拟节点映射对应的真实的节点,之后进行存储或读取.
虚拟节点机制,一般不会把真实节点放在哈希环上,只放虚拟节点
一致性哈希可能会因为一个节点的缺失,导致下一个节点需要缓存的数据激增,可能导致这个节点也崩溃,这样会造成连锁反应,这就是哈希雪崩.(虚拟节点机制也可以缓解哈希雪崩)