Mastering Algorithms with C(set)

本文介绍了一个基于链表实现的集合数据结构,包括初始化、插入、删除、并集、交集、差集等基本操作,并通过两个示例程序展示了集合的使用方法及集合覆盖问题的求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(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;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值