代码改变世界

[转载]算法王帖:精选经典的24个算法 [3.BFS和DFS优先搜索]

2010-12-16 00:29  Rollen Holt  阅读(1004)  评论(1编辑  收藏  举报

算法王帖:精选经典的24个算法 [1.A*搜索算法]

 

-------------------------------------------------

翻遍网上,关于此类BFS和DFS算法的文章,很多。但全都是抄来抄去,最后,都说不出个所以然来。

此文,我自作主张,加精。读完此文,我想,

你对图的广度优先搜索和深度优先搜索定会有个通通透透,彻彻底底的认识。

 

---------------------

首先,看下算法导论一书关于 此DFS 深度优先搜索算法和 BFS 广度优先搜索算法的概述。

算法导论第二版,中译本,第324页。

广度优先搜索(BFS)

在Prime最小生成树算法,和Dijkstra单源最短路径算法中,都采用了与BFS 算法类似的思想。

BFS(G, s)
 1  for each vertex u ∈ V [G] - {s}
 2       do color[u] ← WHITE
 3          d[u] ← ∞
 4          π[u] ← NIL

  //除了源顶点s之外,第1-4行置每个顶点为白色,置每个顶点u的d[u]为无穷大,

  //置每个顶点的父母为NIL。

 5  color[s] ← GRAY

  //第5行,将源顶点s置为灰色,这是因为在过程开始时,源顶点已被发现。
 6  d[s] ← 0       //第6行,将d[s]初始化为0。

 7  π[s] ← NIL     //第7行,将源顶点的父顶点置为NIL。

 8  Q ← Ø
 9  ENQUEUE(Q, s)

  //第8、9行,初始化队列Q,使其仅含源顶点s。

 

10  while Q ≠ Ø
11      do u ← DEQUEUE(Q)

  //第11行,确定队列头部Q头部的灰色顶点u,并将其从Q中去掉。
12         for each v ∈ Adj[u]        //for循环考察u的邻接表中的每个顶点v
13             do if color[v] = WHITE
14                   then color[v] ← GRAY     //置为灰色
15                        d[v] ← d[u] + 1     //距离被置为d[u]+1
16                        π[v] ← u            //u记为该顶点的父母
17                        ENQUEUE(Q, v)        //插入队列中
18 
        color[u] ← BLACK     
 //u 置为黑色

 

illustrates the progress of BFS on a sample graph.
[转载]算法王帖:精选经典的24个算法 <wbr>[3.BFS和DFS优先搜索]
 
[转载]算法王帖:精选经典的24个算法 <wbr>[3.BFS和DFS优先搜索]
广度优先遍历演示地址:
 
  
深度优先探索算法 DFS 
Vertex u is WHITE before time d[u], GRAY between time d[u] and time f [u], and BLACK thereafter.
The following pseudocode is the basic depth-first-search algorithm. The input graph G may be undirected or directed. The variable time is a global variable that we use for timestamping.
 
DFS(G)
1  for each vertex u ∈ V [G]
2       do color[u] ← WHITE
3          π[u] ← NIL
4  time ← 0
5  for each vertex u ∈ V [G]
6       do if color[u] = WHITE
7             then DFS-VISIT(u)
 
DFS-VISIT(u)
1  color[u] ← GRAY     ▹White vertex u has just been discovered.
2  time ← time +1
3  d[u] time
4  for each v ∈ Adj[u]  ▹Explore edge(u, v).
5       do if color[v] = WHITE
6             then π[v] ← u
7                         DFS-VISIT(v)
8  color[u] BLACK      ▹ Blacken u; it is finished.
9  f [u] ▹ time ← time +1
 
 
 
 illustrates the progress of DFS on the graph shown in
[转载]算法王帖:精选经典的24个算法 <wbr>[3.BFS和DFS优先搜索]
//先后顺序 -> 横向
 
 
深度优先搜索的性质
括号定理(时间先后顺序) 
 
[转载]算法王帖:精选经典的24个算法 <wbr>[3.BFS和DFS优先搜索]

 

 

 

[转载]算法王帖:精选经典的24个算法 <wbr>[3.BFS和DFS优先搜索]

[转载]算法王帖:精选经典的24个算法 <wbr>[3.BFS和DFS优先搜索]

图的深度优先遍历演示系统:

http://sjjg.js.zwu.edu.cn/SFXX/sf1/sdyxbl.html

 

 

 

咱们来看深度优先搜索的递归实现与非递归实现,

最后,再给出俩算法实现的具体代码。 

1图的深度优先搜索算法的回顾:

图的深度优先搜索用递归实相当的简洁好懂:

void dftR(PGraphMatrix inGraph)

{

       PVexType v; 

       assertF(inGraph!=NULL,"in dftR, pass in inGraph is nulln");

       printf("n===start of dft recursive version===n");

       for(v=firstVertex(inGraph);v!=NULL;v=nextVertex(inGraph,v))

              if(v->marked==0)

                     dfsR(inGraph,v);

       printf("n===end of   dft recursive version===n");

}

 

void dfsR(PGraphMatrix inGraph,PVexType inV)

{

       PVexType v1;

       assertF(inGraph!=NULL,"in dfsR,inGraph is nulln");

       assertF(inV!=NULL,"in dfsR,inV is nulln");

       inV->marked=1;

       visit(inV);

       for(v1=firstAdjacent(inGraph,inV);v1!=NULL;v1=nextAdjacent(inGraph,inV,v1))

       //v1当为v的邻接点。

              if(v1->marked==0)

                     dfsR(inGraph,v1);

}

 

 

 

2 DFS 非递归版本

2.1.1非递归版本1---借助结点类型为队列的栈实现

       首先,将从某个顶点开始进行的深度优先搜索树画出,可以看到,
对从某个结点开始的深度优先遍历,实际上就是基于这个深度优先搜索树一个遍历,
不过,树中的的很多结点当marked值为1时将不必再访问.

       举例如下:
根据深度优先搜索规则,图1对应的两棵深度优先搜索树如右所示.
       其中,用土黄色”\”标注的树枝表示在第一次试探的过程中便不需要访问的边,
而用蓝色”\”标注的树枝则表示在回访过程中不再需要访问的结点.

      
       联系树的前序遍历的非递归实现:
       可知,其中无非是分成“探左”和“访右”两大块访右需借助栈中弹出的结点进行.
       在图的深度优先搜索中,同样可分成“深度探索”和“回访上层未访结点”两块:

       1图的深度探索这样一个过程和树的“探左”完全一致,只要对已访问过的结点作一个判定即可
       2而图的回访上层未访结点树的前序遍历中的“访右”也是一致的.
但是,对于树而言,是提供rightSibling这样的操作的,因而访右相当好实现。
在这里,若要实现相应的功能,我考虑是将每一个当前结点的下层结点中,如果有m个未访问结点,
则最左的一个需要访问,而将剩余的m-1个结点按从左到右的顺序推入一个队列中。
并将这个队列压入一个堆栈中。

       这样,当当前的结点的邻接点均已访问或无邻接点需要回访时,
则从栈顶的队列结点中弹出队列元素,将队列中的结点元素依次出队,
若已访问,则继续出队(当当前队列结点已空时,则继续出栈,弹出下一个栈顶的队列),
直至遇到有未访问结点(访问并置当前点为该点)或直到栈为空(则当前的深度优先搜索树停止搜索)

 

将算法通过精简过的C源程序的方式描述如下:

//dfsUR:功能从一个树的某个结点inV发,以深度优先的原则访问所有与它相邻的结点

void dfsUR(PGraphMatrix inGraph,PVexType inV)
{
 PSingleRearSeqQueue tmpQ;  //定义临时队列,用以接受栈顶队列及压栈时使用
 PSeqStack testStack;       //存放当前层中的m-1个未访问结点构成队列的堆栈.
 //一些变量声明,初始化动作
 //访问当前结点
 inV->marked=1;
 visit(inV);


 do
 {
  flag2=0;
  //flag2是一个重要的标志变量,用以、说明当前结点的所有未访问结点的个数,两个以上的用2代表*/
  //flag2:0:current node has no adjacent which has not been visited.
  //1:current node has only one adjacent node which has not been visited.
  //2:current node has more than one adjacent node which have not been visited.
  
  v1=firstAdjacent(inGraph,inV);    //邻接点v1
  while(v1!=NULL) //访问当前结点的所有邻接点 
  {
   if(v1->marked==0)//find one adjacent node which has not been visited.
   {    
    if(flag2==0)//visit the first unvisited adjacent node 
    {
     //访问最左结点
     visit(v1);
     v1->marked=1;
     flag2=1;
     //记录最左儿子
     lChildV=v1;   
     //save the current node's first unvisited(has been visited at this time)adjacent node
    }      
    else if(flag2==1)//current node has second  unvisited node 
    {
     //新建一个队列,申请空间,并加入第一个结点      
     flag2=2;
    }
    else if(flag2==2)//current node has more  unvisited node
    {
     enQueue(tmpQ,v1);
    }
   }
   v1=nextAdjacent(inGraph,inV,v1);
  }


  if(flag2==2)//push adjacent  nodes which are not visited.
  {            
   //将存有当前结点的m-1个未访问邻接点的队列压栈
   seqPush(testStack,tmpQ);
   inV=lChildV;
  }
  else if(flag2==1)//only has one adjacent which has been visited. 
  {           
   //只有一个最左儿子,则置当前点为最左儿子
   inV=lChildV;
  }
  else if(flag2==0)
   //has no adjacent nodes or all adjacent nodes has been visited
  {    
  //当当前的结点的邻接点均已访问或无邻接点需要回访时,则从栈顶的队列结点中弹出队列元素,
  //将队列中的结点元素依次出队,若已访问,则继续出队(当当前队列结点已空时,
  //则继续出栈,弹出下一个栈顶的队列),直至遇到有未访问结点(访问并置当前点为该点)或直到栈为空
   flag=0;
   while(!isNullSeqStack(testStack)&&!flag)
   {    
    v1=frontQueueInSt(testStack);
    deQueueInSt(testStack);
    if(v1->marked==0)
    {      
     visit(v1);
     v1->marked=1;
     inV=v1;
     flag=1;                                 
    }
   }
  }                                
 }while(!isNullSeqStack(testStack));//the algorithm ends when the stack is null
 
}

 

所以,这里应使用的数据结构的构成方式应该采用下面这种形式:
1)队列的实现中,每个队列结点均为图中的结点指针类型.
定义一个以队列尾部下标加队列长度的环形队列如下:

