思路:
利用棧非遞歸實現深度優先遍歷(DFS)圖。先把起始頂點訪問併入棧;然後每次取棧頂元素,找到一個與棧頂頂點連接並且未被訪問的頂點,隨即訪問此頂點,並將此頂點入棧;直到某一頂點沒有出邊(針對有向圖)或者所有連接的頂點都已經被訪問過了,刪除棧頂元素;循環上述步驟,直到棧爲空,深度優先遍歷結束。
注:深度優先遍歷到所有頂點的前提是此圖爲連通圖;若此圖爲兩個連通圖組成的圖,則需要兩次深度優先遍歷,每次都取其中一個連通圖任一點作爲起始頂點。
代碼:
#include <iostream>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
typedef int T; //頂點的值類型 int, char, double and so on
struct Node
{
T value; //頂點值
int numbers; //頂點編號
bool operator==(const Node &other)
{
if((this->numbers==other.numbers)&&(this->value==other.value))
return true;
else
return false;
}
Node(int a1=0,int a2=0)
{
numbers=a1;
value=a2;
}
};
struct Edge
{
int num1; //起始頂點
int num2; //終止頂點
int weight; //邊所對應的權值
};
class Graph
{
private:
int vertex_nums; //頂點數
int edge_nums; //邊數
vector<Node> vertex; //頂點表,強制設爲編號從0開始
vector<Edge> edge; //邊表
vector<vector<int> > edge_maze; //鄰接矩陣,存儲各個頂點連接關係
public:
Graph(int n1=10,int n2=10)
{
vertex_nums=n1;
edge_nums=n2;
for(int i=0;i<vertex_nums;i++)
{
Node a;
a.numbers=i;
a.value=0;
vertex.push_back(a);
}
for(int i=0;i<vertex_nums;i++) //鄰接矩陣初始化
{
vector<int> temp(vertex_nums,0);
edge_maze.push_back(temp);
}
cout<<"please input the edges about the graph: vertex_number1 vertex_number2 weight"<<endl;
int x,y,z;
for(int i=0;i<edge_nums;i++)
{
cin>>x>>y>>z;
Edge temp_edge;
temp_edge.num1=x;
temp_edge.num2=y;
temp_edge.weight=z;
edge.push_back(temp_edge);
edge_maze[x][y]=1;
edge_maze[y][x]=1;
}
}
void print_edge_maze()
{
cout<<endl;
cout<<"輸出鄰接矩陣"<<endl;
cout<<" ";
for(int i=0;i<vertex_nums;i++)
cout<<"v"<<i<<" ";
cout<<endl;
for(int i=0;i<vertex_nums;i++)
{
cout<<"v"<<i<<" ";
for(int j=0;j<vertex_nums;j++)
{
cout<<edge_maze[i][j]<<" ";
}
cout<<endl;
}
}
void print_edge_vec()
{
cout<<endl;
cout<<"輸出邊表:"<<endl;
cout<<"起始頂點-->結束頂點 邊權值"<<endl;
for(int i=0;i<edge_nums;i++)
{
cout<<" v"<<edge[i].num1<<" -->"<<" v"<<edge[i].num2<<" "<<edge[i].weight<<endl;
}
}
//基於DFS非遞歸遍歷圖
void DFS_Graph_noniterator(int start_vertex_num=0)
{
vector<int> if_output(vertex_nums,0); //指示頂點是否被遍歷
Node first(start_vertex_num);
stack<Node> s;
cout<<endl;
cout<<"遍歷頂點路徑如下"<<endl;
cout<<"v"<<first.numbers<<"---->";
if_output[start_vertex_num]=1; //標記已被訪問
s.push(first);
while(!s.empty())
{
Node temp=s.top();
int i;
for(i=0;i<edge_nums;i++)
{
if((edge[i].num1==temp.numbers)&&(if_output[edge[i].num2]==0))
{
cout<<"v"<<edge[i].num2<<"---->";
if_output[edge[i].num2]=1; //標記已被訪問
Node push_node(edge[i].num2);
s.push(push_node);
break;
}
else if((edge[i].num2==temp.numbers)&&(if_output[edge[i].num1]==0))
{
cout<<"v"<<edge[i].num1<<"---->";
if_output[edge[i].num1]=1; //標記已被訪問
Node push_node(edge[i].num1);
s.push(push_node);
break;
}
else
continue;
}
if(i==edge_nums)
s.pop();
}
cout<<"end"<<endl;
}
//基於BFS非遞歸遍歷圖
void BFS_Graph_nonrecursive(int start_vertex_num=0)
{
vector<int> if_output(vertex_nums,0); //指示頂點是否被遍歷
Node first(start_vertex_num);
queue<Node> qu;
qu.push(first);
if_output[start_vertex_num]=1; //入隊即表示即將被遍歷
cout<<endl;
cout<<"遍歷頂點路徑如下"<<endl;
while(!qu.empty())
{
Node temp=qu.front();
qu.pop();
cout<<"v"<<temp.numbers<<"---->";
//遍歷所有邊,找到與隊列頭結點連接的頂點,將所有與頭頂點連接的頂點加入隊列
for(int i=0;i<edge_nums;i++)
{
if(edge[i].num1==temp.numbers)
{
if(if_output[edge[i].num2]==0) //未被遍歷
{
Node temp_node(edge[i].num2); //將連接點加入隊列
qu.push(temp_node);
if_output[edge[i].num2]=1; //入隊即表示即將被遍歷
}
}
else if(edge[i].num2==temp.numbers)
{
if(if_output[edge[i].num1]==0) //未被遍歷
{
Node temp_node(edge[i].num1); //將連接點加入隊列
qu.push(temp_node);
if_output[edge[i].num1]=1;
}
}
else
continue;
}
}
cout<<"end"<<endl;
cout<<"遍歷結束"<<endl;
}
};
int main()
{
Graph graph(8,10);
graph.print_edge_vec();
graph.print_edge_maze();
//graph.BFS_Graph_nonrecursive();
graph.DFS_Graph_noniterator();
return 0;
}
輸出:
please input the edges about the graph: vertex_number1 vertex_number2 weight
0 1 0
1 2 1
2 3 2
3 4 3
4 5 4
5 6 5
6 7 6
7 3 7
7 4 8
6 4 9
輸出邊表:
起始頂點-->結束頂點 邊權值
v0 --> v1 0
v1 --> v2 1
v2 --> v3 2
v3 --> v4 3
v4 --> v5 4
v5 --> v6 5
v6 --> v7 6
v7 --> v3 7
v7 --> v4 8
v6 --> v4 9
輸出鄰接矩陣
v0 v1 v2 v3 v4 v5 v6 v7
v0 0 1 0 0 0 0 0 0
v1 1 0 1 0 0 0 0 0
v2 0 1 0 1 0 0 0 0
v3 0 0 1 0 1 0 0 1
v4 0 0 0 1 0 1 1 1
v5 0 0 0 0 1 0 1 0
v6 0 0 0 0 1 1 0 1
v7 0 0 0 1 1 0 1 0
遍歷頂點路徑如下
v0---->v1---->v2---->v3---->v4---->v5---->v6---->v7---->end