微信公众号:算法面试题
扫码开启算法之旅
总结:
跳表具有如下性质:
(1) 由很多层结构组成
(2) 每一层都是一个有序的链表
(3) 最底层(第0层)的链表包含所有元素
(4) 如果一个元素出现在第i层中,则它在第0到第i-1层也都会出现
(5) 跳表是一种随机化的数据结构(通过掷硬币的过程可以看出)
点评:跳表是一种应用广泛的数据结构,著名的Redis与LevelDB系统的源码中,均可看到跳表的踪影。
代码实现
下面是作者用JavaScript实现的一个跳表,包括查找、插入和删除操作。
1//定义跳表结点
2function Node(key, value) {
3 this.key = key;
4 this.value = value;
5 //next指针数组
6 //此元素跨越多少层,next数组就含有多少指向下一结点的指针
7 this.next = [];
8}
9
10//跳表
11class SkipList {
12 constructor() {
13 //头结点不存值
14 this.head = new Node(undefined, undefined);
15 //初始时,跳表层数为0
16 this.level = 0;
17 //初始时,跳表含有0个元素
18 this.size = 0;
19 }
20
21 //查找操作,通过key获取值
22 get(key) {
23 let p = this.head;
24 for(let i = this.level - 1; i >= 0; i--) {
25 while(p.next[i] && p.next[i].key <= key) p = p.next[i];
26 if(p.key == key) return p.value;
27 }
28 return undefined;
29 }
30
31 //插入操作,插入一个键值对
32 set(key, value) {
33 let p = this.head;
34 //update用于记录每层拐点
35 let update = new Array(this.level);
36 for(let i = this.level - 1; i >= 0; i--) {
37 while(p.next[i] && p.next[i].key <= key) p = p.next[i];
38 if(p.key == key) {
39 p.value = value;
40 return this;
41 }
42 update[i] = p;
43 }
44 let newNode = new Node(key, value);
45 //k代表新插入结点跨越层数
46 let k = 1;
47 //模拟抛硬币过程
48 while(Math.random() < 0.5) k++;
49
50 if(k > this.level) {
51 for(let i = this.level; i < k; i++) {
52 newNode.next[i] = null;
53 this.head.next[i] = newNode;
54 }
55 this.level = k;
56 k = update.length;
57 }
58
59 for(let i = k - 1; i >= 0; i--) {
60 newNode.next[i] = update[i].next[i];
61 update[i].next[i] = newNode;
62 }
63
64 this.size++;
65 return this;
66 }
67
68 //删除一个键值对
69 delete(key) {
70 let p = this.head;
71 //update用于记录每层拐点
72 let update = new Array(this.level);
73 for(let i = this.level - 1; i >= 0; i--) {
74 while(p.next[i] && p.next[i].key < key) p = p.next[i];
75 update[i] = p;
76 }
77 if(p.next[0] && p.next[0].key == key) {
78 let deleteNode = p.next[0];
79 for(let i = deleteNode.next.length - 1; i >= 0; i--) {
80 update[i].next[i] = deleteNode.next[i];
81 deleteNode.next[i] = null;
82 if(this.head.next[i] == null) {
83 this.level--;
84 }
85 }
86 this.head.next.length = this.level;
87 this.size--;
88 return true;
89 }
90 return false;
91 }
92}