数据结构-图的c++实现(包括最小生成树和最短路径的计算

#pragma once
//图,采用邻接矩阵储存
#ifndef My_Head_H
	#define My_Head_H
	#include "G://code/c++/myhead.h"
#endif // !My_Head_H

constexpr auto MAX_VERTEX_NUM = 20;



//采用邻接矩阵储存
template<typename ElemType1,typename ElemType2>
class MGraph
{
public:
	//是否为空
	bool Is_Empty();

	//用Kruskal算法构造最小生成树
	void Mini_Span_Tree_Kreskal();

	//用Prim算法构造最小生成数
	void Mini_Span_Tree_Prim(ElemType1 vertex);

	//有向网从某个顶点出发到其余各点的最短路径(Dijkstra)
	void Shortest_Path_Dijkstra();

	//有向网各对顶点之间的最短路径(Floyd)
	void Shortest_Path_Floyd();

protected:
	//图的种类。有向图=0;有向网=1;无向图=2;无向网=3
	int kind;
	//图的顶点个数
	int vexNum;
	ElemType1 verxs[MAX_VERTEX_NUM];//顶点的数据值数组;

	int arcNum;//图的边数
	ElemType2 arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
	//邻接矩阵,对于图用1和0表示是否相邻,对于网表示两顶点之间的权值
};

template<typename ElemType1, typename ElemType2>
bool MGraph<ElemType1, ElemType2>::Is_Empty()
{
	return !vexNum;
}

template<typename ElemType1, typename ElemType2>
void MGraph<ElemType1, ElemType2>::Mini_Span_Tree_Kreskal()
{
	struct
	{
		int begin;//边的起始点
		int end;//边的结束点
		ElemType2 cost;//边的权值
	}edges[MAX_VERTEX_NUM];//按权值从大到小记录每条边的信息数组

	int Min_Shortest;
	
	int set[MAX_VERTEX_NUM] = { 0 };//生成最小生成树的辅助数组,用以判断有无产生环路

	//将数组edges元素边的权值置为无限大以初始化
	for (int k = 0; k < arcNum; k++)
		edge[k].cost = INFINITY;

	//扫描邻接矩阵,把各边按权重从小到大排序;
	for (int i = 0; i < vexNum; i++)
	{
		for (int j = 0; j < vexNum; j++)
		{
			if (arc[i][j] != INFINITY)
			{
				for (k = 0; k < arcNum; k++)
					if (arcs[i][j] < edge[k].cost) break;
				Min_Shortest = k;
				//找到辅助数组已经输入的边数
				for (; edges[k].cost != INFINITY; k++);

				for (; k > Min_Shortest; k--)
				{
					edgex[k].begin = edges[k - 1].begin;
					edgex[k].end = edges[k - 1].end;
					edgex[k].cost = edges[k - 1].cost;
				}
				//输入当前边的信息
				edgex[k].begin = i;
				edgex[k].end = j;
				edgex[k].cost = arc[i][j];
			}
		}
	}
	
	int begin_set, end_set;
	for (k = 1; k < vexNum; k++)
	{
		begin_set = find(set, edges[k].begin);
		end_set = find(set, edges[k].end);
		if (begin_set != end_set)
		{
			//说明二者并不在一个子集中,将边k加入到最小生成树中
			set[begin_set] = end_set;
			cout << edges[k].begin << "--" << edges[k].cost << "-->"edges[k].end << endl;
		}
	}

}

template<typename ElemType1, typename ElemType2>
void MGraph<ElemType1, ElemType2>::Mini_Span_Tree_Prim(ElemType1 vertex)
{
	if (Is_Empty) return;
	int min, i, j, t;
	int adjvex[MAX_VERTEX_NUM];//保存相关顶点下标
	int lowcost[MAX_VERTEX_NUM];//保存顶点离最小生成树的距离
	lowcost[0] = 0;//初始化第一个为0,即将第一个结点加入生成树
	for (i = 1; i < vexNum; i++)
	{
		lowcost[i] = arcs[0][i];
		adjvex[i] = 0;
	}
	for (i = 1; i < vexNum; i++)
	{
		min = 65535;
		for (j = 1; j < vexNum; j++)
		{
			if (lowcost[j] != 0 && lowcost[j] < min)
			{
				min = lowcost[j];
				t = j;
			}
			adjvex[t] = 1;//标记该点进入最小生成树
			cout << "--" << lowcost[t] << "-->" << t;
		}
		lowcost[t] = 0;
		for (j = 1; j < vexNum; j++)
		{
			if (arcs[t][j] < lowcost[j] && lowcost[j] != 0)
			{
				lowcost[j] = arcs[t][j];
				adjvex[j] = t;
			}
		}
	}
}

template<typename ElemType1, typename ElemType2>
void MGraph<ElemType1, ElemType2>::Shortest_Path_Dijkstra()
{  
	int order = 1;//预存放生成最短路径的顺序号
	int k; //存放起始点的下标
	ElemType1 begin_vertex; //存放起始点的权值
	ElemType2 shortest[MAX_VERTEX_NUM];//储存起始点到每个顶点的最短距离;
	int path[MAX_VERTEX_NUM] = { 0 };//储存起始点通向每个点最短路径的前一个结点;
	bool final[MAX_VERTEX_NUM] = { 0 };//表示是否已经生成到该点的最短路径;
	cin >> begin_vertex; //输入起始点(点的值而不是标号)
	while (1)
	{
		for (k = 0; k < vexNum && verxs[k] != begin_vertex; k++);
		//如果找不到那个点,需要重新输入
		if (k == vexNum)
		{
			cout << "顶点" << begin_vertex << "不存在,需要重新输入" << endl;
			cin >> begin_vertex;
		}
		break;   //找到该顶点,k为其下标。退出输入循环;
	}
	//至此k表示起始结点的下标
	shortest[k] = 0;
	final[k] = true;
	path[k] = k;

	for (int i = 0; i < vexNum; i++)
	{
		//用邻接矩阵初始化最初的最短距离
		shortest[i] = arc[k][i];
		if (arc[k][i] != INFINITY) path[i]= k;
	}

	for (i = 1; i < vexNum; i++)
	{
		//找到还未生成最短路径的所有点中和起始点距离最近的点,记录在min_i里。
		int min = INFINITY;
		int min_i;
		for (int j = 0; j < vexNum; j++)
		{
			if (!final[j] && shortest[j] < min)
			{
				min = shortest[j];
				min_i = j;
			}
		}
		final[min_i] = 1;
		for (int j = 0; j < vexNum; j++)
		{
			if (!final[j] && min + arc[min_i][j] < shortest[j])
			{
				shortest[j] = min + arc[min_i][j];
				path[j] = min_i;
			}
		}
		
	}
	for (int j = 0; j < vexNum; j++)
		cout << "-->" << path[j];
}


template<typename ElemType1, typename ElemType2>
void MGraph<ElemType1, ElemType2>::Shortest_Path_Floyd()
{
	int path[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
	ElemType2 D[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
	int i, j, k;
	for (i = 0; i < vexNum; i++)
	{
		for (j = 0; j < vexNum; j++)
		{
			D[i][j] = arcs[i][j];
			path[i][j] = j;
		}
	}
	for (i = 0; i < vexNum; i++)
	{
		for (j = 0; j < vexNum; j++)
		{
			for (k = 0; k < vexNum; k++)
			{
				if (D[j][k] > D[j][i] + D[i][k])
				{
					D[j][k] = D[j][i] + D[i][k];
					p[j][k] = p[j][i];
				}
			}
		}
	}
}

int find(int set[], int f)
{
	while (set[f] > 0)
		f = set[f];
	return f;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值