数据结构课程设计之二叉树和树的遍历.docx
- 文档编号:5044086
- 上传时间:2022-12-12
- 格式:DOCX
- 页数:48
- 大小:608.31KB
数据结构课程设计之二叉树和树的遍历.docx
《数据结构课程设计之二叉树和树的遍历.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计之二叉树和树的遍历.docx(48页珍藏版)》请在冰豆网上搜索。
数据结构课程设计之二叉树和树的遍历
##大学
数据结构课程设计报告
题目:
二叉树和树的遍历
院(系):
计算机工程学院
学生姓名:
班级:
学号:
起迄日期:
2011-6-21至2011-6-25
指导教师:
2010—2011年度第2学期
一、需求分析
1.问题描述:
进行二叉树和树的各种遍历,包括递归和非递归。
2.基本功能
二叉树前序递归遍历、二叉树中序递归遍历、二叉树后序递归遍历、二叉树前序非递归遍历、二叉树中序非递归遍历、二叉树后序非递归遍历、二叉树层次非递归遍历
树先根递归遍历、树后根递归遍历、树先根非递归遍历、树后根非递归遍历、树层次非递归遍历,可循环执行直到按退出键。
3.输入输出
字符串形式
二、概要设计
1.设计思路:
在递归遍历二叉树时,主要看遍历的根的先后,可根据遍历根,遍历左子树和遍历右子树的顺序不同来实现二叉树的先序,中序,后序递归遍历,二叉树的先序和中序非递归则用到了栈,一般都是先根进栈然后左孩子进栈,二叉树的后序遍历则用到了队列,并用tag数组值0、1来标记二叉树结点的左右,树的先根非递归和后序非递归则参考了二叉树的先序和中序非递归遍历,也用到了栈,它的层次遍历则用到了队列。
2.数据结构设计:
//二叉树的结点结构
typedefstructbitnode{
chardata;
structbitnode*lchild,*rchild;
}bitnode,*bitree;
//二叉树的栈的结构
typedefstruct{
bitree*base;
bitree*top;
intstacksize;
}sqstack;
为二叉树的先序和中序非递归提供栈,保存已经访问过的结点信息。
//二叉树后序非递归的栈的结构
typedefstructnode1{
bitreedata[30];//默认30个元素,这里需要一个辅助堆栈!
!
!
inttop;
}stack;
top能够保存结点是左还是右孩子,该栈为后序遍历提供保存结点信息。
//二叉树的队列结点结构
typedefstructqnode{
bitreedata;
structqnode*next;
}qnode,*queueptr;
//二叉树的队列结构
typedefstruct{
queueptrfront;
queueptrrear;
}linkqueue;
该队列能为二叉树层序遍历提供先进先出的数据访问条件
//树的结点结构
typedefstructcsnode{
chardata;
structcsnode*firstchild,*nextsibling;
}csnode,*cstree;
//树的栈的结构
typedefstruct{
cstree*base;
cstree*top;
intstacksize;
}sqstack1;
为树的前根和后根非递归遍历提供保存已经访问过的数据信息
//树的队列结点结构
typedefstructqnode1{
cstreedata;
structqnode1*next;
}qnode1,*queueptr1;
//树的队列结构
typedefstruct{
queueptr1front;
queueptr1rear;
}linkqueue1;
为树的层次遍历提供条件
3.软件结构设计:
cout<<"1:
进行二叉树的操作2:
进行树的操作3:
退出"< 这是初始界面。 进行选择. cout<<"前序递归遍历是: "; preordertraverse(T); cout<<"中序递归遍历是: "; inordertraverse(T); cout<<"后序递归遍历是: "; postordertraverse(T); cout<<"前序非递归遍历是: "; preordertraverse1(T); cout<<"中序非递归遍历是: "; inordertraverse1(T); cout<<"后序非递归遍历是: "; postordertraverse1(T); cout<<"层次非递归遍历是: "; gradatraverse(T); cout<<"先根递归遍历是: "; preordertraverse2(T1); cout<<"后根递归遍历是: "; postordertraverse2(T1); cout<<"树前根非递归遍历是: "; preordertraverse3(T1); cout<<"树后根非递归遍历是: "; postordertraverse3(T1); cout<<"层次非递归遍历是: "; gradatraverse1(T1); 函数的返回值都是int型的,当函数执行成功,会返回1。 三、详细设计 1.定义程序中所有用到的数据及其数据结构,及其基本操作的实现; //二叉树的结点结构 typedefstructbitnode{ chardata; structbitnode*lchild,*rchild; }bitnode,*bitree; //二叉树的栈的结构 typedefstruct{ bitree*base; bitree*top; intstacksize; }sqstack; //二叉树后序非递归的栈的结构 typedefstructnode1{ bitreedata[30];//默认30个元素,这里需要一个辅助堆栈! ! ! inttop; }stack; //二叉树的队列结点结构 typedefstructqnode{ bitreedata; structqnode*next; }qnode,*queueptr; //二叉树的队列结构 typedefstruct{ queueptrfront; queueptrrear; }linkqueue; //树的结点结构 typedefstructcsnode{ chardata; structcsnode*firstchild,*nextsibling; }csnode,*cstree; //树的栈的结构 typedefstruct{ cstree*base; cstree*top; intstacksize; }sqstack1; //树的队列结点结构 typedefstructqnode1{ cstreedata; structqnode1*next; }qnode1,*queueptr1; //树的队列结构 typedefstruct{ queueptr1front; queueptr1rear; }linkqueue1; 2.主函数和其他函数的伪码算法; intmain() { bitreeT;cstreeT1; intm,n,h,k=1,l=1,t=1; while(t){ cout<<"1: 进行二叉树的操作2: 进行树的操作3: 退出"< 输入m; while(m! =1&&m! =2&&m! =3){ 提醒输入错误,请重新输入; 输入m; } if(m==1){ 输出请先建立二叉树(按先输入本结点然后输左孩子右孩子的顺序,'@'代表空结点)。 输出请输入结点的数据(char型); createbitree(T);//建立一棵二叉树 if(! T)输出该树为空并退出。 while(l){ cout<<"1: 二叉树前序递归遍历2: 二叉树中序递归遍历"< cout<<"3: 二叉树后序递归遍历4: 二叉树前序非递归遍历"< cout<<"5: 二叉树中序非递归遍历6: 二叉树后序非递归遍历"< cout<<"7: 二叉树层次非递归遍历8: 退出"< cout<<"以何种形式遍历该二叉树: "; 输入n; 如果n是1,进行二叉树前序递归遍历,如果n是2,进行二叉树中序递归遍历,如果n是3,进行二叉树后序递归遍历,如果n是4,进行二叉树前序非递归遍历,如果n是5,进行二叉树中序非递归遍历,如果n是6,进行二叉树后序非递归遍历,如果n是7,进行二叉树层序非递归遍历,如果n是8,退出,如果n不是1至8的数,程序自动退出, 同样, if(m==2){ 输入请先建立树(按先输入本结点然后输第一个孩子第一个兄的弟顺序'@'代表空结点) 请输入结点的数据(char型); createtree(T1);//建树函数 if(! T1)输出该树为空。 while(k){ cout<<"1: 树先根递归遍历2: 树后根递归遍历"< cout<<"3: 树先根非递归遍历4: 树后根非递归遍历"< cout<<"5: 树层次非递归遍历6: 退出"< cout<<"以何种形式遍历该树: "; 输入h, 如果h是1,对根进行先根递归遍历,如果h是2,对根进行后根递归遍历,如果h是3,对根进行先根非递归遍历,如果h是4,对根进行后序非递归遍历,如果h是5,对根进行层次遍历,如果h是6,退出。 如果输入的不是1至6的数,程序会自动退出。 最后如果t是3,程序退出,否则会继续弹出最开始的菜单,程序继续运行。 如二叉树的先序递归遍历: intpreordertraverse(bitreeT){ if(T根不空){ 访问根结点 先序遍历左子树(T->lchild)) 先序遍历右子树(T->rchild)) return1; return0; } return1; } 二叉树的中序后序递归遍历和它类似。 二叉树的前序非递归: intpreordertraverse1(bitreeT){ bitreep; sqstacks; initstack(s);//初始化一个栈 p=T; while(p不空或栈不空){ while(p不空){ visit(p);//访问p push(s,p); p=p->lchild; } if(! stackempty(s)) { pop(s,p); p=p->rchild; } } return0; } 3.主要函数的程序流程图,实现设计中主程序和其他子模块的算法,以流程图的形式表示。 4.画出函数之间的调用关系图。 当选择进行何种遍历时,通过switch语句能直接调用该函数,函数之间调用关系很少。 四、调试分析 1.实际完成的情况说明(完成的功能,支持的数据类型等): 能进行二叉树和树的各种遍历,包括递归和非递归,支持的数据类型是char型。 2.程序的性能分析,包括时空分析: 采用栈和队列来处理遍历,当树的输入数据不多时,占用时间和空间不多。 3.上机过程中出现的问题及其解决方案: 上机中出现了一些问题,首先是栈的应用还不是很熟练,在指针操作上出了一些问题,还有在一些时候没有把栈更改的信息及时返回,导致遍历时出错,在二叉树的后序非递归遍历时,需要在进队列的同时,把二叉树结点是左还是右通过tag数组用0、1来标记。 在树的先根和后根遍历时,参照了二叉树的先序和中序遍历,层次遍历时则运用队列,和二叉树的层次遍历差别在于它有多个孩子结点,因此在遍历时要注意。 4.程序中可以改进的地方说明: 遍历的内容基本实现了多种多样,但还可以尝试运用队列来建树,程序运行的界面还有待改进,容错方面也有待改进。 5.程序中可以扩充的功能及设计实现假想: 森林的遍历可以添加,主要实现可以参考树的遍历。 五、测试结果 六、用户手册 说明如何使用你编写的程序,详细列出每一步的操作步骤: 首先选择进行的操作1: 进行二叉树的操作2: 进行树的操作3: 退出。 如果输入的不是1、2、或,3则提醒输入错误,要重新输入。 选择1,进行二叉树操作,先建立一棵二叉树,按先输入本结点然后输左孩子右孩子的顺序,'@'代表空结点,并且输入该二叉树的数据类型要是char型,二叉树建好之后按回车即可选择进行遍历: 1: 二叉树前序递归遍历2: 二叉树中序递归遍历3: 二叉树后序递归遍历4: 二叉树前序非递归遍历5: 二叉树中序非递归遍历6: 二叉树后序非递归遍历7: 二叉树层次非递归遍历8: 退出,如果输入的不是这8个数,程序会自动退出,退出遍历二叉树后,还可选择进行树的操作,先建立树,然后按回车后,可选择树的遍历方式: 树先根递归遍历2: 树后根递归遍历3: 树先根非递归遍历4: 树后根非递归遍历5: 树层次非递归遍历6: 退出,如果输入的不是这六个数,程序也会自动退出,否则会按照选择进行遍历。 七、体会与自我评价 通过这次数据结构课程设计,让我复习了很多c语言的知识,也加深了对数据结构知识的理解,达到了融会贯通的作用,尽管程序并不是完全自己独创,但大部分都是自己独立完成的,有一部分是借鉴参考了一些老师以前给的算法并与同学讨论完成的,但是也同样起到了锻炼自己读写程序的能力,在这个实验中,主要用到了栈和队列的知识,在递归遍历中,要理解递归的先后顺序和遍历时的根与左右子树的遍历,在用栈时则要明确进出栈的顺序,即先进后出,而在用队列时则要注意它是先进先出的顺序,在做二叉树的后序非递归遍历时,它和二叉树的前序和中序非递归遍历有很大差别,因为它需要一个标记数组tag,树的前根和后根非递归遍历与二叉树的先序和中序遍历很类似,只需要,稍作修改就可以了,它的非递归层次遍历则要用一个队列,在队列出一个结点的同时,把它的各个兄弟结点都入队列,这样当把队列出空时,就是层次遍历了,就可以满足层次遍历的要求,这个程序在界面上有些粗糙,还可以改进,还可以尝试在建树时用队列而不是递归的方法,在程序中出现过指针指的非法的情况,这是对细节的掌握不够,还有体会到了用引用来作为参数的好处,它可以把函数对参数做的改变保存下来,而不需要每次都返回值。 借鉴参考的遍历算法都很巧妙,值得自己去慢慢体会,并争取内化成一种解题思想,虽然编写程序过程很枯燥,有时候出现错误不会应对的时候也很懊恼,但最终实现之后还是很有成就感的,以后要多做题,勤于思考,不懂多问。 争取有更大的进步。 源代码 #include #defineNULL0 usingnamespacestd; #definestack_init_size100 #definemaxsize100 #definestackincrement10 chare; //二叉树的结点结构 typedefstructbitnode{ chardata; structbitnode*lchild,*rchild; }bitnode,*bitree; //二叉树访问结点数据的函数 intvisit(bitreep){ cout<<(p->data)<<""; return1; } //建立二叉树函数(递归的方法) intcreatebitree(bitree&T){ charch; cin>>ch; if(ch=='@')T=NULL; else{ if(! (T=(bitnode*)malloc(sizeof(bitnode))))exit(0); T->data=ch; createbitree(T->lchild); createbitree(T->rchild); } return1; } //二叉树先序递归遍历 intpreordertraverse(bitreeT){ if(T){ if(visit(T)) if(preordertraverse(T->lchild)) if(preordertraverse(T->rchild)) return1; return0; } return1; } //二叉树中序递归遍历 intinordertraverse(bitreeT){ if(T) { if(inordertraverse(T->lchild)) if(visit(T)) if(inordertraverse(T->rchild))return1; return0; } return1; } //二叉树后序递归遍历 intpostordertraverse(bitreeT){ if(T){ if(postordertraverse(T->lchild)) if(postordertraverse(T->rchild)) if(visit(T))return1; return0; } return1; } //栈的结点结构 typedefstruct{ bitree*base; bitree*top; intstacksize; }sqstack; //初始化一个空栈 intinitstack(sqstack&S){ S.base=(bitree*)malloc(stack_init_size*sizeof(bitree)); if(! S.base)exit(0); S.top=S.base; S.stacksize=stack_init_size; return1; } intpop(sqstack&S,bitree&p){//这里用了引用 if(S.top==S.base)return0; p=*--S.top; return1; } //压栈函数 intpush(sqstack&S,bitreep){ if(S.top-S.base>=S.stacksize){ S.base=(bitree*)realloc(S.base,(S.stacksize+stackincrement)*sizeof(bitree)); if(! S.base)exit(0); S.top=S.base+S.stacksize; S.stacksize+=stackincrement; } *S.top++=p; return1; } //判断是否栈空函数 intstackempty(sqstack&S) { if(S.top==S.base)return1; elsereturn0; } //二叉树先序非递归遍历 intpreordertraverse1(bitreeT){ bitreep; sqstacks; initstack(s); p=T; while(p||! stackempty(s)){ while(p){ visit(p); push(s,p); p=p->lchild; } if(! stackempty(s)) { pop(s,p); p=p->rchild; } } return0; } //二叉树的中序非递归遍历 intinordertraverse1(bitreeT){ bitreep; sqstacks; initstack(s); p=T; while(p||(! stackempty(s))){ if(p){ push(s,p); p=p->lchild; } else{ pop(s,p); if(! visit(p)) return0; p=p->rchild; } } return0; } //二叉树的后序非递归遍历 typedefstructnode1{ bitreedata[30];//默认30个元素,这里需要一个辅助堆栈! ! ! inttop; }stack; voidinitstack1(stack*&s) {s=(stack*)malloc(sizeof(stack)); s->top=-1;} boolstackempty1(stack*s) {returns->top==-1;} boolisfull1(stack*s) {returns->top==49;} voidpush1(stack*s,bitreeT) { if(! isfull1(s)) s->data[++s->top]=T;//栈顶指针始终指向堆栈最上面可用的一个元素,因此入栈时候,先要将指针加1,然后再执行入栈操作! elsecout<<"已满"< } bitreepop1(stack*s) {if(! stackempty1(s))returns->data[s->top--];} bitreegettop1(stack*s) {if(! stackempty1(s))returns->data[s->top];}//出栈时,先取出栈顶指针指向的元素,然后再将指针减1,使其指向栈中下一个可用元素! voidpostordertraverse1(bitreeT) { bitreep; stack*s=NULL; initstack1(s); p=T; intTag[50];//栈,用于标识从左(0)或右 (1)返回 while(p! =NULL||! stackempty1(s)) { while(p! =NULL) { push1(s,p); Tag[s->top]=0; p=p->lchild; } while(! stackempty1(s)&&Tag[s->top]==1) { p=pop1(s); cout< } if(! stackempty1(s)){ Tag[s->top]=1;//设置标记右子树已经访问 p=gettop1(s); p=p->rchild; } elsebreak; } } //二叉树层次遍历 typedefstructqnode{ bitreedata; structqnode*next; }qnode,*queueptr; typedefstruct{ queueptrfront; queueptrrear; }linkqueue; //初始化一个空队列函数 intinitqueue(linkqueue&q){ q.front=q.rear=(queueptr)malloc(sizeof(qnode)); if(! q.front)exit(0); q.front->next=NULL; return1; } //对列的插入函数 intenqueue(linkqueue
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 课程设计 二叉 遍历