- •Алгоритмы поиска и сортировки. Сортировки: выбором, обменом, вставкой. Анализ сложности алгоритмов на примере сортировок. Простой и бинарный поиск.
- •Оценка алгоритмов сортировки
- •Классификация алгоритмов сортировок
- •Сортировка выбором
- •Void selectSort(t* arr, int size)
- •Сортировка пузырьковым всплытием (обменом)
- •Void bubbleSort(t* arr, int size)
- •If(pr) break;
- •Шейкерная (перемешиванием) сортировка
- •Void ShakerSort(t* arr, int start, int n)
- •Int left, right, I;
- •Сортировка вставками
- •Void insertSort(t* a, int size)
- •// Поиск места элемента в готовой последовательности
- •Быстрая сортировка
- •Рассмотрим алгоритм подробнее.
- •Общий алгоритм
- •Void quickSortR(t* a, long n) {
- •Модификации кода и метода
- •Void qsortR(t *a, long size) {
- •InsertSort(a, size);
- •Итеративная QuickSort
- •Void qSortI(t a[], long size)
- •Сортировка слиянием
- •Void Merging_Sort (t *a, int n){
- •Сортировка методом Шелла
- •Void Shell_Sort (t *a, int n)
- •Алгоритмы поисков в массивах
- •Линейный поиск (поиск в лоб) в массивах
- •Двоичный поиск (дихотомия)
Двоичный поиск (дихотомия)
Перед применением алгоритма двоичного поиска массив обязательно должен быть отсортирован.
В первом цикле делим весь наш исходный отсортированный массив пополам и сравниваем ключ поиска со средним значением (по которому делили массив).
Если равны, то ключ поиска найден, иначе, если ключ поиска меньше этого среднего значения, то продолжим поиск в первой половине массива, в обратном случае, во второй части.
В следующем цикле выбранную часть массива также делим пополам и, как и в предыдущем цикле выполняем сравнение.
В случае, если ключ поиска не совпал с центральным элементом, выбираем нужную часть и в следующем цикле будем уже работать с ней.
Т.е. после каждого сравнения отсекается ровно половина, сокращая тем самым область поиска.
Так продолжается до тех пор, пока значение центрального элемента не совпадет с ключом поиска, либо не исчерпаются все элементы в получаемых подмассивах.
Для поиска в массиве, состоящем из 1024 элементов, потребуется максимум 10 сравнений, т.к. деление будет происходить так: 512, 256, 128, 64, 32, 16, 8, 4, 2, 1.
Посчитать максимальное количество сравнений можно и таким образом: представим 1024 как 2 в 10-й степени.
Число степени и будет нам говорить о количестве максимальных сравнений.
К примеру, в массиве из 1 048 576 (2 в 20-й степени) элементов, нужно выполнить как максимум только 20 сравнений.
Если брать в сравнение этот вид поиска и линейный поиск, то в массиве из 1 048 576 элементов, нужно было бы выполнить в среднем 1 048 576 / 2 сравнений, а это целых 524 288.
Программа, реализующая алгоритм двоичного поиска в массиве:
template<class T>
int binarySearch (T a[], int size, T key ) { int low=0, int high=size-1;
//выделяем место в памяти для переменной, которая будет //у нас сохранять значение середины массива int middle;
//цикл двоичного поиска //цикл длится, пока между границами массива есть значения while (low <= high) {
middle = (low + high) / 2;
//если найден ключ поиска, то возвращаем его индекс if (key == a[middle])
return middle;
//в случае, если не найден ключ поиска, и его значение меньше //среднего значения, меняем верхнюю границу массива, тем самым //отсекая половину с большими значениями, в которой точно искать //нечего else if (key < a[middle])
high = middle - 1;
//в случае, если не найден ключ поиска, и его значение больше //среднего значения, меняем нижнюю границу массива, тем самым //отсекая половину с меньшими значениями else
low = middle + 1;
}
//если ключ поиска не найден в массиве, то возвращаем -1 return -1;
}
Результат работы некоторой программы:
Как мы видим, по результатам работы программы ищем число 4 (ключ поиска).
В первой итерации определяется середина массива, значением является число 14. Происходит сравнение ключа поиска с этим значением и, в случае несоответствия, продолжается поиск.
Целью поиска выбирается подмассив меньших значений, т.к. ключ поиска 4 меньше 14.
Во второй итерации выведен этот подмассив.
Теперь серединой выбрано значение 6 - оно также не совпадает с ключом поиска, которое меньше 6.
И опять, в разделенном пополам массиве также выбирается подмассив с меньшими значениями.
Его мы видим в третьей итерации.
На данном этапе подмассив уже состоит всего - лишь из трех значений, серединой выбирается 2.
Сравниваем с ключом - не совпадает, 4 больше, чем 2, а значит, поиск на следующей итерации будет проходить в подмассиве с большими значениями.
На четвертой итерации мы видим, что подмассив состоит из всего - лишь из одного числа, которое выбирается серединой, выполняется проверка и находится ключ.
Выводится сообщение, что ключ поиска найден в элементе массива с индексом 2.
В данном примере было использовано максимальное число сравнений, равное четырем. Как вы уже знаете, максимальным числом возможных сравнений является степень числа 2, возведя в которую мы получим размер массива.
