数据结构 集合_集合(数学)抽象数据类型的C语言实现
链表是实现集合的一种理想的方式。将List以typedef的方式重命名为Set。这样做能保留链表简洁的特性,还能使集合具有了一些多态的特性。
使用这种方法的最大好处就是可以使用list_next来遍历一个集合,使用list_rem_next来移除一个成员,而不用根据成员所存储的数据来标识它。
我们先来查看一下集合抽象数据类型头文件的内容:
示例1:集合(抽象数据类型)头文件
#ifndef SET_H #define SET_H #include <stdlib.h> #include "list.h" /*将集合定义成List结构*/ typedef List Set; /*集合的初始化*/ void set_init(Set *set,int (match*)(const void *key1,const void *key2),void(*destroy)(void *data)); /*集合销毁,定义成链表销毁函数*/ #define set_destroy List_destroy /*向集合中插入元素*/ int set_insert(Set *set, const void *data); /*从集合中移除元素*/ int set_remove(Set *set, void **data); /*求集合的并集*/ int set_union(Set *setu, const Set *set1, const Set *set2); /*求集合的交集*/ int set_intersection(Set *seti, const Set *set1,const Set *set2); /*求集合的差集*/ int set_difference(Set *setd, const Set *set1,const Set *set2); /*判断成员是否属于集合*/ int set_is_member(const Set *set, const void *data); /*判断子集*/ int set_is_subset(const Set *set1, const Set *set2); /*判断集合是否相等*/ int set_is_equal(const Set *set1, const Set *set2); /*集合中元素的个数*/ #define set_size(set) ((set)->size) #endif
下面是各种操作的具体实现:
示例2:集合抽象数据类型的实现
#include <stdlib.h> #include <string.h> #include "list.h" #include "set.h" /*set_init 初始化一个集合*/ void set_init(Set *set,int(*match)(const void *key1,const void *key2), void(*destroy)(void *data)) { /*调用list_init*/ list_init(set,destroy); /*单独初始化match成员*/ set->match = match; return; } /*set_insert 向集合中插入一个成员*/ int set_insert(Set *set,const void *data) { /*不能向集合中插入已有成员*/
if(set_is_member(set,data))
return -1;
/*调用list_ins_next插入元素至尾端*/
return list_ins_next(set,list_tail(set),data);
}
/*set_remove 移除元素*/
int set_remove(Set *set,void **data)
{
ListElmt *member, *prev;
/*查找要移除的成员*/
prev=NULL;
/*遍历链表*/
for(member=list_head(set); member != NULL; member = list_next(member))
{
if(set->match(*data,(list_data(member)))
break;
prev=member; /*prev刚好指向匹配成功的成员的前一个成员*/
}
/*没有找到成员则返回*/
if(member==NULL)
return -1;
/*移除成员*/
return list_rem_next(set,prev,data);
}
/*set_union 求解两个集合的并集*/
int set_union(Set *setu,const Set *set1,const Set *set2)
{
ListElmt *member;
void *data;
/*初始化一个并集集合*/
set_init(setu,set1->match,NULL);
/*将集合1的内容插入并集*/
for(member=list_head(set1);member!=NULL;member=list_next(member))
{
data=list_data(member);
if(list_ins_next(setu,list_tail(setu),data)!=0)
{
set_destroy(setu);
return -1;
}
}
/*插入集合2的成员*/
for(member=list_head(set2);member!=NULL;member=list_next(member))
{
if(set_is_member(set1,list_data(member)))
{
continue;
}
else
{
data=list_data(member);
if(list_ins_next(setu,list_tail(setu),data))!=0)
{
set_destroy(setu);
return -1;
}
}
}
return 0;
}
/*set_intersection 求解两个集合的交集*/
int set_intersection(Set *seti,const Set *set1,const Set *set2)
{
ListElmt *member;
void *data;
/*初始化交集集合*/
set_init(seti,set1->match,NULL);
/*同时在两个集合中出现的元素将被插入交集集合中*/
for(member=list_head(set1);member!=NULL;list_next(member))
{
if(set_is_member(set2,list_data(member))
{
data=list_data(member);
if(list_ins_next(seti,list_tail(seti),data))!=0)
{
set_destroy(seti);
return -1;
{
}
}
return 0;
}
/*set_difference 求解两个集合的差集*/
int set_intersection(Set *setd,const Set *set1,const Set *set2)
{
ListElmt *member;
void *data;
/*初始化差集集合*/
set_init(setd,set1->match,NULL);
/*不同时在两个集合中出现的元素将被插入差集集合中*/
for(member=list_head(set1);member!=NULL;list_next(member))
{
if( ! set_is_member(set2,list_data(member))
{
data=list_data(member);
if(list_ins_next(setd,list_tail(setd),data))!=0)
{
set_destroy(setd);
return -1;
{
}
}
return 0;
}
/*set_is_member 判断由data指定的成员是否在由set指定的集合中*/
int set_is_member(const Set *set,void *data)
{
ListElmt *member;
for(member=list_head(set);member!=NULL;list_next(member))
{
if(set->match(data,list_data(member))
return 1;
}
return 0;
}
/*set_is_subset 判断集合set1是否是集合set2的子集*/
int set_is_subset(const Set *set1,const Set *set2)
{
ListElmt *member;
/*首先排除集合1成员数量大于集合2成员数量的情况*/
if(set_size(set1)>set_size(set2))
return 0;
/*如果set1的成员不都在set2中,则判断不成立,除此成立*/
for(member=list_head(set1);member!=NULL;list_next(member))
{
if( !set_is_member(set2,list_data(member)))
{
return 0;
}
}
return 1;
}
/*set_is_equal 判断两个集合是否相等*/
int set_is_equal(const Set *set1,const Set *set2)
{
/*首先排除两个集合成员数量不相等的情况*/
if(set_size(set1) != set_size(set2))
return 0;
/*两个集合成员数量相等,且一个集合是另一个集合的子集时,这两个集合相等*/
return set_is_subset(set1,set2);
}