JavaRush /Java блог /Random /Алгоритмы сортировки в теории и на практике
Viacheslav
3 уровень

Алгоритмы сортировки в теории и на практике

Статья из группы Random
Сортировка — один из базовых видов активности или действий, выполняемых над предметами. Ещё в детсве детей учат сортировать, развивая мышление. Компьютеры и программы — тоже не исключение. Существует огромное множество алгоритмов. Предлагаю посмотреть, какие есть и как они работают. Кроме того, вдруг однажды вас спросят об одном из них на собеседовании?
Алгоритмы сортировки в теории и на практике - 1

Вступление

Сортировка элементов — одна из категорий алгоритмов, к которым разработчик должен привыкнуть. Если когда-то, когда я учился, информатика не воспринималась так серьёзно, сейчас уже в школе должны уметь реализовывать алгоритмы сортировки и понимать их. Базовые алгоритмы, самые простые, реализованы при помощи цикла for. Естественно, чтобы отсортировать коллекцию элементов,например, массив, нужно по этой коллекции как-то пройти. Например:

int[] array = {10, 2, 10, 3, 1, 2, 5};
for (int i = 0; i < array.length; i++) {
	System.out.println(array[i]);
}
Что можно сказать об этом участке кода? Мы имеем цикл, в котором меняем значение индекса (int i) с 0 до последнего элемента в массиве. Фактически, мы просто берём каждый элемент в массиве и печатаем его содержимое. Чем больше элементов в массиве, тем дольше будет выполняться код. То есть, если n — количество элементов, при n=10 программа будет выполняться дольше, чем при n=5, в 2 раза. Когда в нашей программе есть один цикл, время выполнения растёт линейно: чем больше элементов, тем дольше выполнение. Получается, что алгоритм кода выше работает за линейное время (n). В таких случаях говорят, что "сложность алгоритма" равна O(n). Это обозначение ещё называют "большое О" или "асимптотическое поведение". Но можно запомнить просто "сложность алгоритма".
Алгоритмы сортировки в теории и на практике - 2

Простейшая сортировка (Bubble Sort)

Итак, мы имеем массив и можем по нему итерироваться. Отлично. Давайте попробуем теперь его отсортировать по возрастанию. Что это значит для нас? Это значит, что имея два элемента (например, a=6, b=5), мы должны переставить местами a и b, если a больше чем b (если a > b). Что для нас это значит при работе с коллекцией по индексу (как в случае с массивом)? Это значит, что если элемент с индексом а больше, чем элемент с индексом b, (array[a] > array[b]), такие элементы надо поменять местами. Перемену мест часто называют swap. Существуют различные способы перемены мест. Но мы используем простой, понятный и легко запоминаемый код:

private void swap(int[] array, int ind1, int ind2) {
    int tmp = array[ind1];
    array[ind1] = array[ind2];
    array[ind2] = tmp;
}
Теперь можем написать следующее:

int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int i = 1; i < array.length; i++) {
	if (array[i] < array[i - 1]) {	
		swap(array, i, i-1);
	}
}
System.out.println(Arrays.toString(array));
Как мы видим, элементы действительно поменялись местами. Мы начали с одного элемента, т.к. если массив будет всего из одного элемента, выражение 1 < 1 не вернёт true и тем самым мы обезопасим себя от случаев из массива в один элемент или вовсе без них, а код будет выглядеть лучше. Но наш итоговый массив не отсортирован всё равно, т.к. за один проход не удаётся всех отсортировать. Придётся добавить ещё цикл, в котором мы будем выполнять проходы один за одним до тех пор, пока не получим отсортированный массив:

