[C++] partial_sort_copy et indices

keng Messages postés 13 Statut Membre -  
mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   -
Bonjour,

j'ai un vecteur de la STL
je veux savoir par exemple quels sont les 10 plus grands éléments et aussi savoir leur indice dans le vecteur

partial_sort_copy de la STL peut récupérer les 10 plus grandes valeurs mais comment récupérer les indices de ces valeurs dans mon vecteur d'origine ?

merci
++
Configuration: Linux Fedora
Firefox 2.0.0.5

3 réponses

  1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 943
     
    Voici une façon de faire :
    #include <vector>
    #include <map>
    #include <iostream>
    
    // On ne conserve que les n premiers éléments en accord avec la relation d'ordre choisie
    template <typename T,typename Tsort>
    void find_n_best_elements(
        const std::vector<T> & v,
        unsigned n,
        std::map<T,std::size_t,Tsort> & map_n_best_elements
    ){
        const std::size_t vsize = v.size();
        for(std::size_t i=0;i<vsize;++i){
            map_n_best_elements[v[i]] = i;
            if(map_n_best_elements.size() > n){
                // On vire le n+1 ieme élément car on a déjà n éléments meilleurs
                map_n_best_elements.erase(map_n_best_elements.rbegin()->first);
            }
        }
    }
    
    int main(){
        // Construire le vecteur de départ
        std::vector<int> v;
        v.push_back(1);
        v.push_back(4);
        v.push_back(2);
        v.push_back(8);
        v.push_back(5);
        v.push_back(3);
        v.push_back(7);
    
        // Afficher le vecteur
        const std::size_t vsize = v.size();
        for(std::size_t i=0;i<vsize;++i){
            std::cout << "v[" << i << "]\t" << v[i] << std::endl;
        }
    
        // Chercher les n=3 plus grands entiers
        // - les valeurs sont des ici int
        // - les index sont toujours des std::size_t
        // - la relation d'ordre est std::greater (un élément plus grand est meilleur qu'un élément plus petit)
        typedef std::map<int,std::size_t,std::greater<int> > my_map_t;
        my_map_t map_3_biggest_int;
        find_n_best_elements(v,3,map_3_biggest_int);
    
        // Afficher le résultat
        my_map_t::const_iterator
            mit (map_3_biggest_int.begin()),
            mend(map_3_biggest_int.end());
        for(;mit!=mend;++mit){
            std::cout << "valeur = "  << mit->first << "\tindex = "
                << mit->second << std::endl;
        }
        return 0;
    }

    Ce qui donne ;
    v[0]    1
    v[1]    4
    v[2]    2
    v[3]    8
    v[4]    5
    v[5]    3
    v[6]    7
    valeur = 8      index = 3
    valeur = 7      index = 6
    valeur = 5      index = 4
    

    Tu noteras que si tu cherches les n plus petits éléments il te suffit de changer std::greater par std::less (qui est la relation d'ordre par défaut dans une map).
    ....
        typedef std::map<int,std::size_t,std::less<int> > my_map_t;
        // ou directement : typedef std::map<int,std::size_t > my_map_t;
    ....
    

    donne :
    v[0]    1
    v[1]    4
    v[2]    2
    v[3]    8
    v[4]    5
    v[5]    3
    v[6]    7
    valeur = 1      index = 0
    valeur = 2      index = 2
    valeur = 3      index = 5
    

    Tu peux aussi définir ton propre foncteur si tu souhaites utiliser une autre relation d'ordre que std::less ou std::greater
    https://cpp.developpez.com/faq/cpp/?page=La-STL#STL_functor

    Bonne chance
    0
  2. keng Messages postés 13 Statut Membre 1
     
    merci pour ta réponse détaillée et rapide !

    et si je veux récupérer les indices des valeurs qui sont au-dessus d'un seuil ?
    il y a une fonction de la STL pour faire ça ?

    merci encore
    ++
    0
  3. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 943
     
    Il faut lire la doc :)
    https://community.hpe.com/t5/custom/page/page-id/HPPSocialUserSignonPage?redirectreason=permissiondenied&referer=https%3A%2F%2Fcommunity.hpe.com%2Ft5%2FServers-Systems-The-Right%2FSGI-com-Tech-Archive-Resources-now-retired%2Fba-p%2F6992583

    Cf les fonctions upper_bound et lower_bound. Contrairement au find la clé recherchée n'a pas besoin d'être dans le container (ce qui revient à rechercher un seuil) (find() renvoie end() si la clé n'existe pas).
    #include <iostream>
    #include <set>
    
    int main(){
        std::set<int> s;
        s.insert(5);
        s.insert(3);
        s.insert(1);
        s.insert(7);
        s.insert(2);
        s.insert(8);
    
        // Parcourir l'ensemble
        std::cout << "[begin...end[: ";
        for(std::set<int>::const_iterator it=s.begin();it!=s.end();++it){
            std::cout << *it << ' ';
        }
        std::cout << std::endl;
    
        const int bound = 3;
        std::set<int>::const_iterator
            it_ub = s.upper_bound(bound),
            it_lb = s.lower_bound(bound),
            it_end = s.end();
    
        std::cout << "LB(" << bound << ") = "  << *it_lb << std::endl
                  << "UB(" << bound << ") = " << *it_ub  << std::endl;
    
        // Parcourir de begin à UB (exclue) (ie jusqu'à LB comprise):
        std::cout << "[begin...UB[: ";
        for(std::set<int>::const_iterator it=s.begin();it!=it_ub;++it){
            std::cout << *it << ' ';
        }
        std::cout << std::endl;
    
        // Parcourir de UB (comprise) à end :
        std::cout << "[UB...end[: ";
        for(std::set<int>::const_iterator it=it_ub;it!=it_end;++it){
            std::cout << *it << ' ';
        }
        std::cout << std::endl;
    
        return 0;
    }
    

    ce qui donne :
    [begin...end[: 1 2 3 5 7 8
    LB(3) = 3
    UB(3) = 5
    [begin...UB[: 1 2 3
    [UB...end[: 5 7 8

    Bonne chance
    0