Std :: map insert или std :: map find?

Предполагая карту, на которой вы хотите сохранить существующие записи. В 20% случаев вводимая вами запись - это новые данные. Есть ли преимущество в выполнении std :: map :: find, а затем std :: map :: insert с использованием этого возвращенного итератора? Или быстрее попытаться вставить, а затем действовать в зависимости от того, указывает ли итератор, что запись была или не была вставлена?

Я был исправлен и намеревался использовать std :: map :: lower_bound вместо std :: map :: find.

Superpolock 07.08.2009 22:37
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
93
1
70 661
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Между ними не будет почти никакой разницы в скорости, find вернет итератор, insert делает то же самое и в любом случае будет искать на карте, чтобы определить, существует ли уже запись.

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

map [key] - пусть stl разберется. Это наиболее эффективная передача вашего намерения.

Да, достаточно честно.

Если вы выполняете поиск, а затем вставку, вы выполняете 2 x O (log N), когда вы получаете промах, поскольку поиск только сообщает вам, нужно ли вставлять, а не туда, куда вставка должна идти (lower_bound может помочь вам там) . Просто прямая вставка, а затем изучение результата - вот путь, которым я бы пошел.

Нет, если запись существует, она возвращает ссылку на существующую запись.

Kris Kumler 19.09.2008 01:24

-1 за этот ответ. Как сказал Крис К., использование map [key] = value перезапишет существующую запись, а не «сохранит» ее, как требуется в вопросе. Вы не можете проверить наличие с помощью map [key], потому что он вернет созданный по умолчанию объект, если ключ не существует, и создаст его как запись для ключа

netjeff 01.12.2008 09:36

Дело в том, чтобы проверить, заполнена ли карта, и только добавить / перезаписать, если ее там нет. Использование map [key] предполагает, что значение уже существует всегда.

srm 11.11.2013 21:40

Любые ответы об эффективности будут зависеть от точной реализации вашего STL. Единственный способ узнать наверняка - это сравнить результаты в обоих направлениях. Я предполагаю, что разница вряд ли будет значительной, поэтому решайте, исходя из того, какой стиль вы предпочитаете.

Это не совсем так. STL отличается от большинства других библиотек тем, что предоставляет явные требования big-O для большинства своих операций. Существует гарантированная разница между 2 * O (log n) и 1 * O (log n), независимо от того, какую реализацию функции используют для достижения этого поведения O (log n). Другой вопрос, является ли эта разница существенный на вашей платформе. Но разница будет всегда.

srm 11.11.2013 21:42

@srm, определяющий требования big-O, по-прежнему не говорит вам, сколько времени займет операция в абсолютном выражении. Гарантированной разницы, о которой вы говорите, не существует.

Mark Ransom 11.11.2013 22:41

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

Если вас беспокоит эффективность, вы можете проверить hash_map <>.

Обычно map <> реализуется как двоичное дерево. В зависимости от ваших потребностей hash_map может быть более эффективным.

Хотел бы. Но в стандартной библиотеке C++ нет hash_map, и PHB не допускают кода за пределами этого.

Superpolock 20.09.2008 00:33
std :: tr1 :: unordered_map is the hash map that is proposed to be added to the next standard, and should be available within most current implementations of the STL.
beldaz 16.03.2010 10:02

Ответ на этот вопрос также зависит от того, насколько дорого стоит создание типа значения, который вы храните на карте:

typedef std::map <int, int> MapOfInts;
typedef std::pair <MapOfInts::iterator, bool> IResult;

void foo (MapOfInts & m, int k, int v) {
  IResult ir = m.insert (std::make_pair (k, v));
  if (ir.second) {
    // insertion took place (ie. new entry)
  }
  else if ( replaceEntry ( ir.first->first ) ) {
    ir.first->second = v;
  }
}

Для типа значения, такого как int, приведенное выше будет более эффективным, чем поиск с последующей вставкой (при отсутствии оптимизации компилятора). Как указано выше, это связано с тем, что поиск по карте выполняется только один раз.

Однако вызов вставки требует, чтобы у вас уже было сконструировано новое «значение»:

class LargeDataType { /* ... */ };
typedef std::map <int, LargeDataType> MapOfLargeDataType;
typedef std::pair <MapOfLargeDataType::iterator, bool> IResult;

