删除操作的原型为 int DeleteBSTree(PNode* pRoot, int data),返回类型int用来表示删除是否成功,其中PNode表示如下
typedef int DataType;
typedef struct BSTreeNode
{
DataType _data;
struct BSTreeNode *_left;
struct BSTreeNode *_right;
}Node, *PNode;
删除操作的原理为:首先在二叉搜索树中查找值为data的结点,如果不存在,则返回,否则将待删除的结点分为以下四种情况:
- 待删除的结点无孩子结点
- 待删除的结点只有左孩子
- 待删除的结点只有右孩子
- 待删除的结点有左孩子和右孩子
其中情况1可归类到2或3。
相应的方法如下:
- 直接删除该结点
- 删除该结点并使该结点的双亲结点指向该结点的左孩子结点
- 删除该结点并使该结点的双亲结点指向该结点的右孩子结点
- 在该结点的右子树中寻找关键码(值)最小的结点,将关键码最小的结点的值赋给该结点,然后再删除关键码最小的结点
对于情况2.待删除的结点只有左孩子又可分为如下3种情况,b和c的不同在于结点1是其双亲的左孩子结点,而结点2是其双亲的右孩子结点。而对于根结点5,若删除则需改变外部指向搜索二叉树的指针。情况3和情况2类似。
而对于情况4.待删除的结点有左孩子和右孩子,删除某个结点后必须使剩下二叉树的仍然具有搜索二叉树的性质。
具体代码如下:
int DeleteBSTree(PNode* pRoot, int data)
{
PNode pCur = NULL;
PNode pParent = NULL;
PNode pDel = NULL;
assert(pRoot);
if (NULL == pRoot)
return 0;
//1.找待删除的结点
pCur = *pRoot;
while (pCur)
{
if (data == pCur->_data)
break;
else if (data < pCur->_data)
{
pParent = pCur;
pCur = pCur->_left;
}
else
{
pParent = pCur;
pCur = pCur->_right;
}
}
if (NULL == pCur)
return 0;
//2.删除结点
//待删除结点只有左孩子 || 叶子结点
if (NULL == pCur->_right)
{
if (pCur == *pRoot)
{
pDel = *pRoot;
*pRoot = (*pRoot)->_left;
}
else
{
pDel = pCur;
if (pCur == pParent->_left)
pParent->_left = pCur->_left;
else
pParent->_right = pCur->_left;
}
}
//只有右孩子
else if (NULL == pCur->_left)
{
if (pCur == *pRoot)
{
pDel = *pRoot;
*pRoot = (*pRoot)->_right;
}
else
{
pDel = pCur;
if (pCur == pParent->_left)
pParent->_left = pCur->_right;
else
pParent->_right = pCur->_right;
}
}
//待删除结点有左子树和右子树
else
{
//找右子树中值最小的结点来替换待删除的结点
pParent = pCur; //因为是从右子树中找,所以pParent更新为pCur
pDel = pCur->_right;
while (pDel->_left)
{
pParent = pDel;
pDel = pDel->_left;
}
pCur->_data = pDel->_data;
if (pDel == pParent->_left)
pParent->_left = pDel->_right;
else
pParent->_right = pDel->_right;
}
free(pDel);
return 1;
}