返回顶部
首页 > 资讯 > 后端开发 > Python >Kasaraju算法--强连通图遍历及其
  • 705
分享到

Kasaraju算法--强连通图遍历及其

遍历算法Kasaraju 2023-01-30 23:01:43 705人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

在理解有向图和强连通分量前必须理解与其对应的两个概念,连通图(无向图)和连通分量。 连通图的定义是:如果一个图中的任何一个节点可以到达其他节点,那么它就是连通的。 例如以下图形: 这是最简单的一个连通图,即使它并不闭合。由于节点间的路径

在理解有向图和强连通分量前必须理解与其对应的两个概念,连通图(无向图)和连通分量。

连通图的定义是:如果一个图中的任何一个节点可以到达其他节点,那么它就是连通的。

例如以下图形:

这是最简单的一个连通图,即使它并不闭合。由于节点间的路径是没有方向的,符合从任意一个节点出发,都可以到达其他剩余的节点这一条件,那么它就是连通图了。

 

连通分量

 

显然这也是一个图,只不过是由三个子图组成而已,但这并非一个连通图。这三个子图叫做这个图的连通分量,连通分量的内部归根还是一个连通图。

 

有向图:

在连通图的基础上增加了方向,两个节点之间的路径只能有单一的方向,即要么从节点A连向节点B,要么从节点B连向节点A。有向图与连通图(更准确来说是无向图)最大的区别在于节点之间的路径是否有方向。

有向图也分两种,一种是有环路的有向图。另外一种是无环路的有向图,即通常所说的有向无环图DAG(Directed Acyclic Graph)。严格来说,第一种有环路的图,如果任意一个节点都可以与其他节点形成环路,那么它也是一个连通图。

 

例如下面的就为一个有向图同时也是连通图:

 

强连通分量

强连通分量SCCs(strongly connected components)是一种有向的连通图。

如果一个图的连通分量是它里面所有节点到能够彼此到达的最大子图,那么强连通分量SCCs就是一个有向图中所有节点能够彼此到达的子图。

 

显然由345组成的子图是无法到达由012组成的子图的。那么012和345分别组成两个强连通分量。

 

在实际的现实问题中,我们考虑问题可能就不会简单地研究无向图。例如地图上的最短路径规划,ARP路由算法等等,考虑的都是有向图的问题。

如果有这样一个需求,我们希望用最少的次数遍历所有节点,怎么处理呢?

 

时间效应问题,强连通分量间的时间问题。

如果有向图的各个强连通分量中的元素个数相仿,那么,它们内部分别进行遍历的时间量级别是相等的,但实际情况是,这种情况很少发生。一般从一个强连通分量到另一个强连通分量。

 

正如上面的需求:如何用最少的次数遍历整个有向图的所有节点。假设我们将0、1、2组成子图1,将3、4、5组成子图,子图1有一条指向子图2的路径。这时候,我们从子图1的任意一点开始遍历。假设我们从1开始遍历,那么遍历的顺序将会是1—2,那么来到2的时候问题来了,是先走0的路径还是走子图1和子图2之间的路径去遍历节点3呢?

如果我们先遍历节点0,那么我们遍历完节点0之后,发现节点1已经遍历过,就会返回节点2,再沿着子图1和子图2之间的路径去遍历子图2。这看起来是挺合理的。

但问题是,如果是先遍历节点3(也就是说先遍历子图2)呢?

假设沿着子图1和子图2的路径去遍历子图2,那么子图2遍历完后,子图1还剩下节点0没有被遍历,这时候就会出现很为难的事情,因为之前遍历的情况无法判断哪些节点是没有遍历的,只能是原路返回,依次去从新遍历,“发现”哪些节点是还没去遍历的。似乎上图比较简单,这种方法不会耗费太多的时间。但如果是节点2连接着(并指向)许多个强连通子图的有向图,这种“返回式”的遍历将会是很费劲的一件事。

 

为了解决这个问题,Kosaraju算法提出了它的解决方案。Kosaraju算法的核心操作是将所有节点间的路径都翻转过来。下面分析一下为什么这种算法有它的优势。

还是拿上面的图来讲述。想象一下上面的有向图中的所有节点间的路径都翻转过来了。读者可以自己用一张纸简单画一下。就像下面的图:

 

这一次,我们还是以0、1、2组成子图1,以3、4、5组成子图2。所不同的是,这次遍历的起始点从子图1开始。

 

多强连通分量的有向图

