数据结构平衡二叉树

平衡二叉树(也称为AVL树)是一种特殊类型的二叉搜索树,在这种树中,任何节点的两个子树的高度差都不超过1。这种高度平衡保证了树的操作(如插入、删除和查找)都具有O(log n)的时间复杂度。AVL树通过在每个节点执行旋转操作来实现自平衡。

AVL树节点的定义

AVL树的节点包括键值、高度属性以及左右子节点的引用。这里是一个简单的AVL树节点类定义的示例:

class AVLNode<T extends Comparable<T>> {
    T key;
    int height;
    AVLNode<T> left;
    AVLNode<T> right;

    public AVLNode(T key) {
        this.key = key;
        this.height = 1; // 新节点的高度默认为1
        this.left = null;
        this.right = null;
    }
}

AVL树的插入操作

插入操作首先遵循二叉搜索树的规则,然后可能需要通过一系列旋转来恢复平衡。在每次插入之后,需要更新节点的高度并检查每个节点的平衡因子(左子树高度和右子树高度的差异)。如果平衡因子绝对值超过1,则需要进行旋转来重新平衡树。

public AVLNode<T> insert(AVLNode<T> node, T key) {
    if (node == null) {
        return new AVLNode<T>(key);
    }

    if (key.compareTo(node.key) < 0) {
        node.left = insert(node.left, key);
    } else if (key.compareTo(node.key) > 0) {
        node.right = insert(node.right, key);
    } else {
        // 重复的键值不允许在AVL树中
        return node;
    }

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

    // 获取平衡因子
    int balanceFactor = getBalanceFactor(node);

    // 根据平衡因子进行旋转操作以恢复平衡
    // 左左(右旋)
    if (balanceFactor > 1 && key.compareTo(node.left.key) < 0) {
        return rightRotate(node);
    }

    // 右右(左旋)
    if (balanceFactor < -1 && key.compareTo(node.right.key) > 0) {
        return leftRotate(node);
    }

    // 左右(左右旋)
    if (balanceFactor > 1 && key.compareTo(node.left.key) > 0) {
        node.left = leftRotate(node.left);
        return rightRotate(node);
    }

    // 右左(右左旋)
    if (balanceFactor < -1 && key.compareTo(node.right.key) < 0) {
        node.right = rightRotate(node.right);
        return leftRotate(node);
    }

    // 如果树已经平衡,则直接返回节点
    return node;
}

旋转操作

在AVL树中有四种旋转操作:右旋、左旋、左右旋和右左旋。下面是左旋和右旋操作的代码示例。

右旋
private AVLNode<T> rightRotate(AVLNode<T> y) {
    AVLNode<T> x = y.left;
    AVLNode<T> 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;
}
左旋
private AVLNode<T> leftRotate(AVLNode<T> x) {
    AVLNode<T> y = x.right;
    AVLNode<T> 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;
}

细节和注意事项

在处理AVL树时,一些关键的细节需要注意:

  • 高度更新:在每次插入或删除节点后,必须更新经过的节点的高度。
  • 平衡因子计算:平衡因子是左子树高度减去右子树高度。如果平衡因子的绝对值大于1,需要旋转来恢复平衡。
  • 旋转类型选择:根据不平衡的类型(左左、右右、左右、右左),选择正确的旋转操作。

请注意,实现AVL树的完整代码相当复杂,包括多种情况和边界条件。上述代码是为了说明AVL树的核心概念而大幅度简化的,真实的实现更加复杂,并且还会包括删除操作和更多辅助函数。在实际应用中,通常建议使用标准库中提供的平衡树实现,如C++的std::multiset、Java的TreeMap等,除非你明确需要自己实现AVL树以获取特定的性能优化或者学习目的。

你可能感兴趣的:(算法,集合,数据结构)