红黑树

【转】各种二叉树

断了今生、忘了曾经 提交于 2019-12-06 16:05:22
数据库中的数据一般是放在磁盘里面,存取数据的时候就要访问磁盘, 物理访问过程:盘片旋转,磁臂移动 两个过程。盘片旋转到指定位置之后,移动磁臂开始进行数据的存取。 那么存取数据的时间(快慢)主要是在哪部分消耗呢?主要就是 定位 过程消耗的。 所以:考虑到提高存取数据的速率,实际上就是减少磁盘定位(I/O操作)的次数。 来举个例子。来 顺序查找 。 查找5的时候,从头到尾的遍历,一共需要定位5次。不用再赘述,显然这样的顺序查找是最低效的。 为了提高效率,来 二叉树 。 二叉树的规范我就不说了, 一共6个数,无论查找哪个数,最多也就定位3次。 嗯,既然二叉树这么方便,那大家都用二叉树好了。额,其实图一那种情况,也算是二叉树,那算是一种情况。如果无法保证提高效率的稳定性,那这种结构还是不好。 (在这里记录一个知识点) 先序,中序,后序遍历。说一点就好,这里的先中后,说的是根节点。 为了提升稳定性,来 平衡二叉树 。 平衡二叉树用平衡因子差值来判断是否平衡,并旋转二叉树。平衡因子:左右子树高度差。平衡二叉树里平衡因子不能超过1,否则旋转。 长叹一口气,这样稳定了吧? 稳定是稳定,但是为了二叉树的稳定,牺牲了一些更重要的东西——时间。 当新增删除数据导致的旋转二叉树时,很耗时间的! 所有的操作的目的都是为了节省时间,提高效率。这样操作舍本逐末了。但也不是丝毫没有可取之处。 使用场景

数据结构解析-HashMap

回眸只為那壹抹淺笑 提交于 2019-12-06 06:28:11
概要 HashMap在JDK1.8之前的实现方式 数组+链表,但是在JDK1.8后对HashMap进行了底层优化,改为了由 数组+链表+红黑树实现,主要的目的是提高查找效率。 如图所示: JDK版本 实现方式 节点数>=8 节点数<=6 1.8以前 数组+单向链表 数组+单向链表 数组+单向链表 1.8以后 数组+单向链表+红黑树 数组+红黑树 数组+单向链表 HashMap 1.继承关系 public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable 2.常量&构造方法 //这两个是限定值 当节点数大于8时会转为红黑树存储 static final int TREEIFY_THRESHOLD = 8; //当节点数小于6时会转为单向链表存储 static final int UNTREEIFY_THRESHOLD = 6; //红黑树最小长度为 64 static final int MIN_TREEIFY_CAPACITY = 64; //HashMap容量初始大小 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 //HashMap容量极限 static final int

从2-3-4树模型到红黑树实现

只谈情不闲聊 提交于 2019-12-06 06:26:32
目录 从2-3-4树模型到红黑树实现 前言 2-3-4树 查找 插入 树的生长 删除 左倾红黑树 查找 插入 删除 总结 参考文献 从2-3-4树模型到红黑树实现 前言 红黑树,是一个高效的二叉查找树。其定义特性保证了树的路径长度在黑色节点上完美平衡,使得其查找效率接近于完美平衡的二叉树。 但是红黑树的实现逻辑很复杂,各种旋转,颜色变化,直接针对其分析,大多数都是死记硬背各种例子,不太容易有个直观的理解。实际上,红黑树是实现手段,是其他概念模型为了方便在二叉树上实现进而定义的节点颜色这个信息。如果从概念模型入手,再一一对应,就容易理解的多了。而红黑树能够对应的模型有2-3树,2-3-4树等,下面我们会以2-3-4树作为概念模型,对红黑树进行分析。 2-3-4树 2-3-4树是对完美平衡二叉树的扩展,其定义为: 在一个节点中,可以存在1-3个 key 。 2-节点,拥有1个 key 和2个子节点。 3-节点,拥有2个 key 和3个子节点。 4-节点,拥有3个 key 和4个子节点。 子节点为空的节点称为叶子节点。 任意从根节点到叶子节点的路径拥有相同的长度,即路径上的链接数相同。 下图就是一个2-3-4树: 查找 2-3-4树的查找很简单,类似于二叉树,步骤如下: 将查找 key 和节点内的 key 逐一对比。 如果命中,则返回节点内 key 的对应值。 如果节点内的 key

HashMap深入浅出