struct SingleRearSeqQueue;
typedef PVexType   QElemType;
typedef struct SingleRearSeqQueue* PSingleRearSeqQueue;
struct SingleRearSeqQueue
{
 int rear;
 int quelen;
 QElemType dataPool[MAXNUM];
};
其余基本操作不再赘述.     


2)堆栈的实现中,每个堆栈中的结点元素均为一个指向队列的指针,定义如下:
#define SEQ_STACK_LEN 1000
#define StackElemType PSingleRearSeqQueue
struct SeqStack;
typedef struct SeqStack* PSeqStack;
struct SeqStack
{
 StackElemType dataArea[SEQ_STACK_LEN];
 int slot;
};
为了提供更好的封装性,对这个堆栈实现两种特殊的操作

2.1) deQueueInSt操作用于将栈顶结点的队列中的队首元素弹出.
void deQueueInSt(PSeqStack inStack)
{
 if(isEmptyQueue(seqTop(inStack))||isNullSeqStack(inStack))
 {
  printf("in deQueueInSt,under flow!n");
  return;    
 }    
 deQueue(seqTop(inStack));
 if(isEmptyQueue(seqTop(inStack)))
  inStack->slot--;
}

2.2) frontQueueInSt操作用以返回栈顶结点的队列中的队首元素.
QElemType frontQueueInSt(PSeqStack inStack)
{
 if(isEmptyQueue(seqTop(inStack))||isNullSeqStack(inStack))
 {
  printf("in frontQueueInSt,under flow!n");
  return      'r'; 
 }    
 
 return getHeadData(seqTop(inStack));
}

 

