克鲁斯卡尔算法实验报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验报告
实验原理:
Kruskal 算法是一种按照图中边的权值递增的顺序构造最小生成树的方法。其基本思想是:设无向连通网为G=(V,E),令G 的最小生成树为T,其初态为T=(V,{}),即开始时,最小生成树T 由图G 中的n 个顶点构成,顶点之间没有一条边,这样T 中各顶点各自构成一个连通分量。然后,按照边的权值由小到大的顺序,考察G 的边集E 中的各条边。若被考察的边的两个顶点属于T 的两个不同的连通分量,则将此边作为最小生成树的边加入到T 中,同时把两个连通分量连接为一个连通分量;若被考察边的两个顶点属于同一个连通分量,则舍去此边,以免造成回路,如此下去,当T 中的连通分量个数为1 时,此连通分量便为G 的一棵最小生成树。
如教材153页的图4.21(a)所示,按照Kruskal 方法构造最小生成树的过程如图 4.21 所示。在构造过程中,按照网中边的权值由小到大的顺序,不断选取当前未被选取的边集中权值最小的边。依据生成树的概念,n 个结点的生成树,有n-1 条边,故反复上述过程,直到选取了n-1 条边为止,就构成了一棵最小生成树。
实验目的:
本实验通过实现最小生成树的算法,使学生理解图的数据结构存储表示,并能理解最小生成树Kruskal 算法。通过练习,加强对算法的理解,提高编程能力。
实验内容:
(1)假定每对顶点表示图的一条边,每条边对应一个权值;
(2)输入每条边的顶点和权值;
(3)输入每条边后,计算出最小生成树;
(4)打印最小生成树边的顶点及权值。
实验器材(设备、元器件):
PC机一台,装有C语言集成开发环境。
数据结构与程序:
#include
#include
#include
using namespace std;
#define X 105
typedef struct Edge
{
int w;
int x, y;
} Edge; //储存边的struct,并储存边两端的结点
class GraphNode
{
public:
int data;
int father;
int child;
} GraphNode[X]; //储存点信息的并查集类(点的值,父结点,子结点)Edge edge[X*X];
bool comp(const Edge, const Edge);
void update(int);
int main()
{
int node_num;
int sum_weight = 0;
FILE *in = fopen("C:\\Users\\瑞奇\\Desktop\\编程实验\\数据结构实验\\FileTemp\\in.txt", "r");
cout << "Reading data from file..." << endl << endl;
//cout << "Please input the total amount of nodes in this Graph: ";
//cin >> node_num;
fscanf(in, "%d", &node_num);
//cout << "Please input the data of each node: " << endl;
for(int i = 1;i <= node_num;i++)
{
//cin >> GraphNode[i].data;
fscanf(in, "%d", &GraphNode[i].data);
GraphNode[i].father = GraphNode[i].child = i;
} //初始化点集
//cout << "Please input the relation between nodes in this format and end with (0 0 0):" << endl << "(first_node second_node egde_weight)" << endl;
int x, y, w, tmp_cnt = 1;
//while(cin >> x >> y >> w && w)
while(fscanf(in, "%d%d%d", &x, &y, &w) != EOF && w)
edge[tmp_cnt].w = w, edge[tmp_cnt].x = x, edge[tmp_cnt++].y = y;
fclose(in);
sort(edge+1, edge+tmp_cnt, comp); //对边权进行排序
cout << "The MinSpanTree contains following edges: " << endl << endl;
for(int i = 1;i <= tmp_cnt;i++) //循环找最小边
if(GraphNode[edge[i].x].father != GraphNode[edge[i].y].father)
{
int n = edge[i].x;
int m = n;
if(GraphNode[m].father != m) //使用并查集对边是否可用进行判断
{
m = GraphNode[m].father;
GraphNode[m].father = GraphNode[edge[i].y].father;
}
GraphNode[edge[i].x].father = GraphNode[edge[i].y].father;
GraphNode[edge[i].y].child = GraphNode[edge[i].x].child;
while(GraphNode[n].child != n)
n = GraphNode[n].child;
update(n); //在合并点集后对并查集进行更新
sum_weight += edge[i].w; //计算总权
cout << "\t" << "The edge between " << GraphNode[edge[i].x].data << " & " << GraphNode[edge[i].y].data << " with the weight " << edge[i].w << endl;
}
cout << endl << "And the total weight of the MinSpanTree add up to: " << sum_weight << endl;
return 0;
}
bool comp(const Edge a, const Edge b)
{
return a.w < b.w;
}
void update(int n)
{
if(GraphNode[n].father == n)
return;
GraphNode[GraphNode[n].father].child = GraphNode[n].child;
//更新孩子结点update(GraphNode[n].father); //递归更新
GraphNode[n].father = GraphNode[GraphNode[n].father].father;
//更新父结点
}
程序运行结果:
运行程序,程序读取文件,获取文件中关于图的信息:结点数,结点值,结点间边权。
然后使用Kruskal算法对录入信息进行处理:
1.对边权排序