图的拓扑排序——卡恩算法

拓扑排序

有向图的拓扑排序是其顶点的线性排序,使得对于从顶点u 到顶点v 的每个有向边uv ,u 在排序中都在v 之前。

在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序(Topological sorting)。

  1. 每个顶点出现且只出现一次;
  2. 若A在序列中排在B的前面,则在图中不存在从B到A的路径。

//#include<Windows.h>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 105;
const int MAX_E = 10005;
const int MAX_V = 105;

struct ENode
{
    int to;
    int Next;
};
ENode Edegs[MAX_E];
int Head[MAX_V];
int tnt;
void Add_ENode(int w, int v)
{
    ++tnt;
    Edegs[tnt].to = v;
    Edegs[tnt].Next = Head[w];
    Head[w] = tnt;
    /*可以拓扑排序则保证这是一个有向图*/
}
int IN_degree[maxn];//记录每个点的入度;
int Queue[maxn];
int main()
{
    int n, m;
    int u, v;
    scanf_s("%d %d", &n, &m);
    memset(IN_degree, 0, sizeof(IN_degree));
    memset(Head, -1, sizeof(Head));
    tnt = -1;
    for (int i = 0; i < m; i++)
    {
        scanf_s("%d %d", &u, &v);
        Add_ENode(u, v);
        IN_degree[v] ++;
    }

    int iq = 0;
    for (int i = 1; i <= n; i++)
    {
        if (IN_degree[i] == 0)
        {
            Queue[iq++] = i;
        }
    }
    for (int i = 0; i < iq; i++)
    {
        for (int k = Head[Queue[i]]; k != -1; k = Edegs[k].Next)
        {
            IN_degree[Edegs[k].to] --;
            if (IN_degree[Edegs[k].to] == 0)
            {
                Queue[iq++] = Edegs[k].to;
            }
        }
    }
    for (int i = 0; i <= iq; i++)
    {
        printf("%d%c", Queue[i], i != iq - 1 ? ‘ ‘ : ‘\n‘);
    }
//    system("pause");
    return 0;
}

拓扑排序,卡恩算法

卡恩算法

  假设L 是存放结果的列表,先找到那些入度为零的节点,把这些节点放到L 中,因为这些节点没有任何的父节点。然后把与这些节点相连的边从图中去掉,再寻找图中的入度为零的节点。对于新找到的这些入度为零的节点来说,他们的父节点已经都在L中了,所以也可以放入L。重复上述操作,直到找不到入度为零的节点。如果此时L中的元素个数和节点总数相同,说明排序完成;如果L中的元素个数和节点总数不同,说明原图中存在环,无法进行拓扑排序。

概括起来,即以下三步:

  ①从有向图中选择一个没有前驱(入度为0)的点,输出它。

  ②从网(图)中删除它,并且删除从它出发的所有有向边。

  ③重复上面步骤,直到图(网)中不再存在没有前驱(入度为0)的点为止。

对于上面的算法,如果最终存在不能删除的点,则剩余的点之间一定构成环路。

实现方式:用链式前向星存储整张图,在读入数据时统计每个点的入度。每删除一个点,就删除所有从它出发的边,并且把对应的终点入度-1,再去删除下一个点。

实现代码

//#include<Windows.h>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 105;
const int MAX_E = 10005;
const int MAX_V = 105;

struct ENode
{
    int to;
    int Next;
};
ENode Edegs[MAX_E];
int Head[MAX_V];
int tnt;
void Add_ENode(int w, int v)
{
    ++tnt;
    Edegs[tnt].to = v;
    Edegs[tnt].Next = Head[w];
    Head[w] = tnt;
    /*可以拓扑排序则保证这是一个有向图*/
}
int IN_degree[maxn];//记录每个点的入度;
int Queue[maxn];
int main()
{
    int n, m;
    int u, v;
    scanf_s("%d %d", &n, &m);
    memset(IN_degree, 0, sizeof(IN_degree));
    memset(Head, -1, sizeof(Head));
    tnt = -1;
    for (int i = 0; i < m; i++)
    {
        scanf_s("%d %d", &u, &v);
        Add_ENode(u, v);
        IN_degree[v] ++;
    }

    int iq = 0;
    for (int i = 1; i <= n; i++)
    {
        if (IN_degree[i] == 0)
        {
            Queue[iq++] = i;
        }
    }
    for (int i = 0; i < iq; i++)
    {
        for (int k = Head[Queue[i]]; k != -1; k = Edegs[k].Next)
        {
            IN_degree[Edegs[k].to] --;
            if (IN_degree[Edegs[k].to] == 0)
            {
                Queue[iq++] = Edegs[k].to;
            }
        }
    }
    for (int i = 0; i <= iq; i++)
    {
        printf("%d%c", Queue[i], i != iq - 1 ? ‘ ‘ : ‘\n‘);
    }
//    system("pause");
    return 0;
}

拓扑排序

原文地址:https://www.cnblogs.com/Amaris-diana/p/10695363.html

时间: 2024-11-02 02:07:47

图的拓扑排序——卡恩算法的相关文章

有向无环图(DAG)拓扑排序的两种方法

