Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Книга C++.doc
Скачиваний:
24
Добавлен:
10.11.2019
Размер:
2.48 Mб
Скачать

Программа 5

// бросание шестигранной кости 6000 раз

#include < iostream.h >

#include < stdlib.h >

#include < time.h >

void main()

{

const int arraySize = 6;

int face, // объявление переменной face

frequency[arraySize] = {0}; /* объявление массива и инициализация

его нулевыми значениями */

srand (time(NULL));

for(int i = 0; i < 6000; i++)

{

// имитация броска игральной кости

face = rand() % 6 + 1;

/* увеличение значения соответсвующего элемента

массива на 1 */

++ frequency[face];

}

// вывод результатов на экран

cout << "Face" << '\t' << "Frequency\n";

for (face = 0; face < arraySize; face++)

cout << face + 1 << '\t' << frequency[face] << '\n';

}

Программа нахождения минимального и максимального элементов массива

Рассмотрим задачу нахождения минимального и максимального элементов массива.

#include <iostream.h>

void main()

{

const int n = 10; // Размерность массива

float a[n]; // Объявление массива

for(int i = 0; i < n; i++)

{

cout << "Input the a[" << i << "] element:\t";

cin >> a[i]; // Ввод значений массива

}

float Min, Max; // Минимум и максимум

Min = Max = a[0]; // инициализируются первым элементом массива

for(i = 1; i < n; i++) // Сравнение с текущим элементом

if(a[i] > Max)

Max = a[i]; // Текущий максимальный элемент

else if(a[i] < Min)

Min = a[i]; // Текущий минимальный элемент

cout << endl;

for(i = 0; i < n; i++)

cout << a[i] << "\t"; // Вывод исходного массива

cout << "\nMin element:\t" << Min << "\nMax element:\t" << Max << endl;

// Вывод результатов поиска

}

В данной программе обе переменные Min и Max изначально инициализируются первым элементом массива. Затем в цикле идет проверка: если текущий элемент массива больше Max, то переменной Max присваивается текущий элемент. И наоборот, если текущий элемент массива меньше Min, то переменной Min присваивается текущий элемент.

Сортировка массивов

Исторически зарождение методов машинной сортировки можно отнести еще к прошлому столетию, и за столь длительное время многие специалисты успели испробовать свои силы в этой области. Нет нужды говорить о важности самой области. Практически сортировка и поиск в той или иной мере присутствуют во всех приложениях; в частности, при обработке больших объемов данных эффективность именно этих операций определяет эффективность, а иногда и работоспособность всей системы. Поэтому можно сказать, что достаточно четкие представления об этой области нужны при решении любой задачи на ЭВМ как обязательные элементы искусства програмирования. В этом уроке мы обсудим простейшие известные способы сортировки и поиска.

Программа сортирует значения массива, используя один из самых простых способов. Сначала она сравнивает элементы массива a[0] и а[1], меняя местами их значения, если они не упорядочены, затем проделывает то же самое с элементами а[1] и а[2], а[2] и а[3] и т.д.. При выполнении этой последовательности операций элементы с большим значанием будут продвигаться вправо, и на самом деле элемент с наибольшим значением займет положение а[7]. При многократном выполнении этого процесса соответствующие элементы попадут в позиции а[6], а[5] и т.д., так что в конце концов все элементы будут упорядочены.

На рисунке представлено действие данной сортировки на восьми числах.

Рисунок - Пузырьковая сортировка

Ряд чисел удобно представить не горизонтально, а вертикально, чтобы элемент а[7] был сверху, а а[0] - снизу. Используемая при сортировке техника, получила название метода пузурька (пузырьковая сортировка ), потому что большие элементы, подобно пузурькам, "всплывают" на соответствующую позицию.

Сортировка выполняется с помощью вложенного цикла for. Если необходима перестановка, она выполняется тремя присваиваниями

hold = a[i];

a[i] = a[i+1];

a[i+1] = hold;

где дополнительная переменная hold временно хранит одно из двух переставляемых значений. Перестановку нельзя выполнить двумя присваиваниями

a[i] = a[i+1];

a[i+1] = a[i];

т.к. после первого присваивания значение а[i] будет потеряно, следовательно необходима дополнительная переменная.

/* Программа сортирует значения массива в возрастающем

порядке методом пузурька*/

#include < iostream.h >

void main()

