C++ 如何使使用线性探测的哈希表更有效?

C++ 如何使使用线性探测的哈希表更有效?,c++,hash,memory-efficient,C++,Hash,Memory Efficient,我正在尝试实现一个高效的哈希表,其中使用带步长的线性探测来解决冲突。该功能必须尽可能高效。没有不必要的=或=操作。我的代码运行正常,但效率不高。这种效率由公司内部系统进行评估。它需要更好 有两个类表示键/值对:CKey和CValue。这些类都有一个标准构造函数、复制构造函数和重写运算符=和=。它们都包含一个返回内部私有变量值的getValue()方法。CKey中还有方法getHashLPS(),它返回哈希表中的哈希位置 int getHashLPS(int tableSize,int step,

我正在尝试实现一个高效的哈希表,其中使用带步长的线性探测来解决冲突。该功能必须尽可能高效。没有不必要的
=
=
操作。我的代码运行正常,但效率不高。这种效率由公司内部系统进行评估。它需要更好

有两个类表示键/值对:
CKey
CValue
。这些类都有一个标准构造函数、复制构造函数和重写运算符
=
=
。它们都包含一个返回内部私有变量值的
getValue()
方法。
CKey
中还有方法
getHashLPS()
,它返回哈希表中的哈希位置

int getHashLPS(int tableSize,int step, int collision) const
{
    return ((value + (i*step)) % tableSize);
}
class CTable
{
    struct CItem {
            CKey key;
            CValue value;
        };
    CItem **table;
    int valueCounter;       
}
哈希表

int getHashLPS(int tableSize,int step, int collision) const
{
    return ((value + (i*step)) % tableSize);
}
class CTable
{
    struct CItem {
            CKey key;
            CValue value;
        };
    CItem **table;
    int valueCounter;       
}
方法

// return collisions count
int insert(const CKey& key, const CValue& val)
{
    int position, collision = 0;

    while(true)
    {
        position = key.getHashLPS(tableSize, step, collision); // get position
        if(table[position] == NULL) // free space
        {
            table[position] = new CItem; // save item
            table[position]->key = CKey(key);
            table[position]->value = CValue(val);
            valueCounter++;
            break;
        }

        if(table[position]->key == key) // same keys => overwrite value
        {
            table[position]->value = val;
            break;
        }

        collision++; // current positions is full, try another

        if(collision >= tableSize) // full table
            return -1;
    }

    return collision;
}

// return collisions count
int remove(const CKey& key)
{
    int position, collision = 0;

    while(true)
    {
        position = key.getHashLPS(tableSize, step, collision);
        if(table[position] == NULL) // free position - key isn't in table or is unreachable bacause of wrong rehashing
            return -1;

        if(table[position]->key == key) // found
        {
            table[position] = NULL; // remove it
            valueCounter--;

            int newPosition, collisionRehash = 0;
            for(int i = 0; i < tableSize; i++, collisionRehash = 0) // rehash table
            {
                if(table[i] != NULL) // if there is a item, rehash it
                {
                    while(true)
                    {
                        newPosition = table[i]->key.getHashLPS(tableSize, step, collisionRehash++);
                        if(newPosition == i) // same position like before
                            break;

                        if(table[newPosition] == NULL) // new position and there is a free space
                        {
                            table[newPosition] = table[i]; // copy from old, insert to new
                            table[i] = NULL; // remove from old
                            break;
                        }
                    }
                }
            }

            break;
        }

        collision++; // there is some item on newPosition, let's count another

        if(collision >= valueCounter) // item isn't in table
            return -1;
    }

    return collision;
}
//返回冲突计数
插入整数(常数和键、常数和值)
{
int位置,碰撞=0;
while(true)
{
position=key.getHashLPS(表大小、步长、冲突);//获取位置
if(table[position]==NULL)//可用空间
{
表[position]=新建CItem;//保存项
表[position]->key=CKey(键);
表[位置]->值=CValue(val);
valueCounter++;
打破
}
if(表[position]->key==key)//相同的key=>覆盖值
{
表[position]->值=val;
打破
}
碰撞+++;//当前位置已满,请尝试其他位置
if(冲突>=表大小)//满表
返回-1;
}
返回碰撞;
}
//返回冲突计数
int移除(常数和键)
{
int位置,碰撞=0;
while(true)
{
position=key.getHashLPS(表大小、步长、冲突);
if(table[position]==NULL)//自由位置-键不在表中或由于错误的重新灰化而无法访问
返回-1;
如果(表[position]->key==key)//找到
{
表[position]=NULL;//删除它
值计数器--;
int newPosition,collisionRehash=0;
for(inti=0;ikey.getHashLPS(tableSize,step,collisionRehash++);
if(newPosition==i)//像以前一样的位置
打破
if(table[newPosition]==NULL)//新位置且存在可用空间
{
表[newPosition]=表[i];//从旧复制,插入到新
表[i]=NULL;//从旧表中删除
打破
}
}
}
}
打破
}
collision++;//newPosition上有一些项目,让我们再数一个
如果(冲突>=valueCounter)//项不在表中
返回-1;
}
返回碰撞;
}
这两个函数都返回冲突计数(出于我自己的目的),当搜索的
CKey
不在表中或表已满时,它们返回
-1


墓碑是禁止的。移除后重新灰化是必须的。

我看到的最大改进是移除功能。你不需要把整张桌子重新刷一遍。您只需要从移除点开始重新灰化,直到到达空桶为止。此外,在重新散列时,请在重新散列之前删除并存储所有需要重新散列的项,以便在将它们放回时不会妨碍它们

还有一件事。对于所有哈希,提高效率的最快方法是降低loadFactor(元素与支持数组大小的比率)。这减少了碰撞的数量,这意味着减少了寻找开放点的迭代,并减少了移除时的重新灰化。在极限情况下,当加载因子接近0时,碰撞概率接近0,它变得越来越像一个数组。当然,内存的使用会增加

更新
您只需要从移除点开始重新刷新,然后按步长前进,直到达到空值。原因是这些是唯一可能因移除而改变其位置的对象。所有其他对象都会到达完全相同的位置,因为它们不属于同一个“碰撞运行”

一个可能的改进是预先分配一个citem数组,这样可以避免malloc()s/news和free()删除;您需要将数组更改为“CItem*table;”


但同样:你想要的基本上是在一辆方轮汽车上平稳行驶。

“高效线性探测哈希表”有点像“高效泡泡排序”。你要求海报女郎提供效率低下的算法。如果你关心效率,那就换一种方式。我知道,但这是一项任务,所以我必须去做。采用高效的算法很容易,但不容易很好地实现低效的算法;每个表上只提供一个免费列表。正如其他人所说,随着频繁的删除和插入,线性探测可能不是最佳选择@安德鲁:家庭作业?@wildplasser。关键不在于选择最佳解决方案,而是使用它并尽可能地解决它。你能告诉我,为什么从移除的位置重新灰化就足够了,而不是重新灰化所有的“桶”?@Andrew我编辑了回复。基本上,你只需要重新灰化任何可能会倒下的东西,以填补移除时留下的洞。其他的一切都会回到原来的样子是的,我