English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Map является связным контейнером STL, который предоставляет однонаправленная (первый может называться ключом, каждый ключ может出现 только один раз в map, второй может называться значением ключа) возможность обработки данных, благодаря этой особенности, он может предложить быстрый путь для обработки однонаправленных данных. Рассмотрим организацию данных внутри map, map внутренне строит одноцветное дерево (тип нестрого балансированного двоичного дерева), это дерево имеет функцию автоматического сортирования данных, поэтому все данные внутри map упорядочены, в будущем мы увидим, какие преимущества это предоставляет.
Рассмотрим пример того, что такое однонаправленная карта данных. Например, в классе каждый номер студента и его имя существуют однонаправленная карта данных, этот модель легко описать с помощью map,很明显 номер студента описывается int, имя описывается строкой (в этой статье строку не описывают char *, а используют STL string), ниже приведен код описания map:
Map<int, string> mapStudent;
1. Конструкторы map
Map предоставляет 6 конструкторов,这块涉及到 内存分配器 这些东西,略过不表,在下文中我们将接触到一些map конструкторов, здесь хочу отметить, что мы обычно используем следующий метод для создания map:
Map<int, string> mapStudent;
2. Вставка данных
После конструирования контейнера map мы можем вставлять данные в него. Здесь рассмотрим три метода вставки данных:
Первый способ:Вставка данных с помощью функции insert, рассмотрим пример (ниже приведенный код написан от руки, должен быть компилируем под VC и GCC, все могут запустить и увидеть результат, в VC, пожалуйста, добавьте это предложение, чтобы скрыть предупреждение 4786: #pragma warning (disable:4786))
#include <map> #include <string> #include <iostream> Использовать пространство имён std; Int main() { Map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, "student_one")); mapStudent.insert(pair<int, string>(2, "student_two")); mapStudent.insert(pair<int, string>(3, "student_three")); iterator<int, string> iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) { Cout << iter->first << " " << iter->second << end; } }
Второй способ:Вставка данных с помощью функции insert, рассмотрим пример.
#include <map> #include <string> #include <iostream> Использовать пространство имён std; Int main() { Map<int, string> mapStudent; mapStudent.insert(map<int, string>::value_type (1, “student_one”)); mapStudent.insert(map<int, string>::value_type (2, “student_two”)); mapStudent.insert(map<int, string>::value_type (3, “student_three”)); iterator<int, string> iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) { Cout << iter->first << " " << iter->second << end; } }
Третий способ:Вставка данных с помощью метода массива, давайте рассмотрим пример
#include <map> #include <string> #include <iostream> Использовать пространство имён std; Int main() { Map<int, string> mapStudent; mapStudent[1] = "student_one"; mapStudent[2] = “student_two”; mapStudent[3] = "student_three"; iterator<int, string> iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) { Cout << iter->first << " " << iter->second << end; } }
Несмотря на то, что все три метода могут вставить данные, они имеют различия, конечно, первый и второй методы по эффекту одинаковы, вставка данных с помощью функции insert涉及到 концепцию уникальности набора, то есть, если в map уже есть этот ключ, операция insert не может вставить данные, но с помощью метода массива это возможно, он может заменить значение, связанное с этим ключом, это объясняется программой
mapStudent.insert(map<int, string>::value_type (1, “student_one”)); mapStudent.insert(map<int, string>::value_type (1, “student_two”));
После выполнения этих двух строк, значение ключа 1 в mapStudent будет “student_one”, вторая строка не будет生效, это означает, что это касается того, как мы можем узнать, был ли успешен вставка строки insert, мы можем получить это через pair, как показан следующий код
Pair<map<int, string>::iterator, bool> Insert_Pair; Insert_Pair = mapStudent.insert(map<int, string>::value_type (1, “student_one”));
Мы можем узнать, был ли успешен вставка, через вторую переменную pair, его первая переменная возвращает итератор map, если вставка успешна, то Insert_Pair.second должен быть true, в противном случае false.
Ниже приведен завершенный код, демонстрирующий, как определяется успешность вставки
#include <map> #include <string> #include <iostream> Использовать пространство имён std; Int main() { Map<int, string> mapStudent; Pair<map<int, string>::iterator, bool> Insert_Pair; Insert_Pair = mapStudent.insert(pair<int, string>(1, “student_one”)); If(Insert_Pair.second == true) { Cout << ”Insert Successfully” << endl; } Else { Cout << ”Insert Failure” << endl; } Insert_Pair = mapStudent.insert(pair<int, string>(1, “student_two”)); If(Insert_Pair.second == true) { Cout << ”Insert Successfully” << endl; } Else { Cout << ”Insert Failure” << endl; } iterator<int, string> iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) { Cout << iter->first << " " << iter->second << end; } }
Вам можно использовать следующий код, чтобы увидеть эффект вставки данных в массив, который перекрывает данные
#include <map> #include <string> #include <iostream> Использовать пространство имён std; Int main() { Map<int, string> mapStudent; mapStudent[1] = "student_one"; mapStudent[1] = “student_two”; mapStudent[2] = "student_three"; iterator<int, string> iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) { Cout << iter->first << " " << iter->second << end; } }
3. Размер map
После того как данные вставлены в map, как мы можем узнать, сколько данных уже вставлено, можно использовать функцию size, способ использования следующий:
Int nSize = mapStudent.size();
4. Прогон данных
Вот три способа проецировать map
Первый способ: использование прямого итератора, примеры программы приведены выше, не будем останавливаться на этом
Второй способ: использование обратного итератора, примеры см. ниже, чтобы体会到 эффект, пожалуйста, сами запустите программу
#include <string> #include <iostream> Использовать пространство имён std; Int main() { Map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, "student_one")); mapStudent.insert(pair<int, string>(2, "student_two")); mapStudent.insert(pair<int, string>(3, "student_three")); reverse_iterator iter; for(iter = mapStudent.rbegin(); iter != mapStudent.rend(); iter++) { Cout << iter->first << " " << iter->second << end; } }
Третий способ: использование массивного способа, описание программы следующее
#include <map> #include <string> #include <iostream> Использовать пространство имён std; Int main() { Map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, "student_one")); mapStudent.insert(pair<int, string>(2, "student_two")); mapStudent.insert(pair<int, string>(3, "student_three")); int nSize = mapStudent.size() //Здесь ошибка, должно быть for(int nIndex = 1; nIndex <= nSize; nIndex++) //by rainfish for(int nIndex = 0; nIndex < nSize; nIndex++) { Cout << mapStudent[nIndex] << end; } }
5. Поиск данных (включая определение, находится ли этот ключевой слово в map)
Здесь мы体会到, что map гарантирует упорядоченность данных при вставке.
Существует много способов определить, находится ли данные (ключевое слово) в map, здесь, хотя заголовок и гласит о поиске данных, здесь будут穿插аться множество базовых способов использования map.
Вот три способа поиска данных
Первый способ:Использование функции count для определения наличия ключевого слова, недостаток его в том, что он не может определить местоположение данных, из-за特性的 map,一对一 соответствие, это определяет, что возвращаемое значение функции count только два: либо 0, либо 1, в случае возникновения, естественно, возвращается 1
Второй способ:Использование функции find для определения местоположения данных, она возвращает итератор, который возвращает итератор местоположения данных при возникновении данных, если в map нет данных для поиска, он возвращает итератор, равный итератору функции end, описание программы
#include <map> #include <string> #include <iostream> Использовать пространство имён std; Int main() { Map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, "student_one")); mapStudent.insert(pair<int, string>(2, "student_two")); mapStudent.insert(pair<int, string>(3, "student_three")); iterator<int, string> iter; iter = mapStudent.find(1); if(iter != mapStudent.end()) { Cout << "Найдено, значение - " << iter->second << endl; } Else { Cout << "Не найдено" << endl; } }
Третий способ:Этот метод используется для определения наличия данных, он显得有些笨拙,но я планирую объяснить его здесь
Использование функции Lower_bound, эта функция используется для возвращения нижнего ограничителя ключа (является итератором)
Использование функции Upper_bound, эта функция используется для возвращения верхнего ограничителя ключа (является итератором)
Например: если в map уже вставлены 1, 2, 3, 4, то lower_bound(2) возвращает 2, а upper_bound(2) возвращает 3
Функция Equal_range возвращает pair, где первый элемент - это итератор, возвращаемый Lower_bound, а второй итератор - это итератор, возвращаемый Upper_bound. Если эти итераторы равны, то это означает, что в map не出现这个 ключ, комментарий программы
#include <map> #include <string> #include <iostream> Использовать пространство имён std; Int main() { Map<int, string> mapStudent; mapStudent[1] = "student_one"; mapStudent[3] = "student_three"; mapStudent[5] = "student_five"; iterator<int, string> iter; iter = mapStudent.lower_bound(2); { // Возвращается нижний ограничитель 3, итератор Cout << iter->second << endl; } iter = mapStudent.lower_bound(3); { // Возвращается нижний ограничитель 3, итератор Cout << iter->second << endl; } iter = mapStudent.upper_bound(2); { // Возвращается верхний ограничитель 3, итератор Cout << iter->second << endl; } iter = mapStudent.upper_bound(3); { // Возвращается верхний ограничитель 5, итератор Cout << iter->second << endl; } Pair<map<int, string>::iterator, map<int, string>::iterator> mapPair; mapPair = mapStudent.equal_range(2); if(mapPair.first == mapPair.second) { cout << "Не найдено" << endl; } Else { Cout << "Find" << endl; } mapPair = mapStudent.equal_range(3); if(mapPair.first == mapPair.second) { cout << "Не найдено" << endl; } Else { Cout << "Find" << endl; } }
6. Очистка данных и определение пустоты
Очистить данные map можно с помощью функции clear(), определить, есть ли данные в map, можно с помощью функции empty(), она возвращает true, если map пуст
7. Удаление данных
Здесь используется функция erase, у которой есть три overload функции, их использование будет подробно описано в примере
#include <map> #include <string> #include <iostream> Использовать пространство имён std; Int main() { Map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, "student_one")); mapStudent.insert(pair<int, string>(2, "student_two")); mapStudent.insert(pair<int, string>(3, "student_three")); //Если вы хотите продемонстрировать эффект вывода, выберите один из следующих вариантов, вы получите лучше видимый результат //Если нужно удалить 1, удалить с помощью итератора iterator<int, string> iter; iter = mapStudent.find(1); mapStudent.erase(iter); //Если нужно удалить 1, удалить по ключу Int n = mapStudent.erase(1); //Если удалено, возвращается 1, в противном случае 0 //Используйте итератор для удаления участков //Следующий код очистит весь map mapStudent.erase(mapStudent.begin(), mapStudent.end()); //При удалении участка要注意, это также characteristic STL, удаление участка является集合ом, передним закрытым и задним открытым //Добавьте код для遍нения и вывода }
8. Другие методы использования функций
Здесь есть функции swap, key_comp, value_comp, get_allocator и т.д., эти функции не используются часто в программировании, поэтому мы их опустим, если вы хотите изучить их, вы можете сделать это самостоятельно
9. Сортировка
Рассказываем о более сложных методах, связанных с сортировкой, в STL по умолчанию используется оператор '<' для сортировки, у кода, приведенного выше, с точки зрения сортировки нет никаких проблем, так как ключи являются типом int, который поддерживает оператор '<', в некоторых случаях, когда ключ является структурой, возникает проблема при сортировке, так как у нее нет операции '<', функции insert и т.д. не проходят компиляцию, далее мы рассмотрим два метода решения этой проблемы
Первый случай: перегрузка оператора <, пример программы
#include <map> #include <string> Использовать пространство имён std; Типedef struct tagStudentInfo { Int nID; String strName; }StudentInfo, *PStudentInfo; //Информация о студенте Int main() { int nSize; // Использование информации о студенте для отображения оценок map<StudentInfo, int> mapStudent; iterator iter; StudentInfo studentInfo; studentInfo.nID = 1; studentInfo.strName = "student_one"; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90)); studentInfo.nID = 2; studentInfo.strName = "student_two"; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80)); for (iter = mapStudent.begin(); iter != mapStudent.end(); iter++) cout << iter->first.nID << endl << iter->first.strName << endl << iter->second << endl; }
Этот код не может быть скомпилирован, нужно перегрузить оператор <, вот так:
Типedef struct tagStudentInfo { Int nID; String strName; Оператор bool < (tagStudentInfo const& _A) const { //Эта функция определяет стратегию сортировки, по nID, если nID равны, то по strName Если (nID < _A.nID) вернуться true; Если (nID == _A.nID) вернуться strName.compare(_A.strName) < 0; Вернуть false; } }StudentInfo, *PStudentInfo; //Информация о студенте
Второй случай: использование функции-оболочки, в этот момент в структуре нет прямого перегрузки меньше, программа пояснение
#include <map> #include <string> Использовать пространство имён std; Типedef struct tagStudentInfo { Int nID; String strName; }StudentInfo, *PStudentInfo; //Информация о студенте Classs sort { Публичный: Оператор bool () (StudentInfo const &_A, StudentInfo const &_B) const { Если (_A.nID < _B.nID) вернуться true; Если (_A.nID == _B.nID) вернуться _A.strName.compare(_B.strName) < 0; Вернуть false; } } Int main() { // Использование информации о студенте для отображения оценок Map<StudentInfo, int, sort>mapStudent; StudentInfo studentInfo; studentInfo.nID = 1; studentInfo.strName = "student_one"; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90)); studentInfo.nID = 2; studentInfo.strName = "student_two"; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80)); }
10. Кроме того
Поскольку STL является единым целым, многие методы map связаны с другими компонентами STL, например, при сортировке, по умолчанию используется меньше, то есть less<>, если нужно сортировать от大到小的, это涉及到 много моментов, которые невозможно объяснить все.
Должно быть также упомянуто, что из-за того, что map внутренне упорядочен, и это гарантируется красно-черным деревом, многие функции имеют время выполнения O(log2N), если функцию map можно реализовать, а также STL Algorithm может выполнить эту функцию, рекомендуется использовать встроенные функции map, так как они более эффективны.
Должно быть упомянуто, что map имеет характеристики пространства, так как каждый элемент map соответствует узлу красно-черного дерева, и этот узел занимать 16 байт памяти, когда он не сохраняет ваши данные, это включает в себя указатель родителя, указатели на детей слева и справа, и еще один энум (символизирующий красно-черный, эквивалент балансирующего фактора в балансирующем двоичном дереве), я думаю, вы должны знать, что это место очень затратное на память, больше не буду говорить...
Вот и все, что я хотел рассказать вам о кратком изложении использования STL map в C++. Надеюсь, вам понравится и вы поддержите tutorial!