Опубликован: 06.10.2011 | Доступ: свободный | Студентов: 1681 / 107 | Оценка: 4.67 / 3.67 | Длительность: 18:18:00
Лекция 11:

Проектирование и инженерия алгоритма: топологическая сортировка

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

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

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

10.1. Постановка задачи

Вы решили сегодняшний день посвятить культуре: что может быть лучше, чем посещение Лувра и музея Орсе в Париже? Но для этого вам понадобится карта, и нужно приобрести проездной на метро, поскольку срок старого уже истек, но для проездного нужны деньги, так что придется зайти в банк или воспользоваться банкоматом. Можно выразить эти ограничения следующим образом:

[Map, Louvre], [Map, Orsay], [Pass, Louvre], [Pass, Orsay], [Money, Pass]
    

Здесь каждое ограничение задается парой [x, y], означающей, что "x должно случиться прежде чем y". Это можно отобразить графически:

Упорядочение ограничений

Рис. 10.1. Упорядочение ограничений

Топологической сортировкой множества элементов, подчиняющихся ограничениям порядка, называется перечисление элементов в порядке, удовлетворяющем ограничениям. В данном примере топологическими сортировками являются последовательности:

Money, Pass, Map, Louvre, Orsay
Map, Money, Pass, Orsay, Louvre
Money, Map, Pass, Louvre, Orsay
    

Заметьте: последовательность Pass, Money, Map, Louvre, Orsay некорректна, поскольку нарушается ограничение [Money, Pass].

Задача топологической сортировки может иметь:

  • несколько решений, как в данном примере;
  • в точности одно решение;
  • ни одного решения, как было бы, в случае если и только если ограничения образовывали бы цикл – множество ограничений: [e_1,e_2], [e_2, e_3], \ldots [e_n, e_1] для некоторого n >= 1. Если мы добавим в наш пример ограничение [Orsay, Money], создавая тем самым цикл, то никакого решения больше существовать не будет, так как мы, с одной стороны, требуем, чтобы "утром – стулья, вечером – деньги", а с другой стороны, требуем "деньги вперед".

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

Примеры применения

Задача топологической сортировки возникает всякий раз, когда требуется упорядочить элементы при некоторых ограничениях на их порядок следования. Вот несколько примеров.

  • Для графического дисплея рассмотрим окна – графические прямоугольники, которые могут пересекаться. Нам необходим алгоритм, рисующий эти прямоугольники с учетом их наложения друг на друга. Это задача топологической сортировки. Зададим следующие ограничения: [B, A], [D, A], [D, C], [B, D], [E, C]. Здесь ограничение [x, y] содержательно означает "x не должно скрывать никакую часть y". Возможным решением является последовательность: B, D, E, A, C.
    Прямоугольники с ограничением предшествования

    Рис. 10.2. Прямоугольники с ограничением предшествования
  • При промышленной сборке сложных изделий – турбины или самолета – множество задач по управлению сборкой сопровождается ограничениями, например, структурная работа над элементом должна предшествовать его окраске. Топологическая сортировка дает расписание, совместимое с этими ограничениями.
  • Подобная задача возникает при управлении проектами, особенно при управлении программными проектами. Если проект связан с некоторой проблемной областью, то он должен сопровождаться глоссарием (словарем) технических терминов (непонимание между экспертами проблемной области и разработчиками ПО является главным источником ошибок и провалов). Определение любого термина может ссылаться на другие термины. Термины в словаре могут идти в алфавитном порядке, как принято в словарях, но также полезно иметь версию словаря, которая может читаться в последовательности, где каждый термин объясняется через уже определенные термины. Создание такого словаря предполагает топологическую сортировку.
  • При описании класса вы, возможно, хотели бы, чтобы его компоненты шли в порядке, гарантирующем, что никакой вызов компонента не встречается до его описания1В некоторых языках программирования таково требование синтаксиса. Но взаимная рекурсия методов, когда А вызывает В, а В вызывает А, приводит к циклу, так что в язык приходится вводить специальные конструкции предварительного объявления (предварительно объявляется В, затем объявляется А, затем дается полное объявление В). .
  • Топологическая сортировка позволяет улучшить эффективность компиляции ОО-программ при реализации наследования и в особенности – динамического связывания, обсуждаемого в последующих лекциях. Проблема актуальна для больших программ со многими классами и состоит в нумерации классов таким образом, чтобы номер, приписанный классу, был близок к номерам классов, являющихся его потомками – классами, которые наследуют от него прямо или косвенно. Используя "наследует от" как отношение порядка, компилятор EiffelStudio, основываясь на топологической сортировке, достигает существенной оптимизации требуемой памяти, что является основой жизнеспособности ОО-подхода.

Точки на плоскости

Вот пример, дающий удобную визуализацию задачи. Рассмотрим точки на плоскости:

Конечное множество точек

Рис. 10.3. Конечное множество точек

Введем для точек p_1 с координатами (x_1, y_1) и p_2 с координатами (x_2, y_2) отношение \ll ("строго меньше"), устанавливающее, что p_1 \ll p_2, если:

  • x_1 \le x_2;
  • y_1 \le y_2;
  • p_1 \ne p_2 (точки не совпадают).

