【发布时间】:2016-01-01 23:36:35
【问题描述】:
我已经声明并定义了以下 HashTable 类。请注意,我需要一个哈希表的哈希表,因此我的 HashEntry 结构包含一个 HashTable 指针。公共部分没什么大不了的,它有传统的哈希表函数,所以为了简单起见,我把它们去掉了。
enum Status{ACTIVE, DELETED, EMPTY};
enum Type{DNS_ENTRY, URL_ENTRY};
class HashTable{
private:
struct HashEntry{
std::string key;
Status current_status;
std::string ip;
int access_count;
Type entry_type;
HashTable *table;
HashEntry(
const std::string &k = std::string(),
Status s = EMPTY,
const std::string &u = std::string(),
const int &a = int(),
Type e = DNS_ENTRY,
HashTable *t = NULL
): key(k), current_status(s), ip(u), access_count(a), entry_type(e), table(t){}
};
std::vector<HashEntry> array;
int currentSize;
public:
HashTable(int size = 1181, int csz = 0): array(size), currentSize(csz){}
};
我正在使用二次探测,当我点击array.size()/2 时,我在我的 rehash 函数中将向量的大小加倍。当需要更大的表大小时使用以下列表。
int a[16] = {49663, 99907, 181031, 360461,...}
我的问题是这个类消耗了太多的内存。我刚刚用 massif 对其进行了分析,发现它需要 33MB(3300 万字节!)的内存来进行 125000 次插入。说清楚,其实
1 insertion -> 47352 Bytes
8 insertion -> 48376 Bytes
512 insertion -> 76.27KB
1000 insertion 2MB (array size increased to 49663 here)
27000 insertion-> 8MB (array size increased to 99907 here)
64000 insertion -> 16MB (array size increased to 181031 here)
125000 insertion-> 33MB (array size increased to 360461 here)
这些可能是不必要的,但我只是想向您展示内存使用情况如何随输入而变化。如您所见,重新散列完成后,内存使用量翻了一番。例如,我们的初始数组大小是 1181。而我们刚刚看到 125000 个元素 -> 33MB。
为了调试问题,我将初始大小更改为 360461。现在 127000 插入不需要重新散列。我看到这个初始值使用了 20MB 的内存。这仍然很大,但我认为这表明重新散列存在问题。以下是我的 rehash 函数。
void HashTable::rehash(){
std::vector<HashEntry> oldArray = array;
array.resize(nextprime(array.size()));
for(int j = 0; j < array.size(); j++){
array[j].current_status = EMPTY;
}
for(int i = 0; i < oldArray.size(); i++){
if(oldArray[i].current_status == ACTIVE){
insert(oldArray[i].key);
int pos = findPos(oldArray[i].key);
array[pos] = oldArray[i];
}
}
}
int nextprime(int arraysize){
int a[16] = {49663, 99907, 181031, 360461, 720703, 1400863, 2800519, 5600533, 11200031, 22000787, 44000027};
int i = 0;
while(arraysize >= a[i]){i++;}
return a[i];
}
这是用于重新散列和其他任何地方的插入函数。
bool HashTable::insert(const std::string &k){
int currentPos = findPos(k);
if(isActive(currentPos)){
return false;
}
array[currentPos] = HashEntry(k, ACTIVE);
if(++currentSize > array.size() / 2){
rehash();
}
return true;
}
我在这里做错了什么?即使它是由重新散列引起的,当没有重新散列时,它仍然是 20MB,我相信 20MB 对于 100k 个项目来说太多了。这个哈希表应该包含大约 800 万个元素。
【问题讨论】:
-
是否有理由为每个条目存储整个表?如果您可以发布将
HashTable分配给HashEntry的代码,这可能会有所帮助。 -
@Jason 哈希表的每个条目都可以在其条目中包含一个哈希表。除了这个自我参照的定义,我想不出其他任何东西。当然感谢您的帮助,但我不明白您将 HashTable 分配给 HashEntry 是什么意思。这些是不同的类,可以互相分配吗?
-
@Jason 在这些分析过程中我也没有任何嵌套的哈希表。它只是一个主哈希表,其 HashEntries 中的 HashTables 为 NULL。
-
@A.S.H 在这些分析期间,没有嵌套的哈希表。所以我什至没有碰它们,我只是调用了插入函数并得到了这些内存使用情况。
-
我猜“我们不允许”解释了您为什么不使用
std::unordered_map,这将是显而易见的解决方案。
标签: c++ data-structures hashtable