|
40 | 40 | 6) "60"
|
41 | 41 | ```
|
42 | 42 |
|
43 |
| -此时我们通过 `object` 指令查看 zset 的数据结构,可以看到当前有序集合存储的还是是**ziplist(压缩列表)**。 |
| 43 | +此时我们通过 `object` 指令查看 zset 的数据结构,可以看到当前有序集合存储的还是**ziplist(压缩列表)**。 |
44 | 44 |
|
45 | 45 | ```bash
|
46 | 46 | 127.0.0.1:6379> object encoding rankList
|
47 | 47 | "ziplist"
|
48 | 48 | ```
|
49 | 49 |
|
50 |
| -因为设计者考虑到 Redis 数据存放于内存,为了节约宝贵的内存空间在有序集合在元素小于 64 字节且个数小于 128 的时候,会使用 ziplist,而这个阈值的默认值的设置就来自下面这两个配置项。 |
| 50 | +因为设计者考虑到 Redis 数据存放于内存,为了节约宝贵的内存空间,在有序集合元素小于 64 字节且个数小于 128 的时候,会使用 ziplist,而这个阈值的默认值的设置就来自下面这两个配置项。 |
51 | 51 |
|
52 | 52 | ```bash
|
53 | 53 | zset-max-ziplist-value 64
|
@@ -78,7 +78,7 @@ zset-max-ziplist-entries 128
|
78 | 78 |
|
79 | 79 | 为了更好的回答上述问题以及更好的理解和掌握跳表,这里可以通过手写一个简单的跳表的形式来帮助读者理解跳表这个数据结构。
|
80 | 80 |
|
81 |
| -我们都知道有序链表在添加、查询、删除的平均时间复杂都都是**O(n)**即线性增长,所以一旦节点数量达到一定体量后其性能表现就会非常差劲。而跳表我们完全可以理解为在原始链表基础上,建立多级索引,通过多级索引检索定位将增删改查的时间复杂度变为**O(log n)**。 |
| 81 | +我们都知道有序链表在添加、查询、删除的平均时间复杂都都是 **O(n)** 即线性增长,所以一旦节点数量达到一定体量后其性能表现就会非常差劲。而跳表我们完全可以理解为在原始链表基础上,建立多级索引,通过多级索引检索定位将增删改查的时间复杂度变为 **O(log n)** 。 |
82 | 82 |
|
83 | 83 | 可能这里说的有些抽象,我们举个例子,以下图跳表为例,其原始链表存储按序存储 1-10,有 2 级索引,每级索引的索引个数都是基于下层元素个数的一半。
|
84 | 84 |
|
@@ -145,8 +145,8 @@ r=n/2^k
|
145 | 145 | 1. 跳表的高度计算从原始链表开始,即默认情况下插入的元素的高度为 1,代表没有索引,只有元素节点。
|
146 | 146 | 2. 设计一个为插入元素生成节点索引高度 level 的方法。
|
147 | 147 | 3. 进行一次随机运算,随机数值范围为 0-1 之间。
|
148 |
| -4. 如果随机数大于 0.5 则为当前元素添加一级索引,自此我们保证生成一级索引的概率为**50%**,这也就保证了 1 级索引理想情况下只有一半的元素会生成索引。 |
149 |
| -5. 同理后续每次随机算法得到的值大于 0.5 时,我们的索引高度就加 1,这样就可以保证节点生成的 2 级索引概率为**25%**,3 级索引为**12.5%**…… |
| 148 | +4. 如果随机数大于 0.5 则为当前元素添加一级索引,自此我们保证生成一级索引的概率为 **50%** ,这也就保证了 1 级索引理想情况下只有一半的元素会生成索引。 |
| 149 | +5. 同理后续每次随机算法得到的值大于 0.5 时,我们的索引高度就加 1,这样就可以保证节点生成的 2 级索引概率为 **25%** ,3 级索引为 **12.5%** …… |
150 | 150 |
|
151 | 151 | 我们回过头,上述插入 7 之后,我们通过随机算法得到 2,即要为其建立 1 级索引:
|
152 | 152 |
|
@@ -283,10 +283,10 @@ public void add(int value) {
|
283 | 283 |
|
284 | 284 | 查询逻辑比较简单,从跳表最高级的索引开始定位找到小于要查的 value 的最大值,以下图为例,我们希望查找到节点 8:
|
285 | 285 |
|
286 |
| -1. 跳表的 3 级索引首先找找到 5 的索引,5 的 3 级索引**forwards[3]**指向空,索引直接向下。 |
287 |
| -2. 来到 5 的 2 级索引,其后继**forwards[2]**指向 8,继续向下。 |
288 |
| -3. 5 的 1 级索引**forwards[1]**指向索引 6,继续向前。 |
289 |
| -4. 索引 6 的**forwards[1]**指向索引 8,继续向下。 |
| 286 | +1. 跳表的 3 级索引首先找找到 5 的索引,5 的 3 级索引 **forwards[3]** 指向空,索引直接向下。 |
| 287 | +2. 来到 5 的 2 级索引,其后继 **forwards[2]** 指向 8,继续向下。 |
| 288 | +3. 5 的 1 级索引 **forwards[1]** 指向索引 6,继续向前。 |
| 289 | +4. 索引 6 的 **forwards[1]** 指向索引 8,继续向下。 |
290 | 290 | 5. 我们在原始节点向前找到节点 7。
|
291 | 291 | 6. 节点 7 后续就是节点 8,继续向前为节点 8,无法继续向下,结束搜寻。
|
292 | 292 | 7. 判断 7 的前驱,等于 8,查找结束。
|
@@ -605,7 +605,7 @@ Node{data=23, maxLevel=1}
|
605 | 605 |
|
606 | 606 | ### 平衡树 vs 跳表
|
607 | 607 |
|
608 |
| -先来说说它和平衡树的比较,平衡树我们又会称之为 **AVL 树**,是一个严格的平衡二叉树,平衡条件必须满足(所有节点的左右子树高度差不超过 1,即平衡因子为范围为 `[-1,1]`)。平衡树的插入、删除和查询的时间复杂度和跳表一样都是 **O(log n)**。 |
| 608 | +先来说说它和平衡树的比较,平衡树我们又会称之为 **AVL 树**,是一个严格的平衡二叉树,平衡条件必须满足(所有节点的左右子树高度差不超过 1,即平衡因子为范围为 `[-1,1]`)。平衡树的插入、删除和查询的时间复杂度和跳表一样都是 **O(log n)** 。 |
609 | 609 |
|
610 | 610 | 对于范围查询来说,它也可以通过中序遍历的方式达到和跳表一样的效果。但是它的每一次插入或者删除操作都需要保证整颗树左右节点的绝对平衡,只要不平衡就要通过旋转操作来保持平衡,这个过程是比较耗时的。
|
611 | 611 |
|
@@ -674,7 +674,7 @@ private Node add(Node node, K key, V value) {
|
674 | 674 |
|
675 | 675 | ### 红黑树 vs 跳表
|
676 | 676 |
|
677 |
| -红黑树(Red Black Tree)也是一种自平衡二叉查找树,它的查询性能略微逊色于 AVL 树,但插入和删除效率更高。红黑树的插入、删除和查询的时间复杂度和跳表一样都是 **O(log n)**。 |
| 677 | +红黑树(Red Black Tree)也是一种自平衡二叉查找树,它的查询性能略微逊色于 AVL 树,但插入和删除效率更高。红黑树的插入、删除和查询的时间复杂度和跳表一样都是 **O(log n)** 。 |
678 | 678 |
|
679 | 679 | 红黑树是一个**黑平衡树**,即从任意节点到另外一个叶子叶子节点,它所经过的黑节点是一样的。当对它进行插入操作时,需要通过旋转和染色(红黑变换)来保证黑平衡。不过,相较于 AVL 树为了维持平衡的开销要小一些。关于红黑树的详细介绍,可以查看这篇文章:[红黑树](https://javaguide.cn/cs-basics/data-structure/red-black-tree.html)。
|
680 | 680 |
|
@@ -726,7 +726,7 @@ private Node < K, V > add(Node < K, V > node, K key, V val) {
|
726 | 726 |
|
727 | 727 | 1. **多叉树结构**:它是一棵多叉树,每个节点可以包含多个子节点,减小了树的高度,查询效率高。
|
728 | 728 | 2. **存储效率高**:其中非叶子节点存储多个 key,叶子节点存储 value,使得每个节点更够存储更多的键,根据索引进行范围查询时查询效率更高。-
|
729 |
| -3. **平衡性**:它是绝对的平衡,即树的各个分支高度相差不大,确保查询和插入时间复杂度为**O(log n)**。 |
| 729 | +3. **平衡性**:它是绝对的平衡,即树的各个分支高度相差不大,确保查询和插入时间复杂度为 **O(log n)** 。 |
730 | 730 | 4. **顺序访问**:叶子节点间通过链表指针相连,范围查询表现出色。
|
731 | 731 | 5. **数据均匀分布**:B+树插入时可能会导致数据重新分布,使得数据在整棵树分布更加均匀,保证范围查询和删除效率。
|
732 | 732 |
|
|
0 commit comments