一、实验概述
实验题目:求集合的并、交、差运算。
实验目的:掌握单链表的应用。
实验内容:编写一个程序,采用单链表表示集合,利用单链表操作,完成集合的并、交、差运算。
实验要求:1.用C或C++实现运算。
2.Sort(slink *L)函数对链表中L所有数据节点按值域递增排序。
3.Union(slink *la,slink *lb, slink *lc)函数求两个集合的并集。
4.InerSect (slink *la,slink *lb, slink *lc)函数求集合的交集。
5.Subs(slink *la,slink *lb, slink *lc)函数求集合的差集。
二、代码结构
set.h
声明链表结构体,以及与集合操作相关的函数。
function.cpp
实现对集合操作相关的函数。包括集合的创建、判断、打印、删除等。
三、函数讲解
void InitializeList(slink *&plist);
初始化链表的函数,创建表头。
void InitializeList(slink *&plist){
plist = (slink*)malloc(sizeof(slink));
if(plist == NULL){
printf("fail to init list");
exit(1);
}
plist->next = NULL;
}
bool ListisEmpty(slink *plist);
检查链表(集合)是否为空的函数。因为会有空集的情况出现,所以要进行判断。
bool ListisEmpty(slink *plist){
if(plist == NULL)
return true;
else
return false;
}
void CreateSet(slink *&L);
创建一个集合。通过键盘进行集合中元素的输入,当输入值为回车的时候停止。
void CreateSet(slink *&L){
slink *p;
p = L ;//找到头节点
int element;
printf("please input several integer elements:");
scanf("%d",&element);
while(getchar()!='\n') {
p = p->next = (slink*)malloc(sizeof(slink));
p->element = element;
scanf("%d",&element);
}
p = p->next = (slink*)malloc(sizeof(Setnode));
p->element = element;//再执行一次,不然会少最后一个元素
p->next=NULL;
}
void PrintSet(slink *L);
打印集合,利用while循环和链表的特性,进行遍历。
void PrintSet(slink *L){
slink* p=L->next;
while(p!=NULL){
printf("%d ", p->element);
p = p -> next;
}
}
void Sort(slink *L);
对链表L所有数据节点按值域递增排序。
p1,p2,相当于指向同一集合的指针,在保证集合中元素不变的情况下对元素
的值进行比较。因为实验对于时间复杂度没有要求,我的方法就简单粗暴。相当
于是利用嵌套的while循环做了冒泡排序,注意重置p2指针的位置,保证下一次
循环从第一个元素开始比较。如果想缩短时间的话,可以在结构体中加一个int型
的变量,记录第一层while循环的次数,也就是p2重置的位置。同时在if执行的
块里添加一个记录变量,如果输入的集合本身有序,那么直接跳出循环。
void Sort(slink *L){
slink *p1,*p2;
p2 = p1 = L->next;
int temp;
//增值排序
while(p1!=NULL){
while(p2!=NULL){
if(p1->element>p2->element){
temp = p2->element;
p2->element = p1->element;
p1->element = temp;
}
p2 = p2->next;
}
p1 = p1->next;
p2 = p1;//重置p2指针位置
}
}
void Union(slink *la,slink *lb,slink *lc);
求两个有序集合的并集。
la是指向集合A的指针,lb是指向集合B的指针,lc为所求集合(此处为并
集)指针。
void Union(slink *la,slink *lb,slink *lc){
slink *pa,*pb,*pc;
pc = lc,pa = la->next,pb = lb->next;
//先把集合A、B中的元素全部赋给集合C,再利用去重函数删去重复元素
while(pa!=NULL){
pc = pc->next = (slink*)malloc(sizeof(Setnode));
pc->element = pa->element;
pa = pa->next;
}
while(pb!=NULL){
pc = pc->next = (slink*)malloc(sizeof(Setnode));
pc->element = pb->element;
pb = pb->next;
}
Sort(lc);
RemoveElement(lc);
pc->next = NULL;
}
void InerSect(slink *la,slink *lb,slink *lc);
求两个有序集合的交集。
遍历并比较A、B两个中相同的元素,若相同,就加入C集合。
void InerSect(slink *la,slink *lb,slink *lc){
slink *pa,*pb,*pc;
pc = lc,pa = la->next,pb = lb->next;
while(pa!=NULL){
while(pb!=NULL){
//寻找同时属于集合A、B的元素
if(pa->element==pb->element){
pc = pc->next = (slink*)malloc(sizeof(Setnode));
pc->element = pa->element;
}
pb = pb->next;
}
pa = pa->next;
pb = lb->next;//重新定位
}
pc->next = NULL;
}
void Subs(slink *la,slink *lb,slink *le);
求两个有序集合的差集。
遍历并比较A、B两个集合中的元素,若相同,则替换,并继续向下遍历。
将符合条件的元素加入集合C。此处我选择将相同元素替换为-10000,在之后
遍历遇到这个元素便跳过。
void Subs(slink *la,slink *lb,slink *lc){
slink *pa,*pb,*pc;
pa = la->next, pb = lb->next, pc = lc;
while(pa!=NULL){
while(pb!=NULL){
if(pa->element == pb->element){
pa->element = -10000;
}
pb = pb->next;
}
pa = pa->next;
pb = lb->next;//重新定位
}
pa = la->next;
while(pa!=NULL){
if(pa->element==-10000){
pa = pa->next;
}
else{
pc = pc->next = (slink*)malloc(sizeof(Setnode));
pc->element = pa->element;
pa = pa->next;
}
}
pc->next = NULL;
}
void RemoveElement(slink *L);
删除重复元素。
根据集合的定义,一个集合中不能存在相同的元素,因此在链表添加完元素
后要检查并去重。
此处,寻找重复元素的思路和上述求差集的函数一致,如果有重复的,就
跳过,并改变链表连接的节点。
void RemoveElement(slink *L){
slink *p,*p1,*p2;
p = L->next;
while(p!=NULL){
p2 = p->next;
while(p2!=NULL){
if(p2->element == p->element){
p2->element = -10000;//找到重复元素,替换为-10000;改进:可以新建一个链表来进行替换,这样就可以不改变原集合的元素
}
p2 = p2->next;
}
p = p->next;
}
p = L->next;
p1 = L;
while(p!=NULL){
if(p->element==-10000){
p = p->next;
}
else{
p1 = p1->next = (slink*)malloc(sizeof(Setnode));
p1->element = p->element;
p = p->next;
}
}
L = p1;//将去过重的集合赋给该链表
L->next = NULL;//尾节点
}
四、结果演示
空集的判断还没有加上,需要的朋友们可以自己动脑筋想一下。