二叉树、红黑树理解

摘要:
在理解红黑树之前,首先了解下一个二叉树的特征。左右子树也是二进制排序树。因此,基于这种情况,引入了一种平衡二叉树,而红黑树只是其中一种平衡的二叉树。红黑树的几个特征1.节点是黑色或红色的。4.每个红色子节点必须是黑色的,即没有两个连续的红色节点。推荐一个超级链接,在线构建红黑树:https://rbtree.phpisfuture.com/会发现,当红黑树的特性不满足时,红黑树的规则将通过旋转来满足。红黑树的旋转参考链接:https://blog.csdn.net/u011240877/article/details/53329023#%E6%8C%87%E5%AE%9A%E8%8A%82%E7%82%B9-X-%E7%9A%84%E5%B7%A6%E6%97%8B-%E5%8F%B3%E5%9B%BE%E8%BD%AC%E6%88%90%E5%B7%A6%E5%9B%BEx节点左手p:xr:yif(p!

  在理解红黑树之前,先了解下二叉树的特性。

  (1)左子树上节点的值小于等于其根节点的值。(2)右子树上节点的值大于等于其根节点的值。(3)左、右子树也分别为二叉排序树。

   如下图所示,比如我们要查询8 ,第一次9>8,所以找到了9的左子树5;第二次8>5,找到了5的右子树7;第三次7<8,找到了7的右子树8。其实就是利用了二分法的特性进行了查询,时间复杂度也在lgN。

 二叉树、红黑树理解第1张

   但是也会有那种不平衡的二叉树,就是左子树深度和右子树深度存在明显的差异,那这样我们要查询一棵树的话,可能要一直遍历下去,如下图所示,则要一直遍历其右子树。这样查询的时间复杂度将趋近于n。和数组查询某个元素的值的时间复杂度相同了。所以基于这种情况,引入了平衡二叉树,而红黑树正好是平衡二叉树的一种。

二叉树、红黑树理解第2张

  红黑树的几个特性

  1.节点是黑色或者红色。
  2.根节点是黑色的。
  3.所有得叶节点都是黑色,(这里说得都说NULL节点)。

  4.每个红色的子节点一定都是黑色,也就是不存在两个连续的红色节点。

  5.从任意节点到其每个子节点的所有路径都包含相同数目的黑色节点。

  推荐一个超nice的链接,在线构造红黑树:https://rbtree.phpisfuture.com/   会发现当不满足红黑树特性得时候,会通过旋转来达到符合红黑树得规则。 红黑树得旋转参考链接:https://blog.csdn.net/u011240877/article/details/53329023#%E6%8C%87%E5%AE%9A%E8%8A%82%E7%82%B9-x-%E7%9A%84%E5%B7%A6%E6%97%8B-%E5%8F%B3%E5%9B%BE%E8%BD%AC%E6%88%90%E5%B7%A6%E5%9B%BE

二叉树、红黑树理解第3张

x节点左旋(右图转到左图)
p: x
r: y
if(p!= null){
	Entry<K,V> r = p.right;
	 p.right = r.left;
	 if(r.left != null){
		r.left.parent = p;  //设置β的父亲为x
	 }
	 r.parent = p.parent;	//设置y的父亲是x的父亲
	if(p.parent == null){   //如果x没有父亲,则y就是最老得根节点
		root = r
	}else if(p.parent.left == p){ //如果x有父亲并且它是它父亲得左孩子,则x得父亲认y为左孩子
		p.parent.left = r;
	}else{
		p.parent.rgiht = r;  //如果x是它父亲得右孩子,父亲就认y为右孩子
	}	
	r.left = p;			//y逆袭成功,x成为了它得左孩子
	p.parent = r;
}


节点y得右旋(左图转到右图)
p:x 
r:y 
if(r != null){
	Entry<K,V> p = r.left;
	r.left = p.right
	if(p.right != null){
		p.right.parent = r;    //设置β的父亲为y
	}	
	p.parent = r.parent;
	if(r.parent == null){		//判断y是否存在父节点,若不存在,则x升级为根节点
		root = p;
	}else if(r.parent.left == r){ //若y存在父节点,并且是其父节点得左子树得话,那么x升级为y得父节点得右左节点
		r.parent.left = p;
	}else{
		r.parent.right = p;		 //若y存在父节点,并且是其父节点得右子树得话,那么x升级为y得父节点得右节点
	}
	p.right = r;				//x升级成功,y成了x得右节点
	r.parent = p;				//y得父节点更新为x

}

  

  总结: (1)当插入一个节点时,默认是红色得。如果当父节点也是红色,则向上递归换色。如果跟节点变为红色,则对其旋转,旋转方向根据左右节点深度,若左节点过深,则向右旋转;之后再从根节点,依次向下修改颜色 。

      (2)从根节点到红色节点,符合得路径上面校验黑色节点数量是否一致,,如果不一致,那同样和(1)中一样,先旋转,再修改颜色。  前面推荐得链接,尽量多试试,有助于理解。

免责声明:文章转载自《二叉树、红黑树理解》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Oracle11g温习-第九章:表空间和数据文件管理JAVA虚拟机体系结构下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(四)

一、红黑树 1、红黑树 2、红黑树复杂度 3、使用红黑树的模块 1、本地内存做的红黑树 ngx_conf_module ngx_event_timer_rbtree #管理定时器的红黑树 2、管理定时器的红黑树 Ngx_http_file_cache Ngx_http_geo_module Ngx_http_limit_conn_module Ng...

C 工具库8:map

本篇介绍另外一个在C++ stl中常用的容器map.我打算将map的实现容器和map接口分开,创建map的时候可以传递一个实现了interface_map_container接口的对象指针进来,如果这个参数传0,则默认使用红黑树做实际的容器.这样做的好处是用户可以根据性能需求传递自己定制的容器类.例如在游戏程序中常见的数据表.一般通过一个索引查询,并且在程...

BZOJ 3217: ALOEXT (块状链表套trie)

第一次写块状链表,发现还挺好写的,但是一点地方写错加上强制在线就会各种姿势WA/TLE/RE爆… 想法就是分块后,在每一个块上维护最大值和次大值,还在每一个块上维护一棵trie树来求异或最大值.散块直接暴力…这想法暴力吧…这道题不用考虑合并,因为最多分出(n+q)/Bsz块.详细的做法如下 对于修改一个数,首先在该块的trie数中删除该数(直接伪删,也就是...

深入理解HashMap第一篇

HashMap 1.描述 HashMap是常用的Java集合之一,是基于哈希表的Map接口的实现。设计目标是尽量实现哈希表O(1)级别的增删改查效果,与HashTable主要区别为不支持同步和允许null作为key和value。 各项默认值 初始容量(capacity):16(1<<4),即2^4。 最大容量:(1<<30),即...

redis 在 php 中的应用(key篇)

本文为我阅读了redis参考手册之后结合博友的博客编写,注意 php_redis 和 redis-cli 的区别(主要是返回值类型和参数用法) 目录: KEY(键) DEL EXISTS EXPIRE EXPIREAT keys MOVE PERSIST TTL RANDOMKEY RENAME RENAMENX TYPE SORT KEY(...

排序算法时间复杂度的下界

《算法导论》中有一节讲的是“(比较)排序算法时间的下界”,本文将论述同一个问题,思路略有差异。本文将从信息熵的角度论述排序算法时间复杂度的下界。若本文论述过程中有错误或是不足,还请各位指正。 1. 问题归约     排序,涉及到被排序的序列和排序的方法。(比较)排序算法时间的下界对被排序的序列和排序方法做了以下限制 没有关于被排序序列的先验信息,譬如序列...