...

пятница, 18 октября 2013 г.

Непрактичные сортировки – бессмысленные и беспощадные

image

А что это мы всё об умных да об эффективных алгоритмах? А давайте эту тоскливую осеннюю пятницу развеем чем-нибудь контрпродуктивным!?


Представляю Вашему вниманию ТОП-5 самых нетрадиционных сортировок всех времён и народов.


Младопрограммистам такое полезно показывать в дидактических целях. Всех остальных как минимум позабавит.




image

С этой сортировкой нужно быть предельно осторожным. Неосмотрительно угодив в трясину, рискуете сгинуть навсегда.

Принцип прост как плесень. Перетряхиваем массив до тех пор пока он внезапно не отсортируется. Процесс может счастливо завершиться сразу, а может длиться до тепловой смерти Вселенной. Это уж как повезёт.


image

Средняя сложность по времени: O(n x n!). Есть также и лучшая: Ω(n). Что интересно, худшая временная сложность этого алгоритма науке неизвестна.


Аккуратно. Код, в котором можно увязнуть.


import java.util.Random;

public class BogoSortAlgorithm extends SortAlgorithm {

//Если есть массив, значит его можно отсортировать
public void sort(int data[]) throws Exception {
if (data.length > 0) runBogoSort(data);
}

//А вот и сортировочное болото
private void runBogoSort(int data[]) throws Exception {

Random generator;
int tempVariable;
int randomPosition;

do {

generator = new Random();

for (int i = 0; i < data.length; i++) {

randomPosition = generator.nextInt(data.length);
tempVariable = data[i];
data[i] = data[randomPosition];
data[randomPosition] = tempVariable;
pause(i,randomPosition);

}

} while(!isSorted(data)); //Пока не отсортируем

}

//Проверяем, отсортирован ли массив
private boolean isSorted(int data[]) {

for (int i = 1; i < data.length; i++)
if (data[i] < data[i - 1]) return false;

return true;

}

}







image

Где BogoSort, там и BozoSort. Метод сортировки детского клоуна Бозо™ легко объяснить даже трёхлетнему ребёнку. Выбираем наугад два элемента, меняем местами, проверяем не привело ли это к успеху. Если нет, то повторяем те же действия – и так до до победного конца.

image

Может показаться, что BozoSort принипиально не отличается от BogoSort, но это только на первый взгляд. Клоун Бозо™ сортирует со средней временной сложностью O(n x n!) и это же является и верхней границей по времени.


Клоун Бозо™ ещё и искромётно программирует.


import java.util.Random;

class BozoSortAlgorithm extends SortAlgorithm {

void sort(int a[]) throws Exception {

boolean sorted = false; //Считаем что не отсортировано

while (!sorted) {

//Берём наугад два элемента массива...
int index1 = Randomize(a.length);
int index2 = Randomize(a.length);

//... и меняем их местами
int temp = a[index2];
a[index2] = a[index1];
a[index1] = temp;
pause(index1, index2);

//Отсортировали?

sorted = true;

for (int i = 1; i < a.length; i++) {
if (a[i-1] > a[i]) {
pause(i, i-1);
sorted = false;
break;
}
}

}

}

//Выбираем в массиве случайный индекс
private int Randomize( int range ) {

double rawResult;
rawResult = Math.random();
return (int) (rawResult * range);

}

}







image

Взглянем на задачу сортировки сквозь призму комбинаторики. Любой массив – обычное конечное множество из n элементов, для которого существует n! перестановок. Некоторые из них – массив в упорядоченном состоянии. Составив алгоритм для перебора всех перестановок, мы неизбежно найдём ту самую.

image

Худшая сложность по времени как и у клоуна Бозо™ – O(n х n!). А вот с лучшей дела обстоят получше – О(n).


Элегантный перебор всех перестановок массива.


class PermSortAlgorithm extends SortAlgorithm {

//Отсортировали подмассив?
boolean issorted(int a[], int i) throws Exception {

for (int j = a.length-1; j > 0; j--) {

//Сравниваем и если что - меняем
compex(j, j - 1);

if(a[j] < a[j - 1]) {
return false;
}

}

return true;

}

//Рекурсивный PermSort
boolean sort(int a[], int i) throws Exception {

int j;

// Проверка на упорядоченность подмассива
if (issorted(a, i)) {
return true;
}

// Подмассив не отсортирован.
// Поэтому перебираем перестановки элементов.

for(j = i+1; j < a.length; j++) {

compex(i, j);

//Попробуем-ка переставить
int T = a[i];
a[i] = a[j];
a[j] = T;

//Рекурсивно призываем новую перестановку
if(sort(a, i + 1)) {
return true;
}

//Возврат к исходному состоянию
T = a[i];
a[i] = a[j];
a[j] = T;

}

return false;

}

//Сортируем исходный массив с помощью алгоритма PermSort.
void sort(int a[]) throws Exception {
sort(a, 0);
}

}







image

Сортировка названа в честь комик-труппы «Three Stooges» («Три недоумка») веселившей американскую публику в прошлом веке: с начала 30-х по конец 60-х. К слову, всего «недоумков» было шестеро, за 4 десятилетия творческой деятельности состав трио иногда менялся.

Развесёлая троица специализировалась на фарсе и эксцентрике. Также ведёт себя и сортировка: подобно карикатурному персонажу она безумно мечется по массиву; как и положено в буффонаде – после нелепых приключений с главным героем всё хорошо. Массив отсортирован, happy end.


Алгоритм остроумно рекурсивен.


