C++实现AVL树

C++实现AVL树

在这篇文章中,我们将探索如何使用C++实现AVL树。AVL树是一种自平衡二叉搜索树,这意味着它会在插入或删除节点后自动调整自己的高度,以保持平衡。这是通过旋转操作实现的,我们将在代码中看到这一点。

首先,我们定义了一个名为AVL_Node的模板结构,该结构包含左、右和父节点指针,一个平衡因子(右子树高度减去左子树高度),以及一个存储键值对的pair

template <class K, class V>
struct AVL_Node
{
    struct AVL_Node<K, V> *_left;
    struct AVL_Node<K, V> *_right;
    struct AVL_Node<K, V> *_parent;

    int _bf;        // blance factor //右子数高度-左子树高度
    pair<K, V> _kv; /* data */
};

然后,我们定义了一个new_node函数,用于创建新的节点。

接下来,我们定义了一个名为AVL_TREE的模板类,它包含一个指向根节点的指针。这个类包含了插入节点、中序遍历和前序遍历的方法。

插入方法首先检查树是否为空,如果是,则创建一个新的根节点。如果不是,则找到合适的位置插入新节点,并更新父节点的平衡因子。如果插入新节点后树变得不平衡,那么就需要进行旋转操作。我们的代码支持四种类型的旋转:LL、LR、RR和RL。

bool insert(const pair<K, V> &value)
{
   if (_root == nullptr)
        { // 空的情况
            _root = new_node(value);
            if (_root == nullptr)
            {
                std::cerr << "malloc erro" << std::endl;
                return false;
            }
            return true;
        }
        Node *parent = nullptr;
        Node *current = _root;
        while (current)
        {
            if (current->_kv.first > value.first)
            { // 要插入的值比当前的值小
                parent = current;
                // 去当前节点的左边
                current = current->_left;
            }
            else if (current->_kv.first < value.first)
            { // 要插入的值比当前值大
                parent = current;
                // 去当前节点的右边
                current = current->_right;
            }
            else
            {
                return false;
            }
        }
        // 此时current为要插入的位置
        current = new_node(value);
        if (current == nullptr)
        {
            std::cerr << "malloc erro" << std::endl;
            return false;
        }
        current->_parent = parent;
        // 比较新节点应该在parent节点的左边还是右边
        if (current->_kv.first > parent->_kv.first)
        {
            parent->_right = current;
        }
        else
        {
            parent->_left = current;
        }
        // 更新平衡因子
        while (parent)
        {
            // 如果新插入节点是在父节点左边,那么bf--
            if (current == parent->_left)
            {
                parent->_bf--;
            }
            else
            {
                parent->_bf++;
            }
            if (parent->_bf == -1 || parent->_bf == 1)
            {
                // 继续向上更新
                current = parent;
                parent = parent->_parent;
                continue;
            }
            else if (parent->_bf == 0)
            {
                // 说明此时parent 左右子树高度平衡,但是它高度不变,不用向上更新了
                break;
            }
            else
            {
                // 此时bf>1,需要旋转
                // 判断属于RR、RL、LL、LR哪一种
                if (parent->_bf == 2)
                {
                    // 这个属于RR或者RL
                    if (parent->_right->_bf == 1 && parent->_right->_right->_bf != -1)
                    {
                        // 一定是左旋
                        RotateL(parent);
                    }
                    else
                    {
                        // RL
                        // 先找到bf为-1的那个节点
                        Node *d_node = parent;
                        while (d_node->_bf != -1)
                        {
                            d_node = d_node->_right;
                        }
                        RotateR(d_node);
                        d_node->_parent->_bf = 1;
                        d_node->_bf = 0;
                        RotateL(parent);
                    }
                }
                else if (parent->_bf == -2)
                {
                    if (parent->_left->_bf == -1 && parent->_left->_left->_bf != 1)
                    {
                        // 一定是右旋
                        RotateR(parent);
                    }
                    else
                    {
                        // LR
                        Node *i_node = parent;
                        while (i_node->_bf != 1)
                        {
                            i_node = i_node->_left;
                        }
                        RotateL(i_node);
                        i_node->_parent->_bf = -1;
                        i_node->_bf = 0;
                        RotateR(parent);
                    }
                }
                return true;
            }
        }
        return true;
}