void foo (MapOfLargeDataType & m, int k) {

  // This call is more expensive than a find through the map:
  LargeDataType const & v = VeryExpensiveCall ( /* ... */ );

  IResult ir = m.insert (std::make_pair (k, v));
  if (ir.second) {
    // insertion took place (ie. new entry)
  }
  else if ( replaceEntry ( ir.first->first ) ) {
    ir.first->second = v;
  }
}

Чтобы вызвать 'insert', мы платим за дорогостоящий вызов для создания нашего типа значения - и, судя по тому, что вы сказали в вопросе, вы не будете использовать это новое значение в 20% случаев. В приведенном выше случае, если изменение типа значения карты не является вариантом, более эффективно сначала выполнить «поиск», чтобы проверить, нужно ли нам создавать элемент.

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

Ответ принят как подходящий

Ответ: вы тоже. Вместо этого вы хотите сделать что-то, что предложено в пункте 24 Эффективный STL от Скотт Мейерс:

typedef map<int, int> MapType;    // Your map type may vary, just change the typedef

MapType mymap;
// Add elements to map here
int k = 4;   // assume we're searching for keys equal to 4
int v = 0;   // assume we want the value 0 associated with the key of 4

MapType::iterator lb = mymap.lower_bound(k);

if (lb != mymap.end() && !(mymap.key_comp()(k, lb->first)))
{
    // key already exists
    // update lb->second if you care to
}
else
{
    // the key does not exist in the map
    // add it to the map
    mymap.insert(lb, MapType::value_type(k, v));    // Use lb as a hint to insert,
                                                    // so it can avoid another lookup
}

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

puetzk 21.09.2008 17:13

Два вопроса: 1) Чем отличается использование lower_bound от поиска для карты? 2) Для «карты», не правда ли, что операция правой руки && всегда истинна, когда «lb! = Mymap.end ()»?

Richard Corden 22.09.2008 12:03

@Richard: find () возвращает end (), если ключ не существует, lower_bound возвращает позицию, в которой должен находиться элемент (что, в свою очередь, может использоваться как подсказка для вставки). @puetzek: Не будет ли "просто вставка" перезаписать референтное значение для существующих ключей? Не уверен, хочет ли ОП этого.

peterchen 07.10.2009 00:55

кто-нибудь знает, есть ли что-то подобное для unordered_map?

Giovanni Funchal 13.07.2010 18:39

@Helltone: Реализации MS (msdn.microsoft.com/en-us/library/bb982322.aspx) и IBM (publib.boulder.ibm.com/infocenter/comphelp/v9v111/topic/…), похоже, имеют вставки с подсказками, но я не могу догадаться, как они будут работать с несортированными данными - как угадать подходящую точку вставки?

beldaz 10.12.2010 01:31

Они этого не делают. Подсказка не используется, только для совместимости. См. здесь

default 27.11.2013 02:43

@puetzk «просто использовать вставку» - это нормально, если вставляемая вещь стоит недорого, см. ответ Ричарда Кордена. Решение Скотта Мейера обходит это.

Chris Drew 28.08.2014 12:53

@peterchen map :: insert не перезаписывает существующее значение, если оно существует, см. cplusplus.com/reference/map/map/insert.

Chris Drew 28.08.2014 13:00

Разве это не меняется на upper_bound в C++ 11? См. Раздел о сложности. en.cppreference.com/w/cpp/container/map/insert

Tyler 23.07.2016 05:29

@Tyler lower_bound возвращает первый ключ, который больше или равен (> =) искомому ключу, а upper_bound возвращает первый ключ, который больше (>), чем искомый ключ. Если искомого ключа нет на карте, lower_bound и upper_bound возвращают один и тот же итератор, поэтому ответ остается действительным. Имя «lower_bound» неточно для функции.

unlut 23.10.2020 13:30

Кажется, у меня недостаточно очков, чтобы оставить комментарий, но отмеченный ответ мне кажется длинным - если учесть, что insert все равно возвращает итератор, зачем искать lower_bound, когда вы можете просто использовать возвращенный итератор. Странный.

Поскольку (конечно, до C++ 11) использование вставки означает, что вам все равно нужно создать объект std::map::value_type, принятый ответ позволяет избежать даже этого.

KillianDS 30.01.2014 17:42

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