int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
boolean needIteration = true;
while (needIteration) {
	needIteration = false;
	for (int i = 1; i < array.length; i++) {
		if (array[i] < array[i - 1]) {
			swap(array, i, i-1);
			needIteration = true;
		}
	}
}
System.out.println(Arrays.toString(array));
Вот наша первая сортировка и отработала. Мы итерируемся во внешнем цикле (while) до тех пор, пока не решим, что итераций больше не нужно. По умолчанию перед каждой новой итерацией мы допускаем, что наш массив отсортирован, и больше итерироваться не хотим. Поэтому, мы проходим элементы последовательно и проверяем это допущение. Но если элементы не по порядку, мы выполняем swap элементов и понимаем, что нет уверенности, что теперь элементы в правильном порядке. Следовательно, хотим выполнить ещё одну итерацию. Например, [3, 5, 2]. 5 больше трёх, всё хорошо. Но 2 меньше 5. Однако [3, 2, 5] требует ещё одного прохода, т.к. 3 > 2 и их нужно поменять местами. Так как мы используем цикл в цикле, получается, что сложность нашего алгоритма увеличивается. При n элементах она становится n * n, то есть O(n^2). Такая сложность называется квадратичной. Как мы понимаем, мы не можем точно знать, сколько понадобится итераций. Показатель сложности алгоритма служит цели показать тенденцию роста сложности, худший случай. Насколько сильно будет увеличиваться время работы при изменении количества элементов n. Сортировка пузырьком — одна из самых простых и неэффективных сортировок. Её ещё иногда называют "глупой сортировкой". Материал по теме:
Алгоритмы сортировки в теории и на практике - 3

Сортировка выбором (Selection Sort)

Другая сортировка — сортировка выбором. Она также имеет квадратичную сложность, но об этом чуть позже. Итак, идея простая. Каждый проход выбирать самый минимальный элемент и смещать его в начало. При этом каждый новый проход начинать сдвигаясь вправо, то есть первый проход — с первого элемента, второй проход — со второго. Выглядеть это будет следующим образом:

int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int left = 0; left < array.length; left++) {
	int minInd = left;
	for (int i = left; i < array.length; i++) {
		if (array[i] < array[minInd]) {
			minInd = i;
		}
	}
	swap(array, left, minInd);
}
System.out.println(Arrays.toString(array));
Данная сортировка неустойчива, т.к. одинаковые элементы (с точки зрения той характеристики, по которой мы сортируем элементы) могут изменить своё положение. Хороший пример приведён в статье на Википедии: Сортировка_выбором. Материал по теме:
Алгоритмы сортировки в теории и на практике - 4

Сортировка вставками (Insertion Sort)

Сортировка вставками тоже имеет квадратичную сложность, так как у нас опять цикл в цикле. В чём отличие от сортировки выбором? Данная сортировка является "устойчивой". Это значит, что одинаковые элементы не изменят свой порядок. Одинаковые с точки зрения характеристики, по которой мы сортируем.

int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int left = 0; left < array.length; left++) {
	// Вытаскиваем значение элемента
	int value = array[left];
	// Перемещаемся по элементам, которые перед вытащенным элементом
	int i = left - 1;
	for (; i >= 0; i--) {
		// Если вытащили значение меньшее — передвигаем больший элемент дальше
		if (value < array[i]) {
			array[i + 1] = array[i];
		} else {
			// Если вытащенный элемент больше — останавливаемся
			break;
		}
	}
	// В освободившееся место вставляем вытащенное значение
	array[i + 1] = value;
}
System.out.println(Arrays.toString(array));
Материал по теме:
Алгоритмы сортировки в теории и на практике - 5

Челночная сортировка (Shuttle Sort)

Среди простых сортировок есть ещё одна — челночная сортировка. Но мне больше нравится шаттл сорт. Мне кажется, мы редко говорим про космические челноки, а челночный у нас скорее бег. Поэтому проще представить, как в космос запускаются шаттлы. Вот вам ассоциация с этим алгоритмом. В чём суть алгоритма? Суть алгоритма в том, что мы итерируемся слева направо, при этом при выполнении swap элементов мы выполняем проверку всех остальных элементов, которые остались позади, не нужно ли повторить swap.

int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int i = 1; i < array.length; i++) {
	if (array[i] < array[i - 1]) {
		swap(array, i, i - 1);
		for (int z = i - 1; (z - 1) >= 0; z--) {
			if (array[z] < array[z - 1]) {
				swap(array, z, z - 1);
			} else {
				break;
			}
		}
	}
}
System.out.println(Arrays.toString(array));
Материал по теме:
Алгоритмы сортировки в теории и на практике - 6

Сортировка Шелла

Ещё одной простой сортировкой является сортировка Шелла. Суть её похожа на сортировку пузырьком, но каждую итерацию мы имеем разный промежуток между сравниваемыми элементами. Каждую итерацию он уменьшается вдвое. Вот пример реализации:

