web-dev-qa-db-fra.com

Elément à l'index dans un std :: set?

Je suis tombé sur ce problème: je n'arrive pas à sélectionner l'élément à la position de l'index dans un std::set normal. Est-ce un bug dans STD?

Ci-dessous un exemple simple:

#include <iostream>
#include <set>

int main()
{
    std::set<int> my_set;
    my_set.insert(0x4A);
    my_set.insert(0x4F);
    my_set.insert(0x4B);
    my_set.insert(0x45);

    for (std::set<int>::iterator it=my_set.begin(); it!=my_set.end(); ++it)
        std::cout << ' ' << char(*it);  // ups the ordering

    //int x = my_set[0]; // this causes a crash!
}

Tout ce que je peux faire pour résoudre le problème?

22
hauron

Cela ne provoque pas de crash, ça ne compile pas. set n'a pas accès par index.

Vous pouvez obtenir le nième élément comme ceci:

std::set<int>::iterator it = my_set.begin();
std::advance(it, n);
int x = *it;

En supposant que my_set.size() > n, bien sûr. Vous devez savoir que cette opération prend du temps approximativement proportionnellement à n. En C++ 11, il existe une manière plus agréable de l'écrire:

int x = *std::next(my_set.begin(), n);

Encore une fois, vous devez savoir que n est dans les limites en premier.

48
Steve Jessop

Une implémentation habituelle de std :: set consiste à utiliser des arbres de recherche binaires , notamment des arbres de recherche binaires auto-équilibrés tels que des arbres rouges-noirs

Ils ne vous donnent pas un accès constant au nième élément. Cependant, vous semblez vouloir le premier. Alors essayez dans C++ 11 :

auto it = my_set.begin();
int first=0;
if (it != my_set.end()) first = *it;
7

Parfois, il y a une bonne raison d'avoir besoin d'un ensemble dans lequel vous pouvez indexer. J'ai récemment dû implémenter cette fonctionnalité pour prendre en charge une API héritée dotée de fonctions permettant de renvoyer le nombre d'éléments et l'élément à un index afin que l'appelant puisse énumérer les éléments.

Ma façon de résoudre le problème consiste à utiliser std :: vector et std :: equal_range pour rechercher et insérer ou supprimer des éléments de l'ensemble. Par exemple, l'insertion d'un nouvel élément dans l'ensemble ressemble à ceci:

    std:vector<std::string> my_set;

    ...

    std::string new_item("test");

    auto range = std::equal_range(my_set.begin(),my_set.end(),new_item);
    if (range.first == range.second)
        my_set.insert(range.first,new_item);

La suppression est très similaire: utilisez equal_range pour rechercher l'élément, et si range.first est not égal à range.second, supprimez cette plage.

0
Graham Asher

Vous ne pouvez pas y accéder en temps constant.

Mais vous pouvez accéder à n’importe quel élément dans O(n) fois ...

std::set<int>::iterator it;
it=my_set.begin();
advance(it,n);
cout<<*it;
0
Abhishek

Ce n'est pas un bug dans le STD. Il n'y a pas d'accès aléatoire dans un std::set. Si vous avez besoin d'un accès aléatoire par index, vous pouvez utiliser std::vector

0
José D.