一. 跳表的定义
跳表,又叫做跳跃表、跳跃列表,在有序链表的基础上增加了“跳跃”的功能
跳表 在原来的有序链表上加上了多级索引,通过索引来快速查找;可以支持快速的删除、插入和查找操作。
Redis中 的 SortedSet、LevelDB 中的 MemTable 都用到了跳表
二. 跳表的搜索
从顶层链表的首元素开始,从左往右搜索,直至找到一个大于或等于目标的元素,或者到达当前层链表的尾部
如果该元素等于目标元素,则表明该元素已被找到
如果该元素大于目标元素或已到达链表的尾部,则退回到当前层的前一个元素,然后转入下一层进行搜索
三. 总结
- 跳表使用的是空间换时间的思想,通过构建多级索引来提高查询效率,实现基于链表的“二分查找”,跳表是一种动态的数据结构,支持快速的查找、插入和删除操作,时间复杂度是 O(logn)。
- 跳表的空间复杂度是 O(n),不过跳表可以通过改变索引策略,动态的平衡执行效率和内存消耗。
四.java代码实现
package com.xizi.al;
import java.util.Random;
// 跳表中存储的是正整数,并且存储的数据是不重复的 public class SkipList {
private static final int MAX_LEVEL = 16; // 结点的个数
private int levelCount = 1; // 索引的层级数
private Node head = new Node(); // 头结点
private Random random = new Random();
// 查找操作
public Node find(int value){
Node p = head;
for(int i = levelCount - 1; i >= 0; --i){
while(p.next[i] != null && p.next[i].data < value){
p = p.next[i];
}
}
if(p.next[0] != null && p.next[0].data == value){
return p.next[0]; // 找到,则返回原始链表中的结点
}else{
return null;
}
}
// 插入操作
public void insert(int value){
int level = randomLevel();
Node newNode = new Node();
newNode.data = value;
newNode.maxLevel = level; // 通过随机函数改变索引层的结点布置
Node update[] = new Node[level];
for(int i = 0; i < level; ++i){
update[i] = head;
}
Node p = head;
for(int i = level - 1; i >= 0; --i){
while(p.next[i] != null && p.next[i].data < value){
p = p.next[i];
}
update[i] = p;
}
for(int i = 0; i < level; ++i){
newNode.next[i] = update[i].next[i];
update[i].next[i] = newNode;
}
if(levelCount < level){
levelCount = level;
}
}
// 删除操作
public void delete(int value){
Node[] update = new Node[levelCount];
Node p = head;
for(int i = levelCount - 1; i >= 0; --i){
while(p.next[i] != null && p.next[i].data < value){
p = p.next[i];
}
update[i] = p;
}
if(p.next[0] != null && p.next[0].data == value){
for(int i = levelCount - 1; i >= 0; --i){
if(update[i].next[i] != null && update[i].next[i].data == value){
update[i].next[i] = update[i].next[i].next[i];
}
}
}
}
// 随机函数
private int randomLevel(){
int level = 1;
for(int i = 1; i < MAX_LEVEL; ++i){
if(random.nextInt() % 2 == 1){
level++;
}
}
return level;
}
// Node内部类
public class Node{
private int data = -1;
private Node next[] = new Node[MAX_LEVEL];
private int maxLevel = 0;
// 重写toString方法
@Override
public String toString(){
StringBuilder builder = new StringBuilder();
builder.append("{data:");
builder.append(data);
builder.append("; leves: ");
builder.append(maxLevel);
builder.append(" }");
return builder.toString();
}
}
// 显示跳表中的结点
public void display(){
Node p = head;
while(p.next[0] != null){
System.out.println(p.next[0] + " ");
p = p.next[0];
}
System.out.println();
}
}