C++11: Zwei Möglichkeiten zum Übergeben von Parametern beim Instanziieren von unordered_map

[Haftungsausschluss] Ich bin eine Person mit wenig Talent und Wissen, und dies ist nur eine Möglichkeit, andere vorzustellen. Wenn es Fehler gibt, hoffe ich, dass Sie mich korrigieren.

[Originallink] C++11: ungeordnete Karten Von Ernesto Bascón Pantojas Blog

【Zusammenfassung des Inhalts】

        1. Einführung in ungeordnete Karten.
        2. Zwei Möglichkeiten, Parameter beim Instanziieren von ungeordneter_Karte zu übergeben

【Text】

       C++ STL stellt einen geordneten Kartenassoziativcontainer (Vorlagenklasse) bereit, und seine interne Implementierung ist ein effizienter ausgeglichener Binärbaum; der Vorteil dieser Implementierung ist eine hohe Abrufeffizienz (durchschnittliche Zeitkomplexität O (log2N), N repräsentiert die Elemente in der Kartennummer). ) und durchqueren Sie den Kartencontainer, um Elemente in der sortierten Reihenfolge zu finden.

       C++11 fügt einen ungeordneten Kartencontainer hinzu, dessen interne Implementierung eine Hash-Tabelle ist. Der wesentliche Vorteil dieser Implementierung besteht darin, dass die zeitliche Komplexität des Zugriffs auf jedes Element im Container konstant ist (O(1)), ihr offensichtlicher Nachteil besteht jedoch darin, dass die Elemente im Container ungeordnet sind und mehr Speicherplatz benötigen (im Vergleich zu Map). .

      Die API beider Kartenarten ist ziemlich ähnlich; Schauen Sie sich zum Beispiel diesen Code an:

     Die APIs der beiden oben genannten Kartencontainer sind sehr ähnlich, wie im folgenden Beispielcode gezeigt:

#include <iostream>
#include <string>
#include <map>
#include <unordered_map>
 
using namespace std;
 
template <class T>
void show(const T& x)
{
    for (const auto& i : x)
        cout << i.first << "; " << i.second << endl;
}
 
template <template <class...> class T>
void test()
{
    T<string, int> x;
    x.insert(make_pair("one", 1));
    x.insert(make_pair("two", 2));
    x.insert(make_pair("three", 3));
    x.insert(make_pair("four", 4));
     
    show(x);
}
 
 
 
int main()
{
  test<map>();
  cout << "*******************" << endl;
  test<unordered_map>();
}

Die Ausgabe des obigen Programmcodes ist wie folgt:


four; 4
one; 1
three; 3
two; 2
*******************
one; 1
three; 3
two; 2
four; 4

        如你所见:

  • 两种容器创建和操作使用的方式完全一致。
  •  unordered_map容器的输出是无序的。

       如果只是使用STL提供的基本类型(int ,char,long,short,etc)和strings,一切都很美好(STL已经提供默认的hash code和compare函数)。一旦我们想使用自定义的数据类型:类(class)或结构体(struct)时,使用unordered_map就不太舒适了。

      我们知道,在JAVA中,如果类要作为容器的键(Key),需要重写(override)类的equals 和hashCode方法,否则代码能正常编译,却难如期工作。(假设你已经有java知识)

      在C++中,我们也需要做类似的事情,比如,1、需要实现一个函数对象hash(function object,对应于下面代码片段中的hash<KEY>参数)用于生成哈希值(hash code),2、同时需要实现一个函数对象equal_to(对应于下面代码中的equal_to<K>参数)用于比较自定义类或结构体的两个对象,3、实例化unordered map容器时,传入前两步构造的函数对象作为模板参数。具体代码如下:

template <typename KEY, typename VALUE, typename HASH = hash<KEY>, typename EQUAL = equal_to<K> >
class unordered_map
{ ..... };
        Beim Instanziieren eines ungeordneten Kartencontainers lautet die Vorlage des zu implementierenden Hash-Funktionsobjekts wie folgt:

template <typename T>
class hash
{
    public:
        long operator()(const T& o) const { return 0; }
};

und bietet Spezialisierungen für alle primitiven Typen und für die Klasse std::string.

Die equal_toKlassenvorlage wird ähnlich wie folgt implementiert:

template <typename T>
class equal_to
{
  public:
    bool operator()(const T& a, const T& b) const { return a == b; }
};
        Wenn wir es also wagen, den Operator „operator==“ in der benutzerdefinierten Klasse oder Struktur von KEY neu zu schreiben, müssen wir den Vorlagenparameter „EQUAL“ (Funktionsobjekt „equal_to“) nicht bereitstellen.

        Nehmen Sie nun die benutzerdefinierte Struktur (Strukturartikel_ID) und die benutzerdefinierte Klasse (Klassenartikel) als Beispiel. Die Implementierung lautet wie folgt:

struct article_id
{
  string brand;
  int id;
   
  article_id(const string& b, int id) : brand(b), id(id) { }
};
 
ostream& operator<<(ostream& os, const article_id& a)
{
  return os << "(" << a.brand << ") " << a.id;
}
 
class article
{
  string brand, model, description;
 
  public:
    article(const string& b, const string& m, const string& d)
       : brand(b), model(m), description(d) { }
 
    const string& get_brand() const { return brand; }
    const string& get_model() const { return model; }
    const string& get_description() const { return description; }
};
 
ostream& operator<<(ostream& os, const article& a)
{
  return os << "Brand: " << a.get_brand() << "; Model: " << a.get_model()
         << "; Description: " << a.get_description();
}
      Wenn Sie ungeordneten Kartenspeicher verwenden, eine benutzerdefinierte Struktur (Artikel-ID) als Schlüssel und die Instanz der benutzerdefinierten Klasse Artikel als Wert (<Artikel-ID, Artikelobjekt>) als Schlüssel-Wert-Paar verwenden, müssen wir die folgende Arbeit ausführen , 1. Implementieren Sie das Hash-Funktionsobjekt , 2. Implementieren Sie das gleich _to-Funktionsobjekt, der Code lautet wie folgt:
class article_hash
{
  public:
    long operator()(const article_id& x) const
    {
        hash<string> z;
        return z(x.brand) * 100 + x.id;
    }
};
 
class article_equal_to
{
  public:
     bool operator()(const article_id& a, const article_id& b) const
     {
        return a.brand == b.brand && a.id == b.id;
     }
};

       Nachdem wir die Funktionsobjekte hash und equal_to definiert haben, können wir die benutzerdefinierte Struktur Article_id als Schlüssel der ungeordneten Kartenfunktion verwenden. Der Code lautet wie folgt:

int main()
{
   unordered_map<article_id, article, article_hash, article_equal_to> x;
   x.insert(make_pair(article_id("acme", 1), article("acme", "tv", "Acme TV")));
   x.insert(make_pair(article_id("foo", 4), article("foo", "phone", "fooPhone")));
   show(x);
   return 0;
}
      Bisher haben wir die erste Möglichkeit kennengelernt, Parameter beim Instanziieren eines ungeordneten Kartencontainers zu übergeben, d. h. beim Instanziieren des Containers den von Ihnen implementierten Vorlagenparameter des Funktionsobjekts (Hash equal_to) anzuzeigen.

      Eine andere ausgereiftere Möglichkeit besteht darin, die Funktionsobjekte „article_hash“ und „article_equal_to“ einer benutzerdefinierten Struktur oder Klasse zu verwenden, um die Hash- und equal_to-Vorlagen im Namespace „std“ zu „überschreiben“ (Spezialisierungen).

namespace std
{
    template <>
    class hash<article_id>
    {
      public:
        long operator()(const article_id& x) const
        {
            hash<string> z;
            return z(x.brand) * 100 + x.id;
        }
    };
     
    template <>
    class equal_to<article_id>
    {
      public:
         bool operator()(const article_id& a, const article_id& b) const
         {
            return a.brand == b.brand && a.id == b.id;
         }
    };
}

        Wenn wir die zweite Methode verwenden, um die Hash- und equal_to-Vorlagen im Namespace std neu zu schreiben (Spezialisierungen) und den ungeordneten Kartencontainer zu instanziieren, besteht keine Notwendigkeit, die eingehenden Parameter 3 und Parameter 4 anzuzeigen (Typname HASH = hash <KEY>, Typname EQUAL=equal_to <K>)

int main()
{
   unordered_map<article_id, article> x;
   x.insert(make_pair(article_id("acme", 1), article("acme", "tv", "Acme TV")));
   x.insert(make_pair(article_id("foo", 4), article("foo", "phone", "fooPhone")));
   show(x);
   return 0;
}

WIRKLICH COOL.OVER :).

Weitere Links:

http://cpptutorials.freeforums.org/tr1-unordered-map-t621.html

http://stackoverflow.com/questions/15595804/c-hash-function-for-string-in-unordered-map

http://stackoverflow.com/questions/15601568/need-example-of-stdunordered-map-constructor




                       

         


おすすめ

転載: blog.csdn.net/zdsx1104/article/details/23301527