Оригинал: Exercise OnClickListener
Переводчик: Феликс Ли
Лицензия: CC BY-NC-SA 4.0
Гордо использует Google Translate
Теперь вы попробуете реализовать алгоритмы сортировки для вашего DoubleLinkedList
данных. Для этих описаний я буду использовать "числовой список" для представления случайного списка объектов. Это может быть колода карт, список чисел на бумаге, список имён или что угодно другое, что можно отсортировать. Когда вы пытаетесь отсортировать числовой список, обычно есть три варианта:
Сортировка пузырьком
Если вы ничего не знаете о сортировках, это наиболее вероятный вариант, который вы попробуете. Он просто включает прохождение по списку и обмен любых неправильно расположенных пар. Вы продолжаете проходить по списку, менять местами пары до тех пор, пока не перестанете делать какие-либо замены. Легко понять, но особенно медленный.
Быстрая сортировка
Этот метод также известен как "сортировка Хоара". Она работает путём выбора опорного элемента, разделения списка на две части — элементы меньше опорного и элементы больше опорного, а затем рекурсивной сортировки каждой части. Быстрая сортировка эффективна и часто используется благодаря своей скорости.
Сортировка слиянием
Этот метод сортировки работает путём деления списка на более мелкие части, сортировки этих частей и последующего объединения их обратно в один отсортированный список. Этот подход обеспечивает стабильность и эффективность при работе с большими данными.> Этот алгоритм сортировки делит список пополам, затем на четыре части, пока он больше не может быть разделён. Затем он объединяет эти части обратно, но при этом проверяет порядок каждой части, чтобы правильно выполнить операцию. Это умный алгоритм, хорошо работающий со связными списками, но не очень эффективный для массивов фиксированной размерности, так как вам нужна некоторая очередь для отслеживания частей.> Быстрая сортировка
Это похоже на сортировку слиянием, потому что это "разделяй и властвуй" алгоритм, но принцип заключается в том, чтобы менять местами элементы вокруг точки разделения, а не разделять и объединять список. В самом простом виде вы выбираете диапазон от нижней границы до верхней и точку разделения. Затем меняете местами элементы выше точки разделения, если они больше её, и ниже, если меньше. Затем выбираете новую нижнюю границу, верхнюю и точку разделения, находящиеся внутри нового неотсортированного списка, и повторяете процесс. Она делит список на меньшие блоки, но не разделяет его таким образом, как сортировка слиянием.
процедура bubbleSort(A : список сортируемых элементов)
n = длина(A)
повторять
swapped = false
для i = 1 до n-1 включительно делать
/* Если эта пара элементов расположена неправильно */
если A[i-1] > A[i] то
/* Обменять их местами и помнить об этом */
swap(A[i-1], A[i])
swapped = true
конец если
конец для
пока swapped
конец процедуры
```Вы заметите, что псевдокод представляет собой лишь приближенное описание алгоритма, которое может сильно различаться от одного источника к другому — книг, авторов или страниц Википедии. Он предполагает, что вы можете прочитать этот "контур" программы и адаптировать его под свои нужды. Иногда это может напоминать старый язык программирования Algol, а иногда выглядеть как некорректно оформленный JavaScript или Python. Вам просто нужно догадываться о значении этого контура и переводить его в нужный вам формат. Вот мой начальный перевод данного конкретного псевдокода:
```py
def bubble_sort(numbers):
"""Сортирует список чисел методом пузырьковой сортировки."""
while True:
# Начнём с предположения, что список уже отсортирован
is_sorted = True
# Будем сравнивать пары элементов, пропустив первый элемент
node = numbers.begin.next
while node:
# Пройдёмся по списку и сравним текущий элемент со следующим
if node.prev.value > node.value:
# Если предыдущий элемент больше, меняем их местами
node.prev.value, node.value = node.value, node.prev.value
# Это значит, что нам потребуется ещё один проход по списку
is_sorted = False
node = node.next
# Если мы сделали полный проход по списку и ничего не поменяли,
# значит он уже отсортирован
if is_sorted: break
```Я добавил эти комментарии, чтобы вы могли учиться и следовать за процессом. Сравните, что я сделал здесь, с исходным псевдокодом. Также обратите внимание, что структура данных, используемая на страницах Википедии, отличается от `DoubleLinkedList`. Код Википедии предполагает работу с массивами или списками. Вам следует заменить эту строчку:
```python
if A[i-1] > A[i] then
на использование DoubleLinkedList
, переведенное на Python:
if node.prev.value > node.value:
Мы не можем легко случайно обращаться к элементам DoubleLinkedList
, поэтому нам нужно преобразовать операции с индексами массива в .next
и .prev
. В цикле также важно проверять, являются ли свойства next
или prev
равными None
. Этот переход требует много времени для перевода, обучения и догадок относительно того, что именно имеется в виду в данном псевдокоде.
Теперь вы должны потратить время на изучение этого Python-кода bubble_sort
, чтобы понять, как я его реализовал. Убедитесь, что вы просмотрели моё видео в реальном времени и получили больше контекста. Вы также должны создать графики выполнения алгоритма на различных типах списков (отсортированных, случайных, с повторами и т.д.). Как только вы поймёте, как это сделано, проведите исследование pytest
и алгоритма merge_sort
:
import sorting
from dllist import DoubleLinkedList
from random import randint
``````markdown
max_numbers = 30
def random_list(count):
numbers = DoubleLinkedList()
for i in range(count, 0, -1):
numbers.shift(randint(0, 10000))
return numbers
def is_sorted(numbers):
node = numbers.begin
while node and node.next:
if node.value > node.next.value:
return False
else:
node = node.next
return True
def test_bubble_sort():
numbers = random_list(max_numbers)
sorting.bubble_sort(numbers)
assert is_sorted(numbers)
def test_merge_sort():
numbers = random_list(max_numbers)
sorting.merge_sort(numbers)
assert is_sorted(numbers)
Этот тестовый код включает важную часть, где используется функция `random.randint` для генерации случайных данных для тестирования. Этот тест не проверяет многие граничные случаи, но это начало, которое мы будем улучшать впоследствии. Вспомните, что вы еще не реализовали `sort.merge_sort`, поэтому вы можете не писать этот тестовый метод или закомментировать его.
Как только вы завершите тестирование и напишете этот код, снова изучите страницу Википедии, а затем попробуйте несколько других версий `bubble_sort` перед тем, как пробовать `merge_sort`.
### Слиянием сортировка
Я пока не готов был вас попросить самостоятельно её реализовать. Я повторю этот процесс для функции `merge_sort`, но на этот раз я хочу, чтобы вы попробовали реализовать алгоритм слиянием сортировки, используя псевдокод с страницы Википедии. После этого вы сможете сравнить вашу реализацию с моей.
Несколько реализаций предлагается, но я использую "сверху вниз" версию:
``````py
def merge_sort(m):
if len(m) <= 1:
return m
left = []
right = []
for i, x in enumerate(m):
if i < len(m) / 2:
left.append(x)
else:
right.append(x)
left = merge_sort(left)
right = merge_sort(right)
return merge(left, right)
def merge(left, right):
result = []
while left and right:
if left[0] <= right[0]:
result.append(left[0])
left = left[1:]
else:
result.append(right[0])
right = right[1:]
while left:
result.append(left[0])
left = left[1:]
while right:
result.append(right[0])
right = right[1:]
return result
# Для test_merge_sort напишите оставшиеся тестовые случаи функции, а затем попробуйте её реализацию.
# Вам может потребоваться способ вычисления количества узлов от данного узла.
# Это то, что DoubleLinkedList не делает.
def count(node):
count = 0
while node:
node = node.next
count += 1
return count
def сортировка_слиянием(числа):
числа.begin = слияние_узел(числа.begin)
# ужасный способ получить конец
узел = числа.begin
while узел.next:
узел = узел.next
числа.end = узел
def слияние_узел(начало):
"""Сортирует список чисел методом сортировки слиянием."""
if начало.next == None:
return начало
средняя = len(начало) // 2
# сканирование до середины
сканер = начало
for i in range(0, средняя - 1):
сканер = сканер.next
# установка узла середины сразу после точки сканирования
средний_узел = сканер.next
# разрыв в точке середины
сканер.next = None
средний_узел.prev = None
слева = слияние_узел(начало)
справа = слияние_узел(средний_узел)
return слияние(слева, справа)
def слияние(слева, справа):
"""Выполняет слияние двух списков."""
результат = None
if слева == None:
return справа
if справа == None:
return слева
if значение(слева) > значение(права):
результат = справа
результат.next = слияние(слева, справа.next)
else:
результат = слева
результат.next = слияние(слева.next, справа)
результат.next.prev = результат
return результат
При попытке реализовать это, я буду использовать этот код как "памятку", чтобы быстро получить подсказки. Вы также заметите, что я пытаюсь полностью воспроизвести этот код из видео, поэтому вы можете видеть, как я стараюсь решить те же проблемы, с которыми вы могли столкнуться.### Быстрая сортировка
```Наконец, попробуйте реализовать quick_sort
и создайте тестовый случай `test_quicksort`. Я рекомендую вам начать с простой реализации быстрой сортировки с использованием обычных списков в Python. Это поможет лучше понять алгоритм. Затем используйте простой Python-код, чтобы сделать его способным работать с головным узлом `DoubleLinkedList`. Помните, что стоит потратить достаточно времени на это, а также провести множество тестов и отладочных операций в `test_quicksort`.
quick_sort
?O(n^2)
или O(n log n)
, что указывает на то, что эти алгоритмы имеют плохие временные характеристики в худшем случае. Определение "большого O" для алгоритма выходит за рамки этой книги, но мы кратко обсудим эти метрики в упражнении 18.DoubleLinkedList
? Если ты сделаешь так, тебе придется скопировать этот код для других управляемых данными структур? У нас нет такого дизайна, который позволил бы этим сортировочным алгоритмам работать со всеми "похожими на связный список" структурами данных.Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )