一、跳表简述

跳表可以看做是一个带有索引的链表,在介绍跳表之前先看一下一个普通的链表,假如当前维护了一个有序的链表:

现在要在这个链表中查找128,因为事先不知道链表中数值的分布情况,我们只能从前到后依次遍历,那么有没有什么取巧的方法呢?

如果我们能够存储下最中间节点的引用,比如存储节点29的引用,然后每次要查找节点的时候就先跟29比较一下,如果比29小就还是从前往后找(因为不会超过中间节点,从前往后和从中间往前区别不大),如果比29大就直接跳到29开始往后找,这种思想就是为链表添加了一个简单的索引,一下可以节省掉一半的查找时间。跳表的设计思想类似,通过为链表的每个节点设置高度来添加索引,不同的高度称为不同的层,每一层的next只能指向当前层的下一个节点,下面是一个跳表的示例:

最左面一列null为head节点,用于保存每一层的第一个节点,在查找的时候先从最高层开始查找,比如要在上面的跳表中查找128:

首先取最高层第六层的next,是47,比128小,直接跳到47,然后47的第六层的next是null,说明到了最后一个了,层数减少,47的第五层的next是255,比128大,也不行,继续减少层数,47的第四层的next是255,依然比128大,继续减少层数,47的第三层的next是128,get it!

看上面的过程有没有意识到一个问题,就是如果跳表的层数过多的话”比较-降层“这个过程就会有不少的浪费,比如上面的在47这个节点进行了4次比较才找到了有效的next节点,如果这个值再大一点的话就会退化得很严重。那么这个层是如何来的呢,跳表的高度是通过一个随机数决定的,初始时默认为一层,然后一直产生随机数只要小于0.5就将层数加一层继续随机,但是随机这种东西毕竟是不可控的,为了避免出现过高的层数最好还是设置一个最大层数以免某些节点的层数过大。

二、跳表的实现

跳表的简单Java实现:

SkipList.java:

package alg.link;

import org.apache.commons.lang3.StringUtils;

/**
* 跳表结构的简单Java实现
*
* @author CC11001100
*/
public class SkipList<T extends Comparable<T>> { private static final double DEFAULT_CONTINUE_INCREMENT_LEVEL_THRESHOLD = 0.75;
private static final int DEFAULT_MAX_LEVEL = 10; // 用于控制层数,决定层数时当随机数小于此值时会一直升层直到最大,取值范围[0, 1],值越大越可能得到高层数,此值设置不当很有可能退化成链表
private double continueIncrementLevelThreshold;
// 为了防止随机数出现异常情况过高,对最大层数做一个限制
private int maxLevel;
// 链表的头结点,每一层的头都保存在这里
private Node<T> head; public SkipList() {
this(DEFAULT_CONTINUE_INCREMENT_LEVEL_THRESHOLD, DEFAULT_MAX_LEVEL);
} public SkipList(double threshold) {
this(threshold, DEFAULT_MAX_LEVEL);
} public SkipList(double threshold, int maxLevel) {
this.continueIncrementLevelThreshold = threshold;
this.maxLevel = maxLevel;
this.head = new Node<>(null, 0);
// 初始化时就将其扩充到最大避免后面扩容增加复杂性,只有head会浪费一些空间其它节点都是有几层申请多长的数组
this.head.next = new Node[maxLevel];
} public void add(T value) {
Node[] previous = findPrevious(value);
Node<T> node = new Node<>(value, randomLevel());
for (int i = 0; i < previous.length && i < node.level; i++) {
node.next[i] = previous[i].next[i];
previous[i].next[i] = node;
}
if (node.level > head.level) {
for (int i = node.level - 1; i >= 0 && head.next[i] == null; i--) {
head.next[i] = node;
}
head.level = node.level;
}
} public void remove(T value) {
Node[] previous = findPrevious(value);
Node node = previous[0].next[0];
if (node.value.compareTo(value) != 0) {
return;
}
for (int i = 0; i < previous.length && i < node.level; i++) {
previous[i].next[i] = node.next[i];
}
} public boolean contains(T value) {
Node[] previous = findPrevious(value);
Node node = previous[0].next[0];
return node.value.compareTo(value) == 0;
} private int randomLevel() {
int level = 1;
while (level < maxLevel && Math.random() < continueIncrementLevelThreshold) {
level++;
}
return level;
} private Node[] findPrevious(T value) {
Node[] previous = new Node[head.level];
Node<T> node = head;
for (int i = head.level - 1; i >= 0; i--) {
while (node.next[i] != null && node.next[i].value.compareTo(value) < 0) {
node = node.next[i];
}
previous[i] = node;
}
return previous;
} /**
* head_next level_next # 注释,实际不会打印标题
* 67 67
* 67 67
* 67 67
* 67 67
* 19 19 67
* 19 19 67
* 6 6 19 67
* 6 6 19 67 82
* 6 6 19 46 67 82
*/
public void show() {
StringBuilder sb = new StringBuilder();
for (int i = maxLevel; i > 0; i--) {
// 这一层级的头指针指向谁
Node levelHead = head.next[i - 1];
if (levelHead != null) {
sb.append(String.format("%-10s", levelHead.value.toString())).append("\t");
} else {
sb.append(StringUtils.repeat(" ", 10)).append("\t");
}
// 然后是每一层按层数是否出现打印value或空白填充
Node node = head.next[0];
while (node != null) {
String s = node.value.toString();
if (node.level >= i) {
sb.append(s).append("\t");
} else {
sb.append(StringUtils.repeat(" ", s.length())).append("\t");
}
node = node.next[0];
}
if (i != 1) {
sb.append("\n");
}
}
System.out.println(sb.toString());
} private static class Node<T extends Comparable<T>> {
// 当前节点的值
T value;
// 当前节点的层数
int level;
// 记录当前节点在每一层的next节点
Node<T>[] next; private Node(T value, int level) {
this.value = value;
this.level = level;
this.next = new Node[level];
}
} }

SkipListTest.java:

package alg.link;

import java.util.ArrayList;
import java.util.List;
import java.util.Random; /**
* @author CC11001100
*/
public class SkipListTest { public static void main(String[] args) { SkipList<Integer> skipList = new SkipList<>();
Random random = new Random();
List<Integer> numList = new ArrayList<>();
for (int i = 0; i < 30; i++) {
int n = random.nextInt(100);
System.out.println("now insert " + n);
skipList.add(n);
skipList.show();
numList.add(n);
System.out.println("---------------------------------------------------------------------------"); if (Math.random() < 0.5 && !numList.isEmpty()) {
int removeNum = numList.remove(random.nextInt(numList.size()));
System.out.println("now remove " + removeNum);
skipList.remove(removeNum);
skipList.show();
System.out.println("---------------------------------------------------------------------------");
}
} } }

测试效果:

now insert 35

35        	35
35 35
35 35
---------------------------------------------------------------------------
now insert 56
56 56
56 56
56 56
56 56
56 56
56 56
56 56
35 35 56
35 35 56
35 35 56
---------------------------------------------------------------------------
now remove 35
56 56
56 56
56 56
56 56
56 56
56 56
56 56
56 56
56 56
56 56
---------------------------------------------------------------------------
now insert 45
56 56
56 56
56 56
56 56
56 56
45 45 56
45 45 56
45 45 56
45 45 56
45 45 56
---------------------------------------------------------------------------
now remove 56 45 45
45 45
45 45
45 45
45 45
---------------------------------------------------------------------------
now insert 7 45 45
45 45
45 45
45 45
7 7 45
---------------------------------------------------------------------------
now insert 57 45 45
45 45
45 45
45 45 57
7 7 45 57
---------------------------------------------------------------------------
now remove 7 45 45
45 45
45 45
45 45 57
45 45 57
---------------------------------------------------------------------------
now insert 75 45 45
45 45
45 45
45 45 57
45 45 57 75
---------------------------------------------------------------------------
now remove 75 45 45
45 45
45 45
45 45 57
45 45 57
---------------------------------------------------------------------------
now insert 96 45 45
45 45 96
45 45 96
45 45 57 96
45 45 57 96
---------------------------------------------------------------------------
now remove 96 45 45
45 45
45 45
45 45 57
45 45 57
---------------------------------------------------------------------------
now insert 40
40 40
40 40
40 40
40 40
40 40
40 40 45
40 40 45
40 40 45
40 40 45 57
40 40 45 57
---------------------------------------------------------------------------
now remove 40 45 45
45 45
45 45
45 45 57
45 45 57
---------------------------------------------------------------------------
now insert 69 45 45
45 45
45 45 69
45 45 57 69
45 45 57 69
---------------------------------------------------------------------------
now insert 11 45 45
11 11 45
11 11 45 69
11 11 45 57 69
11 11 45 57 69
---------------------------------------------------------------------------
now insert 19 45 45
11 11 45
11 11 45 69
11 11 19 45 57 69
11 11 19 45 57 69
---------------------------------------------------------------------------
now insert 55 45 45
11 11 45
11 11 45 55 69
11 11 19 45 55 57 69
11 11 19 45 55 57 69
---------------------------------------------------------------------------
now remove 55 45 45
11 11 45
11 11 45 69
11 11 19 45 57 69
11 11 19 45 57 69
---------------------------------------------------------------------------
now insert 43 45 45
11 11 45
11 11 45 69
11 11 19 45 57 69
11 11 19 43 45 57 69
---------------------------------------------------------------------------
now remove 43 45 45
11 11 45
11 11 45 69
11 11 19 45 57 69
11 11 19 45 57 69
---------------------------------------------------------------------------
now insert 5 45 45
11 11 45
11 11 45 69
11 11 19 45 57 69
5 5 11 19 45 57 69
---------------------------------------------------------------------------
now remove 5 45 45
11 11 45
11 11 45 69
11 11 19 45 57 69
11 11 19 45 57 69
---------------------------------------------------------------------------
now insert 92 45 45
11 11 45
11 11 45 69
11 11 19 45 57 69 92
11 11 19 45 57 69 92
---------------------------------------------------------------------------
now remove 45 11 11
11 11 69
11 11 19 57 69 92
11 11 19 57 69 92
---------------------------------------------------------------------------
now insert 56 11 11
11 11 69
11 11 19 57 69 92
11 11 19 56 57 69 92
---------------------------------------------------------------------------
now insert 31 11 11
11 11 69
11 11 19 31 57 69 92
11 11 19 31 56 57 69 92
---------------------------------------------------------------------------
now insert 29 11 11
11 11 29 69
11 11 19 29 31 57 69 92
11 11 19 29 31 56 57 69 92
---------------------------------------------------------------------------
now insert 96 11 11 96
11 11 29 69 96
11 11 19 29 31 57 69 92 96
11 11 19 29 31 56 57 69 92 96
---------------------------------------------------------------------------
now insert 0 11 11 96
0 0 11 29 69 96
0 0 11 19 29 31 57 69 92 96
0 0 11 19 29 31 56 57 69 92 96
---------------------------------------------------------------------------
now remove 19 11 11 96
0 0 11 29 69 96
0 0 11 29 31 57 69 92 96
0 0 11 29 31 56 57 69 92 96
---------------------------------------------------------------------------
now insert 54 11 11 54 96
0 0 11 29 54 69 96
0 0 11 29 31 54 57 69 92 96
0 0 11 29 31 54 56 57 69 92 96
---------------------------------------------------------------------------
now insert 8 11 11 54 96
0 0 11 29 54 69 96
0 0 11 29 31 54 57 69 92 96
0 0 8 11 29 31 54 56 57 69 92 96
---------------------------------------------------------------------------
now remove 56 11 11 54 96
0 0 11 29 54 69 96
0 0 11 29 31 54 57 69 92 96
0 0 8 11 29 31 54 57 69 92 96
---------------------------------------------------------------------------
now insert 60 11 11 54 96
0 0 11 29 54 69 96
0 0 11 29 31 54 57 69 92 96
0 0 8 11 29 31 54 57 60 69 92 96
---------------------------------------------------------------------------
now insert 41 41 41
11 11 41 54 96
0 0 11 29 41 54 69 96
0 0 11 29 31 41 54 57 69 92 96
0 0 8 11 29 31 41 54 57 60 69 92 96
---------------------------------------------------------------------------
now remove 92 41 41
11 11 41 54 96
0 0 11 29 41 54 69 96
0 0 11 29 31 41 54 57 69 96
0 0 8 11 29 31 41 54 57 60 69 96
---------------------------------------------------------------------------
now insert 20 41 41
11 11 20 41 54 96
0 0 11 20 29 41 54 69 96
0 0 11 20 29 31 41 54 57 69 96
0 0 8 11 20 29 31 41 54 57 60 69 96
---------------------------------------------------------------------------
now remove 41 11 11 20 54 96
0 0 11 20 29 54 69 96
0 0 11 20 29 31 54 57 69 96
0 0 8 11 20 29 31 54 57 60 69 96
---------------------------------------------------------------------------
now insert 58 11 11 20 54 96
0 0 11 20 29 54 58 69 96
0 0 11 20 29 31 54 57 58 69 96
0 0 8 11 20 29 31 54 57 58 60 69 96
---------------------------------------------------------------------------
now remove 31 11 11 20 54 96
0 0 11 20 29 54 58 69 96
0 0 11 20 29 54 57 58 69 96
0 0 8 11 20 29 54 57 58 60 69 96
---------------------------------------------------------------------------
now insert 79 11 11 20 54 96
0 0 11 20 29 54 58 69 96
0 0 11 20 29 54 57 58 69 79 96
0 0 8 11 20 29 54 57 58 60 69 79 96
---------------------------------------------------------------------------
now insert 38 11 11 20 54 96
0 0 11 20 29 54 58 69 96
0 0 11 20 29 38 54 57 58 69 79 96
0 0 8 11 20 29 38 54 57 58 60 69 79 96
---------------------------------------------------------------------------
now insert 31 11 11 20 54 96
0 0 11 20 29 54 58 69 96
0 0 11 20 29 31 38 54 57 58 69 79 96
0 0 8 11 20 29 31 38 54 57 58 60 69 79 96
---------------------------------------------------------------------------
now remove 79 11 11 20 54 96
0 0 11 20 29 54 58 69 96
0 0 11 20 29 31 38 54 57 58 69 96
0 0 8 11 20 29 31 38 54 57 58 60 69 96
---------------------------------------------------------------------------
now insert 78 11 11 20 54 78 96
0 0 11 20 29 54 58 69 78 96
0 0 11 20 29 31 38 54 57 58 69 78 96
0 0 8 11 20 29 31 38 54 57 58 60 69 78 96
---------------------------------------------------------------------------
now remove 0 11 11 20 54 78 96
11 11 20 29 54 58 69 78 96
11 11 20 29 31 38 54 57 58 69 78 96
8 8 11 20 29 31 38 54 57 58 60 69 78 96
---------------------------------------------------------------------------

