mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-15 08:26:06 +00:00
First version.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# Резюме
|
||||
|
||||
### Основные моменты
|
||||
|
||||
- Сортировка пузырьком реализует сортировку путем обмена соседних элементов. Добавив флаг для досрочного возврата, мы можем оптимизировать лучшую временную сложность сортировки пузырьком до $O(n)$.
|
||||
- Сортировка вставками на каждом раунде вставляет элемент из неотсортированного диапазона в правильную позицию в отсортированном диапазоне, завершая таким образом сортировку. Хотя временная сложность сортировки вставками составляет $O(n^2)$, благодаря относительно небольшому количеству элементарных операций она очень популярна для задач сортировки небольших объемов данных.
|
||||
- Быстрая сортировка реализует сортировку на основе операции разделения с опорным элементом. При разделении с опорным элементом возможна ситуация, когда каждый раз выбирается наихудший базовый элемент, что приводит к ухудшению временной сложности до $O(n^2)$. Введение медианного или случайного базового элемента может снизить вероятность такого ухудшения. Приоритетная рекурсия более короткого подмассива может эффективно уменьшить глубину рекурсии, оптимизируя пространственную сложность до $O(\log n)$.
|
||||
- Сортировка слиянием включает две фазы: разделение и слияние, типично воплощая стратегию "разделяй и властвуй". При сортировке слиянием массива необходимо создать вспомогательный массив, пространственная сложность составляет $O(n)$; однако пространственная сложность сортировки связного списка может быть оптимизирована до $O(1)$.
|
||||
- Блочная сортировка включает три шага: распределение данных по блокам, сортировка внутри блоков и объединение результатов. Она также воплощает стратегию "разделяй и властвуй" и подходит для случаев с очень большим объемом данных. Ключ к блочной сортировке заключается в равномерном распределении данных.
|
||||
- Сортировка подсчетом является частным случаем блочной сортировки, она реализует сортировку путем подсчета количества появлений данных. Сортировка подсчетом подходит для случаев с большим объемом данных, но ограниченным диапазоном данных, и требует, чтобы данные могли быть преобразованы в положительные целые числа.
|
||||
- Поразрядная сортировка реализует сортировку данных путем последовательной сортировки по разрядам, требуя, чтобы данные могли быть представлены в виде чисел с фиксированным количеством разрядов.
|
||||
- В целом, мы хотим найти алгоритм сортировки, обладающий такими преимуществами, как высокая эффективность, стабильность, сортировка на месте и адаптивность. Однако, как и в случае с другими структурами данных и алгоритмами, не существует алгоритма сортировки, который одновременно удовлетворял бы всем этим условиям. В практических приложениях необходимо выбирать подходящий алгоритм сортировки в зависимости от характеристик данных.
|
||||
- На рисунке ниже сравниваются эффективность, стабильность, местность и адаптивность основных алгоритмов сортировки.
|
||||
|
||||

|
||||
|
||||
### Вопросы и ответы
|
||||
|
||||
**В:** В каких случаях стабильность алгоритма сортировки является необходимой?
|
||||
|
||||
В реальности мы можем сортировать объекты по какому-либо их атрибуту. Например, у студентов есть два атрибута: имя и рост, и мы хотим реализовать многоуровневую сортировку: сначала отсортировать по имени, получив `(A, 180) (B, 185) (C, 170) (D, 170)`; затем отсортировать по росту. Поскольку алгоритм сортировки нестабилен, можно получить `(D, 170) (C, 170) (A, 180) (B, 185)`.
|
||||
|
||||
Можно заметить, что позиции студентов D и C поменялись местами, упорядоченность по имени нарушена, а это нежелательно.
|
||||
|
||||
**В:** Можно ли поменять местами порядок "поиска справа налево" и "поиска слева направо" при разделении с опорным элементом?
|
||||
|
||||
Нет, когда мы используем крайний левый элемент в качестве базового, необходимо сначала выполнить "поиск справа налево", а затем "поиск слева направо". Этот вывод несколько противоречит интуиции, давайте разберем причину.
|
||||
|
||||
Последний шаг разделения с опорным элементом `partition()` -- это обмен `nums[left]` и `nums[i]`. После завершения обмена все элементы слева от базового элемента `<=` базового элемента, **это требует, чтобы перед последним шагом обмена обязательно выполнялось условие `nums[left] >= nums[i]`**. Предположим, мы сначала выполняем "поиск слева направо", тогда если не найдется элемент больше базового, **цикл завершится при `i == j`, и в этот момент возможно `nums[j] == nums[i] > nums[left]`**. То есть в этом случае последняя операция обмена поместит элемент больше базового в крайнюю левую позицию массива, что приведет к сбою разделения с опорным элементом.
|
||||
|
||||
Приведем пример: дан массив `[0, 0, 0, 0, 1]`, если сначала выполнить "поиск слева направо", после разделения с опорным элементом массив станет `[1, 0, 0, 0, 0]`, этот результат неверен.
|
||||
|
||||
Если подумать глубже, если мы выберем `nums[right]` в качестве базового элемента, то все будет наоборот, необходимо сначала выполнить "поиск слева направо".
|
||||
|
||||
**В:** Почему при оптимизации глубины рекурсии быстрой сортировки выбор более короткого массива гарантирует, что глубина рекурсии не превысит $\log n$?
|
||||
|
||||
Глубина рекурсии -- это количество текущих невозвращенных рекурсивных методов. На каждом раунде разделения с опорным элементом мы разделяем исходный массив на два подмассива. После оптимизации глубины рекурсии длина подмассива, в который происходит рекурсия, максимум составляет половину длины исходного массива. Предположим наихудший случай, когда длина всегда составляет половину, тогда конечная глубина рекурсии будет $\log n$.
|
||||
|
||||
Вспомним исходную быструю сортировку, мы можем последовательно рекурсивно обрабатывать массивы большей длины, в наихудшем случае $n$, $n - 1$, $\dots$, $2$, $1$, глубина рекурсии составит $n$. Оптимизация глубины рекурсии может избежать такой ситуации.
|
||||
|
||||
**В:** Когда все элементы в массиве равны, временная сложность быстрой сортировки составляет $O(n^2)$? Как обработать такой случай деградации?
|
||||
|
||||
Да. В этом случае можно рассмотреть разделение массива с помощью опорного элемента на три части: меньше, равно и больше базового элемента. Рекурсия выполняется только для частей меньше и больше. При таком методе для массива, где все входные элементы равны, достаточно одного раунда разделения с опорным элементом для завершения сортировки.
|
||||
|
||||
**В:** Почему наихудшая временная сложность блочной сортировки составляет $O(n^2)$?
|
||||
|
||||
В наихудшем случае все элементы попадают в один блок. Если мы используем алгоритм $O(n^2)$ для сортировки этих элементов, то временная сложность составит $O(n^2)$.
|
||||
Reference in New Issue
Block a user