int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
// Высчитываем промежуток между проверяемыми элементами
int gap = array.length / 2;
// Пока разница между элементами есть
while (gap >= 1) {
    for (int right = 0; right < array.length; right++) {
        // Смещаем правый указатель, пока не сможем найти такой, что
        // между ним и элементом до него не будет нужного промежутка
       for (int c = right - gap; c >= 0; c -= gap) {
           if (array[c] > array[c + gap]) {
               swap(array, c, c + gap);
           }
        }
    }
    // Пересчитываем разрыв
    gap = gap / 2;
}
System.out.println(Arrays.toString(array));
Материал по теме:
Алгоритмы сортировки в теории и на практике - 7

Cортировка слиянием (merge sort)

Помимо указанных простых сортировок, есть сортировки и посложнее. Например, сортировка слиянием. Во-первых, нам на помощь придёт рекурсия. Во-вторых, сложность у нас будет уже не квадратичная, как мы с вами привыкли. Сложность данного алгоритма — логарифмическая. Записывается как O(n log n). Итак, давайте сделаем это. Сначала, напишем рекурсивный вызов метода сортировки:

public static void mergeSort(int[] source, int left, int right) {
        // Выберем разделитель, т.е. разделим пополам входной массив
        int delimiter = left + ((right - left) / 2) + 1;
        // Выполним рекурсивно данную функцию для двух половинок (если сможем разбить(
        if (delimiter > 0 && right > (left + 1)) {
            mergeSort(source, left, delimiter - 1);
            mergeSort(source, delimiter, right);
        }
}
Теперь, давайте к нему добавим основное действие. Вот пример нашего суперметода с реализацией:

public static void mergeSort(int[] source, int left, int right) {
        // Выберем разделитель, т.е. разделим пополам входной массив
        int delimiter = left + ((right - left) / 2) + 1;
        // Выполним рекурсивно данную функцию для двух половинок (если сможем разбить(
        if (delimiter > 0 && right > (left + 1)) {
            mergeSort(source, left, delimiter - 1);
            mergeSort(source, delimiter, right);
        }
        // Создаём временный массив с нужным размером
        int[] buffer = new int[right - left + 1];
        // Начиная от указанной левой границы идём по каждому элементу
        int cursor = left;
        for (int i = 0; i < buffer.length; i++) {
            // Мы используем delimeter чтобы указывать на элемент из правой части
            // Если delimeter > right, значит в правой части не осталось недобавленных элементов
            if (delimiter > right || source[cursor] > source[delimiter]) {
                buffer[i] = source[cursor];
                cursor++;
            } else {
                buffer[i] = source[delimiter];
                delimiter++;
            }
        }
        System.arraycopy(buffer, 0, source, left, buffer.length);
}
Запустим пример при помощи вызова метода mergeSort(array, 0, array.length-1). Как видно, суть сводится к тому, что мы принимаем на вход массив с указанием начала и конца участка для сортировки. При начале сортировки — это начало и конец массива. Далее мы вычисляем delimiter — положение делителя. Если делитель может разделить на 2 части, значит вызываем рекурсивно сортировку для участков, на которые делитель разбил массив. Подготавливаем дополнительный буферный массив, в котором выделяем отсортированный участок. Далее устанавливаем курсор в начало сортируемого участка и начинаем идти по каждому элементу пустого массива, который мы подготовили, и заполняем его наименьшими элементами. Если элемент, на который указывает курсор меньше, чем элемент, на который указывает делитель — помещаем в буферный массив этот элемент и сдвигаем курсор. В противном случае помещаем в буферный массив элемент, на который указывает разделитель и сдвигаем разделитель. Как только разделитель уйдёт за границы сортируемого участка или мы заполним весь массив, указанный диапазон считается отсортированным. Материал по теме:
Алгоритмы сортировки в теории и на практике - 8

Сортировка подсчётом (Counting Sort) и Поразрядная сортировка (Radix Sort)

Другим интересным алгоритмом сортировки является сортировка подсчётом (Counting Sort). Алгоритмическая сложность в этом случае будет O(n+k), где n — количество элементов, а k — максимальное значение элемента. Есть с алгоритмом одна незадача: нам нужно знать минимальное и максимальное значение в массиве. Вот пример реализации сортировки подсчётом:

public static int[] countingSort(int[] theArray, int maxValue) {
        // Массив со "счётчиками" размером от 0 до максимального значения
        int numCounts[] = new int[maxValue + 1];
        // В соответствующей ячейке (индекс = значение) увеличиваем счётчик
        for (int num : theArray) {
            numCounts[num]++;
        }
        // Подготавливаем массив для отсортированного результата
        int[] sortedArray = new int[theArray.length];
        int currentSortedIndex = 0;
        // идём по массиву со "счётчиками"
        for (int n = 0; n < numCounts.length; n++) {
            int count = numCounts[n];
            // идём по количеству значений
            for (int k = 0; k < count; k++) {
                sortedArray[currentSortedIndex] = n;
                currentSortedIndex++;
            }
        }
        return sortedArray;
    }
Как мы понимаем, очень неудобно, когда мы должны знать заранее минимальное и максимальное значение. И тут есть другой алгоритм — Radix Sort. Я здесь приведу алгоритм только визуально. Реализацию см. в материалах:
Алгоритмы сортировки в теории и на практике - 9
Материалы:
Алгоритмы сортировки в теории и на практике - 10

Быстрая сортировка Java (Quick Sort)

Ну и на сладкое — один из самых известных алгоритмов: быстрая сортировка. Она имеет алгоритмическую сложность, то есть мы имеем O(n log n). Данную сортировку ещё называют сортировкой Хоара. Интересно, что алгоритм был придуман Хоаром во время его пребывания в Советском Союзе, где он обучался в Московском университете компьютерному переводу и занимался разработкой русско-английского разговорника. А ещё данный алгоритм в более сложной реализации используется в Arrays.sort в Java. А что с Collections.sort? Предлагаю посмотреть самостоятельно, как сортируются они "под капотом". Итак, код:

