链表是实现集合的一种理想的方式。将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. 搭建企业级PPTP服务器

    本文收录在企业项目实战系列 一.VPN 介绍 1.介绍 虚拟私人网络(英语:Virtual Private Network,缩写为VPN)是一种常用于连接中.大型企业或团体与团体间的私人网络的通讯方法 ...

  2. Tomcat8源码笔记(六)连接器Connector分析

    根据 Tomcat8源码笔记(五)组件Container分析 前文分析,StandardService的初始化重心由 StandardEngine转移到了Connector的初始化,本篇记录下Conn ...

  3. greenev —— Python 异步网络服务框架

    greenev是一个基于greenlet协程,事件驱动,非阻塞socket模型的Python网络服务框架,它使得可以编写同步的代码,却得到异步执行的优点. 本项目受到gevent, openresty ...

  4. 记录一下对swiper4.x.js在H5单页中的滑动优化

    应用场景 仅仅应用于单页应用的滑动操作,用swiper4.x接管页面的滚动操作.用来支持顶部和尾部的回弹效果,进一步来支持常见那种下拉刷新动画效果.不适用于轮播图那种应用场景. 虽然只是针对swipe ...

  5. 第6章 LVM详解

    6.1 LVM相关概念和机制 LVM(Logical Volume Manager)可以让分区变得弹性,可以随时随地的扩大和缩小分区大小,前提是该分区是LVM格式的. lvm需要使用的软件包为lvm2 ...

  6. haproxy配置示例和需要考虑的问题

    HaProxy系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html haproxy是一个非常优秀的负载均衡工具,它的特性非常丰富,功能也非常非常 ...

  7. 十大经典排序算法详细总结(含JAVA代码实现)

    原文出处:http://www.cnblogs.com/guoyaohua/p/8600214.html 0.排序算法说明 0.1 排序的定义 对一序列对象根据某个关键字进行排序. 0.2 术语说明 ...

  8. 在Object-C中学习数据结构与算法之排序算法

    笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速 ...

  9. 从零开始学安全(七)●Linux基础命令学习笔记

    halt 关机reboot 现在重新启动su - 如果当前是普通用户,则输入这条命令切换到管理员用户(root),如果要切换到其他用户则敲入 su - 用户名 如: su - wangxin root ...

  10. Spring核心——Bean的定义与控制

    在Sring核心与设计模式的文章中,分别介绍了Ioc容器和Bean的依赖关系.如果阅读过前2文就会知道,Spring的整个运转机制就是围绕着IoC容器以及Bean展开的.IoC就是一个篮子,所有的Be ...