本文是基于《算法(第四版)》中的Union Find讲解,采用C语言实现了Quick Find和Quick Union。
1. 概述
给定N个对象,dynamic connectivity主要研究以下两个问题:
1. 判断p和q是否相连。
2. 连接两个对象p和q。
在建立模型时采用一维数组存放0~N-1个对象的信息,这样可以简化很多很UF无关的细节。
2. Quick Find
假设把0~N-1个对象放在数组id[ ]中,每次读进来一对(p,q)时,如果相连的话就continue,如果不相连则通过把id[p]的内容改为id[q]的内容使它们连接起来。此时第1节中的两个问题等价于:
1. id[p] ?= id[q]
2. 把所有的id[p]都换成id[q]
代码如下:
#include <stdio.h>
#include <malloc.h>
bool query(int* id, int p, int q)
{
//判断id[p]和id[q]是否连通,是返回1,否返回0
return *(id + p) == *(id + q);
}
void union_command(int *id, int N, int p, int q)
{
int k;
int idp = *(id + p);
int idq = *(id + q);
for (k = 0; k < N; k++)
{
if (*(id + k) == idp)
*(id + k) = idq;
}
}
int main()
{
int N;
int *id;
int i, p, q;
printf("Input node number:\n");
scanf_s("%d", &N);
id = (int*)malloc(N*sizeof(int));
//初始化
for (i = 0; i < N; i++)
*(id + i) = i;
//接受输入对,判断是否连通,若否创建连接
while (scanf_s("%d %d", &p, &q) == 2)
{
if (!query(id, p, q))
{
//union_command(id, N, p, q);
union_command(id, p, q);
}
//将数组打印出来看一下
for (i = 0; i < N; i++)
printf("%d ", *(id + i));
printf("\n");
}
return 0;
}
测试时可以采用书上的例子:
3. Quick Union
Quick Find的缺陷在于每次要把id[p]换成id[q]的时候都需要遍历数组。Quick Union相当于Quick Find的改进算法,目的在于减少遍历次数。具体做法就是把数组中的元素看作是树中的parent。这样第1节中的两个问题转化为:
1. 判断p和q是否具有同一个root。
2. union的时候把p的root改为q的root。
代码中只需要改union_command函数:
void union_command(int *id, int p, int q)
{
int i, j;
for (i = p; i != *(id + i); i = *(id + i));
for (j = q; j != *(id + j); j = *(id + j));
if (i != j)
*(id + i) = j;
}
测试时可以采用书上的例子: