#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int element;
struct node* Lchild,*Rchild;
}node;
typedef struct tree
{
struct node *root;
}tree;
node * creat(tree *a)
{
a->root=NULL;
}
void Insert(tree *a,int x)
{
node *r,*p,*q;
r=(node*)malloc(sizeof(node));//生成临时节点存储需要插入的值
r->element=x;
r->Lchild=NULL;
r->Rchild=NULL;
if (!(a->root))//如果根节点不为空(根节点就没有左子树右子树的说法了,直接另根节点为r即可)
{
a->root=r;
return;
}
p=a->root;
while(p!=NULL)
{
q=p;//记录下父节点
if (x<p->element)//如果小于该节点的权值,扫描左子树
p=p->Lchild;
else
if (x>p->element)//如果大于该节点的权值,扫描右子树
p=p->Rchild;//这边要注意一定要有else,笔者这边曾经犯错~~,否则满足了x<p->element之后的值又满足了x>p->element~~
else
{
printf("该数已经存在!\n");//否则二叉搜索树已经存在该值,不需要再插入
return;
}
}
if (x<q->element)//因为前面是while(q),即运行结果是当q为NULL时,此时最后一个非空节点为q
q->Lchild=r;
else
q->Rchild=r;
}
int find(tree *h,int x)//该函数的目的是看看x是否在二叉搜索树中,如果在返回1,反之返回0
{
node *p=h->root;
while(p)
{
if (x<p->element)
p=p->Lchild;
if (x>p->element)
p=p->Rchild;
else
return 1;
}
return 0;
}
void Remove(tree *h,int x)//该函数的目的是在二叉搜索树中删除权值为x的值
//删除方法是首先通过搜索找到该节点(如果该节点不存在则提示),分两种情况
//1,若该节点有两棵子树,用中序遍历的后续节点来代替该节点,再用2来删除后续节点(因为中序遍历一定是遍历该节点的右子树的左子树一直到底,即一定最多只有一棵子树)
//2,若该节点最多只有一棵子树(或者需要删除的后续节点只有一棵子树),那么如果左子树非空用左孩子代替
//如果右子树非空,那么用右孩子代替,注意删除根节点的特殊情况
{
node *p=h->root,*r,*s,*q,*c;
while (p&&p->element!=x)
{
q=p;
if (x<p->element)
p=p->Lchild;
else
if (x>p->element)
p=p->Rchild;
}
if (!p)//如果直接到最后了,说明搜索树中不存在该值
{
printf("没有找到该值\n");
return;
}
if (p->Lchild&&p->Rchild)//如果左子树和右子树都存在
{
s=p->Rchild;//中序遍历根节点后是右子树(因为p是要删除的节点,所以不能动)
r=p;
while (s->Lchild)//遍历这个时右子树先扫描右子树的左子树(这个应该算是中序遍历的内容吧~~)
{
r=s;
s=s->Lchild;
}
p->element=s->element;//如何替换:1权值替换2接下去的指向替换(此时p已经是后继节点了),这个有点坑,p=s其实是指向的变换,并不是内容的交换
p=s;
q=r;//3父节点指向替换
}
if (p->Lchild)
c=p->Lchild;
else
c=p->Rchild;
if (p==h->root) h->root=c;//如果删除根节点,那么直接用存在的子孩子代替
else
if (p==q->Lchild) q->Lchild=c;
else
q->Rchild=c;
}
void PreOrd(node *a)
{
if (a)
{
printf("%d ",a->element);
PreOrd(a->Lchild);
PreOrd(a->Rchild);
}
}
int main()
{
tree s;
node *start;
int t;
creat(&s);
Insert(&s,4);//验证Insert函数
Insert(&s,2);
Insert(&s,6);
Insert(&s,1);
Insert(&s,3);
Insert(&s,5);
Insert(&s,7);
printf("搜索树已建成!先序遍历结果为:");
PreOrd(s.root);
printf("\n");
printf("请输入需要搜索的数\n");
scanf("%d",&t);//验证find函数
if (find(&s,t))
printf("%d在搜索树中\n",t);
else
printf("%d不在搜索树中\n",t);
printf("请输入需要删除的数\n");
scanf("%d",&t);
Remove(&s,t);
printf("修改过后的搜素树的前序遍历为:");
PreOrd(s.root);
printf("\n");
return 0;
}
//思考,原来我认为这个Insert是需要有返回值的,即一旦是根节点要返回根节点地址,后来我发现并不需要,因为s->root永远都是指的根节点,就算后来有删除操作,
#include <stdlib.h>
typedef struct node
{
int element;
struct node* Lchild,*Rchild;
}node;
typedef struct tree
{
struct node *root;
}tree;
node * creat(tree *a)
{
a->root=NULL;
}
void Insert(tree *a,int x)
{
node *r,*p,*q;
r=(node*)malloc(sizeof(node));//生成临时节点存储需要插入的值
r->element=x;
r->Lchild=NULL;
r->Rchild=NULL;
if (!(a->root))//如果根节点不为空(根节点就没有左子树右子树的说法了,直接另根节点为r即可)
{
a->root=r;
return;
}
p=a->root;
while(p!=NULL)
{
q=p;//记录下父节点
if (x<p->element)//如果小于该节点的权值,扫描左子树
p=p->Lchild;
else
if (x>p->element)//如果大于该节点的权值,扫描右子树
p=p->Rchild;//这边要注意一定要有else,笔者这边曾经犯错~~,否则满足了x<p->element之后的值又满足了x>p->element~~
else
{
printf("该数已经存在!\n");//否则二叉搜索树已经存在该值,不需要再插入
return;
}
}
if (x<q->element)//因为前面是while(q),即运行结果是当q为NULL时,此时最后一个非空节点为q
q->Lchild=r;
else
q->Rchild=r;
}
int find(tree *h,int x)//该函数的目的是看看x是否在二叉搜索树中,如果在返回1,反之返回0
{
node *p=h->root;
while(p)
{
if (x<p->element)
p=p->Lchild;
if (x>p->element)
p=p->Rchild;
else
return 1;
}
return 0;
}
void Remove(tree *h,int x)//该函数的目的是在二叉搜索树中删除权值为x的值
//删除方法是首先通过搜索找到该节点(如果该节点不存在则提示),分两种情况
//1,若该节点有两棵子树,用中序遍历的后续节点来代替该节点,再用2来删除后续节点(因为中序遍历一定是遍历该节点的右子树的左子树一直到底,即一定最多只有一棵子树)
//2,若该节点最多只有一棵子树(或者需要删除的后续节点只有一棵子树),那么如果左子树非空用左孩子代替
//如果右子树非空,那么用右孩子代替,注意删除根节点的特殊情况
{
node *p=h->root,*r,*s,*q,*c;
while (p&&p->element!=x)
{
q=p;
if (x<p->element)
p=p->Lchild;
else
if (x>p->element)
p=p->Rchild;
}
if (!p)//如果直接到最后了,说明搜索树中不存在该值
{
printf("没有找到该值\n");
return;
}
if (p->Lchild&&p->Rchild)//如果左子树和右子树都存在
{
s=p->Rchild;//中序遍历根节点后是右子树(因为p是要删除的节点,所以不能动)
r=p;
while (s->Lchild)//遍历这个时右子树先扫描右子树的左子树(这个应该算是中序遍历的内容吧~~)
{
r=s;
s=s->Lchild;
}
p->element=s->element;//如何替换:1权值替换2接下去的指向替换(此时p已经是后继节点了),这个有点坑,p=s其实是指向的变换,并不是内容的交换
p=s;
q=r;//3父节点指向替换
}
if (p->Lchild)
c=p->Lchild;
else
c=p->Rchild;
if (p==h->root) h->root=c;//如果删除根节点,那么直接用存在的子孩子代替
else
if (p==q->Lchild) q->Lchild=c;
else
q->Rchild=c;
}
void PreOrd(node *a)
{
if (a)
{
printf("%d ",a->element);
PreOrd(a->Lchild);
PreOrd(a->Rchild);
}
}
int main()
{
tree s;
node *start;
int t;
creat(&s);
Insert(&s,4);//验证Insert函数
Insert(&s,2);
Insert(&s,6);
Insert(&s,1);
Insert(&s,3);
Insert(&s,5);
Insert(&s,7);
printf("搜索树已建成!先序遍历结果为:");
PreOrd(s.root);
printf("\n");
printf("请输入需要搜索的数\n");
scanf("%d",&t);//验证find函数
if (find(&s,t))
printf("%d在搜索树中\n",t);
else
printf("%d不在搜索树中\n",t);
printf("请输入需要删除的数\n");
scanf("%d",&t);
Remove(&s,t);
printf("修改过后的搜素树的前序遍历为:");
PreOrd(s.root);
printf("\n");
return 0;
}
//思考,原来我认为这个Insert是需要有返回值的,即一旦是根节点要返回根节点地址,后来我发现并不需要,因为s->root永远都是指的根节点,就算后来有删除操作,
//也会妥善处理根节点的问题,所以不需要返回值~~