跳跃表是一种随机化数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间),并且对并发算法友好。

关于跳跃表的具体介绍可以参考MIT的公开课:跳跃表

跳跃表的应用

Skip list(跳表)是一种可以代替平衡树的数据结构,默认是按照Key值升序的。Skip list让已排序的数据分布在多层链表中,以0-1随机数决定一个数据的向上攀升与否,通过“空间来换取时间”的一个算法,在每个节点中增加了向前的指针,在插入、删除、查找时可以忽略一些不可能涉及到的结点,从而提高了效率。

在Java的API中已经有了实现:分别是

ConcurrentSkipListMap(在功能上对应HashTable、HashMap、TreeMap) ;

ConcurrentSkipListSet(在功能上对应HashSet). 

确切来说,SkipList更像Java中的TreeMap,TreeMap基于红黑树(一种自平衡二叉查找树)实现的,时间复杂度平均能达到O(log n)。

HashMap是基于散列表实现的,时间复杂度平均能达到O(1)。ConcurrentSkipListMap是基于跳表实现的,时间复杂度平均能达到O(log n)。

Skip list的性质

(1) 由很多层结构组成,level是通过一定的概率随机产生的。
(2) 每一层都是一个有序的链表,默认是升序
(3) 最底层(Level 1)的链表包含所有元素。
(4) 如果一个元素出现在Level i 的链表中,则它在Level i 之下的链表也都会出现。
(5) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。 Ø ConcurrentSkipListMap具有Skip list的性质 ,并且适用于大规模数据的并发访问。多个线程可以安全地并发执行插入、移除、更新和访问操作。与其他有锁机制的数据结构在巨大的压力下相比有优势。 Ø TreeMap插入数据时平衡树采用严格的旋转(比如平衡二叉树有左旋右旋)来保证平衡,因此Skip list比较容易实现,而且相比平衡树有着较高的运行效率。 Java代码实现: 1. SkipListEntry.java , 这是跳跃表中存储的每个元素实体类,包含 上下左右 四个指针。
01
package skiplist;
02 03
public class SkipListEntry {
04
public String key;
05
public Integer value;
06 07
public int pos; //主要为了打印 链表用
08 09
public SkipListEntry up, down, left, right; // 上下左右 四个指针
10 11
public static String negInf = new String("-oo"); // 负无穷
12
public static String posInf = new String("+oo"); // 正无穷
13 14
public SkipListEntry(String k, Integer v) {
15
key = k;
16
value = v;
17 18
up = down = left = right = null;
19
}
20 21
public Integer getValue() {
22
return value;
23
}
24 25
public String getKey() {
26
return key;
27
}
28 29
public Integer setValue(Integer val) {
30
Integer oldValue = value;
31
value = val;
32
return oldValue;
33
}
34 35
public boolean equals(Object o) {
36
SkipListEntry ent;
37
try {
38
ent = (SkipListEntry) o; // 检测类型
39
} catch (ClassCastException ex) {
40
return false;
41
}
42
return (ent.getKey() == key) && (ent.getValue() == value);
43
}
44 45
public String toString() {
46
return "(" + key + "," + value + ")";
47
}
48
} 2. SkipList.java, 跳跃表类,包含算法的实现。 head 和 tail 分别是 顶层的头和尾。
001
package skiplist;
002 003
import java.util.*;
004 005
public class SkipList {
006
public SkipListEntry head; // 顶层的第一个元素
007
public SkipListEntry tail; // 顶层的最后一个元素
008 009
public int n; // 跳跃表中的元素个数
010 011
public int h; // 跳跃表的高度
012
public Random r; // 投掷硬币
013 014
public SkipList() // 默认构造函数...
015
{
016
SkipListEntry p1, p2;
017 018
p1 = new SkipListEntry(SkipListEntry.negInf, null);
019
p2 = new SkipListEntry(SkipListEntry.posInf, null);
020 021
head = p1;
022
tail = p2;
023 024
p1.right = p2;
025
p2.left = p1;
026 027
n = 0;
028
h = 0;
029
r = new Random();
030
}
031 032
/** 返回 包含的元素个数 */
033
public int size() {
034
return n;
035
}
036 037
/** 跳跃表是否为空 */
038
public boolean isEmpty() {
039
return (n == 0);
040
}
041 042
//在最下面一层,找到要插入的位置前面的那个key
043
public SkipListEntry findEntry(String k) {
044
SkipListEntry p;
045
p = head;
046 047
while (true) {
048
/**
049
* 一直向右找,例: k=34.
050
* 10 ---> 20 ---> 30 ---> 40 ^ | p 会在30处停止
051
* --------------------------------------------
052
***/
053
while (p.right.key != SkipListEntry.posInf
054
&& p.right.key.compareTo(k) <= 0) {
055
p = p.right;
056
// System.out.println(">>>> " + p.key);
057
}
058
// 如果还有下一层,就到下一层继续查找
059
if (p.down != null) {
060
p = p.down;
061
//System.out.println("vvvv " + p.key);
062
} else
063
break; // 到了最下面一层 就停止查找
064
}
065 066
return (p); // p.key <= k
067
}
068 069
/** 返回和key绑定的值 */
070
public Integer get(String k) {
071
SkipListEntry p;
072 073
p = findEntry(k);
074 075
if (k.equals(p.getKey()))
076
return (p.value);
077
else
078
return (null);
079
}
080 081
/** 放一个key-value到跳跃表中, 替换原有的并返回 */
082
public Integer put(String k, Integer v) {
083
SkipListEntry p, q;
084
int i;
085 086
p = findEntry(k);
087 088
if (k.equals(p.getKey())) {
089
Integer old = p.value;
090
p.value = v;
091
return (old);
092
}
093 094
q = new SkipListEntry(k, v);
095
q.left = p;
096
q.right = p.right;
097
p.right.left = q;
098
p.right = q;
099 100
i = 0; // 当前层 level = 0
101 102
while (r.nextDouble() < 0.5) {
103 104
//如果超出了高度,需要重新建一个顶层
105
if (i >= h) {
106
SkipListEntry p1, p2;
107 108
h = h + 1;
109
p1 = new SkipListEntry(SkipListEntry.negInf, null);
110
p2 = new SkipListEntry(SkipListEntry.posInf, null);
111 112
p1.right = p2;
113
p1.down = head;
114 115
p2.left = p1;
116
p2.down = tail;
117 118
head.up = p1;
119
tail.up = p2;
120 121
head = p1;
122
tail = p2;
123
}
124 125
while (p.up == null) {
126
p = p.left;
127
}
128
p = p.up;
129 130
SkipListEntry e;
131 132
e = new SkipListEntry(k, null);
133
e.left = p;
134
e.right = p.right;
135
e.down = q;
136 137
p.right.left = e;
138
p.right = e;
139
q.up = e;
140 141
q = e; // q 进行下一层迭代
142
i = i + 1; // 当前层 +1
143 144
}
145
n = n + 1;
146 147
return (null); // No old value
148
}
149 150
public Integer remove(String key) {
151
return (null);
152
}
153 154
public void printHorizontal() {
155
String s = "";
156
int i;
157
SkipListEntry p;
158 159
p = head;
160 161
while (p.down != null) {
162
p = p.down;
163
}
164 165
i = 0;
166
while (p != null) {
167
p.pos = i++;
168
p = p.right;
169
}
170 171
p = head;
172
while (p != null) {
173
s = getOneRow(p);
174
System.out.println(s);
175 176
p = p.down;
177
}
178
}
179 180
//用了打印测试
181
public String getOneRow(SkipListEntry p) {
182
String s;
183
int a, b, i;
184 185
a = 0;
186 187
s = "" + p.key;
188
p = p.right;
189 190
while (p != null) {
191
SkipListEntry q;
192 193
q = p;
194
while (q.down != null)
195
q = q.down;
196
b = q.pos;
197 198
s = s + " <-";
199 200
for (i = a + 1; i < b; i++)
201
s = s + "--------";
202 203
s = s + "> " + p.key;
204 205
a = b;
206 207
p = p.right;
208
}
209 210
return (s);
211
}
212 213
//用了打印测试
214
public void printVertical() {
215
String s = "";
216
SkipListEntry p;
217
p = head;
218
while (p.down != null)
219
p = p.down;
220 221
while (p != null) {
222
s = getOneColumn(p);
223
System.out.println(s);
224 225
p = p.right;
226
}
227
}
228
//用了打印测试
229
public String getOneColumn(SkipListEntry p) {
230
String s = "";
231
while (p != null) {
232
s = s + " " + p.key;
233
p = p.up;
234
}
235
return (s);
236
}
237
} 测试类,Test.java
01
package skiplist;
02 03
public class Test1 {
04
public static void main(String[] args) {
05
SkipList S = new SkipList();
06 07
S.printHorizontal();
08
System.out.println("------");
09
// S.printVertical();
10
// System.out.println("======");
11 12
S.put("ABC", 123);
13
S.printHorizontal();
14
System.out.println("------");
15
// S.printVertical();
16
//System.out.println("======");
17 18
S.put("DEF", 123);
19
S.printHorizontal();
20
System.out.println("------");
21
// S.printVertical();
22
// System.out.println("======");
23 24
S.put("KLM", 123);
25
S.printHorizontal();
26
System.out.println("------");
27
// S.printVertical();
28
// System.out.println("======");
29 30
S.put("HIJ", 123);
31
S.printHorizontal();
32
System.out.println("------");
33
// S.printVertical();
34
// System.out.println("======");
35 36
S.put("GHJ", 123);
37
S.printHorizontal();
38
System.out.println("------");
39
// S.printVertical();
40
// System.out.println("======");
41 42
S.put("AAA", 123);
43
S.printHorizontal();
44
System.out.println("------");
45
// S.printVertical();
46
// System.out.println("======");
47 48
}
49
} 输出结果:
01
-oo <-> +oo
02
------
03
-oo <-> ABC <-> +oo
04
-oo <-> ABC <-> +oo
05
------
06
-oo <-> ABC <---------> +oo
07
-oo <-> ABC <-> DEF <-> +oo
08
------
09
-oo <-> ABC <---------> KLM <-> +oo
10
-oo <-> ABC <-> DEF <-> KLM <-> +oo
11
------
12
-oo <-----------------> HIJ <---------> +oo
13
-oo <-> ABC <---------> HIJ <-> KLM <-> +oo
14
-oo <-> ABC <-> DEF <-> HIJ <-> KLM <-> +oo
15
------
16
-oo <-------------------------> HIJ <---------> +oo
17
-oo <-> ABC <-----------------> HIJ <-> KLM <-> +oo
18
-oo <-> ABC <-> DEF <-> GHJ <-> HIJ <-> KLM <-> +oo
19
------
20
-oo <---------------------------------> HIJ <---------> +oo
21
-oo <---------> ABC <-----------------> HIJ <-> KLM <-> +oo
22
-oo <-> AAA <-> ABC <-> DEF <-> GHJ <-> HIJ <-> KLM <-> +oo
23
------ 每次运行的结果是不一样的,这就是为什么说跳跃表是属于随机化数据结构。 代码参考:Implementing the skip list data structure

