Сортировка Шелла
Описание
Сортировка Шелла (Shell sort) - это алгоритм сортировки, являющийся усовершенствованным вариантом сортировки вставками. Идея метода Шелла состоит в сравнении элементов, стоящих не только рядом, но и на определенном расстоянии друг от друга.
При сортировке Шелла сначала сравниваются и сортируются между собой значения, стоящие один от другого на некотором расстоянии d
. После этого процедура повторяется для некоторых меньших значений d
, а завершается сортировка Шелла упорядочиванием элементов при d = 1
(то есть обычной сортировкой вставками).
Хотя сортировка Шелла во многих случаях медленнее, чем быстрая сортировка, она имеет ряд преимуществ:
- отсутствие потребности в памяти под стек
- отсутствие деградации при неудачных наборах данных: быстрая сортировка легко деградирует до
O(n^2)
, что хуже, чем худшее гарантированное время для сортировки Шелла
Принцип работы
Нужно отсортировать список [ 35, 33, 42, 10, 14, 19, 27, 44 ]
. Берем d = 4
(d
- это интервал). Разбиваем массив на пары элементов {35, 14}
, {33, 19}
, {42, 27}
и {10, 44}
.

Сравниваем пары элементов и меняем их местами при необходимости. Новый массив выглядит так:

Берем d = 2
, получаем пары {14, 27, 35, 42}
и {19, 10, 33, 44}
.

Сравниваем пары элементов и меняем их местами при необходимости. Новый массив выглядит так:

Берем d = 1
и упорядочиваем элементы массива с помощью сортировки вставками:

Сложность
Лучшее | Среднее | Худшее | Память | Стабильность |
---|---|---|---|---|
n log(n) | Зависит от размера шага | n (log(n))^2 | 1 | Нет |
Реализация
// algorithms/sorting/shell-sort.js
import Sort from './sort'
export default class ShellSort extends Sort {
sort(arr) {
// Копируем оригинальный массив во избежание его модификации
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/structuredClone
const _arr = structuredClone(arr)
// Определяем шаг - половина массива
let step = Math.floor(_arr.length / 2)
// До тех пор, пока шаг больше нуля
while (step > 0) {
// Сравниваем все пары элементов
for (let i = 0; i < _arr.length - step; i++) {
let currentIndex = i
let gapShiftedIndex = i + step
while (currentIndex >= 0) {
this.callbacks.visitingCallback(_arr[currentIndex])
// Сравниваем и меняем элементы местами при необходимости
if (
this.comparator.lessThan(_arr[gapShiftedIndex], _arr[currentIndex])
) {
const tmp = _arr[currentIndex]
_arr[currentIndex] = _arr[gapShiftedIndex]
_arr[gapShiftedIndex] = tmp
}
gapShiftedIndex = currentIndex
currentIndex -= step
}
}
// Уменьшаем шаг в 2 раза
step = Math.floor(step / 2)
}
return _arr
}
}
Тестирование
// algorithms/sorting/__tests__/shell-sort.test.js
import ShellSort from '../shell-sort'
import {
equalArr,
notSortedArr,
reverseArr,
sortedArr,
SortTester,
} from '../sort-tester'
// Константы временной сложности
const SORTED_ARRAY_VISITING_COUNT = 320
const NOT_SORTED_ARRAY_VISITING_COUNT = 320
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 320
const EQUAL_ARRAY_VISITING_COUNT = 320
describe('ShellSort', () => {
it('должен отсортировать массив', () => {
SortTester.testSort(ShellSort)
})
it('должен отсортировать массив с помощью кастомной функции сравнения', () => {
SortTester.testSortWithCustomComparator(ShellSort)
})
it('должен отсортировать отрицательные числа', () => {
SortTester.testNegativeNumbersSort(ShellSort)
})
it('должен посетить массив одинаковых элементов указанное количество раз', () => {
SortTester.testAlgorithmTimeComplexity(
ShellSort,
equalArr,
EQUAL_ARRAY_VISITING_COUNT,
)
})
it('должен посетить отсортированный массив указанное количество раз', () => {
SortTester.testAlgorithmTimeComplexity(
ShellSort,
sortedArr,
SORTED_ARRAY_VISITING_COUNT,
)
})
it('должен посетить неотсортированный массив указанное количество раз', () => {
SortTester.testAlgorithmTimeComplexity(
ShellSort,
notSortedArr,
NOT_SORTED_ARRAY_VISITING_COUNT,
)
})
it('должен посетить инвертированный отсортированный массив указанное количество раз', () => {
SortTester.testAlgorithmTimeComplexity(
ShellSort,
reverseArr,
REVERSE_SORTED_ARRAY_VISITING_COUNT,
)
})
})
Запускаем тесты:
npm run test ./algorithms/sorting/__tests__/shell-sort
