Алгоритм сортировки пузыря не отслеживает текущее состояние массива.
Даже если он получает полностью отсортированный массив в качестве ввода, время выполнения останется одинаковым O (n ^ 2 ^) Сложность. По конструкции этот алгоритм анализирует все соседние пары элементов исходного массива n раз, где n это длина массива.
Оптимизированный пузырь
Алгоритм сортировки пузырьков не отслеживает текущее состояние массива любым способом.
Даже если мы отправим уже отсортированную массив в качестве ввода, нам понадобится одинаковое количество петлевых итераций, что и для несортированного массива, чтобы получить результат.
Производительность может быть улучшена путем добавления флага (логической переменной), которая будет контролировать, был ли по крайней мере один обмен на текущей итерации.
Если нет, то массив отсортирован, и задача завершена.
const optimizedBubbleSort = (arr) => {
let hasSwapped = false;
let outerLoopIterationCount = 0;
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i; j++) {
if (arr[j] > arr[j + 1]) {
hasSwapped = true;
let tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
if (!hasSwapped) {
return outerLoopIterationCount;
} else {
hasSwapped = false;
}
outerLoopIterationCount++;
}
return outerLoopIterationCount;
}
Давайте возьмем два массива, чтобы проверить реализацию. Второй два раза длиннее, чем первый, но у него есть только один элемент.
- Отображение начального состояния массивов
- Мы сортируем их и сохраняем количество итераций что
ОптимизацияBubblyortФункция сортировки вернется - Отображение массивов снова, чтобы убедиться, что они сортируются и проверьте количество итераций, которые необходимо сортировать
const testData = [ 0, -1, 4, 5, 2, -3 ];
const almostSortedTestData = [ 12, -3, -1, 0, 2, 4, 5, 7, 8, 9, 10 ];
console.log(testData, `Initial testData state`);
console.log(almostSortedTestData, `Initial almostSortedTestData state`);
const iterationsTestData = optimizedBubbleSort(testData);
const iterationsAlmostSortedTestData = optimizedBubbleSort(almostSortedTestData);
console.log(testData, `Total iterations: ${iterationsTestData}`);
console.log(almostSortedTestData, `Total iterations: ${iterationsAlmostSortedTestData}`);
Вывод консоли:
[ 0, -1, 4, 5, 2, -3 ] Initial testData state [ 12, -3, -1, 0, 2, 4, 5, 7, 8, 9, 10 ] Initial almostSortedTestData state [ -3, -1, 0, 2, 4, 5 ] Total iterations: 6 [ -3, -1, 0, 2, 4, 5, 7, 8, 9, 10, 12 ] Total iterations: 2
Хотя второй массив оказался в 2 раза дольше, чем первый, нам нужно только два итерация внешней петли, чтобы сортировать его.
На втором проходе Hasswapped Флаг не изменился. Это означает, что не было обменов, и массив уже был отсортирован. Мы сразу завершили оптимизированный алгоритм сортировки пузыря и не потратили впустую дополнительного времени.
Кстати, если мы попытаемся сортировать массив, в котором все элементы уже расположены в порядке возрастания, используя ОптимизацияBubblyort Функция, то нам понадобится только одна итерация внешней петли. Так что в лучшем случае мы получаем O (n) сложность времени выполнения.
const testData = [ 0, 1, 2, 3, 4, 5, 6 ];
console.log(testData, `Initial testData state`);
const iterationsTestData = optimizedBubbleSort(testData);
console.log(testData, `Total iterations: ${iterationsTestData}`);
Вывод консоли:
[ 0, 1, 2, 3, 4, 5, 6 ] Initial testData state [ 0, 1, 2, 3, 4, 5, 6 ] Total iterations: 1
Коктейль сортирует
Сортировка коктейля – еще одно улучшение пузырькового сорта. Альтернативные имена для этого алгоритма сортировки являются шейкер сортировки или двунаправленные сортировки.
Мы начинаем точно так же, как в пузыре, и «нажать» максимальный элемент. После этого мы разворачиваемся и «выдвиньте» минимум оставшихся элементов.
Как только мы доберемся до начала массива, уже будет 2 элемента в своих местах – первый и последний. Таким образом, мы сделаем в 2 раза меньше итераций внешней петли. Благодаря этому, скорость коктейля сорта будет немного выше, чем у сортировки пузыря.
Мы начнем с небольшого рефакторинга и извлечении функции обмена из нашего алгоритма. Мы назовем это менять :
function swap(arr, i, j) {
let tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
Затем мы реализуем коктейль Worth в JavaScript:
function cocktailSort(arr) {
let left = 0;
let right = arr.length - 1;
let hasSwapped = false;
let outerLoopIterationCount = 0;
while (left < right) {
outerLoopIterationCount++;
for (let i = left; i < right; i++) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
hasSwapped = true;
}
}
right--;
for (let i = right; i > left; i--) {
if (arr[i] < arr[i - 1]) {
swap(arr, i, i - 1);
hasSwapped = true;
}
}
left++;
if (!hasSwapped) {
return outerLoopIterationCount;
} else {
hasSwapped = false;
}
}
return outerLoopIterationCount;
}
И, используя тот же массив, давайте убедиться, что имеется действительно 2x меньше итераций внешней петли:
const testData = [ 0, -1, 4, 5, 2, -3 ];
console.log(testData, `Initial testData state`);
const iterationsTestData = cocktailSort(testData);
console.log(testData, `Total iterations: ${iterationsTestData}`);
Как видите, массив отсортирован, и общие итерации это 3 вместо 6 для OptimizeBubblyort. :
[ 0, -1, 4, 5, 2, -3 ] Initial testData state [ -3, -1, 0, 2, 4, 5 ] Total iterations: 3
Узнайте полный стек JavaScript
Оригинал: “https://dev.to/coderslang/optimized-bubble-sort-in-javascript-cocktail-sort-4hf0”