數據結構之迪杰斯特拉算法

前言:前面兩篇文章介紹了生成圖的最小生成樹的算法,接下來兩篇文章會介紹圖的最短路徑的算法,迪杰斯特拉算法和弗洛伊德算法。迪杰斯特拉算法是用來計算一個點到其他所有點的最短路徑,這個點稱之為源點。

一、實現流程

回憶一下我們之前學習的 Prim 算法,構建最小生成樹。從一個頂點出發,不斷地尋找離當前生成樹最近的節點,將節點加入到生成樹。而尋找源點到其他節點的最短路徑的 Dijkstra 算法,和 Prim 算法非常的類似。
因為假設當前5號節點和0號節點之間有兩條路徑,利用 Prim 算法,我們生成一個最小生成樹,那么在最小生成樹中,0 號節點和 5 號節點之間的路徑一定是最短的,也就是 Dijkstra 算法要找的最短路徑。所以整個實現流程非常的相似。和 Prim 一樣,時間復雜度也是 O(v^2),只和頂點有關。
具體的實現流程大家可以參考 Prim算法,我就不贅述了,咱們來仔細看一下代碼實現上有什么不一樣

二、代碼實現

1、初始化常量和數據類型

#define MAX_VEX 100
#define INFINITY INT_MAX // 使用 INT_MAX 代表無窮大// 圖的結構體定義
typedef struct {int vexnum; // 節點數int arcnum; // 邊數int arcs[MAX_VEX][MAX_VEX]; // 鄰接矩陣
} MGraph;

首先我們要求源點到其他節點的最短路徑 dist,就需要用一個數組,來保存當前源點到所有節點的路徑長度。
我們需要一個數組來存儲每個節點的 path,每次更新路徑長度的時候,都需要更新當前節點的前驅結點。
另外為了防止對一個節點重復進行判斷,我們需要一個數組 final,來記錄一個節點是否已經找到最短路徑 。

// 初始化
const int v0 = 0; // 將源點硬編碼為0
int final[MaxVex]; // 記錄節點有沒有找到最短路徑
int path[MaxVex]; // 記錄每個節點的前驅結點
int dist[MaxVex]; // 記錄源點到每個節點的最短路徑

初始化的時候,根據鄰接矩陣來初始化 dist 數組,為 0 號節點到其他節點的邊的權值; final數組全部初始化為 0 表示都沒有訪問過,0號節點 final[0] 初始化為 1,表示已經訪問過;path 數組和 0 號節點直接相連的節點的 path 記為 0 ,不直接相連的節點 path 記為 -1。

// --- 1. 初始化 ---for (int i = 0; i < G.vexnum; i++) {final[i] = 0;                // 所有頂點初始都未找到最短路徑dist[i] = G.arcs[v0][i];     // v0 到各點的直連距離if (dist[i] < INFINITY && i != v0) {path[i] = v0;            // 如果有直連路徑, 前驅為 v0} else {path[i] = -1;            // 否則無前驅}}dist[v0] = 0;   // 源點到自身的距離為 0final[v0] = 1;  // 源點已找到最短路徑path[v0] = -1;  // 源點無前驅

接下來就是主要的處理過程。首先外層需要 G.vexnum - 1 次循環,因為每次只能找到一個最近節點。內層有兩個操作需要循環:一個是找當前最近的節點;另一個是以找到的最近節點更新剩下的 dist 數組。
還要初始化一個 k 變量,用來記錄每次找到的距離 0 號節點最近的節點

// --- 2. 主循環: 每次找到一個頂點的最短路徑 ---
int k = -1; // k 用于記錄當前找到的最近頂點的索引
for (int i = 1; i < G.vexnum; i++) { // 循環 n-1 次, 找出 n-1 個頂點的最短路int min = INFINITY;// a. 尋找當前離源點最近的未訪問頂點 kfor (int j = 0; j < G.vexnum; j++) {if (!final[j] && dist[j] < min) {min = dist[j];k = j;}}// b. 將 k 標記為已找到最短路徑final[k] = 1;// c. 以 k 為跳板, 更新其他未訪問頂點的距離for (int j = 0; j < G.vexnum; j++) {// 如果 j 未被訪問, 且經過 k 到達 j 的距離更短if (!final[j] && (long)dist[k] + G.arcs[k][j] < dist[j]) {dist[j] = dist[k] + G.arcs[k][j]; // 更新距離path[j] = k;                      // 更新前驅}}
}

三、整體代碼

