这可能不是正确的词,所以如果有人能告诉我实际调用这种数据类型,那将是值得赞赏的。
我有一个编程任务,我必须将哈希映射实现为一个预告链接列表数组,由教授宣布。
LN** map = nullptr;
数组的每个索引都应该从单独的预告片节点开始,这就是我遇到问题的地方。每当我尝试加倍数组的长度时,代码会以某种方式将一定数量的预告片节点等于索引零处的数组长度。在我做了一堆插入后,哈希映射通常看起来像这样。
// # Represents nullptr
// pair[,] is a trailer.
map m = bin[0]: pair[,] -> pair[,] -> pair[,] -> pair[,] -> pair[,] -> pair[,] -> pair[,] -> pair[,] -> #
bin[1]: pair[Shirley,Peanutbuttercup] -> pair[,] -> #
bin[2]: pair[Nicholas,Kafka] -> pair[,] -> #
bin[3]: pair[,] -> #
bin[4]: pair[Sora,Phammyy] -> pair[,] -> #
bin[5]: pair[Selv,Anthony] -> pair[,] -> #
bin[6]: pair[,] -> #
bin[7]: pair[,] -> #
这很奇怪,考虑到我将代码加倍的代码是。
bins *= 2;
map = new LN*[bins];
for (int i=0; i<bins; i++) {
map[i] = new LN();
}
while (!q.empty()) {
Entry e = q.dequeue();
int hash = hash_compress(e.first);
map[hash] = new LN(e, map[hash]);
}
我不希望任何人能够调试我的代码(虽然很可能有人可以,这会很棒)但我很感激,如果有人能详细解释这种数据类型,那么我可以有一个更好地解决了我搞砸的问题。
LN定义为
private:
class LN {
public:
LN () : next(nullptr){}
LN (const LN& ln) : value(ln.value), next(ln.next){}
LN (Entry v, LN* n = nullptr) : value(v), next(n){}
Entry value; // typedef ics::pair<KEY,T> Entry; declared earlier
LN* next;
};
答案 0 :(得分:2)
如果您想保留“预告片”节点的教授概念,以下代码将执行此操作。我建议强烈反对“预告片”节点的想法,因为它为你购买了 nothing ,只是让列表管理变得更加乏味。你的教授基本上是在告诉你把一些东西放在假设的中作为碰撞列表,但是你投入的东西永远不会与任何东西相撞。 NULL是一个很好的列表结尾标记,我建议你改用它。
我认为最重要的缺失是在构建新地图时,从旧地图中添加不来计算预告片节点。我相信他们都映射到插槽零,你盲目地将它们放入你的新地图。换句话说,在重新划分碰撞列表时,您并没有忽略无用的预告片节点。
下面的代码与您要获得的代码一样高效,不需要中间队列,没有节点复制,只需要重新移动移动的现有节点(他们的指针)到新表:
// double the size of the hash table.
unsigned int old_bin = bin;
bin *= 2;
LN** new_map = new LN*[bin]();
// load new set of trailers into new map
for (unsigned int i=0; i<bin; ++i)
new_map[i] = new LN();
// walk the old table (0..old_bin-1) rehashing and
// moving existing nodes to new slots in the hash table.
for (unsigned int i=0; i<old_bin; ++i)
{
// without the "trailer node", this should just be (map[i])
while (map[i]->next)
{
// pull node from old collision list at i
LN *p = map[i];
map[i] = p->next;
// rehash to new table based on new table size
unsigned int idx = hash_compress(p->value.first);
p->next = new_map[idx];
new_map[idx] = p;
}
// delete trailer node (better be the last one)
delete map[i];
}
delete [] map;
map = new_map;
多数民众赞成。这将是相当更清洁,没有所有的拖车节点精神错乱,但你可以把你的教授。如果您使用NULL作为冲突结束列表标记而不是某些虚构的预告片节点,则将近一半的代码将消失。我很尊重你的教授为什么他认为在碰撞列表中放置任何不是碰撞的是个好主意(因为它不是)。
答案 1 :(得分:0)
int hash = hash_compress(e.first);
你得到很多哈希值为0.你检查空输入吗?如果总是认为散列有效,那么如何区分有效输入和无效输入。
如桌子所示。
map m = bin[0]: pair[,] -> pair[,] -> pair[,] -> pair[,] -> pair[,] -> pair[,] -> pair[,]
您的代码
map[hash] = new LN(e, map[hash]);
正在生成这些,因为e是空的,因此哈希值总是为0.否则它们会在那里结束呢?
编辑:因此,空条目是用作输入的预先存在的“预告片”......