最短路径——单源最短路径(无权图-BFS最短路径)、Dijkstra算法、Floyd算法(王道版)

参考王道《2023年数据结构考研复习指导》

一、单源最短路径-无权图-BFS最短路径

#include <iostream>

#define MaxVerTexNum 20

typedef char VertexType;							// 顶点的数据类型
typedef int EdgeType;								// 带权图中边上权值的数据类型

// 邻接矩阵存储图
typedef struct {
	VertexType Vex[MaxVerTexNum];					// 顶点表
	EdgeType Edge[MaxVerTexNum][MaxVerTexNum];		// 邻接矩阵,边表
	int vexnum, arcnum;								// 图的当前顶点数和边数/弧数
} MGraph;

// 链式队列结点
typedef struct LinkNode {
	int data;					// 存储图的顶点的下标
	struct LinkNode* next;
} LinkNode;

// 链式队列
typedef struct LinkQueue {
	LinkNode* front, * rear;
} LinkQueue;

bool visited[MaxVerTexNum];		// 已访问标志数组
int d[MaxVerTexNum];			// 记录每个顶点到u的最短路径长度
int path[MaxVerTexNum];			// 记录每个顶点在广度优先生成树中的父节点

bool InitQueue(LinkQueue& Q);
bool IsEmpty(LinkQueue Q);
bool EnQueue(LinkQueue& Q, int x);
bool DeQueue(LinkQueue& Q, int& x);
void DestroyQueue(LinkQueue& Q);
int FirstNeighbor(MGraph G, int x);
int NextNeighbor(MGraph G, int x, int y);
void BFS_MIN_Distance(MGraph G, int u);

int main() {
	MGraph G = {
		{'1', '2', '3', '4', '5', '6', '7', '8'},
		{
			{0,1,0,0,1,0,0,0},
			{1,0,0,0,0,1,0,0},
			{0,0,0,1,0,1,1,0},
			{0,0,1,0,0,0,1,1},
			{1,0,0,0,0,0,0,0},
			{0,1,1,0,0,0,1,0},
			{0,0,1,1,0,1,0,1},
			{0,0,0,1,0,0,1,0},
		},
		8, 10
	};

	BFS_MIN_Distance(G, 1);

	for (int i = 0; i < G.vexnum; ++i) {
		std::cout << d[i] << " ";
	}
	std::cout << std::endl;

	for (int i = 0; i < G.vexnum; ++i) {
		std::cout << path[i] << " ";
	}
	std::cout << std::endl;

	system("pause");
	return 0;
}

/*==================================================================*/
// 初始化队列(带头结点)
bool InitQueue(LinkQueue& Q) {
	Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
	if (Q.front == NULL)
		return false;

	Q.front->next = NULL;
	return true;
}

// 判断队列是否为空
bool IsEmpty(LinkQueue Q) {
	if (Q.front == Q.rear)
		return true;
	else
		return false;
}

// 入队(带头结点)
bool EnQueue(LinkQueue& Q, int x) {
	LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
	if (s == NULL)
		return false;
	s->data = x;
	s->next = NULL;
	Q.rear->next = s;
	Q.rear = s;
	return true;
}

// 出队(带头结点)
bool DeQueue(LinkQueue& Q, int& x) {
	if (IsEmpty(Q))
		return false;

	LinkNode* p = Q.front->next;
	x = p->data;
	Q.front->next = p->next;
	if (p == Q.rear)			// 若此时是最后一个结点出队
		Q.rear = Q.front;
	free(p);
	return true;
}

void DestroyQueue(LinkQueue& Q) {
	LinkNode* p = Q.front->next;
	LinkNode* q;
	while (p != NULL) {
		q = p;
		p = p->next;
		free(q);
	}
	free(Q.front);
	Q.front = Q.rear = NULL;
}

/*==================================================================*/
// 求图G中顶点x(下标)的第一个邻接点,若有则返回顶点号。若x没有邻接点或图中不存在x,则返回-1
int FirstNeighbor(MGraph G, int x) {
	if (x >= G.vexnum)
		return -1;

	int i = 0;
	while (i < G.vexnum) {
		if (G.Edge[x][i] != 0)
			return i;
		i++;
	}
	return -1;
}

// 假设图G中顶点y是顶点x的一个邻接点,返回除y之外顶点x的下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1
int NextNeighbor(MGraph G, int x, int y) {
	if (x >= G.vexnum || y >= G.vexnum)
		return -1;

	int i = y + 1;
	while (i < G.vexnum) {
		if (G.Edge[x][i] != 0)
			return i;
		i++;
	}
	return -1;
}

