web-dev-qa-db-fra.com

Pourquoi quelqu'un utiliserait-il set au lieu de unordered_set?

C++ 0x introduit unordered_set Qui est disponible dans boost et dans de nombreux autres endroits. Ce que je comprends, c’est que unordered_set Est une table de hachage avec une complexité de recherche de O(1). D'autre part, set n'est rien d'autre qu'un arbre avec une complexité de recherche de log(n). Pourquoi diable voudrait-on utiliser set au lieu de unordered_set? C.-à-d. Existe-t-il un besoin de set plus?

128
AraK

Lorsque, pour quelqu'un qui veut parcourir les éléments de l'ensemble, l'ordre est important.

205
moonshadow

Les ensembles non ordonnés doivent payer pour leur temps d'accès moyen O(1)) de plusieurs manières:

  • set utilise moins de mémoire que unordered_set pour stocker le même nombre d'éléments.
  • Pour un petit nombre d'éléments, les recherches dans un set pourraient être plus rapide que les recherches dans un unordered_set.
  • Même si de nombreuses opérations sont plus rapides dans le cas moyen pour unordered_set, il est souvent garanti qu’ils ont meilleure complexité dans le pire des cas pour set (par exemple insert).
  • Ce settrie les éléments est utile si vous voulez y accéder dans l’ordre.
  • Vous pouvez comparer lexicographiquement différents sets avec <, <=, > et >=. unordered_sets ne sont pas nécessaires pour prendre en charge ces opérations.
294
sth

Chaque fois que vous préférez un arbre à une table de hachage.

Par exemple, les tables de hachage sont "O (n)" dans le pire des cas. O(1) est le cas moyen. Les arbres sont au pire "O (log n)".

26
Mehrdad Afshari

Considérez des algorithmes de lignes à la volée. Ces algorithmes échoueraient complètement avec les tables de hachage, mais fonctionneraient à merveille avec des arbres équilibrés. Pour vous donner un exemple concret d'algorithme sweepline, considérons l'algorithme de fortune. http://en.wikipedia.org/wiki/Fortune%27s_algorithm

6
ldog

Parce que std :: set fait partie de Standard C++ et qu'unordered_set ne l’est pas. C++ 0x n'est PAS un standard, pas plus que Boost. Pour beaucoup d'entre nous, la portabilité est essentielle, ce qui signifie rester fidèle à la norme.

6
anon

Utilisez set quand:

  1. Nous avons besoin de données ordonnées (éléments distincts).
  2. Il nous faudrait imprimer/accéder aux données (par ordre de tri).
  3. Nous avons besoin de prédécesseur/successeur d'éléments.

Utilisez unordered_set lorsque:

  1. Nous devons conserver un ensemble d'éléments distincts et aucune commande n'est requise.
  2. Nous avons besoin d’un seul élément d’accès, c’est-à-dire sans traversée.

Exemples:

ensemble:

Entrée: 1, 8, 2, 5, 3, 9

Sortie: 1, 2, 3, 5, 8, 9

Unordered_set:

Entrée: 1, 8, 2, 5, 3, 9

Sortie: 9 3 1 8 2 5 (peut-être cet ordre, influencé par la fonction de hachage)

Principalement différence:

enter image description here

Remarque: (dans certains cas, set est plus pratique), par exemple, en utilisant vector comme clé

set<vector<int>> s;
s.insert({1, 2});
s.insert({1, 3});
s.insert({1, 2});

for(const auto& vec:s)
    cout<<vec<<endl;   // I have override << for vector
// 1 2
// 1 3 

La raison pour laquelle vector<int> peut être la clé de set car vector écraser operator<.

Mais si vous utilisez unordered_set<vector<int>> vous devez créer une fonction de hachage pour vector<int>, car le vecteur n’a pas de fonction de hachage, vous devez donc en définir une comme:

struct VectorHash {
    size_t operator()(const std::vector<int>& v) const {
        std::hash<int> hasher;
        size_t seed = 0;
        for (int i : v) {
            seed ^= hasher(i) + 0x9e3779b9 + (seed<<6) + (seed>>2);
        }
        return seed;
    }
};

vector<vector<int>> two(){
    //unordered_set<vector<int>> s; // error vector<int> doesn't  have hash function
    unordered_set<vector<int>, VectorHash> s;
    s.insert({1, 2});
    s.insert({1, 3});
    s.insert({1, 2});

    for(const auto& vec:s)
        cout<<vec<<endl;
    // 1 2
    // 1 3
}

vous pouvez voir que dans certains cas unordered_set est plus compliqué.

Principalement cités sur: https://www.geeksforgeeks.org/set-vs-unordered_set-c-stl/https://stackoverflow.com/a/29855973/6329006 =

6
Jayhello

Pardon, une dernière chose à noter à propos de la propriété triée:

Si vous voulez une plage de données dans un conteneur, par exemple: Vous avez enregistré l'heure dans set, et vous voulez l'heure à partir de 2013 -01-01 au 2014-01-01.

Pour nordered_set c'est impossible.

Bien entendu, cet exemple serait plus convaincant pour les cas d'utilisation entre map et nordered_map.

3
Mr. Pei

Une dernière chose, en plus de ce que d’autres ont déjà mentionné. Alors que la complexité amortie attendue pour l'insertion d'un élément dans un unordered_set est O (1), de temps en temps, il volonté prend O(n) car la table de hachage doit être restructuré (le nombre de compartiments doit changer) - même avec une 'bonne' fonction de hachage. Tout comme insérer un élément dans un vecteur prend O(n) de temps en temps parce que le tableau sous-jacent doit être réaffecté.

L'insertion dans un ensemble prend toujours au plus O (log n). Cela pourrait être préférable dans certaines applications.

3
Blargle

g++ 6.4 stdlibc ++ ordonné par rapport à un repère défini non ordonné

J'ai analysé cette implémentation dominante de Linux C++ pour voir la différence:

enter image description here

Les détails complets de l'analyse de référence et l'analyse ont été donnés à: Quelle est la structure de données sous-jacente d'une STL définie en C++? et je ne les répéterai pas ici.

"BST" signifie "testé avec std::set et "hash map" signifie "testé avec std::unordered_set. "Heap" est pour std::priority_queue que j’ai analysé à: tas vs arbre de recherche binaire (BST)

En résumé:

  • le graphique montre clairement que dans ces conditions, l'insertion de hashmap était toujours beaucoup plus rapide lorsqu'il y avait plus de 100 000 éléments, et la différence s'accentuait avec l'augmentation du nombre d'éléments

    Le coût de cette augmentation de vitesse est que vous ne pouvez pas traverser efficacement dans l'ordre.

  • les courbes suggèrent clairement que ordonné std::set est basé sur la BST et std::unordered_set est basé sur hashmap. Dans la réponse de référence, j'ai également confirmé que, par étape GDB, débogage du code.

Question similaire pour map vs unordered_map: Y a-t-il un avantage à utiliser map par rapport à unordered_map dans le cas de clés triviales?

D'entrée de jeu, je dirais qu'il est pratique d'avoir des relations dans une relation si vous souhaitez la convertir en un format différent.

Il est également possible que s’il soit plus rapide d’accéder, le temps nécessaire à la construction de l’index ou de la mémoire utilisée lors de sa création et/ou de son accès est plus long.

1
Rushyo

Si vous voulez que les choses soient triées, vous utiliseriez set au lieu de unordered_set. unordered_set est utilisé en dépassement lorsque l'ordre stocké n'a pas d'importance.

1
leiz