// 迪杰斯特拉算法 源點到其他節點的最短路徑
#include <stdio.h>
#include <stdlib.h>
#include <limits.h> // 用于 INT_MAX#define MAX_VEX 100
#define INFINITY INT_MAX // 使用 INT_MAX 代表無窮大// 圖的結構體定義
typedef struct {int vexnum; // 節點數int arcnum; // 邊數int arcs[MAX_VEX][MAX_VEX]; // 鄰接矩陣
} MGraph;// 迪杰斯特拉算法 (源點默認為0)
void Dijkstra(MGraph G) {const int v0 = 0; // 將源點硬編碼為0int final[MAX_VEX]; // final[i]=1 表示已找到從 v0 到 vi 的最短路徑int path[MAX_VEX];  // path[i] 記錄 vi 的前驅頂點int dist[MAX_VEX];  // dist[i] 記錄從 v0 到 vi 的當前最短路徑長度// --- 1. 初始化 ---for (int i = 0; i < G.vexnum; i++) {final[i] = 0;                // 所有頂點初始都未找到最短路徑dist[i] = G.arcs[v0][i];     // v0 到各點的直連距離if (dist[i] < INFINITY && i != v0) {path[i] = v0;            // 如果有直連路徑, 前驅為 v0} else {path[i] = -1;            // 否則無前驅}}dist[v0] = 0;   // 源點到自身的距離為 0final[v0] = 1;  // 源點已找到最短路徑path[v0] = -1;  // 源點無前驅// --- 2. 主循環: 每次找到一個頂點的最短路徑 ---int k = -1; // k 用于記錄當前找到的最近頂點的索引for (int i = 1; i < G.vexnum; i++) { // 循環 n-1 次, 找出 n-1 個頂點的最短路int min = INFINITY;// a. 尋找當前離源點最近的未訪問頂點 kfor (int j = 0; j < G.vexnum; j++) {if (!final[j] && dist[j] < min) {min = dist[j];k = j;}}// b. 將 k 標記為已找到最短路徑final[k] = 1;// c. 以 k 為跳板, 更新其他未訪問頂點的距離for (int j = 0; j < G.vexnum; j++) {// 如果 j 未被訪問, 且經過 k 到達 j 的距離更短if (!final[j] && (long)dist[k] + G.arcs[k][j] < dist[j]) {dist[j] = dist[k] + G.arcs[k][j]; // 更新距離path[j] = k;                      // 更新前驅}}}// --- 3. 打印結果 ---printf("從源點 %d 到各頂點的最短路徑和距離如下:\n", v0);for (int i = 0; i < G.vexnum; i++) {if (i == v0) continue;printf("頂點 %d: 距離 = %-5d, 路徑: ", i, dist[i]);int temp_path[MAX_VEX];int count = 0;int p = i;while (p != -1) {temp_path[count++] = p;p = path[p];}for (int j = count - 1; j >= 0; j--) {printf("%d", temp_path[j]);if (j > 0) printf(" -> ");}printf("\n");}
}int main() {MGraph G;// 初始化圖G.vexnum = 6; // 6個頂點 (0, 1, 2, 3, 4, 5)G.arcnum = 11; // 11條邊for (int i = 0; i < G.vexnum; i++) {for (int j = 0; j < G.vexnum; j++) {if (i == j) {G.arcs[i][j] = 0;} else {G.arcs[i][j] = INFINITY;}}}// 構建一個全連通的有向圖的鄰接矩陣G.arcs[0][1] = 50;G.arcs[0][2] = 10;G.arcs[0][4] = 45;G.arcs[0][5] = 100;G.arcs[1][2] = 15;G.arcs[1][4] = 10;G.arcs[2][0] = 20;G.arcs[2][3] = 15;G.arcs[3][1] = 20;G.arcs[3][4] = 35;G.arcs[4][3] = 30;G.arcs[5][3] = 3;Dijkstra(G); // 調用函數, 無需傳入源點return 0;
}

其實和 Prim 算法只有一點不一樣,就是更新其他未訪問頂點的距離中的條件
Prim 算法是 if(lowcost[j]!=0 && G.arcs[k][j]<lowcost[j])
Dijkstra 算法是 if (!final[j] && (long)dist[k] + G.arcs[k][j] < dist[j])
前半句都是判斷節點是否已經被訪問過,只有后半句不一樣
Prim 算法是生成最小生成樹,當加入一個節點的時候,這個節點和樹中的其他節點形成一個整體,因此只要 k 這個節點到 j 的距離更小,說明 j 離生成樹的距離還可以更近,就更新 j 節點的路徑
Dijkstra 算法是計算源點到其他節點的距離,所以必須對比從 源點到k+k到jdist[j]

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/90457.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/90457.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/90457.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

