数据结构-最短路径问题

一.问题分类

二.无权图单源最短路算法

dist[]数组记录的是个个顶点到源点的距离这个数组的下标表示顶点

源点到自己的距离是0,dist[s]=0

path[]数组记录的是这个顶点的前驱,可以同过这个数组找到源点到个个顶点的距离

代码如下

void Unweighted(MGraph Graph, Vertex S) {
	Vertex V,W;
	dist[S] = 0;//初始化源点到自己的距离
	queue<Vertex>q;
	q.push(S);//压栈
	while(!q.empty()) {
		/*弹栈*/
		V = q.front();
		q.pop();
			
		for (W = 0; W < Graph->Nv; W++) {
			/*点W到源点的距离没有被确定并且两个顶点有边,*/
			if (dist[W] == -1 && IsEdge(Graph, V, W) ){
				dist[W] = dist[V] + 1;/*更新距离*/
				path[W] = V;//记录W的前驱
				q.push(W);
			}
		}
			
	}
}

dist[]和path[]都初始为-1

全部代码

#include<iostream>
#include<queue>
using namespace std;
#define INIFIN 65535/*表示没有边*/
#define MaxVertenNum 100/*最大顶点值*/
typedef int Vertex;/*顶点的下标用整形表示*/
typedef int WeightType;/*权重*/
int dist[MaxVertenNum], path[MaxVertenNum];
/* 边的定义*/
typedef struct ENode* PtrToENode;
struct ENode
{
	Vertex V1, V2;/*有向图<v1,v2>*/
	//WeightType Weight;/*权重*/
};
typedef PtrToENode Edge;

//图的定义
typedef struct GNode* PtrToGNode;
struct GNode {
	int Nv;/*顶点个数*/
	int Ne;/*边的个数*/
	WeightType G[MaxVertenNum][MaxVertenNum];
};
typedef PtrToGNode MGraph;

MGraph CreateGraph(int VerNum) {
	/*创建1个VN个顶点0条边的图*/
	Vertex V, W;
	MGraph Graph = new GNode();
	Graph->Nv = VerNum;
	Graph->Ne = 0;
	for (V = 0; V < Graph->Nv; V++)
		for (W = 0; W < Graph->Nv; W++)
			Graph->G[V][W] = INIFIN;
	return Graph;
}
//插入边
void InsertEdge(MGraph Graph, Edge E)
{
	/* 插入边 <V1, V2> */
	Graph->G[E->V1][E->V2] = 1;
	/* 若是无向图,还要插入边<V2, V1> */
	//Graph->G[E->V2][E->V1] = 1;  
}


MGraph BuildGraph() {
	Edge E;
	MGraph Graph;
	Vertex Nv;
	cin >> Nv;/*顶点个数*/
	Graph = CreateGraph(Nv);
	cin >> Graph->Ne;/*输入边的个数*/
	if (Graph->Ne != 0) {
		
		for (int i = 0; i < Graph->Ne; i++) {
			E = new ENode();
			cin >> E->V1 >> E->V2;
			InsertEdge(Graph, E);
		}
	}
	return Graph;
}
bool IsEdge(MGraph G, Vertex v1, Vertex v2) {
	return G->G[v1][v2] < INIFIN ? true : false;
}
void Unweighted(MGraph Graph, Vertex S) {
	Vertex V,W;
	dist[S] = 0;//初始化源点到自己的距离
	queue<Vertex>q;
	q.push(S);//压栈
	while(!q.empty()) {
		/*弹栈*/
		V = q.front();
		q.pop();
			
		for (W = 0; W < Graph->Nv; W++) {
			/*点W到源点的距离没有被确定并且两个顶点有边,*/
			if (dist[W] == -1 && IsEdge(Graph, V, W) ){
				dist[W] = dist[V] + 1;/*更新距离*/
				path[W] = V;//记录W的前驱
				q.push(W);
			}
		}
			
	}
}
void FindDp(int V) {
	if (V == -1)
		return;
	FindDp(path[V]);
	cout << V << " ";

}
int main()
{
	MGraph G = BuildGraph();
	for (int i = 0; i < MaxVertenNum; i++) {
		dist[i] = path[i] = -1;
	}

	Unweighted(G, 0);
	cout << "请输入终点顶点:";
	int n;
	cin >> n;
	cout << "源点到终点的路径:";
	FindDp(n);
	cout << endl;
	system("pause");
	return 0;
}
/*
7
12
0 1
0 3
1 3
1 4
2 0
2 5
3 2
3 4
3 5
3 6
4 6
6 5
*/