public static void quickSort(int[] source, int leftBorder, int rightBorder) {
        int leftMarker = leftBorder;
        int rightMarker = rightBorder;
        int pivot = source[(leftMarker + rightMarker) / 2];
        do {
            // Двигаем левый маркер слева направо пока элемент меньше, чем pivot
            while (source[leftMarker] < pivot) {
                leftMarker++;
            }
            // Двигаем правый маркер, пока элемент больше, чем pivot
            while (source[rightMarker] > pivot) {
                rightMarker--;
            }
            // Проверим, не нужно обменять местами элементы, на которые указывают маркеры
            if (leftMarker <= rightMarker) {
                // Левый маркер будет меньше правого только если мы должны выполнить swap
                if (leftMarker < rightMarker) {
                    int tmp = source[leftMarker];
                    source[leftMarker] = source[rightMarker];
                    source[rightMarker] = tmp;
                }
                // Сдвигаем маркеры, чтобы получить новые границы
                leftMarker++;
                rightMarker--;
            }
        } while (leftMarker <= rightMarker);

        // Выполняем рекурсивно для частей
        if (leftMarker < rightBorder) {
            quickSort(source, leftMarker, rightBorder);
        }
        if (leftBorder < rightMarker) {
            quickSort(source, leftBorder, rightMarker);
        }
}
Тут всё очень страшно, так что будем разбираться. Для входного массива int[] source выставляем два маркера, левый (L) и правый (R). При первом вызове они соответствуют началу и концу массива. Далее определяется опорный элемент, он же pivot. После этого наша задача — переместить значения, меньшие чем pivot, в левую от pivot часть, а большие — в правую. Для этого сначала двигаем указатель L, пока не найдём значение, большее чем pivot. Если меньше значения не нашли, то L совпадёт с pivot. Потом двигаем указатель R пока не найдём меньшее, чем pivot значение. Если меньшее значение не нашли, то R совпадёт с pivot. Далее, если указатель L находится до указателя R или совпадает с ним, то пытаемся выполнить обмен элементов, если элемент L меньше, чем R. Далее L сдвигаем вправо на 1 позицию, R сдвигаем влево на одну позицию. Когда левый маркер L окажется за правым маркером R это будет означать, что обмен закончен, слева от pivot меньшие значения, справа от pivot — большие значения. После этого рекурсивно вызываем такую же сортировку для участков массива от начала сортируемого участка до правого маркера и от левого маркера до конца сортируемого участка. Почему от начала до правого? Потому что в конце итерации так и получится, что правый маркер сдвинется настолько, что станет границей части слева. Этот алгоритм более сложный, чем простая сортировка, поэтому его лучше зарисовать. Возьмём белый лист бумаги, запишем: 4 2 6 7 3 , а Pivot по центру, т.е. число 6. Обведём его в круг. Под 4 напишем L, под 3 напишем R. 4 меньше чем 6, 2 меньше чем 6. Итого, L переместился на положение pivot, т.к. по условию L не может уйти дальше, чем pivot. Напишем снова 4 2 6 7 3 , обведём 6 вкруг (pivot) и поставим под ним L. Теперь двигаем указатель R. 3 меньше чем 6, поэтому ставим маркер R на цифру 3. Так как 3 меньше, чем pivot 6 выполняем swap, т.е. обмен. Запишем результат: 4 2 3 7 6 , обводим 6 вкруг, т.к. он по прежнему pivot. Указатель L на цифре 3, указатель R на цифре 6. Мы помним, что двигаем указатели до тех пор, пока L не зайдём за R. L двигаем на следующую цифру. Тут хочется разобрать два варианта: если бы предпоследняя цифра была 7 и если бы она была не 7, а 1. Предпоследня цифра 1: Сдвинули указатель L на цифру 1, т.к. мы можем двигать L до тех пор, пока указатель L указывает на цифру, меньшую чем pivot. А вот R мы не можем сдвинуть с 6, т.к. R не мы можем двигать только если указатель R указывает на цифру, которая больше чем pivot. swap не делаем, т.к. 1 меньше 6. Записываем положение: 4 2 3 1 6, обводим pivot 6. L сдвигается на pivot и больше не двигается. R тоже не двигается. Обмен не производим. Сдвигаем L и R на одну позицию и подписываем цифру 1 маркером R, а L получается вне числа. Т.к. L вне числа — ничего не делаем, а вот часть 4 2 3 1 выписываем снова, т.к. это наша левая часть, меньшая, чем pivot 6. Выделяем новый pivot и начинаем всё снова ) Предпоследняя цифра 7: Сдвинули указать L на цифру 7, правый указатель не можем двигать, т.к. он уже указывает на pivot. т.к. 7 больше, чем pivot, то делаем swap. Запишем результат: 4 2 3 6 7, обводим 6 кружком, т.к. он pivot. Указатель L теперь сдвигается на цифру 7, а указатель R сдвигается на цифру 3. Часть от L до конца нет смысла сортировать, т.к. там всего 1 элемент, а вот часть от 4 до указателя R отправляем на сортировку. Выбираем pivot и начинаем всё снова ) Может на первый взгляд показаться, что если расставить много одинаковых с pivot значений, это сломает алгоритм, но это не так. Можно напридумывать каверзных вариантов и на бумажке убедиться, что всё правильно и подивиться, как такие простые действия предоставляют такой надёжный механизм. Единственный минус — такая сортировка не является стабильной. Т.к. при выполнении обмена одинаковые элементы могут поменять свой порядок, если один из них встретился до pivot до того, как другой элемент попал в часть до pivot при помощи обмена. Материал:

Итог

Выше мы рассмотрели "джентельменский" набор алгоритмов сортировки, реализованных на Java. Алгоритмы вообще штука полезная, как с прикладной точки зрения, так и с точки зрения развития мышления. Некоторые из них попроще, некоторые посложнее. По каким-то умные люди защищали различные работы на степени, а по другим писали толстые-толстые книги. Надеюсь, приложенный к статье материал позволит вам узнать ещё больше, так как это обзорная статья, которая и так получилась увесистой. И цель её — дать небольшое вступление. Про введение в алгоритмы можно так же прочитать ознакомиться с книгой "Грокаем Алгоримы". Также мне нравится плэйлист от Jack Brown — AQA Decision 1 1.01 Tracing an Algorithm. Ради интереса можно посмотреть на визуализацию алгоритмов на sorting.at и visualgo.net. Ну и весь Youtube к вашим услугам.
Комментарии (87)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Perl Developer Уровень 9
5 февраля 2023
Что за дичь автор нам втирает? Не читайте даже эту статью - в кажем коде фундаментальные ошибки!
1 октября 2022
😲😵Попал сюда на 6 уровне, бродя по ссылкам из статьи в статью. Ужс...надеюсь к какому-то времени разберусь и с этим.
Илья Городищ Уровень 21
30 сентября 2022
Вот мой mergesort, вроде багов не обнаружено.

    public static void mergeSort(int[] array, int left, int right) {
        int gap = right - left;
        int delimiter = left + gap / 2 + 1;
        if (delimiter > 0 && gap > 1) {
            mergeSort(array, left, delimiter - 1);
            mergeSort(array, delimiter, right);
        }

        int[] merged = new int[gap + 1];
        int cursor = left;
        for (int i = 0; i < gap + 1; i++) { 
            if (cursor > left + gap / 2) {
                merged[i] = array[delimiter++];
            } else if (delimiter > right) {
                merged[i] = array[cursor++];
            } else if (array[cursor] < array[delimiter]) {
                merged[i] = array[cursor++];
            } else merged[i] = array[delimiter++];
        }
        System.arraycopy(merged, 0, array, left, gap + 1);
    }
