红黑树是一颗二叉平衡查找树。
一般情况下,二叉查找树的操作执行时间为O(lgn),但是,在二叉查找树中为有序的数据后,例如递增的全在右子树上,递减的都在左子树上,就会退化成一个具有n个节点的线性链,运行时间就会变成O(n)。红黑树的出现就会使树变的相对平衡,使之时间复杂度稳定在O(lgn)。
使用情况:不断地有数据插入
性质: 每个节点不是红色就是黑色 根节点总是黑色 如果节点是红色,则它的子节点必是黑色的 从根节点到叶节点的每条路径,黑高相同
红黑树的三种修正方式 ①变色 ②左旋 ③右旋
左旋操作:对x左旋,x的右子节点为y ①y的左子节点赋值给x的右节点,并将x赋值给y左子节点(不为空)的父节点。 ②x的父节点赋值给y的父节点,并更改父节点的指向(父节点左右子节点为y)。 ③将y的左子节点设为x,x的父节点设置为y 右旋操作:对y右旋,y的左子节点为x ①将x的右子节点赋值给y的左子节点,同时将y赋值给x右子节点的父节点 ②y的父节点赋值给x的父节点,同时更改父节点的指向(左右子节点为x) ③将x的右子节点设为y,y的父节点设为x 插入操作 ①找到插入位置(二叉搜索树) ②判断插入节点是左子节点还是右子节点 ③插入节点,修正树 注:第一次插入,不需要调整,只需要把根节点涂黑; 插入节点的父节点是黑色的,不需要调整 修正操作(插入节点的父节点是红色的) ①插入节点的父节点和叔叔节点均为红色 调整:将当前节点的父节点和叔叔节点涂黑,祖父节点涂红,当前节点指向祖父节点继续判断。 ②插入节点的父节点是红色,叔叔节点是黑色,且插入节点是父节点的右子节点 调整:将当前节点的父节点作为新的节点,对其进行左旋操作。 ③插入节点的父节点是红色,叔叔节点是黑色,且插入节点是父节点的左子节点 调整:将当前节点的父节点涂黑,祖父节点涂红,在祖父节点进行右旋。 根节点涂黑 变色>左旋>右旋
//对x进行左旋操作 public void leftRotate(RBNode<T> x){ RBNode<T> y=x.right;//左旋操作将x的右节点赋值给y //第一步:y的左子节点赋值给x的右子节点,y的左子节点不为空时将x赋值给y左子节点的父节点(即为y) x.right=y.left; if(y.left!=null){ y.left.parent=x; //??????????? } //第二步:将x的父节点p(非空时)赋值给y的父节点,同时更新p的子节点为y(左或者右) y.parent=x.parent; if(x.parent!=null){ if(x.parent.left==x){ x.parent.left=y; }else { x.parent.right=y; } }else { this.root=y;//Y为根节点 } //第三步:将y的左子节点设为x,x的父节点设为y y.left=x; x.parent=y; }
//对y进行you旋操作 public void rightRotate(RBNode<T> y){ RBNode<T> x=y.left; //1.将x的右子节点赋值给y的左子节点,并且x.right!=null时,将x复制给 y.left=x.right; if(x.right!=null){ x.right.parent=y; ////???????????????? } //2.将y的父节点赋值给x的父节点,同时更新父节点的左右指向 x.parent=y.parent; if(y.parent==null){ this.root=y; }else{ if(y.parent.left==y){ y.parent.left=x; }else{ y.parent.right=x; } } //3 x,y的只想 y.parent=x; x.right=y; }