如果解决的问题:
Dijkstra算法就是解决单源最短路径问题:
步骤:
产生从源点v0到它自身的路径,其长度为0,将源点v0加入最短路径S中。这些通过以下代码就可以实现:
mark[v0] = true;
path[v0] = -1;
curShortLen[v0] = 0;
(2)更新和源点v0直接邻接的所有顶点i对应的curShortLen[i]。
(3)然后找出第一条最短路径及其顶点k。更新path[k]=v0。
(4)将顶点k加入S,并对与顶点k直接邻接的所有顶点i对应的curShortLen[i]进行更新,更新公式为curShortLen[i] = min{curShortLen [i],curShortLen[k]+w(k,i)},其中w(k,i)是边< k,i >上的权值。
(5)求下一条最短路径的终点,也就是还没有加入最短路径的顶点中具有最短的curShortLen[k]值的顶点k。
(6)重复(4)和(5),直到将所有从源点v0可达的顶点都加入最短路径中。
其实,上面步骤中的(4)、(5)和(2)、(3)完全是一样的,我在用代码实现的时候也是将其视为统一情况处理。
代码部分:
//Dijkstra算法的辅助函数,用于找出下一条最短路径的终点
template
int Graph::FinMinLen(T * curShortLen, bool * mark)
{
int minIndex = -1;
T minLen = INT_MAX;
for (int i = 1; i < n; ++i) {
if (!mark[i] && minLen > curShortLen[i]) {
minIndex = i;
minLen = curShortLen[i];
}
}
return minIndex;
}
//迪杰斯特拉算法解决单源最短路径问题
template
void Graph::Dijkstra(int v0)
{
if (v0 < 0 || v0 > n - 1) {
cout << "input error!" << endl;
return;
}
T *curShortLen = new T[n]; //curShortLen[i]存放从源点v0到i的当前最短路径的长度
int *path = new int[n]; //path[i]给出从v0到顶点i的最短路径上,位于顶点i前面的那个顶点
for (int i = 0; i < n; ++i) {
curShortLen[i] = INT_MAX;
path[i] = -1;
}
Dijkstra(v0, path, curShortLen);
}
//迪杰斯特拉算法解决单源最短路径问题,私有,内部调用
template
void Graph::Dijkstra(int v0, int * path, T * curShortLen)
{
bool *mark = new bool[n]; //mark[i]表示顶点i是否已加入单源最短路径里
for (int i = 0; i < n; ++i) {
mark[i] = false;
}
mark[v0] = true;
path[v0] = -1;
curShortLen[v0] = 0;
int k = v0; //最近加入单源最短路径中的顶点
int nextK = -1; //即将加入单源最短路径中的顶点
ENode *p;
int count = 0; //用来计数单源最短路径上有多少条边
for (int i = 1; i < n; ++i) { //循环n-1次,将其他顶点都加入单源最短路径中
for (p = enodes[k]; p; p = p->next) {
int j = p->adjVex;
if (!mark[j] && curShortLen[j] > curShortLen[k] + p->weight) {
curShortLen[j] = curShortLen[k] + p->weight; //保证curShortLen[j] = min{curShortLen[j],curShortLen[k]+p->weight}
}
}
nextK = FinMinLen(curShortLen, mark); //找到下一条最短路径的终点
if (-1 == nextK) { //返回-1,说明从v0出发的单源最短路径已经都找到了
break;
}
else {
mark[nextK] = true; //加入最短路径中
path[nextK] = k; //记录终点信息,方便回溯
k = nextK; //k指向最近加入的顶点
count++; //路径上的边数加1
}
}
//输出最短路径结果
cout << "shortest path:" << endl;
int lastVer; //最短路径中的上个顶点
stack tmp; //用栈来逆序储存最短路径上的顶点
for (int i = 1; i <= count; ++i) {
cout << curShortLen[k] << " : ";
tmp.push(k);
lastVer = path[k];
while (lastVer != v0) {
tmp.push(lastVer);
lastVer = path[lastVer];
}
tmp.push(v0);
cout << tmp.top();
tmp.pop();
while (!tmp.empty()) {
cout << "->" << tmp.top();
tmp.pop();
}
cout << endl;
k = path[k]; //将k置为最短路径上在该点之前的那个顶点
}
}
解决所有顶点之间的最短路径。
步骤:
Floyd算法的思想是:设集合S的初始状态为空集合,然后依次向集合S中加入顶点0,1…,n-1,每次加入一个顶点,我们更新d[i][j]。d[i][j]被定义为从i到j中间只经过S中的顶点的、所有可能路径中的最短路径的长度。如果从i到j,中间只经过S中的顶点当前没有路径相通,那么d[i][j]为一个大值INT_MAX。随着S中的顶点不断增加,d[i][j]的值不断修正,当所有顶点都加入S中时,d[i][j]的值就是从i到j的最短路径。
代码:
//获得边u-v的权值
template
T Graph::GetWeight(int u, int v)
{
if (u == v) {
return 0;
}
ENode *p = enodes[u];
while (p != NULL && p->adjVex != v) {
p = p->next;
}
if (p) {
return p->weight;
}
else {
// cout<<"edge "<
void Graph::Floyd()
{
int path[n][n]; //n*n矩阵,path[i][j]表示从顶点i到j的最短路径上,顶点j的前一个顶点
T d[n][n]; //d[i][j]存放从顶点i到顶点j的当前最短路径的长度
int i, j, k;
//初始化矩阵
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
d[i][j] = GetWeight(i, j);
if (i != j && d[i][j] < INT_MAX) {
path[i][j] = i;
}
else {
path[i][j] = -1;
}
}
}
for (k = 0; k < n; k++) { //n次更新矩阵
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (d[i][k] + d[k][j] < d[i][j])
{ //加入顶点k之后更新矩阵
d[i][j] = d[i][k] + d[k][j];
path[i][j] = path[k][j];
}
}
}
}
//输出所有顶点之间的最短路径结果
cout << "shortest path between two vertex:" << endl;
stack tmp; //用栈来逆序储存最短路径上的顶点
int m;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (i == j) {
continue;
}
cout << "from " << i << " to " << j << " : ";
if (path[i][j] == -1) { //表示不可达
cout << "not connected" << endl;
}
else {
tmp.push(j);
m = path[i][j];
while (m != -1) { //在最短路径上进行反向回溯
tmp.push(m);
m = path[i][m];
}
cout << tmp.top();
tmp.pop();
while (!tmp.empty()) {
cout << "->" << tmp.top();
tmp.pop();
}
cout << endl;
}
}
}
}
有关基础的定义在我博客图的章有全部源码,可以关注我的博客,在数据结构与算法的章节,有相关的源码,与对应的博客,小伙伴们,一起加油吧。