数据结构——图的最小生成树和最大生成树之Kruskal算法理解和实现

数据结构——图的最小生成树和最大生成树之Prim算法理解和实现

Kruskal算法理解:

对于n个顶点 最小路径生成树 有n-1条路径

首先将顶点按权值从小到大排好

然后从最小的开始选择权重

设置一个parent数组 用来选择
其含义就是 parent每次都会变化

但是对于一个路径来说 如果收尾都对应这parent同一个位置的值 说明二次走这个顶点

定义邻接矩阵和边集数组

#include<iostream>
#include <iomanip>
using namespace std;

typedef char Vertextype;//顶点类型
typedef int Edgetype;//边缘权值
typedef int Status;
#define MAXVER 9//最大顶点数
#define INF 65535//代表无穷
#define NULL 0

//定义图——邻接矩阵
typedef struct Graph
{
    
    
	Vertextype Ver[MAXVER];
	Edgetype Arc[MAXVER][MAXVER];
	int NumVer, NumEdg;
}MGraph;

//定义边集数组Edge
typedef struct EdgeNode{
    
    
	int begin;
	int end;
	int weight;
}EdgeNode, *Edge;//这个数组一定要固定吗  开始我这里是写的固定数组 改成这样后面加上一个new即可变成动态数组

Status Find(int *parent, int f);

生成图

//生成图——邻接矩阵
Status CreatGraph(MGraph &G)
{
    
    
	int i, j, w;
	cout << "Please enter the number of verticesof the graph : " << endl;
	cin >> G.NumVer;
	cout << "Please enter the number of edges the graph : " << endl;
	cin >> G.NumEdg;
	cout << "Please enter the name of vex : " << endl;
	for (i = 0; i < G.NumVer; i++){
    
    
		//cout << "Please enter the NO." << i + 1 << "%d name of vex : " << endl;
		cin >> G.Ver[i];
	}

	cout << "Diagonal infinity ..." << endl;
	for (i = 0; i < G.NumVer; i++)
		for (j = 0; j < G.NumVer; j++)
		{
    
    
		G.Arc[i][j] = INF;//简单图  不循环
		//cout << G.arc[i][j] << endl;//不理解为啥是1
		}
	cout << "...Diagonal infinity" << endl;

	for (int k = 0; k < G.NumEdg; k++){
    
    //因为具体哪条边存在不一定 所以选择性输入边
		cout << "Enter the subscripts and weights from vertex vi to vertex vj : " << endl;
		cin >> i >> j >> w;
		/*cout << "Please enter the subscript j of the edge : " << endl;
		cin >> j;
		cout << "Please enter the weight from vertex "<<i<<" to vertex "<<j<<" : " << endl;
		cin >> w;*/

		G.Arc[i][j] = w;
		G.Arc[j][i] = G.Arc[i][j];//无向图  边的信息  是对称的  //有向图的话 无需设置

	}
	return 0;
}

//将邻接矩阵转化为边集数组

邻接矩阵有对称性 且主对角元素不存在 遍历赋值的时候要注意

Status GraphToEdge(MGraph &G, Edge *edges)
{
    
    
	EdgeNode *t;
	int i, j,k=0;
	//观察邻接矩阵的结构  主对角线不存在  只遍历一半即可
	for (i = 0; i < G.NumVer; i++)
		for (j = i+1; j < G.NumVer; j++){
    
    
		if (G.Arc[i][j] != INF){
    
    //权值存在
			edges[k] = new EdgeNode;
			edges[k]->begin = i;
			edges[k]->end = j;
			edges[k]->weight = G.Arc[i][j];
			k++;
		}
		}
	//cout << k << endl << endl;

	//冒泡排序
	for (i = 0; i < G.NumEdg - 1; i++)
		for (j = 0; j < G.NumEdg - i - 1;j++)
			if (edges[j]->weight > edges[j + 1]->weight){
    
    
			t = edges[j];
			edges[j] = edges[j+1];
			edges[j + 1] = t;
			}

	/*for (i = 0; i < G.NumEdg; i++){
		cout << edges[i].weight << endl;
	}*/
	return 0;
}

Kruskal算法

对于parent那 手动画图更好理解

Status MinSpanTree(MGraph &G,Edge *edges)
{
    
    
	int i, n, m;
	int parent[MAXVER];
	for (i = 0; i < G.NumVer; i++)
		parent[i] = 0;
	for (i = 0; i < G.NumEdg; i++)
	{
    
    
		n = Find(parent, edges[i]->begin);//选择首尾下标
		m = Find(parent,edges[i]->end);

		if (m != n)//判断是否循环  这里画图更容易理解
		{
    
    
			parent[n] = m;
			cout << edges[i]->begin << "____" << edges[i]->end << "____" << edges[i]->weight << endl;
		}
	}
	return 0;
}

Status Find(int *parent, int f)
{
    
    
	while (parent[f]>0)
	{
    
    
		f = parent[f];
	}
	return f;
}


int main()
{
    
    
	MGraph G;
	Edge *edges=(Edge *)malloc(sizeof(EdgeNode));
	CreatGraph(G);
	GraphToEdge(G,edges);
	MinSpanTree(G,edges);
	system("pause");
	return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46096297/article/details/113559809