编制一个演示集合的并交和差运算的程序实习报告Word文档格式.docx
《编制一个演示集合的并交和差运算的程序实习报告Word文档格式.docx》由会员分享,可在线阅读,更多相关《编制一个演示集合的并交和差运算的程序实习报告Word文档格式.docx(11页珍藏版)》请在冰豆网上搜索。
DestroyList(&
初始条件:
有序表L已存在。
操作结果:
销毁有序表L。
ListLength(L)
1.有序表的抽象数据类型定义为
返回有序表L的长度。
ListEmpty(L)
若有序表L为空表,则返回True,否则返回False。
GetElem(L,pos)
若1<
=pos<
=Length(L),则返回表中第pos个元素。
LocateElem(L,e,&
q)
若有序表L中存在元素e,则q指示L中第一个值为e的元素的位置,并返回函数值TRUE;
否则q指示第一个大于e的元素的前驱的位置,并返回函数值FALSE。
ListTraverse(q,visit())
有序表L已存在,q指示L中一个元素。
依次对L中q指示的元素开始的每个元素调用函数visit()。
}ADTOrderdeList
2集合的抽象数据表类型定义为:
ADTset{
D={ai|ai为小写英文字母且互不相同,i=1,s,...n,0<
=n<
=26}
CreateSet(&
T,Str)
Str为字符串。
生成一个由Str中小写字母构成的集合T。
DestroySet(&
T)
集合T已存在。
销毁集合T结构。
Union(&
T,S1,S2)
集合S1,S2已存在。
生成一个由S1,S2并集字母构成的集合T。
Intersection(&
T,S1,S2)
生成一个由S1,S2交集字母构成的集合T。
Difference(&
生成一个由S1,S2差集字母构成的集合T。
printSet(T)
按字母次序显示集合T的全部元素。
三、详细设计
1.元素类型
typedefcharElemType;
typedefstructNodeType{ElemTypedata;
NodeType*next;
}NodeType,*LinkType;
statusMakeNode(LinkType&
p,ElemTypee)
{p=(LinkType)malloc(sizeof(NodeType));
if(!
p)returnFALSE;
p->
data=e;
p->
next=NULL;
returnTRUE;
}
voidFreeNode(LinkType&
p)
{}
LinkTypeCopy(LinkTypep)
{
s=(LinkType)malloc(sizeof(NodeType));
if(!
s)returnNULL;
s->
data=p->
data;
s->
returns;
ElemTypeElem(LinkTypep)
LinkTypeSuccNode(LinkTypep)
typedefstruct{LinkTypehead,tail;
intsize;
}OrderedLise;
有序链表的基本操作设置如下:
boolInitList(OrderedLise&
L);
voidDestroyList(OrderedLise&
boolListEmpty(OrderedLiseL);
intListLength(OrderedLiseL);
LinkTypeGetElemPos(OrderedLiseL,intpos);
boolLocateElem(OrderedLiseL,ElemTypee,LinkType&
q);
voidAppend(OrderedLise&
L,LinkTypes);
voidInsertAfter(OrderedLise&
L,LinkTypeq,LinkTypes);
voidListTraverse(LinkTypep,status(*visit)(LinkTypeq));
BOOLInitList(OrderedLise&
{
if(MakeNode(head,'
'
)){L.tail=L.head;
L.size=0;
returnTRUE;
else{L.head=NULL;
returnFALSE;
}//InitList
p=L.head;
while(p){q=p;
p=SuccNode(p);
FreeNode(q);
L.head=L.tail=NULL;
}//DestroyList
LinkTypeGetElemPos(OrderedListL,intpos)
if(!
L.head//pos<
1//pos>
L.size)returnNULL;
elseif(pos==L.size)returnL.tail;
else{
p=L.head->
next;
k=1;
while(p&
&
k<
pos){p=SuccNode(p);
k++;
returnp;
}//GetElemPos
statusLocateElem(OrderedListL,ElemTypee,LinkType&
if(L.head;
p=pre->
//pre指向*p的前驱,p指向第一个元素结点
while(p&
data<
e){pre=p;
p=SucNode(p);
}
if(p&
date==e)returnTRUE;
else{p=pre;
returnFALSE;
elsereturnFALSE;
}//LocateElem
voidAppend(OrderedLisr&
L,LinkTypes)
if(L.head&
s){
if(L.tail!
=L.head)L.tail->
next=s;
elseL.head->
next=s;
L.tail=s;
L.size++;
}//Append
voidInsertAfter(Orderlist&
L,linkTypeq,LinkTypes)
if(L.head&
q&
next=q->
q->
if(L.tail==q)L.tail=s;
L.size++;
}//InserAfter
voidListTraverse(LinkTypep,status(*visit)(LinkType))
while(p){viset(p);
p=SuccNode(p);
}//ListTraverse
3.集合
typedefOrderedListOrderedSet;
集合类型的基本操作的类C伪码描述如下:
voidCreateSet(OrderedSer&
T,char*s)
//生成由串s中小写字母构成的集合T,IsLower是小写字母判别函数
if(InitList(T))//
for(i=1;
i<
=length(s);
i++)
if(islower(s[i])&
!
LocateElem(T,s[i],p))
//
if(MakeNode(q,s[i]))InsertAfter(T,P,q);
}//CreateSet
voidDestroySet(OrderedSer&
DestroyList(T);
voidUnion(OrderedSet&
T,OrderedSetS1,OrderedSetS2)
if(InitList(T)){
p1=GetElemPos(S1,1);
p2=GetElemPos(S2,1);
while(p1&
p2){
c1=Elem(p1);
c2=Elem(p2);
if(c1<
=c2){
Append(T,Copy(p1));
p1=SuccNode(p1);
if(c1==c2)p2=SuccNode(p2);
else{Append(T,Copy(p2));
p2=SuccNode(p2);
while(p1)
{Append(T,Copy(p1));
while
(2)
{Append(T,Copy(p2));
voidIntersection(OrderedSet&
InitList(T))T.head=NULL;
else{
p2=GetElemPos(S2,1);
c2=Elem(p2);
c2)p1=SuccNode(p1);
elseif(c1>
c2)p2=SuccNode(p2);
voidDifference(OrderedSet&
c2){Append(T,Copy(p1));
p1=SuccNode(p1);
c2)p2=SuccNode(p2);
else{p1=SuccNode(p1);
p2=SuccNode(p2);
voidWriteSetElem(linkTypep)
printf('
'
);
WriteElem(Elem(p));
voidprintSet(OrderedSetT)
p=GetElempos(t,1);
['
if(p){WriteElem(Elem(p));
ListTraverse(p,WriteSetElem);
]'
4.主函数和其他函数的伪码算法
voidmain()
Initilization();
do{
ReadCommand(cmd);
Interpret(cmd);
}while(cmd!
='
q'
cmd!
Q'
voidInitialization()
clrser();
在屏幕上方显示操作命令清单:
MakeSet1--1MakeSet2--2Union--uIntersaction--iDifference--dQuit--q;
在屏幕下方显示操作命令提示框;
CreateSet(Set1,"
"
PrintSet(Set1);
CreateSet(Set2,"
voidReadCommand(charcmd)
显示键入操作命令符的提示信息;
do{cmd=getche();
while(cmd@['
1'
2'
U'
i'
I'
d'
D'
]));
voidInterpret(charcmd)
switch(cmd){
case'
:
显示以串的形式键入集合元素的提示信息;
scanf(v);
CreatSet(Set1,v);
PrintSet(set1);
break;
CreatSet(Set2,v);
PrintSet(set2);
u'
Union(Set3,Set1,Set2);
printSet(Set3);
DestroyList(Set3);
Intersaction(Set3,Set1,Set2);
Set3
Difference(Set3,Set1,Set2);
}//Interpret
四、调试分析
1.由于对集合的三种运算推敲不足,在有序链表类型的早期版本未设置尾指针和Append操作,导致算法低效。
2.刚开始是曾忽略了一些变量参数的标识“&
”,是调试程序时费时不少。
今后应重视确定参数的变量和赋值属性的区别和标识。
3.本程序的模板划分比较合理,且尽可能将指针的操作装在结点和链表的两个模块中,致使集合模块的调试比较顺利。
反之,如此划分的模块并非完全集合,因为在实现集合操作的编码中仍然需要判别指针是否为空。
按理,两个链表的并、交和差的操作也应封装在链表的模块中,而在集合的模块中,只要进行相应的应用即可。
4.算法的时空分析
1)由于有序表采用带头结点的有序单链表,并增设尾指针和表的长度两个标识,各种操作的算法时间复杂度比较合理。
InitList,ListEmpty,Listlength,Append和InsertAfter以及确定链表中第一个结点和之后一个结点的位置都是O
(1)的,DestroyList,LocateElem和TraverseList几确定链表中间结点的位置等则是O(n)的,n为链表长度。
2)基于有序链表实现的有序集的各种运算和操作的时间复杂度分析如下:
构造有序集算法CreateSet读入n个元素,逐个用LocateElem判定不在当前集合中及确定插入位置后,才用InsertAfter插入到有序集合中,所以时间复杂度是O(n2)。
求并集算法Union利用集合的“有序性”将两个集合的m+n个元素不重复地依次利用APPend插入到当前并集的末尾,故可在O(m+n)时间完成。
可对求交集算法Intersection和求差集算法Difference作类似地分析,它们也是O(m+n)。
销毁集合算法DestorySet和显示集合算法PruntSet都是对每个元素调用一个O
(1)的函数,因此都是O(n)的。
除了构造有序集算法CreateSet用一个串变量读入个元素,需要O(n)的辅助空间外,其余算法使用的辅助空间与元素个数无关,即是O
(1)的。
5.本实习作业采用数据抽象的程序设计方法,将程序划分为四个层次结果:
元素结点,有序链表、有序集和主控模块,使得设计时思路清晰,实现时调试顺利,各模块具有较好的可重用性,确实得到了一次良好的程序设计训练。
六、测试结果
执行命令‘1’:
键入magazine后,构造集合Set1:
[a,e,g,I,m,n,z]
执行命令‘2’:
键入paper后,构造集合Set2:
[a,p,e,r]
执行命令‘u’:
构建集合Set1和Set2的并集:
[a,e,g,i,m,n,p,r,z]
执行命令‘i’:
构建集合Set1和Set2的交集:
[a,e]
执行命令‘d’:
构建集合Set1和Set2的差集:
[g,I,m,n,z]
键入012oper4a6tion89后,构造集合Set1:
[a,e,I,n,o,p,r,t]
键入errordata后,构造集合Set2:
[a,d,e,o,r,t]
[a,d,e,i,n,o,p,r,t]
[a,e,o,r,t]
[i,n,p]