顶点深度优先次序

来源:互联网 发布:网络赌钱平台破解方法 编辑:程序博客网 时间:2024/05/21 23:50

在调用dfs的过程中,几种添加顶点到集合的顺序。一共有四种顺序:

  • Pre-Order,在递归调用dfs之前将当前顶点添加到queue
  • Reverse Pre-Order,在递归调用dfs之前将当前顶点添加到stack
  • Post-Order,在递归调用dfs之后将当前顶点添加到queue
  • Reverse Post-Order,在递归调用dfs之后将当前顶点添加到stack

最后一种的用途最广,至少目前看来是这样,比如步骤2-a以及拓扑排序中,都是利用的Reverse Post-Order来获取顶点集合。

Kosaraju的主要步骤:

  1. G求解Reverse Post-Order,即上文中的”伪拓扑排序“
  2. G进行转置得到GR
  3. 按照第一步得到的集合中顶点出现的顺序,对GR调用DFS得到若干颗搜索树
  4. 每一颗搜索树就代表了一个强连通分量

#include <stdlib.h>#include <iostream>#include <stack>#include <queue>using namespace std;struct node                       /* 图顶点结构定义     */{   int vertex;                    /* 顶点数据信息       */   node *nextnode;         /* 指下一顶点的指标   */};const int vertexnum = 4;/*顶点的数目*/const int instance = 4;typedef struct node *graph;       /* 图形的结构新型态   */node head[vertexnum+1];              /* 图形顶点数组       */node reversehead[vertexnum+1];              /* 图形顶点数组       */int visited[vertexnum+1];                   /* 遍历标记数组       */int id[vertexnum+1];                        /*标记连通分量的编号*///int edgeto[vertexnum+1];/*标记节点前继*///int onstack[vertexnum+1];/*标记栈中节点*/int count = 0;  /*连通分量编号*/int edgenum = 0;/*边的数目*/queue<int> pre;queue<int> post;stack<int> reversepost;/********************根据已有的信息建立邻接表********************/void creategraph(int node[instance][2],int num)/*num指的是图的边数*/{   graph newnode;                 /*指向新节点的指针定义*/   graph ptr;   int from;                      /* 边的起点          */   int to;                        /* 边的终点          */   int i;   for ( i = 0; i < num; i++ )    /* 读取边线信息,插入邻接表*/   {      from = node[i][0];         /*    边线的起点            */      to = node[i][1];           /*   边线的终点             */         /* 建立新顶点 */      newnode = ( graph ) malloc(sizeof(struct node));      newnode->vertex = to;        /* 建立顶点内容       */      newnode->nextnode = NULL;    /* 设定指标初值       */      ptr = &(head[from]);         /* 顶点位置           */      while ( ptr->nextnode != NULL ) /* 遍历至链表尾   */         ptr = ptr->nextnode;     /* 下一个顶点         */      ptr->nextnode = newnode;    /* 插入节点        */   }}void createreversegraph(int node[instance][2],int num)/*num指的是图的边数*/{   graph newnode;                 /*指向新节点的指针定义*/   graph ptr;   int from;                      /* 边的起点          */   int to;                        /* 边的终点          */   int i;   for ( i = 0; i < num; i++ )    /* 读取边线信息,插入邻接表*/   {      to = node[i][0];         /*    边线的起点            */      from = node[i][1];           /*   边线的终点             */         /* 建立新顶点 */      newnode = ( graph ) malloc(sizeof(struct node));      newnode->vertex = to;        /* 建立顶点内容       */      newnode->nextnode = NULL;    /* 设定指标初值       */      ptr = &(reversehead[from]);         /* 顶点位置           */      while ( ptr->nextnode != NULL ) /* 遍历至链表尾   */         ptr = ptr->nextnode;     /* 下一个顶点         */      ptr->nextnode = newnode;    /* 插入节点        */   }}void dfs(int current){visited[current] = 1;pre.push(current);cout<<current<<endl;node *p;p = head[current].nextnode;while(p != NULL){if(visited[p->vertex] == 0){visited[p->vertex] = 1;dfs(p->vertex);}p = p->nextnode;}post.push(current);reversepost.push(current);}void kosarajuSCCdfs(int current){visited[current] = 1;id[current] = count;node *p;p = reversehead[current].nextnode;cout<<current<<" ";while(p != NULL){if(visited[p->vertex] == 0){visited[p->vertex] = 1;kosarajuSCCdfs(p->vertex);}p = p->nextnode;}}void kosarajuSCC(){int current;for(int i=1;i <= vertexnum;i++){visited[i] = 0;}count = 0;while(!reversepost.empty()){current = reversepost.top();reversepost.pop();if(visited[current] == 0){kosarajuSCCdfs(current);cout<<endl;count++;}}}/****************************** 主程序******************************/int main(){   graph ptr; /*  int node[instance][2] = { {1, 2}, {2, 1},                         {1, 3}, {3, 1},                       {1, 4}, {4, 1},                       {2, 5}, {5, 2},                       {2, 6}, {6, 2},                       {3, 7}, {7, 3},                       {4, 7}, {4, 4},                       {5, 8}, {8, 5},                       {6, 7}, {7, 6},                       {7, 8}, {8, 7} }; */  int node[instance][2] = {   {1, 2}, {2, 3},{3,4},{4,2}                    };   int i;   edgenum = 4;   //clrscr();   for ( i = 1; i <= vertexnum; i++ )      /*   顶点数组初始化  */   {      head[i].vertex = i;         /*    设定顶点值      */      head[i].nextnode = NULL;    /*       指针为空     */      visited[i] = 0;             /* 设定遍历初始标志   */     //onstack[i] = 0;   }   creategraph(node,instance);          /*    建立邻接表      */   createreversegraph(node,instance);          /*    建立邻接表      */   cout<<"Content of the gragh's ADlist is:\n";   for ( i = 1; i <= vertexnum; i++ )   {      cout<<"vertex"<<head[i].vertex<<" ->";/* 顶点值    */      ptr = head[i].nextnode;             /* 顶点位置   */      while ( ptr != NULL )       /* 遍历至链表尾       */      {         cout<<" "<<ptr->vertex<<" ";  /* 印出顶点内容   */         ptr = ptr->nextnode;         /* 下一个顶点     */      }      cout<<endl;               /*   换行             */   }   cout<<"\nThe end of the dfs are:\n";   for(i=1;i<=vertexnum;i++){   if(visited[i] == 0){   dfs(i);                        /* 打印输出遍历过程   */   count++;   }   }   cout<<endl;     kosarajuSCC();}

