前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >最小生成树----克鲁斯卡尔算法

最小生成树----克鲁斯卡尔算法

作者头像
大忽悠爱学习
发布2021-03-23 20:56:59
6720
发布2021-03-23 20:56:59
举报
文章被收录于专栏:c++与qt学习c++与qt学习

克鲁斯卡尔算法基本思想

在这里插入图片描述
在这里插入图片描述

普利姆算法和克鲁斯卡尔算法比较:

在这里插入图片描述
在这里插入图片描述

伪代码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数据结构设计

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

连通分量

在这里插入图片描述
在这里插入图片描述

图解

注意:将边数组按照权值大小排好序是算法的前提

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最小生成树算法

在这里插入图片描述
在这里插入图片描述

完整代码

代码语言:javascript
复制
#include<iostream>
using namespace std;
#define MaxVertex 10//最大顶点数为10
#define MaxEdge 100//最大边数为100
typedef int DataType;//顶点数组存储的顶点数据类型
//边集结构体
struct EdgeType 
{
	int from, to;//记录起始和结束顶点的下标
	int weight;//边上的权值
};
//边集数组
class EdgeGraph 
{
private:
	DataType vertex[MaxVertex];//顶点数组
	EdgeType edge[MaxEdge];//边集数组
	int vertexNum;//顶点个数
	int EdgeNum;//边的个数
public:
	EdgeGraph(DataType v[],int n,int e);
	//对边集数组进行排序
	//1.快速排序
	void quick_sort(int begin,int end);
	//克鲁斯卡尔算法
	void Kruskal();
};
EdgeGraph::EdgeGraph(DataType v[], int n, int e)
{
	//初始化顶点个数
	vertexNum = n;
	//初始化边的个数
	EdgeNum = e;
	//初始化顶点数组
	for (int i = 0; i < vertexNum; i++)
	{
		vertex[i] = v[i];
	}
	//初始化边集数组
	for (int i = 0; i < EdgeNum; i++)
	{
		edge[i].from = -1;
		edge[i].to = -1;
		edge[i].weight = 0;
	}
	//人工给边集数组赋值赋值
	for (int i = 0; i < EdgeNum; i++)
	{
		cin >> edge[i].from>>edge[i].to>>edge[i].weight;
	}
}
//交换
void swap(int& v1, int& v2)
{
	int temp = v1;
	v1 = v2;
	v2 = temp;
}
//交换排序
int swap_sort(EdgeType r[], int begin, int end)
{
	//键值前面元素都比键值小,键值后面元素都比键值大
	int i = begin;//设置起初begin位置的值为键值
	int j = end;
	//i==j时退出循环
	while (i < j)
	{
		while (i < j && r[i].weight <= r[j].weight)
		{
			j--;//通过while循环,从end位置开始向后不断搜索,直到找到一个比r[i]小的值,或者i=j
		}
		//找到比r[i]小的值,就进行交换----交换过后r[j]是键值
		if (i < j)
		{
			swap(r[i], r[j]);
			//因为当前r[i]位置已经比较过了,下一次进入i移动的while循环时,可以不必再次比较当前r[i]
			i++;
		}
		while (i < j && r[i].weight <= r[j].weight)
		{
			i++;//通过while循环,从begin位置开始向前不断搜索,直到找到一个比r[j]大的值,或者i=j
		}
		//找到比r[j]大的值,就进行交换----交换过后r[i]是键值
		if (i < j)
		{
			swap(r[i], r[j]);
			//因为当前r[j]位置已经比较过了,下一次进入j移动的while循环时,可以不必再次比较当前r[j]
			j--;
		}
	}
	return i;
}
//对边集数组进行快速排序
void EdgeGraph::quick_sort(int begin,int end)
{
	int pos = 0;//记录当前键值的位置
	if (begin < end)//数组中不止一个元素
	{
		pos = swap_sort(edge, begin, end);//对当前区间数组进行排序,返回排序完成后的键值
		quick_sort(begin, pos - 1);//对当前键值前半部分进行排序
		quick_sort(pos + 1, end);//对当前键值后半部分进行排序
	}
}
//找到所在树的根节点:父母的数组      顶点下标    
int findRoot(const int parent[],const int& vex)
{
	int x = vex;
	//如果当前传入的顶点就是根节点,那么我们需要返回他的顶点值,不然就会返回-1

	while (parent[x] >-1)
	{
		x = parent[x];
	}
	return x;
}
void EdgeGraph::Kruskal()
{
	//定义parent数组
	int parent[MaxVertex];
	//初始化parent数组
	for (int i = 0; i < vertexNum; i++)
	{
		parent[i] = -1;
	}
	//先对边集数组进行排序
	quick_sort(0, EdgeNum-1);
	//测试--------打印边集数组
	cout << "边集数组打印:" << endl;
	cout << "from: " << "  to:  " << "  weight:  " << endl;
	for (int i = 0; i < EdgeNum; i++)
	{
		cout <<edge[i].from<<"\t"<<edge[i].to<<"\t"<<edge[i].weight << endl;
	}
	//遍历边集数组
	cout << "从起点开始的最小生成树:" << endl;
	int vex1, vex2;//vex1---起始顶点     vex2----结束顶点
	//num在这里是用来计算当前循环了几次的
	for (int i = 0,num=0; i < EdgeNum; i++)
	{
		vex1 =findRoot( parent,edge[i].from);//得到起始顶点的所在树根节点
		vex2 = findRoot(parent,edge[i].to);//得到结束顶点所在树的根节点
		//两个顶点的根节点不同,不会构成环
		if (vex1 != vex2)//满足条件说明此时要添加边
		{
			//输出加入边的格式
			cout << "("<<edge[i].from << "," << edge[i].to << ")" << endl;
			//设置起始顶点的根节点是结束顶点根节点的父亲
			parent[vex2] = vex1;//合并树
			num++;
			if (num == vertexNum - 1)//循环了图的顶点数-1次,提前返回
				return;
		}
	}
}
//测试------------------
void test()
{
	DataType v[6] = { 0,1,2,3,4,5 };
	EdgeGraph p(v, 6, 9);
	p.Kruskal();
}
int main()
{
	test();
	system("pause");
	return 0;
}
在这里插入图片描述
在这里插入图片描述

