C++ Fleury 算法用于打印欧拉路径或回路2025年3月21日 | 阅读13分钟 Fleury 算法 是解决图中欧拉路径和回路的最常用方法之一。它提供了一种系统的方式来遍历图的边,每条边仅访问一次。欧拉路径包含所有边,而欧拉回路是一个闭环,两者都代表对图的边的完整覆盖。然而,这些路径和回路只有在图中固有的特定条件下才能识别。 Fleury 算法执行对图的系统搜索,以找到欧拉路径或回路。然后,它会遍历边,确保每条边只访问一次,同时保持图的连通性。当有多种选择时,算法会智能地选择那些不充当桥梁的边,从而防止图分裂成不连通的组件。 Fleury 算法用于无向图的欧拉路径和回路这是 Fleury 算法的简单版本。Fleury 算法 用于发现无向图中的欧拉路径和回路。它确保在欧拉回路中每条边恰好经过一次,在欧拉路径中则经过两次。算法从选择起始顶点开始,然后选择具有最少替代的边,避免桥梁以防止过早断开。 重复此过程直到所有边都被遍历,算法就形成了一条覆盖每条边一次的路径或回路。这种简洁性和效率使 Fleury 算法成为研究无向图欧拉特征的有用工具。 程序输出 Eulеrian Path or Circuit: Graph has no Eulеrian path or circuit. 说明 提供的 C++ 代码实现了 Fleury 算法,用于查找无向图中的欧拉路径或回路。该算法旨在仅一次遍历图中的每条边,形成欧拉路径(如果恰好有两个奇数度顶点)或欧拉回路(如果所有顶点都是偶数度)。
算法首先使用邻接表来表示图。邻接表是一种数据结构,其中每个顶点都维护一个相邻顶点列表。在 C++ 中,代码使用一个 Graph 类来封装这种结构。构造函数设置顶点数,并使用 addEdge 方法添加边到图中。
在深入研究算法本身之前,验证给定图是否满足欧拉路径或回路的要求至关重要。Fleury 算法要求图中所有顶点度数都是偶数(如果是欧拉回路),或者恰好有两个顶点的度数是奇数(如果是欧拉路径)。在算法开始时进行此检查,以确保图适合后续遍历。
Fleury 算法基于不遍历桥梁(移除后会断开图的边)的原理进行图的导航。其核心是,算法的主循环从当前顶点选择下一条边,将其从图中删除,然后移动到边的另一端。重复此过程直到覆盖所有边。该算法使用堆栈来维护访问顶点的顺序。
Fleury 算法的一个重要元素是在遍历过程中避免桥梁。桥梁是指其移除会增加图中连通分量数量的边。为确保算法不会意外地创建桥梁,isValidNextEdge 函数会检查移除边 (u, v) 是否会断开图的连接。 它通过进行深度优先搜索 (DFS) 并计算边移除前后可达顶点的数量来实现。如果数量保持不变,则可以安全地遍历该边。
dfsCount 函数使用深度优先搜索来确定从给定顶点可达的顶点数量。它用于确认移除一条边是否会断开图。这种计数机制对于确保算法的决策不影响图的连通性至关重要。
Fleury 算法的主循环始终选择并遍历边,并更新堆栈。如果一个顶点没有更多边了,它就被认为是欧拉路径或回路的一部分,算法通过弹出堆栈中的最后一个顶点来回溯。遍历一直持续到所有边都被覆盖。
最后,算法打印遍历操作期间访问的顶点序列。这个序列根据初始条件,等同于图中的欧拉路径或回路。
在提供的示例中,使用了一个具有四个顶点和特定边的图来演示该算法。图的顶点为 0、1、2 和 3。边连接 0-1、0-2、1-2 和 2-3。输出定义了从指定顶点开始的欧拉路径或回路。 复杂度分析 时间复杂度 图初始化(构造函数) 构造函数为图提供了几个顶点,并设置了邻接表。此操作的时间复杂度为O(V),其中 V 是顶点的数量。 添加边(addEdge) 边插入还需要修改两个顶点的邻接表集。最坏的情况下,当每个顶点的度数恒定时,时间复杂度为 O(1)。 删除边(removeEdge) 当删除一条边时,意味着从两个顶点的邻接表中删除条目。然而,在最复杂的情况下,当每个顶点的度数恒定时,时间复杂度为 O(1)O(1)。 深度优先搜索 (DFS): 可访问的顶点通过DFS 操作计算。然而,在所有顶点都可以从其他顶点到达的最坏情况下,时间复杂度可能达到O(V + E),其中 V 是节点数,E 是边数。 Fleury 算法 (fleuryAlgorithm) 该方法的基本阶段是选择边、删除它们以及运行 DFS。每一步,它要么执行 DFS (O(V + E)),要么从邻接表中弹出边 (O(1))。因此,复杂度为O(V * (V+E)),其中 V 是顶点数,E 是边数。 最后,时间复杂度为O(V * (V + E)),这取决于 DFS 过程。 空间复杂度 图表示 图表示的空间复杂度包括存储邻接表。最坏的情况下,当没有重复边时,空间复杂度为O (V + E),其中 V 是顶点的数量,E 是边的数量。 DFS 堆栈 DFS 遍历使用一个堆栈来维护访问过的顶点。最坏的情况下,堆栈的大小可能为 V,导致空间复杂度为O(V)。 附加数据结构 其他结构,如用于记账的数组和向量,也对整体空间复杂度有贡献。然而,最坏情况下,这些数据结构的空间需求为O(V)。 最后,空间复杂度由图表示和其他数据结构决定,结果为O (V+ E)。 欧拉路径和回路的概念可以应用于有向图。在有向图中,Fleury 算法的一个变体可能包括考虑顶点的入度和出度来确定是否存在欧拉路径或回路。 Fleury 算法用于有向图,经过调整以考虑顶点的入度和出度。关键思想是遍历边并保持欧拉性质。 入度和出度的概念对于建立欧拉路径或回路的逻辑非常重要。与无向图不同,无向图的边是双向的,有向图的边具有指定的起始和结束顶点。 有向图的欧拉路径和回路有向图中的欧拉路径是恰好遍历一次有向边的路径。而欧拉回路是以同一顶点开始和结束,恰好访问一次所有有向边的回路。 入度和出度在有向图中,对于每个顶点,入度表示指向它的边的数量,而出度表示指向它的边的数量。 要存在欧拉路径,最多只能有一个顶点满足 (出度+1) = 入度,并且最多只能有一个顶点满足入度 + 1 = 出度。所有其他顶点都需要满足入度等于出度。 对于欧拉回路,每个顶点都必须满足入度等于出度。 程序输出 Eulеrian Path or Circuit: Graph has no Eulеrian path or circuit. 说明 上述 C++ 代码实现了 Fleury 算法用于有向图。在这种情况下,Fleury 算法是经典方法在有向图中寻找欧拉路径或回路的改编。该算法在考虑顶点入度和出度的情况下,恰好遍历每条边一次。
Graph 类封装了有向图的形式和函数。它还有私有成员,包括顶点数 (V) 和邻接表 (adj)。邻接表是向量的向量,表示顶点之间的有向边。
构造函数根据给定的顶点数创建图,并根据顶点数初始化邻接表。
addEdge 方法在顶点 u 和 v 之间创建有向边。它更新邻接表以反映有向关系。 图是用固定数量的顶点构建的;因此,时间复杂度为O (V)。
边是邻接表的修改,在最坏(稀疏图)情况下,其时间复杂度为 1。
删除边是指删除邻接表中的条目。
寻找欧拉路径或回路的循环的时间复杂度为O(V),其中 V 是顶点的数量。
算法的核心是通过遍历图并确保每条边都是有效的来体现。最坏情况下,其复杂度可能为O(V^2),其中 V 是顶点的数量。
检查下一条边的有效性需要遍历邻接表,在最坏情况下,其复杂度为O(d),其中 d 是顶点的最大度数。 整体时间复杂度由遍历步骤决定,在最坏情况下为 O(V^2),其中 V 是顶点的数量。 空间复杂度 图表示 图表示的空间复杂度包括存储邻接表。在最坏情况下(稠密图),其复杂度为O(V^2),V 是顶点的数量。 DFS 堆栈 DFS 遍历使用一个堆栈来记住访问过的顶点。在最坏情况下,堆栈的大小可能为 V,导致空间复杂度为O(V)。 附加数据结构 使用向量和布尔数组的附加数据结构用于计费,并增加了空间复杂度。这些记录结构最多需要O(V)空间。 图表示支配着总空间复杂度;在最坏情况下,其复杂度为O(V^2),其中 V 是顶点的数量。 Dijkstra 算法结合 Fleury 思想(欧拉路径)Dijkstra 算法和Fleury 思想的结合,用于在一个 -步过程中找到欧拉路径。首先,使用 Dijkstra 算法确定图中两个奇数度顶点之间的最短路径。这一步保证了通过以最优方式连接标准度顶点,使图变成欧拉图。一旦确定了最短路径,就通过并入这些计算出的路径来调整图,将其变成欧拉图。 然后,应用 Fleury 算法在修改后的图中找到欧拉路径。Fleury 算法的特点是所有边都被恰好遍历一次,同时不遍历任何桥梁边。这种组合方法通过结合 Dijkstra 高效的路径查找和 Fleury 算法用于遍历欧拉路径,为具有均匀度顶点的图中的路径优化和欧拉路径确定问题提供了全面的解决方案。 程序输出 Eulеrian Path: 1 3 4 3 4 2 4 3 2 3 1 2 4 2 3 2 1 3 1 2 0 2 1 0 1 0 2 0 1 时间复杂度 鉴于 Dijkstra 算法、combineDijkstraAndFleury 中的重要循环以及 Fleury 算法的时间复杂度,总体时间复杂度由其中最高者决定。因此,总体时间复杂度为O(((V+E) * log(v)))。 空间复杂度 总空间复杂度根据图表示、Dijkstra 算法、组合以及 Fleury 算法的空间复杂度中的最高者计算。因此,稠密图在最坏情况下的总体空间复杂度为O(V^2),稀疏图为O(V+E)。 |
简介:(C++23 中可用) 是 range 库的一部分,位于 <ranges> 头文件中。它允许您生成多个范围的笛卡尔积,创建一个迭代这些范围中所有可能元素组合的视图。std::views::cartesian_product 的目的 std::views::cartesian_product 提供了一个高效的...
阅读 10 分钟
在本文中,我们将讨论其不同的方法,例如时间复杂度、空间复杂度。鸭子数(Duck Number)是一种独特的正整数,其十进制表示中至少有一个零。关键要求是...
阅读 4 分钟
简介:对于计算机编程,矩阵操作是一个主要且高度必要的工作。从图像处理和数据分析开始,矩阵扮演着结构的角色。存在多种类型的变形,包括旋转、反射和放大。在本文中,我们将讨论……
阅读 10 分钟
在本文中,我们将讨论如何在 C++ 中查找两个 multimaps 的对称差。在进行实现之前,我们必须了解 multimaps。C++ 中的 Multimap 是什么?在 C++ 中,“std::multimap”是一个关联容器,它存储键值对,其中...
阅读 6 分钟
引言 一个著名的数学序列被称为“康托尔序列”,它是通过对给定数字网格的 it 表示进行之字形排列而构建的。康托尔序列经常出现在数学的各个分支中,例如数论,甚至在……
阅读 10 分钟
在本文中,我们将讨论 C++ 中的 std::is_destructable,包括其语法和示例。什么是 std::is_destructable?在 C++ 中,std::is_destructable 是一种类型特征函数。它有助于确定某种类型是否可以使用 delete 运算符进行销毁。它定义在 <type_traits>...
阅读 3 分钟
引言:C++ 中的 monad(源自 Haskell 等函数式编程语言)表示一种设计模式,它允许在管理值、上下文或副作用的同时,以受控的方式链接操作。在 C++ 中,monad 不是原生内置的,但可以通过...
7 分钟阅读
在 C++ 中填充每个节点中的右指针 填充二叉树每个节点中的右指针是计算机科学中的一个经典问题,涉及增强树的结构以支持特定类型的遍历和操作。这个问题尤其与...
阅读 17 分钟
在本文中,我们将讨论C++中的单词方阵方法,包括其语法、参数和示例。什么是单词方阵?单词方阵是指一种语言,它由适合方格的单词组成。这些单词的读法相同……
14 分钟阅读
在本文中,我们将讨论其作用、元素、工作原理、实现、优点和挑战。引言:词法分析器也称为扫描器或标记器。它是编译器的第一阶段。它将源代码从字符序列转换为...
阅读 10 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India