左旋和右旋函数如下:

void RotateL(Node *node)
{
    // 左旋函数
        Node *cur_parent = node->_parent;
        Node *current = node;
        // 传入节点的右节点
        Node *right = node->_right;
        // 传入节点的右右节点
        Node *rr = right->_right;
        // 让右节点的左节点赋值给cur的右边(管它有没有无所谓)
        current->_right = right->_left;
        // 判断是否存在,如果存在就就要使右左节点的父节点指向cur
        if (right->_left)
        {
            right->_left->_parent = current;
        }
        // 让右节点的左子树为cur,同时在让cur的父节点指向右节点之前要保存其的父节点
        right->_left = current;
        current->_parent = right;
        // 让右节点的父节点指向原cur的父节点(管他存不存在)
        right->_parent = cur_parent;
        // 判断cur的父节点存不存在,存在就要考虑是连接在cur的父节点的左边还是右边
        if (cur_parent)
        {
            if (cur_parent->_kv.first > right->_kv.first)
            {
                cur_parent->_left = right;
            }
            else
            {
                cur_parent->_right = right;
            }
        }
        else
        {
            // 不存在,那么右节点现在就是根
            _root = right;
        }
        // 更新bf
        // 当前节点和右节点都变为0
        current->_bf = 0;
        right->_bf = 0;
}

void RotateR(Node *node)
{
   // 右旋函数
        // 和左旋类似
        Node *cur_parent = node->_parent;
        Node *current = node;
        Node *left = node->_left;
        Node *ll = left->_left;
        // 让左节点的右节点赋值给cur的左边
        current->_left = left->_right;
        if (current->_left)
        {
            current->_left->_parent = current;
        }
        left->_right = current;
        left->_parent = cur_parent;
        if (cur_parent)
        {
            if (cur_parent->_kv.first > current->_kv.first)
            {
                cur_parent->_left = left;
            }
            else
            {
                cur_parent->_right = left;
            }
        }
        else
        {
            _root = left;
        }
        // 更新平衡因子
        left->_bf = 0;
        current->_bf = 0;
}

最后,我们还有中序遍历和前序遍历函数,用于打印树的内容。

void midOrder()
{
    midorder(_root);
}
void prevOrder()
{
    prevorder(_root);
}
void midorder(Node *node)
{
   if (node == nullptr)
   {
       return;
   }
   midorder(node->_left);
   std::cout << node->_kv.first << std::endl;
   midorder(node->_right);
}
 void prevorder(Node *node)
 {
    if (node == nullptr)
    {
       return;
    }
    std::cout << node->_kv.first << " : " << node->_bf << std::endl;
    prevorder(node->_left);
    prevorder(node->_right);
 }

