Как было предложено, наиболее эффективным по времени алгоритмом является сохранение частот каждого символа в массиве. Обратите внимание, однако, что если вы просто проиндексируете массив с символами, вы можете вызвать неопределенное поведение. А именно, если вы обрабатываете текст, который содержит кодовые точки за пределами диапазона 0x00-0x7F, например текст, закодированный с помощью UTF-8, в лучшем случае вы можете столкнуться с нарушением сегментации, а в худшем случае с повреждением данных стека:
char frequncies [256] = {};
frequencies ['á'] = 9; // Oops. If our implementation represents char using a
// signed eight-bit integer, we just referenced memory
// outside of our array bounds!
Решение, которое правильно учитывает это, будет выглядеть примерно так:
template <typename charT>
charT most_frequent (const basic_string <charT>& str)
{
constexpr auto charT_max = numeric_limits <charT>::max ();
constexpr auto charT_min = numeric_limits <charT>::lowest ();
size_t frequencies [charT_max - charT_min + 1] = {};
for (auto c : str)
++frequencies [c - charT_min];
charT most_frequent;
size_t count = 0;
for (charT c = charT_min; c < charT_max; ++c)
if (frequencies [c - charT_min] > count)
{
most_frequent = c;
count = frequencies [c - charT_min];
}
// We have to check charT_max outside of the loop,
// as otherwise it will probably never terminate
if (frequencies [charT_max - charT_min] > count)
return charT_max;
return most_frequent;
}
Если вы хотите перебирать одну и ту же строку несколько раз, измените приведенный выше алгоритм (как construct_array
), чтобы использовать std::array <size_t, numeric_limits <charT>::max () - numeric_limits <charT>::lowest () + 1>
. Затем верните этот массив вместо максимального символа после первого цикла for и опустите часть алгоритма, которая находит наиболее часто встречающийся символ. Создайте std::map <std::string, std::array <...>>
в коде верхнего уровня и сохраните в нем возвращенный массив. Затем переместите код для поиска наиболее часто встречающегося символа в этот код верхнего уровня и используйте кешированный массив счетчиков:
char most_frequent (string s)
{
static map <string, array <...>> cache;
if (cache.count (s) == 0)
map [s] = construct_array (s);
// find the most frequent character, as above, replacing `frequencies`
// with map [s], then return it
}
Теперь это работает только для целых строк. Если вы хотите многократно обрабатывать относительно небольшие подстроки, вам следует использовать первую версию. В противном случае я бы сказал, что вам лучше всего сделать что-то вроде второго решения, но разбивая строку на управляемые куски; таким образом, вы можете получить большую часть информации из своего кеша, только пересчитывая частоты в фрагментах, в которых находятся ваши итераторы.
24.01.2013