诶,算法这个东西,其实没那么简单,但是也没那么难。
红黑树,其实已经有很多大佬都整理过了,而且文章博客都写得超好,我写这篇文章的目的是:自己整理一次,这些知识才是自己的,否则永远是别人的~
该系列已经全部更完,有5篇文章:
【算法】红黑树(二叉树)概念与查询(一):https://blog.csdn.net/lsr40/article/details/85230703
【算法】红黑树插入数据(变色,左旋、右旋)(二):https://blog.csdn.net/lsr40/article/details/85245027
【算法】红黑树插入数据的情况与实现(三):https://blog.csdn.net/lsr40/article/details/85266069
【算法】红黑树删除数据(寻找继承人)(四):https://blog.csdn.net/lsr40/article/details/85322371
【算法】红黑树删除数据(最后一步,平衡红黑树)(五):https://blog.csdn.net/lsr40/article/details/86711889
本文先讲讲概念和查询!
本人菜鸡,如果文中有误,还请各位批评指出!!!一定加以改正(虽然可能会解释得不清楚,但是绝对不能误导新人)!
关于数据存储结构,无非就是增删改查(数据库不就是这样),对于红黑树来说改不就相当于把原来的值remove(删除),然后再put(插入/新增)一个新的值,所以主要还是了解增删查!
一、概念
1、类似红黑树的这种树状结构有什么用?
可以用来快速解决一些查询问题,大家请看图
二叉树基本性质:二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。
用自己的话总结下:
1、有一个根节点
2、每个节点都有两个分支
3、最下面的节点叫叶子节点
所以如果把数据变成二叉树就可以直接看到最左边的叶子节点是最小值,最右边的叶子节点是最大值,而且我们在遍历的时候,我只需要遍历3次就可以找到我想要的值!
2、相同的数据可以构成很多颗二叉树啊,哪种是最好的,哪种是最坏的?
如下两图
获得最大值和最小值的遍历次数,似乎变多了?而且整个二叉树的高度变高了,但是这两张图,好像也没有违反二叉树的任何规则,所以我们发现如果二叉树偏向严重的话,会导致效率变低,当全部偏成一条的时候,效率是最差的,大概如图:
所以除了最后一层树枝上(总体的最后一层是叶子,所以最后一层树枝就是总体的倒数第二层),可以不用都存在左右节点,其他的树枝上最好都存在左右子节点,也就是不偏的二叉树,效率会比偏的二叉树效率高!(合理的高度应该是:,就是以2为底的logN,N就是数组的size,我的例子中有9个数,所以合理的高度应该是4层)
3、我听说过什么用中序,前序,后序遍历二叉树是干嘛的?
这里就不再介绍中序,前序,后序是如何遍历的了,就直接说应用在哪里!
-1.前序遍历:可以用来实现目录结构的显示。
-2.中序遍历:一颗树,被中序遍历之后,就是value从小到大的排列,当然也可以用来做表达式树,在编译器底层实现的时候用户可以实现基本的加减乘除,比如 a*b+c。
-3.后序遍历:可以用来实现计算目录内的文件占用的数据大小。
4、红黑树和二叉树又有什么区别?
红黑树是一种特殊的二叉树!
我们也发现,相同数据生成的二叉树形状各异,有些性能好,有些性能差,红黑树是一种自平衡二叉树,就是在每次插入新的数据的时候,红黑树会进行变色和旋转来使生成的树不会出现偏的情况
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的,也就是说不可能出现两个连续的红色节点,不过两个连续的黑色节点是可能出现的
(5)从任意一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
后两条特性才是最关键的!
当然,如果您觉得我的翻译不够准确的话,可以看看英文原文
(1)Each node is either red or black.
(2)The root is black. This rule is sometimes omitted. Since the root can always be changed from red to black,but not necessarily vice versa, this rule has little effect on analysis.
(3)All leaves (NIL) are black.
(4)If a node is red, then both its children are black.
(5)Every path from a given node to any of its descendant NIL nodes contains the same number of black nodes.
英文wiki地址:https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
二、查询
红黑树的查询和普通的二叉树查询是一样的,当我想查某个数的时候,只需要把这个数从根节点比较,如果比根节点大,那就继续比较根节点的右节点,否则就是根节点的左节点,以此类推。
java中的TreeMap底层就是实现红黑树。
一起来看看java是怎么实现的?
//在TreeMap的277行,get方法
public V get(Object key) {
//通过getEntry方法,获得对应的p点
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
//在342行getEntry方法
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
//将传入的key,变成一个可比较的类型,赋值为k
Comparable<? super K> k = (Comparable<? super K>) key;
//前面的判断是获得比较器,然后获得root也就是根节点p
Entry<K,V> p = root;
//进入循环,一直到p为空才停止
while (p != null) {
int cmp = k.compareTo(p.key);
//如果传入的key比根节点小,p重新赋值,p变为该节点的左节点
if (cmp < 0)
p = p.left;
else if (cmp > 0)
//如果传入的key比根节点大,p重新赋值,p变为该节点的右节点
p = p.right;
else
//如果不大于也不小于,证明找到该值,就将该值return
return p;
}
//如果遍历结束,都没有进入到 return p,证明传入的key不存在,直接返回null
return null;
}
所以查询是最简单的,只要是二叉树,都是这种查询方式!
那么本篇的内容也说完了。
总结:
1、二叉树是什么,有什么用?
简答:将N个数据插入到一颗二叉树中,来减少迭代的次数,加快查询
2、二叉树中的前序,中序,后序遍历是什么?
简答:按照一定的顺序遍历二叉树,各有各的应用场景
3、红黑树又是什么,它有哪些性质,为什么会有红黑树出现?
简答:二叉树有可能会偏,导致查询性能不能达到理想的优化,红黑树是自平衡二叉树,每次插入新的数据的时候,会变色和旋转,来让高度保持在这个合理高度内
4、java中treemap是如何实现红黑树的查询的?
简答:如代码所示
5、分享一个生成红黑树的网站!
http://sandbox.runjs.cn/show/2nngvn8w
好了,本人菜鸡一只,也在继续学习中,接下来会更新红黑树的插入(红黑树的删除我可能也会更吧,但是其实我现在也还没搞太明白,希望过段时间能清晰的搞懂),如果我有什么笔误的地方,还望大家批评指出,尽量做到不误导新人!有什么问题,大家也可以留言讨论~