.

数据结构笔记之跳表(SkipList)的更多相关文章

  1. 存储系统的基本数据结构之一: 跳表 (SkipList)

    在接下来的系列文章中,我们将介绍一系列应用于存储以及IO子系统的数据结构.这些数据结构相互关联又有着巨大的区别,希望我们能够不辱使命的将他们分门别类的介绍清楚.本文为第一节,介绍一个简单而又有用的数据 ...

  2. 跳表SkipList

    原文:http://www.cnblogs.com/xuqiang/archive/2011/05/22/2053516.html 跳表SkipList   1.聊一聊跳表作者的其人其事 2. 言归正 ...

  3. C语言跳表(skiplist)实现

    一.简介 跳表(skiplist)是一个非常优秀的数据结构,实现简单,插入.删除.查找的复杂度均为O(logN).LevelDB的核心数据结构是用跳表实现的,redis的sorted set数据结构也 ...

  4. 跳表 SkipList

    跳表是平衡树的一种替代的数据结构,和红黑树不同,跳表对树的平衡的实现是基于一种随机化的算法,这样就使得跳表的插入和删除的工作比较简单.     跳表是一种复杂的链表,在简单链表的节点信息之上又增加了额 ...

  5. 3.3.7 跳表 SkipList

    一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下,ConcurrentHashMap 存取速度是ConcurrentSki ...

  6. 跳表(SkipList)设计与实现(Java)

    微信搜一搜「bigsai」关注这个有趣的程序员 文章已收录在 我的Github bigsai-algorithm 欢迎star 前言 跳表是面试常问的一种数据结构,它在很多中间件和语言中得到应用,我们 ...

  7. [转载] 跳表SkipList

    原文: http://www.cnblogs.com/xuqiang/archive/2011/05/22/2053516.html leveldb中memtable的思想本质上是一个skiplist ...

  8. 跳表(SkipList)原理篇

    1.什么是跳表? 维基百科:跳表是一种数据结构.它使得包含n个元素的有序序列的查找和插入操作的平均时间复杂度都是 O(logn),优于数组的 O(n)复杂度.快速的查询效果是通过维护一个多层次的链表实 ...

  9. 跳表(skiplist)Python实现

    # coding=utf-8 # 跳表的Python实现 import random # 最高层数设置为4 MAX_LEVEL = 4 def randomLevel(): ""& ...

