- •Глава 2. Сортировка и порядковые статистики
- •Отношение на множестве целых чисел является линейным порядком, а включение множеств нет.
- •Алгоритм 8. Лексикографической сортировки
- •Алгоритм 9. Лексикографической сортировки строк различной длины
- •Алгоритм 10.1. Построение сортирующего дерева
- •Алгоритм 10.2. Сортдеревом
- •Алгоритм 11. Быстрсорт
- •Алгоритм 12.1. Нахождение k-го наименьшего элемента
- •Алгоритм 12.2. Нахождение k-го наименьшего элемента со случайным выбором разбивающего элемента
- •Int Selection(int array[], unsigned order, unsigned init, unsigned fin);
- •Void main()
- •Int result, result1, *array, *array1;
- •Int Selection(int array[], unsigned order, unsigned init, unsigned fin)
- •Int divisor, temp;
Алгоритм 12.2. Нахождение k-го наименьшего элемента со случайным выбором разбивающего элемента
Вход. Массив элементов Array[i], 1 i n, принадлежащих множеству S, на котором установлен линейный порядок , и целое k, 1 k n.
Выход. k-й наименьший элемент из массива Array.
Метод. В основе алгоритма лежит рекурсивная процедура, Selection (Выбор), аналогичная алгоритму 12.1. Отличие заключается в выборе разбивающего элемента m=Array[j]. В данном алгоритме разбивающий элемент выбирается случайным образом внутри последовательности Array[i], 1 i n. В абсолютном большинстве языков программирования определены датчики равномерно распределённых целых чисел на отрезке от 0 до n–1. Поэтому выбрать случайный элемент в последовательности не составляет труда. В отличие от алгоритма 12.1 в данном случае при каждом отдельном разбиении не гарантируется, что процедура Selection будет применяться к последовательностям, суммарный размер которых меньше исходной последовательности. Однако эффективность данного алгоритма доказывает следующая теорема.
Теорема 10. Среднее время работы алгоритма 12.2 линейно.
Доказательство. Пусть T(n) – среднее время, затрачиваемое алгоритмом Selection на последовательности из n элементов. Предположим для простоты, что все элементы множества S различны. (При наличии повторяющихся элементов результат не изменится).
Пусть элемент m, выбранный в качестве разбивающего, является i-м наименьшим элементом в S. Число i может принимать значения 0, 1, 2,, n–1 равновероятно. Если i>k, то Selection вызывается для последовательности, состоящей из i–1 элементов, а если i<k, то для последовательности, состоящей из n–i элементов. Поэтому среднее время работы рекурсии равно
Остальная часть процедуры Selection занимает время cn для некоторой постоянной c, так что при n2
T(n) cn +
В качестве упражнения докажите самостоятельно, что если T(1) c, то T(n) 4cn для всех n2.
Основные элементы программы нахождения k-го наименьшего элемента последовательности с использованием алгоритма 12.2 приведены ниже.
Программа 12.2 Нахождения k-го наименьшего элемента
// Программа использует порядковые статистики для выбора k-го наименьшего элемента
// массива, имеющего длину NUM
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <time.h>
#define NUM 124
Int Selection(int array[], unsigned order, unsigned init, unsigned fin);
Void main()
{
unsigned order, index, counter, logic;
Int result, result1, *array, *array1;
randomize();
//Выделение динамической памяти для массива array
array=new int[NUM];
// В этом месте должна стоять программа ввода массива array,
// из элементов которого необходимо выбрать k-ый по величине (k=order)
for(index=0; index<NUM; array1[index]=array[index]=random(NUM<<1),index++);
// В этом месте необходимо задать элемент order
result=Selection(array, order, 0, NUM-1);
if (result==-32767) printf("Error: order вне границ массива array \n");
else printf("%d-й наименьший элемент массива array %d\n", order, result);
delete [ ] array;
} // Конец main