日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dijkstra算法_最短路径问题——迪杰斯特拉算法(Dijkstra)

發(fā)布時間:2025/3/12 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dijkstra算法_最短路径问题——迪杰斯特拉算法(Dijkstra) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

假期過長,導致停更了好長時間,復習一道算法題找找感覺。

前段時間看到一篇文章,里面提到了統(tǒng)治世界的十大算法,其中之一就是迪杰斯特拉算法(Dijkstra),該算法主要解決的”最短路徑“這一類問題。說法雖然夸張了點,但它在實際生活中確實應用廣泛,例如地圖軟件等,大部分游戲中自動尋路等功能,使用到的 A*搜索算法也是基于迪杰斯特拉算法優(yōu)化而來。那么迪杰斯特拉算法是如何實現(xiàn)的呢?

假如我們現(xiàn)在有如下一個有向圖,圖中有 6 個頂點,編號分別為 1~6,帶有箭頭的直線表示的是能從一個頂點到達另外一個頂點,直線上的數(shù)字表示的是兩個頂點之間的距離,現(xiàn)在求頂點 1 到頂點 6 的最短距離。

由于圖中的點比較少,我們直接手動計算就能算出來這個結(jié)果,但是如果頂點很多,有成千上萬個,手動計算就很難了,我們只能通過程序來計算,那么我們的程序該如何寫呢?

思路

從圖中我們可以看到,頂點 1 只能直接到達頂點 2、3、5,不能直接到達頂點 6,所以要想從 1 到達 6,就必須得從其他頂點中轉(zhuǎn)。