class StoogeSortAlgorithm extends SortAlgorithm {

void sort(int a[], int lo, int hi) throws Exception {

//Сравниваем/меняем элементы на концах отрезка
if(a[lo] > a[hi]) {
int T = a[lo];
a[lo] = a[hi];
a[hi] = T;
}

//Меньше трёх?
if(lo + 1 >= hi) return;

//Чему равна одна треть?
int third = (hi - lo + 1) / 3;

sort(a, lo, hi - third); //Для первых 2/3 массива
sort(a, lo + third, hi); //Для последних 2/3 массива
sort(a, lo, hi - third); //Для первых 2/3 массива

}

//Вызываем сортировку для всего массива
void sort(int a[]) throws Exception {
sort(a, 0, a.length-1);
}

}







image

Берём отрезок массива (вначале это весь массив) и сравниваем элементы на концах отрезка. Если слева больше чем справа, то, естественно, меняем местами.

Затем, если в отрезке не менее трёх элементов, то тогда:

1) вызываем Stooge sort для первых 2/3 отрезка;

2) вызываем Stooge sort для последних 2/3 отрезка;

3) снова вызываем Stooge sort для первых 2/3 отрезка.

Сложность алгоритма подсчитана подкупающе точно: O(nlog 3 / log 1.5). Это не какие-то там мутные O(n).




image

Сам Бабушкин непосредственно не является автором метода, однако именно глубокие идеи Алексея легли в основу алгоритма.
Краткая справка о Бабушкине
Алексей Бабушкин, программист из Барнаула, предприниматель, инноватор. Студент 4-го курса АлтГТУ.

Участник региональной образовательной программы для одарённых школьников и молодёжи «Будущее Алтая». Победитель конкурса «Старт в науку».


Грантополучатель программы «У.М.Н.И.К.» проводимой Фондом содействию развития малых форм предприятий в научно-технической сфере.


Разработчик запатентованного антивируса «Иммунитет». Создатель оригинального гаджета «Флешка-маркер». Автор принципиально нового алгоритма архивации файлов.


По приглашению компании Microsoft принимал непосредственное участие в тестировании бета-версии Windows 8.






Принципиально новый алгоритм архивации файлов, предложенный Бабушкиным
Алгоритм архивации таков: любой файл представляет собой HEX-последовательность символов, переводим этот HEX в DEC, получаем неебически-большое число, дописываем перед этим число 0, — получаем число в диапазоне от 0 до 1 с огромным числом знаков после запятой, а дальше всё просто — подбираем 2 таких целочисленных числа, частное которых даст нам искомое число в диапазоне от 0 до 1 с точностью совпадений до последнего знака. Беда в подборе чисел, которое может идти и 2 часа, а может идти и 2 недели. Есть опытные образцы и работающая программа, и всё это работает.

Алексей Бабушкин






Пусть дан массив из n элементов. Последовательность перемещений элементов на свои места представима в виде ряда n-ричных одноразрядных чисел. Эту последовательность также можно считать многоразрядным n-ричным числом (назовём его числом Бабушкина). Каждый разряд этого числа – индекс позиции массива, в которую нужно вставить очередной элемент. Как получить такое число? Если число Бабушкина представить в 10-чном виде, получим большое (или не очень, зависит от размера массива) число, дописываем перед этим число 0, — получаем дробное число в диапазоне от 0 до 1, с некоторым числом знаков после запятой, а дальше всё просто — подбираем 2 таких целочисленных числа, частное которых даст нам искомое число в диапазоне от 0 до 1 с точностью совпадений до последнего знака. Найдём 2 таких числа – автоматически получаем последовательность перестановок, упорядочивающую массив.

Кому-то что-то не ясно? Сортировка Бабушкина пошагово:


1) Допустим, нужно отсортировать массив из n элементов (индексация начинается с нуля, индекс последнего элемента n — 1).

2) Специально подбираем два простых десятичных числа, x и y (x < y).

3) Делим x на y. Получаем дробное число от 0 до 1. Ноль отбрасываем, дробную часть оставляем. По сути дела получаем некое целое десятичное число.

4) DEC-представление числа, полученное на шаге 3, переводим в n-ричную систему счисления.

5) Берём в массиве 0-й элемент и помещаем его в дополнительный массив на позицию, индекс которой равен первой цифре в n-ричном представлении числа, полученном на шаге 4.

6) Берём в массиве 1-й элемент и помещаем его в дополнительный массив на позицию, индекс которой равен второй цифре в n-ричном представлении числа, полученном на шаге 4.

7) Берём в массиве 2-й элемент и помещаем его в дополнительный массив на позицию, индекс которой равен третьей цифре в n-ричном представлении числа, полученном на шаге 4.



n + 4) Берём в массиве n — 1 элемент и помещаем его в дополнительный массив на позицию, индекс которой равен последней цифре в n-ричном представлении числа полученном на шаге 4.

n + 5) Переносим все элементы из дополнительного массива в основной.

n + 6) PROFIT!!!


Преимущество сортировки Бабушкина перед любым другим методом очевидно – упорядочивание осуществляется с минимальными затратами, элементы сразу вставляются на свои места. Всё строится на использовании ряда n-ричных чисел, которые суть изначально правильная последовательность перемещений, приводящая к необходимому результату. Это делает сортировку Бабушкина бесспорным лидером по временной сложности – худший, средний и лучший результат – O(n). Нужно только подобрать два числа, которые при делении одного на другое сразу дадут самую экономную последовательность.


Есть опытные образцы и работающая программа и всё это работает.






Сортировка Бабушкина на Java.

К сожалению, реализацию на Java сортировку Бабушкина найти не удалось. Извините.





На этом всё, экспресс-экскурс в мир альтернативных сортировок окончен, благодарю за внимание. Если не сложно, заполните карточку для голосования, прилагаемую к раздаточным материалам лекции.

Отдельная благодарность Патрику Морину (Patrick Morin) за любезно предоставленные java-примеры.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Комментариев нет:

Отправить комментарий