3)DFS 非递归主要算法的实现:
//外层的周游层和递归版一致
void dftUR(PGraphMatrix inGraph)
{
 PVexType v;
 
 assertF(inGraph!=NULL,"in dftR, pass in inGraph is nulln");
 
 printf("n===start of dft recursive version===n");
 for(v=firstVertex(inGraph);v!=NULL;v=nextVertex(inGraph,v))
  if(v->marked==0)
   dfsUR(inGraph,v);
  printf("n===end of   dft recursive version===n");
}


void dfsUR(PGraphMatrix inGraph,PVexType inV)
{
 PSingleRearSeqQueue tmpQ;
 PSeqStack             testStack;
 PVexType v1,lChildV;
 int flag,flag2;
 int i;
 
 assertF(inGraph!=NULL,"in dfsR,inGraph is nulln");
 assertF(inV!=NULL,"in dfsR,inV is nulln");
 
 testStack=(PSeqStack)malloc(sizeof(struct SeqStack));
 assertF(testStack!=NULL,"in main,testStack is nulln");
 
 testStack=createNullSeqStack();
 for(i=0;i<inGraph->n;i++)
  testStack->dataArea[i]=(PSingleRearSeqQueue)malloc(sizeof(struct SingleRearSeqQueue));
 
 inV->marked=1;
 visit(inV);
 
 do
 {
  flag2=0;
  //
  //flag2:
  //0:current node has no adjacent which has not been visited.
  //1:current node has only one adjacent node which has not been visited.
  //2:current node has more than one adjacent node which have not been visited.
  
  v1=firstAdjacent(inGraph,inV);
  while(v1!=NULL)
  {
   if(v1->marked==0)//find one  adjacent node which has not been visited.
   {   
    if(flag2==0)//visit the first unvisited adjacent node
    {
     visit(v1);
     v1->marked=1;
     flag2=1;
     lChildV=v1;   
     //save the current node's first unvisited(has been visited at this time)adjacent node
    }    
    else if(flag2==1)//current node has second  unvisited node
    {
     tmpQ=(PSingleRearSeqQueue)malloc(sizeof(struct SingleRearSeqQueue)); 
     assertF(tmpQ!=NULL,"tmpQ is nulln");
     tmpQ=createNullSingleRearSeqQueue();
     
     
     for(i=0;i<inGraph->n;i++)
      tmpQ->dataPool[i]=(PVexType)malloc(sizeof(VexType)); 
     
     enQueue(tmpQ,v1);
     flag2=2;
    }
    else if(flag2==2)//current node has more  unvisited node
    {
     enQueue(tmpQ,v1);
    }
   }
   v1=nextAdjacent(inGraph,inV,v1);
  }
  
  if(flag2==2)//push adjacent  nodes which are not visited.
  {
   seqPush(testStack,tmpQ);
   inV=lChildV;
  }
  else if(flag2==1)//only has one adjacent which has been visited.
  {
   inV=lChildV;
  }
  else if(flag2==0)//has no adjacent nodes or all adjacent nodes has been visited
  {
   flag=0;
   while(!isNullSeqStack(testStack)&&!flag)
   {    
    v1=frontQueueInSt(testStack);
    deQueueInSt(testStack);
    if(v1->marked==0)
    {
     visit(v1);
     v1->marked=1;
     inV=v1;
     flag=1;                               
    }
   }
  }                                
 }while(!isNullSeqStack(testStack));//the algorithm ends when the stack is null
}

