【问题标题】:C++ Sorted Set of ObjectsC++ 排序的对象集
【发布时间】:2020-02-19 01:43:38
【问题描述】:

我正在使用std::set<T>,其中 T 是我自己的班级。有没有办法让一个集合始终按我的类的属性 A 排序,并且仍然保持里面的所有元素在我的类中的属性 B 方面是唯一的。

class T
{
public:
    int A;
    int B;
}

所以我需要我的类实例按 A 排序并按 B 唯一。任何 std::set 的替代方案,只要它是 STL 的一部分,也可以接受。

【问题讨论】:

  • 你可以继承 std::set 的子类吗?
  • @Jeffrey 你是对的。至于你的问题,如果我已经插入了 elemetn A=4 和 B=2,如果我尝试添加 A=3 B=2 它不应该被添加。但我也永远不会传递这样的意见。
  • @JosephLarson 我认为它应该可以工作。
  • 如果 2,3 排在 2,4 之前,或者如果首先添加(或其他一些逻辑)必须 2,4 排在第一位,您关心吗?
  • @user4581301 我不知道。

标签: c++ algorithm sorting stl set


【解决方案1】:

我可能会使用中间函数。下面的代码说明了这一点。

#include <iostream>
#include <set>

class Foo {  // Your T
public:
    int A;
    int B;
    Foo(int a, int b) : A(a), B(b) { }
};

template <typename T, typename Comparison>
void addToSet(std::set<T, Comparison>& s, Foo item)
{
    for (auto i : s) {
        if (i.B == item.B) {
            // Do whatever you need here, currently item is not added.
            return;
        }
    }
    s.insert(item);
}

int main()
{
    auto comp = [](Foo a, Foo b) { return a.A < b.A; };
    std::set<Foo, decltype(comp)> sortedSet(comp);

    auto quickAdd = [&sortedSet](Foo item) mutable { addToSet(sortedSet, item); };

    quickAdd(Foo(1, 2));
    quickAdd(Foo(5, 2));  // Shouldn't be seen
    quickAdd(Foo(5, 5));

    for (auto i : sortedSet)
        std::cout << "A: " << i.A << ", B: " << i.B << '\n';
}

这个输出

A: 1, B: 2
A: 5, B: 5

这应该符合您的标准。

一些注意事项,我将 Foo 类型硬编码到 addToSet 函数中,因为不添加具有匹配 B 键的项目的特定要求。 main 中的 quickAdd lambda 就是这样我不必总是输入 sortedSet 作为第一个参数。您可以自然地修改comp 函数以获得您想要的任何行为,例如按 B 键对匹配的 A 键或 A 键从高到低进行排序。

【讨论】:

  • 我们能否在 addToSet 中更有效地循环遍历集合中的所有项目?
  • 我对此表示怀疑。这是我目前能想到的验证唯一 B 键的唯一方法,同时保留 std::set。您可以重载==,然后使用std::priority_queue
  • @KaloyanManev 当我放弃我的答案不可行时,这就是我想要弄清楚的。如果您有一个 set(用于快速拒绝)和一个有序列表,它们被打包在另一个类中(使其表现得像 Library Container 的奖励积分),您可以以存储成本获得两全其美。跨度>
  • @user4581301 这不会复制我的数据吗?
  • @KaloyanManev 这就是存储成本。一个可以存储对另一个的引用,但指针通常与int 一样重或更重,并且指针追逐的额外成本使得指针列表不值得。
【解决方案2】:
class Foo {  // Your T
public:
int A;
int B;
Foo(int a, int b) : A(a), B(b) { }
bool operator==(Foo&& other){
  return B == other.B;
}
};

auto comp = [](Foo a, Foo b) { return a.A < b.A; };
std::set<Foo, decltype(comp)> sortedSet(comp);

sortedSet.insert({1, 2});
sortedSet.insert({5, 2});  // Shouldn't be seen
sortedSet.insert({5, 5});

std::cout <<std::endl;
for (auto i : sortedSet)
    std::cout << "A: " << i.A << ", B: " << i.B << '\n';

它应该可以工作。

【讨论】:

    【解决方案3】:

    只需按两个属性排序,属性A 的优先级高于属性B

    class T
    {
    public:
       int A;
       int B;
       bool operator < (T other) const
       {
           return (A<other.A) || ((A == other.A) && (B < other.B));
       }
    }
    

    如果不按两个参数排序,很难保证唯一性。其他方法是在属性B 上使用哈希函数,它应该是一种更快的方法,但正确实现可能很复杂。因为要达到合适的效率,您需要实现自己的容器 - 您可以围绕 std::map&lt;propertyA, std::unordered_map&lt;propertyB, remaining_data&gt;&gt; 编写一个包装器以实现 set 的接口,但我怀疑它会比简单的 std::set 更有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      • 1970-01-01
      • 2015-04-23
      • 2016-04-01
      相关资源
      最近更新 更多