数据结构课程设计学院:信息科学与工程学院专业:计算机科学与技术班级:学号:学生姓名:指导教师: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<stdio.h>#include<stdlib.h>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、本实习作业采用数据抽象的程序设计方案,将程序化分为四个层次结构,使得设计时思路清晰,实现时调试顺利,各模块具有较好的可用性,确实得到了一次良好的程序设计训练。