热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

跳跃表C语言实现

我们都知道,链表的好处是插入和删除方便,但是遍历则比较慢。如果要找到链表最末尾的元素,那么需要查找时间复杂度是O(n)。跳跃表就是为了解

我们都知道,链表的好处是插入和删除方便,但是遍历则比较慢。如果要找到链表最末尾的元素,那么需要查找时间复杂度是O(n)。

跳跃表就是为了解决这个问题而提出,跳跃表可以理解为在链表的基础上加上了多级索引。

为了保证插入的均衡以及查询的速率,跳跃表的新节点插入时,会计算一个随机的层数(不大于最大层数)。然后从该层逐步向最底层插入,当该层没有元素时,那么这个新的节点就是第一个元素。而如果该层已经有元素时,则在插入时会保证该层的全体元素整体有序。

插入的代码如下(其中MAXLEVEL是跳表的最大层数):

//在跳表内插入记录
void insert(SkipList *skipList, int key, int val) {Node *update[MAXLEVEL];int i=0;for(i=0;iheader;}int curLevel = getRandomLevel();Node *node = (Node*)malloc(sizeof(Node));node->level = curLevel;node->key = key;node->val = val;for(i=0;inext[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 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
#include
#include
#define MAXLEVEL 2typedef 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;iheader;}int curLevel = getRandomLevel();Node *node = (Node*)malloc(sizeof(Node));node->level = curLevel;node->key = key;node->val = val;for(i=0;inext[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 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;iheader = &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;
}

 


推荐阅读
  • 该楼层疑似违规已被系统折叠隐藏此楼查看此楼*madebyebhrz*#include#include#include#include#include#include#include ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 在Kubernetes上部署JupyterHub的步骤和实验依赖
    本文介绍了在Kubernetes上部署JupyterHub的步骤和实验所需的依赖,包括安装Docker和K8s,使用kubeadm进行安装,以及更新下载的镜像等。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • C语言自带的快排和二分查找
    Author🚹:CofCaiEmail✉️:cai.dongjunnexuslink.cnQQ😙:1664866311personalPage&#x ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 如何利用 Myflash 解析 binlog ?
    本文主要介绍了对Myflash的测试,从准备测试环境到利用Myflash解析binl ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 本文整理了Java中java.lang.NoSuchMethodError.getMessage()方法的一些代码示例,展示了NoSuchMethodErr ... [详细]
author-avatar
玄天战猫
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有