Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Результат_2012_02_09.docx
Скачиваний:
6
Добавлен:
20.04.2015
Размер:
593.36 Кб
Скачать

Задача 3: Напечатать все содержимое файла на экран (оптимизация).

Рассуждения:

  1. Следует отметить, что в конкретно этой задачи мы не использовали реально произвольный доступ. При чтении в пункте 7 мы добавляли строки в конец вектора, а при выводе в пункте 8 мы перемещались по индексам последовательно, «без скачков». Так же мы добавляли только в конец массива. Именно это подсказывает оптимизацию решения – вместо vector для хранения строк использовать ДЕК. Следует отметить, что операция добавления в конец ДЕК занимает константное время. Поэтому часть программы для чтения строки из файла можно оптимизировать следующим образом:

//здесь будем хранить строки

deque<string> lines;

//пока не дошли до конца файла

while (ifs.eof() == false) {

string curLine;

getline(ifs, curLine);

lines.push_back(curLine);

}

ifs.close();

  1. Операцию чтения можно еще уменьшить по объему исходного кода воспользовавшить тем фактом, что getline – это функция, которая возвращает то, что прочитала. Поэтому уменьшенный код оптимизации будет следующим:

//здесь будем хранить строки

deque<string> lines;

string curLine;

//пока что-то получаем из файла

while (getline(ifs, curLine)) {

lines.push_back(curLine);

}

ifs.close();

  1. Для того, что бы оптимизировать 8й пункт решения задачи необходимо отметить последовательность перемещения по элементам вектора. Оптимизацию можно произвести с использованием стандартной функции for_each. Она может принимать 3 параметра – начало последовательности, окончание последовательности, указатель на функцию действия с одним элементом последовательности.

  2. Начало последовательности можно найти с помощью функции дека begin(), а окончание последовательности – с помощью функции дека end().

  3. Необходимо написать функцию для вывода одного элемента последовательности:

void printLine(string line) {

cout << line << endl;

}

  1. Приведем полный код оптимизированного решения:

#include <iostream>

#include <fstream>

#include <string>

#include <deque>

#include <algorithm>

using namespace std;

void printLine(string line) {

cout << line << endl;

}

int main() {

//ввод имени файла

cout << "enter filename: " << flush;

string dictionary_name;

dictionary_name = "D:\\sample.txt";

//cin >> dictionary_name;

//открытие файла

ifstream ifs(dictionary_name);

//проверка на корректность открытия файла

if (!ifs.is_open()) {

cout << "Could not open file: " << dictionary_name <<endl;

return 1;

}

//здесь будем хранить строки

deque<string> lines;

//пока не дошли до конца файла

while (ifs.eof() == false) {

string curLine;

getline(ifs, curLine);

lines.push_back(curLine);

}

ifs.close();

cout << endl;

for_each(lines.begin(), lines.end(), printLine);

cout << "----- file end -------" << endl << "press enter";

char z;

cin.get(z);

return 0;

}

Задача 4. Удалить все нечетные элементы из массива

Размышления.

  1. Для того, что бы удалить элементы из массива, необходимо создать массив. А для создания массива необходимо получить размер массива. Пусть пользователь вводит размер массива с клавиатуры.

  2. Пользователь вводит размер с клавиатуры, которая является стандартным устройством ввода. Поэтому можно использовать поток ввода cin. Следует отметить, что для использования cin необходимо подключть подуль #include <iostream>. И если быть более точным, то использовать надо не cin, а std::cin. Но для сокращения записи подключим пространство имен std с помощью using namespace std.

  3. Для операции ввода из стандартного потока используется оператор >>. Поэтому первый шаг в реализации получения размера будет:

#include <iostream>

using namespace std;

int main(int argc, char* argv[]) {

int size;

cin >> size;

cout << "user enter value: " << size;a

return 0;

}

  1. Но в этом решении есть недостаток – если пользователь введет некорректное значение, то будет не хорошо. Для исправления этого недостатка воспользуется тем, что оператор >> является функцией, которая возвращает успешность или не успешность операции. Если операция не успешна, то надо восстановить корректное состояние различных флагов с помощью функции clear() и убрать все данные, которые находятся в буфере. Следует отметить, что последним символом в буфере будет символ ‘\n’. После очистки входного потока надо повторно перейти к получению числа. Поэтому реализация считывания корректного числа будет следующая:

#include <iostream>

using namespace std;

int getCorrectValue() {

while (true) {

int size;

if (!(cin >> size)) {

cin.clear();

while(std::cin.get()!= '\n');

continue;

}

return size;

}

}

int main(int argc, char* argv[]) {

int size = getCorrectValue();

cout << "user enter value: " << size;

return 0;

}

  1. Теперь можно перейти к созданию массива. Следует отметить, что для создания массива используется оператор new[], поэтому для его удаления необходимо использовать delete[]. С учетом этого, следующий шаг в реализации задачи будет:

#include <iostream>

using namespace std;

int getCorrectValue() {

while (true) {

int size;

if (!(cin >> size)) {

cin.clear();

while(std::cin.get()!= '\n');

continue;

}

return size;

}

}

