数据结构课程设计实验报告(并查集)
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
3. 代码简介: (1) Find 函数,用来查找某节点所在的集合,需要一个整形参数(节点的 编号),返回一个整形值。(所在集合的头节点的编号) (2) min 函数,用来连接输入的两个节点所在的集合,需要两个整形参数 (两个节点的编号),无返回值。 (3) chushihua 函数,用来创建新的并查集,需要两个整形参数(分别是 节点的个数和连接节点的通道的数目),无返回值。 (4) count 函数,用来计算并查集含有集合的个数,需要一个整形参数(节 点的个数),返回一个整形值。(并查集含有集合的个数) (5) 代码能实现并查集的创建,初始化,合并集合,查找节点所在集 合和计算并查集中所含集合的数目。
生成的并查集图为:
合并后并查集图为:
初始化后并查集的图:
合并后并查集的图:
2. 调试遇到的问题: 基本没遇到什么大问题,只是有很多输入语句后面没加分号,输入语句没加 取地址之类的小错误。
3. 经验体会: 这是第一次自己在没有人指点的情况下自己去学习一种数据结构,刚刚开始 会觉得可能会很难,抱着恐惧的心情去上网查找资料,不过在找到资料后, 认真阅读了一遍,发现没有想象中恐怖和困难,挺简单的,看了几遍就懂了 并查集是什么和并查集的基本操作,觉得自己还是挺厉害的(自夸)。 在我们计算机类,自学是很重要的,计算机专业知识更新快,书本上的知识 只是基础而且很微不足道,我们要学会自己查找资料自学,不要恐惧自学, 没试过就不知道难易程度,不要被听起来很可怕名字吓到,就像这次,自学 了才发现原来并查集没有自己想象的那么困难。
4.由主函数中接受到参数 x 给 Find 函数,函数通过对 pre 数组的下标是否和数组的 内容相等,从而判断该节点是否是根节点,找到后根节点的编号返回给主函数。
5. 由主函数接受到参数 x,y 给 mix 函数,函数通过 Find 函数分别找到 x 和 y 的根节 点,然后通过把 y 所在集合的根节点的数组值改成 x 所在集合根节点的数组下标, 从而使得 x 所在集合的根节点成为 y 所在集合的根结点的上级。从而把两个集合合 并。
void mix(int x,int y) // { int fx=Find(x),fy=Find(y); if(fx!=fy) {
pre[fy]=fx; } }
合并结合
int chushihua(int N,int M) //
初始化
{
int a,b,i; //N 节点的个数 M 连接通道的数目
for(i=1;i<=N;i++) pre[i]=i;
scanf("%d",&d);
switch(d)
{
case 1:printf("\n");
printf("
输入并查集的节点个数: ");
scanf("%d",&N);
printf("
输入并查集中连接节点的通道的个数: ");
scanf("%d",&M);
chushihua(N,M);break;
case 2:printf("\n");
for(i=1;i<=M;i++)
//
吸收并整理数据
{
printf("
输入第%d条通道连接的两个个节点: ",i);
scanf("%d%d",&a,&b);
mix(a,b);
}
}
int count(int N)
//
{
有多少个集合
int ans,i;
memset(t,0,sizeof(t));
for(i=1;i<=N;i++)
{ // 下面这段代码,其实就是 join 函数,只是稍作改动以适应题目要
求
//
每读入一条路,看它的端点 p1,p2 是否已经在一个连通分支里
了
scanf("%d %d",&p1,&p2);
f1=find(p1);
f2=find(p2);
//
如果是不连通的,那么把这两个分支连起来
//
分支的总数就减少了 1,还需建的路也就减了 1
候,有 n 个城镇,一条路都没有 // 那么要修 n-1 条路才能把它们连
起来
total=n-1;
// 每个点互相独立,自成一个集合,从 1 编号到 n // 所以每个点的上
级都是自己
for(i=1;i<=n;i++) { pre[i ]=i; }
//
共有 m条路
scanf("%d",&m); while(m--)
二. 解题思路:
1. 创建两个数组 pre 和 t , pre 数组下标用于表示节点的编号,数组内容 表示节点的上级。 t 用于标记独立块的根结点
2. 首先定义出主函数的基本框架流程,用 while 和 switch 函数来实习功 能的选择
3. 由主函数中接收到参数 N、M给 chushihua 函数,然后函数用 for 循环给 pre 数组 赋值,使得并查集中每个节点都编好号而且每个节点自己成为一个集合,然后用 mix 函数把需要连接的节点连起来,创建出一个新的并查集。
一. 题目要求 :
1. 实验的要求: 本次实验题目要求是实现并查集的初始化、合并集合、查找节点所在 集合和与并查集相关的应用的实现。
2. 并查集的简介: 在一些问题中, 我们需要划分n个不同的元素成若干组, 每一组的元素 构成一个集合。这种问题的一个解决办法是,在开始时,让每个元素自成一 个单元集合,然后按一定顺序将属于同一组的元素所在的集合合并。期间要反 复用到查找一个元素属于哪一个集合的运算。适合于描述这类问题的抽象数据 类型称为并查集(union-find sets)
printf("
输入通道连接的两个个节点: ");
scanf("%d%d",&a,&b);
mix(a,b);
printf(" 合并成功\n");break;
case 3:printf("\n");
while(c!=0){
printf("
请输入要查找的节点, 输入 0 退出查找:");
scanf("%d",&c);
6. 由主函数接受到参数 N给 count 函数,用 for 循环把各个节点遍历,如果第 i 个节 点是根节点,就把第 i 个节点所在的 t 数组的值赋值为 1,否则为 0,然后用 ans 标志 t 数组中 1 的个数。最后把 ans 返回给主函数。
该代码用了线性表的数据结构。
三. 调试分析:
1. 代码演示:
解题代码: #include <iostream> #include <stdio.h> #include <stdlib.h> int pre[1000 ];
using namespace std;
int find(int x)
{
int r=x;
while (pre[r ]!=r)
r=pre[r ];
华南农业大学信息学院
课程设计实验
学院
数学 与 信息 学
班级 14 网工 1
学号 201430350114 姓名 赖文杰
院
实
验
题 ■设计性 □综合性
目
代码直观,有调理,按时完成,独立完成,实验报告详细,还添加了其他功能,不
自 过注释不过详细,表达能力不好,部分代码直接照抄网上,总体良好。
我
评
价
能够实现实验要求的功能
e=Find(c);
printf("
节点所在集合为%d\n",e);}c=100;break;
case 4:printf("\n");
f=count(N);
printf("
并查集中集合的个数为: %d\n",f);break;
case 0:break;
default:printf("\n");
printf(" } }
int pre[1050]; // bool t[1050]; //t
用于存储节点 用于标记独立块的根结点
int Find(int x) // { int r=x; while(r!=pre[r])
r=pre[r];
查找节点所在集合
int i=x,j; while(pre[i]!=r) {
j=pre[i]; pre[i]=r; i=j; } return r; }
//
{
t[Find(i)]=1;
}
for(ans=0,i=1;i<=N;i++)
if(t[i])
ans++;
标记根结点
return ans; }
int main()
{
int a,b,c,d,N,M,e,f;
printf(" 首先创建一个并查集 \n");
printf(" 输入并查集的节点个数:");
四. 相关应用:
题目表述:设地图中有若干做城镇,每个城镇可以看作一个点,城镇间有若干 条路,试求还需要多少条路才能使全地图联通。 输入格式 第一行输入两个整数个 n,m,表述有 n 个城镇,m条路。 接下来 m行,每行输入每条路联通的城镇。 输出格式
输出联通全地图所需路的条数。 输入样例 53 12 23 45 输出样例 1
scanf("%d",&N);
printf(" 输入并查集中连接节点的通道的个数: ");
Fra Baidu bibliotek
scanf("%d",&M);
chushihua(N,M);
printf(" 创建完毕\n");
while(d!=0){
printf("\n 请输入要执行的功能 \n1. 初始化\n2. 合并结合\n");
printf("3. 找节点所在集合 \n4. 并查集中集合的个数\n0. 退出\n\n");
int i=x; int j;
while(i!=r)
{
j=pre[i ];
pre[i ]=r;
i=j;
}
return r;
}
int main()
{
int n,m,p1,p2,i,total,f1,f2;
while(scanf("%d",&n) && n) //
读入 n,如果 n 为 0,结束
{
//
刚开始的时
return 0; }
请输入正确的选项");break;
。
if(f1!=f2)
{
pre[f2 ]=f1;
total--;
}
//
如果两点已经连通了,那么这条路只是在图上增加了一个环 //
对连通性没有任何影响,无视掉
}
// 最后输出还要修的路条数
printf("%d\n",total);
}
return 0;
}
五. 附录:
源代码:#include<iostream> #include <stdio.h> #include <stdlib.h> #include<cstring> using namespace std;
算法有新意
教
程序运行通过
师
算法注释说明
评
接口参数说明
语
按期上交文档资料及源程序
独立完成实验
体现团队合作精神。
成
绩
√ 全部 □部分 √ 有 □一般 √ 全部 □部分 √ 完善 □仅有功能说明 √ 有 □无 √ 所有 □部分 √ 能 □不能 √ 能够 □不能
实验题目:并查集 班级: 14 网络工程一班
姓名:赖文杰 学号: 201430350114 完成日期: 2015/9/30
生成的并查集图为:
合并后并查集图为:
初始化后并查集的图:
合并后并查集的图:
2. 调试遇到的问题: 基本没遇到什么大问题,只是有很多输入语句后面没加分号,输入语句没加 取地址之类的小错误。
3. 经验体会: 这是第一次自己在没有人指点的情况下自己去学习一种数据结构,刚刚开始 会觉得可能会很难,抱着恐惧的心情去上网查找资料,不过在找到资料后, 认真阅读了一遍,发现没有想象中恐怖和困难,挺简单的,看了几遍就懂了 并查集是什么和并查集的基本操作,觉得自己还是挺厉害的(自夸)。 在我们计算机类,自学是很重要的,计算机专业知识更新快,书本上的知识 只是基础而且很微不足道,我们要学会自己查找资料自学,不要恐惧自学, 没试过就不知道难易程度,不要被听起来很可怕名字吓到,就像这次,自学 了才发现原来并查集没有自己想象的那么困难。
4.由主函数中接受到参数 x 给 Find 函数,函数通过对 pre 数组的下标是否和数组的 内容相等,从而判断该节点是否是根节点,找到后根节点的编号返回给主函数。
5. 由主函数接受到参数 x,y 给 mix 函数,函数通过 Find 函数分别找到 x 和 y 的根节 点,然后通过把 y 所在集合的根节点的数组值改成 x 所在集合根节点的数组下标, 从而使得 x 所在集合的根节点成为 y 所在集合的根结点的上级。从而把两个集合合 并。
void mix(int x,int y) // { int fx=Find(x),fy=Find(y); if(fx!=fy) {
pre[fy]=fx; } }
合并结合
int chushihua(int N,int M) //
初始化
{
int a,b,i; //N 节点的个数 M 连接通道的数目
for(i=1;i<=N;i++) pre[i]=i;
scanf("%d",&d);
switch(d)
{
case 1:printf("\n");
printf("
输入并查集的节点个数: ");
scanf("%d",&N);
printf("
输入并查集中连接节点的通道的个数: ");
scanf("%d",&M);
chushihua(N,M);break;
case 2:printf("\n");
for(i=1;i<=M;i++)
//
吸收并整理数据
{
printf("
输入第%d条通道连接的两个个节点: ",i);
scanf("%d%d",&a,&b);
mix(a,b);
}
}
int count(int N)
//
{
有多少个集合
int ans,i;
memset(t,0,sizeof(t));
for(i=1;i<=N;i++)
{ // 下面这段代码,其实就是 join 函数,只是稍作改动以适应题目要
求
//
每读入一条路,看它的端点 p1,p2 是否已经在一个连通分支里
了
scanf("%d %d",&p1,&p2);
f1=find(p1);
f2=find(p2);
//
如果是不连通的,那么把这两个分支连起来
//
分支的总数就减少了 1,还需建的路也就减了 1
候,有 n 个城镇,一条路都没有 // 那么要修 n-1 条路才能把它们连
起来
total=n-1;
// 每个点互相独立,自成一个集合,从 1 编号到 n // 所以每个点的上
级都是自己
for(i=1;i<=n;i++) { pre[i ]=i; }
//
共有 m条路
scanf("%d",&m); while(m--)
二. 解题思路:
1. 创建两个数组 pre 和 t , pre 数组下标用于表示节点的编号,数组内容 表示节点的上级。 t 用于标记独立块的根结点
2. 首先定义出主函数的基本框架流程,用 while 和 switch 函数来实习功 能的选择
3. 由主函数中接收到参数 N、M给 chushihua 函数,然后函数用 for 循环给 pre 数组 赋值,使得并查集中每个节点都编好号而且每个节点自己成为一个集合,然后用 mix 函数把需要连接的节点连起来,创建出一个新的并查集。
一. 题目要求 :
1. 实验的要求: 本次实验题目要求是实现并查集的初始化、合并集合、查找节点所在 集合和与并查集相关的应用的实现。
2. 并查集的简介: 在一些问题中, 我们需要划分n个不同的元素成若干组, 每一组的元素 构成一个集合。这种问题的一个解决办法是,在开始时,让每个元素自成一 个单元集合,然后按一定顺序将属于同一组的元素所在的集合合并。期间要反 复用到查找一个元素属于哪一个集合的运算。适合于描述这类问题的抽象数据 类型称为并查集(union-find sets)
printf("
输入通道连接的两个个节点: ");
scanf("%d%d",&a,&b);
mix(a,b);
printf(" 合并成功\n");break;
case 3:printf("\n");
while(c!=0){
printf("
请输入要查找的节点, 输入 0 退出查找:");
scanf("%d",&c);
6. 由主函数接受到参数 N给 count 函数,用 for 循环把各个节点遍历,如果第 i 个节 点是根节点,就把第 i 个节点所在的 t 数组的值赋值为 1,否则为 0,然后用 ans 标志 t 数组中 1 的个数。最后把 ans 返回给主函数。
该代码用了线性表的数据结构。
三. 调试分析:
1. 代码演示:
解题代码: #include <iostream> #include <stdio.h> #include <stdlib.h> int pre[1000 ];
using namespace std;
int find(int x)
{
int r=x;
while (pre[r ]!=r)
r=pre[r ];
华南农业大学信息学院
课程设计实验
学院
数学 与 信息 学
班级 14 网工 1
学号 201430350114 姓名 赖文杰
院
实
验
题 ■设计性 □综合性
目
代码直观,有调理,按时完成,独立完成,实验报告详细,还添加了其他功能,不
自 过注释不过详细,表达能力不好,部分代码直接照抄网上,总体良好。
我
评
价
能够实现实验要求的功能
e=Find(c);
printf("
节点所在集合为%d\n",e);}c=100;break;
case 4:printf("\n");
f=count(N);
printf("
并查集中集合的个数为: %d\n",f);break;
case 0:break;
default:printf("\n");
printf(" } }
int pre[1050]; // bool t[1050]; //t
用于存储节点 用于标记独立块的根结点
int Find(int x) // { int r=x; while(r!=pre[r])
r=pre[r];
查找节点所在集合
int i=x,j; while(pre[i]!=r) {
j=pre[i]; pre[i]=r; i=j; } return r; }
//
{
t[Find(i)]=1;
}
for(ans=0,i=1;i<=N;i++)
if(t[i])
ans++;
标记根结点
return ans; }
int main()
{
int a,b,c,d,N,M,e,f;
printf(" 首先创建一个并查集 \n");
printf(" 输入并查集的节点个数:");
四. 相关应用:
题目表述:设地图中有若干做城镇,每个城镇可以看作一个点,城镇间有若干 条路,试求还需要多少条路才能使全地图联通。 输入格式 第一行输入两个整数个 n,m,表述有 n 个城镇,m条路。 接下来 m行,每行输入每条路联通的城镇。 输出格式
输出联通全地图所需路的条数。 输入样例 53 12 23 45 输出样例 1
scanf("%d",&N);
printf(" 输入并查集中连接节点的通道的个数: ");
Fra Baidu bibliotek
scanf("%d",&M);
chushihua(N,M);
printf(" 创建完毕\n");
while(d!=0){
printf("\n 请输入要执行的功能 \n1. 初始化\n2. 合并结合\n");
printf("3. 找节点所在集合 \n4. 并查集中集合的个数\n0. 退出\n\n");
int i=x; int j;
while(i!=r)
{
j=pre[i ];
pre[i ]=r;
i=j;
}
return r;
}
int main()
{
int n,m,p1,p2,i,total,f1,f2;
while(scanf("%d",&n) && n) //
读入 n,如果 n 为 0,结束
{
//
刚开始的时
return 0; }
请输入正确的选项");break;
。
if(f1!=f2)
{
pre[f2 ]=f1;
total--;
}
//
如果两点已经连通了,那么这条路只是在图上增加了一个环 //
对连通性没有任何影响,无视掉
}
// 最后输出还要修的路条数
printf("%d\n",total);
}
return 0;
}
五. 附录:
源代码:#include<iostream> #include <stdio.h> #include <stdlib.h> #include<cstring> using namespace std;
算法有新意
教
程序运行通过
师
算法注释说明
评
接口参数说明
语
按期上交文档资料及源程序
独立完成实验
体现团队合作精神。
成
绩
√ 全部 □部分 √ 有 □一般 √ 全部 □部分 √ 完善 □仅有功能说明 √ 有 □无 √ 所有 □部分 √ 能 □不能 √ 能够 □不能
实验题目:并查集 班级: 14 网络工程一班
姓名:赖文杰 学号: 201430350114 完成日期: 2015/9/30