(1)set.h
/*****************************************************************************
* *
* -------------------------------- set.h --------------------------------- *
* *
*****************************************************************************/
#ifndef SET_H
#define SET_H
#include <stdlib.h>
#include <string.h>
#include "list.h"
/*****************************************************************************
* *
* Implement sets as linked lists. *
* *
*****************************************************************************/
typedef List Set;
/*****************************************************************************
* *
* --------------------------- Public Interface --------------------------- *
* *
*****************************************************************************/
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)
/*****************************************************************************
* *
* -------------------------------- set.c --------------------------------- *
* *
*****************************************************************************/
/*****************************************************************************
* *
* ------------------------------- set_init ------------------------------- *
* *
*****************************************************************************/
void set_init(Set *set, int (*match)(const void *key1, const void *key2),
void (*destroy)(void *data)) {
/*****************************************************************************
* *
* Initialize the set. *
* *
*****************************************************************************/
list_init(set, destroy);
set->match = match; // 比较函数,使用memcmp
return;
}
/*****************************************************************************
* *
* ------------------------------ set_insert ------------------------------ *
* *
*****************************************************************************/
int set_insert(Set *set, const void *data) {
/*****************************************************************************
* *
* Do not allow the insertion of duplicates. *
* *
*****************************************************************************/
if (set_is_member(set, data)) // 判断该数是否存在
return 1;
/*****************************************************************************
* *
* Insert the data. *
* *
*****************************************************************************/
return list_ins_next(set, list_tail(set), data);
}
/*****************************************************************************
* *
* ------------------------------ set_remove ------------------------------ *
* *
*****************************************************************************/
int set_remove(Set *set, void **data) {
ListElmt *member,
*prev;
/*****************************************************************************
* *
* Find the member to remove. *
* *
*****************************************************************************/
prev = NULL;
for (member = list_head(set); member != NULL; member = list_next(member)) {
if (set->match(*data, list_data(member)))
break;
prev = member; // 因为基于链表实现的集合,只能根据前一个结点来删除下一个
}
/*****************************************************************************
* *
* Return if the member was not found. *
* *
*****************************************************************************/
if (member == NULL)
return -1;
/*****************************************************************************
* *
* Remove the member. *
* *
*****************************************************************************/
return list_rem_next(set, prev, data);
}
/*****************************************************************************
* *
* ------------------------------- set_union ------------------------------ *
* *
*****************************************************************************/
int set_union(Set *setu, const Set *set1, const Set *set2) {
// 集合的并,返回的是新的集合
ListElmt *member;
void *data;
/*****************************************************************************
* *
* Initialize the set for the union. *
* *
*****************************************************************************/
set_init(setu, set1->match, NULL);
/*****************************************************************************
* *
* Insert the members of the first set. *
* *
*****************************************************************************/
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;
}
}
/*****************************************************************************
* *
* Insert the members of the second set. *
* *
*****************************************************************************/
for (member = list_head(set2); member != NULL; member = list_next(member)) {
if (set_is_member(set1, list_data(member))) { // 判断是否重复
/***********************************************************************
* *
* Do not allow the insertion of duplicates. *
* *
***********************************************************************/
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;
/*****************************************************************************
* *
* Initialize the set for the intersection. *
* *
*****************************************************************************/
set_init(seti, set1->match, NULL);
/*****************************************************************************
* *
* Insert the members present in both sets. *
* *
*****************************************************************************/
for (member = list_head(set1); member != NULL; member = 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_difference(Set *setd, const Set *set1, const Set *set2) {
// 集合的差
ListElmt *member;
void *data;
/*****************************************************************************
* *
* Initialize the set for the difference. *
* *
*****************************************************************************/
set_init(setd, set1->match, NULL);
/*****************************************************************************
* *
* Insert the members from set1 not in set2. *
* *
*****************************************************************************/
for (member = list_head(set1); member != NULL; member = 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 ---------------------------- *
* *
*****************************************************************************/
int set_is_member(const Set *set, const void *data) { //判断该数值是否存在于集合中
ListElmt *member;
/*****************************************************************************
* *
* Determine if the data is a member of the set. *
* *
*****************************************************************************/
for (member = list_head(set); member != NULL; member = list_next(member)) {
if (set->match(data, list_data(member)))
return 1;
}
return 0;
}
/*****************************************************************************
* *
* ----------------------------- set_is_subset ---------------------------- *
* *
*****************************************************************************/
int set_is_subset(const Set *set1, const Set *set2) {
// 子集
ListElmt *member;
/*****************************************************************************
* *
* Do a quick test to rule out some cases. *
* *
*****************************************************************************/
if (set_size(set1) > set_size(set2))
return 0;
/*****************************************************************************
* *
* Determine if set1 is a subset of set2. *
* *
*****************************************************************************/
for (member = list_head(set1); member != NULL; member = 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) {
// 集合是否相等
/*****************************************************************************
* *
* Do a quick test to rule out some cases. *
* *
*****************************************************************************/
if (set_size(set1) != set_size(set2))
return 0;
/*****************************************************************************
* *
* Sets of the same size are equal if they are subsets. *
* *
*****************************************************************************/
return set_is_subset(set1, set2);
}
#endif
(2)ex-1.c
/*****************************************************************************
* *
* ex-1.c *
* ====== *
* *
* Description: Illustrates using a set (see Chapter 7). *
* *
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
#include "set.h"
/*****************************************************************************
* *
* ------------------------------- print_set ------------------------------ *
* *
*****************************************************************************/
static void print_set(const Set *set) {
ListElmt *member;
int *data,
size,
i;
/*****************************************************************************
* *
* Display the set. *
* *
*****************************************************************************/
fprintf(stdout, "Set size is %d\n", size = set_size(set));
i = 0;
member = list_head(set);
while (i < size) {
data = list_data(member);
fprintf(stdout, "set[%03d]=%03d\n", i, *data);
member = list_next(member);
i++;
}
return;
}
/*****************************************************************************
* *
* ------------------------------- match_int ------------------------------ *
* *
*****************************************************************************/
static int match_int(const void *key1, const void *key2) {
/*****************************************************************************
* *
* Determine whether two integers match. *
* *
*****************************************************************************/
return !memcmp(key1, key2, sizeof(int));
}
/*****************************************************************************
* *
* --------------------------------- main --------------------------------- *
* *
*****************************************************************************/
int main(int argc, char **argv) {
Set set,
set1,
set2;
int *data,
retval,
i;
/*****************************************************************************
* *
* Initialize the set. *
* *
*****************************************************************************/
set_init(&set, match_int, free);
/*****************************************************************************
* *
* Perform some set operations. *
* *
*****************************************************************************/
fprintf(stdout, "Inserting 10 members\n");
for (i = 9; i >= 0; i--) {
if ((data = (int *)malloc(sizeof(int))) == NULL)
return 1;
*data = i + 1;
if ((retval = set_insert(&set, data)) < 0)
return 1;
else if (retval == 1)
free(data);
}
print_set(&set);
fprintf(stdout, "Inserting the same members again\n");
for (i = 9; i >= 0; i--) {
if ((data = (int *)malloc(sizeof(int))) == NULL)
return 1;
*data = i + 1;
if ((retval = set_insert(&set, data)) < 0)
return 1;
else if (retval == 1)
free(data);
}
print_set(&set);
fprintf(stdout, "Inserting 200 and 100\n");
if ((data = (int *)malloc(sizeof(int))) == NULL)
return 1;
*data = 200;
if ((retval = set_insert(&set, data)) < 0)
return 1;
else if (retval == 1)
free(data);
if ((data = (int *)malloc(sizeof(int))) == NULL)
return 1;
*data = 100;
if ((retval = set_insert(&set, data)) < 0)
return 1;
else if (retval == 1)
free(data);
print_set(&set);
fprintf(stdout, "Removing 100, 5, and 10\n");
i = 100;
data = &i;
if (set_remove(&set, (void **)&data) == 0)
free(data);
i = 5;
data = &i;
if (set_remove(&set, (void **)&data) == 0)
free(data);
i = 10;
data = &i;
if (set_remove(&set, (void **)&data) == 0)
free(data);
print_set(&set);
fprintf(stdout, "Removing three members\n");
if (list_rem_next(&set, NULL, (void **)&data) == 0)
free(data);
if (list_rem_next(&set, NULL, (void **)&data) == 0)
free(data);
if (list_rem_next(&set, NULL, (void **)&data) == 0)
free(data);
print_set(&set);
fprintf(stdout, "Removing all members\n");
while (set_size(&set) > 0) {
if (list_rem_next(&set, NULL, (void **)&data) == 0)
free(data);
}
print_set(&set);
/*****************************************************************************
* *
* Initialize two sets. *
* *
*****************************************************************************/
set_init(&set1, match_int, free);
set_init(&set2, match_int, free);
/*****************************************************************************
* *
* Perform some set operations. *
* *
*****************************************************************************/
for (i = 9; i >= 0; i--) {
if ((data = (int *)malloc(sizeof(int))) == NULL)
return 1;
*data = i + 1;
if ((retval = set_insert(&set1, data)) < 0)
return 1;
else if (retval == 1)
free(data);
if (i == 5 || i == 6 || i == 7) {
if ((data = (int *)malloc(sizeof(int))) == NULL)
return 1;
*data = i * 10;
if ((retval = set_insert(&set2, data)) < 0)
return 1;
else if (retval == 1)
free(data);
}
else if (i == 3 || i == 1) {
if ((data = (int *)malloc(sizeof(int))) == NULL)
return 1;
*data = i;
if ((retval = set_insert(&set2, data)) < 0)
return 1;
else if (retval == 1)
free(data);
}
}
fprintf(stdout, "Set 1 for testing unions, intersections, and differences\n");
print_set(&set1);
fprintf(stdout, "Set 2 for testing unions, intersections, and differences\n");
print_set(&set2);
fprintf(stdout, "Determining the union of the two sets\n");
if (set_union(&set, &set1, &set2) != 0)
return 1;
print_set(&set);
fprintf(stdout, "Destroying the union\n");
set_destroy(&set);
fprintf(stdout, "Determining the intersection of the two sets\n");
if (set_intersection(&set, &set1, &set2) != 0)
return 1;
print_set(&set);
fprintf(stdout, "Testing whether the intersection equals Set 1...Value=%d "
"(0=OK)\n", set_is_equal(&set, &set1));
fprintf(stdout, "Testing whether Set 1 equals itself...Value=%d (1=OK)\n",
set_is_equal(&set1, &set1));
fprintf(stdout, "Testing whether the intersection is a subset of Set 1..."
"Value=%d (1=OK)\n", set_is_subset(&set, &set1));
fprintf(stdout, "Testing whether Set 2 is a subset of Set 1...Value=%d "
"(0=OK)\n", set_is_subset(&set2, &set1));
fprintf(stdout, "Destroying the intersection\n");
set_destroy(&set);
fprintf(stdout, "Determining the difference of the two sets\n");
if (set_difference(&set, &set1, &set2) != 0)
return 1;
print_set(&set);
i = 3;
fprintf(stdout, "Testing whether %03d is in difference...Value=%d (0=OK)\n",i,
set_is_member(&set, &i));
i = 5;
fprintf(stdout, "Testing whether %03d is in difference...Value=%d (1=OK)\n",i,
set_is_member(&set, &i));
/*****************************************************************************
* *
* Destroy the sets. *
* *
*****************************************************************************/
fprintf(stdout, "Destroying the sets\n");
set_destroy(&set);
set_destroy(&set1);
set_destroy(&set2);
return 0;
}
(3)ex-2.c
/*****************************************************************************
* *
* ex-2.c *
* ====== *
* *
* Description: Illustrates set covering (see Chapter 7). *
* *
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cover.h"
#include "list.h"
#include "set.h"
/*****************************************************************************
* *
* Define the number of members in the skills and player sets. *
* *
*****************************************************************************/
#define SKILLS_COUNT 12
#define PLAYER_COUNT 8
/*****************************************************************************
* *
* ----------------------------- print_skills ----------------------------- *
* *
*****************************************************************************/
static void print_skills(const Set *skills) {
ListElmt *member;
char *data;
int size,
i;
/*****************************************************************************
* *
* Display the set of skills. *
* *
*****************************************************************************/
fprintf(stdout, "Set size is %d\n", size = set_size(skills));
i = 0;
member = list_head(skills);
while (i < size) {
data = list_data(member);
fprintf(stdout, "skills[%03d]=%c\n", i, *data);
member = list_next(member);
i++;
}
return;
}
/*****************************************************************************
* *
* ----------------------------- print_players ---------------------------- *
* *
*****************************************************************************/
static void print_players(const Set *players) {
ListElmt *member;
/*****************************************************************************
* *
* Display the skills for each player in the set of players. *
* *
*****************************************************************************/
for (member = list_head(players); member != NULL; member = list_next(member)){
fprintf(stdout, "Player %c\n", *(char *)((KSet *)list_data(member))->key);
print_skills(&((KSet *)list_data(member))->set);
}
return;
}
/*****************************************************************************
* *
* ------------------------------- match_key ------------------------------ *
* *
*****************************************************************************/
int match_key(const void *key1, const void *key2) {
/*****************************************************************************
* *
* Determine whether two keyed sets match. *
* *
*****************************************************************************/
if (*(char *)((const KSet *)key1)->key == *(char *)((const KSet *)key2)->key)
return 1;
else
return 0;
}
/*****************************************************************************
* *
* ------------------------------ match_skill ----------------------------- *
* *
*****************************************************************************/
int match_skill(const void *skill1, const void *skill2) {
/*****************************************************************************
* *
* Determine whether two skills match. *
* *
*****************************************************************************/
if (*(const char *)skill1 == *(const char *)skill2)
return 1;
else
return 0;
}
/*****************************************************************************
* *
* --------------------------------- main --------------------------------- *
* *
*****************************************************************************/
int main(int argc, char **argv) {
Set skills,
players,
covering;
char skills_array[SKILLS_COUNT],
subids_array[PLAYER_COUNT];
KSet player_array[PLAYER_COUNT];
int retval,
i;
/*****************************************************************************
* *
* Create the set of skills. *
* *
*****************************************************************************/
fprintf(stdout, "Creating the set of skills\n");
set_init(&skills, match_skill, NULL);
skills_array[0] = 'a';
skills_array[1] = 'b';
skills_array[2] = 'c';
skills_array[3] = 'd';
skills_array[4] = 'e';
skills_array[5] = 'f';
skills_array[6] = 'g';
skills_array[7] = 'h';
skills_array[8] = 'i';
skills_array[9] = 'j';
skills_array[10] = 'k';
skills_array[11] = 'l';
for (i = 0; i < SKILLS_COUNT; i++) {
if (set_insert(&skills, &skills_array[i]) != 0)
return 1;
}
print_skills(&skills);
/*****************************************************************************
* *
* Create some player sets with certain skills. *
* *
*****************************************************************************/
fprintf(stdout, "Creating the player subsets\n");
set_init(&players, match_key, NULL);
subids_array[0] = '1';
subids_array[1] = '2';
subids_array[2] = '3';
subids_array[3] = '4';
subids_array[4] = '5';
subids_array[5] = '6';
subids_array[6] = '7';
subids_array[7] = '8';
for (i = 0; i < PLAYER_COUNT; i++) {
player_array[i].key = &subids_array[i];
set_init(&player_array[i].set, match_skill, NULL);
switch (i) {
case 0:
if (set_insert(&player_array[i].set, &skills_array[0]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[1]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[2]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[3]) != 0)
return 1;
break;
case 1:
if (set_insert(&player_array[i].set, &skills_array[4]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[5]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[6]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[7]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[8]) != 0)
return 1;
break;
case 2:
if (set_insert(&player_array[i].set, &skills_array[9]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[10]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[11]) != 0)
return 1;
break;
case 3:
if (set_insert(&player_array[i].set, &skills_array[0]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[4]) != 0)
return 1;
break;
case 4:
if (set_insert(&player_array[i].set, &skills_array[1]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[5]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[6]) != 0)
return 1;
break;
case 5:
if (set_insert(&player_array[i].set, &skills_array[2]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[3]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[6]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[7]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[10]) != 0)
return 1;
if (set_insert(&player_array[i].set, &skills_array[11]) != 0)
return 1;
break;
default:
if (set_insert(&player_array[i].set, &skills_array[11]) != 0)
return 1;
}
if (set_insert(&players, &player_array[i]) != 0)
return 1;
}
print_players(&players);
/*****************************************************************************
* *
* Compute the set covering. *
* *
*****************************************************************************/
fprintf(stdout, "Generating the cover\n");
if ((retval = cover(&skills, &players, &covering)) != 0)
return 1;
if (retval == 1)
fprintf(stderr, "The set could not be covered\n");
else
print_players(&covering);
/*****************************************************************************
* *
* Destroy the sets. *
* *
*****************************************************************************/
fprintf(stdout, "Destroying the sets\n");
for (i = 0; i < PLAYER_COUNT; i++)
set_destroy(&player_array[i].set);
set_destroy(&skills);
return 0;
}