--------------------

//、完。 July、2010/10/29。

//以下内容不纳入本文范围。仅供 参考。

 

 

 

深度优先搜索与广度优先搜索的具体实现源码: 

-------------------------------

  1. //算法功能:  
  2. //DFS 
  3. #include <stdio.h>  
  4. #include <stdlib.h>  
  5.  
  6. #define OK 1  
  7. #define NULL 0  
  8. #define MAX_VERTEX_NUM 20 // 最大顶点数  
  9. typedef int Status;  //函数的类型,其值是函数结果状态代码  
  10.  
  11.  
  12.  
  13. typedef char VertexType;  
  14. typedef int VRType;  
  15. typedef int InfoType;  
  16.  
  17. typedef struct ArcNode  
  18. {  
  19.         int adjvex;   //该边所指的顶点的位置  
  20.         struct ArcNode *nextarc;   //指向下一条边的指针  
  21.         InfoType *info;    
  22. }ArcNode;   //表的结点  
  23.  
  24.  
  25. typedef struct VNode  
  26. {  
  27.         VertexType data;   //顶点信息(如数据等)  
  28.         ArcNode *firstarc;   //指向第一条依附该顶点的边的弧指针  
  29. }VNode, AdjList[MAX_VERTEX_NUM];   //头结点  
  30.  
  31. typedef struct ALGraph  
  32. {  
  33.         AdjList vertices;  
  34.         int vexnum, arcnum;   //图的当前顶点数和弧数  
  35.         int kind;  
  36. }ALGraph;  
  37.  
  38. //返回顶点v在顶点向量中的位置  
  39. int LocateVex(ALGraph G, char v)  
  40. {  
  41.         int i;  
  42.         for(i = 0; v != G.vertices[i].data && i < G.vexnum; i++)  
  43.                 ;  
  44.         if(i >= G.vexnum)  
  45.                 return -1;  
  46.         return i;  
  47. }  
  48.  
  49.  
  50. //构造邻接链表  
  51. Status CreateDN(ALGraph &G)  
  52. {  
  53.         int i, j;  
  54.         ArcNode *s;  
  55.         printf("输入有向图顶点数: ");  
  56.         scanf("%d", &G.vexnum);  
  57.         printf("输入有向图边数: ");  
  58.         scanf("%d", &G.arcnum);  
  59.         getchar();  
  60.  
  61.         for(int i = 0; i < G.vexnum; i++)  
  62.         {  
  63.                 printf("输入第%d个顶点信息:", i+1);  
  64.                 scanf("%c", &G.vertices[i]);   //构造顶点向量  
  65.                 G.vertices[i].firstarc = NULL;  
  66.                 getchar();  
  67.         }  
  68.  
  69.         char v1, v2;  
  70.           
  71.         for(int k = 0; k < G.arcnum; k++)  
  72.         {  
  73.                 printf("输入第 %d 条边依附的顶点v1: ", k+1);  
  74.                 scanf("%c", &v1);  
  75.                 getchar();  
  76.                 printf("输入第 %d 条边依附的顶点v2: ", k+1);  
  77.                 scanf("%c", &v2);  
  78.                 getchar();  
  79.  
  80.                 int i = LocateVex(G, v1);  
  81.                 int j = LocateVex(G, v2);    //确定v1 , v2在G中的位置  
  82.  
  83.                 s = (ArcNode*) malloc (sizeof(ArcNode));  
  84.  
  85.                 s->adjvex = j;   //该边所指向的顶点的位置为j  
  86.                 s->nextarc = G.vertices[i].firstarc;  
  87.                 G.vertices[i].firstarc =s;  
  88.         }  
  89.         return OK;  
  90. }  
  91.  
  92.  
  93. Status PrintAdjList(ALGraph &G)  
  94. {  
  95.         int i;  
  96.         ArcNode *p;  
  97.         printf("%4s%6ssn""编号""顶点""相邻边编号");  
  98.  
  99.         for(int i = 0; i < G.vexnum; i++)  
  100.         {  
  101.                 printf("Ml", i, G.vertices[i].data);  
  102.                 for(p = G.vertices[i].firstarc; p; p = p->nextarc)  
  103.                         printf("M", p->adjvex);  
  104.                 printf("n");  
  105.         }  
  106.         return OK;  
  107.  
  108. }  
  109.  
  110. void DFS(ALGraph G, int v, int *visited)  
  111. {  
  112.         int w;  
  113.         ArcNode *s;  
  114.         visited[v] = 1;  
  115.         printf("%c ->", G.vertices[v].data);  
  116.         s = G.vertices[v].firstarc;  
  117.         while(s != NULL)  
  118.         {  
  119.                 w = s->adjvex;  
  120.                 if(visited[w] == 0)  
  121.                         DFS(G, w, visited);  
  122.                 s = s->nextarc;   //访问下一个邻接点。
  123.         }  
  124. }  
  125.  
  126. //对图G做深度优先遍历  
  127. Status DFSTraverse(ALGraph G)  
  128. {  
  129.         int v;  
  130.         int visited[MAX_VERTEX_NUM];  
  131.         for(v = 0; v < G.vexnum; ++v)  
  132.                 visited[v] = 0;   //初始化visited[v]  
  133.         for(v = 0; v < G.vexnum; ++v)  
  134.                 if(visited[v] == 0)  
  135.                         DFS(G, v, visited);   //对未访问的顶点调用上述函数DFS()  
  136.         printf("完成n");  
  137.         return OK;  
  138. }  
  139.  
  140. int main()  
  141. {  
  142.         printf("==========================n");  
  143.         ALGraph G;  
  144.         CreateDN(G);  
  145.         printf("有向图的邻接表为:n");  
  146.         PrintAdjList(G);  
  147.         printf("深度优先遍历该有向图:n");  
  148.         DFSTraverse(G);  //调用图的深度优先函数DFSTraverse()  
  149.         return 0;  
  150. }

 

 

 

 