我們定義一個數(shù)組,用來表示每個頂點到頂點 1 的距離,數(shù)組的索引表示的是頂點編號,數(shù)組元素的值表示的是到頂點 1 的最小距離。

  • 開始我們在頂點 1 上,頂點 1 能到達 2、3、5,數(shù)組的狀態(tài)如下。

    索引123456
    最小距離06010null50null
  • 從頂點 2 處中轉(zhuǎn),頂點 2 能到達頂點 4,距離為 35,所以頂點 1 到頂點 4 的距離為 60+35=95,數(shù)組狀態(tài)如下:

  • 索引123456
    最小距離060109550null
  • 從頂點 3 處中轉(zhuǎn),頂點 3 能到達 4,距離為 30。如果通過頂點 3 中轉(zhuǎn),那么 1 到達 4 的距離為 40,小于經(jīng)過 2 中轉(zhuǎn)的距離,所以數(shù)組中到頂點 4 的距離更新為 40。頂點 3 還能到達頂點 5,同理,通過頂點 2 中轉(zhuǎn),1 到達 5 的距離為 10+25=35,小于 1 直接到達 5 的距離,因此數(shù)組中到達頂點 5 的距離更新為 35,更新后,數(shù)組狀態(tài)如下:
  • 索引123456
    最小距離060104035null
  • 從頂點 5 中轉(zhuǎn),頂點 5 能到達 2,如果頂點 1 通過頂點 5 到達 2,距離為 35+30=65,大于頂點 1 直接到達 2,所以不更新。由于頂點 2 在前面已經(jīng)遍歷過它能到達哪些點了,所以后面不需要再遍歷它。頂點 5 還能到達頂點 6,所以此時 1 到達 6 的距離為 35+105=140,數(shù)組狀態(tài)如下:
  • 索引123456
    最小距離060104035140
  • 從頂點 4 中轉(zhuǎn),頂點 4 也能達到頂點 6。如果通過頂點 4 中轉(zhuǎn),那么 1 到達 6 的距離為 40+15=55,這個距離小于從 5 中轉(zhuǎn),所以更新數(shù)組,更新后,數(shù)組狀態(tài)如下:
  • 索引123456
    最小距離06010403555

    以上流程,就是迪杰斯特拉算法在計算最短路徑問題時的核心流程。

    代碼實現(xiàn)

    首先我們需要將這個有向圖用代碼表示出來,通常表示圖的方法有兩種:第一種是鄰接矩陣(也就是二維數(shù)組),第二種是鄰接表(也就是數(shù)組+鏈表),這里我們選用鄰接表法來表示一個有向圖。

    另外我們還需要定義頂點之間的邊,一條邊有起點和終點,還有邊的權(quán)重信息,也就是長度,用類 Edge 表示。代碼如下:

    private?class?Edge?{
    ????//?起始定點
    ????public?int?s;
    ????//?終止定點
    ????public?int?t;
    ????//?邊的權(quán)重
    ????public?int?weight;

    ????Edge(int?s,?int?t,?int?weight)?{
    ????????this.s?=?s;
    ????????this.t?=?t;
    ????????this.weight?=?weight;
    ????}
    }

    有向圖我們用類 Graph 表示,類中有兩個屬性:頂點個數(shù) v 和描述頂點之間邊的信息的數(shù)組 adj,我們還提供了一個方法:addEdge,用來在兩個頂點之間添加一條邊。代碼如下:

    public?class?Graph?{

    ????//?頂點個數(shù)(頂點編號從0開始,在本文例子中,編號為0的頂點不存在)
    ????private?int?v;

    ????//?記錄每個頂點的邊
    ????private?LinkedList[]?adj;public?Graph(int?v)?{this.v?=?v;//?初始化this.adj?=?new?LinkedList[v];for?(int?i?=?0;?i?????????????adj[i]?=?new?LinkedList();
    ????????}
    ????}//?添加一條邊,從s到達tpublic?void?addEdge(int?s,?int?t,?int?weight)?{
    ????????Edge?edge?=?new?Edge(s,?t,?weight);
    ????????adj[s].add(edge);
    ????}
    }

    定義好了圖的描述信息后,接下來通過代碼來實現(xiàn)迪杰斯特拉算法,其代碼和注釋如下。

    有兩處邏輯稍微解釋一下。第一處:flag 數(shù)組記錄的是已經(jīng)遍歷過的頂點,用來防止死循環(huán),例如頂點 1 能到達 2,我們接著會判斷 2 能到達哪些點,頂點 1 又能到達 5,5 也能到達 2,如果沒有 flag 數(shù)組來記錄頂點 2 我們已經(jīng)遍歷過了,那么我們就會繼續(xù)遍歷 2,這樣會導致死循環(huán)。第二處:predecessor 數(shù)組記錄的是路徑信息,數(shù)組的索引表示的頂點編號,元素的值表示的是哪一個頂點到達當前頂點的,例如:predecessor[3]=1 表示的是通過頂點 1 到達的頂點 3。

    //?采用迪杰斯特拉算法找出從s到t的最短路徑
    public?void?dijkstra(int?s,?int?t)?{
    ????int[]?dist?=?new?int[v];????//?記錄s到每個頂點的最小距離,數(shù)組下標表示頂點編號,值表示最小距離
    ????boolean[]?flag?=?new?boolean[v];????//?記錄遍歷過的頂點,數(shù)組下標表示頂點編號,值表示是否遍歷過該頂點
    ????for?(int?i?=?0;?i?????????dist[i]?=?Integer.MAX_VALUE;????//?初始狀態(tài)下,將頂點s到其他頂點的距離都設(shè)置為無窮大
    ????}
    ????int[]?predecessor?=?new?int[v];?????//?記錄路徑,索引表示頂點編號,值表示到達當前頂點的頂點是哪一個
    ????Queue?queue?=?new?LinkedList<>();
    ????queue.add(s);
    ????dist[s]?=?0;????//?s->s的路徑為0while?(!queue.isEmpty())?{
    ????????Integer?vertex?=?queue.poll();if?(flag[vertex])?continue;?//?已經(jīng)遍歷過該頂點,就不再遍歷
    ????????flag[vertex]?=?true;for?(int?i?=?0;?i?????????????Edge?edge?=?adj[vertex].get(i);if?(dist[vertex]?//?如果出現(xiàn)了比當前路徑小的方式,就更新為更小路徑
    ????????????????dist[edge.t]?=?dist[vertex]?+?edge.weight;
    ????????????????predecessor[edge.t]?=?vertex;
    ????????????}
    ????????????queue.add(edge.t);
    ????????}
    ????}//?打印路徑
    ????System.out.println("最短距離:"?+?dist[t]);
    ????System.out.print(s);
    ????print(s,?t,?predecessor);
    }

    print 函數(shù)的作用是打印從頂點 s 到達頂點 t 的最短路徑中,需要經(jīng)過哪些點,具體代碼如下,就是一個遞歸調(diào)用,比較簡單:

    //?打印路徑
    private?void?print(int?s,?int?t,?int[]?predecessor)?{
    ????if?(t?==?s)?{
    ????????return;
    ????}
    ????print(s,?predecessor[t],?predecessor);
    ????System.out.print("?->?"?+?t);
    }

    測試

    根據(jù)文中的示例,構(gòu)建一個圖,進行結(jié)果測試,代碼如下:

    public?static?void?main(String[]?args)?{
    ????//?構(gòu)建圖
    ????Graph?graph?=?new?Graph(7);
    ????graph.addEdge(1,?2,?60);
    ????graph.addEdge(1,?3,?10);
    ????graph.addEdge(1,?5,?50);
    ????graph.addEdge(2,?4,?35);
    ????graph.addEdge(3,?4,?30);
    ????graph.addEdge(3,?5,?25);
    ????graph.addEdge(4,?6,?15);
    ????graph.addEdge(5,?2,?30);
    ????graph.addEdge(5,?6,?105);
    ????//?計算最短距離
    ????graph.dijkstra(1,?6);
    }

    測試結(jié)果:

    總結(jié)

    迪杰斯特拉算法的思想與廣度優(yōu)先搜索(BFS)的思路比較像,每次找到自己能到達的頂點,然后依次往外擴散,直到遍歷完所有頂點。

    總結(jié)

    以上是生活随笔為你收集整理的dijkstra算法_最短路径问题——迪杰斯特拉算法(Dijkstra)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。