{

const int arraySize = 8;

//объявление и инициализация массива

int a[arraySize] = {6, 10, 5, 0, 2, 11, 7, 3};

int hold;

//Следующая строка выводит на экран сообщение:

//Элементы данных в исходном порядке:

cout <<"\nThe enteried data is : \n";

// вывод массива на экран

for (int i = 0; i < arraySize; i++)

cout << a[i] << '\t';

// сортировка массива

bool flag = true; //флаг сотировки

// (false-массив не отсортирован, true-массив отсортирован)

// Изначально предполагаем оптимистический вариант

// объявили вспомогательные переменные

for (int j = 1;; j++) //создаем бесконечный цикл

{

for(i = 0; i <arraySize-j; i++)

if (a[i] > a[i+1])

{

//выполняем перестановку

hold = a[i];

a[i] = a[i+1];

a[i+1] = hold;

flag = false;

}

if(flag) //массив отсортирован?

break;//да - выход из цикла

flag = true; //иначе - устанавливаем флаг сортировки

}

//Следующая строка выводит на экран сообщение:

//Элементы данных в порядке возрастания:

cout << "\nIncrements data's series:\n";

// вывод массива на экран

for (i = 0; i < arraySize; i++)

cout << a[i] << '\t';

cout << '\n';

}

Главное достоинство пузырьковой сортировки заключается в простоте ее программирования. Однако, выполняется она медленно. Это становится очевидным при сортировке больших массивов.

Поиск

Часто, программисту приходится работать с большими объемами данных, хранящимися в виде массивов. Может оказаться необходимым определить, содержит ли массив, значение которое соответствует определенному ключевому значению. Процесс нахождения какого-то элемента массива называет поиском. В данном уроке мы рассмотрим наиболее простой способ поиска - линейный поиск.

Линейный поиск сравнивает каждый элемент массива с ключом поиска. Поскольку массив не упорядочен, вполне вероятно, что отыскиваемое значение окажется первым элементом массива. Но в среднем, однако, программа должна сравнить с ключом поиска половину элементов массива.

#include <iostream.h >

int linearSearch(int [], int, int);

void main()

{

const int arraySize = 100;

int a[arraySize], searchKey, element;

for( int x = 0; x < arraySize; x++)

a[x] = 2*x;

//Следующая строка выводит на экран сообщение

//Введите ключ поиска:

cout << "Please, enter the key: ";

cin >> searchKey;

element = linearSearch(a, searchKey, arraySize);

if(element != -1)

//Следующая строка выводит на экран сообщение

//Найдено значение в элементе

cout << "\nThe key was found in element " << element << '\n';

//Следующая строка выводит на экран сообщение

//Значение не найдено

else cout << "\nValue not found ";

}

int linearSearch (int array[], int key, int sz)

{

for (int i = 0; i < sz; i++)

if(array[i] == key)

return i;

return -1;

}

Метод линейного поиска хорошо работает для небольших или для несортированных массивов. Однако, для больших массивов линейный поиска неэффективен. Если массив отсортирован, можно использовать высокоэффективный метод двоичного поиска.

Алгоритм двоичного поиска исключает половину еще непроверенных элементов массива после каждого сравнения. Алгоритм определяет местоположение среднего элемента массива и сравнивает его с ключом поиска. Если они равны, то ключ поиска найден и выдается индекс этого элемента. В противном случае задача сокращается на половину элементов массива. Если ключ поиска меньше, чем средний элемент массива, то дальнейший поиск осуществляется в первой половине массива, а если больше, то во второй половине. Если ключ поиска не совпадает со средним элементом выбранного подмассива (части исходного массива), то алгоритм повторно применяется и сокращает область поиска до четверти исходного массива. Поиск продолжается до тех пор, пока ключ поиска не станет равным среднему элементу или пока оставшийся подмассив содержит хотя бы один элемент, не равный ключу поиска.