JAVA SkipList 跳表 的原理和使用例子的更多相关文章

  1. skiplist(跳表)的原理及JAVA实现

    前记 最近在看Redis,之间就尝试用sortedSet用在实现排行榜的项目,那么sortedSet底层是什么结构呢? "Redis sorted set的内部使用HashMap和跳跃表(S ...

  2. skiplist 跳表(2)-----细心学习

    快速了解skiplist请看:skiplist 跳表(1) http://blog.sina.com.cn/s/blog_693f08470101n2lv.html 本周我要介绍的数据结构,是我非常非 ...

  3. skiplist 跳表(1)

    最近学习中遇到一种新的数据结构,很实用,搬过来学习. 原文地址:skiplist 跳表   为什么选择跳表 目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等. ...

  4. SkipList跳表基本原理

    为什么选择跳表 目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等. 想象一下,给你一张草稿纸,一只笔,一个编辑器,你能立即实现一颗红黑树,或者AVL树 出来吗 ...

  5. SkipList跳表(一)基本原理

    一直听说跳表这个数据结构,说要学一下的,懒癌犯了,是该治治了 为什么选择跳表 目前经常使用的平衡数据结构有:B树.红黑树,AVL树,Splay Tree(这个树好像还没有听说过),Treep(也没有听 ...

  6. 【转】SkipList跳表基本原理

    增加了向前指针的链表叫作跳表.跳表全称叫做跳跃表,简称跳表.跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表.跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找.跳表不仅 ...

  7. 利用skipList(跳表)来实现排序(待补充)

    用于排名的数据结构 一般排序为利用堆排序(二叉树)和利用skipList(跳表)的方式 redis中SortedSet利用skipList(跳表)来实现排序,复杂度为O(logn),利用空间换时间,类 ...

  8. skip-list(跳表)原理及C++代码实现

    跳表是一个很有意思的数据结构,它实现简单,但是性能又可以和平衡二叉搜索树差不多. 据MIT公开课上教授的讲解,它的想法和纽约地铁有异曲同工之妙,简而言之就是不断地增加“快线”,从而降低时间复杂度. 当 ...

  9. SkipList 跳表

    1.定义描述      跳跃列表(也称跳表)是一种随机化数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间).      基本上,跳跃列表是对有序的链表增加 ...

