Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лк07 Сортировки.doc
Скачиваний:
27
Добавлен:
28.10.2018
Размер:
1.73 Mб
Скачать

Лексикографическая сортировка

Топологическая сортировка

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

Например:

  1. В словаре термин определен через другие термины. Обозначим отношением U  V, если слово U определено через слово V. Топологическая сортировка означает, что в словаре все слова, участвующие в определении данного слова, находятся раньше его.

  2. В программе процедура может содержать вызов других процедур. Обозначим отношением U  V, если процедура U вызывает процедуру V. Топологическая сортировка означает, что в программе описание всех вызываемых процедур находятся раньше описания вызывающей процедуры (понятие рекурсии здесь не рассматривается).

Определим частичный порядок на множестве S как отношение частичного порядка между элементами множества. Обозначим отношение порядка символом  (читается «предшествует»).

Отношение порядка удовлетворяет следующим трем свойствам:

  1. Если x  y и у  z , то x  z (транзитивность).

  2. Если x  y , то не у  х (ассимметричность).

  3. Не выполняется x  x (иррефлексивность).

Частичную упорядоченность множества S можно представить в виде ориентированного графа, вершины которого соответствуют элементам множества S, а дуги — отношению порядка между соответствующими вершинами (элементами).

Свойства 1 и 2 частичного порядка элементов множества гарантируют отсутствие циклов в ортографе.

Цель топологической сортировки преобразовать частичный порядок в линейный. Свойства (1) и (2) частичного порядка обеспечивают отсутствие циклов. Это и есть то необходимое условие, при котором возможно преобразование к линейному порядку.

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

Рассмотрим пример топологической сортировки на множестве чисел: S={1, 2, 3, 4, 5, 6, 7, 8, 9, 10}.

Пусть отношение частичного порядка на множестве S задано следующими отношениями элементов:

  1. 1<2

  2. 2<4

  3. 4<6

  4. 2<10

  5. 4<8

  6. 6<3

  7. 1<3

  8. 3<5

  9. 5<8

  10. 7<5

  11. 7<9

  12. 9<4

  13. 9<10

Удобно проиллюстрировать отношение частичного порядка с помощью графа, где вершины – это элементы множества, а стрелки – отношение порядка.

На графе отсутствуют циклы, что является необходимым условием частично упорядоченного множества.

Выберем элемент, которому не предшествует никакой другой – 7. Исключим его из множества. Выберем следующий элемент, которому не предшествует никакой другой – 9. И т.д.

В результате получим линейное упорядочение вида:

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

Type lref = ^leader; указатель на элемент

tref = ^trailer; указатель на последующий элемент

leader = record

key: integer; идентифицирующий ключ

count : integer; счетчик предшествующих элементов

trail : tref; указатель на список последующих элементов

next : lref; указатель на следующий элемент списка

end;

trailer = record

id : lref; указатель на элемент, являющийся последователем

next : tref; указатель на следующий элемент списка

end;

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

Head

tail

1

key

2

4

6

10

8

3

5

7

9

0

count

1

2

1

2

2

2

2

0

1

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

Будем считать, что список имеем голову (head) и хвост (tail):

function L(w: integer): lref;

var h: lref;

begin

h:= head; tail^.key:=w;

while h^.key <> w do h:= h^.next;

if h = tail then

begin

new(tail);

h^.count:= 0;

h^.trail:= nil;

h^.next:= tail;

end;

L:=h

End;

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

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

После реорганизации списка, выполненной следующим образом, список будет выглядеть так:

p:= head; head:= nil;

while p<>tail do

begin

q:= p;

p:=p^.next;

if q^.count= 0 then

begin

q^.next:= head; head:= q;

end

end;

1

7

HEAD

0

0

Program Toposort;

Type

lref = ^leader;

tref = ^trailer;

leader = record

key, count : integer;

trail : tref;

next : lref;

end;

trailer = record

id : lref;

next : tref;

end;

Var

head, tail, p, q: lref;

t: tref;

z, x, y: integer;

function L(w: integer): lref;

var h: lref;

begin

h:= head; tail^.key:=w;

while h^.key <> w do

h:= h^.next;

if h = tail then

begin

new(tail);

inc(z);

h^.count:= 0;

h^.trail:= nil;

h^.next:= tail;

end;

L:=h

end;

Begin

new(head); tail:= head;

z:= 0;

{создание структуры данных}

read(x);

while x <> 0 do

begin

read(y);

p:=L(x); q:=L(y);

new(t); t^.id:=q;

t^.next:= p^.trail;

p^.trail:= t;

inc(q^.count);

read(x);

end;

{реорганизация списка}

p:= head; head:= nil;

while p<>tail do

begin

q:= p;

p:=p^.next;

if q^.count= 0 then

begin

q^.next:= head;

head:= q;

end

end;

{проход по списку и вывод элементов, с изменением поля Count у последователей и добавлением новых элементов в список}

q:= head;

while q <> nil do

begin

writeln(q^.key);

dec(z);

t:= q^.trail;

q:= q^.next;

while t <> nil do

begin

p:= t^.id;

dec(p^.count);

if p^.count = 0

then

begin

p^.next:=q;

q:= p;

end;

t:= t^.next

end;

end;

if z <> 0 then writeln('Множество не является частично упорядоченным');

end.