轉自:http://blog.sina.com.cn/s/blog_5ff8e88e01013lot.html
這幾天,用到了這個功能,但在網上找到了一份資料,思路寫的很清晰,但代碼有錯誤。因此,我就按着這個思路,自己整理了代碼,現在說明如下:(引用前部分思想,更新后部分代碼)
兩點間所有路徑的遍歷算法
中國海洋大學 信息科學與工程學院 熊建設 梁磊
摘要:本文首先簡單介紹圖的深度優先遍歷算法,接着根據圖的深度優先遍歷算法求出連通圖中兩點間所有路徑,並給出代碼。
關鍵詞:圖、深度優先遍歷、算法
Abstract:This arcicle introduces the Depth-First Traversal method,then introduces an algorithm to find all roads from one point to another point in a simple graph,and gives the codes with C++.
Key Words:Graph、 Algorithm
一、深度優先遍歷(Depth-First Traversal)
1.圖的深度優先遍歷的遞歸定義
假設給定圖G的初態是所有頂點均未曾訪問過。在G中任選一頂點v為初始出發點(源點),則深度優先遍歷可定義如下:首先訪問出發點v,並將其標記為已訪問過;然后依次從v出發搜索v的每個鄰接點w。若w未曾訪問過,則以w為新的出發點繼續進行深度優先遍歷,直至圖中所有和源點v有路徑相通的頂點(亦稱為從源點可達的頂點)均已被訪問為止。若此時圖中仍有未訪問的頂點,則另選一個尚未訪問的頂點作為新的源點重復上述過程,直至圖中所有頂點均已被訪問為止。
圖的深度優先遍歷類似於樹的前序遍歷。采用的搜索方法的特點是盡可能先對縱深方向進行搜索。這種搜索方法稱為深度優先搜索(Depth-First Search)。相應地,用此方法遍歷圖就很自然地稱之為圖的深度優先遍歷。
2、深度優先搜索的過程
設x是當前被訪問頂點,在對x做過訪問標記后,選擇一條從x出發的未檢測過的邊(x,y)。若發現頂點y已訪問過,則重新選擇另一條從x出發的未檢測過的邊,否則沿邊(x,y)到達未曾訪問過的y,對y訪問並將其標記為已訪問過;然后從y開始搜索,直到搜索完從y出發的所有路徑,即訪問完所有從y出發可達的頂點之后,才回溯到頂點x,並且再選擇一條從x出發的未檢測過的邊。上述過程直至從x出發的所有邊都已檢測過為止。此時,若x不是源點,則回溯到在x之前被訪問過的頂點;否則圖中所有和源點有路徑相通的頂點(即從源點可達的所有頂點)都已被訪問過,若圖G是連通圖,則遍歷過程結束,否則繼續選擇一個尚未被訪問的頂點作為新源點,進行新的搜索過程。
二、求兩點間所有路徑的算法