----------------------------------------------------

  1. //算法功能:  
  2. //BFS。
  3. #include <stdio.h>  
  4. #include <stdlib.h>  
  5.  
  6. #define OK 1  
  7. #define NULL 0  
  8. #define MAX_VERTEX_NUM 20 // 最大顶点数  
  9. #define MAXQSIZE 100  
  10. typedef int Status;  //函数的类型,其值是函数结果状态代码  
  11.  
  12.  
  13.  
  14. typedef char VertexType;  
  15. typedef char QElemType;  
  16. typedef int InfoType;  
  17.  
  18. typedef struct ArcNode  
  19. {  
  20.         int adjvex;   //该边所指的顶点的位置  
  21.         struct ArcNode *nextarc;   //指向下一条边的指针  
  22.         InfoType *info;    
  23. }ArcNode;   //表的结点  
  24.  
  25.  
  26. typedef struct VNode  
  27. {  
  28.         VertexType data;   //顶点信息(如数据等)  
  29.         ArcNode *firstarc;   //指向第一条依附该顶点的边的弧指针  
  30. }VNode, AdjList[MAX_VERTEX_NUM];   //头结点  
  31.  
  32. typedef struct ALGraph  
  33. {  
  34.         AdjList vertices;  
  35.         int vexnum, arcnum;   //图的当前顶点数和弧数  
  36.         int kind;  
  37. }ALGraph;  
  38.  
  39. typedef struct SqQueue  
  40. {  
  41.         QElemType *base;  
  42.         int front;  
  43.         int rear;  
  44. }SqQueue;  
  45.  
  46. //返回顶点v在顶点向量中的位置  
  47. int LocateVex(ALGraph G, char v)  
  48. {  
  49.         int i;  
  50.         for(i = 0; v != G.vertices[i].data && i < G.vexnum; i++)  
  51.                 ;  
  52.         if(i >= G.vexnum)  
  53.                 return -1;  
  54.         return i;  
  55. }  
  56.  
  57.  
  58. //构造无向图邻接链表  
  59. Status CreateUDN(ALGraph &G)  
  60. {  
  61.         int i, j;  
  62.         ArcNode *s, *t;  
  63.         printf("输入有向图顶点数: ");  
  64.         scanf("%d", &G.vexnum);  
  65.         printf("输入有向图边数: ");  
  66.         scanf("%d", &G.arcnum);  
  67.         getchar();  
  68.  
  69.         for(int i = 0; i < G.vexnum; i++)  
  70.         {  
  71.                 printf("输入第%d个顶点信息:", i+1);  
  72.                 scanf("%c", &G.vertices[i]);   //构造顶点向量  
  73.                 G.vertices[i].firstarc = NULL;  
  74.                 getchar();  
  75.         }  
  76.  
  77.         char v1, v2;  
  78.           
  79.         for(int k = 0; k < G.arcnum; k++)  
  80.         {  
  81.                 printf("输入第 %d 条边依附的顶点v1: ", k+1);  
  82.                 scanf("%c", &v1);  
  83.                 getchar();  
  84.                 printf("输入第 %d 条边依附的顶点v2: ", k+1);  
  85.                 scanf("%c", &v2);  
  86.                 getchar();  
  87.  
  88.                 int i = LocateVex(G, v1);  
  89.                 int j = LocateVex(G, v2);    //确定v1 , v2在G中的位置  
  90.  
  91.                 s = (ArcNode*) malloc (sizeof(ArcNode));  
  92.                 t = (ArcNode*) malloc (sizeof(ArcNode));  
  93.  
  94.                 s->adjvex = j;   //该边所指向的顶点的位置为j  
  95.                 s->nextarc = G.vertices[i].firstarc;  
  96.                 G.vertices[i].firstarc =s;  
  97.  
  98.                 t->adjvex = i;   //该边所指向的顶点的位置为j  
  99.                 t->nextarc = G.vertices[j].firstarc;  
  100.                 G.vertices[j].firstarc =t;  
  101.         }  
  102.         return OK;  
  103. }  
  104.  
  105. Status InitQueue(SqQueue &Q)  
  106. {  
  107.         Q.base = (QElemType *) malloc (MAXQSIZE * sizeof(QElemType));  
  108.         if(!Q.base)  
  109.         {  
  110.                 printf("分配地址失败!");  
  111.                 return 0;  
  112.         }  
  113.         Q.front = Q.rear = 0;  
  114.         return OK;  
  115. }  
  116.  
  117. //已访问图顶点入队  
  118. Status EnQueue(SqQueue &Q, QElemType e)  
  119. {  
  120.         if((Q.rear+1) % MAXQSIZE == Q.front)   //队列已满  
  121.         {  
  122.                 printf("队列已满!");  
  123.                 return 0;  
  124.         }  
  125.         Q.base[Q.rear] = e;  
  126.         Q.rear = (Q.rear+1) % MAXQSIZE;  
  127.         return OK;  
  128. }  
  129.  
  130. //判断队列是否为空  
  131. Status QueueEmpty(SqQueue Q)  
  132. {  
  133.         if(Q.front == Q.rear)  
  134.                 return OK;  
  135.         else 
  136.                 return 0;  
  137. }  
  138.  
  139. //辅助队列队头顶点出队  
  140. char DeQueue(SqQueue &Q)  
  141. {  
  142.         QElemType e;  
  143.         if(Q.front == Q.rear)  //队列为空  
  144.         {  
  145.                 printf("队列为空!");  
  146.                 return 0;  
  147.         }  
  148.         e = Q.base[Q.front];  
  149.         Q.front = (Q.front+1) % MAXQSIZE;  
  150.         return e;  
  151. }  
  152.  
  153.  
  154. Status PrintAdjList(ALGraph &G)  
  155. {  
  156.         int i;  
  157.         ArcNode *p;  
  158.         printf("%4s%6ssn""编号""顶点""相邻边编号");  
  159.  
  160.         for(int i = 0; i < G.vexnum; i++)  
  161.         {  
  162.                 printf("Ml", i, G.vertices[i].data);  
  163.                 for(p = G.vertices[i].firstarc; p; p = p->nextarc)  
  164.                         printf("M", p->adjvex);  
  165.                 printf("n");  
  166.         }  
  167.         return OK;  
  168.  
  169. }  
  170.  
  171. void DFS(ALGraph G, int v, int *visited)  
  172. {  
  173.         int w;  
  174.         ArcNode *s;  
  175.         visited[v] = 1;  
  176.         printf("%c ->", G.vertices[v].data);  
  177.         s = G.vertices[v].firstarc;  
  178.         while(s != NULL)  
  179.         {  
  180.                 w = s->adjvex;  
  181.                 if(visited[w] == 0)  
  182.                         DFS(G, w, visited);  
  183.                 s = s->nextarc;  
  184.         }  
  185. }  
  186.  
  187. //对图G做广度优先遍历  
  188. Status BFSTraverse(ALGraph G)  
  189. {  
  190.         int v, u, w;  
  191.         int visited[MAX_VERTEX_NUM];  
  192.         ArcNode *s;  
  193.         char e;  
  194.         SqQueue Q;    //辅助队列  
  195.         for(v = 0; v < G.vexnum; ++v)  
  196.                 visited[v] = 0;   //初始化visited[v]  
  197.         InitQueue(Q);  
  198.         for(v = 0; v < G.vexnum; ++v)  
  199.                 if(visited[v] == 0)   //尚未访问的顶点  
  200.                 {  
  201.                         visited[v] = 1;  
  202.                         printf("%c ->", G.vertices[v].data);  
  203.                         EnQueue(Q, G.vertices[v].data);   //已访问顶点入队  
  204.                         while(!QueueEmpty(Q))   //辅助队列非空  
  205.                         {  
  206.                                 e = DeQueue(Q);   //返回辅助队列中的头结点  
  207.                                 u = LocateVex(G, e);  
  208.                                 s = (ArcNode *) malloc (sizeof(ArcNode));  
  209.                                 s = G.vertices[u].firstarc;  
  210.                                 while(s != NULL)   //*顶点e还有邻接顶点  
  211.                                 {  
  212.                                         w = s->adjvex;  
  213.                                         if(visited[w] == 0)  
  214.                                         {  
  215.                                                 visited[w] = 1;  
  216.                                                 printf("%c ->", G.vertices[w].data);  
  217.                                                 EnQueue(Q, G.vertices[w].data);  
  218.                                         }  
  219.                                         s = s->nextarc;  
  220.                                 }  
  221.                         }  
  222.                 }  
  223.  
  224.         printf("完成n");  
  225.         return OK;  
  226. }  
  227.  
  228. int main()  
  229. {  
  230.         printf("==========================n");  
  231.         printf("=n");  
  232.  
  233.         ALGraph G;  
  234.         CreateUDN(G);  
  235.         printf("无向图的邻接表为:n");  
  236.         PrintAdjList(G);  
  237.         printf("广度优先遍历该无向图:n");  
  238.         BFSTraverse(G);  //调用图的深度优先函数DFSTraverse()  
  239.         return 0;  
  240. }

 

 

搜索引擎算法的额外研究: 

在抓取网页的时候,网络蜘蛛一般有两种策略:广度优先和深度优先(如下图所示)。
  广度优先是指网络蜘蛛会先抓取起始网页中链接的所有网页,然后再选择其中的一个链接网页,继续抓取在此网页中链接的所有网页。这是最常用的方式,因为这个方法可以让网络蜘蛛并行处理,提高其抓取速度。
 
  深度优先是指网络蜘蛛会从起始页开始,一个链接一个链接跟踪下去,处理完这条线路之后再转入下一个起始页,继续跟踪链接。这个方法有个优点是网络蜘蛛在设计的时候比较容易。
[转载]算法王帖:精选经典的24个算法 <wbr>[3.BFS和DFS优先搜索]