数据结构与算法—单源最短路径dijkstra算法
介紹
對于dijkstra算法,很多人可能感覺熟悉而又陌生,可能大部分人比較了解bfs和dfs,而對dijkstra和floyd算法可能知道大概是圖論中的某個算法,但是可能不清楚其中的作用和原理,又或許,你曾經(jīng)感覺它很難,那么,這個時候正適合你重新認(rèn)識它。
Dijkstra能是干啥的?
Dijkstra是用來求單源最短路徑的
就拿上圖來說,假如直到的路徑和長度已知,那么可以使用dijkstra算法計算南京到圖中所有節(jié)點(diǎn)的最短距離。
單源什么意思?
- 從一個頂點(diǎn)出發(fā),Dijkstra算法只能求一個頂點(diǎn)到其他點(diǎn)的最短距離而不能任意兩點(diǎn)。
和bfs求的最短路徑有什么區(qū)別?
- bfs求的與其說是路徑,不如說是次數(shù)。因?yàn)閎fs他是按照隊(duì)列一次一次進(jìn)行加入相鄰的點(diǎn),而兩點(diǎn)之間沒有權(quán)值或者權(quán)值相等(代價相同)。處理的更多是偏向迷宮類的這種都是只能走鄰居(不排除特例)。
Dijkstra在處理具體實(shí)例的應(yīng)用還是很多的,因?yàn)榫唧w的問題其實(shí)帶權(quán)更多一些。
比如一個城市有多個鄉(xiāng)鎮(zhèn),鄉(xiāng)鎮(zhèn)可能有道路,也可能沒有,整個鄉(xiāng)鎮(zhèn)聯(lián)通,如果想計算每個鄉(xiāng)鎮(zhèn)到a鎮(zhèn)的最短路徑,那么Dijkstra就派上了用場。
算法分析
對于一個算法,首先要理解它的運(yùn)行流程。
對于一個Dijkstra算法而言,前提是它的前提條件和環(huán)境:
- 一個連通圖,若干節(jié)點(diǎn),節(jié)點(diǎn)可能有數(shù)值,但是路徑一定有權(quán)值。并且路徑不能為負(fù)。否則Dijkstra就不適用。
Dijkstra的核心思想是貪心算法的思想。不懂貪心?
貪心算法(又稱貪婪算法)是指,在對問題求解時,總是做出在當(dāng)前看來是最好的選擇。也就是說,不從整體最優(yōu)上加以考慮,他所做出的是在某種意義上的局部最優(yōu)解。
貪心算法不是對所有問題都能得到整體最優(yōu)解,關(guān)鍵是貪心策略的選擇,選擇的貪心策略必須具備無后效性,即某個狀態(tài)以前的過程不會影響以后的狀態(tài),只與當(dāng)前狀態(tài)有關(guān)。
對于貪心算法,在很多情況都能用到。下面舉幾個不恰當(dāng)?shù)睦?#xff01;
打個比方,吃自助餐,目標(biāo)是吃回本,那么胃有限那么每次都僅最貴的吃。
上學(xué)時,麻麻說只能帶5個蘋果,你想帶最多,那么選五個蘋果你每次都選最大的那個五次下來你就選的最重的那個。
不難發(fā)現(xiàn)上面的策略雖然沒有很強(qiáng)的理論數(shù)學(xué)依據(jù),或者不太好說明。但是事實(shí)規(guī)律就是那樣,并且對于貪心問題大部分都需要排序,還可能會遇到類排序。并且一個物體可能有多個屬性,不同問題需要按照不同屬性進(jìn)行排序,操作。
那么我們的Dijkstra是如何貪心的呢?對于一個點(diǎn),求圖中所有點(diǎn)的最短路徑,如果沒有正確的方法胡亂想確實(shí)很難算出來,并且如果暴力匹配復(fù)雜度呈指數(shù)級上升不適合解決實(shí)際問題。
那么我們該怎么想呢?
Dijkstra算法的前提:
簡單的概括流程為:
- 一般從選定點(diǎn)開始拋入優(yōu)先隊(duì)列。(路徑一般為0),boolean數(shù)組標(biāo)記0的位置(最短為0) , 然后0周圍連通的點(diǎn)拋入優(yōu)先隊(duì)列中(可能是node類),并把各個點(diǎn)的距離記錄到對應(yīng)數(shù)組內(nèi)(如果小于就更新,大于就不動,初始第一次是無窮肯定會更新),第一次就結(jié)束了
- 從隊(duì)列中拋出距離最近的那個點(diǎn)B(第一次就是0周圍鄰居)。這個點(diǎn)距離一定是最近的(所有權(quán)值都是正的,點(diǎn)的距離只能越來越長。)標(biāo)記這個點(diǎn)為true,并且將這個點(diǎn)的鄰居加入隊(duì)列(下一次確定的最短點(diǎn)在前面未確定和這個點(diǎn)鄰居中產(chǎn)生),并更新通過B點(diǎn)計算各個位置的長度,如果小于則更新!
- 重復(fù)二的操作,直到所有點(diǎn)都確定。
算法實(shí)現(xiàn)
package 圖論;import java.util.ArrayDeque; import java.util.Comparator; import java.util.PriorityQueue; import java.util.Queue; import java.util.Scanner;public class dijkstra {static class node{int x; //節(jié)點(diǎn)編號int lenth;//長度public node(int x,int lenth) {this.x=x;this.lenth=lenth;}}public static void main(String[] args) {int[][] map = new int[6][6];//記錄權(quán)值,順便記錄鏈接情況,可以考慮附加鄰接表initmap(map);//初始化boolean bool[]=new boolean[6];//判斷是否已經(jīng)確定int len[]=new int[6];//長度for(int i=0;i<6;i++){len[i]=Integer.MAX_VALUE;}Queue<node>q1=new PriorityQueue<node>(com);len[0]=0;//從0這個點(diǎn)開始q1.add(new node(0, 0));int count=0;//計算執(zhí)行了幾次dijkstrawhile (!q1.isEmpty()) {node t1=q1.poll();int index=t1.x;//節(jié)點(diǎn)編號int length=t1.lenth;//節(jié)點(diǎn)當(dāng)前點(diǎn)距離bool[index]=true;//拋出的點(diǎn)確定count++;//其實(shí)執(zhí)行了6次就可以確定就不需要繼續(xù)執(zhí)行了 這句可有可無,有了減少計算次數(shù)for(int i=0;i<map[index].length;i++){if(map[index][i]>0&&!bool[i]){node node=new node(i, length+map[index][i]);if(len[i]>node.lenth)//需要更新節(jié)點(diǎn)的時候更新節(jié)點(diǎn)并加入隊(duì)列{len[i]=node.lenth;q1.add(node);}}}} for(int i=0;i<6;i++){System.out.println(len[i]);}}static Comparator<node>com=new Comparator<node>() {public int compare(node o1, node o2) {return o1.lenth-o2.lenth;}};private static void initmap(int[][] map) {map[0][1]=2;map[0][2]=3;map[0][3]=6;map[1][0]=2;map[1][4]=4;map[1][5]=6;map[2][0]=3;map[2][3]=2;map[3][0]=6;map[3][2]=2;map[3][4]=1;map[3][5]=3;map[4][1]=4;map[4][3]=1;map[5][1]=6;map[5][3]=3; } }執(zhí)行結(jié)果:
當(dāng)然,dijkstra算法比較靈活,實(shí)現(xiàn)方式也可能有點(diǎn)區(qū)別,但是思想是不變的:一個貪心思路。dijkstra執(zhí)行一次就能夠確定一個點(diǎn),所以只需要執(zhí)行點(diǎn)的總和次數(shù)即可完成整個算法。
歡迎感謝小伙伴點(diǎn)贊、關(guān)注,贈人玫瑰,手有余香!蟹蟹!
總結(jié)
以上是生活随笔為你收集整理的数据结构与算法—单源最短路径dijkstra算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构与算法—图论之dfs、bfs(深
- 下一篇: 短小精悍的多源最短路径算法—Floyd算