排序二叉树节点的删除

首先先看看这个删除节点12后的树,还要保证该平衡二叉树的特性保持不变

删除节点详细分为三类:

第一类.所删除的节点是叶子节点,这样就可以先遍历这个树,然后找到需要删除的节点,把它free掉就好

第二类:就是所删除的节点只有一个左孩子,或者只有一个右孩子,则把该节点的孩子变为它父亲的孩子 ,然后删除这个结点

在这个例子把28删除,就是把30连接到12上

第三类:就是最麻烦的一类,假如我们要删除节点12,直接删除就会破坏了排序二叉树的结构,那么我们想到一个方法,就是把这类转换成第一类,那么重点来了,我们找到要删除的结点后,找到在这个节点左子树的最右的节点或者右子树的最左侧的节点,把这个节点的值覆盖到要删除的节点上,然后删除左子树的最右的节点或者右子树的最左侧的节点,

 我们看这个例子:要删除12 先找到以12位根的左子树的最右的节点 就是数字6 ,把6覆盖到节点·12,然后删除节点6

                           或者找到右子树的最左边的节点 就是该树上的28,把28覆盖到节点12上,再删除28,就变成了第二类删除

代码如下:核心函数Search 和 DelNode

#include<stdio.h>
#include<stdlib.h>

typedef struct node
{
	int nValue;
	struct node *pLeft;
	struct node *pRight;
}BinatyTree;

void InsertNode(BinatyTree **pTree,int nNum)
{
	BinatyTree *pTemp = NULL;
	pTemp = (BinatyTree*)malloc(sizeof(BinatyTree));
	pTemp->nValue = nNum;
	pTemp->pLeft = NULL;
	pTemp->pRight = NULL;

	//空树
	if(*pTree == NULL)
	{
		*pTree = pTemp;
		return;
	}

	//非空树
	BinatyTree *pNode = *pTree;

	while(1)
	{
		if(nNum > pNode->nValue)
		{
			//去右侧
			if(pNode->pRight == NULL)
			{
				pNode->pRight = pTemp;
				return;
			}
			
			//向右走
			pNode = pNode->pRight;
		}
		else if(nNum < pNode->nValue)
		{
			//去左侧
			if(pNode->pLeft == NULL)
			{
				pNode->pLeft = pTemp;
				return;
			}
			pNode = pNode->pLeft;
		}
		else
		{
			printf("数据错误.\n");
			return;
		}
	}
}

void CreateBST(int arr[],int nLength,BinatyTree **pTree)
{
	if(arr == NULL || nLength <=0)return;

	int i;
	for(i = 0;i<nLength;i++)
	{
		InsertNode(pTree,arr[i]);
	}
}

void Search(BinatyTree *pTree,int nNum,BinatyTree **pDel,BinatyTree **pFather)
{
	while(pTree != NULL)
	{
		if(pTree->nValue == nNum)
		{
			*pDel = pTree;
			return;
		}
		else if(pTree->nValue > nNum)
		{
			*pFather = pTree;
			pTree = pTree->pLeft;
		}
		else 
		{
			*pFather = pTree;
			pTree = pTree->pRight;
		}
	}
}


void DelNode(BinatyTree **pTree,int nNum)
{
	if(*pTree == NULL)return;

	//查找
	BinatyTree *pDel = NULL;
	BinatyTree *pFather = NULL;

	Search(*pTree,nNum,&pDel,&pFather);

	if(pDel == NULL)return;

	//分析情况
	//两个
	BinatyTree *pMark = NULL;
	if(pDel->pLeft != NULL && pDel->pRight!= NULL)
	{
		//找左的最右
		pMark = pDel;

		//向左走一步
		pFather = pDel;
		pDel = pDel->pLeft;

		while(pDel->pRight != NULL)
		{
			pFather = pDel;
			pDel = pDel->pRight;
		}

		//值覆盖
		pMark->nValue = pDel->nValue;
	}

	//被删除节点是根节点
	if(pFather == NULL)
	{
		*pTree = pDel->pLeft ? pDel->pLeft : pDel->pRight;
		free(pDel);
		pDel = NULL;
		return;
	}

	//被删除节点非根
	if(pDel == pFather->pLeft)
	{
		pFather->pLeft = pDel->pLeft ? pDel->pLeft:pDel->pRight;
		free(pDel);
		pDel = NULL;
		return;
	}
	else
	{
		pFather->pRight = pDel->pLeft ? pDel->pLeft:pDel->pRight;
		free(pDel);
		pDel = NULL;
		return;
	}
}

void Traversal(BinatyTree *pTree)
{
	if(pTree == NULL)return;
	Traversal(pTree->pLeft);
	printf("%d ",pTree->nValue);
	Traversal(pTree->pRight);
}

int main()
{
	int arr[] = {10,38,2,100,80,15,1,8,16};
	BinatyTree *pTree = NULL;
	CreateBST(arr,sizeof(arr)/sizeof(arr[0]),&pTree);
	Traversal(pTree);
	printf("\n");
	DelNode(&pTree,10);
	Traversal(pTree);
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值