Каков самый быстрый способ проверить, существует ли значение в std::map?

Каков самый быстрый способ проверить, существует ли значение в std::map<int, int>? Должен ли я использовать unordered map? В этой задаче я не могу использовать никакие библиотеки вместо std.

Теперь я не знаю никаких способов сделать это без проверки всех значений.

Метод .find() ищет по ключу, не так ли?

IsCeo228 12.01.2023 10:27

@IsCeo228 IsCeo228 Ах да, я пропустил вопрос. Затем вам нужно будет использовать итератор по карте и перебирать ее.

Fareanor 12.01.2023 10:30

Я не могу думать ни о чем другом, кроме как просто перебирать весь контейнер. Если вам нужен более быстрый способ, вам нужно изменить свой контейнер на что-то еще, желательно отсортированное.

pptaszni 12.01.2023 10:32

Вы можете использовать быструю хеш-карту на github. github.com/greg7mdp/sparsepp

real_fan 12.01.2023 12:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
150
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

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

Если необходимо выполнить только один поиск, обратная карта будет излишней.

Yves Daoust 12.01.2023 10:46

@YvesDaoust правда, об этом упоминалось в ответе.

Lajos Arpad 12.01.2023 11:34

Что касается значений, map на самом деле не отличается от списка или вектора. Таким образом, исчерпывающий (линейный) поиск — самый быстрый способ.

Если у вас нет очень больших наборов данных (более 100 000 или около того), время доступа к картам не должно вас беспокоить, поскольку в любом случае оно будет очень незначительным, потому что у вас уже есть int в качестве ключа. Чтобы проверить, существует ли value на карте или нет, вы должны просто использовать итераторы или, может быть, std::find_if. Неважно, какой способ вы выберете, он все равно будет линейным (O (n)).

// both examples assume you using c++ 17 standart
// simple cycle variant
bool is_value_exists(auto const &map, int val) {
  for (auto const &[key, value] : map) {
    if (value == val) return true;
  }
  return false;
}
// find if version
#include <algorithm>
bool is_value_exists2(auto const &map, int val) {
  return std::find_if (
    map.begin(), 
    map.end(),
    [val](auto const &kv) { return kv.second == val; }
  ) != map.end();
}

Что вы подразумеваете под "время доступа к картам не должно вас беспокоить"? Что, если я делаю это миллион раз в секунду?

Passer By 12.01.2023 10:47

@PasserBy, если у вас есть небольшие карты, изменение std:map на std::unordered_map и наоборот не сильно повлияет. При некоторых числах помещение их в отсортированный вектор и запуск бинарного поиска сделают свое дело с той же скоростью. Это начинает иметь значение, когда у вас много данных - неупорядоченная карта начинает иметь много коллизий и медленно деградирует до линейного поиска. Что касается того, что мы все еще говорим о парах <int, int>.

Sugar 12.01.2023 10:59

Я не понимаю смысла, который вы делаете со своим комментарием. Нет, поиск по std::vector с 100 000 элементов будет невероятно быстрее, чем перебор std::map с 100 000 элементов. В вашем ответе нигде нет std::unordered_map. Но что более важно, ваш ответ без исключения говорит о том, что проблемы не существует. Ну, может. И ваш ответ заставляет людей думать иначе.

Passer By 12.01.2023 11:58

Мой ответ не подразумевал отсутствие проблемы, он утверждает, что размышления о типах контейнеров в состоянии OP, скорее всего (OP - новый член), являются преждевременной оптимизацией, и ему не следует беспокоиться о времени доступа, поскольку в любом случае его проблема будет линейной сложностью.

Sugar 12.01.2023 13:16
Ответ принят как подходящий

Самый быстрый способ - не делать этого. Не ищите значения в картах, ищите ключи в картах.

Если вам нужно искать значение, используйте другую структуру данных (или отдельную карту).

Единственный способ поиска значения на карте — линейный (O(N)), но из-за накладных расходов на кеширование при итерации по структуре данных карты он будет даже медленнее, чем итерация, например. вектор.

Предположительно, данные предоставляются на карте. Преобразование в другую структуру может быть контрпродуктивным.

Yves Daoust 12.01.2023 10:43
need to search for a value, use another data structure (or a separate map) Как и в случае с Хранить дополнительную неупорядоченную карту от значения до количества вхождений.
greybeard 12.01.2023 12:51

Всякий раз, когда вы вводите пару ключ-значение в экземпляр std::map, также добавляйте его указатель на итератор этого элемента в переменной std::vector<iterator_...>.

myVec[value]=myMap.find(key); // at time of inserting a new key

Таким образом, вы можете просто использовать значение в качестве ключа (индекса) в векторе и напрямую обращаться к содержимому карты с помощью этого указателя после сравнения с nullptr.

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


Вы также можете использовать map-iteration-search в качестве резервного хранилища кэша с прямым отображением (который работает быстрее всего для целочисленных ключей (значения здесь)). Все попадания в кеш будут обслуживаться за счет побитовой операции & с некоторым значением, например 8191, 4095 и т. д. (O(1)). Все промахи кеша по-прежнему потребуют полной итерации элементов карты, которая выполняется медленно (O(N)).

Таким образом, если коэффициент попаданий в кэш близок к 100%, он может приближаться к O(1), в противном случае это будет O(N), что будет медленным.

Другие вопросы по теме