【问题标题】:Optimizing a nested loop in C优化 C 中的嵌套循环
【发布时间】:2017-01-09 05:02:39
【问题描述】:

我有一个嵌套循环来查找 1 和 x 之间的所有可能的数字组合,每组 4 个,其中 a

当发现每个组时调用一个方法来对这些数字的总和进行简单的等价测试。

该循环确实有效并产生了预期的输出(这个特定 x 的一组数字),但是需要 12 秒以上才能找到这个答案,另外需要大约 5 秒来测试剩余的可能性,考虑到 x,这绝对是不好的值为

我尝试让外部循环迭代 a

改变这个循环有什么更好的方法?

for (a = 1; a < x; a++) {
    for (b = a + 1; b < x; b++) {
        for (c = b + 1; c < x; c++) {
            for (d = c + 1; d < x; d++) {
                check(a, b, c, d);
            }
        }
    }
}

【问题讨论】:

  • 你认为你检查了多少种组合?您认为每次组合检查花费多少时间是合理的?
  • 你只是想计算每组四个数字的总和吗?我认为如果您对您在这里尝试做的事情进行更多解释,这可能会有所帮助。我想大部分优化机会都在check() 函数中,您在这里没有透露。
  • 整个循环应该在一秒钟内运行。至于组合,我在循环中放了一个打印语句,我相信我得到了任何给定 x 的正确数字。如果需要,我可以添加方法代码,但它会检查是否 a+b+c+d && a * b * c * d == x,如果为真则打印这些数字。
  • 您希望它在一秒钟内运行吗?如果 x 为 1000,则内部循环将迭代(999 次选择 4)次,除非我弄错了,否则超过 410 亿次。你需要一个非常快的处理器来做到这一点。
  • 如果您希望您的计算在 1 秒内运行,那么您很可能需要一种完全不同于枚举和测试每个可能组合的方法。

标签: c for-loop optimization


【解决方案1】:

有了如此深的嵌套,您可以引入的任何早期退出(尤其是在外部循环中)都可以获得巨大的收益。

例如,您写道 check 正在测试 a + b + c + d == x &amp;&amp; a * b * c * d == x - 这样您就可以计算中间的总和和乘积,并在遇到可能无法选择后续数字的数字时中断。

一个例子:

for (a = 1; a < x; a++) {
  for (b = a + 1; b < x; b++) {
    int sumAB = a + b;
    if (sumAB + sumAB > x) break;
    int prodAB = a * b;
    if (prodAB * prodAB > x) break;
    for (c = b + 1; c < x; c++) {
      int sumABC = sumAB + c;
      if (sumABC + c > x) break;
      int prodABC = prodAB * c;
      if (prodABC * c > x) break;
      for (d = c + 1; d < x; d++) {
        int sumABCD = sumABC + d;
        if (sumABCD > x) break;
        if (sumABCD != x) continue;
        int prodABCD = prodABC * d;
        if (prodABCD > x) break;
        if (prodABCD != x) continue;
        printf("%d, %d, %d, %d\n", a, b, c, d);
      }
    }
  }
}

这只是一个示例 - 您可以在此处进一步限制所有检查(例如,将第一个检查设为 sumAB + sumAB + 3 &gt; x)。重点是提前退出。

我为每个循环添加了一个计数器,计算它被输入了多少次,并尝试了你的版本和我的版本,x = 100。我的版本的循环条目少了几个数量级:

没有提前退出:99、4851、156849、3764376
提前退出:99、4851、1122、848

【讨论】:

  • 其实有6、7个数量级。
  • 顺便说一句,如果满足其中一个条件,您不应该continue,而是break,因为该分支中生成的所有后续总和和乘积将大于部分总和或乘积,因此树枝可以在那里修剪。 的运行速度快了一百万倍。美妙之处在于,修剪的好处会随着 x 增长(即最需要的时候),因为几乎所有的组合都太大了。
  • @Stargateur 你知道它应该为哪个 x 显示结果吗?我没有,这确实使测试变得困难。问题与perfect numbers 类似但不完全相同,我在网上找不到任何可能答案的参考。
  • @PeterA.Schneider 哎呀,你当然是对的,固定的。要求在最里面的循环中更详细一点。
  • 你内联了check() :-)。
猜你喜欢
  • 2013-05-30
  • 2015-05-29
  • 1970-01-01
  • 2020-08-28
  • 2021-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多