为甚么要诞生平衡二叉排序树?
因为一般的二叉树,面对有序数组,会变得很畸形。
这种就是畸形而且诡异的东西。
平衡二叉树的核心是要平衡,一个二叉排序树如果不平衡,我们需要通过旋转的方式让它变得平衡,不然肯定不行啊同志。
一定要清楚知道二叉树的,左右高度。
左右高度差,小于2就是平衡的,大于2就不平衡了。
先进行分类一共4个分类
找到出问题那个节点的父亲节点,你的孩子影响了高度,你就要承担责任·,需要找到父亲节点。
找到出问题节点的父亲节点。然后根据父亲节点的位置,判定是什么问题类型?是rr?rl?ll ?还是Lr
这种是左子树比右子树长
这个分类主要是看,哪个树,孩子,影响了高度问题。
出问题的节点就是那个影响了,深度的节点。
比如ll,
确定好影响二叉树高度的那个点,看看那个需要被修剪的枝叶是在根节点的左左,还是右右。上图明显是左左。
需要通过旋转来进行,让二叉树平衡起来。
前面都是左边树太多,要通过右旋转,解决问题
这种属于右边太多,右旋解决问题。
直接这么解决左旋不就完了???
两种最复杂情况
先右旋,再左旋,丢给别人去背锅。让部下背锅
右旋之后,实际上已经变成了rr情况,这样左旋就行了。
左旋转步骤
原来的6这个节点,没有指向,所以会被垃圾回收掉。
不过这种方法很傻逼,我觉得前文提到的那个就鸠占鹊巢,才是,最好的解决方案
这就是鸠占鹊巢,之所以要让6继承4的领地,是因为4的领地是有上面的指针直接指向的,你要直接让6继承4的一切势力范围,包括4背后的东西,你都要继承过来,最好的办法就是你自己带上9筒,装成4的样子,这样才能把4背后东西都继承过来。
直接让根节点的右指针指向右子树的左节点
然后让右子树的左指针指向自己不就完了。?
本质还是,4带着小弟3,去占领了,6的小弟5的位置,5只能委屈巴巴的当了4的小弟,而6伪装成了4的样子,带上9筒,装成了4。
比如上图这种直接这样解决就行。
调整的就是红线部分
最重要的是,还要把指在
这就是比较简单的左旋。
二叉树介绍
package org.example.sort;
public class HeroNode{
//实现这个接口之后,可以按照你想要方式进行排序
public int no;
public HeroNode left;
public HeroNode right;
public HeroNode(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", left=" + left +
", right=" + right +
'}';
}
public HeroNode() {
}
public void infoxOrder(){
if(this == null){
return;
}
//中序遍历
//左根右
if(this.left != null){
this.left.infoxOrder();
}
System.out.print(this.no + " ");
if(this.right != null){
this.right.infoxOrder();
}
}
//根节点交给树里面那个方法去进行判断,我不管了
//默认进来就是好的
public HeroNode delNode(HeroNode parent,int typeflag,int value){//带着父节点进来
//typeflag确保我们知道父亲是往哪里递归的
//typeflag = 1往左递归,0往右递归
if(this == null){
return new HeroNode(-1);
}
else if(this.no == value){
if(typeflag == 1){//父类向左递归过来
parent.left = this.left == null ? this.getRight() : this.getLeft();
//如果子节点左边为空,那就等于右节点
}
else {
//父类向右递归过来的
parent.right = this.left == null ? this.getRight() : this.getLeft();
}
return this;
}
else if(this.no >= value){
//往左递归
parent = this;//递归前保留当前节点作为父亲节点
typeflag = 1;
if(this.left == null){
return new HeroNode(-1);
}
return this.left.delNode(parent,typeflag,value);
}
else if(this.no < value){
parent = this;
typeflag = 0;
if(this.right == null){
return new HeroNode(-1);
}
return this.right.delNode(parent,typeflag,value);
}
return new HeroNode(-1);
}
// //树的高度就是递归看
// //每一棵树的高度都是,向左递归看到左子树,向右递归看看右子树,
// public int height(){
// //树的高度题目
// //输的高度本质就是看看左子树,和右子树深度,返回最大那个值
// return Math.max(this.left == null ? 0 : this.left.height(),this.right == null ? 0 : this.right.height()) + 1;//
//
//查一下左子树的高度
//前面二叉树哪里,会处理一下High初始值得问题的
public int height(int high){//代表高度
int resultHigh;//作为返回结果的高度
int leftHight = 0;//代表左子树高度
int rightHight = 0;//右子树高度
if(this.left == null && this.right == null){
//循环终止条件
resultHigh = high;//左右子树都为null那么就返回当前深度
}
else{
if(this.left != null){
//递归得到左子树高度
leftHight = this.left.height(high + 1);//每次递归深度加1
}
if(this.right != null){
//递归得到右子树高度
rightHight = this.right.height(high + 1);
}
resultHigh = Math.max(leftHight,rightHight);//每个节点都是一颗二叉树,比较一下,左右子树高度然后返回高度
}
return resultHigh;
//向左向右递归,得到左右子树高度
//然后进行比较
}
//对头节点左旋转,麻烦的在于还要估计,被旋转的根节点上面还有人,所以我们只能给他带上9筒。让他继承实力范围。
public void leftRotate(){
//左旋转
HeroNode newNode = new HeroNode(this.no);//创建新节点,将原来根节点值放进去
newNode.left = this.left;
newNode.right = this.right.left;
this.no = this.right.no;//带上9筒,开始伪装
this.right.left = newNode;
this.right = this.right.right;
}
//添加进去一个节点
public void add(HeroNode node){
if(this == null){
return;//递归终止条件
}
//传递进来这个Node要自己找位置
//添加一个节点
//先判断一下和根节点的关系
if(this.no <= node.no){
if(this.right == null){
this.right = node;//大于根节点,并且根节点右边空着,直接挂上去
}
else
this.right.add(node);//否则当前节点带着Node向右递归
}
else{
if(this.left == null){
this.left = node;
}
else
this.left.add(node);
}
//添加完一个节点之后,如果右子树比左子树高,那么直接左旋
}
}
红黑树本质就是自平衡二叉树,就是每次加入一个节点之后,树都会自我遍历深度,倘若不平衡,会通过自我旋转来让树变成平衡二叉树。