繁体   English   中英

提供良好的哈希函数

[英]Providing a good hash function

在我最初的问题(详细的实验研究): 适当的容器快速插入和查找n维真实向量(提供初始基准测试)我得到了非常奇怪的行为使用未分类集管理随机N维浮点数组与我的初始(可能设计糟糕的Hash功能):

#include <iostream>
#include <chrono>
#include <random>
#include <array>
#include <unordered_set>

const int N = 3;  // Dimensionality of the arrays

std::array<double, N> getRandomArray() {
  // Engines and distributions retain state, thus defined as static
  static std::default_random_engine e;                    // engine
  static std::uniform_real_distribution<double> d(0, 1);  // distribution
  std::array<double, N> ret;
  for (size_t i = 0; i < N; ++i) {
    ret[i] = d(e);
  }
  return ret;
}

// Return Squared Euclidean Distance
template <typename InputIt1, typename InputIt2>
double EuclideanDistance2(InputIt1 beg1, InputIt1 end1, InputIt2 beg2) {
  double val = 0.0;
  while (beg1 != end1) {
    double dist = (*beg1++) - (*beg2++);
    val += dist*dist;
  }
  return val;
}

struct ArrayHash {  // Hash Function
  std::size_t operator() (const std::array<double, N>& arr) const {
    std::size_t ret = 0;
    for (const double elem : arr) {
      ret += std::hash<double>()(elem);
    }
    return ret;
  }
};

struct ArrayEqual {  // Equivalence Criterion
  bool operator() (const std::array<double, N>& arr1,
                          const std::array<double, N>& arr2) const {
    return EuclideanDistance2(arr1.begin(), arr1.end(), arr2.begin()) < tol*tol;
  }
 private:
  static constexpr double tol = 1e-6;  // Comparison tolerance
};


int main() {
  // create a unordered set of double arrays (usda)
  std::unordered_set<std::array<double, N>, ArrayHash, ArrayEqual> usda;
  // record start time
  auto start = std::chrono::steady_clock::now();
  // Generate and insert one hundred thousands new double arrays
  for (size_t i = 0; i < 100000; ++i) {
    // Get a new random double array (da)
    std::array<double, N> da = getRandomArray();
    usda.insert(da);
  }
  // record finish time
  auto end = std::chrono::steady_clock::now();
  std::chrono::duration<double> diff = end - start;
  std::cout << "Time to generate and insert unique elements into UNORD. SET: "
            << diff.count() << " s\n";
  std::cout << "unord. set size() = " << usda.size() << std::endl;
  return 0;
}

两个最奇怪的事情是:

  1. 在没有任何优化标志的情况下运行实验,即使具有宽松的容差(1e-1),几乎所有随机向量(实现为N维阵列)都被识别为唯一的。 我没有使用vectorssets观察到这一点。
  2. 在打开-O3优化标志的同时,独特元素的数量与没有优化的数字明显不同,这肯定表明我的方法存在问题。

编辑:考虑到@WhozCraig备注解决了第二个问题。

所以,我的问题是 :这一种奇怪的行为,因为我的哈希函数设计得很糟糕? 如果是这样,你能否建议如何为我的案例制作更好的哈希函数?

您的程序显示未定义的行为(未初始化的std::size_t ret变量)。

首先, ArrayEqual不会引发等价关系。 这不是传递-存在三个阵列abc使得a是“足够接近” bb是“足够接近” c ,但a是不是“足够接近” c

其次, ArrayHash可能不会为ArrayEqual声明的两个数组返回相同的哈希值。

这两个都是std::unordered_set的模板参数的先决条件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM