【问题标题】:Container with std::vector and std::set properties ?具有 std::vector 和 std::set 属性的容器?
【发布时间】:2015-01-14 16:29:45
【问题描述】:

C++ 世界中是否存在具有这些属性的容器?

  • 元素是独一无二的,并在可自定义的比较器的帮助下排序
  • 提供随机访问运算符。

我目前正在将我的数据收集到 std::set<C,COMPARATOR> 中,然后执行 std::copy(_set.begin(),_set.end(),std::back_inserter(_vec)) 以便能够随机访问有序集合。然而,规模可能会达到数亿。

【问题讨论】:

  • 堆会有帮助吗?您不会有总排序,但可以选择最大元素。
  • @Quentin 没有严格的顺序是必要的
  • 您是否要在数据中间进行大量插入和/或删除?这将对可接受的解决方案产生重大影响。您当前的解决方案可以通过直接添加到向量并在其上运行 std::sort 来改进,总体上应该会稍微快一些。
  • @MarkRansom 对向量进行排序的问题在于它不能保证唯一性。如果我遍历数据,我希望相同键的双重插入被静默忽略。
  • @Oncaphillis 如果你只有比较少的重复,你可以在std::sort之后使用std::unique。顺便说一句,说您的情况涉及首先一劳永逸地构建数据结构,然后再读取它是正确的吗?

标签: c++ c++11 containers


【解决方案1】:

如果可以选择 Boost,请查看 flat_set in the Containers library

flat_set 的接口与std::set 的接口相同,但它提供了随机访问迭代器,如std::vector

#include <boost/container/flat_set.hpp>

[...]

boost::container::flat_set<int> c;
c.insert(1);
c.insert(2);
c.insert(3);
c.insert(4);

// unfortunately, no operator[] on the container itself,
// but the iterator is random access
int third_element = c.begin()[2];

如果您被标准库卡住了,您可以为此目的使用排序的vector。标准库实际上在 &lt;algorithm&gt; 标头中提供了许多算法,允许您执行几乎所有可以使用带有排序迭代器范围的 set 执行的操作。

【讨论】:

  • 我将不得不查看插入/删除的性能,但我认为就是这样。提升绝对是一种选择
  • 他们提供了一个随机访问迭代器但没有operator[]?想知道这样做的理由是什么。
  • 好吧,我进行了一次测试,插入了 10^6 个随机数,并且花了一些时间。像 140 秒。插入 std::set 并随后复制到 std::vector 是在 1 秒内完成的。由于初始化后我没有做很多插入/删除,我想我坚持我的解决方案。但是,我仍然将此答案作为我最初问题的正确解决方案。
  • @Barry [] 的语义是通过键/索引访问容器,但是 set 或 flat_set 没有键/索引,除非您说值本身就是键/索引。在这种情况下,唯一有效的赋值是 set[n] = n;并且读取访问根本没有任何作用,因为您返回的值将始终是密钥本身。
【解决方案2】:

据我所知没有。但是,由于有数亿个元素和一些有序访问,您可能希望内存表示紧凑且连续,这对您的容器类提出了更高的要求。

我会选择std::vector 并使用您描述的方法或任何其他排序算法。之后您可能不需要您的std::set,因此您可以释放内存。

【讨论】:

    【解决方案3】:

    不在标准 C++ 库中,不。您可以使用set/priority_queue 进行订购,也可以使用vector/deque 进行随机访问。

    但是没有什么可以阻止您围绕vector 编写自己的包装器,它只是强制执行排序。根本没有那么多代码。一些示例函数:

    template <typename T, typename COMP = std::less<T>>
    class sorted_vec {
        std::vector<T> vec_;
    
    public:
        // random access
        using iterator = typename std::vector<T>::iterator;
        T& operator[](size_t idx) { return vec_[idx]; }
    
        iterator begin() { return vec_.begin(); }
        iterator end() { return vec_.end(); }
    
        // insertion
        void push(const T& val) {
            vec_.insert(std::lower_bound(vec_.begin(), vec_.end(), COMP{}),
                        val);
        }
    };
    

    【讨论】:

    • 我还要写T&amp; operator[]const 版本,所以你可以通过const 参考。
    • @vsoftco 对,这绝不是一个详尽的功能列表(例如,没有const_iterator等)
    猜你喜欢
    • 1970-01-01
    • 2023-04-09
    • 2015-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-11
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多