В настоящее время у меня есть объект std::map<std::string,int>
, в котором целочисленное значение хранится в уникальном строковом идентификаторе, и я ищу эту строку. Он делает в основном то, что я хочу, за исключением того, что не отслеживает порядок вставки. Поэтому, когда я перебираю карту, чтобы распечатать значения, они сортируются по строке; но я хочу, чтобы они были отсортированы в соответствии с порядком (первой) вставки.
Я думал об использовании vector<pair<string,int>>
вместо этого, но мне нужно найти строку и увеличить целочисленные значения примерно в 10 000 000 раз, поэтому я не знаю, std::vector
будет ли a значительно медленнее.
Есть ли способ использовать std::map
или есть другой std
контейнер, который лучше соответствует моим потребностям?
[Я использую GCC 3.4, и у меня, вероятно, не более 50 пар значений std::map
].
Спасибо.
источник
Ответы:
Если у вас есть только 50 значений в std :: map, вы можете скопировать их в std :: vector перед печатью и отсортировать через std :: sort с использованием соответствующего функтора.
Или вы можете использовать boost :: multi_index . Это позволяет использовать несколько индексов. В вашем случае это могло бы выглядеть так:
источник
Вы можете объединить a
std::vector
сstd::tr1::unordered_map
(хеш-таблицей). Вот ссылка на документацию Boost дляunordered_map
. Вы можете использовать вектор для отслеживания порядка вставки и хеш-таблицу для частого поиска. Если вы выполняете сотни тысяч поисков, разница между поиском O (log n)std::map
и O (1) для хеш-таблицы может быть значительной.источник
std::map
работать так, как предполагалось (то есть, сортируя себя при вставке), и имеет быстрое время выполнения. (Я прочитал это после написания моей версии, в которой я использовал std :: list!)Проведите параллель
list<string> insertionOrder
.Когда пришло время печатать, перебирайте список и просматривайте карту .
источник
std::string_view
для ключей карты, ссылаясь наstd::string
вinsertionOrder
списке. Это позволяет избежать копирования, но вы должны быть осторожны, чтобыinsertionOrder
элементы пережили ключи на карте, ссылающиеся на них.У Tessil есть очень хорошая реализация упорядоченной карты (и набора), которая является лицензией MIT. Вы можете найти это здесь: order-map
Пример карты
источник
Если вам нужны обе стратегии поиска, вы получите два контейнера. Вы можете использовать a
vector
с вашими фактическими значениямиint
и поставитьmap< string, vector< T >::difference_type>
рядом с ним, возвращая индекс в вектор.Чтобы завершить все это, вы можете инкапсулировать оба в одном классе.
Но я считаю, что у boost есть контейнер с несколькими индексами.
источник
То, что вы хотите (не прибегая к Boost), - это то, что я называю «упорядоченным хешем», который, по сути, представляет собой гибрид хэша и связанного списка со строковыми или целочисленными ключами (или и тем, и другим одновременно). Упорядоченный хеш поддерживает порядок элементов во время итерации с абсолютной производительностью хеша.
Я собирал относительно новую библиотеку сниппетов C ++, которая заполняет то, что я считаю дырами в языке C ++ для разработчиков библиотеки C ++. Иди сюда:
https://github.com/cubiclesoft/cross-platform-cpp
Взять:
Если данные, управляемые пользователем, будут помещены в хэш, вам также может потребоваться:
Вызвать это:
Я столкнулся с этим потоком SO на этапе исследования, чтобы узнать, существует ли уже что-нибудь вроде OrderedHash, не требуя от меня добавления огромной библиотеки. Я был разочарован. Так что я написал свой. И теперь я поделился им.
источник
Вы не можете сделать это с картой, но вы можете использовать две отдельные структуры - карту и вектор и поддерживать их синхронизацию - то есть когда вы удаляете с карты, находите и удаляете элемент из вектора. Или вы можете создать
map<string, pair<int,int>>
- и в своей паре сохранить размер () карты при вставке для записи позиции вместе со значением int, а затем, когда вы печатаете, использовать член позиции для сортировки.источник
Другой способ реализовать это - использовать
map
вместоvector
. Я покажу вам этот подход и расскажу о различиях:Просто создайте класс, у которого есть две карты за кулисами.
Затем вы можете открыть итератор для итератора
data_
в правильном порядке. То, как вы это делаете, -insertion_order_
это итерация, и для каждого элемента, полученного в результате этой итерации, выполните поиск вdata_
со значением изinsertion_order_
Вы можете использовать более эффективный
hash_map
для insert_order, поскольку вам не нужно напрямую выполнять итерациюinsertion_order_
.Для вставки у вас может быть такой метод:
Есть много способов улучшить дизайн и позаботиться о производительности, но это хорошая основа для начала реализации этой функциональности самостоятельно. Вы можете сделать это шаблонным, и вы можете фактически хранить пары как значения в data_, чтобы вы могли легко ссылаться на запись в insert_order_. Но я оставляю эти вопросы дизайна в качестве упражнения :-).
Обновление : я полагаю, я должен сказать кое-что об эффективности использования карты и вектора для insert_order_
Возможно, если вы не собираетесь так часто использовать удаления, вам следует использовать векторный подход. Подход с картой был бы лучше, если бы вы поддерживали другой порядок (например, приоритет) вместо порядка вставки.
источник
Вот решение, для которого требуется только стандартная библиотека шаблонов без использования мультииндекса boost:
вы можете использовать
std::map<std::string,int>;
иvector <data>;
где на карте вы храните индекс расположения данных в векторе, а вектор хранит данные в порядке вставки. Здесь доступ к данным имеет сложность O (log n). отображение данных в порядке вставки имеет сложность O (n). вставка данных имеет сложность O (log n).Например:
источник
Это отчасти связано с ответом Фейсалса. Вы можете просто создать класс-оболочку вокруг карты и вектора и легко синхронизировать их. Правильная инкапсуляция позволит вам контролировать метод доступа и, следовательно, какой контейнер использовать ... вектор или карту. Это позволяет избежать использования Boost или чего-то подобного.
источник
Одна вещь, которую вы должны учитывать, - это небольшое количество используемых вами элементов данных. Возможно, что быстрее будет использовать только вектор. На карте есть некоторые накладные расходы, из-за которых поиск в небольших наборах данных может оказаться более дорогостоящим, чем поиск в более простом векторе. Итак, если вы знаете, что всегда будете использовать примерно одинаковое количество элементов, проведите сравнительный анализ и посмотрите, соответствует ли производительность карты и вектора тем, о чем вы действительно думаете. Вы можете обнаружить, что поиск в векторе, состоящем всего из 50 элементов, почти такой же, как на карте.
источник
// Должно быть похоже на этого человека!
// При этом сохраняется сложность вставки O (logN) и удаления также O (logN).
источник
Используется
boost::multi_index
с индексами карты и списка.источник
Карта пары (str, int) и статического int, которая увеличивается при вызовах вставки, индексирует пары данных. Возможно, добавить структуру, которая может возвращать статический int val с членом index ()?
источник