精华内容
下载资源
问答
  • 跳表实现原理

    2019-04-15 00:40:42
    跳表实现原理 是一种动态的数据结构,它可以支持快速的插入、查找、查询操作.写起来并不复杂,甚至可以替代红黑树. 对于一个单链表来讲,即使链表中的储存数据是有序的.如果我们想要在其中查找某个数据,也只能...

    跳表实现原理

    是一种动态的数据结构,它可以支持快速的插入、查找、查询操作.写起来并不复杂,甚至可以替代红黑树.

    对于一个单链表来讲,即使链表中的储存数据是有序的.如果我们想要在其中查找某个数据,也只能从头到尾遍历链表.这样的效率会很低,时间复杂度也很高 O(n).

    如何提升链表的查询效率呢? 我们对链表建立一级索引层.每两个节点提取一个节点到上一级.图中的 down 表示 down 指针,指向下一级结点。


    这种链表加多级索引的结构,就是跳表

    小结:

    跳表采用空间换时间的设计思路,通过构建多级索引来提高查询的效率,实现了基于链表的二分查找.跳表是一种动态的数据结构,支持快速的插入.

    展开全文
  • 前言做游戏的一般都有游戏排行榜的需求,要查一下某个uid的积分排名第几,这里我给大家推荐之前我们使用的一种排序算法,跳表skiplist。跳表是一个随机化的数据结构。它允许快速查询一个有序...

    前言

    做游戏的一般都有游戏排行榜的需求,要查一下某个uid的积分排名第几,这里我给大家推荐之前我们使用的一种排序算法,跳表skiplist。

    跳表是一个随机化的数据结构。它允许快速查询一个有序连续元素的数据链表。跳跃列表的平均查找和插入时间复杂度都是O(log n),优于普通队列的O(n)。性能上和红黑树,AVL树不相上下,但跳表的原理非常简单,目前Redis和LevelDB中都有用到。

    跳表是一种可以替代平衡树的数据结构。跳表追求的是概率性平衡,而不是严格平衡。因此,跟平衡二叉树相比,跳表的插入删除操作要简单得多,执行也更快。

    跳表和平衡二叉树

    为什么跳表可以高效的获取rank呢?只能说跳表的数据结构设计巧妙。

    跳表本身提供的功能类似于平衡二叉树以及高级变种,可以对目标值进行快速查找,时间复杂度为O(lgN)。但是跳表的实现原理比实现一颗高效的平衡二叉树(比如红黑树)要简单太多,这是跳表非常大的一个优势。

    关键在于,跳表计算某个score的排名次序,与在跳表中找到这个score的时间复杂度是一样的,仍旧是O(lgN)。反观二叉树系列,它们找到一个值也很快,但是要想知道这个值排名第几,似乎只能按照先序遍历的方式来统计排在前面的值个数。

    其实跳表获取排名的思路也是数一下前面有多少个值,但因为”跳跃”的关系,统计的过程被加速了,因而rank效率更高。

    跳表find原理

    因为rank的计算过

    展开全文
  • (1)复杂度分析原理与方法 (2)数组与链表原理和使用场景讲解 (3)栈原理与应用场景讲解 (4)队列原理与应用场景讲解 (5)递归原理与虚拟机栈场景应用 (6)二分查找及其应用场景 1.跳表与链表 ①原始链表查找效率...

      数据结构&算法模块总结

    1.跳表与链表


        ①原始链表查找效率为O(N)
        跳表优化思路:  每隔两个或两个以上节点时,提取一个节点到上一级,抽取出来的一级称为索引或索引层。down指针,可以指向下一级结点 。 这种链表加多级索引的结构,就是跳表。
        例如要查找节点16,可以现在索引层遍历,当遍历到13发现下一个节点为17。此时不能再继续走,所以从13节点往下走,然后再遍历到16节点
         ③索引层高度与效率:如果在第一级索引上创建第二级。那么查找16过程为1->7->7->9->13->13->16,共6节点,效率有提升。

    2.跳表查询效率计算


    (1)第k层节点个数    

        如果每两个节点抽取一个节点作为上一级索引的节点,那第一级索引的结点个数大约就是n/2,第二级索引的结点个数大约就是n/4,第三级索引的结点个数大约就是n/8,依次类推,也就是说, 第k级索引的结点个数是第k-1级索引的结点个数的1/2 ,那第k级索引结点的个数就是n/(2 k )。

    (2)查询复杂度

         假设索引有h级,最高级的索引只有2个结点。通过上面的公式,可以得到n/(2h)=2,从而求得h=log2n-1。如果包含原始链表这一层,整个跳表的高度就是log2n。在跳表中查询某个数据的时候, 如果每一层都要遍历m个结点,那在跳表中查询一个数据的时间复杂度就是 O(m*logn)(横向遍历节点个数*纵向总高度) ,因此复杂度就是O(logn)
     每一级索引都最多只需要遍历3个结点,也就是说m=3。即m=跨节点个数(2)+1
        假设我们要查找的数据是x,在第k级索引中,我们遍历到y结点之后,发现x大于y,小于后面的结点z,所以我们通过y的down指针,从第k级索引下降到第k-1级索引。 在第k-1级索引中,y和z之间只有3个结点(包含y和z),所以,我们在K-1级索引中最多只需要遍历3个结点, 依次类推,每一级索引都最多只需要遍历3个结点 (但如果有插入操作打乱节点规律,则不一定为3节点)

    3.跳表空间复杂度计算


    (1)每次节点个数:

        假设原始链表大小为n,那第一级索引大约有n/2个结点,第二级索引大约有n/4个结点,以此类推,每上升一级就减少一半,直到剩下2个结点。

    (2)索引节点总和

        上述第1到第k层索引的结点总和=n/2+n/4+n/8…+8+4+2=n-2,因此复杂度为0(N)

    (3)复杂度缩减方法——提高节点跨度

        以3跨度为例,总的索引结点大约就是n/3+n/9+n/27+…+9+3+1=n/2,因此索引跨度越大会减少空间复杂度。

    4.跳表插入和删除


    (1)插入操作

        为了保证链表有序性,先找到插入位置然后插入,因此时间复杂度就是查找复杂度O(log N)。
        例如插入6, 先找到6的位置(5和7中间),然后直接插入 (假设链表是双链表)

    (2)删除操作(同上)

    5.跳表索引动态更新


    (1)更新原因    

        我们不停地往跳表中插入数据时,如果不更新索引,就有可能出现某2个索引结点之间数据非常多的情况。极端情况下,跳表还会退化成单链表。

    (2)更新方法

        不同于红黑树通过旋转左右子树平衡,跳表利用随机函数维护平衡性。通过一个随机函数,来决定将这个结点插入到哪几级索引中,比如随机函数生成了值K,那我们就将这个结点添加到第一级到第K级这K级索引中

         从概率上来讲,能够保证跳表的索引大小和数据大小平衡性,不至于性能过度退化。具体随机实现无规范。

    6.跳表与红黑树


        由于Redis在有序集合中才会用到,主要涉及到的操作如下:

    • 插入一个数据;

    • 删除一个数据;

    • 查找一个数据;

    • 按照区间查找数据(比如查找值在[100, 356]之间的数据);

    • 迭代输出有序序列。

        与红黑树主要差别在于区间查找数据,由于两者查找一个数的时间复杂度都是logn,但是跳表只需要在原始链表层往后遍历即可,而红黑树还要进行回溯操作才能遍历,复杂度高。

    展开全文
  • 跳表原理实现

    千次阅读 2018-03-01 16:29:43
    redis中sort-set的底层是跳表跳表是一种变形的链表。普通链表的查找删除的时间复杂度为O(n),但是使用跳表的期望值是log2(n),媲美AVL树。 跳表的节点思想: 跳表的节点,通过指针指向一个可动态开辟长度的数组,...

            redis中sort-set的底层是跳表。跳表是一种变形的链表。普通链表的查找删除的时间复杂度为O(n),但是使用跳表的期望值是log2(n),媲美AVL树。
    跳表的节点思想:
    跳表的节点,通过指针指向一个可动态开辟长度的数组,根据随机的数字来随机该节点的跳表level,每个level又是一个指针,指向该level的下一个节点,最终指向NULl。
    跳表的插入思想:
    每个跳表节点都有数组存放着level的指针,插入数据的时候,首先随机一个level给新要插入的数据。然后从头结点的对应level开始,模拟单链表进行查找,如果待插入值小于节点值,则进行纵向查找即减少level值。重复进行该操作,同时需要记录下每次链表指向的节点值,当level值为空或者没有查找到该元素,则返回失败,否则成功。链表的前后串联起来。
    跳表的删除思想:
    类似于插入操作,不同的是,找到元素则进行删除,没找到则返回失败。

    参考博客:http://blog.csdn.net/linyu19872008/article/details/72403962
      http://blog.csdn.net/bluecll/article/details/37094991

      http://blog.51cto.com/flyingsnail/1020034

            代码实现:

    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAX_LEVEL 8
    
    struct Node
    {
    	int value;
    	struct Node *next[1];
    };
    typedef struct SkipList
    {
    	int level;
    	struct Node *head;
    }SkipList;
    
    Node *CreateNode(int level, int value)
    {
    	Node *node = (Node *)malloc(sizeof(Node) + level *sizeof(Node *));
    	node->value = value;
    	return node;
    }
    SkipList *Init()
    {
    	//SkipList *list = new SkipList();
    	SkipList *list = (SkipList *)malloc(sizeof(SkipList));
    	list->level = 0;
    	list->head = CreateNode(MAX_LEVEL + 1, 0);
    	for (int i = 0; i < MAX_LEVEL; i++)
    	{
    		list->head->next[i] = NULL;
    	}
    	return list;
    }
    int Random()
    {
    	int k = 1;
    	while (rand() % 2)
    	{
    		k++;
    	}
    	return k > MAX_LEVEL ? MAX_LEVEL : k;
    }
    void Insert(SkipList *list, int value)
    {
    	Node *update[MAX_LEVEL];
    	Node *p, *q = NULL;
    	p = list->head;
    	int k = list->level;
    
    	//记录下value应该插入的每一层的位置
    	for (int i = k - 1; i >= 0; --i)
    	{
    		while ((q = p->next[i]) && (q->value <= value))
    		{
    			if (q->value == value)
    			{
    				printf("error:insert error %d\n", value);
    				return;
    			}
    			p = q;
    		}
    		update[i] = p;
    	}
    
    	//更新skiplist的level值
    	k = Random();
    	if (k > list->level)
    	{
    		for (int i = list->level; i < k; ++i)
    		{
    			update[i] = list->head;
    		}
    		list->level = k;
    	}
    
    	//进行申请节点,插入操作
    	Node *node = CreateNode(k, value);
    	printf("k: %d    level: %d\n", k, list->level);
    	for (int i = 0; i < k; ++i)
    	{
    		node->next[i] = update[i]->next[i];
    		update[i]->next[i] = node;
    	}
    }
    void Delete(SkipList *list, int value)
    {
    	Node *update[MAX_LEVEL];
    	Node *p, *q = NULL;
    	p = list->head;
    	int k = list->level;
    
    	//一层一层的查找value值
    	for (int i = k - 1; i >= 0; --i)
    	{
    		while ((q = p->next[i]) && q->value < value)
    			p = q;
    		update[i] = p;
    	}
    	
    	//如果和最底层相等证明存在
    	if (q && (q->value == value))
    	{
    		for (int i = 0; i < k; ++i)
    		{
    			if (update[i]->next[i] == q)
    			{
    				update[i]->next[i] = q->next[i];
    			}
    		}
    		free(q);
    
    		//重新维护跳表的level
    		for (int i = list->level - 1; i >= 0; --i)
    		{
    			if (list->head->next[i] == NULL)
    			{
    				list->level--;
    			}
    		}
    	}
    }
    //void Show(SkipList *sl)
    //{
    //	//从最高层开始打印  
    //	Node *p, *q = NULL;
    //
    //	//从最高层开始搜  
    //	int k = sl->level;
    //	for (int i = k - 1; i >= 0; i--)
    //	{
    //		p = sl->head;
    //		while (q = p->next[i])
    //		{
    //			printf("%d -> ", p->value);
    //			p = q;
    //		}
    //		printf("\n");
    //	}
    //	printf("\n");
    //}
    void Show(SkipList *list)
    {
    	Node *p, *q = NULL;
    	for (int i = list->level - 1; i >= 0; --i)
    	{
    		p = list->head;
    		while (q = p->next[i])
    		{
    			printf("%d -> ", q->value);
    			p = q;
    		}
    		printf("\n");
    	}
    	printf("\n");
    }
    int main()
    {
    	SkipList *list = Init();
    	int ar[] = { 5, 7, 6, 4, 3, 9, 0, 1, 8 , 2 , 2};
    	for (int i = 0; i < sizeof(ar)/sizeof(ar[0]); ++i)
    	{
    		Insert(list, ar[i]);
    	}
    	Show(list);
    	Show(list);
    	Delete(list, 8);
    	Show(list);
    }

    展开全文
  • 跳表实现原理

    2021-01-26 10:37:46
    跳表,是基于链表实现的一种类似“二分”的算法。它可以快速的实现增,删,改,查操作。 我们先来看一下单向链表如何实现查找 当我们要在该单链表中查找某个数据的时候需要的时间复杂度为O(n). 怎么提高查询...
  • 跳表原理实现 Golang 版 有时候,我们会说,在计算机世界里,其实只有两种数据结构,一个是数组一个是链表。原因是其他的数据结构都是基于这两种数据结构做的扩展。 数组和链表的优缺点实在是非常的明显。数组...
  • 跳表原理及其实现

    2017-09-27 09:47:54
    跳表作为一种数据结构通常用于取代平衡树。 起因 平衡树可以用于表示抽象的数据类型如字典和有序链表,它通过树旋转(Tree Rotation)操作强制使树结构保持平衡来保证节点搜索的效率。在数据为随机插入的情况...
  • SkipList(跳表)是一个随机化的数据结构,可以被看做二叉树的一个变种,它在性能上和红黑树,AVL树不相上下,但是跳表原理非常简单,目前在Redis和LeveIDB中都有用到。只要你能熟练操作链表,就能轻松实现一个 跳表...
  • 跳表实现

    2020-12-13 01:55:26
    Skip lists: a probabilistic alternative to balanced trees的论文上提出的,这篇论文在网上可以下载到PDF版,篇幅不长,只有8页,而且没有废话,前3页就把跳表的原理交代清楚了,如果只想了解跳表实现原理,看前...
  • 针对有序链表为了实现高效的查找,可以使用跳表这种数据结构。 其根本思想是 二分查找 的思想。 跳表的前提条件是针对有序的单链表 ,实现高效地查找,插入,删除。
  • 一、概念何为跳表呢?我们先维基百科对其定义继续剖析:跳跃列表是一种数据结构。它允许快速查询一个有序连续元素的数据链表,而其快速查询是通过维护一个多层次的链表,且每一层链表中的元素是前一层链...
  • SkipList 跳表原理

    2018-12-16 14:41:08
    SkipList 跳表的原理 前言 在各类数据结构中,实现的方式无非两种,数组/链表,跳表是一种基于链表改进的数据结构,能够...接下来我们将了解跳表实现原理跳表的结构 以下是一个普通的链表,假设我们需要访问...
  • 本篇文章重在实现跳表这种数据结构第一次接触是在Redis里面,当时只是学习了跳表的理论知识,光靠理论是难以支撑的,这点在字节面试过程中被问到跳表便可体会到 跳表是一种非常高校的数据结构,是由美国科学家...
  • SkipList跳表原理实现

    千次阅读 2013-08-26 16:01:14
    想象一下,给你一张草稿纸,一只笔,一个编辑器,你能立即实现一颗红黑树,或者AVL树 出来吗? 很难吧,这需要时间,要考虑很多细节,要参考一堆算法与数据结构之类的树, 还要参考网上的代码,相当麻烦。   用...
  • SkipList跳表基本原理

    2018-08-04 19:48:11
    SkipList跳表基本原理 为什么选择跳表 目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等。 想象一下,给你一张草稿纸,一只笔,一个编辑器,你能立即实现一颗红黑树,或者AVL树 出来吗?...
  • 跳表原理

    2018-12-11 10:55:02
    跳表原理非常简单,跳表其实就是一种可以进行二分查找的有序链表。 跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。首先在最高级索引上查找最后一个小于当前查找元素的位置,然后再跳到次高级...
  • 想象一下,给你一张草稿纸,一只笔,一个编辑器,你能立即实现一颗红黑树,或者AVL树 出来吗? 很难吧,这需要时间,要考虑很多细节,要参考一堆算法与数据结构之类的树, 还要参考网上的代码,相当麻烦。 用跳表...
  • levelDB跳表实现

    2016-03-02 23:22:00
    跳表原理就是利用随机性建立索引,加速搜索,并且简化代码实现难度。具体的跳表原理不再赘述,主要是看了levelDB有一些实现细节的东西,凸显自己写的实现不足之处。 去除冗余的key template<typename Key, ...
  • // 这里为了实现跳表层级,就用了数组的的结构来定义下一个节点 // 比如: next[1] 表示当前节点,指向第一层的节点。next[2] 表示当前节点,指向第二层的节点。 // 就如同(一、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,453
精华内容 2,181
关键字:

跳表实现原理