眾所周知常用的圖遍歷方式有深度優先遍歷和廣度優先遍歷兩種,那么我首先來看看這兩種算法的具體實現,我們用G[Max][Max]表示圖的鄰接矩陣。
//三個全局變量
ool Visited[Max];//訪問標志
void(*VisFunction)(int Vertex);//訪問頂點
ool(*IsEdgeFuncion)(int G[][Max],intv,int u);//判斷連邊
void Depth_First(intG[][Max],void(*VisFunc)(int),bool(*IsEdgeFun)(int G[][Max],int, int),intBeginVer)
inti
for(i=0;i<Max;i++)Visited[i]=false
VisFunction=VisFunc
IsEdgeFuncion=IsEdgeFu
if(BeginVer<0||BeginVer>=Max)BeginVer=0
DFS(G,BeginVer)
void DFS(int G[][Max],int BeginVer)
Visited[BeginVer]=true
VisFunction(BeginVer)
for(inti=0;i<Max;i++)
if(IsEdgeFuncion(G,BeginVer,i)&&!Visited[i]){
DFS(G,i)
void Depth_FirstVer(intG[][Max],void(*VisFunc)(int),bool(*IsEdgeFun)(int G[][Max],int, int),intBeginVer)
usingstd::stack
tack<int>MyStack
inti
for(i=0;i<Max;i++)Visited[i]=false
VisFunction=VisFunc
IsEdgeFuncion=IsEdgeFu
if(BeginVer<0||BeginVer>=Max)BeginVer=0
MyStack.push(BeginVer);//Initializatio
Visited[BeginVer]=true
//++Number;//改進
VisFunction(BeginVer)
int Vertex
while(!MyStack.empty()){
Vertex=MyStack.top()
int j=0
for(;j<Max;j++){
if(IsEdgeFuncion(G,Vertex,j)&&!Visited[j]){
MyStack.push(j)
Visited[j]=true
VisFunction(j)
//if(++Number==Max)return;//改進
reak
if(j>=Max)MyStack.pop()
我們用非遞歸版本來分析(比較清楚),我們知道在遍歷過程中,每個頂點都要進一次棧且僅僅一次,n個頂點就會有n次進棧,現在我們在分析一下,每一次進棧后做什么呢?
當頂點u進棧后,就要以u為當前點繼續遍歷,也就說要尋找它的下一個鄰接點v,時間為o(n),當沿着v這個分支遍歷結束后又會回到u這點,找下一個沒訪問的鄰接點v’(如果有的的話)。然后沿着v’分支繼續遍歷,因此對每次進棧可能需要o(cn)次尋找下一個元素。因此總的時間復雜度為0(n2)=c1n+c2n+…cnn;
從這個分析我們可以改進上面的算法,用一個變量(Number)來記錄已經訪問過的元素個數,一點Number等於頂點個數時就可以直接退出了,而不必返回去訪問一些沒用的分支了。
當圖用鄰接表儲存時,那么當當頂點u進棧后,要尋找它的下一個鄰接點v,時間為o(e1),其中e1為u的鄰接邊個數, 此總的時間復雜度為0(n+e)=n+e1+e2+…+en;其中e= e1+e2+…+en為無向圖中邊數,有向圖弧數。O(n)是初始化訪問標志等所耗時間。
void BFS(intG[][Max],void(*VisFunc)(int),bool(*IsEdgeFun)(int G[][Max],int, int),intBeginVer)
usingstd::queue
queue<int>Myqueue
inti
for(i=0;i<Max;i++)Visited[i]=false
VisFunction=VisFunc
IsEdgeFuncion=IsEdgeFu
if(BeginVer<0||BeginVer>=Max)BeginVer=0
Myqueue.push(BeginVer)
Visited[BeginVer]=true
VisFunction(BeginVer)
intVertex
while(!Myqueue.empty()){
Vertex=Myqueue.front()
Myqueue.pop()
for(intj=0;j<Max;j++){
if(IsEdgeFuncion(G,Vertex,j)&&!Visited[j]){
Myqueue.push(j)
Visited[j]=true
VisFunction(j)
在廣度優先的遍歷中每個頂點都要進(出)一次列隊且僅僅一下(類似於深度優先遍歷的進棧),對於每一個頂點u出列隊后,要訪問的所有鄰接點,時間為o(n),因此我們可知廣度優先遍歷和深度優先遍歷總的時間復雜度是一樣的為o(n2)或o(n+e)
他們都能實現對圖的遍歷,且時間復雜度也是一樣的。但對於同一個圖他們的訪問順序是不一樣的。這樣的不一樣可能會影響他們的具體應用。
從上面的算法(都看非遞歸本版)可以看出,深度優先遍歷時使用的stack,stack的原則是先進后出,且每一次進棧后,馬上跳出當前的for循環。以當前進棧元素為起點繼續往下遍歷,如果沒能找到一個合適的元素(j>=Max)那么就將當前元素出棧,這樣保證了能沿着分支回到父節點。
而在廣度優先使用的是queue,queue的原則是先進先出,且每一出列隊后,以出隊元素為起點,遍歷它所有的鄰接點。
