zoukankan      html  css  js  c++  java
  • 关于深度优先遍历图的非递归算法的一个讨论

    参考:

    http://www.cnblogs.com/kubixuesheng/p/4399705.html

    http://www.cnblogs.com/dolphin0520/archive/2011/07/13/2105236.html

    图的深度优先遍历递归算法大概如下:

     1 //访问标志数组
     2 int visited[MAX] = {0};
     3 
     4 //用邻接表方式实现深度优先搜索(递归方式)
     5 //v 传入的是第一个需要访问的顶点
     6 void DFS(MGraph G, int v)
     7 {
     8     //图的顶点的搜索指针
     9     ArcNode *p;
    10     //置已访问标记
    11     visited[v] = 1;
    12     //输出被访问顶点的编号
    13     printf("%d  ", v);
    14     //p指向顶点v的第一条弧的弧头结点
    15     p = G.vertices[v].firstarc;
    16     while (p != NULL)
    17     {
    18         //若p->adjvex顶点未访问,递归访问它
    19         if (visited[p->adjvex] == 0)
    20         {
    21             DFS(G, p->adjvex);
    22         }
    23         //p指向顶点v的下一条弧的弧头结点
    24         p = p->nextarc;
    25     }
    26 }
    View Code

    图的广度优先遍历算法大概如下:

     1 #include <iostream>
     2 #include<queue>
     3 using namespace std;
     4 
     5 const int MAX = 10;
     6 //辅助队列的初始化,置空的辅助队列Q,类似二叉树的层序遍历过程
     7 queue<int> q;
     8 //访问标记数组
     9 bool visited[MAX];
    10 //图的广度优先搜索算法
    11 void BFSTraverse(Graph G, void (*visit)(int v))
    12 {
    13     int v = 0;
    14     //初始化访问标记的数组
    15     for (v = 0; v < G.vexnum; v++)
    16     {
    17         visited[v] = false;
    18     }
    19     //依次遍历整个图的结点
    20     for (v = 0; v < G.vexnum; v++)
    21     {
    22         //如果v尚未访问,则访问 v
    23         if  (!visited[v])
    24         {
    25             //把 v 顶点对应的数组下标处的元素置为真,代表已经访问了
    26             visited[v] = true;
    27             //然后v入队列,利用了队列的先进先出的性质
    28             q.push(v);
    29             //访问 v,打印处理
    30             cout << q.back() << " ";
    31             //队不为空时
    32             while (!q.empty())
    33             {
    34                 //队头元素出队,并把这个出队的元素置为 u,类似层序遍历
    35                 Graph *u = q.front();
    36                 q.pop();
    37                 //w为u的邻接顶点
    38                 for (int w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G,u,w))
    39                 {
    40                     //w为u的尚未访问的邻接顶点
    41                     if (!visited[w])
    42                     {
    43                         visited[w] = true;
    44                         //然后 w 入队列,利用了队列的先进先出的性质
    45                         q.push(w);
    46                         //访问 w,打印处理
    47                         cout << q.back() << " ";
    48                     }//end of if
    49                 }//end of for
    50             }//end of while
    51         }//end of if
    52     }// end of for
    53 }
    View Code

    上面是用邻接表结构实现的代码。下面是用邻接矩阵实现的代码,包含递归深搜、非递归深搜、广搜,可以参考一下:

      1 #include<iostream>
      2 #include<queue>
      3 #include<stack>
      4 #include<stdlib.h>
      5 #define MAX 100
      6 using namespace std;
      7 
      8 typedef struct 
      9 {
     10     int edges[MAX][MAX];    //邻接矩阵
     11     int n;                  //顶点数
     12     int e;                  //边数
     13 }MGraph;
     14 
     15 bool visited[MAX];          //标记顶点是否被访问过
     16 
     17 void creatMGraph(MGraph &G)    //用引用作参数
     18 {
     19     int i,j;
     20     int s,t;                 //存储顶点编号
     21     int v;                   //存储边的权值
     22     for(i=0;i<G.n;i++)       //初始化
     23     {
     24         for(j=0;j<G.n;j++)
     25         {
     26             G.edges[i][j]=0;
     27         }
     28         visited[i]=false;
     29     }
     30     for(i=0;i<G.e;i++)      //对矩阵相邻的边赋权值
     31     {
     32         scanf("%d %d %d",&s,&t,&v);   
     33 //两个顶点确定一条边
     34 //输入边的顶点编号以及权值
     35         G.edges[s][t]=v;
     36     }
     37 }
     38 
     39 void DFS(MGraph G,int v)      //深度优先搜索
     40 {
     41     int i;
     42     printf("%d ",v);          //访问结点v
     43     visited[v]=true;
     44     for(i=0;i<G.n;i++)       //访问与v相邻的未被访问过的结点
     45     {
     46         if(G.edges[v][i]!=0&&visited[i]==false)
     47         {
     48             DFS(G,i);//若没访问则继续,而且根据顶点的序号按数序访问
     49         }
     50     }
     51 }
     52 //stack弹出顺序有问题
     53 void DFS1(MGraph G,int v)   //非递归实现
     54 {
     55     stack<int> s;
     56     printf("%d ",v);        //访问初始结点
     57     visited[v]=true;
     58     s.push(v);              //入栈
     59     while(!s.empty())
     60     {
     61         int i,j;
     62         i=s.top();          //取栈顶顶点
     63         for(j=0;j<G.n;j++)  //访问与顶点i相邻的顶点
     64         {
     65             if(G.edges[i][j]!=0&&visited[j]==false)
     66             {
     67                 printf("%d ",j);     //访问
     68                 visited[j]=true;
     69                 s.push(j);           //访问完后入栈
     70                 break;               //找到一个相邻未访问的顶点,访问之后则跳出循环
     71             }
     72         }
     73 //对于节点4,找完所有节点发现都已访问过或者没有临边,所以j此时=节点总数,然后把这个4给弹出来
     74 直到弹出1,之前的深度搜索的值都已弹出,有半部分还没有遍历,开始遍历有半部分
     75         if(j==G.n)                   //如果与i相邻的顶点都被访问过,则将顶点i出栈
     76             s.pop();
     77     }
     78 }
     79 
     80 void BFS(MGraph G,int v)      //广度优先搜索
     81 {
     82     queue<int> Q;             //STL模板中的queue
     83     printf("%d ",v);
     84     visited[v]=true;
     85     Q.push(v);
     86     while(!Q.empty()) 
     87     {
     88         int i,j;
     89         i=Q.front();         //取队首顶点
     90         Q.pop();//弹出一个,然后遍历这个节点的子节点,然后遍历完再弹出下一个
     91         for(j=0;j<G.n;j++)   //广度遍历
     92         {
     93             if(G.edges[i][j]!=0&&visited[j]==false)
     94             {
     95                 printf("%d ",j);
     96                 visited[j]=true;
     97                 Q.push(j);
     98             }
     99         }
    100     }
    101 }
    102 
    103 int main(void)
    104 {
    105     int n,e;    //建立的图的顶点数和边数
    106     while(scanf("%d %d",&n,&e)==2&&n>0)
    107     {
    108         MGraph G;
    109         G.n=n;
    110         G.e=e;
    111         creatMGraph(G);
    112         DFS(G,0);
    113         printf("
    ");
    114     //    DFS1(G,0);
    115     //    printf("
    ");
    116     //    BFS(G,0);
    117     //    printf("
    ");
    118     }
    119     return 0;
    120 }
    View Code

    在网络上查了很多资料,又去看了好几本教材,发现这些地方对图的深度优先遍历算法的讲解,基本都是用递归算法实现的。对非递归算法实现描述不是很多。上面第三段代码实现了非递归深搜算法。

    在寻找资料过程中,也在思考如何实现,大概设计了如下两种算法:

    算法一:(这个是一个错误的思路

    1 st.push(v1)//出发点入栈 
    2 while(!st.empty()) 
    3 {
    4     temp=st.top(); st.pop();//临时备份栈顶节点到temp,删除栈顶节点 
    5     printf(temp);//访问temp(原先的栈顶节点) 
    6     根据temp寻找所有未曾访问的相邻节点,并把这些节点入栈
    7 }

    算法二:

     1 printf(v1);//访问出发节点 
     2 st.push(v1);//出发点入栈 
     3 while(!st.empty()) 
     4 {
     5     temp=st.top();//读取栈顶节点到temp
     6     循环遍历temp的所有相邻节点: 
     7  8         如果(发现一个未曾访问的相邻节点w):
     9 10             printf(w);//访问节点w
    11             st.push(w);//把w入栈
    12             退出循环
    13 14 15     if(temp没有未曾访问的相邻节点) 
    16         st.pop();//删除栈顶节点
    17 }

    这两种算法,假如仅仅是对树进行深搜,应该是没有错的。但是对图进行深搜,算法一确实不正确的。看下面这个例子:

    对这个图从V0出发做深搜,假如按照算法一操作,假设节点入栈顺序为:V0,V1,V3,……

    其中v1和V3入栈时,V0已经出栈。但是取出栈顶V3做访问操作,然后再把V3的相邻未曾访问节点入栈,则会使得V1再一次 入栈。所以算法一不正确。

  • 相关阅读:
    WebStorm破解方法
    jQuery学习笔记2
    jquery.js 3.0报错, Uncaught TypeError: url.indexOf is not a function
    animate.css –齐全的CSS3动画库--- 学习笔记
    MySQL数据库---表的操作
    MySQL数据库---库的操作
    MySQL数据库---前言
    CppUnit使用和源码解析
    代码覆盖率检查
    代码Verify简介
  • 原文地址:https://www.cnblogs.com/huashanqingzhu/p/8639475.html
Copyright © 2011-2022 走看看