概述
SkipList 是由William Pugh发明的一种数据结构,它的作用类似平衡二叉树,对查找,删除,插入操作的时间复杂度为O(logN),是一种十分高效的查找结构。SkipList使用随机化的平衡方案取代了平衡二叉树的严格的平衡方案,因此它也是一种随机化的数据结构。SkipList基于并联的链表,是对有序的链表附加上随机个数的前进的链接,使得在查找过程中可以快速地跳过部分链表而得名。
如上图所示,a为普通的排好序的LinkList,在a中查找一个元素,最坏情况下,我们需要对比所有的节点,如果修改成如b那样,间隔的list中的元素加上指向前面第二个的元素指针,则查找一个元素最多需要【n/2】+ 1次对比,同理对应c来说,则需要【n/4】 + 1次,如果对任意第2^i个节点拥有i个指针来指向前面的i个节点,那么其查找效率就会降到logN,但是这种数据结构虽然可以很快的进行查找,但是对于插入和删除操作确实不切实际的。一个拥有k个向前指针的节点称为k层节点,像之前描述的结构,节点的层次分布模式为:%50为1层,25%为2层,12.5%为三层,以此类推。如果按一定比例来随机分配节点的层次的话(如图中的e),节点的第i个向前指针只需指向第i层的下一个节点。当插入一个节点时,随机的选择它的层次,并且不再需要改变。虽然有时候某些层次的安排会带来低效的执行效率,但是因为是随机化的,所以这种情况是很罕见的。
初始化
SkipList的所有层级的子list都终结于NIL(不带任何合法值的元素),刚创建的SkipList的层级为1,只有一个头结点,并且只包含一个指向NIL的向前结点。
随机化层次选择
设拥有第i个向前指针的节点,同时拥有第i+1个向前指针分布比例为p,若有一半的节点有第i个向前指针的节点,同时拥有第i+1个向前指针,则p等于1/2.则随机化的层次选择过程如下:
randomLevel() lvl := 1 -- random() that returns a random value in [0...1) while random() < p and lvl < MaxLevel do lvl := lvl + 1 return lvl
这里有个MaxLevel,它的值为 MaxLevel =L(N)= log(1/p)N (p=1/2)=log(2).N,它表示跳跃表最大允许的层次。
效率分析
设C(K)为查找第k个节点需要消耗的时间,则:
C(0) = 0 C(k) = (1–p) (在同一层查找) + p (向下一层查找)
化简得
C(k) = (1–p) (1 + C(k)) + p (1 + C(k–1)) C(k) = 1/p + C(k–1) C(k) = k/p
因为k《=MaxLevel=L(n)/p + 1/(1–p),为O(logN)
查找过程
Search(list, searchKey) x := list.eader -- loop invariant: x.key < searchKey for i := list.level downto 1 do while x.forward[i].key < searchKey do x := x.forward[i] -- x.key < searchKey <= x.forward[1].key x := x.forward[1] if x.key = searchKey then return x.value else return failure
模拟查找过程:
查找6的过程如下:
- 首先从最高层开始,发现6在 header跟6节点之间
-
然后继续降到第三层
- 还是发现6在 header跟6节点之间,降到第二层
- 第一层时,发现6在节点3和6直接,此时x指向3这个节点
-
3的下一个节点是6,刚好找到
插入过程
Insert(list, searchKey, newValue) local update[1..MaxLevel] x := list.header for i := list.level downto 1 do while x.forward[i].key < searchKey do x := x.forward[i] -- x.key < searchKey £ x.forward[i].key update[i] := x x := x.forward[1] if x.key = searchKey then x.value := newValue else lvl := randomLevel() if lvl > list.level then for i := list.level + 1 to lvl do update[i] := list.header list.level := lvl x := makeNode(lvl, searchKey, value) for i := 1 to level do x.forward[i] := update[i].forward[i] update[i].forward[i] := x
删除过程
Delete(list, searchKey) local update[1..MaxLevel] x := list.header for i := list.level downto 1 do while x.forward[i].key < searchKey do x := x.forward[i] update[i] := x x := x.forward[1] if x.key = searchKey then for i := 1 to list.level do if update[i].forward[i] != x then break update[i].forward[i] := x.forward[i] free(x) while list.level > 1 and list.header.forward[list.level] = NIL do list.level := list.level – 1
SCALA实现
package chiyx.algo.datastruct /** * Created with IntelliJ IDEA. * scala版本的跳跃表的实现 * @author qianshang@taobao.com * @since 下午11:00 13-9-2 * */ class SkipList[T <% Ordered[T]] { /** * 随机化的概率,每层节点拥有上一层指针的概率 */ private val P = 0.5 /** * 最高层级为8,则 N的合适范围在 2^^8 */ private val MaxLevel = 8 private val header: SkipNode[T] = new SkipNode[T](MaxLevel) /** * 当前的最大层级编号,从0开始编号 */ private var level = 0 /** * 随机产生插入节点的层高 * @return */ def randomLevel = { val lvl = (Math.log(1.0 - Math.random()) / Math.log(1 - P)).toInt Math.min(lvl, MaxLevel) } /** * 检查是否包含元素 * @param o * @return */ def contains(o: T) = { var x = header for (i <- level.to(0, -1)) { while (x.forward(i) != null && x.forward(i).value < o) { x = x.forward(i) } } x = x.forward(0) x != null && x.value.equals(o) } /** * 插入元素 * @param o */ def insert(o: T) { var x = header val update = new Array[SkipNode[T]](MaxLevel + 1) for (i <- level.to(0, -1)) { while (x.forward(i) != null && x.forward(i).value < o) { x = x.forward(i) } update(i) = x } x = x.forward(0) /** * 如果不存在,则创建节点 */ if (x == null || x.value != o) { val lvl = randomLevel if (lvl > level) { for (i <- level to lvl) { update(i) = header } level = lvl } x = new SkipNode[T](o, lvl) for (i <- 0 to lvl) { x.forward(i) = update(i).forward(i) update(i).forward(i) = x } } } /** * 删除操作 * @param o */ def delete(o: T) { var x = header val update = new Array[SkipNode[T]](MaxLevel + 1) for (i <- level.to(0, -1)) { while (x.forward(i) != null && x.forward(i).value < o) { x = x.forward(i) } update(i) = x } x = x.forward(0) //元素存在的情况下才需要删除 if (x != null && x.value == o) { for (i <- 0 to level) { if (update(i).forward(i) == x) { update(i).forward(i) = x.forward(i) } } while (level > 0 && header.forward(level) == null) { level = level - 1 } } } } /** * 跳跃表中的节点 * @tparam T */ private class SkipNode[T](val level: Int) { var value: T = _ /** * 指向多个层级的下个节点的指针数组 */ val forward: Array[SkipNode[T]] = new Array[SkipNode[T]](level + 1) def this(ve: T, level: Int) = { this(level) value = ve } } object SkipListApp { def main(args: Array[String]) { val sList = new SkipList[Int] sList insert 5 sList insert 4 sList insert 6 sList insert 9 println( sList contains 6) sList delete 6 println( sList contains 6) } }
相关推荐
跳跃表(Skiplist)是一种在Redis中广泛使用的数据结构,它作为一种概率性的平衡树替代方案,通过概率性平衡而非严格平衡,实现了更简单、更快的插入和删除算法。本篇将深入探讨跳跃表的基本概念、工作原理以及其在...
数据结构 数据结构_C++之17_skiplist
SkipList是一种数据结构,它的设计灵感来源于随机化算法,它在查找、插入和删除操作上的平均时间复杂度为O(log n),在实际应用中表现出色。开源项目的意义在于,开发者可以免费获取并使用这个库,同时查看源代码学习...
### Skip List 数据结构详解 #### 一、引言与背景 Skip list 是一种概率性数据结构,它在很多场景下可以替代平衡树作为首选的实现方法。与平衡树相比,Skip list 具有更简单的实现、更快的速度以及更低的空间消耗...
Skiplist是一种高效、随机化的数据结构,常用于数据库和搜索引擎等场景,它的主要特点是查找、插入和删除操作的时间复杂度平均为O(log N),与平衡二叉搜索树相当,但实现起来更为简单。在Go语言中实现Skiplist,可以...
跳跃表(Skiplist)是一种高效的数据结构,能够快速查询一个有序连续元素的数据链表。它的平均查找和插入时间复杂度都是 O(log n) ,优于普通队列的 O(n) 。下面是跳跃表的详细知识点: 跳跃表的简介 跳跃表是一种...
Redis中的跳跃列表(skiplist)是一种高效的数据结构,用于实现有序集合(sorted set)。它是一种概率性数据结构,通过随机概率控制层数,从而在平均情况下提供接近于对数时间复杂度的查找、插入和删除操作。skiplist...
数据结构原本,大一统,外文书原版 Data structures Contents Articles Introduction 1 Data structure 1 Linked data structure 3 Succinct data structure 6 Implicit data structure 8 Compressed data structure...
`fis3-deploy-skip-packed` 是一个针对前端构建工具 FIS3(Fast Interaction for Server-side)的扩展插件,主要作用在于部署阶段跳过已经压缩的文件,避免重复处理,从而优化构建过程。 FIS3 是腾讯推出的一款前端...
跳表(Skiplist)是一种高效的数据结构,它在实现上类似于多层索引的跳跃式访问,由Marc P. Lehmann在1990年提出。VB.NET是一种基于.NET Framework的面向对象的编程语言,它提供了丰富的库和工具,使得开发者能够...
在计算机科学领域,跳跃表(Skip List)是一种可以用来替代平衡树的数据结构,尤其是在实现有序映射(Sorted Map)和有序集合(Sorted Set)时被广泛使用。本文将详细介绍一个特殊类型的跳跃表——1-5确定性跳跃表,...
跳过列表是一种高效的数据结构,由Peter M....通过对"senior-thesis-on-skiplist"的深入研究,不仅可以掌握跳过列表这一重要的数据结构,还能增强C++编程和算法实现的能力,对于计算机科学的学习和职业生涯都非常有益。
- **课程设计目的**: 认识并应用Skip List数据结构,体验线性结构的变种。 - **基本要求**: - 实现Skip List的ADT(抽象数据类型),包括初始化、查找、插入、删除等操作。 - 分析各基本操作的时间复杂度。 - 针对...
跳跃表是一种高效的数据结构,常用于数据库和搜索引擎中,它能提供近似于O(log N)的时间复杂度进行插入、删除和查找操作。本压缩包"skipList.rar"包含了一个用C++实现的跳跃表,该实现参考了Redis中的zskiplist。...
跳过列表数据结构的纯python实现。 介绍 跳过列表是一种数据结构,可以用来代替平衡树。 跳过列表使用概率平衡而不是严格执行的平衡,因此,与等效树平衡算法相比,跳过列表中插入和删除的算法要简单得多,并且速度...
import SkipList from '@aureooms/js-skip-list' ;const list = SkipList . from ( decreasing , range ( 10000 ) ) ;[ ... list ] ; // [9999, 9998, ...]list . add ( ... )list . get ( ... )list . has ( ... )...
跳跃表(Skiplist)是一种随机化数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间),并且对并发算法友好。跳跃表的结构是:假如底层有10个节点,那么底层的上一层理论上就...
跳表(Skip List)是一种随机化的数据结构,用于高效地实现查找、插入和删除操作,其性能接近于平衡二叉搜索树,但实现起来更为简单。在Java编程中,跳表通常被用作数据库和搜索引擎中的索引结构,因为它的平均时间...
这个数据集很可能包含了一个简化版的文本数据,方便初学者理解和实现skip-gram模型。 描述中的"skip-gram 代码复现"意味着我们将要探讨如何从零开始编写或理解skip-gram模型的代码实现。这通常涉及到以下几个关键...
1. 跳表(Skiplist)数据结构的基础知识: - 跳表是一种可以替代平衡二叉树的数据结构。 - 它的核心思想是利用随机化算法在概率上保证数据访问时间的平衡性。 - 跳表的数据不需要以树形结构存储,因此在进行并行...