如此經典的算法竟一直沒有單獨的實現過,真是遺憾啊。
廣度優先搜索在過去實現的二值圖像連通區域標記和prim最小生成樹算法時已經無意識的用到了,深度優先搜索倒是沒用過。
這次單獨的將兩個算法實現出來,因為算法本身和圖像沒什么關系,所以更純粹些。
廣度優先搜索是從某一節點開始,搜索與其線連接的所有節點,按照廣度方向像外擴展,直到不重復遍歷所有節點。
深度優先搜索是從某一節點開始,沿着其搜索到的第一個節點不斷深入下去,當無法再深入的時候,回溯節點,然后再在回溯中的某一節點開始沿另一個方向深度搜索,直到不重復的遍歷所有節點。
廣度優先搜索用的是隊列作為臨時節點存放處;深度優先搜索可以遞歸實現(算法導論就是用遞歸實現的偽代碼),不過我這里是用棧作為臨時節點存放處。
感覺也沒什么好介紹的了,抄算法導論上的介紹也沒什么意思,所有的內容都是書上的,真正學東西還是要看書。
下面是運行結果:
原連通圖:
廣度優先搜索:
深度優先搜索:
matlab代碼如下,其中的畫圖函數netplot.m。
BFS.m
clear all;close all;clc %初始化鄰接壓縮表 b=[1 2;1 3;1 4;2 4; 2 5;3 6;4 6;4 7]; m=max(b(:)); %壓縮表中最大值就是鄰接矩陣的寬與高 A=compresstable2matrix(b); %從鄰接壓縮表構造圖的矩陣表示 netplot(A,1) %形象表示 head=1; %隊列頭 tail=1; %隊列尾,開始隊列為空,tail==head queue(head)=1; %向頭中加入圖第一個節點 head=head+1; %隊列擴展 flag=1; %標記某個節點是否訪問過了 re=[]; %最終結果 while tail~=head %判斷隊列是否為空 i=queue(tail); %取隊尾節點 for j=1:m if A(i,j)==1 && isempty(find(flag==j,1)) %如果節點相連並且沒有訪問過 queue(head)=j; %新節點入列 head=head+1; %擴展隊列 flag=[flag j]; %對新節點進行標記 re=[re;i j]; %將邊存入結果 end end tail=tail+1; end A=compresstable2matrix(re); figure; netplot(A,1)
DFS.m
clear all;close all;clc %初始化鄰接壓縮表 b=[1 2;1 3;1 4;2 4; 2 5;3 6;4 6;4 7]; m=max(b(:)); %壓縮表中最大值就是鄰接矩陣的寬與高 A=compresstable2matrix(b); %從鄰接壓縮表構造圖的矩陣表示 netplot(A,1) %形象表示 top=1; %堆棧頂 stack(top)=1; %將第一個節點入棧 flag=1; %標記某個節點是否訪問過了 re=[]; %最終結果 while top~=0 %判斷堆棧是否為空 pre_len=length(stack); %搜尋下一個節點前的堆棧長度 i=stack(top); %取堆棧頂節點 for j=1:m if A(i,j)==1 && isempty(find(flag==j,1)) %如果節點相連並且沒有訪問過 top=top+1; %擴展堆棧 stack(top)=j; %新節點入棧 flag=[flag j]; %對新節點進行標記 re=[re;i j]; %將邊存入結果 break; end end if length(stack)==pre_len %如果堆棧長度沒有增加,則節點開始出棧 stack(top)=[]; top=top-1; end end A=compresstable2matrix(re); figure; netplot(A,1)
compresstable2matrix.m
function A=compresstable2matrix(b) [n ~]=size(b); m=max(b(:)); A=zeros(m,m); for i=1:n A(b(i,1),b(i,2))=1; A(b(i,2),b(i,1))=1; end end