Для четырех точек, показанных на рисунке, справедливо следующее:

a\ll b\qquad\qquad a\ll d\qquad\qquad b\ll d\qquad\qquad c\ll d

Топологическая сортировка для этого отношения дает любое перечисление точек, для которого если p « q, то в списке перечисления p предшествует q. Для наших четырех точек существуют три таких перечисления:

a, b, c, d
a, c, b, d
c, a, b, d
        

Три возможных обхода точек можно визуализировать:

Три типологических сортировки множества точек

Рис. 10.4. Три типологических сортировки множества точек

С другой стороны, перечисление a, d, b, c не совместимо с отношением, поскольку свойство c « d требует, чтобы c предшествовало d.

10.2. Основы топологической сортировки

Задача, обсуждаемая в этой главе, имеет точную математическую формулировку.

Определение: задача топологической сортировки
Для заданного на конечном множестве ациклического отношения r требуется найти отношение полного порядка, для которого r является подмножеством.

Это определение использует математические понятия – отношения как множества, ациклические отношения, отношения порядка (полного или частичного), которые теперь предстоит рассмотреть.

Бинарные отношения

Определение: отношение
Отношение на множестве А (для простоты рассматривается только бинарное отношение) задается множеством пар в форме [x, y], где оба элемента пары являются элементами А.

Примером отношения на множестве {1, 2, 3} является:

{[1, 2], [1, 3], [2, 3]}
        

Мы можем назвать это отношением < ("меньше", так как x и y принадлежат множеству {1, 2, 3} и x меньше y).

Мы можем использовать отношения для описания предыдущих примеров.

  • Отношение below (ниже) на множестве прямоугольников, содержащее все пары прямоугольников [x, y], таких, что в области наложения прямоугольников должны показываться точки y, а не x.
  • Отношение before (прежде) – множество пар {[Map, Louvre], [Map, Orsey], …} – является отношением на множестве {Pass, Money, Map, Louvre, Orsay}, содержащим пары [x, y], такие, что событие x должно произойти раньше y.
  • Отношение used_in ("используется в"), заданное на множестве терминов словаря, содержит все пары [x, y], такие, что определение термина y содержит термин x.
  • Отношение called_by ("вызывается в"), заданное на множестве методов класса, содержит все пары [x, y], такие, что тело метода y содержит вызов метода x.
  • Отношение « над точками – множество пар {[a, b], [a, d], [b, d], [c, d]}.

Ациклические отношения

Все наши примеры были до сих пор ациклическими отношениями. Это понятие определяется следующим образом:

Определение: ациклическое отношение
Отношение является ациклическим, если у него нет циклов.

Это определение следует дополнить.

Определение: цикл в отношении
Циклом для отношения r над множеством A является последовательность x_1,\;\ldots x_m (m\ge 2) из элементов A, такая, что все последовательные пары [x_i,x_{i+1}] для 1\le i < m принадлежат r, и x_m = x_1.

Отношение before, введенное ранее, циклов не имеет:

Отношение, описывающее ограничение порядка

Рис. 10.5. Отношение, описывающее ограничение порядка
Простейший случай цикла для отношения r встречается (при m = 2) для элемента x, такого, что [x, x] принадлежит r.

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

Теорема об отсутствии предшественника
Для любого ациклического отношения r над непустым, конечным множеством А существует элемент x из А, не имеющий предшественника в r.
Определение: предшественник
Предшественником элемента y для отношения r является элемент x, такой, что пара [x, y] принадлежит r.

Теорема доказывается от противного. Предположим противное, что каждый элемент в А имеет по меньшей мере одного предшественника. Пусть x_1 – элемент из А (он существует, так как множество не пусто). По предположению, у него есть хоть один предшественник, выберем любой и назовем его x_2. По тем же причинам есть предшественник x_3 и у x_2, так что в r существует пара [x_3, x_2]. Продолжая вывод, следует признать существование бесконечной последовательности [x_{i+1}, x_i], принадлежащей r для каждого i >= 1. Поскольку А – конечное множество, последовательность должна иметь повторяющиеся элементы. Более точно: у последовательности x_1, x_2, \ldots x_{n+1}, где n – число элементов A, все элементы не могут быть различными; поэтому должны быть целые i и j, для 1\le i<j\le n+1, такие, что x_i = x_j, но тогда последовательность x_j, x_{j-1}, \ldots x_i является циклом. Пришли к противоречию.

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

Предположение о конечности множества А существенно. Теорема неприменима к бесконечным множествам, например, отношение "меньше" для целых чисел в математике ациклическое, но каждый его элемент имеет предшественника.

Отношения порядка

Идея топологической сортировки встраивает данное ациклическое отношение в отношение полного (тотального) порядка. Для определения этого понятия предварительно определим простое отношение порядка.

Определение: отношение порядка (строгое, возможно частичное)
Отношение является отношением порядка, если оно удовлетворяет следующим свойствам для любых элементов x, y, z из множества X, на котором оно определено.
О1 Антирефлексивность: отношение не имеет пар вида [x,x].
O2 Транзитивность: из того, что отношению принадлежат пары [x, y] и [y, z], следует, что отношению принадлежит и пара [x, z].

