圖的相關算法也算是自己的一個軟肋了,當年沒選修圖論也是一大遺憾。
圖像處理中,也有使用圖論算法作為基礎的相關算法,比如圖割,這個算法就需要求最大流、最小割。所以熟悉一下圖論算法對於圖像處理還是很有幫助的。
Dijkstra和Bellman-Ford類似,都是解決單源最短路徑問題,不同的是這個方法只能解決邊為非負的問題,實現的好的Dijkstra算法運行時間要快於Bellman-ford。
算法步驟如下:
1.首先設置隊列,所有節點入列,源節點值為0,其他節點值為無窮。
2.然后在隊列中找值最小的節點並出列。
3.計算出列的節點所有后繼節點的距離。
4.松弛方法,如果新計算的距離小於上次計算的距離,那么更新距離,即將后繼節點值設為較小的距離,並將后繼節點的前趨設為當前的出列節點。
5.對剩余的節點隊列繼續找最小值並出列,不斷循環2、3、4步直到隊列中沒有節點了。
步驟是上面沒錯,不過我程序中沒有完全按照上述的步驟實現。不同的地方在於我沒有做出列操作,而是通過標記節點的形式實現的。
運行結果如下,圖(是圖不是圖片)是算法導論367頁上的:
matlab代碼如下,netplot和compresstable2matrix和上一篇使用的一樣:
main.m
clear all;close all;clc %初始化鄰接壓縮表,1 2 10 表示從節點1到節點2,邊的權重為10 b=[1 2 10;1 4 5;2 3 1; 2 4 2; 3 5 4;4 2 3; 4 3 9; 4 5 2;5 1 7; 5 3 6]; m=max(max(b(:,1:2))); %壓縮表中最大值就是鄰接矩陣的寬與高 A=compresstable2matrix(b); %從鄰接壓縮表構造圖的矩陣表示 netplot(A,1) %形象表示 S=inf(1,m); %從開始的源點到每一個節點的距離 S(1)=0; %源點到自己的距離為0 pa=zeros(1,m); %存儲每個節點的前驅,在松弛過程中賦值 pa(1)=1; %源點的前趨是自己
visit=zeros(1,m); %標記某個節點是否訪問過了 index=1; %從index節點開始搜索 %判斷是否對所有節點都找的最短路徑了。可能會有源點沒有路徑到目標節點的情況,那就無限循環了 while sum(visit)~=m %沒有出隊列操作,不過通過visit來等價的表示了 visit(index)=1; %標記第index節點為已入列的節點 [S pa]=relax(S,pa,A,visit,index,m); %松弛,如果兩個節點間有更短的距離,則用更短的距離 index=extract_min(S,visit,index,m); %使用已訪問的最小的節點作為下一次搜索的開始節點 end %最終我們需要的就是這兩個值 S %源點到其他每一點的距離 pa %其他每一節點的前趨 %算法到此結束,下面只是為了形象的表示而寫的。 re=[]; for i=2:m re=[re;pa(i) i A(pa(i),i)]; end A=compresstable2matrix(re); %從鄰接壓縮表構造圖的矩陣表示 figure; netplot(A,1) %形象表示
relax.m
%邊緣松弛,使用更短的距離作為節點的值 function [S pa]=relax(S,pa,A,visit,index,m) i=index; for j=1:m if A(i,j)~=inf && visit(j)~=1 %搜索沒有標記過的節點 if S(j)>S(i)+A(i,j) %將較小的值賦給正在搜尋的節點 S(j)=S(i)+A(i,j); pa(j)=i; end end end end
extract_min.m
%提取隊列中尚未標記的最小的值的序號 function index=extract_min(S,visit,index,m) Mi=inf; for j=1:m if visit(j)~=1 if S(j)<Mi Mi=S(j); index=j; end end end end