运行结果

三.有权图单源最短路算法

S集合存储的是的已经确定最短距离的顶点,起初集合只有一个顶点源点

若顶点V没有收录到集合,dist[V]表示源点到顶点V的距离,但这个距离不是真正的最短路径,当V顶点被收录到集合的时候,dist[V]才是最短距离

每次从dist[]中找到距离最短的顶点

当有顶点加入到集合中的时候,可能会影响dits[W]的值,及顶点的邻接点

代码如下

Vertex FindMinDist(MGraph Graph) {
	/*返回未被收入顶点中的最小dist者*/
	Vertex MinV, V;
	int MinDist = INFINITY;
	for (V = 0; V < Graph->Nv; V++) {
		if (Visted[V] == false && dist[V] < MinDist) {
			/*若V未被收录,且dist[V]更小*/
			MinDist = dist[V];/*更新最小距离*/
			MinV = V;/*更新最小顶点*/
		}
	}
	if (MinDist < INFINITY)/*若找到最小dist*/
		return MinV;/*返回对应的顶点下标*/
	else return 0;/*若这样的顶点不存在,返回错误标记*/
}
bool Dijkstra(MGraph Graph, Vertex S) {
	Vertex V, W;

	/*初始化:此处默认邻接矩阵中不存在的边用INFINITY表示*/
	for (V = 0; V < Graph->Nv; V++) {
		dist[V] = Graph->G[S][V];//与S结点邻接把边值放到dist中
		if (dist[V] < INFINITY)//有边记录它的前驱
			path[V] = S; //记录V的前驱V的前驱是S
		else
			path[V] = -1;
		Visted[V] = false;//全部顶点都没有收录
	}
	/*先将收起点收入集合*/
	dist[S] = 0;
	Visted[S] = true;//放到集合中
	while (1) {
		/*找到未被收入顶点中dist最小者*/
		V = FindMinDist(Graph);
		if (!V)/*如不存在*/
			break;//算法结束
		Visted[V] = true;//收录V
		for (W = 0; W < Graph->Nv; W++)
			if (Visted[W] == false && Graph->G[V][W] < INFINITY) {
				if (Graph->G[V][W] < 0)//若有负边
					return false;//
				if (dist[V] + Graph->G[V][W] < dist[W]) {
					dist[W] = dist[V] + Graph->G[V][W];
					path[W] = V;//跟新S到W的路径
				}
			}
	}
	return true;
}

全部代码

#include<iostream>
using namespace std;
#define INFINITY 65535/*设为最大值*/
#define MaxVertexNum 100 /*最大顶点树设为100*/
typedef int Vertex; /*用顶点下标表示为整型*/
typedef int WeightType;/*边的权值设为整型*/
typedef char DataType;/*顶点存储的数据类型设为字符型*/

int Visted[MaxVertexNum];//集合等于false的都属于未被找的最短路径的结点
int dist[MaxVertexNum];//路径长度//
int path[MaxVertexNum];

/*边的定义*/
typedef struct ENode* PtrToENode;
struct ENode {
	Vertex V1, V2;/*有向边<v1,v2>*/
	WeightType Weight;/*权重 */

}; typedef PtrToENode Edge;

/*图的定义*/
typedef struct GNode* PtrToGNode;
struct GNode
{
	int Nv;/*顶点个数*/
	int Ne;/*边的个数*/
	WeightType G[MaxVertexNum][MaxVertexNum];
};
typedef PtrToGNode MGraph;/*以邻接矩阵存储的图的类型*/

