如何为大量数据生成hashmap

How to generate a hashmap for huge chunk of data?

本文关键字:hashmap 数据      更新时间:2023-10-16

我想创建一个映射,使一组指针指向动态大小的数组。我确实使用了哈希和链。但由于我使用它的数据是巨大的,程序在几次迭代后给出std::bad_alloc。其原因可能是new用于生成链表。

有人建议我应该使用哪种数据结构吗?或者其他可以改善哈希表内存使用的方法?

程序是c++编写的。

这是我的代码看起来像:初始化哈希表:

class Link
{ 
  public:
         double iData; 
         Link* pNext; 
         Link(double it) : iData(it) 
         { }
         void displayLink()
         { cout << iData << " "; }
}; 
class List
 {
  private:
          Link* pFirst; 
  public:
         List() 
         { pFirst = NULL; }
         void insert(double key) 
         {
           if(pFirst==NULL)
           pFirst = new Link(key);
       else
          {
        Link* pLink = new Link(key);
        pLink->pNext = pFirst;
        pFirst = pLink;
       }
         }     
 }; 
class HashTable
{      
  public:
         int arraySize;
         vector<List*> hashArray; 
         HashTable(int size) 
         {
            hashArray.resize(size); 
            for(int j=0; j<size; j++) 
            hashArray[j] = new List; 
         }
};

主要代码片段:

int t_sample = 1000;
 for(int i=0; i < k; i++)                                // initialize random position
{
        x[i] = (cal_rand() * dom_sizex);   //dom_sizex = 20e-10  cal_rand() generates rand no between 0 and 1
        y[i] = (cal_rand() * dom_sizey);    //dom_sizey = 10e-10
}
for(int t=0; t < t_sample; t++)
{
 int size;
 size = cell_nox * cell_noy; //size of hash table cell_nox = 212, cell_noy = 424
 HashTable theHashTable(size); //make table
 int hashValue = 0;
 for(int n=0; n<k; n++)   // k = 10*212*424
 {
  int m = x[n] /cell_width;     //cell_width = 4.7e-8
  int l = y[n] / cell_width;
   hashValue = (kx*l)+m;
   theHashTable.hashArray[hashValue]->insert(n); 
  }
   -------
   -------
 }

首先,使用标准容器。在您的特定情况下,您可能需要:

  • std::unordered_multimap<int, double>
  • std::unordered_map<int, std::vector<double>>

(注意:如果你没有c++ 11,可以在Boost中使用)

你的主循环变成(使用第二个选项):

typedef std::unordered_map<int, std::vector<double>> HashTable;
for(int t = 0; t < t_sample; ++t)
{
    size_t const size = cell_nox * cell_noy;
       // size of hash table cell_nox = 212, cell_noy = 424
    HashTable theHashTable;
    theHashTable.reserve(size);
    for (int n = 0; n < k; ++n)   // k = 10*212*424
    {
        int m = x[n] / cell_width;     //cell_width = 4.7e-8
        int l = y[n] / cell_width;
        int const cellId = (kx*l)+m;
        theHashTable[cellId].push_back(n);
    }
}

这将不会泄漏内存(可靠地),尽管当然您可能有其他泄漏,因此将为您提供可靠的基线。它也可能比你的方法更快,有一个更方便的界面,等等。

一般来说,你不应该重新发明轮子,除非你有一个特定的需要,而现有的轮子不能满足你的需求,或者你实际上是在学习如何创造一个轮子,或者创造一个更好的轮子。

操作系统必须解决与内存页面相同的问题,也许值得看看这是如何完成的?首先,让我们假设所有页面都在磁盘上。页是固定大小的内存块。对于您的用例,假设它是记录的数组。因为RAM是有限的,所以操作系统维护一个页码和它在RAM中的位置之间的映射。

那么,假设您的页面有1000条记录,并且您想访问记录2024,您将向操作系统请求第2页,并从该页读取记录24。这样,你的地图大小只有1/1000。

现在,如果您的页面没有映射到内存位置,那么它要么在磁盘上,要么以前从未被访问过(为空)。然后您需要换出另一个页面,并从磁盘加载该页(并更新位置映射)。

这是对发生的事情的一个非常简单的描述,如果有人这样描述我,我不会感到惊讶。

关键是:

这对你意味着什么?

首先,你的数据超过了你的RAM——如果你不想先尝试压缩,你就无法避免写入磁盘。其次,如果您愿意,您的链可以作为页面工作,但我想知道仅仅分页您的哈希码是否会更好。我的意思是,使用上面的位作为页码,下面的位作为页面中的偏移量。避免冲突仍然是关键,因为您希望加载尽可能少的页面。您仍然可以链接页面,最终得到一个小得多的地图。第二,最关键的部分是决定要换掉哪些页面来为新页面腾出空间。LRU应该没问题。如果您能更好地预测哪些页面需要(不需要),那就更好了。第三,你需要页面占位符来告诉你它们是在内存中还是在磁盘上。