int main(int argc, char* argv[]) {

int size = getCorrectValue();

if (size < 0) {

cout << "array size can not be negative number";

return 1;

}

int *data = new int[size];

delete[] data;

return 0;

}

  1. Теперь аозникает вопрос о заполнении массива. Пусть массив заполняется случайными числами. В С++ для генерации случайных чисел используется функция rand(), которая возвращает числа в диапазоне от 0 до RAND_MAX, которая является константой. Но в общем случае нам необходимо получать числа в диапазоне от [min;max). Поэтому для генерации числа необходимо адаптировать эту функцию. Если диапазон [0;RAND_MAX) поделить на RAND_MAX, то получим диапазон [0;1). Если диапазон от [0;1) умножить на (max-min), то получим диапазон [0;max-min). Если к результату прибавить min, то получим диапазон от [min; max). Поэтому функция генерации случайного числа будет выглядить следующим образом:

int getRandValue(int max, int min) {

return (((double)rand())/RAND_MAX)*(max - min) + min;

}

В ней отдельно следует отметить преобразование результата функции rand() в тип double. Если этого преобразования не будет, то rand()/RAND_MAX будет являтся операцией целое/целое и оператор «/» будет является целочисленным делением и результатом всегда будет 0. Поэтому для того, что бы оператор «/» стал делением, необходимо использовать явное преобразование в тип double.

Еще одним обязательным действием вяляется инициализация генератора случайных чисел с помощью функции srand(). Следует отметить, что время запуска программы каждый раз является разным, поэтому в качестве стартового значения можно воспользоваться результатом функции time(). В кодах инициализация генератора случайных чисел будет следующая:

srand(time(NULL));

  1. Теперь можно написать функцию заполнения массива случайными числами.

void fillArray(int *data, int size) {

for (int i = 0; i < size; i++) {

data[i] = getRandValue(-5, 10);

}

}

  1. Следующей задачей является вывод массива до обработки и после обработки. Для вывода массива нам нужно знать сам массив, его размер. Но и так же потребуется «заголовок» для вывода массива (что бы пользователь мог отличать массивы до обработки и после обработки). Заголовок – это строка. Можно воспользоваться типом std::string (подключив модуль #include <string>), но можно воспользоваться char * (т.к. в данном случае строка заголовка при выводе не будет меняться). Реализация этой задачи в кодах будет следующая:

void printArray(char *caption, int *data, int size) {

cout << caption << ": ";

for (int i = 0; i < size; i++) {

cout << data[i] << " ";

}

cout << "\n";

}

  1. Теперь необходимо написать функцию, которая будет обрабатывать массив. Очевидно, что при удалении элементов массива массив будет меняться. Так же для выполнения задания необходима функция удаления элемента по индексу (логика которой почти аналогична логике удаления элемента по индексу на C#, за исключением того, что старый массив необоходимо удалить). И для работы с массивом необходимо знать его размер.

void delByIndex(int *&data, int &size, int index) {

int *newData = new int[size - 1];

for (int i = 0; i < index; i++) {

newData[i] = data[i];

}

for (int i = index; i < size - 1; i++) {

newData[i] = data[i + 1];

}

delete[] data;

data = newData;

size--;

}

void mainAction(int *&data, int &size) {

for (int i = size - 1; i >= 0; i--) {

if (data[i] % 2 == 1) {

delByIndex(data, size, i);

}

}

}

  1. Теперь можно реализовать всю задачу. Следует отметить, что пользователю желательно реализовать задержку после завершения работы, что бы он мог увидеть результаты работы программы. Для этого воспользуемся функцией _getch(). Следует отметить, что она без проблем работает в Visual C++, но в других компиляторах может называться _getch() или отсутствовать. Но она не носит принципиального характера для логики решения задачи, поэтому воспользуемся ею.

#include <time.h>

#include <conio.h>

#include <iostream>

using namespace std;

void delByIndex(int *&data, int &size, int index) {

int *newData = new int[size - 1];

for (int i = 0; i < index; i++) {

newData[i] = data[i];

}

for (int i = index; i < size - 1; i++) {

newData[i] = data[i + 1];

}

delete[] data;

data = newData;

size--;

}

void mainAction(int *&data, int &size) {

for (int i = size - 1; i >= 0; i--) {

if (data[i] % 2 == 1) {

delByIndex(data, size, i);

}

}

}

int getCorrectValue() {

while (true) {

int size;

if (!(cin >> size)) {

cin.clear();

while(std::cin.get()!= '\n');

continue;

}

return size;

}

}

void printArray(char *caption, int *data, int size) {

cout << caption << ": ";

for (int i = 0; i < size; i++) {

cout << data[i] << " ";

}

cout << "\n";

}

int getRandValue(int max, int min) {

return (((double)rand())/RAND_MAX)*(max - min) + min;

}

void fillArray(int *data, int size) {

for (int i = 0; i < size; i++) {

data[i] = getRandValue(-5, 10);

}

}

int main(int argc, char* argv[]) {

srand(time(NULL));

cout << "enter array size: ";

int size = getCorrectValue();

if (size < 0) {

cout << "array size can not be negative number";

_getch();

return 1;

}

int *data = new int[size];

fillArray(data, size);

printArray("before process", data, size);

mainAction(data, size);

printArray("after process", data, size);

delete[] data;

_getch();

return 0;

}