删除二叉搜索树中的某个结点

本文介绍了一种在二叉搜索树中删除指定值结点的算法实现,详细阐述了不同情况下结点删除的具体步骤,并提供了完整的源代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

删除操作的原型为 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. 待删除的结点只有右孩子
  4. 待删除的结点有左孩子和右孩子

其中情况1可归类到2或3。

相应的方法如下:

  1. 直接删除该结点
  2. 删除该结点并使该结点的双亲结点指向该结点的左孩子结点
  3. 删除该结点并使该结点的双亲结点指向该结点的右孩子结点
  4. 在该结点的右子树中寻找关键码(值)最小的结点,将关键码最小的结点的值赋给该结点,然后再删除关键码最小的结点


对于情况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;
}