技術文檔 | OpenAI 的 Kafka 演進之路與 Pulsar 遷移潛力

導讀ChatGPT 用戶量指數級暴漲&#xff0c;OpenAI 的 Kafka 集群在一年內增長 20 倍至 30 個集群[1]&#xff0c;其 Kafka 架構面臨日均千億級消息&#xff08;峰值 QPS 800萬/秒&#xff09; 的壓力。這揭示了一個關鍵事實&#xff1a;OpenAI 的成功不只依賴模型&#xff0c;更…

【bug】 jetson上opencv無法錄制h264本地視頻

在Jetson Orin NX上無法使用opencv直接錄制h264/h265視頻流&#xff08;h264格式的視頻流才能在瀏覽器播放&#xff09; 解決&#xff1a; 軟件編碼&#xff1a;需要源碼編譯opencv 1.環境準備 pip uninstall opencv-python sudo apt install build-essential cmake git python…

解決http的web服務中與https服務交互的問題

問題背景&#xff1a; 需要在一個http的web服務中直接跟另一個https服務交互&#xff0c;不經過自身后端。 又來到了熟悉的跨域訪問問題。 解決邏輯就是使用nginx轉發&#xff0c;涉及到的文件也就是nginx.conf文件&#xff0c;前面解決minio鏈接時已經有經驗了&#xff0c;但…

網站訪問信息追蹤系統在安全與性能優化中的關鍵作用——網絡安全—仙盟創夢IDE

<?php // 收集訪問信息 $visitorInfo未來之窗 [timestamp > date(Y-m-d H:i:s),ip > $_SERVER[REMOTE_ADDR] ?? unknown,page > $_SERVER[REQUEST_URI] ?? unknown,method > $_SERVER[REQUEST_METHOD] ?? unknown,user_agent > $_SERVER[HTTP_USER_A…

Oracle 時間處理函數和操作符筆記

前言 寫sql時經常用到時間處理函數&#xff0c;我整理了一份Oracle的常用sql筆記,供大家參考。 如果對你有幫助&#xff0c;請點贊支持~ 多謝&#x1f64f; 筆記 -- 1. 獲取當前日期和時間 -- SYSDATE, SYSTIMESTAMP, CURRENT_DATE, CURRENT_TIMESTAMP, LOCALTIMESTAMP SELE…

TDengine時序數據庫 詳解

1. TDengine 簡介 TDengine 是一款 高性能、分布式、支持 SQL 的時序數據庫&#xff08;Time-Series Database, TSDB&#xff09;&#xff0c;專為 物聯網&#xff08;IoT&#xff09;、工業互聯網、金融監控、日志分析 等場景設計。其核心特點包括&#xff1a; 超高性能&…

【IDEA】idea怎么修改注冊的用戶名稱?

文章目錄[toc]問題**方法 1&#xff1a;通過 JetBrains 賬戶網站修改****方法 2&#xff1a;通過 IDEA 內跳轉修改&#xff08;快捷方式&#xff09;****注意事項****補充&#xff1a;修改 IDEA 內的項目級用戶名**如何退出IDEA用戶登錄&#xff1f;問題 在 IntelliJ IDEA 中修…

AR眼鏡重塑外科手術導航:精準“透視”新突破

在現代醫學領域&#xff0c;增強現實&#xff08;AR www.teamhelper.cn &#xff09;技術正以前所未有的方式改變外科手術導航的面貌。通過為醫生提供實時的三維可視化、精準的空間定位和智能交互功能&#xff0c;AR眼鏡正在成為手術室中的重要工具。本文將系統介紹AR眼鏡在手術…

服務端對接 HTTP 接口傳輸圖片 采用base64還是 multipart/form-data

在服務端對接HTTP接口傳輸圖片時&#xff0c;選擇 multipart/form-data 還是 Base64 編碼&#xff0c;需要根據具體場景權衡。以下是詳細對比和建議&#xff1a;1. multipart/form-data 優點 更適合大文件傳輸&#xff1a; 直接以二進制流傳輸圖片&#xff0c;無需編碼/解碼&am…

如何在 Windows 上安裝 MongoDB 及常見問題

MongoDB 是一款 NoSQL 數據庫&#xff0c;在數據管理和存儲方面以其無與倫比的強大功能和多功能性而脫穎而出。該平臺憑借其靈活性、可擴展性和高性能保持著領先優勢&#xff0c;贏得了眾多企業的信賴。在這方面&#xff0c;MongoDB 以及其在 Windows 操作系統中的表現&#xf…

