部分排列

2024-01-07

我有以下递归函数用于输出部分组合:

void comb(string sofar, string rest, int n) {

    string substring;

    if (n == 0)
        cout << sofar << endl;
    else {
        for (size_t i = 0; i < rest.length(); i++) {
            substring = rest.substr(i + 1, rest.length());
            comb(sofar + rest[i], substring, n - 1);
        }
    }
}

像这样调用:

comb("", "abcde", 3);

通过部分组合,我的意思是它使用 n 个选择和 r 个元素(而不是 n 个选择、n 个元素)。

但是,我想考虑元素的顺序(即排列)。我可以找到许多完整排列的算法,但不是部分排列。


现在是进行性能现实检查的时候了。如果您只对一次访问 5 件事 3 的排列感兴趣,请立即停止阅读,因为访问次数太少了,这并不重要(除非您可能已经这样做了十亿次)。

但如果您需要访问更多的东西,并且一次访问更多的东西,性能就真的开始变得重要了。例如,访问 26 个字符串:“abcdefghijklmnopqrstuvwxyz”,一次六个项目怎么样?随着排列,成本增长得非常快......

对于性能测试,最好注释掉终端的输出,因为这往往是一个非常慢的操作,会淹没其他所有内容。

这个答案 https://stackoverflow.com/a/34867494/576911(目前接受的)看起来像这样:

#include <chrono>
#include <iostream>
#include <string>

using std::string;
using std::cout;

void comb(string sofar, string rest, int n)
{
    // std::cout << "comb('" << sofar << "', '" << rest << "', " << n << ")\n";
    string substring;

    if (n == 0)
        ; //cout << sofar << '\n';
    else {
        for (size_t i = 0; i < rest.length(); i++) {
            substring = rest.substr(0, i) + rest.substr(i + 1, rest.length());
            comb(sofar + rest[i], substring, n - 1);
        }
    }
}

int main()
{
    std::string s("abcdefghijklmnopqrstuvwxyz");
    auto t0 = std::chrono::steady_clock::now();
    comb("",s, 6);
    auto t1 = std::chrono::steady_clock::now();
    std::cout << std::chrono::duration<double>{t1-t0}.count() << '\n';
}

在我的系统上(clang++ -std=c++14 test.cpp -O3)输出:

14.2002

这个答案使用std::next_permutation https://stackoverflow.com/a/34868103/576911明显更快。

#include <algorithm>
#include <chrono>
#include <iostream>

// Requires: sequence from begin to end is sorted
//           middle is between begin and end
template<typename Bidi, typename Functor>
void for_each_permuted_combination(Bidi begin,
                                   Bidi middle,
                                   Bidi end,
                                   Functor func) {
  do {
    func(begin, middle);
    std::reverse(middle, end);
  } while (std::next_permutation(begin, end));
}

int
main()
{
    std::string s("abcdefghijklmnopqrstuvwxyz");
    auto t0 = std::chrono::steady_clock::now();
    for_each_permuted_combination(s.begin(), s.begin()+6, s.end(),
        [](auto first, auto last)
        {
//             for (; first != last; ++first)
//                 std::cout << *first;
//             std::cout << '\n';
        });
    auto t1 = std::chrono::steady_clock::now();
    std::cout << std::chrono::duration<double>{t1-t0}.count() << '\n';
}

其输出:

8.39237

这快了 69%!这种速度的提高很大程度上可以归因于第一个算法中隐含的分配和释放的缺乏。

不过我想指出更快的算法 http://howardhinnant.github.io/combinations.html.

驱动程序看起来像:

#include "combinations"
#include <chrono>
#include <iostream>
#include <string>

int
main()
{
    std::string s("abcdefghijklmnopqrstuvwxyz");
    auto t0 = std::chrono::steady_clock::now();
    for_each_permutation(s.begin(), s.begin()+6, s.end(),
        [](auto first, auto last)
        {
//             for (; first != last; ++first)
//                 std::cout << *first;
//             std::cout << '\n';
            return false;
        });
    auto t1 = std::chrono::steady_clock::now();
    std::cout << std::chrono::duration<double>{t1-t0}.count() << '\n';
}

输出是:

0.2742

This is 快 30 倍 than 答案使用std::next_permutation https://stackoverflow.com/a/34868103/576911 and 快 51 倍 than 目前接受的答案 https://stackoverflow.com/a/34867494/576911!并作为n and r随着增长,这些性能数字的差异也会增大。

The 链接库 http://howardhinnant.github.io/combinations.html是免费且开源的。实现位于链接处,可以从中复制/粘贴。我不会说这很简单。我只是声称它的性能令人信服。性能差异是如此巨大,以至于它可以决定问题能否在实际时间内得到解决。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

部分排列 的相关文章

