平衡二叉树(AVL树)的创建

二叉排序树存在的问题

假设有数列{1,2,3,4,5,6} 创建二叉排序树后如下图所示。下面的二叉排序树处在一些问题:
1、左子树全部为空,从形式上看更像单链表
2、查询速度明显降低不能发挥BST的优势,其查询效率还不如单链表
采用平衡二叉树可以避免这种情况的发生
在这里插入图片描述

平衡二叉树

平衡二叉树(AVL树)是一颗空树或者它的左右两个子树的高度差的绝对值不超过1并且左右子树也是平衡二叉树。AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
在这里插入图片描述

二叉树不平衡的情况

在结点插入过程中,由于任意两个结点最多只有两个儿子,因此高度不平衡时,结点的两颗子树的高度相差2.容易看出,这种不平衡可能出现在下面4中情况中
在这里插入图片描述

单旋转

下图动画展示的是左旋
在这里插入图片描述
在上述的4中情况中只有1、2可以通过一次左旋或者右旋得到平衡二叉树
在这里插入图片描述
在这里插入图片描述

双旋转

如果3、4两种情况仅仅只做一次旋转我们发现它还是一颗非平衡二叉树
在这里插入图片描述
而是需要两次旋转才能得到一颗平衡二叉树
在这里插入图片描述

左旋思路分析

(1)先创建一个值和要旋转子树的根结点值相同的新结点
(2)把要旋转的子树的根节点的左子树设置为新结点的左子树
(3)把根节点的右子树的左子结点设置成新结点的右子树
(4)把根节点的右子结点的值赋值给新结点
(5)把根节点的右子树的右子树设置成根结点的右子树
(6)把新结点设置成根节点的右子结点
右旋的思路与左旋差不多
在这里插入图片描述

代码

public class Node {

    private int value;
    private Node left;
    private Node right;

    public Node(int value){
        this.value = value;
    }

    /**
     * @return 返回当前结点的左子树的高度
     */
    public int leftHeight(){
        if (this.left == null) {
            return 0;
        }else {
            return this.left.height();
        }
    }

    /**
     * @return 返回当前结点的右子树的高度
     */
    public int rightHeight(){
        if (this.right == null) {
            return 0;
        }else {
            return this.right.height();
        }
    }

    /**
     * @return 返回以当前结点为根结点的树的高度
     */
    public int height(){
        return Math.max(left == null ? 0 :left.height(),right == null ? 0 : right.height())+1;
    }

    /**
     * 左旋转
     */
    public void leftRotate(){
        /*先创建一个值和要旋转子树的根结点值相同的新结点*/
        Node newNode = new Node(this.value);
        /*把要旋转的子树的根节点的左子树设置为新结点的左子树*/
        newNode.setLeft(this.left);
        /*把根节点的右子树的左子结点设置成新结点的右子树*/
        newNode.setRight(this.right.getLeft());
        /*把根节点的右子结点的值赋值给新结点*/
        this.value = this.right.getValue();
        /*把根节点的右子树的右子树设置成根结点的右子树*/
        this.right = this.right.getRight();
        /*把新结点设置成根节点的左子结点*/
        this.left = newNode;
    }

    /**
     * 右旋转
     */
    public void rightRotate(){
        /*先创建一个值和要旋转子树的根结点值相同的新结点*/
        Node newNode = new Node(this.value);
        /*把要旋转的子树的根节点的右子树设置为新结点的右子树*/
        newNode.setRight(this.right);
        /*把根节点的左子树的右子结点设置成新结点的左子树*/
        newNode.setLeft(this.left.getRight());
        /*把根节点的左子结点的值赋值给新结点*/
        this.value = this.left.getValue();
        /*把根节点的左子树的左子树设置成根结点的左子树*/
        this.left = this.left.getLeft();
        /*把新结点设置成根节点的右子结点*/
        this.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 (this.right != null && this.right.leftHeight() > this.right.rightHeight()){
                /*先对右子树进行右旋转*/
                this.right.rightRotate();
            }
            leftRotate();
            return;
        }
        if (leftHeight() - rightHeight() > 1){ /*右旋转*/
            /*如果左子树的右子树高度大于左子树的左子树的高度*/
            if (this.left != null && this.left.rightHeight() > this.left.leftHeight()){
                /*先对左子树进行左旋转*/
                this.left.leftRotate();
            }
            rightRotate();
        }
    }


    /**
     * 中序遍历
     */
    public void midDisplay(){
        if (this.left != null) {
            this.left.midDisplay();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.midDisplay();
        }
    }
	getter and setetr;
    @Override
    public String toString() {
        return "Node{" + "value=" + value + '}';
    }