这就是我们的C++ AVL树实现。希望这篇文章能帮助你理解AVL树以及如何在C++中实现它。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AVL树的插入和删除操作都需要对树进行旋转操作来保持AVL树的平衡性。下面是C语言实现AVL树插入和删除操作: AVL树插入操作: ```c // AVL树节点定义 struct AVLNode { int key; int height; struct AVLNode* left; struct AVLNode* right; }; // 计算节点高度 int height(struct AVLNode* node) { if (node == NULL) { return 0; } return node->height; } // 右旋操作 struct AVLNode* rotate_right(struct AVLNode* y) { struct AVLNode* x = y->left; struct AVLNode* t2 = x->right; // 执行旋转 x->right = y; y->left = t2; // 更新高度 y->height = max(height(y->left), height(y->right)) + 1; x->height = max(height(x->left), height(x->right)) + 1; return x; } // 左旋操作 struct AVLNode* rotate_left(struct AVLNode* x) { struct AVLNode* y = x->right; struct AVLNode* t2 = y->left; // 执行旋转 y->left = x; x->right = t2; // 更新高度 x->height = max(height(x->left), height(x->right)) + 1; y->height = max(height(y->left), height(y->right)) + 1; return y; } // 计算平衡因子 int balance_factor(struct AVLNode* node) { if (node == NULL) { return 0; } return height(node->left) - height(node->right); } // 插入节点 struct AVLNode* avl_insert(struct AVLNode* node, int key) { // 执行BST插入 if (node == NULL) { struct AVLNode* new_node = (struct AVLNode*)malloc(sizeof(struct AVLNode)); new_node->key = key; new_node->height = 1; new_node->left = NULL; new_node->right = NULL; return new_node; } if (key < node->key) { node->left = avl_insert(node->left, key); } else if (key > node->key) { node->right = avl_insert(node->right, key); } else { // key已经存在,不需要插入 return node; } // 更新高度 node->height = max(height(node->left), height(node->right)) + 1; // 计算平衡因子 int bf = balance_factor(node); // 如果平衡因子大于1,需要进行旋转操作 if (bf > 1) { if (key < node->left->key) { // 左左情况,执行右旋操作 return rotate_right(node); } else { // 左右情况,先对左子树进行左旋操作,再对根节点进行右旋操作 node->left = rotate_left(node->left); return rotate_right(node); } } else if (bf < -1) { if (key > node->right->key) { // 右右情况,执行左旋操作 return rotate_left(node); } else { // 右左情况,先对右子树进行右旋操作,再对根节点进行左旋操作 node->right = rotate_right(node->right); return rotate_left(node); } } return node; } ``` AVL树删除操作: ```c // 查找最小值节点 struct AVLNode* find_min(struct AVLNode* node) { if (node == NULL) { return NULL; } if (node->left == NULL) { return node; } return find_min(node->left); } // 删除节点 struct AVLNode* avl_delete(struct AVLNode* node, int key) { // 执行BST删除 if (node == NULL) { return NULL; } if (key < node->key) { node->left = avl_delete(node->left, key); } else if (key > node->key) { node->right = avl_delete(node->right, key); } else { if (node->left == NULL || node->right == NULL) { // 被删除节点只有一个子节点或者没有子节点 struct AVLNode* temp = node->left ? node->left : node->right; if (temp == NULL) { // 没有子节点,直接删除 temp = node; node = NULL; } else { // 有一个子节点,用子节点替换被删除节点 *node = *temp; } free(temp); } else { // 被删除节点有两个子节点,找到右子树的最小值节点替换被删除节点 struct AVLNode* temp = find_min(node->right); node->key = temp->key; node->right = avl_delete(node->right, temp->key); } } if (node == NULL) { return NULL; } // 更新高度 node->height = max(height(node->left), height(node->right)) + 1; // 计算平衡因子 int bf = balance_factor(node); // 如果平衡因子大于1,需要进行旋转操作 if (bf > 1) { if (balance_factor(node->left) >= 0) { // 左左情况,执行右旋操作 return rotate_right(node); } else { // 左右情况,先对左子树进行左旋操作,再对根节点进行右旋操作 node->left = rotate_left(node->left); return rotate_right(node); } } else if (bf < -1) { if (balance_factor(node->right) <= 0) { // 右右情况,执行左旋操作 return rotate_left(node); } else { // 右左情况,先对右子树进行右旋操作,再对根节点进行左旋操作 node->right = rotate_right(node->right); return rotate_left(node); } } return node; } ``` 以上是AVL树的插入和删除操作的C语言实现。需要注意的是,AVL树的插入和删除操作都需要对树进行旋转操作来保持平衡,因此这些操作的时间复杂度是O(log n)。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值