3 Stimmen

Beibehaltung eines eindeutigen Satzes von Elementen nach verschiedenen Kriterien C++ STL

Ich muss eine Komponente entwickeln, die eine mehr als 100.000 Instanzen einer Klasse haben wird. Und ich möchte einen Bericht erstellen, der auf den verschiedenen Kriterien (Mitglieder) der jeweiligen Klasse erstellen. zum Beispiel, Eine Mitarbeiterklasse mit den Datenfeldern id, Namen, Adresse, Telefonnummer. Bericht Generierung wird basieren auf


  1. Namen_aufsteigend
  2. Namen_absteigend
  3. addr_ascending
  4. phoneno_aszierend
  5. eindeutige_Namen
  6. eindeutige_Adresse
  7. einzigartig_phoneno

Die Laufzeit-Iteration von Instanzen für jeden Aufruf ist sehr langsam, da es sich um eine lineare Operation für eine große Anzahl von Instanzen handelt und einen Sortiermechanismus erfordert.

So habe ich einen Zeiger von jeder Instanz in einem Container auf verschiedene sortierte Weise gespeichert. Aber erfordert mehr Speicher als erforderlich. Bitte schlagen Sie mir einen besseren Weg, dies zu tun. Ich habe Beispiel-Code-Snippet gepostet, die ich gefolgt, um oben zu erreichen.

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     };

5voto

icecrime Punkte 70619

Scheint ein perfekter Kandidat zu sein für Boost.MultiIndex :

Die Boost-Multi-Index-Behälter Bibliothek bietet eine Klassenvorlage namens multi_index_container, die ermöglicht. die Konstruktion von Containern Pflege eines oder mehrerer Indizes mit unterschiedlicher Sortierung und Zugriff Semantik .

3voto

Khaled Alshaya Punkte 90854

Ich habe Boost.Multi_index in der Vergangenheit erfolgreich verwendet. Auf den ersten Blick mag man es seltsam finden, aber in Wirklichkeit ist es eine sehr interessante Bibliothek. Beachten Sie bei der Verwendung, dass Sie nicht das "Wie", sondern das "Was" in Ihrem angepassten Container bereitstellen. Nehmen wir an, dass Sie den folgenden Typ haben:

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;
    }
};

Sie erstellen einen Container, der die Objekte und so viele Indizes enthält, wie Sie möchten. Bevor wir beginnen, definieren wir die Tags der Indizes. Die Tags sind einfach Tags!, die Sie verwenden, um auf Ihre Indizes mit Namen zuzugreifen, anstatt mit magischen Zahlen:

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

Dann definieren wir unsere "Datenbank" mit den erforderlichen Indizes:

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;

Der erste Punkt ist die Art der Elemente im Container. Dann sagen Sie, ich möchte diesen Container durch Folgendes indizieren:

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> >
>

Sie geben einfach die Art des Indexes an, den Sie offenlegen möchten. Es gibt verschiedene Typen, und es hängt von der Semantik der Daten ab, die Sie haben. Es ist gut, ein Tag für jeden Index anzugeben (der erste Parameter), und Sie geben an, dass Sie den Typ durch den zweiten Template-Parameter indizieren wollen. Es gibt verschiedene Möglichkeiten, den "Schlüssel" der Daten zu wählen. Der Schlüssel muss eigentlich nicht eindeutig sein!

Von nun an gehen Sie mit user_db wie mit einem normalen std::multi_set ! mit einem kleinen Unterschied, der tatsächlich den Unterschied ausmacht ;) Nehmen wir an, Sie möchten die Informationen über die seriösen Benutzer aus einer Datei laden und die geordneten Informationen nach den von uns erstellten Ungenauigkeiten neu sortieren:

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

2voto

Juraj Blaho Punkte 13081

Blick auf boost::multi_index aquí . Es gibt einen Container boost::multi_index_contaier die es Ihnen ermöglicht, mit verschiedenen Tasten nach Artikeln zu suchen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X