В наихудшем случае двоичный поиск в массиве из 1024 элементов потребует только 10 сравнений. Повторяющееся деление 1024 на 2 (поскольку после каждого сравнения мы можем исключить половину элементов массива) дает 512, 256, 128, 64, 32, 16, 8, 4, 2 и 1. Число 1024 (210) делится на 2 только десять раз. Деление на 2 эквивалентно одному сравнению в алгоритме двоичного поиска. Массив из 1048576 (220) элементов требует для нахождения ключа поиска самое большее 20 сравнений. Массив из одного миллиарда элементов требует для нахождения ключа поиска максимум 30 сравнений. Это огромное увеличение эффективности по сравнению с линейным поиском, который в среднем требует числа сравнений, равного половине числа элементов в массиве. Для миллиарда элементов выигрыш равен разнице между 500 миллионами сравнений и 30 сравнениями! Максимальное количество сравнений, необходимое для двоичного поиска в любом отсортированном массиве, может быть определено как первый показатель степени, при возведении в который числа 2 будет превышено число элементов в массиве.

Приведенная ниже Программа представляет итеративную версию функции binarySearch, реализующей алгоритм двоичного поиска. Функция получает четыре аргумента - массив целых чисел b, целое число searchKey, индекс массива low и индекс массива high. Если ключ поиска не соответствует среднему элементу массива, то устанавливается такое значение индекса low или high, что дальнейший поиск проводится в меньшем подмассиве. Если ключ поиска меньше среднего элемента, индекс high устанавливается как middle - 1, и поиск продолжается среди элементов от low до middle - 1. Если ключ поиска больше среднего элемента, индекс low устанавливается как middle + 1, и поиск продолжается среди элементов от middle - 1 до high. Программа использует массив из 15 элементов. Степень двойки для первого числа, большего, чем количество элементов в данном массиве, равна 4 (16 = 2 ), так что для нахождения ключа поиска нужно максимум четыре сравнения. Функция printRow выводит каждый подмассив в процессе двоичного поиска. Средний элемент в каждом подмассиве отмечается символом звездочки (*), чтобы указать тот элемент, с которым сравнивается ключ поиска.

Программа

// двоичный поиск в массиве

#include <iostream.h>

int binarySearch(int [], int, int, int, int);

void printRow(int [], int, int, int, int);

void main( void )

{

const int arraySize = 15;

int a[arraySize], key, result;

// инициализация элементов массива

for ( int i = 0; i < arraySize; i++)

a[i] = 2*i;

cout << "Input key, a number in [0,28]: ";

cin >> key;

// вызов функции binarySearch и присвоение,

// возвращаемого ею значения переменной result

result = binarySearch(a, key, 0, arraySize -1, arraySize);

if(result != -1)

cout << '\n' << key << " found in " << result

<< " element of array\n";

else

cout << '\n' << key << " not found \n";

}

// Двоичный поиск

int binarySearch(int b[], int searchKey, int low, int high, int size)

{

int middle;

while (low <= high)

{

middle = (low + high) / 2;

printRow(b, low, middle, high, size);

if (searchKey == b[middle])

return middle;

else if (searchKey < b[middle])

high = middle - 1;

else

low = middle + 1;

}

return -1;

}

// печать одной строки, показывающей текущую

// текущую обрабатываемую часть массива

void printRow(int b[], int low, int mid, int high, int size)

{

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

if (i < low || i > high)

cout << " ";

else

{

if (i*2 < 10) cout << " ";

else cout << " ";

if(i == mid)

cout << b[i] << '*'; /* отметить среднее значение */

else

cout << b[i] << ' ';

}

cout << '\n';

}

Фрагмент кода

if (i*2 < 10) cout << " ";

else cout << " ";

используется, для форматирования выходных данных. Иначе тот же результат можно получить, используя манипулятор потока setw(), как показано во фрагменте ниже. Обращение setw(3) определяет, что следующая выходная величина будет напечатана с шириной (размером) поля 3, т.е. ее значение будет содержать по крайней мере 3 символьных позиции. Если длина выходной величины менее 3 символов, она по умолчанию быдет выравнена в поле по правому символу. Если длина выходной величины более 3, размер поля будет увеличен, чтобы вместить полную величину. Программы, использующие подобное обращение, должны содержать директиву

#include<iomanip.h>

Другим манипулятором потока является обращение endl (аббревиатура словосочетания "end line"). Манипулятор endl выводит символ новой строки. Его использование не требует подключения файла iomanip.h

/*функция printRow с использованием манипуляторов потока*/

void printRow(int b[], int low, int mid, int high, int size)

{

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

if (i < low || i > high) cout << " ";

else if(i == mid)

cout << setw(3) << b[i] << '*';

else

cout << setw(3) << b[i] << ' ';

cout << endl;

}