平衡二叉树的实现(java代码)
平衡二叉树引出和介绍:
平衡二叉树的创建图解过程:
AVL树代码实现(java)
package com.bingym.temp01.avl;
public class AvlTreeDemo {
/*
* 平衡二叉树:AVL树:是由排序二叉树存在的一些问题导致的
* 它是一颗空树或者左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树
* 下面的代码我们将实现通过二叉排序树===>左右旋转(或者双旋转)得到平衡二叉树:
* */
public static void main(String[] args) {
//int[] arr = {10, 11, 7, 6, 8, 9};
int[] arr = {8,7,11,10,12,9};
//创建一颗AVL树
AVLTree avlTree = new AVLTree();
//添加结点
for (int i = 0; i < arr.length; i++) {
avlTree.add(new Node(arr[i]));
}
//进行中序遍历
System.out.println("该AVL树中序遍历结果为:");
avlTree.infixOrder();
System.out.println("该AVL树的高度为:" + avlTree.getRoot().height());
System.out.println("该AVL树的左子树的高度:" + avlTree.getRoot().leftHeight());
System.out.println("该AVL树的右子树的高度:" + avlTree.getRoot().rightHeight());
System.out.println("该AVL树的根节点" + avlTree.getRoot());
}
}
//定义平衡二叉树
class AVLTree {
private Node root;
public Node getRoot() {
return root;
}
// 添加结点的方法
public void add(Node node) {
if (root == null) {
root = node;// 如果root为空则直接让root指向node
} else {
root.add(node);
}
}
// 中序遍历
public void infixOrder() {
if (root != null) {
root.infixOrder();
} else {
System.out.println("二叉排序树为空,不能遍历");
}
}
}
//定义结点类Node
class Node {
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
//中序遍历的方法
public void infixOrder() {
//左子树递归遍历
if (this.left != null) {
this.left.infixOrder();
}
//输出当前结点
System.out.println(this);
//右子树递归遍历
if (this.right != null) {
this.right.infixOrder();
}
}
//结点的添加方法
public void add(Node node) {
if (node == null) {
//首先判断添加的结点是否为空,若为空,直接返回
return;
}
if (node.value < this.value) {//如果传入结点的value值小于当前根节点的value值
if (this.left == null) {//若当前根节点的左子树为空
this.left = node;
}else {
this.left.add(node);//递归地向左子树添加
}
}else {//如果传入结点的value值大于(或者等于)当前根节点的value值
if (this.right == null) {
this.right = node;
}else {
this.right.add(node);//递归地向右子树添加
}
}
//按照二叉排序树的规则添加完结点以后:需要判断当前树是否进一步满足AVL树的要求
if (this.rightHeight() - this.leftHeight() > 1) {
//当添加完一个结点后,如果: (右子树的高度-左子树的高度) > 1 , 左旋转
/*
* 在进行左旋转之前,我们需要判断它的右子树的左子树高度是否大于它的右子树的右子树的高度
* 即是否需要进行双旋转
* */
if (this.right != null && this.right.leftHeight() > this.right.rightHeight()) {
//进行双旋转
//1.先对它的右子结点(右子树)进行右旋转
this.right.rightRotate();
//2.然后再对当前结点进行左旋转
this.leftRotate();
}else {
//直接进行左旋转
this.leftRotate();
}
//****处理完毕,直接返回,不然会进入下面进行右旋转的代码! ! !
return;
}
if (this.leftHeight() - this.rightHeight() > 1) {
//当添加完一个结点后,如果 (左子树的高度 - 右子树的高度) > 1, 右旋转
/*
* 进行右旋转之前,我们需要先判断它的左子树的右子树的高度是否大于它的左子树的左子树的高度
* 即是否进行双旋转
* */
if (this.left != null && this.left.rightHeight() > this.right.leftHeight()) {
//进行双旋转
//1.先对它的左子结点(左子树)进行左旋转
this.left.leftRotate();
//2.再对当前结点进行右旋转
this.rightRotate();
}else {
this.rightRotate();
}
}
}
//返回以该结点为根节点的树的高度
public int height() {
return Math.max(this.left == null ? 0 : this.left.height(),this.right == null ? 0 : this.right.height()) + 1;//比较左子树和右子树的最大高度 + 1
}
//返回左子树的高度
public int leftHeight() {
if (this.left == null) {
return 0;
}else {
return this.left.height();
}
}
//返回右子树的高度
public int rightHeight() {
if (this.right == null) {
return 0;
}else {
return this.right.height();
}
}
/*
* 左旋转:当添加结点时:左子树的高度rightHeight - leftHeight > 1时,我们需要进行左旋转进行二叉树的调整
* 使其满足AVL树的条件
* 1)创建一个新的结点newNode:使其value值等于当前结点的值
* 2)把新结点的左子树设置为当前结点的左子树:newNode.left = this.left;
* 3)把新结点的右子树设置为当前结点的右子树的左子树:newNode.right = this.right.left;
* 4)把当前结点的值换成右子结点的值:this.value = this.right.value;
* 5)把当前结点的右子树设置为右子树的右子树:this.right = this.right.right;
* 6)把当前结点的左子树设置为新结点this.left = newNode;
* */
public void leftRotate() {
//1)创建一个新的结点newNode:使其value值等于当前结点的值
Node newNode = new Node(value);
//2)把新结点的左子树设置为当前结点的左子树:newNode.left = this.left;
newNode.left = this.left;
//3)把新结点的右子树设置为当前结点的右子树的左子树:newNode.right = this.right.left;
newNode.right = this.right.left;
//4)把当前结点的值换成右子结点的值:this.value = this.right.value;
this.value = this.right.value;
//5)把当前结点的右子树设置为右子树的右子树:this.right = this.right.right;
this.right = this.right.right;
//6)把当前结点的左子树设置为新结点this.left = newNode;
this.left = newNode;
}
/*
* 右旋转:当添加结点时:左子树的高度leftHeight - rightHeight > 1时,我们需要进行右旋转进行二叉树的调整
* 1)创建一个新的结点:值为当前结点的value值
* 2)把新结点的右子树设置为当前结点的右子树:newNode.right = this.right;
* 3)把新结点的左子树设置为当前结点的左子树的右子树:new.left = this.left.right;
* 4)把当前结点的值换成左子结点的值:this.value = this.left.value;
* 5)把当前结点的左子树设置为左子树的左子树:this.left = this.left.left;
* 6)把当前结点的右子树设置为新结点this.right = newNode;
* */
public void rightRotate() {
//1)创建一个新的结点:值为当前结点的value值
Node newNode = new Node(value);
//2)把新结点的右子树设置为当前结点的右子树:newNode.right = this.right;
newNode.right = this.right;
//3)把新结点的左子树设置为当前结点的左子树的右子树:newNode.left = this.left.right;
newNode.left = this.left.right;
//4)把当前结点的值换成左子结点的值:this.value = this.left.value;
this.value = this.left.value;
//5)把当前结点的左子树设置为左子树的左子树:this.left = this.left.left;
this.left = this.left.left;
//6)把当前结点的右子树设置为新结点this.right = newNode;
this.right = newNode;
}
}