基本介绍
1)平衡二叉树也平衡二叉搜索树又称为AVL树,可以保证查询效率较高。
2)具有以下特点:它是一棵空树或它的左右子树高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。
应用案例-单旋转(左旋转)
1)要求:给你一个数列,创建对应平衡二叉树数列{4,3,6,5,7,8}
思路:①创建一个新的节点newNode(以4这个之创建)创建一个新的节点,值等于当前的节点的值。
②把新节点的左子树设置为当前的节点的左子树。
③把新节点的右子树设置为当前节点的右子树的左子树。
④把当前节点的值换为右子节点的值
⑤把当前节点的右子树设置成右子树的右子树。
⑥把当前节点的左子树设置为新节点。
代码实现:
//左旋转方法
public void leftRotate(){
// 创建新的结点,以当前根结点的值
Node newNode=new Node(value);
// 把新的结点的左子树设置成当前结点的左子树
newNode.left=left;
// 把新的结点的右子树设置成带你过去结点的右子树的左子树
newNode.right=right.left;
// 把当前结点的值替换成右子结点的值
value=right.value;
// 把当前结点的右子树设置成当前结点右子树的右子树
right=right.right;
// 把当前结点的左子树(左子结点)设置成新的结点
left=newNode;
}
应用案例-单旋转(右旋转):
要求给你一个数列,创建一个数列,创建对应的平衡二叉树数列{10,12,8,9,7,6}
思路分析:
①创建一个新的节点 ,值等于当前根节点的值
②把新节点的右子树设置了当前节点的右子树。
③把新节点的左子树设置了当前节点的左子树的右子树。
④把当前节点的值换为左子树节点的值
⑤把当前节点的左子树设置成左子树的左子树
⑥把当前的节点右子树设置为新节点
示意图:
代码实现:
// 右旋转
public void rightRotate(){
// 创建新的结点,以当前根结点的值
Node newNode=new Node(value);
// 把新节点的右子树设置了当前节点的右子树。
newNode.right=right;
// 把新节点的左子树设置了当前节点的左子树的右子树。
newNode.left=left.right;
// 把当前节点的值换为左子树节点的值
value=left.value;
// 把当前节点的左子树设置成左子树的左子树
left=left.left;
// 把当前的节点右子树设置为新节点
right=newNode;
}
双旋转
前面的两个数列,进行单旋转就可以将非平衡二叉树转成平衡的二叉树,但是在某些情况下,单旋转不能完成平衡二叉树转换。比如数列int[]arr={10,11,7,6,8,9} ,并没有转成AVL树。
解决思路分析
①当符号右旋转的条件时。
②如果它的左子树的右子树高度大于它的左子树的高度。
③先对当前这个节点的左子节点进行左旋转。
④在对当前这个节点进行右旋转的操作即可。
上述的全部代码实现:
package com.lut.excise.tree;
public class AVLTree {
public static void main(String[] args) {
int[] arr = { 10, 11, 7, 6, 8, 9 };
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()); //3
System.out.println("树的左子树高度=" + avlTree.getRoot().leftHeight()); // 2
System.out.println("树的右子树高度=" + avlTree.getRoot().rightHeight()); // 2
System.out.println("当前的根结点=" + avlTree.getRoot());//8
}
private Node root;
public Node getRoot() {
return root;
}
// 添加结点的方法
public void add(Node node){
if(root==null){
root=node;// 如果root为空则直接让root指向node
}else {
root.addNode(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;
}
// 返回左子树的高度
public int leftHeight(){
if(left==null){
return 0;
}else {
return left.height();
}
}
// 返回右子树的高度
public int rightHeight(){
if(right==null){
return 0;
}else {
return right.height();
}
}
//左旋转方法
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 height(){
return Math.max(left==null?0:left.height(),right==null?0:right.height())+1;
}
// 添加结点的方法
// 递归的形式添加结点,注意需要满足二叉排序树的要求
public void addNode(Node node){
if(node==null){
return;
}
// 判断传入的结点的值,和当前子树的根结点的值关系
if(node.value<this.value){
// 如果当前结点左子结点为null
if(this.left==null){
this.left=node;
}else {// 递归的向左子树添加
this.left.addNode(node);
}
}else {// 添加的结点的值大于等于 当前结点的值
if(this.right==null){
this.right=node;
}else {
// 递归的向右子树添加
this.right.addNode(node);
}
}
// 当添加完一个结点后,如果: (右子树的高度-左子树的高度) > 1 , 左旋转
if(rightHeight()-leftHeight()>1){
//如果它的右子树的左子树的高度大于它的右子树的右子树的高度
if(right!=null&&right.leftHeight()>right.rightHeight()){
// 先对右子结点进行右旋转
right.rightRotate();
// 然后在对当前结点进行左旋转
leftRotate();
}else {
// 直接进行左旋转即可
leftRotate();
}
return;
}
//当添加完一个结点后,如果 (左子树的高度 - 右子树的高度) > 1, 右旋转
if(leftHeight()-rightHeight()>1){
// 当添加完一个结点后,如果 (左子树的高度 - 右子树的高度) > 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();
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
}