最近在写数据结构课设,基于字典树,avl树,pat树(压缩字典树),哈希表写个英汉词典
写完后会开源, 可以期待一波
分享一些饶有趣味的感悟hhh
AVL树的删除操作要虽比插入复杂一点,不过思想很值得揣摩
抛开细节,如果真的找到了那个要删除的节点,问题就转化为,如何使删除完的树继续平衡呢,利用二叉排序树的特点——左子树比根小,右子树比根大 , 找到左子树中的最大值或者右子树中的最小值来替换他, 因为在局部子树的最值节点,都是在边缘地带,牵扯的鸡毛蒜皮之事都远小于拖家带口的节点
❓那么, 该选左子树中的最大值还是右子树中的最小值呢?随便都可以吗
答案是否定的, 不要因小失大, 小——删除一个节点;大——整棵自平衡二叉查找树的平衡性
我们可以将情况进一步细化
另一方面,如果当前没找到那个要删除的节点, 就需要根据与目标的大小相比较,进而选择左/右子树走下去(递归实现), 当回溯回来的时候,可能已经按上面的那种情况实现了删除, 那样就需要判断是否失衡, 此刻的左右子树高度差是否为二(即失衡), 接下来的问题就回归到树的旋转上去了,上一篇博文有所提及
C++实现AVL树的四种旋转_☆迷茫狗子的秘密基地☆-CSDN博客结构template
AVLNode* AVLTree::MaxNode(AVLNode* pRoot)
{
if(pRoot == nullptr) return nullptr;
while(pRoot->rchild != nullptr)
{
pRoot = pRoot->rchild;
}
return pRoot;
}
AVLNode* AVLTree::MinNode(AVLNode* pRoot)
{
if(pRoot == nullptr) return nullptr;
while(pRoot->lchild != nullptr)
{
pRoot = pRoot->lchild;
}
return pRoot;
}
void AVLTree::DeleteWord(string word)
{
root = _deleteWord(root, word);
}
AVLNode* AVLTree::_deleteWord(AVLNode* pRoot, string word)
{
if(pRoot == nullptr){
//cout << "不存在" << word << endl;
return nullptr;
}
//找到对应值
if(pRoot->data.first == word)
{
// 如果同时存在左右子树,则根据高度选择更换左子树最大节点或右子树最小节点
if(pRoot->lchild != nullptr && pRoot->rchild != nullptr)
{
if(GetH(pRoot->lchild) > GetH(pRoot->rchild))
{
AVLNode* left_max = MaxNode(pRoot->lchild); // 用左子树的最大节点替代当前节点
pRoot->data = left_max->data; // 当前分支情况left_max不可能为nullptr,可以直接覆盖data
pRoot->lchild = _deleteWord(pRoot->lchild, left_max->data.first); // 转移矛盾为删除左子树的最大节点
}else{
AVLNode* right_min = MinNode(pRoot->rchild); // 用右子树的最小节点替代当前节点
pRoot->data = right_min->data; // 当前分支情况right_min不可能为nullptr,可以直接覆盖data
pRoot->lchild = _deleteWord(pRoot->lchild, right_min->data.first); // 转移矛盾为删除左子树的最大节点
}
}
// 至少一个子树为空
else{
AVLNode* p = pRoot;
if(pRoot->lchild != nullptr)
pRoot = pRoot->lchild;
else if(pRoot->rchild != nullptr)
pRoot = pRoot->rchild;
delete p;
cout << "成功删除" << word << endl;
return nullptr;
}
}
else if(pRoot->data.first > word)
{
pRoot->lchild = _deleteWord(pRoot->lchild, word);
// 若是处理左子树完后失衡,则对右子树进行旋转变换
if(GetH(pRoot->rchild) - GetH(pRoot->lchild) == 2)
{
if(GetH(pRoot->rchild->lchild) > GetH(pRoot->rchild->rchild))
pRoot = RL_Rotation(pRoot);
else
pRoot = Left_Rotation(pRoot);
}
}
else if(pRoot->data.first < word)
{
pRoot->rchild = _deleteWord(pRoot->rchild, word);
// 若是处理右子树完后失衡,则对左子树进行旋转变换
if(GetH(pRoot->lchild) - GetH(pRoot->rchild) == 2)
{
if(GetH(pRoot->lchild->rchild) > GetH(pRoot->lchild->lchild))
pRoot = LR_Rotation(pRoot);
else
pRoot = Right_Rotation(pRoot);
}
}
return pRoot;
}