Алгоритмы неформально. Инструкция для начинающих питонистов - [32]

Шрифт
Интервал

right = [2,4,6,7,8,8,10,12,13,14]

newcab=merging(left,right)

Код в листинге 4.4 создает newcab — список, содержащий все элементы left и right, объединенные и упорядоченные. Чтобы убедиться в том, что функция слияния сработала, выполните команду print(newcab).


От слияния к сортировке

Когда вы знаете, как выполнять слияние, сортировка слиянием становится доступной для понимания. Начнем с создания простой функции сортировки слиянием, которая работает только со списками из двух и менее элементов. Одноэлементный список уже отсортирован, и если он передается на вход функции сортировки слиянием, то должен просто возвращаться в неизменном виде. Если функции сортировки слиянием передается список из двух элементов, то его можно разделить на два одноэлементных списка (которые уже отсортированы по определению) и вызвать функцию слияния для этих одноэлементных списков, чтобы получить итоговый отсортированный список из двух элементов. Следующая функция Python решает эту задачу:

import math

def mergesort_two_elements(cabinet):

    newcabinet = []

    if(len(cabinet) == 1):

        newcabinet = cabinet

    else:

        left = cabinet[:math.floor(len(cabinet)/2)]

        right = cabinet[math.floor(len(cabinet)/2):]

        newcabinet = merging(left,right)

    return(newcabinet)

В этом коде синтаксис индексирования списков Python используется для разбие­ния сортируемой полки на две: левую и правую. В строках, определяющих left и right, выражения :math.floor(len(cabinet)/2) и math.floor(len(cabinet)/2): обозначают всю первую и всю вторую половину исходной полки соответственно. Эту функцию можно вызвать с любым списком, содержащим один или два элемента, — например, mergesort_two_elements([3,1]) — и убедиться в том, что она успешно возвращает отсортированный результат.

Теперь напишем функцию, которая сортирует список из четырех элементов. Если разбить список из четырех элементов на два подсписка, то каждый подсписок будет содержать два элемента. Для объединения этих списков можно воспользоваться алгоритмом слияния. Однако вспомните, что он предназначен для объединения двух уже отсортированных списков. Эти два списка могут не быть отсортированными, так что применение алгоритма слияния не обеспечит их успешной сортировки. Но каждый из подсписков содержит всего два элемента, а мы только что написали функцию, которая выполняет сортировку слиянием со списками, содержащими два элемента. Разобьем список из четырех элементов на два подсписка, вызовем функцию сортировки слиянием, которая работает с двумя двухэлементными списками, для каждого из этих подсписков, а затем выполним слияние двух отсортированных списков, получая отсортированный результат из четырех элементов. Эту задачу решает следующая функция Python:

def mergesort_four_elements(cabinet):

    newcabinet = []

    if(len(cabinet) == 1):

        newcabinet = cabinet

    else:

        left = mergesort_two_elements(cabinet[:math.floor(len(cabinet)/2)])

        right = mergesort_two_elements(cabinet[math.floor(len(cabinet)/2):])

        newcabinet = merging(left,right)

    return(newcabinet)

cabinet = [2,6,4,1]

newcabinet = mergesort_four_elements(cabinet)

Можно и дальше продолжать писать такие функции, работающие со списками все большего размера. Но настоящий прорыв наступает, когда вы осознаете, что весь процесс можно свернуть с помощью рекурсии. Возьмем функцию из листинга 4.5 и сравним ее с предыдущей функцией mergesort_four_elements().


Листинг 4.5. Реализация функции сортировки слиянием

def mergesort(cabinet):

    newcabinet = []

    if(len(cabinet) == 1):

        newcabinet = cabinet

    else:

    ❶ left = mergesort(cabinet[:math.floor(len(cabinet)/2)])

    ❷ right = mergesort(cabinet[math.floor(len(cabinet)/2):])

        newcabinet = merging(left,right)

    return(newcabinet)

Как видите, функция почти идентична функции mergesort_four_elements(). Принципиальные отличия заключаются в том, что при создании отсортированных списков left и right она не вызывает другую функцию, работающую с меньшими списками. Вместо этого она вызывает сама себя для меньшего списка ❶❷. Сор­тировка слиянием относится к категории алгоритмов «разделяй и властвуй». Мы начинаем с большого несортированного списка. Последовательно разбиваем его на фрагменты все меньшего размера, пока не получим заведомо отсортированные списки из одного элемента, после чего начинаем выполнять их слияние, пока не вернемся к одному большому отсортированному списку. Вы можете вызвать функцию сортировки слиянием для списка любого размера и убедиться в том, что она работает:

cabinet = [4,1,3,2,6,3,18,2,9,7,3,1,2.5,-9]

newcabinet = mergesort(cabinet)

print(newcabinet)

В результате объединения всего кода сортировки слиянием будет получен список 4.6.


Листинг 4.6. Полный код сортировки слиянием

def merging(left,right):

    newcabinet = []

    while(min(len(left),len(right)) > 0):

        if left[0] > right[0]:

            to_insert = right.pop(0)

            newcabinet.append(to_insert)

        elif left[0] <= right[0]:

            to_insert = left.pop(0)

            newcabinet.append(to_insert)


Рекомендуем почитать
Пользовательские истории. Искусство гибкой разработки ПО

Пользовательские истории – это метод описания требований к разрабатываемому продукту. В книге рассказано, как правильно использовать данную технику, чтобы сфокусироваться на поставленной задаче и пожеланиях клиента, а не распыляться на реализации второстепенных функций. Автор книги показывает, как данный подход не только ускоряет и систематизирует разработку, но и улучшает взаимопонимание в команде.


Программное обеспечение и его разработка

Автор книги — американский специалист по программированию, один из руководителей фирмы IBM, в своей книге делает попытку изложить общие проблемы создания программного обеспечения, его сопровождения и использования. Особенно подробно рассматриваются все фазы разработки программ разных типов. Изложение ясное, удачно иллюстрировано примерами.Для программистов разной квалификации и пользователей ЭВМ.fb2: ВНИМАНИЕ. В тексте присутствуют таблицы. Рекомендуется читать файл с помощью программы, поддерживающей их отображение.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


JavaScript для детей. Самоучитель по программированию

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


C# 4.0: полное руководство

В этом полном руководстве по C# 4.0 - языку программирования, разработанному специально для среды .NET, - детально рассмотрены все основные средства языка: типы данных, операторы, управляющие операторы, классы, интерфейсы, методы, делегаты, индексаторы, события, указатели, обобщения, коллекции, основные библиотеки классов, средства многопоточного программирования и директивы препроцессора. Подробно описаны новые возможности C#, в том числе PLINQ, библиотека TPL, динамический тип данных, а также именованные и необязательные аргументы.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.