图的遍历
继续上一次计算两个节点之间的所有路径,这次采用深度优先遍历与广度优先遍历算法来遍历整个图
图如下:
1、深度优先遍历:
思想:
利用递归,与树的遍历不同的是,可能在图中某些节点之间是不连通的。本代码中使用的是递归,当然也是可以使用栈的非递归形式
代码:
#include <stack>
#include <queue>
#include <iostream>
using namespace std;
#define NUM 12
#define MAX_PATH 100
struct Node
{
int key;
int flag;
Node()
{
flag=0;
}
};
template<class T>
class Queue:public queue<T>
{
public:
T dequeue()
{
T tmp=front();
queue<T>::pop();
return tmp;
}
void enqueue(const T&e1)
{
push(e1);
}
bool isEmpty()
{
return empty();
}
};
class Graph
{
public:
int resultPath[MAX_PATH][NUM];//寻找所有路径
bool Mark[NUM];//标记是否已经访问
public:
Graph()
{
Reset();
}
//将矩阵中的元素置为空
void Reset()
{
for (int i=0;i<NUM;i++)
{
for (int j=0;j<MAX_PATH;j++)
{
resultPath[i][j]=0;
}
Mark[i]=false;
}
}
void test()
{
int Matrix[NUM][NUM]={
{0,1,0,1,0,0,0,0,0,0,0,0}, //A
{1,0,1,0,0,0,0,0,0,0,0,0},//B
{0,1,0,1,1,0,0,0,0,0,0,0},//C
{1,0,1,0,0,1,0,0,0,0,0,0}, //D
{0,0,1,0,0,0,1,0,0,0,0,0}, //E
{0,0,0,1,0,0,1,1,0,0,0,0}, //F
{0,0,0,0,1,1,0,0,0,0,0,0}, //G
{0,0,0,0,0,1,0,0,0,0,0,0},//H
{0,0,0,0,0,0,0,0,0,1,0,1},//I
{0,0,0,0,0,0,0,0,1,0,1,1},//J
{0,0,0,0,0,0,0,0,0,1,0,0},//K
{0,0,0,0,0,0,0,0,1,1,0,0}//L
};
findPathBetweenTwoNode(Matrix);//找到所有的简单路径
DFE(Matrix);//图的遍历,采用深度优先遍历算法
}
/************************************************************************/
/* 函数功能:图的遍历
参数说明:vNum,顶点的个数
Matrix 邻接图
*/
/************************************************************************/
void DFE(int Matrix[NUM][NUM])
{
//////////////////////深度优先遍历//////////////////////////////////
Reset();//将元素置空
int result[NUM]={0};//存放遍历结果
int nPos=0;
for(int i=0;i<NUM;i++)
{
deapFirstSearch(Matrix,result,nPos,i);//进行深度优先遍历算法
}
cout<<"遍历的顺序为:"<<endl;
for (int i=0;i<NUM;i++)
{
cout<<result[i]<<" ";
}
///////////////////////广度优先遍历////////////////////////
Reset();
for (int i=0;i<NUM;i++)
{
result[i]=0;//清空数据
}
breadFirstSearch(Matrix,result);//进行广度优先遍历算法
cout<<endl<<"广度遍历的顺序为:"<<endl;
for (int i=0;i<NUM;i++)
{
cout<<result[i]<<" ";
}
}
/************************************************************************/
/*函数功能:深度优先遍历
参数说明:Matrix 矩阵
*/
/************************************************************************/
void deapFirstSearch(int Matrix[NUM][NUM],int *result,int &nResultPos,int nSearchPos)
{
if (Mark[nSearchPos]==false)
{
*(result+nResultPos)=(nSearchPos+1);//索引是从0开始的
Mark[nSearchPos]=true;
nResultPos++;
for (int i=0;i<NUM;i++)
{
if (Matrix[nSearchPos][i]==1)
{
deapFirstSearch(Matrix,result,nResultPos,i);
}
}
}
}
运行结果:
上面已经将广度优先的代码附上,主要利用的是队列,利用标记来表明是否已经访问过了
//广度优先遍历算法
//思想:利用队列
void breadFirstSearch(int Matrix[NUM][NUM],int *result)
{
Queue<int>tempQueue;//定义队列
int nSearchPos=0;//顶点遍历的索引,用以判断当前顶点是否已经遍历过
int nResulPos=0;//索引遍历结果的元素
while(nSearchPos<NUM)
{
if (Mark[nSearchPos]==false)//当节点还没有访问
{
tempQueue.enqueue(nSearchPos);//入队列
Mark[nSearchPos]=true;//标识已经访问过
while(!tempQueue.isEmpty())//当队列不为空
{
int dataPos=tempQueue.dequeue();//取出队最前面的元素
result[nResulPos]=(dataPos+1);//存入结果集中
nResulPos++;
for (int i=0;i<NUM;i++)
{
if (Matrix[dataPos][i]==1&&Mark[i]==false)//判断与该节点是否有联通且该节点没有被访问过
{
tempQueue.enqueue(i);//出队列
Mark[i]=true;//标记为已访问,这里很关键。试想将Mark放在for循环的外面??造成尽管有的节点已经入队列了,但是因为没有标记,所以再次的入队列,死循环
}
}
}
}
nSearchPos++;//顶点索引加1
}
}
};
运行结果:
小结:
1)利用好队列与栈
2)小小标记用途多