最短距离Dijkstra算法
算法思想:使用广度优先搜索解决赋权有向图或者无向图的单源最短路径,最终得到一个最短路径树。
算法初始化:
1、最短距离数组dis,起点能直接到达的顶点相应的设置其值,起点不能直接达到的顶点的路径长度设为无穷大。
2、最短路径顶点集合T,初始集合中只有起点。
算法过程:
1、从最短距离数组dis中选择最小值,将其加入T集合
2、判断加入的该顶点是否可以到达其他顶点,如果可以到达的其他顶点的路径长度比起点直接到达短,那么更新这些顶点在dis中的值。
3、继续从dis中选择最小值,重复上述动作,直到T中包含图的所有顶点。
代码实现说明:
1、vertexes数组,记录从起始顶点到每个顶点的距离dist,起初把所有顶点的dist都初始化为无穷大,把起始顶点的dis值初始化为0,然后放其到优先级队列中。
2、predecessor数组,记录每个顶点的前驱顶点,为了还原最短路径方便。
3、inqueue数组,记录顶点是否曾添加到优先级队列中,为了避免一个顶点被多次添加到队列中。
4、从优先级队列中取出dist最小的顶点minVertex,然后看这个最小顶点能到达的所有顶点。如果minVertex的dist加上它与nextVertex之间边的权重w小于nextVertex当前dist值,那么将nextVertex的dist更新为minVerext的dist加上w,然后把nextVertex加入到优先级队列中。重复这个过程直到找到终止顶点t或者队列为空。
#include<iostream>
#include<vector>
#include<limits.h>
using namespace std;
class Edge {
public:
int sid; // 边的起始顶点编号
int tid; //边的终止顶点编号
int w; //权重
Edge(int sid, int tid, int w) {
this->sid = sid;
this->tid = tid;
this->w = w;
}
};
class Graph {
private:
vector<Edge *> * adj; //邻接表
int v; //顶点个数
public:
Graph(int v) {
this->v = v;
this->adj = new vector<Edge *>[v];
}
~Graph() {
if (this->adj != NULL) {
for (int i = 0; i < v; ++i) {
for (int j = 0; j < adj[i].size(); ++j) {
delete adj[i][j];
}
}
delete [] adj;
}
}
// 添加边
void AddEdge(int s, int t, int w) {
Edge * e = new Edge(s, t, w);
adj[s].push_back(e);
}
void Dijkstra(int s, int t); //Dijkstra算法
void Print(int s, int t, int * predecessor);
};
class Vertex {
public:
int id; //顶点编号
int dist; //从起始顶点到这个顶点的距离
Vertex (int id, int dist) {
this->id = id;
this->dist = dist;
}
Vertex () {
this->id = 0;
this->dist = INT_MAX;
}
};
class PriorityQueue {
private:
Vertex * nodes; //顶点和边信息
int size; //堆可以存储的最大数据个数
int count; //堆中已经存储的数据个数
public:
PriorityQueue(int v) {
nodes = new Vertex[v+1];
size = v + 1;
count = 0;
}
~PriorityQueue() {
if (nodes != NULL) {
delete [] nodes;
}
count = 0;
}
void Add(Vertex* ver); //将元素加入堆中
void Update(Vertex* ver); //更新堆中元素值
bool IsEmpty();
void Print();
Vertex Poll(); //取出堆顶元素并删除
void Adjust(int index); //堆化操作
};
Vertex PriorityQueue::Poll() {
Vertex top(nodes[1].id, nodes[1].dist);
nodes[1] = nodes[count];
count--;
int index = 1;
while(true) {
int maxpos = index;
if (2 * index < count && nodes[2 * index].dist < nodes[maxpos].dist) {
maxpos = 2 * index;
}
if (2 * index + 1 < count && nodes[2 * index + 1].dist < nodes[maxpos].dist) {
maxpos = 2 * index + 1;
}
if (maxpos == index) {
break;
}
int tmp_dist = nodes[index].dist;
int tmp_id = nodes[index].id;
nodes[index].dist = nodes[maxpos].dist;
nodes[index].id = nodes[maxpos].id;
nodes[maxpos].dist = tmp_dist;
nodes[maxpos].id = tmp_id;
}
return top;
}
bool PriorityQueue::IsEmpty() {
return count == 0;
}
void PriorityQueue::Add(Vertex* ver) {
if(count < size) {
count++;
nodes[count].dist = ver->dist;
nodes[count].id = ver->id;
//自下而上进行堆化
Adjust(count);
} else {
cout << "error! size is full!" << endl;
}
}
void PriorityQueue::Adjust(int index) {
int i = index;
while (i / 2 > 0 && nodes[i / 2].dist > nodes[i].dist) {
int tmp_dist = nodes[i / 2].dist;
int tmp_id = nodes[i / 2].id;
nodes[i / 2].dist = nodes[i].dist;
nodes[i / 2].id = nodes[i].id;
nodes[i].dist = tmp_dist;
nodes[i].id = tmp_id;
}
}
void PriorityQueue::Update(Vertex* ver) {
bool isupdate = false;
for (int i = 1; i <= count; ++i) {
if (nodes[i].id == ver->id) {
nodes[i].dist = ver->dist;
isupdate = true;
Adjust(i);
break;
}
}
if (isupdate == false) {
cout << "error! not find id:" << ver->id << endl;
}
}
void PriorityQueue::Print() {
for (int i = 1; i <= count; ++i) {
cout << nodes[i].dist << " ";
}
cout << endl;
}
void Graph::Dijkstra(int s, int t) {
// predecessor 存放前驱节点,用来还原最短路径
int * predecessor = new int[v];
Vertex* vers = new Vertex[v];
// inqueue 标记是否进入过队列
bool * inqueue = new bool[v];
for (int i = 0; i < v; ++i) {
vers[i].id = i;
inqueue[i] = false;
}
//小顶堆
PriorityQueue* q = new PriorityQueue(v);
q->Print();
vers[s].dist = 0;
inqueue[s] = true;
q->Add(&vers[s]);
225 }
while (!q->IsEmpty()) {
Vertex minV = q->Poll(); //取出堆顶元算并删除
if (minV.id == t) break; // 这就是最短路径
for (int i = 0; i < adj[minV.id].size(); ++i) {
Edge * e = adj[minV.id][i];
Vertex nextV = vers[e->tid];
if (minV.dist + e->w < nextV.dist) {
nextV.dist = minV.dist + e->w;
predecessor[nextV.id] = minV.id;
if (inqueue[nextV.id] == true) {
q->Update(&nextV);
} else {
q->Add(&nextV);
inqueue[nextV.id] = true;
}
}
}
}
cout << s;
Print(s, t, predecessor);
cout << endl;
}
void Graph::Print(int s, int t, int * predecessor) {
if (s == t) return;
Print(s, predecessor[t], predecessor);
cout << "->" << t;
}
int main() {
Graph g(6);
g.AddEdge(0, 1, 10);
g.AddEdge(0, 4, 15);
g.AddEdge(1, 2, 15);
g.AddEdge(1, 3, 2);
g.AddEdge(2, 5, 5);
g.AddEdge(3, 2, 1);
g.AddEdge(3, 5, 12);
g.AddEdge(4, 5, 10);
g.Dijkstra(0, 5);
}