一、实验要求
a)从程序完善性上考虑,集合元素输入时,要有检查元素重复的功能,每个集合中不允许有重复的元素。集合可以用数组存储,也可以用链表存储。
b)实现交、并、差运算时,分别把代码写成函数的形式,即实现交运算的函数,实现并运算的函数,实现差运算的函数,在主函数中分别调用三个函数。
c)使用菜单形式对应各个操作,应允许用户反复查看结果,想结束程序时,输入负数结束,使其编成一个完整的小软件。菜单参考示例如下:
1---输入集合A和B
2---求集合A交B
3---求集合A并B
4---求集合A-B
退出,输入一个负数!
二、设计思想
1.实验要求写为菜单形式,用Switch分支语句最方便,并且应用while循环语句使用户得以重复使用功能。先把菜单和Switch的框架写出来,然后再填充各个函数实现功能。在用户选择2,3,4操作时,应先判断此时是否存在集合A,B。
2.对于查重,应在每次输入数据后,用该数据与已输入数据进行比对,若有重复的则使其重新输入,所以此处应用循环语句,设一标记flag,当输入符合条件的数据时跳出循环。对于查重函数,参数为链表头指针和输入的数据,先检查头指针是否为NULL,若是表明链表无数据,不需要比较,否则依次比较。当输入的数据已存在时,为了使数据可以继续输入(我设置当输入 -1 时停止输入,以防用户一次输入所有数据(例1 2 1 3 4 5 -1)造成输入停止),应清空重复数据之后的缓冲区,使用户得以继续输入。
3.求并集,为保留原数据,创建新的链表复制集合A,拿集合B的一个元素依次与新链表的全部元素比较,若没有相同的数据则在新链表之后添加该数据,直至集合B的最后一个元素比较完毕。
4.求交集,创建新链表,拿集合B的一个元素依次与集合A的元素比较,若有相同的元素,则把这个元素复制到新链表末尾。
5.求差,创建新链表,A-B时,拿集合A的一个元素依次与集合B的元素比较,若无相同的元素,把其复制到新链表末尾。B-A同理。
三、代码
1.主函数、菜单和判断集合是否存在的函数
struct Link
{
int date;
struct Link* next;
};
typedef struct Link link;
void menu()
{
cout << "*******************************" << endl;
cout << "* 请选择: *" << endl;
cout << "* 1.输入集合A和B *" << endl;
cout << "* 2.求集合A并B *" << endl;
cout << "* 3.求集合A交B *" << endl;
cout << "* 4.求集合 A-B 和 B-A *" << endl;
cout << "* 输入任意负数退出 *" << endl;
cout << "*******************************" << endl;
}
//判断集合AB是否存在
bool judge(link* head1, link* head2)
{
if (head1 != NULL && head2 != NULL)
return true;
else
{
cout << "请先输入集合A B(完成操作1)" << endl;
return false;
}
}
int main()
{
link* head1 = NULL,* head2 = NULL;
int n = 0;
while (n >= 0)
{
menu();
cin >> n;
switch (n)
{
case 1:
cout << "请输入集合A(当输入-1时结束):" << endl;
head1 = create();
cout << "请输入集合B(当输入-1时结束):" << endl;
head2 = create();
cout << "集合A: ";
output(head1);
cout << "集合B: ";
output(head2);
break;
case 2:
if (judge(head1, head2))
bing(head1, head2);
break;
case 3:
if (judge(head1, head2))
jiao(head1, head2);
break;
case 4:
if (judge(head1, head2))
{
cout << "集合A-B: ";
cha(head1, head2);
cout << endl;
cout << "集合B-A:";
cha(head2, head1);
}
break;
}
if (n > 4)
cout << "请输入合适的代号" << endl;
}
return 0;
}
2.创建集合A、B,查重
我设置当输入 -1 时停止输入,以防用户一次输入所有数据(例1 2 1 3 4 5 -1)造成输入停止,应清空重复数据之后的缓冲区,使用户得以继续输入。
bool check(link* head, int n) //查重
{
link* pre = head;
int ch = 0;
if (pre->next == NULL)//空链表不用比较
return false;
while (pre->next != NULL)
{
pre = pre->next;
//拿新输入的数和之前输入进来的数比较,若重复则置为true,再次进入循环重新输入
if (pre->date == n)
{
cout << "元素" << n << "与已输入元素重复,无效输入,请重新输入后续元素" << endl;
while (getchar() != '\n')
{//清空缓存区,当输入重复时不因为-1而结束该集合的输入,可以继续输入新的元素
}
return true;
}
}
return false;
}
//创建链表(当输入-1时结束)
link* create()
{
link* head, * pre, * p;
head = pre = (link*)malloc(sizeof(Link));
head->next = NULL;
while (1)
{
bool flag = true;
int n = 0;
p = (link*)malloc(sizeof(Link));
while (flag)
{
cin >> n;
flag = check(head, n);//先比较,输入不重复置false出循环
if (n == -1)
break;
}
if (n == -1)
break;
p->date = n;
p->next = NULL;
pre->next = p;
pre = p;
}
return head;
}
//输出链表
void output(link* head)
{
link* pre;
pre = head->next;
cout << "{ ";
while (pre->next != NULL)
{
cout << pre->date << ",";
pre = pre->next;
}
cout << pre->date << " }";
cout << endl;
cout << endl;
}
3.集合并集
void bing(link* head1, link* head2)
{
link* pre1, * pre2, * head, * pre, * p;
pre1 = head1->next;
pre2 = head2->next;
head = (link*)malloc(sizeof(Link));
pre = head;
head->next = NULL;
while (pre1 != NULL) //保留原数据,新建集合C复制集合A
{
p = (link*)malloc(sizeof(Link));
p->date = pre1->date;
pre->next = p;
pre = p;
p->next = NULL;
pre1 = pre1->next;
}
while (pre2 != NULL)//拿集合B里的一个数和新集合的每一个数进行比较
{
int flag = 1;
pre = head->next;//保证每次从头开始比较
while (pre->next != NULL)//若此处为pre->next!=NULL则出循环时pre为空,无法在末尾拼接数据。
{
if (pre2->date == pre->date)//相等时,集合B元素不符合条件
{
flag = 0; //flag置0,不让该元素进入新集合
break; //跳出这次循环,从集合B的下一个元素重新开始
}
pre = pre->next;
}
if (pre2->date == pre->date) //此时pre在末尾,刚好可以进行拼接
{
flag = 0;
}
if (flag == 1)
{
p = (link*)malloc(sizeof(Link));
pre->next = p;
p->date = pre2->date;
p->next = NULL;
}
pre2 = pre2->next;
}
cout << "集合A并B为: ";
output(head);
}
4、集合交集
void jiao(link* head1, link* head2)
{
link* head, * pre, * pre1, * pre2, * p;
pre1 = head1->next;
head = pre = (link*)malloc(sizeof(Link));
head->next = NULL;//创新新链表保存交集元素
//拿集合A的一个数和集合B的每个数比较
while (pre1 != NULL)
{
pre2 = head2->next;
while (pre2 != NULL)
{
if (pre1->date == pre2->date) //相等时符合条件,直接添加到新链表里
{
p = (link*)malloc(sizeof(Link));
p->date = pre1->date;
p->next = NULL;
pre->next = p;
pre = p;
break;
}
pre2 = pre2->next;
}
pre1 = pre1->next;
}
cout << "集合A交B为: ";
output(head);
}
5、集合差集
A-B是在集合A而不在B中的元素,拿集合A的一个元素和集合B的每个元素比较,一旦相等就不符合条件。B-A同理。
void cha(link* head1, link* head2)
{
link* head, * pre, * pre1, * pre2, * p;
pre1 = head1->next;
head = pre = (link*)malloc(sizeof(Link));//新建链表保存差集元素
head->next = NULL;
//A-B是在集合A而不在B中的元素,拿集合A的一个元素和集合B的每个元素比较,一旦相等就不符合条件
while (pre1 != NULL)
{
bool flag = true;
pre2 = head2->next;
while (pre2 != NULL)
{
if (pre1->date == pre2->date)
{
flag = false; //相等不符合条件,置false不让其进入新链表
break;
}
pre2 = pre2->next;
}
if (flag)
{
p = (link*)malloc(sizeof(Link));
p->date = pre1->date;
p->next = NULL;
pre->next = p;
pre = p;
}
pre1 = pre1->next;
}
output(head);
}
练习才是王道!
与君共勉。