В чем разница между std::list‹std::pair› и std::map в C++ STL?

В чем разница между std::list<std::pair> и std::map? Есть ли метод find для списка?


person Boolean    schedule 02.08.2010    source источник


Ответы (7)


std::map<X, Y>:

  • является упорядоченной структурой по отношению к ключам (то есть, когда вы перебираете ее, ключи всегда будут увеличиваться).
  • поддерживает только уникальные ключи (Xs)
  • предлагает быстрый метод find() (O(log n)), который находит пару ключ-значение по ключу
  • предлагает оператор индексации map[key], который также быстро

std::list<std::pair<X, Y> >:

  • представляет собой простую последовательность парных Xs и Ys. Они остаются в том порядке, в котором вы их положили.
  • может содержать любое количество дубликатов
  • поиск определенного ключа в list равен O(N) (без специального метода)
  • предлагает метод splice.
person jpalecek    schedule 02.08.2010
comment
Для полноты: std::vector‹std::pair‹X, Y› › предлагает поиск O(log n) и меньше (и должен быть быстрее), чем карта для неизменяемых данных. Полезно, например. статический, часто используемый поиск. Но используйте карту, пока не покажете, что оптимизация принесет реальную пользу. - person Alice Purcell; 05.08.2010
comment
@chrispy: std::vector‹std::pair‹X, Y› › предлагает поиск O(log n) ТОЛЬКО при сортировке - person jpalecek; 05.08.2010
comment
да, действительно, следовательно, это O (n) для вставки после сортировки и, следовательно, лучше всего для статических данных - person Alice Purcell; 08.08.2010

std::pair

std::pair — это шаблонная структура кортежа, ограниченная двумя элементами, называемыми первым и вторым:

std::pair<int, std::string> myPair ;
myPair.first = 42 ;
myPair.second = "Hello World" ;

std::pair используется STL (и другим кодом) как "общий контейнер" для одновременной агрегации двух значений без необходимости переопределять еще один struct.

std::map

std::map — это шаблонный ассоциативный контейнер, связывающий вместе ключи и значения. Самый простой (но не более эффективный) пример:

std::map<int, std::string> myMap ;
myMap[42] = "Fourty Two" ;
myMap[111] = "Hello World" ;
// ...
std::string strText ;  // strText is ""
strText = myMap[111] ; // strText is now "Hello World"
strText = myMap[42] ;  // strText is now "Fourty Two"
strText = myMap[23] ;  // strText is now "" (and myMap has
                       // a new value "" for key 23)

std::pair и std::map

Примечание. Это был ответ на исходный, неотредактированный вопрос.

Функции std::map должны одновременно возвращать итераторы к ключам и значениям, чтобы оставаться эффективными... Поэтому очевидным решением является возврат итераторов к парам:

std::map<int, std::string> myMap ;
myMap[42] = "Fourty Two" ;
myMap[111] = "Hello World" ;

myMap.insert(std::make_pair(23, "Bye")) ;

std::map<int, std::string>::iterator it = myMap.find(42) ;
std::pair<int, std::string> keyvalue = *it ;    // We assume 42 does
                                                // exist in the map
int key = keyvalue.first ;
int value = keyvalue.second ;

std::list<std::pair<A,B> > и std::map<A,B>

Примечание: отредактировано после редактирования вопроса.

Таким образом, на первый взгляд карта пар и список пар кажутся одним и тем же. Но это не так:

Карта по своей сути упорядочена предоставленным функтором, тогда как список будет хранить пары [A, B] именно там, где вы их поместили. Это делает вставку O (log n) для карты, тогда как необработанная вставка внутри списка представляет собой постоянную сложность (поиск, куда ее вставить, — еще одна проблема).

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

Таким образом, поиск элемента на карте — это O(log n), а в неупорядоченном списке — O(n). И если список упорядочен, и вы хотите использовать дихотомию, вы не получите ожидаемого прироста производительности, так как обход элементов в любом случае выполняется поэлементно.

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

person paercebal    schedule 02.08.2010

std:pair содержит ровно два объекта. std:map содержат коллекцию парных объектов.

Вы не можете использовать find() для пары, потому что там нечего искать. Вам нужен объект pair.First или pair.Second

ОБНОВЛЕНИЕ: Предполагая, что вы имели в виду разницу между map<> и list<pair<> >: карта должна быть реализована для быстрого поиска члена key. list имеет простой линейный список. Поиск элемента в списке требует просмотра всего списка. Однако std::find() будет работать в обоих случаях.

person James Curran    schedule 02.08.2010

(Отредактировано после уточнения)

std::map оптимизирован для быстрого поиска. Он имеет собственный метод find, который использует свою внутреннюю структуру для обеспечения хорошей производительности. Как правило, он будет проверять только log(N) ключей, где N — количество элементов на карте.

std::list<std::pair> — это простой связанный список, поэтому он поддерживает только поэлементный обход. Вы можете использовать отдельный алгоритм std::find или std::find_if с пользовательским предикатом, который проверяет только член first, чтобы лучше соответствовать семантике std::map::find, но это будет очень медленно. На самом деле ему придется просмотреть каждую пару в списке для любого неудачного поиска и в среднем половину для любого успешного поиска.

person Walter Mundt    schedule 02.08.2010

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

#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
        map<string, int> myMap;
        myMap["myKey"] = 1337;

        map<string, int>::iterator myIterator = myMap.begin();

        pair<string, int> myPair = *myIterator;

        cout<<"the key \""<<myPair.first<<"\" maps to the value of "<<myPair.second<<endl;
        cout<<"the key \"myKey"\" maps to the value of "<<myMap["myKey"]<<endl;
        return 0;
}

Я бы посоветовал поискать в Google и прочитать полный справочник по API STL, поскольку STL (за исключением хранения логических значений в векторах и других подобных странностей) реализует множество функций структуры данных, которые вы хотели бы использовать в любой программе, не изобретая велосипед.

person Novikov    schedule 02.08.2010
comment
STL map реализуются не хэш-картами, а красно-черными (или подобными) деревьями. - person jpalecek; 02.08.2010
comment
Есть несколько мест, где документация STL не соответствует требованиям, установленным стандартом C++, поэтому чтение STL API может привести к тому, что вы на самом деле его не используете. - person Dennis Zickefoose; 02.08.2010

Карта может обеспечить лучшее время поиска в диапазоне O (log n), в то время как список может иметь время поиска O (n).

person Udhay    schedule 25.03.2014

std::pair предназначен только для группировки ровно двух объектов (скажем, "координаты на странице" состоят из X и Y).

std::map — это отображение одного набора объектов на другой.

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

Однако вы МОЖЕТЕ использовать std::pair в качестве значения карты, если это то, что вы хотите.

person DVK    schedule 02.08.2010