树和二叉树层序遍历二叉树.docx
- 文档编号:4005997
- 上传时间:2022-11-27
- 格式:DOCX
- 页数:26
- 大小:31.70KB
树和二叉树层序遍历二叉树.docx
《树和二叉树层序遍历二叉树.docx》由会员分享,可在线阅读,更多相关《树和二叉树层序遍历二叉树.docx(26页珍藏版)》请在冰豆网上搜索。
树和二叉树层序遍历二叉树
树和二叉树-层序遍历二叉树
通过上机实践,帮助学生进一步掌握指针变量和动态变量的含义,掌握二叉树的结构特性,以及各种存储结构的特点及适用范围,掌握用指针类型描述、访问和处理二叉树的运算。
【实验内容】
实验题目一:
层序遍历二叉树
【实验步骤】
1已知二叉树以二叉链表作为存储结构,写一个算法按层序遍历它,通过程序在终端屏幕上打印出它的层序序列。
2先建立二叉树的二叉链表存储结构,再遍历它。
3利用队列完成算法。
编程实现以二叉链表存储的二叉树的中序遍历的非递归算法。
编程实现二叉树的中序线索链表的生成(线索化)及其遍历的算法。
实验题目二:
交换二叉树的所有结点的左右子树
【实验步骤】
1已知二叉树以二叉链表作为存储结构,写一个算法交换该二叉树的所有结点的左右子树。
2先建立二叉树的二叉链表存储结构,再完成算法,注意结果的输出形式!
3利用栈。
可设二叉树的根指针为t,且以二叉链表表示,可利用一个指针栈来实现,且设栈单元包括数据域和指针域,当树非空时,将当前的树根结点进栈,同时将当前栈顶元素出栈当作根结点,然后依据当前的根结点是否具有孩子结点来判定是否将其左右指针交换;再将交换后的左指针或右指针入栈,如此反复,直到栈空。
【程序说明】
该程序集成了如下功能:
(1)二叉树的建立
(2)递归和非递归先序,中序和后序遍历二叉树
(3)按层次遍历二叉树
(4)交换二叉树的左右子树
(5)输出叶子结点
(6)递归和非递归计算叶子结点的数目
#include
#include
#include
#include
#include
typedefstructBinnode{
chardata;
structBinnode*lchild;
structBinnode*rchild;
}Binnode;
/*按照前序遍历建立二叉树*/
voidCreat_Bintree(Binnode**t)
{
charch;
scanf("\n%c",&ch);
if(ch=='0')*t=NULL;
else
{
*t=(Binnode*)malloc(sizeof(Binnode));
if(!
*t)exit(OVERFLOW);
(*t)->data=ch;
printf("%c:
left",ch);Creat_Bintree(&(*t)->lchild);
printf("%c:
right",ch);Creat_Bintree(&(*t)->rchild);
}
}
/*按照前序递归遍历二叉树*/
voidPreorder1(Binnode*t)
{
if(t!
=NULL)
{
printf("%c",t->data);
Preorder1(t->lchild);
Preorder1(t->rchild);
}
}
/*按照中序递归遍历二叉树*/
voidInorder1(Binnode*t)
{/*printf("\n输出中序递归遍历序列:
");*/
if(t!
=NULL)
{
Inorder1(t->lchild);
printf("%c",t->data);
Inorder1(t->rchild);
}
}
/*按照后序递归遍历二叉树*/
voidPosorder1(Binnode*t)
{/*printf("\n输出后序递归遍历序列:
");*/
if(t!
=NULL)
{
Posorder1(t->lchild);
Posorder1(t->rchild);
printf("%c",t->data);
}
}
/*按照前序非递归遍历二叉树*/
voidpreorder2(Binnode*root)/*先序非递归遍历二叉树*/
{Binnode*p,*stack[100];
inttop;
p=root;
if(root!
=NULL)
{top=1;
stack[top]=p;
while(top>0)
{
p=stack[top];/*将右小孩放入栈*/
top--;
printf("%c",p->data);
if(p->rchild!
=NULL)
{top++;
stack[top]=p->rchild;
}
if(p->lchild!
=NULL)
{top++;
stack[top]=p->lchild;
}
}
}
}
/*按照中序非递归遍历二叉树*/
voidInorder2(Binnode*root)/*中序非递归遍历二叉树*/
{Binnode*p,*stack[100];
inttop=0;
p=root;
do{
while(p!
=NULL)
{
top++;
stack[top]=p;
p=p->lchild;
}
if(top>0)
{
p=stack[top];/*p所指的节点为无左子树或其左子树已经遍历过*/
top--;
printf("%c",p->data);
p=p->rchild;
}
}while(p!
=NULL||top!
=0);
}
/*按照后序非递归遍历二叉树*/
voidPosorder2(Binnode*t)
{
Binnode*s[100];
inttop=-1;
intflag[100];
while(t!
=NULL||top!
=-1)
{
while(t)
{
top++;
flag[top]=0;
s[top]=t;
t=t->lchild;
}
while(top>=0&&flag[top]==1)
{
t=s[top];
printf("%c",t->data);
top--;
}
if(top>=0)
{
t=s[top];
flag[top]=1;
t=t->rchild;
}
else
{
t=NULL;
}
}
}
/*按照层次遍历二叉树*/
intfront=0,rear=1;
voidLevelorder(Binnode*t)
{
Binnode*q[100];
q[0]=t;
/*intfront=0,rear=1;*/
while(front { if(q[front]) { printf("%c",q[front]->data); q[rear++]=q[front]->lchild; q[rear++]=q[front]->rchild; front++; } else { front++; } } } /*递归法将二叉树的左右子树互换*/ voidExchange1(Binnode*t) { Binnode*temp; if(t) { Exchange1(t->lchild); Exchange1(t->rchild); temp=t->lchild; t->lchild=t->rchild; t->rchild=temp; } } /*非递归法将二叉树的左右子树互换*/ voidExchange2(Binnode*t) { Binnode*temp; Binnode*s[100]; inttop=0; while(t||top) { if(t) { s[top++]=t; temp=t->lchild; t->lchild=t->rchild; t->rchild=temp; t=t->lchild; } else { t=s[--top]->rchild; } } } /*递归法求叶子结点个数*/ intLeaves_Num1(Binnode*t) { if(t) { if(t->lchild==NULL&&t->rchild==NULL) { return1; } return(Leaves_Num1(t->lchild)+Leaves_Num1(t->rchild)); } elsereturn0; } /*非递归法求叶子结点个数*/ intLeaves_Num2(Binnode*t) { Binnode*s[100]; intcount=0,top=0; while(t||top>0) { if(t) { s[top++]=t; if(t->lchild==NULL&&t->rchild==NULL) { count++; printf("%c",t->data);/*输出叶子结点*/ } t=t->lchild; } else { t=s[--top]->rchild; } } returncount; } intmain() { Binnode*proot=NULL; intp,q; printf("1.CreateBitree: \n"); Creat_Bintree(&proot);/*建立二叉树时,无左右孩子的结点输入’0’值*/ printf("\n2.OutputDiguiPreOrder: \n"); Preorder1(proot); printf("\n3.OutputNotDiguiPreOrder: \n"); preorder2(proot); printf("\n4.OutputDiguiInOrder: \n"); Inorder1(proot); printf("\n5.OutputNotDiguiInOrder: \n"); Inorder2(proot); printf("\n6.OutputDiguiPostOrder: \n"); Posorder1(proot); printf("\n7.OutputNotDiguiPostOrder: \n"); Posorder2(proot); printf("\n8.OutputLevelOrde: \n"); Levelorder(proot); Exchange1(proot); printf("\n9.OutputDiguiExchange: \n"); Preorder1(proot); Exchange2(proot); printf("\n10.OutputNotDiguiExchange: \n"); Preorder1(proot); printf("\n11.Leaves_Node: \n"); q=Leaves_Num2(proot); printf("\n12.OutputNotDiguiLeaves_Num: %d\n",q); p=Leaves_Num1(proot); printf("13.OutputDiguiLeaves_Num: %d\n",p); printf("\nThisSystemOnceAgain\n"); return0; } 【思考题】 编程实现二叉树的中序线索链表的生成(线索化)及其遍历的算法。 【调试说明】 (1)建立二叉树时,必须按先序遍历方式依次输入结点值(该程序中为字符)。 当输入叶子结点时,它的左右子树为空以输入“0”值作为结束。 (2)该程序集中了二叉树操作的常用算法,根据需要可以在此基础上进行裁剪,只实现其中一种即可,并调试运行。 当用二叉链表作为二叉树的存储结构时,因为每个结点中只有指向其左、右孩子结点的指针,所以从任一结点出发只能直接找到该结点的左、右孩子。 在一般情况下靠它无法直接找到该结点在某种遍历次序下的前驱和后继结点。 如果在每个结点中增加指向其前驱和后继结点的指针,将降低存储空间的效率。 与此同时,我们可以证明: 在n个结点的二叉链表中含有n+1个空指针。 因为含n个结点的二叉链表中含有2n个指针,除了根结点,每个结点都有一个从父结点指向该结点的指针,因此一共使用了n-1个指针,所以在n个结点的二叉链表中含有2n-(n-1)=n+1个空指针。 因此,可以利用这些空指针,存放指向结点在某种遍历次序下的前驱和后继结点的指针。 这种附加的指针称为线索,加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。 为了区分一个结点的指针是指向其孩子的指针,还是指向其前驱或后继结点的线索,可在每个结点中增加两个线索标志。 这样,线索二叉树结点类型定义为: Lchild Ltag Data Rtag Rchild 其中: 1.Ltag=0时,表示Lchild指向该结点的左孩子; 2.Ltag=1时,表示Lchild指向该结点的线性前驱结点; 3.Rtag=0时,表示Rchild指向该结点的右孩子; 4.Rtag=1时,表示Rchild指向该结点的线性后继结点; 以二叉链表结点数据结构所构成的二叉链表作为二叉树的存储结构,叫做线索二叉链表;指向结点的线性前驱或者线性后继结点的指针叫做线索;加上线索的二叉树称为线索二叉树;对二叉树以某种次序遍历将其变为线索二叉树的过程叫做线索化。 中序线索化是指用二叉链表结点数据结构建立二叉树的二叉链表,然后按照中序遍历的方法访问结点时建立线索。 例如有如上图所示二叉树,则中序遍历的顺序是: O/J*I+HAG 【参考程序】 #include #include typedefenum{Link,Thread}PointerTag;/*指针标志*/ typedefcharDataType; typedefstructBiThreTree{/*定义结点元素*/ PointerTagLTag,RTag; DataTypedata; structBiThreTree*lchild,*rchild; }BiThreTree; BiThreTree*pre;/*全局变量,用于二叉树的线索化*/ BiThreTree*CreateTree()/*按前序输入建立二叉树*/ { BiThreTree*T; DataTypech; scanf("%c",&ch); if(ch==’#’) T=NULL; else {T=(BiThreTree*)malloc(sizeof(BiThreTree)); T->data=ch; T->LTag=Link;/*初始化时指针标志均为Link*/ T->RTag=Link; T->lchild=CreateTree(); T->rchild=CreateTree(); } returnT; } voidInThread(BiThreTree*T) { BiThreTree*p; p=T; if(p) { InThread(p->lchild); if(! p->lchild) {p->LTag=Thread; p->lchild=pre; } if(! pre->rchild) {pre->RTag=Thread; pre->rchild=p; } pre=p; InThread(p->rchild); } } BiThreTree*InOrderThrTree(BiThreTree*T)/*中序线索化二叉树*/ { BiThreTree*Thre;/*Thre为头结点的指针*/ Thre=(BiThreTree*)malloc(sizeof(BiThreTree)); Thre->lchild=T; Thre->rchild=Thre; pre=Thre; InThread(T); pre->RTag=Thread; pre->rchild=Thre; Thre->rchild=pre; returnThre; } voidInThrTravel(BiThreTree*Thre)/*中序遍历二叉树*/ { BiThreTree*p; p=Thre->lchild; while(p! =Thre)/*指针回指向头结点时结束*/ { while(p->LTag==Link) p=p->lchild; printf("%4c",p->data); while(p->RTag==Thread&&p->rchild! =Thre) {p=p->rchild; printf("%4c",p->data); } p=p->rchild; } } voidmain() { BiThreTree*T,*Thre; printf(“PreOrderCreateBinaryTree: \n”); T=CreateTree(); Thre=InOrderThrTree(T); printf(“InOrderTraverseBinaryTree: \n”); InThrTravel(Thre); system("pause"); } 【调试举例】 (1)建立二叉树时,按先序遍历方式输入: “ABD##EH##I##CF##G##”,其中“#”表示空指针。 (2)建立的二叉树为: A BC DEFG HI (3)程序输出为中序遍历线索化二叉树的结果: DBHEIAFCG 已知A、B和C为三个递增有序的线性表,现要求对A表作如下操作: 删除那些既在B表中出现又在C表中出现的元素。 【实验步骤】 1.试对顺序表编写实现上述操作的算法并上机编写代码,要求算法尽可能高效。 在实验报告中分析你的算法的时间复杂度。 2.A表中要删除的元素实际上就是在三个表中都存在的元素。 注意这三个线性表都是递增有序的线性表! 可以利用这一性质减少对线性表“扫描”的趟数。 3.改用单链表作为存储结构编写算法,请释放A表中无用的结点空间,并上机编程实现。 【算法思想】 先从B和C中找出共有元素same,再从A中从当前位置开始,凡小于same的元素均保留,等于same的就跳过,大于same时就再找下一个same。 【顺序存储结构算法描述】 voidSqList_Delete(SqList&A,SqListB,SqListC) { i=0;j=0;m=0;/*i指示A中元素原来的位置,m为移动后的位置*/ while(i { if(B.elem[j] elseif(B.elem[j]>C.elem[k])k++; else{ same=B.elem[j];/*找到了相同元素same*/ while(B.elem[j]==same)j++; while(C.elem[k])==same)k++;/*j,k后移到新的元素*/ while(i A.elem[m++]=A.elem[i++];/*需要保留的元素移动到新位置*/ while(i }/*else*/ }/*while*/ while(i A.elem[m++]=A.elem[i++];/*A的剩余元素重新存储*/ A.length=m; }/*SqList_Delete*/ 【顺序存储结构参考程序】 #include main() { #defineN3/*宏定义,代表数组维数*/ #defineM4 #defineT5 inti,j,k,r,m,same;/*定义变量分别指向数组a,b,c*/ inta[N],b[M],c[T]; printf(“pleaseinputnumbers: \n”); for(i=0;i for(j=0;j for(k=0;k i=0;j=0;m=0;k=0;/*分别赋值为0,即指向数组的第一元素*/ while(i { if(b[j] elseif(b[j]>c[k])k++; else{ same=b[j]; while(b[j]==same)j++; while(c[k]==same)k++; while(i a[m++]=a[i++]; while(i } } while(i a[m++]=a[i++]; printf("a[%d]={",m);/*输出删除元素后的数组a/* for(r=0;r printf("%d",a[m-1]); printf("}\n"); return; } 【程序调试】 程序运行是屏幕显示: pleaseinputnumbers: 此时输入三组测试数据,数据间用空格隔开: 234回车 3456回车 45678回车 程序输出结果: a[3]={2,3},即删除了数组a中即在b和c中都出现的元素。 【单链表存储结构参考程序】 #include #include TypedefstructLNode{ intdata; structLNode*next; }Lnode,*LinkList;/*定义链表节点的结构*/ voidmain() {/*功能: 建立单链表A,B,C,并且删除A中均在B和C中出现的数据。 */ CreateList(LinkListhead);/*函数声明*/ ListDelete(LinkListLa,LinkListLb,LinkListLc); Print(LinkListhead); LinkListheadA,headB,headC; headA=NULL; headB=NULL; headC=NULL; headA=CreateList(headA);/*建立链表*/ headB=CreateList(headB); headC=CreateList(headC); print(headA);/*输出显示链表数据*/ print(headB); print(headC); headA=ListDelete(headA,headB,headC);/*删除A中满足条件的节点*/ Print(headA); } LinkListcreateList(LinkListhead) {/*功能: 建立有头节点head的数据单链表*/ LinkListp,q; p=q=(LinkList)malloc(sizeof(Ln
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 二叉 树层序 遍历
![提示](https://static.bdocx.com/images/bang_tan.gif)