数据结构-AVL树实践

AVL树是一种自平衡二叉搜索树,其中任何节点的两个子树的高度最多相差1。它以发明者Adelson-Velsky和Landis的名字命名。当进行插入或删除操作后,如果某个节点的平衡因子(左子树高度减去右子树高度的差)不是-1、0或1,则需要通过旋转来重新平衡树。

下面是创建和维护AVL树的一些核心实践步骤:

旋转操作

为了维持AVL树的平衡性,在插入或删除节点时可能需要执行以下四种旋转操作之一:

  1. 右旋(Right Rotation) - 当节点的左子树比右子树高时:
    T1, T2, T3 and T4 are subtrees.
         z                                      y 
        / \                                   /   \
       y   T4      Right Rotate (z)          x      z
      / \          - - - - - - - - ->      /  \    /  \ 
     x   T3                               T1  T2  T3  T4
    / \
    

T1 T2
```

  1. 左旋(Left Rotation) - 当节点的右子树比左子树高时:

       z                                y
      /  \                            /   \ 
     T1   y     Left Rotate(z)       z      x
         /  \   - - - - - - - ->    / \    / \
        T2   x                     T1  T2 T3  T4
            / \
          T3  T4
    
  2. 左-右旋(Left-Right Rotation) - 先对节点的左子树进行左旋,再对节点进行右旋。

  3. 右-左旋(Right-Left Rotation) - 先对节点的右子树进行右旋,再对节点进行左旋。

插入操作

插入操作首先类似于二叉搜索树的插入,之后包括以下步骤:

  1. 更新每个节点的高度。
  2. 计算每个节点的平衡因子(即左子树高度 - 右子树高度)。
  3. 如果平衡因子不是-1、0或1,则根据子树的高度差进行适当的旋转操作以重新平衡。

删除操作

删除操作首先与二叉搜索树的删除类似,之后也包括类似插入操作的平衡调整:

  1. 如果删除了一个节点,需要回溯到根节点,并更新沿途节点的高度。
  2. 计算每个节点的平衡因子。
  3. 如果平衡因子不是-1、0或1,执行适当的旋转操作。

AVL树代码实现

下面是创建AVL树节点和进行右旋转操作的Java代码片段示例:

class AVLNode {
    int key, height;
    AVLNode left, right;

    public AVLNode(int d) {
        key = d;
        height = 1; // 新节点初始高度设置为1
    }
}

class AVLTree {
    AVLNode root;

    // 获取节点的高度
    int height(AVLNode N) {
        if (N == null)
            return 0;
        return N.height;
    }

    // 右旋转操作
    AVLNode rightRotate(AVLNode y) {
        AVLNode x = y.left;
        AVLNode T2 = x.right;

        // 旋转
        x.right = y;
        y.left = T2;

        // 更新高度
        y.height = Math.max(height(y.left), height(y.right)) + 1;
        x.height = Math.max(height(x.left), height(x.right)) + 1;

        // 返回新的根节点
        return x;
    }

    // TODO: 左旋转、左-右旋转、右-左旋转、插入和删除操作的实现
}

// 使用
public class Main {
    public static void main(String[]```java
      args) {
        AVLTree tree = new AVLTree();

        // 示例插入操作
        tree.root = tree.insert(tree.root, 10);
        tree.root = tree.insert(tree.root, 20);
        tree.root = tree.insert(tree.root, 30);
        tree.root = tree.insert(tree.root, 40);
        tree.root = tree.insert(tree.root, 50);
        tree.root = tree.insert(tree.root, 25);

        // AVL树现在应该平衡了

        // 打印树的中序遍历结果
        tree.inOrder(tree.root);
    }
}

class AVLTree {
    // ...(之前的代码)

    // 左旋转操作
    AVLNode leftRotate(AVLNode x) {
        AVLNode y = x.right;
        AVLNode T2 = y.left;

        // 旋转
        y.left = x;
        x.right = T2;

        // 更新高度
        x.height = Math.max(height(x.left), height(x.right)) + 1;
        y.height = Math.max(height(y.left), height(y.right)) + 1;

        // 返回新的根节点
        return y;
    }

    // 获取平衡因子
    int getBalance(AVLNode N) {
        if (N == null)
            return 0;
        return height(N.left) - height(N.right);
    }

    // 插入节点操作
    AVLNode insert(AVLNode node, int key) {
        // 执行BST的常规插入
        if (node == null)
            return (new AVLNode(key));

        if (key < node.key)
            node.left = insert(node.left, key);
        else if (key > node.key)
            node.right = insert(node.right, key);
        else // 不允许有重复键
            return node;

        // 更新父节点的高度
        node.height = 1 + Math.max(height(node.left), height(node.right));

        // 获取平衡因子,检查是否失衡
        int balance = getBalance(node);

        // 如果节点失衡,则进行4种情况的检查并旋转
        // 左左情况
        if (balance > 1 && key < node.left.key)
            return rightRotate(node);

        // 右右情况
        if (balance < -1 && key > node.right.key)
            return leftRotate(node);

        // 左右情况
        if (balance > 1 && key > node.left.key) {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }

        // 右左情况
        if (balance < -1 && key < node.right.key) {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }

        // 返回未失衡的节点
        return node;
    }

    void inOrder(AVLNode node) {
        if (node != null) {
            inOrder(node.left);
            System.out.print(node.key + " ");
            inOrder(node.right);
        }
    }
}

在上述代码中,insert方法实现了AVL树的插入操作,它首先执行标准的二叉搜索树插入过程,然后更新节点的高度,并通过getBalance方法获取平衡因子来检查树是否失衡。如果树失衡,根据失衡类型执行相应的旋转操作。我们还实现了中序遍历的递归方法inOrder来打印树的内容。

请注意,这是一个简化的AVL树实现,仅用于演示目的。在实际应用中,你可能需要更完整的实现,例如包含删除节点、错误处理和更健壮的数据输入处理。此外,上述代码只在Java中演示了概念,并没有涵盖所有的边缘情况和异常处理。

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员爱学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值