再来看一下这个多子图的强连通图,如果像上图所示,从子图1开始,就会像上文提到的那样,遍历到节点2,会出现多个去向的问题。而在还没有遍历完子图1的前提下,从节点2过渡到子图2/子图3,再回溯的时候会引来较大的麻烦。通过Kosaraju算法之后,从2节点出发的路径都会变成指向2。此时,遍历的起点还是从子图1开始,由于子图1没有出路,就不会出现上面所说的问题。再遍历完子图1后,继续遍历子图2、子图3。而子图2、子图3的遍历都是在强连通分量内部实现的。

 

 

算法实现

邻接集表示的有向图

N={
    "a":{"b"},   #a
    "b":{"c"},   #b
    "c":{"a","d","g"},   #c
    "d":{"e"},   #d
    "e":{"f"},   #e
    "f":{"d"},   #f
    "g":{"h"},   #g
    "h":{"i"},   #h
    "i":{"g"}    #i
}

 

翻转图实现代码:

def re_tr(G):
    GT = {}
    for u in G:
        for v in G[u]:
            # print(GT)
            if GT.get(v):
                GT[v].add(u)
            else:
                GT[v] = set()
                GT[v].add(u)

    return GT

 

深度遍历算法实现代码:

#递归实现深度优先排序
def rec_dfs(G,s,S=None):
    if S is None:
        #S = set()    #集合存储已经遍历过的节点
        S = list()    #用列表可以更方便查看遍历的次序,而用集合可以方便用difference求差集
    # S.add(s)
    S.append(s)
    print(S)
    for u in G[s]:
        if u in S:continue
        rec_dfs(G,u,S)

return S

 

在强连通图内遍历

#遍历有向图的强连通分量
def walk(G,start,S=set()):     #传入的参数S,即上面的seen很关键,这避免了通过连通图之间的路径进行遍历
    P,Q = dict(),set()      #list存放遍历顺序,set存放已经遍历过的节点     
    P[start] = None
    Q.add(start)
    while Q:
        u = Q.pop()                      #选择下一个遍历节点(随机性)
        for v in G[u].difference(P,S):         #返回差集
            Q.add(v)
            P[v] = u
    print(P)    
    return P

 

获得强连通分量

#获得各个强连通图
def scc(G):
    GT = re_tr(G)
    sccs,seen = [],set()
    for u in rec_dfs(G,"a"):    #以a为起点
        if u in seen:continue
        C = walk(GT,u,seen)
        seen.update(C)
        sccs.append(C)
    return sccs

 

单元测试

print(scc(N))

结果:
{'a': None, 'c': 'a', 'b': 'c'}
{'d': None, 'f': 'd', 'e': 'f'}
{'g': None, 'i': 'g', 'h': 'i'}
[{'a': None, 'c': 'a', 'b': 'c'}, {'d': None, 'f': 'd', 'e': 'f'}, {'g': None, 'i': 'g', 'h': 'i'}]

 

这是本人学习过程所写的第一篇关于图的算法文章,供大家一起学习讨论。其中难免会有错误。如有错误之处,请各位指出,万分感谢!

 

--结束END--

本文标题: Kasaraju算法--强连通图遍历及其