对kosaraju的证明,这个版本比较清晰,来自http://blog.csdn.net/dm_vincent/article/details/8554244

证明的目标,就是最后一步 --- 每一颗搜索树代表的就是一个强连通分量

证明:设在图GR中,调用DFS(s)能够到达顶点v,那么顶点sv是强连通的。

两个顶点如果是强连通的,那么彼此之间都有一条路径可达,因为DFS(s)能够达到顶点v,因此从sv的路径必然存在。现在关键就是需要证明在GR中从vs也是存在一条路径的,也就是要证明在G中存在sv的一条路径。

而之所以DFS(s)能够在DFS(v)之前被调用,是因为在对G获取ReversePost-Order序列时,s出现在v之前,这也就意味着,v是在s之前加入该序列的(因为该序列使用栈作为数据结构,先加入的反而会在序列的后面)。因此根据DFS调用的递归性质,DFS(v)应该在DFS(s)之前返回,而有两种情形满足该条件:

  1. DFS(v) START -> DFS(v) END -> DFS(s) START -> DFS(s) END
  1. DFS(s) START -> DFS(v) START -> DFS(v) END -> DFS(s) END

是因为而根据目前的已知条件,GR中存在一条sv的路径,即意味着G中存在一条vs的路径,而在第一种情形下,调用DFS(v)却没能在它返回前递归调用DFS(s),这是和G中存在vs的路径相矛盾的,因此不可取。故情形二为唯一符合逻辑的调用过程。而根据DFS(s) START -> DFS(v) START可以推导出从sv存在一条路径。

所以从sv以及vs都有路径可达,证明完毕。

 

复杂度分析:

根据上面总结的Kosaraju算法关键步骤,不难得出,该算法需要对图进行两次DFS,以及一次图的转置。所以复杂度为O(V+E)


参考:

http://blog.csdn.net/dm_vincent/article/details/8554244

http://blog.csdn.net/michealtx/article/details/8233814

http://www.cnblogs.com/luweiseu/archive/2012/07/14/2591370.html

http://www.cnblogs.com/suoloveyou/archive/2012/05/06/2486589.html

http://edward-mj.com/?p=455