SkipList数据结构学习
来源:互联网 发布:鳄鱼有耳朵吗 知乎 编辑:程序博客网 时间:2024/05/23 19:19
1.跳表是什么:
跳表是平衡树的一种替代的数据结构,但是和红黑树不相同的是,跳表对于树的平衡的实现是基于一种随机化的算法的,这样也就是说跳表的插入和删除的工作是比较简单 的。
2.为什么要使用跳表:
目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等。想象一下,给你一张草稿纸,一只笔,一个编辑器,你能立即实现一颗红黑树,或者AVL树出来吗? 很难吧,这需要时间,要考虑很多细节,要参考一堆算法与数据结构之类的树,还要参考网上的代码,相当麻烦。用跳表吧,跳表是一种随机化的数据结构,目前开源软件 Redis 和 LevelDB 都有用到它,它的效率和红黑树以及 AVL 树不相上下,但跳表的原理相当简单,只要你能熟练操作链表,就能轻松实现一个 SkipList。
3.跳表原理
有序表的搜索
考虑一个有序表:
从该有序表中搜索元素 < 23, 43, 59 > ,需要比较的次数分别为 < 2, 4, 6 >,总共比较的次数为 2 + 4 + 6 = 12 次。有没有优化的算法吗? 链表是有序的,但不能使用二分查找。类似二叉搜索树,我们把一些节点提取出来,作为索引。得到如下结构:
这里我们把 < 14, 34, 50, 72 > 提取出来作为一级索引,这样搜索的时候就可以减少比较次数了。我们还可以再从一级索引提取一些元素出来,作为二级索引,变成如下结构:
这里元素不多,体现不出优势,如果元素足够多,这种索引结构就能体现出优势来了。这基本上就是跳表的核心思想,其实也是一种通过“空间来换取时间”的一个算法,通过在每个节点中增加了向前的指针,从而提升查找的效率。
下面的结构是就是跳表:
其中 -1 表示 INT_MIN, 链表的最小值,1 表示 INT_MAX,链表的最大值。
跳表具有如下性质:
(1) 由很多层结构组成
(2) 每一层都是一个有序的链表
(3) 最底层(Level 1)的链表包含所有元素
(4) 如果一个元素出现在 Level i 的链表中,则它在 Level i 之下的链表也都会出现。
(5) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。
跳表的搜索
例子:查找元素 117
(1) 比较 21, 比 21 大,往后面找
(2) 比较 37, 比 37大,比链表最大值小,从 37 的下面一层开始找
(3) 比较 71, 比 71 大,比链表最大值小,从 71 的下面一层开始找
(4) 比较 85, 比 85 大,从后面找
(5) 比较 117, 等于 117, 找到了节点。
4.跳表简单实现:
代码如下:
节点数据结构SkipNode
public class SkipNode {
private int data;
private SkipNode next[] = null;
public SkipNode(int data, int level) {
this.data = data;
this.next = new SkipNode[level];
}
public int getData() {
return data;
}
public SkipNode[] getNext() {
return next;
}
}
public static void main(String[] args) {
SkipList list = new SkipList();
int size = 100000;
long start = System.currentTimeMillis();
for (int index = 0; index < size; ++index) {
list.insert(index);
}
long end = System.currentTimeMillis();
System.out.println((end - start));
}
}
/**
* Created by yangzhuo02 on 2015/5/26.
*/
import java.util.Random;
public class SkipList {
//设定对打level为32
private static int MAXLEVEL = 32;
private int level = 0;
private SkipNode head;
public SkipList() {
this.level = level;
this.head = new SkipNode(0, MAXLEVEL + 1);
}
/**
*节点插入的时候会随机分配一个level
*
**/
private int randomLevel() {
Random random = new Random();
int level = Math.abs(random.nextInt() % MAXLEVEL);
return level > this.level ? (this.level + 1) : level;
}
/**
*插入操作
*
**/
public void insert(int value) {
SkipNode tmpHead = this.head;
//频繁的生成大空间数组,是非常消耗时间的,尤其在性能比较差的机器上
SkipNode[] updateNode = new SkipNode[MAXLEVEL - 1];
int index = level;
for (; index > 0; --index) {
while (tmpHead != null && tmpHead.getData() < value) {
updateNode[index] = tmpHead.getNext()[index];
tmpHead = tmpHead.getNext()[index];
}
}
boolean exists = (tmpHead != null && tmpHead.getData() == value);
if (exists) {
return;
}
int level = this.randomLevel();
SkipNode insertNode = new SkipNode(value, level + 1);
for (int tmpIndex = level; tmpIndex >= 0; --tmpIndex) {
if (updateNode[tmpIndex] == null) {
updateNode[tmpIndex] = this.head;
}
SkipNode next = updateNode[tmpIndex].getNext()[tmpIndex];
insertNode.getNext()[tmpIndex] = next;
updateNode[tmpIndex].getNext()[tmpIndex] = insertNode;
}
this.level = Math.max(level, this.level);
}
/*
这里没有做同步处理
*/
public boolean find(int value) {
SkipNode tmpHead = this.head;
for (int index = level; index > 0; --index) {
while (tmpHead.getNext()[index] != null && tmpHead.getNext()[index].getData() < value) {
tmpHead = tmpHead.getNext()[index];
}
}
return tmpHead != null && tmpHead.getData() == value;
}
/**
*删除操作,先找到对应的节点,依次删除
*
**/
public void delete(int value) {
SkipNode tmpHead = this.head;
//使用这个是应为,只有这样才能获取需要删除节点的前驱和后继节点
//最后如果该层的节点都删除了,还需要修改level的值
SkipNode[] updateNode = new SkipNode[level + 1];
int index = level;
for (; index > 0; --index) {
while (tmpHead.getNext()[index] != null && tmpHead.getNext()[index].getData() < value) {
tmpHead = tmpHead.getNext()[index];
updateNode[index] = tmpHead;
}
}
if (tmpHead.getData() == value) {
for (int tmpIndex = level; tmpIndex >= 0; --tmpIndex) {
SkipNode tmpNode = updateNode[index].getNext()[tmpIndex];
updateNode[index] = tmpNode.getNext()[tmpIndex];
if (updateNode[index] != null) {
--level;
}
}
}
}
}
- SkipList数据结构学习
- 一种数据结构 跳表skiplist
- 高级数据结构-SkipList
- 【数据结构】跳跃列表 SkipList
- 数据结构 跳表skiplist
- 扩展数据结构--跳表(SkipList)
- 深入剖析 redis 数据结构 skiplist
- 数据结构之跳表Skiplist
- Redis-数据结构-跳跃表-skiplist
- 跳表Skiplist学习笔记
- leveldb学习:skiplist
- SkipList 跳表学习
- 【从下而上学习Redis】数据结构篇(一):跳跃表(skiplist)
- 源码分析redis的有序集合,学习skiplist跳跃表数据结构
- skiplist
- skiplist
- SkipList
- skiplist
- sax解析XML文件
- ios-信号量
- tableView 的使用步骤和方法
- 小火箭原理
- 网络编程,socket编程,TCP
- SkipList数据结构学习
- eclispe 远程调试 Tomcat 下项目代码问题
- 深入理解Java:SimpleDateFormat安全的时间格式化
- JSSDK,微信JS接口,分享朋友圈狀態捕獲,項目實例
- Java网络编程(一):服务端与客户端建立(UDP方式)
- scrollview 的各类代理方法汇总
- android 手机的网络时间同步
- java学习3-冒泡排序对数组进行排序
- Crashlytics 教程