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树

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

  • 水彩过程 | 树树树树

    练习了一下树的画法,用毛笔勾树干,扇形笔画树叶还是又快又方便的。因为不是写实风格,只要把树的意象画出来就可以,所以...

  • 树·树

    ​如果有来生,要做一棵树,站成永恒,没有悲欢姿势,一半在尘土里安详。一半在风里飞扬,一半洒落阴凉,一半沐浴阳光。 ...

  • 树,树……

    树,树…… ——洛尔迦 树,树, 枯了又绿。 脸蛋美丽的姑娘 在那里摘橄榄。 风,塔楼上的求爱者, 拦腰把她...

  • 橄榄树树树

    在建班级群的时候,我顺手打了三个树——橄榄树树树。是的,这是橄榄树第三次起航。 第一次,在北京,我说,我愿意在无人...

  • 树,与树

    (第一次学着简书里文友看图写诗,2020的图,各位讲究着看吧) 文/三少爷的糖 一颗树站在山头 遥望着远方,朦胧中...

  • 树,与树

    我不是一个很喜欢女生哭闹的人。 哭闹,意味着理智被情感摧毁。 理智没了,沟通渠道也就关闭了。 没有了沟通,剩下的就...

  • 树和树

    我的家门前有一棵柏树,不是什么稀罕的树,但它却挺直腰杆儿,坚定的伫立在我家门前,望着远方,似乎在等什么人又不像在等...

  • 树树秋声

    余秋雨说:生命,是一树花开,或安静或热烈,或寂寞或璀璨。日子,就在岁月的年轮中渐次厚重,那些天真的、跃动的、抑或沉...

  • 短篇‖树树

    这是一条幽静的古道,两旁尽是残垣断壁,竟也有一些台阶通向几栋还算有顶篷的石质的建筑物。我和我的伙伴着级上了一段...

网友评论

      本文标题:C++AVL树

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