圖的遍歷(深度優先搜尋)
阿新 • • 發佈:2018-12-25
1、深度優先搜尋遍歷過程
圖的深度優先搜尋(Depth First Search),和樹的先序遍歷比較類似。
它的思想:假設初始狀態是圖中所有頂點均未被訪問,則從某個頂點v出發,首先訪問該頂點,然後依次從它的各個未被訪問的鄰接點出發深度優先搜尋遍歷圖,直至圖中所有和v有路徑相通的頂點都被訪問到。 若此時尚有其他頂點未被訪問到,則另選一個未被訪問的頂點作起始點,重複上述過程,直至圖中所有頂點都被訪問到為止。
顯然,深度優先搜尋是一個遞迴的過程
深度優先遍歷特點是,選定一個出發點後進行遍歷,能前進則前進,若不能前進,回退一步再前進,或再回退一步後繼續前進。依此重複,直到所有與選定點相通的所有頂點都被遍歷。
2、示例
對圖7-25連通無向圖採用深度優先搜尋遍歷可得到頂點訪問序列:v0,v1,v3,v7,v4,v8,v2,v5,v6
對圖7-26連通無向圖採用深度優先搜尋遍歷可得到頂點訪問序列:v0,v1,v3,v2,v4,v5,v6,v7
對圖7-27連通無向圖採用深度優先搜尋遍歷可得到頂點訪問序列:v0,v1,v4,v3,v2或v2,v3,v0,v1,v4或v2,v1,v0,v4,v3
3、連通圖的深度優先遍歷
給定一圖G=<V,E>,用visited[i]表示頂點i的訪問情況,初值設為0,表示所有頂點未被訪問過,當頂點被訪問過時置1。則初始情況下所有的visited[i]都為0。假設從頂點V 0開始遍歷,則下一個遍歷的頂點是V0的第一個鄰接點Vi,接著遍歷Vi的第一個鄰接點Vj,……直到所有的頂點都被訪過。
4、程式碼
無向圖,鄰接矩陣儲存:
對圖7-25深度優先遍歷:
#include <iostream> using namespace std; #define INFINITY 65535 /* 表示權值的無窮*/ typedef int EdgeType;//邊上的權值型別 typedef int VertexType;//頂點型別 const int MaxSize=100; int visited[MaxSize];//全域性標識陣列 class MGraph//鄰接矩陣類 { public: MGraph(){vertexNum=0;edgeNum=0;} MGraph(VertexType a[],int n);//建構函式,初始化具有n個頂點的零圖 void CreateMGraph1(MGraph *Gp);//建立無向圖的鄰接矩陣 void DFS(int v);//從v出發深度優先遍歷的遞迴函式 void DFS1(int v);//從v出發深度優先遍歷的非遞迴函式 public: int vertexNum,edgeNum;//頂點數和邊數 EdgeType adj[MaxSize][MaxSize];//鄰接矩陣 VertexType vertex[MaxSize];//頂點表 }; //建構函式,初始化具有n個頂點的零圖 MGraph::MGraph(VertexType a[],int n) { vertexNum=n;edgeNum=0; for(int i=0;i<n;i++) vertex[i]=a[i]; for(int i=0;i<n;i++) for(int j=0;j<n;j++) adj[i][j]=0; } //建立無向圖的鄰接矩陣表示 void MGraph::CreateMGraph1(MGraph *Gp) { int i, j, k; cout << "請輸入頂點數和邊數(空格分隔):" << endl; cin >> Gp->vertexNum >> Gp->edgeNum; cout << "請輸入頂點資訊(空格分隔):" << endl; for (i = 0; i < Gp->vertexNum; i++) cin >> Gp->vertex[i]; for (i = 0; i < Gp->vertexNum; i++) { for (j = 0; j < Gp->vertexNum; j++) Gp->adj[i][j] = 0; } for (k = 0; k < Gp->edgeNum; k++) { cout << "請輸入邊(vi, vj)的上標i,下標j(空格分隔):" << endl; cin >> i >> j; Gp->adj[i][j] = 1; Gp->adj[j][i] = 1;// 因為是無向圖,矩陣對稱 } } //從v出發深度優先遍歷的遞迴函式 void MGraph::DFS(int v) { int n=vertexNum;//頂點數目 if(v<0||v>=n) throw "位置出錯"; cout<<vertex[v]<<" ";//輸出頂點v visited[v]=1;//被訪問過 for(int j=0;j<n;j++) if(visited[j]==0&&adj[v][j]==1)//沒被訪問過且存在邊(v,j) DFS(j); } //從v出發深度優先遍歷的非遞迴函式 void MGraph::DFS1(int v) { int S[MaxSize],n=vertexNum,top=-1,j; if(v<0||v>=n) throw "位置出錯"; cout<<vertex[v]<<" ";//輸出頂點v visited[v]=1;//被訪問過 S[++top]=v;//頂點v進棧 while(top!=-1) { v=S[top];//棧頂元素出棧 for(j=0;j<n;j++) { if(visited[j]==0&&adj[v][j]==1)//沒被訪問過且存在邊(v,j) { cout<<vertex[j]<<" "; visited[j]=1; S[++top]=j; break; } } if(j==n) top--; } } int main() { MGraph grph; grph.CreateMGraph1(&grph); for(int i=0;i<MaxSize;i++) visited[i]=0; for(int i=0;i<grph.vertexNum;i++) { for(int j=0;j<grph.vertexNum;j++) {cout<<grph.adj[i][j]<<" ";} cout<<endl; } cout<<"遞迴深度優先遍歷結果:"<<endl; grph.DFS(0); for(int i=0;i<MaxSize;i++) visited[i]=0; cout<<endl<<"非遞迴深度優先遍歷結果:"<<endl; grph.DFS1(0); return 0; }
無向圖,鄰接表儲存:
圖7-25:
#include <iostream>
using namespace std;
#define INFINITY 65535 /* 表示權值的無窮*/
typedef int EdgeType;//邊上的權值型別
typedef int VertexType;//頂點型別
const int MaxSize=100;
int visited[MaxSize];//全域性標識陣列
//無向圖鄰接表。邊表結點結構
struct EdgeNode
{
int adjvex;//鄰接點域
EdgeNode *next;//指向下一個邊結點的指標
};
//無向圖鄰接表。表頭結點結構
struct VexNode
{
VertexType vertex;//頂點
EdgeNode *firstedge;//邊表的頭指標
};
//鄰接表類
class ALGraph
{
public:
ALGraph()//無參建構函式
{
vertexNum=0;
edgeNum=0;
for(int i=0;i<MaxSize;i++)
adjlist[i].firstedge=NULL;
}
ALGraph(VertexType a[],int n);//有參建構函式
void createGraph(int start, int end);//建立圖,採取前插法
void DFSL(int v);//從v出發深度優先遍歷可達頂點遞迴函式
void DFSL1(int v);//從v出發深度優先遍歷可達頂點的非遞迴函式
void displayGraph(int nodeNum);//列印
void CountComp(ALGraph g);//求連通分量數,判斷圖的連通性
private:
VexNode adjlist[MaxSize];//存放頂點表的陣列
int vertexNum,edgeNum;//圖的頂點數和邊數
};
//有參建構函式。構造頂點表
ALGraph::ALGraph(VertexType a[],int n)
{
vertexNum=n;
edgeNum=0;
for(int i=0;i<vertexNum;i++)
{
adjlist[i].vertex=a[i];
adjlist[i].firstedge=NULL;
}
}
//建立圖,採取前插法
void ALGraph::createGraph(int start, int end)
{//邊(start,end)
//adjlist[start].vertex=start;//表頭結點中的頂點
EdgeNode *p=new EdgeNode;//邊結點
p->adjvex=end;//鄰接點
//p->weight=weight;
p->next=adjlist[start].firstedge;//前插法插入邊結點p
adjlist[start].firstedge=p;
}
//列印儲存的圖
void ALGraph::displayGraph(int nodeNum)
{
int i,j;
EdgeNode *p;
for(i=0;i<nodeNum;i++)
{
p=adjlist[i].firstedge;
while(p)
{
cout<<'('<<adjlist[i].vertex<<','<<p->adjvex<<')'<<endl;
p=p->next;
}
}
}
//從v出發深度優先遍歷可達頂點遞迴函式
void ALGraph::DFSL(int v)
{
int n=vertexNum;
int j;
EdgeNode *p;
if(v>=n||v<0) throw "位置出錯";
cout<<adjlist[v].vertex<<" ";
visited[v]=1;
p=adjlist[v].firstedge;
while(p)
{
j=p->adjvex;//頂點
if(visited[j]==0) DFSL(j);
p=p->next;
}
}
//從v出發深度優先遍歷可達頂點的非遞迴函式
void ALGraph::DFSL1(int v)
{
int S[MaxSize],top=-1,j,n=vertexNum;
EdgeNode *p;
if(v>=n||v<0) throw "位置出錯";
cout<<adjlist[v].vertex<<" ";
visited[v]=1;
S[++top]=v;//v進棧
while(top!=-1)
{
v=S[top];//棧頂元素出棧
p=adjlist[v].firstedge;
while(p)
{
j=p->adjvex;//頂點
if(visited[j]==1) p=p->next;
else
{
cout<<adjlist[j].vertex<<" ";
visited[j]=1;
S[++top]=j;//v進棧
p=adjlist[j].firstedge;
}
}
if(j=vertexNum) top--;
}
}
//求連通分量數,判斷圖的連通性
void ALGraph::CountComp(ALGraph g)
{
int count=0;
int n=g.vertexNum;
for(int v=0;v<n;v++)
{
if(visited[v]==0)
{
count++;
g.DFSL(v);
}
}
if(count==1) cout<<endl<<"改圖是連通的!"<<endl;
else cout<<endl<<"改圖不連通,連通分量數為:"<<count<<endl;
}
int main()
{
int a[9]={0,1,2,3,4,5,6,7,8};
ALGraph gr=ALGraph(a,9);//初始化表頭
gr.createGraph(0,2);
gr.createGraph(0,1);
gr.createGraph(1,4);
gr.createGraph(1,3);
gr.createGraph(2,6);
gr.createGraph(2,5);
gr.createGraph(5,6);
gr.createGraph(3,7);
gr.createGraph(4,7);
gr.createGraph(7,8);
gr.displayGraph(9);
for(int i=0;i<MaxSize;i++)
visited[i]=0;
gr.DFSL1(0);
//gr.CountComp(gr);
return 0;
}