参考: http://www.cnblogs.com/daoluanxiaozi/archive/2012/05/18/2507212.html
两种图的遍历算法在其他图的算法当中都有应用,并且是基本的图论算法。
广度优先搜索(BFS),可以被形象的描述为“浅尝辄止”,具体一点就是每个顶点只访问它的邻接节点(如果它的邻接节点没有被访问)并且记录这个邻接节点,当访问完它的邻接节点之后就结束这个顶点的访问。
广度优先用到了“先进先出”队列,通过这个队列来存储第一次发现的节点,以便下一次的处理;而对于再次发现的节点,我们不予理会——不放入队列,因为再次发现的节点:
《算法导轮》对两种搜索都采用了很聪明的做法,用白色WHITE来标志未发现的节点,用灰色GRAY来标志第一次被发现的节点,用黑色BLACK来标志第二次被发现的节点。
于是有了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
BFS(G,s)
for
each vertex v in V[G]
status[v] = WHITE
/******其他初始化******/
status[s] = GRAY
//s是原点
queue q
入队(q,s);
while
q非空
t = 出队(q);
for
each vertex v in Adj[t]
//与t邻接的点
if
status[v] = WHITE
//只对未访问的操作
status[v] = GRAY
//标记为第一次访问
/******其他操作******/
入队(q,v)
status[t] = BLACK
//此点已经处理完了
|
导轮还在上面伪代码的“其他”中加入了访问长度和父节点的操作。此举可以算出,从源点到其他顶点路径的最少步数和它的具体路径。
关于广度优先搜索的一个简单应用:
假如有问题,每个村庄之间都通过桥来联通,先给出村庄的图,问村庄A到村庄B最少要通过多少座桥?这个问题可以很容易的转化为上面的BFS问题。
深度优先搜索(DFS),可以被形象的描述为“打破沙锅问到底”,具体一点就是访问一个顶点之后,我继而访问它的下一个邻接的顶点,如此往复,直到当前顶点一被访问或者它不存在邻接的顶点。
同样,算法导论采用了“聪明的做法”,用三种颜色来标记三种状态。但这三种状态不同于广度优先搜索:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
DFS(G,s)
for
each vertex v in V(G)
status[v] = WHITE
/******其他初始化******/
for
each vertex v in V(G)
if
(status[v]==WHITE)
DFS-VISIT(v)
DFS-VISIT(v)
status[v] = GRAY
for
each vertex t in Adj(v)
if
status[t] = WHITE
DFS-VISIT(t)
/******其他操作******/
status[v] = BLACK
|
通过给DFS搜索过程中给每一个顶点加时间戳,就可以实现拓扑排序了。实现拓扑排序需要:
对于每一个顶点,都有两个时间戳,分别这样来定义:
两个算法都是O(V+E),在用到的时候适当选取。在使用白灰黑标志的时候,突然明白了如何用深度优先搜索来判断有向图中是否存在环。
深度优先和广度优先各有各的优缺点:
在更多的情况下,深优是比较好的方案。
代码如下:
//bst_dst.in file
7 8
1 2
1 4
2 6
2 4
4 3
3 5
5 7
6 4
//查看图的连通性
#include
#include
#include
#include
using namespace std;
//7 7
//1 2
//1 4
const int MAX = 100;
int nArray[MAX][MAX] = {0};
bool BST(int (*nMap)[MAX], int nEdge, int nStart, int nEnd) //广度优先使用queue - 迪科斯彻单元最短路径算法
{
if(nMap == NULL || nEdge == 0 || nStart == nEnd)
return false;
queue
bool *pVisit = new bool[nEdge+1];
memset(pVisit, 0, nEdge*sizeof(bool));
s.push(nStart);
pVisit[nStart] = true;
while(!s.empty())
{
int temp = s.front();
s.pop();
for(int i=1; i<=nEdge; i++)
{
if(nMap[temp][i] != 0)
{
if(i == nEnd)
return true;
if(!pVisit[i])
{
s.push(i);
cout << i << endl;
pVisit[i] = true;
}
}
}
}
return false;
}
enum
{
WHITE,
GRAY,
BLACK
};
bool visit(int (*nMap)[MAX], int nEdge, int nStart, int nEnd, int *pVisit)
{
if(nStart == nEnd)
{
return true;
}
for(int i=1; i<=nEdge; i++)
{
if( nMap[nStart][i] != 0 && pVisit[i]== WHITE)
{
pVisit[i] = GRAY;
cout < bool bRes = visit(nMap, nEdge, i, nEnd, pVisit);
if(bRes == true)
return true;
pVisit[i] = BLACK;
}
}
return false;
}
// void visit(int (*nMap)[MAX], int nEdge, int nStart, int nEnd, int *pVisit) //没返回值的版本
// {
// if(nStart == nEnd)
// {
// return;
// }
// for(int i=1; i<=nEdge; i++)
// {
// if( nMap[nStart][i] != 0 && pVisit[i]== WHITE)
// {
// pVisit[i] = GRAY;
// cout < // bool bRes = visit(nMap, nEdge, i, nEnd, pVisit);
// pVisit[i] = BLACK;
// }
// }
// }
bool DST(int (*nMap)[MAX], int nEdge, int nStart, int nEnd) //深度优先使用递归
{
if(nMap == NULL || nEdge == 0 || nStart == nEnd)
return false;
int *pVisit = new int[nEdge+1];
memset(pVisit, 0, nEdge*sizeof(int));
pVisit[nStart] = GRAY;
bool bRes = visit(nMap, nEdge, nStart, nEnd, pVisit);
pVisit[nStart] = BLACK;
if(bRes)
{
delete []pVisit;
return true;
}
delete []pVisit;
return false;
}
int main(){
freopen("bst_dst.in", "r", stdin);
int nPointNum = 0, nLineNum = 0;
cin >> nPointNum >> nLineNum;
for(int i=0; i< nLineNum; i++)
{
int x, y;
cin >> x >> y;
nArray[x][y] = 1;
nArray[y][x] = 1;
cout << x << " " << y << endl;
}
cout << "the result:" << DST(nArray, nPointNum, 1, 3) << endl;
return 0;
}