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++中实现它。