随机推荐

  • Maven 程序集插件模块集源指令不包含任何文件并且与包含的模块不匹配

    我有一个多模块 Maven 项目 我正在尝试让程序集插件的模块集源部分正常工作 我有模块 模块父模块 module a and 模块组件 module a and 模块组件是的孩子模块父模块 模块组件已声明 pom 依赖项module a
  • 如何从 vcpkg 检索 cmake 目标名称?

    安装软件包后 vcppkg 非常有帮助地显示相关的 CMake 目标 libwebp x64 windows 包提供了 CMake 目标 find package WebP CONFIG REQUIRED target link libra
  • 相当于hadoop中mongo的out:reduce选项

    我正在重写 MongoDB 映射缩减作业以使用 Hadoop 使用 mongo hadoop 连接器 但是当我将两个数据集映射到同一个集合时 它会覆盖这些值而不是使用它们 reduce collectionName 如果结果集中和旧集合中存
  • 在 R 中制作分区统计图:合并来自多个州的邮政编码形状文件

    受到这里帖子的激励 使用 R 开发地理专题图 https stackoverflow com questions 1260965 developing geographic thematic maps with r 我正在考虑构建基于邮政编
  • 从 ActiveRecord/Rails 查询中检索单个记录

    我发出如下查询 精确检索 0 或 1 条记录 car Car where vin 1234567890abcdefg 返回的当然是长度为 1 的汽车列表 所以我最终添加 first在查询末尾 car Car where vin 123456
  • 在 UITabBarController 上的选项卡之间共享背景视图

    是否可以在 UITabBarController 上的选项卡之间具有相同的背景 而不必在所有视图上设置相同的背景 我想在后台放置一个视图 定期执行非常短的非资源密集型动画 切换选项卡时 我希望该动画能够持续存在 我已经阅读了如何为 UINa
  • JavaScript 中的节点是什么?

    我想知道 JavaScript 中的节点到底是什么 如函数中所示 element nodeType row parentNode removeChild row 在这种情况下 节点 只是一个 HTML 元素 DOM 是代表网站 HTML 的
  • Fiware Ultralight 2.0 IoTAgent:如何从设备发送测量?

    我正在研究一个 POC 使用 Fiware 平台创建智能城市物联网项目 我正在尝试运行端到端流程 我正在运行以下 Docker 容器 容器 ID 端口名称 24f036202f78 0 0 0 0 4041 gt 4041 tcp 0 0
  • 如何为自定义 Java 标记添加 Eclipse 快速修复?

    我想向 Eclipse 的问题视图报告 Java 文件的自定义问题并为它们提供快速修复 标准方法是使用扩展点org eclipse core resources markers声明自定义标记并通过调用添加标记org eclipse core
  • 在 VS 设计器中加载包时禁用 SSIS 包验证

    我有一些部署到 SQL 2005 Server 的 SSIS 包 随后在 Visual Studio 2003 中设计和维护 当我打开任何 BIDS 项目以及其中一个包时 设计器总是验证每个数据流和任务目的 通常 这不是问题 但是 在某些情
  • Jasmine单元测试observable订阅不触发

    我将 Angular 5 与 Jasmine 和 Karma 一起使用 我正在尝试测试某个功能是否有效 但我的订阅在单元测试期间没有触发 这导致我的单元测试失败 因为我正在使用 jasmine 的 did 函数 我想让这个单元测试成功 我已
  • Tomcat 中的 NIO 连接器

    我试图通过配置 server xml 文件在 Tomcat 6 0 中启用 NIO 连接器 但我得到Firefox 无法与位于 localhost 8081 的服务器建立连接 每当我输入时在浏览器中本地主机 8081 这就是我在 Tomca
  • DataGridTextColumn - 如何绑定IsReadonly?

    在 Silverlight 4 中 DataGridTextColumn 的 IsReadOnly 属性似乎不是依赖属性 因此我无法将它绑定到视图模型上的属性 似乎唯一的选择是使用 DataTemplate 但即使在这里我也面临两个主要问题
  • 用循环填充矩阵

    我正在尝试创建一个矩阵n by k with kmvn 使用循环进行协变量 非常简单 但到目前为止还没有工作 这是我的代码 n 1000 k 5 p 100 mu 0 sigma 1 x matrix data NA nrow n ncol
  • 如何在 laravel eloquent 中添加两列值并执行 where 条件

    这是我的桌子 id remaining amount additional amount 1 200 0 2 100 100 3 300 100 4 200 50 我正在尝试获取总和为剩余数量 额外金额 gt 0 result this g
  • 响应 SwiftUI 中的按键事件

    我想响应按键 例如esc键在 macOS OSX 上 以及在 iPad 上使用外部键盘时 我怎样才能做到这一点 我想过用 available available与 SwiftUI 的onExitCommand https developer
  • 一行中没有所有 True 值的布尔数组

    I have numpy array np random seed 100 mask np random choice True False size 10 3 print mask True True False False False
  • 如何在 git url 的用户名或密码中转义“@”

    在命令行上推送到 git 的格式之一是 Url format https username password github com owner repo 我的挑战是用户名和密码 这是我无法控制的共享帐户 包含 在他们里面 实际上都是 在这种
  • Spring-Boot Jersey:允许 Jersey 提供静态内容

    该应用程序使用 JDK 8 Spring Boot 和 Spring Boot Jersey 启动器 并打包为 WAR 尽管它是通过 Spring Boot Maven 插件在本地运行 我想做的是将我动态 在构建时 生成的文档作为欢迎页面
  • 部分排列

    我有以下递归函数用于输出部分组合 void comb string sofar string rest int n string substring if n 0 cout lt lt sofar lt lt endl else for s