二叉树之搜索树

本文通过具体的代码示例,详细介绍了如何使用C语言实现二叉搜索树的各种操作,包括构造平衡二叉搜索树、先序与中序遍历、节点的查找、插入与删除等,并分享了一些在实践中遇到的问题及解决方法。

       昨天加今天,一直写不好关于二叉搜索树的代码,主要思想没有理解透彻,终于,今天晚上把他们做了出来,也多了许多感悟,具体见代码。

     

/*根据升序数组构造平衡二叉搜索树*/
#include <stdio.h>
#include <stdlib.h>
typedef struct tree_node_s {  
   char data;  
   struct tree_node_s *lchild;  
   struct tree_node_s *rchild;  
}tree_node_t, *Tree; 
//无序数组建立有序二叉树
Tree OrderTree(int *a,int length)
{
	Tree insertTree(Tree &b,int x);
	Tree t=NULL;
	t=(Tree)malloc(sizeof(tree_node_t));
	t->data=*a;
	t->lchild=NULL;
	t->rchild=NULL;
	for(int i=1;i<length;i++)
	{
		t=insertTree(t,a[i]);
	}
	return t;

}
//升序建立二叉树
Tree BinNodeBuildTree(int *a,int start,int end)
{
	int mid =(end+start)/2;
	Tree t=NULL;
	int b=a[mid];
	if(start>end)
		return t;
	t=(Tree)malloc(sizeof(tree_node_t));
	t->lchild=NULL;
	t->rchild=NULL;
	t->data=b;
	t->lchild=BinNodeBuildTree(a,start,mid-1);
	t->rchild=BinNodeBuildTree(a,mid+1,end);
	return t;

}
//先序遍历
void PreOrder(Tree b)
{
	if(b!=NULL)
	{
		printf("\t%d",b->data);
		PreOrder(b->lchild);
		PreOrder(b->rchild);
	}
}
//中序遍历
void InOrder(Tree b)
{
	if(b!=NULL)
	{
		InOrder(b->lchild);
		printf("\t%d",b->data);
		InOrder(b->rchild);
	}
}
//查找节点
Tree searchTree(Tree &b,int x)
{
	bool solve=false;
	Tree p;
	 p=b;
	while(p && !solve) //最后,1.p找到,!solve=false,(p && !solve)=0,跳出循环。
		               //      2.p未找到,p=NULL,!solve=true,(p && !solve)=0,也跳出循环。
	{
		if(x==p->data)
		{
			printf("已找到%d\n",x);
			solve=true;
			return p;
		}else if(x<p->data){
			p=p->lchild;
		}else{
			p=p->rchild;
		}
	}
	if(p==NULL)
	{
		printf("没有找到\n");
	}
	return b;
}
//插入节点
Tree insertTree(Tree &b,int x)
{
	Tree p;
	p=(Tree)malloc(sizeof(tree_node_t));
	p->data=x;
	p->lchild=NULL;
	p->rchild=NULL;
	if(b==NULL)
	{
		return p;
	}
	if(p->data < b->data)
	{
		b->lchild=insertTree(b->lchild,x);
	}else{
		b->rchild=insertTree(b->rchild,x);
	}
	return b;
}
//非递归方法插入节点
void insertTree2(Tree &b,int x)
{
	Tree p;
	p=(Tree)malloc(sizeof(tree_node_t));
	p->data=x;
	p->lchild=NULL;
	p->rchild=NULL;
	while(b->lchild!=NULL && b->rchild!=NULL)
	{
		if(p->data<b->data)
		{
			b=b->lchild;
			if(b==NULL)
			{
				b=p;
			}
		}else{
			b=b->rchild;
			if(b==NULL)
			{
				b=p;
			}
		}

	}

}
//删除节点
void deleteTree(Tree &b,int x)
{
	Tree p,q;//p为所找的节点,q为所找节点的父节点
	p=b;
	while(p!=NULL)
	{
		if(x==p->data)
		{
			break;

		}else if(x>p->data){
			q=p;
			p=p->rchild;
		}else{
			q=p;
			p=p->lchild;
		}
	}
	if(p==NULL)
	{
		printf("无此节点:%d",x);
	}
	//若p是叶子节点
	if(p->lchild==NULL&&p->rchild==NULL)
	{
		if(p==b)//p是根
			b=NULL;
		else if(q->lchild==p)
		{
			q->lchild=NULL;
			p=NULL;
		}else{
			q->rchild=NULL;
			p=NULL;
		}
		free(p);
	}

	//若p为单支节点
	else if(p->rchild==NULL&&p->lchild!=NULL) //p的右子树为空
	{
		if(p==b)
		{
			if(p->lchild==NULL)
			{
				b=p->rchild;
			}else{
				b=p->lchild;
			}
		}
		else if(q->lchild==p)
		{
			q->lchild=p->lchild;
		}
		else
		{
			q->rchild=p->lchild;
		}
		free(p);
	}
	else if(p->rchild!=NULL&&p->lchild==NULL) //p的左子树为空
	{
		if(p==b)
		{
			if(p->lchild==NULL)
			{
				b=p->rchild;
			}else{
				b=p->lchild;
			}
		}
		else if(q->lchild==p)
		{
			q->lchild=p->rchild;
		}
		else
		{
			q->rchild=p->rchild;
		}
		free(p);
	}
	
	//p的左右子树均不为空
	//如果一个结点有右孩子,则该结点的后继,至多有一个子女,而且是右孩子。
	//因为假如该结点的后继有左孩子和右孩子,那么其左孩子的值肯定是介于该结点和其后继之间的,
	//那么按照二叉查找树的性质,这个左孩子就应该是该结点的后继,所以,这与原先的后继相互矛盾.
	else //(p->lchild!=NULL&&p->rchild!=NULL)
	{
		//找到P的后继节点,即p的右子树的最小值,即右子树的左子书的最后一个值
		Tree n,m;//n 为p的后继,m 为n的父节点
		n=p->rchild;
		while(n->lchild)
		{
			m=n;
			n=n->lchild;
		}
		p->data=n->data;
		m->lchild=n->rchild;	
	}

}

int main ()
{
	Tree p=NULL;
	Tree q=NULL;
	int a[12]={15,5,16,3,12,20,10,13,18,23,6,7};
	int b[5]={1,2,3,6,5};

	p=OrderTree(a,12);

	InOrder(p);
	printf("\n");
	deleteTree(p,5);
	InOrder(p);
	printf("\n");

/*	p=BinNodeBuildTree(a,0,4);
	q=BinNodeBuildTree(a,0,4);
	PreOrder(p);
	printf("\n");
	insertTree(p,4);
	PreOrder(p);
	printf("\n");
	insertTree2(q,4);
	PreOrder(p);
	printf("\n");*/
	return 0;
}

另外,还发现了一个问题,废了我很长时间,代码没有错误,但是就是无法执行到底,发现是用了太多的if,不知道用太多的if还会出问题?我把他们改成了else If,就可以好好执行了,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值