public class AVLTree {
    private Node root;

    /**
     * 添加结点
     */
    public void addNode(Node node){
        if (root == null) {
            root = node;
        }else {
            root.add(node);
        }
    }

    /**
     * 中序遍历
     */
    public void midShow(){
        if (root != null) {
            root.midDisplay();
        }else {
            System.out.println("树为空");
        }
    }

    public Node getRoot() {
        return root;
    }
}

测试类

public class AVLTest {
    public static void main(String[] args) {
        int[] arr = {2,1,5,4,6,3};
        AVLTree avlTree = new AVLTree();
        for (int i = 0; i < arr.length; i++) {
            avlTree.addNode(new Node(arr[i]));
        }
        avlTree.midShow();
        System.out.println("平衡二叉树树高"+avlTree.getRoot().height());
        System.out.println("左子树树高"+avlTree.getRoot().leftHeight());
        System.out.println("右子树书高"+avlTree.getRoot().rightHeight());
    }
}

运行结果

Node{value=1}
Node{value=2}
Node{value=3}
Node{value=4}
Node{value=5}
Node{value=6}
平衡二叉树树高3
左子树树高2
右子树书高2

Process finished with exit code 0
  • 6
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C语言创建平衡二叉树的示例代码: ```c #include <stdio.h> #include <stdlib.h> // 定义平衡二叉树结点 typedef struct AVLNode { int data; // 数据域 int height; // 结点高度 struct AVLNode *left; // 左子树指针 struct AVLNode *right; // 右子树指针 } AVLNode, *AVLTree; // 获取结点高度 int getHeight(AVLTree T) { if (T == NULL) { return -1; } else { return T->height; } } // 获取两个数中的最大值 int max(int a, int b) { return a > b ? a : b; } // LL旋转 AVLTree LLRotation(AVLTree A) { AVLTree B = A->left; A->left = B->right; B->right = A; A->height = max(getHeight(A->left), getHeight(A->right)) + 1; B->height = max(getHeight(B->left), A->height) + 1; return B; } // RR旋转 AVLTree RRRotation(AVLTree A) { AVLTree B = A->right; A->right = B->left; B->left = A; A->height = max(getHeight(A->left), getHeight(A->right)) + 1; B->height = max(getHeight(B->right), A->height) + 1; return B; } // LR旋转 AVLTree LRRotation(AVLTree A) { A->left = RRRotation(A->left); return LLRotation(A); } // RL旋转 AVLTree RLRotation(AVLTree A) { A->right = LLRotation(A->right); return RRRotation(A); } // 插入结点 AVLTree insert(AVLTree T, int data) { if (T == NULL) { T = (AVLTree)malloc(sizeof(AVLNode)); T->data = data; T->height = 0; T->left = T->right = NULL; } else if (data < T->data) { T->left = insert(T->left, data); if (getHeight(T->left) - getHeight(T->right) == 2) { if (data < T->left->data) { T = LLRotation(T); } else { T = LRRotation(T); } } } else if (data > T->data) { T->right = insert(T->right, data); if (getHeight(T->right) - getHeight(T->left) == 2) { if (data > T->right->data) { T = RRRotation(T); } else { T = RLRotation(T); } } } T->height = max(getHeight(T->left), getHeight(T->right)) + 1; return T; } // 中序遍历 void inorderTraversal(AVLTree T) { if (T != NULL) { inorderTraversal(T->left); printf("%d ", T->data); inorderTraversal(T->right); } } int main() { AVLTree T = NULL; int arr[] = {3, 2, 1, 4, 5, 6, 7, 10, 9, 8}; int len = sizeof(arr) / sizeof(arr[0]); for (int i = 0; i < len; i++) { T = insert(T, arr[i]); } inorderTraversal(T); // 输出:1 2 3 4 5 6 7 8 9 10 return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值