HTML Diff
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>