/*==================================================================*/
// 求顶点u到其他顶点的最短路径
void BFS_MIN_Distance(MGraph G, int u) {	// 从顶点u出发,广度优先遍历图G
	for (int i = 0; i < G.vexnum; ++i) {
		d[i] = -1;		// -1代表无穷大
		path[i] = -1;	// 最短路径从哪个定点过来
	}
	
	d[u] = 0;
	visited[u] = true;
	LinkQueue Q;
	InitQueue(Q);
	EnQueue(Q, u);							// 顶点u入队列Q
	while (!IsEmpty(Q)) {
		DeQueue(Q, u);						// 顶点u出队列
		for (int w = FirstNeighbor(G, u); w >= 0; w = NextNeighbor(G, u, w)) {	//检测v所有邻接点
			if (!visited[w]) {				// w为v的尚未访问的邻接点
				d[w] = d[u] + 1;			// 路径长度加1
				path[w] = u;				// 最短路径应从u到w
				visited[w] = true;			// 对w做已访问标记
				EnQueue(Q, w);				// 顶点w入队
			}
		}
	}
	DestroyQueue(Q);
}

二、Dijkstra算法

#include <iostream>

#define MaxVerTexNum 20								

typedef char VertexType;							// 顶点的数据类型
typedef int EdgeType;								// 带权图中边上权值的数据类型

// 邻接矩阵存储图
typedef struct {
	VertexType Vex[MaxVerTexNum];					// 顶点表
	EdgeType Edge[MaxVerTexNum][MaxVerTexNum];		// 邻接矩阵,边表
	int vexnum, arcnum;								// 图的当前顶点数和边数/弧数
} MGraph;

bool final[MaxVerTexNum];							// 标记各顶点是否已找到最短路径
EdgeType dist[MaxVerTexNum];						// 最短路径长度
int path[MaxVerTexNum];								// 路径上的前驱(记录前驱节点的下标)

void ShortestPath_Dijkstra(MGraph G, int u);
void get_Path(int u, int v);
void find_Path(int v);

int main() {
	MGraph G = {
		{'0', '1', '2', '3', '4'},
		{
			{-1, 10, -1, -1, 5},
			{-1, -1, 1, -1, 2},
			{-1, -1, -1, 4, -1},
			{7, -1, 6, -1, -1},
			{-1, 3, 9, 2, -1}
		},
		5, 10
	};

	ShortestPath_Dijkstra(G, 0);
	get_Path(0, 2);

	system("pause");
	return 0;
}

// 从顶点u出发,到其他结点的最短路径
void ShortestPath_Dijkstra(MGraph G, int u) {
	for (int i = 0; i < G.vexnum; ++i) {		// 初始化辅助数组
		final[i] = false;
		dist[i] = G.Edge[u][i];
		path[i] = G.Edge[u][i] == -1 ? -1 : 0;
	}
	final[u] = true;
	dist[u] = 0;				// 顶点u到自身的最短距离为0

	for (int i = 0; i < G.vexnum; ++i) {
		if (i == u)
			continue;
		int min = -1;			// -1代表无穷大
		int v;					// 下一个已找到最短路径的结点
		for (int j = 0; j < G.vexnum; ++j) {
			if (final[j] == false) {
				if (min == -1 && dist[j] != -1) {
					v = j;
					min = dist[j];
				}
				else if (min != -1 && dist[j] != -1 && dist[j] < min) {
					v = j;
					min = dist[j];
				}
			}
		}
		final[v] = true;
		
		for (int j = 0; j < G.vexnum; ++j) {		// 更新dist和path信息
			if (final[j] == false) {
				if (dist[j] == -1 && G.Edge[v][j] != -1) {
					dist[j] = dist[v] + G.Edge[v][j];
					path[j] = v;
				}
				else if (dist[j] != -1 && G.Edge[v][j] != -1 && dist[j] > dist[v] + G.Edge[v][j]) {
					dist[j] = dist[v] + G.Edge[v][j];
					path[j] = v;
				}
			}
		}

	}
}

void get_Path(int u, int v) {
	std::cout << "从" << u << "到" << v << "的最短距离为:" << dist[v] << std::endl
		<< "路径为:";
	find_Path(v);
	std::cout << std::endl;
}

void find_Path(int v) {
	if (path[v] == -1) {
		std::cout << v;
	}
	else
	{
		find_Path(path[v]);
		std::cout << " -> " << v;
	}
}

三、Floyd算法

#include <iostream>

#define MaxVerTexNum 20								

typedef char VertexType;							// 顶点的数据类型
typedef int EdgeType;								// 带权图中边上权值的数据类型