MGraph CreateGraph(int VertexNum) {
	/*初始化一个有VN个顶点但没有边的图*/
	Vertex V, W;
	MGraph Graph;
	Graph = new GNode();
	Graph->Nv = VertexNum;
	Graph->Ne = 0;
	/*初始化邻接矩阵*/
	for (V = 0; V < Graph->Nv; V++)
		for (W = 0; W < Graph->Nv; W++)
			Graph->G[V][W] = INFINITY;
	return Graph;
}
void Insert(MGraph Graph, Edge E) {
	Graph->G[E->V1][E->V2] = E->Weight;
}
bool IsEdge(MGraph Graph, Vertex V, Vertex W) {
	return Graph->G[V][W] < INFINITY ? true : false;
}
/*邻接矩阵存储*/

Vertex FindMinDist(MGraph Graph) {
	/*返回未被收入顶点中的最小dist者*/
	Vertex MinV, V;
	int MinDist = INFINITY;
	for (V = 0; V < Graph->Nv; V++) {
		if (Visted[V] == false && dist[V] < MinDist) {
			/*若V未被收录,且dist[V]更小*/
			MinDist = dist[V];/*更新最小距离*/
			MinV = V;/*更新最小顶点*/
		}
	}
	if (MinDist < INFINITY)/*若找到最小dist*/
		return MinV;/*返回对应的顶点下标*/
	else return 0;/*若这样的顶点不存在,返回错误标记*/
}
bool Dijkstra(MGraph Graph, Vertex S) {
	Vertex V, W;

	/*初始化:此处默认邻接矩阵中不存在的边用INFINITY表示*/
	for (V = 0; V < Graph->Nv; V++) {
		dist[V] = Graph->G[S][V];//与S结点邻接把边值放到dist中
		if (dist[V] < INFINITY)//有边记录它的前驱
			path[V] = S; //记录V的前驱V的前驱是S
		else
			path[V] = -1;
		Visted[V] = false;//全部顶点都没有收录
	}
	/*先将收起点收入集合*/
	dist[S] = 0;
	Visted[S] = true;//放到集合中
	while (1) {
		/*找到未被收入顶点中dist最小者*/
		V = FindMinDist(Graph);
		if (!V)/*如不存在*/
			break;//算法结束
		Visted[V] = true;//收录V
		for (W = 0; W < Graph->Nv; W++)
			if (Visted[W] == false && Graph->G[V][W] < INFINITY) {
				if (Graph->G[V][W] < 0)//若有负边
					return false;//
				if (dist[V] + Graph->G[V][W] < dist[W]) {
					dist[W] = dist[V] + Graph->G[V][W];
					path[W] = V;//跟新S到W的路径
				}
			}
	}
	return true;
}
void FindDp(int V) {
	if (V == -1)
		return;
	FindDp(path[V]);
	cout << V << endl;

}
int main()
{
	MGraph Graph = CreateGraph(7);
	Graph->Ne = 12;
	Vertex a[12] = { 0,0,1,1,2,2,3,3,3,3,4,6 };
	Vertex b[12] = { 1,3,3,4,0,5,2,4,5,6,6,5 };
	WeightType w[12] = { 2,1,3,10,4,5,2,2,8,4,6,1 };

	/* 读入边,格式为"起点 终点 权重",插入邻接矩阵 */
	for (int i = 0; i < Graph->Ne; i++) {
		Edge E = (Edge)malloc(sizeof(struct ENode)); /* 建立边结点 */
		E->V1 = a[i]; E->V2 = b[i]; E->Weight = w[i];
		/* 注意:如果权重不是整型,Weight的读入格式要改 */
		Insert(Graph, E);
	}


	for (int i = 0; i < MaxVertexNum; i++) { Visted[i] = false; dist[i] = INFINITY; path[i] = -1; }
	Dijkstra(Graph, 0);
	int n;
	cin >> n;

	FindDp(n);
	return 0;
}

运行结果

