顺序表结构编程实现两集合交并补
#include <iostream>
#include<stdio.h>
#include <stdlib.h>
using namespace std;
#define OK 1
#define ERROR 0
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
#define OVERFLOW -2
typedef struct
{
int *elem; //定义一个指针表示存储空间基址
int length; //当前表长(特指元素个数)
int listsize;
} SqList;
//初始化
int InitList_Sq(SqList &L)
{
L.elem=(int *)malloc(LIST_INIT_SIZE*sizeof(int));//动态分配内存
if(!L.elem)
exit(OVERFLOW);
L.length=0;
L.listsize=LIST_INIT_SIZE;
return OK;
}
//给顺序表赋值
void fuzhi(SqList &L)
{
int n,m;
cout<<"请输入集合的数据元素个数"<<endl;
cin>>n;
for(int i=0; i<n; i++)
{
cout<<"请输入第"<<i+1<<"的数据元素的值"<<endl;
cin>>m;
L.elem[i]=m;
L.length++;
}
cout<<"赋值成功"<<endl;
}
void Get(SqList L)
//输出当前列表
{
//cout<<"当前列表:"<<endl;
for(int i=0; i<L.length; i++)
{
cout<<L.elem[i]<<" ";
}
cout<<endl;
}
int GetElem(SqList L,int i,int &e)
//用e返回L中第i个元素的值
{
if(i<1||i>L.length)
return ERROR;
e=L.elem[i-1];
return OK;
}
int equal_e(int a,int b)
{
if(a==b)
return OK;
else
return ERROR;
}
int LocateElem(SqList L,int e,int (*compare)(int,int))
//在表中查找第一个值与e满足compare()元素的位序
{
int i=1;
int *p=L.elem;
while(i<=L.length&&!(*compare)(*p++,e))
++i;
if(i<=L.length)
return i;
else
return 0;
}
//在顺序表指定位置插入元素
int ListInsert_Sq(SqList &L,int i,int e)
{
if(i<1||i>L.length+1)
return ERROR;
if(L.length>=L.listsize)
{
int *newbase;
newbase=(int*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(int));//扩充内存
if(!newbase)
exit(OVERFLOW);
L.elem=newbase;
L.listsize+=LISTINCREMENT;
}
int *p,*q;
q=&(L.elem[i-1]);
for(p=&(L.elem[L.length-1]); p>=q; p--)
*(p+1)=*p;
*q=e;
++L.length;
return OK;
}
void union_set(SqList La,SqList Lb,SqList &Lc)
//a与b的并集放入c中
{
int La_len=La.length;
int Lb_len=Lb.length;
int e;
for(int i=1; i<=Lb_len; i++)
{
GetElem(Lb,i,e);
if(!LocateElem(La,e,equal_e))
ListInsert_Sq(La,++La_len,e);
}
for(int i=1; i<=La_len; i++)
{
GetElem(La,i,e);
ListInsert_Sq(Lc,i,e);
}
}
int mixture(SqList La,SqList Lb,SqList &Lc)
//a与b的交集
{
int La_len=La.length;
int Lb_len=Lb.length;
int e;
int index=0;
//cout<<Lc.length<<endl;
SqList p=La_len<=Lb_len?La:Lb;
SqList q=La_len>Lb_len?La:Lb;
for(int i=1; i<=p.length; i++)
{
GetElem(p,i,e);
if(LocateElem(q,e,equal_e))
{
ListInsert_Sq(Lc,++index,e);
//Get(Lc);
}
}
if(Lc.length)
return OK;
else
return ERROR;
}
int different(SqList La,SqList Lb,SqList &Lc)
//求a-b差集
{
int La_len=La.length;
int e;
int index=0;
for(int i=1; i<=La_len; i++)
{
GetElem(La,i,e);
if(!LocateElem(Lb,e,equal_e))
ListInsert_Sq(Lc,++index,e);
}
if(Lc.length)
return OK;
else
return ERROR;
}
int main()
{
SqList La,Lb;
InitList_Sq(La);
InitList_Sq(Lb);
cout<<"集合A:"<<endl;
fuzhi(La);
cout<<"集合A中元素: ";
Get(La);
cout<<endl;
cout<<"集合B:"<<endl;
fuzhi(Lb);
cout<<"集合B中元素: ";
Get(Lb);
cout<<endl;
cout<<"A并B:"<<endl;
SqList Lc1;
InitList_Sq(Lc1);
union_set(La,Lb,Lc1);
Get(Lc1);
cout<<endl;
cout<<"A交B:"<<endl;
SqList Lc2;
InitList_Sq(Lc2);
if(mixture(La,Lb,Lc2))
{
Get(Lc2);
cout<<endl;
}
else
{
cout<<"null"<<endl;
cout<<endl;
}
cout<<"A-B:"<<endl;
SqList Lc3;
InitList_Sq(Lc3);
if(different(La,Lb,Lc3))
Get(Lc3);
else
cout<<"null"<<endl;
return 0;
}
剖析:
1.初始化
//初始化
int InitList_Sq(SqList &L)
{
L.elem=(int *)malloc(LIST_INIT_SIZE*sizeof(int));//动态分配内存
if(!L.elem)
exit(OVERFLOW);
L.length=0;
L.listsize=LIST_INIT_SIZE;
return OK;
}
- malloc()为动态存储分配函数,需要头文件<stdlib.h>.
- 这里我们从堆中动态分配了400个字节的内存空间(按照int 是4个字节计算,即100个int的大小)。然后将首地址返回给L.elem,若函数执行失败则返回null。
- exit(n)就是退出,传入的参数n是程序退出时的状态码,0表示正常退出,其他表示非正常退出
2.往顺序表中插入元素
//在顺序表指定位置插入元素
int ListInsert_Sq(SqList &L,int i,int e)
{
if(i<1||i>L.length+1)
return ERROR;
if(L.length>=L.listsize)
{
int *newbase;
newbase=(int*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(int));//扩充内存
if(!newbase)
exit(OVERFLOW);
L.elem=newbase;
L.listsize+=LISTINCREMENT;
}
int *p,*q;
q=&(L.elem[i-1]);
for(p=&(L.elem[L.length-1]); p>=q; p--)
*(p+1)=*p;
*q=e;
++L.length;
return OK;
}
- realloc(a,b)函数用来扩大动态分配区域,即当第二个参数b大于第一个参数a指向的动态内存大小时将重新申请一个大小为b的内存空间。
- 添加时为防止覆盖要先把后面的向后移再插入。
3.构造一个按某种规则定位的函数
int equal_e(int a,int b)
{
if(a==b)
return OK;
else
return ERROR;
}
int LocateElem(SqList L,int e,int (*compare)(int,int))
//在表中查找第一个值与e满足compare()元素的位序
{
int i=1;
int *p=L.elem;
while(i<=L.length&&!(*compare)(*p++,e))
++i;
if(i<=L.length)
return i;
else
return 0;
}
- compare那个是把一个函数作为变量传入函数locateElem()中,本题中compare指向equal_e()函数。
- 本题中函数locateElem()的功能是找到顺序表L中第一个和e相同的元素位置。
4.求两个集合的并集
void union_set(SqList La,SqList Lb,SqList &Lc)
//a与b的并集放入c中
{
int La_len=La.length;
int Lb_len=Lb.length;
int e;
for(int i=1; i<=Lb_len; i++)
{
GetElem(Lb,i,e);
if(!LocateElem(La,e,equal_e))
ListInsert_Sq(La,++La_len,e);
}
for(int i=1; i<=La_len; i++)
{
GetElem(La,i,e);
ListInsert_Sq(Lc,i,e);
}
}
- 如果集合B中的元素在集合A中全找了一遍都没有相等的话,那LocateElem()函数中的i就会大于L.length。此时这里的if判断成真。我们把这个e添加到集合A的最后一位。
5.两个集合求交集
int mixture(SqList La,SqList Lb,SqList &Lc)
//a与b的交集
{
int La_len=La.length;
int Lb_len=Lb.length;
int e;
int index=0;
//cout<<Lc.length<<endl;
SqList p=La_len<=Lb_len?La:Lb;
SqList q=La_len>Lb_len?La:Lb;
for(int i=1; i<=p.length; i++)
{
GetElem(p,i,e);
if(LocateElem(q,e,equal_e))
{
ListInsert_Sq(Lc,++index,e);
//Get(Lc);
}
}
if(Lc.length)
return OK;
else
return ERROR;
}
- 因为两集合的交集一定小于等于两集合中最小的那个,所以我们从小集合中取元素跟大集合比较,这样更快一点。
- 如果对比成功的位置小于L.length说明集合A中存在这个元素,此时if判断成真,我们将它放入新的顺序表中表示交集。
6.两集合求差
int different(SqList La,SqList Lb,SqList &Lc)
//求A-B差集
{
int La_len=La.length;
int e;
int index=0;
for(int i=1; i<=La_len; i++)
{
GetElem(La,i,e);
if(!LocateElem(Lb,e,equal_e))
ListInsert_Sq(Lc,++index,e);
}
if(Lc.length)
return OK;
else
return ERROR;
}
- A − B A - B A−B 和 B − A B - A B−A可不一样,所以这里只能从A中拿元素和B里的元素进行比较。
- 差集和交集规则相反,if里面加一个!就好。