【问题标题】:c++ generate key for unordered_map from 3 floats valuesc++ 从 3 个浮点值生成 unordered_map 的键
【发布时间】:2012-05-29 18:12:32
【问题描述】:

我真的不明白:

我正在读取点,每个点都包含 3 个浮点值,来自二进制文件。 将此点保存在 unordered_map 中

因此我尝试从这 3 个浮点值中创建一个键:

初衷: 只需使用确切的位作为密钥:

unordered_map<string, vector<float>> points;
string vecToKey( float* a ) {
char bytes[12];
memcpy(bytes, a, 12);
return string(bytes);
}

关键是我绝对想以这种方式消除相同的点 但是

在一个阅读约 21374 点的示例项目中 地图结果大小 = 10640 点

使用以下方法作为密钥创建会产生正确的结果 共 10687 点

string vec3ToKey( float a[3] ) {
float a1[3];
a1[0] = a[0];
a1[1] = a[1];
a1[2] = a[2];
stringstream ss;
boost::archive::text_oarchive oa(ss);
oa << a1;
return ss.str();
}

问题在于速度。第二种方法大约需要 16 秒,第一种方法只需 1-2 秒... 我只是无法解释自己为什么会有差异......

我很欣赏每一个想法:)

【问题讨论】:

  • 如果您关心速度,请不要使用std::strings 作为开始。
  • 第一块代码坏了。 string(bytes) 怎么知道输出字符串应该是多少字节?第二种方法需要很长时间,因为它必须将浮点数转换为文本。
  • @DavidSchwartz 如果bytes 的长度为 13 并且初始化为零,则第一个可以工作,尽管这仍然是个坏主意。
  • string(bytes) 怎么知道它的大小是 13?
  • 第一个例子也被某些浮点数打破,这些浮点数在其模式中包含零作为一个字节。

标签: c++ floating-point key unordered-map


【解决方案1】:
string vecToKey( float* a ) {
  char bytes[12];
  memcpy(bytes, a, 12);
  return string(bytes);
}

您使用的字符串构造函数在第一个空字节处停止。浮点值可以包含空字节。所以字符串可能不能准确地表示三个浮点数。您可以通过在其中粘贴一个断言来查看:

  string s(bytes);
  assert(s.size() == sizeof bytes);
  return s;
}

另一个问题是bytes 可能包含空字节,并且程序可能会将随机垃圾复制到字符串中或以其他方式表现出未定义的行为。

我建议您不要尝试以这种方式滥用字符串。您需要一个包含三个浮点数的键,因此请使用一个准确表示该键的键:std::array&lt;float,3&gt;。或者更好的是使用“Point”类,因为这就是三个浮点数所代表的。

由于没有内置的数组散列函数,你可以使用这样的东西:

// taken from http://stackoverflow.com/questions/6899392/generic-hash-function-for-all-stl-containers
template <class T>
inline void hash_combine(std::size_t & seed, const T & v)
{
  std::hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

struct Hasher {
    size_t operator() (std::array<float,3> const &v) {
        size_t h = std::hash<float>()(v[0]);
        hash_combine(h,v[1]);
        hash_combine(h,v[2]);
        return h;
    }
};


std::unordered_map<std::array<float,3>,vector<float>,Hasher> map;

【讨论】:

    【解决方案2】:

    将索引更改为整数类型,例如unsigned int。试试这样的代码:

    unsigned int vec3toKey( float a[3] )
    {
       unsigned char *in = reinterpret_cast<unsigned char>(a);
       unsigned int ret = 2654435761u;
       for(int i = 0; i < (3 * sizeof(float)); ++i)
         ret = (ret * 2654435761u) ^ *in++;
       return ret;
    }
    

    【讨论】:

      【解决方案3】:
      【解决方案4】:

      通用容器可以使用任何类型作为键。当然,您在此应用程序中有某种点类。那应该是你的钥匙。

      显然,您需要重载散列函数才能使用您自己的类型(感谢 DavidSchwartz)。这个问题解决了:

      C++ unordered_map user defined type

      PS:如果你没有点结构或类,你可能想要一个:p

      【讨论】:

      • 看起来您需要 == 重载的无序地图,对吧?
      • 你需要一个比较函数和一个散列函数来使用某个东西作为 unordered_map 的关键类。
      【解决方案5】:

      我尝试使用@bames53 解决方案,但遇到了一些编译问题。在考虑this answer 和这里给出的@bames53 是我拥有的最终版本

        #include <iostream>
        #include <string>
        #include <vector>
        #include <unordered_map>
      
      
        template <typename C> struct Hasher{
                            typedef typename C::value_type value_type;
                            inline std::size_t operator() (const C &c) const{
                                std::size_t seed = 0;
                                for(typename C::const_iterator it = c.begin(); it != c.end(); ++it){
                                    std::hash<value_type> hasher;
                                    seed ^= hasher(*it) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
                                }
                                return seed;
                            }
        };
      
        int main()
        {
      
                    std::unordered_map<std::array<float, 3>, std::vector<float>, Hasher<std::array<float, 3>>> E;
                        std::array<float, 3> t1 = {34, 56,78};
                        std::vector<float> result;
                        result.push_back(45);
                        E[t1] = result;
      
        }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-24
        • 2018-07-14
        • 1970-01-01
        • 2013-08-10
        • 1970-01-01
        • 2017-04-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多