哈希函数用于6个整数的良好排序/比较

时间:2014-06-23 11:27:35

标签: c++ optimization hash set

我在这里玩了一个问题......我设法用以下方法解决了这个问题:

 struct wrap
 {
    char grid[7];
    bool operator==(const wrap &segundo) const
    {
        return !strcmp(segundo.grid, grid);
    }
    bool operator<(const wrap &segundo) const
    {
         return strcmp(grid, segundo.grid) < 0;
    }
    //other stuff here
 }

现在我试图看看使用6个整数而不是那个数组会提高速度:

 struct wrap
 {
    int x1, x2, x3, y1, y2, y3; 

    bool operator==(const wrap &segundo) const
    {
        return x1 == segundo.x1 && x2 == segundo.x2 && x3 == segundo.x3 && y1 == segundo.y1 && y2 == segundo.y2 && y3 == segundo.y3;
    }
    bool operator<(const wrap &segundo) const
    {       
        return ??? // I want to know a good thing to put here... 
                       // I have some Ideas but would appreciate suggestions
    }

让我更好地解释一下情况:我使用了一套,我昨天开始玩套装,所以我不太了解它......

我知道它需要运营商&lt;知道如何对元素进行排序......但是在使用find方法时它是否使用了我对operator ==的定义?或者它会在比较时以元素的顺序进行反演,这就是它?

如果上一个问题的答案是第二种可能性,如果结构实现运算符==,它会表现不同(因为&lt;是由程序员提供的,它可能会利用其他运算符可能是为避免一些否定而提供?)

回到我的代码,我想到了:

 return 100000*x1 + 10000*y1 + 1000*x2 + 100*y2 + 10*x3 + y3 - (same sum for the second) > 0; 

最后一个问题:这6个整数的值可以在[0,9]中,将它们改为短路或字符可以提高速度还是记忆?

2 个答案:

答案 0 :(得分:2)

  

在使用find方法时是否使用了我对operator ==的定义?

没有

  

在比较时会按元素的顺序进行反演,就是这样吗?

那是对的。它在比较操作中找到了一个等效的键,不一定是等于,它的参数。如果

,则密钥k1k2是等效的
!(k1 < k2) && !(k2 < k1)
  

如果结构实现operator==

,它的行为会有所不同

没有。有序关联容器仅使用单个比较操作 - 默认情况下为std::less<key_type>,默认情况下使用operator<。即使你提供了一个相等运算符,它也不一定会得到与容器所需的等价测试相同的结果,因此容器不能使用它。

  

将它们改为短裤或字符可以提高速度还是记忆力?

它很有可能,但它是你需要衡量的东西。同样,判断您建议的无分支算术比较是否优于词典比较(如strcmp / memcmp或元组比较)的唯一方法是测量。

另一种可能性是在一个64位操作中对它们进行比较:

union {
    uint8_t bytes[8]; // Make sure unused bytes are set to zero
    uint64_t all;
} grid;

bool operator<(const wrap &segundo) const {
    return grid.all < segundo.grid.all;
}

您可能还想调查std::unordered_set,这是一个哈希容器,如果您不关心元素的顺序,它可以更有效。

答案 1 :(得分:1)

所有容器都知道你的对象是它有一个运算符&lt;所以。 operator ==如果它不存在则不会被使用。

运营商&lt;你提供的东西必须是一个有意义的:

if not x<y and not y<x ==> y==x

最简单的算子&lt;对于一个系列是字典比较。

sorted_set(默认c ++集)将使用operator&lt;按顺序保存集合,并从O(lgN)中的集合中找到 unorderd_set将使用一个哈希函数,假设一个不错的哈希函数将表现得更好,然后设置在除最小集之外的所有集合上,并且不允许对项目顺序做出任何假设。

编辑: 您的运营商的问题&lt;可能是溢出之一。除非您知道x1,x2,x3等的MAX值,否则您的建议可能会产生错误的结果。

x1 * 1000000可能会传递MAX_INT,在这种情况下,它将成为一个巨大的负值。 x2可能大于10,000,如果它很大而x1很小则再次得到错误的结果。

我的第一次尝试是使用像

这样的东西
   std::tie(x1, x2, x3 ... ) < std::tie(o.x1, o.x2, o.x3, ...) 

保持代码可读,实质上它是字典比较:

if (x1== o.x1) {
    if (x2== o.x2) { 
       if (x3 == o.x3 {
          ...
       } else { 
           return x3 < o.x3;
       }
    } else {
      return x2 < o.x2;
    }
} else {
    return x1 < o.x1;
}