Déterminer si un non-ordonnée vector<T> a tous les éléments uniques

Profilage mon cpu code a suggéré que je que de passer un long moment de la vérification pour voir si un conteneur contient complètement des éléments uniques. En supposant que j'ai des gros contenant des éléments non triés (avec < et = défini), j'ai deux idées sur la façon dont cela pourrait être fait:

La première à l'aide d'un ensemble:

template <class T>
bool is_unique(vector<T> X) {
  set<T> Y(X.begin(), X.end());
  return X.size() == Y.size();
}

La deuxième boucle sur les éléments:

template <class T>
bool is_unique2(vector<T> X) {
  typename vector<T>::iterator i,j;
  for(i=X.begin();i!=X.end();++i) {
    for(j=i+1;j!=X.end();++j) {
      if(*i == *j) return 0;
    }
  }
  return 1;
}

J'ai testé du mieux que je peux, et de ce que je peux recueillir à partir de la lecture de la documentation sur la STL, la réponse est (comme d'habitude), ça dépend. Je pense que dans le premier cas, si tous les éléments sont uniques, il est très rapide, mais si il y a une grande dégénérescence de l'opération semble prendre en O(N^2). Pour le imbriquée itérateur approche au contraire, cela semble être vrai, il est rapide comme l'éclair si X[0]==X[1] mais prend (à juste titre) O(N^2) si tous les éléments sont uniques.

Est-il une meilleure façon de le faire, peut-être un STL algorithme construit à cet effet? Si non, avez-vous des suggestions à la semaine précédente un peu plus d'efficacité?

  • Si le conteneur ne peut contenir des doublons à tous? Peut-être vous avez besoin d'un jeu, pas un vecteur?
  • Votre mise si is_unique serait plus rapide si elle a pris comme const vector<T>& comme argument, au lieu d'accepter son argument par valeur. De cette façon, vous éviter de faire une copie du vecteur et puis aussi la copie de cette copie dans un ensemble.
  • Neil, le récipient doit d'accès aléatoire (d'où le vecteur) pour d'autres parties du code.
  • Si possible, vous souhaitez peut-être envisager de garder le vecteur trié tout le temps que vous le construire. Que ferait is_unique (si mis en œuvre par std::set ou std::unique) exécuter en temps linéaire. En gardant le vecteur trié, vous répartissez le travail au fil du temps, et d'avoir à "payer" pour une partie du travail qu'une seule fois par élément, plutôt que de prendre un grand succès par devoir tout calculer à chaque fois que vous appelez is_unique.
  • Quel est exactement le type de T?
  • Pouvez-vous définir une fonction de hachage sur votre type d'élément? Si donc, à l'aide d'une table de hachage au lieu de binaire basée sur l'arbre set devrait fonctionner très bien, en particulier si vous effectuez un test d'adhésion sur tous les insérer au lieu d'ajouter tout d'abord et puis de vérifier. Noter que la standard STL n'ont pas de base de hachage récipients, bien hash_set se présente comme une extension, ou de l'utilisation de Boost.
  • En plus de tzaman commentaire, je pense que vous devriez également considérer la taille moyenne de votre jeu de données. Passez-vous le temps de vérifier les collisions en milliers de vecteurs de plusieurs dizaines d'entrées chacun, ou des dizaines de vecteurs de milliers d'entrées de chaque? Lire le papier sur la recherche ou de l'algorithmes de tri écrit dans les 15 dernières années, et il est difficile de ne pas en trouver un qui parle de la façon dont ceci ou cela algorithme dépasse l'actuel champion par tels et tels pour cent dans une liste en particulier de la taille de portée (par exemple, 10k à 50k entrées).

InformationsquelleAutor Hooked | 2010-05-04