C++ 中的 std::views::cartesian_product2025年5月14日 | 阅读10分钟 引言C++ 中的 std::views::cartesian_product (C++23 中可用) 是 <ranges> 头文件下的范围库的一部分。它允许您生成多个范围的笛卡尔积,创建一个视图,该视图遍历这些范围中所有可能的元素组合。 std::views::cartesian_product 的目的std::views::cartesian_product 提供了一种有效的方法来从多个输入范围生成笛卡尔积,而无需显式嵌套循环。它惰性操作,意味着实际的乘积是在您遍历视图时计算的,这使得它对于大型数据集来说内存效率很高。 语法和用法要使用 std::views::cartesian_product,请包含 <ranges> 头文件。 让我们看看它如何以基本形式工作 实施输出 Cartesian Product (range1 x range2): (1, 5) (1, 6) (1, 7) (2, 5) (2, 6) (2, 7) (3, 5) (3, 6) (3, 7) Filtered Cartesian Product (only even elements): (2, 6) 说明步骤 1:定义两个范围 程序首先定义两个数字范围。而不是使用更高级的 C++ 功能,范围是使用简单的列表(向量)创建的。第一个范围包含 {1, 2, 3} 等数字,第二个范围包含 {5, 6, 7} 等数字。这些范围是生成所有可能元素对的输入。 步骤 2:笛卡尔积计算 笛卡尔积是指生成第一个范围中的一个元素与第二个范围中的一个元素的所有组合。为了实现这一点,程序使用了两个嵌套循环。外层循环遍历第一个范围中的每个元素,对于第一个范围的每个组件,内层循环遍历第二个范围中的每个元素。这将创建所有可能的对(例如 (1, 5)、(1, 6)、(2, 5) 等)。当程序找到每个对时,它会将它们打印到屏幕上。 步骤 3:过滤乘积 生成笛卡尔积后,程序会应用一个条件来过滤掉特定的组合。在这种情况下,条件检查一对中的两个数字是否都是偶数。如果是,程序将打印该对。例如,如果第一个数字是 2,第二个数字是 6,它们都是偶数,因此该对将被显示。如果一个或两个数字是奇数,则该对将被跳过。 步骤 4:打印结果 随着循环的运行并找到所有对,程序将笛卡尔积打印到屏幕上,显示每对数字。然后,在应用过滤器后,它仅打印满足两个数字都是偶数条件的对。 复杂度分析时间复杂度 笛卡尔积生成
过滤
因此,程序的整体时间复杂度为 O(n * m),其中 n 是第一个范围的大小,m 是第二个范围的大小。 空间复杂度 输入空间
笛卡尔积存储
方法 1:递归笛卡尔积递归方法通过一次遍历一个范围并递归地将结果与其他范围组合来生成多个范围(或列表)的笛卡尔积。此技术通过将问题分解为更小的子问题来消除对嵌套循环的需求。 实施输出 { 1 3 5 } { 1 3 6 } { 1 4 5 } { 1 4 6 } { 2 3 5 } { 2 3 6 } { 2 4 5 } { 2 4 6 } 说明步骤 1:定义输入 程序以定义多个范围(或数字列表)开始。每个范围包含一组数字,目标是生成从每个范围中选择一个数字的所有可能组合。输入由分组的几个数字列表组成。 步骤 2:递归函数设置 递归函数是解决方案的核心部分。它接受三个输入
深度从 0 开始,意味着函数首先处理第一个范围。随着递归的进行,它会深入到下一个范围,直到所有范围都被处理。 步骤 3:递归的基例 递归需要一个停止条件。当函数处理完所有范围时,就会发生基例。换句话说,当深度等于范围数量时,意味着已经形成了一个完整的组合。此时,该组合将被打印出来或返回。 步骤 4:递归情况(回溯) 在递归情况下,函数会遍历当前范围(基于深度)中的每个元素。对于每个元素,它会将该元素添加到当前组合中,然后进行递归调用以进入下一个范围(即增加深度)。 递归调用完成后,它会通过从当前组合中删除最后一个元素来“回溯”。这确保程序可以在没有先前选择干扰的情况下探索其他可能的组合。此回溯过程使程序能够系统地构建范围内的所有组合,而不会遗漏任何可能性。 步骤 5:构建和打印组合 随着递归的深入,程序通过从每个范围添加一个元素来构建一个组合。一旦达到基例(所有范围都已处理),函数就会打印当前组合。打印后,它会回溯以探索其余的可能性。 示例 想象一下有三个范围,如 {1, 2}、{3, 4} 和 {5, 6}。递归函数首先从第一个范围中选择 1,然后调用自身来处理第二个范围,选择 3,最后处理第三个范围,选择 5。这就形成了组合 (1, 3, 5)。一旦完成,它就会回溯,删除 5,然后尝试 6 来创建组合 (1, 3, 6)。所有范围中的所有元素都会发生相同的过程,以确保生成所有可能的组合。 步骤 6:完成 递归将继续进行,直到从每个范围中选择一个元素的所有可能组合都被打印出来。通过使用递归和回溯,代码可以在不需要复杂循环的情况下有效地探索所有组合。 复杂度分析时间复杂度 对于递归方法,时间复杂度取决于范围的数量和每个范围的大小 笛卡尔积生成
递归函数调用
因此,递归方法的整体时间复杂度为 O(n^k)。 空间复杂度 输入存储
递归栈
组合的临时存储
由于组合被立即打印或处理,而无需在内存中存储,因此不需要额外的空间来同时存储所有组合。 因此,整体空间复杂度为 O(k * n),主要由输入大小和递归深度决定。 性质1. 可扩展性 处理多个范围:递归方法可以处理任意数量的范围,无论您有两个范围还是几十个范围。这种灵活性使其具有高度的可扩展性。像嵌套循环这样的传统解决方案,当范围数量增加时,会变得越来越复杂且难以管理。相比之下,递归保持了解决方案的简单性,因为递归深度会随着范围数量的增加而自然增加。函数无需重写;它可以处理任意数量的输入范围,只需调整递归深度即可。 动态输入:由于递归不依赖于显式定义的循环,因此它可以适应运行时动态确定范围数量的情况。此属性在输入数据未提前固定的场景中很重要,例如处理用户提供的数据或配置时。 2. 回溯效率 内存效率:回溯确保探索每个组合,而不会不必要地保留不再属于当前组合的元素。一旦算法探索了一条路径,它就会立即通过从当前组合中删除最近的方面来回溯。这确保算法不会存储冗余或不必要的数据。 有效探索:回溯是一项强大的技术,因为它能够系统地探索所有可能性而无需重复工作。通过“撤销”先前的选择并探索替代路径,递归方法可以有效地生成所有可能的组合,而无需将所有组合都存储在内存中。 3. 动态范围处理 适应动态输入:与需要程序员定义需要多少循环的硬编码循环不同,递归可以适应动态输入大小。您可以轻松修改输入范围的数量(或其内容),而无需更改 函数 的核心逻辑。这使得解决方案高度适应输入可能频繁更改的场景,例如在用户可配置软件中。 处理任意数据:递归可以处理不仅大小不同,内容也可能不同的范围(例如 字符串、对象 或其他 数据类型)。您可以插入不同类型的范围而无需修改算法,这使得该方法对于各种应用程序都非常通用,例如在不同域中生成所有可能的配置或组合。 |
在本文中,我们将通过不同的例子讨论 C++ 中的波动数。什么是波动数?“波动数”是指数字交替递增和递减的整数。例如,数字 131 在递增、递减和递增的序列中交替,这使其成为波动数……
5 分钟阅读
引言 技术数字是数学上探索的属性概念,通常在编程中用于解决特定的问题或挑战。术语本身在数学或计算机科学中不是标准概念,但它在编程竞赛中无处不在...
阅读 17 分钟
简介 C++17 库中添加了一个至关重要的函数“std::filesystem::is_regular_file()”,它为程序员提供了一种简单的方法来确定给定的路径是否指向文件系统中的一个常规文件。与传统的处理文件相比,此函数提供了更丰富的功能和用户友好的替代方案...
阅读 4 分钟
Solovay-Strassen 素数测试是一种概率算法,用于确定给定的数字是素数还是合数。与保证素性但对于大数字来说计算成本高昂的埃拉托斯特尼筛法等确定性方法不同,Solovay-Strassen 平衡了效率和准确性。该算法的核心是...
阅读 4 分钟
算法问题解决中的一个基本问题是“超越者计数”,它衡量数组元素的相对顺序。它计算数组中每个元素右侧严格大于该元素的元素数量。它...
阅读 16 分钟
在本文中,我们将使用其算法和实现讨论如何在 C++ 中根据给定条件恢复打乱的队列。问题陈述:考虑两个数组 A[] 和 B[],以及 N 个排队等候的个人。个人姓名由数组 A[] 表示...
阅读 6 分钟
“连接木棍的最小成本”问题是一个常见的算法任务,其中必须将多个木棍元素合并成一根,成本等于连接的两个木棍长度之和。目标是降低总体成本... ...
11 分钟阅读
在本文中,您将通过几个示例了解如何使用 C++ 中的 DSU 检测图中的循环。图:图是由节点(顶点)和连接节点对的边组成的集合。图可以是定向的或非定向的,并且可以分配权重……
阅读20分钟
算法竞赛中的常见问题大多与“硬币堆”问题有关。本文提供了一种数学观察和高效算法的方法。让我们详细了解如何解决它。问题陈述:您有两个硬币堆 A 和 B,其中 A 和 B...
阅读 4 分钟
在本文中,我们将讨论其属性、示例、优点和缺点。什么是? Gijswijt's Sequence 实际上是一个数字序列,可以根据字符串中的各种项进行读取。它基于对数字的计数来简洁地定义...
5 分钟阅读
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India