在不同的标准C ++ STL上维护一组唯一的元素

时间:2010-12-15 12:57:29

标签: c++

  

我必须开发一个组件   将有一个以上   100,000个类的实例。和我   想要基于的生成报告   不同的标准(成员)   特定班级。例如,   具有数据字段ID的员工类,   名字,地址,phoneno。报告   一代将基于


  1. names_ascending
  2. names_descending
  3. addr_ascending
  4. phoneno_asceding
  5. unique_names
  6. unique_addr
  7. unique_phoneno
  8. 每次调用的实例的运行时迭代非常慢,因为它是对大量实例的线性操作,需要排序机制。

    所以我以不同的排序方式在容器中存储了每个实例的指针。但是需要更多的内存。请建议我这样做的更好方法。我已经发布了我遵循的示例代码片段以实现上述目标。

    class Employee
    {
        int    m_id;
        string m_name;
        string m_addr;
        string m_phone;
    
    public:
        Employee(int id, string name, string addr, string phone) : 
             m_id(id), m_name(name), m_addr(addr), m_phone(phone) { }
    
        int    id()      const { return m_id;    }
        string name()    const { return m_name;  }
        string addr()    const { return m_addr;  }
        string phoneno() const { return m_phone; }
    };
    
    //custom predicate for std containers
    struct IDComparator
    {
        bool operator() (const Employee* e1, const Employee* e2 )
        {
           return e1->id() < e2->id();
        }
    };
    
    struct NameComparator
    {
        bool operator() (const Employee* e1, const Employee* e2 )
        {
           return e1->name() < e2->name();
        }
    }
    
    struct AddressComparator
    {
        bool operator() (const Employee* e1, const Employee* e2 )
        {
           return e1->addr() <  e2->addr();
        }
    };
    
    struct PhoneComparator
    {
        bool operator() (const Employee* e1, const Employee* e2 )
        {
           return e1->phoneno() < e2->phoneno();
        }
    };
    
    
    //Class which holds huge number of employee instances
    class Dept
    {
    private:
        typedef set<Employee*, IDComparator> EMPID; //unnique id
        typedef EMPID::iterator EMPID_ITER;
    
        typedef multiset<const Employee*, NameComparator> EMPNAME;   // for sorted names
        typedef EMPNAME::iterator NAME_ITER;
    
        typedef multiset<const Employee*, AddressComparator> EMPADDR; // for sorted addr
        typedef EMPADDR::iterator ADDR_ITER;
    
        typedef multiset<const Employee*, PhoneComparator> EMPPHONE;  // for sorted phoneno
        typedef EMPPHONE::iterator PHONE_ITER;
    
    private:
        EMPID    m_empids;
        EMPNAME  m_names ;
        EMPADDR  m_addr;
        EMPPHONE m_phoneno;
    
    public:
        Dept() { }
        ~Dept() { //delete the instances of employees }
    
        void add(Employee* e) 
        {
            EMP_ITER iter = m_empids.insert(e).first;
            const Employee* empptr = &*iter;
            m_names.insert(empptr);    // adds employee pointer to name multimap
            m_addr.insert(empptr);     // adds employee pointer to addr multimap
            m_phoneno.insert(empptr);  // adds employee pointer to phone multimap
        }
    
    
        void print_emp_dtls()       const; //prints all the emp dtls iterating though EMPID 
    
        void print_unique_names()   const; //iterate EMPNAME & use upperbound & lowerbound, prints unique names 
        void print_asc_name()       const; //iterate EMPNAME & prints all names in ascending order
        void print_desc_name()      const; //back iterate EMPNAME & prints all names in descending order
    
        void print_unique_adrr()    const; //iterate EMPADDR & use upperbound & lowerbound, prints unique address
        void print_asc_addr()       const; //iterate EMPADDR & prints all addr in ascending order
        void print_desc_addr()      const; //back iterate EMPADDR & prints all address in descending order
    
        void print_unique_phoneno() const; //iterate EMPPHONE & use upperbound & lowerbound,prints unique phoneno
        void print_asc_phoneno()    const; //iterate EMPPHONE & prints all phoneno in ascending order
        void print_desc_phoneno()   const; //back iterate EMPPHONE & prints all phoneno in     };
    

3 个答案:

答案 0 :(得分:5)

似乎是Boost.MultiIndex的完美候选人:

  

Boost多指数容器   库提供了一个类模板   名为multi_index_container的   能够构建容器   保持一个或多个指数   不同的排序和访问   语义

答案 1 :(得分:3)

我过去成功使用过Boost.Multi_index。你可能会从第一眼看到它很奇怪,但实际上它是退出有趣的库。在使用它时请记住,您没有在自定义容器中提供“如何”而是“什么”。假设您有以下类型:

struct user_t
{
    string id, name, email;
    int age;
    friend ostream& operator<<(ostream& output_stream, const user_t& user)
    {
        return output_stream
            << user.id    << " "
            << user.name  << " "
            << user.age   << " "
            << user.email << "\n";
    }
    friend istream& operator>>(istream& input_stream, user_t& user)
    {
        return input_stream >> user.id >> user.name >> user.age >> user.email;
    }
};

您将创建一个容器,它可以保存对象和任意数量的索引。在我们开始之前,我们定义索引的标签。标签只是标签!您用来通过名称而不是神奇的数字来访问索引:

struct by_id    { };
struct by_name  { };
struct by_age   { };
struct by_email { };

然后我们用所需的索引定义我们的“数据库”:

typedef multi_index_container<
    user_t,
    indexed_by
    <
      ordered_unique<tag<by_id>, member<user_t, string, &user_t::id> >,
      ordered_non_unique<tag<by_name>, member<user_t, string, &user_t::name> >,
      ordered_non_unique<tag<by_age>, member<user_t, int, &user_t::age> >,
      ordered_non_unique<tag<by_email>, member<user_t, string, &user_t::email> >
    >
> user_db;

首先是容器中的元素类型。然后,您说我想通过以下内容索引此容器:

indexed_by
<
  ordered_unique<tag<by_id>, member<user_t, string, &user_t::id> >,
  ordered_non_unique<tag<by_name>, member<user_t, string, &user_t::name> >,
  ordered_non_unique<tag<by_age>, member<user_t, int, &user_t::age> >,
  ordered_non_unique<tag<by_email>, member<user_t, string, &user_t::email> >
>

您只需指定要公开的索引类型。实际上有各种类型,它取决于您拥有的数据的语义。最好为每个索引(第一个参数)指定一个标记,并指定要通过第二个模板参数索引类型。实际上有多种方法可以选择数据的“关键”。密钥实际上不需要是唯一的!

从现在开始,您只需像常规std::multi_set一样处理user_db!实际上差别很小;)让我们说你想从文件中加载系列化用户的信息,并根据我们创建的不足重新定位有序信息:

 user_db load_information()
{
    ifstream info_file("information.txt");
    user_db db;
    user_t user;
    while(info_file >> user)
        db.insert(user);
    return db;
}
template <typename index_t>
void save_information_by(ostream& output_stream, const index_t& index)
{
    ostream_iterator<user_t> serializer(output_stream);
    copy(index.begin(), index.end(), serializer);
}
int main()
{
    ofstream
        by_id_file("by_id.txt"),
        by_name_file("by_name.txt"),
        by_age_file("by_age.txt"),
        by_email_file("by_email.txt");
    user_db db = load_information();
    // You see why we created the tags,
    // if we didn't we had to specify the index like the following:
    // const auto& name_index  = db.get<by_name>(); ==
    // const auto& name_index  = db.get<1>();
    const auto& id_index    = db.get<by_id>();
    const auto& name_index  = db.get<by_name>();
    const auto& age_index   = db.get<by_age>();
    const auto& email_index = db.get<by_email>();
    save_information_by(by_id_file, id_index);
    save_information_by(by_name_file, name_index);
    save_information_by(by_age_file, age_index);
    save_information_by(by_email_file, email_index);
}

答案 2 :(得分:2)

查看boost::multi_index here。有一个容器boost::multi_index_contaier,允许您使用各种键搜索项目。