左旋、右旋、双旋
package com.example.dataalgorithm.tree.avl;
/**
* @author qb
* @version 1.0
* @date 2022/3/5 15:06
*/
public class AvlTreeDemo {
public static void main(String[] args) {
// int[] arr ={4,3,6,5,7,8}; //左旋转
// int[] arr ={10,12,8,9,7,6}; //右旋转
//当符合右旋转的条件的时候,如果他的左子树的右子树高度大于他的右子树的高度
//先对当前节点的左节点先进行左旋转,然后再对当前节点进行向右旋转的操作
int[] arr ={10,11,7,6,8,9}; //双旋转
//创建一个AVLTree对象
AVLTree avlTree = new AVLTree();
for (int i = 0; i < arr.length; i++) {
avlTree.add(new Node(arr[i]));
}
System.out.println("中序遍历");
avlTree.infixOrder();
System.out.println("在做平衡处理之后");
System.out.println("树的高度:"+avlTree.getRoot().height());
System.out.println("树的左子高度:"+avlTree.getRoot().leftHeight());
System.out.println("树的右子高度:"+avlTree.getRoot().rightHeight());
System.out.println("当前的根节点:"+avlTree.getRoot());
System.out.println("当前的根节点的左节点:"+avlTree.getRoot().left);
System.out.println("当前的根节点的右节点:"+avlTree.getRoot().right);
}
}
class AVLTree{
private Node root;
public Node getRoot(){
return this.root;
}
public Node search(int value){
if(null == root){
return null;
}
else {
return root.search(value);
}
}
/**
* 1.以node为根节点的二叉排序树的最小节点的值
* 2. 删除node为根节点的二叉树的最小节点
* @param node 传入的节点 当做二叉排序树的根节点
* @return 以node为根节点的二叉排序树的最小节点的值
*/
public int delRightTreeMin(Node node){
Node target = node;
//循环的查找左节点,就会找的最小值
while (target.left != null){
target = target.left;
}
//这时target就指向了最小节点
//删除最小节点
delNode(target.value);
return target.value;
}
public Node searchParent(int value){
if(null == root){
return null;
}
return root.searchParent(value);
}
public void delNode(int value){
if(null == root){
return;
}else{
//1.需要去找到要删除的节点 targetNode
Node targetNode = search(value);
//如果要没找到
if(null == targetNode){
return;
}
//如果我们发现targetNode没有父节点
if(root.right == null && root.left == null){
root = null;
return;
}
//去找到targetNode的父节点
Node parent = searchParent(value);
//如果要删除的节点是叶子节点
if(null == targetNode.left && null== targetNode.right){
//判断targetNode是父节点的左子节点还是右子节点
if(null != parent.left && parent.left.value == value){
parent.left = null;
}
else if(null != parent.right && parent.right.value == value){
parent.right = null;
}
}
//
else if(targetNode.left != null && targetNode.right != null){
int minVal = delRightTreeMin(targetNode.right);
targetNode.value = minVal;
}
else {
//删除只有一颗子树的节点
//如果要删除的节点有左子节点
if(targetNode.left != null){
if(null != parent){
//如果targetNode是parent 的左子节点
if(null != parent.left && parent.left.value == value){
parent.left = targetNode.left;
}
else {
parent.right = targetNode.left;
}
}else{
root = targetNode.left;
}
}
//要删除的节点有右子节点
else {
if(null != parent){
//如果targetNode是parent的左子节点
if(null != parent.left && parent.left.value == value){
parent.left = targetNode.right;
}
else {
//如果targetNode是parent的右子节点
parent.right = targetNode.right;
}
}else{
root = targetNode.right;
}
}
}
}
}
public void add(Node node){
if(null == root){
root = node;
}
else {
root.add(node);
}
}
public void infixOrder(){
if(null != root){
root.infixOrder();
}else{
System.out.println("当前二叉排序树为空!");
}
}
}
/**
* 创建node节点
*/
class Node{
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
/**
* 左旋转
*/
public void leftRotate(){
//创建新的节点,以当前根节点的值
Node newNode = new Node(value);
//把新的节点的左子树设置成当前节点的左子树
newNode.left = left;
//把新的节点的右子树设置成当前节点的右子树的左子树
newNode.right = right.left;
//把当前节点的值替换成 右子节点的值
value = right.value;
//把当前节点的右子树,设置成当前节点的右子节点的右子节点
right = right.right;
//把当前节点的左子节点 设置成新的节点
left = newNode;
}
/**
* 右旋转
*/
public void rightRotate(){
Node newNode = new Node(value);
newNode.right = right;
newNode.left = left.right;
value = left.value;
left = left.left;
right = newNode;
}
/**
* 返回左子树的高度
*/
public int leftHeight(){
if(null == left){
return 0;
}
return left.height();
}
/**
* 返回右子树的高度
*/
public int rightHeight(){
if(null == right){
return 0;
}
return right.height();
}
/**
* 返回以该节点为根节点的树的高度
*/
public int height(){
return Math.max(left == null ? 0 : left.height(),right == null ? 0 : right.height()) + 1;
}
/**
* 查找要删除的节点
* @param value 期望删除的值
* @return 返回对应的节点
*/
public Node search(int value){
if(value == this.value){
return this;
}
else if(value < this.value){
//如果查找的值小于当前节点,则需要递归找左子树
if(null == this.left){
return null;
}
return this.left.search(value);
}
else{
//查找的值不小于,递归右子树
if(null == this.right){
return null;
}
return this.right.search(value);
}
}
/**
* 查找要删除节点的父节点
* @param value 要找的节点的值
* @return 返回的是要删除节点的父节点的值
*/
public Node searchParent(int value){
//如果当前节点就是要删除节点的父节点
if((null != this.left && this.left.value == value)
|| (null != this.right && this.right.value == value)){
return this;
}
else {
//如果查找的值小于当前的值,并且当前节点的左子节点不为空
if(value < this.value && null != this.left){
return this.left.searchParent(value);
}
else if(value >= this.value && null != this.right){
return this.right.searchParent(value);
}
else{
//没有找到父节点
return null;
}
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
/**
* 添加节点,递归形式添加节点
*/
public void add(Node node){
if(null == node){
return;
}
//判断传入的节点的值,和当前子树的根节点的值关系
if(node.value < this.value){
//如果当前节点左子节点为空
if(this.left == null){
this.left = node;
}else{
this.left.add(node);
}
}
else {
if(this.right == null){
this.right = node;
}
else{
this.right.add(node);
}
}
//当添加完一个节点后,如果右子树的高度 - 左子树的高度 > 1 使用左旋转
if(rightHeight() - leftHeight() > 1){
//如果他的右子树的左子树的高度大于他的右子树的右子树的高度
if(right != null && right.leftHeight() < right.rightHeight()){
//先对他的右子树进行旋转
right.rightRotate();
}
leftRotate();
return;
}
//当添加完一个节点后,如果 左子树的高度 - 右子树的导高度 > 1
if(leftHeight() - rightHeight() > 1){
//如果他的左子树的右子树的高度大于他的左子树
if(left != null && left.rightHeight() > left.leftHeight()){
//先对当前节点的左节点 -》 左旋转
left.leftRotate();
//在对当前节点进行右旋转
}
rightRotate();
}
}
/**
* 中序遍历
*/
public void infixOrder(){
if(this.left != null){
this.left.infixOrder();
}
System.out.println(this);
if(this.right != null){
this.right.infixOrder();
}
}
}