// 邻接矩阵存储图
typedef struct {
	VertexType Vex[MaxVerTexNum];					// 顶点表
	EdgeType Edge[MaxVerTexNum][MaxVerTexNum];		// 邻接矩阵,边表
	int vexnum, arcnum;								// 图的当前顶点数和边数/弧数
} MGraph;

int A[MaxVerTexNum][MaxVerTexNum];					// 各顶点间的最短路径长度
int path[MaxVerTexNum][MaxVerTexNum];				// 两顶点之间的中转点

void ShortestPath_Floyd(MGraph G);
void get_Path(int u, int v);
void find_Path(int u, int v);

int main() {
	MGraph G = {
		{'0', '1', '2', '3', '4'},
		{
			{-1, -1, 1, -1, 10},
			{-1, -1, -1, 1, 5},
			{-1, 1, -1, -1, 7},
			{-1, -1, -1, -1, 1},
			{-1, -1, -1, -1, -1},
		},
		5, 7
	};

	ShortestPath_Floyd(G);
	get_Path(0, 4);

	system("pause");
	return 0;
}

void ShortestPath_Floyd(MGraph G) {
	for (int i = 0; i < G.vexnum; ++i) {
		for (int j = 0; j < G.vexnum; ++j) {
			A[i][j] = G.Edge[i][j];
			path[i][j] = -1;
		}
	}

	for (int k = 0; k < G.vexnum; ++k) {			// 以Vk作为中转点
		for (int i = 0; i < G.vexnum; ++i) {
			for (int j = 0; j < G.vexnum; ++j) {
				if (A[i][j] == -1 && A[i][k] != -1 && A[k][j] != -1) {
					A[i][j] = A[i][k] + A[k][j];
					path[i][j] = k;
				}
				else if (A[i][j] != -1 && A[i][k] != -1 && A[k][j] != -1 && A[i][j] > A[i][k] + A[k][j]) {
					A[i][j] = A[i][k] + A[k][j];
					path[i][j] = k;
				}
			}
		}
	}
}

void get_Path(int u, int v) {
	std::cout << "从" << u << "到" << v << "的最短距离为:" << A[u][v] << std::endl
		<< "路径为:";
	std::cout << u << " -> ";
	find_Path(u, v);
	std::cout << v << std::endl;
}

void find_Path(int u, int v) {
	if (path[u][v] != -1) {
		find_Path(u, path[u][v]);
		std::cout << path[u][v] << " -> ";
		find_Path(path[u][v], v);
	}
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
离字典,将起始节点的距离设为0,其他节点的距离设为无穷大 distances = {node: sys.maxsize for node in graph} distances[start] = 0 # 初始化已访问节点的集合和未访以下是使用问节点D的集ijkstra合 visited = set() unvisited算法求解最短路径的Python = set(graph) while unvisited: # 代码示例: ```python class D选择当前ijkstra距: def __init__(self, graph离最小的节点 , start, current goal): self.graph = graph # 邻接表_node = min(unvisited, key=lambda self node: distances[node]) # 更新.start = start当前节点的 # 起邻居节点点 self.goal =的距离 goal # 终点 for neighbor in graph self.open[current_node]: _list = {} if neighbor in # open 表 self.closed_list unvisited: new_distance = distances[current_node] + = {} graph[current_node][neighbor # closed 表 self.open_list[start] if new_distance] = < distances[neighbor]: 0.0 # 将 distances[neighbor] = new_distance # 将当前起点放入 open_list 中 self.parent = {节点标记start:为已访 None} 问,并从未访问集合中移除 visited.add # 存储节点的父子关系。键为(current_node) 子节点, unvisited值为父.remove(current_node) return节点。方便做最 distances def print后_path(dist路径的ances,回 start溯 self.min, end): _dis = None # 根 # 最短路径的长度 def shortest_path据距离字典和终点节点(self): while True: ,逆向 if self打印路径.open_list is path = [end None: ] print('搜索 current_node =失败 end while current_node !=, 结束!') break distance start: , min_node = for neighbor in graph min(zip[current_node]: if(self.open_list distances[current.values(), self_node] ==.open_list.keys distances[neighbor())) #] + graph 取出距[neighbor][current_node]: 离最小的节点 self path.open_list.pop.append(min_node)(neighbor) current_node = neighbor break path.reverse() # 将其从 open_list 中去除 self print.closed("_list[minShortest_node] = path from", distance # 将节点加入 closed start, "to", end,_list ":", "->".join(path)) # 示例 中 if min_node == self.goal: # 如果节点为的邻接矩阵终点 self.min_dis = distance 表示 graph shortest = { _path = [ 'Aself.goal]': {'B': # 5, 'C 记录从': 终1}, 点回溯的路径 'B

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

陈阿土i

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值