四.多源最短路算法

D^k[i][j]表示i到j经过k的最小长度

依次将每个点作为中间点去做更新

k=V-1是D[i][j]将最小路径更新完成

bool Floyd(MGraph Graph) {
	for(int i=0;i<Graph->Nv;i++)
		for (int j = 0; j < Graph->Nv; j++) {
			D[i][j] = Graph->G[i][j];
			path[i][j] = -1;
		}
	/*k表示中间点*/
	for(int k=0;k<Graph->Nv;k++)
		for (int i = 0; i < Graph->Nv; i++)
			for (int j = 0; j < Graph->Nv; j++)
				if (D[i][k] + D[k][j] < D[i][j]) {
					D[i][j] = D[i][k] + D[k][j];
					if (i == j && D[i][j] < 0)/*若出现负边无法解决*/
						return false;
					path[i][j] = k;
				}
	return true;
}

全部代码

#include<iostream>
using namespace std;
#define MaxvertexNum 100/*最大顶点值*/
#define INF 65535/*无穷大表示没有边直接相连*/
typedef int Vertex;/*顶点下标*/
typedef int WeightType;/*权重*/
WeightType D[MaxvertexNum][MaxvertexNum];/*D[i][j],顶点i到顶点j的最短距离*/
Vertex path[MaxvertexNum][MaxvertexNum];/*记录路径*/

/*边的定义*/
typedef struct ENode* PtrToENode;
struct ENode
{
	Vertex V1, V2;
	WeightType Weigtht;
};
typedef PtrToENode Edge;


/*图的定义*/
typedef struct GNode* PtrToGNode;
struct GNode {
	int Nv;/*顶点个数*/
	int Ne; /*边的个数*/
	WeightType G[MaxvertexNum][MaxvertexNum];
};
typedef PtrToGNode MGraph;

MGraph CreateGraph(int Vertexnum) {
	MGraph G = new GNode();
	G->Nv = Vertexnum;
	G->Ne = 0;

	for (int i = 0; i < G->Nv; i++)
		for (int j = 0; j < G->Nv; j++)
			G->G[i][j] = INF;
	return G;
}
void InsertEdeg(MGraph Graph, Edge E) {
	Graph->G[E->V1][E->V2] = E->Weigtht;
	Graph->G[E->V2][E->V1] = E->Weigtht;
}

bool Floyd(MGraph Graph) {
	for(int i=0;i<Graph->Nv;i++)
		for (int j = 0; j < Graph->Nv; j++) {
			D[i][j] = Graph->G[i][j];
			path[i][j] = -1;
		}
	/*k表示中间点*/
	for(int k=0;k<Graph->Nv;k++)
		for (int i = 0; i < Graph->Nv; i++)
			for (int j = 0; j < Graph->Nv; j++)
				if (D[i][k] + D[k][j] < D[i][j]) {
					D[i][j] = D[i][k] + D[k][j];
					if (i == j && D[i][j] < 0)/*若出现负边无法解决*/
						return false;
					path[i][j] = k;
				}
	return true;
}
//void FindDp(int i, int j) {
//	if (path[i][j] == -1)
//		return;
//	FindDp(i, path[i][j]);
//	cout << j;
//}
MGraph BuildGraph() {
	Edge E;
	MGraph Graph;
	Vertex Nv;
	cin >> Nv;/*顶点个数*/
	Graph = CreateGraph(Nv);
	cin >> Graph->Ne;/*输入边的个数*/
	if (Graph->Ne != 0) {

		for (int i = 0; i < Graph->Ne; i++) {
			E = new ENode();
			cin >> E->V1 >> E->V2>>E->Weigtht;
			E->V1--;
			E->V2--;
			InsertEdeg(Graph, E);
		}
	}
	return Graph;
}
int main()
{
	MGraph Graph = BuildGraph();
	Floyd(Graph);
	int i,j;
//	cin >> i>>j;
//	FindDp(i,j);
	return 0;
}

 怎么样打印两点之间的路径还没有写好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值