Сортировки в гифках 8 самых популярных алгоритмов
Анимированные gifs (сортировки) алгоритмов
Каков наилучший способ генерации gif алгоритмов, таких как этот в Википедии? В Linux любой язык действительно.
3 ответа
1 Решение msandiford [2011-08-14 16:32:00]
Есть, вероятно, более удобные для пользователя способы, но в прошлый раз я это сделал, я использовал gifsicle для сборки некоторых предварительно созданных фреймов в анимацию.
ImageMagick может построить анимацию, собрав несколько растровые изображения в один:
Также можно создавать анимированные gif с Gimp, если вы предпочитаете инструмент GUI. Многое, если вы google it.
Быстрая сортировка — один из лучших методов сортировки массивов
Если вы программируете и ваш код уходит дальше написания калькулятора, ты вы не раз столкнётесь или сталкивались с необходимостью отсортировать тот или иной массив данных. Существует множество способов сортировки. В этой статье мы разберём основные из них и сделаем акцент на быстрой сортировке.
Понятие быстрой сортировки
Быстрая сортировка — Quick Sort или qsort. По названию становится понятно, что это и для чего. Но если не понятно, то это алгоритм по быстрой сортировке массива, алгоритм имеет эффективность O(n log n) в среднем. Что это значит? Это значит, что среднее время работы алгоритма повышается по той же траектории, что и график данной функции. В некоторых популярных языках имеются встроенные библиотеки с этим алгоритмом, а это уже говорит о том, что он крайне эффективен. Это такие языки, как Java, C++, C#.
Алгоритм
Метод быстрой сортировки использует рекурсию и стратегию «Разделяй и властвуй».
1. В массиве ищется некий опорный элемент, для простоты лучше взять центральный, но если вы хотите поработать над оптимизацией, то придётся попробовать разные варианты.
2. Слева от опоры ищется элемент больший, чем опорный, справа — меньший, чем опорный, затем меняем их местами. Делаем это, пока максимальный справа не будет меньше, чем минимальный слева. Таким образом, все маленькие элементы кидаем в начало, большие — в конец.
3. Рекурсивно применяем данный алгоритм к левой и правой части нашего алгоритма отдельно, затем ещё и ещё, до достижения одного элемента или определённого количества элементов. Что же это за количество элементов? Есть ещё один способ оптимизировать данный алгоритм. Когда сортируемая часть становится примерно равной 8 или 16, то можно обработать её обычной сортировкой, например пузырьковой. Так мы повысим эффективность нашего алгоритма, т.к. маленькие массивы он обрабатывает не так быстро, как хотелось бы.
Таким образом, будет обработан и отсортирован весь массив. А теперь наглядно изучим данный алгоритм
Эффективность быстрой сортировки
Является ли быстрая сортировка самым быстрым алгоритмом сортировки? Однозначно нет. Сейчас появляется всё больше и больше сортировок, на данный момент самая быстрая сортировка — это Timsort, она работает крайне быстро для массивов, изначально отсортированных по-разному. Но не стоит забывать, что метод быстрой сортировки является одним из самых простых в написании, это очень важно, ведь, как правило, для рядового проекта нужно именно простое написание, а не громадный алгоритм, который сам ты и не напишешь. Timsort — тоже не самый сложный алгоритм, но звание самого простого ему точно не светит.
Реализация алгоритма
Ну вот мы и дошли до самого «вкусного». Теперь разберём, как реализовывается данный алгоритм. Как говорилось ранее, он не слишком сложен в реализации, скорее, даже прост. Но мы всё равно полностью разберём каждое действие нашего кода, чтобы вы поняли, как работает быстрая сортировка.
Наш метод называется quickSort. В нём запускается основной алгоритм, в который мы передаём массив, первый и последний его элементы. Запоминаем в переменные i и k первый и последний элемент сортируемого отрезка, чтобы не изменять эти переменные, так как они нам нужны. Затем проверяем расстояние между первым и последним проверяемым: оно больше или равно единице? Если нет, значит, мы пришли к центру и нужно выйти из сортировки этого отрезка, а если да, то продолжаем сортировку.
Затем за опорный элемент берём первый элемент в сортируемом отрезке. Следующий цикл делаем до того момента, пока не дойдём до центра. В нём делаем ещё два цикла: первый — для левой части, а второй — для правой. Их мы выполняем, пока есть элементы, подходящие под условие, или пока не дойдём до опорного элемента. Затем, если минимальный элемент всё же справа, а максимальный — слева, меняем их местами. Когда цикл заканчивается, меняем первый элемент и опорный, если опорный меньше. Затем мы рекурсивно делаем наш алгоритм для правого и левого участка массива и так продолжаем, пока не дойдём до отрезка длиной в 1 элемент. Тогда все наши рекурсивные алгоритмы будут return, и мы полностью выйдем из сортировки. Также внизу имеется метод swap — вполне стандартный метод при сортировке массива заменами. Чтобы несколько раз не писать замену элементов, пишем один раз и меняем элементы в данном массиве.
В заключение можно сказать, что по соотношению «качество-сложность» быстрая сортировка находится на лидирующей позиции среди всех алгоритмов, поэтому вам стоит однозначно взять метод на заметку и использовать при необходимости в своих проектах.
Сортировки в гифках: 8 самых популярных алгоритмов
традиционные алгоритмы сортировки массивов написанные на Swift 4
Quick Sort (быстрая сортировка)
Выбираем некоторый опорный элемент (например, средний). После этого разбиваем исходный массив на три части: элементы эквивалентные опорному, меньше, больше опорного. Рекурсивно вызовемся от большей и меньшей частей. В итоге получим отсортированный массив, так как каждый элемент меньше опорного стоял раньше каждого большего опорного.
Асимптотика:
сложность в худшем | сложность в среднем | сложность в лучшем |
---|---|---|
O(n 2 ) | O(n log n) | O(n) |
худший случай: если опорный элемент наименьший или наибольший из всех, то каждый раз массив разбивается на подмассивы размерами 1 и n-1 | — | лучший случай: массив постоянно разбивается опорным элементом на две раные части |
Расход памяти: В общем случае O(log n). При неудачных подборках опорного элемнта O(n) — здесь память будет расходоваться не на создание новых вспомогательных массивов, а на рекурсию, хранение адресов возврата и локальных переменных.
Алгоритм неустойчив (неудачные входные данные могут привести к значительному увеличению времени работы и расхода памяти). Является одним из самых быстродействующих алгоритмов, однако для массивов с небольшим количеством элементом может оказаться малоэффективным.
Selection Sort (сортировка выбором)
Алгоритм пробегает по всем ещё не упорядоченным элементам, ищет среди них минимальный (сохраняя его значение и индекс) и переставляет в конец выстриваемого списка.
Асимптотика:
сложность в худшем | сложность в среднем | сложность в лучшем |
---|---|---|
O(n 2 ) | O(n 2 ) | O(n 2 ) |
Расход памяти: O(1). Дополнительной памяти не требуется.
Bubble Sort (пузырьковая сортировка)
Соседние элементы сравниваются и при необходимости меняются местами, в результате «лёгкие» элементы перемещаются к началу списка, а «тяжёлые» — к концу. Операция циклически выполняется для оставшихся элементов.
Асимптотика:
сложность в худшем | сложность в среднем | сложность в лучшем |
---|---|---|
O(n 2 ) | O(n 2 ) | O(n) |
Расход памяти: O(1). Дополнительной памяти не требуется.
Алгоритм устойчив. На практике может использоваться лишь для сортировки маленьких массивов. И в этом случае лучше взять классическую сортировку, а не её модификацию.
Shaker Sort (сортировка перемешиванием)
Устанавливаем левую и правую границы сортируемой области массива. Поочерёдно просматриваем массив справа налево и слева направо. На очередной итерации при достижении правой границы сдвигаем её на предыдущий элемент (-1) и движемся справа налево, при достижении левой границы сдвигаем её на следующий элемент (+1) и двигаемся слева направо.
Асимптотика:
сложность в худшем | сложность в среднем | сложность в лучшем |
---|---|---|
O(n 2 ) | зависит от выбранных шагов | O(n log 2 n) |
худший случай: отсортированный в обратном порядке массив | — | лучший случай: отсортированный массив |
Расход памяти: O(1). Дополнительной памяти не требуется.
Shell Sort (сортировка Шелла)
Сравниваем элементы находящиеся друг от друга на некотором расстоянии (шаге). В алгоритме два цикла. Внутренний переставляет элементы. Внешний служит для изменения шага, через который внутренний цикл элементы будет переставлять. Шаг постепенно сокращается до 1 (минимальное расстояние между двумя элементами) — и тогда алгоритм Шелла превращается в обычную сортировку вставками.
Асимптотика:
сложность в худшем | сложность в среднем | сложность в лучшем |
---|---|---|
O(n 2 ) | O(n 2 ) | O(n) |
худший случай: неудачный выбор шага | — | лучший случай: массив уже отсортирован в правильном порядке |
Расход памяти: O(1). Дополнительной памяти не требуется.
Counting Sort (сортировка подсчётом)
Проходимся по массиву и подсчитываем количество вхождений каждого элемента. После проходим по массиву значений и выводим каждое число столько раз, сколько нужно.
Асимптотика:
сложность в худшем | сложность в среднем | сложность в лучшем |
---|---|---|
O(n) | O(n) | O(n) |
Расход памяти: O(1). Дополнительной памяти не требуется.
Алгоритм устойчив. Применение сортировки подсчётом целесообразно лишь тогда, когда массив состоит из целочисленных, положительных чисел.
Merge Sort (сортировка слиянием)
Исходный массив делится надвое на всё меньшие подмассивы, пока количество элементов в очередных не станет равным 2 или 1. Если в подмассиве 2 элемента, то он упорядочивается банальным сравнением. А подмассив из одного элемента по своей сути является упорядоченным. Затем происходит обратный процесс — слияние подмассивов. Поскольку подмассивы к этому времени являются упорядоченными, то можем сравнивать лишь элементы, стоящие в их начале.
Асимптотика:
сложность в худшем | сложность в среднем | сложность в лучшем |
---|---|---|
O(n log n) | O(n log n) | O(n log n) |
Расход памяти: O(n). Требует дополнительной памяти, примерно равной размеру исходного массива. Память расходуется на рекурсивный вызов и на постоянное создание вспомогательных подмассивов.
Алгоритм устойчив. На «почти отсортированных» массивах работает столь же долго, как на хаотичных.
Heap Sort (пирамидальная сортировка)
Строим на основе неотсортированного массива так называемую двоичную кучу или пирамиду. В результате получается бинарное дерево каждый узел которого больше предыдущего, тем самым на вершине дерева оказывается элемент с максимальным значением. Затем вершина дерева переставляется в конец, откуда и будет выстраиваться отсортированный подмассив. А среди оставшихся элементов происходит ряд перестановок с целью восстановить дерево, чтобы в его вершине вновь оказался максимальный элемент из ещё не отсортированной части. Таким образом на первом месте постоянно оказывается один из самых «лёгких» элементов, который затем серией перестановок отправляется назад.
Асимптотика:
сложность в худшем | сложность в среднем | сложность в лучшем |
---|---|---|
O(n log n) | O(n log n) | O(n log n) |
Расход памяти: O(1). Дополнительной памяти не требуется. Хотя в алгоритме присутствует рекурсивный вызов, но чтобы добраться до конца даже очень большого массива, рекурсий нужно мало, и они моментально закрываются.
Алгоритм устойчив. На почти отсортированных массивах работает столь же долго, как и на хаотических данных. Не работает на связанных списках и других структурах памяти последовательного доступа. Из-за сложности реализации выигрыш получается только на больших размерах массива.
Алгоритмы сортировки в Python
Введение
Иногда данные, которые мы храним или извлекаем в приложении, могут находится в беспорядочном состояние. И иногда возникает необходимость упорядочивания данные прежде чем их можно будет эффективно использовать. За все эти годы учеными было создано множество алгоритмов сортировки для организации данных.
В этой статье мы рассмотрим наиболее популярные алгоритмы сортировки, разберем, как они работают, и напишем их на Python. Мы также сравним, как быстро они сортируют элементы в списке.
Для простоты реализации алгоритмов сортировать числа будем в порядке их возрастания.
Пузырьковая сортировка (Bubble Sort)
Этот самый простой алгоритм сортировки который выполняет итерации по списку, сравнивая элементы попарно и меняя их местами, пока более крупные элементы не перестанут «всплывать» до конца списка, а более мелкие элементы не будут оставаться «снизу».
Объяснение
Начнем со сравнения первых двух элементов списка. Если первый элемент больше второго, мы меняем их местами. Если они уже в нужном порядке, мы оставляем их как есть. Затем мы переходим к следующей паре элементов, сравниваем их значения и меняем местами при необходимости. Этот процесс продолжается до последней пары элементов в списке.
Достигнув конца списка, повторяем этот процесс для каждого элемента снова. Хотя это крайне неэффективно. Что если в массиве нужно сделать только одну замену? Почему мы все еще повторяем, даже если список уже отсортирован? Получается нам нужно пройти список n^2 раза.
Очевидно, что для оптимизации алгоритма нам нужно остановить его, когда он закончит сортировку.
Откуда нам знать, что мы закончили сортировку? Если бы элементы были отсортированы, то нам не пришлось бы их менять местами. Таким образом, всякий раз, когда мы меняем элементы, мы устанавливаем флаг в True, чтобы повторить процесс сортировки. Если перестановок не произошло, флаг останется False, и алгоритм остановится.
Реализация
Мы можем реализовать пузырьковую сортировку в Python следующим образом:
Алгоритм работает в цикле while, прерываясь только тогда, когда никакие элементы не меняются местами. Вначале мы установили для swapped значение True, чтобы алгоритм прошел по списку хотя бы один раз.
Сложность
Сложность пузырьковой сортировки в худшем случае (когда список отсортирован в обратном порядке) равна O(n^2).
Сортировка выбором (Selection Sort)
Этот алгоритм сегментирует список на две части: отсортированные и несортированные. Он постоянно удаляет наименьший элемент из несортированного сегмента списка и добавляет его в отсортированный сегмент.
Объяснение
На практике нам не нужно создавать новый список для отсортированных элементов, мы будет обрабатывать крайнюю левую часть списка как отсортированный сегмент. Затем мы ищем во всем списке наименьший элемент и меняем его на первый элемент.
Теперь мы знаем, что первый элемент списка отсортирован, мы получаем наименьший элемент из оставшихся элементов и заменяем его вторым элементом. Это повторяется до тех пор, пока последний элемент списка не станет оставшимся элементом для изучения.
Реализация
Мы видим, что по мере того как i увеличивается, нам нужно проверять все меньше элементов.
Сложность
Сложность сортировки выбором в среднем составляет O(n^2).
Сортировка вставками (Insertion Sort)
Как и Сортировка выбором, этот алгоритм сегментирует список на отсортированные и несортированные части. Он перебирает несортированный сегмент и вставляет просматриваемый элемент в правильную позицию отсортированного списка.
Объяснение
Предполагается, что первый элемент списка отсортирован. Затем мы переходим к следующему элементу, назовем его х. Если x больше первого элемента, мы оставляем его как есть. Если x меньше, мы копируем значение первого элемента во вторую позицию и затем устанавливаем первый элемент в x.
Когда мы переходим к другим элементам несортированного сегмента, мы непрерывно перемещаем более крупные элементы в отсортированном сегменте вверх по списку, пока не встретим элемент меньше x, или не достигнем конца отсортированного сегмента, а затем поместим x в его правильное положение.
Реализация
Сложность
Сложность сортировки вставками в среднем равна O(n^2).
Пирамидальная сортировка (Heap Sort) (англ. Heapsort, «Сортировка кучей»)
Этот популярный алгоритм сортировки, как сортировки вставками и выбором, сегментирует список на отсортированные и несортированные части. Он преобразует несортированный сегмент списка в структуру данных типа куча (heap), чтобы мы могли эффективно определить самый большой элемент.
Объяснение
Мы начинаем с преобразования списка в Max Heap – бинарное дерево, где самым большим элементом является корневой узел. Затем мы помещаем этот элемент в конец списка. Затем мы восстанавливаем нашу Max Heap, которая теперь имеет на одно меньшее значение, помещая новое наибольшее значение перед последним элементом списка.
Мы повторяем этот процесс построения кучи, пока все узлы не будут удалены.
Реализация
Мы создаем вспомогательную функцию heapify для реализации этого алгоритма:
Сложность
В среднем сложность сортировки кучи составляет O(nlog (n)), что уже значительно быстрее, чем в предыдущих алгоритмах.
Сортировка слиянием (Merge Sort)
Этот алгоритм «разделяй и властвуй» разбивает список пополам и продолжает разбивать список на пары, пока в нем не будут только одиночные элементы.
Соседние элементы становятся отсортированными парами, затем отсортированные пары объединяются и сортируются с другими парами. Этот процесс продолжается до тех пор, пока мы не получим отсортированный список со всеми элементами несортированного списка.
Объяснение
Мы рекурсивно разделяем список пополам, пока не получим списки с одиночным размером. Затем мы объединяем каждую половину, которая была разделена, и при этом сортируя их.
Сортировка осуществляется путем сравнения наименьших элементов каждой половины. Первый элемент каждого списка сравнивается с первым. Если первая половина начинается с меньшего значения, то мы добавляем ее в отсортированный список. Затем мы сравниваем второе наименьшее значение первой половины с первым наименьшим значением второй половины.
Каждый раз, когда мы выбираем меньшее значение в начале половины, мы перемещаем индекс, элемент которого нужно сравнить на единицу.
Реализация
Обратите внимание, что функция merge_sort(), в отличие от предыдущих алгоритмов сортировки, возвращает новый отсортированный список, а не сортирует существующий список.
Поэтому для сортировки слиянием требуется пространство в памяти для создания нового списка того же размера, что и входной список.
Сложность
В среднем сложность сортировки слиянием составляет O(nlog (n)).
Быстрая сортировка (Quick Sort)
Это то же алгоритм «разделяй и властвуй» и его наиболее часто используют их описанных в этой статье. При правильной настройке он чрезвычайно эффективен и не требует дополнительного пространства памяти как сортировка слиянием. Мы разделяем список вокруг элемента точка опоры, сортируя значения вокруг этой точки.
Объяснение
Быстрая сортировка начинается с разбиения списка – выбора одного значения списка, которое будет в его отсортированном месте. Это значение называется опорным. Все элементы, меньшие, чем этот элемент, перемещаются влево. Все более крупные элементы перемещены вправо.
Зная, что опорный элемент находится на своем правильном месте, мы рекурсивно сортируем значения вокруг этого элемента, пока не будет отсортирован весь список.
Реализация
Сложность
В среднем сложность быстрой сортировки составляет O(nlog (n)).
Примечание. Алгоритм быстрой сортировки будет работать медленно, если опорный элемент будет наименьшим или наибольшим элементом списка. Быстрая сортировка обычно работает быстрее с более сбалансированными значениями. В отличие от сортировки кучи и сортировки слиянием, обе из которых имеют худшие времена O(nlog (n)), быстрая сортировка имеет худшее время O(n^2).
Встроенные функции сортировки Python
Хотя полезно знать и понимать эти алгоритмы сортировки, в большинстве проектов Python вы, вероятно, будете использовать встроенную функцию сортировки.
Создадим новый список, чтобы отсортировать его содержимое с помощью метода sort():
Или мы можем использовать функцию sorted() для создания нового отсортированного списка:
Они оба сортируются в порядке возрастания, но вы можете легко отсортировать в порядке убывания, установив для флага реверса в значение True:
В отличие от созданных нами функций алгоритма сортировки, обе эти функции могут сортировать списки кортежей и классов. Функция sorted() может сортировать любой итеративный объект, который включает в себя – списки, строки, кортежи, словари, наборы (set) и пользовательские итераторы.
Встроенная функция сортировки реализуют алгоритм сортировки Тима. Этот алгоритм, основан на сортировке слиянием и сортировке вставкой.
Сравнение скорости
Чтобы понять, как быстро работают рассмотренные алгоритмы, мы сгенерируем список из 5000 чисел от 0 до 1000. Затем мы определим время, необходимое для завершения каждого алгоритма. Повторим это 10 раз, чтобы мы могли более надежно установить производительность сортировки.
Вот какие результаты мы получили, время в секундах:
Run | Bubble Пузырьковая |
Selection Выбором |
Insertion Вставкой |
Heap Пирамидальная |
Merge Слиянием |
Quick Быстрая |
---|---|---|---|---|---|---|
1 | 5.531886100769043 | 1.2315289974212646 | 1.6035542488098145 | 0.04006671905517578 | 0.0261991024017334 | 0.016391992568969727 |
2 | 4.921762228012085 | 1.2472858428955078 | 1.5910329818725586 | 0.03999590873718262 | 0.025842905044555664 | 0.01661396026611328 |
3 | 4.916421890258789 | 1.2244019508361816 | 1.5936298370361328 | 0.044072866439819336 | 0.028622865676879883 | 0.01646280288696289 |
4 | 5.154704332351685 | 1.2505383491516113 | 1.6346361637115479 | 0.04128289222717285 | 0.028828144073486328 | 0.01860785484313965 |
5 | 4.955228805541992 | 1.2898740768432617 | 1.61759614944458 | 0.04515719413757324 | 0.033148765563964844 | 0.01885080337524414 |
6 | 5.049072980880737 | 1.2546651363372803 | 1.625154972076416 | 0.042572975158691406 | 0.02595210075378418 | 0.01628708839416504 |
7 | 5.05591893196106 | 1.2491188049316406 | 1.6198101043701172 | 0.040289878845214844 | 0.027335166931152344 | 0.017602920532226562 |
8 | 5.087991952896118 | 1.2580881118774414 | 1.6260371208190918 | 0.04264688491821289 | 0.02633810043334961 | 0.017055988311767578 |
9 | 5.032891750335693 | 1.2491509914398193 | 1.6144649982452393 | 0.04302191734313965 | 0.032937049865722656 | 0.0176239013671875 |
10 | 5.142928838729858 | 1.2202110290527344 | 1.5727391242980957 | 0.03966116905212402 | 0.0257260799407959 | 0.016061067581176758 |
Avg | 5.084880781173706 | 1.2474863290786744 | 1.6098655700683593 | 0.04187684059143067 | 0.02809302806854248 | 0.017155838012695313 |
Вы можете получить другие значения, если попробуете повторить тест самостоятельно, но общее соотношение должно быть одинаковым или похожим. Пузырьковая сортировка (Bubble Sort) – самая медленная и наихудшая из всех алгоритмов. Хотя она очень полезно в качестве введения в изучения алгоритмов сортировки, оно не подходит для практического использования.
Мы также заметили, что быстрая сортировка выполняется очень быстро, почти в два раза быстрее, чем сортировка слиянием, и для ее работы не требуется много памяти. Напомним, что наш опорный элемент был основан на среднем элементе списка, разные опорные элементы могут дать разные результаты.
Поскольку сортировка вставкой выполняет намного меньше сравнений, чем сортировка выбором, то обычно она выполняются быстрее, но в нашем тесте сортировка выбором выполнилась немного быстрее.
Сортировка вставкой делает гораздо больше замен, чем сортировка выбором. Скорее всего обмен значениями занял значительно больше времени, чем сравнение значений, поэтому мы получили этот «противоположный» результат.
При выборе алгоритма сортировки следует помнить о самих данных и среде запуска алгоритмов, так как это тоже влияет на производительность.
Заключение
Алгоритмы сортировки дают нам много способов упорядочить наши данные. Мы рассмотрели 6 различных алгоритмов – Bubble Sort, Selection Sort, Insertion Sort, Merge Sort, Heap Sort, Quick Sort – и их реализации в Python.
Количество сравнений и перестановок, которые выполняет алгоритм вместе со средой, в которой выполняется код, являются ключевыми определяющими факторами производительности. В реальных приложениях Python рекомендуется придерживаться встроенных функций сортировки Python из-за их гибкости и скорости.
Сортировки в гифках: 8 самых популярных алгоритмов
Сортировка пузырьком (обменная сортировка) – простой в реализации и малоэффективный алгоритм сортировки. Метод изучается одним из первых на курсе теории алгоритмов, в то время как на практике используется очень редко.
Алгоритм состоит из повторяющихся проходов по сортируемому массиву. За каждый проход элементы последовательно сравниваются попарно и, если порядок в паре неверный, выполняется обмен элементов. Проходы по массиву повторяются раз или до тех пор, пока на очередном проходе не окажется, что обмены больше не нужны, что означает — массив отсортирован. При каждом проходе алгоритма по внутреннему циклу, очередной наибольший элемент массива ставится на своё место в конце массива рядом с предыдущим «наибольшим элементом», а наименьший элемент перемещается на одну позицию к началу массива («всплывает» до нужной позиции как пузырёк в воде, отсюда и название алгоритма).
Худшее время | ||||
---|---|---|---|---|
Лучшее время | ||||
Среднее время | ||||
Затраты памяти |
Худшее время |
---|
Лучшее время |
Среднее время |
Затраты памяти |