范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

让你的代码更加优雅的编程技巧跳转表

  跳表比较好理解,但是实际用代码来表示,还是有点复杂的。
  实现的方法不唯一 1. 什么是跳表
  跳表是 链表 + 索引 的一种数据结构 ,是以空间换取时间的方式,关于跳表参考: https://baike.baidu.com/item/跳表/22819833?fr=aladdin2. 跳表概念
  跳表在原有链表的基础上,增加索引,从而可以进行二分查找,提高搜寻效率。
  原始链表Head ——> 1 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL
  新增了索引的链表(跳表)Head2 ————————> 8 ———————————————————————> NULL  Head1 ————————> 8 —————————> 23 —————————> NULL  Head0 ——> 1 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL
  Head0 , Head1 , Head2 上都是真实的节点,这就是以空间换取时间
  例如算上Head, 元素数据一共有 6 个,而添加索引后,元素一共有 11 个3. 跳表增删查规则
  3.1 跳表数据节点
  数据节点可以和链表节点一致 ,也可以定义如下节点,除了数据外,有指针指向 前一个/后一个/上一个/下一个 节点,以便后续查找操作。typedef struct {         int data;         struct Node *next; // 后一个节点         struct Node *last; // 前一个节点         struct Node *up; // 上一个节点         struct Node *down; // 下一个节点 } Node;
  3.2 跳表初始化
  当跳表有多少层的时候,应当建立多少个头结点,例如: 跳表为3层Head2 ——> NULL Head1 ——> NULL Head0 ——> NULL 3.3 查找
  删除/新增 都会进行查询才操作,无非是删除/新增索引而已。
  例如有如下数据Head2 —————————————————————> 23 —————————> NULL  Head1 ————————> 8 —————————> 23 —————————> NULL  Head0 ——> 1 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL
  要查找 13这个节点
  去除无效层
  例如: Head2 后面第一个节点的数据 23 , 而 23 大于 13 , 所以 Head2 没有数据匹配查询,故需要跳到下面一层,至 Head1 上进行查询。
  查询至Head0层
  去除无效层后数据进入了 Head1 , 在Head1上进行匹配,当匹配到 23 时,23大于13,将23标记为 查询结束点,对23的上一个节点 8 进行 向下指针操作,进入 Head0层的8节点。
  查找实际数据
  从Head0层的8 进行查找,直至 查询结束标记点(head1 23), 查询的数据分别为 8 , 12 ,23 查询结束,未找到数据。
  嵌入式物联网需要学的东西真的非常多,千万不要学错了路线和内容,导致工资要不上去!
  无偿分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!某鱼上买估计至少要好几十。
  点击这里找小助理0元领取:嵌入式物联网学习资料(头条)
  3.4 新增
  新增操作需要记录索引寻址过程,以便后续新增索引。
  头结点插入
  头结点插入一定是 去除无效层 至Head0 , 且 Head0的第一个节点都比插入节点要大的情况下
  例如:
  如下跳表,插入 2Head2 —————————————————————> 23 —————————> NULL  Head1 ————————> 8 —————————> 23 —————————> NULL  Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL
  尾结点插入
  头结点插入一定是 去除无效层 至Head0 , 且 Head0的第一个节点都比插入节点要小,直至NULL节点的情况下
  例如:
  如下跳表,插入 65Head2 —————————————————————> 23 —————————> NULL  Head1 ————————> 8 —————————> 23 —————————> NULL  Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL
  中间节点插入
  除开以上2种情况,其余情况为 中间节点插入
  新增索引
  抛硬币的方法,当数据量达到一定规模的时候,一定是趋近于 50%的。
  所以跳表会越来越趋向于如下形式    3     3       7 1   3   5   7   9 1 2 3 4 5 6 7 8 9
  判断是否需要新增索引,采取抛硬币的方法来判断,即: 随机数 取余 为 0 则需要新增,否则不需要。
  例如如下跳表,插入 65Head2 —————————————————————> 23 —————————> NULL  Head1 ————————> 8 —————————> 23 —————————> NULL  Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL
  寻址应该为
  Head2: 23
  Head1: 23
  元素数据插入后为Head2 —————————————————————> 23 ———————————————> NULL  Head1 ————————> 8 —————————> 23 ———————————————> NULL  Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> 65 —> NULL
  当插入65节点后,若判断需要索引的时候,则先为 Head1 添加索引,添加位置为 寻址地址之后,寄 Head1: 23Head2 —————————————————————> 23 ———————————————> NULL  Head1 ————————> 8 —————————> 23 —————————> 65 —> NULL  Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> 65 —> NULL
  继续判断,若不需要添加索引,则插入结束
  若还需要添加索引,则继续上述操作,直至 索引层 达到最高层
  3.5 删除
  删除首先是查找操作【3.3 查找】
  若未找到该节点,则删除失败
  若找到了该节点,则应当提到该数据最高索引层,再从高到低删除
  例如:
  如下跳表,删除 23Head2 —————————————————————> 23 ———————————————> NULL  Head1 ————————> 8 —————————> 23 —————————> 65 —> NULL  Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> 65 —> NULL
  找到 Head0 23 后,应该向上找到 Head2 23 ,然后从高向低删除,若删除后,该索引没有数据了,则索引层减1
  则删除Head2 23 后数据如下Head1 ————————> 8 —————————> 23 —————————> 65 —> NULL  Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> 65 —> NULL
  删除Head1 23 后数据如下Head1 ————————> 8 ———————————————————————> 65 —> NULL  Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> 65 —> NULL
  删除Head0 23后数据如下Head1 ————————> 8 ————————————————> 65 —> NULL  Head0 ——> 3 ——> 8 ——> 12 ——> 55 ——> 65 —> NULL  4. 代码
  skipList.c# include  # include  # include   int MaxLevel = 8; // 最大层数 int currLevel = 0; // 当前层数  // 数据节点 typedef struct {         int data;         struct Node *next;         struct Node *last;         struct Node *up;         struct Node *down; } Node;  // 记录索引寻址过程 typedef struct {         int level;         struct Node *node; } skipStep;  // 判断是否需要新增索引, 抛硬币 bool randNum() {         if(0 == (rand() % 2))                 return true;          return false; }  // 新增节点 bool add(Node *SL[] , int data) {          printf("新增节点: %d ",data);         int level = currLevel;          Node *Head = NULL;         Node *tmp = NULL;         Node *last = NULL;          // 初始化索引 数据为 Head 地址         skipStep steps[MaxLevel];         int i;         for (i=0;inext;          while ((level > 0) && (data < tmp->data)) {                 level--;                 Head = SL[level];                 tmp = Head->next;         }          // 根据索引寻找Head0数据节点         while ((level > 0)) {                  while (tmp != NULL) {                         if (data < tmp->data) {                                 steps[level].level = level;                                 if (NULL != last)                                          steps[level].node = last;                                 tmp = last->down;                                 level--;                                 break;                         }                          last = tmp;                         tmp = tmp->next;                 }                 if (NULL == tmp) {                         steps[level].level = level;                         if (NULL != last)                                  steps[level].node = last;                         tmp = last->down;                         level--;                  }         }          // Head0 数据合适的节点         while (tmp != NULL) {                 if (data < tmp->data) {                         break;                 }                 last = tmp;                 tmp = tmp->next;         }          // 新增节点         Node *newData = (Node *)malloc(sizeof(Node));         newData->data = data;         newData->up = NULL;         newData->down = NULL;         newData->last = NULL;         newData->next = NULL;          int k = 0;          // Head0 插入原始数据         if (NULL == last ) {                 // 头结点                  Head = SL[0];                 Node *headNext = Head->next;                 if (NULL != headNext) {                         newData->next = headNext;                         headNext->last = newData;                          newData->last = Head;                   }                   Head->next = newData;                 newData->last = Head;           } else if ( NULL == tmp) {                 // 尾节点                 last->next = newData;                 newData->last = last;           } else {                 // 中间节点                 newData->next = tmp;                 tmp->last = newData;                  newData->last = last;                 last->next = newData;         }          // 构建索引         while (randNum()) {                 k++;                 if (k >= MaxLevel) break;                  // 新增索引数据                 Node *newIndex = (Node *)malloc(sizeof(Node));                 newIndex->data = data;                 newIndex->up = NULL;                 newIndex->down = NULL;                 newIndex->next = NULL;                 newIndex->last = NULL;                  // 建立上下级关系                 newIndex->down = newData;                 newData->up = newIndex;                  Node *node = steps[k].node;                  // node->next                 Node *nextIndex = node->next;                   node->next = newIndex;                 newIndex->last = node;                  newIndex->next = nextIndex;                 if (NULL != nextIndex)                          nextIndex->last = newIndex;                  newData = newIndex;                  // 判断是否需要新增索引层数                 if (k > currLevel)                          currLevel = k;         } }   // 初始化头结点 Node *initSkipList(Node *skipList[]) {         int i;         for (i=0;idata = -1-i;                 newHead->down = NULL;                 newHead->up = NULL;                 newHead->next = NULL;                 newHead->last = NULL;                  skipList[i] = newHead;           }         return skipList; }  // 打印跳表数据 void PrintSkipList(Node *SL[]) {         if (NULL == SL) {                 return;         };          int level = currLevel;         //int level = MaxLevel;          int i;         for (i=level;i>=0;i--) {                 Node *Head = SL[i];                  Node *tmp = Head->next;                 printf("第%d层		",i);                 while (NULL != tmp) {                         printf(" %d	",tmp->data);                          tmp = tmp->next;                 }                 printf(" ");         } }  // 查询数据 Node *query(Node *SL[] , int data) {         printf("查询数据: %d ",data);          int level = currLevel;          Node *Head = NULL;         Node *tmp = NULL;         Node *last = NULL;          Head = SL[level];         tmp = Head->next;         int endQuery = -1;          // 筛除无效层         while ((level > 0) && (data < tmp->data)) {                 level--;                 endQuery = tmp->data;                 Head = SL[level];                 tmp = Head->next;         }          // 根据索引定位到Head0层         while ((level > 0 )) {                  while (tmp != NULL) {                         if (data < (tmp->data)) {                                 level--;                                 endQuery = tmp->data;                                 tmp = last->down;                                 break;                         }                          last = tmp;                         tmp = tmp->next;                 }                 if (NULL == tmp) {                         tmp = last->down;                         endQuery = -1;                         level--;                 }          }          // 查询实际数据         while (NULL != tmp) {                 if (endQuery != -1)                         if (tmp->data > endQuery) {                                         tmp = NULL;                                         break;                         }                 if (tmp->data == data) {                         break;                 }                 tmp = tmp->next;         }         // 返回查询的数据节点,若没有查询到,应当返回NULL ,否则返回实际的地址         return tmp; }  // 删除数据 bool del(Node *SL[],int data) {         printf("删除数据: %d ",data);          // 找到节点地址         Node *tmp = query(SL,data);          if (NULL == tmp) {                 printf("未找到节点,删除失败 ");                 return false;         }         int level = 0;         Node *t_last = NULL;         Node *t_next = NULL;           // 找到该数据最高索引         while (NULL != tmp->up) {                 level++;                 tmp = tmp->up;         }          // 由上至下删除索引/数据         while (tmp != NULL) {                 t_last = tmp->last;                 t_next = tmp->next;                  Node *t_down = tmp->down;                  if (t_last == NULL) {                         printf("上一个节点不可能为空,删除失败,层数: %d ",level);                         return false;                 }                  t_last->next = t_next;                  if (NULL != t_next)                         t_next->last = t_last;                 else                         t_last->next = NULL;                  if ((t_last == SL[level]) && (NULL == t_next)) {                         currLevel--;                  }                 free(tmp);                  tmp = t_down;                 level--;         }          return true;   }  int main() {          Node *SL[MaxLevel];          Node *skipList = initSkipList(SL);         if (NULL == SL) {                 printf("skipList 申请失败 ");                 return -1;         }          // 测试新增         int num[] = {1,3,2,10,8,9,22,30,29,120,99,78,55,76,21};         int i;         for (i=0;i
广州新规!二孩以上家庭,公积金房贷有调整12月9日,16届24次市政府常务会议审议通过了广州市人口与计划生育服务规定(简称规定),规定明确提出通过完善住房财政教育金融人才就业等支持政策,促进人口长期均衡发展,优化生育服务英联杯曼联VS伯恩利球队近况分析曼联本赛季变化不小,目前八胜两平四负的战绩,位列联赛第五位。滕哈赫入主之后是将他在阿贾克斯的执教理念搬了过来,虽然阿贾克斯在联赛中也是一支崇尚进攻且充满压迫性的球队,但曼彻斯特联VS伯恩利曼联曼联本赛季战绩不佳,目前排名第五,距离热刺只有三分之遥,C罗也离开了球队,而卡塞米罗马丁内斯埃里克森等球队也都是球队的主力,所以他们必须要拿到欧战区。在过去的两次热身赛中,他们英联杯纽卡斯尔伯恩茅斯纽卡斯尔伯恩茅斯纽卡斯尔本赛季表现相当出色,凭借8胜6平1负的战绩,拿到30分暂列联赛第3的位置,目前也仅落后榜首阿森纳7分。纽卡斯尔联进攻端表现出色防守也相当稳固,是目前英超联赛纽卡斯尔联VS伯恩茅斯这个赛季,纽卡的崛起和球队的不懈努力最终获得了成功。他们在15场联赛中的战绩是8胜6平1败。他们在联赛中打入29个进球,11个失球,目前积分榜上位列第3。纽卡斯尔最近没有什么大的赛英联赛杯,纽卡斯尔联VS伯恩茅斯英联赛杯,纽卡斯尔联VS伯恩茅斯英联杯从196061赛季举办,到今年已经进行了62届,因为201617赛季开始卡拉宝(功能饮料)的赞助,所以这杯赛现在也叫卡拉宝杯。英联杯的参赛队伍英联杯纽卡斯尔联VS伯恩茅斯除了夏季前锋艾萨克(3场2球)长期因伤缺阵外,边锋圣马克西曼(8场1球3助攻)和中场乔乔林顿(15场1球1助攻)也在世界杯友谊赛中受伤下场。前者小腿有问题,后者腿筋拉伤,能否参加比英联杯情报南安普敦新帅主场首秀,林肯城主力阵容齐整沃克皮特斯归队,一名后卫缺席南安普敦右卫沃克皮特斯(本赛季11场比赛都是首发出场),英国媒体报导说,这场比赛他将会在这场比赛中恢复。另外,拉里奥斯(本赛季5场2次首发)也会在这场比库兹马女友又来了!露一身白斑,NBA最另类花魁,拥抱奇才巨星NBA常规赛,奇才113110险胜太阳,终于结束了球队的10连败,此役,奇才当家球星库兹马发挥出色,他拿到29分6篮板6助攻,此外队友比尔也有不错的数据,27分6篮板6助攻,不得不在鸿蒙智能座舱上,窥见智能汽车的下半场世界上本没有座舱。100多年前当卡尔本茨制造出世界上第一辆汽车时,别说舱了,连顶篷都没有,座椅发动机等部件全部暴露在外面,所谓的座舱,大概就是一把椅子。当然,在人们对汽车的要求不再16连败!成为CBA唯一没有获胜的球队,网友滚出CBA宁波队输给深圳队11分,遭到16连败CBA常规赛第16轮,宁波队与深圳队的比赛,双方经过四节比拼,最终,深圳队依靠末节比赛发力,以10190赢了宁波队11分。如此一来,深圳队收获了
经开区举办首届幼儿园保健医技能大赛2023年1月9日至10日,经开区首次开展了保健医技能大赛活动。活动共65所幼儿园积极参与,经选拔及名校推荐,38名保健医脱颖而出,代表参加全区比赛活动。据了解,大赛活动聘请西安市平民玩家的赵云诸葛亮逆向增强,马忠专门打太尉吴枪马忠要全赛季登场了,SP关羽强度也非常高,赵云诸葛亮这两个老武将逆向增强,未来的出场率将会提升。游戏策划穿越三国之我是关羽,水淹七军威震华夏。游戏玩家穿越三国之我是马忠,抓关羽抓诸热门洗地机横评破除大牌迷信,添追美石谁是新王者?去年双十一清洁电器大战里,洗地机开始越来越多出现在消费者的购物车里。和所有新兴家电爆火的逻辑相似,大疫已三年让消费者更加关注家居清洁,国内因区别于国外的硬地板结构,让消费者对深度清别甩锅给施海荣!近几年江苏女排的人才培养方向错误早已埋祸根施海荣遭到了江苏球迷们的口诛笔伐一届饱受疫情影响的排超联赛终于尘埃落定,现在最郁闷的,无疑是江苏女排的球迷们从上届的亚军,一下子跌落到了第六名,换了是谁,心里都会不开心。浏览网上江曼联爆内讧,滕哈格欲撤马奎尔职!费迪南德怒骂这是狗屁决定!曼联最近的热闹可真不少,前几天刚刚传出C罗规则开始给队员限薪。现在又曝出新闻,主教练要取消马奎尔的队长资格。目前,支持者和反对者正在激烈争论,名宿费迪南德甚至直接对滕哈格大爆粗口。游戏党首发购入16GB新机,简单上手后,说说我的真实使用感受2023年已经到来,在新年伊始之际,许多人都会选择换一台崭新的手机开启新的一年,我也不例外。尤其是作为一名资深手游党,自原神更新大版本后,我的旧手机性能居然有些跟不上了,玩起来经常层林尽染寿乡枫景独美镇山公园内的红枫灿若红霞,展现出一派万木霜天红烂漫的绚丽景色。想要感受长潭枫叶的美丽,最好的方式就是乘坐游船。坐船穿行于长潭之中,仿佛置身于一幅色彩浓艳的油画中。满山的枫叶披上彩霞联想,在手机这块该多花点心思了经常混数码圈的,估计都知道这玩意。没错,就是ThinkPad上标志性的小红点,堪称机圈里最经典的设计之一。一开始ThinkPad上用的不是小红点,而是轨迹球。ThinkPad220iPhone14再翻车,灵动岛问题频发,小米11售后获人民网点赞iPhone14系列一出来就受到人们的热烈追捧,灵动岛是这次硬件上创新玩出的新花样,仅仅一个灵动岛,就让果粉玩的不亦乐乎。不过一个月后iPhone14Pro出现的问题还是不少,这也这8个隐藏极深的小米手机技巧,5年米粉都不一定全知道,超实用今天想和大家分享8个小米手机藏得极深的技巧,5年米粉都不一定全知道,学会这8招,让你的小米手机更好用!桌面无字模式有些朋友喜欢干净的手机页面,并不喜欢桌面图标的文字,其实我们可以让货拉拉SSL证书踩坑之旅一背景简介1遇到的问题2020年,货拉拉运营部门和客户端开发对齐了https网络通信协议中的SSL网络证书校验方案但是由于Android客户端的证书配置不规范,导致在客户端内置的S