2010-10-19 7 views
5

J'ai un vecteur de doubles. Je veux trier du plus haut au plus bas, et obtenir les indices des éléments K supérieurs. std :: tri ne fait que trier et ne retourne pas les index je crois. Quel serait un moyen rapide d'obtenir les meilleurs indices K des éléments les plus importants?comment pourrais-je trier une liste et obtenir les meilleurs éléments K? (STL)

+2

Ne seraient-ils pas 0, 1, 2, 3, 4, 5, 6, 7, 8 et 9? – wheaties

+0

Après le tri, les premiers éléments K (ou derniers K éléments) seraient les éléments supérieurs. – Kendrick

+1

après tri, oui, mais apparemment kop aimerait trouver les indices dans la gamme originale, avant le tri. – flownt

Répondre

2

La première chose qui vient à l'esprit est un peu hackish, mais vous pouvez définir une struct qui a stocké à la fois le double et son index d'origine, puis surcharger l'opérateur < pour trier en fonction du double:

struct s { 
    double d; 
    int index; 
    bool operator < (const struct &s) const { 
     return d < s.d; 
    } 
}; 

Ensuite, vous pouvez récupérer les index d'origine de la structure.

exemple Fuller:

vector<double> orig; 
vector<s> v; 
... 
for (int i=0; i < orig.size(); ++i) { 
    s s_temp; 
    s_temp.d = orig[i]; 
    s_temp.index = i; 
    v.push_back(s); 
} 
sort(v.begin(), v.end()); 
//now just retrieve v[i].index 

Cela les laisser triées de la plus petite à la plus grande, mais vous pouvez surcharger la place l'opérateur> puis passer plus à la fonction de tri si on le souhaite.

+0

-1: trop lent pour la chose, que vous voulez ... –

+0

nth_element comme vous l'avez suggéré ne fonctionnerait pas si le N supérieur devait être trié eux-mêmes; partial_sort ne serait significativement plus rapide que si K était plutôt petit et n plutôt grand - n log (K) par opposition à n log (n); mais n'hésitez pas à utiliser partial_sort si vous avez besoin de la performance, mais vous devrez surcharger l'opérateur> et trier du plus grand au plus petit (partial_sort trie la partie supérieure des éléments, pas la partie inférieure) – user470379

+0

Oui, vous ' re droit. Mais quand vous n'avez pas d'attentes sur K et N (je ne sais pas combien K sera plus petit que N), il est préférable d'utiliser un tri partiel (je pense) - cela pourrait être plus rapide dans 50% des cas, mais c'est quand même moins perdu de temps. Et juste une remarque - vous n'avez pas besoin de surcharger l'opérateur> pour faire l'oposite et le rendre compliqué, si vous en avez besoin. Vous pourriez juste passer une fonction, définie par vous, à partial_sort. Par exemple: 'partial_sort (myvector.begin(), myvector.begin() + 5, myvector.end(), myfunction);' C'est également similaire à nth_element. –

0

Vous n'êtes pas sûr des algorithmes pré-conservés, mais jetez un oeil à selection algorithms; Si vous avez besoin des K premiers éléments d'un ensemble de N valeurs et N est beaucoup plus grand que K, il existe des méthodes beaucoup plus efficaces.

Si vous pouvez créer une classe d'indexation (comme la réponse de @ user470379 - essentiellement une classe qui encapsule un pointeur/index sur les données "réelles" en lecture seule), utilisez une file d'attente prioritaire de taille maximale K, et ajoutez chaque élément non trié à la file d'attente prioritaire, en supprimant l'élément le plus en bas lorsque la file atteint la taille K + 1. Dans les cas comme N = 10 , K = 100, cela gère les cas beaucoup plus simplement + efficacement qu'un tri complet.

0

OK, qu'en pensez-vous?

bool isSmaller (std::pair<double, int> x, std::pair<double, int> y) 
{ 
    return x.first< y.first; 
} 

