最近在学习二叉树,看了下网上关于二叉查找树(搜索树)的创建,插入,查找,删除的代码都是一些零碎的代码,在这给出可以运行的完整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);
}
程序可能不是最简洁的,但便于学习和理解,由于时间有限没做太多的测试,欢迎大家指出其中的错误。