2010-12-15 22 views
3

我必須開發一個組件,其中 將具有超過100,000個類的實例。並且我想根據特定類的不同標準(成員) 生成報告。例如, 具有數據字段ID, 名稱,地址,phoneno的員工類。報告wiil根據在不同的標準上維護一組獨特的元素C++ STL


  1. names_ascending
  2. names_descending
  3. addr_ascending
  4. phoneno_asceding
  5. unique_names
  6. unique_addr
  7. 聯合國 代ique_phoneno

每次調用的實例的運行時迭代非常慢,因爲它是大量實例的線性操作並且需要排序機制。

所以我已經存儲在不同的排序方式的容器中的每個實例的指針。但需要比所需更多的內存。請給我一個更好的方法來做到這一點。我已經發布了示例代碼片段,我遵循上面的實現。

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

我過去成功地使用了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> > 
> 

您只需指定要暴露的索引類型。實際上有各種類型,它取決於你擁有的數據的語義。給每個索引(第一個參數)賦予一個標籤是很好的,並且您指定要通過第二個模板參數的內容來索引該類型。實際上有多種方式來選擇數據的「關鍵」。關鍵並不需要實際唯一!

從現在開始,你只需要處理user_db就像正常的std::multi_set!一個小的差異,使差異實際上;)比方說,你要加載serilaized用戶從文件信息,並根據我們建立的indecies reserlize訂購信息:

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); 
} 
+0

+1提供代碼! :) – Nim 2010-12-15 14:17:34

+0

感謝球員....我熟悉STL,但新手到BOOST庫。這對我有用。 – Naveen 2010-12-15 14:23:02

+0

@Naveen:那麼你應該接受正確的答案:這就是你如何說Stack Overflow的「感謝這個解決方案」! – icecrime 2010-12-15 21:59:16

2

boost::multi_indexhere。有一個容器boost::multi_index_contaier它允許您使用各種鍵搜索項目。

5

似乎是Boost.MultiIndex一個完美的候選人:

升壓多指標集裝箱 庫提供了一個類模板 名爲multi_index_container將 使容器 維護一個或多個索引與 不同的建設排序和訪問 語義