跳表原理
跳变是一种高效的搜索结构,是对链表的一种优化,如下图所示,以下图片均摘自博客,原始的链表结构如下图,实现查找、删除和插入复杂度都为O(n)
,因为需要遍历链表
而跳表的思想如下,即多加一些索引,高层的索引跳跃连接,可以更快地抵达要查找的目标节点,查找时先从最高层索引开始,高速前进,当下一个节点的值大于要查找的值时就进入下一层,相当于减速,直到最底层找到目标节点
时间复杂度
相对于原始链表,优势在于高层索引可以快速跨越,能实现
O
(
l
o
g
2
n
)
O(log_2n)
O(log2n)级别的查找、删除和插入,计算如下,其实是一种近似的计算方法,默认在每一层只查找一次,然后就进入下一层,则查找的次数就是跳表的高度h
,但是一般情况下每一层肯定不止找一次,因此最小的查找次数就是跳表的高度h
,关键是求得h
,通过找规律很容易得出:
一级索引的节点为
n
/
2
n/2
n/2,二级索引的节点数为
n
/
4
n/4
n/4,则第k级索引的节点数为
n
/
2
k
n/2^k
n/2k,最高级索引H通常只有两个节点,即头尾,因此满足
2
=
n
/
2
H
2=n/2^H
2=n/2H,解得
H
=
l
o
g
2
n
−
1
H=log_2n-1
H=log2n−1,再加上原始的链表得到跳表的层数为
h
=
H
+
1
=
l
o
g
2
n
h=H+1=log_2n
h=H+1=log2n,因此时间复杂度为
O
(
l
o
g
2
n
)
O(log_2n)
O(log2n)。
Java实现
Java实现如下,相对于红黑树等二分查找结构实现更简单
import java.util.Random;
class SkipList {
private static final int MAX_LEVEL = 16;
private int levelCount = 1;
private Node head = new Node();
private Random random = new Random();
class Node {
private int data;
private Node[] forwards = new Node[MAX_LEVEL];
private int maxLevel;
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{data: ");
sb.append(data);
sb.append("; level: ");
sb.append(maxLevel);
sb.append(" }");
return sb.toString();
}
}
public Node find(int value) {
Node p = head;
for (int i = levelCount - 1; i >= 0; i--) {
while (p.forwards[i] != null && p.forwards[i].data < value)
p = p.forwards[i];
}
if (p.forwards[0] != null && p.forwards[0].data == value)
return p.forwards[0];
return null;
}
public void insert(int value) {
Node p = head;
int level = randomLevel();
Node node = new Node();
node.data = value;
node.maxLevel = level;
Node update[] = new Node[level];
for (int i = level - 1; i >= 0; i--) {
while (p.forwards[i] != null && p.forwards[i].data < value)
p = p.forwards[i];
update[i] = p;
}
for (int i = 0; i < level; i++) {
node.forwards[i] = update[i].forwards[i];
update[i].forwards[i] = node;
}
if (levelCount < level)
levelCount = level;
}
public void delete(int value) {
Node[] deleteNode = new Node[MAX_LEVEL];
Node p = head;
for (int i = levelCount - 1; i >= 0; i--) {
while (p.forwards[i] != null && p.forwards[i].data < value)
p = p.forwards[i];
deleteNode[i] = p;
}
if (p.forwards[0] != null && p.forwards[0].data == value)
for (int i = levelCount - 1; i >= 0; i--)
if (deleteNode[i] != null && deleteNode[i].forwards[i].data == value)
deleteNode[i].forwards[i] = deleteNode[i].forwards[i].forwards[i];
}
public void printAll() {
Node p = head;
while (p.forwards[0] != null) {
System.out.print(p.forwards[0] + " ");
p = p.forwards[0];
}
System.out.println();
}
private int randomLevel() {
int level = 0;
for (int i = 0; i < MAX_LEVEL; i++) {
if (random.nextInt() % 2 == 1) {
level++;
}
}
return level;
}
}
public class main {
public static void main(String[] args) {
SkipList list = new SkipList();
list.insert(1);
list.insert(4);
list.insert(3);
list.insert(5);
list.printAll();
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)