Dijkstra堆优化解析

用vector数组来存储每个节点的相邻节点

#include<iostream>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1000010;
/*
	边尾=====>边头
*/
struct qnode {
	int v;//顶点index
	int c;//源点到该顶点的最短距离
	qnode(int _v = 0, int _c = 0) :v(_v), c(_c) {}
	//重载<, 变成最小堆(根据源点到节点的路径长度从大到小排,优先队列中top元素是最小的)
	bool operator <(const qnode& r)const {
		return c > r.c;
	}
};
struct Edge {
	int v, cost;//和找到的最短路径节点相邻的顶点,连接这两个顶点边权重
	Edge(int _v = 0, int _cost = 0) :v(_v), cost(_cost) {}
};
vector<Edge>AdjList[MAXN];//类似邻接表(边节点以顺序表存储)
bool vis[MAXN];//访问数组
int dist[MAXN];//距离数组
//点的编号从 1 开始
void Dijkstra(int n, int start) {	//顶点数,源点
	memset(vis, false, sizeof(vis));//访问数组初始化全false
	for (int i = 1; i <= n; i++)	//距离数组初始化inf
		dist[i] = INF;
	priority_queue<qnode>que;
	dist[start] = 0;
	que.push(qnode(start, 0));//源点入队
	qnode tmp;
	while (!que.empty()) {
		tmp = que.top();	//因为重载了<,top节点到源点距离一定是最短的
		que.pop();
		int u = tmp.v;		//找到的最短路径节点的节点号u
		if (vis[u])			//判断是否已经访问过了
			continue;
		vis[u] = true;		//设置成已访问
		//对当前找到的最短路径节点的边界点组访问(和该节点相邻的节点,用到邻接表知识)
		for (int i = 0; i < AdjList[u].size(); i++) {
			int v = AdjList[u][i].v;	//边头节点
			int cost = AdjList[u][i].cost;//边权重
			//1.这个节点没被访问
			//2.上一轮源节点到该节点的距离>从源点到当前最短路径节点距离+当前最短路径节点到这个节点的距离
			if (!vis[v] && dist[v] > dist[u] + cost) {
				dist[v] = dist[u] + cost;//更新
				que.push(qnode(v, dist[v]));//进入优先队列,为下一轮找最短路径节点做准备
			}
		}
	}
}
//边尾,边头,权重
//向类似邻接表添加边
void addedge(int u, int v, int w) {
	AdjList[u].push_back(Edge(v, w));
}

int main() {
	addedge(1, 3, 8);
	addedge(3, 4, 5);
	addedge(4, 5, 6);
	addedge(1, 2, 13);
	addedge(2, 6, 9);
	addedge(2, 7, 7);
	addedge(1, 5, 30);
	addedge(5, 6, 2);
	addedge(6, 7, 17);
	addedge(1, 7, 32);
	Dijkstra(7, 1);
	cout << "以V1为起点,到各点的最短路径:" << endl;
	for (int i = 1; i <= 7; i++)
		cout << 'V' << i  << "\t";
	cout << endl;
	for (int i = 1; i <= 7; i++)
		printf("%2d\t", dist[i]);

}

测试例子:
在这里插入图片描述
测试结果:
在这里插入图片描述

发布了3 篇原创文章 · 获赞 1 · 访问量 29

猜你喜欢

转载自blog.csdn.net/weixin_42341040/article/details/105297013