C ++无序设置内存不足

时间:2014-03-04 22:39:28

标签: c++ algorithm memory-management for-loop

该程序遍历1到400的4个数字的每个组合,并查看可以从产品中生成多少个唯一数字。 我相信用于保存已经检查过的数字的unordered_set变得过大,因此它会退出;任务经理告诉我它是1.5 GB。

有什么方法可以让这段代码运行?我想可能会拆分该组或以某种方式找到更有效的公式。

注意:根据评论,我想再说一遍,我没有存储所有250亿个数字。我只存储~100,000,000个号码。问题的RANGE为400,但我正在寻找一个可以处理500甚至1000而没有内存问题的综合解决方案。

#include <iostream>
#include <unordered_set>
using namespace std;

const int RANGE = 400;

int main(){

    unordered_set<long long> nums;

    for(long long a=1; a<=RANGE; a++)
    {
        for(long long b=a; b<=RANGE; b++)
        {
            for(long long c=b; c<=RANGE; c++)
            {
                for(long long d=c; d<=RANGE; d++)
                {
                    unordered_set<long long>::const_iterator got = nums.find(a*b*c*d);
                    if (got == nums.end())
                    {
                        nums.insert(a*b*c*d);
                    }
                }
            }
        }
        cout << a << endl;
    }

    cout << nums.size() << endl;

    return 0;
}

2 个答案:

答案 0 :(得分:5)

您需要使用64位编译器编译代码,以允许分配超过大约2GB的内存。你在运行它的机器上还需要至少4GB的RAM,或者最多需要几乎永远完成。

“bitset”,每个条目使用一位将占用大约3GB的内存。

使用现有的代码,它将在具有64位g ++编译器的Linux机器上使用大约4GB的内存,完成大约需要220秒,给出答案:

86102802
1152921504606846975

根据/ usr / bin / time -v:

Command being timed: "./a.out"
User time (seconds): 219.15
System time (seconds): 2.01
Percent of CPU this job got: 99%
Elapsed (wall clock) time (h:mm:ss or m:ss): 3:42.53
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 4069336
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 679924
Voluntary context switches: 1
Involuntary context switches: 23250
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0

答案 1 :(得分:2)

您的解决方案的工作原理是对1到400之间的四个数字进行每个唯一的排列,将它们相乘,然后存储结果,然后计算它们。在最小,这将需要400 * 400 * 400 * 400bits~3GB,这显然比您的硬件/编译器/操作系统可以处理的更多。 (可能是编译器,很容易修复)

那么,如果我们尝试一步一步地解决该计划呢?我们能算一下这些数字中有多少套产品的产品在1000到2000之间吗?

for(a=1; a<400; ++a)
{
    bmin = max(1000/a/400/400, a); //a*b*400*400 is at least 1000
    bmax = min(2000/a, 400);       //a*b*1*1 is at most 2000
    for(b=bmin; b<=bmax; b++)
    {
        cmin = max(1000/a/b/400, b);  //a*b*c*400 is at least 1000
        cmax = min(2000/a/b, 400);    //a*b*c*1 is at most 2000
        for(c=cmin; c<=cmax; c++)
        {
            dmin = max(1000/a/b/c, c);   //a*b*c*d is at least 1000
            dmax = min(2000/a/b/c, 400); //a*b*c*d is at most 2000
            for(d=dmin; d<=dmax; d++) //this will usually be zero, one, or two numbers
            {
                res = a*b*c*d;
                if (res>=1000 && res<2000) //a rare few WILL be outside this range
                    YES

我们可以简单地计算0-1000之间可以访问的产品数量,然后是1000-2000,然后是2000-3000等,最多400 * 400 * 400 * 400。这是一个显着速度慢的算法,但由于它占用的内存非常少,所以希望增加的缓存一致性将弥补一些差异。

事实上,说到内存非常少,因为每批中的目标数字总是在1000的连续范围内,那么你可以使用bool nums[1000] = {}而不是unordered_set,这应该给出重要的性能提升。

我的完整代码在这里:http://coliru.stacked-crooked.com/a/bc1739e972cb40f0,我已经确认我的代码与您的代码具有相同的结果。在修复了几个错误之后,对于使用MSVC2013的小RANGE,您的算法仍然远远超过我的算法。 (对于使用MSVC进行测试的其他人,请务必使用未附加的调试器进行测试,这会使原始代码的时序产生巨大差异)

origional(   4) found          25 in      0s
     duck(   4) found          25 in      0s
origional(   6) found          75 in      0s
     duck(   6) found          75 in      0s
origional(   9) found         225 in      0s
     duck(   9) found         225 in      0s
origional(  13) found         770 in      0s
     duck(  13) found         770 in      0s
origional(  17) found        1626 in  0.001s
     duck(  17) found        1626 in      0s
origional(  25) found        5135 in  0.004s
     duck(  25) found        5135 in  0.002s
origional(  35) found       14345 in  0.011s
     duck(  35) found       14345 in  0.015s
origional(  50) found       49076 in  0.042s
     duck(  50) found       49075 in  0.076s
origional(  71) found      168909 in  0.178s
     duck(  71) found      168909 in  0.738s
origional( 100) found      520841 in  0.839s
     duck( 100) found      520840 in  7.206s
origional( 141) found     1889918 in  5.072s
     duck( 141) found     1889918 in 76.028s

当我研究这个问题时,最终发生的事情是我的算法需要大量的64位分区,即使在64位操作系统中也是如此。