|
Поиск и извлечение элемента отображения
Оператор взятия индекса является простейшим способом извлечения элемента. Например:
// map<string,int> word_count;
| int count = word_count[ "wrinkles" ];
Однако этот способ работает так, как надо, только при условии, что запрашиваемый ключ действительно содержится в отображении. Иначе оператор взятия индекса поместит в отображение элемент с таким ключом. В данном случае в word_count занесется пара
string( "wrinkles" ), 0
Класс map предоставляет две операции для того, чтобы выяснить, содержится ли в нем определенное значение ключа.
· count(keyValue): функция-член count() возвращает количество элементов с данным ключом. (Для отображения оно равно только 0 или 1). Если count() вернула 1, мы можем смело использовать индексацию:
int count = 0;
if ( word_count.count( "wrinkles" ))
| count = word_count[ "wrinkles" ];
· find(keyValue): функция-член find() возвращает итератор, указывающий на элемент, если ключ найден, и итератор end() в противном случае. Например:
int count = 0;
map<string,int>::iterator it = word_count.find( "wrinkles" );
if ( it != word_count.end() )
| count = (*it).second;
Значением итератора является указатель на объект pair, в котором first содержит ключ, а second – значение. (Мы вернемся к этому в следующем подразделе.)
Навигация по элементам отображения
После того как мы построили отображение, хотелось бы распечатать его содержимое. Мы можем сделать это, используя итератор, начальное и конечное значение которого получают с помощью функций-членов begin() и end(). Вот текст функции display_map_text():
void
display_map_text( map<string,loc*> *text_map )
{
typedef map<string,loc*> tmap;
tmap::iterator iter = text_map->begin(),
iter_end = text_map->end();
while ( iter != iter_end )
{
cout << "word: " << (*iter).first << " (";
int loc_cnt = 0;
loc *text_locs = (*iter).second;
loc::iterator liter = text_locs->begin(),
liter_end = text_locs->end();
while (liter != liter_end ) {
if ( loc_cnt )
cout << ',';
else ++loc_cnt;
cout << '(' << (*liter).first
<< ',' << (*liter).second << ')';
++liter;
}
cout << ")\n";
++iter;
}
cout << endl;
| }
Если наше отображение не содержит элементов, данная функция не нужна. Проверить, пусто ли оно, можно с помощью функции-члена size():
display_map_text( text_map );
Но более простым способом, без подсчета элементов, будет вызов функции-члена empty():
if ( ! text_map->empty() )
| display_map_text( text_map );
Словарь
Вот небольшая программа, иллюстрирующая построение отображения, поиск в нем и обход элементов. Здесь используются два отображения. Первое, необходимое для преобразования слов, содержит два элемента типа string. Ключом является слово, которое нуждается в специальной обработке, а значением – слово, заменяющее ключ. Для простоты мы задали пары ключ/значение непосредственно в тексте программы (вы можете модифицировать программу так, чтобы она читала их из стандартного ввода или из файла). Второе отображение используется для подсчета произведенных замен. Текст программы выглядит следующим образом:
#include <map>
#include <vector>
#include <iostream>
#include <string>
int main()
{
map< string, string > trans_map;
typedef map< string, string >::value_type valType;
// первое упрощение:
// жестко заданный словарь
trans_map.insert( va1Type( "gratz", "grateful" ));
trans_map.insert( va1Type( "'em", "them" ));
trans_map.insert( va1Type( "cuz", "because" ));
trans_map.insert( va1Type( "nah", "no" ));
trans_map.insert( va1Type( "sez", "says" ));
trans_map.insert( va1Type( "tanx", "thanks" ));
trans_map.insert( va1Type( "wuz", "was" ));
trans_map.insert( va1Type( "pos", "suppose" ));
// напечатаем словарь
map< string,string >::iterator it;
cout << "Наш словарь подстановок: \n\n";
for ( it = trans_map.begin();
it != trans_map.end(); ++it )
cout << "ключ: " << (*it).first << "\t"
<< "значение: " << ("it).second << "\n";
cout << "\n\n";
// второе упрощение: жестко заданный текст
string textarray[14]={ "nah", "I", "sez", "tanx",
"cuz", "I", "wuz", "pos", "to", "not",
"cuz", "I", "wuz", "gratz" };
vector< string > text( textarray, textarray+14 );
vector< string >::iterator iter;
// напечатаем текст
cout << "Исходный вектор строк:\n\n";
int cnt = 1;
for ( iter = text-begin(); iter != text.end();
++iter,++cnt )
cout << *iter << ( cnt % 8 ? " " : "\n" );
cout << "\n\n\n";
// map для сбора статистики
map< string,int > stats;
typedef map< string,int >::value_type statsValType;
// здесь происходит реальная работа
for ( iter=text.begin(); iter != text.end(); ++iter )
if (( it = trans_map.find( *iter ))
!= trans_map.end() )
{
if ( stats.count( *iter ))
stats [ *iter ] += 1;
else stats.insert( statsVa1Type( *iter, 1 ));
*iter = (*it).second;
}
// напечатаем преобразованный текст
cout << "Преобразованный вектор строк:\n\n";
cnt = 1;
for ( iter = text.begin(); iter != text.end();
++iter, ++cnt )
cout << *iter << ( cnt % 8 ? " " : "\n" );
cout << "\n\n\n";
// напечатаем статистику
cout << "И напоследок статистика:\n\n";
map<string,int,less<string>,allocator>::iterator siter;
for (siter=stats.begin(); siter!=stats.end(); ++siter)
cout << (*siter).first << " "
<< "было заменено "
<< (*siter).second
<< (" раз(а)\n" );
| }
Вот результат работы программы:
Наш словарь подстановок:
key: 'em value: them
key: cuz value: because
key: gratz value: grateful
key: nah value: no
key: pos value: suppose
key: sez value: says
key: tanx value: thanks
key: wuz value: was
Исходный вектор строк:
nah I sez tanx cuz I wuz pos
to not cuz I wuz gratz
Преобразованный вектор строк:
no I says thanks because I was suppose
to not because I was grateful
И напоследок статистика:
cuz было заменено 2 раз(а)
gratz было заменено 1 раз(а)
nah было заменено 1 раз(а)
pos было заменено 1 раз(а)
sez было заменено 1 раз(а)
tanx было заменено 1 раз(а)
wuz было заменено 2 раз(а)
Удаление элементов map
Существуют три формы функции-члена erase() для удаления элементов отображения. Для единственного элемента используется erase() с ключом или итератором в качестве аргумента, а для последовательности эта функция вызывается с двумя итераторами. Например, мы могли бы позволить удалять элементы из text_map таким образом:
string removal_word;
cout << "введите удаляемое слово: ";
cin >> removal_word;
if ( text_map->erase( remova1_word ))
cout << "ok: " << remova1_word << " удалено\n";
| else cout << "увы: " << remova1_word << " не найдено!\n";
Альтернативой является проверка: действительно ли слово содержится в text_map?
map<string,loc*>::iterator where;
where = text_map.find( remova1_word );
if ( where == text_map->end() )
cout << "увы: " << remova1_word << " не найдено!\n";
else {
text_map->erase( where );
cout << "ok: " << remova1_word << " удалено!\n";
| }
В нашей реализации text_map с каждым словом сопоставляется множество позиций, что несколько усложняет их хранение и извлечение. Вместо этого можно было бы иметь по одной позиции на слово. Но контейнер map не допускает дублирующиеся ключи. Нам следовало бы воспользоваться классом multimap, который рассматривается в разделе 6.15.
Упражнение 6.20
Определите отображение, где ключом является фамилия, а значением – вектор с именами детей. Поместите туда как минимум шесть элементов. Реализуйте возможность делать запрос по фамилии, добавлять имена и распечатывать содержимое.
Упражнение 6.21
Измените программу из предыдущего упражнения так, чтобы вместе с именем ребенка записывалась дата его рождения: пусть вектор-значение хранит пары строк – имя и дата.
Упражнение 6.22
Приведите хотя бы три примера, в которых нужно использовать отображение. Напишите определение объекта map для каждого примера и укажите наиболее вероятный способ вставки и извлечения элементов.
Не нашли, что искали? Воспользуйтесь поиском по сайту:
©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.
|