Работаем с std::map

Работаем с std::map

Задачка довольно лёгкая:

Для каждый буквы из алфавита нужно посчитать количество вхождений в файл. Вывести в убывающем порядке.

Input. txt

AaA Bb ZZZZZZZZZZZZZZZZ output. txt

Z 16

A 3

B 2

C 0

D 0

Напишем “каркас приложения”:

#include <iostream>

#include <fstream> // File-stream

#include <string>

#include <map> // Здесь будем хранить количество вхождений букв в файле using namespace std; int main()

{ return 0;

}

Для начала, нам нужно прочитать строку из файла, делается это достаточно просто: fstream readFile( "input. txt" ); string fileData; getline( readFile, fileData ); readFile. close();

Теперь нам нужно написать один из основных алгоритмов программы — подсчёт количества вхождений символа в строку. Как же мы будем хранить информацию? В std::map. Этот контейнер представляет собой пару Key => Value. Key у нас будет очередная буква из алфавита, Value — количество вхождений её в строку.

Заполняем начальными значениями

Создаем экземпляр такого контейнера и заполним его всеми буквами из латинского алфавита: map<char, int> dataArray; for( char i = 'A'; i < 'A'+26; ++i )

{ dataArray[i] = 0;

}

Если вам непонятен цикл, посмотрите на таблицу ascii-символов.

Большая латинская буква ‘A’ начинается с 65 или 0х41 номеров, поэтому нам нужно продвигать цикл от этого значения по +26-е. Значит наш цикл будет работать от 65-го по 90-е значение таблицы. В результате получим список: A = 0; B = 0; …

Заполняем в список сформированную информацию

Следующим шагом будет наполнение списка. Проходим по строке, переводим строку в верхний регистр, находим в списке соответствующую запись и увеличиваем её значение на 1.

For( int i = 0; i < fileData. size(); i++ )

{ fileData[i] = toupper( fileData[i] ); if( fileData[i] != ' ' )

{ dataArray[fileData[i]]++;

}

}

Не забываем проверять текущий символ на равенство пробелу.

Теперь уже мы получили такой список: A = 3; B = 2; C = 0; … ; Z = 16

Следующей задачей будет вывести его в спадающем порядке. Тут есть пару проблем: map сортирует Key по алфавиту, сделать сортировку по Value встроенными методами нельзя. Выходом будет создать ещё один контейнер, только теперь вида: Value => Key из старого. Т. е. мы получим: 3 = A, B = 2 … После чего и сможем отсортировать наш список.

Меняем местами ключ и значение

Напишем template-функцию, которая будет делать swap ключ-значение: template<typename T, typename U> map<U, T> converseMap( const map<T, U> &dataArray )

{ map<U, T> resultArray; for( map<T, U>::const_iterator it = dataArray. begin(); it!= dataArray. end(); ++it )

{ resultArray. insert( make_pair(it->second, it->first) );

} return resultArray;

}

Решено, теперь просто вывести список в обратном порядке, так как числа в Key сортируются по возростанию.

Вывод списка в обратном порядке map<int, char> resultArray = converseMap( dataArray ); for( map<int, char>::reverse_iterator it = resultArray. rbegin(); it!= resultArray. rend(); ++it )

{ cout << it->second << " " << it->first << "\n";

}

Так как нельзя использовать обратный цикл, используя begin(), end(), нам нужно включить специальные функции rbegin(), rend(). rbegin возвращает итератор на конец списка. rend возвращает итератор на начало списка. Также нужно использовать другой тип итераторов:reverse_iterator. Не забываем, что в текущем списке записи в виде: 3 => A, поэтому нам сразу нужно выводить значение, потом ключ.

Вот и всё, удачного кодинга!


Карта сайта


Информационный сайт Webavtocat.ru