一文搞懂什么是跳表

199 阅读2分钟

一. 跳表的定义

跳表,又叫做跳跃表、跳跃列表,在有序链表的基础上增加了“跳跃”的功能

跳表 在原来的有序链表上加上了多级索引,通过索引来快速查找;可以支持快速的删除、插入和查找操作。

Redis中 的 SortedSet、LevelDB 中的 MemTable 都用到了跳表

image.png

二. 跳表的搜索

从顶层链表的首元素开始,从左往右搜索,直至找到一个大于或等于目标的元素,或者到达当前层链表的尾部

如果该元素等于目标元素,则表明该元素已被找到

如果该元素大于目标元素或已到达链表的尾部,则退回到当前层的前一个元素,然后转入下一层进行搜索

三. 总结

  • 跳表使用的是空间换时间的思想,通过构建多级索引来提高查询效率,实现基于链表的“二分查找”,跳表是一种动态的数据结构,支持快速的查找、插入和删除操作,时间复杂度是 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();
}

}