算法导论-最小生成树之kruskal算法和prim算法

1.Kruskal算法:集合A是一个森林,其结点为给定图的结点。每次加入集合A的安全边永远是权重最小的连接两个不同分量的边。、

在最开始实现kruskal算法时,自己不知道如何实现集合A这个森林,也不知道怎么合并树。直到后来,自己去搜索了一下此算法的实现,才发现其实要用到之前自己一直觉得没啥用也不怎么理解的不相交集。

下面是Kruskal算法的实现代码:

KRUSKAL.h

typedef struct eNode* edge;
typedef struct graph* graphs;


struct eNode
{
	int w;//权重
	int u;//起点
	int v;//终点
};


struct graph
{
	int n;//图的节点数
	int e;//图的边数
	int **g;//图的邻接矩阵
};


void sort(edge e,int n);//根据权重排序
int findSet(int i,int *s);//判断两节点是否属于同一棵树
void unionSet(int i, int j, int *s);//合并两棵树
edge mst_kruskal(graphs g);

KRUSKAL.cpp

#include"stdafx.h"
#include"KRUSKAL.h"
#include<iostream>
using namespace std;


void sort(edge e, int n)
{
	int i, j, key, u, v;
	for (j = 1; j<n; j++){
		key = e[j].w;
		u = e[j].u;
		v = e[j].v;
		i = j - 1;
		while (i >= 0 && e[i].w>key){
			e[i + 1].w = e[i].w;
			e[i + 1].u = e[i].u;
			e[i + 1].v = e[i].v;
			i = i - 1;
		}
		e[i + 1].w = key;
		e[i + 1].u = u;
		e[i + 1].v = v;
	}
}


int findSet(int i, int *s)
{
	if (s[i] == i)
		return i;
	else
		return findSet(s[i], s);
}


void unionSet(int i, int j, int *s)
{
	s[j] = i;
}


edge mst_kruskal(graphs g)
{
	int i, j, k, sum = 0;
	int *s;
	edge a,e;
	a = (eNode *)malloc(sizeof(eNode)*g->n);
	e = (eNode *)malloc(sizeof(eNode)*g->e);
	k = 0;
	s = (int *)malloc(sizeof(int)*g->n);
	for (i = 0; i < g->n; i++)
		s[i] = i;
	for (i = 0; i < g->n; i++)
	{
		for (j = 0; j < g->n; j++)
		{
			if (g->g[i][j] != 0)
			{
				e[k].w = g->g[i][j];
				e[k].u = i;
				e[k].v = j;
				k++;
			}
		}
	}
	sort(e, g->e);
	j = 0;
	for (i = 0; i < g->e; i++)
	{
		if (findSet(e[i].u, s) != findSet(e[i].v, s))
		{
			a[j].u = e[i].u;
			a[j].v = e[i].v;
			a[j].w = e[i].w;
			sum += e[i].w;
			unionSet(e[i].u, e[i].v, s);
			j++;
		}
	}
	return a;
}

main.cpp

// KRUSKAL.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include"KRUSKAL.h"
#include<iostream>
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
	int i,j,u,v,w;
	graphs g;
	edge a;
	g = (struct graph *)malloc(sizeof(struct graph));
	cout << "Please input the number of the verteces and egdes of the graph:" << endl;
	cin >> g->n >> g->e;
	g->g = (int **)malloc(sizeof(int *)*g->n);
	for (i = 0; i < g->n; i++)
		g->g[i] = (int *)malloc(sizeof(int)*g->n);
	for (i = 0; i < g->n; i++)
	{
		for (j = 0; j < g->n; j++)
			g->g[i][j] = 0;
	}
	cout << "Please input the start and the end of edges with their weight:" << endl;
	for (i = 0; i < g->e; i++)
	{
		cin >> u >> v >> w;
		g->g[u][v] = w;
	}
	a = (struct eNode *)malloc(sizeof(struct eNode)*(g->n-1));
	a = mst_kruskal(g);
	cout << "The mst is:" << endl;
	for (i = 0; i < g->n-1; i++)
		cout << a[i].u << "->" << a[i].v << " " << a[i].w << endl;
	system("pause");
	return 0;
}

2.Prim算法:集合A是一棵树,每次加入到A中的安全边永远是连接A和A之外某结点的边中权重最小的边。

prim算法的实现相对简单,本来想用一个最小优先队列来实现的,但是发现最小优先队列在实现过程中比较复杂,后来去看了一下别人的实现才发现只要维护三个数组就可以了。

下面是prim算法的实现代码:

PRIM.h

typedef struct graph* graphs;

struct graph
{
	int n;
	int e;
	int **g;
};


void mst_prim(graphs g, int r);

PRIM.cpp

#include"stdafx.h"
#include"PRIM.h"
#include<iostream>
using namespace std;


void mst_prim(graphs g, int r)
{
	int* min_cost;
	int* father;
	int* isQ;
	int sum = 0;
	min_cost = (int *)malloc(sizeof(int)*g->n);
	father = (int *)malloc(sizeof(int)*g->n);
	isQ = (int *)malloc(sizeof(int)*g->n);
	int i,j;
	for (i = 0; i < g->n; i++)
	{
		min_cost[i] = g->g[r][i];
		father[i] = r;
		isQ[i] = 1;
	}
	isQ[r] = 0;
	for (i = 0; i < g->n-1; i++)
	{
		int min=INT_MAX,id;
		for (j = 0; j < g->n; j++)
		{
			if (isQ[j] == 1 && min_cost[j] < min)
			{
				min = min_cost[j];
				id = j;
			}
		}
		isQ[id] = 0;
		sum += min_cost[id];
		cout << father[id] << "->" << id <<" "<<min_cost[id]<< endl;
		for (j = 0; j < g->n; j++)
		{
			if (isQ[j]==1 && (g->g[id][j] < min_cost[j]))
			{
				father[j] = id;
				min_cost[j] = g->g[id][j];
			}
		}
	}
}

main.cpp

// PRIM.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include"PRIM.h"
#include<iostream>
using namespace std; 


int _tmain(int argc, _TCHAR* argv[])
{
	graphs g;
	int i, j,u,v,w;
	g = (struct graph*)malloc(sizeof(struct graph));
	cout << "Please enter the number of vertces and edges of the graph:" << endl;
	cin >> g->n >> g->e;
	g->g = (int **)malloc(sizeof(int *)*g->n);
	for (i = 0; i < g->n; i++)
		g->g[i] = (int *)malloc(sizeof(int)*g->n);
	for (i = 0; i < g->n;i++)
		for (j = 0; j < g->n; j++)
			g->g[i][j] =INT_MAX;
	cout << "Please enter the start node and end node of the graph with their weight:" << endl;
	for (i = 0; i < g->e; i++)
	{
		cin >> u >> v >> w;
		g->g[u][v] = w;
		g->g[v][u] = w;
	}
	cout << "Please enter the root node of the mst:" << endl;
	cin >> u;
	mst_prim(g, u);
	system("pause");
	return 0;
}

点赞