int main() 
{ 
    //... 
    //you have your vector<double> here, say name is d; 
    std::vector<std::pair<double, int> > newVec(d.size()); 
    for(int i = 0; i < newVec.size(); ++i) 
    { 
     newVec[i].first = d[i]; 
     newVec[i].second = i; //store the initial index 
    } 
    std::sort(newVec.begin(), newVec.end(), &isSmaller); 
    //now you can iterate through first k elements and the second components will be the initial indices 
} 
0

Utilisation multimap pour vector « s (valeur, index) pour gérer dups. Utilisez les itérateurs inversés pour parcourir les résultats dans l'ordre décroissant.

#include <multimap> 
#include <vector> 
using namespace std; 

multimap<double, size_t> indices; 
vector<double> values; 

values.push_back(1.0); 
values.push_back(2.0); 
values.push_back(3.0); 
values.push_back(4.0); 

size_t i = 0; 
for(vector<double>::const_iterator iter = values.begin(); 
     iter != values.end(); ++iter, ++i) 
{ 
    indices.insert(make_pair<double,int>(*iter, i)); 
} 

i = 0; 
size_t limit = 2; 
for (multimap<double, size_t>::const_reverse_iterator iter = indices.rbegin(); 
    iter != indices.rend() && i < limit; ++iter, ++i) 
{ 
    cout << "Value " << iter->first << " index " << iter->second << endl; 
} 

sortie est

Valeur 4 Indice 3

Valeur 3 Indice 2

Si vous voulez juste les vector indices après tri, utilisez ceci:

#include <algorithm> 
#include <vector> 
using namespace std; 

vector<double> values; 

values.push_back(1.0); 
values.push_back(2.0); 
values.push_back(3.0); 
values.push_back(4.0); 

sort(values.rbegin(), values.rend()); 

Les K premières entrées sont indexées de 0 à K-1, et apparaissent dans l'ordre décroissant. Celui-ci utilise itérateurs inverse combinés à la norme sort (en utilisant less<double> pour atteindre l'ordre décroissant lorsque itéré avant Équivalemment.

sort(values.rbegin(), values.rend(), less<double>()); 

Exemple de code pour l'excellente solution nth_element suggérée par @Kiril ici (K = 125000, N = 500000). Je voulais essayer ça, alors voilà.

vector<double> values; 

for (size_t i = 0; i < 500000; ++i) 
{ 
    values.push_back(rand()); 
} 

nth_element(values.begin(), values.begin()+375000, values.end()); 
sort(values.begin()+375000, values.end()); 

vector<double> results(values.rbegin(), values.rbegin() + values.size() - 375000); 
10

vous pouvez utiliser le nth_element algorithme STL - cela vous renvoyer les N plus grands éléments (ce qui est le plus rapide, en utilisant stl) et ensuite utiliser .Sort sur eux, ou vous pouvez utiliser l'algorithme de partial_sort, si vous voulez que les premiers éléments de K à trier (:

en utilisant simplement .Sort est horrible - il est très lent pour le but que vous voulez .. .Sort est grand algorithme STL, mais pour trier le tout récipient, non seulement les premiers éléments K (ce n'est pas un accident l'existence de nth_element et partial_sort;)

+1

+1 pour trouver nth_element. (s'il vous plaît lien vers les documents officiels si) –

+0

http://cplusplus.com/reference/algorithm/nth_element, là vous pouvez trouver le partial_sort, aussi –

+1

@Jason: Où trouvez-vous des "documents officiels" en ligne pour lier? – GManNickG

0

Vous avez donc réellement besoin d'une structure qui mappe les indices en doubles correspondants.

Vous pouvez utiliser la classe std::multimap pour effectuer cette correspondance. Comme Jason l'a noté std::map ne permet pas les clés en double. Après avoir fait cela, vous pouvez itérer sur les dix premiers éléments car la carte préserve le tri des clés des éléments.

+0

cela ne fonctionne pas s'il y a des doublons. –