【算法导论】拓扑排序

拓扑排序

一,邻接表(无前驱实现)

该方法的每一步总是输出当前无前趋(即入度为零)的顶点

其抽象算法可描述为:
    NonPreFirstTopSort(G){//优先输出无前趋的顶点
         while(G中有入度为0的顶点)

                       do{
               从G中选择一个入度为0的顶点v且输出之;(栈顶弹出)
               从G中删去v及其所有出边;(压栈)
                }
            if(输出的顶点数目<|V(G)|)
                 //若此条件不成立,则表示所有顶点均已输出,排序成功。
           Error("G中存在有向环,排序失败!");
     }
注意:
 无前趋的顶点优先的拓扑排序算法在具体存储结构下,为便于考察每个顶点的人度,可保存各顶点当前的人度。为避免每次选入度为0的顶点时扫描整个存储空间,可设一个栈或队列暂存所有入度为零的顶点:
 在开始排序前,扫描对应的存储空间,将人度为零的顶点均入栈(队)。以后每次选人度为零的顶点时,只需做出栈(队)操作即可。

二,邻接表(DFS深度优先)

    当从某顶点v出发的DFS搜索完成时,v的所有后继必定均已被访问过(想像它们均已被删除),此时的v相当于是无后继的顶点,因此在DFS算法返回之前输出顶点v即可得到 DAG的逆拓扑序列。
 其中第一个输出的顶点必是无后继(出度为0)的顶点,它应是拓扑序列的最后一个顶点。若希望得到的不是逆拓扑序列,同样可增加T来保存输出的顶点。若假设T是栈,并在DFSTraverse算法的开始处将T初始化,
 利用DFS求拓扑序列的抽象算法可描述为:
     void DFSTopSort(G,i,T)

     {
          //在DisTraverse中调用此算法,i是搜索的出发点,T是栈
          int j;
          visited[i]=TRUE; //访问i
          for(所有i的邻接点j)//即<i,j>∈E(G)
              if(!visited[j])
          DFSTopSort(G,j,T);
         //以上语句完全类似于DFS算法
          Push(&T,i); //从i出发的搜索已完成,输出i
      }
   只要将深度优先遍历算法DFSTraverse中对DFS的调用改为对DFSTopSort的调用,即可求得拓扑序列T。其具体算法不难从上述抽象算法求精后得到。
  若G是一个DAG,则用DFS遍历实现的拓扑排序与NonSuccFirstTopSort算法完全类似;但若C中存在有向环,则前者不能正常工作。

