数据结构: 平衡二叉树 AVL树

平衡二叉树

特点

  • 平衡二叉树是对二叉搜索树的优化,为了防止二叉搜索树退化退化成为链表.通过对树的高度进行如下控制:

《数据结构: 平衡二叉树 AVL树》

  • 对于任意一个节点,其左子树和右子树的高度差不能超过1
  • 平衡二叉树的高度和节点数量之间的关系是 O(logN)的
  • 标记每个节点的高度

定义

template<typename Key, typename Value>
class AVL {

private:
	struct Node {
		Key key;
		Value value;
		Node *left;
		Node *right;
		int height; // 这个节点的所在的高度

		Node(key key, Value value) {
			this->key = key;
			this->value = value;
			this->height = 1; // 添加节点的时候,都是添加的叶节点,所以其默认高度为1.
			this->left = this->right = NULL;
		}
	};

	Node *root;
	int size;
public:
	AVL() {
		root = NULL;
		size = 0;
	}

	~AVL() {
	}
}

常见操作

平衡二叉树的两个重要操作:

  • 插入
  • 删除

插入和删除类似于 二叉搜索树 . 但是要维护平衡性

帮助函数

  • 获得这个节点node的高度

    int getHeight(Node* node) {
        if (node == NULL) // 若为空,返回0
            return 0;
        return node->height;
    }
    
  • 获得这个节点node的平衡因子

    这里使用的左孩子节点的高度 – 右孩子节点的高度

    若 >1, 则向左倾斜

    若 <-1,则向右倾斜

    int getBalanceRFacetor(Node* node) {
        if (node == NULL) {
            return 0;
        }
        return getHeight(node->left) - getHeight(node->right);
    }
    
  • 判断这个树是否为 二叉搜索树 BST

    中序遍历后,判断是否有序.

    void inOrder(Node* node, vector<Key> &keys) {
        if (node) {
            inOrder(node->left, keys);
            keys.push_back(node->value);
            inOrder(node->right, keys);
        }
    }
    bool isBST() {
        vector<Key> keys;
        inOrder(root, keys);
        for (int i = 1; i < keys.size(); i++) {
            if (keys[i - 1] > keys[i])
                return false;
        }
        return true;
    }
    
  • 判断这个数是否为 平衡二叉树 AVL

    // 判断是否是平衡二叉树
    bool isBalanced() {
        return isBalanced(root);
    }
    bool isBalanced(Node* node) {
        if (node == NULL)
            return true;
        int balancedFactor = getBalanceRFacetor(node);
        if (abs(balancedFactor) > 1) {
            return false;
        }
        // 递归判断其左子树和右子树是否为AVL
        return isBalanced(node->left) && isBalanced(node->right);
    }
    

1. 添加节点

调用方式:

Node* add(Key key, Value value) {
    root = add(root, key, value);
    return root;
}

节点再怎么失衡都逃不过4种情况:

《数据结构: 平衡二叉树 AVL树》

维护平衡性三个步骤:

  1. 更新height
  2. 计算平衡因子
  3. 调整结构,通过旋转,维护平衡性
  • LL (左子树的左边节点)

《数据结构: 平衡二叉树 AVL树》

《数据结构: 平衡二叉树 AVL树》

代码如下:

//右旋转
Node* rightRotate(Node* y) {
    Node* x = y->left;
    Node* T3 = x->right;
    x->right = y;
    y->left = T3;
    // 更新节点的heigh值
    y->height = max(getHeight(y->left),getHeight(y->right))+1;
    x->height = max(getHeight(x->left), getHeight(x->right))+1;
    return x;
}
  • RR (右子树的右边节点)

《数据结构: 平衡二叉树 AVL树》

《数据结构: 平衡二叉树 AVL树》

Node* leftRotate(Node* y) {
    Node* x = y->right;
    Node* T2 = x->left;

    x->left = y;
    y->right = T2;

    // 更新节点的heigh值
    y->height = max(getHeight(y->left), getHeight(y->right)) + 1;
    x->height = max(getHeight(x->left), getHeight(x->right)) + 1;
    return x;
}
  • LR情况(左子树的右边节点)

《数据结构: 平衡二叉树 AVL树》

《数据结构: 平衡二叉树 AVL树》
《数据结构: 平衡二叉树 AVL树》

// LR,
if (balanceFactor > 1 && getBalanceRFacetor(node->left) < 0) {
    node->left = leftRotate(node->left);
    return rightRotate(node);
}
  • 右左情况(右子树的左边节点)

