Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СТА (лекции+лабы) / Структуры и алгоритмы обработки данных.docx
Скачиваний:
97
Добавлен:
16.03.2016
Размер:
1.9 Mб
Скачать

Struct IntegerVector

{

Int * m_pData;

Int m_nUsed;

Int m_nAllocated;

};

Следует отметить, что все переменные, входящие в состав структуры получили префикс “m_”, что означает членство (membership). Это не является обязательным требованием языка С++, а всего лишь рекомендуемой многими профессиональными программистами стилистической конвенцией. Такие идентификаторы легко отличить от других видов переменных благодаря префиксу, что повышает читабельность кода.

Типичные манипуляции со структурой-вектором следует выделить в отдельные функции с интуитивно понятным интерфейсом. Во-первых, необходима функция инициализации вектора, т.е., приведения его в начальное пригодное к использованию состояние:

void IntegerVectorInit ( IntegerVector & _vector, int _allocatedSize = 10 )

{

   _vector.m_pData = new int[ _allocatedSize ];

   _vector.m_nAllocated = _allocatedSize;

   _vector.m_nUsed      = 0;

}

Во-вторых, вектор должен освобождать выделенные им ресурсы памяти:

Void IntegerVectorDestroy ( IntegerVector & _vector )

{

   delete[] _vector.m_pData;

}

В-третьих, необходима функция для добавления очередного числа в конец вектора, которая автоматически увеличивает размер вектора в случае необходимости:

void IntegerVectorPushBack ( IntegerVector & _vector, int _data )

{

   // Закончилось ли место в векторе?

   if ( _vector.m_nUsed == _vector.m_nAllocated )

   {

       // Выделяем новый блок, в 2 раза больше прежнего

       int nAllocatedNew = _vector.m_nAllocated * 2;

       int * pNewData = new int[ nAllocatedNew ];

       // Копируем данные из прежнего блока в новый

       memcpy(

           pNewData,

           _vector.m_pData,

           sizeof( int ) * _vector.m_nAllocated

       );

       // Освобождаем старый блок и подменяем адрес на новый блок

       delete[] _vector.m_pData;

       _vector.m_pData = pNewData;

       // Обновляем количество выделенных ячеек

       _vector.m_nAllocated = nAllocatedNew;

   }

   // Записываем данное в очередную ячейку

   _vector.m_pData[ _vector.m_nUsed++ ] = _data;

}

Аргументы функций получили префикс в виде символа “_”, что также является одной из популярных стилистических конвенций.

Имея под рукой такие вспомогательные функции, выделенные из предыдущей версии программы, преобразуем основную программу в простую и очень читабельную:

Int main ()

{

   // Приглашение пользователя ко вводу

   std::cout << "Input integers, stop with Ctrl+Z: ";

   

   // Создаем вектор и инициализируем его одним вызовом

   IntegerVector v;

   IntegerVectorInit( v );

   // Пытаемся вводить числа с консоли одно за другим

   while ( true )

   {

       // Попытка ввода числа

       int temp;

       std::cin >> temp;

       if ( std::cin )

           // Просто просим вектор добавить новое данное в конец

           IntegerVectorPushBack( v, temp );

       else

           // Конец ввода

           break;

   }

   // Количество введенных данных сохранено в переменной m_nUsed в векторе

   // Выводим данные в обратном порядке

   for ( int i = v.m_nUsed - 1; i >= 0; i-- )

       std::cout << v.m_pData[ i ] << ' ';

   std::cout << std::endl;

   // Просим вектор освободить выделенные им ресурсы

   IntegerVectorDestroy( v );

}

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

Повторное использование решения

Предположим, возникла более сложная задача. Пользователь вводит последовательность целых чисел произвольной длины, программа создает последовательность частичных сумм и выводит ее на экран. Если на вход подана последовательность “1 2 3 4 5”, программа должна выдавать последовательность “1 3 6 10 15”, где каждое следующее число формируется как сумма текущего числа и всех предыдущих обработанных.

Чтобы не реализовывать логику работы с динамически растущим массивом целых чисел снова и снова, сначала следует применить еще один этап рефакторинга, выделив логику структуры данных в отдельные файлы исходного кода. Следует сформировать заголовочный файл с описанием структуры и прототипами функций, а тела функций разместить в отдельный файл. Заголовочный файл следует включать во всех местах использования данной функциональности.

integer_vector.hpp