这是我参与更文挑战的第16天,活动详情查看: 更文挑战 😄
每日一题~~~
特性: 性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3.所有叶子都是黑色。(叶子是NUIL节点)
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5.. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
简单的说: 根黑、叶黑、子黑、黑的数目相同、要么黑要么红
插入:
今天撸了红黑树的插入操作,希望多记忆几次,牢固记忆。
package com.jd.platform.async.algorithm.redblacktree;
/**
* @author 我就是你
* @version 1.0
* @date 2021/6/16 0013 17:13
*/
public class RBTree {
TreeNode head; //树的头节点
//创建红色的默认节点,但是未设置父节点
public TreeNode getNode(int val) {
TreeNode defaultNode = new TreeNode(val);
defaultNode.color = Color.RED; //默认为红色
return defaultNode;
}
//打印树
public void printTree(TreeNode node) {
if(head==null) {
System.out.println("树是空的,请确认init()方法已经执行!");
return ;
}
if(node==null) return ;
else {
//前序遍历
System.out.print("节点的值:"+node.val+" 节点的颜色:"+node.color);
if(node.parent!=null) System.out.println(" 节点的父节点:"+node.parent.val);
else System.out.println(" 这是根节点");
printTree(node.left);
printTree(node.right);
}
}
/*************************************************minit**************************************************/
//树的初始化
public void init(int[] arr) {
for(int i=0;i<arr.length;++i) {
insert(head,null,arr[i],-1);
}
}
//inset 开始插入 ,lr为0代表left lr为1代表right lr为-1表示是根节点
public void insert(TreeNode head,TreeNode parent,int i,int lr) {
if(head==null) {
TreeNode x = getNode(i);
x.parent=parent;
head = x;
if(lr==1) parent.right = head;
else if(lr==0) parent.left = head;
insert1(head);
}
else { //递归插入
if(i>head.val) insert(head.right,head,i,1);
if(i<head.val) insert(head.left,head,i,0);
}
}
//case1:插入的节点为根节点,将插入节点置为红色,前期x的父节点x.parent必须确定下来
public void insert1(TreeNode x) {
if(x.parent==null) {
x.color = Color.BLACK;
head = x; //将首节点指向x
return ;
} else insert2(x);
}
//case2:插入的节点不为根节点
//且插入的节点的父节点为黑色的,那么红黑树是不用调节的
public void insert2(TreeNode x) {
if(x.parent.color==Color.BLACK) return ;
else insert3(x);
}
//case3如果插入节点的父节点为红色 ,违反父子节点都为红色的
// 如果叔叔节点为红色,只需将叔叔节点和父节点同时设为黑色,同时祖父节点设为红色
//但这会引入新问题,祖父节点和其自身父节点有可能都为红色,使用尾递归向上上滤
public void insert3(TreeNode x) {
TreeNode par = x.parent; //父节点
TreeNode gra = par.parent; //祖父节点
TreeNode unc = (par==gra.left)? gra.right : gra.left; //叔叔节点
if(unc!=null && unc.color==Color.RED) {
unc.color = Color.BLACK;
par.color = Color.BLACK;
gra.color = Color.RED;
insert1(gra); //尾递归上滤
} else insert4(x);
}
//case4: 如果叔叔节点为黑色或者null
public void insert4(TreeNode x) {
TreeNode par = x.parent; //父节点
TreeNode gra = par.parent; //祖父节点//如果父节点是祖父节点的左节点,但x是父节点的右节点,交换x和其父节点,且x变为其原父节点的父节点
if(par==gra.left && x==par.right) {
gra.left = x;
x.left = par;
x.parent = gra;
par.right = null;
par.parent = x;
insert5(par);
}
//如果父节点是祖父节点的右节点,但是x是父节点的左节点,交换x和其父节点,且x变为祖父节点的右节点
else if(par==gra.right && x==par.left) {
gra.right = x;
x.right = par;
x.parent = gra;
par.left = null;
par.parent = x;
insert5(par);
}
else {
insert5(x); //因为这个x节点有可能变为父节点了,所以要在insert5进行判断是否为变换后的父节点
}
}
public void insert5(TreeNode x) {
TreeNode par = x.parent; //父节点
TreeNode gra = par.parent; //祖父节点
TreeNode ggra = gra.parent; //祖父节点的父节点
if(x==par.left) {
gra.left = par.right;
par.right = gra;
par.parent = ggra;
gra.parent = par;
if(gra.left!=null) gra.left.parent = gra; //如果节点不为空更新父节点信息
//ggra.left = par;
if(ggra==null) head = par;
else {
if(par.val>ggra.val) ggra.right = par;
else ggra.left = par;
}
}
else if(x==par.right) {
//if(x.val==12) System.out.println("12的父节点的左节点:"+par.left.val);
gra.right = par.left;
par.left = gra;
par.parent = ggra;
gra.parent = par;
if(gra.right!=null) gra.right.parent = gra; //要更新父节点信息
if(ggra==null) head = par; //根节点要重新指向
else {
if(par.val>ggra.val) ggra.right = par;
else ggra.left = par;
}
}
//颜色变化
gra.color = Color.RED;
par.color = Color.BLACK;
}
/*************************************************main**************************************************/
public static void main(String[] args) {
int[] arr = {5,3,1,7,9,6,15,12,14,13};
RBTree rbt = new RBTree();
rbt.init(arr);
rbt.printTree(rbt.head);
}
//红黑树节点
private class TreeNode{
Color color=Color.RED;
int val;
TreeNode left;
TreeNode right;
TreeNode parent;
TreeNode(int value) {
val = value;
}
}
//树节点枚举类
private enum Color{
RED,BLACK;
}
}
总结:
case1:插入的节点为根节点,将插入节点置为红色
case2:插入的节点不为根节点
且插入的节点的父节点为黑色的,那么红黑树是不用调节的
case3如果插入节点的父节点为红色 ,违反父子节点都为红色的
如果叔叔节点为红色,只需将叔叔节点和父节点同时设为黑色,同时祖父节点设为红色
但这会引入新问题,祖父节点和其自身父节点有可能都为红色,使用尾递归向上上滤
case4: 如果叔叔节点为黑色或者null
如果父节点是祖父节点的左节点,但x是父节点的右节点,交换x和其父节点,且x变为其原父节点的父节点
如果父节点是祖父节点的右节点,但是x是父节点的左节点,交换x和其父节点,且x变为祖父节点的右节点
真心感谢帅逼靓女们能看到这里,如果这个文章写得还不错,觉得有点东西的话
求点赞👍 求关注❤️ 求分享👥 对8块腹肌的我来说真的 非常有用!!!
如果本篇博客有任何错误,请批评指教,不胜感激 !❤️❤️❤️❤️