Сортировка вставками — различия между версиями
AlexeyL (обсуждение | вклад)  | 
				 (исправлена опечатка "на на" -> "на")  | 
				||
| (не показано 17 промежуточных версий 4 участников) | |||
| Строка 1: | Строка 1: | ||
| − | '''Сортировка вставками''' — квадратичный алгоритм сортировки.  | + | '''Сортировка вставками''' (англ. ''Insertion sort'') — квадратичный алгоритм [[Сортировка|сортировки]].  | 
==Алгоритм==  | ==Алгоритм==  | ||
| Строка 9: | Строка 9: | ||
==Псевдокод==  | ==Псевдокод==  | ||
| − |   '''  | + |   '''function''' insertionSort(a):  | 
    '''for''' i = 1 '''to''' n - 1  |     '''for''' i = 1 '''to''' n - 1  | ||
      j = i - 1  |       j = i - 1  | ||
| Строка 75: | Строка 75: | ||
== Оптимизации ==  | == Оптимизации ==  | ||
=== Бинарные вставки ===  | === Бинарные вставки ===  | ||
| − | Теперь вместо линейного поиска позиции мы будем использовать [[Целочисленный двоичный поиск | бинарный поиск]], следовательно количество сравнений изменится с <tex>O(N^2)</tex> до <tex> O(N\log N) </tex>. Количество сравнений заметно уменьшилось, но для того, чтобы поставить элемент   | + | Теперь вместо линейного поиска позиции мы будем использовать [[Целочисленный двоичный поиск | бинарный поиск]], следовательно количество сравнений изменится с <tex>O(N^2)</tex> до <tex> O(N\log N) </tex>. Количество сравнений заметно уменьшилось, но для того, чтобы поставить элемент на своё место, всё ещё необходимо переместить большое количество элементов. В итоге время выполнения алгоритма в асимптотически не уменьшилось. Бинарные вставки выгодно использовать только в случае когда сравнение занимает много времени по сравнению со сдвигом. Например когда мы используем массив длинных чисел.    | 
| − |   '''  | + |   '''function''' insertionSort(a):  | 
    '''for''' i = 1 '''to''' n - 1  |     '''for''' i = 1 '''to''' n - 1  | ||
      j = i - 1  |       j = i - 1  | ||
| − |       k =   | + |       k = binSearch(a, a[i], 0, j)  | 
      '''for''' m = j '''downto''' k  |       '''for''' m = j '''downto''' k  | ||
        swap(a[m], a[m+1])  |         swap(a[m], a[m+1])  | ||
