红黑树
红黑树 其实就是一个二叉树。php
经常使用的二叉树类型
简单说二叉树概念:二叉树 又称度为至多二的树。
平衡二叉树微信
平衡二叉树又称 AVL 树
特色:一个根节点的左右个子树的高度差不超过1数据结构
平衡二叉树app
非平衡二叉树spa
高度差已经大于1 了。
平衡树解决的问题就是 可以最大限度的增长访问的每一个节点的的平均性
。保证每一个节点被访问的次数平衡。.net
彻底二叉树
除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺乏右边的若干结点。
堆排序 结构其实就是一个彻底二叉树的结构,倒序和正序就是用的 大根堆 小根堆的原理。3d
满二叉树
每一个节点是叶节点或者度为2.
code
查找二叉树
这种树的特色是 每一个根节点大于左子树上的任意一个节点,小于等于右子树上的任意一个节点。
举个简单例子:
好比说 我如今要查找 4 这个数字 ,首先 我先比较 根节点就行,若是比根节点小的话,那么确定在左边的子树列表里面。那么右边的就不用看了。而后依次同理比较。
查找二叉树 可以提升查询速度的效率。orm
可是还有一种状况 比较特殊:
这样的 比较尴尬了,一边倒的状况它也知足查找二叉树的概念。可是效率就不那么高效了。blog
在说原理以前说一下
高度与深度区别:
1.深度定义是从上往下的
2.高度定义是从下往上的
3.空数高度0
4.叶子结点高度1
红黑树原理
知足一个树是红黑树条件:
1.每一个节点要么是红色,要么是黑色。
2.根节点必须是黑色
3.红色节点不能连续(红色节点的孩子和父亲都不能都是红色)
4.从任意节点出发,到其全部叶子节点的简单路径上都包含相同数目的黑色节点.
5.每一个红色节点的两个子节点必定都是黑色(叶子节点包含NULL)
红黑树的结构
如图
红黑树从根节点到每一个叶子节点的路径都包含相同数量的黑色节点,所以从根节点到叶子节点的路径中包含的黑色节点数被称为树的“黑色高度(black-height)
一颗树黑色高度为3得红黑树,从根结点到叶结点的最短路径长度是3(黑-黑-黑),最长路径为4(黑-红-黑-红-黑)。因为第4条性质,不可能在最长路径中加入更多的黑色结点,由于性质3规定红色结点的子结点必须是黑色的,所以在同一简单路径中不容许有两个连续的红色结点。红黑树中最长路径就是一条红黑交替的路径
对于给定的黑色高度为n的红黑树,从根结点到叶结点的简单路径的最短长度为n-1,最大长度为2(n-1)。全部对树的操做必须保持上面列出的属性。特别要指出的是,插入和删除树的结点的操做必须遵循这些原则。
红黑树插入过程当中状况
每次插入元素的时候会将 元素 着色为红色。其目的为了快的知足红黑树的4个条件
红黑树结构不会旋转变化状况:
1.当插入的节点为的父亲为黑色节点。【什么都不用作】
2.被插入的节点是根节点。【直接把此节点涂为黑色】
红黑树结构发生旋转变化状况:
1. 当前节点的父节点【60】是红色,且当前节点的祖父节点【40】的另外一个子节点(叔叔节点)也是红色。
2.当前插入的父节点是红色,当前叔叔节点的黑色,且当前节点为其父亲节点的左孩子。(进行左旋)
3.当前插入的父节点是红色,当前叔叔节点的黑色,且当前节点为其父亲节点的右孩子。(进行右旋)
如图所示
红黑树结构发生旋转变化状况已经对应的措施以下
左旋 :右边过于臃肿
右旋 :左边过于臃肿
相对复杂的红黑树 旋转最大不超过3次
下面展现一个红黑树插入数据过程
树的旋转问题
为何会出现旋转?
对于平衡树来讲,当插入或者删除的时候,树的结构会发生破坏所以会致使。所以须要对树进行旋转来保证树的平衡。
先拿 平衡二叉树的 查找二叉树举一个例子:
此时当前二叉树 是新增一个60数字红色。此时 当前二叉树不平衡了,那么须要进行左旋 须要把当前40 那个节点做为跟节点,而后把30和20 旋转下来。
此时你们发现这样仍是会有问题。发现又不知足二叉树了,如今变三叉了,不要急 ,此时再次挑战须要把中间的 33 那个分支砍掉,接在哪边呢?根据查找二叉树的规则,比根节点小的放在左边,比根节点大的放在右边。33 比40 小 可是 比30 大。如图
红黑树应用
TreeMap 典型红黑树
TreeSet
左旋代码:
右旋代码:
插入元素:
//左旋右侧须要平衡 private void rotateLeft(Entry<K,V> p) { if (p != null) { //拿到根节点的右子节点 Entry<K,V> r = p.right; //把根节点的右子节点的左节点,赋值 p.right = r.left; if (r.left != null) //将根节点这个值赋值到当前断开的跟节点上 r.left.parent = p; //r 未来要成为新的根节点 p.parent 为根 ,使得他为新的跟节点 r.parent = p.parent; if (p.parent == null) root = r; //若是p 为左孩子,让他仍是成为左孩子 同理 else if (p.parent.left == p) p.parent.left = r; else p.parent.right = r; //最后 将当前交换的跟换值 r.left = p; p.parent = r; } }
private void rotateRight(Entry<K,V> p) { if (p != null) { Entry<K,V> l = p.left; p.left = l.right; if (l.right != null) l.right.parent = p; l.parent = p.parent; if (p.parent == null) root = l; else if (p.parent.right == p) p.parent.right = l; else p.parent.left = l; l.right = p; p.parent = l; } }
public V put(K key, V value) { Entry<K,V> t = root; if (t == null) { compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null); size = 1; modCount++; return null; } int cmp; Entry<K,V> parent; // split comparator and comparable paths Comparator super K> cpr = comparator; if (cpr != null) { do { parent = t; cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } else { if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable super K> k = (Comparable super K>) key; do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } Entry<K,V> e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; fixAfterInsertion(e); size++; modCount++; return null; }
红黑树的优点
红黑树可以以O(log2(N))的时间复杂度进行搜索、插入、删除操做。此外,任何不平衡都会在3次旋转以内解决。这一点是AVL所不具有的,是很是高效的数据结构。
本文分享自微信公众号 - WHICH工做室(which_cn)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。