这是我参与「第五届青训营」伴学笔记创作活动的第13天。本篇为第五届字节跳动青训营-寒假专场-后端基础课程的笔记。
引入
redis为什么采用跳表而不是红黑树?? 显然这样的事实暗示着跳表相较于红黑树在某些场景下更加高效,就让我们来了解一下跳表。
跳表 SkipList
跳表分为多层,每层都是数据的索引,上层是下层的子集。
传统单链表的查询速率是 O(N) 。跳表正是基于这个数据结构,增加了层数。我们从高层开始查找,如果值相等就找到了目标,或者我们可以缩小目标的范围,并且进入更深层进行查找(层数越深,包含的元素(索引)越多,查找到的几率就越大)。
从某种角度来看,跳表就是可以实现高效二分查找的有序链表。
假设跳表实际存储元素 N 个
- 其一级索引有 个元素
- K 级索引有 个元素
- 总高度 为
- 最高级的索引层共有2个索引
- 查找时候,每层最多需要访问索引3次,这样查询时间复杂度就是
跳表的插入
插入跳表,我们希望其时间复杂度是对数级别的,而且我们希望插入后跳表可以保持高效的查找能力。
- 首先,插入元素时,我们决定要为这个元素创建几级的索引
- 创建多少级的索引需要满足一定分布。
- 1级索引创建概率为 0.5
- 2级索引创建概率为 0.25
- 3级索引创建概率为 0.125
- 以此类推
- 从最高级的索引层开始执行插入,直到最底层
- 这样就完成了跳表的插入更新
跳表的删除
从上往下,边搜索,便删除索引。
问题解决
redis为什么采用跳表而不是红黑树??
Redis 中的有序集合(zset) 支持的操作:
插入一个元素
删除一个元素
查找一个元素
有序输出所有元素
按照范围区间查找元素 其中,前四个操作红黑树也可以完成,且时间复杂度跟跳表是一样的。按照区间来查找数据这个操作,跳表效率高。可以做到 O(logn) 的时间复杂度。
JUC——ConcurrentSkipListMap
ConcurrentSkipListMap是线程安全的有序的哈希表,适用于高并发的场景。
特点:
- 相比于HashMap key是有序的
- 相比于HashMap 支持更高的并发
- 在多线程程序中,如果需要对Map的键值进行排序时,请尽量使用ConcurrentSkipListMap,可能得到更好的并发度。