本文链接: https://lsjlt.com/news/180573.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Kasaraju算法--强连通图遍历及其
    在理解有向图和强连通分量前必须理解与其对应的两个概念,连通图(无向图)和连通分量。 连通图的定义是:如果一个图中的任何一个节点可以到达其他节点,那么它就是连通的。 例如以下图形: 这是最简单的一个连通图,即使它并不闭合。由于节点间的路径...
    99+
    2023-01-30
    遍历 算法 Kasaraju
  • Python算法之图的遍历
    本节主要介绍图的遍历算法BFS和DFS,以及寻找图的(强)连通分量的算法 Traversal就是遍历,主要是对图的遍历,也就是遍历图中的每个节点。对一个节点的遍历有两个阶段,首先是发现(discover),...
    99+
    2022-06-04
    遍历 算法 Python
  • JavaMorris遍历算法及其在二叉树中的应用
    目录一.Morris遍历1.什么是Morris遍历2.基本思想3.Morris遍历的优点和缺点4.二叉树的线索化二.中序Morris遍历1.中序Morris遍历的分析2.中序Morr...
    99+
    2023-05-18
    Java Morris遍历算法 Java Morris遍历
  • OpenCV 通过Mat遍历图像的方法汇总
    目录方法一、直接对图像像素修改.at<typename>(i,j)二、用指针.ptr<uchar>(k)来遍历输入图像,数组[]生成输出图像三、用指针.ptr...
    99+
    2024-04-02
  • JavaScript二叉树及遍历算法实例分析
    这篇“JavaScript二叉树及遍历算法实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看...
    99+
    2024-04-02
  • JavaScript二叉树及各种遍历算法详情
    目录什么是二叉树满二叉树完全二叉树二叉树的存储数组存储链表存储与二叉树相关的算法深度优先遍历广度优先遍历先序遍历中序遍历后序遍历前言: 上一篇文章中介绍了树的概念、深度优先遍历和广度...
    99+
    2024-04-02
  • python二叉树类以及其4种遍历方法实例
    目录前言实例代码:相关阅读内容:总结前言 之前学习过binarytree第三方库,了解了它定义的各种基本用法。 昨天在问答频道中做题时碰到一个关于二叉树的算法填空题,感觉代码不错非常...
    99+
    2024-04-02
  • OpenCV通过Mat遍历图像的方法有哪些
    本文小编为大家详细介绍“OpenCV通过Mat遍历图像的方法有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“OpenCV通过Mat遍历图像的方法有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。我们在实际...
    99+
    2023-06-29
  • Python Prim算法通过遍历墙实现迷宫的生成
    之前,我们在另外一篇文章中使用Prim算法生成了一个完美迷宫,利用的是遍历网格的方法,这一次,我们要教教大家用遍历墙的方法生成,上一篇文章链接:Python利用Prim算法生成迷宫 ...
    99+
    2023-01-06
    Python Prim生成迷宫 Python生成迷宫 Python Prim算法
  • 目录穿越/遍历漏洞及对其防御方法的绕过
    目录穿越/遍历漏洞及对其防御方法的绕过 介绍:   目录穿越(目录遍历)是一个Web安全漏洞,攻击者可以利用该漏洞读取运行应用程序的服务器上的任意文件。 这可能包括应用程序代码和数据,后端系统的登录信...
    99+
    2023-09-07
    服务器 linux 网络
  • Python二叉树的定义及常用遍历算法分析
    本文实例讲述了Python二叉树的定义及常用遍历算法。分享给大家供大家参考,具体如下: 说起二叉树的遍历,大学里讲的是递归算法,大多数人首先想到也是递归算法。但作为一个有理想有追求的程序员。也应该学学非递归...
    99+
    2022-06-04
    遍历 算法 定义
  • C语言数据结构与算法图的遍历分析
    这篇文章主要介绍“C语言数据结构与算法图的遍历分析”,在日常操作中,相信很多人在C语言数据结构与算法图的遍历分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言数据结构与算法图的遍历分析”的疑惑有所帮助!...
    99+
    2023-06-22
  • C++实现图的遍历算法(DFS,BFS)的示例代码
    目录图的定义图的相关术语图的创建(邻接矩阵)---结构体图的创建(邻接矩阵)---邻接矩阵的创建图的创建(邻接表)---结构体图的创建(邻接表)---邻接表的创建对邻接矩阵进行深度优...
    99+
    2024-04-02
  • C语言数据结构与算法之图的遍历(一)
    目录引入 深度优先搜索代码实现 完整代码  引入  在数据结构中常见的有深度优先搜索和广度优先搜索。为什么叫深度和广度呢?其实是针对图的遍历而言的,请看下面这个图: 图是由一些小圆...
    99+
    2024-04-02
  • C语言数据结构与算法之图的遍历(二)
    目录前言 广度优先搜索过程主要思想 代码实现  前言  在上一章的内容中我们使用了深度优先搜索来进行遍历,这一章我们选择使用广度优先搜索来完成这个图的遍历 --> 结果如下:...
    99+
    2024-04-02
  • 怎么使用Tarjan算法求解强连通分量
    本篇内容介绍了“怎么使用Tarjan算法求解强连通分量”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!算法框...
    99+
    2024-04-02
  • 使用Shell遍历目录及其子目录中的所有文件方法
    新建一个shell文件 $ vi traveDir.sh unXPRPHcZz输入以下代码 #! /bin/bash function read_dir(){ for file in `ls $1` #注...
    99+
    2022-06-04
    Shell 遍历目录 文件
  • C语言算法积累图的遍历邻接表简单路径
    目录题目:思路:代码:题目: 假设图用邻接表表示,设计一个算法,输出从顶点Vi到Vj的所有简单路径 关键字: 图,邻接表,简单路径 思路: Vi=u,Vj=v 本题采用基于递归的深度...
    99+
    2024-04-02
  • C语言数据结构与算法中怎样完成图的遍历
    C语言数据结构与算法中怎样完成图的遍历,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。前言 我们选择使用广度优先搜索来完成这个图的遍历 --> 结果如下:广度...
    99+
    2023-06-22
  • 剑指Offer之Java算法习题精讲N叉树的遍历及数组与字符串
    题目一 N叉树题——前序遍历 根据给定的N叉树根节点,返回它节点值的前序遍历 具体题目如下 解法 class Solution { Arra...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作