链表是实现集合的一种理想的方式。将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. 【ASP.NET MVC系列】浅谈ASP.NET MVC 视图

    ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...

  2. Jenkins结合.net平台工具之Nunit

    有时候我们需要对从git上拉取的项目进行单元测通过以后才可以发布到测试环境,.net平台下单元测试的框架也很多例如mstest,nunit,xunit等,下面以Nunit为例讲解如何通过Jenkins ...

  3. SHELL脚本--简介

    bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html 脚本都以#!/bin/bash开头,“#”称为sharp,“! ...

  4. iOS 快速排序

    一.快速排序概念及其思想 快速排序(QuickSort),又称为交换排序,是分治算法的一种,快速排序采用分治的策略. 1.分治法的基本思想: 将原问题分解为若干个规模更小但结构和原问题相似的子问题.递 ...

  5. javascript小实例,编写一个方法,实现从n-m个数中随机选出一个整数

    别怪我是一个闷葫芦,没那么多花哨的语言,废话不多说,先说说小实例的要求: 编写一个方法,实现从n-m个数中随机选出一个整数,要求:传递的参数不足两个或者不是有效数字,返回[0-1]之间的随机数,需要解 ...

  6. [nodejs] nodejs开发个人博客(四)数据模型

    数据库模型 /model/db.js 数据库操作类,完成链接数据库和数据库的增删查改 查询表 /*查询*/ select:function(tableName,callback,where,field ...

  7. 26.C++- 泛型编程之类模板(详解)

    在上章25.C++- 泛型编程之函数模板(详解) 学习了后,本章继续来学习类模板   类模板介绍 和函数模板一样,将泛型思想应用于类. 编译器对类模板处理方式和函数模板相同,都是进行2次编译 类模板通 ...

  8. Java_冒泡排序_原理及优化

    冒泡排序及其优化 一.原理及优化原理 1.原理讲解 冒泡排序即:第一个数与第二个数进行比较,如果满足条件位置不变,再把第二个数与第三个数进行比较.不满足条件则替换位置,再把第二个数与第三个数进行比较, ...

  9. awk、nawk、mawk、gawk的简答介绍

    awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理.数据可以来自标准输入.一个或多个文件,或其它命令的输出(即管道).它支持用户自定义函数和 动态正则表达式等先进功能,是linu ...

  10. Netty中的HttpObjectAggregator

    Http的Get,POST Get请求包括两个部分: request line(包括method,request uri,protocol version)) header 基本样式: GET /?n ...