ⅰ亾dé卋堺 提交于 2019-12-06 05:34:06
HashMap数据结构   HashMap的本质就是一个数组加链表,数组默认长度是16,存储的元素达到总长度的75%就会扩容一倍。map.put(key,val),实际上就是根据hash散列对数组长度取模,来均匀的打到每一个下标上,填满数组每个下标位。但世事不可能这么完美,可能两个元素经过hash取模后下标会一样,为了避免hash冲突,hashmap就维护了一个链接的数据结构,相同下标的元素存到一个链表中。但是这样get(key)的时候会有一个问题,如果仅仅只是get数组上的元素速度会很快,但是get链表上的元素就会非常耗时,假使链表的深度为n,那么get所需的时间复杂度就是O(N),所以jdk1.8的时候做了一个优化,就是在原有的数据结构中加了一个红黑树,当链表的长度>=8时,会转成红黑树。    为何初始容量要是2的整数次幂 /** * The default initial capacity - MUST be a power of two. */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16   这是jdk8中的初始容量,同时告诉我们默认的初始容量-必须是2的幂。可是我们创建 HashMap<String,String> map = new HashMap<String,String>(7);

并发容器之ConcurrentHashMap(JDK 1.8版本)

本秂侑毒 提交于 2019-12-06 05:27:57
1.ConcurrentHashmap简介 在使用HashMap时在多线程情况下扩容会出现CPU接近100%的情况,因为hashmap并不是线程安全的,通常我们可以使用在java体系中古老的hashtable类,该类基本上所有的方法都采用synchronized进行线程安全的控制,可想而知,在高并发的情况下,每次只有一个线程能够获取对象监视器锁,这样的并发性能的确不令人满意。另外一种方式通过Collections的 Map<K,V> synchronizedMap(Map<K,V> m) 将hashmap包装成一个线程安全的map。比如SynchronzedMap的put方法源码为: public V put(K key, V value) { synchronized (mutex) {return m.put(key, value);} } 实际上SynchronizedMap实现依然是采用synchronized独占式锁进行线程安全的并发控制的。同样,这种方案的性能也是令人不太满意的。针对这种境况,Doug Lea大师不遗余力的为我们创造了一些线程安全的并发容器,让每一个java开发人员倍感幸福。相对于hashmap来说,ConcurrentHashMap就是线程安全的map,其中利用了锁分段的思想提高了并发度。 ConcurrentHashMap在JDK1

【集合系列】- 深入浅出分析HashMap

痞子三分冷 提交于 2019-12-06 02:36:43
一、摘要 在集合系列的第一章,咱们了解到,Map的实现类有HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties等等。 关于HashMap,一直都是一个非常热门的话题,只要你出去面试,我保证一定少不了它! 本文主要结合JDK1.7和JDK1.8的区别,就HashMap的数据结构和实现功能,进行深入探讨,废话也不多说了,直奔主题! 二、简介 在程序编程的时候,HashMap是一个使用非常频繁的容器类,它允许键值都放入null元素。除该类方法未实现同步外,其余跟Hashtable大致相同,但跟TreeMap不同,该容器不保证元素顺序,根据需要该容器可能会对元素重新哈希,元素的顺序也会被重新打散,因此不同时间迭代同一个HashMap的顺序可能会不同。 HashMap容器,实质还是一个哈希数组结构,但是在元素插入的时候,存在发生hash冲突的可能性; 对于发生Hash冲突的情况,冲突有两种实现方式, 一种开放地址方式(当发生hash冲突时,就继续以此继续寻找,直到找到没有冲突的hash值),另一种是拉链方式(将冲突的元素放入链表) 。 Java HashMap采用的就是第二种方式,拉链法。 在jdk1.7中,HashMap主要是由数组+链表组成,当发生hash冲突的时候

从物联网防火墙himqtt源码谈哈希和红黑树的应用场景区别

