if (in >> prev_x)
{
// Последовательность содержит не менее одного элемента.
size_t cur_run = 1; // текущая длина
max_run = 1; // по крайней мере, есть один элемент
while (in >> x)
{
if (x != prev_x) // соседние элементы не равны
{
cur_run = 1;
prev_x = x;
}
else // продолжается подпоследовательность равных
{
++cur_run;
}
max_run = max(max_run, cur_run);
}
}
return max_run;
}
// П.4: тестирование функции из п.3 на заданном массиве с заданным результатом.
bool test_max_duprun_stream(const double a[], size_t n, size_t result)
{
stringstream test;
for (size_t i = 0; i < n; ++i)
test << a[i] << ' ';
return result == max_duprun(test);
}
// Тип функции-"тестера".
using Max_duprun_tester = bool (*)(const double a[], size_t n, size_t result);
// П.2 и п.4: тестирование функции из п.1 или п.3 (выбирается через tester).
int test_max_duprun(Max_duprun_tester tester)
{
const double test1[] = { 1, 1, 2, 2, 2, 2, 0, 4, 2, 2 };
if (!tester(test1, 0, 0)) return 1;
if (!tester(test1, 1, 1)) return 2;
if (!tester(test1, 2, 2)) return 3;
if (!tester(test1, 5, 3)) return 4;
// sizeof возвращает размер статического массива в байтах
// (!) при этом массив должен быть виден в данном контексте непосредственно,
// (!) иначе программист рискует получить вместо размера массива размер указателя на него
if (!tester(test1, sizeof(test1) / sizeof(double), 4))
return 5;
const double test2[] = { -4, -3, -2, -1 };
if (!tester(test2, sizeof(test2) / sizeof(double), 1))
return 6;
const double test3[] = { 1, 2, 3, 3, 0, 0, 0, 1, 2 };
if (!tester(test3, sizeof(test3) / sizeof(double), 3))
return 7;
// Все тесты пройдены успешно.
return 0;
}
int main()
{
cout << test_max_duprun(test_max_duprun_array)
<< test_max_duprun(test_max_duprun_stream)
<< endl;
return EXIT_SUCCESS;
}
0540-digit_freqs.cpp
// digit_freqs.cpp
// Частоты цифр (относительно всех, только графических, друг друга).
// Выводит только ненулевые частоты.
#include
#include
#include // CHAR_BIT
#include
#include
using namespace std;
// Количество разных байт. Байт и char -- синонимы в C и C++.
const size_t BYTES = 1u << CHAR_BIT;
// Целочисленный тип для представления счётчиков.
// Тип streamoff -- целочисленный тип, достаточный для того, чтобы описать смещение в потоке
// или размер любого файла в данной системе, т.е. "достаточно большое целое".
using Counter = streamoff;
// Тип "гистограмма" -- массив счётчиков.
using Histogram = Counter[BYTES];
// Строит гистограмму байт потока. Добавляет количества к счётчикам h.
// Возвращает общее количество.
Counter byte_histogram(istream &in, Histogram h)
{
Counter bytes_read = 0;
// Читать по символу из потока, увеличивая на каждой итерации соответствующий счётчик в h.
for (char ch; in.get(ch); ++bytes_read)
h[(unsigned char)ch]++; /* Приведение к unsigned char необходимо так как
по стандарту char может быть "знаковым" и "верхняя половина" диапазона
в таком случае попадает в отрицательные индексы, что (при прямом использовании char)
повлекло бы выход за пределы массива h. */
return bytes_read;
}
// Строит гистограмму массива. Добавляет количества к счётчикам h.
// Возвращает переданный размер.
size_t byte_histogram(const char a[], size_t sz, Histogram h)
{
for (size_t i = 0; i < sz; ++i)
h[(unsigned char)(a[i])]++; /* Приведение к unsigned char необходимо так как
по стандарту char может быть "знаковым" и "верхняя половина" диапазона
в таком случае попадает в отрицательные индексы, что (при прямом использовании char)
повлекло бы выход за пределы массива h. */
return sz;
}
// Тип: указатель на функцию, принимающую и возвращающую целое число.
using Char_predicate = int (*)(int);
// Возвращает сумму элементов гистограммы, для индексов которых предикат filter возвращает истину.
Counter histogram_filter_sum(const Histogram h, Char_predicate filter)
{
Counter s = 0;
for (size_t i = 0; i < BYTES; ++i)
s += filter((int)i)? h[i]: 0; /* i приводится к int,
т.к. стандартные функции --- символьные предикаты принимают int, а не size_t */
return s;
}
// Преобразование номер десятичной цифры -> символ цифры.
inline unsigned char dec_digit(int n)
{
assert(0 <= n && n < 10);
return '0' + n;
}
// Для заданной гистограммы и заданного общего количества символов total получить частоты цифр.
// Возвращает суммарную частоту.
// Данную функцию удобно использовать для тестирования.
double digits_freqs(const Histogram h, Counter total, double freqs[10])
{
Counter h_digit_sum = 0;
const auto divisor = double(total);
for (int digit = 0; digit < 10; ++digit)
{
const auto h_digit = h[dec_digit(digit)];
h_digit_sum += h_digit;
freqs[digit] = h_digit / divisor;
}
return h_digit_sum / divisor;
}
// Вывести частоты в стандартный поток вывода.
// total_freq -- значение, возвращаемое функцией digits_freqs.
void print_digit_freqs(const double freqs[10], double total_freq)
{
for (int digit = 0; digit < 10; ++digit)
{
const auto digit_freq = freqs[digit];
if (digit_freq != 0.0)
cout << dec_digit(digit) << ": " << digit_freq << '\n';
}
cout << "Total: " << total_freq << endl;
}
// "Комплекс мероприятий": по гистограмме получить и вывести частоты для всех трёх случаев из задания.
// total -- количество всех символов (сумма гистограммы).
void print_relative_digit_freqs(const Histogram h, Counter total)
{
double freqs[10];
// 1. Для всех символов.
cout << "Digits among all characters\n";
print_digit_freqs(freqs,
digits_freqs(h, total, freqs));
// 2. Для графических.
cout << "\nDigits among graphical characters\n";
print_digit_freqs(freqs,
digits_freqs(h, histogram_filter_sum(h, isgraph), freqs));
// 3. Для цифр.
cout << "\nDigits among digits\n";
print_digit_freqs(freqs,
digits_freqs(h, histogram_filter_sum(h, isdigit), freqs));
}
///////////////////////////////////////////////////////////////////////////////
// Тестирование
// Сравнение на равенство пары массивов из 10 double.
bool are_freqs_equal(const double ft[10], const double fr[10])
{
for (int i = 0; i < 10; ++i)
if (ft[i] != fr[i])
return false;
return true;
}
// Собственно автоматический тест.
int test_digits_freqs()
{
const auto text = "This is a text with some 013 digits in it 01456...";
// 50 символов, из них графических 40, цифр 8, 0 и 1 встречаются дважды, 3456 -- однажды.
const double
f0[10] = { 0.04, 0.04, 0.0, 0.02, 0.02, 0.02, 0.02 },
f1[10] = { 0.05, 0.05, 0.0, 0.025, 0.025, 0.025, 0.025 },
f2[10] = { 0.25, 0.25, 0.0, 0.125, 0.125, 0.125, 0.125 };
Histogram h = {};
double freqs[10];
const auto total = byte_histogram(text, 50, h);
if (digits_freqs(h, total, freqs) != 0.16)
return 1;
if (!are_freqs_equal(freqs, f0))
return 2;
if (digits_freqs(h, histogram_filter_sum(h, isgraph), freqs) != 0.2)
return 3;
if (!are_freqs_equal(freqs, f1))
return 4;
if (digits_freqs(h, histogram_filter_sum(h, isdigit), freqs) != 1.0)
return 5;
if (!are_freqs_equal(freqs, f2))
return 6;
return 0;
}
int main()
{
cout << "Testing: " << test_digits_freqs() << endl;
Histogram h = {};
auto total = byte_histogram(cin, h);
cin.clear();
cout.precision(16);
print_relative_digit_freqs(h, total);
return EXIT_SUCCESS;
}
0545-cstring_array.cpp
// cstring_array.cpp
// Ввод-вывод средствами стандартной библиотеки C (не C++),
// управление динамической памятью также средствами C (malloc, calloc, realloc, free).
#include // malloc, realloc, free
#include // puts, fgets
#include // strlen, memcpy
using namespace std;
/// Максимальная длина строки (не включая '\0'), возвращаемой нашим вариантом gets.
const size_t MAX_GETS_LENGTH = 1023;
/// Вместо std::gets (которая объявлена устаревшей), мы реализуем
/// собственную функцию gets, создающую строку в динамической памяти.
/// Если строка на вводе слишком длинная, отрезаем на MAX_GETS_LENGTH символах.
/// Возвращает нулевой указатель, если не удалось прочитать ни одного символа.
char* gets()
{
char buffer[MAX_GETS_LENGTH + 1];
if (!fgets(buffer, MAX_GETS_LENGTH + 1, stdin))
return nullptr;
// Узнать длину считанной строки.
auto alloc_len = strlen(buffer) + 1;
// В отличие от gets, fgets записывает в буфер и перевод строки (если хватает места).
// Уберём этот перевод строки.
if (alloc_len > 1 && buffer[alloc_len - 2] == '\n')
{
buffer[alloc_len - 2] = '\0';
--alloc_len;
}
// Выделить в динамической памяти место на копию.
const auto new_str = (char*)malloc(alloc_len);
if (!new_str) // не хватило памяти?
return nullptr;
// Скопировать содержимое буфера в выделенную память.
memcpy(new_str, buffer, alloc_len);
return new_str;
}
/// Читаем построчно и складываем в динамический массив указатели.
/// Последний указатель в массиве обязательно нулевой.
/// Возвращает нулевой указатель в случае невозможности выделить память хотя бы на два указателя.
/// Увеличиваем массив "на ходу" по мере необходимости.
char** getlines()
{
Do'stlaringiz bilan baham: |