随机推荐

  1. 非对称算法,散列(Hash)以及证书的那些事

    转载请注明出处 http://blog.csdn.net/pony_maggie/article/details/35389657 作者:小马 这几个概念在金融电子支付领域用得比較多,我忽然认为把它们 ...

  2. 有關AWS EC2 (EBS 收費)的問題

    有關AWS EC2 (EBS 收費)的問題 之前一陣子的時候,公司在使用Amazone Web Service (AWS)的 EC2 (Amazon Elastic Compute Cloud).不過 ...

  3. windows防火墙开放zabbix端口(批处理)

    windows系统在防火墙开启的情况下,打开zabbix端口(10050与10051) 可以手动添加规则,也可以使用批处理生成. 一.下面先介绍批处理 netsh advfirewall firewa ...

  4. centos7.2 64位安装java

    1.  wget http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk- ...

  5. CISP/CISA 每日一题 18

    CISSP 每日一题(答)What is the purpose of an access review and audit? Checkto ensure that users do not hav ...

  6. 洛谷 P4779【模板】单源最短路径(标准版)

    洛谷 P4779[模板]单源最短路径(标准版) 题目背景 2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路. 然后呢? 10 ...

  7. Activity学习

    http://www.360doc.com/content/13/1106/11/203871_327110236.shtml http://www.jianshu.com/p/e6971e8a8da ...

  8. LayoutAnimation-容器动画

    1.LayoutAnimation的作用主要就是加载到一个layout上,让这个layout里面的所有控件都有相同的动画效果.现在用到的是在listview中添加动画,使得它每一个item都是滑落显示 ...

  9. eclipse- log 打印跟输出到文件

    1.在eclipse中打印log,经常使用的就是log.e(string,string) 代码中如下 @Override public boolean onTouchEvent(MotionEvent ...

  10. ontouch-控件添加ontouch监听事件

    1,代码public class CalculatorViewPager extends ViewPager {}中 package com.android.calculator2; import a ...