跳跃表
来源:互联网 发布:淘宝客关闭返利 编辑:程序博客网 时间:2024/05/16 17:59
跳跃表(skiplist)是非常优秀的数据结构,其插入,查询,删除的复杂度为O(logN),即使在最坏情况下为O(N),但最坏情况出现概率低。与skiplist的各种操作复杂度相当的数据结构还有大家熟知的AVL树,红黑树等,但跳跃表的实现比实现简单,想一想AVL树,红黑树的左旋右旋各种旋,不参考各种代码以及书籍不可能写出来。目前LevelDB的核心数据结构是用跳跃表实现的,redis的sorted set数据结构也是跳表实现的。
当我们使用链表存储有序数列时,查询操作的复杂度为O(N)。跳跃表是一种随机化的数据结构,能够有效解决有序链表查找特定值的困哪,其是典型的空间换时间。
构建有序链表:
构建跳跃表:
以下为redis的sorted set中关于跳跃表的代码:
skiplist.h
#ifndef __SKIPLIST_H#define __SKIPLIST_H#define SKIPLIST_MAXLEVEL 8 typedef struct skiplistNode { double score; struct skiplistNode *backward;//指向前继结点 struct skiplistLevel { struct skiplistNode *forward;//记录该结点在每一层的后继结点 }level[];}skiplistNode;typedef struct skiplist { struct skiplistNode *header, *tail; unsigned long length; int level;}skiplist;#endif
skiplist.c
#include "skiplist.h"#include <stdlib.h>#include <stdio.h>skiplistNode *slCreateNode(int level, double score) { skiplistNode * sn = malloc(sizeof(*sn) + level*sizeof(struct skiplistLevel)); sn->score = score; return sn;}skiplist *slCreate(void) { int j; skiplist *sl; sl = malloc(sizeof(*sl)); sl->level = 1; sl->length = 0; sl->header = slCreateNode(SKIPLIST_MAXLEVEL, 0); for(j = 0; j < SKIPLIST_MAXLEVEL; j++) { sl->header->level[j].forward = NULL; } sl->header->backward = NULL; sl->tail = NULL; return sl;}void slFreeNode(skiplistNode *sn) { free(sn);}void slFree(skiplist *sl) { skiplistNode *node = sl->header->level[0].forward, *next; free(sl->header); while(node) { next = node->level[0].forward; slFreeNode(node); node = next; } free(sl);}int slRandomLevel(void) {//加入随机性,计算插入值应该是在第几层 int level = 1; while((rand()&0xFFFF) < (0.5 * 0xFFFF)) level += 1; return (level < SKIPLIST_MAXLEVEL) ? level : SKIPLIST_MAXLEVEL;}skiplistNode *slInsert(skiplist *sl, double score) { skiplistNode *update[SKIPLIST_MAXLEVEL]; skiplistNode *node; node = sl->header; int i, level; for ( i = sl->level-1; i >= 0; i--) { while(node->level[i].forward && node->level[i].forward->score < score) { node = node->level[i].forward; } update[i] = node; } level = slRandomLevel(); if (level > sl->level) { for (i = sl->level; i< level ;i++) { update[i] = sl->header; } sl->level = level; } node = slCreateNode(level, score); for (i = 0; i < level; i++) { node->level[i].forward = update[i]->level[i].forward; update[i]->level[i].forward = node; } node->backward = (update[0] == sl->header? NULL : update[0]); if (node->level[0].forward) node->level[0].forward->backward = node; else sl->tail = node; sl->length++; return node;}void slDeleteNode(skiplist *sl, skiplistNode *x, skiplistNode **update){ int i; for (i = 0; i < sl->level; i++) { if (update[i]->level[i].forward == x) { update[i]->level[i].forward = x->level[i].forward; } } if (x->level[0].forward) { x->level[0].forward->backward = x->backward; } else { sl->tail = x->backward; } while (sl->level > 1 && sl->header->level[sl->level-1].forward == NULL) sl->level--; sl->length--;}int slDelete(skiplist *sl, double score) { skiplistNode *update[SKIPLIST_MAXLEVEL], *node; int i; node = sl->header; for(i = sl->level-1; i >= 0; i--) { while (node->level[i].forward && node->level[i].forward->score < score) { node = node->level[i].forward; } update[i] = node; } node = node->level[0].forward; if (node && score == node->score) { slDeleteNode(sl, node, update); slFreeNode(node); return 1; } else { return 0; } return 0;}int slSearch(skiplist *sl, double score) { skiplistNode *node; int i; node = sl->header; for (i = sl->level-1; i >= 0 ;i--) { while(node->level[i].forward && node->level[i].forward->score < score) { node = node->level[i].forward; } } node = node->level[0].forward; if (node && score == node->score) { printf("Found %d\n",(int)node->score); return 1; } else { printf("Not found %d\n", (int)score); return 0; }}void slPrint(skiplist *sl) { skiplistNode *node; int i; for (i = 0; i < SKIPLIST_MAXLEVEL; i++) { printf("LEVEL[%d]: ", i); node = sl->header->level[i].forward; while(node) { printf("%d -> ", (int)(node->score)); node = node->level[i].forward; } printf("NULL\n"); }}#ifdef SKIP_LIST_TEST_MAINint main() { srand((unsigned)time(0)); int count = 20, i; printf("### Function Test ###\n"); printf("=== Init Skip List ===\n"); skiplist * sl = slCreate(); for ( i = 0; i < count; i++) { slInsert(sl,i); } printf("=== Print Skip List ===\n"); slPrint(sl); printf("=== Search Skip List ===\n"); for (i = 0; i < count; i++) { int value = rand()%(count+10); slSearch(sl, value); } printf("=== Delete Skip List ===\n"); for (i = 0; i < count+10; i+=2) { printf("Delete[%d]: %s\n", i, slDelete(sl, i)?"SUCCESS":"NOT FOUND"); } slPrint(sl); slFree(sl); sl = NULL;}#endif
测试结果:
### Function Test ###=== Init Skip List ====== Print Skip List ===LEVEL[0]: 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13 -> 14 -> 15 -> 16 -> 17 -> 18 -> 19 -> NULLLEVEL[1]: 0 -> 2 -> 4 -> 7 -> 9 -> 10 -> 11 -> 12 -> 14 -> 15 -> 17 -> 18 -> NULLLEVEL[2]: 7 -> 10 -> 12 -> 14 -> 15 -> NULLLEVEL[3]: 10 -> 14 -> 15 -> NULLLEVEL[4]: 10 -> 14 -> NULLLEVEL[5]: NULLLEVEL[6]: NULLLEVEL[7]: NULL=== Search Skip List ===Found 1Found 18Not found 21Not found 24Found 10Not found 20Found 14Found 10Found 19Found 18Not found 27Found 5Found 0Found 0Found 18Not found 26Found 13Not found 28Not found 29Not found 23=== Delete Skip List ===Delete[0]: SUCCESSDelete[2]: SUCCESSDelete[4]: SUCCESSDelete[6]: SUCCESSDelete[8]: SUCCESSDelete[10]: SUCCESSDelete[12]: SUCCESSDelete[14]: SUCCESSDelete[16]: SUCCESSDelete[18]: SUCCESSDelete[20]: NOT FOUNDDelete[22]: NOT FOUNDDelete[24]: NOT FOUNDDelete[26]: NOT FOUNDDelete[28]: NOT FOUNDLEVEL[0]: 1 -> 3 -> 5 -> 7 -> 9 -> 11 -> 13 -> 15 -> 17 -> 19 -> NULLLEVEL[1]: 7 -> 9 -> 11 -> 15 -> 17 -> NULLLEVEL[2]: 7 -> 15 -> NULLLEVEL[3]: 15 -> NULLLEVEL[4]: NULLLEVEL[5]: NULLLEVEL[6]: NULLLEVEL[7]: NULL
0 0
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 跳跃表
- 校验手机号和获取验证码
- 防止程序猿和前端狗打架的几条约定
- svn报错:“Previous operation has not finished; run 'cleanup' if it was interrupted“ 的解决方法
- 动态规划练习03:采药
- python3 爬虫连接mysql
- 跳跃表
- Java程序包含继承时的子父类执行顺序
- ContentProvider和Cursor以及CursorAdapter三者之间内部链接实现原理 解析
- 小莫的成神之旅(二)纯css3实现翻转效果
- Android 6.0 SystemUI之通知栏下拉时周边全透明
- Android开发 adb命令简介
- hello csdn
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- RabbitMQ linux环境安装