使用 std::complex<double> 作为 std::map 键

Using std::complex<double> as a std::map key

本文关键字:std 作为 gt map lt complex 使用 double      更新时间:2023-10-16

如何在地图中使用复数作为键? 这是一个不会编译的小示例:

#include <complex>
#include <map>
int main() {
  std::complex<double> zero = 0.0;
  std::map<std::complex<double>, int> theMap;
  return (theMap.count(zero));
}

我可以毫无错误地创建映射,但是任何方法(例如,上面的count调用以及find[]运算符、insert 等(都会产生编译时错误。 这绝对是我的理解问题,因为我使用 clang 和 g++ 得到了类似的结果。

看起来编译器无法比较两个复数。 我创建了所有的比较运算符(例如,bool operator< (const std::complex & lhs, const std::complex & rhs) {return (std::norm(lhs) < std::norm(rhs));}(,它适用于比较复数(只要你不介意3 < -5为真,这对map来说应该没问题(,但编译器不会拾取它。

我在unordered_map方面有类似的问题(complex<double>没有哈希

(

你的方法的问题在于,对于有序容器,例如 std::map ,密钥必须适合严格的弱排序。来自维基百科:

严格的弱排序具有以下属性。对于 S 中的所有 x 和 y,

对于所有 x,并不是 x <x(自反性(。>

对于所有 x,y,如果 x <y,则><x(不对称(的情况并非如此。>

对于所有 x、y 和 z,如果 x <z,则><z(传递性(。>

对于所有 x、y 和 z,如果 x 与 y 不可比较,y 与 z 不可

比较,则 x 与 z 不可比较(不可比较性的传递性(。

不幸的是,没有自然的方法对复数施加严格的弱排序。例如,1

我没有看过实现,但根据 cppreference std::map使用 std::less<T> 作为比较运算符,这可能不是专门用于std::complex的,如果你实现一个传递它作为模板中的第三个参数,std::map<std::complex, int, LessOperator>std:unordered_map 类似,您可以在其中提供哈希函子和相等函子。如果两者都实现了,则可以使用 std::complex 作为键。

主要答案已在上面的评论中指出。问题是复数不是有序的,因此没有预定义的std::complex<T>较小运算符。不过,您可以为自己定义一个,这很容易通过使用已经定义的较小运算符来std::array<T,2>

#include <iostream>
#include<complex>
#include<map>
#include<unordered_map>
#include<array>
template<typename T> struct less {};
    template<typename T>
    struct less<std::complex<T> >
    {
        bool operator()(std::complex<T> const& a, std::complex<T> const& b)
        {
            return std::array<T,2>{a.real(),a.imag()} < std::array<T,2>{b.real(),b.imag()};
        }
    };
int main()
{
    std::map<std::complex<double>, int, less<std::complex<double> > > m;
    m[std::complex<double>(1.0,0.0)]=1;
    m[std::complex<double>(0.0,1.0)]=2;
    m[{0.5,0.5}]=3;
    return 0;
}

在此处查看实时示例。