图的应用1.最小生成树——kruskal算法实现(加边法)


#include
using namespace std;
//用邻接矩阵来存储
#define MaxNum 10//最大顶点数
#define MaxInt 32767//无穷大
#define MinInt -1//认为较小
typedef char  VerType;//数据类型
typedef int ArcType;//权值类型

//定义图的结构

typedef struct {
	VerType ver[MaxNum];//顶点表
	ArcType arc[MaxNum][MaxNum];//邻接矩阵
	int vernum, arcnum;	//点数,边数
}AMGraph;
//引入辅助结构1,Edge:储存边的信息,包括两个点的信息和权值
struct edge {
	VerType Head;//边的起点
	VerType Tail;//边的终点
	ArcType lowCost;//边的权值
}Edge[MaxNum];//边的信息

//定位

int Locate(AMGraph G, VerType v1) {
	for (int i = 0; i < G.vernum; i++) {
		if (G.ver[i] == v1) {
			return i;
		}
	}
	return -1;
}
//创建无向图
bool createUDN(AMGraph &G) {
	cout << "Please input the vernum and arcnum" << endl;
	cin >> G.vernum >> G.arcnum;
	cout << "Please input the name of points" << endl;
	int i = 0, j = 0;
	for (i = 0; i < G.vernum; i++)
		cin >> G.ver[i];
	//初始化邻接矩阵
	for (i = 0; i < G.vernum; i++) {
		for (j = 0; j < G.vernum; j++) {
			if (i != j)
				G.arc[i][j] = MaxInt;
			else G.arc[i][j] = 0;
		}
	}
	//开始操作,构造邻接表
	cout << "Please input arcnum graph " << endl;
	VerType v1, v2;
	ArcType w;
	int p, q;
	for (i = 0; i < G.arcnum; i++) {
		cin >> v1 >> v2 >> w;
		p = Locate(G, v1); q = Locate(G, v2);
		Edge[i] = { v1,v2,w };
		G.arc[p][q] = w;
		G.arc[q][p] = G.arc[p][q];
	}
	return true;
}
void show(AMGraph G) {
	int i, j;
	for (i = 0; i < G.vernum; i++) {
		for (j = 0; j < G.vernum; j++) {
			if (G.arc[i][j] == MaxInt)  printf("INF\t");
			else printf("%-3d\t", G.arc[i][j]);
		}
		cout << endl;
	}
}

//算法思想:加边法
// 1.将数组Edge的元素从小到大排序
// 2.依次查看数组的边,循环下列操作:
// 2.1依次从排好序的Edge数组中选择一条边(u,u2);
// 2.2在Vexset中分别查找v1,v2所在的联通分量vs1,vs2,进行判断
// 如果vs1==vs2,表明2个顶点属于同一个联通分量,舍去此边,而选择下一条权值最小的边
// vs1!=vs2,表明2个顶点属于不同两个联通分量,输出此边,合并两个联通分量

//引入辅助结构2,Vexset[i] 标识各个顶点所属的连通分量,初始化时都各自成为一个连通分量
void Sort(edge a[],int length) {
	//插入排序
	for (int i = 1; i < length - 1; i++) {
		edge Temp=a[i];
		int temp = a[i].lowCost;
		int inner = i;
		while (inner > 0 && a[inner - 1].lowCost >= temp) {
			a[inner] = a[inner - 1];
			inner--;
		}
		a[inner] = Temp;
	}
}

//算法开始
//int Vexset[MaxNum]辅助数组

void MiniSpanTree_Kruskal(AMGraph G) {
	//无向图以邻接矩阵形式存储,构造G的最小生成树,输出T的各边
	//初始化
	int Vexset[MaxNum];
	Sort(Edge,G.vernum);//将数组Edge中的元素按照权值从小到大排序
	int i = 0;
	for (i = 0; i < G.arcnum; i++) Vexset[i] = i;
	int v1, v2;//下标
	int vs1, vs2;//连通分量
	//开始
	for (i = 0; i < G.arcnum; i++) {
		v1 = Locate(G, Edge[i].Head);//Head下标
		v2 = Locate(G, Edge[i].Tail);//Tail下标
		vs1 = Vexset[v1];//获取边v1起始点所在连通分量vs1
		vs2 = Vexset[v2];//获取边v2起始点所在连通分量vs2
		if (vs1 != vs2) {//边2个顶点分属于不同的连通分量
			cout << "start at point "<<Edge[i].Head << " ,end at point " << Edge[i].Tail <<  "\n";//输出此边
			//合并两个联通分量
			for (int j = 0; j < G.vernum; j++) {
			//合并vs1和vs2两个分量,统一编号为vs1,相当于是归到一个连通分量
				if (Vexset[j] == vs2)
					Vexset[j] = vs1;//集合编号为vs2的都改成vs1
			}
		}
		//如果vs1==vs2,表明2个顶点属于同一个联通分量,舍去此边,而选择下一条权值最小的边,跳到下一次循环
	}
}
int main() {
	AMGraph G;
	createUDN(G);
	show(G);
	MiniSpanTree_Kruskal(G);
}

你可能感兴趣的:(c++数据结构,C++)