Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конец главы 3.doc
Скачиваний:
13
Добавлен:
05.11.2018
Размер:
926.21 Кб
Скачать

3.8. Приложения и обобщения алгоритма объединить–найти

Мы уже видели, как в задаче построения остовного дерева, описанной в примере 3.1, естественно возникает последовательность основных операций ОБЪЕДИНИТЬ и НАЙТИ. В этом разделе мы познакомимся с несколькими другими задачами, которые приводят к последовательностям операций ОБЪЕДИНИТЬ и НАЙТИ. В нашей первой задаче надо осуществить вычисления в свободном режиме, т. е. прочесть всю последовательность операций перед выдачей каких бы то ни было ответов.

Приложение 1. MIN-задача в свободном режиме

Даны два типа операций: ВСТАВИТЬ(i) и ИЗВЛЕЧЬ_MIN. Начнем с множества S, вначале пустого. Каждый раз, когда встречается операция ВСТАВИТЬ(i), целое число i помещается в S. Каждый раз, когда выполняется операция ИЗВЛЕЧЬ_МIN, разыскивается и удаляется наименьший элемент в S.

Пусть такая последовательность операций ВСТАВИТЬ и ИЗВЛЕЧЬ_MIN, что для каждого операция ВСТАВИТЬ(i) встречается не более одного раза. По данной последовательности надо найти последовательность целых чисел, удаляемых операцией ИЗВЛЕЧЬ_MIN. Задача решается в свободном режиме, поскольку предполагается, что вся последовательность известна до того, как надо вычислить даже первый элемент выходной последовательности.

MIN-задачу в свободном режиме можно решить следующим методом. Пусть kчисло операций ИЗВЛЕЧЬ_МIN в . Можно записать  в виде , где каждая подпоследовательность

for I 1 until n do

begin

j НАЙТИ(i);

if jk then

begin

print i "удаляется j-й операцией ИЗВЛЕЧЬ_MIN";

ОБЪЕДИНИТЬ(j, СЛЕД[j], СЛЕД[j]);

СЛЕД[ПРЕД[j]] <– СЛЕД[j];

ПРЕД[СЛЕД[j]] <– ПРЕД[j]

end

end

Рис. 3.23. Программа для решения MIN-задачи в свободном режиме.

, состоит только из операций ВСТАВИТЬ, а Е обозначает операцию ИЗВЛЕЧЬ_МIN. Промоделируем  с помощью алгоритма 3.3. Начальная последовательность множеств для работы алгоритма объединения строится так: если в последовательности ; встречается операция ВСТАВИТЬ(i), то считаем, что множество с именем , содержит элемент i. Для того чтобы для тех значений j, для которых существует множество с именем j, образовать дважды связанный упорядоченный список, пользуемся двумя массивами ПРЕД и СЛЕД. Вначале ПРЕД[j] = j - 1 для 1  j k + 1 и СЛЕД[j] = j + 1 для 0 j k. Затем выполняется программа, приведенная на рис. 3.23.

Легко видеть, что время выполнения этой программы ограничено временем работы алгоритма объединения множеств. Следовательно, MIN-задача в свободном режиме имеет временную сложность O(nG(n)).

Пример 3.8. Рассмотрим последовательность операций  = 4 3 E 2 Е 1 E, где j означает ВСТАВИТЬ(j), а Е– ИЗВЛЕЧЬ_MIN. Тогда (1 = 4 3, 2 = 2, 3 = 1 и 4 пустая последовательность. Начальная структура данных представляет собой последовательность множеств

1={3, 4}, 2={2}, 3={1}, 4 = .

При первом выполнении for-цикла выясняется, что НАЙТИ(1) = 3. Следовательно, ответом на третью операцию в  ИЗВЛЕЧЬ_MIN будет 1. Последовательность множеств превращается в

1 = {3, 4}, 2 = {2}, 4={1}.

В этот момент СЛЕД[2] = 4 и ПРЕД[4] = 2, поскольку множества с именами 3 и 4 были слиты в одно множество с именем 4.

При следующем прохождении с i = 2 выясняется, что НАЙТИ(2) = 2. Таким образом, ответом на вторую операцию ИЗВЛЕЧЬ_МIN будет 2. Множество с именем 2 сливается со следующим множеством (с именем 4) и получается последовательность множеств

1 = {3, 4}, 4 = {1, 2}.

Два последних прохождения устанавливают, что ответ на первую операцию ИЗВЛЕЧЬ_МIN есть 3 и что 4 никогда не извлекается. 

Рассмотрим другое приложение – задачу определения глубины. В частности, она возникает при "приравнивании" идентификаторов в программе на языке ассемблера. Во многих языках ассемблера есть операторы, описывающие, что два идентификатора представляют одну и ту же ячейку памяти. Как только ассемблер встречает оператор, приравнивающий два идентификатора  и , он должен найти два множества S и S идентификаторов, эквивалентных соответственно  и , и заменить эти два множества их объединением. Очевидно, задачу можно смоделировать последовательностью операций ОБЪЕДИНИТЬ И НАЙТИ.

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