跳表(Skip List)是一个非常有趣的概率型数据结构,特别适合用于需要快速查找的有序数据集合。
跳表通过空间换时间(多级索引),用概率平衡代替严格平衡,在实现简单性和性能之间取得了很好的平衡。就像城市交通系统,既有直达高速路(高层索引),也有普通街道(底层链表),根据需求灵活选择路径
跳表的核心思想——地铁快速线
想象你每天要坐地铁从第1站到第100站:
- 普通链表就像普通地铁线,必须每站都停(逐个节点遍历)
- 跳表就像同时存在多条线路:
- 快线A:只停1, 25, 50, 75, 100站
- 快线B:停1, 10, 20, 30,…100站
- 普通线:每站都停 - 当你想去第85站时:
- 先在快线A坐到75站
- 换乘快线B到80站
- 最后换普通线到85站 - 这样通过多级"快速通道",大大减少了需要经过的站点数量。
跳表的可视化结构示例
假设有序链表存储数据:1→3→5→7→9→11→13→15
一个可能的跳表结构:
- 层级3:1 -----------------------> 9 --------> 15
- 层级2:1 --------> 5 --------> 9 --------> 13
- 层级1:1 ->3 ->5 ->7 ->9 ->11->13->15
查找数字13的过程:
- 从顶层3开始:1→9→15(15太大,回退到9)
- 下到层级2:9→13(找到!)
跳表的随机层数机制
跳表最巧妙的设计是节点的"层数"是随机生成的(类似抛硬币):
- 每个新节点默认有第1层
- 抛硬币如果是正面,就增加一层,直到出现反面为止
- 理论上会有约50%的节点有第2层,25%有第3层,12.5%有第4层…
- 这种随机性让跳表保持了近似平衡,而无需像红黑树那样复杂的旋转操作。
实际应用场景
- Redis的有序集合(Sorted Set)底层使用跳表
- LevelDB的MemTable实现
- 需要频繁插入/删除的有序数据集