落爺英雄遲暮 提交于 2019-12-06 01:53:14
从物联网防火墙 himqtt 源码谈哈希和红黑树的应用 场景区别 himqtt 是首款完整源码的高性能 MQTT 物联网防火墙 - MQTT Application FireWall , C 语言编写,很多数据结构适合初学者收藏。 哈希和红黑树的详细教程很多,本文就不重复了,但初学者往往云里雾里,不知道实战项目该用谁,今天笔者就从结合 himqtt 的源码,从物联网安全角度来对比一下哈希数据结构和红黑树的应用场景。 一、哈希和红黑树基本原理 哈希( hash )也称散列,通过散列算法变成固定的输出到数组,所有的线性数据结构中,数组的定位速度最快,因为它可通过数组下标直接定位到相应的数组空间,就不需要一个个查找。 红黑树的自旋是天才的设计,是一种特殊的平衡二叉树数据结构,特点也是从几十万的数据里面几步就能查找到,速度快。 二、物联网安全使用场景 首先 github 上下载源码, https://github.com/qq4108863/himqtt ,在 src\waf 目录有 hashmap.c 和 mqtt_rbtree.c ,分别是哈希和红黑树算法。 1 、速度对比 物联网可能是数百万设备联网,对高并发要求很大,所以,对网络安全产品第一要求的是性能和速度。总体来说,哈希查找速度会比红黑树快,而且查找速度基本和数据量大小无关,属于常数级别 ; 而 RB 树的查找速度是 log(n

DS 红黑树详解

一个人想着一个人 提交于 2019-12-05 23:52:08
   通过上篇博客知道,二叉搜索树的局限在于 不能完成自平衡 ,从而导致不能一直保持高性能。     AVL树 则定义了 平衡因子 绝对值不能大于1,使二叉搜索树达到了 严格的高度平衡 。        还有一种能自我调整的二叉搜索树,     红黑树 : 通过标记节点的颜色(红/黑),使其拥有自平衡的二叉搜索树。         红黑树性质 : 性质1:每个节点要么是黑色,要么是红色。 性质2:根节点是黑色。 性质3:每个叶子节点(NIL)是黑色。 性质4:每个红色结点的两个子结点一定都是黑色。 性质5:所有路径都包含数量相同的黑结点     这些约束强制了红黑树的 关键性质 : 红黑树没有一条路径会比其他路径的两倍长(同一起点) 。所以 这个树大致上是平衡的 ,不会像二叉搜索树出现极端情况。     是性质4和5导致路径上确保了这个结果。最短的路径只有黑色节点,最长路径有交替的红色和黑色节点。因为所有的路径黑色节点数量相同,所以没有路径能多于任何其他路径的两倍长。         红黑树节点定义: enum Colour { RED, BLACK, }; template<class K,class V> class RBtreeNode { RBtree<K,V>* _left; RBtree<K,V>* _right; RBtree<K,V>* _parent; pair

STL关联式容器

帅比萌擦擦* 提交于 2019-12-05 12:20:59
关联式容器的特征:所用元素都会根据元素的键值自动被排序。 set STL 中的关联式容器低层数据结构为红黑树,其功能都是调用低层数据结构中提供的相应接口。 set元的元素不会像map那样同时拥有键(key)和值(value)。 set元素的键就是值,值就是键,并不允许两个元素有相同的键。 multiset允许相同键值存在。 因为set元素的键和值相等,所以不允许对set元素的值进行修改。(数据结构会根据key对元素进行排序,对value的更改会改变树中元素的排列顺序)。 set容器提供的迭代器为 const iterator; set类的声明: template <class _Key, class _Compare, class _Alloc> class set; set类含三个模板参数,键类型_Key,键比较方法_Compare,分配器类型_Alloc;平时经常用到的是第一个模板参数:键类型_Key,如: set<int> iset={1,2,3,4,5}; 另外两个模板参数在特殊的应用场景上会发挥作用。_Compare模板参数可以指定容器中元素的比较方法,根据容器存放元素的大小,可修改内存分配策略_Alloc。这两个参数都可已通过设置set的构造函数参数来进行指定: explicit set(const _Compare& __comp, const allocator

Java集合源码之HashMap

纵饮孤独 提交于 2019-12-05 07:39:27
1. 简介 HashMap是一个哈希表,线程不安全, key 唯一, value 可重复,允许 key 和 value 为null。遍历时是无序的。 底层结构是基于链表散列,也就是数组+链表。数组也被称为哈希桶,桶里面就装着链表,链表中的每个节点,就是哈希表中的每个元素。 在JDK8中,当链表长度达到8的时候,就会转为红黑树。 它实现了 Map<K, V>, Cloneable, Serializable 接口。 接下来我们就来看下源码: 2. 属性 // 序列化ID,用于序列化和反序列化 private static final long serialVersionUID = 362498820763181265L; // 默认初始容量也就是16-必须为2的幂。 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 // 最大容量。 // 如果两个构造函数都使用参数隐式指定了更高的值,则使用该容量。 // 必须是2的30次方。 static final int MAXIMUM_CAPACITY = 1 << 30; // 默认的负载因子 static final float DEFAULT_LOAD_FACTOR = 0.75f; // Entry数组,也就是哈希桶,长度为2的n次幂 transient