PrintList_Sq(L);
}
1.5.调试分析和测试结果
(1).在调用指针时应先将其初始化,如果没有初始化指针就调用它,这样很不安全,虽然你有时可以运行,却有了不安定的因素。
如:
int*data;可以成定义:
intdata[52];这里的data是一个常量地址,也是一个数组名,因此不用担心它没有被初始化。
(2).这题的时间复杂度是O(52)。
(3).虽然本次程序的题目难度与其他问题相比不是很高,但仍有很多问题我们是很容易忽视的,其一:
在理解题目的要求时,注意翻牌的次数可能有多次;其二:
for循环的嵌套使用在书写时很容易漏掉大括弧。
第二章:
线索二叉树
2.1.需求分析
任务1.建立中序线索二叉树,并且中序遍历;
2.求中序线索二叉树上已知结点中序的前驱和后继;
2.2.概要设计
本题目重在设计二叉树的各种线索化实现,以C语言作为编程语言,实现对二叉树的先、中、后三种序列的线索化。
旨在使我们在课程设计过程中能进一步学习各种所需函数,以及了解二叉树的各种线索化过程。
其中各函数分别为:
BiThrTreeCreateBiTree();//创建二叉树;
BiThrTreeCopyBiTree(BiThrTree&rt)//复制一棵二叉树;
voidPreOrderTraverse(BiThrTreeT)//先序遍历二叉树;
voidInOrderTraverse(BiThrTreeT)//中序遍历二叉树;
voidPostOrderTraverse(BiThrTreeT)//后序遍历二叉树;
boolPreOrderThreading(BiThrTree&Thrt,BiThrTreeT)//先序线索化二叉树;
voidPreThreading(BiThrTreep)//先序搜索结点的建立;
boolInOrderThreading(BiThrTree&Thrt,BiThrTreeT)//中序线索化二叉树;
voidInThreading(BiThrTreep)//中序搜索结点的建立;
voidbackThreading(BiThrTreep)//后序搜索结点的建立;
BiThrTreebackorderThreading(BiThrTree&rt)//后序线索化二叉树;
BiThrTreeparent(BiThrTree&thrt,BiThrTree&p)//查找结点
voidPreOrderTraverse_Thr(BiThrTreeThrt)//遍历先序线索化二叉树;
voidInOrderTraverse_Thr(BiThrTreeThrt)//遍历中序线索化二叉树;
voidbackorderTraver(BiThrTreeThrt)//遍历后序线索化二叉树;
voidInOrder_Thr_T(BiThrTreeThrt,BiThrTree&T)//将线索化后的二叉树还原;
2.3.详细设计
二叉树的遍历本质上是将一个复杂的非线性结构转换为线性结构,使每个结点都有了唯一前驱和后继(第一个结点无前驱,最后一个结点无后继)。
对于二叉树的一个结点,查找其左右子女是方便的,其前驱后继只有在遍历中得到。
为了容易找到前驱和后继,有两种方法。
一是在结点结构中增加向前和向后的指针fwd和bkd,这种方法增加了存储开销,不可取;二是利用二叉树的空链指针。
现将二叉树的结点结构重新定义如下:
lchild
ltag
data
rtag
rchild
其中:
ltag=0时 lchild指向左子女;
ltag=1时 lchild指向前驱;
rtag=0时 rchild指向右子女;
rtag=1时 rchild指向后继;
2、对二叉树进行中序线索化的算法
bithptr *pre; /* 全程变量 */
void INTHREAD(bithptr *p) {
if(p!
=NULL)
{
INTHREAD(p->lchild); /* 左子树线索化 */
if(p->lchild==NULL) {
p->ltag=1;p->lchild=pre;
} if(p->rchild==NULL)
p->rtag=1;
if(pre!
=NULL && pre->rtag==1)
pre->rchild=p; pre=p; /* 前驱指向当前结点 */
INTHREAD(p->rchild); /* 右子树线索化 */
3、在线索二叉树上查找前驱和后继
(1)中序线索二叉树:
若结点的ltag=1,lchild指向其前驱;否则,该结点的前驱是以该结点为根的左子树上按中序遍历的最后一个结点。
若rtag=1,rchild指向其后继;否则,该结点的后驱是以该结点为根的右子树上按中序遍历的第一个结点。
求后继的算法如下:
bithptr *INORDERNEXT(bithptr *p) {
if (p->rtag==1)
return(p->rchild);
else {
q=p->rchild; /* 找右子树最先访问的结点 */
while (q->ltag==0)
q=q->lchild;
return(q);
}
}
求前驱的算法如下:
bithptr *INORDERNEXT(bithptr *p) {
if (p->ltag==1)
return(p->lchild);
else {
q=p->lchild;/* 找左子树最后访问的结点 */
while (q->rtag==0)
q=q->rchild;
return(q);
}
}
2.4.程序流程图
(1)线索化二叉树的遍历
在程序设计中,实现线索化二叉树的遍历,实质上就是在查找每个结点的前驱和后继,而结点是否有前驱和后继、他们分别是什么,就要分情况去讨论。
1.中序遍历线索化二叉树(InOrderTraverse_Thr(Thrt))时,结点的前驱应是遍历左子树时访问的第一个结点,既左子树最左下方的结点,结点的后继应是遍历右子树时访问的第
图3.11PreOrderTraverse_Thr(Thrt)
遍历先序线索化二叉树
图3.12InOrderTraverse_Thr(Thrt)
遍历中序线索化二叉树
一个结点,既右子树最左下方的结点。
二叉树最左下方的结点没有前驱,最右下方的结点没有后继。
设计该函数的流程如图3.12所示。
2.在后序线索树(PostOrderTraverse_Thr(Thrt))中找结点后继比较复杂,分三种情况
(1)根结点没有后继;
(2)若结点是其双亲的右孩子或是其双亲的左孩子且其双亲没有右子树,则后继为双亲;(3)若结点是其双亲的左孩子且其双亲有右子树,则后继为其
双亲的右子树上按后序遍历访问的第一个结点。
设计该函数的流程如图3.13所示。
3.还原线索化二叉树(InOrder_Thr_T(Thrt,T)):
涉及该函数的主要目的是在每次线索后
图3.13backOrderTraverse_Thr(Thrt)遍历后序线索化二叉树
都能清除掉前一次线索化过程中所留下的指针,因为不通顺序的线索化,其修改的空指针也不同,因此,进行下一次线索化前,必须还原空指针。
此函数的流程如图3.14所示。
图3.14InOrder_Thr_T(Thrt,T)
还原线索化后的二叉树
图3.15menu_select()
控制选择菜单
2.5.调试分析和测试结果
(1).在编写程序时应该用规范化的格式输入源程序,同时注意不要忘了编写头文件#include、#include;在编程时不要忽略了一些细节,不要忘了;、}等符号,否则程序将无法正常运行。
3.设计体会:
做一个课程设计要注意很多方面,无论是格式,还是书写的内容和要表达的思想都得严格要求自己,所以做起来真的不算容易。
本次课程设计涉及了很多知识,由于往日没有学得很扎实,对某些问题仍然比较疑惑,所以要进行充足的补习。
期间,我翻阅了很多书籍,知识总是联系很紧密的,解决完这个问题又发现了新的问题,之后,为了解决新问题又发现了更多的问题,就这样,我得等到一个一个把问题处理完。
4.结束语:
通过这次的数据结构课程设计,我明显感觉到自己在很多方面的不足。
所以在整个过程中,我不断加深了对数据结构的理解与一些程序写书时要注意的事项,也让我对这门课程有了进一步的了解和认识。
完成一个课程设计要注意很多方面,无论是格式、书写的内容还是要表达的思想,所以我们必须严格要求自己。
本次课程设计涉及了很多知识,由于往日学得不扎实,对某些问题仍然存在疑惑,我查阅了相关书籍,以便将疑难问题解决,同时更加进一步的掌握相关知识。
此次的课程设计不仅让我深刻体会到了学习这门课程的重要性与必要性,也让我懂得了学习是思考一个的过程,我们应该主动去思考学到的知识以及学到后怎么去运用,而不是一味地被动地接受。
数据结构及其算法在解决现实生活中的常见问题和书写软件设计方面上都有着重要的意义,我们应该好好掌握它的相关知识,在以后的学习过程中,更多的去学会如何运用知识。
5.致谢
感谢学校为我们提供的学习及完成课程设计的机会,也感谢老师的教导和同学们对我的帮助与支持。
参考文献:
1、姜学军《数据结构》(C语言版).中国轻工出版社
2、严蔚敏《数据结构》(C语言版).清华大学出版社
3、徐孝凯《数据结构实用教程》(C/C++描述).清华大学出版社
4、陈慧南《数据结构》(使用C++语言描述).东南大学出版社
附录一:
纸牌源程序
#include
#include
#defineSIZE100//线性表存储空间的初始分配量
typedefstruct{
int*elem;//存储空间基址
int*data;
intlength;//当前长度
intlistsize;//当前分配的存储容量
}SqList;
voidInitList_Sq(SqList&L){
//构造一个空的线性表L。
L.elem=(int*)malloc(SIZE*sizeof(int));
if(!
L.elem)
cout<<"ERROR";//存储分配失败
L.data=(int*)malloc(SIZE*sizeof(int));
if(!
L.data)
cout<<"ERROR";//存储分配失败
L.length=0;//空表长度为0
L.listsize=SIZE;//初始存储容量
}//InitList_Sq
voidPrintList_Sq(SqListL){
//显示线性表中所有数据
for(inti=1;i<=L.length;i++)
{if(L.data[i]==1)
cout<}
cout<}
voidup(SqListL){
for(inti=1;i<=L.length;i++)
L.data[i]=1;
}
voiddown(SqListL,intn){
for(inti=2;i<=n;i++)
for(intj=i;j<=L.length;j++)
if(j%i==0){
if(L.data[j]==1)
L.data[j]=0;
elseif(L.data[j]==0)
L.data[j]=1;
}
}
intmain()
{SqListL;
intn=52;
InitList_Sq(L);
for(inti=1;i<=n;i++)
{
L.elem[i]=i;
L.length++;
}
up(L);
down(L,n);
cout<<"正面向上的牌的编号是:
"<PrintList_Sq(L);
}
附录二:
链表源程序
#include
#include"malloc.h"
#include"windows.h"
#definemaxsize20//规定树中结点的最大数目
typedefstructnode{//定义数据结构
intltag,rtag;
chardata;
structnode*lchild,*rchild;
}Bithptr;
Bithptr*Q[maxsize];
Bithptr*CreatTree(){
charch;
intfront,rear;
Bithptr*T,*s;
T=NULL;
front=1;rear=0;
printf("********************线索二叉树操作系统*********************\n");
printf("进行初始化,请依次输入结点以#号结束\n");
ch=getchar();
while(ch!
='#')
{
s=NULL;
if(ch!
='@')
{
s=(Bithptr*)malloc(sizeof(Bithptr));
s->data=ch;
s->lchild=NULL;
s->rchild=NULL;
s->rtag=0;
s->ltag=0;
}
rear++;
Q[rear]=s;
if(rear==1)T=s;
else
{
if(s!
=NULL&&Q[front]!
=NULL)
if(rear%2==0)
Q[front]->lchild=s;
elseQ[front]->rchild=s;
if(rear%2==1)front++;
}
ch=getchar();
}
returnT;
}
voidInorder(Bithptr*T)
{
if(T)
{
if(T->ltag!
=1)Inorder(T->lchild);
printf("%c→",T->data);
if(T->rtag!
=1)Inorder(T->rchild);
}
}
Bithptr*pre=NULL;
voidPreThread(Bithptr*root)
{
Bithptr*p;
p=root;
if(p){
PreThread(p->lchild);
if(pre&&pre->rtag==1)pre->rchild=p;
if(p->lchild==NULL)
{
p->ltag=1;
p->lchild=pre;
}
if(p->rchild==NULL)
p->rtag=1;
pre=p;
PreThread(p->rchild);
}
}
voidPrintIndex(Bithptr*t)
{
Bithptr*f;
f=t;
if(f)
{
if(f->ltag==1&&f->lchild==NULL&&f->rtag==1)
printf("【%c】",f->data);
if(f->ltag==1&&f->lchild!
=NULL)
printf("%c→【%c】",f->lchild->data,f->data);
if(f->ltag==1&&f->rtag==1&&f->rchild!
=NULL)
printf("→%c",f->rchild->data);
elseif(f->rtag==1&&f->rchild!
=NULL)
printf("【%c】→%c",f->data,f->rchild->data);
printf("\n");
if(f->ltag!
=1)PrintIndex(f->lc