Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Разбор классических алгоритмов и олимпиадных задач. Быстрая сортировка, продолжение.


Информационный Канал Subscribe.Ru

Повторюсь: кто может написать что-то, обращайтесь.

QuickSort, продолжение
В прошлый раз я привёл код, в котором за "базовый"(интересно, можно ли его так называть) брался центральный элемент(m:=a[(L+R) div 2];). Существуют и другие варианты выбора базового элемента. Рассмотрим, почему это так важно на примере:
Дан массив из пяти элементов 2 5 1 3 4. Будем действовать по нашему алгоритму:

- за базовый элемент мы выберем 1
- просматривая массив справа налево, найдем число меньшее либо равное 1, это она и есть :)
- просматривая массив слева направо найдём число большее либо равное 1, это число 2
- обменяем их
- получим массив 1 5 2 3 4
- процедура запустится рекурсивно для части массива 5 2 3 4, она преобразуется в 2 5 3 4
- процедура запустится рекурсивно для части массива 5 3 4, она преобразуется в 3 5 4
- процедура запустится рекурсивно для части массива 5 4 , она преобразуется в 4 5

Не такого поведения мы ждали от быстрой сортировки. Всё пошло наперекосяк с самого начала,
когда за базовый элемент мы выбрали наименьшее число массива. В таких случаях быстрая сортировка теряет свои достоинства и становится сортировкой класса O(n2).

За базовый можно взять любой элемент. В некоторых алгоритмах за базовый берётся первый элемент, наверное, это худший вариант(представьте, как будет сортироваться отсортированный(масло масляное) массив). Брать средний элемент, пожалуй, самый "демократичный" вариант. Если же у Вас паническая боязнь, что кто-то специално подсунет данные с наименьшим средним элементом, то Вы можете сгенерировать случайное число. Но это всё были полумеры: получить плюху на случайно сгенерированных массивах они готовы одинаково неплохо.

Самый лучший вариант - это взять средний из трёх элементов массива (поиск медианы трёх). Целесообразно для сравнения брать левый, средний и правый элементы массива. Поясню примером:
Дан массив 54 72 45 39 19 29 31 96 44 21 70 46 51 76 15 34, выберем в нём базовый элемент. Найдём среднее из чисел 54 96 34. Это 54. Реализуйте сами (попутно расставьте эти три числа в нужном порядке и "объясните" алгоритму, что они уже на месте).

Вероятность худшего случая мы снизили до приемлемых размеров. Но у быстрой сортировки есть ещё узкие места. Одно из них - это неадекватные реакции на большое количество одинаковых элементов. Выход есть и из этой ситуации - сменить алгоритм сортировки.

Оптимизация
1. Будем избавляться от рекурсии. Лишние 28 байт на стеке нам не нужны. Стек, мы реализуем программно. Для начала взгляните на процедуру(из прошлой статьи) сортировки и подумайте о том, что нужно хранить в стеке.
Переменные i,j,m,t сохранять не надо(они отрабатывают своё до рекурсивного вызова), остаются только L,R. Что из себя будет представлять стек в программе? Обычный массив + индекс свободной ячейки.
2. Напоследок самое главное. По таблице замеров мы видим, что на маленьких массивах быстрая сортировка заметно проигрывает. Т.к. алгоритм рекурсивный и каждый новый вызов происходит для меньшего массива, следовательно, при сортировке любого массива настанет момент, когда быстрая сортировка не выгодна. Этот момент не фиксирован, попробовав разные значения, у меня получилось, что на массивах длины <=20 нужно применять другой алгоритм. Глядя на таблицу мы видим что на таких данных эффективнее всего InsertionSort.
3. Собрав все три оптимизации воедино, я получил такой код.
P.S. Целесообразность оптимизации смотрите в таблице.

Задачи
1. Найти количество различных чисел среди элементов данного массива.
2. Имеется отсортированный по не убыванию массив из 65536 элементов. В нём случайным образом выбираются два элемента и меняются местами. Эта операция повторяется 256 раз. Ваша задача упорядочить массив по не убыванию.
3. На сельской улице живут Ивановы и Петровы. Необходимо, используя минимальное число обменов, расселить их так, чтобы Ивановы жили с одного конца улицы, а Петровы - с другого.

4. Имеется N камней веса А12,...,АN. Необходимо разбить их на две кучи таким образом,чтобы веса куч отличались не более чем в 2 раза. Если этого сделать нельзя, то указать это.
5. Имеются числа А12,...,АN и B1,B2,...,BN. Составить из них N пар (Аi, Bj) таким образом, чтобы сумма произведений пар была максимальна.

6. Задается словарь. Найти в нём все анаграммы (слова, составленные из одних и тех же букв).

Присылайте решения, желательно с описанием, и они будут публиковаться.

 
Замеры, мс
Кол-во 1632641282565121024204840968192163843276865536
Bubble0.00250.00850.03230.12930.52142.09368.301832.793130.88532.872151.68685.447761
Shaker0.00250.00800.02820.10920.42881.69556.756526.718106.15426.111716.66896.230936
Selection0.00240.00700.02220.07720.28311.08264.196416.53665.508263.501054.24213.419436
Insertion0.00120.00340.01140.04160.15880.61692.44139.719338.740154.76618.772474.213597
InsertionO0.00130.00330.00990.03380.12380.47231.84817.326129.112116.23463.991855.511466
QuickSort 0.0027 0.0062 0.0137 0.0300 0.0650 0.1400 0.3000 0.6400 1.3600 2.9000 6.1400 13.000 28.100
QuickSortO 0.0016 0.0040 0.0092 0.0210 0.0468 0.1000 0.2250 0.4910 1.0600 2.2800 4.8700 10.410 23.270

Subscribe.Ru
Поддержка подписчиков
Другие рассылки этой тематики
Другие рассылки этого автора
Подписан адрес:
Код этой рассылки: comp.soft.prog.fprogram
Отписаться
Вспомнить пароль

В избранное