如下图的DAG: 第一种: (1)从AOV网中选择一个没有前驱的顶点并且输出它: (2)从AOV网中删除该顶点,并且上去所有该顶点为尾的弧: (3)重复上述两步,直到全部顶点都被输出,或者AOV网中不存在没有前驱的顶点. 第二种: 使用深度优先搜索(DFS),并标记每一个节点的第一次访问(pre)和最后一次访问时间(post),最后post的逆序就是DAG的拓扑排序,其实也是节点在进行DFS搜索时,出栈的逆序就是拓扑排序. 拓扑序列的结果有: (1) c++,高等数学,离散数学,数据结构,概率论

图的拓扑排序

定义: 图的拓扑排序是对有向无环图来说的,无向图和有环图没有拓扑排序,或者说不存在拓扑排序,对于一个有向无环图G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若图G存在边< u, v >,则u在线性序列中出现在v之前.对一个有向无环图进行拓扑排序产生的线性序列称为满足拓扑次序的序列.一个有向无环图可以表示某种动作或者方案,或者状态,而有向无环图的拓扑序列通常表示某种某案切实可行或者各个成员之间的某种关系. 举个栗子,看上面那个图,v1v2v3v4v5v6v7v8是

拓扑排序(算法竞赛入门经典)

拓扑排序的定义: 把每个变量看成一个点,”小于“或者”先后“关系看成有向边,则我们得到一个有向图.这样我们的任务实际上是把一个图的所有节点排序,使每一条有向边的(u,v)对应的u都排在v之前,在图论中,我们称之为拓扑排序.不难发现,如果一个有向图里存在回路,则不存在拓扑排序(如果设置一个标志数组,我们可以发现回路中的点一直处于正在被访问状态,这可以作为拓扑排序的结束条件). 我们先看一个样例: 下面我们用邻接矩阵存储这张图:   0 1 2 3 0 0 1 1 1 1 0 0 1 1 2 0 0

java实现AOV图的拓扑排序

拓扑排序作为图的应用,了解拓扑排序必须首先了解AOV图. AOV网表示一个有向图中顶点,用弧表示顶点之间的优先关系.如下图所示,在AOV网中,若从顶点vi到顶点vj之间存在一条有向路径,则称顶点vi为顶点vj的前驱,顶点vj为顶点vi的后继.注意,AOV图不能有回路,否则会将序列陷入死循环,称为死锁. 进行拓扑排序,一般步骤如下: <1>在AOV网中选择一个入度为0的顶点 <2>在AOV网中删除此顶点及其相连的有向边 <3>重复步骤<1>和<2>

DAG图的拓扑排序 python

在DAG中DFS中顶点的出栈顺序即逆拓扑序. def topological_sort( graph ): is_visit = dict( ( node, False ) for node in graph ) li = [] def dfs( graph, start_node ): for end_node in graph[start_node]: if not is_visit[end_node]: is_visit[end_node] = True dfs( graph, end_n

图的拓扑排序、关键路径、最短路径算法 -- C++实现

一:拓扑排序 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前.通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列. 拓扑排序就是要找到入度为0的顶点,并依次压栈.首先将栈顶顶点输出,删除以此顶点为弧尾的顶点,并更新其他顶点的入度.若入度为0,则继续压栈.更新完毕继续出栈,直至栈空.元素出栈并输出

算法学习 - 图的拓扑排序

拓扑排序 拓扑排序是对有向无圈图的顶点的一种排序,使得如果存在一条从Vi到Vj的路径,那么排序中Vj一定出现在Vi后面. 所以假如图里面有圈就不可能完成排序的. 第一种方法 一种简单的办法就是在排序算法中,先找到任意一个没有入边的顶点,然后显示该顶点,并把它和它的边一起从图里删掉.依次类推到最后. 入度(indegree): 顶点v的入度为,所有指向顶点v的变数(u, v). 出度(outdegree): 顶点v的出度为,顶点v所发出的边数(v, u). 下面写下这种方法的伪代码,因为这个的时间

数据结构与算法——有向无环图的拓扑排序C++实现

拓扑排序简介: 拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从Vi到Vj的路径,那么在排序中Vi在Vj的前面. 如果图中含有回路,那么拓扑排序是不可能的.此外,拓扑排序不必是唯一的,任何合理的排序都可以. 对于上面的无环图:v1,v2,v5,v4,v3,v7,v6和v1,v2,v5,v4,v7,v3,v6都是合理的拓扑排序. 一个简单的求拓扑排序的思路: 1.先找出任意一个没有入边的顶点 2.然后显出该点,并将它和它邻接的所有的边全部删除. 3.然后,对图中其它部分做同样的处理.

图的邻接表表示与无环图的拓扑排序

一.  图的最常用的表示方法是邻接矩阵和邻接表. 1,邻接矩阵 邻接矩阵其实就是一个二维数组,对于每条边<u,v>,我们就令A[u][v] = 1,如果图为有权图,我们也可以令A[u][v]等于该权,这么表示的优点是非常简单,但是它的空间需求很大,如果图是稠密的,邻接矩阵是合适的表示方法,如果图是稀疏的,那这种方法就太浪费空间了,下面给出图的邻接矩阵表示例子. 2 邻接表 邻接表是图的常用储存结构之一.邻接表由表头结点和表结点两部分组成,其中图中每个顶点均对应一个存储在数组中的表头结点.如下图