数据结构课程设计_集合的并、交和差运算
数据结构课程设计
学院:信息科学与工程学院
专业:计算机科学与技术
班级:
学号:
学生姓名:
指导教师:
2009 年12 月25 日
一、实验内容
实验题目:编制一个演示集合的并、交和差运算的程序。
需求分析:
1、本演示程序中,集合的元素限定为小写字母字符[“a”…”z”]。集合输入的形
式为一个以“回车符“为结束标志的字符串,串中字符顺序不限。
2、演示程序以用户和计算机的对话方式执行,即在计算机终端上显示“提示信
息“之后,由用户在键盘上输入演示程序中规定的运算命令;相应的输入数据和运算结果显示在其后。
3、程序执行的命令包括:
1)构造集合1;2)构造在集合2;3)求并集;4)求交集;5)求差集;6)返回;7)结束。“构造集合1”和“构造集合2”时,需以字符的形式键入集合元素。
二、数据结构设计
为了实现上述程序的功能,应以有序链表表示集合。为此,需要两个抽象数据类型:有序表和集合。
1、有序表的抽象数据类型定义为:
readdata(pointer head)
初始条件:head是以head为头节点的空链表。
操作结果:生成以head为头节点的非空链表。
pop(pointer head)
初始条件:head是以head为头节点的非空链表。
操作结果:将以head为头节点的链表中数据逐个输出。
2、集合的抽象数据类型定义为:
and(pointer head1,pointer head2,pointer head3)
初始条件:链表head1、head2、head3已存在
操作结果:生成一个由head1和head2的并集构成的集合head3。
or(pointer head1,pointer head2,pointer head3)
初始条件:链表head1、head2、head3已存在
操作结果:生成一个由head1和head2的交集构成的集合head3。
differ(pointer head1,pointer head2,pointer head3)
初始条件:链表head1、head2、head3已存在
操作结果:生成一个由head1和head2的差集构成的集合head3。
3、本程序抱含四个模块:
1)节点结构单元模块——定义有序表的节点结构;
2)有序表单元模块——实现有序表的抽象数据类型;
3)集合单元模块——实现集合获得抽象数据类型;
4)主程序模块:
Void main(){
初始化;
do{
接受命令;
处理命令;
}while(“命令”!=“退出”);
}
三、算法设计
#include
#include
typedef struct LNode//定义结构体类型指针
{
char data;
struct LNode*next;
}*pointer;
void readdata(pointer head)//定义输入集合函数
{
pointer p;
char tmp;
scanf("%c",&tmp);
while(tmp!='\n')
{
p=(pointer)malloc(sizeof(struct LNode));
p->data=tmp;
p->next=head->next;
head->next=p;
scanf("%c",&tmp);
}
}
void pop(pointer head)//定义输出集合函数
{
pointer p;
p=head->next;
while(p!=NULL)
{
printf("%c",p->data);
p=p->next;
}
printf("\n");
}
void and(pointer head1,pointer head2,pointer head3)//定义集合的并集函数{
pointer p1,p2,p3;
p1=head1->next;
while(p1!=NULL)
{
p3=(pointer)malloc(sizeof(struct LNode));
p3->data=p1->data;
p3->next=head3->next;
head3->next=p3;
p1=p1->next;
}
p2=head2->next;
while(p2!=NULL)
{
p1=head1->next;
while((p1!=NULL)&&(p1->data!=p2->data))
p1=p1->next;
if (p1==NULL)
{
p3=(pointer)malloc(sizeof(struct LNode));
p3->data=p2->data;
p3->next=head3->next;
head3->next=p3;
}
p2=p2->next;
}
}
void or(pointer head1,pointer head2,pointer head3)//定义集合的交集函数{
pointer p1,p2,p3;
p1=head1->next;
while(p1!=NULL)
{
p2=head2->next;
while((p2!=NULL)&&(p2->data!=p1->data))
p2=p2->next;
if((p2!=NULL)&&(p2->data==p1->data))
{
p3=(pointer)malloc(sizeof(struct LNode));
p3->data=p1->data;
p3->next=head3->next;
head3->next=p3;
}
p1=p1->next;
}
}
void differ(pointer head1,pointer head2,pointer head3)//定义集合的差集函数{
pointer p1,p2,p3;
p1=head1->next;
while(p1!=NULL)
{
p2=head2->next;
while((p2!=NULL)&&(p2->data!=p1->data))
p2=p2->next;
if(p2==NULL)
{
p3=(pointer)malloc(sizeof(struct LNode));
p3->data=p1->data;
p3->next=head3->next;
head3->next=p3;
}
p1=p1->next;
}
}
void main()//主函数
{
int x;
printf("(输入数据,按回车键结束,第一个集合大于第二个集合)\n");
pointer head1,head2,head3;
head1=(pointer)malloc(sizeof(struct LNode));
head1->next=NULL;
head2=(pointer)malloc(sizeof(struct LNode));
head2->next=NULL;
head3=(pointer)malloc(sizeof(struct LNode));
head3->next=NULL;
printf("请输入集合1:\n");
readdata(head1);//调用输入集合函数
printf("请输入集合2:\n");
readdata(head2);//调用输入集合函数
A:printf("1.并集 2.交集 3.差集 4.结束x.重新运算\n");
do{
printf("请选择序号\n");
scanf("%d",&x);
switch(x)
{
case 1:
printf("两集合的并是\n");
and(head1,head2,head3);//调用并集函数
pop(head3);
head3->next=NULL;
break;
case 2:
printf("两集合的交是\n");
or(head1,head2,head3);//调用交集函数
pop(head3);
head3->next=NULL;
break;
case 3:
printf("两集合的差是\n");
differ(head1,head2,head3);//调用差集函数
pop(head3);
head3->next=NULL;
break;
case 4:break;
default:goto A;
}
}while(x!=4);
}
四、测试数据及程序运行情况
运行时提示输入:
输入集合1:asd
输入集合2:asf
根据提示输入运算类型:1.并集 2.交集 3.差集 4.结束x.重新运算
输入1,输出”fasd”
输入2,输出”as”
输入3,输出”d”
输入4,输出”press any key to continue”(结束)
输入其他数,输出” 1.并集 2.交集 3.差集 4.结束x.重新运算”(重新选择运
算类型)
下面是运行时的界面(附图):
五、实验过程中出现的问题及解决方法
1、由于对集合的三种运算的算法推敲不足,在链表类型及其尾指针的设置时出现错误,导致程序低效。
2、刚开始时曾忽略了一些变量参数的标识”&”,使调试程序浪费时间不少。今后应重视确定参数的变量和赋值属性的区分和标识。
3、开始时输入集合后,程序只能进行一次运算,后来加入switch语句,成功解决了这一难题。
4、该算法并不能排除重复输入相同字符的情况,也不能自动滤去非法字符(如空格、阿拉伯数字等)。
5、本程序的模块划分比较合理,且尽可能的将指针的操作封装在节点和链表的两个模块中,致使集合模块的调试比较顺利。
6、本实习作业采用数据抽象的程序设计方案,将程序化分为四个层次结构,使得设计时思路清晰,实现时调试顺利,各模块具有较好的可用性,确实得到了一次良好的程序设计训练。