广度优先和深度优先区别。

来源:互联网 发布:阿里云客服薪资计算 编辑:程序博客网 时间:2024/05/19 10:13

参考:  http://www.cnblogs.com/daoluanxiaozi/archive/2012/05/18/2507212.html

 

两种图的遍历算法在其他图的算法当中都有应用,并且是基本的图论算法。

 

广度优先搜索

广度优先搜索(BFS),可以被形象的描述为“浅尝辄止”,具体一点就是每个顶点只访问它的邻接节点(如果它的邻接节点没有被访问)并且记录这个邻接节点,当访问完它的邻接节点之后就结束这个顶点的访问。

广度优先用到了“先进先出”队列,通过这个队列来存储第一次发现的节点,以便下一次的处理;而对于再次发现的节点,我们不予理会——不放入队列,因为再次发现的节点:

  1. 无非是已经处理完的了;
  2. 或者是存储在队列中尚未处理的。

image

《算法导轮》对两种搜索都采用了很聪明的做法,用白色WHITE来标志未发现的节点,用灰色GRAY来标志第一次被发现的节点,用黑色BLACK来标志第二次被发现的节点。

于是有了:

+ View Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BFS(G,s)
    foreach vertex v in V[G]
        status[v] = WHITE
        /******其他初始化******/
    status[s] = GRAY   //s是原点
    queue q
    入队(q,s);
    whileq非空
        t = 出队(q);
        foreach vertex v in Adj[t] //与t邻接的点
            ifstatus[v] = WHITE    //只对未访问的操作
                status[v] = GRAY   //标记为第一次访问
                /******其他操作******/
                入队(q,v)
        status[t] = BLACK  //此点已经处理完了

导轮还在上面伪代码的“其他”中加入了访问长度和父节点的操作。此举可以算出,从源点到其他顶点路径的最少步数和它的具体路径。

关于广度优先搜索的一个简单应用:

假如有问题,每个村庄之间都通过桥来联通,先给出村庄的图,问村庄A到村庄B最少要通过多少座桥?这个问题可以很容易的转化为上面的BFS问题。

深度优先搜索

深度优先搜索(DFS),可以被形象的描述为“打破沙锅问到底”,具体一点就是访问一个顶点之后,我继而访问它的下一个邻接的顶点,如此往复,直到当前顶点一被访问或者它不存在邻接的顶点。

同样,算法导论采用了“聪明的做法”,用三种颜色来标记三种状态。但这三种状态不同于广度优先搜索:

  1. WHITE 未访问顶点
  2. GRAY 一条深度搜索路径上的顶点,即被发现时
  3. BLACK 此顶点的邻接顶点被全部访问完之后——结束访问次顶点

image

+ View Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DFS(G,s)
    foreach vertex v in V(G)
        status[v] = WHITE
        /******其他初始化******/
    foreach vertex v in V(G)
        if(status[v]==WHITE)
            DFS-VISIT(v)
 
DFS-VISIT(v)
    status[v] = GRAY
    foreach vertex t in Adj(v)
        ifstatus[t] = WHITE
            DFS-VISIT(t)
            /******其他操作******/
    status[v] = BLACK

通过给DFS搜索过程中给每一个顶点加时间戳,就可以实现拓扑排序了。实现拓扑排序需要:

对于每一个顶点,都有两个时间戳,分别这样来定义:

  1. 在一顶点刚被发现的时候,标记此顶点的第一个时间戳;
  2. 在结束此顶点的访问的时候,标记此顶点的第二个时间戳。时间戳可以用简单的123456来标记,只要能区分大小就行。
因此,你会发现,越早发现的点,他的第一个时间戳会越小,但是他的第二个时间戳会越大。 

总结

两个算法都是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 <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
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<int> s;
 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 <<i << endl;
   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 <<i << endl;
   // 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;
}

 

 

0 0
原创粉丝点击