C语言实现二叉查找树(搜索树)的创建,插入,查找,删除

最近在学习二叉树,看了下网上关于二叉查找树(搜索树)的创建,插入,查找,删除的代码都是一些零碎的代码,在这给出可以运行的完整C代码,并给出写代码过程遇到问题的一些注释,便于大家学习理解二叉查找树(搜索树)的创建,插入,查找,删除。

先来介绍下二叉查找树(搜索树)

二叉查找(搜素)树是满足以下条件的二叉树:1.左子树上的所有节点值均小于根节点值,2右子树上的所有节点值均不小于根节点值,3,左右子树也满足上述两个条件。

  二叉查找树的插入过程如下:1.若当前的二叉查找树为空,则插入的元素为根节点,2.若插入的元素值小于根节点值,则将元素插入到左子树中,3.若插入的元素值不小于根节点值,则将元素插入到右子树中。

  二叉查找树的删除,分三种情况进行处理:

  1.p为叶子节点,直接删除该节点,再修改其父节点的指针(注意分是根节点和不是根节点)。

  2.p为单支节点(即只有左子树或右子树)。让p的子树与p的父亲节点相连,删除p即可;(注意分是根节点和不是根节点)。

  3.p的左子树和右子树均不空。找到p的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替p的值;或者方法二是找到p的前驱x,x一定没有右子树,所以可以删除x,并让x的父亲节点成为y的左子树的父亲节点。

完整代码如下:

/*
*二叉查找树(二叉搜索树)的创建,插入,查找,删除 
*/
#include<stdio.h>
#include<stdlib.h>
struct tnode
{
	int data;
	struct tnode *lchild;
	struct tnode *rchild;
};
struct tnode * tree_insert(struct tnode *root,int data)//插入二叉搜索树的节点 
{
	struct tnode *s;
	//构造要插入的节点
	s=(struct tnode *)malloc(sizeof(struct tnode));
	s->data=data;
	s->lchild=NULL;
	s->rchild=NULL;
	if(root==NULL)
	{
		root=s;
	} 
	else
	{
		if(root->data==s->data)
			return root;
		else
		{
			if(s->data>root->data)
				//tree_insert(root->rchild,s->data); 这样写是错误的,因为不能将根节点和子节点连接在一块。 仔细想一下递归过程。 
				root->rchild=tree_insert(root->rchild,s->data);
			else
				//tree_insert(root->lchild,s->data); 这样写是错误的,因为不能将根节点和子节点连接在一块。
				root->lchild=tree_insert(root->lchild,s->data);
		}
	}
	return root;
}
void tree_scaner(struct tnode *root)
{
	if(root==NULL)
		return;
	
//	printf("%d ",root->data);
	tree_scaner(root->lchild);
	printf("%d ",root->data);
	tree_scaner(root->rchild);
}
int tree_search(struct tnode* root,int data)
{
	if(root==NULL)
		return 0; //return -1程序出错,if语句认为-1不是FALSE。而0是FALSE。 
	else
	{
		if(root->data==data)
			return 1;
		else if(root->data<data)
			return tree_search(root->rchild,data);
		else
			 return tree_search(root->lchild,data);
			
	}
	//return 0; 
}

int tree_delete(struct tnode* root,int data)
{
	struct tnode *p,*pf,*t,*s,*sf;
	//找到要删除的节点 
	t=root;
	int flag=0; 
	if(t->data==data)
	{
		p=root;
		flag=1;
	}
	//出现的一个错误,就是下面的while循环里面,全都是if,而不是if-else,这样是不对的,因为程序的本意是一次循环只执行三种情况的一种。 
	while(t!=NULL)  
	{
		if(t->data>data)
		{
			pf=t;
			t=t->lchild;
		}
		else if(t->data<data)
		{
			pf=t;
			t=t->rchild;
		}
		else if(t->data==data)
		{
			p=t;
			flag=1;
			break;
		}
	}
	//找到要删除的节点
	
	//根据三种不同情况删除节点
	if(flag==0)
	{
		printf("this node not in the tree!");
	} 
	//出现的一个错误,三种情况全用if,而不是if-else,这样是不对的,因为程序的本意是一次循环只执行三种情况的一种。 
	if(p->lchild==NULL&&p->rchild==NULL)
	{
		if(p==root)
		{
			root=NULL;
		}
		else
		{
			//不能这样写<span style="font-family: Arial, Helvetica, sans-serif;">p=NULL;</span>
			if(pf->lchild==p)
				pf->lchild=NULL;
			else
				pf->rchild=NULL;//体会这两种写法的不同。 
		}
	}
	else if((p->lchild==NULL&&p->rchild!=NULL)||(p->lchild!=NULL&&p->rchild==NULL))
	{
		if(p==root)
		{
			if(p->lchild==NULL) 
				root=p->rchild;
			else
				root=p->lchild;
		}
		else
		{
			if(p->lchild==NULL) 
			{
				if(pf->rchild==p)
				{
					pf->rchild=p->rchild;
				}
				else
				{
					pf->lchild=p->rchild;
				}
			}
			else
			{
				if(pf->rchild==p)
				{
					pf->rchild=p->lchild;
				}
				else
				{
					pf->lchild=p->rchild;
				}
			}
		}
	}
	
	else if(p->lchild!=NULL&&p->rchild!=NULL)
	{
		s=p->rchild;
		while(s->lchild!=NULL)
		{
			sf=s;
			s=s->lchild;
		}//纠结的部分,找到p的直接后继 
		p->data=s->data;
		sf->lchild=s->rchild;
	} 
	
}
int main()
{
	struct tnode *root;
	int data,i;
	int tree[12]={15,16,20,18,23,5,12,13,3,10,6,7};
//	root=(struct tnode *)malloc(sizeof(struct tnode));
//构建二叉搜索树 
	root=NULL;//need or not?必须要赋NULL值,因为当节点为空时就把改节点当成根节点。 
	//while(scanf("%d",&data)!=EOF)
	for(i=0;i<12;++i)
	{
		printf("....\n");
		data=tree[i];
		root=tree_insert(root,data);
	}
	//构建二叉搜索树
	tree_scaner(root);//遍历二叉搜索树 
	//在二叉搜索树种查找某个节点
	printf("input key:");
	scanf("%d",&data);
	if(tree_search(root,data)) 
	{
		printf("yes\n");
	}
	else
	{
		printf("failed\n");
	}
	printf("delete key:");
	scanf("%d",&data);
	tree_delete(root,data);
	tree_scaner(root);
}

程序可能不是最简洁的,但便于学习和理解,由于时间有限没做太多的测试,欢迎大家指出其中的错误。

点赞