Доступ к значению карты по индексу

Если у меня есть структура, как

std::map<string, int> myMap;
myMap["banana"] = 1;
myMap["apple"] = 1;
myMap["orange"] = 1;

как получить доступ к myMap[0]?

Я знаю, что карта сортируется внутри, и я в порядке с этим, я хочу получить значение на карте по индексу. Я пробовал myMap[0], но я получаю ошибку:

Error   1   error C2679: binary '[' : no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion)   

Я понимаю, что мог бы сделать что-то вроде этого:

string getKeyAtIndex (int index){
    map<string, int>::const_iterator end = myMap.end(); 

    int counter = 0;
    for (map<string, int>::const_iterator it = myMap.begin(); it != end; ++it) {
        counter++;

        if (counter == index)
            return it->first;
    }
}

но, конечно, это очень неэффективно? Есть ли лучший способ?

5 ответов


код map не должен быть доступен таким образом, его индексируется ключами, а не позициями. А map итератор двунаправленный, как и list, поэтому функция, которую вы используете, не более неэффективна, чем доступ к list по позиции. Ваша функция может быть написана с помощью std::advance( iter, index ) начиная от begin(). Если вы хотите произвольный доступ по позиции, используйте vector или deque.


предыдущий ответ (см. комментарий): Как насчет просто myMap.begin();

вы можете реализовать карту произвольного доступа, используя векторное хранилище, которое по существу является вектором пар. Вы, конечно, теряете все преимущества стандартной библиотечной карты в этот момент.


для достижения вашей цели может быть конкретный (непереносимый) метод реализации, но не тот, который является портативным.

в общем,std::map реализован как тип двоичного дерева, обычно отсортированного по ключу. Определение первого элемента отличается в зависимости от порядка. Кроме того, в вашем определении элемент[0] является узлом в верхней части дерева или самым левым листовым узлом?

многие двоичные деревья реализованы в виде связанных списков. Большинство связанных списков не могут получить прямой доступ, как массив, потому что, чтобы найти элемент 5, Вы должны следовать ссылкам. Это по определению.

вы можете решить эту проблему с помощью std::vector и std::map:

  1. выделить объект из динамической памяти.
  2. сохраните указатель вместе с ключом в std::map.
  3. сохранить указатель в std::vector в нужной позиции на.

на std::map позволит эффективно метод доступа к объекту по ключу.
The std::vector позволит эффективный способ получить доступ к объекту по индексу. Хранение указателей позволяет только один экземпляр объекта, вместо того, чтобы поддерживать несколько копий.


ну, на самом деле вы не можете. Способ, который вы нашли, очень неэффективен, он имеет вычислительную сложность O(n) (n операций в худшем случае, где n-количество элементов в карте).

доступ к элементу в векторе или массиве имеет сложность O (1) по сравнению (постоянная вычислительная сложность, одна операция).

считайте, что карта внутренне реализована как красное черное дерево (или дерево avl, это зависит от реализации) , и каждая вставка, удаление и операция поиска-это наихудший случай O(log n) (требуется логарифм в базовых операциях 2, чтобы найти элемент в дереве), что довольно хорошо.

способ, с которым вы можете иметь дело, - использовать пользовательский класс, который имеет как вектор, так и карту. Вставка в конце класса будет усреднена O(1), поиск по имени будет O(log n), поиск по индексу будет O(1), но в этом случае операция удаления будет O (n).


вы можете использовать некоторые другие карты, как контейнеры .
сохранить размер поля может сделать бинарное дерево поиска легко случайный доступ .
вот моя реализация ...
стиль std, итератор произвольного доступа ...
размер сбалансированного дерева ...
https://github.com/mm304321141/zzz_lib/blob/master/sbtree.h
и дерево B+...
https://github.com/mm304321141/zzz_lib/blob/master/bpptree.h