C++ 中 Tarjan 算法查找强连通分量2025年5月13日 | 阅读 13 分钟 Tarjan 算法,作为大多数相关图算法的基础,用于发现有向图中的强连通分量(SCS)。SCC 是图的基本构建块。因此,组件中的每个顶点都可以访问组件中的任何其他顶点。事实上,这些路径是循环的,因此总有一条路径从任何顶点开始,到达另一个顶点,然后返回到已访问过的顶点。 DFS(深度优先搜索)方法非常有效,因为它在图上提供了出色的性能。通过 DFS 的搜索算法将花费时间深入探索顶点。在宽松的策略方案中,顶点被分配顺序不同的编号。由于缺少“地址”,无法遍历整个图结构,但堆栈允许 DFS 克服此问题。 正是这种方法可以实现资源的最佳利用,并且还有助于图的遍历、路径查找和网络分析。因此,这种过程是必不可少的,可以用于任何需要高效地对图数据结构进行调查的应用程序。 这可以通过不断更新每个顶点的发现时间,并找到通过图的有向边和反向边可以到达的最低顶点来实现;这使得Tarjan 方法能够将强连通分量(SCC)与图的其余部分分开。该算法在遇到其发现时间匹配的顶点时,会比较一个顶点的最低祖先;这是为了找到另一个新的,然后通过从堆栈中提取各种顶点直到到达当前顶点来继续。 方法 1:使用邻接表表示法在数据结构中存储图最流行的方式是邻接表表示法。边列表在 C++ 代码中表示为数组或向量,其中每个元素对应于图中的一个顶点。数组的每个元素(边)是一个列表,其元素(节点)表示与其对应的顶点的相邻顶点。它包含此邻接列表以揭示顶点之间的连通性。因此,它便于遍历和操作,这非常重要。 边列表表示法在 Tarjan 算法等针对图中的 SCC 的算法中特别有利。通过这种表示法,可以轻松地进行顶点的邻域以及图操作,这意味着依赖于图连接和结构的算法可以高效运行。归根结底,正是邻接表表示法的强大功能使其在 C++ 编程中存储和操作图方面具有通用性和高效性。 程序输出 Strongly Connected Components: 4 3 2 1 0 说明
结构化社群已被识别并打印出来,以便能够通过整个图来讲述网络连接的故事。这实际上促进了对图进行强分析和理解的过程,从而也促进了组成元素之间的关系。 复杂度分析时间复杂度 该算法的时间复杂度为O(V+E),其中 V 是顶点数,E 是图中的边数。DFS 遍历是该算法的关键组成部分,每个顶点和边最多访问一次,因此时间复杂度为 O(V+E)。此外, whilst 查找强连通分量是通过一次遍历图的顶点和边来完成的,它需要额外的O(V + E),这会加剧整体时间复杂度。 与边和顶点直接相关意味着该算法在分析大型图方面效率很高,因此适合用于此目的。通过优化利用图的拓扑结构及其派生物,Tarjan 算法成功地识别了对深入图分析至关重要的强连通分量。 空间复杂度 该算法的空间复杂度主要由用于表示图和保存 DFS 遍历所需临时项的数据结构定义。 邻接表表示的空间复杂度为O(V + E),其中 V 是顶点数,E 是有向弧数,因为对于无向图,每条边都单独计数。这就是每个顶点都有一个相邻顶点列表的原因。 另一方面,在发生DFS 遍历时,会存储全局向量以检索发现时间、最低祖先值、堆栈成员状态以及堆栈成员。这些工具总共形成一个O(V)复杂度的数据结构。 因此,该算法的空间复杂度顺序为 O(V + E),由邻接表表示法表示图的空间复杂度所主导。 方法 2:使用哈希表Tarjan 算法,它执行统一查找有向图的所有强连通分量(SCC)的任务,是一种通用的解决方案,适用于各种数据结构,如哈希表、哈希集。它们通过帮助算法快速移动和管理关于顶点和边的拓扑信息来提高算法的速度,从而能够更快地识别 SCC。 通过巧妙地部署这些数据结构来最优地遍历图,并通过实现此算法;它能够以几乎零计算成本有效地识别和聚类图的强连通分量。这种能力表明该算法如何服务于各种图表示以及不同大小的图,同时仍能以预期的最高标准运行。 程序输出 Strongly Connected Components: 8 9 1 5 7 说明Graph 类 使用图类的方向属性和元素的邻接列表来符号化。构造函数初始化 V(顶点),而方法允许识别强连通分量。通过addEdge,建立节点之间的边,从而增强图的连通性。 发生的事件与findSCCs 相反,后者依赖于 Tarjan 算法来暴露与内聚顶点子集相关的连通分量。这种抽象代表了图中的不同顶点,因此可以精确地操作顶点集,从而可以将其应用于广泛的图论相关算法。 DFS 函数 DFS 函数执行深度优先搜索,遍历图的节点以查找超级分量。 图查找算法从起始顶点 u 开始,并跟踪访问的顶点数量和当前的DFS 遍历路径,使用堆栈 (st) 来维护DFS 遍历顺序,使用向量的向量 (SCCs) 来存储已识别的强连通分量,以及用于映射到每个顶点的最低祖先(low) 和查找从一个顶点到另一个顶点的过渡时间的数据结构。 在进行深度优先搜索遍历时,它会确定每个顶点的发现时间和最低祖先,并通过将其存储在堆栈和集合中来记录属于当前 DFS 路径的顶点。它通过验证其最低祖先是否与发现时间相同来确定过程的 SCC。如果是,则从堆栈中弹出顶点,从而形成一个 SCC。 FindSCCs 函数 在 Graph 类中,findSCCs 函数充当指挥家,通过深度优先搜索(DFS)遍历快速找到强连通分量(SCC)。它从每个顶点开始,开发诸如发现时间、最低祖先、堆栈以及包含当前遍历路径中顶点的存储库之类的数据结构。通过遍历所有顶点,它为任何未访问的节点调用DFS 函数来查找图的邻接关系。 在执行过程中遍历图时,算法负责更新发现时间和识别最低祖先,这两者对于识别 SCC 都至关重要。当检测到 SCC 时,这些 SCC 会被收集并存储在向量中以供将来审查。整个DFS 过程用于扫描整个图并深入探索,并且在调用 SCC 函数执行后,可以找到图的结构组织和连接的重要信息。 主函数 Main 函数与描述图边的 Graph 对象一起创建。首先,使用 addVertex 方法创建每个节点并将其添加到图中。然后使用addEdge 方法将边添加到图中,该方法将节点彼此连接。接下来,将调用 findSCCs 方法,它将检测图中的强连通分量。作为此功能的一部分,Tarjan 算法用于遍历图。 通过这样做,可以识别顶点簇,这些簇又会根据它们与其他顶点的连接方式形成 SCC。最后,将考虑的 SCC 存储在控制台中,控制台将显示图的结构组织。因此,此过程使我们能够可视化和研究具有相似特征属性的图的片段,以进行顶点分布;网络分析、交通导航和群组分类。 复杂度分析时间复杂度 主要时间复杂度是由于对图进行的深度优先搜索(DFS)遍历。考虑到算法只遍历每个部分和链接一次,时间复杂度基本上由V 和 E描述,它们分别表示图中的顶点数和边数。 在最坏的情况下,图是密集连接的,任何一个节点都可以到达任何其他节点,这导致 DFS 遍历的时间复杂度为O(V + E)。这是因为在遍历过程中,每个顶点和边只被访问一次。 此外,在DFS 遍历中查找 SCC 的过程包括诸如分配发现时间和最低祖先值之类的操作,以及检查启用SCC 识别的条件。除了计算机操作之外,DFS 遍历也涉及大部分的复杂性。 总之,该算法的总复杂度为O(V + E),其中 V 是顶点数,E 是整个图中的边数。 空间复杂度 该算法的空间复杂度主要涉及在 DFS 遍历期间存储信息以及查找图中强连通分量所需的任何额外数据结构。 以邻接列表格式表示图的空间利用率为O(V + E),其中 V 是顶点数,E 是边数。 DFS 遍历需要一些额外的空间用于记录发现时间、最低祖先的映射,以及用于保存历史记录的堆栈,以及用于当前路径中顶点的使用集。这些数据结构的空间复杂度为O(V)。 存储已识别 SCC 图形的空间复杂度由 SCC 的数量和每个 SCC 中顶点的数量决定。在汇点情况(其中每个顶点都是汇点且顶点本身)下,最坏空间为 V。然而,实际上,SCC 的数量远小于顶点数量,因为图是共享的。 因此,该算法的最终空间复杂度为O(V + E),这由存储图表示所需空间和DFS 遍历期间使用的数据结构所主导。 下一个主题Nude-numbers-in-cpp |
在数学和计算机科学中,自守数(strobogrammatic number)的概念是一个有趣的数字,因为当它旋转 180 度(上下颠倒)时仍然保持不变。这样的数字在结构上是对称的,并且通常用于...
阅读 17 分钟
在本文中,我们将讨论。令人费解的 C++ 功能是 C++20 中引入的一个高级概念。它允许更灵活、更清晰的代码,尤其是在考虑 lambda 函数和成员方法时。下面是 deducing_this 的一些功能,涵盖了……
7 分钟阅读
概述 std:text_encoding 函数是 C++ 中相当概念性的功能之一,它包含了不同类型的文本编码。它有助于在其他字符中进行文本的翻译和处理。在处理文本数据时,此函数有助于确保...
5 分钟阅读
引言 在快速发展的数字时代,有效的管理系统在各种业务领域的组织和效率方面起着关键作用。使用 C++ 文件处理的书店管理系统是一个旨在通过自动化来满足传统书店需求的 Процитовано...
阅读 10 分钟
在本主题中,我们将讨论 C++ 编程语言中的基于范围的 for 循环。C++ 语言在 C++11 及更高版本中引入了一种新的基于范围的 for 循环概念,它比常规的 For 循环要好得多。基于范围的 for 循环做...
5 分钟阅读
数组操作任务对于计算机科学至关重要,尤其是在算法问题解决领域。数组使用其索引进行排列,是存储在连续内存位置中的元素组。在我们必须以不同方式操作数组的情况下,例如通过搜索、排序或...
阅读 6 分钟
在本文中,我们将讨论 C++ 中的 Baum-Sweet 序列,包括其数学解释、算法和方法以及示例。什么是 C++ 中的 Baum-Sweet 序列?Baum-Sweet 序列是一种数学和计算机科学的二元序列,它基于整数的二进制形式,...
阅读 13 分钟
在本文中,我们将讨论 C++ 中原子标志(Atomic Flags)和原子布尔(Atomic Boolean)之间的区别。在讨论它们的区别之前,我们必须了解 C++ 中的原子标志和原子布尔。什么是原子标志 (std::atomic_flag)?低级 C++ 原子类型 std::atomic_flag 可以处于...
阅读 4 分钟
在本文中,我们将讨论 C++ 中惰性求值和及早求值之间的区别。在讨论它们的区别之前,我们必须了解 C++ 中惰性求值和及早求值及其示例。什么是惰性求值?惰性求值仅在表达式的值...
阅读 8 分钟
简介 面无表情是构成编程逻辑技能的基础的重要模式之一。在本节中,我们将通过循环和条件语句编写一个 C++ 程序来打印面无表情。此任务需要形成一个......
5 分钟阅读
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India