假設簡單連通圖如圖1所示,那么它的鄰接表存儲結構如圖2所示。假設我們要找出結點3到結點6的所有路徑,那么,我們就設結點3為起點,結點6為終點。我們需要的存儲結構有:一個保存路徑的棧、一個保存已標記結點的數組,那么找到結點3到結點6的所有路徑步驟如下:
1、 我們建立一個存儲結點的棧結構,將起點3入棧,將結點3標記為入棧狀態;
2、 從結點3出發,找到結點3的第一個非入棧狀態的鄰結點1,將結點1標記為入棧狀態;
3、 從結點1出發,找到結點1的第一個非入棧狀態的鄰結點0,將結點0標記為入棧狀態;
4、 從結點0出發,找到結點0的第一個非入棧狀態的鄰結點2,將結點2標記為入棧狀態;
5、 從結點2出發,找到結點2的第一個非入棧狀態的鄰結點5,將結點5標記為入棧狀態;
6、 從結點5出發,找到結點5的第一個非入棧狀態的鄰結點6,將結點6標記為入棧狀態;
7、 棧頂結點6是終點,那么,我們就找到了一條起點到終點的路徑,輸出這條路徑;
8、 從棧頂彈出結點6,將6標記為非入棧狀態;
9、 現在棧頂結點為5,結點5沒有除終點外的非入棧狀態的結點,所以從棧頂將結點5彈出;
10、 現在棧頂結點為2,結點2除了剛出棧的結點5之外,還有非入棧狀態的結點6,那么我們將結點6入棧;
11、 現在棧頂為結點6,即找到了第二條路徑,輸出整個棧,即為第二條路徑
12、 重復步驟2-11,就可以找到從起點3到終點6的所有路徑;
13、 棧為空,算法結束。
三、算法C++代碼如下:
#include <iostream>
#include <map>
using namespace std;
class node
{
public:
int number;
node *next;
node(int a,node *b)
{
number=a;
next=b;
}
};
class stacks
{
public:
node * top;
stacks(node * a=NULL)
{
top=NULL;
}
void push(int a)
{
if (top==NULL)
top =new node(a,NULL);
else top=new node(a,top);
}
void pop()
{
node *b=top;
top=top->next;
delete b;
}
}; //保存已加入路徑結點的棧
int cur_node;//當前結點,即為棧頂的結點
int next_node=8 ;//當前結點的下一個鄰接點,即剛從棧頂彈出的結點,初始化為8
map<int,int> map_next;//每個結點的下一個鄰接點,即剛從棧頂彈出的結點
int start=3;
int end=6;//起點為3,終點為6
stacks aray[8]={stacks(NULL),stacks(NULL),stacks(NULL),stacks(NULL),stacks(NULL),stacks(NULL),stacks(NULL),stacks(NULL)};
stacks stack(NULL);
int states[8];//保存結點狀態的數組
int main()
{
//初始化map_next
for(int i=0;i<=7;i++)
{
map_next[i] = -1;
}
aray[0].push(2);
aray[0].push(1);
aray[1].push(4);
aray[1].push(3);
aray[1].push(0);
aray[2].push(6);
aray[2].push(5);
aray[2].push(0);
aray[3].push(7);
aray[3].push(1);
aray[4].push(7);
aray[4].push(1);
aray[5].push(6);
aray[5].push(2);
aray[6].push(5);
aray[6].push(2);
aray[7].push(4);
aray[7].push(3);
node* neighbour(int a);// ,int b
stack.push(start);//將起點入棧
states[start]=1;//將起點標記為入棧狀態
while(NULL != stack.top) //棧不為空
{
if (stack.top->number==end)
{
cout<<"end";
node* abc=stack.top;
while(abc->number != start)
{
cout<<abc->number<<",";
abc=abc->next;
}
cout << "start"<<endl;//輸出已找到的路徑
stack.pop();//將棧頂結點彈出
states[end]=0;//清除終點的狀態
map_next[end]=-1;
}
else
{
cur_node=stack.top->number;
if(neighbour(cur_node) != NULL)//鄰居不為空
{
node *d =neighbour(cur_node);
map_next[cur_node] = d->number;
cur_node=d->number;
stack.push(cur_node);
states[cur_node]=1;
}
else
{
stack.pop();
states[cur_node]=0;
map_next[cur_node] = -1;
}
}
}
return 0;
}
node* neighbour(int a)//,int b
{
node *abc=aray[a].top;
while ((NULL!=abc))//結點abc不空
{
if( states[abc->number]==1 )//已經在棧stack里了
{
abc=abc->next;
}
else//不在棧stack里
{
if(-1 == map_next[a])//就要abc作為返回值
{
while(NULL!=abc && states[abc->number]==1)
{
abc = abc->next;
}
return abc;
}
else if(abc->number == map_next[a])
{
abc=abc->next;
while(NULL!=abc && states[abc->number]==1)
{
abc = abc->next;
}
return abc; //將abc的下一個結點返回
}
else
{
abc=abc->next;
}
}
}
return NULL;
}
四、總結
本算法利用無向圖的鄰接表存儲結構,通過深度優先遍歷來查找連通圖中兩點間所有路徑。算法並不復雜,效率較高。由於有向圖也可以用鄰接表來存儲,所以該算法對於有向圖也是適用的。
五,參考文獻
[1] 嚴蔚敏,吳偉民. 數據結構(C 語言版) [M] . 北京:清華大學出版杜,1997
[2] 譚浩強 C++面向對象程序設計 北京:清華大學出版杜,2006
[3] Larry Nyhoff黃達明 數據結構與算法分析:C++語言描述 清華大學出版社 2006