综合源码

  1. #include "stdio.h" 
  2. #include "malloc.h" 
  3. #include "stack.h" 
  4. #define MaxSize 10 
  5. #define Max     100 
  6. stack<int> mystack;//调用系统的栈  
  7. int indegree[Max]; 
  8. /*邻接表  :Adjacency list*/ 
  9. typedef struct ArcNode //边 表节点  
  10.     int  adjvex;//邻接点 数值  
  11.     ArcNode *next;//下一个节点  
  12. }ArcNode ; 
  13. typedef struct  VertexNode //顶点 表节点  
  14.     char  vertex; //顶点表示(A,B,C) 
  15.     ArcNode  *firstedge;//第一个邻接点  
  16. }VertexNode,AdjList[MaxSize]; //为什么要写在这个地方 ???? 
  17.  
  18. //vertexNode  AdjList[MaxSize]; //这样为什么不对??  
  19.   
  20. typedef struct  
  21.  
  22.     AdjList adjlist ;//顶点表   就是竖着的一排  不能是指针么???????????? !!!!!!!!!!! 
  23.     int VertexNumber,arcNum;//图的顶点个数,边个数  
  24. }AlGraph; 
  25.  
  26. void CreatALGraph(AlGraph *G,char a[],int n,int e) //顶点 由数组提供, 边需要用户输入  
  27.      int i,k,j;  
  28.      G->VertexNumber=n;// 顶点个数  
  29.      G->arcNum=e;//边个数     
  30.      for(i=0;i<G->VertexNumber;i++)//初始化 顶点列表  
  31.      {      
  32.          G->adjlist[i].vertex=a[i]; 
  33.          G->adjlist[i].firstedge=NULL;  
  34.      }  
  35.       
  36.      for(k=0;k<G->arcNum;++k)//每次输入 一条边 <i,j> 将该顶点插入 i 顶点后的列链表中  
  37.      { 
  38.          printf("please  input the number of edge's two vertex\n");  
  39.          scanf("%d%d",&i,&j);//有向图 f 
  40.          ArcNode *s=(ArcNode *)malloc(sizeof(ArcNode)); 
  41.          
  42.          s->adjvex=j; //所邻接的 顶点在顶点列表中的下标 
  43.           
  44.          //接下来 将创建好的边 表节点插入 节点i 的边表的表头  
  45.          s->next=G->adjlist[i].firstedge; 
  46.          G->adjlist[i].firstedge=s;         
  47.      } 
  48. void print_Graph(AlGraph *G) //简单的打印出来  
  49.     int i; 
  50.     for(i=0;i<G->VertexNumber;++i) //输出每一行  
  51.     { 
  52.         ArcNode *node= G->adjlist[i].firstedge;  
  53.         printf("%c",G->adjlist[i].vertex);//输出链表节点  
  54.      
  55.         while(node)//输出后续节点  
  56.         { 
  57.             //printf("--->%d", node->adjvex); 
  58.             printf("--->%c", G->adjlist[node->adjvex].vertex); 
  59.             nodenode=node->next; 
  60.         } 
  61.         printf("\n"); 
  62.     }       
  63.  
  64. void topsort(AlGraph *G,int n)//通过记录入度 进行拓扑排序 
  65.     int i; 
  66.          
  67.     memset(indegree,0,sizeof(indegree));//初始化数组  
  68.     /*void *memset(void *s, int c, size_t n);   
  69.      memset:作用是在一段内存块中填充某个给定的值, 
  70.     是对较大的结构体或数组进行清零操作的一种最快方法.*/  
  71.      
  72.     for(i=0;i<n;++i) //初始化整个图 的入度  
  73.     { 
  74.       ArcNode *node= G->adjlist[i].firstedge; 
  75.        
  76.       while(node)  
  77.       { 
  78.          indegree[node->adjvex]++;//让节点 入度加1 
  79.          nodenode=node->next;  
  80.       } 
  81.          
  82.     }  
  83.     //  printf("%d\n",indegree[1]);  
  84.     for(i=0;i<n;++i)//将入度为0 的元素入栈  
  85.     { 
  86.         if(indegree[i]==0) 
  87.            { 
  88.              mystack.push(i); 
  89.            } 
  90.     }            
  91.     int  count=0
  92.      ArcNode *p;  
  93.     while(mystack.size()!=0)//当栈内 元素不为空 
  94.     { 
  95.         i=mystack.top();    //记录栈顶  
  96.         mystack.pop();      //弹出栈顶元素  
  97.         printf("%c",G->adjlist[i]); 
  98.         count++; 
  99.          
  100.         p= G->adjlist[i].firstedge; 
  101.        
  102.         while(p)  
  103.         { 
  104.              //int k=p->adjvex;//记录下标 方便判断  
  105.              indegree[p->adjvex]--;//让节点 入度减1 
  106.              if(indegree[p->adjvex]==0) 
  107.                   mystack.push(p->adjvex); 
  108.              pp=p->next;  
  109.         } 
  110.        
  111.        
  112.     } 
  113.     if(count<n
  114.         printf("有回路\n");  
  115.           
  116. }  
  117. void DFS_top_sort(AlGraph *G,int v,int visited[]) 
  118.      //int  visited[v];//用来区别 顶点有没有被访问过 
  119.      int j; 
  120.      //printf("%c",G->adjlist[v].vertex);//输出顶点 (递归调用 条件下文给出) 
  121.      visited[v]=1; 
  122.      ArcNode *p=G->adjlist[v].firstedge; 
  123.       
  124.      while(p!=NULL) 
  125.      { 
  126.         j=p->adjvex;//后继 的节点的下标 
  127.         if(visited[j]!=1)//后继顶点没有被访问,则递归访问  
  128.            DFS_top_sort(G,j,visited); 
  129.          
  130.          pp=p->next;  
  131.      }    
  132.      mystack.push(v); //将某个节点后继访问完后 压栈   
  133. }  
  134. void  DFS_one(AlGraph *G) 
  135.     int  visited[G->VertexNumber];//用来区别 顶点有没有被访问过 
  136.     int i; 
  137.     for(i=0;i<G->VertexNumber;++i) 
  138.         visited[i]=0; //标志向量初始化 
  139.     for(i=0;i<G->VertexNumber;++i) 
  140.        if(visited[i]==0) //i未访问过  
  141.           DFS_top_sort(G,i,visited);//以i为源点开始DFS搜索  
  142.  
  143.  
  144. void DFS_top_sort_print(AlGraph *G,stack<int> mystack)//深度优先遍历 打印  
  145.     while(mystack.size()) 
  146.     { 
  147.         printf("%c",G->adjlist[mystack.top()]); 
  148.         mystack.pop();//弹出不需要参数  
  149.     } 
  150.      
  151. }  
  152. void NULL_stack(stack<int> mystack)//清空栈  
  153.     while(mystack.size()) 
  154.     { 
  155.          
  156.         mystack.pop();//弹出不需要参数  
  157.     } 
  158.      
  159. int main() 
  160.     AlGraph *G=(AlGraph *)malloc(sizeof(AlGraph)); 
  161.     char a[3]={'A','B','C'}; 
  162.     int n=3
  163.     int e=2;   
  164.     printf("********************\n"); 
  165.     printf("1,创建邻接表类型的图\n"); 
  166.     printf("2,邻接表真实输出\n");  
  167.     printf("3,入度法拓扑排序\n"); 
  168.     printf("4,深度优先遍历法拓扑排序\n"); 
  169.     //printf("4,邻接表广度优先访问\n"); 
  170.     printf("********************\n"); 
  171.       
  172.     int i; 
  173.      
  174.     while(1) 
  175.     { 
  176.         scanf("%d",&i);     
  177.         switch(i) 
  178.         { 
  179.             case 1:CreatALGraph(G,a,n,e); 
  180.                    printf("创建完毕请继续……\n");break; 
  181.             case 2:print_Graph(G);break; 
  182.             case 3:NULL_stack(mystack); 
  183.                    topsort(G,3);  
  184.                    printf("\n");break; 
  185.             case 4:NULL_stack(mystack); 
  186.                    DFS_one(G);//深度优先遍历  
  187.                    DFS_top_sort_print(G,mystack); 
  188.                    printf("\n");break; 
  189.             case 5:break; 
  190.             case 6:break; 
  191.             case 7:break; 
  192.             case 8:break; 
  193.             case 9:break;        
  194.          
  195.         } 
  196.          
  197.     } 
  198.      
  199.     return 0; 
  200. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值