为什么 unordered_map 的执行速度比 look-ups 的二维向量慢 100 倍?

Why does the unordered_map perform about 100 times slower than a 2d vector for look-ups?

6 4 //重量,物品数量 3 4 2 3 4 2 4 3

最优解是8。

Download Link for Large dataset (1000 items)

Download Link for Medium dataset (100 items)

Download Link for Source Code

//代码如下:

//Headers,宏和全局变量:

#include<iostream>
#include<vector>
#include<algorithm>
#include<fstream>
#include<string>
#include<sstream>
#include<unordered_map>
#include<boost/functional/hash.hpp>
using namespace std;

typedef vector< vector<long long> > vii;
typedef vector< pair<int,int> > vp;
typedef pair<int,int> myPair;
typedef unordered_map< myPair, long long, boost::hash<myPair> > myMap;

vp elmnts;
//vii arr2d;
myMap arr;

//背包函数:

long long knapsack(int n, int w)
{
//arr2d.resize(n+1, vector<long long>(w+1));
int vi,wi;

for(int j=0; j<=w; ++j)
//  arr2d[0][j] = 0;
    arr.emplace(make_pair(0,j), 0);

for(int i=1; i<=n; ++i)
{
    vi = elmnts[i-1].first;
    wi = elmnts[i-1].second;

    for(int j=0; j<=w; ++j)
    //  arr2d[i][j] = (wi > j) ? arr2d[i-1][j] : max(arr2d[i-1][j], arr2d[i-1][j-wi] + vi);
        arr.emplace(make_pair(i,j), (wi > j) ? arr[make_pair(i-1,j)] : max(arr[make_pair(i-1,j)], arr[make_pair(i-1,j-wi)]+ vi));
}

//return arr2d[n][w];
return arr[make_pair(n,w)];
}

//主要功能

int main()
{
ifstream file("/home/tauseef/Desktop/DAA2/knapsack1.txt");
int n,w;
string line;
pair<int,int> elmnt;

getline(file, line);
stringstream ss(line);
ss >> w;
ss >> n;

while(getline(file, line))
{
    stringstream ss1(line);
    ss1 >> elmnt.first;
    ss1 >> elmnt.second;
    elmnts.push_back(elmnt);
}

cout<<"\nThe optimal solution is: "<<knapsack(n,w)<<endl;
file.close();
}

没想到差别这么大:在我的机器上数组版本比hash_map版本快100倍。但是转念一想...

你应该预料到地图会更慢 - 有很多开销:调用 make_pair,创建对象对,计算哈希,在地图中搜索它,构造 return 值,来回复制对象与仅查找值相反!

另一方面,您根本不会从切换到地图中获利,因为最后,正如现在编码的那样,您在你的地图在数组中。如果您从地图中遗漏一些元素,但您没有这样做,那么您的更改是有意义的。

但是您的代码中更大的问题是您使用维基百科中的伪多项式算法,它需要 O(n*W) 内存。这意味着您将需要 32GB 内存用于更大的测试用例,这可能意味着要用硬盘交换内存,具体取决于您的系统有多大并且变得非常慢。

解决方案是采用需要O(W)内存的算法版本:

long long knapsack(const vector<myPair> &objects, int W)
{
    vector<long long> bests(W+1, -1L);//-1 = this value is not reachable
    //the only possible configuration at start: an empty set, value is also 0
    bests[0]=0;


    for(const myPair &object:objects){//try out all objects
        int v = object.first;
        int w = object.second;
        //update all possible configurations:
        for(int cur=W;cur>=0;--cur){//backwards->object at most once in every configuration!
          int next=cur+w;
          if(bests[cur]!=-1 && next<=W)//consider only reachable configurations and discard too big weights
            bests[next]=std::max(bests[next], bests[cur]+v);
       }
    }

    return *max_element(bests.begin(), bests.end());
}

最重要的部分是我们向后遍历可能的配置,因此可以就地更新配置(更新的配置是在当前扫描中已经进行的配置)。

我想这个版本对于更大的情况应该需要不到 1 分钟的时间(考虑到输入有多大,这是相当合理的)。我不保证这没有错误,但希望你能理解它的要点。