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

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

шагов, поскольку он должен будет поочередно рассмотреть каждый элемент списка — каждый из n элементов. Таким образом, любой алгоритм сортировки будет иметь сложность как минимум O(n). Добиться результата лучше O(n) невозможно, но можно ли улучшить сложность O(n2) сортировки методом вставки? Да, можно. Сейчас мы рассмотрим алгоритм со сложностью O(n log(n)) — значительное улучшение по сравнению с сортировкой методом вставки.


Сортировка слиянием

Алгоритм сортировки слиянием намного быстрее сортировки методом вставки. Как и сортировка методом вставки, сортировка слиянием состоит из двух частей: одна объединяет два списка (слияние), а другая многократно использует слияние для выполнения фактической сортировки.

Прежде чем переходить к сортировке, рассмотрим сам процесс слияния. Допустим, имеются две полки с папками, каждая из которых отсортирована, но содержимое одной полки не сравнивалось с содержимым другой. Требуется объединить содержимое полок на одной итоговой полке, которая будет полностью отсортирована. Назовем эту операцию слиянием двух отсортированных полок. Как подойти к решению этой задачи?

И снова стоит подумать, как бы вы подошли к решению этой задачи с настоящими полками, прежде чем запускать Python и браться за программирование. Представьте, что вы стоите перед тремя полками: двумя заполненными и отсортированными, содержимое которых требуется объединить, и третьей пустой, на которую будут вставляться папки и которая в конечном счете будет содержать все папки с двух исходных полок. Для удобства будем называть две исходные полки левой и правой (предполагается, что они стоят слева и справа от вас).


Слияние

Чтобы выполнить слияние, возьмем первую папку с каждой из двух исходных полок: с левой полки в левую руку, а с правой полки — в правую. Папка с меньшим номером ставится на новую полку первой. Чтобы определить вторую папку для новой полки, снова возьмем первые папки с левой и правой полок, сравним их и вставим меньшую на последнюю позицию новой полки. Когда левая или правая полка опустеет, мы берем оставшиеся файлы на непустой полке и размещаем их все вместе в конце новой полки. После этого новая полка будет содержать все файлы с левой и правой полки, отсортированные по порядку. В результате содержимое двух исходных полок будет успешно объединено.

В коде Python переменные left и right будут представлять исходные отсортированные полки. Мы также определим список newcabinet, который изначально пуст, а после выполнения будет содержать полный упорядоченный набор всех элементов left и right.

newcabinet = []

Определим исходные списки, которым будут присвоены имена left и right:

left = [1,3,4,4,5,7,8,9]

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

Для сравнения соответствующих первых элементов списков left и right будут использоваться следующие команды if, которые можно будет выполнить только после заполнения секций --...--:

if left[0] > right[0]:

--...--

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

--...--

Если первый элемент списка left меньше первого элемента списка right, то нужно извлечь этот элемент из левого списка и вставить его в newcabinet, и наоборот. Для выполнения этой операции можно воспользоваться встроенной функцией Python pop(), которая вставляется в команду if следующим образом:

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)

Этот процесс — проверка первых элементов списков left и right и извлечение подходящего элемента в новый список — должен продолжаться, пока на обеих полках стоит хотя бы одна папка. По этой причине команды if включаются в цикл while, который проверяет минимальную длину списков left и right. Пока они содержат хотя бы один элемент, процесс продолжается:

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)

Цикл while продолжает выполняться, пока в списках left или right не закончатся элементы для вставки. В этот момент, если список left пуст, все файлы из right вставляются в конец новой полки в текущем порядке, и наоборот. Итоговая вставка может выполняться следующим образом:

if(len(left) > 0):

    for i in left:

        newcabinet.append(i)

if(len(right) > 0):

    for i in right:

        newcabinet.append(i)

Наконец, мы объединяем все эти фрагменты в итоговый алгоритм слияния на Python (листинг 4.4).


Листинг 4.4. Алгоритм слияния двух отсортированных списков

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)

    if(len(left) > 0):

        for i in left:

            newcabinet.append(i)

    if(len(right)>0):

        for i in right:

            newcabinet.append(i)

    return(newcabinet)

left = [1,3,4,4,5,7,8,9]


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

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


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

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


Java 7

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


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

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


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

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


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

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