| − | + | ||
=== Двухпутевые вставки ===  | === Двухпутевые вставки ===  | ||
Суть этого метода в том, что вместо отсортированной части массива мы используем область вывода. Первый элемент помещается в середину области вывода, а место для последующих элементов освобождается путём сдвига элементов влево или вправо туда, куда выгоднее.  | Суть этого метода в том, что вместо отсортированной части массива мы используем область вывода. Первый элемент помещается в середину области вывода, а место для последующих элементов освобождается путём сдвига элементов влево или вправо туда, куда выгоднее.  | ||
| Строка 91: | Строка 91: | ||
!style="background-color:#EEE"| Описание шага  | !style="background-color:#EEE"| Описание шага  | ||
|-  | |-  | ||
| − | |colspan=3|''Первый проход (проталкиваем   | + | |colspan=3|''Первый проход (проталкиваем первый элемент — '''''5''''')''  | 
|-  | |-  | ||
|style="background-color:#FFF;padding:2px 10px"|    | |style="background-color:#FFF;padding:2px 10px"|    | ||
|style="background-color:#FFF;padding:2px 30px"| '''5'''  | |style="background-color:#FFF;padding:2px 30px"| '''5'''  | ||
| − | |style="background-color:#FFF;padding:2px 10px"| Так как в поле вывода нет элементов то мы просто добавляем элемент туда.  | + | |style="background-color:#FFF;padding:2px 10px"| Так как в поле вывода нет элементов, то мы просто добавляем элемент туда.  | 
|-  | |-  | ||
| − | |colspan=3|''Второй проход (проталкиваем   | + | |colspan=3|''Второй проход (проталкиваем второй элемент — '''''7''''')''  | 
|-  | |-  | ||
|style="background-color:#FFF;padding:2px 30px"| 5    | |style="background-color:#FFF;padding:2px 30px"| 5    | ||
|style="background-color:#FFF;padding:2px 30px"| 5 '''7'''  | |style="background-color:#FFF;padding:2px 30px"| 5 '''7'''  | ||
| − | |style="background-color:#FFF;padding:2px 10px"| С помощью Бинарного поиска находим позицию и так как позиция крайняя то сдвигать ничего не приходится.  | + | |style="background-color:#FFF;padding:2px 10px"| С помощью Бинарного поиска находим позицию и, так как позиция крайняя, то сдвигать ничего не приходится.  | 
|-     | |-     | ||
| − | |colspan=3|''Третий проход (проталкиваем   | + | |colspan=3|''Третий проход (проталкиваем третий — '''''3''''')''  | 
|-  | |-  | ||
|style="background-color:#FFF;padding:2px 30px"| 5 7  | |style="background-color:#FFF;padding:2px 30px"| 5 7  | ||
|style="background-color:#FFF;padding:2px 20px"| '''3''' 5 7  | |style="background-color:#FFF;padding:2px 20px"| '''3''' 5 7  | ||
| − | |style="background-color:#FFF;padding:2px 10px"| С помощью Бинарного поиска находим позицию и так как позиция крайняя то сдвигать ничего не приходится.  | + | |style="background-color:#FFF;padding:2px 10px"| С помощью Бинарного поиска находим позицию и, так как позиция крайняя, то сдвигать ничего не приходится.  | 
|-  | |-  | ||
| − | |colspan=3|''Четвертый проход (проталкиваем   | + | |colspan=3|''Четвертый проход (проталкиваем четвертый элемент — '''''4''''')''  | 
|-  | |-  | ||
|style="background-color:#FFF;padding:2px 20px"| 3 5 7  | |style="background-color:#FFF;padding:2px 20px"| 3 5 7  | ||
|style="background-color:#FFF;padding:2px 10px"| 3 '''4''' 5 7  | |style="background-color:#FFF;padding:2px 10px"| 3 '''4''' 5 7  | ||
| − | |style="background-color:#FFF;padding:2px 10px"| С помощью Бинарного поиска находим позицию. Расстояние до левого края зоны вывода меньше   | + | |style="background-color:#FFF;padding:2px 10px"| С помощью Бинарного поиска находим позицию. Расстояние до левого края зоны вывода меньше, чем до правого, значит сдвигаем левую часть.  | 
|-  | |-  | ||
|colspan=3|''Четвертый проход (проталкиваем пятый элемент — '''''6''''')''  | |colspan=3|''Четвертый проход (проталкиваем пятый элемент — '''''6''''')''  | ||
| Строка 121: | Строка 121: | ||
|style="background-color:#FFF;padding:2px 10px"| Расстояние до правого края меньше чем до левого, следовательно двигаем правую часть.  | |style="background-color:#FFF;padding:2px 10px"| Расстояние до правого края меньше чем до левого, следовательно двигаем правую часть.  | ||
|}       | |}       | ||
| − | Как можно заметить структура поля вывода имеет сходство с [[Персистентный дек|   | + | Как можно заметить структура поля вывода имеет сходство с [[Персистентный дек| деком]], а именно мы выбираем край к которому ближе наш элемент, затем добавляем с этой стороны наш элемент и двигаем его. Как мы видим в этом примере понадобилось сдвинуть всего <tex>3</tex> элемента. Благодаря тому что для вставки <tex>j</tex>-ого элемента потребуется <tex>j/2</tex> сдвигов в худшем случае вместо <tex>j</tex>, то и итоговое число необходимых операций в худшем случае составит <tex>N^2 / 4 + N \log N</tex>.  | 
| − | |||
== См. также ==  | == См. также ==  | ||
| Строка 132: | Строка 131: | ||
* [[Сортировка подсчетом]]  | * [[Сортировка подсчетом]]  | ||
* [[Сортировка Шелла]]  | * [[Сортировка Шелла]]  | ||
| − | == Источники ==  | + | == Источники информации==  | 
| − | * [  | + | * [http://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B2%D1%81%D1%82%D0%B0%D0%B2%D0%BA%D0%B0%D0%BC%D0%B8 Сортировка вставками]  | 
| − | * Н. Вирт   | + | * Н. Вирт '''Алгоритмы и структуры данных''' {{---}} Невский Диалект, 2008. {{---}} 352 с. {{---}} ISBN 978-5-7940-0065-8  | 
| − | |||
* [http://rain.ifmo.ru/cat/view.php/vis/sorts/quadratic-2010 Визуализатор квадратичных алгоритмов]  | * [http://rain.ifmo.ru/cat/view.php/vis/sorts/quadratic-2010 Визуализатор квадратичных алгоритмов]  | ||
* [http://rain.ifmo.ru/cat/data/theory/school/ses-VectSort-03/pres.pdf Презентация «Сортировка вектора - 3. Insertion Sort»]  | * [http://rain.ifmo.ru/cat/data/theory/school/ses-VectSort-03/pres.pdf Презентация «Сортировка вектора - 3. Insertion Sort»]  | ||
[[Категория: Дискретная математика и алгоритмы]]  | [[Категория: Дискретная математика и алгоритмы]]  | ||
[[Категория: Сортировки]]  | [[Категория: Сортировки]]  | ||
| + | [[Категория: Квадратичные сортировки]]  | ||
Версия 17:43, 9 февраля 2020
Сортировка вставками (англ. Insertion sort) — квадратичный алгоритм сортировки.
Содержание
Алгоритм
Задача заключается в следующем: есть часть массива, которая уже отсортирована, и требуется вставить остальные элементы массива в отсортированную часть, сохранив при этом упорядоченность. Для этого на каждом шаге алгоритма мы выбираем один из элементов входных данных и вставляем его на нужную позицию в уже отсортированной части массива, до тех пор пока весь набор входных данных не будет отсортирован. Метод выбора очередного элемента из исходного массива произволен, однако обычно (и с целью получения устойчивого алгоритма сортировки), элементы вставляются по порядку их появления во входном массиве.
Так как в процессе работы алгоритма могут меняться местами только соседние элементы, каждый обмен уменьшает число инверсий на единицу. Следовательно, количество обменов равно количеству инверсий в исходном массиве вне зависимости от реализации сортировки. Максимальное количество инверсий содержится в массиве, элементы которого отсортированы по невозрастанию. Число инверсий в таком массиве .
Алгоритм работает за , где — число обменов элементов входного массива, равное числу инверсий. В среднем и в худшем случае — за . Минимальные оценки встречаются в случае уже упорядоченной исходной последовательности элементов, наихудшие — когда они расположены в обратном порядке.
Псевдокод
function insertionSort(a):
  for i = 1 to n - 1
    j = i - 1
    while j  0 and a[j] > a[j + 1] 
      swap(a[j], a[j + 1])
      j--
Пример работы
Пример работы алгоритма для массива
| До | После | Описание шага | 
|---|---|---|
| Первый проход (проталкиваем второй элемент — 2) | ||
| 5 2 4 3 1 | 2 5 4 3 1 | Алгоритм сравнивает второй элемент с первым и меняет их местами. | 
| Второй проход (проталкиваем третий элемент — 4) | ||
| 2 5 4 3 1 | 2 4 5 3 1 | Сравнивает третий со вторым и меняет местами | 
| 2 4 5 3 1 | 2 4 5 3 1 | Второй и первый отсортированы, swap не требуется | 
| Третий проход (проталкиваем четвертый — 3) | ||
| 2 4 5 3 1 | 2 4 3 5 1 | Меняет четвертый и третий местами | 
| 2 4 3 5 1 | 2 3 4 5 1 | Меняет третий и второй местами | 
| 2 3 4 5 1 | 2 3 4 5 1 | Второй и первый отсортированы, swap не требуется | 
| Четвертый проход (проталкиваем пятый элемент — 1) | ||
| 2 3 4 5 1 | 2 3 4 1 5 | Меняет пятый и четвертый местами | 
| 2 3 4 1 5 | 2 3 1 4 5 | Меняет четвертый и третий местами | 
| 2 3 1 4 5 | 2 1 3 4 5 | Меняет третий и второй местами | 
| 2 1 3 4 5 | 1 2 3 4 5 | Меняет второй и первый местами. Массив отсортирован. | 
Оптимизации
Бинарные вставки
Теперь вместо линейного поиска позиции мы будем использовать бинарный поиск, следовательно количество сравнений изменится с до . Количество сравнений заметно уменьшилось, но для того, чтобы поставить элемент на своё место, всё ещё необходимо переместить большое количество элементов. В итоге время выполнения алгоритма в асимптотически не уменьшилось. Бинарные вставки выгодно использовать только в случае когда сравнение занимает много времени по сравнению со сдвигом. Например когда мы используем массив длинных чисел.
function insertionSort(a):
  for i = 1 to n - 1
    j = i - 1
    k = binSearch(a, a[i], 0, j)
    for m = j downto k
      swap(a[m], a[m+1])
Двухпутевые вставки
Суть этого метода в том, что вместо отсортированной части массива мы используем область вывода. Первый элемент помещается в середину области вывода, а место для последующих элементов освобождается путём сдвига элементов влево или вправо туда, куда выгоднее. Пример для набора элементов
| До | После | Описание шага | 
|---|---|---|
| Первый проход (проталкиваем первый элемент — 5) | ||
| 5 | Так как в поле вывода нет элементов, то мы просто добавляем элемент туда. | |
| Второй проход (проталкиваем второй элемент — 7) | ||
| 5 | 5 7 | С помощью Бинарного поиска находим позицию и, так как позиция крайняя, то сдвигать ничего не приходится. | 
| Третий проход (проталкиваем третий — 3) | ||
| 5 7 | 3 5 7 | С помощью Бинарного поиска находим позицию и, так как позиция крайняя, то сдвигать ничего не приходится. | 
| Четвертый проход (проталкиваем четвертый элемент — 4) | ||
| 3 5 7 | 3 4 5 7 | С помощью Бинарного поиска находим позицию. Расстояние до левого края зоны вывода меньше, чем до правого, значит сдвигаем левую часть. | 
| Четвертый проход (проталкиваем пятый элемент — 6) | ||
| 3 4 5 7 | 3 4 5 6 7 | Расстояние до правого края меньше чем до левого, следовательно двигаем правую часть. | 
Как можно заметить структура поля вывода имеет сходство с деком, а именно мы выбираем край к которому ближе наш элемент, затем добавляем с этой стороны наш элемент и двигаем его. Как мы видим в этом примере понадобилось сдвинуть всего элемента. Благодаря тому что для вставки -ого элемента потребуется сдвигов в худшем случае вместо , то и итоговое число необходимых операций в худшем случае составит .
См. также
- Сортировка пузырьком
 - Сортировка выбором
 - Сортировка кучей
 - Сортировка слиянием
 - Быстрая сортировка
 - Сортировка подсчетом
 - Сортировка Шелла
 
Источники информации
- Сортировка вставками
 - Н. Вирт Алгоритмы и структуры данных — Невский Диалект, 2008. — 352 с. — ISBN 978-5-7940-0065-8
 - Визуализатор квадратичных алгоритмов
 - Презентация «Сортировка вектора - 3. Insertion Sort»