跳表全称叫做跳跃表,简称跳表。跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。
跳表在性能上和红黑树,AVL树不相上下,但是跳表的原理非常简单,目前在Redis和LeveIDB中都有用到。
跳表采用随机技术决定元素应该在哪几层,其中的搜索、插入、删除操作的时间均为O(logn),然而,最坏情况下时间复杂性却变成O(n)。相比之下,在一个有序数组或链表中进行插入/删除操作的时间为O(n),最坏情况下为O(n)。
这个是跳表的模型
跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。首先在最高级索引上查找最后一个小于当前查找元素的位置,然后再跳到次高级索引继续查找,直到跳到最底层为止,这时候以及十分接近要查找的元素的位置了(如果查找元素存在的话)。由于根据索引可以一次跳过多个元素,所以跳查找的查找速度也就变快了。
(以上截自百度关于跳表的一些介绍)
不过其中的-1也可以换成任意的负无穷的数,其中最下层是最原始的链表,依次往上是一层二层索引,关于跳表的一些操作,接下来详细介绍。
首先介绍跳表的基本组成单位:跳表节点。
跳表节点包含:
元素值
下一个节点
下一层的对应节点
/**
* 定义跳表节点
*/
public class SkipNode {
//元素值
public int element;
//下一个节点
public SkipNode next = null;
//下一层对应节点
public SkipNode down = null;
public SkipNode( int element ) {
this.element = element;
}
public SkipNode(SkipNode node) {
this.element = node.element;
}
}
其次介绍关于跳表的查找操作
1、从最上层的跳表索引的开头开始
2、假设当前位置为p,将p的下一个节点的值与key比较
1) p下一个节点的值 <= key ,p移动到下一个节点的位置
2) p下一个节点的值 > key 或者 p的下一个值为null,p移动到下一层相应的节点位置
3.到达底层后,p的右边可能还有元素,则移动直到p节点的值=key或者p的下一个节点为空
1) 找到p节点
2) 找不到p节点
/**
* 查找节点
* @param key(节点的值)
* @return 存在时返回最底层对应节点,不存在时返回null
*/
public SkipNode find(int key) {
SkipNode p = head;
while (p != null && p.down != null) {
if (p.next != null && key >= p.next.element) {
// 比右边大或相等时向右
p = p.next;
} else if (p.next == null || key < p.next.element) {
// 否则向下
p = p.down;
}
}
// 到达底层后右边可能还有元素
while (p.next != null && key >= p.next.element ) {
p = p.next;
}
if( p.element != -1 && key == p.element) {
return p;
}
return null;
}