printf("%d\t",arr[i]);
Creatree(&r,arr,i);
printf("输出二叉树的高度:
\n");
printf("%d\n",GetHeight(r));//输出二叉树的高度
printf("输出二叉树的叶子节点:
\n");
outleaf(r);//输出二叉树的叶子节点
printf("\n");
printf("输出中序遍历序列:
\n");
inorder(r);//输出中序遍历序列
printf("\n");
free(arr);//使用完后要释放所申请的空间
return0;
}
五.调试方法和调试过程
调试过程中,出现了大大小小的问题:
第一次编译,很多错误,仔细检查后发现是头文件缺失造成的。
修改后,错误明显少多了。
还有语句后面忘记加分号或者中英文没有区分,导致了一些编译错误。
耐心的调试后,所有的错误都解决了。
六.程序运行主要截图
1.输入DataCount和MaxData,若输入的两个值再指定的范围内(即
),则程序向下执行;若不再指定范围内,则提示重新输入。
运行窗口如下:
图2输入正确的数值
2.创建二叉树,输出高度、叶子节点,对二叉排序树进行中序遍历。
运行窗口如下:
图3高度、叶子节点、中序遍历
七.总结与体会
这次上机练习,感受之一就是手生,好长时间不用c语言编程,有一种陌生感,所以这次练习调试程序过程中也遇到了大大小小的困难,不过通过自己网上查找资料都解决了。
对一些c语言编程用法加深了理解,比如动态分配数组,生成随机数,结构体,递归等内容,现在能够熟练应用,并在实际问题中实现。
其次,深刻认识了二叉排序树的结构,运用递归定义函数实现了二叉树的构建,求解树的高度、叶子节点等内容,有关二叉树的三种遍历方法也清楚了具体的遍历顺序。
实验二:
链式二叉排序树的查找和删除
一.实验目的和要求
1.加深理解数据结构的目的和概念,以及逻辑结构和物理结构的关系;
2.锻炼较为复杂数据结构算法的设计和编程实现;
3.练习链表的程序设计,掌握二叉链表的设计技术;
4.熟悉图结构的物理存储和应用的编程方法;
5.熟悉软件功能的分析设计方法和测试方法。
二.功能分析与设计
1.创建一棵二叉排序树(以下称为源二叉树)。
算法实现:
创建方法与实验一相同,这里不做叙述。
2.从源二叉树拷贝一个二叉树(以下称为二叉树副本)。
算法实现:
首先判断二叉树是否为空,若二叉数为空,则没有任何操作;若二叉树不为空,开辟内存空间,依次复制根节点,左子树和右子树,至此完成二叉树的复制。
部分代码如下:
Tnode*mycopy(Tnode*r){//二叉树的复制
if(!
r)returnNULL;
Tnode*copyr=(Tnode*)malloc(sizeof(Tnode));
copyr->data=r->data;
copyr->lchild=mycopy(r->lchild);
copyr->rchild=mycopy(r->rchild);
returncopyr;
};
3.通过键盘输入数据,指定查找的目标二叉树(源二叉树和二叉树副本),在目标二叉树中查找是否存在该数据,若存在,则输出提示以及该数据节点的地址,若不存在,则输出提示。
算法实现:
首先,通过定义变量k,选择查找哪一棵树。
k=1,表明在源二叉树中查找;k=2,表明在二叉树副本中查找;k=其他值,提示“选择错误”,并且重新输入,直到查找的二叉树为源二叉树或副本。
因为需要在目标二叉树中查找是否存在某数据,所以要定义一个查找节点的函数。
这里编写了search函数,首先判断根节点数值与要查找数值是否相等,若等,则输出找到;若不等,则对左子树、右子树递归调用上面函数。
部分代码如下:
Tnode*search(Tnode*r,intkey){//在二叉排序树中查找值为key的节点
if(r==NULL)
{
printf("没有找到!
");
returnNULL;
}
elseif(r!
=NULL&&key==r->data){
printf("Findit!
\n");
printf("输出数据在内存中的地址:
");
printf("%d",&r);
returnr;
}
elseif(keydata)
returnsearch(r->lchild,key);
elseif(key>r->data)
returnsearch(r->rchild,key);
}
4.删除数据操作:
通过键盘输入数据;如果二叉树副本中存在该数据,则从二叉树副本中删除该数据节点,输出提示,并输出源二叉树和删除操作后的二叉树副本的中序遍历结果和高度;如果二叉树副本中不存在该数据,输出提示,并输出提示源二叉树中是否存在该数据节点以及节点地址。
算法实现:
对二叉树的节点进行删除操作,要分下面三种情况:
1)当删除的节点是叶子节点时,只要把删除节点的父节点对应的指针指向NULL即可,然后释放掉删除节点的空间。
2)当删除的节点只有一个子节点(左子树或右子树),把删除节点的父节点中对应的指针指向删除节点的子节点即可。
然后释放掉删除节点的空间; 3)当删除的节点左右子树都有,这种情况下,必须要找到一个替代删除节点的替代节点,并且保证二叉树的排序性。
根据二叉树的排序性,可知替代节点的键值必须最接近删除节点键值。
比删除节点键值小的所有键值中最大那个,或者是比删除节点键值大的所有键值中最小的那个,是符合要求的。
这两个键值所在的节点分别在删除节点的左子树中最右边的节点,删除节点右子树中最左边的节点;
部分代码如下:
//获得其父节点
Tnode*getFather(Tnode*r,Tnode*s)
{
Tnode*sf;
if(r==NULL||r==s)
sf=NULL;
else{
if(s==r->lchild||s==r->rchild)
sf=r;
elseif(s->data>r->data)
sf=getFather(r->rchild,s);
else
sf=getFather(r->lchild,s);
}
returnsf;
}
//二叉树删除
voidDeleteNode(Tnode*r,intkey)
{
Tnode*L,*LL;//在删除左右子树都有的结点时使用;
Tnode*p=r;
Tnode*parent=r;
intchild=0;//0表示左子树,1表示右子树;
if(!
r)//如果排序树为空,则退出;
return;
while(p)//二叉排序树有效;
{
if(p->data==key)
{
if(!
p->lchild&&!
p->rchild)//叶结点(左右子树都为空);
{
if(p==r)//被删除的结点只有根结点;
free(p);
elseif(child==0)
{
parent->lchild=NULL;//设置父结点左子树为空;
free(p);//释放结点空间;
}
else//父结点为右子树;
{
parent->rchild=NULL;//设置父结点右子树为空;
free(p);//释放结点空间;
}
}
elseif(!
p->lchild)//左子树为空,右子树不为空;
{
if(child==0)//是父结点的左子树;
parent->lchild=p->rchild;
else//是父结点的右子树;
parent->rchild=p->rchild;
free(p);//释放被删除的结点;
}
elseif(!
p->rchild)//右子树为空,左子树不为空;
{
if(child==0)//是父结点的左子树;
parent->lchild=p->lchild;
else//是父结点的右子树;
parent->rchild=p->lchild;
free(p);//释放被删除的结点;
}
else
{
LL=p;//保存左子树的结点;
L=p->rchild;//从当前结点的右子树进行查找;
if(L->lchild)//左子树不为空;
{
LL=L;
L=L->lchild;//查找左子树;
p->data=L->data;//将左子树的数据保存到被删除结点;
LL->lchild=L->lchild;//设置父结点的左子树指针为空;
for(;L->lchild;L=L->lchild);
L->lchild=p->lchild;
p->lchild=NULL;
}
else
{
p->data=L->data;
LL->rchild=L->rchild;
}
}
p=NULL;
}
elseif(keydata)//需删除记录的关键字小于结点的数据;
{//要删除的结点p是parent的左子树;
child=0;//标记在当前结点左子树;
parent=p;//保存当前结点作为父结点;
p=p->lchild;//查找左子树;
}
else//需删除记录的关键字大于结点的数据;
{//要删除的结点p是parent的右子树;
child=1;//标记在当前结点右子树查找;
parent=p;//保存当前结点作为父结点;
p=p->rchild;//查找右子树;
}
}
}
5.将源二叉树视为一个图数据结构,编写函数实现该图的邻接表存储(注意程序需确保该操作不会被重复操作)。
算法实现:
首先对每个顶点
建立一个单链表,这个单链表由邻接于
的所有顶点构成。
这个表头节点通常以顺序存储结构存储,以便随机访问任一顶点的链表。
6.编写函数实现该图的拓扑排序,并输出拓扑序列。
算法实现:
首先在有向图中选取一个没有前驱的顶点(即入度为0的顶点),并输出该顶点;然后从有向图中删除该顶点和以它为尾的所有弧;重复前两步,直到全部顶点都被输出,或者有向图中没有入度为0的顶点为止。
部分代码如下:
voidTopoSort(adjlistGL,intn)
{
inti,j,k,top,m=0;/*m用来统计拓扑序列中的顶点数*/
structedgenode*p;/*单链表*/
int*d=(int*)malloc(n*sizeof(int));/*定义存储图中每个顶点入度的一维整形数组d*/
for(i=0;id[i]=0;/*初始化数组*/
for(i=0;i{
p=GL[i];
while(p!
=NULL)
{
j=p->adjvex;
d[j]++;
p=p->next;
}
}
top=-1;/*初始化用于链接入度为0的元素的栈的栈顶指针为-1*/
for(i=0;iif(d[i]==0)
{
d[i]=top;
top=i;
}
while(top!
=-1)/*每循