链表是实现集合的一种理想的方式。将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);
}

集合抽象数据类型的C语言实现的更多相关文章

  1. 数据结构 集合_集合(数学)抽象数据类型的C语言实现

    链表是实现集合的一种理想的方式.将List以typedef的方式重命名为Set.这样做能保留链表简洁的特性,还能使集合具有了一些多态的特性. 使用这种方法的最大好处就是可以使用list_next来遍历 ...

  2. C语言泛型编程--抽象数据类型

    一.数据类型: 在任何编程语言中,数据类型作为一个整体,ANSI-C包含的类型为:int.double.char……,程序员很少满意语言本身提供的数据类型,一个简单的办法就是构造类似:array.st ...

  3. 采用C/C++语言如何实现复数抽象数据类型Complex

    记录一下! 采用C/C++语言如何实现复数抽象数据类型Complex #include <stdio.h> typedef struct Complex { double e1; // 实 ...

  4. C语言抽象数据类型ADT

    根据编程的问题匹配合适的数据类型.数据项连接构成了链表,定义了一个结构代表单独的项.设计了一些方法把一系列结构构成一个链表.本质上,我们使用C语言的功能设计了一种符合程序要求的新的数据类型.但是上述的 ...

  5. ORACLE抽象数据类型

    ORACLE抽象数据类型 *抽象数据类型*/1,抽象数据类型 概念包含一个或多个子类型的数据类型不局限于ORACLE的标准数据类型可以用于其他数据类型中 2,创建抽象数据类型 的语法(必须用NOT F ...

  6. 【Python&数据结构】 抽象数据类型 Python类机制和异常

    这篇是<数据结构与算法Python语言描述>的笔记,但是大头在Python类机制和面向对象编程的说明上面.我也不知道该放什么分类了..总之之前也没怎么认真接触过基于类而不是独立函数的Pyt ...

  7. 抽象数据类型ADT

    ADT(Abstract Data Type) 类型由什么组成? 一个类型(type)指定两类信息,一个属性集和一个操作集. 假设要定义一个新的数据类型.首先,要提供存储数据的方式,可能是通过设计一个 ...

  8. ADT(abstract data types)抽象数据类型

    1.What is it? An abstract data type is a set of objects together with a set of operations. 抽象数据类型是带有 ...

  9. Week1绪论--抽象数据类型

    一.作业题目 1.构造有理数T,元素e1,e2分别被赋以分子.分母值 2.销毁有理数T 3.用e(引用类型参数)返回有理数T的分子或分母,当入参i为1时返回分子, i为2是返回分母. 4.将有理数T的 ...

随机推荐

  1. MyBatis源码解析(七)——DataSource数据源模块之托管数据源

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6675700.html 1 回顾 之前介绍的非池型与池型数据源都是MyBatis自己定义的内 ...

  2. MySQL中间件之ProxySQL(12):禁止多路路由

    返回ProxySQL系列文章:http://www.cnblogs.com/f-ck-need-u/p/7586194.html 1.multiplexing multiplexing,作用是将语句分 ...

  3. Bootstrap-table使用总结(整合版)

    一.什么是Bootstrap-table? 在业务系统开发中,对表格记录的查询.分页.排序等处理是非常常见的,在Web开发中,可以采用很多功能强大的插件来满足要求,且能极大的提高开发效率,本随笔介绍这 ...

  4. PAT之气死人不偿命的3n+1猜想

    卡拉兹(Callatz)猜想: 对任何一个自然数n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把(3n+1)砍掉一半.这样一直反复砍下去,最后一定在某一步得到n=1.卡拉兹在1950年的世界数 ...

  5. 第一册:lesson 11.

    原文:Is this your shirt? A:Whose shirt is that? Is this your shirt B? B:NO,sir. It's not my shirt.This ...

  6. 23.QT记事本

    描述 主要功能有: 新建,打开,保存,另存为,打印, 编辑,撤销,,拖放,xml配置文件读写,字体更改,查找替换 菜单栏,工具栏,状态栏的实现 如下图所示: 效果如下所示:   源码下载地址: htt ...

  7. Mybatis框架基础支持层——解析器模块(2)

    解析器模块,核心类XPathParser /** * 封装了用于xml解析的类XPath.Document和EntityResolver */ public class XPathParser { / ...

  8. WORLD 快速线

    1,3个“-”     一条直线 2,3个“=”    一条双直线 3,3个“*”     一条虚线 4,3个“~”     一条波浪线 5, 3个“#”    一条隔行线

  9. 将Y-m-d转换为Y年m月d日

    自己编写的,不能直接套用,理解后可自行变化: $var=explode(' ',$res['act_starting']); $var1=$var[0];          $time=explode ...

  10. Django下自定义标签和过滤器

    ---恢复内容开始--- 第一步:确保setting中的INSTALL_APPS配置当前的app,要不然Django无法找到自定义的simple_tag. 第二步:在app中创建templatetag ...