30 января 2013 в 16:57
Изучаем map (ассоциативный массив) C++
На данный момент существует отличный контейнер map, который позволяет вам ассоциировать элементы с чем угодно. Например, у вас есть список продуктов для покупки (список книг в библиотеке). Вам необходимо хранить сколько и чего нужно купить (название и количество книг в библиотеке). Контейнер <map> позволяет нам хранить эти данные в виде ключ-значение (книга-количество, продукт-вес\объем...). Контейнер <map> является отсортированным массивом. Сортировка произведена по ключу.
Для использования <map> вам необходимо сначала его подключить:
#include <map>
Для создание контейнера достаточно написать:
map <key type, data type> map_name;
Например map<string, int> books; Содержит связку название книги / количество
или
map<string, CObject*> objects; Содержит связку название объекта / указатель на объект
Для доступа (или записи) в массив нужно писать:
map_name[key];
Контейнер map также имеет возможность работы с итераторами. Поэтому вы можете использовать с ним множество различных алгоритмов.
Элементы класса map имеют только уникальные значения ключей.
Элементы автоматически сортируются.
Класс multimap может иметь несколько элементов с одинаковым значением ключа.
begin() - итератор на первый элемент;
end() - итератор на элемент идущий после последнего;
rbegin() - итератор на последний элемент (для обратных алгоритмов);
rend() - итератор на позицию перед первым элементом (для обратных алгоритмов).
размер отображения
empty() - возвращает истину, если размер отображения 0;
size() - возвращает число элементов;
max_size() - максимально возможный размер отображения.
count(key) - число элементов соответствующих указанному ключу. Для класса map значения 1 или 0;
find(key) - итератор на первый элемент с указанным ключом;
lower_bound(key) - итератор на первый элемент, чей ключ больше или равен указанному ключу;
upper_bound(key) - итератор на первый элемент, чей ключ больше указанного ключа;
equal_range(key) - диапазон элементов, чей ключ равен указанному ключу;
[] - операция индексации по ключу.
swap(map& m) - обмен значениями с другим отображением;
insert(el) - вставка элемента, возвращается его позиция;
insert(beg,end) - вставка элементов из указанного диапазона;
erase(key) - удалить указанный элемент;
erase(it), erase(start,end) - удаляет элемент с заданным итератором или между заданными
clear() - удалить все элементы.
прочие методы
Для классов перегружены операции =,[],==,!=,<,>,<=,>=.
Про работы с итераторами:
Для обращения к элементу в строках и векторах достаточно было перед именем контейнера поставить *, но в map так не получится, т.к. в каждом элементе хранится 2 значения (ключ и данные). Поэтому надо писать так:
(*iter).first - для обращения к ключу и
(*iter).second -для обращения к данным,
где iter - итератор элемента
Кроме контейнера map существует контейнер multimap. Его отличие в том, что мы можем одному ключу задать несколько соответствий. Например, автору сопоставить несколько написанных им книг.
Примеры:
Программы для подсчета количества слов в тексте и вывод частоты их встречи в процентном соотношении (подсчет частоты встречи слов в тексте в процентах)
#include <iostream>
#include <string>
#include <map>
#include <fstream>
using namespace std;
int main()
{
map <string,int> words;
ifstream in;
in.open("in.txt");
string word;
while (in>>word)
{
words[word]++;
}
ofstream out;
out.open("out.txt");
int count = 0;
map <string,int>::iterator cur;
out<<"Words count:"<<endl;
for (cur=words.begin();cur!=words.end();cur++)
{
out<<(*cur).first<<": "<<(*cur).second<<endl;count+=(*cur).second;
}
out<<"Words percenc:"<<endl;
for (cur=words.begin();cur!=words.end();cur++)
{
out<<(*cur).first<<": "<<(float)((float)(*cur).second/(float)count)*100<<"%"<<endl;
}
return 0;
}
Программа для создания словаря для брута (и не только).
#include <iostream>
#include <string>
#include <map>
#include <fstream>
using namespace std;
int main()
{
map words;
ifstream in;
in.open("in.txt");
string word;
while (in>>word)
{
words[word]++;
}
ofstream out;
out.open("out.txt");
for (map ::iterator it=words.begin();it!=words.end();it++)
{
out<<(*it).first<<";"<<endl;
}
cout<<"Done"<<endl;
return 0;
}
Программа подсчета частоты встречи слов в тексте может быть полезна для расшифровки текста. (Некоторые алгоритмы для шифровки используют замену букв каким-то образом)
Вторая программа, создающая словарь для брута, работает очень просто. Она берет текст и вытаскивает из него все слова.
Ниже приведен пример создания словаря унарных математических функций с помощью класса map и вычисление этих функций по словарю.
#include<iostream>
#include<map>
#include<string>
#include<functional>
#include<math.h>
#define PI 3.1415926
using namespace std;
typedef pointer_to_unary_function<double,double>fdu;
map<string,fdu> funcs;
void testFuncs();
// инициализируем словарь функций
void initFuncs(){
funcs.insert(make_pair("sin",ptr_fun(sin)));
funcs.insert(make_pair("abs",ptr_fun(fabs)));
//...
}
//---------------------------------------------
int main(){
initFuncs();
// используем наш словарь для вычислений
cout<<funcs["abs"](-23)<<endl;
cout<<funcs["sin"](PI/2)<<endl;
cout<<funcs["sin"](PI/6)<<endl;
// тест с ручным вводом
// testFuncs();
return 0;
}
//---------------------------------------------
void testFuncs(){
string key=""; double arg=0;
// выполняем пока не будет набран
// не существующий ключ
// можно также сделать потомка от map
// с возбуждением исключения в [] при не существующем ключе
while(1){
cout<<"input function name and argument:"<<endl;
cin>>key;
// проверка есть ли элемент
// с указанным ключом
if(!funcs.count(key)){
cout<<"no function "<<key<<endl<<"exit"<<endl;
break;
}
cin>>arg;
cout<<"result: "<<funcs[key](arg)<<endl;
}
}
хеш отображения
В дополнение к стандарту stl многие компиляторы реализовали дополнительные классы hash_map и hash_multimap. В нем элементы не сортируются. А для быстрого доступа к элементу по ключу используется специальная хеш-функция.
Включаемый файл зависит от компилятора. Так в MinGw это
#include <ext/hash_map>
В других компиляторах это может быть
#include <hash_map>
Для использования этого класса в MinGw необходимо использовать пространство имен __gnu_cxx.
Во-вторых, часто типом для ключа является строка. А в MinGw (возможно старых версий как у меня) определена хеш-функция только для С строк, но не для класса string. Решается эта проблема специализацией шаблона хеш-функции для класса string. Этот код можно вынести во включаемый файл или вставлять его перед объявлением первой переменной такого типа.
В остальном классы аналогичны map и multimap. Так что переделка предыдущего примера с использованием hash_map для MinGw не составляет труда.
...
#include <ext/hash_map>
...
using namespace __gnu_cxx;
// специализация шаблона хеш-функции для класса string
namespace __gnu_cxx{
template<> struct hash<std::string> {
size_t operator()(const std::string& s) const {
return __stl_hash_string(s.c_str());
}
};
}
...
hash_map<string,fdu> funcs;
...
Эти классы включены в последние стандарты C++ под именами unordered_map и unordered_multimap.
16 февраля 2018 в 16:32
16 февраля 2018 в 16:32
28 июня 2019 в 12:18
Сложно но интересно))
авторизуйтесь
или войдите через