1 added
93 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>В программировании часто встречаются задачи, которые трудно решить "в лоб". Представим, что нам нужно избавиться от повторяющихся элементов в массиве. Попробуем найти все числа, которые встречаются здесь больше, чем один раз:</p>
1
<p>В программировании часто встречаются задачи, которые трудно решить "в лоб". Представим, что нам нужно избавиться от повторяющихся элементов в массиве. Попробуем найти все числа, которые встречаются здесь больше, чем один раз:</p>
2
<p>7, 3, 1, 9, 10, 2, 3, 6, 9, 4, 7, 5, 5, 4, 2, 8, 4, 7</p>
2
<p>7, 3, 1, 9, 10, 2, 3, 6, 9, 4, 7, 5, 5, 4, 2, 8, 4, 7</p>
3
<p>Чтобы это сделать, нужно написать сложный алгоритм. Можно упростить задачу и отсортировать массив. В нем повторяющиеся элементы находятся рядом, поэтому их легко обнаружить, сравнивая соседние числа:</p>
3
<p>Чтобы это сделать, нужно написать сложный алгоритм. Можно упростить задачу и отсортировать массив. В нем повторяющиеся элементы находятся рядом, поэтому их легко обнаружить, сравнивая соседние числа:</p>
4
<p>1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 7, 7, 7, 8, 9, 9, 10</p>
4
<p>1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 7, 7, 7, 8, 9, 9, 10</p>
5
<p>Не удивительно, что одной из самых полезных задач в программировании считается<strong>сортировка</strong>- перестановка элементов в массиве так, чтобы они располагались в убывающем или возрастающем порядке.</p>
5
<p>Не удивительно, что одной из самых полезных задач в программировании считается<strong>сортировка</strong>- перестановка элементов в массиве так, чтобы они располагались в убывающем или возрастающем порядке.</p>
6
<h2>Чем полезна сортировка</h2>
6
<h2>Чем полезна сортировка</h2>
7
-
<p>Познакомимся с сортиров��ой поближе и выясним, где она встречается в практических задачах программиста.</p>
7
+
<p>Познакомимся с сортировкой поближе и выясним, где она встречается в практических задачах программиста.</p>
8
<p>Посмотрим на любой интернет-магазин. В каждом разделе встречаются сотни и тысячи товаров, из которых так сложно выбрать подходящий. Чтобы пользователям было удобнее, магазин предлагает сортировку товаров по цене, по рейтингу или по популярности.</p>
8
<p>Посмотрим на любой интернет-магазин. В каждом разделе встречаются сотни и тысячи товаров, из которых так сложно выбрать подходящий. Чтобы пользователям было удобнее, магазин предлагает сортировку товаров по цене, по рейтингу или по популярности.</p>
9
<p>При этом покупатели выбирают сортировку по своим целям:</p>
9
<p>При этом покупатели выбирают сортировку по своим целям:</p>
10
<ul><li>По возрастанию цены в поисках выгодных предложений</li>
10
<ul><li>По возрастанию цены в поисках выгодных предложений</li>
11
<li>По убыванию цены, если готовы на дорогую покупку</li>
11
<li>По убыванию цены, если готовы на дорогую покупку</li>
12
</ul><p>Чтобы интернет-магазин умел сортировать одни и те же записи по-разному, необходима<strong>универсальная функция сортировки</strong>, о которой поговорим в конце урока.</p>
12
</ul><p>Чтобы интернет-магазин умел сортировать одни и те же записи по-разному, необходима<strong>универсальная функция сортировки</strong>, о которой поговорим в конце урока.</p>
13
<h2>Три алгоритма сортировки</h2>
13
<h2>Три алгоритма сортировки</h2>
14
<p>Существуют десятки алгоритмов сортировки, но изучать все слишком долго. Чтобы не останавливаться на этой теме, мы выбрали три фундаментальных алгоритма:</p>
14
<p>Существуют десятки алгоритмов сортировки, но изучать все слишком долго. Чтобы не останавливаться на этой теме, мы выбрали три фундаментальных алгоритма:</p>
15
<ul><li>Пузырьковая сортировка</li>
15
<ul><li>Пузырьковая сортировка</li>
16
<li>Сортировка выбором</li>
16
<li>Сортировка выбором</li>
17
<li>Быстрая сортировка</li>
17
<li>Быстрая сортировка</li>
18
</ul><p>Все три алгоритма сортируют исходный массив, меняя местами его элементы и не требуя дополнительного пространства.</p>
18
</ul><p>Все три алгоритма сортируют исходный массив, меняя местами его элементы и не требуя дополнительного пространства.</p>
19
<p>Эти алгоритмы помогут понять, как работает сортировка. На их примере вы изучите, какие техники программисты применяют при разработке алгоритмов.</p>
19
<p>Эти алгоритмы помогут понять, как работает сортировка. На их примере вы изучите, какие техники программисты применяют при разработке алгоритмов.</p>
20
<p>При реализации алгоритмов мы должны помнить о<strong>вырожденных случаях</strong>- массивах, в которых один или ноль элементов. Сортировка их не меняет, но наши алгоритмы должны обрабатывать эти случаи - иначе программа завершится с ошибкой.</p>
20
<p>При реализации алгоритмов мы должны помнить о<strong>вырожденных случаях</strong>- массивах, в которых один или ноль элементов. Сортировка их не меняет, но наши алгоритмы должны обрабатывать эти случаи - иначе программа завершится с ошибкой.</p>
21
<h2>Пузырьковая сортировка</h2>
21
<h2>Пузырьковая сортировка</h2>
22
<p>Один из самых простых методов -<strong>пузырьковая сортировка</strong>. Это название произошло от ассоциации с воздухом в воде: на дне пузырьки совсем маленькие, но постепенно поднимаются к поверхности, собирают кислород и увеличиваются.</p>
22
<p>Один из самых простых методов -<strong>пузырьковая сортировка</strong>. Это название произошло от ассоциации с воздухом в воде: на дне пузырьки совсем маленькие, но постепенно поднимаются к поверхности, собирают кислород и увеличиваются.</p>
23
<p>Похожий принцип работает и с элементами массива при такой сортировке. Посмотрите на этот рисунок:</p>
23
<p>Похожий принцип работает и с элементами массива при такой сортировке. Посмотрите на этот рисунок:</p>
24
<p>Мы идем по массиву и перемещаем вправо самый большой элемент из просмотренных. Так мы находим элемент со значением 10, который в итоге побеждает во всех сравнениях и оказывается в правом конце массива.</p>
24
<p>Мы идем по массиву и перемещаем вправо самый большой элемент из просмотренных. Так мы находим элемент со значением 10, который в итоге побеждает во всех сравнениях и оказывается в правом конце массива.</p>
25
<p>Рассмотрим механизм работы данной сортировки на реальном примере. Возьмем массив и сравним элементы попарно от начала к концу: первый со вторым, второй с третьим, третий с четвертым и так далее.</p>
25
<p>Рассмотрим механизм работы данной сортировки на реальном примере. Возьмем массив и сравним элементы попарно от начала к концу: первый со вторым, второй с третьим, третий с четвертым и так далее.</p>
26
<p>Если два соседних элемента находятся в неправильном порядке, меняем их местами. После первого прохода самый большой элемент оказывается справа - его можно больше не сравнивать и не перемещать. Далее повторяем те же действия со всеми остальными числами.</p>
26
<p>Если два соседних элемента находятся в неправильном порядке, меняем их местами. После первого прохода самый большой элемент оказывается справа - его можно больше не сравнивать и не перемещать. Далее повторяем те же действия со всеми остальными числами.</p>
27
<p>Пузырьковая сортировка реализуется в JavaScript с помощью такой функции:</p>
27
<p>Пузырьковая сортировка реализуется в JavaScript с помощью такой функции:</p>
28
-
<p><strong>Javascript</strong></p>
29
-
<p><strong>Python</strong></p>
30
-
<p><strong>PHP</strong></p>
31
-
<p><strong>Java</strong></p>
32
<p>Мы видим здесь два вложенных цикла.<strong>Внешний цикл</strong>ограничивает внутренний цикл на каждом проходе. Сначала он простирается до конца массива, но после первого прохода там оказывается максимальный элемент.</p>
28
<p>Мы видим здесь два вложенных цикла.<strong>Внешний цикл</strong>ограничивает внутренний цикл на каждом проходе. Сначала он простирается до конца массива, но после первого прохода там оказывается максимальный элемент.</p>
33
<p><strong>Внутренний цикл</strong>на следующем проходе движется до предпоследнего элемента, а затем до пред-пред-последнего - и так до тех пор, пока не остается один элемент в левой части:</p>
29
<p><strong>Внутренний цикл</strong>на следующем проходе движется до предпоследнего элемента, а затем до пред-пред-последнего - и так до тех пор, пока не остается один элемент в левой части:</p>
34
-
<p><strong>Javascript</strong></p>
35
-
<p><strong>Python</strong></p>
36
-
<p><strong>PHP</strong></p>
37
-
<p><strong>Java</strong></p>
38
<p>Мы помним, что в JavaScript элементы массива нумеруются с 0 - следовательно, индекс последнего элемента массива items равен items.length - 1.</p>
30
<p>Мы помним, что в JavaScript элементы массива нумеруются с 0 - следовательно, индекс последнего элемента массива items равен items.length - 1.</p>
39
<p>Обмен двух элементов выполняется с помощью временной переменной, которую мы назвали temporary (т.е.<strong>временная</strong>):</p>
31
<p>Обмен двух элементов выполняется с помощью временной переменной, которую мы назвали temporary (т.е.<strong>временная</strong>):</p>
40
-
<p><strong>Javascript</strong></p>
41
-
<p><strong>Python</strong></p>
42
-
<p><strong>PHP</strong></p>
43
-
<p><strong>Java</strong></p>
44
<p>На каждом шаге мы находим наибольший элемент в массиве, а последний оставшийся неизбежно оказывается наименьшим - так мы получаем упорядоченный массив. Проверим работу алгоритма:</p>
32
<p>На каждом шаге мы находим наибольший элемент в массиве, а последний оставшийся неизбежно оказывается наименьшим - так мы получаем упорядоченный массив. Проверим работу алгоритма:</p>
45
-
<p><strong>Javascript</strong></p>
46
-
<p><strong>Python</strong></p>
47
-
<p><strong>PHP</strong></p>
48
-
<p><strong>Java</strong></p>
49
<p>При пузырьковой сортировке соседние элементы часто меняются местами, поэтому она работает довольно медленно. Чтобы сэкономить время, можно сократить количество перестановок. В этом поможет<strong>сортировка выбором</strong>.</p>
33
<p>При пузырьковой сортировке соседние элементы часто меняются местами, поэтому она работает довольно медленно. Чтобы сэкономить время, можно сократить количество перестановок. В этом поможет<strong>сортировка выбором</strong>.</p>
50
<h2>Сортировка выбором</h2>
34
<h2>Сортировка выбором</h2>
51
<p>Этот алгоритм сначала проводит операции сравнения и находит наименьший элемент, а только потом помещает его в начало массива. После первого прохода алгоритм исключает первый элемент из рассмотрения и ищет минимальный элемент в оставшейся части массива, а затем помещаем его на второе место:</p>
35
<p>Этот алгоритм сначала проводит операции сравнения и находит наименьший элемент, а только потом помещает его в начало массива. После первого прохода алгоритм исключает первый элемент из рассмотрения и ищет минимальный элемент в оставшейся части массива, а затем помещаем его на второе место:</p>
52
<p>Этот алгоритм работает гораздо быстрее пузырьковой сортировки, потому что сравнений здесь столько же, а вот обмен всего один - в самом конце.</p>
36
<p>Этот алгоритм работает гораздо быстрее пузырьковой сортировки, потому что сравнений здесь столько же, а вот обмен всего один - в самом конце.</p>
53
<p>Рассмотрим функцию, реализующую сортировку выбором в Java Script:</p>
37
<p>Рассмотрим функцию, реализующую сортировку выбором в Java Script:</p>
54
-
<p><strong>Javascript</strong></p>
55
-
<p><strong>Python</strong></p>
56
-
<p><strong>PHP</strong></p>
57
-
<p><strong>Java</strong></p>
58
<p>В реализации мы сохраняем не сам минимальный элемент, а его индекс в массиве. Это нужно потому, что в конце каждого прохода минимальный элемент записывается в начало массива. При этом элемент, который был там до этого, нужно вставить куда-то в неупорядоченную половину - легче всего просто поменять их местами.</p>
38
<p>В реализации мы сохраняем не сам минимальный элемент, а его индекс в массиве. Это нужно потому, что в конце каждого прохода минимальный элемент записывается в начало массива. При этом элемент, который был там до этого, нужно вставить куда-то в неупорядоченную половину - легче всего просто поменять их местами.</p>
59
<h2>Быстрая сортировка</h2>
39
<h2>Быстрая сортировка</h2>
60
<p>Можно сделать сортировку еще быстрее, если менять местами не соседние элементы, а элементы на самом большом расстоянии друг от друга.</p>
40
<p>Можно сделать сортировку еще быстрее, если менять местами не соседние элементы, а элементы на самом большом расстоянии друг от друга.</p>
61
<p>Возьмем для примера массив, отсортированный в порядке убывания - от больших к меньшим. Чтобы разместить элементы в порядке возрастания, надо попарно поменять их местами: первый и последний, потом второй и предпоследний, и так далее, как показано на схеме:</p>
41
<p>Возьмем для примера массив, отсортированный в порядке убывания - от больших к меньшим. Чтобы разместить элементы в порядке возрастания, надо попарно поменять их местами: первый и последний, потом второй и предпоследний, и так далее, как показано на схеме:</p>
62
<p>Сортировки массива в обратном порядке реализуется так:</p>
42
<p>Сортировки массива в обратном порядке реализуется так:</p>
63
-
<p><strong>Javascript</strong></p>
64
-
<p><strong>Python</strong></p>
65
-
<p><strong>PHP</strong></p>
66
-
<p><strong>Java</strong></p>
67
<p>В примере выше мы создали две переменные-указателя. Переменная left указывает на следующий элемент для обмена слева, а переменная right - справа. Для обмена используем уже знакомую временную переменную temporary:</p>
43
<p>В примере выше мы создали две переменные-указателя. Переменная left указывает на следующий элемент для обмена слева, а переменная right - справа. Для обмена используем уже знакомую временную переменную temporary:</p>
68
-
<p><strong>Javascript</strong></p>
69
-
<p><strong>Python</strong></p>
70
-
<p><strong>PHP</strong></p>
71
-
<p><strong>Java</strong></p>
72
<p>На каждой итерации цикла после обмена мы увеличиваем левый указатель, сдвигая его вправо, и одновременно уменьшаем правый, сдвигая влево:</p>
44
<p>На каждой итерации цикла после обмена мы увеличиваем левый указатель, сдвигая его вправо, и одновременно уменьшаем правый, сдвигая влево:</p>
73
-
<p><strong>Javascript</strong></p>
74
-
<p><strong>Python</strong></p>
75
-
<p><strong>PHP</strong></p>
76
-
<p><strong>Java</strong></p>
77
<p>Похожий подход применяется в алгоритме быстрой сортировки. Он частично упорядочивает массив, перемещая в начало маленькие элементы, а в конец - большие.</p>
45
<p>Похожий подход применяется в алгоритме быстрой сортировки. Он частично упорядочивает массив, перемещая в начало маленькие элементы, а в конец - большие.</p>
78
<p>Частичное упорядочивание делается с помощью программы, похожей на пример выше. Для начала выбираем<strong>опорный элемент</strong>- это условный средний элемент, который помогает отличить маленькие элементы от больших. Затем устанавливаем два указателя на начало и конец массива.</p>
46
<p>Частичное упорядочивание делается с помощью программы, похожей на пример выше. Для начала выбираем<strong>опорный элемент</strong>- это условный средний элемент, который помогает отличить маленькие элементы от больших. Затем устанавливаем два указателя на начало и конец массива.</p>
79
<h3>Принцип работы быстрой сортировки</h3>
47
<h3>Принцип работы быстрой сортировки</h3>
80
<p>Чтобы не запутаться в алгоритме быстрой сортировки, разберем его на схематичном примере. В самом начале наш массив выглядит так:</p>
48
<p>Чтобы не запутаться в алгоритме быстрой сортировки, разберем его на схематичном примере. В самом начале наш массив выглядит так:</p>
81
<p>В качестве опорного элемента выбрано число 4. Левый указатель смотрит на 5, а правый - на 3.</p>
49
<p>В качестве опорного элемента выбрано число 4. Левый указатель смотрит на 5, а правый - на 3.</p>
82
<p>Далее двигаем левый указатель и пропускаем элементы меньше опорного, и ищем неправильный элемент слева. Затем двигаем правый указатель, пропуская элементы больше опорного.</p>
50
<p>Далее двигаем левый указатель и пропускаем элементы меньше опорного, и ищем неправильный элемент слева. Затем двигаем правый указатель, пропуская элементы больше опорного.</p>
83
<p>Таким образом мы ищем пару элементов, в которой левый больше правого. Когда пара найдена, меняем элементы местами. В нашем примере 5 и 3 находятся в неправильной позиции - их надо поменять:</p>
51
<p>Таким образом мы ищем пару элементов, в которой левый больше правого. Когда пара найдена, меняем элементы местами. В нашем примере 5 и 3 находятся в неправильной позиции - их надо поменять:</p>
84
<p>Ищем следующую пару для обмена. Справа от 3 находится 4 - наш следующий кандидат для обмена. Обратите внимание, что 4 - опорный элемент, но он тоже принимает участие в сравнениях и обменах.</p>
52
<p>Ищем следующую пару для обмена. Справа от 3 находится 4 - наш следующий кандидат для обмена. Обратите внимание, что 4 - опорный элемент, но он тоже принимает участие в сравнениях и обменах.</p>
85
<p>Слева от числа 5 находятся числа 6, 9 и 7. Они больше опорного элемента 4, поэтому указатель их пропускает. В итоге он останавливается на числе 2:</p>
53
<p>Слева от числа 5 находятся числа 6, 9 и 7. Они больше опорного элемента 4, поэтому указатель их пропускает. В итоге он останавливается на числе 2:</p>
86
<p>Меняем их местами и ищем следующую пару. Следующие кандидаты - числа 10 и 1:</p>
54
<p>Меняем их местами и ищем следующую пару. Следующие кандидаты - числа 10 и 1:</p>
87
<p>Меняем их местами и останавливаемся, потому что левый и правый указатели упираются друг в друга. Мы получили<strong>частично упорядоченный массив</strong>. Разбиваем его на две части там, где указатели встретились:</p>
55
<p>Меняем их местами и останавливаемся, потому что левый и правый указатели упираются друг в друга. Мы получили<strong>частично упорядоченный массив</strong>. Разбиваем его на две части там, где указатели встретились:</p>
88
<p>Продолжаем частичное упорядочивание левой и правой половин массива. Правая половина перед упорядочиванием показана на рисунке:</p>
56
<p>Продолжаем частичное упорядочивание левой и правой половин массива. Правая половина перед упорядочиванием показана на рисунке:</p>
89
<p>Выбираем новый опорный элемент из подмассива. На этот раз это 7. Сдвигая указатели, меняем местами пары 10 и 5, а также 8 и 6. Числа 4 и 9 останутся на своих местах. Частично упорядоченный подмассив принимает такой вид:</p>
57
<p>Выбираем новый опорный элемент из подмассива. На этот раз это 7. Сдвигая указатели, меняем местами пары 10 и 5, а также 8 и 6. Числа 4 и 9 останутся на своих местах. Частично упорядоченный подмассив принимает такой вид:</p>
90
<p>Левый и правый указатель встречаются посередине - на числе 7. Мы снова разбиваем массив на две половины и переходим к упорядочиванию левой и правой половин.</p>
58
<p>Левый и правый указатель встречаются посередине - на числе 7. Мы снова разбиваем массив на две половины и переходим к упорядочиванию левой и правой половин.</p>
91
<h3>Как реализовать быструю сортировку</h3>
59
<h3>Как реализовать быструю сортировку</h3>
92
<p>Попробуем реализовать алгоритм на JavaScript. Начнем с функции частичного упорядочивания:</p>
60
<p>Попробуем реализовать алгоритм на JavaScript. Начнем с функции частичного упорядочивания:</p>
93
-
<p><strong>Javascript</strong></p>
94
-
<p><strong>Python</strong></p>
95
-
<p><strong>PHP</strong></p>
96
-
<p><strong>Java</strong></p>
97
<p>В качестве параметров функция получает:</p>
61
<p>В качестве параметров функция получает:</p>
98
<ul><li>Массив items</li>
62
<ul><li>Массив items</li>
99
<li>Указатели на левую и правую часть подмассива left и right</li>
63
<li>Указатели на левую и правую часть подмассива left и right</li>
100
<li>Опорный элемент для сравнения pivot</li>
64
<li>Опорный элемент для сравнения pivot</li>
101
</ul><p>Сначала в цикле пропускаются элементы слева, которые меньше опорного:</p>
65
</ul><p>Сначала в цикле пропускаются элементы слева, которые меньше опорного:</p>
102
-
<p><strong>Javascript</strong></p>
103
-
<p><strong>Python</strong></p>
104
-
<p><strong>PHP</strong></p>
105
-
<p><strong>Java</strong></p>
106
<p>Затем пропускаются элементы справа, которые больше опорного:</p>
66
<p>Затем пропускаются элементы справа, которые больше опорного:</p>
107
-
<p><strong>Javascript</strong></p>
108
-
<p><strong>Python</strong></p>
109
-
<p><strong>PHP</strong></p>
110
-
<p><strong>Java</strong></p>
111
<p>Если указатели встретились или зашли друг за друга, мы завершаем цикл и возвращаем место встречи в качестве результата. Нам предстоит разбить массив на два подмассива, поэтому надо решить, что именно возвращать. Мы можем сказать, что граница - это место, где заканчивается левый подмассив, или место, где начинается правый. Большой разницы здесь нет.</p>
67
<p>Если указатели встретились или зашли друг за друга, мы завершаем цикл и возвращаем место встречи в качестве результата. Нам предстоит разбить массив на два подмассива, поэтому надо решить, что именно возвращать. Мы можем сказать, что граница - это место, где заканчивается левый подмассив, или место, где начинается правый. Большой разницы здесь нет.</p>
112
<p>Решим, что функция partition возвращает индекс элемента, где начинается правый подмассив:</p>
68
<p>Решим, что функция partition возвращает индекс элемента, где начинается правый подмассив:</p>
113
-
<p><strong>Javascript</strong></p>
114
-
<p><strong>Python</strong></p>
115
-
<p><strong>PHP</strong></p>
116
-
<p><strong>Java</strong></p>
117
<p>Если указатели остановились, то они указывают на два элемента в неверном порядке. Левый указатель смотрит на элемент, который больше опорного. При этом правый указатель смотрит на элемент, который меньше опорного.</p>
69
<p>Если указатели остановились, то они указывают на два элемента в неверном порядке. Левый указатель смотрит на элемент, который больше опорного. При этом правый указатель смотрит на элемент, который меньше опорного.</p>
118
<p>Меняем местами и сдвигаем элементы, чтобы в следующей итерации продолжить поиск следующей неправильной пары:</p>
70
<p>Меняем местами и сдвигаем элементы, чтобы в следующей итерации продолжить поиск следующей неправильной пары:</p>
119
-
<p><strong>Javascript</strong></p>
120
-
<p><strong>Python</strong></p>
121
-
<p><strong>PHP</strong></p>
122
-
<p><strong>Java</strong></p>
123
<p>Обычно условие завершения цикла пишут в начале (оператор while) или в конце (оператор do…while). В функции partition() условие становится известно в середине цикла.</p>
71
<p>Обычно условие завершения цикла пишут в начале (оператор while) или в конце (оператор do…while). В функции partition() условие становится известно в середине цикла.</p>
124
<p>В языках программирования нет специального синтаксиса для такой ситуации. Обычно программисты записывают бесконечный цикл с помощью конструкции while (true), а выход из цикла делают с помощью операторов break или return:</p>
72
<p>В языках программирования нет специального синтаксиса для такой ситуации. Обычно программисты записывают бесконечный цикл с помощью конструкции while (true), а выход из цикла делают с помощью операторов break или return:</p>
125
-
<p><strong>Javascript</strong></p>
126
-
<p><strong>Python</strong></p>
127
-
<p><strong>PHP</strong></p>
128
-
<p><strong>Java</strong></p>
129
<p>Частично упорядоченный массив нельзя назвать полностью отсортированным. Чтобы закончить сортировку, мы должны рекурсивно повторить упорядочивание для левой и правой половин массива.</p>
73
<p>Частично упорядоченный массив нельзя назвать полностью отсортированным. Чтобы закончить сортировку, мы должны рекурсивно повторить упорядочивание для левой и правой половин массива.</p>
130
<p>Про рекурсию мы говорили на прошлом уроке. Так выглядит рекурсивный алгоритм быстрой сортировки. Он немного похож на рекурсивную функцию бинарного поиска:</p>
74
<p>Про рекурсию мы говорили на прошлом уроке. Так выглядит рекурсивный алгоритм быстрой сортировки. Он немного похож на рекурсивную функцию бинарного поиска:</p>
131
-
<p><strong>Javascript</strong></p>
132
-
<p><strong>Python</strong></p>
133
-
<p><strong>PHP</strong></p>
134
-
<p><strong>Java</strong></p>
135
<p>Для упорядочивания нужно не менее двух элементов. Поэтому мы остановим рекурсивный вызов, когда встретим пустой подмассив или подмассив с одним элементом:</p>
75
<p>Для упорядочивания нужно не менее двух элементов. Поэтому мы остановим рекурсивный вызов, когда встретим пустой подмассив или подмассив с одним элементом:</p>
136
-
<p><strong>Javascript</strong></p>
137
-
<p><strong>Python</strong></p>
138
-
<p><strong>PHP</strong></p>
139
-
<p><strong>Java</strong></p>
140
<p>Функция partition возвращает индекс первого элемента в правом подмассиве. Это помогает функции sort корректно вызвать саму себя:</p>
76
<p>Функция partition возвращает индекс первого элемента в правом подмассиве. Это помогает функции sort корректно вызвать саму себя:</p>
141
-
<p><strong>Javascript</strong></p>
142
-
<p><strong>Python</strong></p>
143
-
<p><strong>PHP</strong></p>
144
-
<p><strong>Java</strong></p>
145
<p>Единственный код, который вызывает вопросы - выбор опорного элемента:</p>
77
<p>Единственный код, который вызывает вопросы - выбор опорного элемента:</p>
146
-
<p><strong>Javascript</strong></p>
147
-
<p><strong>Python</strong></p>
148
-
<p><strong>PHP</strong></p>
149
-
<p><strong>Java</strong></p>
150
<p>Почему мы всегда выбираем самый левый элемент подмассива?</p>
78
<p>Почему мы всегда выбираем самый левый элемент подмассива?</p>
151
<p>Средний элемент должен находиться ровно посередине отсортированного массива. В таком случае его называют<strong>медианой</strong>. Чтобы узнать медиану, нужно иметь отсортированный массив, а чтобы отсортировать массив - знать медиану. Получается замкнутый круг.</p>
79
<p>Средний элемент должен находиться ровно посередине отсортированного массива. В таком случае его называют<strong>медианой</strong>. Чтобы узнать медиану, нужно иметь отсортированный массив, а чтобы отсортировать массив - знать медиану. Получается замкнутый круг.</p>
152
<p>На практике необязательно делить массив ровно пополам - достаточно разбить массив на приблизительно равные части - алгоритм все равно будет работать быстро. Если элементы в массиве расположены в случайном порядке, то можно брать любой элемент по счету - в среднем массив будет всегда разбит пополам.</p>
80
<p>На практике необязательно делить массив ровно пополам - достаточно разбить массив на приблизительно равные части - алгоритм все равно будет работать быстро. Если элементы в массиве расположены в случайном порядке, то можно брать любой элемент по счету - в среднем массив будет всегда разбит пополам.</p>
153
<p>Можно выбрать самый левый элемент в качестве опорного элемента - как видно на примере выше, это работает.</p>
81
<p>Можно выбрать самый левый элемент в качестве опорного элемента - как видно на примере выше, это работает.</p>
154
<p>Выше мы написали универсальную функцию, которая может сортировать отдельные подмассивы. Сложность в том, что такой функцией не очень удобно пользоваться - приходится передавать параметры left и right даже тогда, когда надо отсортировать массив целиком.</p>
82
<p>Выше мы написали универсальную функцию, которая может сортировать отдельные подмассивы. Сложность в том, что такой функцией не очень удобно пользоваться - приходится передавать параметры left и right даже тогда, когда надо отсортировать массив целиком.</p>
155
<p>Чтобы упростить себе жизнь, напишем вспомогательную функцию, которая всегда сортирует массив целиком:</p>
83
<p>Чтобы упростить себе жизнь, напишем вспомогательную функцию, которая всегда сортирует массив целиком:</p>
156
-
<p><strong>Javascript</strong></p>
157
-
<p><strong>Python</strong></p>
158
-
<p><strong>PHP</strong></p>
159
-
<p><strong>Java</strong></p>
160
<p>Быстрая сортировка намного эффективнее сортировки выбором. Причем эта разница особенно видна на больших массивах. Если сортировать миллион элементов, сортировка выбором окажется медленнее в десятки тысяч раз.</p>
84
<p>Быстрая сортировка намного эффективнее сортировки выбором. Причем эта разница особенно видна на больших массивах. Если сортировать миллион элементов, сортировка выбором окажется медленнее в десятки тысяч раз.</p>
161
<h2>Универсальная функция сортировки</h2>
85
<h2>Универсальная функция сортировки</h2>
162
<p>Мы реализовали три функции сортировки, каждая из которых упорядочивает в возрастающем порядке элементы простых типов: чисел, дат, строк.</p>
86
<p>Мы реализовали три функции сортировки, каждая из которых упорядочивает в возрастающем порядке элементы простых типов: чисел, дат, строк.</p>
163
<p>Вспомним пример с интернет-магазином, в котором мы сталкиваемся с более сложной задачей - сортировкой по разным атрибутам. Представим, что нам предстоит сортировать товары по трем атрибутам:</p>
87
<p>Вспомним пример с интернет-магазином, в котором мы сталкиваемся с более сложной задачей - сортировкой по разным атрибутам. Представим, что нам предстоит сортировать товары по трем атрибутам:</p>
164
<ul><li>Название - name</li>
88
<ul><li>Название - name</li>
165
<li>Цена - price</li>
89
<li>Цена - price</li>
166
<li>Рейтинг - rating</li>
90
<li>Рейтинг - rating</li>
167
</ul><p>Сам массив выглядит так:</p>
91
</ul><p>Сам массив выглядит так:</p>
168
-
<p><strong>Javascript</strong></p>
169
-
<p><strong>Python</strong></p>
170
-
<p><strong>PHP</strong></p>
171
-
<p><strong>Java</strong></p>
172
<p>Можно реализовать несколько функций сортировки, но есть и более эффективный способ. Интернет-магазину подойдет<strong>универсальная функция сортировки</strong>.</p>
92
<p>Можно реализовать несколько функций сортировки, но есть и более эффективный способ. Интернет-магазину подойдет<strong>универсальная функция сортировки</strong>.</p>
173
<p>Каждую из трех видов сортировок выше можно сделать универсальной - и тогда алгоритм сможет сортировать данные любого типа. Для этого надо добавить еще один параметр - функцию сравнения (компаратор). Универсальная функция сортировки вызывает компаратор каждый раз, когда требуется сравнить два элемента и определить, какой из них больше.</p>
93
<p>Каждую из трех видов сортировок выше можно сделать универсальной - и тогда алгоритм сможет сортировать данные любого типа. Для этого надо добавить еще один параметр - функцию сравнения (компаратор). Универсальная функция сортировки вызывает компаратор каждый раз, когда требуется сравнить два элемента и определить, какой из них больше.</p>
174
<p>У компаратора два параметра - два элемента массива, которые надо сравнить. Если первый больше второго, компаратор возвращает 1. Если первый меньше второго, компаратор возвращает -1. Если элементы равны, компаратор возвращает 0.</p>
94
<p>У компаратора два параметра - два элемента массива, которые надо сравнить. Если первый больше второго, компаратор возвращает 1. Если первый меньше второго, компаратор возвращает -1. Если элементы равны, компаратор возвращает 0.</p>
175
<p>Вот так будет выглядеть компаратор, сравнивающий элементы по цене:</p>
95
<p>Вот так будет выглядеть компаратор, сравнивающий элементы по цене:</p>
176
-
<p><strong>Javascript</strong></p>
177
-
<p><strong>Python</strong></p>
178
-
<p><strong>PHP</strong></p>
179
-
<p><strong>Java</strong></p>
180
<p>А вот так - компаратор, сравнивающий элементы по рейтингу:</p>
96
<p>А вот так - компаратор, сравнивающий элементы по рейтингу:</p>
181
-
<p><strong>Javascript</strong></p>
182
-
<p><strong>Python</strong></p>
183
-
<p><strong>PHP</strong></p>
184
-
<p><strong>Java</strong></p>
185
<p>Универсальная функция сравнивает два элемента, но не использует операторы "больше" или "меньше". Вместо этого она вызывает компаратор и проверяет результат. Так выглядит универсальная пузырьковая сортировка:</p>
97
<p>Универсальная функция сравнивает два элемента, но не использует операторы "больше" или "меньше". Вместо этого она вызывает компаратор и проверяет результат. Так выглядит универсальная пузырьковая сортировка:</p>
186
-
<p><strong>Javascript</strong></p>
187
-
<p><strong>Python</strong></p>
188
-
<p><strong>PHP</strong></p>
189
-
<p><strong>Java</strong></p>
190
<p>Компаратор также используется, чтобы изменить направление сортировки. Если элементы надо упорядочить по убыванию, новая функция компаратор должна возвращать 1 там, где старая возвращала -1, и наоборот.</p>
98
<p>Компаратор также используется, чтобы изменить направление сортировки. Если элементы надо упорядочить по убыванию, новая функция компаратор должна возвращать 1 там, где старая возвращала -1, и наоборот.</p>