第21章 用于不相交集合的数据结构
21.2 不相交集体的链表表示
#include
#include
#include
typedef struct set_type *set;
struct set_node {
void *key;
struct set_node *next;
struct set_node *representative; //指向代表的集合元素
};
struct set_type {
struct set_node *head;
struct set_node *tail;
int num;
};
void set_node_ini(struct set_node *x, void *key)
{
x->key = key;
x->next = NULL;
x->representative = NULL;
}
set set_create(void *key)
{
set s = malloc(sizeof(struct set_type));
struct set_node *x = malloc(sizeof(struct set_node));
set_node_ini(x, key);
s->head = x;
s->tail = x;
s->num = 1;
x->representative = x;
return s;
}
struct set_node *find_set(set s)
{
return s->head->representative;
}
void update_representative(struct set_node *head,
struct set_node *representative)
{
struct set_node *p = head;
while (p != NULL) {
p->representative = representative;
p = p->next;
}
}
//把较短的链表拼到较长的链表上,更新短链表的每个结点指向代表指针
void set_union(set sa, set sb)
{
if (sa->num < sb->num) {
update_representative(sa->head, sb->head);
sb->tail->next = sa->head;
sa->head = sb->head;
} else {
update_representative(sb->head, sa->head);
sa->tail->next = sb->head;
sa->tail = sb->tail;
}
sa->num += sb->num;
}
void set_destroy(set s, void (*free_key) (void *))
{
free_key(s->head->key);
free(s->head);
free(s);
}
struct edge {
char u;
char v;
};
int main()
{
//数据根据书上图21-1
char vertex[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
set s[256] = { NULL };
struct edge edge_array[] = { {'b', 'd'}, {'e', 'g'}, {'a', 'c'},
{'h', 'i'}, {'a', 'b'}, {'e', 'f'}, {'b', 'c'}
};
int vertex_num = sizeof(vertex) / sizeof(vertex[0]);
for (int i = 0; i < vertex_num; i++) {
char *c = malloc(sizeof(char));
*c = vertex[i];
s[(int)vertex[i]] = set_create(c);
}
//计算连通子图
for (unsigned i = 0; i < sizeof(edge_array) / sizeof(edge_array[0]);
i++) {
set su = s[(int)edge_array[i].u];
set sv = s[(int)edge_array[i].v];
if (find_set(su) != find_set(sv)) {
set_union(su, sv);
}
}
//输出连通子图
char str_set[256][256] = { {0} };
for (int i = 0; i < vertex_num; i++) {
char *pc = find_set(s[(int)vertex[i]])->key;
int len = strlen(str_set[(int)*pc]);
str_set[(int)*pc][len] = vertex[i];
}
printf("输出不相交集合组:\n");
for (int i = 0; i < vertex_num; i++) {
if (strcmp(str_set[(int)vertex[i]], "") != 0) {
printf("%s\n", str_set[(int)vertex[i]]);
}
}
for (int i = 0; i < vertex_num; i++) {
set sv = s[(int)vertex[i]];
set_destroy(sv, free);
}
return 0;
}
21.3 不相交集合森林
#include
#include
#include
typedef struct set_type *set;
struct set_node {
void *key;
int rank;
struct set_node *parent;
};
void set_node_ini(struct set_node *x, void *key)
{
x->key = key;
x->rank = 0;
x->parent = NULL;
}
struct set_type {
struct set_node *root;
};
set set_create(void *key)
{
set s = malloc(sizeof(struct set_type));
s->root = malloc(sizeof(struct set_node));
set_node_ini(s->root, key);
s->root->parent = s->root;
s->root->rank = 0;
return s;
}
void link(struct set_node *x, struct set_node *y)
{
if (x->rank > y->rank) {
y->parent = x;
} else {
x->parent = y;
if (x->rank == y->rank) {
++y->rank;
}
}
}
struct set_node *find_set_path_compression(struct set_node *x)
{
if (x != x->parent) {
x->parent = find_set_path_compression(x->parent);
}
return x->parent;
}
struct set_node *find_set(set s)
{
return find_set_path_compression(s->root);
}
void set_destroy(set s, void (*free_key) (void *))
{
free_key(s->root->key);
free(s->root);
free(s);
}
void set_union(set sa, set sb)
{
link(find_set(sa), find_set(sb));
}
struct edge {
char u;
char v;
};
int main()
{
//数据根据书上图21-1
char vertex[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
set s[256] = { NULL };
struct edge edge_array[] = { {'b', 'd'}, {'e', 'g'}, {'a', 'c'},
{'h', 'i'}, {'a', 'b'}, {'e', 'f'}, {'b', 'c'}
};
int vertex_num = sizeof(vertex) / sizeof(vertex[0]);
for (int i = 0; i < vertex_num; i++) {
char *c = malloc(sizeof(char));
*c = vertex[i];
s[(int)vertex[i]] = set_create(c);
}
//计算连通子图
for (unsigned i = 0; i < sizeof(edge_array) / sizeof(edge_array[0]);
i++) {
set su = s[(int)edge_array[i].u];
set sv = s[(int)edge_array[i].v];
if (find_set(su) != find_set(sv)) {
set_union(su, sv);
}
}
//输出连通子图
char str_set[256][256] = { {0} };
for (int i = 0; i < vertex_num; i++) {
char *pc = find_set(s[(int)vertex[i]])->key;
int len = strlen(str_set[(int)*pc]);
str_set[(int)*pc][len] = vertex[i];
}
printf("输出不相交集合组:\n");
for (int i = 0; i < vertex_num; i++) {
if (strcmp(str_set[(int)vertex[i]], "") != 0) {
printf("%s\n", str_set[(int)vertex[i]]);
}
}
for (int i = 0; i < vertex_num; i++) {
set sv = s[(int)vertex[i]];
set_destroy(sv, free);
}
return 0;
}