跳跃表原理C语言实现

跳跃表和传统链表图示

  • 上图是传统链表,下图是跳跃表图示
  • 可以简单理解跳跃表是在传统顺序链表上通过给节点增加额外(随机个数)指针来做索引,
    其思想类似于折半查询的思想,其效率可以媲美红黑树。

跳跃表C语言实现

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
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#define MAX_L 10
typedef int typekey;
typedef int typevalue;
typedef struct Node
{
typekey key;
typevalue val;
int level;
struct Node * next[1];
} Node;
typedef struct Skiplist
{
int level;
Node * header;
} Skiplist;
int randomLevel()
{
int level=1;
while (rand()%2) {
level++;
}
level= (MAX_L > level) ? level : MAX_L;
return level;
}
Node * create_node(int level)
{
return (Node *)malloc(sizeof(Node) + (level -1)*sizeof(Node*));
}
Skiplist * create_skiplist()
{
int i;
Skiplist *p = (Skiplist *)malloc(sizeof(Skiplist));
p->level = 0;
p->header = create_node(MAX_L);
for (i = 0; i < MAX_L; i++) {
p->header->next[i] = NULL;
}
return p;
}
typevalue search(Skiplist *list, typekey key)
{
Node *q, *p = list->header;
for (int i = list->level - 1; i >= 0 ; --i) {
while ((q = p->next[i]) && q->key < key) {
p = q;
}
if (q && q->key == key) {
return q->val;
}
}
return NULL;
}
void insert(Skiplist * list, typekey key, typevalue val)
{
int level = randomLevel();
Node *pnode = NULL;
list->level = list->level < level ? level : list->level;
Node *q, *p = list->header;
for (int i = list->level - 1; i >= 0 ; --i) {
while ((q = p->next[i]) && q->key < key) {
p = q;
}
;注意可插入相同key的节点
if (i <= level -1) {
if (pnode == NULL) {
pnode = create_node(level);
pnode->key = key;
pnode->val = val;
pnode->level = level;
}
p->next[i] = pnode;
pnode->next[i] = q;
}
}
}
void delete_node(Skiplist *list, typekey key)
{
Node *q, *p = list->header;
Node *pnode = NULL;
;若有相同key一次只删除一个
for (int i = list->level - 1; i >= 0 ; --i) {
while ((q = p->next[i]) && q->key < key) {
p = q;
}
if (q == NULL && p == list->header) {
list->level--;
}
if (q && q->key == key) {
pnode = q;
p->next[i] = q->next[i];
}
}
if (pnode) {
free(pnode);
}
}
void delete_list(Skiplist *list)
{
Node *p = list->header;
while ((p = p->next[0])) {
free(p);
}
free(list->header);
free(list);
}
int main()
{
Skiplist *list = create_skiplist();
int i;
int key;
for (i = 0; i < 100; i++) {
key = rand() % 100 + 1;
insert(list, key, key);
printf("%d ", key);
}
printf("\n");
typevalue val;
char *s;
Node *p = list->header;
while ((p = p->next[0])) {
val = search(list, p->key);
s = val == p->val ? "OK" : "FAILED";
printf("search %s 0x%d val: %d level: %d", s, (int) p, p->val, p->level);
printf(" (");
for (int j = 0; j < p->level; ++j) {
printf("0x%d ", (int) (p->next[j]));
}
printf(")\n");
}
delete_list(list);
return 0;
}

检查内存溢出

1
2
gcc -Wall main.c -g -o test
valgrind --tool=memcheck --leak-check=full ./test