C++ 选择具有唯一性且保持插入顺序的STL容器

C++ 选择具有唯一性且保持插入顺序的STL容器,c++,stl,C++,Stl,我无法决定在以下情况下使用哪个STL容器: 我想保留元素的插入顺序 容器中的元素必须是唯一的 有没有现成的容器可以装这个?我不想在每次执行推回操作之前先使用向量,然后执行std::find。可能有一种很好的内置方法,但一种相当简单的方法是同时使用哈希映射和列表。在每次插入之前检查hash_映射,然后将其同时插入。您可能希望将其封装在一个类中。在您选择的容器(例如list、vector、deque)上实现一个包装类,并重写插入/推回方法,以在插入元素之前检查插入的元素是否唯一 不幸的是,我不知道任

我无法决定在以下情况下使用哪个STL容器:

  • 我想保留元素的插入顺序
  • 容器中的元素必须是唯一的

  • 有没有现成的容器可以装这个?我不想在每次执行
    推回操作之前先使用向量,然后执行
    std::find

    可能有一种很好的内置方法,但一种相当简单的方法是同时使用哈希映射和列表。在每次插入之前检查hash_映射,然后将其同时插入。您可能希望将其封装在一个类中。

    在您选择的容器(例如list、vector、deque)上实现一个包装类,并重写插入/推回方法,以在插入元素之前检查插入的元素是否唯一


    不幸的是,我不知道任何STL容器符合您的标准

    没有标准的库容器直接提供您想要的内容。我将从一个std::vector开始,并编写一个免费函数来执行insert,它为您执行find和push_返回。如果这足够了,就不要再继续了。如果您有性能问题,请考虑一个更复杂的解决方案。

    应该能够完全满足您的要求-您只需使用一个顺序索引即可获得“按插入顺序排序”的要求,或者是一个hash_unique
    或者是一个有序的_unique索引来获得唯一性要求。

    正如其他人所说,没有一个STL容器可以做到这一点。我喜欢尼尔·巴特沃斯的回答。另一种选择是同时使用集合和向量。转到“插入”时,请检查元素是否在集合中。如果是,则不能插入,因为这将违反您的唯一性要求。如果不是,则将其添加到集合中,然后将其插入向量中。这很容易实现,并且可以封装到单个类中。折衷是增加内存开销。但是你可以通过在单个向量上寻找你自己来换取增加的计算时间。这完全取决于您在问题域中处理的数据量以及您的时间和内存限制(如果有)。

    如果您已经安装了boost,我喜欢这个选项。否则,为什么不使用一个列表或向量并在插入时添加一个检查
    (find(k)==std::npos)
    ?我想在一个非常非常大的列表上,它可能会变得有点慢,但在大多数情况下,它会工作得很好。

    您可以这样做:

    • 围绕元素类创建一个包含两个成员的包装器:元素和索引。我们称之为“插入-删除”。索引将是插入顺序

    • 为此类定义比较运算符,它只考虑元素,而不考虑索引。这将确保元素的唯一性,同时记住它们的插入顺序

    • 将std::set和插入计数器包装到另一个类中。然后,如果要插入新元素,请执行以下任一操作:

    • 它已经存在,没有什么可做的
    • 它不会:将其插入地图,同时为其指定当前最大索引+1
    比如:

    class CMagicContainer
    {
      public:
        std::set<InsertedElement> collection;
        int indexGenerator;
    
        ...
    };
    
    class CMagicContainer
    {
    公众:
    std::集合集合;
    int指数发生器;
    ...
    };
    
    嗯,我曾经有过类似的情况。我脑海中浮现的一件事是“我可以使用多个键吗?”?我在谷歌上搜索了一会儿,发现了一个使用std::set的示例。因此,如果您无法使用boost(我建议您使用它,重新发明车轮是没有意义的);你可以试试下面的例子。我认为您可以使用辅助键作为插入位置(自动递增)。从我在互联网上找到的例子;我根据自己的需要量身打造。这是一个相同的修改版本

    卡瓦特:它正在使用宏。我知道它们总的来说是邪恶的,但我想这种用法是可以的

    #include <set>
    #include <functional>
    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <string>
    
    #define MULTIKEYDEF(NAME,TYPE) \
        inline TYPE const & NAME() const { return d_##NAME; } \
        inline void NAME(TYPE const & t) { d_##NAME = t; } \
        TYPE d_##NAME; \
    class T##NAME \
        : public std::unary_function<Tmultikey*,bool> { \
    private: \
        TYPE d_compare; \
    public: \
        T##NAME(TYPE t) : d_compare(t) {} \
        T##NAME(T##NAME const & self) \
        : d_compare(self.d_compare) {} \
        bool operator()(Tmultikey * mk) { \
        return d_compare == mk->##NAME(); \
        } \
       inline TYPE const& name() const { return d_compare; } \
        }
    
    class Tmultikey {
    public:
        // Actual keys
        // Can be accessed through d_primary and d_secondary,
        // or primary() and secondary()
        MULTIKEYDEF(primary , std::string);
        MULTIKEYDEF(secondary, unsigned int);
        // Mandatory
        bool operator < (Tmultikey const& mk) const {
            if(primary() < mk.primary()) return true;
            else if(primary() == mk.primary()) {
                return secondary() < mk.secondary();
            }
            return false;
        }
        // Constructor
        Tmultikey(std::string p, unsigned int s)
            : d_primary(p), d_secondary(s) {}
    
        // Eraser for std::set
        template<typename Compare>
            static void erase(std::set<Tmultikey> & c, Compare op) {
                typename std::set<Tmultikey>::iterator pos = c.begin();
                while(pos != c.end()) {
                    if(op(&(*pos))) {
                        c.erase(pos++);
                    } else ++pos;
                }
            }
          // Eraser for std::set
          template<typename Compare>
          static std::set<Tmultikey>::iterator find_ex(std::set<Tmultikey> & c, Compare op) {
             typename std::set<Tmultikey>::iterator pos = c.begin();
             while(pos != c.end()) {
                if(op(&(*pos))) {
                   break;
                } else ++pos;
             }
             return pos;
          }
    };
    
    int main(int argc, char* argv[])
    {
        std::set<Tmultikey> mkset;
    
        mkset.insert(Tmultikey("1",5));
        mkset.insert(Tmultikey("6",4));
        mkset.insert(Tmultikey("3",7));
        mkset.insert(Tmultikey("1",6));
    
       std::set<Tmultikey>::iterator bg = mkset.begin();
       for (;bg != mkset.end(); ++bg)
       {
          std::cout<<(*bg).primary()<<std::endl;
       }
    
        Tmultikey::erase(mkset,Tmultikey::Tsecondary(4));
        //Tmultikey::erase(mkset,Tmultikey::Tprimary("1"));
    
       std::cout<<"After erase ....\n";
       bg = mkset.begin();
       for (;bg != mkset.end(); ++bg)
       {
          std::cout<<(*bg).primary()<<std::endl;
       }
       bg = mkset.find(Tmultikey("3",7));
       if (bg != mkset.end())
       {
          std::cout<<"Absolute Find:"<<(*bg).primary()<<" "<<(*bg).secondary()<<std::endl;
       }
       //bg = Tmultikey::find_ex(mkset,Tmultikey::Tprimary("1"));
       bg = Tmultikey::find_ex(mkset,Tmultikey::Tsecondary(5));
       if (bg != mkset.end())
       {
          std::cout<<"Partial Find:"<<(*bg).primary()<<" "<<(*bg).secondary()<<std::endl;
       }
       else {
          std::cout<<"Partial Find: FAILED\n";
       }
    
       return 0;
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #定义MULTIKEYDEF(名称、类型)\
    内联类型const&NAME()const{return d###NAME;}\
    内联void NAME(类型const&t){d##NAME=t;}\
    键入d###名称\
    类T##名称\
    :public std::一元函数{\
    私人:\
    d_型比较\
    公众:\
    T##NAME(类型T):d#u compare(T){\
    T##NAME(T##NAME const&self)\
    :d_compare(self.d_compare){}\
    布尔运算符()(Tmultikey*mk){\
    返回d#u compare==mk->##NAME()\
    } \
    内联类型const&name()const{return d_compare;}\
    }
    类Tmultikey{
    公众:
    //实际钥匙
    //可通过d_primary和d_secondary访问,
    //或primary()和secondary()
    MULTIKEYDEF(主,标准::字符串);
    MULTIKEYDEF(辅助,无符号整数);
    //强制性的
    布尔运算符<(t多键常量和mk)常量{
    if(primary()