Ми розглянули простий приклад використання map<> для підрахунку входження окремих літер в текст. Для цієї мети ми використовували контейнер карта<>. Але бібліотека STL нам надає і інший (близький) тип контейнера - це MultiMap<>, який допускає наявність багатьох элементов (пара<>) в своєму складі з однаковими значеннями ключів.
природно, що основні правила функціонування MultiMap<> зміняться (порівняно з карта<>). Для такого контейнера будуть наступні відмінності в поведінці:
Містить впорядковані пари <ключ,значение>, де ключ і значення можуть належати до довільних типів;
Елементи з будь-якими значеннями ключа не повинні бути унікальнімені, в впорядкованої послідовності елементів (по ключу) такі еквівалентні елементи представлені, як різні елементи, і розташовуються вони один за одним;
Оскільки ключі можуть збігатися, то операція додавання нової пари в таблицю (метод вставити()) завжди успішний. Тому немає сенсу повертати результат такої операції: повертається значення - void;
Оскільки тепер у контейнері може перебувати багато елементів з рівними ключами, то вводиться додатковий метод count(). Він отримує параметром значення ключа, повертає число входжень елементів, мають такий ключ, в контейнер;
операції видалення (метод прати()) із зазначенням ключа видаляється елемента видаляє все відразу елементи з однаковими ключами;
подивимося як MultiMap<> впорається з попередньої завданням. Ось текстові файли для тестування програми:
30 Брат і сестра | 11 Дурниця | 34 Бармаглот |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include <iostream> #include <sstream> #include <map> using namespace std; int main(int argc, char **argv) { multimap< char, int > alphabet; while (cin) { string line; getline(cin, line); if (line.empty()) continue; istringstream ist(line); char let; while ((let = ist.get()) && let != EOF) alphabet.insert(pair< char, int >(let, 1)); } cout << "alphabet size = " << alphabet.size() << endl; for (char c = 'a'; c <= 'z'; c++) cout << c << "(" << alphabet.count(c) << ") "; cout << endl; alphabet.erase('a'); cout << "alphabet size = " << alphabet.size() << endl; for (char c = 'a'; c <= 'z'; c++) cout << c << "(" << alphabet.count(c) << ") "; cout << endl; cout << "alphabet size = " << alphabet.size() << endl; } |
Як і в попередньому прикладі, використовується кілька громіздкий введення символів з потоку, що містить текст у багато рядків. Это связано с тем, що а). хотілося б читати і символи пробілу теж як символи, а не як роздільники і б). можна було б просто послідовно читати символи з cin з наступним виключенням переказів рядка. Але в показаному варіанті хотілося б зберегти незалежність від операційної системи (відмінність так званого DOS і UNIX перекладу рядка). В іншій частині код став багато коротше і простіше.
результат того, що ми отримали, показаний нижче (поруч повторено для порівняння той же дію, виконується карта<>):
Звернемо увагу на те, як одиничним оператором видалення alphabet.erase( 'а’ ) ми видалили з таблиць 38 элементов, визначаються ключем 'а’. Звідки взявся розмір size() в 696 элементов?
(Показана форма команди wc обчислює в операційній системі Linux число рядків у файлі. Команда ls виводить довжину файлу, т.е. число окремих байт, символів в файлі. У Windows ви можете спробувати домогтися деякого подібного результату використовуючи команду dir.)
Якщо ми із загального числа символів (довжини в байтах) віднімемо число рядків (перекладів рядків) у файлі, то ми і отримаємо цю цифру: 726 – 30 = 696. Таким образом, для кожного символу вхідного потоку був створений окремий елемент таблиці, например, з ключем 's’ було 39 таких елементів.
Усе, раніше сказане щодо карта контейнера<> (крім алгоритму приміщення і вибірки) в повній мірі відноситься і до MultiMap<>, например, вимога порівнянності ключів і то, як визначити чи перевизначити операцію порівняння.