Такое отношение порядка является также:

О3 асимметричным: из того, что отношению принадлежит пара [x, y] следует, что отношению не принадлежит пара [y, x].

(Доказательство. Если бы обе пары принадлежали отношению, то из транзитивности следовала бы рефлексивность – существование пары [x, x], что противоречит свойству антирефлексивности)

Полное имя для отношения порядка – строгое, возможно частичное отношение порядка. Наши отношения порядка (вскоре мы познакомимся с полным или тотальным отношением) являются строгими, в том же смысле, как отношение < – "строго меньше, чем". Также возможно работать с нестрогими версиями отношения, такими как отношение <= ("меньше или равно").

Отношение "<" на {1, 2, 3} (или на любом другом множестве целых) является отношением порядка. Таким же является отношение « на точках. Наши другие ациклические отношения – before для задач, used_in для терминов, called_by для методов – антирефлексивны и асимметричны, но они не обязательно транзитивны, так что они не являются отношениями порядка. Вскоре мы увидим, как можно получить транзитивную версию.

Отношения порядка в сравнении с ациклическими отношениями

Отношения порядка тесно связаны с ациклическими отношениями. В одном направлении эта связь – прямая.

Теорема: "Ацикличность и отношение порядка" (1)
Любое отношение порядка (более того, любое его подмножество) ациклично.

Доказательство от противного. Предположим, существует цикл x_1, x_2, \ldots x_n, где x_n то же, что и x_1. По транзитивности это влечет рефлексивность, что противоречит антирефлексивности.

Это обобщает доказательство асимметрии: невозможность иметь обе пары [x,y] и [y, x]. Такой случай является частным случаем цикла с двумя элементами. Подобно, пара [x, x], нарушающая антирефлексивность, является циклом с одним элементом.

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

Это может быть проиллюстрировано на отношении before, выражающего ограничения порядка между задачами. Отношение антирефлексивно, асимметрично и ациклично, но оно не транзитивно, поскольку содержит пары [Money, Pass] и [Pass, Louvre], но не содержит пары [Money, Louvre]. Мы можем расширить отношение до транзитивного, добавив все пары вида [x, z], для которых в исходном отношении есть пары [x, y] и [y, z], выполняя эту операцию, пока добавление не перестанет быть возможным. Результатом этого процесса является транзитивное замыкание исходного отношения. Для нашего примера добавятся ровно две связи:

Транзитивное замыкание ограничений порядка

Рис. 10.6. Транзитивное замыкание ограничений порядка

Для отношения called_by между процедурами транзитивное замыкание является отношением, которое выполняется между x и y, если у вызывает x прямо или косвенно. Для отношения child между людьми, обозначающего множество пар [x, y], таких, что x является потомком y, транзитивное замыкание служит отношением, связывающим двух людей, таких, что один из них является потомком, непосредственным или косвенным – прапраправнуком. Транзитивное замыкание отношения r обозначается как r^+, так что мы можем полагать, что child^+ = descendant (потомок представляет транзитивное замыкание отношения "потомок").

Определение: транзитивное замыкание отношения
Транзитивным замыканием отношения r на множестве А является отношение, содержащее все пары вида [x_1, x_m] для некоторой последовательности элементов x_1, x_2, \ldots x_m (m >= 2), такой, что пары [x_i, x_{i+1}] для 1 <= i <= m принадлежат r.

Транзитивное замыкание высвечивает другую сторону отношения между ацикличностью и порядком.

Теорема: "Ацикличность и отношение порядка" (2)
Транзитивное замыкание любого ациклического отношения является отношением порядка.

Доказательство. Транзитивное замыкание любого отношения r очевидно транзитивно. Так что нам остается доказать антирефлексивность. Предположим, что это не так и существует элемент x, такой, что пара [x, x] принадлежит r^+. По определению транзитивного замыкания существует последовательность x_1, x_2, … x_m (m >= 2), такая, что все пары [x_i, x_{i+1}] для 1<= i <= m принадлежат r и что x_1 и x_m равны x. Но это означает существование цикла для r. Пришли к противоречию.

Этот результат позволяет нам рассматривать ациклическое отношение как "ядро" отношения порядка. Взятие транзитивного замыкания дает нам настоящее отношение порядка. Это соответствует интуитивному пониманию отношения, например, такого как before между стоящими перед нами задачами, – если задача Money должна предшествовать задаче Pass, а задача Pass должна предшествовать задаче Louvre, то мы понимаем, что задача Money должна предшествовать задаче Louvre. Другими словами, мы инстинктивно принимаем транзитивное замыкание. Но когда готовятся входные данные для задачи расписания или для другой задачи, в которой предполагается топологическая сортировка, то, естественно, хотелось бы перечислить только базисные ограничения, а не полное транзитивное замыкание. Вот почему топологическая сортировка может использовать ациклическое отношение на входе (многие представления топологической сортировки начинают с отношения порядка, но это избыточное требование, более строгое, чем требуется).

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