Кирилл Уровень 51
30 августа 2022
Ты бы хоть запустил свой код, да посмотрел, как он работает (и работает ли вообще) ))) Дизлайк, стыдно должно быть)
prime Уровень 42
31 июля 2022
вот мерджсорт с понятным обьяснением, этот чел умеет обьяснять доступно https://youtu.be/bOk35XmHPKs пузырьковая сортировка может иметь выход из цикла если оставшаяся часть уже отсортирована, чтобы не делать лишние проходы

public static void bubbleTrue(int[] arr) {
        boolean isSorted = false;
        while (!isSorted) {
            isSorted = true;
            for (int i = 1; i < arr.length; i++) {
                if (arr[i - 1] > arr[i]) {
                    int temp = arr[i-1];
                    arr[i-1] = arr[i];
                    arr[i] = temp;
                    isSorted = false;
                }
            }
        }
    }
Виталий Уровень 41
26 июня 2022
Сортировка слиянием, возможно более понятно будет

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(75, 99, 34, -9, 34, 58, 864);
        System.out.println(sort(list));
    }

    public static List<Integer> sort(List<Integer> mass) {
        if(mass.size() < 2) {    // бызовый слуяай выхода из рекурсии, когда массив имеет 0 или 1 элемент
            return mass;
        }
        else  {
            int delimiter = mass.get(0); // число, относительно которого разделяем массивы
            List<Integer> left = new ArrayList<>(); // левая сторона - числа меньше delimiter
            List<Integer> right = new ArrayList<>(); // правая сторона - числа больше delimiter
            for (int i = 1; i < mass.size(); i++) {
                if (mass.get(i) < delimiter) {
                    left.add(mass.get(i));
                } else {
                    right.add(mass.get(i));
                }
            }
            return merger(sort(left), delimiter, sort(right)); // вызываем sort у новых массивов
        }
    }

    //соединяем левую сторону + delimiter + правую сторону
    private static List<Integer> merger(List<Integer> left, int del, List<Integer> right) {
        left.add(del);
        left.addAll(right);
        return left;
    }
}
Andrey Karelin Уровень 41
2 июня 2022
массив случайных int-ов размером 200 000 элементов, сортируем разными способами: Arrays.sort() time: 74 ms COMBOsort sort time: 63 ms QUICKSORT sort time: 36 ms COUNTING sort time: 99 ms MERGE sort time: 56 ms MERGE(non recursive) sort time: 93 ms INSERT sort time: 2651 ms SHUTTLE sort time: 5341 ms SELECTION sort time: 12935 ms SHELLA sort time: 26127 ms BUBBLE sort time: 70148 ms Причем при арифметическом росте количества элементов...время сортировки первой группы растет не значительно, а последней - очень сильно. С числами в 3...5 раз побольше, последние сортировки отказываются работать совсем((.
hidden #2963026 Уровень 13
26 февраля 2022
как импортировать класса swap
Алексей Уровень 35
16 февраля 2022
Вопрос, скопировал код сортировка слиянием, запустил, он не работает, на этой строке: if (delimiter > right || source[cursor] > source[delimiter]) { выдает ошибку ArrayIndexOutOfBoundsException Или я не догоняю или лыжи не едут, кто-нибудь тестил код из статьи?
Илья Уровень 0
12 февраля 2022
Хорошие объяснения, спасибо за ваш труд! Если уж "жрать" сортировки, клик на доп. ссылки - там тоже хорошо объясняют!