這個(gè)代碼是在圖的鄰接矩陣(無項(xiàng)、有權(quán))的代碼的基礎(chǔ)上,添加了dijkstra最短路徑函數(shù),并且修改測(cè)試用例和主函數(shù)代碼,圖的鄰接矩陣(無項(xiàng)、有權(quán))的代碼具體請(qǐng)查看 【C語言\數(shù)據(jù)結(jié)構(gòu)】圖之鄰接矩陣(無向、有權(quán))代碼簡(jiǎn)單實(shí)現(xiàn),這里就不過多贅述。
dijkstra最短路徑實(shí)現(xiàn)思路
我們用一個(gè)案例來解釋dijkstra最短路徑的思路:
引入問題:求A頂點(diǎn)到達(dá)其他頂點(diǎn)的最短路徑長(zhǎng)度和最短路徑。
引入定義:一個(gè)頂點(diǎn)到達(dá)其他頂點(diǎn)的直接距離的最小值就是最短路徑。
例如,A頂點(diǎn)可以到達(dá)BDEF四個(gè)頂點(diǎn),直接距離分別是AB2,AD4,AE3,AF5,這些距離的最短直接距離是AB2,則AB2就是最短路徑。
因?yàn)槿绻阆霃腁到達(dá)其他頂點(diǎn)再從其他頂點(diǎn)到達(dá)B,第一步的距離一定要比AB這個(gè)直接距離大,所以AB就是最短路徑。
接著我們引入judgment[i]和dist[i]和path[i]一維數(shù)組,分別表示A頂點(diǎn)到i頂點(diǎn)最短路徑有無確定,A頂點(diǎn)到i頂點(diǎn)的最短路徑,和該最短路徑中i頂點(diǎn)的前一個(gè)頂點(diǎn)的下標(biāo)。
首先我們?cè)L問A頂點(diǎn),把A頂點(diǎn)到其他頂點(diǎn)的直接距離,修正到dist數(shù)組中,也就是目前A頂點(diǎn)到其他頂點(diǎn)的最短路徑長(zhǎng)度,path數(shù)組都存儲(chǔ)A,因?yàn)槟壳暗淖疃搪窂街?,各頂點(diǎn)的前一個(gè)頂點(diǎn)的下標(biāo)就是A。
接著我們找到最短的直接距離,依據(jù)定義我們知道AB就是A到B的最短路徑,把judgment[B]修正為true,表示A到B的最短路徑已經(jīng)確定,然后訪問B頂點(diǎn),看看A到B再由B頂點(diǎn)到其他頂點(diǎn)的距離,會(huì)不會(huì)比目前存儲(chǔ)的dist最短路徑還要小,如果還要小,就修正dist和path數(shù)組。
第一步,訪問A頂點(diǎn),得到:
第二步:找到dist中最小的值,這個(gè)值的judgement必須為false,已經(jīng)確定的最短路徑就不需要訪問了。把judgement[B]置true,由B頂點(diǎn)修正dist和path。B頂點(diǎn)到C頂點(diǎn)距離是2,ABC距離一共是4,比dist存儲(chǔ)的無窮要小,就修正dist,接著修正path。
第三步:在還沒有確定最短路徑的頂點(diǎn)中,找dist最小的值,EF隨便選一個(gè),再由E頂點(diǎn)修正其他沒有確定最短路徑的頂點(diǎn)的dist和path,由于E只能到D或者A,A頂點(diǎn)最短路徑已經(jīng)確定不考慮,ED是2,2+3=5大于4,所以不用修正。
第四步:F中找到dist最小的頂點(diǎn)F,把F頂點(diǎn)的judgmen改為T,再通過F頂點(diǎn)修正dist和path,由于F只能到A或者B,AB的最短路徑已經(jīng)確定,不考慮。
第五步:在judgment為F的頂點(diǎn)中找到dist最小的頂點(diǎn),CD選一個(gè)C,judgement改為T,由C頂點(diǎn)修正剩下judgment為F的頂點(diǎn),C可以到BD,B最短路徑已經(jīng)確定不考慮,CD是2,C的dist4+2大于D的dist,不修正。
第六步:
編寫dijkstra最短路徑函數(shù)
void dijkstra(graph g, int v, int dist[], int path[]) {
bool judgment[MAX];
for (int i = 1; i <= g.vexnum; i++) {
judgment[i] = false;
dist[i] = g.arcs[v][i];
if (dist[i] < INFINITY || i == v) {
path[i] = v;
} else {
path[i] = -1;
}
}
dist[v] = 0;
judgment[v] = true;
for (int i = 1; i < g.vexnum; i++) {
int min = INFINITY;
int index_min;
for (int j = 1; j <= g.vexnum; j++) {
if (judgment[j] == false && dist[j] < min) {
index_min = j;
min = dist[j];
}
}
judgment[index_min] = true;
for (int j = 1; j <= g.vexnum; j++) {
if (judgment[j] == false && dist[j] > (dist[index_min] + g.arcs[index_min][j]) && (dist[index_min] + g.arcs[index_min][j]) < INFINITY) {
dist[j] = dist[index_min] + g.arcs[index_min][j];
path[j] = index_min;
}
}
}
}
初始化操作
void dijkstra(graph g, int v, int dist[], int path[])
傳入圖g,以及v頂點(diǎn)下標(biāo),dist一維數(shù)組表示v頂點(diǎn)分別到其他頂點(diǎn)的最短路徑長(zhǎng)度,path一維數(shù)組表示v頂點(diǎn)分別到其他頂點(diǎn)的最短路徑中終點(diǎn)的前一個(gè)頂點(diǎn)。
bool judgment[MAX]
創(chuàng)建一個(gè)判斷數(shù)組,用來判斷每一個(gè)頂點(diǎn)是否是最短路徑,數(shù)據(jù)類型是bool型,如果已經(jīng)確定頂點(diǎn)v到該頂點(diǎn)的最短路徑,對(duì)應(yīng)下標(biāo)存儲(chǔ)true,反之存儲(chǔ)false。
????bool?judgment[MAX];
????for?(int?i?=?1;?i?<=?g.vexnum;?i++)?{
????????judgment[i]?=?false;
????????dist[i]?=?g.arcs[v][i];
????????if?(dist[i]?<?INFINITY?||?i?==?v)?{
????????????path[i]?=?v;
????????}?else?{
????????????path[i]?=?-1;
????????}
????}
初始化judgement,dist,path數(shù)組,首先對(duì)v頂點(diǎn)做處理,遍歷每一個(gè)頂點(diǎn),judgement初始值全部置false,dist數(shù)組數(shù)據(jù)全部更新為v頂點(diǎn)直接到其他各頂點(diǎn)的距離,如果v頂點(diǎn)到i頂點(diǎn)的邊存在,或者v頂點(diǎn)自己到自己,則v頂點(diǎn)到i頂點(diǎn)的前一個(gè)頂點(diǎn)置為v,否則path置-1表示這條邊不存在,這樣就完成了對(duì)v頂點(diǎn)的訪問,即初始化。
循環(huán)遍歷維護(hù)dist和path
dist[v] = 0; judgment[v] = true;
先把v頂點(diǎn)到自己的最短路徑值0,對(duì)應(yīng)judgment值置true,表示已經(jīng)確定v頂點(diǎn)到自己的最短路徑。
for?(int?i?=?1;?i?<?g.vexnum;?i++)?{
????????int?min?=?INFINITY;
????????int?index_min;
????????for?(int?j?=?1;?j?<=?g.vexnum;?j++)?{
????????????if?(judgment[j]?==?false?&&?dist[j]?<?min)?{
????????????????index_min?=?j;
????????????????min?=?dist[j];
????????????}
????????}
????????judgment[index_min]?=?true;
????????for?(int?j?=?1;?j?<=?g.vexnum;?j++)?{
????????????if?(judgment[j]?==?false?&&?dist[j]?>?(dist[index_min]?+?g.arcs[index_min][j])?)?{
????????????????dist[j]?=?dist[index_min]?+?g.arcs[index_min][j];
????????????????path[j]?=?index_min;
????????????}
????????}
????}
最外層的循環(huán)僅表示以下內(nèi)容需要循環(huán)g.vexnum-1次,也就是除去v頂點(diǎn)訪問過的,其他頂點(diǎn)都需要訪問一次。
????????int?min?=?INFINITY;
????????int?index_min;
????????for?(int?j?=?1;?j?<=?g.vexnum;?j++)?{
????????????if?(judgment[j]?==?false?&&?dist[j]?<?min)?{
????????????????index_min?=?j;
????????????????min?=?dist[j];
????????????}
????????}????????judgment[index_min]?=?true;
找到v頂點(diǎn)到其他頂點(diǎn)j直接距離的最短距離,這個(gè)距離即是v頂點(diǎn)到j(luò)頂點(diǎn)的最短路徑,因?yàn)槿绻阆霃钠渌窂降絡(luò)頂點(diǎn),第一步走的路徑一定要比v頂點(diǎn)直接到j(luò)頂點(diǎn)的距離長(zhǎng),所以這個(gè)最短的直接距離就是最短路徑,找到v頂點(diǎn)到index_min頂點(diǎn)的最短路徑,就訪問該頂點(diǎn),并且維護(hù)對(duì)應(yīng)judgment的值,表示v頂點(diǎn)到index_min頂點(diǎn)的最短路徑已經(jīng)確定。
????????for?(int?j?=?1;?j?<=?g.vexnum;?j++)?{
????????????if?(judgment[j]?==?false?&&?dist[j]?>?(dist[index_min]?+?g.arcs[index_min][j])?)?{
????????????????dist[j]?=?dist[index_min]?+?g.arcs[index_min][j];
????????????????path[j]?=?index_min;
????????????}
????????}
訪問index_min頂點(diǎn),根據(jù)這個(gè)頂點(diǎn),看看能不能找到還沒有確定的到達(dá)其他頂點(diǎn)的最短路徑頂點(diǎn)的更小距離,維護(hù)dist和path數(shù)組。
如果這個(gè)j頂點(diǎn)的最短路徑還沒確定,并且v頂點(diǎn)到index_min頂點(diǎn)的最短路徑,加上頂點(diǎn)index_min到j(luò)的路徑長(zhǎng)度比dist存儲(chǔ)的v頂點(diǎn)到j(luò)頂點(diǎn)的最短路徑還要小,就維護(hù)dist的值,并且把這個(gè)還沒確定的最短路徑的j的前一個(gè)頂點(diǎn)的下標(biāo)維護(hù)到path數(shù)組。
依次循環(huán),訪問剩下的頂點(diǎn),維護(hù)dist和path。
編寫主函數(shù)
int main() {
graph g;
int start,end;
initGraph(g);
createGraph(g);
showGraph(g);
printf("\n輸入起點(diǎn)和終點(diǎn):\n");
scanf("%d%d",&start,&end);
int dist[MAX];//dist[i] v頂點(diǎn)到i定點(diǎn)最短路徑的距離
int path[MAX];//path[i] v頂點(diǎn)到i定點(diǎn)最短路徑中i的上一個(gè)頂點(diǎn)下標(biāo)
dijkstra(g, start, dist, path);
printf("\n");
printf("dist:\n");
for(int i=1;i<=g.vexnum;i++){
printf("%d ",dist[i]);
}
printf("\n");
printf("path:\n");
for(int i=1;i<=g.vexnum;i++){
printf("%d ",path[i]);
}
printf("\n\n最短路徑長(zhǎng)度:\n%d\n",dist[end]);
char pathText[MAX]={""};
int cur=end;
pathText[strlen(pathText)]=end+'0';
while(cur!=start){
pathText[strlen(pathText)]=path[cur]+'0';
cur=path[cur];
}
printf("%d到%d的最短路徑:\n",start,end);
for(int i=strlen(pathText)-1;i>=0;i--){
printf("%c ",pathText[i]);
}
printf("\n");
}
/*測(cè)試用例:
5 8
1 2 1
1 5 4
1 3 3
2 4 2
4 5 4
3 4 1
2 3 2
3 5 1
*/
printf("\n\n最短路徑長(zhǎng)度:\n%d\n",dist[end]);
????
????char?pathText[MAX]={""};
????
????int?cur=end;
????pathText[strlen(pathText)]=end+'0';
????while(cur!=start){
????????pathText[strlen(pathText)]=path[cur]+'0';
????????cur=path[cur];
????}
字符數(shù)組這樣初始化,可以利用strlen函數(shù)計(jì)算自己的長(zhǎng)度,以達(dá)到尾插的效果。
先把end終點(diǎn)頂點(diǎn)尾插進(jìn)pathText
接著循環(huán)變量path數(shù)組,直到cur到start為止,這樣最短路徑的逆路程就存儲(chǔ)在pathText數(shù)組中了。
????printf("%d到%d的最短路徑:\n",start,end);
????
????for(int?i=strlen(pathText)-1;i>=0;i--){
????????printf("%c?",pathText[i]);
????}
????printf("\n");
接下來只要從后往前遍歷就可以正向輸出最短路徑了。
完整代碼
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX 100
#define INFINITY 9999
enum graphType {DG, UG, DN, UN}; //圖的類型定義:有向圖,無向圖,有向網(wǎng),無項(xiàng)網(wǎng)
typedef char vertexType;
typedef struct {
vertexType vexs[MAX];
int arcs[MAX][MAX];
int vexnum, arcnum;
graphType kind;
} graph;
void initGraph(graph &g) {
g.kind = UN;
printf("輸入頂點(diǎn)數(shù)和邊數(shù):\n");
scanf("%d%d", &g.vexnum, &g.arcnum);
for (int i = 1; i <= g.vexnum; i++) {
g.vexs[i] = i;
}
for (int i = 1; i <= g.vexnum; i++) {
for (int j = 1; j <= g.vexnum; j++) {
if (i == j) g.arcs[i][j] = 0;
else g.arcs[i][j] = INFINITY;
}
}
}
void createGraph(graph &g) {
int start_index, end_index, weight;
printf("輸入每條邊的起點(diǎn)終點(diǎn)下標(biāo)和邊的權(quán)重:\n");
for (int i = 1; i <= g.arcnum; i++) {
scanf("%d%d%d", &start_index, &end_index, &weight);
g.arcs[start_index][end_index] = weight;
g.arcs[end_index][start_index] = weight;
}
}
void showGraph(graph &g) {
printf("鄰接矩陣:\n");
for (int i = 1; i <= g.vexnum; i++) {
for (int j = 1; j <= g.vexnum; j++) {
printf("%d ", g.arcs[i][j]);
}
printf("\n");
}
}
void dijkstra(graph g, int v, int dist[], int path[]) {
bool judgment[MAX];
for (int i = 1; i <= g.vexnum; i++) {
judgment[i] = false;
dist[i] = g.arcs[v][i];
if (dist[i] < INFINITY || i == v) {
path[i] = v;
} else {
path[i] = -1;
}
}
dist[v] = 0;
judgment[v] = true;
for (int i = 1; i < g.vexnum; i++) {
int min = INFINITY;
int index_min;
for (int j = 1; j <= g.vexnum; j++) {
if (judgment[j] == false && dist[j] < min) {
index_min = j;
min = dist[j];
}
}
judgment[index_min] = true;
for (int j = 1; j <= g.vexnum; j++) {
if (judgment[j] == false && dist[j] > (dist[index_min] + g.arcs[index_min][j]) && (dist[index_min] + g.arcs[index_min][j]) < INFINITY) {
dist[j] = dist[index_min] + g.arcs[index_min][j];
path[j] = index_min;
}
}
}
}
int main() {
graph g;
int start,end;
initGraph(g);
createGraph(g);
showGraph(g);
printf("\n輸入起點(diǎn)和終點(diǎn):\n");
scanf("%d%d",&start,&end);
int dist[MAX];//dist[i] v頂點(diǎn)到i定點(diǎn)最短路徑的距離
int path[MAX];//path[i] v頂點(diǎn)到i定點(diǎn)最短路徑中i的上一個(gè)頂點(diǎn)下標(biāo)
dijkstra(g, start, dist, path);
printf("\n");
printf("dist:\n");
for(int i=1;i<=g.vexnum;i++){
printf("%d ",dist[i]);
}
printf("\n");
printf("path:\n");
for(int i=1;i<=g.vexnum;i++){
printf("%d ",path[i]);
}
printf("\n\n最短路徑長(zhǎng)度:\n%d\n",dist[end]);
char pathText[MAX]={""};
int cur=end;
pathText[strlen(pathText)]=end+'0';
while(cur!=start){
pathText[strlen(pathText)]=path[cur]+'0';
cur=path[cur];
}
printf("%d到%d的最短路徑:\n",start,end);
for(int i=strlen(pathText)-1;i>=0;i--){
printf("%c ",pathText[i]);
}
printf("\n");
}
/*測(cè)試用例:
5 8
1 2 1
1 5 4
1 3 3
2 4 2
4 5 4
3 4 1
2 3 2
3 5 1
*/
代碼運(yùn)行截圖:
結(jié)尾
我們今天學(xué)習(xí)了dijkstra最短路徑的實(shí)現(xiàn),過程一共有三個(gè)一維數(shù)組judgement,dist和path,分別表示最短路徑是否確定,最短路徑長(zhǎng)度,最短路徑前一個(gè)頂點(diǎn)的下標(biāo)。一個(gè)定義:一個(gè)頂點(diǎn)到達(dá)其他頂點(diǎn)的直接距離的最小值就是最短路徑。依次訪問dist最小值頂點(diǎn),這個(gè)頂點(diǎn)的judgement需要為false,然后把這個(gè)fals改為true,接著由這個(gè)頂點(diǎn)修正其他false頂點(diǎn)的dist和path,依次循環(huán)。
最后,感謝您閱讀我的文章,希望這些內(nèi)容能夠?qū)δ兴鶈l(fā)和幫助。如果您有任何問題或想要分享您的觀點(diǎn),請(qǐng)隨時(shí)在評(píng)論區(qū)留言。
同時(shí),不要忘記訂閱我的博客以獲取更多有趣的內(nèi)容。在未來的文章中,我將繼續(xù)探討這個(gè)話題的不同方面,為您呈現(xiàn)更多深度和見解。文章來源:http://www.zghlxwxcb.cn/news/detail-774109.html
謝謝您的支持,期待與您在下一篇文章中再次相遇!文章來源地址http://www.zghlxwxcb.cn/news/detail-774109.html
到了這里,關(guān)于【C語言\數(shù)據(jù)結(jié)構(gòu)】圖dijkstra最短路徑 鄰接矩陣(無項(xiàng)、有權(quán))代碼簡(jiǎn)單實(shí)現(xiàn)深度解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!