跳跃表C语言实现
Posted rongyongfeikai2
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跳跃表C语言实现相关的知识,希望对你有一定的参考价值。
我们都知道,链表的好处是插入和删除方便,但是遍历则比较慢。如果要找到链表最末尾的元素,那么需要查找时间复杂度是O(n)。
跳跃表就是为了解决这个问题而提出,跳跃表可以理解为在链表的基础上加上了多级索引。
为了保证插入的均衡以及查询的速率,跳跃表的新节点插入时,会计算一个随机的层数(不大于最大层数)。然后从该层逐步向最底层插入,当该层没有元素时,那么这个新的节点就是第一个元素。而如果该层已经有元素时,则在插入时会保证该层的全体元素整体有序。
插入的代码如下(其中MAXLEVEL是跳表的最大层数):
//在跳表内插入记录
void insert(SkipList *skipList, int key, int val) {
Node *update[MAXLEVEL];
int i=0;
for(i=0;i<MAXLEVEL;i++){
update[i] = skipList->header;
}
int curLevel = getRandomLevel();
Node *node = (Node*)malloc(sizeof(Node));
node->level = curLevel;
node->key = key;
node->val = val;
for(i=0;i<MAXLEVEL;i++){
node->next[i] = NULL;
}
for(i = curLevel - 1;i>=0;i--){
if(update[i]->next[i] == NULL){
update[i]->next[i] = node;
}else{
//找到一个链表当前层最后的,且小于它的
Node *p = update[i];
while(p->next[i] != NULL && p->next[i]->key < key) {
p = p->next[i];
}
node->next[i] = p->next[i];
p->next[i] = node;
}
}
if(curLevel > skipList->level) {
skipList->level = curLevel;
}
}
具体演示一下插入过程(假设定义的跳表最大层数为2),插入的第一个元素是key:5,val:5(随机出的5的层数是2):
因为每一层都没有其他元素,所以每一层的指针都是指向元素5。
插入的第二个元素是key:2val:2(随机出的2的层数是2):
因为2是小于5的,所以它在header指针之后,而在5元素之前。
插入的第三个元素是key:3val:3(随机出的3的层数是1):
插入的第四个元素是key:4val:4(随机出的4的层数是1):
接下来看查找过程,从最顶层开始向下查找。当找到当前层最后一个小于等于待查找值的元素,如果元素的值已经等于待查找值了,直接返回即可;如果仅仅只是小于,那么就从这个元素的指针继续向下层查找。
查找代码如下:
//在跳表里查找记录
int find(SkipList *skipList, int key) {
Node *p = skipList->header;
for(int i=skipList->level-1;i>=0;i--){
while(p->next[i] != NULL && p->next[i]->key <= key) {
if(p->next[i]->key == key){
printf("level %d:%d", i, p->next[i]->key);
}else{
printf("level %d:%d -> ", i, p->next[i]->key);
}
p = p->next[i];
}
if(p->key == key){
printf("\\n");
return p->val;
}
}
return -1;
}
例如查找4:
第二层只找到小于它的最后一个元素2,接着的5就已经比它大了。那么就由2的指针,继续到第一层找,那么就可以找到4。
如果是普通链表,找到4需要比对4次,而这里只用比对3次。
再看看查找5,由于第二层已经可以直接找到它了,那么实际上只比对了2次 。
可以看到,跳跃表的查找性能相比于普通链表已经有了很大提升。所以,它属于一种用空间来换时间的算法。
完整代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAXLEVEL 2
typedef struct node{
int key;
int val;
struct node *next[MAXLEVEL];
int level;
}Node;
typedef struct {
int level;
Node *header;
}SkipList;
int getRandomLevel() {
return rand()%MAXLEVEL+1;
}
//在跳表内插入记录
void insert(SkipList *skipList, int key, int val) {
Node *update[MAXLEVEL];
int i=0;
for(i=0;i<MAXLEVEL;i++){
update[i] = skipList->header;
}
int curLevel = getRandomLevel();
Node *node = (Node*)malloc(sizeof(Node));
node->level = curLevel;
node->key = key;
node->val = val;
for(i=0;i<MAXLEVEL;i++){
node->next[i] = NULL;
}
for(i = curLevel - 1;i>=0;i--){
if(update[i]->next[i] == NULL){
update[i]->next[i] = node;
}else{
//找到一个链表当前层最后的,且小于它的
Node *p = update[i];
while(p->next[i] != NULL && p->next[i]->key < key) {
p = p->next[i];
}
node->next[i] = p->next[i];
p->next[i] = node;
}
}
if(curLevel > skipList->level) {
skipList->level = curLevel;
}
}
//在跳表里查找记录
int find(SkipList *skipList, int key) {
Node *p = skipList->header;
for(int i=skipList->level-1;i>=0;i--){
while(p->next[i] != NULL && p->next[i]->key <= key) {
if(p->next[i]->key == key){
printf("level %d:%d", i, p->next[i]->key);
}else{
printf("level %d:%d -> ", i, p->next[i]->key);
}
p = p->next[i];
}
if(p->key == key){
printf("\\n");
return p->val;
}
}
return -1;
}
//展示跳表构造
void display(SkipList *skipList) {
int i;
for(i=skipList->level-1;i>=0;i--){
printf("level %d : ", i);
Node *p = skipList->header->next[i];
while(p != NULL){
printf("%d ", p->key);
p = p->next[i];
}
printf("\\n");
}
}
int main() {
//初始化,跳表头指针
SkipList *skipList = (SkipList*)malloc(sizeof(SkipList));
skipList->level = 0;
Node header;
header.key = INT_MIN;
header.val = INT_MIN;
int i=0;
for(i=0;i<MAXLEVEL;i++){
header.next[i] = NULL;
}
skipList->header = &header;
insert(skipList, 5, 5);
printf("\\n");
printf("insert 5 5 \\n");
display(skipList);
insert(skipList, 2, 2);
printf("\\n");
printf("insert 2 2 \\n");
display(skipList);
insert(skipList, 3, 3);
printf("\\n");
printf("insert 3 3 \\n");
display(skipList);
insert(skipList, 4, 4);
printf("\\n");
printf("insert 4 4 \\n");
display(skipList);
printf("\\n");
printf("find val:%d\\n", find(skipList,4));
printf("find val:%d\\n", find(skipList,5));
free(skipList);
return 1;
}
以上是关于跳跃表C语言实现的主要内容,如果未能解决你的问题,请参考以下文章