拓扑排序(有向无环图)

  拓扑排序含义:对一个有向无环图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);    
}

  

原文地址:https://www.cnblogs.com/qian-yi/p/12787383.html