集合的交、并和差运算
数据结构课程设计任务书 |
学生姓名: 专业班级: 软件工程 指导教师: 工作单位: |
题 目: 集合的并、交和差运算 基础要求:
3、提高综合运用所学的理论知识和方法独立分析和解决问题的能力。 主要任务: (包括课程设计工作量及其技术要求,以及说明书撰写等具体要求) (1)任务内容 编制一个能演示执行集合的并、交和差运算的程序。 (2)完成要求 对系统进行功能模块分析、控制模块分析;系统设计要能完成题目所要求的功能;编程简练,可用,尽可能的使系统的功能更加完善和全面;说明书、流程图要清楚;提高学生的论文写作能力;特别要求自己独立完成;在基本要求达到后,可进行创新设计,如改善算法性能、友好的人机界面。 (3)撰写课程设计报告 报告格式按附件要求打印与写课程设计报告;论文包括目录、正文、小结、参考文献、附录等;课程设计论文装订按学校的统一要求完成。 |
时间安排: 内容 天数 地点 构思及收集资料 1 图书馆 编码与调试 3 图书馆 撰写论文 1 图书馆 |
指导教师签名: 年 月 日 |
完整资料一键获取私信我:
- 问题分析和任务定义
1.1 问题的描述
编制一个能演示执行集合的并、交和差运算的程序。
1.2 基本要求
(1) 集合的元素限定为小写字母字符 [‘a’..’z’] ,集合输入的形式为
一个以“回车符“为结束标志的字符串,串中字符顺序不限。
(2) 演示程序以用户和计算机的对话方式执行,即在计算机终端上显示“提
示信息“之后,由用户在键盘上输入演示程序中规定的运算命令﹔相应的输入数
据和运算结果显示在其后。
1.3 程序执行的命令包括:
(1)构造集合1;
(2)构造集合2;
(3)求并集;
(4)求交集;
(5)求差集;
1.4 测试数据
(1)Set1="magazine",Set2="paper",
Set1∪Set2="aegimnprz",Setl ∩Set2="ae",Set1-Set2="gimnz"。
(2)Set1= " 012oper4a6tion89",Set2="error data",
Set1∪Set2="adeinoprt",Setl ∩Set2="aeort",Set1-Set2="inp"。
1.5 实现提示
以有序链表表示集合。
- 数据结构的选择和概要设计
为实现上述程序功能,应该以有序链表表示集合,因此需要两个抽象数据类型:有序表和集合。
2.1 有序表的抽象数据类型定义为:
ADT OrderedList
{
数据对象:D={ai|ai CharSet,i=1,2,3,...n}
数据关系:R1={<ai-1,ai>|ai-1,ai D,ai-1<ai,i=1,2,...n}
基本操作:
InitList(&L)
操作结果:构造一个空的有序表L。
DestroyList(&L)
初始条件:有序表L已经存在。
操作结果:销毁有序表L。
Length(L)
初始条件:有序表L已经存在。
操作结果:返回有序表L的长度。
ListEmpty(L)
初始条件:有序表L已经存在。
操作结果:若有序表L为空表,返回True,否则返回False。
GetElem(L,pos)
初始条件:有序表L已经存在。
操作结果:若pos Length(L),则返回表中第pos哥数据元素。
LocateElem(L,e,&q)
初始条件:有序表L已经存在。
操作结果:若有序表L存在元素e,则q指示L中第一个值为e的元素的位置,并返回函数值TRUE,否则q指示第一个大于e的元素的前驱的位置,并返回函数值FALSE。
Append(&L,e)
初始条件:有序表L已经存在。
操作结果:在有序表L的末尾插入元素e
InsertAfter(&L,q,e)
初始条件:有序表L已经存在,q指示L中一个元素。
操作结果:在有序表L中q指示的元素之后插入元素e。
bianli(q,visit())
初始条件:有序表L已经存在,q指示L中第一个元素。
操作结果:依次对L中q指示的元素开始的每个元素调用函数visit()。
}ADT OrderList
2.2 集合的抽象数据类型为:
ADT Set
{
数据对象:D={ai|ai为小写字母且互不相同,i,2,...n}
数据关系:R1={}
基本操作:
Createset(&T,Str)
初始条件:Str为字符串
操作结果:生成一个由Str中小写字母构成的集合T。
Destoryset(&T)
初始条件:集合T已经存在。
操作结果:销毁集合T的结构。
UnionSet(&T,S1,S2)
初始条件:集合S1和S2都存在。
操作结果:生成一个由S1和S2的差集构成的集合T。
Printset(T)
初始条件:集合T已经存在。
操作结果:按字母次序顺序显示集合T的全部元素。
}AND Set
2.3 程序组成
本程序包含四个模块:
- 结点结构单元模块——定义有序表的结点结构;
(2)有序表单元模块——实现有序表的抽象数据类型;
(3)集合单元模块——实现集合获得抽象数据类型;
(4)主程序模块
(5)int main(){
初始化;
构造集合 1;
构造集合 2;
if(接收命令){
处理命令
}退出
2.4 模块流程图
图2.1 系统模块流程图
图2.2 函数调用流程图
图2.3 主菜单流程图
图2.4 用户操作流程图
2.5 结构体设计
typedef struct SET{
char *elem;
int size;
int length;
}set;
- 详细设计和编码
3.1 源代码
#include<iostream>
using namespace std;
#define OK 1
#define ERROR 0
typedef int Status;
typedef char ElemType;
//定义线性链表
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
//初始化操作
Status InitList(LinkList &L)
{
//构造一个空的单链表L
L=new LNode;
L->next=NULL;
return OK;
}
//存储输入的字符串
Status cun_chu(ElemType *ch,int &length)
{
length=0;
ch[length]=getchar();
length=1;
ch[1000];
while(true)
{
ch[length++]=getchar();
if(ch[length -1 ]=='\n')
{
break;
}
}
return OK;
}
//存储集合
Status Creat(LinkList &L)
{
//初始化链表
InitList(L);
L = new LNode;
L->next=NULL;
LinkList r = L;
int length;
ElemType ch[1000];
cun_chu(ch,length);
for(int i=0;i<length;i++)
{
if(ch[i]<97 || ch[i]>122)
{
continue;
}
LinkList p = new LNode;
p->data = ch[i];
r->next = p;
r=p;
}
r->next = NULL;
return OK;
}
//返回一个集合的长度
Status Length(LinkList L)
{
int i=0;
while(L->next != NULL) //下一个结点不为空
{
i++;
L=L->next;
}
return i;
}
//对一个字母集合进行从小到大的排序
Status Sort(LinkList &L)
{
LinkList p,q,n;
int l=Length(L);
if(l<2) //集合中只有一个元素
{
return OK;
}
int flag=1; //控制集合是否需要重新遍历
for(int i=l-1;i>0&&flag==1;i--)
{
flag=0;
p=L;
q=p->next; //若从头结点开始,指向第一个有data值的结点
n=q->next; //指向与其相邻的下一个结点
for(int j=0;j<i;j++)
{
if(q->data > n->data) //遍历集合,只要存在前一个结点的data值大于后一个就交换两个节点的位置,并使flag的值为1
{
flag=1;
p->next=n;
q->next=n->next;
n->next=q;
q=p->next;
n=q->next;
}
p=q;
q=n;
n=n->next;
}
}
return OK;
}
//输出集合
Status bianli(LinkList L)
{
if(L->next == NULL)
{
cout << "NULL";
}
else
{
LinkList p=L->next;
while(p!=NULL)
{
cout<<p->data;
p=p->next;
}
}
cout<<endl;
return OK;
}
//创建并排序集合
Status CreatSet(LinkList &L)
{
Creat(L); //存储集合
Sort(L); //将集合中的元素从小到大排序
return OK;
}
//集合的并运算
Status UnionSet(LinkList A,LinkList B,LinkList &C)
{
InitList(C); //初始化集合C
LinkList i = A->next; //指向集合A的第一个元素
LinkList j = B->next; //指向集合B的第一个元素
LinkList k = C;
while(i!=NULL && j!=NULL) //两个集合都没有遍历完
{
if(i->data < j->data) //集合A的元素小于B
{
if(k->data != i->data) //集合A的该元素与并集中的上一个存入的元素不同,执行存入
{
k->next=i;
k=i;
}
i=i->next;
}
else if(i->data > j->data) //集合A的元素大于B
{
if(k->data != j->data) //集合A的该元素与并集中的上一个存入的元素不同,执行存入
{
k->next=i;
k=j;
}
j=j->next;
}
else //集合A的元素等于B
{
if(k->data != j->data) //集合A的该元素与并集中的上一个存入的元素不同,执行存入
{
k->next=j;
k=j;
}
i=i->next;
j=j->next;
}
}
if(j!=NULL) //集合A已经遍历结束,集合B没有,将集合B中剩下所有元素插入,并且是不重复插入
{
int m;
if(k->data != j->data) //确保并集中不插入重复元素
{
k->next=j;
m=1;
}
j=j->next;
if(j!=NULL && m==1)
{
k=k->next;
m=0;
}
}
if(i!=NULL) //集合B已经遍历结束,集合A没有,将集合A中剩下所有元素插入,并且是不重复插入
{
int n;
if(k->data != i->data) //确保并集中不插入重复元素
{
k->next=i;
n=1;
}
i=i->next;
if(i!=NULL)
{
k=k->next;
n=0;
}
}
if(k->next != NULL)
{
k=k->next;
}
k->next = NULL;
return OK;
}
//集合的交运算
Status InterSet(LinkList A, LinkList B, LinkList C)
{
InitList(C);
LinkList i = A->next; //指向集合A的第一个元素
LinkList j = B->next; //指向集合B的第一个元素
LinkList k = C;
while(i != NULL && j!=NULL)
{
if(i->data < j->data)
{
i=i->next;
}
else if(i->data > j->data)
{
j=j->next;
}
else
{
if(k->data != i->data)
{
k->next = i;
k=i;
}
i=i->next;
j=j->next;
}
}
k->next = NULL;
return OK;
}
//集合的差运算
Status DifferentSet(LinkList A,LinkList B,LinkList C)
{
InitList(C);
LinkList i = A->next; //指向集合A的第一个元素
LinkList j = B->next; //指向集合B的第一个元素
LinkList k = C;
while(i != NULL && j!=NULL) //如果集合A的元素比B的小,说明该元素之后也不会出现在B集合
{
if(i->data < j->data)
{
if(k->data != i->data)
{
k->next=i;
k=i;
}
i=i->next;
}
else if(i->data > j->data)
{
j=j->next;
}
else //避免集合中重复元素的影响
{
int n=0;
j=j->next;
if(i->next ==NULL)
{
i=i->next;
}
while(i!=NULL && i->next != NULL)
{
if(i->data == i->next->data)
{
i=i->next->next;
n=1;
}
else
{
if(n==0)
{
i=i->next;
}
break;
}
}
}
}
if(i)
{
k->next = i; //如果A有剩余,直接加进去
}
else k->next =NULL;
return OK;
}
//菜单界面
Status showMenu()
{
cout<<"***********"<<endl;
cout<<"***1、集合的并运算***"<<endl;
cout<<"***2、集合的交运算***"<<endl;
cout<<"***3、集合的差运算***"<<endl;
cout<<"***0、退出***"<<endl;
cout<<"***********"<<endl;
return OK;
}
//主函数
Status main()
{
showMenu();
while(1)
{
int select;
cout<<"请输入要执行的指令数字:"<<endl;
cin>>select;
switch(select)
{
case 1: //集合的并集
cout<<"**集合的并运算**"<<endl;
LinkList A;
cout<<"请输入集合A:"<<endl;
CreatSet(A);
//bianli(A);
LinkList B;
cout<<"请输入集合B:"<<endl;
CreatSet(B);
//bianli(B);
LinkList C;
UnionSet(A,B,C);
cout<<"集合的并运算结果为:"<<endl;
bianli(C);
break;
case 2: //集合的交集
cout<<"**集合的交运算**"<<endl;
LinkList D;
cout<<"请输入集合A:"<<endl;
CreatSet(D);
//bianli(D);
LinkList E;
cout<<"请输入集合B:"<<endl;
CreatSet(E);
//bianli(E);
LinkList F;
InterSet(D,E,F);
cout<<"集合的交运算结果为:"<<endl;
bianli(F);
break;
case 3: //集合的差集
cout<<"**集合的差运算**"<<endl;
LinkList G;
cout<<"请输入集合A:"<<endl;
CreatSet(G);
//bianli(G);
LinkList H;
cout<<"请输入集合B:"<<endl;
CreatSet(H);
//bianli(H);
LinkList I;
DifferentSet(G,H,I);
cout<<"集合的差运算结果为:"<<endl;
bianli(I);
break;
break;
case 0: //退出
cout<<"欢迎下次使用"<<endl;
system("pause");
return OK;
break;
default:
break;
}
}
system("pause");
return OK;
}
- 上机调试过程
4.1 调试示例
集合 1={magazine}
集合 2={paper}
4.2 调试结果
图片3.1 程序运行结果图
4.3 调试分析
(1)由于对集合的三种运算的算法推敲不足,在有序链表类型的早期版本未设置尾指针,导致算法低效。
(2)刚开始时忽略了一些变量参数的标识”&”,使调试程序时费时不少。今后应重视确定参数的变量和赋值属性的区分和标识。
- 用户使用说明
程序运行后会显示菜单,用户可以根据菜单号输入相对应的数字,(如果用户输入1,程序将对两个集合进行并集运算并输出相应结果,用户输入2,程序将对两个集合进行交集运算对输出需要结果,用户输入3,程序将对两个集合进行差集运算并输出相应的结果,用户输入0,则程序运行结束,退出系统。)待用户输入相应的菜单号后,程序会提示用户输入集合A和集合B,用户输入完成后按下回车键,程序就会将两个集合的运算结果输出在屏幕上。只要用户不输入0,便可以一直进行运算,且每次可以输入不同的集合。
参考文献
[1]严蔚敏.吴伟民.数据结构 C 语言版.北京.清华大学出版社,2018.6.
[2]数据结构课程设计.https://www.docin.com/p-235288754.html
[3]数据结构课程设计——集合的并,交和差的运算.
[4]谭浩强.C语言程序设计.清华大学出版社
[5]严蔚敏.数据结构(C语言版).清华大学出版社,1999.
[6]严蔚敏.吴伟民.数据结构题集(C语言版).清华大学出版社,2003.5.
[7]李春葆.数据结构教程.清华大学出版社,2005.1.
[8]Jan Harrington(著).陈博(译).面向对象C++数据结构.科学出版社,2005.2.
[9]史蒂芬·普拉达.C Primer Plus 第6版 中文版【M】.人民邮电出版社,2019
[10]史蒂芬·普拉达.C++ Primer Plus中文版【M】.人民邮电出版社,2019
[11]数据结构课程设计-集合的并交和差运算(23页)-原创力文档