【问题标题】:Is something wrong with my hash function我的哈希函数有问题吗
【发布时间】:2014-11-28 20:11:52
【问题描述】:

我正在尝试实现空间散列,并且正在使用来自Optimized Spatial Hashing for Collision Detection of Deformable Objectshash(x, y, z) = (x p1 xor y p2 xor z p3) mod n 的散列函数,其中 n 是散列表中的桶数。

我的哈希函数代码是:

int SpatialHash::hash(int x, int y, int z)
{
    return (((x * P1) ^ (y * P2) ^ (z * P3)) % TABLE_SIZE);
}

有定义:

#define P1 73856093
#define P2 19349663
#define P3 83492791
#define TABLE_SIZE 2000

我只是尝试遍历元素列表,当我尝试将顶点 1、-1、0 放入表中时,它给了我一个 -196 的索引。我的哈希函数是不是在某个地方搞砸了?

【问题讨论】:

    标签: c++ hashtable collision-detection


    【解决方案1】:

    负数的模是负数。例如:

    -7 % 3 = -1
    

    想要这样的东西来代替:

    int positiveModulo(int number, int modulo)
    {
        int result = number % mudulo;
        if (result < 0)
            result += modulo;
        return result;
    }
    

    或避免分支:

    int positiveModulo(int number, int modulo)
    {
        int result = number % mudulo;
        result += modulo;
        result %= modulo;
        return result;
    }
    

    这会给你:

    positiveModulo(-7, 3) = 2
    

    【讨论】:

      【解决方案2】:

      这实际上是一个有趣的问题,因为模运算结果的符号是编程语言设计者和数学家喜欢争论的问题。

      事实上,在 ISO C++ 中,负操作数的模运算的符号是实现定义的。 聪明的语言有一个mod 和一个rem 来捕捉这两种情况。 看看wikipedia page 和他们的编程语言表。

      有趣的是,它是如何在将近 50:50 分开的。

      现在解决您的问题:只需添加一个正模运算即可。 最简单的解决方案是使用abs(...) % N,作为(-a) mod N + a mod N = 0

      【讨论】:

        【解决方案3】:
        #include <iostream>
        #include <vector>
        using namespace std;
        #define P1 73856093
        #define P2 19349663
        #define P3 83492791
        #define TABLE_SIZE 2000
        int positive_mod(int i, int n)
        {
            /* constexpr */ int shift = 64*sizeof i - 1;
            int m = i%n;
            return m+ (m>>shift & n);
        }
        int hasha(int x, int y, int z)
        {
            return positive_mod(((x * P1) ^ (y * P2) ^ (z * P3)) ,TABLE_SIZE);
        }
        
        
        
        
        
        int main(int argc, char **argv)
        {
            int ret = hasha(1,-1,0);
            cout << ret << endl;
        }
        

        【讨论】:

        • 啊是溢出错误?不过我很困惑,因为模运算不应该返回负数吗?我可以只使用 long int 吗?
        • 我对你投了反对票,因为你使用了宏和using namespace std;。回答的重点是让你的代码比提问者更好。
        • 我支持你是因为这家伙 ^.你敲出一些快速代码来显示你在说什么。谢谢。
        猜你喜欢
        • 1970-01-01
        • 2015-10-25
        • 2023-03-21
        • 1970-01-01
        • 2020-10-18
        • 1970-01-01
        • 2015-05-29
        • 2010-10-12
        • 1970-01-01
        相关资源
        最近更新 更多