并查集的简单实现与相关例子展示
- 初始化,初始化并查集
- 合并集合,合并两个节点所在的集合
- 查找节点所在集合,查找某一个节点归属哪一个集合
- 相关应用,商品分类,将并查集运用于商品分类管理中
-
#include <iostream> const int M=1000;//定义并查集的最大容量 int pre[M];//用于储存节点的前驱 int high[M];//用于储存节点的高度 bool initialize(int n);//初始化函数,用于对并查集进行初始化,返回bool类型 int find_p(int n);//查找函数(运用了路径压缩) bool judge(int a, int b);//判断函数,判断两个节点是否属于同一集合的函数 int merge(int a, int b);//合并函数,用于合并两个集合 void yuansu(int n[], int h[]);//应用模块初始化函数,用于导入应用数据 void prin(int i);//应用模块输出函数,用于输出商品所属的类 int main()//程序主函数 { printf("欢迎使用并查集演示程序!\n"); int n, i , c=1; int f, a, b; printf("请输入集合的节点数目:"); scanf("%d", &n); if (initialize(n))//初始化,选择初始化的容量大小 { printf("初始化成功!\n"); } else { printf("初始化失败!\n"); } system("pause");//按任意键继续 system("cls");//清屏函数 while (c == 1)//循环,如果不主动选择退出会一直重复菜单 { int fu;//定义一个变量来操作菜单 printf("* 功能面板 *\n"); printf("*______________________________________________*\n"); printf("* 1.查找单个节点的根节点 \n"); printf("* 2.查看两个节点是否属于同一集合 \n"); printf("* 3.合并两个节点所在的集合 \n"); printf("* 4.退出 \n"); printf("*______________________________________________*\n"); printf("请输入要进行的操作:"); scanf("%d", &fu); switch (fu)//运用switch函数来实现对不同功能的控制 { case 1://查找功能,调用查找函数 printf("请输入要查找的节点:"); scanf("%d", &f); i = find_p(f); printf("该节点的根节点为:%d\n", f); break; case 2://查找两个节点是否属于同一个集合的功能,调用判断函数 printf("请输入要查找的两个节点:\n"); scanf("%d %d", &a, &b); if (judge(a, b)) { printf("根节点一致!\n"); } else { printf("根节点不一致!\n"); } break; case 3://合并集合功能,调用合并函数 printf("请输入要合并的两个节点:\n"); scanf("%d %d", &a, &b); if (merge(a, b)) { printf("合并成功!\n"); } else { printf("合并失败!\n"); } break; case 4://输入4结束程序 c = 0; break; } system("pause");//按任意键继续 system("cls");//清屏函数 } c = 1; initialize(100);//对并查集进行初始化 yuansu(pre,high); while (c == 1)//和上述菜单一样的循环操作,需要输入4才会停止 { int fu; printf("* 应用:商品分类 *\n"); printf("*______________________________________________*\n"); printf("* 1.查找第n号商品属于哪一类(n>0&&n<=100) \n"); printf("* 2.查看两个商品是否属于同一类 \n"); printf("* 3.合并两个商品所在的类 \n"); printf("* 4.退出 \n"); printf("*______________________________________________*\n"); printf("请输入要进行的操作:"); scanf("%d", &fu); switch (fu) { case 1://查找功能,调用查找函数和输出函数 printf("请输入要查找的商品的序号:"); scanf("%d", &f); i = find_p(f); prin(i); break; case 2://调用判断函数 printf("请输入要查找的两件商品的序号:\n"); scanf("%d %d", &a, &b); if (judge(a, b)){ printf("两件商品属于同一类!\n"); } else { printf("两件商品不属于同一类!\n"); } break; case 3://调用合并函数 printf("请输入要合并的两个类中的任意两件商品:\n"); scanf("%d %d", &a, &b); if (merge(a, b)) { printf("合并成功!\n"); } else { printf("合并失败!\n"); } break; case 4://退出 c = 0; break; } system("pause");//按任意键继续 system("cls");//清屏函数 } return 0; } bool initialize(int n)//初始化函数,用于对并查集进行初始化,返回bool类型 { int i; for (i = 0; i < n; i++)//对每个节点进行初始化,每个节点的上级都是自己 { pre[i] = i; high[i] = 1; } if (pre[i - 1] == i - 1 && high[i - 1] == 1)//判断是否初始化成功,并返回一个bool类型 { return true; } else { return false; } } int find_p(int n)//查找函数(运用了路径压缩) { if (pre[n] == n)//递归结束条件,该节点的上级为自己,也就是找到了该集合的代表节点 { return n;//返回代表节点的序号 } return pre[n] = find_p(pre[n]);//递归查找节点的上级,并进行优化,使节点的上级指向该集合的代表节点 } bool judge(int a, int b)//判断函数,判断两个节点是否属于同一集合的函数 { if (find_p(a) == find_p(b))//调用查找函数,查看两个节点所属集合的代表节点是否相同 { return true;//相同,则返回true } else { return false;//不相同。则返回false } } int merge(int a, int b)//合并函数,用于合并两个集合 { a = find_p(a);//查找a所在集合的代表节点 b = find_p(b);//查找b所在集合的代表节点 if (a == b)//判断a和b是否属于同一个集合 { return 0;//如果a和b相同,则a,b属于同一个集合,不需要合并,直接返回false } if (high[a] > high[b])//比较两个集合的高度,尽可能的使合并后的集合简洁 { pre[b] = a; } else { pre[a] = b; } return 1; } void yuansu(int n[], int h[])//应用模块初始化函数,用于导入应用数据 { int i, j = 1; for (i = 1; i <= 100; i++)//这里先默认让10个商品为一类 { n[i] = j; if (i % 10 == 0)//每十个商品以第一个商品为代表 { j += 10; } } } void prin(int i)//应用模块输出函数,用于输出商品所属的类 { int k = 0; while (i != 0)//计算该商品属于第几类 { k = k + i % 10; i /= 10; } printf("该商品属于第%d类。\n", k); }