数据结构课程设计 广义表的运算
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《数据结构》课程设计
题目:广义表的运算
广义表是线性表的推广。
线性表的元素仅限于原子项。
广义表的元素或者是原子,或者是一个广义表,有其自身结构。
广义表通常用圆括号括起来,用逗号分隔其中的元素。
为了区分原子和广义表,书写时用大写字母表示广义表,用小写字母表示原子。
LS=(a1,a2,…,an),LS是广义表的名字,n为它的长度,若ai是广义表,则称它为LS的子表。
若广义表非空(n>=1),则a1是LS的表头,其余元素组成的表(a2,…,an)称为LS的表尾。
一个表展开后所含括号的层数称为广义表的深度。
本设计要求实现广义表的建立、查找、输出、取表头、取表尾及求深度等运算。
选择合适的存储结构表示广义表,并能实现下列运算要求:
(1)用大写字母表示广义表,用小写字母表示原子,并提供设置广义表的值的功
能。
(2)取广义表L的表头和表尾的函数head(L)和tail(L)。
(3)能用这两个函数的复合形式求出广义表中的指定元素。
(4)由广义表的字符串形式到广义表的转换函数Lists Str_ToLists_(S);例如
Str_ToLists_(“ (a,(a,b),c)”)的值为一个广义表。
(5)由广义表到广义表的字符串形式的转换函数char * Lists_To_Str(L)。
(6)最好能设置多个广义表。
解:本题的解法如下:
1算法设计
1.由于广义表(a1,a2,…,an)中的数据元素可以具有不同的结构(或是原子或是列表)因此难以用顺序存储结构表示,通常采取链式存储结构,每个元素都可以用一个结点表示。
一个表结点可由3个域组成:标志域,指针表头的指针域和指针表尾的指针域;而原子结点只需两个域:标志域和值域。
2.假设以字符串L=(a1,a2,…,an) 的形式定义广义表L,建立相应的存储结构。
对广义表进行的操作下递归定义时,可以有两种方法。
一种是把广义表分解成表头和表尾两部分;另一种是把广义表堪称含有n个并列子表(假设原子也视作子表)的表。
在讨论建立广义表的存储结构时,这两种分析方法均可。
3.实现查找,即实现广义表的遍历。
4.取表头和表尾:广义表一般记做LS=(α
1,α
2
,…α
n
)其中,LS是广义表
LS=(α
1,α
2
,…α
n
)的名称,n是它的长度。
在线性表的定义中,α
i
(1<=i<=n)
只限于单个元素,而在广义表的定义中,α
i
可以是单个元素,也可以是广义表,
分别称为广义表LS的原子和子表。
当广义表非空时,称第一个元素α
i
为LS的表头,称其余的元素组成的表(α2,α3,…αn)为LS的表尾。
5.由广义表的字符串形式到广义表转换函数:由于S中的每个子串α
i
定义L 的一个子表,从而产生n 个子问题,即分别由这n个子串 (递归)建立n 个子表,再组合成一个广义表。
其中:可以直接求解的两种简单情况为:以串‘()’建立的广义表是空表,由单字符建立的广义表只是一个原子结点。
若是其他情况,因为第一个子表的标志域为一,代表指向广义表的头指针。
指示表头的指针域指向第一个子表的头指针。
相邻子表之间用表结点相连接。
综上:若 S = '( )'则
L = NIL;否则,构造第一个表结点 *L,并从串S中分解出第一个子串α
1
,对应创建第一个子广义表L->ptr.hp;若剩余串非空,则构造第二个表结点
L->ptr.tp,并从串S中分解出第二个字串α
2
,对应创建第二个子广义表……以此类推直至剩余串为空串止。
6.由广义表到广义表的字符串形式
7.求深度:广义表深度定义为广义表中括弧的重数,是广义表的一种量度。
例如,
多元多项式广义表的深度为多项式中变元的个数。
设非空广义表为LS=(α
1
,α
2,…α
n
)其中α
i
(i=1,2,3…)或为原子或为LS的子表,则求LS的深度可
分解为n个子问题,每个子问题为求α
i 的深度,若α
i
是原子,则由定义其深度
为零,若α
i 是广义表,则和上述一样处理,而LS的深度为各α
i
(i=1,2,3…)
的深度中最大值加一。
空表也是广义表,并由定义可知空表的深度为1。
由此可见,求广义表的深度递归算法有两个终结态:空表和原子,且只要求得αi
(i=1,2,3,…)的深度,广义表的深度就容易求得了。
显然,它应比子表深度的最大值多1.
广义表 LS=(α
1,α
2
,…α
n
)的深度DEPTH(LS)的递归定义为
基本项:DEPTH(LS)=1当LS为空表时
DEPTH(LS)=0当LS为原子时
归纳项:DEPTH(LS)=1+Max{DEPTH(α
i
)}n>=1由此定义容易写出求深度的递归函数。
假设L是GList型的变量则L=NULL表明广义表为空表,L->tag=0表明是原子。
反之,L指向表结点,该结点中的hp指针指向表头,即为L的第一个子表,而结点中的tp指针所指表尾结点中的hp指针指向L的第二个子表。
在第一层中由tp相连的所有尾结点中的hp指针均指向L的子表。
由此可得广义表深度的递归算法。
2程序实现
上机实现算法时由于具体问题牵涉到各种方面,难以综合实现,可以分为几个小的模块将程序先进行初步整合
具体程序:
#include<iostream.h>
#include<string.h>
#include<cstdlib>
class GenListNode{
friend class GenList;
public:
int utype; //0,1,2,3
union{
int intinfo;
char charinfo;
GenListNode* hlink;
}value;
GenListNode* tlink;
GenListNode(){}
};
class GenList{
public:
GenListNode * first;
int Sever( char* &hstr,char * &s );
void strncpy1( char* &hstr,char* &s,int comma );
GenListNode* CreatList( char* s );
void Creat( char* s );
void Display( void );
void Display( char * s ,GenListNode* ls);
void show( GenListNode* ls );
void head(GenListNode* &u);
void tail(GenListNode* &u);
int display(GenListNode* u1,GenListNode* u);
void find(char* s,GenListNode* &u);
};
void GenList::Creat( char* s )
{
first=CreatList(s);
}
GenListNode* GenList::CreatList( char* s )
{
GenListNode *ls,*head;
ls=new GenListNode();
head=ls;
ls->utype=0;
if( strlen(s)<=2 )
{
ls->tlink=NULL;
}else{
char* sub;
while( strlen(s)>2 ){
ls = ls->tlink = new GenListNode();
ls->utype=Sever(sub,s);
switch( ls->utype ){
case 1:ls->value.intinfo=atoi(sub);break;
case 2:ls->value.charinfo=sub[0];break;
case 3:ls->value.hlink=CreatList( sub );break;
}
}
ls->tlink=NULL;
}
return head;
}
int GenList::Sever( char* &hstr,char* &s )
{
char ch=s[0];
int n=strlen( s );
int i=0,k=0,comma=-1;
int x=0,y=0;
while( i<n && (ch!=',' || k!=0) ){
if( ch=='(' ){ k++;}
else{
if( ch==')' ){ k--;}
}
i++;
ch=s[i];
if(ch==',' && x==0){x=10;comma=i;}
if(k==1 && x<8){x++;if(x==2){comma=i;}}
}
if( k!=0 ){
cout<<"括号不配对! 退出程序!"<<endl;
exit(1);
}
if( comma==-1 ) {comma=n;}
strncpy1( hstr,s,comma ); //分割字符串
if( strlen(hstr)>=3 ){return 3;}
else{
if( hstr[0]<='9' && hstr[0]>='0' ){return 1;}
if( hstr[0]<='z' && hstr[0]>='a' ){return 2;}
}
return 1;
}
void GenList::strncpy1 (char* &hstr,char* &s,int comma ){ int n=strlen(s);
hstr=new char[n];
for( int t=0,i=1;i<comma;i++ ){
hstr[t]=s[i];
t++;
}
hstr[t]='\0';
for( t=1,i=comma+1;i<n;t++,i++ )
{s[t]=s[i];}
s[t]='\0';
if(t==1){s[1]=')';s[2]='\0';}
}
void GenList::Display( void ){
show( first );
}
void GenList::Display( char * s ,GenListNode* ls)
{
int i=0;
if(ls->utype==0){
while( ls!=NULL ){
switch( ls->utype ){
case 0:s[i]='(';i++;cout<<"( "; break;
case
1:s[i]='0'+(ls->value.intinfo-0);i++;cout<<ls->value.intinfo;if(ls->t link!=NULL){s[i]=',';i++;cout<<" , ";} break;
case
2:s[i]=ls->value.charinfo;i++;cout<<ls->value.charinfo;if(ls->tlink!= NULL){s[i]=',';i++;cout<<" , ";} break;
case
3:show( ls->value.hlink );if(ls->tlink!=NULL){s[i]=',';i++;cout<<" , ";} break;
}
ls=ls->tlink;
}
s[i]=')';i++;
cout<<" ) "<<endl;
s[i]='\0';
}else{
while( ls!=NULL ){
switch( ls->utype ){
case 0:s[i]='(';i++;cout<<"( "; break;
case
1:s[i]='0'+(ls->value.intinfo-0);i++;cout<<ls->value.intinfo;if(ls->t
link!=NULL){s[i]=',';i++;cout<<" , ";} break;
case
2:s[i]=ls->value.charinfo;i++;cout<<ls->value.charinfo;if(ls->tlink!= NULL){s[i]=',';i++;cout<<" , ";} break;
case 3:show( ls->value.hlink ); break;
}
ls=ls->tlink;
}
cout<<endl;
s[i]='\0';
}
}
void GenList::show( GenListNode* ls )
{
if(ls->utype==0){
while( ls!=NULL ){
switch( ls->utype ){
case 0:cout<<"( "; break;
case 1:cout<<ls->value.intinfo;if(ls->tlink!=NULL){cout<<" , ";} break;
case 2:cout<<ls->value.charinfo;if(ls->tlink!=NULL){cout<<" , ";} break;
case 3:show( ls->value.hlink );if(ls->tlink!=NULL){cout<<" , ";}
break;
}
ls=ls->tlink;
}
cout<<" ) ";
}else{
while( ls!=NULL ){
switch( ls->utype ){
case 0:cout<<"( "; break;
case 1:cout<<ls->value.intinfo;if(ls->tlink!=NULL){cout<<" , ";} break;
case 2:cout<<ls->value.charinfo;if(ls->tlink!=NULL){cout<<" , ";} break;
case 3:show( ls->value.hlink ); break;
}
ls=ls->tlink;
}
}
}
void GenList::head(GenListNode* &u)
{
if(first->tlink!=NULL){
u=new GenListNode;
u->utype=first->tlink->utype;
switch( u->utype ){
case 1:u->value.intinfo=first->tlink->value.intinfo;
break;
case 2:u->value.charinfo=first->tlink->value.charinfo;
break;
case 3: u->value.hlink=first->tlink->value.hlink ;
break;
}
if(first->tlink!=NULL){
first->tlink=first->tlink->tlink;}
u->tlink=NULL;
}else{cout<<"元素列表为空。
"<<endl;}
}
void GenList::tail(GenListNode* &u)
{
GenListNode* x;
x=first;
if(x->tlink!=NULL){
for(;x->tlink->tlink!=NULL;)
{
x=x->tlink;
}
u=new GenListNode;
u->utype=x->tlink->utype;
switch( u->utype ){
case 1:u->value.intinfo=x->tlink->value.intinfo; break;
case 2:u->value.charinfo=x->tlink->value.charinfo; break;
case 3: u->value.hlink=x->tlink->value.hlink ; break;
}
if(x->tlink!=NULL){
x->tlink=NULL;}
u->tlink=NULL;
}else{cout<<"元素列表为空。
"<<endl;}
}
void GenList::find(char* s,GenListNode* &u)
{
int n=strlen(s);
char * s1;
int x=0,y=0,o=0,j=0;
bool i=0;
if(n=1){
if(s[0]<='9' && s[0]>='0'){
for(;first->tlink!=NULL ;){
head(u);
if(u->value.intinfo==s[0]){j=91;cout<<"找到元素。
"<<endl;break;}
}
}
if(s[0]<='z' && s[0]>='a'){
for(;first->tlink!=NULL ;){
head(u);
if(u->value.charinfo==s[0]){j=91;cout<<"找到元素。
"<<endl;break;}
}
}
}
if(n>=2){
GenListNode* p;
for(;first->tlink!=NULL ;){
head(u);
p=u->value.hlink;
p=p->tlink;
for(x=1,y=1;x<n-1;x++){
if(s[x]<='9' && s[x]>='0'){
s1[0]=s[x];
s1[1]='\0';
o=atoi(s1);
if(p->value.intinfo==o){if(p->tlink!=NULL)p=p->tlink;}
}
if(s[x]<='z' && s[x]>='a'){
if(p->value.charinfo==s[x]){if(p->tlink!=NULL)p=p->tlink;}
}
}
if(p->tlink==NULL){j=91;cout<<"找到元素。
"<<endl;break;} }
}
if(j!=91){cout<<"无该元素。
"<<endl;}
}
int GenList::display(GenListNode* u1,GenListNode* u)
{
int x=0;
for(;u1->tlink!=NULL ;){
if(u->utype==u1->utype){
switch( u->utype ){
case 1:if(u->value.intinfo==u1->value.intinfo){x=1;} break;
case 2:if(u->value.charinfo==u1->value.charinfo){x=1;} break;
case 3: if(display(u1->value.hlink,u->value.hlink)){x=1;} break;
}
}
u1=u1->tlink;
}
return x;
}
int main( void ){
char s[45];
char s1[45];
char s2[45];
char s5[45];
int i;
GenListNode* u,* x;
cout<<"*************************************广义表************************************"<<endl;
cout<<"*******************请输入广义表like:(a,b,c,d,(1,2,3,d),f)******************* "<<endl;
cin>>s;
GenList A;
A.Creat(s);
cout<<"1,********取头结点********"<<endl;
cout<<"2,********取尾结点********"<<endl;
cout<<"3,******查找特定元素******"<<endl;
cout<<"4,***将广义表转换成字符***"<<endl;
cout<<"5,*将广义表转换成字符类型*"<<endl;
cout<<"0,**********退出**********"<<endl;
cout<<"执行:";
cin>>i;
for(;i!=0;cin>>i){
switch(i)
{
case 0:
break;
case 1:A.head(u);
A.show(u);break;
case 2:A.tail(u);
A.show(u);break;
case 3:
cout<<"********输入查找元素*******"<<endl;
cin>>s1;
cout<<endl;
A.find(s1,u);
A.show(u);
u=NULL;
break;
case 4:
A.Display();
cout<<endl;
break;
case 5:
cout<<endl;
A.Display(s5,A.first);
A.show(u);
u=NULL;
break;
default:
cout<<"*****请输入正确的口令!*****";
break;
}
cout<<endl;
cout<<"1,********取头结点********"<<endl;
cout<<"2,********取尾结点********"<<endl;
cout<<"3,******查找特定元素******"<<endl;
cout<<"4,***将广义表转换成字符***"<<endl;
cout<<"5,*将广义表转换成字符类型*"<<endl;
cout<<"0,**********退出**********"<<endl;
cout<<"执行:";
}
return 1;
}
3总结
在拿到题目进行设计时,我首先考虑到问题可以分为几个比较简单的小问题依次解决,于是我化整为零,逐个找解决问题的办法,这样设计出的程序条理比较清晰,易于编辑。
但是这就带来了整合程序时的麻烦,我们力求在一个程序中尽可能解决多的问题,但由于水平所限,完成的不是很好。
通过这次课程设计,我感到数据结构的算法实现必须要有深厚的变成技术作为基础。
遇到问题时首先应运用数据结构相关知识写出问题算法,然后根据算法写出相应的程序,最后调试。
其中算法时关键,程序编写是重点。
在以后的学习中,我还要加强这两个方面的学习,不断提高运用计算机解决问题的能力。