《数据结构: 平衡二叉树 AVL树》

《数据结构: 平衡二叉树 AVL树》
《数据结构: 平衡二叉树 AVL树》

// RL
if (balanceFactor < -1 && getBalanceRFacetor(node->right) > 0) {
    node->right = rightRotate(node->right);
    return leftRotate(node);
}

完整代码:

Node* add(Node* node, Key key, Value value) {
    if (node == NULL) {
        node = new Node(key,value);
        size++;
        return node;
    }

    if (key < node->key) {
        node->left = add(node->left, key, value);
    } else if (key > node->value) {
        node->right = add(node->right, key, value);
    } else {
        node->value = value;
    }

    // 更新height
    node->height = 1 + max(getHeight(node->left), getHeight(node->right));

    // 计算平衡因子
    int balanceFactor = getBalanceRFacetor(node);

    // 维护平衡性
    if (abs(balanceFactor) > 1) {
        // LL 1. 插入的元素在不平衡节点的左侧的左侧,右旋转(向左偏斜) 
        if (balanceFactor > 1 && getBalanceRFacetor(node->left)>=0) {
            return rightRotate(node);
        }
        // RR 2. 插入的元素在不平衡节点的右侧的右侧,左旋转(向右偏斜) 
        if (balanceFactor < -1 && getBalanceRFacetor(node->right) <= 0) {
            return leftRotate(node);
        }
        // LR,
        if (balanceFactor > 1 && getBalanceRFacetor(node->left) < 0) {
            node->left = leftRotate(node->left);
            return rightRotate(node);
        }
        // RL
        if (balanceFactor < -1 && getBalanceRFacetor(node->right) > 0) {
            node->right = rightRotate(node->right);
            return leftRotate(node);
        }
    }
    return node;
}

2.删除节点

删除节点时,需要对删除后的节点进行 平衡性维护 ,

所以要设置一个返回用的节点,记作 retNode .

调用方法:

Node* remove(Key key) {
    return remove(root, key);
}
Node* remove(Node* node, Key key) {
    if (node == NULL)
        return NULL;

    // 需要对删除后的节点进行 平衡性维护 
    // 所以要设置一个返回用的节点, 记作 retNode .
    Node* retNode;
    if (key < node->key) {
        node->left = remove(node->left, key);
        retNode = node;
    }
    else if (key > node->key) {
        node->right = remove(node->right, key);
        retNode = node;
    }
    else {  // 当前要删除的节点

        // 待删除节点左子树为空
        if (node->left == NULL) {
            Node* rightNode = node->right;
            node->right = NULL;
            size--;
            retNode = rightNode;
        }
        else if (node->right == NULL) {
            Node* leftNode = node->left;
            node->left = NULL;
            size--;
            retNode = leftNode;
        }
        else { 
            // 左右子树都不为空
            Node* successor = minmum(node->right);
            // removeMin中没有进行平衡维护
            // successor->right = removeMin(node->right); 
            successor->right = move(node->right, successor->key);
            successor->left = node->left;
            node->left = node->right = NULL;
            retNode = successor;
        }
    }

    if (retNode == NULL) {
        return NULL;
    }

    // 更新height
    retNode->height = 1 + max(getHeight(retNode->left), getHeight(retNode->right));
    // 计算平衡因子
    int balanceFactor = getBalanceRFacetor(retNode);
    // 维护平衡性
    if (abs(balanceFactor) > 1) {
        // LL 右旋转(向左偏斜) 
        if (balanceFactor > 1 && getBalanceRFacetor(retNode->left) >= 0) {
            return rightRotate(retNode);
        }
        // RR 左旋转(向右偏斜) 
        if (balanceFactor < -1 && getBalanceRFacetor(retNode->right) <= 0) {
            return leftRotate(retNode);
        }
        // LR,
        if (balanceFactor > 1 && getBalanceRFacetor(retNode->left) < 0) {
            retNode->left = leftRotate(retNode->left);
            return rightRotate(retNode);
        }
        // RL
        if (balanceFactor < -1 && getBalanceRFacetor(retNode->right) > 0) {
            retNode->right = rightRotate(retNode->right);
            return leftRotate(retNode);
        }
    }
    return retNode;
}

参考文献

6天通吃树结构—— 第二天 平衡二叉树

AVL树 / 红黑树 / B树 / B+树 / Trie树的应用

    原文作者:AVL树
    原文地址: https://blog.csdn.net/qjh5606/article/details/85242403
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