【问题标题】:need STL set in insertion order需要按插入顺序设置 STL
【发布时间】:2015-11-03 17:43:21
【问题描述】:

如何按插入顺序将元素存储在集合中。 例如。

set<string>myset;

myset.insert("stack");
myset.insert("overflow");

如果你打印,输出是

overflow
stack

需要的输出:

stack
overflow

【问题讨论】:

  • 您能提供更详细的信息吗?
  • 你需要的是#include &lt;unordered_set&gt; //std::unordered_set&lt;std::string&gt;
  • @SSpoke 这是错误的。即使不知道 unordered 集合是什么,这个名字已经表明它不可能是一个解决方案 :-)

标签: c++ stl set


【解决方案1】:

我只是想知道为什么没有人建议使用像 Boost MultiIndex 这样好的库。这是一个如何做到这一点的示例:

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>

#include <iostream>

template<typename T>
using my_set = boost::multi_index_container<
    T,
    boost::multi_index::indexed_by<
        boost::multi_index::sequenced<>,
        boost::multi_index::ordered_unique<boost::multi_index::identity<T>>
    >
>;

int main() {
    my_set<int> set;
    set.push_back(10);
    set.push_back(20);
    set.push_back(3);
    set.push_back(11);
    set.push_back(1);
    
    // Prints elements of the set in order of insertion.
    const auto &index = set.get<0>();
    for (const auto &item : index) {
        std::cout << item << " ";
    }

    // Prints elements of the set in order of value.
    std::cout << "\n";
    const auto &ordered_index = set.get<1>();
    for (const auto &item : ordered_index) {
        std::cout << item << " ";
    }
}

【讨论】:

    【解决方案2】:

    你需要的是这个,非常简单的标准库。示例在线编译器链接:http://cpp.sh/7hsxo

    #include <iostream>
    #include <string>
    #include <unordered_set> 
    static std::unordered_set<std::string> myset;
    
    
    int main()
    {
        myset.insert("blah");
        myset.insert("blah2");
        myset.insert("blah3");
    
        int count = 0;
        for ( auto local_it = myset.begin(); local_it!= myset.end(); ++local_it ) {
              printf("index: [%d]: %s\n", count,  (*local_it).c_str());
              count++;
        }
        printf("\n");
        for ( unsigned i = 0; i < myset.bucket_count(); ++i) {
            for ( auto local_it = myset.begin(i); local_it!= myset.end(i); ++local_it )
                  printf("bucket: [%d]: %s\n", i,  (*local_it).c_str());
        }
    }
    

    【讨论】:

    • 无序集合,按随机顺序存储元素,如何解决问题??
    【解决方案3】:

    如果您可以使用 Boost,一个非常简单的解决方案是使用仅标头库 Boost.Bimap(双向映射)。

    考虑以下示例程序,它将按插入顺序显示您的虚拟条目 (try out here):

    #include <iostream>
    #include <string>
    #include <type_traits>
    #include <boost/bimap.hpp>
    
    using namespace std::string_literals;
    
    template <typename T>
    void insertCallOrdered(boost::bimap<T, size_t>& mymap, const T& element) {
      // We use size() as index, therefore indexing with 0, 1, ... 
      // as we add elements to the bimap.
      mymap.insert({ element, mymap.size() });
    }
    
    int main() {
      boost::bimap<std::string, size_t> mymap;
    
      insertCallOrdered(mymap, "stack"s);
      insertCallOrdered(mymap, "overflow"s);
    
      // Iterate over right map view (integers) in sorted order
      for (const auto& rit : mymap.right) {
        std::cout << rit.first << " -> " << rit.second << std::endl;
      }
    }
    

    【讨论】:

      【解决方案4】:

      我是这样做的:

      template <class T>
      class VectorSet
      {
      public:
        using iterator                     = typename vector<T>::iterator;
        using const_iterator               = typename vector<T>::const_iterator;
        iterator begin()                   { return theVector.begin(); }
        iterator end()                     { return theVector.end(); }
        const_iterator begin() const       { return theVector.begin(); }
        const_iterator end() const         { return theVector.end(); }
        const T& front() const             { return theVector.front(); }
        const T& back() const              { return theVector.back(); }
        void insert(const T& item)         { if (theSet.insert(item).second) theVector.push_back(item); }
        size_t count(const T& item) const  { return theSet.count(item); }
        bool empty() const                 { return theSet.empty(); }
        size_t size() const                { return theSet.size(); }
      private:
        vector<T> theVector;
        set<T>    theSet;
      };
      

      当然,可以根据需要添加新的转发功能,并且可以转发到两种数据结构中最有效地实现它们的任何一种。如果您打算在这方面大量使用 STL 算法(到目前为止我还不需要),您可能还需要定义 STL 期望找到的成员类型,例如 value_type 等。

      【讨论】:

        【解决方案5】:

        set 是保持插入顺序的错误容器,它会根据排序标准对其元素进行排序而忘记插入顺序。为此,您必须使用诸如向量、双端队列或列表之类的有序容器。如果您还需要 set 提供的关联访问权限,则您必须同时将元素存储在多个容器中,或者使用像 boost::multi_index 这样可以同时维护多个元素顺序的非 STL 容器。

        PS:如果您在将元素插入集合之前对其进行排序,则该集合将使它们保持插入顺序,但我认为这不会解决您的问题。

        如果除了插入顺序之外不需要任何顺序,您还可以将插入编号存储在存储元素中并使其成为排序标准。但是,为什么在这种情况下会使用一个集合完全让我无法理解。 ;)

        【讨论】:

          【解决方案6】:

          一种方法是使用两个容器,一个std::deque 按插入顺序存储元素,另一个std::set 确保没有重复。

          插入元素时,先检查是否在set中,如果是则丢弃;如果不存在,请将其同时插入dequeset

          一种常见的情况是先插入所有元素,然后处理(不再插入),如果是这种情况,可以在插入处理后释放set

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-01-23
            • 1970-01-01
            • 1970-01-01
            • 2013-12-18
            • 2012-07-13
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多