This commit is contained in:
krahets
2026-04-03 18:46:15 +08:00
parent 377736b1bd
commit 9d21ca86b0
352 changed files with 46563 additions and 11262 deletions
+18 -3
View File
@@ -4,7 +4,7 @@ comments: true
# 11.3   Сортировка пузырьком
<u>Сортировка пузырьком (bubble sort)</u> сортирует массив за счет непрерывного сравнения и обмена соседних элементов. Этот процесс напоминает всплытие пузырьков снизу вверх, откуда и произошло название алгоритма.
<u>Сортировка пузырьком (bubble sort)</u> реализует сортировку путем последовательного сравнения и обмена соседних элементов. Этот процесс напоминает всплытие пузырьков снизу вверх, откуда и произошло название алгоритма.
Как показано на рисунке 11-4, процесс "всплытия" можно смоделировать через операцию обмена элементов: начиная от левого края массива и двигаясь вправо, мы последовательно сравниваем соседние элементы и, если "левый элемент > правый элемент", меняем их местами. После завершения прохода максимальный элемент будет перемещен в самый правый конец массива.
@@ -297,7 +297,7 @@ comments: true
## 11.3.2 &nbsp; Оптимизация эффективности
Мы замечаем, что если в каком-либо раунде "всплытия" не произошло ни одного обмена, значит, массив уже отсортирован и можно сразу вернуть результат. Поэтому можно добавить флаг `flag` для отслеживания этой ситуации и немедленного выхода.
Если в каком-либо раунде "всплытия" не произошло ни одного обмена, значит, массив уже отсортирован и можно сразу вернуть результат. Поэтому можно добавить флаг `flag` для отслеживания этой ситуации и немедленного выхода.
После такой оптимизации худшая и средняя временные сложности сортировки пузырьком по-прежнему равны $O(n^2)$ ; однако если входной массив уже полностью упорядочен, достигается лучшая временная сложность $O(n)$ .
@@ -574,7 +574,22 @@ comments: true
=== "Ruby"
```ruby title="bubble_sort.rb"
### Пузырьковая сортировка (оптимизация флагом) ###
### Пузырьковая сортировка ###
def bubble_sort(nums)
n = nums.length
# Внешний цикл: неотсортированный диапазон [0, i]
for i in (n - 1).downto(1)
# Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конец
for j in 0...i
if nums[j] > nums[j + 1]
# Поменять местами nums[j] и nums[j + 1]
nums[j], nums[j + 1] = nums[j + 1], nums[j]
end
end
end
end
# ## Пузырьковая сортировка (оптимизация флагом) ###
def bubble_sort_with_flag(nums)
n = nums.length
# Внешний цикл: неотсортированный диапазон [0, i]
+3 -3
View File
@@ -6,7 +6,7 @@ comments: true
Рассмотренные выше алгоритмы сортировки относятся к "сортировкам на основе сравнений": они упорядочивают данные, сравнивая элементы друг с другом. Временная сложность таких алгоритмов не может быть лучше $O(n \log n)$ . Далее мы рассмотрим несколько "сортировок без сравнений", чья временная сложность может достигать линейного порядка.
<u>Блочная сортировка (bucket sort)</u> является типичным применением стратегии "разделяй и властвуй". Она задает несколько упорядоченных по диапазонам блоков, каждый блок соответствует некоторому диапазону значений; затем данные равномерно распределяются по блокам, внутри каждого блока выполняется сортировка, а в конце результаты блоков объединяются по порядку.
<u>Блочная сортировка (bucket sort)</u> является типичным применением стратегии "разделяй и властвуй". Она создает набор упорядоченных по величине блоков, где каждый блок соответствует определенному диапазону данных; затем элементы равномерно распределяются по этим блокам, внутри каждого блока отдельно выполняется сортировка, а в конце результаты объединяются в порядке блоков.
## 11.8.1 &nbsp; Алгоритм
@@ -452,7 +452,7 @@ comments: true
## 11.8.3 &nbsp; Как добиться равномерного распределения
Теоретически временная сложность блочной сортировки может достигать $O(n)$ ; **ключ к этому - как можно более равномерно распределить элементы по блокам**. На практике данные часто распределены неравномерно. Например, если нужно распределить все товары на Taobao по 10 блокам цен, количество товаров дешевле 100 юаней может быть очень большим, а товаров дороже 1000 юаней - очень маленьким. Если просто разбить диапазон цен на 10 равных частей, число товаров в каждом блоке будет сильно различаться.
Теоретически временная сложность блочной сортировки может достигать $O(n)$ ; **ключ к этому - как можно более равномерно распределить элементы по блокам**. На практике данные часто распределены неравномерно. Например, если нужно распределить все товары на маркетплейсе по 10 ценовым блокам, количество товаров дешевле 100 рублей может быть очень большим, а товаров дороже 1000 рублей - очень маленьким. Если просто разбить диапазон цен на 10 равных частей, число товаров в каждом блоке будет сильно различаться.
Чтобы добиться более равномерного распределения, можно сначала задать грубую линию раздела и приблизительно распределить данные по 3 блокам. **После этого блоки с большим числом товаров можно снова делить на 3 блока и продолжать процесс до тех пор, пока число элементов в каждом блоке не станет примерно одинаковым**.
@@ -462,7 +462,7 @@ comments: true
<p align="center"> Рисунок 11-14 &nbsp; Рекурсивное разбиение по блокам </p>
Если нам заранее известна вероятностная модель распределения цен товаров, **то границы каждого блока можно задавать в соответствии с этим распределением**. Важно отметить, что фактическое распределение данных не обязательно специально измерять - его можно приблизить некоторой вероятностной моделью исходя из свойств данных.
Если нам заранее известна вероятностная модель распределения цен товаров, **то границы цен для каждого блока можно задавать в соответствии с этим распределением**. Важно отметить, что фактическое распределение данных не обязательно специально измерять - его можно приблизить некоторой вероятностной моделью исходя из свойств данных.
Как показано на рисунке 11-15, если предположить, что цены товаров подчиняются нормальному распределению, то можно разумно задать интервалы цен и тем самым распределить товары по блокам достаточно равномерно.
+2 -2
View File
@@ -4,7 +4,7 @@ comments: true
# 11.9 &nbsp; Сортировка подсчетом
<u>Сортировка подсчетом (counting sort)</u> реализует сортировку за счет подсчета количества элементов и обычно используется для массивов целых чисел.
<u>Сортировка подсчетом (counting sort)</u> реализует сортировку за счет подсчета количества вхождений элементов и обычно используется для массивов целых чисел.
## 11.9.1 &nbsp; Простая реализация
@@ -368,7 +368,7 @@ comments: true
!!! note "Связь между сортировкой подсчетом и блочной сортировкой"
Если посмотреть на сортировку подсчетом с точки зрения блочной сортировки, то каждый индекс массива `counter` можно рассматривать как отдельный блок, а процесс подсчета - как распределение элементов по соответствующим блокам. По сути, сортировка подсчетом является частным случаем блочной сортировки для целочисленных данных.
Если посмотреть на сортировку подсчетом с точки зрения блочной сортировки, то каждый индекс массива `counter` можно рассматривать как отдельный блок, а процесс подсчета - как распределение элементов по соответствующим блокам. Иными словами, сортировка подсчетом является частным случаем блочной сортировки для целочисленных данных.
## 11.9.2 &nbsp; Полная реализация
+3 -3
View File
@@ -13,7 +13,7 @@ comments: true
1. Подать на вход массив и построить из него мин-кучу; в этот момент минимальный элемент будет находиться в вершине кучи.
2. Непрерывно выполнять извлечение из кучи и по порядку записывать извлеченные элементы - так получится последовательность, отсортированная по возрастанию.
Хотя этот метод работоспособен, он требует дополнительного массива для хранения извлеченных элементов и потому расходует лишнюю память. На практике обычно используют более изящную реализацию.
Хотя этот метод и работоспособен, он требует дополнительного массива для хранения извлеченных элементов и потому расходует лишнюю память. На практике обычно используют более изящную реализацию.
## 11.7.1 &nbsp; Алгоритм
@@ -21,7 +21,7 @@ comments: true
1. Подать на вход массив и построить из него макс-кучу. После этого максимальный элемент окажется в вершине кучи.
2. Обменять элемент в вершине кучи (первый элемент) с элементом внизу кучи (последний элемент). После обмена длина кучи уменьшается на $1$ , а число уже отсортированных элементов увеличивается на $1$ .
3. Начиная с вершины, выполнить просеивание вниз (sift down) сверху вниз. После этого свойство кучи будет восстановлено.
3. Начиная с вершины, выполнить операцию просеивания сверху вниз. После этого свойство кучи будет восстановлено.
4. Циклически повторять шаг `2.` и шаг `3.` . После $n - 1$ раундов массив будет полностью отсортирован.
!!! tip
@@ -66,7 +66,7 @@ comments: true
<p align="center"> Рисунок 11-12 &nbsp; Шаги пирамидальной сортировки </p>
В реализации кода используется та же функция просеивания сверху вниз `sift_down()`, что и в главе "Куча". Важно помнить, что длина кучи уменьшается по мере извлечения максимального элемента, поэтому функции `sift_down()` нужно передавать параметр длины $n$ , чтобы указать текущую эффективную длину кучи. Код приведен ниже:
В коде используется та же функция просеивания сверху вниз `sift_down()`, что и в главе "Куча". Важно помнить, что длина кучи уменьшается по мере извлечения максимального элемента, поэтому функции `sift_down()` нужно передавать параметр длины $n$ , чтобы указать текущую действительную длину кучи. Код приведен ниже:
=== "Python"
+2 -2
View File
@@ -17,8 +17,8 @@ icon: material/sort-ascending
- [11.1 &nbsp; Алгоритмы сортировки](sorting_algorithm.md)
- [11.2 &nbsp; Сортировка выбором](selection_sort.md)
- [11.3 &nbsp; Пузырьковая сортировка](bubble_sort.md)
- [11.4 &nbsp; Сортировка вставкой](insertion_sort.md)
- [11.3 &nbsp; Сортировка пузырьком](bubble_sort.md)
- [11.4 &nbsp; Сортировка вставками](insertion_sort.md)
- [11.5 &nbsp; Быстрая сортировка](quick_sort.md)
- [11.6 &nbsp; Сортировка слиянием](merge_sort.md)
- [11.7 &nbsp; Пирамидальная сортировка](heap_sort.md)
+5 -5
View File
@@ -4,11 +4,11 @@ comments: true
# 11.4 &nbsp; Сортировка вставками
<u>Сортировка вставками (insertion sort)</u> - это простой алгоритм сортировки, принцип которого очень похож на ручное упорядочивание колоды карт.
<u>Сортировка вставками (insertion sort)</u> - это простой алгоритм сортировки, принцип которого очень похож на ручную сортировку карт в колоде.
Точнее говоря, в неотсортированном диапазоне выбирается опорный элемент, после чего он поочередно сравнивается с элементами слева в уже отсортированном диапазоне и вставляется в правильную позицию.
Точнее говоря, в неотсортированном диапазоне выбирается опорный элемент, после чего он сравнивается с элементами слева в уже отсортированном диапазоне и вставляется в правильную позицию.
На рисунке 11-6 показан процесс вставки элемента в массив. Пусть опорный элемент обозначен как `base` ; нам нужно сдвинуть все элементы от целевого индекса до `base` на одну позицию вправо, а затем присвоить `base` значение в целевом индексе.
На рисунке 11-6 показан процесс вставки элемента в массив. Пусть опорный элемент обозначен как `base` ; нам нужно сдвинуть все элементы от целевого индекса до `base` на одну позицию вправо, а затем записать `base` в целевой индекс.
![Одна операция вставки](insertion_sort.assets/insertion_operation.png){ class="animation-figure" }
@@ -19,8 +19,8 @@ comments: true
Общий процесс сортировки вставками показан на рисунке 11-7.
1. В начальном состоянии отсортирован только первый элемент массива.
2. Выбрать второй элемент массива как `base` ; после вставки в правильную позицию **первые 2 элемента массива окажутся отсортированными**.
3. Выбрать третий элемент как `base` ; после вставки в правильную позицию **первые 3 элемента массива окажутся отсортированными**.
2. Выбрать второй элемент массива как `base` ; после вставки в правильную позицию **первые два элемента массива окажутся отсортированными**.
3. Выбрать третий элемент как `base` ; после вставки в правильную позицию **первые три элемента массива окажутся отсортированными**.
4. Продолжать по аналогии; в последнем раунде в качестве `base` берется последний элемент, и после его вставки **все элементы массива будут отсортированы**.
![Процесс сортировки вставками](insertion_sort.assets/insertion_sort_overview.png){ class="animation-figure" }
+7 -7
View File
@@ -4,10 +4,10 @@ comments: true
# 11.6 &nbsp; Сортировка слиянием
<u>Сортировка слиянием (merge sort)</u> - это алгоритм сортировки на основе стратегии "разделяй и властвуй", который включает этапы "разделения" и "слияния", показанные на рисунке 11-10.
<u>Сортировка слиянием (merge sort)</u> - это алгоритм сортировки, основанный на стратегии "разделяй и властвуй", который включает этапы "разделения" и "слияния", показанные на рисунке 11-10.
1. **Этап разделения**: массив рекурсивно разбивается от середины, и задача сортировки длинного массива превращается в задачи сортировки более коротких массивов.
2. **Этап слияния**: когда длина подмассива становится равной 1, разделение завершается и начинается слияние; левые и правые короткие упорядоченные массивы непрерывно объединяются в более длинный упорядоченный массив, пока процесс не завершится.
1. **Этап разделения**: массив рекурсивно делится пополам, и задача сортировки длинного массива превращается в задачи сортировки более коротких массивов.
2. **Этап слияния**: когда длина подмассива становится равной 1, разделение завершается и начинается слияние; два коротких упорядоченных массива непрерывно объединяются в один более длинный упорядоченный массив, пока процесс не завершится.
![Этапы разделения и слияния в сортировке слиянием](merge_sort.assets/merge_sort_overview.png){ class="animation-figure" }
@@ -54,10 +54,10 @@ comments: true
<p align="center"> Рисунок 11-11 &nbsp; Шаги сортировки слиянием </p>
Нетрудно заметить, что порядок рекурсии в сортировке слиянием совпадает с порядком рекурсии при постфиксном обходе бинарного дерева.
Нетрудно заметить, что порядок рекурсии в сортировке слиянием совпадает с порядком обхода в глубину двоичного дерева.
- **Постфиксный обход**: сначала рекурсивно обходится левое поддерево, затем правое поддерево, а в конце обрабатывается корневой узел.
- **Сортировка слиянием**: сначала рекурсивно обрабатывается левый подмассив, затем правый подмассив, а в конце выполняется слияние.
- **Обход в глубину**: сначала рекурсивно обходится левое поддерево, затем правое поддерево, а в конце обрабатывается корневой узел.
- **Сортировка слиянием**: сначала рекурсивно разделяется левый подмассив, затем правый подмассив, а в конце выполняется слияние.
Реализация сортировки слиянием показана в коде ниже. Обратите внимание: в `nums` объединяемый интервал равен `[left, right]` , а соответствующий интервал в `tmp` равен `[0, right - left]` .
@@ -697,4 +697,4 @@ comments: true
- **Этап разделения**: работу по разбиению списка можно реализовать с помощью "итерации" вместо "рекурсии", тем самым устранив расход памяти на стек вызовов.
- **Этап слияния**: в связном списке добавление и удаление узлов требует только изменения ссылок (указателей), поэтому при слиянии двух коротких упорядоченных списков в один длинный упорядоченный список не нужно создавать дополнительный список.
Детали реализации достаточно сложны; заинтересованные читатели могут изучить соответствующие материалы самостоятельно.
Детали реализации достаточно сложны; заинтересованные читатели могут обратиться к соответствующим материалам самостоятельно.
+39 -8
View File
@@ -43,9 +43,9 @@ comments: true
После завершения разделения исходный массив разбивается на три части: левый подмассив, опорный элемент и правый подмассив; при этом выполняется условие "любой элемент левого подмассива $\leq$ опорный элемент $\leq$ любой элемент правого подмассива". Следовательно, далее нам нужно лишь отсортировать эти два подмассива.
!!! note "Стратегия divide and conquer в быстрой сортировке"
!!! note "Стратегия разделяй и властвуй в быстрой сортировке"
По сути, разделение с опорным элементом сводит задачу сортировки длинного массива к двум задачам сортировки более коротких массивов.
Иными словами, разделение с опорным элементом сводит задачу сортировки длинного массива к двум задачам сортировки более коротких массивов.
=== "Python"
@@ -614,11 +614,11 @@ comments: true
## 11.5.4 &nbsp; Оптимизация выбора опорного элемента
**На некоторых входных данных временная эффективность быстрой сортировки может ухудшаться**. Рассмотрим крайний случай: входной массив полностью отсортирован в обратном порядке. Поскольку в качестве опорного мы выбираем самый левый элемент, после разделения он будет обменян в самый правый конец массива, из-за чего длина левого подмассива станет $n - 1$ , а длина правого - $0$ . Если рекурсия будет продолжаться таким образом, то после каждого разделения один из подмассивов будет иметь длину $0$ , стратегия divide and conquer потеряет смысл, а быстрая сортировка выродится в нечто близкое к "сортировке пузырьком".
**На некоторых входных данных временная эффективность быстрой сортировки может ухудшаться**. Рассмотрим крайний случай: входной массив полностью отсортирован в обратном порядке. Поскольку в качестве опорного мы выбираем самый левый элемент, после разделения он будет обменян в самый правый конец массива, из-за чего длина левого подмассива станет $n - 1$ , а длина правого - $0$ . Если рекурсия будет продолжаться таким образом, то после каждого разделения один из подмассивов будет иметь длину $0$ , стратегия "разделяй и властвуй" потеряет смысл, а быстрая сортировка выродится в нечто близкое к "сортировке пузырьком".
Чтобы по возможности избежать такого сценария, **мы можем улучшить стратегию выбора опорного элемента в процедуре разделения**. Например, можно выбирать случайный элемент массива как опорный. Однако если не повезет и каждый раз будет выбираться неудачный опорный элемент, производительность все равно останется неудовлетворительной.
Чтобы по возможности избежать такого сценария, **можно улучшить стратегию выбора опорного элемента в процедуре разделения**. Например, можно выбирать случайный элемент массива как опорный. Однако если не повезет и каждый раз будет выбираться неудачный опорный элемент, производительность все равно останется неудовлетворительной.
Нужно учитывать, что языки программирования обычно генерируют "псевдослучайные числа". Если специально построить тестовый пример под такую последовательность, эффективность быстрой сортировки все равно может деградировать.
Стоит учитывать, что языки программирования обычно генерируют псевдослучайные числа. Если специально построить тестовый пример под такую последовательность, эффективность быстрой сортировки все равно может деградировать.
Чтобы улучшить ситуацию, можно взять три кандидата (обычно первый, последний и средний элементы массива) и **использовать медиану этих трех значений как опорный элемент**. Благодаря этому вероятность того, что опорный элемент окажется "не слишком маленьким и не слишком большим", заметно возрастает. Конечно, можно брать и большее число кандидатов, чтобы еще сильнее повысить устойчивость алгоритма. После этого вероятность деградации временной сложности до $O(n^2)$ существенно уменьшается.
@@ -1059,9 +1059,20 @@ comments: true
return right
end
### Разбиение с опорными указателями (медиана трех) ###
### Выбрать медиану из трех кандидатов ###
def median_three(nums, left, mid, right)
# Выбрать медиану из трех кандидатов
_l, _m, _r = nums[left], nums[mid], nums[right]
# m находится между l и r
return mid if (_l <= _m && _m <= _r) || (_r <= _m && _m <= _l)
# l находится между m и r
return left if (_m <= _l && _l <= _r) || (_r <= _l && _l <= _m)
return right
end
# ## Разбиение с опорными указателями (медиана трех) ###
def partition(nums, left, right)
### Использовать nums[left] как опорный элемент
# ## Использовать nums[left] как опорный элемент
med = median_three(nums, left, (left + right) / 2, right)
# Переместить медиану в крайний левый элемент массива
nums[left], nums[med] = nums[med], nums[left]
@@ -1353,7 +1364,27 @@ comments: true
=== "Ruby"
```ruby title="quick_sort.rb"
### Быстрая сортировка (оптимизация глубины рекурсии) ###
### Разбиение с опорными указателями ###
def partition(nums, left, right)
# Использовать nums[left] как опорный элемент
i = left
j = right
while i < j
while i < j && nums[j] >= nums[left]
j -= 1 # Идти справа налево в поисках первого элемента меньше опорного
end
while i < j && nums[i] <= nums[left]
i += 1 # Идти слева направо в поисках первого элемента больше опорного
end
# Обмен элементов
nums[i], nums[j] = nums[j], nums[i]
end
# Переместить опорный элемент на границу двух подмассивов
nums[i], nums[left] = nums[left], nums[i]
i # Вернуть индекс опорного элемента
end
# ## Быстрая сортировка (оптимизация глубины рекурсии) ###
def quick_sort(nums, left, right)
# Рекурсивно обрабатывать, пока длина подмассива не станет равной 1
while left < right
+10 -4
View File
@@ -4,9 +4,9 @@ comments: true
# 11.10 &nbsp; Поразрядная сортировка
В предыдущем разделе мы познакомились с сортировкой подсчетом: она подходит для случаев, когда объем данных $n$ велик, а диапазон значений $m$ сравнительно мал. Предположим теперь, что нужно отсортировать $n = 10^6$ студенческих идентификаторов, причем каждый идентификатор является $8$-значным числом. Тогда диапазон данных $m = 10^8$ оказывается очень большим; сортировка подсчетом потребует огромного объема памяти, а поразрядная сортировка позволяет этого избежать.
В предыдущем разделе была рассмотрена сортировка подсчетом: она хорошо подходит для случаев, когда объем данных $n$ велик, а диапазон значений $m$ сравнительно мал. Предположим теперь, что нужно отсортировать $n = 10^6$ номеров студентов, причем каждый номер представляет собой $8$-значное число. Тогда диапазон данных $m = 10^8$ оказывается очень большим; сортировка подсчетом потребует огромного объема памяти, а поразрядная сортировка позволяет этого избежать.
<u>Поразрядная сортировка (radix sort)</u> по своей основной идее совпадает с сортировкой подсчетом и тоже реализует сортировку через подсчет количества. Поверх этого поразрядная сортировка использует иерархию разрядов числа и последовательно сортирует данные по каждому разряду, получая итоговый упорядоченный результат.
<u>Поразрядная сортировка (radix sort)</u> по своей основной идее совпадает с сортировкой подсчетом и тоже реализует сортировку через подсчет количества. При этом поразрядная сортировка использует соотношение между разрядами числа и последовательно сортирует данные по каждому разряду, получая итоговый упорядоченный результат.
## 11.10.1 &nbsp; Алгоритм
@@ -26,7 +26,7 @@ $$
x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
$$
где $\lfloor a \rfloor$ обозначает округление числа $a$ вниз, а $\bmod \: d$ означает взятие остатка по модулю $d$ . Для студенческих идентификаторов выполняется $d = 10$ и $k \in [1, 8]$ .
где $\lfloor a \rfloor$ обозначает округление числа $a$ вниз, а $\bmod \: d$ означает взятие остатка по модулю $d$ . Для студенческих номеров выполняется $d = 10$ и $k \in [1, 8]$ .
Кроме того, нам нужно слегка изменить код сортировки подсчетом, чтобы он мог сортировать числа по их $k$-му разряду:
@@ -675,7 +675,13 @@ $$
(num / exp) % 10
end
### Сортировка подсчетом (сортировка по k-му разряду nums) ###
### Получить k-й разряд элемента num, где exp = 10^(k-1) ###
def digit(num, exp)
# Передача exp вместо k позволяет избежать повторного выполнения дорогостоящих вычислений степени
(num / exp) % 10
end
# ## Сортировка подсчетом (сортировка по k-му разряду nums) ###
def counting_sort_digit(nums, exp)
# Разряды десятичной системы лежат в диапазоне 0~9, поэтому нужен массив корзин длины 10
counter = Array.new(10, 0)
+2 -2
View File
@@ -9,8 +9,8 @@ comments: true
Пусть длина массива равна $n$ ; тогда процесс сортировки выбором выглядит так, как показано на рисунке 11-2.
1. В начальном состоянии все элементы не отсортированы, то есть неотсортированный диапазон индексов равен $[0, n-1]$ .
2. Выбрать минимальный элемент из диапазона $[0, n-1]$ и поменять его местами с элементом в позиции $0$ . После этого первые 1 элементов массива отсортированы.
3. Выбрать минимальный элемент из диапазона $[1, n-1]$ и поменять его местами с элементом в позиции $1$ . После этого первые 2 элементов массива отсортированы.
2. Выбрать минимальный элемент из диапазона $[0, n-1]$ и поменять его местами с элементом в позиции $0$ . После этого первый элемент массива отсортирован.
3. Выбрать минимальный элемент из диапазона $[1, n-1]$ и поменять его местами с элементом в позиции $1$ . После этого первые два элемента массива отсортированы.
4. Продолжать по аналогии. После $n - 1$ раундов выбора и обмена первые $n - 1$ элементов массива будут отсортированы.
5. Оставшийся элемент обязательно является максимальным, сортировать его не нужно, поэтому массив считается отсортированным.
+1 -1
View File
@@ -4,7 +4,7 @@ comments: true
# 11.1 &nbsp; Алгоритмы сортировки
<u>Алгоритмы сортировки (sorting algorithm)</u> используются для упорядочивания набора данных по определенному правилу. Они применяются очень широко, потому что упорядоченные данные обычно проще и быстрее искать, анализировать и обрабатывать.
<u>Алгоритмы сортировки (sorting algorithm)</u> используются для упорядочивания набора данных по определенному правилу. Они применяются очень широко, потому что упорядоченные данные обычно проще анализировать, обрабатывать и искать в них нужные элементы.
Как показано на рисунке 11-1, данными в алгоритмах сортировки могут быть целые числа, числа с плавающей запятой, символы, строки и другие типы. Критерий сравнения тоже можно задать по-разному, например по величине чисел, по порядку ASCII-кодов символов или по пользовательскому правилу.
+1 -1
View File
@@ -13,7 +13,7 @@ comments: true
- Блочная сортировка включает три этапа: распределение данных по блокам, сортировку внутри блоков и объединение результатов. Она тоже отражает стратегию "разделяй и властвуй" и подходит для очень больших объемов данных. Ключ к эффективности блочной сортировки - равномерное распределение данных.
- Сортировка подсчетом является частным случаем блочной сортировки; она реализует сортировку через подсчет числа вхождений данных. Сортировка подсчетом подходит для случаев, когда объем данных велик, но диапазон значений ограничен, и при этом данные можно преобразовать в положительные целые числа.
- Поразрядная сортировка выполняет сортировку данных путем последовательной сортировки по каждому разряду и требует, чтобы данные можно было представить в виде чисел фиксированной разрядности.
- В общем случае нам хотелось бы найти алгоритм сортировки, который одновременно обладал бы высокой эффективностью, стабильностью, свойством выполнения на месте и адаптивностью. Но, как и в других разделах алгоритмов и структур данных, не существует одного алгоритма сортировки, способного удовлетворить всем этим требованиям одновременно. На практике приходится выбирать подходящий алгоритм в зависимости от свойств данных.
- В общем случае нам хотелось бы найти алгоритм сортировки, который одновременно обладал бы высокой эффективностью, стабильностью, выполнением на месте и адаптивностью. Но, как и в других разделах алгоритмов и структур данных, не существует одного алгоритма сортировки, способного удовлетворить всем этим требованиям одновременно. На практике приходится выбирать подходящий алгоритм в зависимости от свойств данных.
- На рисунке 11-19 сравниваются эффективность, стабильность, выполнение на месте и адаптивность основных алгоритмов сортировки.
![Сравнение алгоритмов сортировки](summary.assets/sorting_algorithms_comparison.png){ class="animation-figure" }