思路:
利用栈非递归实现深度优先遍历(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