您的位置:首页 > 其它

二叉查找树的各项操作(重点是结点的删除部分和递归的运用)

2012-01-16 16:20 225 查看
大半年前学二叉树时,看不懂删除结点的代码,对递归的理解很浅,今天把问题一并解决,加深对递归的理解。

1.删除结点的算法描述:如果待删除的结点至多只有一个子结点,那么需要删除的就是这个结点本身,通过改变指针指向即可;如果待删除的结点有2个结点,那么就需要删除这个结点在中序遍历时的直接后继结点,再通过赋值完成删除。删除后要记得释放结点空间。

2.递归:递归在非线性结构中用的非常普遍。二叉树的查找,插入,删除都可以用递归实现。以前刚学递归的时候老师说递归算法需要长时间的学习才能够入门,当时根本感觉不到,现在却越来越体会到了。递归固然能够使得程序清晰简洁,但是如果写错,debug的时候是比较痛苦的。

3.总结:《算法导论》上描述的删除结点的算法非常简洁而且清晰,逻辑非常严密,但自己再理解上花费了不少时间,说明自己的思考练习还差的很远,今后要进一步加强思维上的练习。

4.算法代码及测试代码:

代码如下: 注:前半部分函数是大半年前的代码,命名规则上与现在有所不同。

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

typedef struct node//定义一个二叉树结点   
{
	long item;//结点数值
	int count;//计数器
	struct node *pLeft;
	struct node *pRight;
}NODE;

//函数原型
NODE *CreatNode(long value);
NODE *AddNode(long value,NODE *pNode);
void ListNodesAsc(NODE *pNode);
NODE *tree_search(NODE *pNode,long k);
NODE *iterative_tree_search(NODE *pNode,long k);
NODE *iterative_tree_search(NODE *pNode,long k);
NODE *tree_minimum(NODE *pNode);
NODE *tree_maximun(NODE *pNode);
void parent(NODE *&pNode,NODE *&p,NODE *head);
NODE *tree_successor(NODE *&pNode,NODE *&p,NODE *head);
void tree_delete(NODE *head,long k);

//声明全局变量,存储根结点
NODE *root=NULL;

int main()
{
	long value=0;
	NODE *pNode=NULL;
	long test[]={15,6,3,7,2,4,13,9,18,17,20};//测试数据
	for(int i=0;i<11;i++)
	{
		value=test[i];
		if(pNode==NULL)
			pNode=CreatNode(value);
		else
			AddNode(value,pNode);
	}
	root=pNode;//得到根结点
	ListNodesAsc(pNode);
	printf("\n");
	NODE *result=NULL;

	//测试
	//result=tree_successor(pNode->pLeft->pRight->pRight,result,pNode);
	//parent(pNode->pLeft->pRight->pRight,result,pNode);
	//printf("\n%ld",result->item);
	tree_delete(pNode,15);
	ListNodesAsc(pNode);
	getch();
}

//创建结点
NODE *CreatNode(long value)
{
	NODE *pNode=(NODE *)malloc(sizeof(NODE));
	pNode->item=value;
	pNode->count=1;
	pNode->pLeft=pNode->pRight=NULL;
	return pNode;
}

//添加结点
NODE *AddNode(long value,NODE *pNode)
{
	if(pNode==NULL)
		return CreatNode(value);
	if(pNode->item==value)
	{
		pNode->count++;
		return pNode;
	}
	else if(value<pNode->item)
	{
		if(pNode->pLeft==NULL)
		{
			pNode->pLeft=CreatNode(value);
			return pNode->pLeft;//注意:这里不能直接写成return CreatNode(value);是因为必须要有根结点与左结点的联系
		}
		else                                //加上else看起来更加的清晰,有利于维护
			return AddNode(value,pNode->pLeft);
	}
	else //value>pNode->item的情况
	{
		if(pNode->pRight==NULL)
		{
			pNode->pRight=CreatNode(value);
			return pNode->pRight;
		}
		else
			return AddNode(value,pNode->pRight);
	}
}

//升序排列二叉树(中序遍历二叉树)
void ListNodesAsc(NODE *pNode)
{
	if(pNode->pLeft!=NULL)
		ListNodesAsc(pNode->pLeft);
	for(int i=0;i<pNode->count;i++)
		printf("%d ",pNode->item);
	if(pNode->pRight!=NULL)
		ListNodesAsc(pNode->pRight);
}

//查找
NODE *tree_search(NODE *pNode,long k)
{
	if(pNode==NULL || k==pNode->item)
		return pNode;
	if(k<pNode->item)
		return tree_search(pNode->pLeft,k);
	else
		return tree_search(pNode->pRight,k);
}

//非递归查找
NODE *iterative_tree_search(NODE *pNode,long k)
{
	while(pNode!=NULL && k!=pNode->item)
	{
		if(k<pNode->item)
			pNode=pNode->pLeft;
		else
			pNode=pNode->pRight;
	}
	return pNode;
}

//查找最小值
NODE *tree_minimum(NODE *pNode)
{
	if(pNode==NULL)
		return NULL;
	while(pNode->pLeft!=NULL)
		pNode=pNode->pLeft;
	return pNode;
}

//查找最大值
NODE *tree_maximun(NODE *pNode)
{
	if(pNode==NULL)
		return NULL;
	while(pNode->pRight!=NULL)
		pNode=pNode->pRight;
	return pNode;
}

//计算父亲结点  
void parent(NODE *&pNode,NODE *&p,NODE *head)
{
	if(head!=NULL)
	{
		if((head->pLeft!=NULL && head->pLeft==pNode )|| (head->pRight!=NULL && head->pRight==pNode))
		{
			p=head;
			//return p; //问:为什么这里必须要返回一个指针?  粗心错误,把这个函数的返回值误设为void *
		}		
		if(head->pLeft!=NULL)
			parent(pNode,p,head->pLeft);	
		if(head->pRight!=NULL)
			parent(pNode,p,head->pRight);
	}
}

//查找一个结点的后继   
NODE *tree_successor(NODE *&pNode,NODE *&p,NODE *head)
{
	if(pNode->pRight!=NULL)
		return tree_minimum(pNode->pRight);
	parent(pNode,p,head);
	NODE *p1=p;
	while(p1!=NULL && p1->pRight==pNode)
	{
		pNode=p1;
		parent(p1,p1,head);
	}
	return p1;
}

//删除一个结点
void tree_delete(NODE *head,long k)
{
	NODE *target=tree_search(head,k);
	NODE *y=NULL,*x=NULL;
	NODE *p=NULL;
	if(target->pLeft==NULL || target->pRight==NULL)
		y=target;
	else
		y=tree_successor(target,p,head);
	if(y->pLeft!=NULL)
		x=y->pLeft;
	else
		x=y->pRight;
	parent(y,p,head);
	if(p==NULL)
		root=x;
	else if(y==p->pLeft)
		p->pLeft=x;
	else
		p->pRight=x;
	if(y!=target)
	{
		target->item=y->item;
		free(y);//释放被删除的结点的空间
	}
	else
		free(target);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