Quelle est la structure des données à l'intérieur de std:: map en C++?

je suis débutant et j'apprends le c++ Avoir des moments difficiles pour comprendre les concepts std::map, parce que le code avec lequel je joue implique que le map est un arbre de recherche, c'est-à-dire tous les noms de std::map objets ont *arbre en elle ainsi que des commentaires.

cependant, après lecture de ce document http://www.cprogramming.com/tutorial/stl/stlmap.html j'ai tendance à penser que std::map n'a rien à voir avec l'arbre ou le hash.

donc je suis confus -- les variables et les commentaires dans le code mentir à moi, ou le sujet est plus complexe, je pense que c'est :)

6

6 réponses

std::map est un conteneur associatif. La seule exigence de la norme est que le conteneur doit avoir une interface de conteneur associative et le comportement, la mise en œuvre n'est pas définie. Alors que la mise en œuvre répond aux exigences de complexité et d'interface, est une mise en œuvre valide.

d'autre part, std::map est généralement mis en œuvre avec un arbre rouge-noir , comme la référence dit.

6
répondu Manu343726 2017-05-09 07:15:42

comme l'a écrit chris, la norme ne définit pas la structure interne de la norme std::map ou std::set. Il définit les exigences d'interface et de complexité pour des opérations comme l'insertion d'un élément. Ces structures de données peuvent bien sûr être mises en œuvre sous forme d'arbres. Par exemple, L'implémentation fournie avec VisualStudio est basée sur un arbre rouge-noir.

0
répondu Adam Wulkiewicz 2013-08-24 03:50:53

Carte utilise en interne d'auto-équilibrage de la BST . Jetez un oeil sur ce lien. arbre de recherche binaire auto-équilibrant

0
répondu user1706047 2013-08-24 05:11:14

visualisé extérieurement une carte est juste un conteneur associatif: elle se comporte extérieurement comme un" tableau "(supporte une expression a[x] ) où x peut être n'importe quel type (pas nécessairement entier) est "comparable par <" (donc ordonné).

mais:

  • parce que x peut être n'importe quelle valeur, il ne peut pas être un tableau simple (sinon il doit supporter n'importe quelle valeur d'index: si vous assignez un[1] et un[100] vous avez besoin aussi le 2..99 éléments dans le moyen)
  • parce qu'il doit être rapide dans insert et trouver à n'importe quelle position, il ne peut pas être une structure "linéaire" (sinon les éléments doivent être décalés, et la recherche doit être séquentielle, et les exigences sont "moins que le temps de recherche proportionnel".

l'implémentation la plus courante utilise en interne un arbre d'auto-équilibrage (chaque noeud est une paire clé/valeur, et sont liés àgheter de sorte que le côté gauche a des touches plus basses, et le côté droit a higer touches, de sorte que seraching est relancée pour une recherche binaire), un multi-skip-list (plus rapide que l'arbre dans la récupération, le ralentissement de l'insert) ou une base de hachage table (où chaque valeur de x est relancée à un indice d'un tableau)

0
répondu Emilio Garavaglia 2013-08-24 07:48:56

debug Step into g++ 6.4 stdlibc++ source

saviez-vous que sur Ubuntu 16.04 par défaut g++-6 paquet ou un GCC 6.4 construire à partir de la source vous pouvez entrer dans la bibliothèque C++ sans autre configuration?

en faisant cela nous concluons facilement qu'un arbre rouge-noir utilisé.

cela a du sens, puisque std::map peut être traversé dans l'ordre clé, ce qui ne serait pas efficace si une carte de hachage était utilisée.

a.cpp:

#include <cassert>
#include <map>

int main() {
    std::map<int, int> m;
    m.emplace(1, -1);
    m.emplace(2, -2);
    assert(m[1] == -1);
    assert(m[2] == -2);
}

compiler et déboguer:

g++ -g -std=c++11 -O0 -o a.out ./a.cpp
gdb -ex 'start' -q --args a.out

Maintenant, si vous entrez dans s.emplace(1, -1) vous atteignez immédiatement /usr/include/c++/6/bits/stl_map.h :

556       template<typename... _Args>
557     std::pair<iterator, bool>
558     emplace(_Args&&... __args)
559     { return _M_t._M_emplace_unique(std::forward<_Args>(__args)...); }

qui passe clairement juste avant à _M_t._M_emplace_unique .

donc nous ouvrons le fichier source dans vim et trouvons la définition de _M_t :

    typedef _Rb_tree<key_type, value_type, _Select1st<value_type>,
            key_compare, _Pair_alloc_type> _Rep_type;

    /// The actual tree structure.
    _Rep_type _M_t;

So _M_t est du type _Rep_type et _Rep_type est un _Rb_tree .

OK, maintenant c'est assez de preuves pour moi. Si vous ne croyez pas que _Rb_tree est un arbre noir-rouge, aller un peu plus loin et lire l'algorithme

unordered_map utilise une table de hachage

même procédure, mais remplacer map par unordered_map sur le code.

cela a du sens, puisque std::unordered_map ne peut pas être traversé dans l'ordre, de sorte que la bibliothèque standard a choisi Hachette carte au lieu de l'arbre rouge-noir, puisque Hachette carte a une meilleure amortie insert time complexité.

entrer dans emplace conduit à /usr/include/c++/6/bits/unordered_map.h :

377       template<typename... _Args>
378     std::pair<iterator, bool>
379     emplace(_Args&&... __args)
380     { return _M_h.emplace(std::forward<_Args>(__args)...); }

donc nous ouvrons le fichier source dans vim et cherchons la définition de _M_h :

      typedef __umap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc>  _Hashtable;
      _Hashtable _M_h;

donc c'est une table de hachage.

analogue pour std::set : Quelle est la structure de données sous-jacente d'un ensemble STL en C++?

0

je dirais que si vous pensez à une carte comme une paire, vous ne pouvez pas vous tromper. Map peut être implémenté comme un arbre ou une carte de hachage, mais la façon dont il est implémenté n'est pas aussi importante puisque vous pouvez être sûr que toute implémentation est STL est une implémentation efficace.

-1
répondu Napalidon 2013-08-24 03:25:23