随机推荐

  1. 公钥与私钥的理解,以及https的应用原理

    1.公钥与私钥原理1)鲍勃有两把钥匙,一把是公钥,另一把是私钥2)鲍勃把公钥送给他的朋友们----帕蒂.道格.苏珊----每人一把.3)苏珊要给鲍勃写一封保密的信.她写完后用鲍勃的公钥加密,就可以达到 ...

  2. 在Ubuntu虚拟机上安装DVWA

    学习资料来源:https://www.neddos.tech/?p=107 最后更新时间: 190122·17:41 1> 什么是DVWA(Damn Vulnerable Web Applica ...

  3. PAT甲题题解-1112. Stucked Keyboard (20)-(map应用)

    题意:给定一个k,键盘里有些键盘卡住了,按一次会打出k次,要求找出可能的坏键,按发现的顺序输出,并且输出正确的字符串顺序. map<char,int>用来标记一个键是否为坏键,一开始的时候 ...

  4. BugPhobia开发篇章:Beta阶段第V次Scrum Meeting

    0x01 :Scrum Meeting基本摘要 Beta阶段第五次Scrum Meeting 敏捷开发起始时间 2015/12/17 00:00 A.M. 敏捷开发终止时间 2015/12/17 23 ...

  5. 剑指offer:栈的压入、弹出序列

    题目描述: 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该 ...

  6. 基于python的机器学习实现日元币对人民币汇率预测

    ## 导入所需的包 import pandas as pd import numpy as np import matplotlib.pyplot as plt import tensorflow a ...

  7. wifi

    当自己流量不够用时,总想用点免费的wifi 但大部分的wifi都是需要密码的,所以,搜到一款软件,wifi万能钥匙,它的好处就是可以破解一些密码比较简单的wifi,相反,有利也有弊,因为大部分连接的还 ...

  8. css3新增的伪类和伪元素

    E:target事件属性可返回事件的目标节点(触发该事件的节点),如生成事件的元素.文档或窗口 E:disabled表示不可点击的表单控件 E:enabled表示可点击的表单控件 E:checked表 ...

  9. JetBrains系列WebStorm等中文输入法无法跟随光标的问题的解决办法

    参考:https://blog.csdn.net/wang414300980/article/details/79537875 电脑配置: 解决这个问题的思路就是修改启动软件的JDK,有以下几个方法: ...

  10. [转帖] Kubernetes如何使用ReplicationController、Replica Set、Deployment管理Pod ----文章很好 但是还没具体操作实践 也还没记住.

    Kubernetes如何使用ReplicationController.Replica Set.Deployment管理Pod https://blog.csdn.net/yjk13703623757 ...