如何为大块数据生成hashmap?

时间:2014-06-16 06:23:19

标签: c++ data-structures hashtable

我想制作一个地图,使得一组指针指向动态大小的数组。 我确实使用哈希与链接。但是,由于我使用的数据非常庞大,因此程序在几次迭代后会给出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); 

  }

   -------
   -------
 }

2 个答案:

答案 0 :(得分:2)

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

  • 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);
    }
}

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

一般情况下,你不应该重新发明轮子,除非你有一个特定的需求没有通过可用的轮子解决,或者你实际上正在尝试学习如何创建一个轮子或创建一个更好的轮子。

答案 1 :(得分:0)

操作系统必须解决与内存页面相同的问题,或许值得一看,如何做到这一点?首先,让我们假设所有页面都在磁盘上。页面是固定大小的内存块。对于您的用例,让我们说它是您的记录数组。由于RAM有限,操作系统会在页码和它在RAM中的位置之间保持映射。

因此,假设您的页面有1000条记录,并且您想要访问记录2024,您可以向OS请求第2页,并从该页面读取记录24。这样,你的地图只有1/1000。

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

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

重点是:

这对你意味着什么?

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

希望这有帮助。

相关问题