JS與Go:編程語言雙星的碰撞與共生

在編程語言的璀璨星河中&#xff0c;JavaScript&#xff08;簡稱JS&#xff09;與Go語言憑借各自獨特的魅力&#xff0c;成為不同領域的佼佼者。前者以靈活多變的姿態征服了前端世界&#xff0c;后者則以高效穩健的特性在后端領域嶄露頭角&#xff0c;二者的碰撞與共生&#xf…

【開源】WpfMap:一個基于WPF(Windows Presentation Foundation)技術構建的數據可視化大屏展示頁面

文章目錄一、項目概述1.1 項目定位二、適用場景2.1 企業數據展示2.2 監控中心2.3 會議展示三、功能特性3.1 高度自定義3.2 實時更新3.3 豐富的可視化組件3.4 良好的用戶體驗四、技術資源4.1 開源地址一、項目概述 1.1 項目定位 WpfMap是一個基于WPF&#xff08;Windows Prese…

macbook安裝homebrew

homebrew是什么&#xff1f;Homebrew 是 macOS&#xff08;以及 Linux&#xff09;上的一款包管理工具&#xff0c;被稱為 “macOS 缺失的包管理器”&#xff0c;它能幫助用戶輕松安裝、卸載、更新各種命令行工具、開發環境、應用程序等。簡單來說&#xff0c;它的作用類似手機…

ViLT: 無卷積或區域監督的視覺-語言Transformer

溫馨提示&#xff1a; 本篇文章已同步至"AI專題精講" ViLT: 無卷積或區域監督的視覺-語言Transformer 摘要 視覺與語言預訓練&#xff08;Vision-and-Language Pre-training, VLP&#xff09;在多種聯合視覺與語言的下游任務中顯著提升了性能。目前的 VLP 方法在很…

初識決策樹-理論部分

決策樹 前言 參考了大佬的博客&#xff1a;博客地址 適合分析離散數據&#xff0c;若是連續數據需要轉換成離散數據再做分析(比如圖中的年齡) 結構 決策樹由節點和有向邊組成&#xff1b;節點可分為內部節點和葉節點 內部節點:特征葉節點:類別有向邊:特征的取值范圍 在用決…

opencv--day02--圖像顏色處理及圖像仿射變換

文章目錄前言一、 圖像顏色處理1. 顏色加法1.1 OpenCV加法1.2 numpy加法1.3 顏色加權加法2.顏色空間2.1 RGB顏色空間2.2 HSV顏色空間3. 顏色轉換3.1 讀取的圖片同時轉換3.2 對已有圖片轉換4. 圖像灰度化4.1 灰度圖概念4.2 最大值灰度化4.3 平均值灰度化4.4 加權均值灰度化5. 圖…

第一層nginx訪問url如何透傳到第二層nginx

要讓第一層Nginx將客戶端請求的URL完整透傳到第二層Nginx&#xff0c;關鍵在于正確配置proxy_pass指令及路徑拼接規則。以下是具體配置方法和注意事項&#xff1a; 核心配置原則 proxy_pass指令末尾是否添加/會直接影響URL的透傳方式&#xff1a; 不帶/&#xff1a;會將locatio…

【2025最新畢業設計】外賣點餐小程序(外賣點餐管理系統)

外賣點餐小程序的設計與實現技術大綱&#xff08;Vue.js Element UI&#xff09;需求分析與功能設計用戶需求調研&#xff1a;分析目標用戶群體的核心需求&#xff08;如快速點餐、支付便捷、訂單跟蹤等&#xff09;核心功能模塊劃分&#xff1a;用戶端&#xff08;登錄/注冊、…

兩臺電腦連接交換機,使用其中一臺電腦的網絡上網(NAT轉發)

場景 windows 電腦和 linux電腦連在同一臺交換機上&#xff0c;linux電腦有通過無線網絡。要實現Windows電腦通過交換機共享Linux電腦的無線網絡上網&#xff0c;需將Linux設為網關并進行網絡共享&#xff0c;步驟如下&#xff1a; 一、Linux電腦設置&#xff08;網關配置&…

OpenCV Mat UMat GpuMat Matx HostMem InputArray等設計哲學

一、概覽&#xff1a; GpuMat對應于cuda&#xff1b;HostMem 可以看作是一種特殊的Mat&#xff0c;其存儲對應cuda在主機分配的鎖頁內存&#xff0c;可以不經顯示download upload自動轉變成GpuMat&#xff08;但是和GpuMat并無繼承關系&#xff09;&#xff1b;UMat對應于openc…