树的应用课程设计报告.docx
《树的应用课程设计报告.docx》由会员分享,可在线阅读,更多相关《树的应用课程设计报告.docx(10页珍藏版)》请在冰豆网上搜索。
树的应用课程设计报告
中北大学
数据结构
课程设计说明书
学生姓名:
赫景鑫
学号:
0921010451
学院:
软件学院
专业:
软件工程
题目:
树的应用
成绩
指导教师
尹四清、薛海丽
2011年1月6日
1.设计目的
《数据结构》课程主要介绍最常用的数据结构,阐明各种数据结构内在的逻辑关系,讨论其在计算机中的存储表示,以及在其上进行各种运算时的实现算法,并对算法的效率进行简单的分析和讨论。
进行数据结构课程设计要达到以下目的:
⏹了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;
⏹初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;
⏹提高综合运用所学的理论知识和方法独立分析和解决问题的能力;
训练用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所应具备的科学的工作方法和作风。
2.设计内容和要求
设计内容:
(1)建立一棵树;
(2)将树转换成二叉树;
(3)实现二叉树的前序、中序、后序的递归和非递归遍历算法。
设计要求:
(1)符合课题要求,实现相应功能;
(2)要求界面友好美观,操作方便易行;
(3)注意程序的实用性、安全性;
3.本设计所采用的数据结构
(1)typedefstructBTNode
定义一个用链式存储结构存储的二叉树,其中包括左孩子和右孩子以及数据元素的内容。
和单链表类似,一个二叉链表由头指针唯一确定,若二叉树为空,则头指针指向空。
并且结点内容的数据类型为字符型。
(2)CreateBiTree(BiTree&T)
此函数的功能是构建二叉树。
从键盘上按先序次序输入字符构造二叉链表表示的二叉树T,其中用空格表示空树。
(3)PreOrderTraverse(BiTreeT)
此函数功能是用递归的方法对二叉树进行先序遍历,调用此函数可以获得二叉树的递归的先序遍历的结果。
(4)InOrderTraverse(BiTreeT)
此函数功能是用递归的方法对二叉树进行中序遍历,调用此函数可以获得二叉树的递归的中序遍历的结果。
(5)PostOrderTraverse(BiTreeT)
此函数功能是用递归的方法对二叉树进行后序遍历,调用此函数可以获得二叉树的递归的后序遍历的结果。
(6)NRPreOrder(BiTreebt)
此函数的功能是用非递归的方法实现二叉树的先序遍历算法。
调用此函数可以获得二叉树的非递归的先序遍历的结果。
(7)NRInOrder(BiTreebt)
此函数的功能是用非递归的方法实现二叉树的中序遍历算法。
调用此函数可以获得二叉树的非递归的中序遍历的结果。
(8)NRPostOrder(BiTreebt)
此函数的功能是用非递归的方法实现二叉树的后序遍历算法。
调用此函数可以获得二叉树的非递归的后序遍历的结果。
(9)typedefstruct
{
BiTreeptr;
inttag;
}stacknode;
定义结构体,实现二叉树的非递归的后序遍历。
4.功能模块详细设计
4.1详细设计思想
数据结构是计算机、信息管理、信息与计算机科学等信息类专业最重要的专业基础课程,掌握好数据结构的知识将直接关系到后续专业课程的学习。
数据结构只要研究四个方面的问题:
(1)数据的逻辑结构,即数据之间的逻辑关系;
(2)数据的物理结构,即数据在计算机内的存储方式;(3)对数据的加工,即基于某种存储方式的操作算法;(4)算法的分析;即评价算法的优劣。
本实验是用链式存储结构来存储二叉树并进行一系列的算法,且结点内容的数据类型为字符型。
本程序用VC++6.0编写,可以实现各种二叉树的遍历。
包括先序遍历、中序遍历、后序遍历的递归算法,先序遍历、中序遍历、后序遍历的非递归算法。
二叉树的建立基本思想是:
依次输入的结点信息,若输入的结点不是虚结点,则建立一个新结点。
若新结点是第一个结点,则令其为根结点;否则将新结点作为孩子链接到它的双亲结点上。
程序主要是根据给定二叉树的先序遍历结果,构造出二叉树并输出按中,后序遍历的结果。
其中二叉树的结点用字符表示。
由于本人水平限制并没有实现树转化为二叉树的功能。
●先创建二叉树:
按先序次序输入,构造二叉链表表示的二叉树。
●设计算法:
先序遍历,中序遍历,后序遍历以及先序遍历、中序遍历、后序遍历的非递归算法。
A.前序遍历二叉树
若二叉树非空,则依次进行如下操作:
a)访问根结点;
b)前序遍历左子数;
c)前序遍历右子树。
B.中序遍历二叉树
若二叉树非空,则依次进行如下操作:
a)中序遍历左子树;
b)访问根结点;
c)中序遍历右子树。
C.后序遍历二叉树
若二叉树非空,则依次进行如下操作:
a)后序遍历左子树;
b)后序遍历右子树;
c)访问根结点。
D.先序遍历非递归算法
若二叉树非空,则依次进行如下操作:
a)根节点入栈
b)当堆栈非空时,循环执行一下步骤,出栈取得一个结点指针,访问该结点。
若该结点的右子树非空,则将该结点的右子树指针入栈。
若该结点的左子树非空,则将该结点的左子树指针入栈
c)结束
E.中序遍历非递归算法
若二叉树非空,则依次进行如下操作:
a)先将根结点入栈,然后将根结点的左子结点入栈,接着是已入栈的左子结点的左子结点入栈,以此类推,直到其左子结点为空
b)将最后入栈的子结点出栈
c)若其有右子结点则入栈,接着按1操作;否则将继续按2操作
F.后序遍历非递归算法
若二叉树非空,则依次进行如下操作:
采用标记法,结点入栈时,配一个标志一同入栈
a)遍历左子树的现场保护,
b)遍历右子树前的现场保护。
首先将遍历树的根指针入栈,遍历左子树;返回后,修改栈,遍历右子树;最后访问根结点。
设计main()函数调用以上步骤实现相关功能。
功能流程图如下
4.2核心代码
(1)定义二叉树
用链式存储结构存储二叉树。
其中,Lchild和Rchild是分别指向该结点左孩子和右孩子的指针,data是数据元素的内容。
定义二叉树结点值的类型为字符型且结点个数不超过10个。
typedefcharElemType;
constintMaxLength=10;//结点个数不超过10个
typedefstructBTNode{
ElemTypedata;
structBTNode*lchild,*rchild;
}BTNode,*BiTree;
(2)构造二叉链表
按先序次序输入,构造二叉链表表示的二叉树T,空格表示空树。
voidCreateBiTree(BiTree&T){
charch;
ch=getchar();
if(ch=='')T=NULL;
else{
if(!
(T=(BTNode*)malloc(sizeof(BTNode))))printf("mallocfail!
");
T->data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
(3)递归的先序遍历
函数功能是用递归的方法对二叉树进行先序遍历,调用此函数可以获得二叉树的递归的先序遍历的结果。
voidPreOrderTraverse(BiTreeT){
if(T){
printf("%c",T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
(4)递归的中序遍历
函数功能是用递归的方法对二叉树进行中序遍历。
voidInOrderTraverse(BiTreeT){
if(T){
InOrderTraverse(T->lchild);
printf("%c",T->data);
InOrderTraverse(T->rchild);
}
}
(5)递归的后序遍历
函数功能是用递归的方法对二叉树进行中序遍历。
voidPostOrderTraverse(BiTreeT){
if(T){
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c",T->data);
}
}
(6)非递归的先序遍历算法
函数功能是用非递归的方法对二叉树进行先序遍历。
voidNRPreOrder(BiTreebt)
{BiTreestack[MaxLength],p;
inttop;
if(bt!
=NULL){
top=0;p=bt;
while(p!
=NULL||top>0)
{while(p!
=NULL)
{
printf("%c",p->data);
stack[top]=p;
top++;
p=p->lchild;
}
if(top>0)
{top--;p=stack[top];p=p->rchild;}
}
}
}
(7)非递归的中序遍历算法
此函数的功能是用非递归的方法实现二叉树的中序遍历算法。
voidNRInOrder(BiTreebt)
{BiTreestack[MaxLength],p;
inttop;
if(bt!
=NULL){
top=0;p=bt;
while(p!
=NULL||top>0)
{while(p!
=NULL)
{
stack[top]=p;
top++;
p=p->lchild;
}
if(top>0)
{top--;p=stack[top];printf("%c",p->data);p=p->rchild;}
}
}
}
(5)非递归的后序遍历算法
此函数的功能是用非递归的方法实现二叉树的后序遍历算法。
调用此函数可以获得二叉树的非递归的后序遍历的结果。
其中bt是要遍历树的根指针,后序遍历要求在遍历完左右子树后,再访问根。
需要判断根结点的左右子树是否均遍历过。
可采用标记法,结点入栈时,配一个标志tag一同入栈1:
遍历左子树的现场保护,2:
遍历右子树前的现场保护。
首先将bt和tag(为1)入栈,遍历左子树;为返回后,修改栈顶tag2,遍历右子树;最后访问根结点。
typedefstruct
{
BiTreeptr;
inttag;
}stacknode;
voidNRPostOrder(BiTreebt)
{
stacknodes[MaxLength],x;
BiTreep=bt;
inttop;
if(bt!
=NULL){
top=0;p=bt;
do
{
while(p!
=NULL)
{
s[top].ptr=p;
s[top].tag=1;
top++;
p=p->lchild;
}
while(top>0&&s[top-1].tag==2)
{
x=s[--top];
p=x.ptr;
printf("%c",p->data);
}
if(top>0)
{
s[top-1].tag=2;
p=s[top-1].ptr->rchild;
}
}while(top>0);}
}
5.课程设计心得及存在问题
虽然都说“程序=数据结构+算法”,但我在学习运用数据结构编程之前,并没能深刻体会到这一点,直到这次课设实践。
我感受最深的一点是:
以前用C编程,只是注重如何编写函数能够完成所需要的功能,似乎没有明确的战术,只是凭单纯的意识和简单的语句来堆砌出一段程序。
但现在编程感觉完全不同了。
在编写一个程序之前,自己能够综合考虑各种因素,首先选取自己需要的数据结构,是树还是图或是别的什么?
然后选定一种或几种存储结构来具体的决定后面的函数的主要风格。
最后在编写每一个函数之前,可以仔细斟酌比对,挑选出最适合当前状况的算法。
这样,即使在完整的程序还没有写出来之前,自己心中已经有了明确的原图了。
这样无形中就提高了自己编写的程序的质量。
另外,我还体会到深刻理解数据结构的重要性。
只有真正理解这样定义数据类型的好处,才能用好这样一种数据结构。
了解典型数据结构的性质是非常有用的,它往往是编写程序的关键。
我以前对递归算法一直很害怕,总是看不明白究竟这递归是怎么进行的。
在这次实验中我终于克服了这一障碍,一次次单步执行书中递归函数的例子,并一遍遍在心中自己默默的走,终于弄明白了,真的是功夫不负有心人啊!
这次实验中我也出现过一些比较严重的错误。
在用链表结构编写程序时我错误的把一个定义的一级指针用二级指针来做,结果出现了一些难以想象的后果。
程序设计中不会树化为二叉树的算法,故并未实现此功能。