web-dev-qa-db-fra.com

Existe-t-il une classe sorted_vector, qui prend en charge insert () etc.?

Souvent, il est plus efficace d'utiliser un std::vector Trié au lieu d'un std::set. Quelqu'un connaît-il une classe de bibliothèque sorted_vector, Qui a fondamentalement une interface similaire à std::set, Mais insère des éléments dans le vecteur trié (afin qu'il n'y ait pas de doublons), utilise la recherche binaire pour find éléments, etc.?

Je sais que ce n'est pas difficile à écrire, mais il vaut probablement mieux ne pas perdre de temps et utiliser de toute façon une implémentation existante.

pdate: La raison d'utiliser un vecteur trié au lieu d'un ensemble est la suivante: si vous avez des centaines de milliers de petits ensembles qui ne contiennent que 10 membres chacun, il est plus efficace en mémoire d'utiliser simplement triés vecteurs à la place.

53
Frank

Boost.Container flat_set

Les conteneurs Boost.Container flat_ [multi] map/set sont des conteneurs associatifs basés sur des vecteurs ordonnés basés sur les directives d'Austern et d'Alexandrescu. Ces conteneurs vectoriels ordonnés ont également bénéficié récemment de l'ajout de la sémantique des mouvements au C++, accélérant considérablement les temps d'insertion et d'effacement. Les conteneurs associatifs plats ont les attributs suivants:

  • Recherche plus rapide que les conteneurs associatifs standard
  • Itération beaucoup plus rapide que les conteneurs associatifs standard.
  • Moins de consommation de mémoire pour les petits objets (et pour les gros objets si shrink_to_fit est utilisé)
  • Amélioration des performances du cache (les données sont stockées dans une mémoire contiguë)
  • Itérateurs non stables (les itérateurs sont invalidés lors de l'insertion et de l'effacement d'éléments)
  • Les types de valeurs non copiables et non mobiles ne peuvent pas être stockés
  • Sécurité d'exception plus faible que les conteneurs associatifs standard (les constructeurs de copie/déplacement peuvent lancer lors du décalage des valeurs dans les effacements et les insertions)
  • Insertion et effacement plus lents que les conteneurs associatifs standard (spécialement pour les types non mobiles)

Démo en direct :

#include <boost/container/flat_set.hpp>
#include <iostream>
#include <ostream>

using namespace std;

int main()
{
    boost::container::flat_set<int> s;
    s.insert(1);
    s.insert(2);
    s.insert(3);
    cout << (s.find(1)!=s.end()) << endl;
    cout << (s.find(4)!=s.end()) << endl;
}

jalf: Si vous voulez un vecteur trié, il est probablement préférable d'insérer tous les éléments, puis d'appeler std :: sort () une fois, après les insertions.

boost :: flat_set peut le faire automatiquement :

template<typename InputIterator> 
flat_set(InputIterator first, InputIterator last, 
         const Compare & comp = Compare(), 
         const allocator_type & a = allocator_type());

Effets : construit un ensemble vide en utilisant l'objet de comparaison et l'allocateur spécifiés, et insère des éléments de la plage [premier, dernier).

Complexité : linéaire en N si la plage [premier, dernier) est déjà triée à l'aide de comp et sinon N * log (N) , où N est le dernier - le premier.

28
Evgeny Panasyuk

La raison pour laquelle un tel conteneur ne fait pas partie de la bibliothèque standard est qu'il serait inefficace. L'utilisation d'un vecteur pour le stockage signifie que les objets doivent être déplacés si quelque chose est inséré au milieu du vecteur. Faire cela sur chaque insertion coûte inutilement cher. (En moyenne, la moitié des objets devront être déplacés pour chaque insertion. C'est assez coûteux)

Si vous voulez un vecteur trié, il est probablement préférable d'insérer tous les éléments, puis d'appeler std::sort()ne fois, après les insertions.

7
jalf

Je pense qu'il n'y a pas d'adaptateur de "conteneur trié" dans la STL car il existe déjà les conteneurs associatifs appropriés pour garder les choses triées qui seraient appropriées à utiliser dans presque tous les cas. Pour être honnête, à propos de la seule raison pour laquelle je peux penser du haut de ma tête pour avoir trié vector<> le conteneur pourrait être d'interopérer avec les fonctions C qui attendent un tableau trié. Bien sûr, il me manque peut-être quelque chose.

Si vous pensez qu'un _ vector<> serait plus adapté à vos besoins (étant conscient des défauts d'insertion d'éléments dans un vecteur), voici une implémentation sur Code Project:

Je ne l'ai jamais utilisé, je ne peux donc pas m'en porter garant (ni sa licence - le cas échéant). Mais une lecture rapide de l'article et il semble que l'auteur ait au moins fait un bon effort pour que l'adaptateur de conteneur ait une interface STL appropriée.

Cela semble mériter un examen plus approfondi.

5
Michael Burr

Si vous décidez de lancer le vôtre, vous pouvez également consulter boost: ublas. Plus précisément:

#include <boost/numeric/ublas/vector_sparse.hpp>

et regardez coordonnée_vecteur, qui implémente un vecteur de valeurs et d'index. Cette structure de données prend en charge O(1) insertion (violant le tri), mais trie ensuite les Omega à la demande (n log n). Bien sûr, une fois triées, les recherches sont O (logn) . Si une partie du tableau est triée, l'algorithme le reconnaît et trie uniquement les éléments nouvellement ajoutés, puis effectue une fusion in situ. Si vous vous souciez de l'efficacité, c'est probablement le mieux que vous puissiez faire.

4
Neil G

Le Loki d'Alexandresu a une implémentation vectorielle triée, si vous ne voulez pas passer par l'effort insignifiant de rouler vous-même.

http://loki-lib.sourceforge.net/html/a00025.html

3
Lance Diduck

Ici est ma classe sorted_vector que j'utilise dans le code de production depuis des années. Il a des surcharges pour vous permettre d'utiliser un prédicat personnalisé. Je l'ai utilisé pour des conteneurs de pointeurs, ce qui peut être une très bonne solution dans de nombreux cas d'utilisation.

0
moodboom