二叉排序树中删除一个结点对其祖先是没有影响的,但是对其子孙有影响.
先回顾下二叉排序树的定义:
- 空树是二叉排序树;
- 左子树所有结点的值小于根节点,右子树所有结点的值大于根节点,递归定义.
设删除的那个结点为root
,那么就要在左子树中找一个最大的结点来替换root
或者在右子树中找一个最小的结点来替换root
看图:
这是一颗二叉排序树,我们删除73
这个结点,就会得到下面这张图:
可以看到右子树中77
这个最小的结点替换了73
这个结点,当然,我们也可以让左子树中64
这个结点来替换73
这个结点.
那么现在的问题就变成了如何找二叉排序树中最大或最小的结点,这个就很容易从图中得出来了:
- 二叉排序树中最小的结点在最左边,往左孩子一直走,直到为空;
- 二叉排序树中最大的结点在最右边,往右孩子一直走,直到为空.
有了这个东西,代码就很好写了.
二叉排序树的数据结构:
typedef struct tagBiTree BiTree;
typedef BiTree *pBiTree;
struct tagBiTree {
int data;
pBiTree lchild, rchild;
tagBiTree() {}
tagBiTree(int data, pBiTree lchild = nullptr, pBiTree rchild = nullptr) :
data(data), lchild(lchild), rchild(rchild) {}
};
删除某一指定结点的函数:
void deleteTheNode(pBiTree &p)
{
auto pre = p;
if (p == nullptr)
return ;
if (!p->lchild) {
p = p->rchild;
delete pre;
} else if (!p->rchild) {
p = p->lchild;
delete pre;
} else {
// to Left
/*
auto q = p, pp = p->lchild;
while (pp->rchild)
q = pp, pp = pp->rchild;
if (q == p) {
pp->rchild = p->rchild;
p = pp;
} else {
q->rchild = pp->lchild;
pp->lchild = p->lchild;
pp->rchild = p->rchild;
p = pp;
}
*/
// to Right
auto q = p, pp = p->rchild;
while (pp->lchild)
q = pp, pp = pp->lchild;
if (q == p) {
pp->lchild = p->lchild;
p = pp;
} else {
q->lchild = pp->rchild;
pp->lchild = p->lchild;
pp->rchild = p->rchild;
p = pp;
}
delete pre;
}
}
由于在编程的时候不能直接地看二叉树的结构,因此,我编写了中序遍历来检验算法是否正确,如果删除某一指定结点后,中序遍历仍然是排好序,且只少了删除的那个元素,那么算法就是正确的.
完整测试代码:
#include <bits/stdc++.h>
using namespace std;
typedef struct tagBiTree BiTree;
typedef BiTree *pBiTree;
struct tagBiTree {
int data;
pBiTree lchild, rchild;
tagBiTree() {}
tagBiTree(int data, pBiTree lchild = nullptr, pBiTree rchild = nullptr) :
data(data), lchild(lchild), rchild(rchild) {}
};
void buildBiTree(pBiTree &root, int data)
{
if (root == NULL) {
root = new BiTree(data);
return ;
}
if (root->data > data)
buildBiTree(root->lchild, data);
else
buildBiTree(root->rchild, data);
}
void midVisit(pBiTree root)
{
if (root == nullptr)
return ;
midVisit(root->lchild);
cout << root->data << " ";
midVisit(root->rchild);
}
void deleteTheNode(pBiTree &p)
{
auto pre = p;
if (p == nullptr)
return ;
if (!p->lchild) {
p = p->rchild;
delete pre;
} else if (!p->rchild) {
p = p->lchild;
delete pre;
} else {
// to Left
/*
auto q = p, pp = p->lchild;
while (pp->rchild)
q = pp, pp = pp->rchild;
if (q == p) {
pp->rchild = p->rchild;
p = pp;
} else {
q->rchild = pp->lchild;
pp->lchild = p->lchild;
pp->rchild = p->rchild;
p = pp;
}
*/
// to Right
auto q = p, pp = p->rchild;
while (pp->lchild)
q = pp, pp = pp->lchild;
if (q == p) {
pp->lchild = p->lchild;
p = pp;
} else {
q->lchild = pp->rchild;
pp->lchild = p->lchild;
pp->rchild = p->rchild;
p = pp;
}
delete pre;
}
}
int main()
{
freopen("in", "r", stdin);
freopen("out", "w", stdout);
pBiTree root = nullptr;
int n;
for (cin >> n; n--;) {
int x;
buildBiTree(root, (cin >> x, x));
}
cout << "pre:" << endl;
midVisit(root);
cout << endl;
deleteTheNode(root);
cout << "now:" << endl;
midVisit(root);
cout << endl;
return 0;
}
输入&输出:
输入:
12 73 15 77 6 23 9 20 27 13 64 11 28
输出:
pre: 6 9 11 13 15 20 23 27 28 64 73 77 now: 6 9 11 13 15 20 23 27 28 64 77