【算法百题之十三】二叉搜索树BST的删除

 【算法百题之十三】二叉搜索树BST的删除

     大家好,我是Lampard~~

     很高兴又能和大家见面了,接下来准备系列更新的是算法题,一日一练,早日升仙!

 

     今天的问题是:

     构造二叉搜索树并且实现删除功能。

   

     解题思路:

    首先我们要理解删除分多少种情况,每一种情况要如何处理。那我也不卖关子了,请看图:

   

1- 如果选中的结点没有孩子节点(叶子),那么只需简单地将其删除,

   并把其父亲的子结点设为NULL,又因为不知道被选中结点时其父亲的左孩子还是右孩子,所以我们需要进行判断。

// 如果寻找的是叶子结点,则直接删除
		if (node->isLeaf())
		{
			if (node->isLeftChild() == true)
			{
			    // 是左孩子则把其父亲的左孩子置空
				node->getFather()->DeleteLeftChild();
				delete node;
			}

			else if (node->isLeftChild() == false)
			{
				// 同理是右孩子则把其父亲的右孩子置空
				node->getFather()->DeleteRightChild();
				delete node;
			}
		}


2- 如果被选中结点只有一个孩子(单枝),那么只需要把该结点删除,

   并且把被选中结点的孩子和其父亲联起来就可以了。这时候有四种情况!!!!!!

     被选中结点是父亲的左孩子,结点的左孩子为空。被选中结点是父亲的左孩子,结点的右孩子为空
     被选中结点是父亲的右孩子,结点的左孩子为空。被选中结点是父亲的右孩子,结点的右孩子为空

 

// 如果寻找的结点是单支(只有一个孩子)
		// 分四种情况(我是父亲的左孩子,我的左孩子为空。我是父亲的左孩子,我的右孩子为空)
		// (我是父亲的右孩子,我的左孩子为空。我是父亲的右孩子,我的右孩子为空)

		// 第一种情况
		else if (node->getLeftChild() == NULL && node->isLeftChild()==true)
		{
			node->getFather()->setLeftChild(node->getRightChild());   // 把我父亲的左孩子(我原来的位置)更改为我的右孩子
			node->getRightChild()->setFather(node->getFather());      // 把我的右孩子的父亲改为我父亲
			delete node;
		}

		// 第二种情况
		else if (node->getRightChild() == NULL && node->isLeftChild()== true)
		{
			node->getFather()->setLeftChild(node->getLeftChild());   
			node->getLeftChild()->setFather(node->getFather());   
			delete node;
		}

		//第三种情况
		else if (node->getLeftChild() == NULL && node->isLeftChild() == false)
		{
			node->getFather()->setRightChild(node->getRightChild());
			node->getRightChild()->setFather(node->getFather());
			delete node;
		}

		// 第四种情况
		else if (node->getRightChild() == NULL && node->isLeftChild() == false)
		{
			node->getFather()->setRightChild(node->getLeftChild());
			node->getLeftChild()->setFather(node->getFather());
			delete node;
		}


3- 前两种都比较简单,第二种稍微有点冗长但是都不难!!现在中带你讲第三种!!!

   如果被选中结点有2个孩子,那么需要把右子树中最小,或者左子树中最大的结点(我称为幸运儿),然后把幸运儿的值赋值给被选中结点,接着删除幸运儿。记住了!是删除幸运儿,而不是被选中结点,不要搞混!!!

   我们为什么这样做呢?

   因为,左子树最大或者右子树最小的值放在被删除的位置上,

   才不会违背二叉搜索树的原则(左子树的所有元素都比自己小,右子树所有都比自己大)

 

    我以选择右子树最小结点举例,假如你选择的不是最小,而是倒数第二小会怎么样?

    那是不是就在右子树中存在着一个比自己小的家伙?

     那我是不是就违反了二叉搜索树的原则?

 

     所以我们只能选择这两种情况。OK我们接着往下说,

     那么既然把值赋给了被删除的结点之后,我们要怎么删除这个幸运儿呢?

    (1)如果这个幸运儿是叶子结点,我们就回归到1的情况

    (2)如果这个幸运儿是单支结点(只有一个子树),就回到我们2的情况

      什么?你问我幸运儿有没有可能有两个子树?根本不可能,因为如果有两个子树的话,自己的最值就不能取到了

    


		else if (node->getLeftChild() != NULL && node->getRightChild() != NULL)
		{
			// 自己是父亲的左孩子
			getSmallRightChild(node->getRightChild());

			// 把第一个进队列的取出,然后清空队列
			BinaryTreeNode* theNode = NodeQueue.front(); 
			while (!NodeQueue.empty())
			{
				NodeQueue.pop();
			}

			if (theNode->isLeaf())    // 是叶子
			{
				node->setData(theNode->getData());
				theNode->getFather()->DeleteLeftChild();
			}

			else if (theNode->isLeaf() == false) //证明它有右子树
			{
				theNode->getFather()->setLeftChild(theNode->getRightChild());
				theNode->getRightChild()->setFather(theNode->getFather());
				node->setData(theNode->getData());
			}
		
		}

那么我们怎么找到幸运儿呢?我们以找右子树最小值为例,

只需要用一个队列存起中序遍历的输出数据,,然后第一个就是了嘻嘻

不过记得队列每次用完要清0哦

 

最后我们看看测试结果:

树长这样

 

1.首先我们测试直接删除叶子0

 

2.然后是直接删除单边结点2

 

3.然后是删除有两个子树,且幸运儿是叶子的1

 

4.最后是删除有两个子树,且幸运儿是单边的4,此时幸运儿是5.

 

OK,今天的博客就到这里,谢谢大家!!!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lampard杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值