在上一篇“连通性问题”中已经对这个问题进行来介绍,在这一篇中给出针对以上问题的改进,在代码中已经对原理进行来注释。
加权快速合并算法
1 /** 2 * @file weightedquickunion.c 3 * @brief 加权快速合并算法 4 * 在合并操作中,不是任意把第二棵树连接到第一棵树上,而是记录每棵树中的节点数, 5 * 总是把较小的树连接到较大的树上。这个程序是对快速合并算法的改进,用另一个数组 6 * sz记录每个id[i]==i的对象所在树中的节点数,使得合并操作能够将较小的树连接到 7 * 较大的树上,以防止树中长路经的增长。 8 * @date 2015-01-15 9 */ 10 #include <stdio.h> 11 #define N 1000 12 13 int main(void) 14 { 15 int i, j, p, q; 16 int id[N], sz[N]; 17 //初始化数组元素的初始值 18 for (i = 0; i < N; i++) 19 { 20 id[i] = i; 21 sz[i] = 1; 22 } 23 //循环读入整数对 24 while (scanf("%d-%d", &p, &q) == 2) 25 { 26 //查找p的根节点 27 for (i = p; i != id[i]; i = id[i]); 28 //查找q的根节点 29 for (j = q; j != id[j]; j = id[j]); 30 //如果p和q指向同一个根节点,则从标准输入读取下一对整数对 31 if (i == j) continue; 32 //否则,将p和q各自所在的树合并成一棵树 33 if (sz[i] < sz[j]) 34 {//q所在的树较大 35 id[i] = j; //将p所在的树连接到q所在树的根节点 36 sz[j] += sz[i];//q所在树的根节点存储的节点数在原基础上增加p所在树的节点数 37 } 38 else 39 {//p所在的树较大 40 id[j] = i; //将q所在的树连接到p所在树的根节点 41 sz[i] += sz[j];//p所在树的根节点存储的节点数在原基础上增加q所在树的节点数 42 } 43 printf("New Pair: %d-%d ", p, q); 44 } 45 46 return 0; 47 }
路径压缩算法
1 /** 2 * @file pathcompression.c 3 * @brief 带路径压缩的加权快速合并算法 4 * 在合并操作中,不是任意把第二棵树连接到第一棵树上,而是记录每棵树中的节点数, 5 * 总是把较小的树连接到较大的树上。这个程序是对快速合并算法的改进,用另一个数组 6 * sz记录每个id[i]==i的对象所在树中的节点数,使得合并操作能够将较小的树连接到 7 * 较大的树上,以防止树中长路经的增长。 8 * @brief 路径压缩:在合并操作过程中,添加经过每条路径的另一个指针,使沿路遇见的每个定 9 * 点对应的id元素指向树的根节点。因为对于较短的路径,路径压缩没有多大作用,因此 10 * 在执行合并时,我们只对较大的树执行路径压缩,使经过的每个节点直接指向新的根节点。 11 * @brief 等分路径压缩:它通过使每条链接跳跃到树中向上节点的再向上一个节点来实现压缩。 12 * @date 2015-01-15 13 */ 14 #include <stdio.h> 15 #define N 1000 16 #if 0 17 #define PATH_COMPRESSION //路径压缩 18 #else 19 #define EQUAL_PATHCOMPRESSION //等分路径压缩 20 #endif // 0 21 22 int main(void) 23 { 24 int i, j, p, q, index; 25 int id[N], sz[N]; 26 //初始化数组元素的初始值 27 for (i = 0; i < N; i++) 28 { 29 id[i] = i; 30 sz[i] = 1; 31 } 32 //循环读入整数对 33 while (scanf("%d-%d", &p, &q) == 2) 34 { 35 #ifdef EQUAL_PATHCOMPRESSION 36 //查找p的根节点 37 for (i = p; i != id[i]; i = id[i]) 38 id[i] = id[id[i]]; 39 //查找q的根节点 40 for (j = q; j != id[j]; j = id[j]); 41 id[j] = id[id[j]]; 42 #else 43 //查找p的根节点 44 for (i = p; i != id[i]; i = id[i]); 45 //查找q的根节点 46 for (j = q; j != id[j]; j = id[j]); 47 #endif // EQUAL_PATHCOMPRESSION 48 49 //如果p和q指向同一个根节点,则从标准输入读取下一对整数对 50 if (i == j) continue; 51 //否则,将p和q各自所在的树合并成一棵树 52 if (sz[i] < sz[j]) 53 {//q所在的树较大 54 id[i] = j; //将p所在的树连接到q所在树的根节点 55 sz[j] += sz[i];//q所在树的根节点存储的节点数在原基础上增加p所在树的节点数 56 #ifdef PATH_COMPRESSION 57 //对较大的树进行路径压缩 58 for (i = q; i != id[i];) 59 { 60 index = i; //存储当前节点号 61 i = id[i]; //存储当前节点的父节点号 62 id[index] = j; //当前节点指向新树的根节点 63 } 64 #endif // PATH_COMPRESSION 65 } 66 else 67 {//p所在的树较大 68 id[j] = i; //将q所在的树连接到p所在树的根节点 69 sz[i] += sz[j];//p所在树的根节点存储的节点数在原基础上增加q所在树的节点数 70 #ifdef PATH_COMPRESSION 71 //对较大的树进行路径压缩 72 for (j= p; j != id[j];) 73 { 74 index = j; //存储当前节点号 75 j = id[j]; //存储当前节点的父节点号 76 id[index] = i; //当前节点指向新树的根节点 77 } 78 #endif // PATH_COMPRESSION 79 } 80 printf("New Pair: %d-%d ", p, q); 81 } 82 83 return 0; 84 }