抱歉,您的瀏覽器無法訪問本站
本頁面需要瀏覽器支持(啟用)JavaScript
了解詳情 >

跳跃表(skiplist)简介

跳跃表(skiplist)是一种随机化的数据结构,其实就是给顺序单链表加了多个多层索引,高层次的索引跳跃节点大于底层的,增加是以随机化的方式进行的,在列表中查找的可以快速的跳过部分列表,提高查询效率。 跳跃表以有序的方式在层次化的链表中保存元素, 效率和平衡树媲美 —— 查找、删除、添加等操作都可以在对数期望时间下完成, 并且比起平衡树来说, 跳跃表的实现要简单直观得多。

upload successful

从图中可以分为4个部分构成:
head:负责维护跳跃表的节点指针
跳跃表节点:保存元素值
层:保持着其他元素的指针,高层的指针越过元素数量大于等于低层的指针,为了提高效率,程序总是从高层开始访问,然后随着范围的缩小,降低层次。

跳跃表代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
public class MySkipList<K extends Comparable<? super K>,V>{

private MySkipListNode<K,V> head,tail;//头尾指针
private int nodeNum,levelNum;
private Random random;
private static final double PROBABILITY = 0.5;
private final K HEAD_KEY,TAIL_KEY;
public MySkipList(Class<K> kClass) {
random = new Random();
HEAD_KEY= (K) new NullComparable();
TAIL_KEY= (K) new NullComparable();
head = new MySkipListNode<>(HEAD_KEY,null);
tail = new MySkipListNode<>(TAIL_KEY,null);
horizontalLink(head,tail);
}

public int size(){
return nodeNum;
}

/**
* 在最底层找到要插入位置的元素
* @param key
* @return
*/
private MySkipListNode<K,V> findNode(K key){
MySkipListNode<K,V> node = head;
while (true){
while (node.right.key!=TAIL_KEY&&node.right.key.compareTo(key)<=0){
node = node.right;
}
if (node.down != null){

node = node.down;
}else {
break;
}
}
return node;
}

public MySkipListNode<K,V> get(K key){
MySkipListNode<K,V> node =findNode(key);
if (key.compareTo(node.key)==0){
return node;
}
return null;
}
public boolean add(K key, V value){
if (Objects.isNull(key)){
throw new AssertionError("THE KEY CANNOT BE EMPTY");
}
//如果key存在则直接赋值
MySkipListNode<K,V> node = findNode(key);
if (!(node.key instanceof NullComparable)&&key.compareTo(node.key)==0){
node.value=value;
return true;
}
MySkipListNode<K,V> newNode = new MySkipListNode<>(key,value);
backLink(node,newNode);
int currentLevel = 0;
while(random.nextDouble()<PROBABILITY){
if (currentLevel>=levelNum){
levelNum++;
MySkipListNode<K,V> newHeadNode = new MySkipListNode<K,V>(HEAD_KEY,null);
MySkipListNode<K,V> newTailNode = new MySkipListNode<>(TAIL_KEY,null);
horizontalLink(newHeadNode,newTailNode);
verticalLink(newHeadNode,head);
verticalLink(newTailNode,tail);
head = newHeadNode;
tail = newTailNode;
}
while (node.up == null){
node = node.left;
}
node = node.up;
MySkipListNode<K,V> newUpNode = new MySkipListNode<>(key,null);

backLink(node,newUpNode);
verticalLink(newUpNode,newNode);
newNode = newUpNode;
currentLevel++;
}
nodeNum++;
return true;
}

public List<MySkipListNode> traverseKey(){
List<MySkipListNode> listNodes = new ArrayList<>();
if (nodeNum == 0){
return null;
}
MySkipListNode<K,V> node = head;
StringBuilder builder =new StringBuilder();
while (node.down!=null){
node = node.down;
}
while (node.left!=null){
node = node.left;
}
while (node.right!=null){
listNodes.add(node);
node = node.right;
}
return listNodes;
}

/**
* 将back插入到front的后面。
* @param front
* @param back
*/
public void backLink(MySkipListNode front,MySkipListNode back){
back.left = front;
back.right=front.right;
front.right.left=back;
front.right=back;
}

/**
* 垂直链接
* @param upNode
* @param downNode
*/
public void verticalLink(MySkipListNode<K,V> upNode,MySkipListNode<K,V> downNode){
upNode.down = downNode;
downNode.up = upNode;
}

/**
* 水平链接
* @param leftNode
* @param rightNode
*/
public void horizontalLink(MySkipListNode<K,V> leftNode,MySkipListNode<K,V> rightNode){
leftNode.right = rightNode;
rightNode.left = leftNode;
}

private static class MySkipListNode<K,V>{
private K key;
private V value;
private MySkipListNode<K,V> up,down,left,right;//上下左右

public MySkipListNode(K key, V value) {
this.key = key;
this.value = value;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return key==((MySkipListNode)o).key;
}

@Override
public int hashCode() {
return key.hashCode();
}

@Override
public String toString() {
return "MySkipListNode{" +
"key=" + key +
", value=" + value +
'}';
}
}
private static class NullComparable implements Comparable{

@Override
public int compareTo(Object o) {
System.out.println(o);
return 0;
}

}
public static void main(String[] args) {
MySkipList<String,String> mySkipList = new MySkipList<>(String.class);
Random random = new Random();
for (int i=0;i<20;i++){
int num = random.nextInt(100);
System.out.println("num = "+num);
mySkipList.add(String.valueOf(num),"num="+num);
}
System.out.println(mySkipList.traverseKey());
}
}