课本Dijkstra算法Cpp实现及改正

01点17分,又是一个与奇怪问题较量的夜晚,这一次,我又成功解决了。

起因是发现数据结构书上关于Dijkstra算法的实现有点错误,想要自己更正一下,通过在不同位置插入输出字符来调试代码,找到了几处错漏。

  • 96行的char直接赋值给string出现乱码,两种办法,一是string+=char,另一种是string.puch_back(char)

  • 107行,由于是无向图,有可能路径会重复连上两次,我们要让路径不再逆向连接,例如A起始,默认第一轮是已知AB最短为10,在判断最短路径时,没有排除A,到时AB又连上A,变成ABA,而这个ABA是在path[0]上的,虽然每轮输出最短路径时就不需要输出path[起始点],这样子的错误也是无妨,只需要跳过path[起始点]即可,但是在调试过程中发现这个错漏,还是从根本上修正,可以把它改成有向图,把初始化的arc[j][i]=w去掉。

  • (自己的问题)输出结果为?,发现原来是经典for循环是其他变量在递增时还是写了i++…导致循环出不来

  • 还有一个注意点需要补充,就是可变参数友元函数的声明:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    template <class DataType>
    class MGraph
    {
    ...
    template <class T>
    friend void Dijkstra(MGraph<T> MG,int v);//友元函数声明,注意不可是DataType,会和类冲突,得换掉,这里是T
    }

    //函数实现
    template <class DataType>
    void Dijkstra(MGraph<DataType> MG,int v){//这里可以是DataType
    ...
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//图 DFS BFS Dijkstra 完整代码
#include <iostream>
using namespace std;

#include<string>

const int MaxSize = 10; //图中最多顶点个数
int visited[MaxSize]={0};

struct element
{
int lowcost, adjvex;
};
int Min(int dist[],int ver){
int min=255,minNum=0;
for(int i=0;i<ver;i++){
if(dist[i]<min&&dist[i]>0){
min=dist[i];
minNum=i;
}
}
return minNum;
}
template <class DataType>
class MGraph
{
public:
MGraph(DataType a[ ], int n, int e); //构造函数,建立具有n个顶点e条边的图
~MGraph( ) { } //析构函数为空
void DFSTraverse(int v); //深度优先遍历图
void BFSTraverse(int v); //广度优先遍历图
template <class T>
friend void Dijkstra(MGraph<T> MG,int v);
private:
DataType vertex[MaxSize]; //存放图中顶点的数组
int arc[MaxSize][MaxSize]; //存放图中边的数组
int vertexNum, arcNum; //图的顶点数和边数
};

template <class DataType>
MGraph<DataType>::MGraph(DataType a[ ], int n, int e)
{
int i, j, w=0;
vertexNum=n; arcNum=e;
for (i=0; i<vertexNum; i++)
vertex[i]=a[i];
for (i=0; i<vertexNum; i++)
for (j=0; j<vertexNum; j++)
arc[i][j]=255; // 假设极大值为255,表示两个顶点不邻接
for (int k=0; k<arcNum; k++)
{
cout<<"请输入边的两个顶点的序号:";
cin>>i;
cin>>j;
// arc[i][j]=1; arc[j][i]=1;
cout<<"请输入边的权值:";
cin>>w;
arc[i][j]=w;
// arc[j][i]=w;//改成有向图,使得路径不重复
}
}

template <class DataType>
void MGraph<DataType>::DFSTraverse(int v)
{
cout << vertex[v]; visited[v] = 1;
for (int j = 0; j < vertexNum; j++)
if (arc[v][j] <255 && visited[j]==0)
DFSTraverse(j);
}

template <class DataType>
void MGraph<DataType>::BFSTraverse(int v)
{
int Q[MaxSize];
int front = -1, rear = -1; //初始化队列,假设队列采用顺序存储且不会发生溢出
cout << vertex[v]; visited[v] = 1; Q[++rear] = v; //被访问顶点入队
while (front != rear) //当队列非空时
{
v = Q[++front]; //将队头元素出队并送到v中
for (int j = 0; j < vertexNum; j++)
if (arc[v][j] <255 && visited[j] == 0 ) {
cout << vertex[j];
visited[j] = 1;
Q[++rear] = j;
}
}
}
template <class DataType>
void Dijkstra(MGraph<DataType> MG,int v){
int i,k,num,dist[MaxSize];
string path[MaxSize];
for(int i=0;i<MG.vertexNum;i++){
dist[i]=MG.arc[v][i];
if(dist[i]!=255){
// path[i]=MG.vertex[v]+MG.vertex[i] char直接赋值给string这是不行的
path[i].push_back(MG.vertex[v]);//要用push_back
path[i].push_back(MG.vertex[i]);
}
else path[i]="";
cout<<"|"<<i<<" "<<path[i]<<"|"<<" ";
}
cout<<endl;
for(num=1;num<MG.vertexNum;num++){
k=Min(dist,MG.vertexNum);
cout<<"path"<<k<<" "<<path[k]<<","<<dist[k]<<";";
for(i=0;i<MG.vertexNum;i++){
if(dist[i]>dist[k]+MG.arc[k][i]){
dist[i]=dist[k]+MG.arc[k][i];
path[i]=path[k]+MG.vertex[i];
}
}
dist[k]=0;
cout<<endl;
}
}
int main()
{
char ch[]={'A','B','C','D','E'};
MGraph<char> MG(ch, 5, 7);
for (int i=0; i<MaxSize; i++)
visited[i]=0;
cout<<"深度优先遍历序列是:";
MG.DFSTraverse(0);
cout<<endl;
for (int i=0; i<MaxSize; i++)
visited[i]=0;
cout<<"广度优先遍历序列是:";
MG.BFSTraverse(0);
cout<<endl;
cout<<"从顶点"<<ch[0]<<"到各终点的最短路径分别是:"<<endl;
Dijkstra(MG,0);
cout<<endl;
system("pause");
return 0;
}