java treeset 红黑树_【数据结构】红黑树与跳表-(SortSet)-(TreeMap)-(TreeSet)
SortSet
有序的Set,其实在Java中TreeSet是SortSet的唯一实现类,内部通过TreeMap实现的;而TreeMap是通过红黑树实现的;而在Redis中是通过跳表实现的;
SkipList
跳表,思想类似平衡二叉树,但又不一样;下面摘了一个介绍:
skiplist数据结构简介(摘自:https://www.cnblogs.com/Elliott-Su-Faith-change-our-life/p/7545940.html)
skiplist本质上也是一种查找结构,用于解决算法中的查找问题(Searching),即根据给定的key,快速查到它所在的位置(或者对应的value)。
我们在《Redis内部数据结构详解》系列的第一篇中介绍dict的时候,曾经讨论过:一般查找问题的解法分为两个大类:一个是基于各种平衡树,一个是基于哈希表。但skiplist却比较特殊,它没法归属到这两大类里面。
这种数据结构是由William Pugh发明的,最早出现于他在1990年发表的论文《Skip Lists: A Probabilistic Alternative to Balanced Trees》。对细节感兴趣的同学可以下载论文原文来阅读。
skiplist,顾名思义,首先它是一个list。实际上,它是在有序链表的基础上发展起来的。
我们先来看一个有序链表,如下图(最左侧的灰色节点表示一个空的头结点):
在这样一个链表中,如果我们要查找某个数据,那么需要从头开始逐个进行比较,直到找到包含数据的那个节点,或者找到第一个比给定数据大的节点为止(没找到)。也就是说,时间复杂度为O(n)。同样,当我们要插入新数据的时候,也要经历同样的查找过程,从而确定插入位置。
假如我们每相邻两个节点增加一个指针,让指针指向下下个节点,如下图:
这样所有新增加的指针连成了一个新的链表,但它包含的节点个数只有原来的一半(上图中是7, 19, 26)。现在当我们想查找数据的时候,可以先沿着这个新链表进行查找。当碰到比待查数据大的节点时,再回到原来的链表中进行查找。比如,我们想查找23,查找的路径是沿着下图中标红的指针所指向的方向进行的:
23首先和7比较,再和19比较,比它们都大,继续向后比较。
但23和26比较的时候,比26要小,因此回到下面的链表(原链表),与22比较。
23比22要大,沿下面的指针继续向后和26比较。23比26小,说明待查数据23在原链表中不存在,而且它的插入位置应该在22和26之间。
在这个查找过程中,由于新增加的指针,我们不再需要与链表中每个节点逐个进行比较了。需要比较的节点数大概只有原来的一半。
利用同样的方式,我们可以在上层新产生的链表上,继续为每相邻的两个节点增加一个指针,从而产生第三层链表。如下图:
在这个新的三层链表结构上,如果我们还是查找23,那么沿着最上层链表首先要比较的是19,发现23比19大,接下来我们就知道只需要到19的后面去继续查找,从而一下子跳过了19前面的所有节点。可以想象,当链表足够长的时候,这种多层链表的查找方式能让我们跳过很多下层节点,大大加快查找的速度。
skiplist正是受这种多层链表的想法的启发而设计出来的。实际上,按照上面生成链表的方式,上面每一层链表的节点个数,是下面一层的节点个数的一半,这样查找过程就非常类似于一个二分查找,使得查找的时间复杂度可以降低到O(log n)。但是,这种方法在插入数据的时候有很大的问题。新插入一个节点之后,就会打乱上下相邻两层链表上节点个数严格的2:1的对应关系。如果要维持这种对应关系,就必须把新插入的节点后面的所有节点(也包括新插入的节点)重新进行调整,这会让时间复杂度重新蜕化成O(n)。删除数据也有同样的问题。
skiplist为了避免这一问题,它不要求上下相邻两层链表之间的节点个数有严格的对应关系,而是为每个节点随机出一个层数(level)。比如,一个节点随机出的层数是3,那么就把它链入到第1层到第3层这三层链表中。为了表达清楚,下图展示了如何通过一步步的插入操作从而形成一个skiplist的过程(点击看大图):
从上面skiplist的创建和插入过程可以看出,每一个节点的层数(level)是随机出来的,而且新插入一个节点不会影响其它节点的层数。因此,插入操作只需要修改插入节点前后的指针,而不需要对很多节点都进行调整。这就降低了插入操作的复杂度。实际上,这是skiplist的一个很重要的特性,这让它在插入性能上明显优于平衡树的方案。这在后面我们还会提到。
根据上图中的skiplist结构,我们很容易理解这种数据结构的名字的由来。skiplist,翻译成中文,可以翻译成“跳表”或“跳跃表”,指的就是除了最下面第1层链表之外,它会产生若干层稀疏的链表,这些链表里面的指针故意跳过了一些节点(而且越高层的链表跳过的节点越多)。这就使得我们在查找数据的时候能够先在高层的链表中进行查找,然后逐层降低,最终降到第1层链表来精确地确定数据位置。在这个过程中,我们跳过了一些节点,从而也就加快了查找速度。
刚刚创建的这个skiplist总共包含4层链表,现在假设我们在它里面依然查找23,下图给出了查找路径:
需要注意的是,前面演示的各个节点的插入过程,实际上在插入之前也要先经历一个类似的查找过程,在确定插入位置后,再完成插入操作。
至此,skiplist的查找和插入操作,我们已经很清楚了。而删除操作与插入操作类似,我们也很容易想象出来。这些操作我们也应该能很容易地用代码实现出来。
当然,实际应用中的skiplist每个节点应该包含key和value两部分。前面的描述中我们没有具体区分key和value,但实际上列表中是按照key进行排序的,查找过程也是根据key在比较。
红黑树:
这个介绍就多了,总结一下,一个自平衡的二叉查找树。
java treeset 红黑树_【数据结构】红黑树与跳表-(SortSet)-(TreeMap)-(TreeSet)相关推荐
- rsa算法c语言实现_数据结构与算法之线性表-顺序表实现(C语言版本)
原文托管在Github: https://github.com/shellhub/blog/issues/52 数据结构与算法之线性表-顺序表实现(C语言版本) 前言 数据结构与算法是一个程序员必备的 ...
- 数据结构和算法之——跳表
之前我们知道,二分查找依赖数组的随机访问,所以只能用数组来实现.如果数据存储在链表中,就真的没法用二分查找了吗?而实际上,我们只需要对链表稍加改造,就可以实现类似"二分"的查找算法 ...
- 数据结构与算法学习--跳表
跳表 Skip List是一种随机化的数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间).基本上,跳跃列表是对有序的链表增加上附加的前进链接,增加是以随机 ...
- 二叉查找树 平衡二叉查找树 红黑树 b树 b+树 链表 跳表 链表
https://www.cnblogs.com/mojxtang/p/10122587.html二叉树的新增遍历查找 转载于:https://www.cnblogs.com/wangjing666/p ...
- java单链表输出_数据结构基础------1.线性表之单链表的创建与输出方法(Java版)...
基础知识: 线性表(linear list),是其组成元素间具有线性关系的一种线性结构. 线性表有 ①顺序存储结构(sequential storage structure) 顺序存储结构可以简单的理 ...
- java链表的用法_数据结构(java语言描述)链表的使用
1.定义node类,实现Node结点的构造函数(空结点和指定数值的结点),基本的获取结点的指针域,数据域,设置指针域,数据域. package class2; public class Node { ...
- java冒泡测试代码_数据结构与算法—冒泡排序(Java实现)
[toc] 冒泡排序 程序代码package com.uplooking.bigdata.datastructure;import java.util.Arrays;public class Bubb ...
- java冒泡法优化_数据结构java版之冒泡排序及优化
冒泡排序的时间用大O表示法是O(N^2). 传统的冒泡排序: /** * @param total 要排序的数组长度 */ public void sort(int total){ int num[] ...
- 数据结构java学生成绩排序_数据结构学习--Java简单排序
冒泡排序需要元素每次遍历都从最底部向上冒泡,找到适合的位置后,该位置之后的元素继续向上冒,这样一趟排序结束后,将冒出最大或者最小值. 选择排序需要元素从0号位开始向上遍历一遍,并将最小值放到0号位上, ...
最新文章
- windows下:ERROR 1366 (HY000): Incorrect string value: ‘\xC1\xF5\xB1\xB8‘ for column ‘name‘ at row 1
- linux中创建本地yum库,轻松安装Linux软件
- NOIp2018 Mission Failed Level F
- 中国氢能行业发展现状与投资规划深度研究报告2022-2027年版
- python加减乘除符号_Python项目如何合理组织规避import天坑
- python基础篇——元组
- 中国土壤厚度空间分布数据
- 惠普136nw打印机清零_HP惠普打印机清零大全
- bp神经网络预测案例python_详细BP神经网络预测算法及实现过程实例
- c语言程序设计数字电位器,可编程数字电位器在AVR单片机中的应用
- 【VRP问题】基于节约算法CW求解带容量的车辆路径规划问题(CVRP)
- 校招行测笔试-言语理解与表达
- 黄山学院计算机科学与技术怎么样,黄山学院怎么样?黄山学院点评及最新评价情况...
- java 将对象置空_Java 中将对象引用置 null 的作用?
- 2022年电工(初级)国家题库及在线模拟考试
- 831数据结构与c语言试题,2018年广东工业大学计算机院831数据结构与C语言[专硕]之C程序设计考研核心题库...
- “气球” 的最大数量
- Matlab求解李雅普诺夫(Lyapunov)方程
- 你还停留在使用Dagger2吗? 带你一步一步走进Dagger2的世界
- 电子词典的实现(一)
热门文章
- ServiceStack.Redis的问题与修正
- 人还是很需要成就感的
- pytorch实现性别检测
- 深入学习Java8 Lambda (default method, lambda, function reference, java.util.function 包)
- 快给你的app上锁吧(android图案解锁)
- 开博首发2017年1月13日开博大吉
- 《Node.js入门》Windows 7下Node.js Web开发环境搭建笔记
- SpringMVC _Controller认识(1)
- Yoda 表示法错在哪里
- 数据库-ADONET-在数据集DataSet中使用关系对象DataRelation处理关系