zoukankan      html  css  js  c++  java
  • 拓扑排序(有向无环图)

      拓扑排序含义:对一个有向无环图G进行拓扑排序,将G中所有顶点构成一个线性序列,对于图中任一顶点v1和v2,如果有弧<v1,v2>属于图G的,则在序列中v1要排在v2前.面,如果该有向无环图满足上述条件,这样的线性表序列就是拓扑排序序列

    1.创建结构体

    //定义表结点
    typedef struct ENode{
        int index;//连接顶点的下标
        struct ENode *next; 
    }ENode; 
    
    //表顶点
    typedef struct Node{
        int in;  //入度 
        char data;  //顶点数据
        struct ENode *firstNode;  //指向表结点的指针 
    }Node; 
    
    //邻接链表 
    typedef struct Graph{
        int vexNum;
        int arcNum;
        Node vexs[MAX]; 
    }Graph,*myGraph;

    2.创建有向无环图

    void createGraph(myGraph &G)
    {
        G=(Graph*)malloc(sizeof(Graph)); //动态申请空间
        
        int i,j,k;
        char v1,v2;    //边的两个顶点 
        printf("请输入顶点的数量:");
        scanf("%d",&G->vexNum);
        printf("请输入边的数量:");
        scanf("%d",&G->arcNum);
        
        printf("请依次将顶点数据输入进来
    ");
        for(i=0;i<G->vexNum;i++)   //初始化顶点 
        {
            getchar();
            scanf("%c",&G->vexs[i].data);
            G->vexs[i].firstNode=NULL;  //初始化为空 
            G->vexs[i].in=0;  //初始化入度为0 
        }
        
        printf("请依次将边输入进来
    ");
        for(i=0;i<G->arcNum;i++)
        {
            getchar();
            scanf("%c%c",&v1,&v2);
            
            j=getLocate(G,v1);  //获取下标
            k=getLocate(G,v2);  //获取下标
            
            ENode *currentNode=(ENode*)malloc(sizeof(ENode));
            currentNode->index=k;   //顶点下标 
            currentNode->next=NULL;
            G->vexs[k].in++;    //k的下标入度加1
        
            if(G->vexs[j].firstNode==NULL)//当该顶点没有邻接点时  
            {
                G->vexs[j].firstNode=currentNode; //指向这个结点 
            } 
            else  //当该顶点有邻接点时   直接在链的头部进行插入  不是在尾部插入 
            {
                
                ENode *node=G->vexs[j].firstNode; //储存第一个结点 
                G->vexs[j].firstNode=currentNode; //新节点变成第一个结点 
                currentNode->next=node;   //新的第一个结点指向旧的第一个结点 
            }
        }  
    }

    3.拓扑排序

    void  TopologicalSort(myGraph G)  //满足栈后进先出的个性 
    {
        int top=0;  //栈指针
        int count=0;  //打印次数
        ENode *node; //避免 G->vexs[i].firstNode发生改变
        int *stack; //栈数组
        int getTop; //获取栈顶顶点下标 
        int i,j;
        
        stack=(int*)malloc(G->vexNum*sizeof(int)); //动态生成一个数组
        if(!stack)
        {
            printf("动态生成失败
    ");
        }
        
        for(int i=0;i<G->vexNum;i++)  //先将度为0的先入栈 
        {
            if(G->vexs[i].in==0)
            {
                stack[++top]=i;  //储存入栈顶点的下标 ,从top=1开始 
            }
        } 
        
        while(top!=0)  //当top等于0时,没有出栈元素了 
        {
            int getTop=stack[top--];  //出栈操作 
            printf("%c ",G->vexs[getTop].data);  
            count++;  //用来判断有没有环 
            
            for(node=G->vexs[getTop].firstNode;node!=NULL;node=node->next) 
            {
                j=node->index;  //获取顶点的下标
                if(!(--G->vexs[j].in)) //如果入度为0则入栈 
                {
                    stack[++top]=j;
                }
            }
        }
        
        if(count<G->vexNum) 
        {
            printf("该图有环
    ");
        }
    }

    所有的代码如下:

    #include<stdio.h>
    #include<stdlib.h>
    
    #define MAX 20
    
    //定义表结点
    typedef struct ENode{
        int index;//连接顶点的下标
        struct ENode *next; 
    }ENode; 
    
    //表顶点
    typedef struct Node{
        int in;  //入度 
        char data;  //顶点数据
        struct ENode *firstNode;  //指向表结点的指针 
    }Node; 
    
    //邻接链表 
    typedef struct Graph{
        int vexNum;
        int arcNum;
        Node vexs[MAX]; 
    }Graph,*myGraph;
    
    //获取顶点的下标
    int getLocate(myGraph G,char v)
    {
        int i;
        for(i=0;i<G->vexNum;i++)
        {
            if(v==G->vexs[i].data)
            {
                return i;
            }
        }
        return -1;
    }
    
    //有向的邻接链表的创建
    void createGraph(myGraph &G)
    {
        G=(Graph*)malloc(sizeof(Graph)); //动态申请空间
        
        int i,j,k;
        char v1,v2;    //边的两个顶点 
        printf("请输入顶点的数量:");
        scanf("%d",&G->vexNum);
        printf("请输入边的数量:");
        scanf("%d",&G->arcNum);
        
        printf("请依次将顶点数据输入进来
    ");
        for(i=0;i<G->vexNum;i++)   //初始化顶点 
        {
            getchar();
            scanf("%c",&G->vexs[i].data);
            G->vexs[i].firstNode=NULL;  //初始化为空 
            G->vexs[i].in=0;  //初始化入度为0 
        }
        
        printf("请依次将边输入进来
    ");
        for(i=0;i<G->arcNum;i++)
        {
            getchar();
            scanf("%c%c",&v1,&v2);
            
            j=getLocate(G,v1);  //获取下标
            k=getLocate(G,v2);  //获取下标
            
            ENode *currentNode=(ENode*)malloc(sizeof(ENode));
            currentNode->index=k;   //顶点下标 
            currentNode->next=NULL;
            G->vexs[k].in++;    //k的下标入度加1
        
            if(G->vexs[j].firstNode==NULL)//当该顶点没有邻接点时  
            {
                G->vexs[j].firstNode=currentNode; //指向这个结点 
            } 
            else  //当该顶点有邻接点时   直接在链的头部进行插入  不是在尾部插入 
            {
                
                ENode *node=G->vexs[j].firstNode; //储存第一个结点 
                G->vexs[j].firstNode=currentNode; //新节点变成第一个结点 
                currentNode->next=node;   //新的第一个结点指向旧的第一个结点 
            }
        }  
    }
    
    //打印该邻接表
    void printfGraph(Graph G)  //打印表不要用指针,这样可能会改变图的结构 
    {
        for(int i=0;i<G.vexNum;i++)
        {
            printf("%d ",G.vexs[i].in);
            printf("%c ",G.vexs[i].data);
            while(G.vexs[i].firstNode!=NULL)
            {
                printf("%d ",G.vexs[i].firstNode->index);
                G.vexs[i].firstNode=G.vexs[i].firstNode->next;
            }
            printf("
    ");
        } 
    }
    
    //拓扑排序
    void  TopologicalSort(myGraph G)  //满足栈后进先出的个性 
    {
        int top=0;  //栈指针
        int count=0;  //打印次数
        ENode *node; //避免 G->vexs[i].firstNode发生改变
        int *stack; //栈数组
        int getTop; //获取栈顶顶点下标 
        int i,j;
        
        stack=(int*)malloc(G->vexNum*sizeof(int)); //动态生成一个数组
        if(!stack)
        {
            printf("动态生成失败
    ");
        }
        
        for(int i=0;i<G->vexNum;i++)  //先将度为0的先入栈 
        {
            if(G->vexs[i].in==0)
            {
                stack[++top]=i;  //储存入栈顶点的下标 ,从top=1开始 
            }
        } 
        
        while(top!=0)  //当top等于0时,没有出栈元素了 
        {
            int getTop=stack[top--];  //出栈操作 
            printf("%c ",G->vexs[getTop].data);  
            count++;  //用来判断有没有环 
            
            for(node=G->vexs[getTop].firstNode;node!=NULL;node=node->next) 
            {
                j=node->index;  //获取顶点的下标
                if(!(--G->vexs[j].in)) //如果入度为0则入栈 
                {
                    stack[++top]=j;
                }
            }
        }
        
        if(count<G->vexNum) 
        {
            printf("该图有环
    ");
        }
    }
    
    int main()
    {
        Graph *G;  //申明邻接链表的对象
        createGraph(G);  //创建邻接链表
        printfGraph(*G);   //打印该邻接链表 
        
        printf("该有向图的拓扑排序如下:");
        TopologicalSort(G);    
    }

      

  • 相关阅读:
    面试官:别的我不管,这个JVM虚拟机内存模型你必须知道
    万字长文带你掌握Java数组与排序,代码实现原理都帮你搞明白!
    面试官:就问个Spring容器初始化和Bean对象的创建,你讲一小时了
    来吧,展示!Redis的分布式锁及其实现Redisson的全过程
    Python之OS(系统操作)模块常用函数
    Python之文件操作
    Python之小测试:用正则表达式写一个小爬虫用于保存贴吧里的所有图片
    Python值正则表达式(RE)
    Python之内建函数
    Python之switch
  • 原文地址:https://www.cnblogs.com/qian-yi/p/12787383.html
Copyright © 2011-2022 走看看