对边集数组进行排序的不同方法:

1.快速排序

代码语言:javascript
复制
//交换
void swap(int& v1, int& v2)
{
 int temp = v1;
 v1 = v2;
 v2 = temp;
}
//交换排序
int swap_sort(EdgeType r[], int begin, int end)
{
 //键值前面元素都比键值小,键值后面元素都比键值大
 int i = begin;//设置起初begin位置的值为键值
 int j = end;
 //i==j时退出循环
 while (i < j)
 {
  while (i < j && r[i].weight <= r[j].weight)
  {
   j--;//通过while循环,从end位置开始向后不断搜索,直到找到一个比r[i]小的值,或者i=j
  }
  //找到比r[i]小的值,就进行交换----交换过后r[j]是键值
  if (i < j)
  {
   swap(r[i], r[j]);
   //因为当前r[i]位置已经比较过了,下一次进入i移动的while循环时,可以不必再次比较当前r[i]
   i++;
  }
  while (i < j && r[i].weight <= r[j].weight)
  {
   i++;//通过while循环,从begin位置开始向前不断搜索,直到找到一个比r[j]大的值,或者i=j
  }
  //找到比r[j]大的值,就进行交换----交换过后r[i]是键值
  if (i < j)
  {
   swap(r[i], r[j]);
   //因为当前r[j]位置已经比较过了,下一次进入j移动的while循环时,可以不必再次比较当前r[j]
   j--;
  }
 }
 return i;
}
//对边集数组进行快速排序
void EdgeGraph::quick_sort(int begin,int end)
{
 int pos = 0;//记录当前键值的位置
 if (begin < end)//数组中不止一个元素
 {
  pos = swap_sort(edge, begin, end);//对当前区间数组进行排序,返回排序完成后的键值
  quick_sort(begin, pos - 1);//对当前键值前半部分进行排序
  quick_sort(pos + 1, end);//对当前键值后半部分进行排序
 }
}

2.插入排序

代码语言:javascript
复制
//对边集数组进行快速排序
void EdgeGraph::insert_sort(int begin,int end)
{
	for (int i = 1; i < EdgeNum; i++)
	{
		int j = i - 1;//j记录的是有序序列的最后一个元素
		EdgeType temp = edge[i];//保存无序序列中的第一个元素
		//从有序序列的最后一个元素开始,与temp的权值进行比较,直到找到权值比temp小的元素退出循环
		while (temp.weight<edge[j].weight)
		{
			//每一次循环,都把当前遍历的j位置的值往前移动一次,目的是为了空出一个正确的位置来存放temp
			edge[j + 1] = edge[j];
			j--;
		}
		//while循环结束后,j指向的位置是遍历到比temp小的位置,temp要插入到当前j指向位置的前面
		edge[j + 1] = temp;
	}
}
在这里插入图片描述
在这里插入图片描述

3. 折半插入排序

代码语言:javascript
复制
//对边集数组进行折半插入排序
void EdgeGraph::insert_sort(int begin,int end)
{
	int i;
	EdgeType x;//用来存储无序序列的第一个元素
	int mid;//指向有序序列中间的一个元素
	int low, high;//指向有序序列的开头和结尾
	//i每一次指向无序序列的第一个元素
	for (int i = 1; i < EdgeNum; i++)
	{
		x = edge[i];//无序序列的第一个元素
		low = 0;
		high = i - 1;//有序序列最后一个元素

		//找正确位置
		while (low <= high)
		{
			mid = (low + high) / 2;//有序序列的中间值
			//如果当前的无序序列的第一个x的权值大于等于有序序列中间值的权值
			if (x.weight >=edge[mid].weight)
			{
				//更新比较区间
				low = mid + 1;
			}
			else 
			{
				high = mid - 1;
			}
		}

		//找到要插入的地方时,要对插入地方前面的值进行移动
		//j=i-1指向有序序列最后一个值
		//退出while循环时,high的下标是要插入位置的前一个位置,把从high前面第一个元素开始的值的往前移动一个位置,直到覆盖当前无序序列第一个元素i的位子
		int j;
		for ( j = i - 1; j > high; j--)
		{
			edge[j+1] = edge[j];
		}
		//j此时指向的还是要插入元素的位置
		//移动完后,进行插入
		edge[j+1] = x;
	}
     
}
在这里插入图片描述
在这里插入图片描述
本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-03-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 克鲁斯卡尔算法基本思想
  • 伪代码
  • 数据结构设计
  • 图解
  • 最小生成树算法
  • 完整代码
  • 对边集数组进行排序的不同方法:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com