C++AVL树

作者: youxiaochen | 来源:发表于2020-07-11 18:18 被阅读0次

    前言

    AVL树又叫平衡二叉排序树,是一棵空树或它的任何节点的两个子树的高度最大差别为1的二叉排序树 AVL平衡二叉排序树.png

    一:平衡调整

    每次在插入或者删除节点的时候,都有可能导致树的不平衡, 这里就介绍插入节点时的情况, 删除节点与插入节点的平衡调整类似, 节点调整的4种旋转直接看图
    \color{blue}{蓝色:旋转点 }\color{green}{绿色:插入节点}\color{red}{红色:旋转中心轴点}

    1:左旋,节点的右子树高度与左子树高度差>1时, 且右子节点的右子树高度 >= 右子节点的左子树高度
    左旋转
    2:右旋,节点的左子树高度与右子树高度差>1时, 且左子节点的左子树高度 >= 左子节点的右子树高度
    右旋转.png
    3:先右旋再左旋(1的另一种情况),节点的右子树高度与左子树高度差>1时, 且右子节点的右子树高度 < 右子节点的左子树高度
    先右旋再左旋.png
    4:先左旋再右旋(2的另一种情况),节点的左子树高度与右子树高度差>1时, 且左子节点的左子树高度 < 左子节点的右子树高度
    先左旋再右旋.png
    struct AVLTreeNode {
        int data;
        int height = 1;
        AVLTreeNode *left = NULL;
        AVLTreeNode *right = NULL;
        AVLTreeNode(int data) {
            this->data = data;
        }
        //节点高度
        static int getNodeHeight(AVLTreeNode *node) {
            return node == NULL ? 0 : node->height;
        }
        //重新计算高度
        void calculateHeight() {
            this->height = max(getNodeHeight(left), getNodeHeight(right)) + 1;
        }
        //检测右旋
        AVLTreeNode* checkRightRotate() {
            if (getNodeHeight(this->left) - getNodeHeight(this->right) > 1) {//左孩子>右孩子, 左孩子必不NULL
                if (getNodeHeight(this->left->right) > getNodeHeight(this->left->left)) {
                    return leftRightRotate();
                }
                return rightRotate();
            }
            return this;
        }
        //检测左旋
        AVLTreeNode* checkLeftRotate() {
            if (getNodeHeight(this->right) - getNodeHeight(this->left) > 1) {//左孩子>右孩子, 左孩子必不NULL
                if (getNodeHeight(this->right->left) > getNodeHeight(this->right->right)) {
                    return rightLeftRotate();
                }
                return leftRotate();
            }
            return this;
        }
        //左旋转
        AVLTreeNode* leftRotate() {
            AVLTreeNode *rotateRight = this->right;
            this->right = rotateRight->left;
            rotateRight->left = this;
            this->calculateHeight();
            rotateRight->calculateHeight();
            return rotateRight;
        }
        //右节点先右旋,再左旋转
        AVLTreeNode* rightLeftRotate() {
            this->right = this->right->rightRotate();
            return this->leftRotate();
        }
        //右旋转
        AVLTreeNode* rightRotate() {
            AVLTreeNode *rotateLeft = this->left;
            this->left = rotateLeft->right;
            rotateLeft->right = this;
            this->calculateHeight();
            rotateLeft->calculateHeight();
            return rotateLeft;
        }
        //左节点先左旋,再右旋
        AVLTreeNode* leftRightRotate() {
            this->left = this->left->leftRotate();
            return this->rightRotate();
        }
    };
    

    二:删除节点

    删除节点的方式与二叉排序树删除方法相似,删除之后检测平衡调整, 删除节点可能导致的不平衡需要的调整方式与添加节点类似

    1:删除叶子节点(左右子节点都为空)时,不影响整体树结构,直接删除即可
    2:删除的节点只有左子节点或只有右子节点(即右子节点为空或左子节点为空)时,只需要将其左子节点或右子节点代替删除的节点位置即可
    3:删除节点的左右子节点都不为空时,找到删除节点的前驱(右子树高度<=左子树高度时)或者后继(右子树高度>左子树高度时)为替代删除的节点, 然后删除前驱或者后继点节即可,前驱节点为最右节点不存在右子节点,后继节点为最左节点不存在左子节点,因此删除前驱或后继节点又相当到第1,或第2步了
    class AVLTree {
    
    private:
        AVLTreeNode *root = NULL;
        int len = 0;
        //释放节点及其所有子节点
        void freeNode(AVLTreeNode *node);
        //添加新节点
        AVLTreeNode* addNode(AVLTreeNode *node, int data);
        //删除节点
        AVLTreeNode* removeNode(AVLTreeNode *node, int data);
        /**
         * 获取右节点中最小的节点,并移除该节点
         * @param node
         * @param successor
         * @return 需要旋转时返回旋转后的节点
         */
        AVLTreeNode* removeLeftMinNode(AVLTreeNode *node, AVLTreeNode **successor);
        /**
         * 获取左节点中最大的节点,并移除该节点
         * @param node
         * @param successor
         * @return 需要旋转时返回旋转后的节点
         */
        AVLTreeNode* removeRightMaxNode(AVLTreeNode *node, AVLTreeNode **successor);
    public:
        ~AVLTree();
        int size();
        void add(int data);
        void remove(int data);
    };
    
    AVLTree::~AVLTree() {
        freeNode(root);
        root = NULL;
    }
    
    void AVLTree::freeNode(AVLTreeNode *node) {
        if (node) {
            freeNode(node->left);
            freeNode(node->right);
            delete node;
        }
    }
    
    AVLTreeNode* AVLTree::addNode(AVLTreeNode *node, int data) {
        if (node == NULL) {
            len++;
            return new AVLTreeNode(data);
        }
        if (node->data <= data) {//允许有相同值, 若是在Map中要另处理
            node->right = addNode(node->right, data);
            node = node->checkLeftRotate();
        } else {
            node->left = addNode(node->left, data);
            node = node->checkRightRotate();
        }
        node->calculateHeight();
        return node;
    }
    
    AVLTreeNode* AVLTree::removeRightMaxNode(AVLTreeNode *node, AVLTreeNode **successor) {
        if (node->right) {
            node->right = removeRightMaxNode(node->right, successor);
            node = node->checkRightRotate();
            node->calculateHeight();
            return node;
        } else {
            *successor = node;
            return node->left;
        }
    }
    
    AVLTreeNode* AVLTree::removeLeftMinNode(AVLTreeNode *node, AVLTreeNode **successor) {
        if (node->left) {
            node->left = removeLeftMinNode(node->left, successor);
            node = node->checkLeftRotate();
            node->calculateHeight();
            return node;
        } else {
            *successor = node;
            return node->right;
        }
    }
    
    AVLTreeNode* AVLTree::removeNode(AVLTreeNode *node, int data) {
        if (!node) return NULL;
        if (node->data > data) {
            node->left = removeNode(node->left, data);
            node = node->checkLeftRotate();
        } else if (node->data < data) {
            node->right = removeNode(node->right, data);
            node = node->checkRightRotate();
        } else {
            len--;
            if (!node->left && !node->right) {
                delete node;
                return NULL;
            }
            if (!node->left) {
                AVLTreeNode *right = node->right;
                delete node;
                return right;
            }
            if (!node->right) {
                AVLTreeNode *left = node->left;
                delete node;
                return left;
            }
            AVLTreeNode *successor;
            if (AVLTreeNode::getNodeHeight(node->right) < AVLTreeNode::getNodeHeight(node->left)) {
                //这里不需要检测平衡,删除节点后不会大于右节点
                node->left = removeRightMaxNode(node->left, &successor);
            } else {
                 //这里不需要检测平衡,删除节点后不会大于左节点
                node->right = removeLeftMinNode(node->right, &successor);
            }
            node->data = successor->data;
            delete successor;
        }
        node->calculateHeight();
        return node;
    }
    
    int AVLTree::size() {
        return len;
    }
    
    void AVLTree::add(int data) {
        root = addNode(root, data);
    }
    
    void AVLTree::remove(int data) {
        root = removeNode(root, data);
    }
    
    
    最后附上源码https://github.com/youxiaochen/DataStructTree
    数据结构看10次都不如自己动手敲一次印象深,代码中如有错误欢迎指教

    更多文章请关注:http://www.jianshu.com/u/b1cff340957c

    相关文章

      网友评论

          本文标题:C++AVL树

          本文链接:https://www.haomeiwen.com/subject/ehquqktx.html