Prim和Kruskal性能比较

/*
Prim 邻接表+优先队列优化
Kruskal 邻接矩阵+并查级优化,因为Kruskal里没有需要遍历邻接边的操作,所以简单的用邻接矩阵
结果保证:获得路径即可
e因为要有生成树,原图必须是一条连通的路线,所以e>=n-1

*/
#include<iostream>
#include<queue>
#include<Windows.h>

using namespace std;
const int maxnum = 100;
const int inf = 0x3f3f3f3f;
typedef struct AdjNode {
	int v;
	int w;
	struct AdjNode* next;
}AdjNode;
typedef struct VexNode {
	AdjNode* first;
}VexNode;
typedef struct ALGraph {
	VexNode vexs[maxnum];
	int vexnums;
	int edgenums;
}ALGraph;
int father[maxnum];
typedef struct edge {
	int u;
	int v;
	int w;
	edge(int ui, int vi, int wi)
	{
		u = ui;
		v = vi;
		w = wi;
	}
	edge()
	{

	}
	//运算符重载
	friend bool operator >(const edge e1, const edge e2)
	{
		return e1.w > e2.w;
	}
}edge;
edge e[maxnum];
ALGraph Lg;
int vexnums, edgenums;
bool s[maxnum];
//构建邻接矩阵
void CreateALGraph() {
	cout << "输入顶点数量和边数量:" << endl;
	cin >> vexnums >> edgenums;
	cout << "输入对应的边关系:" << endl;
	//初始化邻接表的顶点
	for (int i = 0; i < vexnums; i++)
	{
		Lg.vexs[i].first = NULL;
	}
	//初始化邻接表的边
	for (int i = 0; i < edgenums; i++)
	{
		int a, b, w;
		cin >> a >> b >> w;
		AdjNode* an = new AdjNode;
		an->v = b;
		an->w = w;
		an->next = Lg.vexs[a].first;
		Lg.vexs[a].first = an;
		AdjNode* bn = new AdjNode;
		bn->v = a;
		bn->w = w;
		bn->next = Lg.vexs[b].first;
		Lg.vexs[b].first = bn;
	}
}
void prim1000()
{
	CreateALGraph();
	int u;
	cin >> u;
	int t1 = GetTickCount();
	for (int z = 0; z < 1000; z++)
	{
		//重置s集合
		for (int i = 1; i <= vexnums; i++)
		{
			s[i] = false;	
		}
		AdjNode* an;
		s[u] = true;							//将u顶点加入s集合中
		priority_queue<edge, vector<edge>, greater<edge> > queue;				//边队列
		edge* path = new edge[vexnums - 1];			//最小生成树结果
		int k = 0;									//记录结果的生成进度
		//将u顶点的邻接边都加入队列中
		an = Lg.vexs[u].first;
		while (an != NULL)
		{
			queue.push(edge(u, an->v, an->w)); //o(e分*loge)
			an = an->next;
		}
		for (int i = 1;queue.size()>0; i++)
		{
			//求出v-s内最近顶点
			edge e = queue.top();
			int t = e.v;
			queue.pop();
			if (k == vexnums - 1) break; //n-1 总o(n*e分*loge)优先队列
			if (s[t]) continue; 
			s[t] = true;						//把顶点加入S中
			path[k++] = e;
			//更新queue将改变的边重新加入队列中,遍历t的所有邻接边 t->i
			an = Lg.vexs[t].first;
			while (an != NULL) //o(e)
			{
				if (!s[an->v])
				{
					queue.push(edge(t, an->v, an->w)); //e总,在这其中已经排过序的边虽然不会再加入queue中但是还是会遍历一遍,所以边的遍历是2遍,排序一个loge,比Kruskal慢了
				}
				an = an->next;
			}
		}
		for (int i = 0; i < vexnums - 1; i++)
		{
			cout << "<" << path[i].u << "," << path[i].v << "> ";
		}
		cout << endl;
	}
	int t2 = GetTickCount();
	cout << "总计耗时:" << t2 - t1 << endl;
}

void CreateAMGraph() 
{
	cout << "输入顶点数量和边数量:" << endl;
	cin >> vexnums >> edgenums;
	//初始化边关系
	cout << "输入对应的边关系:" << endl;
	for (int i = 0; i < edgenums; i++)
	{
		int a, b, w;	
		cin >> a >> b >> w;
		e[i] = edge(a, b, w);
	}
}

int Find(int x)
{
	if (x != father[x])
		father[x] = Find(father[x]);
	return father[x];
}

int Merge(int a, int b)
{
	int p = Find(a);
	int q = Find(b);
	if (p == q) return 0;
	if (p > q)
		father[p] = q;//小的赋值给大的集合号
	else
		father[q] = p;
	return 1;
}
int cmp(const void *a, const void *b)
{
	edge* e1 = (edge*)a;
	edge* e2 = (edge*)b;
	return e1->w - e2->w;
}

void Kruskal1000() 
{
	CreateAMGraph();
	int t1 = GetTickCount();
	for (int z = 0; z < 1000; z++)
	{
		int n = vexnums;
		edge* path = new edge[vexnums - 1];		//最小生成树结果
		int k = 0;
		//并查集初始化与邻近集合初始化
		for (int i = 1; i <= vexnums; i++)
		{
			father[i] = i;
		}
		//对边进行排序
		qsort(e, edgenums, sizeof(e[0]), cmp);  //o(eloge) 一次排序完成

		for (int i = 0; i < edgenums; i++)		//n-1
			if (Merge(e[i].u, e[i].v) /*logn*/) //-->n*logn 从小到大
			{
				path[k++] = e[i];
				n--;
				if (n == 1)
				{
					break;
				}
			}
		for (int i = 0; i < vexnums-1; i++)
		{
			cout << "<" << path[i].u << "," << path[i].v << "> ";
		}
		cout << endl;
	}
	int t2 = GetTickCount();
	cout << "总计耗时:" << t2 - t1 << endl;
}


int main()
{
	prim1000();
	Kruskal1000();
	system("pause");
	return 0;
}

测试数据

7 12
1 2 23
1 6 28
1 7 36
2 3 20
2 7 1
3 7 4
3 4 15
4 7 9
4 5 3
5 7 16
5 6 17
6 7 25
在这里插入图片描述
Kruskal比Prim快多了,无脑用Kruskal算了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JustEasyCode

谢谢您

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值