广义表的运算数据结构与算法课程设计报告.docx
- 文档编号:7695984
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:24
- 大小:187.95KB
广义表的运算数据结构与算法课程设计报告.docx
《广义表的运算数据结构与算法课程设计报告.docx》由会员分享,可在线阅读,更多相关《广义表的运算数据结构与算法课程设计报告.docx(24页珍藏版)》请在冰豆网上搜索。
广义表的运算数据结构与算法课程设计报告
合肥学院
计算机科学与技术系
课程设计报告
2009~2010学年第二学期
课程
数据结构与算法
课程设计名称
广义表的运算
学生姓名
陈发银
学号
0804012028
专业班级
08计本
(2)班
指导教师
王昆仑
2010年6月
题目:
广义表的运算。
本设计要求实现广义表的建立、查找、输出、取表尾、以及求深度、求逆表等。
一、问题分析与任务定义:
此程序需要完成以下几个任务:
首先要将输入的用数组存储的广义表转化成以广义表的存储结构存储的广义表,这个过程也就是生成广义表;查找广义表,查找广义表要返回一个值flag,当flag=1时,程序查找到待查的元素,当flag=0时,程序没有找到待查元素;输出广义表,遍历广义表,输出广义表的遍历结果;取表头,返回表头结点;取表尾,将广义表从第二个元素开始复制到另一个广义表中;求广义表的深度,遍历每一层广义表,将广义表内每层广义表深度最大的广义表相加为同一层所求过的子表中深度的最大值,最后返回值加一即为广义表的深度;求逆表,将广义表逆向输出。
实现本程序需要解决以下问题:
1、如何根据广义表的特点建立广义表。
2、用什么方法才能查找到广义表中每一个元素,如何标志是否找到待查元素。
3、建立广义表,如何根据广义表的存储结构的特点建立广义表。
4、求广义表的深度的依据是什么。
5、运用什么方法才能将广义表逆序。
6、如何实现广义表的遍历。
二、概要设计和数据结构选择:
1、设计思想:
广义表是线性表的一种推广,但它并不是线性表。
课本上在介绍广义表的计本概念的基础上,介绍了广义表的存储及应用。
广义表浓缩了线性表、数组等常见的数据结构的特点,在有效利用存储空间方面更胜一筹,目前在文本处理、人工智能、代数操作和计算机图形方面等各个领域都具有应用价值。
所以在我当时拿到这个题目的时候,虽然它只有短短的几行字,但是我深深的感觉到了它的难度,在后来课程设计中,也证实了我的感觉,每个功能都实在是太难实现了,所以只有各个击破了。
设计程序时,先起草了流程图,通过流程图来看,就使得程序鲜明易懂,接下来先写好了主函数,通过主函数的调用,实现题目要求的各个功能,使得程序模块化,便于编写,即使不会写的子函数,也可以先空着,等待以后想到好的方法后再对其进行操作,同时在程序界面上也做了美化,使人感觉舒畅,另外通过一个循环,能让用户进行循环操作,不至于每次只能进行一项操作,这个循环用的和线性表里的循环有点类似,但其实现的操作不同,当然有了以前实验的基础,这次编写起来,也感觉轻松了不少。
2、广义表的存储结构:
由于广义表中的元素本身又可以具有结构,是一种带有层次的非线性结构,因此难以用顺序存储的结构表示。
通常采用链式存储结构,每个元素可用一个结点表示,结点结构如图1、图2所示:
tag=0
atom
*tp
图1原子结点的存储结构
tag=1
*hp
*tp
图2结点的存储结构
每个结点由三个域构成。
其中tag是一个标志位,用来区分当前结点是原子结点还是子表。
当tag为1时,该结点是子表,第二个域为hp,用以存放子表的地址;当tag为0时,该结点是原子结点,第二个域为atom,用以存放元素值。
tp域是用来存放与本元素同一层的下一个元素对应结点的地址,当该元素是所在层的最后一个元素时,tp的值为NULL。
广义表及结点类型描述如下:
typedefcharElemType;
typedefstructGLode//广义表结构体的定义
{
inttag;/*结点类型标识*/
union
{
ElemTypeatom;/*原子值*/
structGLode*hp;/*指向子表的指针*/
}val;
structGLode*tp;/*指向下一个元素*/
}GList;
例如:
建立广义表:
(a,b(c,d),e),如图3
1
^
0
a
0
b
1
^
0
c
0
d
1
^
0
e
1
^
^
图3广义表的存储图示
3、求广义表的逆表需要用堆栈存储广义表的元素,栈的数据类型如下:
typedefcharElemType;
typedefstruct
{ElemTypedata[maxlen];
inttop;
}SeqStack;
3、程序流程图如图。
三、详细设计与编码
1、建立广义表CreateGL(char*&s)。
在生成广义表之前,用一个数组存储广义表,并用指针s指向数组,通过数组中的元素生成广义表。
基本思想是:
在广义表表达式中,遇到左括号”(”时递归构造子表,否则构造原子结点;遇到逗号时递归构造后续广义表,直到字符串数组结束,以"\0"作为结束标志。
实现过程如下:
GList*CreateGL(char*&s)
{读入广义表的一个字符给ch;
if(ch!
=空格')
{
if(ch=='(')
{递归构造子表;}
elseif(ch==')')
遇到')'字符,子表为空
else
{构造原子结点;}}
else
串结束,子表为空
读入广义表的一个字符给ch;
if(ch==',')
递归构造后续子表;
else
处理表的最后一个元素
返回广义表指针
}
2、遍历广义表DispGL(GList*g)。
输出广义表采用的算法思想是:
若遇到tag=1的结点,这是一个子表的开始,先打印输出一个左括号”(”。
如果该子表为空,则输出一个空格符;否则递归调用输出该子表。
子表打印输出完后,再打印一个右括号”)”。
若遇到tag=0的结点,则直接输出其数据域的值。
若还有后续元素,则递归调用打印后续每个元素,直到遇到tp=NULL。
其实现过程如下:
voidDispGL(GList*g)
{
if(g!
=NULL)
{
if(g->tag==1)
{
输出左括号'(';
if(g->val.hp==NULL)
输出一个空格;
else
递归调用子表;
}
else
输出数据域;
if(g->tag==1)
打印有括号“)”;
if(g->tp!
=NULL)
输出逗号“,”,递归调用输出下一个结点。
}
}
3、广义表的查找:
FindGListX()
在给定的广义表种查找数据域为x的结点,采用的算法思想是:
若遇到tag=0的原子结点,如果是要查找的结点,则查找成功1;否则,若还有后续元素,则递归调用本过程在孩子表中查找,若还有后续元素,则递归调用本过程查找后续每个元素,直到遇到hp域为NULL的元素。
设置flag标志查找结果;flag=1;表示查找成功,否则查找失败。
本函数实现过程如下:
FindGListX(GList*g,charx,int&mark)
{
if(g!
=NULL){
if(g->tag==0&&g->val.atom==x)
{
查找成功mark=1;
}
elseif(g->tag==1)递归调用查找后续元素;
递归查找调用后续元素;
}}
4、求广义表的表头:
head(Glist*g)
GList*head(GList*g)
{GList*p;
if(g->tag==1&&g->val.hp==NULL)
{空表不能求表头;}
else{返回表头结点}}
5、求广义表的表尾:
tail(GList*g)
一个广义表的表尾指的是除去该广义表的第一个元素剩下的部分。
求表尾实现过程如下:
GList*tail(GList*g)
{
if(g==NULL)
{
空表不能求表尾;
}
elseif(g->tag==0)
{
原子不能求表尾;
}
将广义表除去第一个元素,其余的元素复制的广义表q中,既为该广义表的表尾。
returnq;
}
6.求广义表的深度GLDepth(GList*g)。
广义表的深度的递归定义是它等于所有子表中表的最大深度加1,若一个表为空或仅由单个元素所组成,则深度为1。
求广义表深度的递归函数GLDepth()如
实现过程如下:
intGLDepth(GList*g)
{
if(g->tag==0)
为原子时返回;
g=g->val.hp;
if(g==NULL)
为空表时返回1;
while(g!
=NULL)
{
if(g->tag==1)
{
递归调用求出子表的深度;
if(dep>max)
max为同一层所求过的子表中深度的最大值;}
使g指向下一个元素;
}
返回表的深度(max+1)。
}
7、求广义表的逆表NIGList(GList*g,SeqStack*s)
求广义表的逆表的算法思想是:
利用广义表的遍历将广义表的元素存入一个堆栈中,然后在将栈中所有的元素出栈打印,函数的实现如下:
将广义表中的元素存入堆栈中:
voidNIGList(GList*g,SeqStack*s)
{
if(g!
=NULL)
{
if(g->tag==1)
{
将广义表中的“(”以“)”存入栈中;
else
递归调用,将子表中的元素存入栈中;
}
else
将广义表中的元素存入栈中;
if(g->tag==1)
将广义表中的")"以"("存入栈中;
if(g->tp!
=NULL)
将广义表中的","存入栈中;
递归将后续表的内容存入栈中。
}
}
将栈中所有元素输出:
voidPop(SeqStack*s)
{
打印栈中元素。
}
四、上机调试
1、调试函数FindGListX(GList*g,charx,intflag)时,函数起不了作用,对于flag的值不能做改变,在mian函数中使用两个scanf()函数,后面一个函数得不到运行。
解决办法:
在scanf()函数前加getchar(),如下面的程序所示:
flag=0;
getchar();
scanf("%c",&x);
FindGListX(g,x,flag);
if(flag)
printf("找到待查元素!
\n");
else
printf("没有找到待查元素!
\n");break;
2.程序运行后出现图5的错误:
图5错误2
解决办法:
在while循环中加入以下程序:
printf("是否继续:
1.继续;0.停止\n");
printf("请选择:
");
scanf("%d",&xz);
if(xz==1)
system("cls");
else
{
system("cls");
printf("再见!
\n");
}
3.求表尾函数错误,当输入空表时,不能输出空表不能求表尾这句提示语。
如图6所示:
图6错误3
解决方法:
把语句if(g=NULL)改成if(g->tag==1&&g->val.hp==NULL),因为空表为表结点,且空表没子表,所以这话就可以判断出广义表是否为空表了。
五、测试结果及其分析
1、查找广义表中的元素:
(1)待查元素在广义表中的运行结果如图9:
图9找到待查元素
(2)待查元素不在广义表中的运行结果如图10所示:
图10没有找到待查元素
2、求表头运行结果如图11所示:
图11求广义表的表头
3、求广义表的表尾运行结果如图12所示:
图12求广义表的表头
4、求广义表的深度的运行结果如图13所示:
图13求广义表的深度
5、求广义表的逆表的运行结果如图14所示;
图14求广义表的逆表
6、退出广义表的运行结果如图15所示
图15求广义表的逆表
六、用户使用说明
本程序运行过程时带有提示性语句,用户可以根据需要和提示进行操作:
1、运行程序,程序提示输入广义表,出现运行界面;
2、查找广义表中的元素。
选择1,程序提示,输入要查找的元素,若该元素在广义表中,程序显示:
找到待查元素。
否则显示 :
找不到待查元素;
3、求广义表的表头。
选择2,程序输出所求广义表的表头;
4、求广义表的表尾。
选择3,程序输出所求广义表的表尾
5、求广义表的深度。
选择4,程序输出广义表的深度;
6、求广义表的逆表。
选择5,程序输出广义表的逆表;
7、选择0,退出广义表的运算,程序终止;
8、每次操作结束以后,会有提示语句:
是否继续执行其他操作(选择1、继续;0、停止)。
七、总结
1、广义表的运算包括广义表的建立、查找、求表头、求表尾、求深度、广义表删除、求逆表,依据原子结点和结点的存储结构不同,进行相应的操作。
2、程序中多次使用递归调用。
3、使用联合体建立广义表的数据类型。
4、根据栈的特点将广义表逆置输出。
5、程序中使用switch函数,将每个操作分开进行。
八、参考书目
[1]王昆仑李红.数据结构与算法.北京:
中国铁道出版社,2007年6月第一版
[2]谭浩强.《C程序设计指导》.北京:
清华大学出版社,2005年7月
[3]姚群夏清国.数据结构.陕西:
西北工业大学出版社,2004年6月第一版
[4]黄国兴章炯民.数据结构与算法.北京:
机械工业出版社,2004年7月第一版
九、附录
#include
#include
#include
#definemaxlen100
typedefcharElemType;
typedefstructGLNode//广义表结构体的定义
{
inttag;//结点类型标识
union
{
ElemTypeatom;//原子值
structGLNode*hp;//指向子表的指针
}val;
structGLNode*tp;//指向下一个元素,相当于单链表中的next
}GList;
typedefstruct//栈结构的定义
{
ElemTypedata[maxlen];
inttop;
}SeqStack;
GList*CreateGL(char*&s)//建立广义表,生成广义表的链式存储结构
{
GList*h;//定义个新广义表
charch;
ch=*s;//取一个扫描字符
s++;//往后扫描字符
if(ch!
='\0')//判断是否为回车,若不是,则执行下面操作
{
h=(GList*)malloc(sizeof(GList));//动态申请个新广义表
if(ch=='(')//若当前字符为"("时,执行下列操作
{
h->tag=1;//新节点做为表头节点
h->val.hp=CreateGL(s);//递归调用字表,链接到表头结点上
}
elseif(ch==')')
h=NULL;//若为")"时,字表为空
else
{
h->tag=0;
h->val.atom=ch;//若都不满足,则为原子结点,
}}
ch=*s;//取下一个字符
s++;//指针后移
if(h!
=NULL)//判断是否为空
if(ch==',')//当前字符为','
h->tp=CreateGL(s);//递归调用后续子表
else
h->tp=NULL;//否则,则后续字表为空
returnh;
}
voidDispGL(GList*g)//遍历广义表
{
if(g==NULL)return;//若广义表为空,则返回
if(g->tag==0)
printf("%c,",g->val.atom);//若广义表g为原子结点,则直接输出其值
else{//否则为表结点,则输出"("
printf("(");
for(g=g->val.hp;g;g=g->tp)//从字表表头开始,依次遍历其后续子表
DispGL(g);
printf("\b),");}
}
intGLDepth(GList*g)//求广义表的深度
{
intmax=0,dep;//定义变量
if(g->tag==0)//若为原子结点,返回0
return0;
g=g->val.hp;//广义表g被赋值为子表结点
if(g==NULL)//若广义表为空,返回值1
return1;
while(g!
=NULL)//若不为空
{
if(g->tag==1)//若为表结点
{
dep=GLDepth(g);//递归调用,求深度
if(dep>max)
max=dep;
}
g=g->tp;//广义表g被赋值为其后续子表
}
return(max+1);
}
GList*head(GList*g)//求广义表表头
{
GList*p;//定义个新广义表p
if(g->tag==1&&g->val.hp==NULL)//若其为空表时,输出空表不能求表头
{printf("空表不能求表尾\n");
returnNULL;//返回
}
else{p=g->val.hp;//不为空表时,返回广义表g的子表表头结点
returnp;}}
GList*tail(GList*g)//求广义表表尾
{
GList*p;//定义个新广义表p
p=g->val.hp;//P被赋值为广义表g的表头结点
GList*t;
if(g->tag==1&&g->val.hp==NULL)//若其为空表时,输出空表不能求表尾
{printf("空表不能求表尾\n");
returnNULL;//返回
}
elseif(g->tag==0)//若为原子结点时,输出原子结点不能求表尾
{
printf("原子不能求表尾\n");
returnNULL;
}//否则,为表结点
p=p->tp;//p被赋为其后续结点
t=(GList*)malloc(sizeof(GList));//申请一个新结点t
t->tag=1;//t为表结点
t->tp=NULL;//t的后续结点被赋为空
t->val.hp=p;//t的子表为p
returnt;
}
voidFindGListX(GList*g,charx,int&flag)//广义表查找
{
if(g!
=NULL){
if(g->tag==0&&g->val.atom==x)//若为原子结点,且原子结点值等于x,flag=1
{
flag=1;
}
elseif(g->tag==1)//若为表结点
FindGListX(g->val.hp,x,flag);//递归调用其子表的表头结点
FindGListX(g->tp,x,flag);//递归调用其后续结点
}
}
voidNIGList(GList*g,SeqStack*s)//求广义表的逆表
{
if(g!
=NULL)
if(g->tag==1)//若为表结点时
{
s->top++;
s->data[s->top]=')';//将广义表中的"("以“)”存入栈中
if(g->val.hp==NULL)
printf("");
else
NIGList(g->val.hp,s);//递归调用将子表存入栈中
}
else//若为原子结点时
{
s->top++;
s->data[s->top]=g->val.atom;//直接将原子结点值如栈
}
if(g->tag==1)
{
s->top++;
s->data[s->top]='(';//将广义表中的")"以"("存入栈中
}
if(g->tp!
=NULL)
{
s->top++;
s->data[s->top]=',';//将广义表中的","存入栈中
NIGList(g->tp,s);//递归调用将后续表的内容存入栈中
}
}
voidPop(SeqStack*s)//广义表的输出
{
while(s->top>=0)
{
printf("%c",s->data[s->top]);
s->top--;
}
}
voidmain()
{
GList*g,*gt;
system("color1B");
printf("请输入一个广义表:
如(a,(b),c)\n");
charstr[30];
charx;
inty=0,mark,m=1;
SeqStack*k;
k=(SeqStack*)malloc(sizeof(SeqStack));
k->top=-1;
char*s=gets(str);
g=CreateGL(s);
printf("你输入的广义表为:
\n");
while(m)
{
DispGL(g);
printf("\b\n");
printf("\t\t*****广义表的运算*****\n");
printf("\t\t===========================\n");
printf("\t\t|***1.广义表查找***|\n");
printf("\t\t|***2.求广义表头***|\n");
printf("\t\t|***3.求广义表尾***|\n");
printf("\t\t|***4.求广义表深度***|\n");
printf("\t\t|***5.求广义表逆表***|\n");
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 广义 运算 数据结构 算法 课程设计 报告