本文已参与「新人创作礼」活动,一起开启掘金创作之路。
平衡二叉树 - 双旋转(左右旋转)
进行单旋转(即一次旋转)就可以将非平衡二叉树转成平衡二叉树, 但是在某些情况下,单旋转不能完成平衡二
叉树的转换
双旋转原因分析
- 符合右旋转的条件
- 它的左子树的右子树的高度大于它的左子树的高度
- 对当前这个结点的左节点进行左旋转
- 再对当前结点进行右旋转
package com.avl;
/**
* @author Kcs 2022/9/18
*/
public class AvlTreeDemo {
public static void main(String[] args) {
//左旋转数组
int[] arrLeft = {4, 3, 6, 5, 7, 8};
//右旋转数组
int[] arrRight = {10,12, 8, 9, 7, 6};
//双旋转数组
int[] arrDouble = {10,11, 7, 6, 8, 9};
AvlTree avlTree = new AvlTree();
for (int i = 0; i < arrDouble.length; i++) {
avlTree.add(new Node(arrDouble[i]));
}
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);
}
}
/**
* AVL树
*/
class AvlTree {
private Node root;
public Node getRoot() {
return root;
}
/**
* 添加结点
* @param node 结点
*/
public void add(Node node) {
if (root == null) {
root = node;
} else {
root.add(node);
}
}
/**
* 中序遍历
*/
public void infixOrder() {
if (root != null) {
root.infixOrder();
} else {
System.out.println("二叉排序树为空!!");
}
}
}
/**
* 结点
*/
class Node {
/**
* 值
*/
int value;
/**
* 左右结点
*/
Node left;
Node right;
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node{" + "value=" + value + '}';
}
/**
* 返回当前节点的高度,以该节点为根节点的树的高度
* @return 节点的高度
*/
public int height() {
return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
}
/**
* 返回左子树的高度
* @return 左子树高度
*/
public int leftHeight() {
if (left == null) {
return 0;
}
return left.height();
}
/**
* 返回右子树的高度
* @return 右子树高度
*/
public int rightHeight() {
if (right == null) {
return 0;
}
return right.height();
}
/**
* 左旋转
*/
private void leftRotate() {
//1.创建一个新结点newNode,值为当前根节点值
Node newNode = new Node(value);
//2.将新节点的左子树设置为当前节点的左子树
newNode.left = left;
//3.将新节点的右子树设置为当前节点的右子树的左子树
newNode.right = right.left;
//4.将当前节点的值换为右子节点的值
value = right.value;
//5.将当前节点的右子树设置为右子树的右子树
right = right.right;
//6.将当前节点的左子树设置为新节点
left = newNode;
}
/**
* 右旋转
*/
private void rightRotate() {
// 1. 创建一个新结点newNode,值为当前根节点值
Node newNode = new Node(value);
// 2. 将新节点的右子树设置为当前节点的右子树
newNode.right = right;
// 3. 将新节点的左子树设置为当前节点的左子树的右子树
newNode.left = left.right;
// 4. 将当前节点的值为右子节点的值
value = left.value;
// 5. 将当前节点的左子树设置为左子树的左子树
left = left.left;
// 6. 将当前节点的右子树设置为新节点
right = newNode;
}
/**
* 添加结点
* 递归添加结点,满足二叉排序树
* @param node 结点信息
*/
public void add(Node node) {
//结点为空
if (node == null) {
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();
}else {
//不满足,直接进行左旋转
leftRotate();
}
return;
}
//左子树的高度 - 右子树的高度 > 1,则进行右旋转
if (leftHeight() - rightHeight() > 1) {
//它的左子树的右子树的高度大于它的左子树的高度
if (left != null && left.rightHeight() > left.leftHeight()) {
//当前结点的左子树,进行左旋转
left.leftRotate();
//当前结点进行右旋转
rightRotate();
}else {
//直接进行右旋转
rightRotate();
}
}
}
/**
* 中序遍历
*/
public void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.println(this);
if (this.right != null) {
this.right.infixOrder();
}
}
}