如何在std :: set

时间:2015-05-22 13:25:46

标签: c++ c++11 vector set

我最近参加了编程比赛。一项任务是关于几何。我发明的解决方案是使用2D向量的容器,其中每个向量都是唯一的。抛出副本的最快容器是std::unordered_set。但我忘记了如何制作自定义哈希,所以我使用了std::set

struct Vector
{
    int x;
    int y;

    bool operator<(const Vector& rhs) const
    {
        return x < rhs.x && y < rhs.y;
    }
}

std::set<Vector> geometry;

当然是错的。 我明白为什么这是错误的。这是比赛中的六项任务之一,时间限制为2小时。所以我假设,这个任务可以在~20分钟内完成。我可以使用std::vector检查uniquenes,但测试人员有时间限制,而且速度很慢(O(n ^ 2))。

所以我有这些要求:

  1. 容器必须阻止插入副本
  2. 容器必须至少比std::vector
  3. 更快
  4. 代码应该简单,小到足以在大约10分钟内编写和调试
  5. 那么,根据所有这些要求,如何以这种方式存储2D矢量?

4 个答案:

答案 0 :(得分:3)

我认为你在std::set中存储(让我说点数)的想法很好并且在实践中运作良好。

但是您在operator<()的实施中遇到了错误。例如。积分会发生什么

(1, 4)(2, 2)?你的代码会告诉你

(1, 4) >=(2, 2)(2, 2) >= (1, 4),这是stl

中相等的定义

你可以使用std::tie()自动化这样的同情,如下所示:

struct Vector
{
    int x;
    int y;

    bool operator<(const Vector& rhs) const
    {
        return std::tie(x, y) < std::tie(rhs.x, rhs.y);
    }
};

答案 1 :(得分:3)

正如另一个答案所指出的,理论上你的解决方案是正确的。但是,operator <不正确。

使用<complex>的替代方法是使用代表x,y点的std::pairstd::pair包含内置operator <,因此您需要做的就是在operator <函数中调用它。

见这里:http://en.cppreference.com/w/cpp/utility/pair

#include <set>
#include <map>
#include <iostream>

struct Vector
{
    std::pair<int, int> xy;
    Vector(int x_ = 0, int y_ = 0) : xy(std::make_pair(x_, y_)) {}
    bool operator<(const Vector& rhs) const
    { return xy < rhs.xy; }
};

std::set<Vector> geometry;

int main()
{
    geometry.insert(Vector(1,2));
    geometry.insert(Vector(1,5));
    geometry.insert(Vector(1, 8));
    geometry.insert(Vector(1, 8));
    geometry.insert(Vector(1, 8));  // repeated
    geometry.insert(Vector(1, 8));  // repeated
    geometry.insert(Vector(2, 2));

    std::cout << geometry.size();
}

直播示例:http://ideone.com/njmuVX

该示例显示只有唯一项存储在集合中,表明std::pair具有operator <所需的正确语义。

鉴于此,除非您在Vector课程中添加其他成员函数,否则您可以简单地完成此操作:

std::set<std::pair<int, int>> geometry;

然后在main

中执行此操作
int main()
{
    geometry.insert(make_pair(1,2));
    geometry.insert(make_pair(1, 5));
    geometry.insert(make_pair(1, 8));
    geometry.insert(make_pair(1, 8));
}

但是,如果您知道pair代表的内容,并且您打算不将Vector类扩展为超过x / y值的内容,请执行此操作。

答案 2 :(得分:0)

关于std::set中的排序的要点是必须存在某种排序,但排序不必具有任何实际意义。这意味着我们可以自由地使用任何顺序,前提是不同的对从不被视为相等。一个简单的方法是:

struct Vector
{
    int x;
    int y;

    bool operator<(const Vector& rhs) const
    {
        if (x == x.rhs) {
            return y < rhs.y;
        else {
            return x < rhs.x;
        }
    }
}

std::set<Vector> geometry;

在上面,我们将首先对x进行排序,只有它们相等才会对y进行排序。这将提供stl::set所需的唯一排序。

答案 3 :(得分:0)

std::unordered_set与您选择的哈希一起使用。另外,不要忘记重载operator==的唯一性。总而言之,

#include <iostream>
#include <unordered_set>

struct Vector
{
    int x;
    int y;

    Vector(int x_, int y_) : x(x_), y(y_) { }

    friend bool
        operator==(const Vector& lhs, const Vector& rhs)
        { return (lhs.x == rhs.x) && (lhs.y == rhs.y); }
};

struct Hash
{
    int operator()(const Vector& v)
    const { return (v.x + v.y) % 13; }
  //^^^^^
  //hasher functions must be const
};

int main()
{
    std::unordered_set<Vector, Hash> vectorset;

    vectorset.insert(Vector(0, 1)); //unique
    vectorset.insert(Vector(2, 1)); //unique
    vectorset.insert(Vector(3, 4)); //unqiue
    vectorset.insert(Vector(0, 1)); //repeat
    vectorset.insert(Vector(2, 1)); //repeat
    vectorset.insert(Vector(3, 4)); //repeat
    vectorset.insert(Vector(2, 1)); //repeat
    vectorset.insert(Vector(9, 4)); //unique
    vectorset.insert(Vector(2, 1)); //repeat

    std::cout << vectorset.size() << std::endl;

    return 0;
}

输出: 4