Текст
                    В. А. Евстигнеев
В. Н. Касьянов
ТЕОРИЯ
ГРАФОВ
алгоритмы
обработки
деревьев

РОССИЙСКАЯ АКАДЕМИЯ НАУК СИБИРСКОЕ ОТДЕЛЕНИЕ ИНСТИТУТ СИСТЕМ ИНФОРМАТИКИ В. А. Евстигнеев В. Н. Касьянов ТЕОРИЯ ГРАФОВ АЛГОРИТМЫ ОБРАБОТКИ ДЕРЕВЬЕВ Ответственный редактор член-корреспондент РАН В. Е. К о т о в в ВО “НАУКА” НОВОСИБИРСК 1994
УДК 519.1 +519.683 ББК 32.811 Е26 Теория графов: алгоритмы обработки деревьев / В. А. Евстигнеев, В. Н. Касьянов. — Новосибирск: ВО "Наука”. Сибирская издательская фирма, 1994. — 360 с. ISBN 5—02—030332—1. Книга представляет собой справочник программиста и содержит систематическое из- ложение алгоритмов на деревьях, образующих один из наиболее важных и широко исполь- зуемых в программировании классов алгоритмов теории графов. Даны основные мате- матические понятия и модели, методы и алгоритмы, связанные с различными приложе- ниями теории графов. Рассмотрены задачи обходов и генерации деревьев, отыскания кар- касов, построения структурных деревьев, изоморфизма, унификации и преобразования деревьев, организации и представления информации, а также синтаксического анализа. Для специалистов по теории графов, системных и прикладных программистов, а также для специалистов по САПР, конструкторов СБИС. Табл. 5. Ил. 185. Библиогр.: 351 назв. Рецензенты доктора физико-математических наук В. К. Попков, И. В. Попипосин Утверждено к печати Институтом систем информатики СО РАН Справочное издание Евстигнеев Владимир Анатольевич Касьянов Виктор Николаевич Теория графов алгоритмы обработки деревьев Редактор Л. П. Голышева Художественный редактор Л. В. Матвеева Художник В. А Аксенов Технический редактор Н. М. Остроумова Операторы набора Л. К. Грушецкая, П. В. Карповская Операторы электронной верстки Л. Н. Демина, О В. Дробышевич ИБ № 51040 ЛР № 020297 от 27.11.91. Сдано в набор 05.03.93. Подписано в печать 21.12.93. Бумага тип № 2. Формат 60х901/16- Гарнитура тайме. Офсетная печать Усл.печл. 22,5. Уч.-изд. л. 21,9. Тираж 660 экз. Заказ № 537. Ордена Трудового Красного Знамени ВО “Наука”, Сибирская издательская фирма. 630099 Новосибирск, ул. Советская, 18. Оригинал-макет подготовлен в Институте систем информатики СО РАН. Новосибирская типография № 4 ВО “Наука”. 630077 Новосибирск, ул. Станиславского, 25. Е *лКБ—6—44—1993 © В. А. Евстигнеев, В. Н. Касьянов, 1994 042(02)—94 ©Российская Академия наук, 1994 ISBN 5—02—030332—1
Светлой памяти Андрея Петровича Ершова посвящается ПРЕДИСЛОВИЕ Хотя первая книга по теории графов появилась в 1935 г., началом широкого внедрения методов теории графов в практику научных и тех- нических исследований можно считать 50-е гг. Книги по теории графов (К. Берж, Р. Басакер и Т. Саати), вышедшие в начале 60-х гг., уже содержали материалы, описывающие приложения теории графов в исследовании операций, дискретной оптимизации, электротехнике и пр. Затем последовали книги, целиком посвященные вопросам применения теории графов в отдельных областях знаний, в том числе в прог- раммировании. Среди них можно назвать "Введение в теоретическое программирование. Беседы о методе" А. П. Ершова (1977 г.), "Приме- нение теории графов в программировании" В. А. Евстигнеева (1985 г.), "Оптимизирующие преобразования программ" В. Н. Касьянова (1988 г.), "Комбинаторика для программистов" В. Липского (1988 г.). В этих книгах был обобщен и систематизирован громадный опыт использования теоретико-графовых методов для анализа, оптимизации и преобразо- вания программ, организации вычислительных процессов, оценки слож- ности программ и пр. Пионерными в области использования теории графов в программи- ровании были работы А. П. Ершова по организации вычисления арифме- тических выражений (1958 г.) и оптимальному использованию опера- тивной памяти (1962 г.) и заметка Р. Карпа (1960 г., на русском языке — 1962 г.), в которой была введена в практику теоретико-графовая модель программы в виде управляющего графа, или графа переходов, ставшая к настоящему времени классической для решения задач трансляции. Эта модель оказалась чрезвычайно полезной для дальнейших исследований и практических применений в системах автоматизации, в частности для проверки правильности программ и их оптимизации, и не потеряла своей значимости при смене архитектур ЭВМ. Так, управляющий граф лежит в основе многих промежуточных представлений программ и их преобра- зований, используемых в векторизующих и распараллеливающих ком- пиляторах, предназначенных для ЭВМ с параллельной архитектурой. Наряду с управляющим графом в практике программирования ши- роко используются другие граф-модели: граф вызовов процедур, граф зависимостей по данным, адресуемые графы данных, синтаксические де- ревья и деревья разбора, деревья вложенности, деревья сортировки, до- минаторное и постдоминаторное деревья и т.д. К теоретико-графовым относятся и другие широко используемые в программировании модели, такие как вычислительные модели, семантические и ассоциативные сети и операторные схемы, сети Петри, Я-графы Вельбицкого и другие. В процессе чтения лекций и при написании книг мы вынуждены были оставлять в стороне массу интереснейших результатов и полезных ал- горитмов, рассеянных по многочисленным источникам и часто попадав-
4 Предисловие ших в наши руки довольно случайным образом. Мы понимали, что их большая часть обречена на забвение ввиду невозможности перебрать все источники, где материалы могли бы быть опубликованы, и что нужно предпринимать какие-то шаги по исправлению сложившегося положе- ния. Из обсуждения этого вопроса с А. П. Ершовым родилась идея создать энциклопедию алгоритмов на графах, сосредоточив основное внимание на тех из них, которые либо уже нашли применение в программиро- вании, либо являются модификациями или развитием таких алгоритмов. Нам показалось естественным разбить графы на классы и объединять в одну книгу алгоритмы, разработанные для того или иного класса. Естест- венность этого решения, кроме всего прочего, поддерживалась наличием такого очень важного для программирования класса графов, как деревья. Настоящая монография является первой, и надеемся, не последней кни- гой, написанной в плане реализации нашего проекта. Ее появлению предше- ствовал выход в свет двух книг, выпущенных малым тиражом в Вычислитель- ном центре СО РАН: ’’Алгоритмы на деревьях” (1989 г.) и ’’Алгоритмы обра- ботки деревьев” (1990 г.). Книги разошлись мгновенно, и это укрепило нашу решимость подготовить на их основе единую монографию, что мы и сделали. Мы назвали ее ’’Теория графов: алгоритмы обработки деревьев”, а не просто ’’Алгоритмы на деревьях”, чтобы наша книга в библиотеках не попала, как это уже имело место, в раздел ’’биология”. Книга предназначена не только для наведения справок о тех или иных алгоритмах, но и для знакомства с той частью теории графов, которая изу- чает деревья и их приложения. В ней предпринята попытка дать краткое, но по возможности полное описание основных понятий, свойств и областей применения деревьев. Мы понимаем, что в монографии представлена неко- торая выборка известных к настоящему моменту алгоритмов, но надеемся, что она достаточно представительна. О существовании других алгоритмов, по разным причинам не попавших в книгу, читатель может узнать из биб- лиографических комментариев в конце каждой главы. Последние, кроме того, позволяют читателю представить себе историю развития и нынешнее состояние той или иной проблемы теории графов и приложений. Что касает- ся ’’чистой” теории графов, то здесь читателю поможет список дополнитель- ной литературы в конце книги. Монография состоит из 8 глав, которые объединены в три части. В части I излагаются основные понятия, свойства деревьев и такие ба- зисные алгоритмы, как поиск в глубину, алгоритмы кодирования и гене- рации деревьев и т.д. В части II рассматриваются вопросы применения деревьев для решения задач, связанных со структуризацией программ, унификацией, системами переписывания термов, синтаксическим ана- лизом и пр. Часть III посвящена вопросам хранения и поиска инфор- мации. Книга подготовлена к изданию при частичной финансовой поддержке Российского фонда фундаментальных исследований (грант 93-012-576) и Министерства науки, образования и технической политики (грант 2-15- 2-43).
ЧАСТЬ I ОСНОВНЫЕ ПОНЯТИЯ И АЛГОРИТМЫ Глава 1 ДЕРЕВЬЯ И ИХ СВОЙСТВА 1.1. Введение и основные определения 1.1.1. Вводные замечания. Данная глава содержит основные сведения из теории графов, касающиеся деревьев и их свойств. Все неопределяе- мые здесь понятия могут быть найдены в соответствующих книгах, число их (понятий) по возможности сделано минимальным. Свойства деревьев и связанные с ними результаты приводятся вне зависимости от того, используются они далее в алгоритмах или нет. 1.1.2. Определение дерева. Деревом называется неориентированный связный граф без циклов (см. рис. 1.1, а). Неориентированный граф без циклов называется лесом. Другими словами, лес есть несвязный граф, каждая компонента связности которого есть дерево (см. рис. 1.1,6). Дерево конечно, если число вершин в нем конечно, и бесконечно в противном случае. Дерево с одной вершиной называется тривиальным, вырожденным или пустым. Число вершин дерева иногда называют порядком дерева. Рис. 1.7 Дерево, не имеющее вершин степени 2, называется гомеоморфно не- сводимым; дерево, вложенное в евклидову плоскость, называется плоским (см. также определение плоского дерева в п. 1.1.6). Деревья обладают рядом свойств, каждое из которых полностью ха- рактеризует его: а) деревом называется неориентированный граф, любые две вершины которого связаны единственной цепью; б) деревом называемся неориентированный граф без циклов, добавление любого ребра к которому приводит к появлению в точности одного цикла; в) деревом называется связный неориентированный граф, у которого удаление любого ребра приводит к нарушению связности; г) деревом называется связный л-вершинный неориентированный
6 1.1.3. Каталог деревьев не более чем с 8 вершинами граф с п - 1 ребрами; д) деревом называется неориентированный граф без циклов (ациклический) с п вершинами и п - 1 ребрами; е) деревом называется неориентированный граф, все цепи которого простые, т.е. ни одна вершина не входит в них дважды. 1.1.3. Каталог деревьев не более чем с 8 вершинами. Таблица 1.1
1.1.4. Центр и центроид дерева 7 Продолжение табл. 1.1 Гомеоморфно несводимые деревья с числом вершин < 8: п - 1 о п » 20—0 п - 3 Нет 1.1.4. Центр и центроид дерева. Расстояние d(x, у) между верши- нами х и у в дереве есть число ребер в цепи, соединяющей эти вершины. Расстояние от вершины х до наиболее удаленной от нее вершины называ- ется эксцентриситетом е(х} вершины л, т.е. е(х) = max J(x, у). У Наименьший из эксцентриситетов называется радиусом г(Т) дерева Г, т.е.
8 1.1.5. Корневые и ориентированные деревья r(T) = min е(х) = min max d(x, v). X X у Наибольший из эксцентриситетов называется диаметром D(T) дерева, т.е. D(T) = max е(х) = max max d(x, у). X X у Вершина х называется центральной вершиной дерева, если для нее е(х) = = г(Т); центр дерева — это множество всех его центральных вершин. Дере- во, центр которого состоит из двух вершин, называется бицентральным. Центр дерева состоит из одной или двух смежных вершин. Основное свойство центра дерева: центр дерева не меняется, если у дерева удалить все висячие вершины. Свойства дерева, связанные с центром: а) радиус и диаметр дерева связаны соотношением 2г(Т), если центр состоит из одной вершины, 2г(Т) - 1, если центр состоит из двух вершин; б) каждая цепь наибольшей длины проходит через центр дерева. Ветвь к вершине v дерева Т — это максимальное поддерево, содержа- щее v в качестве висячей вершины. Число ветвей к вершине v равно степени вершины у. Вес вершины у дерева определяется как наибольшее число ребер по всем ветвям к у. Вершина у называется центроидной вершиной дерева, если у имеет наименьший вес; центроид дерева — это множество всех его центроидных вершин. Центроид дерева состоит из одной или двух смежных вершин. Наименьшие по числу ребер деревья с одной и двумя центральными и центроидными вершинами: £>(Т) = 1 Центроид 2 1.1.5. Корневые и ориентированные деревья. Дерево называется кор- невым, если в нем выделена вершина г, называемая корнем. Некорневое дерево иногда называют свободным. При решении некоторых задач, например при установлении изоморфизма деревьев, в качестве корня удобно выбирать одну из центральных вершин. Ориентированным деревом с корнем г (или древесностью с корнем г) называется корневое дерево, в котором каждое ребро заменено дугой так, что либо из каждой вершины можно попасть в корень, двигаясь вдоль ориентации дуг (входящее дерево), либо в каждую вершину можно попасть из корня, двигаясь вдоль ориентации дуг (выходящее дерево). Во входящем ориентированном дереве корень достижим из каждой вершины, в выходя- щем — каждая вершина достижима из корня (рис. 1.2).
1.1.5. Корневые и ориентированные деревья 9 Ориентированное дерево кратко называют орде ревом. Нетрудно увидеть, что задание корня превращает дерево в ордерево. В выходящем ордереве в точности одна вершина — корень — имеет нулевую полустепень захода, у всех остальных вершин полустепень за- хода равна единице. Висячие вершины выходящего дерева называются листьями. Выходящее ордерево иногда называют растущим. Пусть Т(Х, U) есть ордерево с корнем г. Расстояние г/(х, у) между вершинами х и у в ордереве есть число дуг в пути, ведущем из х в у. Если такого пути нет, полагают J(x, у) = <». Говорят, что вершины ордерева образуют Л-й ярус или расположены на к-м уровне, если их расстояние от корня г равно к. Наибольшее Л, при котором Л-й ярус не пуст, называется высотой растущего ордерева. Всякая вершина растущего ордерева мо- жет рассматриваться как корень растущего из него поддерева. Для подде- рева аналогичным образом определяется высота (рис. 1.3). Рис. 1.3
1.1.6. Упорядоченные и бинарные деревья 1.1.6. Упорядоченные и бинарные деревья. Выходящее ордерево на- зывается упорядоченным, если у него упорядочены множества выхо- дящих из каждой вершины дуг. Два изоморфных ордерева могут не быть изоморфными, если их рассматривать как упорядоченные с разными упорядочениями выходящих дуг (рис. 1.4). Упорядоченные деревья иначе называют плоскими (см. п. 1.1.2). Ордерево называется бинарным, если оно определяется следующим рекурсивным образом: а) одновершинное дерево есть бинарное дерево; б) тройка (Г/, г, Тг) есть бинарное дерево с корнем г, левым поддере- вом Т{ и правым поддеревом Тг, причем как Т{, так и Тг суть бинарные деревья, возможно, пустые (рис. 1.5). Из этого определения вытекает, что для каждой дуги, выходящей из любой вершины бинарного дерева, указывается, правая она или левая. От упорядоченного дерева бинарное дерево отличается тем, что если из вершины выходит только одна дуга, то обязательно указывается, правая она или левая (рис. 1.6). Бинарные деревья называются также двоично-поисковыми. Некото- рые авторы используют термин ’’бинарное дерево’’ для обозначения упо- рядоченного дерева, у которого из каждой вершины выходят либо две дуги, либо ни одной, и термин ’’двоично-поисковые деревья” для обозна- чения бинарных в нашем смысле деревьев. Обобщением бинарных деревьев являются m-арные деревья, в кото- Рис. 1.5 рых каждая вершина является корнем не более чем т поддеревьев, каждое из которых в свою очередь есть т-арное дерево, возможно, пустое. Рис. 1.6
1.1.8. Каркасы и оркаркасы 11 Левосторонее бинарное дерево определяется рекурсивно следующим образом: а) одновершинное дерево есть левосторонее бинарное дерево; б) бинарное дерево, в котором правое поддерево является пустым, а левое — левосторонним бинарным деревом, есть левостороннее бинарное дерево. Аналогичным образом определяется правостороннее бинарное дерево. 1.1.7. Балансированные бинарные деревья. Бинарное дерево называ- ется балансированным по высоте или АВЛ-деревом (по имени его перво- открывателей Г. М. Адельсона-Вельского и Е. М. Ландиса), если для любой его вершины высота правого поддерева отличается от высоты ле- вого поддерева не более чем на единицу. Высота и-вершинного АВЛ-дерева не превышает (1/2) log л в худшем случае и 1,04 log п в среднем. Бинарное и-вершинное дерево называется балансированным по весу с балансом а, 0 < а < 1/2, если оно удовлетворяет следующим условиям: /1,4-1 а) а < ——г < 1 — а, п, = I Т,\ ; п 4- 1 1 1 б) Г/ и Тг — балансированные по весу деревья с балансом а. Класс бинарных балансированных по весу деревьев обозначается В В [а ]. В балансах деревьев есть ’’пробел”, а именно, для всех а из интер- вала 1/3 < а < 1/2 ВВ [а ] = ВВ [1/2 ]. Классы АВЛ-дёревьев и балансированных по весу деревьев суть различные классы. Высота бинарного /i-вершинного балансированного по весу дерева с балансом а не превышает (log(/t + 1) - 1)/log( 11 (1 -а)). Бинарные деревья, у которых все листья находятся на одном уровне, называются выровненными. Среди выровненных деревьев выделяются следующие классы: а) Н-деревъя, у которых каждая вершина с единственным потомком имеет правого соседа с двумя потомками; б) НВ-деревья. у которых каждая вершина с одним потомком имеет брата с двумя потомками; в) НS-деревья, у которых, если вершина имеет только одного потом- ка, то этот потомок либо есть лист, либо сам имеет двух потомков; г) к-деревья, у которых вершина с одним потомком имеет по крайней мере одного правого соседа и первые к правых соседей (или все правые соседи, если их число меньше к) имеют двух потомков. 1.1.8. Каркасы и оркаркасы. Каркасом неориентированного графа называется его суграф в виде дерева. Каркас называется также остовом или стягивающим деревом. Неориентированный граф имеет каркас, если он связен. Оркаркасом (каркасом) ориентированного графа называется его суг-
12 1.1.9. Метрические свойства, деревьев раф в виде входящего ордерева. Ориентированный граф имеет оркаркас с корнем г, если все вершины орграфа достижимы из г или сама вершина г достижима из всех вершин. В первом случае говорят о каркасе, выходящем из г, а во втором — о каркасе, входящем или заходящем в вершину г. Элементарным преобразованием каркаса Т в каркас Т называется добавление к Т ребра и (при этом образуется в точности один цикл) и удаление ребра v (входящего в образовавшийся цикл), так что снова получается каркас. Для любых двух каркасов Т и Т" всегда найдется последовательность (возможно, пустая) каркасов Tv Т2, ...,7\ такая, что каркас 7\ получается из каркаса ТЬ1 элементарным преобразованием z = 1,... ...,£ + 1, То = Г, Тк^ = Г'. Графом каркасов для данного графа G называется неориентирован- ный граф, каждая вершина которого соответствует каркасу графа G, а две вершины смежны, если соответствующие каркасы получаются друг из друга элементарным преобразованием. Указанное выше свойство кар- касов приобретает вид: граф каркасов всегда гамильтонов. Аналогично определяются элементарное преобразование для оркаркасов и граф оркаркасов. Для последнего имеют место следующие утверждения: — граф оркаркасов гамильтонов; — если G есть граф оркаркасов данного ориентированного графа G, имеющего не менее трех оркаркасов, то любое ребро графа G может быть сделано частью гамильтонова цикла. Пусть ребра графа как-то упорядочены. Тогда каждому каркасу ставится в соответствие вектор длины т, где т — число ребер в графе, z-я координата которого равна 1, если ребро щ входит в данный каркас, и равно 0 в противном случае. Этот вектор носит название вектор-карка- са. Относительно пространства вектор-каркасов известно следующее: размерность пространства вектор-каркасов равна числу ребер I £1 исход- ного графа, если он двусвязен, и IEI -Z>(G) + 1 в противном случае; здесь b(G) есть число блоков в графе. Аналогичные результаты имеют место и для пространства оркаркасов. 1.1.9. Метрические свойства деревьев. Метрическими свойствами называются свойства, определяемые метрикой деревьев, т.е. расстояни- ями между его вершинами. Метрические свойства, связанные с центром дерева, рассмотрены в п. 1.1.4. К другим метрическим свойствам относят- ся следующие: — система расстояний между висячими вершинами дерева определя- ет дерево однозначно с точностью до изоморфизма, — реализация метрики с помощью дерева является наиболее эконом- ной в следующем смысле: если метрику р, заданную на множестве X, можно реализовать деревом Т = (VT, Ет), то для всякого графа G = <VG, Eg) , реализующего ту же метрику, имеем I KJ > I VT\, IEJ > IEJ. G 1 1
1.1.10. Операции над упорядоченными деревьями 13 1.1.10. Операции над упорядоченными деревьями. А. Операция подклеивания П(ТР Т2, Т3). Трем деревьям Тр Т2, Т3 таким, что Т2 есть поддерево дерева Тр ставится в соответствие дерево П(ТР Т2, Т3), получаемое из 7\ присоединением Т3 к корню г(Т2), при этом Т3 становится левым сыном корня г(Т2) (рис. 1.7). Б. Операция перестановки поддеревьев ПР(7\, Т2, Т3). Пусть г(Т2) и г(Т3) суть сыновья одной вершины в дереве Тр тогда результат операции виден из рис. 1.8. В. Операция отделения поддерева О(7\, Т2). Результатом операции является дерево О(Т|5 Т2), получаемое из 7\ выбрасыванием поддерева, корень которого совпадает с корнем дерева Т2 (рис. 1.9). Т2: Рис. 1.9
14 1.1.10. Операции над упорядоченными деревьями Г. Операция выделения самого левого поддерева ВЛП(Т). Д. Операция выделения правого брата ВПБ('Т\, Т2). Под выделением правого брата понимается операция, выделяющая в 7, поддерево, корнем которого является правый брат корня г(Т2). Е. Операция выделения корня ВК(Т). Введем следующие обозначения: А’1 — обращение бинарного отношения А С А х Л; А — транзитивное замыкание бинарного отношения; А — рефлексивно-транзитивное замыкание бинарного отношения А: А = A U {(а, л)к/ G Л}; А(/?) — срез бинарного отношения А через множество В, т.е. А (В) = = {с 13 b G В. (Ь, с) G А}. Для удобства вместо А ({л}) часто пишут А («); prtA — проекция бинарного отношения А по первой компоненте: prt А = {а I 3 Ь, (а, Ь) G А}. Будем считать (л, 0) = 0, (0, Ь) = 0, (0,0) =0. Ориентированным деревом называется пара (Лр А,) , где — ко- нечное множество вершин, а А! £ Л, х Ai удовлетворяет свойствам V<? V/? Vc (л, £, с G Л, ): 1) IА;1 (а) I < 1 л AjU/); 2) IА/(й) I < 1 Л IАгЧс) I =0 => Ь~с. Свойство 1) отражает тот факт, что в вершину входит не более одной дуги и нет циклов; свойство 2) является условием единственности корня. Имеет место следующий факт: если (Aj, А,) — ориентированное дере- во, то (Лр Aj) — абстрактная полурешетка. Упорядоченным деревом называется тройка (Лр Ар А2), где (Лр Aj) — ориентированное дерево, а А2 х Л1 удовлетворяет свойствам: 1) а £ А2 (я); 2) I А2(д) I < 1; 3) LA;1 (а) I 1; 4) А2(я) U А2_| = AjCA^to)). Отношение А2, удовлетворяющее свойствам 1)—4), задает линейный порядок на множестве сыновей каждой вершины. Заметим, что если (А{, А,, А2) — упорядоченное дерево, то множество ЛХА^Л) состоит в точности из одного элемента, называемого корнем дерева. Пусть Ti = (Л-, А,, А2), z = 1, 2, 3, ..., — упорядоченные деревья, л, = лДА;(л.). А. Т4 = П(Тр 72, 73). Если k2 Q Л1 и Л1 П Л3 == 0, то Л4 = Л1 U Л3 , А4 = Al U A, U к2 х к3 , А4 = AJ U А2 U к3 X (AJ(Аг)\А‘(AJ(£2))),
1.1.11 Ря.чметки. НУМРПЯПИИ лбхЛПМ УКПЯПКИ 1 S ’ J -Г’ »- > j — -*’Г-Ч- - ~ иначе операция не определена. Б. Т. = ПР(7,, 7„ 73). Если Л2 С Л' и С Л' то а4=а',а; = а;, А4 = А1 \«А‘) '(к2) х к2 к) к2 х К2(к2) U U ИК*2У'(к3) х к3 U к3 х Aj(£3)) U (Aj)-,a2) х Л3 U U к3 х А‘(Л2) U (Aj)‘'(A3) U Л2 х А}(*3), иначе операция не определена. В. 73 = 0(7,, 7,), А3 = а'\А;(А2), А3 = А[\А2 х л2, А,’ = Aj\A2 х а2 . Г. 7, = ВЛП(7,), a2 = a;(a;u2)\aj <а;<л'))), А; = а; п А2 х А2, А2 - AJ П А2 X А2. Д. 7=ВПБ(7,, 7,), аз=а; (А^л2)), А3 = а; Г) А3 х А3, А| = Aj п А3 х А3. Е. Т2 = ВК(7,), А2 = к1, А2 = 0, А2 = 0. Система операций на множестве упорядоченных деревьев А называ- ется с-полной, если для любого Т С А, Т = {Т.}, i G /, такого, что U А = Л, с помощью этих операций можно построить любое де- /е I рево Т = {А, А,, А‘2>, А С а. Имеют место следующие утверждения: А. Система операций {П, О, ВЛП, ВПБ, ВК} с-полна на множестве всех упорядоченных деревьев, Б. Система операций {П, ПР, О, ВЛП, ВПБ, ВК} функционально независима, 1.1.11. Разметки, нумерации, обходы, укладки. Пусть G = (X, U) — некоторый граф, состоящий из п вершин и т ребер (дуг), т.е. п = IXI и т = \1Л, Разметкой вершин графа G называется функция из X в неко- торое множество L, элементы которого называются пометками, а раз- меткой ребер (дуг) — функция из U в L, Граф G называется помечен- ным, если он снабжен хотя бы одной из таких разметок и если пометки — числа, их часто называют весами, а граф — нагруженным. Отображение F множества X на множество [1 : п] называется нуме- рацией графа G. Пусть F — некоторая нумерация. Через F[i: j] обозначается множе-
16 1.1.12. Базисные нумерации ство вершин {р G X: Ftp) G [/: /]}, а также подграф графа G, образован- ный этим множеством вершин. Дуга и « (р, q) ориентированного графа G с нумерацией F называется F-прямой дугой tF-дугой), если Ftp) < Ftq), и F-обратной дугой, если Ftp) > Ftq). Если некоторый путь по G от р до q не содержит F-обратных дуг, то он называется F-пугпем, а вершина q является F-досгпижимой из вершины р. Укладкой Н длины к графа G называется любое отображение множе- ства [1 : к ], где к > п, на X. Укладка длины п называется обходом графа G. Обычно укладка Н задается в виде последовательности вершин (Ж 1),... ..., Htk)), где к — длина укладки. Подграф (X, Z) неориентированного (ориентированного) графа G = = (X, U) называется лесом обхода Н графа G (обозначение GH = (X, Z)), если Z содержит каждое такое ребро (каждую такую дугу) и G G, что среди вершин, расположенных в Н между вершинами р = Hti) и q = Htj), где i < / и и = (р, </), нет вершин, соединенных ребром (дугой) с вершиной Htj). На рис. 1.10,б изображен лес обхода Н = (2, 3, 1,5, 6, 7, 4, 10, 9, 8, 12, 11, 13) графа G, изображенного на рис. 1.10, а. Рис. 1.11, б содержит лес обхода Я= (2, 3, 8, 4, 7, 6, 1,5) ориентированного графа Gc рис. 1.11, а. 7 6 1.1.12. Базисные нумерации. Прямой нумерацией (или M-нуме- рацией) ориентированного графа G= (X, U) называется любая такая его нумерация F, что справедливы следующие два свойства: 1) для любой вершины р либо в р заходит хотя бы одна F-прямая дуга, либо р не достижима из вершин, F-номера которых меньше Ftp); 2) если (р, q) — такая F-прямая дуга, что среди вершин с F-номерами из tFtp) : Ftq)) нет предшественников вершины р, то среди них нет и предшественников ни одной вершины, F-номер которой больше Ftq).
Рис. 1.11 Нумерация F графа G называется его обратной нумерацией (или N-нумерацией), если существует такая прямая нумерацт я М графа (7, что для любых вершин р и q неравенство F(p) < F(q) выполняется тогда и только тогда, когда либо вершина q является М-достижимой из вершины р, либо M(q) < М{р} и вершина р не является Л/-достижимой из вершины q. На рис. 1.12 для графа G с рис. 1.11, а приведены рядом с вершинами (в скобках) их номера в прямой и обратной нумерациях. Рис. 1.12 Справедливы следующие свойства: а) для любой прямой нумерации М графа G и любого простого путиР- (р,, ...,рР по G такого, чтоМ^р^ = min {A/(p.):/G [1 : s]},6ce вершины Р являются М-достижимыми в G из pt; б) пусть М — некоторая прямая нумерация уграфа G и Р{ = (рр рк)
18 1.1.13. Обходы в ширину и глубину иР2 = (</р ...,4;) —такиеМ-пути по G, что M(pt) < М(с/,) < M(pk) < M(qs), Тогда существует М-путъ по G от qx до рк; в) каждый ориентированный граф обладает по крайней мере одной парой связанных базисных нумераций, причем обратная нумерация графа может соответствовать нескольким его прямым нумерациям (см, пример на рис, 1,13), Рис. /. 13 1.1.13. Обходы в ширину и глубину. Пусть Н — некоторый обход не- ориентированного (или ориентированного) графа G- (X, U), п = IXI и пусть Я|5 где i G [1 : п], обозначает min({z} U {у: H(J) G Л}), где А — множество всех вершин, расположенных в Н левее вершины Ж/) и смежных, т.е. соединеных ребром (дугой), с вершиной ЖО. Н называется обходом (поиском) в ширину графа G, начиная с р, если р « Ж1) и для любых/,/G [1:л ] из i‘< /следует, что H(i) < H(j), Н = (7,2, 1,6, 3, 4, 5, 10, 9, 8, 11, 12, 13) является обходом в ширину графа с рис. 1.10,л, а Я= (2, 7, 3, 8, 4, 6, 5, 1) — обходом в ширину ориентированного графа с рис. 1.11, а. Обход Н ориентированного графа G называется обходом (поиском) в глубину G, начиная с р, если Ж1) = р и Н~{ — прямая нумерация графа G, Например, Я= (2, 3, 8, 4, 7, 6, 1, 5) является обходом в глубину графа G (см. рис. 1.12), начиная с вершины 2. Пусть Н — некоторый обход неориентированного графа G= (X, U), По отношению к Н множество U разбивается на множество древесных ребер, принадлежащих лесу GH, и множество обратных ребер, не при- надлежащих лесу GH, Пусть G’ обозначает ориентированный граф (X, W) такой, что (р, q) G Wтогда и только тогда, когда либо (р, q) — древесное ребро и р расположено в Н левее q, либо (р, q) — обратное ребро и q расположено в Н левее р. Н называется обходом в глубину G, начиная с р, если р = Ж1) и Н — обход в глубину графа G’, Для графа G на рис. 1.10,я и его обхода в глубину Н = (2, 3, 1,5, 6, 7, 4, 10, 9, 8, 12, 11, 13) множества древесных и обратных дуг изображены на рис. 1.10,6 сплошными линиями — древесные дуги, а штриховыми — обратные. Для них граф G’ имеет вид, изображенный на рис. 1.14.
1. i. 14. Остовный лес обхода в глубину и глубинное остонное дерево !9 Рис. 1.14 1.1.14. Остовный лес обхода в глубину и глубинное остовное дерево. Пусть Н — некоторый обход в глубину графа G = (X, U). Тогда лес GH = = (X, Z) обхода Н называется остовным лесом для G, построенным обхо- дом в глубину Н, или, короче, глубинным остовным лесом для G. Если этот лес состоит из единственного дерева, (X, Z) называется глубинным остовным деревом. Вершина, с которой начинается обход Я, считается корнем указанного дерева. Множество дуг ориентированного графа G = (X, U) распадается отно- сительно его обхода в глубину Н на четыре множества: древесные — дуги, принадлежащие лесу обхода Я; обратные — дуги, идущие от по- томков леса обхода к предкам (возможно, из вершины в себя); прямые — дуги, идущие от предков к потомкам, но не являющиеся древесными или обратными; поперечные — дуги, соединяющие вершины, которые не являются ни предками, ни потомками одна другой. На рис. 1.15 для обхода Я = (2, 3, 8, 4, 7, 6, 1, 5) графа Gc рис. 1.11,я древесные дуги нарисованы сплошными двойными линиями, обратные — волнистыми, поперечные — штриховыми, а прямые дуги — сплошными одинарными. Рис. 1.15 4
20 1.2.1. Вводные замечания 1.2. Представление деревьев 1.2.1. Вводные замечания. Представлением дерева называется спо- соб записи информации о нем, однозначно и полностью восстанавлива- ющий структуру дерева и позволяющий вычислять его характеристики. Выбор представления зависит от решаемой задачи и способа (ручной, ма- шинный) ее решения. Способы представления деревьев делятся на общие — для всех графов представления и специфические — для деревьев. 1.2.2. Представление с помощью матрицы смежности. Это представ- ление является общим для всех графов; оно определяет граф однозначно с точностью до изоморфизма, но является довольно неэкономным, так как ненулевыми являются для я-вершинного дерева только 2м - 2 из п2 элементов матрицы. Матрица смежности есть квадратная матрица А размером п х м, у которой элемент а- определяется следующим образом: _ 1, если вершины х и х. смежны, у [0 в противном случае. Для неориентированного графа матрица смежности симметрична относительно главной диагонали, поэтому можно задавать только верх- нюю треугольную половину матрицы, но это не улучшает ситуацию. Другим недостатком этого представления является тот факт, что трудо- емкость алгоритмов, работающих с таким представлением, не может быть ниже О(л3). Достоинство же этого представления — легкость получения, а также возможность использования его для языков, допускающих побитовую обработку двоичных последовательностей, рассматриваемых как одно слово. Пример. 000100000 000100000 000100000 111 0 1 0 0 0 0 0 0 0 1 0 1 1 0 0 000010000 0 0 0 0 1 0 0 1 1 000000100 000000100 Матрица смежности Представление с помощью матрицы инцидентности — также общее
1.2.3. Представление с помощью списков смежное । и для всех графов представление; оно еще более неэкономно и здесь не рассматривается. 1.2.3. Представление с помощью списков смежности. В этом пред- ставлении каждой вершине дерева сопоставляется список смежных вершин вида v.: v , v ,.... v.. 1 2 i Для дерева Т из п. 1.2.2 списки смежности имеют вид: У4 : Vi> V3: V7: Vi •• »4 i > -необязательно При машинной организации списки смежности могут быть связаны между собой разными способами, например, копируя структуру дерева:
22 1 2.4. Представление деревьев как графов данных В приведенном примере в поле маркера стоит плюс, если в поле данных содержится имя вершины, и минус, если поле данных использу- ется для отсылки к новому списку; в поле отсылки стоит либо адрес следующего элемента списка, либо нуль (конец списка). Если в поле отсылки последнего элемента списка стоит вместо нуля адрес первого элемента списка, то мы имеем замкнутый, или циклический, список. Ниже приводится замкнутая списковая структура для дерева Г. Для основного (головного) списка в поле отсылки стоит нуль, свидетельствуя о конце всей структуры. Для ориентированных деревьев возможно задание с помощью двух семейств списков смежности: один содержит вершины, достижимые из данной вершины, другой — вершину-предка. Этот способ легко реализу- ется с помощью симметричных списков, имеющих две отсылки: вперед (как выше) и назад. 1.2.4. Представление деревьев как графов данных. Граф данных получается из структуры данных, если отвлечься от элементарных дан- ных, которые соответствуют вершинам структуры, и сосредоточиться на связях между ними. Пусть С = {с} — множество ячеек данных. Хотя на практике это мно- жество всегда конечно, удобно считать его счетным. Пусть далее Л есть конечное множество частичных преобразований на С, называемых пре- образованиями типа, иЛ' — моноид, порождаемый преобразованиями из Л с помощью операции композиции преобразований. Будем считать, что для каждой пары ячеек с, d G С существует преобразование | G Л та- кое, что|(с) = d~ Определим теперь граф данных Г = (С, Л) как орграф, у которого множеством вершин является множество С и между вершинами с и d имеется дуга (с, J), если существует преобразование £ G Л такое, что </ = £(<?). Ясно, что существование преобразования £ G Лг, переводящего ячей- ку с в dy соответствует наличию пути из вершины с в вершину d, а наложенное выше условие на Лг соответствует утверждению, что граф
1.2.4. Представление деревьев как графов данных 23 данных всегда сильно связен. Примеры. А. Бинарное дерево Т (рис. 1.16). Вершины дерева занумерованы числами 1,2,3, ..., а три типа связей представлены следующими преоб- разованиями над множеством N натуральных чисел: ог(п) = правый потомок (и) = 2и, Ojin) = левый потомок (п) = 2п + 1, л(п) = предок (и) = [л/2]. Преобразование ’’предок” — единственное, которое определено не везде. Факт, что л(1) = [1/2] = 0 N, означает, что ячейка с номером 1 (корень дерева) не имеет предка. Рис. 1.16 Б. Бинарное дерево Т(0 (рис. 1.17). Здесь, в отличие от бинарного дерева Т, преобразование ’’предок” заменено преобразованием = воз- врат в 1, т.е. а>(п) = 1. В. Бинарное дерево Га2 с мостами (рис. 1.18). Множество вершин есть множество N натуральных чисел, множество преобразований А есть множество {иг, а,, л, /?г, Д}, где ог(п) = 2/?, о1 (п) = 2п + 1, л(и) = [л/2], Д(л) = п + 1, если п = 4m (tn > 1); Д (п) = п + 1, если п = 4m + 2 (m > 1). Г. Вариант бинарного дерева (рис. 1.19). Множество вершин есть мно- жество {0} U N, множество преобразований А есть множество {ар а,, л},
24 1.2.4. Представление деревьев как графов данных где cr, (n) = 2п + 1, ar(n) = 2n, п # 0, тг(n) = [n/2 ], п # 0. Рис. 1.18
1.2.5. Представление с помощью списка ребер и кода Прюфера 25 1.2.5. Представление с помощью списка ребер и кода Прюфера. Дере- во при этом способе задается перечислением пар (vf, v) или троек (у., у;, ик), если дополнительно нужна нумерация ребер. Характер связей в списке определяется исходя из условий задачи. Для дерева Т из п. 1.2.2 имеем Т = {<vp v4>, <v2, v4>, <v3, y4>, <v4, v5>, <v5, v6>, <v5, v7>, <v7, v8>, <v7, v9>}. Пусть T — дерево с множеством вершин {vp v2,..., vn}. Будем считать, что номер вершины vi равен /. Сопоставим дереву Т последовательность [яр а2, ..., ап_2] по следующему правилу, представленному в виде функции на ВУ-языке (см. п. 2.1): функ КОД_ПРЮФЕРА(Т: дерево) = 1. Пусть п обозначает число вершин в Г, а А — целочисленный вектор длины п - 2; 2. В:=[1:п]; 3. для г от 1 до м - 1 цикл 4. b :« min {к G В: к — номер висячей вершины}; 5. а [г ] := номер вершины, с которой смежна вершина с номером Ь; 6. В:=В-{Ь}; 7. удалить из Т вершину с номером А [г ] все; 8. возврат А все Пример. Для дерева Т (рис. 1.20) код Прюфера имеет вид: Р2(Т) = = [2, 5, 5, 5, 6, 6, 10, 9, 10, 11, 13, 15, 15, 10, 13, 13, 13]. В случае корневого ордерева процедура получения кода Прюфера аналогична. Необходимо только на последнем месте указывать корневую
26 1.2.6. Операции над деревьями и кода?»1и Прюфера вершину и при распаковке кода исключать номер этой вершины из мно- жества В, Распаковка кода Прюфера осуществляется следующей ВУ-функцией: функ РАСПАКОВКА (А: код) = 1. Пусть Т состоит из вершин {, v2, •••> таких, что номер вершины v равен /, где п — длина кода А плюс 2; 2. В:=[1:и]; 3. для i'От 1 до п + 1 цикл 4. b := min {к Е В\ к Ф А [/] для любого j > 1}; 5. В Т добавить ребро, соединяющее вершины с номерами b и Л[/]; 6. £:=£- {Л} все ; 7. возврат Т все 1.2.6. Операции над деревьями и кодами Прюфера. Будем считать, что вершины двух разных деревьев нумеруются разными числами, при- чем номера одного дерева всегда больше или меньше любого номера другого. Это требование часто выполняется в практических реализаци- ях, так как для вершин каждого дерева обычно отводят последователь- ные массивы номеров ячеек памяти. Если все номера дерева Т{ (или
1.2.6. Операции над деревьями и кодами Прюфера 27 —> ориентированного дерева^) меньше всех номеров дерева Т2 (или Т2), то пишут < Т2 (или Г, < Т2). Рассмотрим следующие операции над деревьями: а I — операция замены номера а вершины Т на номер Ь; b а — операция склеивания двух деревьев по вершинам а и Ь, т.е. дерево Т\а ^ЬТ2 получается из Т2 и 7\ отождествлением вершин а из 7\ и b из Т2 и присвоением склеенной вершине номера b (при склеивании ордерсвьев добавляется требование, чтобы вершина bбыла корневой). Пример Дерево 7\ Дерево Т2 Дерево Т{3 (-^10Т2 Рассмотрим некоторые операции над кодами Прюфера: [ ] — операция формального отбрасывания квадратных скобок; опре- делена на всех выражениях вида ац], Л, [Z>j, b2, ] и состоит в отбрасывани всех внутренних квадратных скобок и добав- лении двух внешних; с— операция вставки кода Прюфера; если Р2(Т{) = [«,, а2, ак, с, ак+2, ..., a„_t ] и среди чисел л^+2, <74+3, •••> нет числа с, то Р2 = Л2’ •’ ак' С’ ак+2> ’’’ Ь Справедливы следующие соотношения, связывающие операции над деревьями и кодами Прюфера: если < Т2, то а Р2( 7\а ±ЬТ2) = [Р2( | Тр, Л, Р2(Т2) 1; Ь если Т, > Т2 , то в этом случае нужно рассматривать дерево 7\Ь ^«Т2, и все сводится к предыдущему случаю; если Т} < Т2, то
28 1.2.7. Оптимальное, кодирование деревьев Р2О\а Ч>Т2) = Р2( ; Т,) *р,т2, ь где с — непосредственный предок вершины а в дереве 7\ ; если Т{ > 7\, то Р2 (Тха ±ЬТ2 ) = [Р2(Т2), Р2( IT,)]. ь 00 1.2.7. Оптимальное кодирование деревьев. Пусть A = .U1A/- , А; — конечное множество. Предположим, что при каком-то способе кодирования элементов из А для запоминания одного элемента из А,- используют самое большее j(i) битов памяти. Кодирование j(i) называется оптимальным, если lim = 1, где H(i) = log2 IA J и IA J — число элементов в А,. При задании дерева списками смежности и при условии, что вершины помечены числами N + 1, N + 2,..., N + и, имеет место соотношение .. у(п) .. (Зп - 2) log2(W + п) 11Ш \ = 11Ш-------гут-т--------= 3, П~*<х>Н(П) п-к» 7/(/1) так как списки смежности содержат (Зп - 2) номеров вершин и каждый номер требует log2 W + п) битов. При задании ордерева списками смежности j(n) = (2п - l)log2W + п), что дает lim-^r-2, П~><х>Н(п) следует, что представление деревьев списками смежности с указанной точки зрения неоптимально. Оптимальным же является кодирование деревьев кодами Прюфера, так как для хранения кода Прюфера необходимо j(n) = (п- 2)log2(N + п) битов памяти, поэтому lim = 1. п-»оо77(и) 1.2,8. Кодирование деревьев с помощью обхода вершин. (Подроб- нее об обходах вершин см. п. 1.1.10.) Пусть дан некоторый порядок про- хождения вершин. Линейным кодом k(T) дерева Т называется слово в некотором алфавите, сформированное согласно заданному порядку про-
1.2.10. Коды, свободные от повторений 29 хождения вершин и составленное по определенному правилу из количе- ственных характеристик и признаков вершин, а также ограничителей. При представлении деревьев линейными кодами предполагается, что дерево расположено на плоскости без пересечения ребер, так что, двига- ясь от корня, можно в каждой вершине говорить о левом, правом, самом левом, самом правом и т.д. ребре. Для удобства примем, что дерево изоб- ражено на плоскости в виде выходящего дерева (см. рис. 1.2, б). За- фиксируем следующий порядок обхода вершин (вариант поиска в глу- бину): начиная с корня v0, выбираем самое левое инцидентное ему ребро, двигаясь по нему, к следующей вершине, если она не висячая, снова выбираем самое левое ребро — и так до тех пор, пока не попадем в висячую вершину. Потом возвращаемся назад к первой вершине, кото- рой инцидентны непройденные ребра, выбираем из них самое левое и движемся до следующей висячей вершины. Обход заканчивается в кор- не, когда будут пройдены все вершины. 1.2.9. Коды с дублированием номеров вершин. Пусть v0 — корень дерева, vp ...,v„ — его узлы, , ...,Г/? — висячие вершины. А. В качестве кода дерева берется перечень номеров вершин, начиная с корня; в коде дерева каждый узел встречается столько раз, сколько он проходится во время обхода, а каждая висячая вершина — только один раз (рис. 1.21). Б. В качестве кода берется перечень всех путей от корня к висячим вершинам (рис. 1.22). В. В качестве кода берется перечень вершин при указанном обходе, но в качестве характеристики вершины берется ее расстояние от корня (рис. 1.23). Г. В качестве кода берется перечень вершин, как в случае В, но вместо каждой монотонно возрастающей или убывающей последовательности записываются лишь ее крайние значения (рис. 1.24). Д. В качестве кода берется 0-1-последовательность, получаемая из кода в случае В, если вместо каждого числа в коде писать ”1” при увеличении расстояния от корня на единицу и ”0” — при уменьшении (рис. 1.25). Данный код является оптимальным по длине (в битах) среди всех возможных кодов корневых упорядоченных деревьев. 1.2.10. Коды, свободные от повторений. Порядок обхода соответст- вует п. 1.2.8. А. В качестве кода берется последовательность полустепеней исхода вершин, выписываемых в порядке, в котором вершины встречаются при обходе, с одним ограничением: при обратном движении по дереву полу- степени исхода не повторяются (см. рис. 1.26). Бинарные деревья при таком кодировании восстанавливаются неоднозначно. Б. В качестве кода берется последовательность расстояний вершин от корня (корень не кодируется). Для деревьев, у которых полустепени исхода вершин равны 2 или 0, достаточно записывать расстояния от кор- ня только для висячих вершин. Бинарные деревья при таком кодиро- вании восстанавливаются неоднозначно. Для дерева на рис. 1.26 данный код имеет вид
30 1.2.10. Коды, свободные от повторений Л(Т) = 2, 3, 3, 1. km - vn, Vp v2, Vp v3, Vp Vp VpV5 Vp v0, v€, v7, v6. vs. v,, vl0, vs, v6, v0 кт - v0. vp v,, v0, vp v3, v4, v0, vp v5, v0 V6' VT ''()• V9- ''o- VS’ VIO Рис. 1.21 km -1,2. 1,2, 3, 2, 1, 2, 1,0, 1, 2, 1,2, 3, 2, 3, 2, I Рис. 1.22 Puc. 1.23 Puc. 1.24 Puc. 1.25 km -220200 Puc. 1.26 В. В качестве кода берется последовательность числа вершин в подде- реве с корнем в рассматриваемой в данный момент вершине. Для дерева на рис. 1.26 данный код имеет вид
I .л,.1л.. j pOotiCBoic ходы корневых деревьев л Л(Т) = 7, 5, 1,3, 1, 1, 1. 1.2.11. Коды с использованием ограничителей. Данные коды ис- пользуют в качестве характеристики вершин такие величины, как высо- ту, порядковый номер среди братьев и др. При этом для устранения неоднозначности восстановления по таким кодам структуры деревьев применяются ограничители. А. В качестве кода берется последовательность букв а и /3, причем а помещается в последовательность, если при обходе встречается внутрен- няя вершина (узел), а/3 — если висячая. Ограничитель записывается в конце каждого поддерева. Для дерева на рис. 1.26 данный код имеет вид Л(Т) = Б. В качестве кода для бинарных деревьев берется последователь- ность чисел 0 и 1, причем левым вершинам соответствует признак ”1”, а правым — ”0”; при построении кода выписываются все пути из корня в листья, после каждого пути ставится ограничитель. Для дерева на рис. 1.26 данный код имеет вид R(T) = 11)101)100)0. 1.2.12. Уровневые коды корневых деревьев. Пусть (Т, z) обозначает корневое дерево с лежащим в его основе свободным деревом Т и корнем z. Уровень вершины v в (Т, z) — это расстояние v от z плюс единица. Уровневый код (обозначение L(T, z) = [Zp /2,..., ln ]) — это последователь- ность целых чисел, полученная выписыванием уровней вершин дерева (Т, z) в постфиксном порядке (см. п. 2.2.13). Уровневый код называется каноническим (обозначение L*(T, z)), если он является наибольшим в лексикографическом упорядочении среди всех уровневых кодов, описы- вающих дерево. Пример. Для дерева Т, изображенного на рис. 1.27, имеем L(T, z) = = [3, 3, 2, 3, 4, 4, 3, 2, 2, 1 ], Г (Т, z) = 14, 4, 3, 3, 2, 3, 3, 2, 2, 1 ]. Рис. 1.27
32 12.13. Ротационный код бинарных деревьев Вершина z называется основным корнем свободного дерева Т (обозна- чение z(T) или просто z), если либо z — единственный центр Т, либо z — один из центров zt и z2 бицентрального дерева Т, определяемый по следу- ющим правилам. Пусть Т{ и Т2 — поддеревья, получаемые из Т уда- лением ребра, соединяющего и z2. В качестве z берется zp если либо 7\ имеет меньше вершин, чем Т2, либо Г, и Т2 состоят из равного числа вершин, но L*(7\, zt) лексикографически предшествует последователь- ности L*(T2, z2); z2 берется в противном случае. Уровневый код L(T, z) называется главным уровневым кодом дерева Т, a L*(T, z) — главным каноническим уровневым кодом дерева Т. 1.2.13. Ротационный код бинарных деревьев. Рассматриваются два вида преобразований бинарных деревьев в бинарные деревья: правая и левая ротации. Рис. 1.28, б изображает результат правой ротации в вершине В дерева, изображенного на рис. 1.28, а, а рис. 1.28, а — резуль- тат левой ротации в вершине А дерева с рис. 1.28, б. При этом любое (или все) из поддеревьев а9/3иу могут быть пустыми. Левая (правая) ротации в вершине А дерева Т имеет глубину Л, если k — порядковый номер вершины А на пути по дереву Т от его корня к самому левому листу. Рис. 1.28 Пусть Т — некоторое бинарное дерево с п вершинами. Тогда последо- вательность (хл_р хп_2, ..., х2, х() называется ротационным кодом дерева Г, если для последовательности деревьев Тл, Tfl_i9 Тп_29 ..., Т2, Тр в кото- рой Г, = Т, Тп — левостороннее дерево, и для любого i дерево Т|+| получа- ется из Ti применением холевых ротаций глубины i. Например, (0, 1,0, 2) — ротационный код дерева Т, изображенного на рис. 1.29. Для того чтобы получить дерево Т по его ротационному коду X = = GV! , х„_2, ..., Xj), нужно выполнить следующую функцию, представ- ленную на языке высокого уровня (см. п. 2.1): функ ДЕРЕВО(X: код )58 1. Пусть Т — левостороннее дерево с п вершинами, где п — длина кода X плюс 1;
1.2.15. Коды Ли 33 2. для к от п - 1 до 1 шаг -1 цикл 3. цикл X[Л] раз 4. Выполнить над Т левую ротацию глубины к все все; 5. возврат Т все т2 1.2.14. Коды Закса. Пусть дано бинарное или Л-ичное дерево Т с п вершинами такое, что каждая внутренняя вершина дерева помечена числом 1, а каждая висячая — числом 0. х-кодом Закса дерева Т называется последовательность пометок его вершин, перечисленных в инфиксном порядке (рис. 1.30). z-кодом Закса дерева Т называется последовательность номеров единиц в х-коде дерева Т, перечисленных в порядке их возрастания (см. рис. 1.30). у-кодом Закса дерева Т называется последовательность номеров нулей в х-коде дерева Т, перечисленных в порядке их возрастания (см. рис. 1.30). 1.2.15. Коды Ли. Пусть Т — бинарное дерево, каждая внутренняя вершина помечена числом 1, а каждая висячая — числом 0. и-кодом Ли дерева Т называется последовательность пометок вер- шин, написанных в порядке обхода его в ширину (рис. 1.31). р-кодом Ли дерева Т называется последовательность номеров единиц ВА. Евстигнеев, В.Н. Касьянов
34 1.2.16. Код Гапта. для 2-3-дсрсньен в w-коде дерева Г, перечисленных в порядке их возрастания (см. рис. 1.31). Поуровневый позиционный код Ли дерева Т высоты h (см. рис. 1.31) — это последовательность М- М2, ..., где — последователь- ность номеров внутренних вершин уровня /, перечисленных в порядке их возрастания. Рис. 1.31 1.2.16. Код Гаптадля2-3-деревьев. Последовательность чисел ^, ... ...,а* называется кодом Гапта 2-3-дерева Т с внутренними вершинами (ключами), если ее можно получить при обходе внутренних вершин де-
1.2.18. Я-представление упорядоченных деревьев 35 рева Т по уровням снизу вверх, начиная с самого нижнего и кончая корнем, путем выписывания количества сыновей вершин, составляющих каждый уровень, в порядке их расположения слева направо (рис. 1.32). (2, Л Л 3) 1.2.17. Классификационная схема линейных кодов. Классифика- ционное дерево линейных кодов представлено на рис. 1.33. В соответ- ствии с приведенной классификацией различаются восемь групп линей- ных кодов. Повторное вхождение символов Наличие ограничителей Использование количественной характерист ики 1.2.18. ^-представление упорядоченных деревьев. Пусть ..., ап — натуральные числа; R-вектор определяется следующим образом: а) если V = (а.), то V есть Я-вектор; б) если V1? ...,Vfl —Я-векторы, то (ар-ар ],...,[Уа ])
36 1.2.19. Машинное представление деревьев с помощью адресной арифметики — также есть Я-вектор, где [ ] — операция формального огбрасывания круглых скобок; в) никакие векторы, кроме указанных в пп. а), б), не являются Я-векторами. Отображение ф множества упорядоченных деревьев в множество R- векторов определяется следующим образом: а) если дерево Т состоит из одной вершины л, то ф(Т) = (а); б) если а — корень упорядоченного дерева Т и 7\,..., Тп — поддеревья Т, то ф(Т) = (л, -л, [</>(7;) ],..., [0(Т ) ]). Пример. Я-вектор, соответствующий дереву Т (рис. 1.34), есть (1,-4, 2, -2, 4, 3, 21,-2, 5, 6, 8, 17, -3, 9, 11, 20). Как нетрудно заметить, Я-вектор есть линейный код с ограничите- лями. 1.2.19. Машинное представление деревьев с помощью адресной ари- фметики. Данное представление есть практическая реализация прин- ципа рассмотрения деревьев как графов данных (см. п. 1.2.4). Форми- ровать деревья с помощью адресной арифметики можно двумя спосо- бами. Идея первого способа применима при любом постоянном количес- тве дуг, выходящих из вершины, но мы изложим ее на примере двоично- го дерева. Пусть имеется вектор памяти А. Тогда начинаем с кванта А [ 1 ], делая его корнем дерева, кванты А [2 ] и А [3 ] — его непосредствен- ными потомками. Вообще непосредственные потомки кванта А [Л ] — это кванты А[2Л] и А[2Л+ 1]. По дереву, которое при этом получается, можно двигаться в обоих направлениях, так как из вершины А [Л ] можно перейти к ее потомкам, удвоив к или удвоив к и прибавив единицу, а можно в обратном направлении, к родителю вершины А [Л], разделив к пополам и отбросив дробную часть. Можно было бы сделать корнем квант А [0 ]; это оказывается удобнее для деревьев более общего вида. Другой способ, основанный на адресной арифметике, применим толь- ко для двоичных деревьев. Если для представления двоичного дерева используется вектор памяти от кванта i до кванта j включительно, то корнем делаем квант m = [(/ + /)/2], т.е. середину вектора, в квантах от
1.2.20. Машинное представление деревьев с использованием сцепления 37 f-го до (т - 1)-го включительно размещаем левое относительно корня поддерево, в квантах от (т + 1)-го до /-го включительно — правое относительно корня поддерево. 1.2.20. Машинное представление деревьев с использованием сцеп- ления. В п. 1.2.3 были рассмотрены представления деревьев в виде списков смежности и их машинная реализация в виде структур, состоящих из звеньев, представляющих собой машинные слова, сцеплен- ные между собой указателями. Здесь рассмотрим общий подход к такому представлению, который состоит в том, что через их программы мы име- ем доступ к корню дерева, т.е. храним адрес корня; на приводимых ниже рисунках это изображается в виде стрелки, которая указывает на верхний элемент. Начав со звена, к которому привела стрелка входа в дерево, можно затем продвигаться по памяти, следуя указателям. Но возвращаться по указателям нельзя; и если необходимо возвратиться по своему следу, то нужно либо завести дополнительные указатели, чтобы ориентация структуры стала двусторонней, либо применить какое-то другое средство. Для структур, о которых здесь идет речь, существует много названий: просто ’’структуры” в языках ПЛ /1 и Алгол-68, ’’многосвязные списки” и специально изобретенное слово ’’плексы”. Примеры. Дерево Т: Представление дерева с помощью многосторонних списков с исполь- зованием двухкомпонентных звеньев, в которых в первом поле нахо- дится либо указатель, либо метка вершины, а во втором — всегда указа- тель (см. п. 1.2.3), имеет вид: ей ей ей ей Представление дерева с помощью двусторонних списков, аналогии-
38 1.3.1. Помеченные деревья ное предыдущему представлению, но с петлями и контурами указателей, благодаря чему достигается двусторонность, выглядит как Представление дерева с помощью односторонних списков с использо- ванием звеньев одинакового размера (одно поле для данных и три поля указателей в каждом слове) имеет вид Представление дерева с помощью двусторонних списков с использо- ванием звеньев переменного размера, снабженных счетчиками, в кото- рых задается количество указателей в данном звене, выглядит как . 1.3. Перечисление и подсчет деревьев 1.3.1. Помеченные деревья Теорема Кэли. Число tn помеченных деревьев с п вершинами равно t =гГ2. п Теорема Скойнса. Число 2-раскрашенных деревьев с т вершинами одного цвета и п вершинами другого равно
1.3.2. Непомеченные деревья 39 S ’«'"'wi"’' п Теорема Рида. Число помеченных гомеоморфно несводимых деревьев равно 1.3.2. Непомеченные деревья. Пусть Т(х) = Л=1 — производящая функция для корневых деревьев. Таким образом, Тп представляет собой число корневых деревьев с п вершинами. Теорема Пойа. Перечисляющий ряд корневых деревьев удовлетворя- ет соотношению Т(х) = х • ехр{^ Т(.?) /к}. к=1 (*) Из этой теоремы следует, что Т(х) однозначно определяется функциональным уравнением (*), из которого выводится следующая формула для ТС:), принадлежащая Кэли: Т(х) = хД(1 Числа корневых деревьев с п вершинами для п < 26 найдены Риорда- ном, а для п < 39 — Швенком. fl Т(п) /1 ТОО 1 1 14 32 973 2 1 15 87 811 3 2 16 235 381 4 4 17 634 847 5 9 18 1 721 159 6 20 19 4 688 676 7 48 20 12 826 228 8 115 21 35 221 832 9 286 22 97 055 181 10 719 23 268 282 855 И 1 842 24 743 724 984 12 4 766 25 2 067 174 645 13 12 486 26 5 759 636 510 Здесь содержатся первые 26 значений функции Т(п). Следующая рекурсивная функция для вычисления Т(п) принадле- жит Оттеру:
40 1.3.3. Перечисление лесов пТ(п + 1) = Т(1) • S(n, 1) + 2T(2)S(n,2) + ... + nT(n)S(n, m), где S(n,k) = % Т(п + 1 -j+k). \<j<n/k Пусть w = 2 *3' /1 = 1 — производящая функция для деревьев, так что ttl есть число деревьев с п вершинами. Теорема Оттера. Ряд /(х), перечисляющий деревья, выражается че- рез ряд Т(х) для корневых деревьев с помощью формулы t(x) = Т(х) - ^(х) - Цх2)). Значения / для п < 26 вычислены Риорданом и приведены ниже: н bi п bi 1 1 14 3 159 2 1 15 7 741 3 1 16 19 320 4 2 17 48 629 5 3 18 123 867 6 6 19 317 955 7 11 20 823 065 8 23 21 2 144 505 9 47 22 5 623 756 10 106 23 14 828 074 11 235 24 39 299 897 12 551 25 104 606 890 13 1 301 26 279 793 450 1.3.3. Перечисление лесов. Пусть перечисляющим многочленом для лесов с п вершинами будет функция где Д q — число лесов с п вершинами и q ребрами. Тогда производящая функция для лесов имеет вид /1 = 1 Теорема Харари — Палмера. Перечисляющий многочлен для лесов
1.3.4. Ориентированные деревья 41 с п вершинами имеет вид п (1 4- / — 1 \ /.^)=sn * * И,у*. (/) Ь=1 \ Jk ) где сумма берется по всем разбиениям (J) числа п. Здесь числа tk имеют тот же смысл, что и в п. 1.3.2. Для п = 6 многочлен /6(х) имеет вид f,(x) = 1 + х + 2л2 + 4х3 + 6х4 + бх5. Число лесов выражается через число деревьев с помощью следующих формул, принадлежащих Харари: 1 + f(x, у) = ехр{£ § (tk/n)(xk~l/)n} , п=1 к=1 1 +f(x, у) = И к=1 1.3.4. Ориентированные деревья. Пусть г(х) и R(x) — перечисля- ющие ряды для ориентированных и для корневых ориентированных де- ревьев соответственно. Теорема Харари — Принса. Перечисляющие ряды г(х) и R(x) для ориентированных и корневых ориентированных деревьев удовлетворя- ют соотношениям R(x) = х(ехр{^ Я(х*)/Л})2 и г(х) =Я(х) - Д2(х). Первые 21 коэффициент рядов г(х) и R(x) найдены Риорданом. Ниже приводятся значения коэффициентов тп ряда г(х) ирп ряда R(x): п гп Рп 1 1 1 2 1 2 3 3 7 4 8 26 5 27 107 6 91 458 7 350 2 058 8 1 376 9 498 9 5 743 44 947 10 24 635 216 598 11 108 968 1 059 952 12 492 180 5 251 806
42 1.3.5. Гомеоморфно несводимые деревья 1.3.5. Гомеоморфно несводимые деревья. Пусть Л(х), Н(х) и Н(х) обозначают перечисляющие ряды для следующих трех классов гомео- морфно несводимых деревьев: а) ’’обычных”, б) корневых и в) с висячими корнями. __ Теорема Харари — Принса. Перечисляющие ряды Жх), Жх) и Л(х) для гомеоморфно несводимых деревьев удовлетворяют соотношениям ад = -Ц^ад - уз(Я2(х) + ЯСх2)) Л(х) = -Н(х) + Ц^ад. Л Л Для первых 12 членов ряд h(x) имеет вид Л(х) = х + х2 + х4 + х5 + 2х6 + 2х7 + 4х8 + 5х9 + 10х10 + 14х11 + 26х12 + .... 1.3.6. Плоские или упорядоченные деревья. Если в плоском дереве в смысле п. 1.1.2 выделен корень, то практически имеем дело с упорядо- ченными деревьями. Для них имеет место _ Теорема Харари — Принса — Татта. Если Р(х), Р(х) и р(х) — перечисляющие ряды для соответствующих трех типов плоских де- ревьев: с висячими корнями, корневых и просто деревьев, то Р(х) = x%(Z(CnP(x)/x)), р(х) = Р(х) - (W) [?(%) - Р(х2) ]. Несколько первых членов ряда р(х) имеют вид р(х) = х + х2 + х3 + 2х4 + Зх5 + бх6 + 14х7 + .... Ряд Р(х) является также перечисляющим рядом для таких плоских деревьев с висячими корнями, у которых каждая вершина имеет степень I или 3. Точнее, число плоских деревьев порядка и, имеющих висячие корни, совпадает с числом плоских деревьев с висячими корнями, обла- дающих п - 2 вершинами степени Зил-1 вершинами степени 1. Двой- ственным утверждением к рассмотренному является следующее: ряд Р(х) перечисляет число способов триангулирования выпуклого м-уголь- ника, в котором одна из сторон выделена как корень и ориентирована; триангулирование при этом осуществляется путем проведения диагона- лей, не имеющих точек пересечения, отличных от вершин м-угольника. Коэффициенты ряда Р(х), называемые обычно числами Каталана, подсчитывают также число неассоциативных произведений с п сом- ножителями. 1.3.7. Каркасы в неориентированном графе. Число каркасов в не- ориентированном графе определяется с помощью следующей матричной
1.3.8. Каркасы в ориентированных графах 43 теоремы о деревьях в графе. Пусть М(О обозначает матрицу, получае- мую из матрицы А «7), где A (G) — матрица смежности графа (7, с по- мощью подстановки в ней на место z-ro диагонального элемента числа deg V,-. Матричная теорема о деревьях для графов. Для всякого связного помеченного графа G все алгебраические дополнения матрицы М«7) равны друг другу и их общее значение представляет собой число карка- сов графа (7. Пример. Для графа G (рис. 1.35) с матрицей смежности А(0 = 0 110 10 10 110 1 0 0 10 матрица М«7) имеет вид М((7) = 2-1-1 0 -12-10 -1 -1 3 -1 0 0-1 1 Алгебраическое дополнение, например, элемента л14, равно 3. Соот- ветствующие каркасы графа G показаны на рис. 1.36. Рис. 1.35 Интересен также следующий результат. Пусть G — п-вершинный граф без петель и Во — его матрица инциденции с одной удаленной строкой (т.е. с п~ 1 независимыми строками). Пусть В'о — транс- понированная матрица к Во. Тогда определитель I Во • В'о I равен числу остовных деревьев графа G. 1.3.8. Каркасы в ориентированных графах. Число каркасов в ориен- тированном графе определяется с помощью аналогичной матричной тео- ремы о деревьях в орграфе. Пусть G — орграф с матрицей смежности А «7). Определим диагональную матрицу Мои1, у которой (z, 0-й элемент равен полустепени исхода deg"v2 вершины vi. Затем положим Cou( = Mout - А (С?. Аналогично определяется матрица Cin = Min - А ((7). Матричная теорема о деревьях для орграфов. Все алгебраические дополнения i-й строки матрицы Сои1 равны друг другу, и их общее зна- чение есть число каркасов орграфа G, входящих в вершину у- Двойст- венным образом общее значение алгебраических дополнений i-го столб- ца матрицы Cin равно числу каркасов, выходящих из вершины Пример. Для графа G (см. рис. 1.35) матрицы Сои( и Cin имеют вид:
44 1.4. Библиографический комментарий 2-1 0 0-1 0 2-1-1 О О 0 1-10 0-1-1 0 -1 -1 0 0 0 1 1-1 0 0-1 О 2-1-10 О 01-10 0-10 2-1 -1 0 0 0 2 Используя их, убеждаемся сразу, исходя из первой строки матрицы Cout и из первого столбца матрицы Cin, что орграф G имеет в точности четыре каркаса, выходящих из вершины 1, и два каркаса, входящих в эту вершину (рис. 1.37). Рис. 1.37 1.4. Библиографический комментарий С точки зрения классической теории графов деревья — мало привле- кательный объект, в монографиях по теории графов им редко отводится больше одной главы. Иное отношение к деревьям в прикладной теории графов: они играют важную роль в программировании, теории инфор- мационных систем, электротехнике, химии и пр. Предлагаемый в дан- ной главе материал (особенно это касается п. 1.1 и отчасти пп. 1.2 и 1.3) можно найти в большинстве монографий по теории графов. В основном мы ориентировались на монографии Ф.Харари и А.А.Зыкова. Материал п. 1.1.10 заимствован из статьи [2 ], а пп. 1.1.11 —1.1.14 — из книги [6 ]. Представление деревьев как графов данных было исследовано в рабо- тах А.Розенберга, их изложение и библиографию можно найти в обзоре
Список литературы 45 [3 ]. Результаты, связанные с представлением деревьев в виде кода Прю- фера, взяты из статьи [1], оттуда же взято понятие оптимального кодирования. Кодирование деревьев с помощью обходов вершин наибо- лее полно рассмотрено в работе [5] и диссертации А.П.Завады [4]. Описанные в пп. 1.2.12—1.2.18 коды и представления деревьев рассмат- ривались в работах [2, 12—16]. Следует также указать на препринт В.К.Попкова [8 ], посвященный этой тематике, а также на работу Д.Кну- та [7 ], где отдельный большой раздел посвящен деревьям, в частности прошитым деревьям, представлениям деревьев, в том числе представ- лениям произвольных корневых деревьев бинарными деревьями и пр. Описанное же в данной главе машинное представление деревьев изложе- но по книге П.Холла [11 ]. По материалам [ 10 ] написан п. 1.3 с привлечением цифровых данных из [9 ]. К этим же работам мы отсылаем и за библиографическими справками. СПИСОК ЛИТЕРАТУРЫ 1. Анисимов А.В. Об оптимальной упаковке деревьев// Кибернетика. — 1976. — № 3. — С.89—91. 2. Анисимов А.В., Карпенко И.В., Крижановский В.В. Представление упорядоченных де- ревьев// Там же. — 1980. — №3. — С.29—34. 3. Евстигнеев В. А. Графы адресуемых данных// Комбинаторно-алгебраические методы в прикладной математике. — Горький, 1986. — С.39—60. 4. Завада А.П. Исследование средних оценок вычислительной сложности алгоритмов обработки структур данных типа дерева. — Автореф. дне.... канд. физ.-мат.наук (05.13,11). —Киев, 1987. 5. Завада А.П., Кожевникова Г.П. К анализу алгоритмов над деревьями. Векторные коды. Генерация случайных структур и характеристика дерева// Кибернетика. — 1984. — № 5. — С.12—18. 6. Касьянов В.Н. Оптимизирующие преобразования программ. — M.: Наука, 1988. 7. Кнут Д. Искусство программирования для ЭВМ. Т.1. Основные алгоритмы. — M.: Мир, 1976. 8. Попков В.К. Представление деревьев.— Новосибирск, 1981. — 26 с. — (Препринт/ АН СССР, Сиб. отд-ние, ВЦ; 242). 9. Риордан Дж. Введение в комбинаторный анализ. — М.: Изд-во иностр, лит., 1963. 10. Харари Ф., Палмер Э. Перечисление графов. — М.: Мир, 1977. 11. Холл П. Вычислительные структуры. Введение в нечисленное программирование. — М.: Мир, 1978. 12. ВеуегТ., Hedetniemi S.M. Constant time generation of rooted trees//SIAM J. Computing. — 1980. — Vol. 9, N4. — P. 706—712. 13. Gupta U., Lee D.T., Wong C.K. Ranking and unranking of 2-3 trees//Ibid. — 1982. — Vol. 11,N3. — P.582—590. 14. LeeC.C., Lee D.T., Wong C.K. Generating binary trees of bounded hight//Acta Informatica. — 1986. — Vol. 23, N6. — P.529—544. 15. Zaks S. Lexicographic generation of ordered trees//Theor. Comp. Sci. — 1980. — Vol. 10, N1. — P.63—83. 1 6. Zerling D. Generating binary trees using rotations //J. ACM. — 1985. — Vol. 32, N3. — P.694—701.
Глава 2 модели вычислений, сложное 1Ь И ОСНОВНЫЕ АЛГОРИТМЫ 2.1. Введение и язык представления алгоритмов 2.1.1. Вводные замечания. В данной главе описывается подход, ис- пользуемый в книге для представления алгоритмов и анализа их коррек- тности и сложности, а также рассматриваются классы алгоритмов реали- зации основных обходов графов и деревьев (п. 2.2) и конструирования деревьев с заданными свойствами (п. 2.3). В основе подхода лежит специальный язык высокого уровня (ВУ- язык), который позволяет формулировать алгоритмы работы с деревь- ями в естественной форме, допускающей прямой анализ их коррект- ности и сложности, а также простой перенос алгоритмов на традици- онные языки программирования и ЭВМ с сохранением полученных оце- нок сложности. ВУ-язык содержит не только средства, ориентированные на задачи обработки деревьев, но и способы реализации этих средств на уровне равнодоступной адресной машины (РАМ), включающие оценки их сложности. РАМ — математическая модель вычислений, которая является хоро- шим приближением к классу обычных, традиционных вычислительных машин с точки зрения отражения затрат времени и памяти при представ- лении данных и алгоритмов, целиком помещающихся в оперативной памяти. 2.1.2. РАМ. Равнодоступная адресная машина моделирует вычисли- тельную машину с одним сумматором, в которой команды программы не могут изменять сами себя. РАМ состоит из входной ленты, с которой она может только считывать, выходной ленты, на которую она может только записывать, и памяти (рис. 2.1). Хп Входная лента (только читать) Счетчик команд Программа Сумматор >’/ У 2 Уз У4 У5 Рис. 2.1
2.1.2. РАМ 47 Входная лента РАМ — это последовательность клеток, содержащих записи целых чисел и доступных для считывания по одной в соответствии с их упорядоченностью. Выходная лента состоит из неограниченной последовательности клеток, которые вначале все пусты; при выполнении команды записи происходит печать целого числа в первой свободной клетке выходной ленты. Память РАМ — это последовательность подряд пронумерованных ячеек, каждая из которых способна хранить двоичную запись произволь- ного целого числа. Обращение к значению, хранимому в некоторой ячей- ке, осуществляется по адресу (номеру) этой ячейки. Ячейка с номером О называется сумматором. Адресация может быть не только абсолютной, когда явно указывается номер ячейки, но и косвенной. При косвенной адресации указывается адрес некоторой другой ячейки (называемой ссылкой, или указателем), содержимое которой рассматривается в каче- стве абсолютного адреса адресуемой ячейки. Состояние памяти — это отображение Wадресов в двоичные слова, сопоставляющее каждому адресу п то слово Win), которое хранится (со- держится) в ячейке с адресом и. Программа — это конечная последовательность команд, занумеро- ванных числами 1,2,3,.... Счетчик команд — это переменная, принима- ющая значение из множества неотрицательных целых чисел. Состояние вычисления (конфигурация) — это четверка (х, W, к, у), где х — непрочитанная часть входной ленты, W — состояние памяти, к — значение счетчика команд, а у — заполненная часть входной ленты. Выполнение РАМ-программы начинается с выполнения ее первой ко- манды, нормально завершается выполнением команды останова и описывается протоколом выполнения — последовательностью конфигу- раций, в которой конфигурация (х, W, 1, е), где х — вход, е — пустая цепочка и W(k) = 0 для любого к, является первой (начальной), а каждая следующая конфигурация, если она имеется, получается из текущей выполнением команды, номер которой указан в текущей конфигурации. Конфигурация, в которой счетчик команд равен нулю (ошибочная кон- фигурация) или номеру команды останова, может быть только последней (заключительной) конфигурацией протокола выполнения. Если выпол- нение РАМ-программы нормально завершается, то его результат — запись на выходной ленте, находящейся слева от печатающей головки. Каждая команда РАМ имеет имя (код операции) и операнд. Операнд может быть одного из следующих типов: ”=/" — означает само число i и называется литералом*, "Г — содержимое ячейки z; ”*z” — используется для косвенной адресации, т.е. значением операнда служит содержимое ячейки, адрес которой имеется в ячейке с номером и Обозначая через Via) значение операнда а, получаем: V(=i) = i; Vii) = VK(z) и V(*i) = W(W(i)), где W — текущее состояние памяти. Набор команд РАМ традиционен для реальных ЭВМ и состоит из следующих групп: — команды считывания и запоминания: =>а, где а имеет вид "=Г или — запоминает число, равное текущему содержимому сумматора (обозначим его через Д, т.е. W(Q) = А), в ячейке, адрес которой равен Via); "<=а" — присваивает сумматору значение Via);
48 2.1.3. Вычислительная сложность РАМ-программ — арифметические и логические команды: [+] а, В а, [3 я — присваивают сумматору значения Д + Via), Д - Via), Д ♦ Via) соответственно;0 а, [#| а, 0 а, 0 а, Г<1 а, ГТ] а — присваивают сумматору значения Д = Via), Д # Via), А > Via), Д < Via), Д < Via), Д > Via) соответственно;Q а — присваивает сумматору целую часть от деления Д на Via), если Via) О, и присваивает счетчику команд ноль, если Via) « 0; Г7] а, [71 a. PI а — присваивают сумматору значения Д v Via), Д AV id), -• Via) соответст- венно; ___ — команды перехода: |на| а — присваивает счетчику команд зна- чение Via); |пер|= i — присваивает счетчику команд значение i, если Д — это истинное значение; ______ — команды ввода и вывода: |ввод| а, где а имеет вид "-Г или ’’Г, — присваивает ячейке с адресом Via) содержимое доступной клетки вход- ной ленты либо присваивает ноль счетчику команд, если уже вся лента прочитана; |вывод | а — печатает на выходную ленту значение Via); — команда останова: |стоп| — завершает исполнение программы. Предполагается, что, если это не оговорено особо, каждая команда при своем выполнении увеличивает значение счетчика команд на едини- цу, если она не последняя в программе, а последняя присваивает счет- чику команд ноль. Пример. Программа с рис. 2.2 осуществляет нахождение наиболь- шего общего делителя двух целых чисел. Здесь метка отделяется от ко- манды двоеточием, а команды РАМ-программы перечисляются через точку с запятой. 1: |ввод|= 1; 2: |ввод|=2; 3: <= 1; 4: И 2; 5: |пер| = 17; 6: * 1; 7: 0 2; 8: |пер| = 13; 9: * 1; Ю: □ 2; 11: => =1; 12: [на] =3 13: ГЯ 2: 14: ЕЕ] 1; 15: => = 2; 16: Гна~|= 3; 17: 1 ВЫВОД |= 1; 18: 1СТОП1. Рис. 2.2 2.1.3. Вычислительная сложность РАМ-программ. Имеются два подхода к определению времени, необходимого для выполнения команд РАМ, и объема памяти, используемого каждым регистром РАМ. При равномерном весовом критерии считается, что каждая РАМ-ко- манда затрачивает одну единицу времени и каждый регистр использует одну единицу памяти. Если не оговорено противное, то сложность РАМ- программы будет измеряться в соответствии с равномерным весовым критерием. Логарифмический весовой критерий учитывает ограниченность раз- мера реальной ячейки памяти в ЭВМ и основывается на предположении, что объем памяти, необходимый для хранения значения, равен длине
2.1.4. Свойства РАМ, связь РАМ с другими моделями вычислений 49 двоичного представления этого значения (т.е. для целого числа п > О требуется /(и) ж [log2 + 1 единиц памяти), а время исполнения ко- манды пропорционально длине ее операндов (например, время команды <= i равно /(0, команды => i — + Z(Z), а команды[3 ♦ i — Z(VK(O)) + + KWiiY) +/dF(IF(z)))). Временная сложность в худшем случае (или просто временная слож- ность) РАМ-программы — это функция/,пах(п), равная наибольшей (по всем входам размера п) из сумм времен, затраченных на каждую срабо- тавшую команду при обработке одного входа размера и. Временная сложность в среднем — это среднее/ave(n), взятое по всем входам размера п, тех же самых сумм. Временная сложность в лучшем случае — это функция/min(M), равная наименьшей (по всем входам размера п) из сумм времен, затраченных на каждую сработавшую команду при обработке одного входа размера п. При равновероятном появлении входов значение/ахе (и) равно сумме времен, затраченных на каждую сработавшую команду при обработке всех входов размера м, деленной на количество входов размера и. Такие же понятия определяются для емкости памяти, только вместо ’’времен, затраченных на каждую сработавшую команду”, надо под- ставить в определение фразу: ’’емкость всех регистров, к которым было обращение”. Обычно рассматривается поведение указанных выше сложностных функций в пределе при увеличении размера входа, поскольку именно асимптотическая сложность алгоритма определяет в итоге размер задач, которые можно решить этим алгоритмом. Для описания асимптотичес- кого поведения сложностных функций используется следующий фор- мализм. Говорят, что функция f(ri) не больше по порядку, чем g(n) (обозна- чение f(n) e O(g(n))), если существует такая константа с > 0, что почти для всех п (т.е. для всех, кроме конечного множества, значений п) спра- ведливо f(n) < с • g(n). Функциями) не меньше по порядку, чем g(n) (обозначение f(n) - Q(g(n))), если существует такая константа с > 0, что f(n) > с • g(n) для почти всех п. Функции f(n) и g(n) одного и того же порядка (обозначенияf(n) » ®(g(n)) wwif(ri) Н g(n)), если/(п) - O(g(n)) nf(n) = Q(g(n)). 2.1.4. Свойства РАМ, связь РАМ с другими моделями вычислений. Пусть ,..., хп — целые числа, находящиеся в п первых клет- ках входной ленты, и пусть программа Р записывает у в первую клетку выходной ленты, а затем через некоторое время останавливается. Тогда говорят, что Р вычисляет функцию /Ц, х„) =у. А. Множество РАМ-программ вычисляет класс частично рекурсив- ных функций. Пусть на входной ленте находится цепочка s « xt х2... хп в алфавите {1, 2, ..., г}, причем символ Xj расположен в первой клетке, х2 — во вто- рой и т.д., а в (п+1)-й клетке расположен 0 — символ, который будет использоваться в качестве концевого маркера. Входная цепочка s допу-
50 2.1.5. Труднорешаемые и NP^полные задачи скается РАМ-программой Р, если Р прочитывает все ее символы и кон- цевой маркер, пишет 1 в первой клетке выходной ленты и останавлива- ется. Языком, допускаемым программой Р, называется множество всех цепочек (слов), допускаемых ею. Б. Язык допускается некоторой РАМ тогда и только тогда, когда он рекурсивно перечислим. Язык допускается РАМ, останавливающей- ся на всех входах, тогда и только тогда, когда он рекурсивен. Модель вычислительной машины, получившая название РАСП, отличается от РАМ лишь тем, что ее программа находится в памяти и может изменять себя. В. Как при равномерном, так и при логарифмическом весах команд для любой РАМ-программы (соответственно РАСП-программы) с временной сложностью Т(п) существует такая постоянная к, что найдется эквивалентная РАСП-программа (соответственно РАМ- программа), временная сложность которой не превосходит к • Т(п), РАМ с логарифмическим весом и машины Тьюринга (МТ) полино- миально связаны. При равномерном весе нет полиномиальной связи между РАМ и МТ, хотя любую МТ с временной сложностью Т(п) > п можно промоделировать некоторой РАМ за время О(Т(п)). Ниже приведены затраты времени, требуемые машине А для мо- делирования работы алгоритма сложности Т(п) на машине В; 1 МТ — машина Тьюринга с одной лентой, К МТ — машина Тьюринга с К лен- тами (табл. 2.1): Таблица 2.1 Моделируемая машина В Моделирующая машина А 1 МТ К мт РАМ 1 МТ — 0(700) 0(700 logTOO) к мт Otftn)) — 0(700log700) РАМ О(Т2(/0) — 2.1.5. Труднорешаемые и АР-полные задачи. Полиномиальным ал- горитмом (или алгоритмом полиномиальной временной сложности) на- зывается алгоритм, у которого временная сложность равна О(/(«)), где f(n) — некоторая полиномиальная функция. Задача называется труднорешаемой, если для ее решения не сущест- вует полиномиального алгоритма. Класс NP — это класс задач распознавания свойств (т.е. задач, реше- ниями которых могут быть либо ”да”, либо ’’нет”), которые могут быть решены за полиномиальное время на недетерминированной РАМ при логарифмическом весовом критерии. (Недетерминированная РАМ полу- чается из РАМ добавлением команды ВЫБОР (Lp L2, Lr), означаю- щей, что недетерминированы выбор и последующее выполнение одного из операторов Д, ..., Lr,) Большинство практически важных задач, для которых в настоящее время не известны полиномиальные алгорит- мы, после переформулировки их в виде задач распознавания свойств попадают в этот класс.
• 2.1.7. Векторы, записи, шкалы и массивы 51 Задача из NP называется NP-полной, если всякая другая задача из класса NP может быть сведена к ней за полиномиальное время. Таким образом, если для некоторой NP-полной задачи существует полиноми- альный алгоритм, то и любая задача из класса NP полиномиально раз- решима, а если какая-то задача из NP труднорешаема, то и любая NP- полная задача является труднорешаемой. 2.1.6. ВУ-язык и структура ВУ-программы. Данный язык в качестве базовых содержит традиционные конструкции математики и языков программирования. Наряду с обычными для современных языков типами простых и составных данных он позволяет такие более сложные структу- ры данных, как, например, деревья, графы и т.д. (см. пп. 2.1.8—2.1.10). Для каждой базовой конструкции ВУ-языка фиксируется класс ее до- пустимых реализаций на РАМ. Предполагается, что ВУ-язык позволяет наряду с базовыми использовать любые необходимые конструкции, если очевидны или заранее зафиксированы оценки их сложности, а также те реализации этих конструкций на РАМ, которые допускают указанные оценки. ВУ-программа представляет собой последовательность глобальных описаний переменных, процедур и функций, за которой следует опера- тор вызова основной процедуры. Все процедуры и функции могут рабо- тать с глобальными переменными и иметь локальные переменные, а так- же формальные параметры; при этом скалярные параметры подставля- ются по значению, а структурные — по ссылке. В основе системы типов ВУ-языка лежит конечное множество дан- ных, неделимых (простых) с точки зрения имеющихся в языке операций и образующих подмножества, называемые простыми типами данных и состоящие из целых, вещественных чисел, логических и литерных дан- ных, ссылок и меток. Другие типы данных (составные) строятся из прос- тых типов с помощью нескольких операций, обычно называемых конст- рукторами типов. Ниже перечисляются некоторые из основных способов структурирования составных данных в ВУ-языке. 2.1.7. Векторы, записи, шкалы и массивы. Наиболее простой струк- турой данных является вектор — последовательность равных по объему элементов, расположенных в памяти РАМ подряд. Зная адрес начального элемента вектора и размер одного его элемента, можно за фиксирован- ное время осуществить доступ к любому элементу вектора по его номеру. Обобщенный вектор (или запись) состоит из разнообъемных элемен- тов, расположенных подряд. Для доступа за фиксированное время к эле- ментам записи достаточно иметь, аналогично предыдущему, ссылку на начальный элемент и вектор смещений элементов относительно началь- ного элемента. Часто в силу своего размера несколько элементов вектора (или запи- си) могут быть записаны в одной ячейке — так называемые упакованные векторы (или записи). Важным частным случаем упакованного вектора является шкала (или битовый вектор), когда каждый элемент вектора занимает один бит. Логические (покомпонентные) операции над шка- лами будем обозначать через О, о, о и называть расширенными
52 2.1.9. Графы и деревья (элементарными) операциями РАМ. Таким образом, логическая опе- рация над шкалами длины г требует г элементарных шагов РАМ и только один расширенный шаг, а доступ к произвольному элементу занимает фиксированное время как в элементарных, так и в расширенных шагах. Существует такое расположение элементов многомерного массива в виде вектора, которое позволяет за фиксированное время осуществить доступ к любому элементу массива по его индексам. Перечисленные структуры данных представляют собой совокупность собственно информационных элементов и управляющей информации, задающей их расположения. Будем предполагать, что эта управляющая информация вынесена в специальные записи, называемые паспортами (или дескрипторами), что позволяет иметь общую программу доступа для всех объектов одного и того же типа. 2.1.8. Строки, очереди, стеки и списки. Строка — это конечная по- следовательность однотипных элементов. Существенным для строки яв- ляется то, что доступ к ее элементам (и любая другая работа с ними) всегда осуществляется в соответствии с их упорядоченностью: он на- чинается с первого или последнего элемента строки и продолжается пе- реходом от текущего элемента к следующему в строке или предыдущему. Строками специального вида являются стеки и очереди. В этих строках доступ возможен только к начальному элементу и означает его удаление из строки, а вставка элемента осуществляется таким образом, что добав- ляемый элемент становится новым начальным в случае стека или новым конечным в случае очереди. Для строк естественной отображающей структурой является список, представляющий собой совокупность записей, каждая из которых со- стоит из управляющей и собственно информационной частей. При этом в зависимости от реальных операций над строкой в управляющей части содержится информация об адресах предыдущего и последующего эле- ментов (двусторонний список) или информация только об адресе после- дующего элемента (односторонний список), а дескриптор списка наряду со ссылкой на первый и текущий элементы списка может включать ссыл- ку на его последний элемент. Такие операции над списками, как взятие первого элемента из списка А с его удалением или без удаления (обозна- чение э А и э А), добавление элемента а в список А (обозначение А «- а) и сочленение двух списков А и В (обозначение A U В), можно выполнить за ограниченное (постоянной величиной) число шагов, а операцию до- бавления элементов списка В в список А (обозначение А <= В) — за число шагов, пропорциональное длине списка. 2.1.9. Графы и деревья. Различные представления графов и деревьев описаны в п. 1.2. Нетрудно увидеть, что для графа с п вершинами и т дугами любое такое представление требует порядка п + т элементов памяти и позволя- ет за фиксированное время осуществлять доступ к любой вершине или дуге графа, выбирать первого предшественника или преемника, а также следующего предшественника или преемника (если доступ к текущему элементу уже осуществлен), выбрать первую (или следующую) дугу, исходящую из данной вершины или заходящую в нее, определить на-
2.1.10. Наборы 53 чальную НАЧАЛО (и) или конечную КОНЕЦ (и) вершины заданной дуги и. Множества предшественников р, преемников р, дуг, заходящих ври исходящих из р, будем обозначать через ПРЕД(р), ПРЕЕМ (р), ЗАХОД (р) и ИСХОД (р) соответственно. Каждое из рассмотренных представлений деревьев требует порядка п элементов памяти, где п — число вершин дерева, и, как правило, позво- ляет за фиксированное время выбирать по любой вершине р ее отца (обозначение ОТЕЦ(р)), брата (обозначение БРАТ(р)) и сына (обозна- чение СЫН(р)), а также проверять, является ли вершина корнем, лис- том или внутренней вершиной. Укладки, обходы, нумерации и разметки (вершин или дуг графа) суть отображения из некоторого множества [1 : Л], k > 1, где элементами это- го множества являются имена вершин или дуг в случае обходов, нуме- раций или разметок. Поэтому для них отображающей структурой явля- ется вектор. В зависимости от реальных операций над данным обходом, нумерацией или разметкой (если она имеет вид отображения из [1 : к ] на множество [1 : Л]) дополнительно вводится вектор, представляющий об- ратное отображение к указанному. 2.1.10. Наборы. Пусть дано некоторое множество А. Под набором над А (построенным над множеством А) понимается такая структура дан- ных, которая описывает некоторое разбиение множества А (вначале на одноэлементные подмножества) и позволяет выполнять операции сле- дующих двух типов. Слить В с С, где В и С — некоторые подмножества из текущего состояния набора. Результатом этой операции является замена в наборе множеств В и С на множество С = С U В. Найти а, где а — элемент из А. Выдается имя того множества из набора, которому в данный момент принадлежит элемент а. Вначале именем одноэлементного подмножества является имя элемента, образу- ющего это подмножество. Существует такая реализация набора на РАМ, при которой любая последовательность, состоящая из п операций слить и не более т опе- раций найти, может быть выполнена за время О (т • а(т,п)), гдеа(т,п) — очень медленно растущая функция, обратная функции Аккермана. Эта реализация предполагает задание набора в виде помеченного гра- фа, образованного совокупностью г деревьев, где г — число подмножеств в текущем состоянии набора. Вершинами каждого дерева являются эле- менты одного подмножества, а корень дерева помечен именем этого под- множества. Считается, что операция найти а осуществляет следующую последовательность действий: вначале определяется вершина а в графе, затем осуществляется прохождение пути из этой вершины в корень со- держащего ее дерева Т и определение имени множества, метящего этот корень. В процессе прохождения пути (а., ..., а) от вершины а до корня осуществляется его сжатие — такое преобразование дерева, в результате которого каждая из вершин а{, ..., а[ч становится сыном корня (рис. 2.3). Выполнение операции слить В с С осуществляется в следующие два этапа: сначала выбираются те два корня, которые помечены именами В и С; затем корень меньшего (по числу вершин) из двух деревьев преобра-
54 2.1.1!. Структуры действий зуется в сына корня второго (большего) дерева, которому и приписыва- ется имя С. При этом предполагается, что указанный граф представляется в памяти РАМ таким образом, что объем необходимой памяти составляет порядка I А I элементов, операция слить выполняется за фиксированное число шагов, а время выполнения операции найти о является линейным относительно длины пути от вершины а до соответствующего корня. Любая последовательность действий над набором, состоящая из О(м) слияний подмножеств и О(т) нахождений элементов, может быть вы- полнена за время O(min(n log п + т)> (я + т) х а(и, пг)). 2.1.11. Структуры действий. В ВУ-языке применяются традици- онные конструкции языков программирования, такие как выражения, условия, операторы и процедуры. Помимо набора операций и операто- ров, ориентированных на работу со структурированными данными (пп: 2.1.6—2.1.10), в ВУ-языке имеется ряд базовых конструкций, нефор- мальное описание которых дается ниже. А. Операторы присваивания. Оператор переменная := выражение задает присваивание переменной скалярного значения выражения или ссылки на его составное значение. Таким образом, временная сложность оператора присваивания определяется как время, затрачиваемое на вычисление выражения, плюс единица. Выполнение группового опера- тора присваивания (переменная!, переменная2,..., переменная//) := (выражение!,..., выражение2,..., выражение?/) состоит из двух последовательно выполняемых шагов: вычисления зна- чений ’’значение 1”,.../’значение А” всех выражений, стоящих в правой части, и N присваиваний, К-е из которых имеет вид ’’выражение К := значение К”.
2.1.11. Структуры действий 55 Б. Составной и условный операторы. Составной оператор — это серия операторов, заключенных в операторные скобки начало и конец; время его выполнения равно сумме времен выполнения операторов, сос- тавляющих серию. Имеются две формы условных операторов: если условие то серия операторов иначе серия операторов все, если условие то серия операторов все. Время выполнения условного оператора складывается из времен, тре- буемых на проверку условия и выполнения соответствующей серии опе- раторов’ В. Операторы прерывания. Любой из операторов ВУ-программы можно сделать помеченным, написав перед ним метку через двоеточие. Главное назначение метки — дать возможность оператору прерывания, имеющему одну из следующих форм: завершить метка при условие, завершить метка, начать метка при условие, начать метка, остановить текущее выполнение помеченного оператора данной меткой. При этом завершить-оператор выводит за помеченный оператор, а на- чать-оператор приводит к его новому выполнению. Если оператор пре- рывания содержит условие, то переход осуществляется только при истинном его значении. Сложность оператора прерывания равна вре- мени, требуемому на проверку условия, плюс единица. Г. Операторы цикла. Имеются следующие виды операторов цикла: пока условие цикл серия операторов все, повторять серия операторов до условие все цикл серия операторов все, для переменная от начальное значение до конечное значение через шаг цикл серия операторов все для переменная от начальное значение до конечное значение цикл серия операторов все, для всех переменная из выражение цикл серия операторов все. В пока-операторе при истинности условия происходит выполнение серии операторов, и этот процесс повторяется до тех пор, пока условие не станет ложным. Время, требуемое на его выполнение, получается суммированием времен, необходимых для всех сделанных проверок ус- ловия и всех осуществляемых выполнений серии операторов. Повторять-оператор трактуется аналогично, но в нем серия операто- ров выполняется до проверки условия, и истинность условия завершает выполнение цикла. Оператор цикл S все эквивалентен оператору пока истина цикл S все.
56 2.1.12. Процедуры и функции В для-операторе начальное значение, конечное значение и шаг явля- ются выражениями, которые вычисляются один раз в начале выполнения оператора, а шаг, равный 1, иногда опускается. В для-всех-операторе сначала вычисляется выражение, значением которого является составной объект, как правило, строка. Затем выпол- няется серия операторов для каждого элемента вычисленного составного объекта, взятого в качестве значения переменной. Например, если А — непустая строка, не изменяемая при выполнении оператора S, то опера- тор для всех х из А цикл S все эквивалентен оператору повторять х :s э Л; S до A s 0 все, т.е. оператор В <= А эквивалентен оператору для всех а из А цикл В а все. Анализ сложности повторять-оператора, цикл-оператора, для-опе- ратора и для-всех-оператора должен быть очевиден в свете предыдущего анализа пока-оператора. Д. Описание переменных. Осуществляется с помощью оператора переменная : тип « выражение, в котором либо выражение, задающее начальное значение переменной, либо тип переменной могут отсутствовать. Сложность оператора описания на единицу больше времени, необходимого для вычисления выражения. Следует заметить, что обычно переменные не будут описываться, если их смысл легко восстанавливается из контекста. 2.1.12. Процедуры и функции. Процедурный механизм поддержи- вается следующими видами операторов: проц имя (список формальных параметров)88 серия операторов все, проц имя = серия операторов все, функ имя (список формальных параметров) » серия операторов все, функ имя « серия операторов все, возврат выражения, вызвать имя (список фактических параметров), вызвать имя. В ВУ-программе можно определить и впоследствии вызвать процеду- ры и функции. После того как функция описайа с помощью функ-опера- тора, к ней можно обратиться в любом выражении, вызывая ее по имени с нужными фактическими параметрами. При обращении к функции пос- ледним оператором, выполняемым в данной функции, должен быть воз- врат-оператор. Этот оператор приводит к окончанию выполнения обра- щения к функции и выдает в качестве его результата значение выра- жения, стоящего за словом возврат. Процедура описывается с помощью проц-оператора, и к ней можно обратиться с помощью вызвать-оператора, содержащего нужные фак- тические параметры. В процессе выполнения вызвать-оператора обычно изменяются объекты, глобальные по отношению к процедуре. В опреде- лении процедуры возврат-оператор не нужен: завершение выполнения серии операторов, образующей тело процедуры, завершает и выполне-
2.2.1. Рекурсивный алгоритм обхода графа в глубину 57 ние вызвать-оператора. Слово вызвать в операторе обращения к проце- дуре может отсутствовать. Время на обращение к процедуре или к функции равно времени, требуемому на выполнение соответствующей серии операторов плюс длина списка формальных параметров. 2.1.13. Дополнительные средства. В ВУ-программу можно вставлять комментарии (например, в виде номеров операторов, начинающих строки, изображающие операторы ВУ-программы, или в виде отдельного оператора % примечание %, имеющего нулевую сложность), а также ис- пользовать практически все, что читаемо и недвусмысленно. 2.2. Обходы графов и деревьев в глубину и ширину 2.2.1. Рекурсивный алгоритм обхода графа в глубину. Необходимость в алгоритмах обходов графов и деревьев в глубину и ширину (см. п. 1.1.13) возникает во многих приложениях. Например, они существенно исполь- зуются при решении задач искусственного интеллекта, являются базо- выми в алгоритмах проверки связности, планарности и других свойств графов, а также в методах решения задач динамического распределения памяти. В данном пункте приводятся общие алгоритмы, осуществляющие раз- ные обходы графов при разных реализациях их структур данных, ал- горитмы обхода графа в глубину и ширину, ориентированные на разные представления графа, а также алгоритмы основных способов обхода деревь- ев и лесов в глубину — в префиксном, инфиксном и постфиксном порядках. Все приведенные алгоритмы имеют линейную временную сложность. Используя рекурсивную процедуру, линейный по временной слож- ности алгоритм обхода графа G в глубину можно записать следующим образом: проц РЕКУРСИВНЫЙ-ОБХОД(р : вершина) - Посетить вершину р; для всех q из множества вершин, смежных с р цикл если q еще не посещалась то РЕКУРСИВНЫЙ-ОБХОД(<7) все все все; для всех р из множества вершин G цикл если р еще не посещалась то РЕКУРСИВНЫЙ-ОЬХОД(р) все все. 2.2.2. Общий алгоритм обхода графа с запоминанием дуг. Задача Объекты. Ориентированный граф G, каждая вершина которого может находиться в одном из двух состояний: ’’помечена”, ’’непомечена".
58 2.2.2. Общий алгоритм обхода графа с запоминанием дуг Операции. Для любой вершины р графа G операция ПОМЕТИТЬ (р) выполнима, если р находится в состоянии ’’непомечена”, и при своем выполнении переводит р в состояние "помечена", а предикат НЕПОМЕ- ЧЕНА (р) ложен, если р находится в состоянии "помечена". Дано. Задана вершина р0 такая, что каждая вершина графа G, достижимая из р0, находится в состоянии "непомечена". Требуется. Перевести в состояние "помечена" все вершины гра- фа G, достижимые из р0. Замечание. Предполагается, что процедура ПОМЕТИТЬ (р) при своем выполнении осуществляет определенные действия с информаци- онным содержимым вершины р, для реализации которых и производится обход графа. Решение Программа проц ЛЕС (р0: вершина) = 1. S : семейство дуг в 0; 2. q : вершина - р0; 3. L : начало ПОМЕТИТЬ (q); .4. S<= ИСХОДА); 5. пока 5^0 цикл 6. :я КОНЕЦ (э S); 7. если НЕПОМЕЧЕНА(^) то начать L все все конец все Пояснения. Рассмотрим граф, изображенный на рис. 2.4. При выполнении ЛЕС(р0) состояние S меняется следующим образом: 0, {UpUj.Uj}, {w2,u3},{u2,u3,u4}, {u3,u4}, {и4},{и6,и5,и4}, {us,u4}, {u4},0, а вершины графа посещаются в следующей последовательности: Ро> РгРг Рис. 2.4
2.2.4. Алгоритм обхода графа в ширину с использованием внешней очереди 59 Свойства.*, 1. Временная сложность алгоритма составляет О(к) времени, где к — число дуг графа G, достижимых из вершины р0. 2. Алгоритм изменяет состояние непомеченной вершины q тогда и только тогда, когда q достижима из р. 3. Если S является стеком, то процедура помечает вершины графа G, достижимые из р0, в порядке поиска в глубину, а если S — очередь, то вершины помечаются в порядке поиска в ширину. 2.2.3. Общий алгоритм обхода графа с запоминанием его вершин. Задача Та же, что в алгоритме 2.2.2. Решение Программа проц ЛЕС 1(р0: вершина) = 1. S : семейство вершин = 0; 2. S «-р0; ПОМЕТИТЬ(р0); 3. пока 5*0 цикл 4. q :=э S; 5. для всех р из ПЕРЕМ (q) цикл 6. если НЕПОМЕЧЕНА(р) то 7. ПОМЕТИТЬ(р); S <- р все все все все Пояснение. Рассмотрим выполнение ЛЕС1 (р0), где р — вершина графа на рис. 2.4. В нем S принимает следующую последовательность значений: 0, (Ро),0, (P2,Pj), (P,),0. Свойства. Для алгоритма 2.2.3 справедливы все свойства алго- ритма 2.2.2 с тем отличием, что если S является стеком, то ЛЕС1 может помечать вершины графа G, достижимые из р0, в порядке, отличном от их обхода при поиске в глубину. 2.2.4. Алгоритм обхода графа в ширину с использованием внешней очереди. Задача Объекты. Упорядоченный ориентированный граф G, каждая вер- шина которого может находиться в одном из трех состояний: ’’непомече- на", ’’помечена и непройдена”, ’’пройдена”, а каждая дуга — в одном из двух состояний: ’’пройдена”, ’’непройдена”. Операции. Для любой вершины q графа G операция ДУГА(^) выдает имя первой дуги, исходящей из q, либо ничто, если q — лист (т.е.
60 2.2.4. Алгоритм обхода графа в ширину с использованием внешней очереди нет исходящих из q дуг), ПОМЕТИТЬ^) переводит вершину q из состо- яния ’’непомечена" в состояние ’’помечена и непройдена”, ПРОЙТИ- ВЕРШИНУ(^) переводит вершину q из состояния ’’помечена и непройде- на” в состояние ’’пройдена”, а предикат НЕПОМЕЧЕНА^) выдает зна- чение истина, если q находится в состоянии ’’непомечена”. Для любой дуги w графа G операция СЛ ЕД (w) выдает имя следующей дуги, исходящей из той же вершины, что и w, либо ничто, если w — последняя исходящая дуга, а ПРОЙТИ-ДУГУ(и>) переводит дугу из состояния ’’непройдена” в состояние ’’пройдена”. Дано. Каждая дуга графа G, достижимая из заданной вершины р0, находится в состоянии ’’непройдена”, а каждая вершина, достижимая из р0, — в состоянии "непомечена”. Требуется. Перевести в состояние "пройдена” все вершины и дуги графа G, достижимые из р0, выполняя над ними каждую из опе- раций ПОМЕТИТЬ, ПРОЙТИ-ВЕРШИНУ и ПРОЙТИ-ДУГУ в поряд- ке первого попадания в них при обходе графа G в ширину, начиная с р0. Пример. Для графа G с рис. 2.5, а и его вершины 1 в состояние ’’пройдены” должны перейти все те его вершины и дуги, которые образу- ют дерево, изображенное на рис. 2.5, б. Вершины проходятся (и помеча- ются) в порядке 1,2,5,6,3,4, а (1,2), (1,5), (1,6), (2,3), (3,4) — порядок прохождения дуг. Решение Программа процОБХОД-В-ШИРИНУ(р0: вершина) в 1. Q : очередь вершин = 0; 2. ПОМЕТИТЬ (р0); 3. пока Q цикл 4. Q; w ДУГА(^); 5. пока w # ничто цикл 6. ПРОЙТИ-ДУГУ (w); 7. р := КОНЕЦОг); 8. если НЕПОМЕЧЕНА(р) то
2.2.5. Алгоритм обхода графа в ширину с использованием внутренней очереди 61 9. ПОМЕТИТЬ(р); Q <- р все; 10. и>:= СЛЕДО0 все; 11. ПРОЙТИ-ВЕРШИНУ («/) все все Пояснения. Процедура ОБХОД-В-ШИРИНУ базируется на ал- горитме 2.2.3. В ней уточняются реализация семейства S, а также дей- ствия цикла 5—7 по последовательному выбору всех преемников вер- шины q. Кроме этого в процедуру ОБХОД-В-ШИРИНУ добавляются действия по прохождению дуг, а действия по прохождению вершин раз- биваются на две части — ПОМЕТИТЬ и ПРОЙТИ-ВЕРШИНУ. Свойства. 1. Временная сложность алгоритма составляет О(к + /) времени, где к и t — количества дуг и вершин графа G, достижимых из р0. 2. При выполнении ОБХОД-В-ШИРИНУ (р0) операция ПОМЕТИТЬ применяется к любой вершине qy достижимой из р0, перед обработкой операцией ПРОЙТИ-ДУГУ всех дуг w, исходящих из д, а операция ПРОЙТИ-ВЕРШИНУ — после этой обработки. 3. В каждый момент выполнения ОБХОД-В-ШИРИНУ(р0) размер очереди Q не превышает величины 1 - 1, где t — число вершин графа G, достижимых из р0. 2.2.5. Алгоритм обхода графа к ширину с использованием внутрен- ней очереди. Задача Объекты. Ориентированный граф G и некоторая вершина qy не принадлежащая графу G. Вершины графа могут находиться в одном из двух состояний: "непомечена", "помечена". Вершине q и каждой вершине графа G приписан атрибут СЛЕД, значением которого может быть имя любой вершины графа. Операции. Для любой вершины р графа G логическая операция НЕПОМЕЧЕНА (р) выдает значение истина, если р в состоянии "непо- мечена", операция ПРОЙТИ-ВЕРШИНУ (р) переводит вершину из сос- тояния "непомечена" в состояние "помечена". Дано. Каждая вершина графа G находится в состоянии "непомече- на", а значением #.СЛЕД является имя некоторой вершины р0 графа G. Требуется. Перевести в состояние "помечена" все вершины гра- фа G, достижимые из р0, выполняя над ними операцию ПРОЙТИ-ВЕР- ШИНУ в порядке первого попадания в них при обходе графа G в ширину, начиная с р0. Решение Программа проц ОБХОД-В-ШИРИНУ-1 = 1. р :» q. СЛЕД; ПРОЙТИ-ВЕРШИНУ (р);
62 2.2.6. Алгоритм обхода графа в ширину без использования дополнительной памяти 2. пока р # q цикл 3. q := ^.СЛЕД; 4. для всех г из ПРЕЕМ (q) цикл 5. если НЕПОМЕЧЕНА(г) то 6. ПРОЙТИ-ВЕРШИНУ(г); 7. р.СЛЕД := г; р := г все все все р.СЛЕД := ничто все Пояснения. Процедура ОБХОД-В-ВЕРШИНУ-1 является уточ- нением алгоритма 2.2.3. В ней с помощью вершины q и атрибута СЛЕД реализуется S в режиме очереди: если р « q, то очередь S пуста; при р # q очередь состоит из элементов </.СЛЕД, (q.СЛЕД).СЛЕД, ..., р0. Оператор 3 исключает элемент из очереди, а оператор 7 добавляет новый элемент в очередь. Свойства. 1. Время выполнения ОБХОД-В-ШИРИНУ-1 составляет О(к + /) времени, если Ли/ — количества дуг и вершин графа G, достижимых из р0 соответственно. 2. После завершения выполнения процедуры ОБХОД-В-ШИРИНУ-1 последовательность р0, р0.СЛЕД, (р0.СЛЕД).СЛЕД, ..., р, где р.СЛЕД = ничто, содержит все вершины графа G, достижимые из р0, причем в порядке применения к ним операции ПОСЕТИТЬ-ВЕРШИНУ. 2.2.6. Алгоритм обхода графа в ширину без использования допол- нительной памяти. Задача Объекты. Упорядоченный ориентированный граф G, каждая вер- шина которого может находиться в одном из трех состояний: "непомече- на", ’’помечена и непройдена” и ’’пройдена", а каждая дуга — в одном из двух состояний: "пройдена” и "непройдена". Каждой вершине и дуге графа G приписан атрибут СВЯЗЬ, значением которого может быть имя любой вершины или любой дуги графа. Операции. Помимо операций ПОМЕТИТЬ, ПРОЙТИ-ВЕРШИ- НУ, НЕПОМЕЧЕНА и ПРОЙТИ-ДУГУ, описанных в алгоритме 2.2.4, имеется логическая операция СВЯЗЬ-ДУГА(Е), значением которой яв- ляется истина, если Е.СВЯЗЬ — это имя дуги. Дано. Каждая дуга w графа G, достижимая из заданной вершины р0, находится в состоянии "непройдена”, причем значением атрибута и\СВЯЗЬ является либо имя следующей дуги, исходящей из той же вершины, что и w, либо ничто, если w — последняя исходящая дуга. Каждая вершина р графа G, достижимая из р0, находится в состоянии "непомечена", причем значением атрибута р.СВЯЗЬ является либо имя первой дуги, исходящей из р, либо ничто, если р — лист. Т ребуется. То же, что и в алгоритме 2.2.4.
2.2.6. Алгоритм обхода графа в ширину без использования дополнительной памяти 63 Решение Программа проц ОБХОД-В-ШИРИНУ-2(р0: вершина) = 1. F:-p; У :=р; ПОМЕТИТЬ(р0); 2. пока Г.СВЯЗЬ # ничто цикл F := ЛСВЯЗЬ все; 3. пока V * ничто цикл 4. Е := V; 5. пока (Е.СВЯЗЬ # ничто) Л СВЯЗЬ-ДУГА(Е) цикл 6. Е := Е.СВЯЗЬ; ПРОЙТИ-ДУГУ(Е); 7. <?:= КОНЕЦ (Е); 8. если НЕПОМЕЧЕНА(^) то 9. ЕСВЯЗЬ := F := q\ 10. ПОМЕТИТЬ^); 11. пока Г.СВЯЗЬ # ничто цикл 12. F:= Г.СВЯЗЬ все все все; 13. ПРОЙТИ-ВЕРШИНУОО; V- Е.СВЯЗЬ; 14. Е.СВЯЗЬ :« ничто все все Пояснения. Процедура ОБХОД-В-ШИРИНУ-2 базируется на алгоритме 2.2.4, но использует для реализации очереди вместо внешней памяти места расположения пустых ссылок, с необходимостью возника- ющие при стандартном представлении графа списками исходящих дуг. В этой реализации алгоритм поддерживает очередь в виде множества вер- шин и дуг, связанных в односторонний список значениями атрибута СВЯЗЬ, который содержит вместе с каждой помеченной вершиной все исходящие из нее дуги (см. рис. 2.6, на котором схематично изображено представление графа с рис. 2.5, а в тот момент, когда вершины 1, 2 и 5 перешли в состояние "помеченных”). Когда вершина q помечается (стро- ка 10), включаются в очередь она сама (строка 9) и все исходящие из нее дуги (строки 11, 12). После прохождения вершины (строка 13), ничто опять становится значением атрибута СВЯЗЬ последней дуги, исходя- щей из этой вершины (строки 13, 14). В процедуре ОБХОД-В-ШИРИ- НУ-2 используются три локальные переменные: V — вершина, которая проходится; Е — обработанный элемент списка, реализующего очередь; F — последний элемент этого списка. Свойства. 1. Алгоритм требует на выполнение О(Л + 0 времени, где к и t — количества дуг и вершин графов, достижимых из р0. 2. В процессе выполнения процедуры ОБХОД-В-ШИРИНУ-2(р0) каждой элемент списка дуг, достижимых из р0, обрабатывается дважды: первый раз только для установки F (строки 2 и 11, 12), а второй — при выполнении ПРОЙТИ-ДУГУ (строка 6).
64 2.2.7. Алгоритм обхода в ширину графа с циклическими списками дуг Начало очереди Рис. 2.6 2.2.1. Алгоритм обхода в ширину графа с циклическими списками дуг. Задача Объекты и операции. Те же, что и в алгоритме 2.2.6. Дано. Каждая дуга графа G, достижимая из заданной вершины р0, находится в состоянии ’’непройдена”, причем каждое множество дуг, исходящих из одной и той же вершины, через атрибут СВЯЗЬ связано в циклический список. Каждая вершина q графа G, достижимая из р0, находится в состоянии ’’непомечена’’, причем значением атрибута ^.СВЯЗЬ является либо имя одной из дуг, исходящих из <7, либо ничто, если q — лист. Требуется. То же, что и в алгоритме 2.2.4. Р е ш е н и е Программа проц ОБХОД-В-ШИРИНУ-3(р0: вершина) « 1. У :=р0; ПОМЕТИТЬ(р0); 2. если р0 .СВЯЗЬ « ничто то 3. F := р0 4. иначе F :в .СВЯЗЬ; р0.СВЯЗЬ :в Г.СВЯЗЬ; 5. КСВЯЗЬ :» ничто
2.2.7. Алгоритм обхода в ширину графа с циклическими списками дуг 65 все; 6. пока V * ничто цикл 7. £:= V; 8. пока СВЯЗЬ-ДУГА(Р) цикл 9. Е := Р.СВЯЗЬ; ПРОЙТИ-ДУГУ(Е); р ~ КОНЕЦ(Р); 10. если НЕПОМЕЧЕНА(р) то 11. ПОМЕТИТЬ(р); Р.СВЯЗЬ := />; 12. если р.СВЯЗЬ = ничто то 13. Г:=Р 14. иначе F := р.СВЯЗЬ; р.СВЯЗЬ := Р.СВЯЗЬ; 15. Р.СВЯЗЬ := ничто все все все; 16. ПРОЙТИ-ВЕРШИНУ(У); 17. если У=Рто 18. V := Р.СВЯЗЬ; Р.СВЯЗЬ ничто 19. иначе (V, КСВЯЗЬ, Р.СВЯЗЬ) := (Р.СВЯЗЬ, Р, КСВЯЗЬ) все все все Пояснение. В отличие от алгоритма 2.2.6 процедура ОБХОД-В- ШИРИНУ-3 не обрабатывает списки исхрдящих дуг дважды (ликви- дируется первая обработка, целью которой является перевычисление Р). Это достигается за счет нетрадиционного представления графа G: множе- ства исходящих дуг образуют по атрибуту СВЯЗЬ не односторонние списки, а односторонние циклы (сравни рис. 2.6 и 2.7, а). После того как Рис. 2.7 3 ВА. Евстигнеев, В.Н. Касьянов
66 2.2.9. Алгоритм обхода бинарного дерева в глубину с внешним стеком метится некоторая вершина w (операторы 1 и 11), разрывается односто- ронний цикл исходящих дуг между его первой и последней дугами, до- бавляются w и ее исходящие дуги к концу очереди, перевычисляется F (см. рис. 2.7, б). После выполнения операции ПРОЙТИ-ДУГУ(Е) вос- станавливается односторонний цикл дуг, исходящих из w (операторы 17—19). Некоторое увеличение размера процедуры ОБХОД-В-ШИРИ- НУ-3 по отношению к ОБХОД-В-ШИРИНУ-2 объясняется тем фактом, что пустые циклы дуг требуют специальной обработки. 2.2.8. Способы прохождения бинарных деревьев. Для прохождения бинарного дерева в глубину можно воспользоваться тремя способами: проходить вершины в префиксном (или прямом) порядке, в инфиксном (или обратном) порядке и, наконец, в постфиксном (или концевом) по- рядке. Эти три способа определяются рекурсивно следующим образом. В случае, когда бинарное дерево пусто, оно проходится без выполнения каких-либо действий; в противном же случае прохождение состоит из трех действий, одних и тех же для разных способов, но выполняемых в разных последовательностях: префиксный порядок — посетить корень, пройти левое поддерево, пройти правое поддерево; инфиксный порядок — пройти левое поддерево, посетить корень, пройти правое поддерево; постфиксный порядок — пройти левое поддерево, пройти правое подде- рево, посетить корень. Применяя это определение к бинарному дереву с рис. 2.8, получаем, что при префиксном порядке прохождения вершины посещаются в последовательности 1, 2, 3, 4, 5, 6, 7, 8, 9, при инфиксном — 3, 2, 1,5, 6, 4, 8, 7, 9, а присюстфиксном порядке — 3, 2,6,5, 8,9, 7, 4, 1. 2.2.9. Алгоритм обхода бинарного дерева в глубину с внешним сте- ком. Задача Объекты. Бинарные деревья, каждая вершина которых может на- ходиться в одном из двух состояний: "непройдена", ’’пройдена’’.
2.2.9. Алгоритм обхода бинарного дерева в глубину с внешним стеком 67 Операции. Для любого имени дерева Т операция КОРЕНЬ (Г) выдает корень дерева с именем 7, а операции ЛДЕРЕВО(Т) и ПДЕРЕ- В0(7) — имена деревьев, являющихся соответственно левым и правым поддеревьями дерева с именем 7. Операция ПРОЙТИ-ВЕРШИНУ (р) переводит любую заданную вершину р из состояния ’’непройдена” в сос- тояние ’’пройдена”. Дано. Каждая вершина заданного бинарного дерева Т находится в состоянии "непройдена”. Требуется. Перевести все вершины дерева Т в состояние "прой- дена”, выполняя над ними операцию ПРОЙТИ-ВЕРШИНУ в инфикс- ном порядке обхода дерева. Решение Программа проц ОБХОД-ДЕРЕВА(Т : дерево) = 1. S : стек деревьев * 0; 2. D : дерево =7; 3. L: цикл 4. если D « ничто то 5. если S = 0 то 6. закончить L 7. иначе D := э S все; 8. ПРОЙТИ-ВЕРШИНУ (KOPEHb(D)) 9. D :=ПДЕРЕВО(D) 10. иначе S Z>; D := ЛДЕРЕВО(£>) все все все Пояснения. Алгоритм осуществляет инфиксный порядок про- хождения вершин дерева. Когда выполнение достигает оператора 10, правила обхода требуют обработки того дерева R, имя которого хранится в переменной D. Поэтому имя дерева R сохраняется в стеке S, а затем проходится левое поддерево дерева R. Когда прохождение левого подде- рева завершается, выполняется оператор 7 для извлечения запомненного имени R из стека. После прохождения корня дерева R (оператор 8) обра- ботка дерева заканчивается прохождением правого поддерева (оператор 9). Свойства. 1. Начиная с любого выполнения оператора 4, при котором D * ни- что, алгоритм осуществляет прохождение в инфиксном порядке дерева £>, а затем возвращается к выполнению оператора 4 с тем же состоянием стека S, но с D s ничто. 2. Глубина стека S не превышает глубины дерева 7. 3. Если в процедуре ОБХОД-ДЕРЕВА оператор 8 перенести в начало оператора 10, разместив его перед "S <- £>", будет получена процедура, реализующая префиксный обход дерева.
68 2.2.10. Алгоритм обхода в глубину прошитого бинарного дерева 2.2.10. Алгоритм обхода в глубину прошитого бинарного дерева. Объекты. Бинарные деревья, каждая вершина которых может на- ходиться в одном из двух состояний: ’’непройдена”, "пройдена". Вершинам дерева приписаны атрибуты ЛСВЯЗЬ и ПСВЯЗЬ, значениями которых являются имена его вершин. Операции. Для любой вершины р дерева Т логические операции ПВНИЗ(р) и ЛВНИЗ(р) выдают истинные значения, если текущие зна- чения атрибутов р.ПСВЯЗЬ и р.ЛСВЯЗЬ — это имена вершин, явля- ющихся потомками вершины р. Смысл операций КОРЕНЬ и ПРОЙТИ- ВЕРШИНУ тот же, что и в алгоритме 2.2.9. Дано. Каждая вершина р дерева Т находится в состоянии ’’непрой- дена" и имеет следующие значения атрибутов: р.ЛСВЯЗЬ = q, если q — корень левого поддерева вершины р либо пусто правое поддерево у р и q — предшественник р при инфиксном порядке прохождения 7, и ЛСВЯЗЬ = ни- что в противном случае; р.ПСВЯЗЬ = q. если q — корень правого подде- рева вершины р либо пусто правое поддерево у pwq — преемник р при инфиксном порядке прохождения 7, и р.ПСВЯЗЬ = ничто в противном случае (на рис. 2.9 приведены значения атрибутов ЛСВЯЗЬ и ПСВЯЗЬ для вершин дерева 7 из рис. 2.8). Требуется. То же, что и в алгоритме 2.2.9. Программа функ СЛЕД(р : вершина) в 1. р.ПСВЯЗЬ; 2. если ПВНИЗ(р) то 3. пока Л ВНИЗ (q) цикл 4. q := q. ЛСВЯЗЬ все все 5. возврат q все проц ОБХОД-ПРОШИТОГО-ДЕРЕВА (7 : дерево) « 1. р:= К0РЕНЬ(7);
2.2.12. Алгоритм обхода бинарного дерева в глубину без дополнительной памяти 69 2. пока ЛВНИЗ(р) цикл р := р.ЛСВЯЗЬ все; 3. пока р# ничто цикл 4. ПРОЙТИ-ВЕРШИНУ (р); р СЛЕД(р) все все Пояснения. Для любой вершины р функция СЛЕД вычисляет имя вершины, следующей за р в инфиксном порядке обхода дерева, либо выдает ничто, если р — последняя вершина. Оператор цикла 2 при- сваивает переменной р имя вершины, с которой начинается инфиксный обход дерева. Свойства. 1. Атрибуты Л СВЯЗЬ и ПСВЯЗЬ каждой вершины дерева проверяют- ся точно один раз. 2. Число выполнений операции ПРОЙТИ-ВЕРШИНУ равно числу вершин в дереве. 2.2Л1. Замечания к алгоритмам 2.2.9 и 2.2.10. Д.Кнут в работе [10] описал реализации алгоритмов 2.2.9 и 2.2.10 в виде MIX-программ, для выполнения первой из которых требуется 15л + г + 3 единиц времени, а второй — Ил-г + 8, где п — число вершин дерева, г — число вершин, не имеющих правых поддеревьев. Прохождение прошитых деревьев не только требует меньше памяти (в процедуре ОБХОД-ПРОШИТОГО-ДЕРЕВА нет стека, который есть в процедуре ОБХОД-ДЕРЕВА), но и осуществляется несколько быстрее; в случае машины MIX отношение затрачиваемых времен равно примерно 3:2. Прошитые деревья растут почти так же просто, как и обычные, при- чем связи-нити (т.е. ссылки вверх по дереву) можно использовать для вычисления по имени любой вершины р, следующей за ней вершины в префиксном порядке и предыдущей к ней вершины в инфиксном или постфиксном порядке. Эффективность при этом будет такой же, как и при работе алгоритма 2.2.10 (см. [10]). Алгоритм 2.2.10 по существу не пользуется связями-нитями ЛСВЯЗЬ; в функции СЛЕД оператор 2 можно заменить оператором если ЛВНИЗ(р) # ничто то и тем самым получить вариант алгоритма 2.2.10 для прохождения в инфиксном порядке так называемых правопроши- тых деревьев (т.е. в которых проводятся только связи-нити ПСВЯЗЬ). 2.2Л 2. Алгоритм обхода бинарного дерева в глубину без допол- нительной памяти. Задача Объекты. Бинарные деревья и некоторая вершина </0, не принад- лежащая деревьям. Вершины деревьев и qQ имеют по три атрибута: НО- МЕР, ЛСВЯЗЬ и ПСВЯЗЬ. Значениями атрибута НОМЕР являются чис- ла из отрезка [0:3 ], а атрибутов ПСВЯЗЬ и ЛСВЯЗЬ — имена вершин. Дано. Имя корня дерева Т является значением атрибута <70.ПСВЯЗЬ, а 0о.НОМЕР * 2. Значения атрибутов любой вершины q де- рева Т удовлетворяют следующим свойствам: фНОМЕР = 0; ^.ЛСВЯЗЬ = вр, если р — корень левого поддерева у q\ (/.ПСВЯЗЬ sp, если р —
70 2.2.12. Алгоритм обхода бинарного дерева в глубину без дополнительной памяти корень правого поддерева у q; ^.ЛСВЯЗЬ = ничто, если пусто левое под- дерево у q; (/.ПСВЯЗЬ = ничто, если пусто правое поддерево у q. Т ребуется. Обойти в глубину дерево Г, заходя в каждую вер- шину р ровно три раза и увеличивая значение атрибута р.НОМЕР на единицу при каждом заходе в вершину р. Решение Программа проц ОБХОД-ДЕРЕВА-1 = 1. р := qQ.ПСВЯЗЬ; q := ?0; 2. пока р qQ цикл 3. р.НОМЕР := р.НОМЕР + 1; 4. L: если р.НОМЕР = 3 то (р, р.ЛСВЯЗЬ, р.ПСВЯЗЬ, q) := (р.ЛСВЯЗЬ, р.ПСВЯЗЬ, (/, р) 5. иначе если р.ЛСВЯЗЬ # ничто то 6. если р.ЛСВЯЗЬ.НОМЕР = 0 то 7. (р, р.ЛСВЯЗЬ, р.ПСВЯЗЬ, q) := (р.ЛСВЯЗЬ, р.ПСВЯЗЬ, q, р); 8. завершить L все; 9. (р.ЛСВЯЗЬ, р.ПСВЯЗЬ, q) := (р.ПСВЯЗЬ, (/, р.ЛСВЯЗЬ) все все все все Пояснения. В отличие от алгоритма 2.2.9 хранение пути от кор- ня к обрабатываемой вершине р осуществляется не с использованием дополнительной памяти (в процедуре ОБХОД-ДЕРЕВА для этого ис- пользуется стек 5), а внутри дерева путем моделирования стека через значения атрибутов НОМЕР, ЛСВЯЗЬ, ПСВЯЗЬ вершин дерева. При этом q — это верх стека 5, а для любой вершины w значение w.HOMEP равно: нулю, если w еще не включалась в S; единице, если w находится в S и обрабатывается левое поддерево вершины двум, если w находится в S и обрабатывается правое поддерево трем, если w уже удалена из 5. Эта дополнительная информация о вершинах позволяет моделировать S = (ps = q, р^р ..., р0), запоминая имя любой вершины phl как значение атрибута вершины рЬ1: либо атрибута р, .ЛСВЯЗЬ, если р-.НОМЕР = 1, либо атрибута р^.ПСВЯЗЬ, если ргНОМЕР = 2 (рис. 2.10; значения ат- рибута НОМЕР указаны рядом с соответствующими вершинами дерева). Замечание. Использования виртуального корня q0 можно избе- жать, заменив оператор 1 в процедуре ОБХОД-ДЕРЕВА-1 на оператор (р, q) : = (КОРЕНЬ(Т), КОРЕНЬ(Т)) и условие в операторе 2 на выра- жение р.НОМЕР # 3.
2.2.13. Обход в глубину произвольных деревьев и лесов 71 Рис. 2.10 2.2.13. Обход в глубину произвольных деревьев и лесов. От бинар- ных деревьев можно перейти к обычным, используя естественное соот- ветствие между упорядоченными лесами и бинарными деревьями. Указанное соответствие определяется таким образом, что для упоря- доченного леса L и соответствующего ему бинарного дерева Т справед- ливы следующие свойства: 1) L и Т имеют одно и то же множество вершин; 2) вершина р является левым сыном вершины q в Т тогда и только тогда, когда р — левый сын у q в L; 3) вершина р является правым сыном вершины q в Т тогда и только тогда, когда р — брат вершины q в L либо р — корень такого дерева, которое непосредственно следует в L за деревом с корнем q. В рамках этого соответствия способы прохождения бинарного дерева (см. п. 2.2.8), примененные к упорядоченным лесам, принимают следую- щий вид: префиксный порядок — посетить корень первого дерева, прой- ти поддеревья первого дерева (в префиксном порядке), пройти остав- шиеся деревья (в префиксном порядке); инфиксный порядок — пройти поддеревья первого дерева (в инфиксном порядке), посетить корень пер- вого дерева, пройти оставшиеся деревья (в инфиксном порядке); пост- фиксный порядок — пройти поддеревья первого дерева (в постфиксном порядке), пройти оставшиеся деревья (в постфиксном порядке), посе- тить корень первого дерева. Например, для леса, записанного с помощью вложенных скобок (А(В,С(К>), F(J), G)), префиксный порядок определяет.последовательность А, В, С, К. D, Е, Н. F, J, G, инфиксный порядок — В, К, С, Л, Я, В, J, В, G, £>, а постфиксный порядок — К, С, В, Н, J, G, F, Е. D, А. В прошитом бинарном дереве, соответствующем заданному лесу, правые связи-нити идут от самого правого сына к отцу семьи.
72 2.2.14. Алгоритм обхода графа в глубину без использования дополнительной памяти 2.2.14. Алгоритм обхода графа в глубину без использования до- полнительной памяти. Задача Объекты. Упорядоченный ориентированный граф G с одной выде- ленной вершиной <у0, называемой фиктивной. Вершина qQ имеет един- ственного преемника, который обозначается через р0. Каждой вершине р графа G сопоставлено три атрибута: КД — число дуг, исходящих из р, МД — массив из р.КД имен вершин, а также НД — некоторое неотрицательное число, не превышающее р.КД. Дано. Значения атрибутов любой вершины р удовлетворяют следу- ющим свойствам: р.НД = 0 и для любого i G [1 : р.КД] значением р.МД [/ ] является имя г-го преемника вершины р. Требуется. Для всех вершин р графа (7, достижимых из р0, уста- новить значения р.НД # 0, присваивая им ненулевые значения в поряд- ке обхода графа в глубину, начиная с р0. Решение Программа проц ОБХОД-В-ГЛУБИНУ (#0 : вершина) = 1. t: вершина = ничто; 2. q : вершина = <? • 3. #0.НД := 1; р : = <р0.МД[1 ]; 4. L : начало </.МД [#.НД ]:=/;/ •= Q •= р; 5. L1 : начало 6. пока #.НД < </.КД цикл 7. <7.НД:=<7.НД+1; 8. р:-фМД[<7.НД]; 9. если р # ничто то 10. если р.НД = 0 то начать L все все все; 11. если р # ничто то 12. p:=^;Q:=/; 13. t := t/.MDta.HD]; 14. tf.MDftf.HD] :=р; 15. начать LI все конец конец все Пояснения. Уточняет алгоритм 2.2.2 на основе идеи переклю- чения дуг в графе, позволяющей моделировать стек 5 без использования дополнительной памяти (см. также алгоритм 2.2.12). Пусть = /, /2, •••> tm — максимальная последовательность имен вершин графа, в которой /1+1 = = /;.МД Ц..НД ] и /<+1 # ничто для всех L Тогда при выполнении процедуры ОБХОД-В-ГЛУБИНУ текущим состоянием стека S является последова-
2.2.15. Алгоритм прямой нумерации вершин графа 73 тельность * ^.МД[^.НД + 1 ], фМД[<?.НД + 2], ... , #.МД[<?.КД], ^.МДкрНД + I ], ГрМД^.НД+ 2], ..., ^.МД^.КД], ..., /ш.МД[Гт.НД + 1], /,„.МД [/,„.НД + 2], ..., гж.МД[/ж.КД ]; причем операторы 1—3 устанавли- вают стек пустым и р равным р0, оператор 4 добавляет в стек преемников вершины р, оператор 7 помечает вершину как пройденную, а операторы 5— 15 — это реализация цикла 5—7 процедуры ЛЕС (см. алгоритм 2.2.2). Свойства. После завершения выполнения алгоритма атрибуты любой вершины р удовлетворяют следующим свойствам: р.НД > 0, если р достижима из р0; р.КД равно числу дуг, исходящих из р; для всех i значением р.МД [/] является имя z-ro преемника вершины р. 2.2.15. Алгоритм прямой нумерации вершин графа. Задача Объекты. Упорядоченный ориентированный граф С, каждой вершине которого сопоставлен атрибут Nt — некоторое целое из отрезка [О : п ], где п — число вершин из (7. Операции. Для любых вершины р и дуги w операция ПДУГА(р) выдает имя первой дуги, исходящей из р, либо ничто, если р — лист, а СДУГАОу) — имя следующей дуги, исходящей из той же вершины, что и и’, либо ничто, если дуга iv последняя. Операция ПОСЕТИТЬ — произвольная, не изменяющая (7. Дано. р.М = 0 для любой вершины р графа С. Требуется. В качестве значений атрибута Nt сопоставить всем вершинам графа Сих номера в прямой нумерации. Решение Программа проц НОМЕР (р : вершина; NM : целое) » 1. S : стек дуг = 0; 2. р.Л/ := АЛ/; NM := NM + 1; 3. w := ПДУГА(р); ПОСЕТИТЬ(р); 4. L : цикл 5. если iv # ничто то 6. р := КОНЕЦ(и'); 7. если р.Л/ = 0то 8. S - iv; >v := ПДУГА(р); ПОСЕТИТЬ(р); 9. р.М := АЛ/; АЛ/ := АЛ/ + 1 10. иначе iv := СДУГА(и>) все 11. иначе если 5 = 0 то завершить L 12. иначе w := СДУГАО5) все все все все; проц ПРЯМАЯ-НУМЕРАЦИЯ = 1. АЛ/:=1;
74 2.2.16. Алгоритм базисных нумераций графа 2. для всех р из множества вершин графа G цикл если р.Л/ = 0 то НОМ ЕР (р, АЛ/) все все все Пояснения. Действие процедуры ПРЯМАЯ-НУМЕРАЦИЯ на граф G то же, что и при обращении НОМЕР(<70,0), где q(} — фиктивная вершина, соединенная дугой с каждой вершиной графа G, а НО- МЕР (<7о,О) осуществляет обход в глубину расширенного графа (т.е. графа G с фиктивной вершиной qtt), начиная с вершины q(] и приписывая вер- шинам расширенного графа в качестве их атрибутов М элементы после- довательности чисел 0,1,2, ..., и, в порядке первого попадания в вер- шины. Свойства. При выполнении алгоритма каждый оператор проце- дур ПРЯМАЯ-НУМЕРАЦИЯ и НОМЕР выполняется не более шах (и, т) раз, где т — число дуг графа G, а операция ПОСЕТИТЬ применяется к каждой вершине графа G ровно один раз, причем ее применение к вершинам графа осуществляется в порядке возрастания их Л/-номеров. 2.2.16. Алгоритм базисных нумераций графа. Задача Объекты. Упорядоченный ориентированный граф (7, каждой вер- шине которого сопоставлены два атрибута: М и N— числа из отрезка [0 : п ], где п — число вершин графа С. Операции. Помимо операций ПДУГА, СДУГА и ПОСЕТИТЬ, описанных в алгоритме 2.2.15, имеются четыре операции ПРОЙТИ-ДУ- ГУ-ДЕРЕВА, ПРОЙТИ-ПРЯМУЮ-ДУГУ, ПРОЙТИ-ПОПЕРЕЧНУЮ- ДУГУ и ПРОЙТИ-ОБРАТНУЮ-ДУГУ, каждая из которых относит к соответствующему классу ту дугу графа, которая указана в качестве ее параметра. Дано. р.Л/ = 0 и p.N = 0 для любой вершины р графа G. Т ребуется. Сопоставить в качестве значений атрибутов М и N базисные нумерации графа (см. п. 1.1.22) и отнести каждую дугу графа к подходящему классу относительно дерева поиска в глубину (см. п. 1.1.24). Решение Программа проц БАНУМ (р : вершина; АЛ/, NN : целое) = 1. S : стек дуг = 0; 2. р.М := АЛ/; NM := АЛ/ + 1; г := р; 3. w - ПДУГА(р); ПОСЕТИТЬ(р); 4. г := р; 5. L: цикл 6. если w # ничто то 7. р:=КОНЕЦ(т0; 8. еслир.Л/ = 0то 9. ПРОЙТИ-ДУГУ-ДЕРЕВА(и);
2.2.17. Алгоритм обхода графа в глубину с двусторонним прохождением дуг графа 75 10. S *- иг, w := ПДУГА(р); ПОСЕТИТЬ(р); 11. p.M'=NM\NM -~NM+ 1; 12. r:=p 13. иначе если p.N 0 то 14. если г.М < р.М то 15. ПРОЙТИ-ПРЯМУЮ-ДУГУМ 16. иначе ПРОЙТИ-ПОПЕРЕЧНУЮ-ДУГУ (w) все 17. иначе ПРОЙТИ-ОБРАТНУЮ-ДУГУСиО все; 18. := СДУГАСиО все 19. иначе r.N := NN\ NN := NN - 1; 20. если 5 = 0 то завершить L 21. иначе w S; г := HA4AJIO(w); w := С ДУ ГА (w) все все все все; проц БАЗИСНЫЕ-НУМЕРАЦИИ = 1. NM:=i-,NN~n; 2. для всех р из множества вершин графа G цикл 3. если р.М = 0 то БАНУМ (р, NM, NN) все все все Пояснения. Базируется на алгоритме 2.2.15 и свойствах М и N нумераций (см. п. 1.1.12). Переменная г хранит имя вершины, являю- щейся верхом стека вершин. Свойства. 1. При выполнении алгоритма каждый оператор процедур БАЗИС- НЫЕ-НУМЕРАЦИИ и БАНУМ выполняется не более тах(м,щ) раз, где т — число дуг графа G, а операция ПОСЕТИТЬ применяется к каждой вершине графа ровно один раз, причем вершины графа обрабатываются этой операцией в порядке возрастания их М- ном еров. 2. Заменив в строке 1 процедуры БАЗИСНЫЕ-НУМЕРАЦИИ опера- тор NN := п на оператор NN := 1 , а в строке 19 процедуры БАНУМ опера- тор NN := NN - 1 на оператор NN := NN + 1, получаем процедуру, вычис- ляющую дополнительную нумерацию в атрибутах N вершины графа. 2.2.17. Алгоритм обхода графа в глубину с двусторонним прохож- дением дуг графа. Задача Объекты. Упорядоченный ориентированный граф G, каждая вер- шина которого может находиться в одном из двух состояний: ’’помечена”, ’’непомечена”. Операции. Помимо операций ПДУГА, СДУГА и ПОСЕТИТЬ, описанных в алгоритме 2.2.15, имеются операции ВПЕРЕД-ПО-ДЕРЕ-
76 2.2.17. Алгоритм обхода графа в глубину с двусторонним прохождением дуг графа ВУ, НАЗАД-ПО-ДЕРЕВУ, ВПЕРЕД-ВНЕ-ДЕРЕВА и НАЗАД-ВНЕ-ДЕ- РЕВА, не изменяющие граф G, а также ПОМЕТИТЬ и НЕПОМЕЧЕНА, первая из которых, будучи применной к некоторой вершине, переводит ее в состояние ’’помечена”, а вторая выдает истину, если указанная вер- шина находится в состоянии ’’непомечена". Дано. Каждая вершина графа G, достижимая из заданной вершины р0, находится в состоянии "непомечена”. Т ребуется. В порядке обхода графа G в глубину, начиная с р0, перевести все вершины, достижимые из р0, в состояние "помечена" и выполнить над ними операцию ПОСЕТИТЬ, а также применить к каж- дой дуге w графа G, достижимой из р0, операции ВПЕРЕД-ПО-ДЕРЕВУ и НАЗАД-ПО-ДЕРЕВУ, если w — дуга дерева обхода, либо операции ВПЕРЕД-ВНЕ-ДЕРЕВА и НАЗАД-ВНЕ-ДЕРЕВА, если w — не древес- ная дуга. Решение Программа проц ОБХОД-В-ГЛУБИНУ-1 (р : вершина) = 1. S :стек дуг = 0; 2. ПОМЕТИТЬ(р0); р := р0; w := ПДУГА(р); 3. пока (iv # ничто) v (S # 0) цикл 4. если w * ничто то 5. # := КОНЕЩиО; 6. если НЕПОМЕЧЕНА*?) то 7. ВПЕРЕД-ПО-ДЕРЕВУ(10; S <- w; 8. ПОМЕТИТЬ*?); р := w := ПДУГА*?); 9. иначе ВПЕРЕД-ВНЕ-ДЕРЕВАОу); 10. НАЗАД-ВНЕ-ДЕРЕВА(^); 11. . ил:=СДУГА(т0 все 12. иначе w :=5S; ПОСЕТИТЬ(КОНЕЦО0); 13. если 5 = 0 то р :« р0 14. иначе р := КОНЕЦ(э 5) все; 15. НАЗАД-ПО-ДЕРЕВУ(w); w := СДУГА(иО все все; 16. ПОСЕТИТЬ*р0) все Пояснения. Пусть G — граф, приведенный на рис. 2.4, и пусть ПДУГА*р0) = и,, СДУГА*^,) = и2, ПДУГА*р,) = и6. Тогда при вызове ОБХОД-В-ГЛУбИНУ-1(р0) выполнение обрабатывающих операций над элементами графа G будет осуществляться в следующей последователь- ности:* ПОМЕТИТЬ^), ВПЕРЕД-ПО-ДЕРЕВУ(W0, ПОМЕТИТЬ(р2), ВПЕРЕД-ПО-ДЕРЕВУ(w4), ПОМЕТИТЬ*/?,), ВПЕРЕД-ВНЕ-ДЕРЕ- BA(w6), НАЗАД-ВНЕ-ДЕРЕВА(^), ВПЕРЕД-ВНЕ-ДЕРЕВА(н5), НА-
2.2.18. Алгоритм обхода в глубину с двусторонним прохождением дуг 77 ЗАД-ВНЕ-ДЕРЕВА(и5), ПОСЕТИТЬ^), НАЗАД-ВНЕ-ДЕРЕВА(^), ПОСЕТИТЬ(р2), НАЗАД-ПО-ДЕРЕВУ (ut), ВПЕРЕД-ВНЕ-ДЕРЕ- ВА(и2), НАЗАД-ВНЕ-ДЕРЕВА(ы2), ВПЕРЕД-ВНЕ-ДЕРЕВА(и3), НА- ЗАД-ВНЕ-ДЕРЕВА(м3), ПОСЕТИТЬ(р0). Свойства. 1. Пусть q — некоторая вершина графа G, достижимая из р0, и тур туг — последовательность дуг, исходящих из q. Тогда в процессе выполнения процедуры ОБХОД-В-ГЛУБИНУ сначала помечается вершина q, затем последовательно вперед и назад проходятся дуги тур wr и лишь затем посещается вершина q. 2. Операция ПОМЕТИТЬ применяется к вершинам графа, дости- жимым из р0, в порядке их первого посещения при обходе в глубину, а операция ПОСЕТИТЬ — последнего посещения вершин. 2. 2.18. Алгоритм обхода графа в глубину с двусторонним прохож- дением дуг и распределенной реализацией стека. Задача Объекты. Упорядоченный ориентированный граф G, каждая вершина которого может находиться в одном из двух состояний (’’поме- чена”, ’’непомечена”) и имеет в качестве атрибута СВЯЗЬ имя некоторой дуги. Операции. Те же, что и в алгоритме 2.2.17. Дано. Все вершины графа С, достижимые из заданной вершины р0, непомечены и имеют ничто значением атрибута СВЯЗЬ. Требуется. То же, что и в алгоритме 2.2.17. Решение Программа проц ОбХОД-В-ГЛУбИНУ-2 (р0; вершина) = 1. v : дуга = ничто; р : вершина = рп 2. ПОМЕТИТЬ(р0); w := ПДУГА(р0); 3. пока (ту # ничто) V (у # ничто) цикл 4. если w * ничто то 5. ?:= КОНЕЦ (ту); 6. если НЕПОМЕЧЕНА(^) то 7. ВПЕРЕД-ПО-ДЕРЕВУ(ту); 8. ПОМЕТИТЬО/); 9. ((/.СВЯЗЬ, у, р, w) := (v, ту, q, (/.СВЯЗЬ) 10. иначе ВПЕРЕД-ВНЕ-ДЕРЕВА(ту) ; 11. НАЗАД-ВНЕ-ДЕРЕВА(ту) ; 12. ту := ту.СВЯЗЬ все 13. * иначе (ту, у) := (у, КОНЕЦ(у).СВЯЗЬ); 14. ПОСЕТИТЬ(КОНЕЩту)); 15. если у = ничто то р := р0 16. иначе р := КОНЕЦ (у) все;
78 2.2.19. Алгоритм обхода в глубину без дополнительной памяти 17. НАЗАД-ПО-ДЕРЕВУ(и>); w = в^СВЯЗЬ все все; 18. ПОСЕТИТЬ(р0) все Пояснения. Основывается на алгоритме 2.2.17 и использует для представления стека S атрибут СВЯЗЬ вершин графа: для каждой вершины d дерева обхода значением Л.СВЯЗЬ является имя дуги дерева, заходящей в посещаемую вершину р, причем у» ничто, если р « р0. Свойств а. Те же, что и в алгоритме 2.2.17. Замечание. В процессе реализации обхода переменная р нигде не используется и может быть удалена из процедуры ОБХОД-В-ГЛУБИ- НУ-2 (вместе с ее вычислениями), если процедуры прохождения дуг графа не используют имя текущей посещаемой вершины. 2.2.19. Алгоритм обхода графа в глубйну с двусторонним прохож- дением дуг и без использования дополнительной памяти. Задача Объекты. Упорядоченный ориентированный граф G, каждая вершина которого может находиться в одном из двух состояний: ’’помече- на”, ’’непомечена”; атрибут СВЯЗЬ каждого элемента хранит имя неко- торого элемента графа G, а атрибут ВЕРШИНА каждой дуги — имя некоторой его вершины. Операции. Помимо операций ПОМЕТИТЬ, НЕПОМЕЧЕНА, ПОСЕТИТЬ, НАЗАД-ПО-ДЕРЕВУ, ВПЕРЕД-ВНЕ-ДЕРЕВА, НАЗАД- ВНЕ-ДЕРЕВА, ВПЕРЕД-ПО-ДЕРЕВУ, описанных в алгоритме 2.2.17, имеется логическая операция СВЯЗЬ-ДУГА, которая для элемента F графа G выдает истину, если Г.СВЯЗЬ — это имя дуги. Дано. Все вершины графа G, достижимые из заданной вершины р0, непомечены. Для любого элемента d графа G выполнены свойства: б/.СВЯЗЬ = w, если w — имя первой дуги, исходящей из d, либо w — имя следующей за d дуги, исходящей из той же вершины, что и г/.СВЯЗЬ = ничто, если d — лист, либо d — это последняя дуга в списке исходящих дуг; J.BEPIIIMHA s q, если дуга d заходит в вершину q. Т ребуется. То же, что и в алгоритме 2.2.17. Решение Программа проц ОБХОД-В-ГЛУБИНУ-3 (р : вершина) = 1. F :« ничто; ПОМЕТИТЬ(р0); 2. V:« р ; Е У.СВЯЗЬ; 3. пока (Е * ничто) v (У # р0) цикл 4. если Е * ничто то 5. q :« Е.ВЕРШИНА; 6. если НЕПОМЕЧЕНА(^) то 7. ВПЕРЕД-ПО-ДЕРЕВУ (Е); 8. КСВЯЗЬ:=Е;
2.2.20. Алгоритм обхода в глубину графа, представленного в виде массива дуг 79 9. (V, F, Е.ВЕРШИНА) := (q, V, F); 10. ПОМЕТИЛИ V); Е :« У.СВЯЗЬ 11. иначе ВПЕРЕД-ВНЕ-ДЕРЕВА(Е); 12. НАЗАД-ВНЕ-ДЕРЕВА(Е); 13. (Е, F, Е.СВЯЗЬ) := (Е.СВЯЗЬ, Е, F) все 14. иначе пока СВЯЗЬ-ДУГА(Е) цикл 15. (Е, F, ЛСВЯЗЬ) := (Г, ЛСВЯЗЬ, Е) все; 16. У.СВЯЗЬ := Е; ПОСЕТИТЕ И); Е := ЛСВЯЗЬ; 17. (V, Л Е.ВЕРШИНА) := (Л Е.ВЕРШИНА, Ю; 18. НАЗАД-ПО-ДЕРЕВУ (Л); 19. (Е, Л Е.СВЯЗЬ) := (ЛСВЯЗЬ, Е, F) все все; 20. пока F # ничто цикл (Е, F, ЛСВЯЗЬ) := (F, ЛСВЯЗЬ, Е) все; 21. р0.СВЯЗЬ :« Е; ПОСЕТИТЬ (р0) все Пояснения. Базируется на алгоритме 2.2.17, но моделирует стек 5 внутри графа G с использованием атрибутов СВЯЗЬ и ВЕРШИНА. Процедура использует три переменные: V — имя посещаемой вершины, Е — имя проходной дуги, F — так называемая сцепка. Сцепка F определяется по следующим правилам: если Е не является первой дугой, исходящей из V, то F — имя дуги, предшествующей в списке дуг, исходящих из V; если Е — первая дуга, исхоящая из V, то Е = = ничто при V в ponF— имя отца вершины р в дереве обхода при V pQ. На рис. 2.11 для графа G из рис. 2.5 приведены его представления непос- редственно перед прохождением вперед по древесной дуге (4.5) (рис. 2.11, а) и после (рис. 2.11, б), а также после прохождения дуги (5.2) (рис. 2.11 ,в), не принадлежащей дереву (в этот момент Е = ничто). Свойства. 1. Для процедуры ОБХОД-В-ГЛУБИНУ-3 справедливы свойства ал- горитма 2.2.17. 2. В процессе выполнения процедуры ОБХОД-В-ГЛУБИНУ-3 обра- батывается ровно два раза каждый элемент списков дуг, исходящих из вершин, достижимых из р0. 3. После завершения работы процедуры ОБХОД-В-ГЛУБИНУ-3 все элементы графа в качестве атрибутов СВЯЗЬ и ВЕРШИНА имеют те же значения, что и до начала работы процедуры. 2.2.20. Алгоритм обхода в глубину графа, представленного в виде массива дуг, с двусторонним прохождением дуг графа. Задача Объекты. Упорядоченный ориентированный граф G, вершины и дуги которого согласованно занумерованы и номера элементов которого могут выступать в качестве их имен. Имеется массив ПРЕЕМ длины т, где т — число дуг в G, а граф G расширен изолированной вершиной %,
80 2.2.20. Алгоритм обхода в глубину графа, представленного в виде массива дуг называемой фиктивной. Каждой вершине q расширенного графа сопо- ставлены два атрибута: ПД — номер первой дуги, исходящей из <?, либо т + 1, если q — фиктивная вершина, и НД — некоторое неотрицательное число, не превышающее числа дуг, исходящих из q. Операции. Для операций ПОСЕТИТЬ, ВПЕРЕД-ПО-ДЕРЕВУ, НАЗАД-ПО-ДЕРЕВУ, ВПЕРЕД-ВНЕ-ДЕРЕВА, НАЗАД-ВНЕ-ДЕРЕ-
2.2.20. Алгоритм обхода в глубину графа, представленного в виде массива дуг 81 ВА, описанных в алгоритме 2.2.17, имеется возможность в качестве пара- метров указывать номера соответствующих элементов графа G. Имеется также операция ПОМЕТИТЬ, побочный эффект которой состоит в приписывании вершине с указанным номером в качестве атрибута НД числа 1. Дано. Для любой вершины q и дуги w элемент ПРЕЕМ [w] — это номер конечной вершины дуги w, а #.НД = 0. Требуется. Для всех вершин q графа G, достижимых из р0, уста- новить атрибут (/.НД неравным нулю, изменяя нулевые значения атри- бута НД вершин на ненулевые в порядке обхода графа G в глубину, начиная с р0, и выполняя над дугами соответствующие операции про- хождения. Решение Программа проц ОБХОД-В-ГЛУБИНУ-4 (р0: вершина) = 1. р : вершина = 0; q : вершина = р0; 2. tv :== р0.ПД; ПОМЕТИТЬ(р0); 3. пока (w < (q + 1).ПД) V (q * р0) цикл 4. если w < (q + 1).ПД то 5. если ПРЕЕМ [и>].НД = 0то 6. ВПЕРЕД-ПО-ДЕРЕВУ (iv); 7. </.НД := )v - (/.ПД + 1; 8. (q, р, ПРЕЕМ [w]) := (HPEEM[iv], q, р); 9. w :» </.ПД; ПОМЕТИТЬ(</); 10. иначе ВПЕРЕД-ВНЕ-ДЕРЕВА(и>); 11. НАЗАД-ВНЕ-ДЕРЕВА(и>); w:=iv+ 1 все 12. иначе ПОСЕТИТЬ((/); w := р.ПД + р.НД - 1; 13. (</, р, ПРЕЕМ [iv]) := (р, ПРЕЕМbv], q); 14. НАЗАД-ПО-ДЕРЕВУОг); w := w + 1 все; все; 15. ПОСЕТИТЬ(р0) все Пояснения. Базируется на алгоритмах 2.2.17 и 2.2.19 при использовании специального представления графа (см. рис. 2.11, г, где приведено представление в виде массива дуг графа G из рис. 2.5). Для любой вершины d графа G множество {iv: б/.ПД <w<(d + 1).ПД} состоит из номеров всех дуг, исходящих из Процедура ОБХОД-В- ГЛУБИНУ-4 использует три локальные переменные: q — посещаемая вершина, w — проходимая дуга, а также р — отец вершины q в дереве обхода (причем р = 0, если q — корень дерева, т.е. если </ = р0). Свойства. 1. Для процедуры ОБХОД-В-ГЛУБИНУ-4 справедливы свойства ал- горитма 2.2.17.
82 2.3.2. Алгоритм генерации упорядоченных деревьев 2. В процессе выполнения процедуры ОБХОД-В-ГЛ У БИНУ-4 список преемников любой вершины, достижимой из р0, обрабатывается ровно один раз. 3. После завершения процедуры ОБХОД-В-ГЛУБИНУ-4 все элемен- ты графа G имеют те же значения, что и до начала ее выполнения. 2.3. Генерация деревьев 2.3.1. Вводные замечания. Рассматриваются задачи полного и равно- вероятного порождения деревьев из разных классов: упорядоченных, бинарных, бинарных заданной высоты, Л-арных, корневых и свободных деревьев. Пусть зафиксирован некоторый класс деревьев D. Тогда решением задачи полного порождения является алгоритм построения последовательности всех элементов из D без повторения, а задачи равно- вероятного порождения — алгоритм, генерирующий любое дерево из D с одинаковым математическим ожиданием, равным 1/IDI. 2.3.2. Алгоритм генерации упорядоченных деревьев. Задача Операции. ВЕЕР(я) по заданному целому числу п строит упоря- доченное дерево, состоящее из корня п и листьев 1,2, ..., и- 1 (рис. 2.12). СНИЖЕНИЕ (р) применима к любой вер- шине дерева, имеющей более одного сына, и гвляет за время 0(1) преобразование, шное на рис. 2.13. ^ТИЕ-ПУТИ (р) делает сыновьями кор- 5 вершины, которые либо являлись сы- и вершины р, либо принадлежали корня дор (рис. 2.14), за время О (Л), длина пути от корня до р. Рис. 2.13
2.3.2. Алгоритм генерации упорядоченных деревьев 83 Корень ф п Рис. 2.14 НОМЕРА (Т) обходит дерево Т в постфиксном порядке и нумерует вершины в порядке их посещения (см. п. 2.2.13). Дано. Целое число п. Требуется. Сгенерировать все упорядоченные деревья с п вер- шинами. Решение Программа проц СЛЕДУЮЩЕЕ-ДЕРЕВО (Т : дерево) = 1. р:= КОРЕНЬ (Т); 2. если ЧИСЛО-СЫНОВЕЙ(р) > 1 то 3. СНИЖЕНИЕ (р) 4. иначе цикл р := СТАРШИЙ-СЫН (р) 5. до ЧИСЛО-СЫНОВЕЙ(р) > 1 все; 6. . СНИЖЕНИЕ(р); 7. СЖАТИЕ-ПУТИ(р) все все; проц ГЕНЕРАЦИЯ (и ; цел)= 1. Г:=ВЕЕР(п); 2. НОМЕРА(Т); 3. %деревопостроено% 4. для к от 2 до Ьп цикл 5. СЛЕДУЮЩЕЕ-ДЕРЕВО (D; 6. % дерево построено % все все
84 2.3.2. Алгоритм генерации упорядоченных деревьев Пояснения. В процедуре ГЕНЕРАЦИЯ через Ьп обозначено ко- личество упорядоченных деревьев с п вершинами (см. п. 1.3.6). Заметим, что процедура СЛЕДУЮЩЕЕ-ДЕРЕВО невыполнима, если Т — линей- ное дерево (см. цикл 4—5 процедуры). Однако ошибки здесь не возника- ет, поскольку линейное дерево всегда генерируется последним. П р и м е р. На рис. 2.15 приведена последовательность всех деревь- ев, генерируемых при обращении к процедуре ГЕНЕРАЦИЯ с п = 5. Ря- дом с деревьями указаны их коды (d2, d3, dA)f где di — число сыновей вершины с номером I. Стрелка указывает на преобразуемую вершину. (О, О, 0) (о, о, 1) (0,2, 1) (1, 0, 0) (1, о, 1) (1, О, 2) (1, 1, 0) (1, 1, 1) Рис. 2.15
2.3.3. Алгоритм генерации бинарных деревьев 85 Свойства. 1. Средняя длина всех сжимаемых путей не превышает 11/16. 2. Среднее время, затрачиваемое процедурой ГЕНЕРАЦИЯ на пост- роение одного дерева, равно 0(1). 2.3.3. Алгоритм генерации бинарных деревьев. Задача Операции. ЛЕВОЕ-ЛИНЕЙНОЕ-ДЕРЕВО(л) строитлевосторо- нее дерево, состоящее из п вершин. ПРАВАЯ-РОТАЦИЯ(р) осуществляет преобразование, представлен- ное на рис. 2.16. ПОЗИЦИЯ (к,Т) выдает вершину, занимающую Л-ю позицию в пути по дереву Т от его корня к самому левому листу. ЛЕВАЯ-РОТАЦИЯ(^) осуществляет переход от дерева рис. 2.16, б к дереву рис. 2.16, а. Дано. Целое число и. Требуется. Сгенерировать все бинарные деревья с п вершинами. Решение Программа проц ПРОВЕРКА (Л : цел, Т : дерево, R : вектор) = 1, (т, Z) (п - к - R [Л + 1 ], 0); 2. пока I < m цикл 3. если I * Ото ПРАВАЯ-РОТАЦИЯ(ПОЗИЦИЯ(Л, Л) все; 4. (/?[*], Z) :« (R[k + 1 ] + /,/ + 1); 5. если к e 1 то 6. % дерево построено % 7. иначе ПРОВЕРКАМ - 1, Т, Я) все все; 8. % восстанавливается позиция к дерева % 9. цикл m раз ЛЕВАЯ-РОТАЦИЯ(ПОЗИЦИЯ(Л, Л) все все; проц ГЕНЕРАЦИЯ (п : цел) = 1. Я:массив « {(/, 0) : i G [1 : п ]};
86 ' 2.3.3. Алюритм генерации бийарных деревьев 2. Т := ЛЕВОЕ-ЛИНЕЙНОЕ-ДЕРЕВО(и); 3. ПРОВЕРКА (п - 1, Т, Л) вее Пояснения. Рассмотрим работу процедуры с точки зрения гене- рации ротационных кодов (см. п. 1.2.13) соответствующих генериру- емых ею деревьев. Пусть X = (хл_15 ..., х2, х,) обозначает ротационный код дерева Г. Процедура осуществляет генерацию всех ротационных ко- дов в лексикографическогм порядке, основываясь на стратегии возврат- ного хода. Дерево возвратного хода для и = 4 приведено на рис. 2.17. Здесь пометки дуг от корня к листьям изображают значения х3, х2, Xj в соответствующем порядке. Пометка любой вершины — это то значение, которое присваивается элементу R [Л ] после того, как в кодовом слове заполнен элемент хк. Нетрудно видеть, что R [Л + 1 ] — это суммарное количество правых ротаций, выполненных до заполнения хк, т.е. R [Л + 1 ] = = хпЧ + хп+2 + ... + xk+l, ат — максимальное значение, допустимое для хк. Свойства. 1. Каждый из операторов, образующих тела циклов 2—7 и 9, выпол- 1 2/т няется 2ап раз, где ап = - - у ( j — количество бинарных деревьев на п вершинах. 2. Среднее время, затрачиваемое процедурой ГЕНЕРАЦИЯ на пост- роение одного дерева, равно 0(1). 3. 2(п- 1)(п + 2) — среднее число ротаций при построении одного дерева. Замечание. Используя свойства алгоритма, нетрудно его моди- фицировать таким образом, чтобы алгоритм генерировал только рота- ционный код всех полных бинарных деревьев.
2.3.4. Алгоритм генерации бинарных деревьев заданной высоты 87 2.3.4. Алгоритм генерации бинарных деревьев заданной высоты. Задача Объекты. Бинарные деревья Т фиксированной высоты Л, пред- ставленные в виде М, А) — рис. 2.18. Это представление базируется на поуровневом позиционном коде Ли (см. п. 1.2.15). Дерево Т состоит из компонент 7V, М и А, имеющих следующий смысл: N — вектор N[1 ], N[2], ..., N[h] распределения bhvtpchhhx вершин по уровням, где N[k] — это количество внутренних вершин дерева Т, расположенных на уровне Л; М — последовательность, полученная из TVs Ml; М2; ...; МА, где Mz = = Mz[l ], Mz[2], ..., — вектор позиций расположения внутрен- них вершин на уровне z, путем удаления векторов Mz для полностью заполненных уровней z, т.е. при переходе от Л? к М удаляется вектор Ml, а также все такие векторы Mz, что N[z ]« 27V[z - 1 ]; А — вектор номеров А [1 ], А [2 ], ..., А [/] не полностью заполненных уровней дерева, где / — это количество не полностью заполненных уров- ней для дерева Г, a A[z] — это z-й (в порядке их рассмотрения снизу вверх) не полностью заполненный уровень дерева. Рис 2.18
88 2.3.4. Алгоритм генерации бинарных деревьев заданной высоты На рис. 2.18 h = 6; А = 1, 2, 3, 2, 4, 1; М = 1, 2, 4; 3, 5; 4; полностью заполнены уровни 1, 2 и 5; А = 1, *3, 4. Свойства. Для любого дерева Т = (А, М, А):А[1 ] = 1; 1 < А[Л + 1 ] < Л <2N[k ] для каждого Л, 1 < к < Л; S^Aft]ж п, где п — число внутренних вершин дерева Т. Дано. Целые числа и и Л. Требуется. Сгенерировать все бинарные деревья с п внутрен- ними вершинами и с высотой, не превышающей Л, в такой последова- тельности 7\ = (N^ Mv, Ар, Т2 = (N2, М2, Л2), ..., Т- (Nit Д), ..., что для любых i и у, если i < то высота Т- превышает высоту или Т. и Т- совпадают по высоте и либо Ni лексикографически предшествует N., либо = N. и Mi лексикографически предшествует Д. Решение Программа функ НАЧАЛЬНОЕ-А(п, к : цел) = 1. если п < кто 2. возврат (Г, (У™) 3. иначе г := max{Z: (п - к) > 2l - Z- 1}; 4. m := (п - к) - (2Г - г - 1); 5., возврат (lw, 2°, 21, ..., 2м) ф НАЧАЛЬНОЕ-ЛЧди, г) все все; проц СЛЕДУЮЩЕЕ-А(А : вектор; и, к : цел) = 1. Z:=max{Z:Z< £, A[Z} # 1, A[Z] # 2A[Z- 1 ]}; 2. % если N не лексикографический максимум, то Z > 1 % к 3. т:=Е /=1+1 4. Mi]:=)V[j]+l; 5. для j от i до к - 1 цикл 6. г := тах{/: m > r<2lk~J)- 1)}; 7. АГ[/+1]:-г+1; 8. m := m - N[у ] все все; проц СЛЕД-ДЕРЕВО (М, N, A, D : вектор) = 1. к :=min{/ :£>[/]* 0}; к 2. р := ДЛИНА(М)-J [/]]+2>|У] - 1; 3. М[р} :=М[р] + 1; 4. (q,pl) := (р + А[Ж]|-О[Ц/>+ D; 5. если £>[£];* W[А[Л]] то 6. если М[pl ] - М[р] = 1 то 7. £>[&]:= D[£] - 1 8. иначе D[£] :=JV[A[£]]
2.3.4. Алгоритм генерации бинарных деревьев заданной высоты 89 9. пока pl < q цикл 10. (Л/(р1 ],р,р1) (Л/[р1 ]+ l,pl,p+ 1) все все 11. иначе если М[р] = 2 * ЛГ[Л] - 1 ]то 12. D[£]:«Dpt]- 1 все все; 13. р :« q + 1; 14. для iот к - 1 до 1 шаг - 1 цикл 15. для j [Л [z ] ] шаг 1 цикл 16. (ЛЛр],р) (Лр+1) все; 17. D[i]:-N[A[i]] все; все; проц ГЕНЕРАЦИЯ (л, Л : цел) = 1. для А от Л шаг - 1 до [log, (п + 1)] цикл 2. N :- НАЧАЛЬНОЕ-Лчя, к); 3. ДЕРЕВЬЯ-ДЛЯ-TV: начало 4. Вычислить по N лексикографически минимальное А7 и построить по N и 5/массивы ТИ, А и D; 5. % дерево построено % 6. пока М не лексикографический максимум цикл 7. СЛЕД-ДЕРЕВОСУ, ТИ, Л, D); 8. % дерево построено % все; 9. если N не лексикографический максимум то 10. СЛЕДУЮЩЕЕ-TVW, л, Л); 11. начать ДЕРЕВЬЯ-ДЛЯ-TV все конец все все Пояснения. Функция НАЧАЛЬНОЕ-N — это рекурсивный ал- горитм вычисления лексикографически минимального N для заданных п и к, например, для п « 24 и к - 6 имеем НАЧАЛЬНОЕ-TV (24,6)» «(1,1,1,2,4,8) Ф НАЧАЛЬНОЕ-N (7,4) = «(1,1,1,2,4,8) ф (1,1,1,2) ф НАЧАЛЬНОЕ-TV (2,2) « -(1,1,1,2,4,8) ф (1,1,1,2) ф (1,1)« -(1,1,2,3,6,11). Процедура СЛЕДУЮЩЕЕ-TV по некоторому TV, не являющемуся лек- сикографически максимальным для заданных п и Л, вычисляет в TV лек- сикографически следующее за TV распределение п вершин по к уровням
90 2.3.5. Алгоритм генерации Парных деревьев бинарного дерева. Здесь i — это первая справа позиция элемента в N, поддающегося увеличению, а ди — количество вершин дерева, которые нужно распределить по к - i уровням, расположенным ниже г, после уве- личения числа вершин на г-м уровне (оператор 4). Оператор цикла 5—8 строит в N[i + 1 ], N[i + 2 ], ..., TV [Л] лексикографический минимум, про- блема построения которого аналогична решаемой вызовом НАЧАЛЬ- Н0Е-А(т, к - 1) с тем отличием, что здесь первый элемент (А [г + 1 ]) не должен быть обязательно равен единице. Процедура СЛЕД-ДЕРЕВО работает с деревом Т в терминах векторов М, N, А и Д где D — вектор, используемый для указания на те крайние справа позиции вершин в М, которые можно перемещать вправо, не нарушая распределения А: D[£] = 0, если все вершины на уровне А [Л] расположены в крайних справа позициях, и равно позиции первой спра- ва перемещаемой вершины на уровне А [Л] иначе (заметим, что подобно индексам массива А индексы массива D — это номера не полностью заполненных уровней дерева, занумерованных снизу). Например, при N - 1, 2, 3, 2, 4, 1 и А = 1, 3, 4 имеем D = 1, 1,2 для М = 1, 2, 4; 3, 6; 1 и D = 0, 1,2 для М = 1, 2, 4; 3, 6; 8. Результатом работы процедуры СЛЕД-ДЕРЕВО является перевычисление М и £), соответствующее пе- реходу к дереву Т’ = (А, М, А), которое по условию задачи должно быть сгенерировано вслед за Т. Рассмотрим процедуру СЛЕДЕРЕВО более детально. В ней А [Л ] — уровень, ар — позиция вершины в Л/, которая должна быть сдвинута вправо на одну позицию при переходе к Г'. Этот сдвиг осуществляется оператором 3. Затем (строки 4—17) осуществляется размещение в левые позиции всех вершин, которые расположены за вершиной р на уровне А [Л ] (операторы 4—12), и всех вершин с уровней А [г ], 1 < К к (опера- торы 4—17), с соответствующим изменением D; q — это позиция в М самой правой вершины уровня А [Л ]. Условие 5 проверяет, не является ли текущая вершина самой правой на этом уровне, а условие 11 — ста- новится ли текущая вершина самой правой. Свойство. Алгоритм затрачивает в среднем на генерацию одного дерева 0(1) времени. 2.3.5. Алгоритм генерации Л-арных деревьев. Задача Дано. Целые числа Лип. Т ребуется. Сгенерировать все п-вершинные Л-арные деревья. Решение Программа проц ГЕНЕРАЦИЯ (п : цел; к : цел) = 1. для всех i из [1 : п ] цикл В [/ ] := (к - 1) * п + i все; 2. % код построен % 3. пока В # (Л, 2 ♦ Л, ..., п * к) цикл 4. Пусть j — максимальное целое, для которого В [/ ] > к * j иВ[/]>В[/-1] + 1 (предполагается, что В [0 ] = 0); 5. В[/]:«В[/]-1;
2.3.6. Алгоритм генерации корневых деревьев 91 6. для всех i из [/ + 1 : п ] цикл 7. В[1] :=(Ы)м + 1 все; 8. % код построен % все все Пояснение. Алгоритм генерирует последовательность у-кодов Закса Л-арных деревьев с п вершинами (см. п. 1.2.14) в порядке, обрат- ном лексикографическому. Свойство. Среднее время генерации кода одного дерева составля- етО(1). 2.3.6. Алгоритм генерации корневых деревьев. Задача Дано. Целое число м. Требуется. Сгенерировать все корневые деревья с п вершинами. Решение Программа проц КОРНЕВЫЕ-ДЕРЕВЬЯ (п : цел) = 1. L:= (1, 2, ..., п); 2. если п < 2 то р := 1 иначе р п все; 3. Р := (1, 2, ..., р- 1, 0, 0, ..., 0); 4. 5:=(0л); 5. % первое дерево построено % 6. пока р > 1 цикл 7. L[p]:=L[p]-l; 8. если* (р< п) A ((L[p]#2)v (L[p - 1 ] # 2)) то 9. J:=p-P[L[p]]; 10. пока р < п цикл 11. (S[p],P[L[p]],p) := (P[L[p]],p,p+ 1); 12. L[p]:=L[p-J] все все; 13. пока L [р ] = 2 цикл 14. р:=р-1; 15. P[L[p]]-=S[p] все; 16. %следующее дерево построено% все все Пояснение. В процессе работы алгоритма происходит много- кратный переход от текущего канонического уровневого кода L к коду s(L) таким образом, что генерируются все канонические уровневые коды в лексикографически убывающем порядке, начиная от кода [1,2, ..., п j и кончая кодом [1,2,2, ..., 2]. Пусть£= [/1? ..., 1п] [1,2,2, ..., 2] и пусть
92 2.3.7. Алгоритм генерации свободных деревьев р - max {Л : 1к > 2} и q e max {Л : к < р и lk = lp - 1}. Тогда s(L) e [sp s„], где 5; = lt для всех i G [1 : р) и s,s sh(p^q) для всех i G [pin] (см.ниже): L [1,2,3,2,2,2] [1,2,3,4,2,2] [1,2,3,4,3,2,2,2,2,2,2,21 [1,2,3,4,5,5,2,2,2,21 [1,2,2,2,2,21 [1,2,3,3,3,31 [1,2,3,4,2,3,4,2,3,4,2,31 [1,2,3,4,5,4,5,4,5,41 Отношение между L и s(D схематично можно изобразить следующим образом: L-,/^,^2,2,...,2] т т т Q Q Q В процедуре КОРНЕВЫЕ-ДЕРЕВЬЯ вектор L хранит текущий код, вектор Р используется для быстрого нахождения q по заданному р, а вектор S — для быстрого изменения вектора Р. Свойство. Среднее время, затрачиваемое алгоритмом на гене- рацию одного дерева, составляет 0(1). 2.3.7. Алгоритм генерации свободных деревьев. Задача Дано. Целое число и. Требуется. Сгенерировать без повторения все неизоморфные свободные деревья с числом вершин п. Решение Программа проц СЛЕД-ДЕРЕВО (L, W: вектор; n, р, q, Л1, Л2, с, г: цел) = 1. ф:=ложь; 2. если(свп + 1) V (р = Л2) a ((L[A1 ] = L[A2] + 1) л (п = Л2>г-Ы) V (L[/il] = L[A2]) А (п-Л2 + 1 <г-й1)) 3. тоесли£[г] > Зто 4. (р, q) := (г, W[r ]); 5. если Л1 « г то Л1 := Л1 - 1 все; 6. фистина; 7. иначе (р, г, q) := (г, г - 1, 2) все все; 8. (нужно_г, нужно_с, нужно_Л2) := (ложь, ложь, ложь); 9. если р < Л1 то Л1 := р - 1 все; 10. если р < г то нужно_г: = истина 11. иначе если р < Л2 то нужно_Л2 := истина
, 2.3.7. Алгоритм генерации свободных деревьев 93 12. иначе если (ЦЛ2] = £[Л1 ]- 1) л (и-Л2 = г-Л1) 13. то если р < с то нужно_с: = истина все 14. иначе с := Q все все все; 15. (стар_р, <5, стар_/<7, стар-М^, р) := (р, q-р, L[q], W[q], Q); 16. для i от стар_р до п цикл 17. L[z] :-L[i+<5]; 18. если Л [z ] = 2 то Иф]1 19. иначе p:=i; 20. если L [i ] = стар_/</ то q := crap_w 21. иначе q := W[i + <5 ] - <3 все; 22. все; 23. если нужно_г Л (£[<]“ 2) то 24. (нужно_г, нужно_Л2, г) (ложь, истина, i - 1) все; 25. если нужно_Л2 Л (L[i] < L[i - 1 ]) Л (i > г + 1) то 26. (нужно_Л2, Л2) := (ложь, i - 1); 27. если (L[A2] = Л[/г1 ] - 1) л (п - hl = г- Л1) то 28. нужно_с := истина 29. иначе с := Q все все; 30. если нужно_с то 31. если L[i] # ЦЛ1 -hl + i]~ 1 то 32. (нужно_с, с) := (ложь, i) 33. иначе сi + 1 все все все; 34. если ф то 35. г:=/г-Л1 + 1; 36. для i от г + 1 до п цикл (L[i], W[i ]) ;= (i - г + 1, i - 1) все; 37. (Ж[г + 1 ], Л2, р, q, с) :ш (1, п, п, р - 1, Q) 38. иначе если р = Q то 39. если Цстар_р - 1 ] # 2 то р стар_р - 1 40. иначе р := стар_р - 2 все; 41. ?:=Ж[р] все; 42. если нужно_Л2то 43. Л2 := п; 44. если (£[Л2] -ЦЛ1 ] - 1) л (Л1 - г) то с п + 1 45. иначе с Q все
94 2.3.7. Алгоритм генерации свободных деревьев все все все; проц СВОБОДНЫЕ-ДЕРЕВЬЯ (п : цел) = 1/ £:=[n/2J+l; 2. L := (1, 2, ..., Л, 2, 3, ..., п - Л + 1); 3. Ж:=(0, 1, k - 1, 1, £ + 1, ..., п - 1); 4. если п = 4 то р := 3 иначе р := п все; 5. (q, Л1, Л2, г) := (п - 1, Л, п, Л); 6. если нечетное п то с - Q иначе с :« п + 1 все; 7. % дерево сгенерировано % 8. пока q * 0 цикл 9. СЛЕД-ДЕРЕВО (L, IP, n, р, q9 Л1, Л2, с, г) 10. %дерево сгенерировано% все все Пояснения. В основу данного алгоритма положен алгоритм 2.3.6 генерации корневых деревьев. В процессе работы процедуры СВОБОД- НЫЕ-ДЕРЕВЬЯ осуществляется генерация всех главных канонических уровневых кодов n-вершинных свободных деревьев (см. п. 1.2.Г2) с ис- пользованием процедуры СЛЕД-ДЕРЕВО, реализующей определенную модификацию функции s, положенной в основу алгоритма 2.3.6. Здесь L и W — целочисленные векторы длины п; в L хранится ка- нонический уровневый код L* (Т, z) текущего дерева (Г, z), а в W[i] — индекс элемента в L, соответствующего в дереве (Т, z) отцу вершины, представленной элементом L [i ]; р — это наибольший индекс такой, что L[p] # 2, а <7 — это такой наибольший индекс, что <7 < ри£[#] = £[р]-1. L можно рассматривать как уровень корня z (а именно: уровень 1), сцепленный с уровневыми кодами каждой из компонент, получающихся* после удаления z из Г. Эти уровневые коды компонент называются ос- новными подпоследовательностями L, начинаются с уровня 2, а не 1, но в другом являются каноническими уровневыми кодами, причем они упо- рядочены в L по высоте, hi — это наименьший индекс наибольшего зна- чения уровня в /-й основной подпоследовательности L, а т — первая позиция второй основной подпоследовательности. Таким образом, L[hi ] - 2 — это высота первого поддерева дерева (Г, z), a L[h2] - 2 — высота второго, причем z — единственный центр Т при L [Л1 ] = L [hl ] и Т является бицентральным при L[h\ ] « L[A2]-1. Кроме того L является главным каноническим уровневым кодом тогда и только тогда, когда справедливы следующие свойства: (i) Л2 (и, следовательно, т) существует; (ii) L[A2] > ЦЛ1]- 1; (iii) если в (ii) равенство, то ш-2 < п-пг-2; (iv) если в (iii) равенство, то для LI = [L[2 ] - 1, L[3 ] - 1, ..., L[m~ 1]- - 1 ]hL2 = [L[l ]9L[m],L[m + 1 ], ..., L[n]] имеем: Li = L2 или LI короче L2, или LI и L2 имеют одну и ту же длину, но L1 лексикографически предшествует L2.
2.3.8. Генерация равновероятных деревьев 95 с — это первый элемент из L2, который отличен от соответствующего ему элемента в LI, а г « т - 1. В процедуре СВОБОДНЫЕ-ДЕРЕВЬЯ цикл 8—10 работает до тех пор, пока не будет построен код L = [1,2,2, ..., 2]. Значение с уста- навливается равным Q, если оно не требуется на следующей итерации. Свойства. 1. Алгоритм занимает О(п) памяти и в среднем тратит на построение одного дерева 0(1) времени. 2. Алгоритм генерирует все основные канонические уровневые после- довательности в их лексикографическом упорядочении. 2.3.8. Генерация равновероятных деревьев. Существуют три подхо- да (генерация по номеру, по времени и прямая генерация) к генерации равновероятных деревьев, каждый из которых основывается на датчике равновероятных чисел. Пусть зафиксирован некоторый класс деревьев D и пусть d s I JO I. Первые два подхода предполагают рассмотрение некоторого линейно- го упорядочения на Z), позволяющее связать с каждым деревом Т G D его номер л (Г). А. Генерация по номеру (см., например, п. 2.3.10) состоит из двух шагов: генерация равновероятного номера г дерева из Z); построение де- рева Г, для которого л (Т) « г. Б. Генерация по времени предполагает использование алгоритма пол- ной генерации D, последовательно порождающего деревья из D в соот- ветствии с заданным линейным упорядочением (например, одного из алгоритмов,2.3.1-2.3.7), и состоит из двух шагов: генерация равноверо- ятного времени t на применение алгоритма полной генерации; приме- нение алгоритма полной генерации деревьев из D до тех пор, пока не исчерпается время /. В. Прямая генерация (см., например, п. 2.3.9) означает непосредст- венное построение случайного дерева в неупорядоченном множестве D. Замечание. Из-за ограниченности длины машинного слова в ре- альных ЭВМ существующие датчики случайных чисел генерируют лишь конечное множество чисел, число которых может оказаться меньше d. Поэтому во всех предлагаемых подходах случайное дерево (неважно, явно или неявно: через его номер или время, необходимое на его порож- дение алгоритмом полной генерации) выделяется на основе некоторой конечной последовательности (|р ..., ..., £,), где / > 1. Элемент^ этой последовательности сужает D до одного из подмножеств D},..., , образу- ющих разбиение D, сужает полученное подмножество аналогичным образом и т.д., а £, приводит к некоторому подмножеству, состоящему из одного дерева, построение которого считается результатом генерации случайных деревьев. При этом необходимо, чтобы последовательность (|,, •••» , £? обладала следующими свойствами: равной вероятностью для каждого £ и независимостью событий между собой.
™ 2.3.9. Алгоритм генерации равновероятных упорядоченных деревьев 2.3.9. Алгоритм прямой генерации равновероятных упорядоченных корневых деревьев. Задача Операции. СЛУЧАЙНОЕ-ЧИСЛО — датчик равновероятных ве- щественных чисел %, 0 < | < 1. , Дано. Целое число п. Требуется. Сгенерировать равновероятное n-вершинное упоря- доченное корневое дерево. Решение Программа функ СЛУЧАЙНОЕ-ДЕРЕВО (п : цел)= 1. (В[1],В[2»л-2],/) .-(1,0, 1); 2. для г от 1 до п - 2 цикл 3. | := СЛУЧАЙНОЕ-ЧИСЛО; 4. а — (j +1) * (J + i - 1) • <j- 1 >/(2 * j * (2 ♦ i- 1) ♦ (i - 1)); 5. если$<ато 6. (B[2 ♦ i],B[2 * i + 1],/) := (1, 1,/+ 1) 7. иначе/3 — tt + j) ♦ (i-j)/((i- 1) • (2 * i- 1)); 8. если£ < a +/3to 9. (B[2*i],B[2* z + 1]) :=(l,0) 10. иначе у := 2 ♦/3; 11. если | < a + у то 12. (B[2 • z], В[2 * i+ 1]) (0, 1) 13. иначе (B[2 * i], В[2 • i + 1 ],/> :=(0, 0, j- 1) все все все все; 14. возврат В все Пояснения. Вектор В длины 2(п - 1) используется для хранения генерируемого дерева, представленного в виде двоичного кода с дуб- лированием вершин <Д, /32,..., /52я_2>, который образуется путем обхода в глубину дерева, когда всякий раз при увеличении расстояния от корня записывается "Г, а при уменьшении — "0" (см. п. 1.2.9). Следует за- метить, что некоторая двоичная последовательность <Д,/32, ...,/32„_2) является кодом указанного вида тогда и только тогда, когда /3, ” 1, Ргп-2 “ 6, У ft i=n— 1 и У (5,, > i для любого кЕ [2: п). i-i i-i Построение кода в В состоит из вычисления В [1 ] и В[2п - 2 ] (опера- тор 1), за которым следует п-2 шага, на каждом из которых ге- нерируется одна из пар ”00" (оператор 13), ”01" (оператор 12), "10” (опе- ратор 9) или "И" (оператор 6). Здесь
2.3.9. Алгоритм генерации равновероятных упорядоченных деревьев 97 a-ID^I/ID^.1, где для любых i и j через Dij обозначается множество деревьев с п вер- шинами, у которых в начальном зафиксированном отрезке кода единиц на /больше, чем нулей, а оставшийся непостроенный (различающий их) отрезок имеет длину 2i - 1 (т.е. осталось выполнить i - 1 шаг в процессе построения результирующего дерева). Другими словами, построение кода случайного дерева В можно ин- терпретировать как последовательное выполнение п - 2 шагов, на каж- дом из которых множество сужается до одного из множеств (Di4 и , что соответствует записи в В одной из пар: 1) ”00’’, 2) "01" либо "10", 3) "11". Всевозможные последовательности таких шагов мож- но рассматривать на плоскости с целочисленными координатами (рис. 2.19, случай п в 6). При этом — это количество различных путей из точки (/, /) в точку (1,1).
98 2.3.10. Алгоритм генерации по номеру равновероятных £-арных деревьев Например, при п = 6и последовательности случайных чисел 0,75; 0,47; 0,19; 0,89 получается путь Ds^ ^2,1 которому соответствует код 1110100100. Свойство. Алгоритм занимает О{п) времени и О(п) памяти. Замечание. Данный алгоритм можно использовать для генера- ции равновероятных деревьев из других классов, определяя подходящие взаимно однозначные соответствия между классом упорядоченных кор- невых деревьев и другими классами. Например, функция g(/3), которая заменяет в последовательности fl каждую цифру ”1” на ’’2", задает взаимно однозначное соответствие между кодами 1.2.9.Д упорядоченных корневых деревьев и кодами 1.2.10.А бинарных деревьев (рис. 2.20). 2.3.10. Алгоритм генерации по номеру равновероятных Л-арных де- ревьев. Задача Операции. Н - (i + '~ l) - 10 - 1)/(Хс - 1)J . , . , . -S ( j}-~kr) (*r)/((*-l)r+l>. Для любых k.nnl значение H((k- 1) м - I - 1, м, к) — это количество различных таких u-кодов Ли (см. п. 1.2.15) Л-арных n-вершинных де- ревьев, которые начинаются с 0м. Дано. Целые числа м, к и t. Требуется. Сгенерировать Л-арное n-вершинное дерево 7, м-код Ли которого в антилексикографическом упорядочении является Z-м по порядку (обозначаем t » индекс (Т)). Решение Программа. функ ДЕРЕВО_ПО_НОМЕРУ (£, n, t: цел) = 1. (а, у) := (Z, п); 2. цикл Найти такое что Ж/., у, к) < а < Ж/. + 1, у, к); 3. (а, у) :НнМ/.,/Д), 1 у-1) 4. до а « 1 все;
2.3.10. Алгоритм генерации по номеру равновероятных Парных деревьев 99 5. + у H{l.J.k)% 6. (Л, т) := ((О(Ас~1)<;о, 1;°), /0 + 1); s :ш (к - 1) * т - Zw; 7. ПОВТОР: начало 8. (ЛГ$+ 1], Л[$ + 2], А[к* т]) := (Л[$-/;+1], Л[$-£ + 2], ...» А{к* (m- 1)]); 9. (Л[$-£ + 1],Л[$-£ + 2], ...» Л[$]) := (О*1, 1); 10. т := т + 1; 11. если ли < пто 12. 5 :« (к - 1) * т -1 ; начать ПОВТОР все конец; 13. возврат(0, Л) все Пояснения. Операторы 1—4 осуществляют декомпозицию t (она единственна) такую, что Г=1+ Заметим, что для а - ((У 1/3) Е а(к ,п), где а(к, п)— множество после- довательностей, полученных из u-кодов Ли А-арных n-вершинных де- ревьев удалением первого нуля, имеем: индекс(а) = 1, если п = 0 (т.е. а — пустая последовательность); индекс (а) = Н((к - l)n - I - 1, п, к) + индекс (О'*4/?), если п > 0. Операторы 6—12 строят код Ли с конца: начиная с (O<fc-I);o, Ро) G а (/о> к), в него вставляются последователь- ности О*"1! для получения элементов из a(JQ + 1,£), a(jQ + 2,А),...,а(м,Л). В качестве примера рассмотрим слу- чай a G а(3,3), когда индекс (а) =8. После операторов 1-4 имеем 8 = Я(2,3,3) + Я(0,2,3) + 1. Оператор 6 присваивает Л последо- вательность (001). Операторы 8-9 из- меняют Л на (000101) — вставкой 001 после первого нуля, а затем — на (000100101). Результатом функции является код (0000100101) дерева, изображенного на рис. 2.21. Рис. 2.21 Свойство. Временная сложность алгоритма составляет O(max((nlogn)/к, кп)), причем (nlogn)/k в этом выражении связано с осуществлением декомпозиции t (оператор цикла 2-4).
100 2.4. Библиографический комментарий 2.4. Библиографический комментарий Исследования моделей вычислений — это важное и хорошо развитое направление математики, знакомство с результатами которого можно начать с обзоров [13, 15, 16]. Использование РАМ для анализа алго- ритмов получило широкое распространение с 70-х гг. В работах, посвя- щенных анализу сложности конкретных задач и алгоритмов, в терминах операций для РАМ становится нормой применение псевдоязыка (лекси- кона) программирования, допускающего использование традиционных конструкций математики и языков программирования. Первая систе- матическая реализация этого подхода проводится в [1 ], где с единых позиций излагаются результаты построения и анализа алгоритмов для разных задач, включая задачи на графах и задачи реализации сложных структур данных (там же можно почерпнуть дополнительные сведения о РАМ и ее связи с другими моделями вычислений). ВУ-язык нами заимствован из монографии [8 ], а алгоритмы обходов и генерации базируются на следующих работах: [38 ] — алгоритмы 2.2.2, 2.2.5 и 2.2.14; [22] — алгоритмы 2.2.3, 2.2.12; [36] — алгоритмы 2.2.4, 2.2.6, 2.2.7, 2.2.17—2.2.20; [10] — алгоритмы 2.2.9, 2.2.10; [8] — ал- горитмы 2.2.15 и 2.2.16; [34] — алгоритм 2.3.2; [44] — алгоритм 2.3.3; [25 ] — алгоритм 2.3.4; [43 ] — алгоритмы 2.3.5 и 2.3.10; [18 ] — алгоритм 2.3.6; [41 ] — алгоритм 2.3.7; [7 ] — алгоритм 2.3.9. В книге [16 ] дается обзор важнейших идей и работ в области теории алгоритмов. Излагаются в систематизированном виде основные откры- тия, связанные с понятием алгоритма, приложения теории алгоритмов к математической логике, теории вероятностей, теории информации и др. Рассматривается влияние теории алгоритмов на алгоритмическую прак- тику. Статья [15 ] — это обзор основных понятий и результатов собственно теории сложности вычислений, а также некоторых результатов по ана- лизу сложности конкретных задач. Она содержит представительную биб- лиографию (около 400 наименований) и уделяет значительное внимание вопросам, представляющим интерес не только для теории сложности вы- числений, но и для различных разделов математики, имеющих дело с разработкой и анализом алгоритмов. Монография [5 ] — это подробное руководство по теории WP-полных задач. Она может служить как учебником для читателя, интересующего- ся теорией труднорешаемых задач, так и справочником для исследовате- ля и практика, сталкивающегося с алгоритмами и их сложностью. Книга содержит более 300 комбинаторных задач, для каждой из которых, по- мимо основной формулировки и источника, приводится комментарий, включающий сводку результатов о задаче и ее модификациях (с ука- занием авторов), а также смежные вопросы. Вопросам формализованного сложносгного анализа и эффективиза- ции программных исследований свойств алгоритмов и структур данных посвящена книга [11 ]. В ней описание общей методики иллюстрируется на примере алгоритмов над деревьями.
2.4. Библиографический комментарий 101 Работа [14] обращена к читателю, который интересуется комбина- торными алгоритмами в силу их практического значения. В ней пред- принята довольно успешная попытка систематизации комбинаторных алгоритмов, выявления их общих черт и закономерностей. Рассматрива- ются вопросы представления и порождения комбинаторных объектов, их подсчета и оценивания, исчерпывающего и быстрого поиска, сортировки, обработки графов и др. Авторы старались выделить практически важные аспекты комбинаторных алгоритмов и опустить детали, которые может восполнить любой квалифицированный программист. Монография [4] посвящена общим принципам решения задач на ЭВМ, разработке и анализу алгоритмов. Несомненным достоинством является то, что при сравнительно небольшом объеме она покрывает обширный фактический материал (в том числе и генераторы случайных чисел) и может помочь в первоначальном знакомстве с предметом, под- робно изложенным в монографиях [1, 10]. Методам представления сложноорганизованных данных в памяти вы- числительной машины и создания программ со сложными структурами данных посвящены книги [2, 3, 9,10—12, 33, 37 ]. В работе [23 ] рассматривается отличное от лексикографического ли- нейное упорядочение на множестве всех кодов 2-3-деревьев с п внут- ренними вершинами. Приводятся алгоритмы для определения номера кода в упорядоченном множестве и для построения кода по его номеру; каждый из алгоритмов занимает О (и) времени после некоторого шага предварительной обработки, требующего О(п2) памяти и времени. Алго- ритмы решения задачи генерации для В-деревьев рассматриваются в [24 ]. В работе [26 ] решается проблема генерации, нахождения порядково- го номера и восстановления по номеру м-вершинных АВЛ-деревьев. При- водится код АВЛ-дерева в виде двух целочисленных последовательно- стей, называемых ЛДП-последовательностями, и рассматривается ли- нейное упорядочение на этих последовательностях. Приводятся алго- ритмы нахождения порядкового номера и восстановления дерева по но- меру за время O(zilog2n) и O(nlog2n), если до их применения выполнен шаг, требующий O(n2logn) времени. В статье [32 ] приводится способ кодирования бинарных деревьев пос- ледовательностями номеров уровней их листьев, перечисленных слева направо, и описывается критерий того, что некоторая последователь- ность целых чисел является кодом бинарного дерева. Приводится ал- горитм генерации списка всех кодов в лексикографическом порядке за линейное время от длины списка. Описываются алгоритмы определения по коду его номера в списке, а также построения кода по его номеру в списке. Другие подходы к решению этих же задач рассматриваются в работах [20, 28—30, 42 ]. В работе [39] рассматривается множество i-арных деревьев на п вершинах, к > 2, п > 0, и лексикографический порядок на множестве перестановок, используемых для кодирования деревьев. Приводятся ал- горитмы сложности О(пк) для определения номера кода в упорядочен- ном множестве и построения кода по его номеру. Описывается алгоритм
102 Список литературы генерации всех кодов за линейное время от числа Л-арных деревьев на п вершинах. Статья [31 ] расширяет результаты, полученные в [32 ] для бинарных деревьев, на Л-арные деревья. Л-арное дерево с п листьями кодируется последовательностью из п номеров уровней листьев дерева. Приводится алгоритм генерации списка всех таких последовательностей в лексико- графическом порядке, тратящий в среднем на один код О (к) времени. Строится алгоритм сложности О(п) для определения номера кода в списке и построения кода по его номеру в списке. В работе [19 ] рассматривается задача конструирования по любой пос- ледовательности весов w,, ..., wn и целому числу t > 2 такого дерева Т с максимальной пол у степенью исхода, не превышающей Z, и листьями у,, v2, ..., v„, что минимизируется функция fT(w^ ..., wn) » max{( + и; : i G G [1 : n ]}, где 4 обозначает длину пути по Т от корня до у,. Минимальное значение /(w2, ..., %) ..., w„) называется минимаксной дли- т ной взвешенного пути. Найдена верхняя оценка для ..., wn) и пост- роен эффективный алгоритм конструирования дерева, оптимального от- носительно минимаксной длины взвешенного пути. Аналогичная задача для Л-арных деревьев решается в работе [27 ]. Пусть р — вершина дерева Т. Удаляя р из Т вместе с инцидентными ей ребрами, получаем семейство поддеревьев {7^, ..., Трк} и последова- тельность чисел р = ($,, ..., sk), в которой s{ обозначает количество вер- шин в Tt. Пусть VT обозначает семейство последовательностей р, соот- ветствующих вершинам Т. В работе [21 ] описываются полиномиальные алгоритмы ответа на следующие вопросы: дано семейство W последова- тельностей, образованных из строго положительных целых чисел, суще- ствует ли свободное дерево Т такое,что VT » Если такое дерево суще- ствует, имеются ли неизоморфные деревья 7\ и Т2 такие, что VT = VT = На базе этих алгоритмов конструируется алгоритм для генерации всех неизоморфных деревьев 7, для которых VT = Ж. Различные алгоритмы генерации равновероятных графов из разных классов содержатся в работах [6,40]. СПИСОК ЛИТЕРАТУРЫ 1. Ахо А., Хопкрофт Дж., Ульман Дж. Построение и анализ вычислительных алгоритмов. — М.: Мир, 1978. 2. Берзтисс А.Т. Структуры данных. — М.: Статистика, 1974. 3. Вирт Н. Алгоритмы + структуры данных - программы. — М.: Мир, 1985. 4. Гудман С., Хидетниеми С. Введение в разработку и анализ алгоритмов. — М.: Мир, 1981. 5. Гэри М., Джонсон Д. Вычислительные машины и труднорешаемые задачи. — М.: Мир, 1982. 6. Завада А.П. Исследование средних оценок вычислительной сложности алгоритмов обработки структур данных типа дерева: Автореф.дис.... канд.физ.-мат. наук: 05.13.11. — Киев, 1987.
Список литературы 103 7. Завада А.П., Кожевникова Г.П. К анализу алгоритмов над деревьями. Векторные коды. Генерация случайных структур и характеристика дерева// Кибернетика. — 1984. — N5. — С. 12—18. 8. Касьянов В.Н. Оптимизирующие преобразования программ. — М.: Наука, 1988. 9. Касьянов В.Н., Сабельфельд В.К. Сборник заданий по практикуму на ЭВМ. — М.: Нау- ка, 1986. 10. Кнут Д. Искусство программирования для ЭВМ. Т. 1. Основные алгоритмы. — М.: Мир, 1976. 11. Кожевникова Г.П. Структуры данных и проектирование эффективной вычислительной среды. —Львов: Вищашк., 1986. 12. Лавров С.С., Гончарова Л.И. Автоматическая обработка данных, хранение инфор- мации в памяти ЭВМ. — М.: Наука, 1971. 13. Непомнящий В.А., Дехтярь М.И. Математическая теория программирования. Обзор за- рубежных работ. — Новосибирск, 1982. — 52 с. — (Препр./ АН СССР. Сиб. отд-ние. ВЦ; 341). 14. Рейнгольд Эм НивергельтЮ., Део Н. Комбинаторные алгоритмы: теория и практика. — М.:Мир, 1980. 15. Слисенко А.О. Сложностные задачи теории вычислений// Успехи мат. наук. — 1981. — Т. 36, N 6. — С. 21—103. 16. Успенский В.А., Семенов А.Л. Теория алгоритмов: основные открытия и приложения. — М.< Наука, 1987. 17. Холл П. Вычислительные структуры. Введение в нечисловое программирование. — М.: Мир, 1978. 18. Beyer Т., Hedetniemi S.M. Constant time generation of rooted trees//SIAM J. Comput. — 1980. — Vol. 9, N 4. — P. 706—712. 19. Coppersmith D., Klawe M.M., Pippenger N.J. Alphabetic minimax trees of degree at most f//Ibid. — 1986. — Vol. 15, N 1. — P. 189—192. 20. Er M.C. Enumerating ordered trees lexicographically// Comput. J. — 1985. — Vol. 28, N 5. — P. 538—542. 21. Gavril F., Schonheim J. Constructing trees with prescribed cardinalities for the components of their vertex deleted subgraphs//!. Algorithms. — 1985. — Vol. 6, N 2. — P. 239—252. 22. Gries D. The Schorr-Waite graph marking algorithm//Acta Informatica. — 1979. — Vol. 11, Fasc. 3. — P. 223—232. , 23. Gupta U., Lee D. T., Wong C.K. Ranking and unranking of 2-3 trees//SIAM J. Comput. — 1982. — Vol. 11, N 3. — P. 582—590. 24. Gupta U.L., Lee D.T., Wong C.K. Ranking and unranking of Л-trees//!. Algorithms. — 1983. — Vol. 4, N 1. — P. 11—60. 25. Lee C.C., Lee D.T., Wong C.K. Generating binary trees of bounded hight//Acta Informatica. — 1986. — Vol. 23, N 5. — P. 529—544. 26. Li L. Ranking and unranking AVL-trees//SIAM J. Comput. — 1986. — Vol. 15, N 4. — P. 1025—1035. 27. Kirkpatrick D.G., Klawe M.M. Alphabetic minimax trees//Ibid. — 1985. — Vol. 14, N 4. — P. 514—526. 28. Pallo J.M. Enumerating, ranking and unranking binary trees// Comput. J. — 1986. — Vol. 29, N 2. — P. 171—175. 29. Proskurowski A. On the generation of binary trees//!. ACM. — 1980. — Vol. 27, N 1. — P. 1—2.
104 Список литературы 30. Rotem D., Varol Y.L. Generation of binary trees from ballot sequences//!. ACM. — 1978. — Vol. 25, N 3. — P. 396—404. 31. Ruskey F. Generating f-ary trees lexicographically//SIAM J. Comput. — 1978. — Vol. 7, N 4. — P. 424—439. 32. Ruskey F., HuT.C. Generation binary trees lexicographically//Ibid. — 1977. — Vol. 6, N 4. — P. 745—758. 33. Schorr H., Waite W.M. An efficient machine independent procedure for carbage collection in various list structures//Comm. ACM. — 1967. — Vol. 10, N 8. — P. 501—506. 34. SkarbekW. Generating ordered trees//Theor. Comp. Sci. — 1988. — Vol. 57, N 1. — P. 153—159. 35. Solomon MM Finkel R.A. A note on enumerating binary trees//!. ACM. — 1980. — Vol. 27, Nl.— P.3—5. 36. Tarjan R.E. Space-efficient implementation of graph search methods//ACM Trans. Math. Software. — 1983. — Vol. 9, N 3. — P. 326—339. 37. TarjanILE., Van LeeuwenJ. Worst-case analysis of set union algorithms//!. ACM. — 1984. — Vol. 31, N 2. — P. 245—281. 38. Thorelli L.E. Marking algorithms//BIT. — 1972. — Vol. 12, N 4. — P. 555—568. 39. Trojanowski A.E. Ranking and listing algorithms for Л-агу trees//SIAM!. Comput. — 1978. — Vol. 7, N 4. — P. 492—509. 40. Wilf H.S. The uniform selection of trees//!. Algorithms. — 1981. — Vol. 2, N1. — P. 204—207. 41. Wright R.A.et al. Constant time generation of free trees//SIAM!. Comput. — 1986. — Vol. 15, N 2. — P.540—548. 42’ Zaks S. Lexicographically generation of ordered trees// Theor. Comp. Sci. — 1980. — Vol. 10, Nl. —P.63—83. 43. Zaks S. Generation and ranking of Л-ary trees//Inf. Process. Lett. — 1982. — Vol. 14, N 1. — p. 44—48. 44. Zerling D. Generating binary trees using rotations// !. ACM. — 1985. — Vol. 32, N 3. — P. 694—701.
Глава 3 КАРКАСЫ 3.1. Задача об отыскании оптимального каркаса 3.1.1. Содержательная постановка задачи. Оптимальным каркасом взвешенного графа G называется каркас, минимизирующий некоторую функцию от весов входящих в него ребер. Чаще всего в качестве такой функции выступает сумма весов ребер, реже — произведение, еще реже — произвольная сепарабельная функция. Оптимальный каркас еще назы- вают кратчайшей связывающей сетью для данного графа. Задача о построении кратчайшей связывающей сети возникает доста- точно часто в различных приложениях, например, при планировании очередности пропуска задач для минимизации обращения к памяти, а также входит как вспомогательная при решении более сложных задач. Эта задача хорошо известна, ее постановка и методы решения встреча- ются практически в каждой книге по теории графов и их приложениям. 3.1.2. Нахождение каркасов в обыкновенных графах. Приводимые ниже два алгоритма являются вариантами поиска в глубину и ширину. Алгоритм нахождения каркаса на основе поиска в глубину Вход. Связный граф С7(У, £), заданный списками смежности ЗА- ПИСЬ [v], vG У. Выход. Каркас (У, Т) графа (7. проц WGD(G\ граф; у: вершина) == % поиск в глубину, соединенный с нахождением ребер дерева; переменные НОВЫЙ, ЗАПИСЬ, Т — глобальные % 1. НОВЫЙ [у ] := ложь; 2. для и G. ЗАПИСЬ [у ] цикл 3. если НОВЫЙ [и ] то % (у,и) — новое ребро% 4. Т:=Ти{(у,м)}; 5. HWU); все все; начало % главная программах 7. для и G Vцикл НОВЫЙ [у] := истина все; 8. Т := 0 % Т = множество найденных к этому моменту ребер % 9. WGD (г) % г — произвольная вершина графа % все конец Алгоритм нахождения каркаса на основе поиска в ширину Вход. Связный граф G = (У, Е), представленный списками смеж- ности ЗАПИСЬ [у], у G У. Выход. Каркас (У, Г) графа G. проц КАРКАС (G: граф; у: вершина) = 1. для и G У цикл НОВЫЙ [w ] := истина все; % инициализация % 2. Т:=0;
106 3.1.3. Алгоритм Краскала % Т - множество найденных к этому моменту ребер % 3. ОЧЕРЕДЬ = 0; ОЧЕРЕДЬ <= г; 4. НОВЫЙ [г] - ложь; % г — корень каркаса % 5. пока ОЧЕРЕДЬ # 0 цикл 6. ОЧЕРЕДЬ; 7. для и G ЗАПИСЬ [v ] цикл 8. если НОВЫЙ [и ] то % (у, и) — новое ребро% 9. ОЧЕРЕДЬ <= и; 10. НОВЫЙ [и] :=ложь; 11. Т:=Т U {(v, и)} все все все все 3.1.3. Алгоритм Краскала. Содержательно данный алгоритм пред- ставляет собой следующую последовательность шагов. Шаг 1. Начать с вполне несвязного графа Т, содержащего п изо- лированных вершин. Примечание: п есть число вершин исходного графа G. Ш а г 2. Упорядочить ребра графа G в порядке неубывания их весов. Ш а г 3. Начав с первого ребра в этом списке, добавлять ребра в графе Т, соблюдая условие: такое добавление не должно приводить к появ- лению цикла в Т. Ш а г 4. Повторять шаг 3 до тех пор, пока число ребер в Т не станет равным п - 1. Получившееся дерево является оптимальным каркасом графа G. Наиболее трудоемким является шаг 2: для графа с m ребрами нужно выполнить порядка mlog2m операций, чтобы составить полный список ребер в порядке возрастания их весов. Однако полный список, вообще говоря, не требуется, так как весьма правдоподобно, что п - 1 до- пустимых ребер, образующих оптимальный каркас, будут найдены после просмотра только ’’верхней” части списка, содержащей г < m ребер. Отсюда немедленно следует, что процедура сортировки, используемая на шаге 2, должна быть процедурой многократного обращения, дающей корректное расположение первых р ребер в конце р-го цикла обращения. Это потребует только rlog2w операций. Тем не менее применение ал- горитма Краскала эффективно для графов с малым числом ребер. Опишем более формализованный вариант алгоритма Краскала. Пусть G= (V, Е) — неориентированный граф с функцией стоимости с, задан- ной на его ребрах. Требуется построить оптимальный каркас Т = (У, S). Пусть VS — набор непересекающихся множеств вершин. Каждое множе- ство W из У5 представляет собой связное множество вершин, образую- щее дерево в остовном лесу, представленном набором FS. Ребра выбираются из Е в порядке возрастания стоимости. Ребра (у, w) рас- сматриваются по очереди. Если у и и* принадлежат одному и тому же множеству из VS, то ребро (у, w) исключается из рассмотрения. Если у и
3.1.3. Алгоритм Краскала 107 w принадлежат разным множествам — W\ и W2 (это значит, что Ж, и W2 еще не соединены), то сливаем их в одно множество и добавляем (у, ту) к множеству S ребер, входящих в окончательное остовное дерево. Здесь можно воспользоваться алгоритмом объединения непересекающихся множеств, описанным, например, в [2, п. 4.7 ]. Алгоритм Краскала Вход. Неориентированный граф G = (V, Е) с функцией стоимости ребер с. Выход. Оптимальный каркас Т = (У, S). Метод проц ОПТИМАЛЬНЫЙ-КАРКАС (G: граф) = 1. S:=0; 2. VS := 0; 3. Построить очередь с приоритетами Q, содержащую все ребра из Е\ 4. для всех у из Г цикл добавить {у} к VS все; 5. пока I VS I >1 цикл 6. Выбрать в Q ребро (у, ту) наименьшей стоимости; 7. Удалить (у, ту) из Q; 8. Если у и ту принадлежат различным множествам W\ и W2 из VS 9. то заменить W\ и W2 на W\ U W2 в VS: 10. добавить (у, ту) к S все все все Разумеется, на самом деле на шаге 3 алгоритма ребра не сортируются, а хранятся в виде сортирующего дерева, 2-3-дерева (см. п. 5.1.8) или какой- нибудь другой приемлемой структуры данных, пока они не потребуются. Повторное обращение в строке 6 с целью найти ребро наименьшей стоимости является основной операцией с СОРТДЕРЕВОМ (см. [1 ]). Пример. Для графа (7, показанного на рис. 3.1, последовательность действий сведена в таблицу; получившееся в итоге дерево показано на рис. 3.2. Ребро Стоимость (Vp 1 (Уз* v4> 3 (У2, У7) 4 (Уз* v7) 9 (Уз* Ъ> 15 (У4, У7) 16 (У4, У5) 17 (Ур Уз) 20 (Ур Уб> 23 (у5, У7) 25 (У5* 28 <Уб* v7) 36 Рис. 3.1
108 3.1.4. Алгоритм Прима Ребро (vi, v7) (V3, v4) (v2, V7) (v3, v7) (V2, V3) (V4, V7) (V4, v5) (Vp v2) (Vp V6) Действие Добавить Отбросить Добавить Отбросить Добавить Множества в VS (связные подграфы) {Vp V7}, {v2}, {v3}, {v4}, {v5}, {v6} {Vp V7}, {v2}, {v3, v4}, {v5}, {v6} {Vp V2, v7}, {v3, v4}, {v5}, {v6} {Vp V2, v3, v4, v7}, {v5},{v6} {Vp v2, v3, v4, v5, V7},{v6} {Vp v2, v3, v4, v5, v6, v7} 3.1.4. Алгоритм Прима. Этот алгоритм порождает оптимальный кар- кас посредством разрастания одного поддерева Ts. Разрастание поддере- ва Ts происходит за счет присоединения ребер (v;, vp, где v2 G Ts и v; £ Ts; причем добавляемое ребро должно иметь наименьший вес с-. Процесс продолжается до тех пор, пока число ребер в Ts не станет равным п - 1. Алгоритм начинает работу с присвоения каждой вершине v. Ts по- метки [ст, Д], где сг на каждом шаге есть ближайшая к vy вершина из поддерева 4 а — вес ребра (a., v;). На каждом шаге выполнения алгоритма вершина, например V*, с наименьшей пометкой /5- присо- единяется к Ts посредством добавления ребра («», v<). Поскольку к Ts добавлена новая вершина v.*, то, может быть, придется изменить пометки [а>, РД У некоторых вершин vy Ts ( если, например, c(v;, v.*) меньше существующей пометки /?.) и после этого продолжить процесс. Алгоритм Вход. Неориентированный граф G = (У, Е) с функцией стоимости ребер с. Выход. Оптимальный каркас Т = (У, S). Метод Шаг 1 . Пусть Ts = {vs}, где v5 — произвольно выбранная вершина, и = 0. Шаг 2 . Для каждой вершины v. Ts найти вершину aj G Ts такую, что
3.1.5. Алгоритм Соллина 109 С(« > V.) = mm [с(Ч, V.) ] = 0., и приписать вершине Vj пометку [ау, /Зу]. Если такой вершины а нет, т.е. при Гуу А Т$ = 0, приписать вершине vy- метку [0, «> ]. Шаг 3 . Выбрать такую вершину у;*, что 4-=т^.]. Обновить данные: Ts = Ts U {v/}, U [(a*, vy0}. Если I Ts\ = n, to стоп. Ребра в образуют оптимальный каркас. Если I Ts I < п, то перейти к шагу 4. Шаг 4 . Для всех £ Ts таких, что G Гу*, обновить метки следующим образом: а) если v;), то положить fi. = c(v*, у;), а== у.* и вернуться к шагу 3; б) если Pj < c(v*. у;), то перейти к шагу 3. Как видно из описания алгоритма, он может использоваться для на- хождения оптимальных каркасов в графах, близких к полным. Пример. Для графа, представленного на рис. 3.1, последователь- ные шаги алгоритма Прима приведены на рис. 3.3. 3.1.5. Алгоритм Соллина. Содержательно этот алгоритм состоит из следующих шагов: Шаг 1 . Соединить каждую вершину с ее ближайшим соседом. Шаг 2 . Рассмотреть каждую полученную связную компоненту как одну вершину. Сохранить ребра, ведущие из одной компоненты связ- ности к другой. Переход к шагу 1. 3.1.6. Алгоритм Тарьяна—Черитона. Содержательно этот алгоритм состоит из следующих шагов: Начальный шаг. Взять некоторую вершину. Выбрать наименьшее по весу ребро, инцидентное этой вершине. Это ребро явля- ется первым ребром оптимального каркаса. Общий шаг. Ребра, выбранные к этому моменту, определяют лес F, являющийся частичным графом исходного графа. (Изолированные вершины, не инцидентные ни одному ребру, выбранному к данному мо- менту, рассматриваются как одновершинные деревья.) Взять некоторое дерево из леса, пусть это будет Г. Выбрать наименьшее из ранее не выбранных ребро (у, w), инцидентное вершине в Т и вершине в другом дереве Т. Удалить все ребра, меньшие (v, w), которые инцидентны Т (эти ребра образуют цикл с ребрами из Т). Добавить (v, w) к оптимально- му каркасу (модифицировав лес F, объединяя Т и Г'). Повторять общий шаг, пока все вершины не окажутся связанными. Чистка. (Этот необязательный шаг может исполняться после любого исполнения общего шага. Он упрощает последующие вычисления удалением излишних ребер.) Удалить все невыбранные ребра, имеющие оба конца в вершинах одного и того же дерева леса F. Для каждой пары деревьев, связанных невыбранным ребром, удалить все, кроме мини-
но 3.1.6. Алгоритм Тарья на—Черитона мального по весу, ребра, связывающие эту пару деревьев. vilv?JI 4 о Ъ) '•J'rW О О v</r7,16j ^1^7^51 о о vjvj.25! v4lv7J6l Т5 = [v7 ,vtf -изменена мешка у v6 О o ^/v7,/6/ ^/v7i25/ Ts‘{ve v2.v?) О d vJv7,25] vjvjt з/ Ts-{v„vi,''J,v7} Puc. 3.3 Данный метод требует наличия механизма для выбора дерева Т и механизма для хранения деревьев леса.
3.1.6. Алгоритм Тарьяна—Черитона 111 Объекты . Граф Ge множеством вершин Vе {1,2,..., и}, заданный списками смежности Z(y). Напомним, что каждое ребро (v, w) встречает- ся в этих списках дважды: в списках /(у) и I(w). Каждое дерево i леса F определяется множеством i его вершин и очередью i ребер, инцидентных ему. Вначале каждая вершина v представляется множеством {у} и оче- редью, содержащей все ребра из Z(y). Операции. Реализация алгоритма предполагает использование следующих операций: НАЙТИ (х) — определяет имя множества, содержащего вершину х; ОБЪЕДИНЕНИЕ (i, у) — объединяет множества i и j и присваивает новому множеству имя /; ИНИЦ(г, L) — инициализирует множество /, включающее все вершины из списка L; ОЧОБЪЕДС/, у) — объединяет очереди i и j и присваивает новой оче- реди имя ц МИН (/) — отыскивает наименьшее по весу ребро в очереди г, имею- щее один конец вне дерева /, а также удаляет это ребро и все меньшие ребра из очереди L (Заметим, что МИН (0 должен использовать опе- рацию НАЙТИ для проверки, имеет ли данное ребро концевую вершину вне дерева г.); ОЧИНИЦ(г, L) — инициализирует очередь г, включающую все ребра из списка L. Программа проц МИНКАРКАС = 1. для i = 1 до п цикл 2. иница; {/}); 3. ОЧИНИЦа,/(/)); все; 4. пока имеется более чем одно дерево цикл 5. выполнить чистку (если нужно); 6. выбрать некоторое дерево Л; 7. (i, у) :=МИН(Л); 8. добавить ребро (i, у) к оптимальному каркасу; 9. х:=НАЙТИ(у); 10. ОБЪЕДИНЕНИЕ (хД); 11. ОЧОБЪЕД(хД); все все Особенности реализации. Для реализации строки 10 алгоритма существуют однородный подход и подход ’’дерево с наимень- шим числом вершин вначале”. При однородном подходе все деревья ор- ганизуются в виде произвольной очереди. Берется первый элемент этой очереди — это дерево Т и соединяется с некоторым другим деревом Т', затем оба удаляются из очереди, новое дерево помещается в хвост оче- реди, и процесс повторяется. Трудоемкость такого выбора — О(и). При альтернативном подходе первым проверяется дерево с наименьшим числом вершин. Этот подход также может быть реализован
112 3.1.6. Алгоритм Тарьяна—Черитона с трудоемкостью О(п), хотя мультипликативная константа в этом случае больше. Он требует хранения числа вершин в дереве и использования массива А размерности п, в котором элемент Л (0 есть список деревьев с i вершинами. Так как число вершин в дереве заключается между 1 и п и никогда не уменьшается, то можно использовать указатель, который движется вдоль массива А для отыскания дерева с наименьшим числом вершин. Массив модифицировать легко, если каждое дерево имеет в нем свой указатель на позицию. Существуют также несколько альтернативных подходов к реализа- ции очередей: неупорядоченный список, список упорядоченных мно- жеств и ’’левое” дерево. Остановимся на первых двух. Представление очереди в виде неупорядоченного списка является простейшим. При этом представлении операция МИН (0 имеет трудоем- кость О(т(/)) плюс затраты на использование m(i) операций НАЙТИ, операция ОЧОБЪЕД(/,у) имеет трудоемкость 0(1), а операция ИНИЦ(/, L) — трудоемкость O(m(D). Здесь m(i) — размер очереди i. При представлении в виде списка упорядоченных множеств очередь i есть список множеств, каждое из которых вначале имеет мощность к плюс (возможно) некоторые ’’специальные" множества мощности мень- ше к. Каждое множество есть упорядоченный список, но само множество этих списков неупорядоченно. Операция ИНИЦ(/, L) исполняется раз- биением £ на |_1 L \ /к\ множеств мощности к и самое большее одно мно- жество мощности меньше к. Затем эти множества упорядочиваются, что требует 0(1 £1 log&) операций. Операция ОЧОБЪЕДО’, у) исполняется путем слияния списка множеств в очереди i со списком множеств в оче- реди у. Это требует 0(1) операций. Операция МИН(О исполняется про- веркой ребер в каждом множестве очереди i по порядку, при этом отбра- сываются те из них, которые не соединяют два различных дерева. Потом сравниваются наименьшие ребра в каждом таком множестве и выбирает- ся среди них наименьшее. Операция МИН(О имеет трудоемкость O(s(z) + + Ki)) плюс затраты на s(i) + Z(D - 1 операций НАЙТИ. Здесь s(i) — число упорядоченных множеств в очереди z, a Ki) — число ребер, удален- ных из очереди операцией МИН(О. Предположим, что мы представляем очереди указанным способом, инициализируем в начале р-го шага алгоритма очереди и используем данное представление очереди (т.е. инициализированное в начале р-го шага) вплоть до #-го шага алгоритма. Так как существует не более п/2р очередей в начале р-го шага, то после инициализации имеют место не более 2т/к + п/2р подмножеств во всех этих очередях. Трудоемкость инициализации очереди — О(т log£). Время исполнения любого шага пропорционально т/к + п/2р + £(у), где £(у) — число ребер, удаленных из очередей. Таким образом, полная трудоемкость инициализации и исполнения алгоритма с шага р по шаг q равна О( [т/к + п/2р ](q~ р) + т). Рассмотрим следующее исполнение алгоритма МИНКАРКАС. Шаг 1 . Инициализировать все очереди как неупорядоченные множества. Шаг 2 . Исполнять МИНКАРКАС до шага log log log и.
3.1.7. Алгоритм отыскания оптимального оркаркаса 113 Шаг 3. Инициализировать заново все очереди как списки упорядо- ченных множеств мощности kL = log log п. Шаг 4 . Исполнять МИНКАРКАС до шага log log п. Шаг 5. Инициализировать все очереди как списки упорядоченных множеств мощности к2 e logn. Шаг 6 . Исполнять МИНКАРКАС до завершения. Полная трудоемкость этого процесса равна О(т + т log log log п + + т log log п) для инициализации и переинициализации очередей плюс О(т log log log п + т + т) на каждый шаг исполнения (включая все опе- рации ОБЪЕДИНЕНИЯ, НАЙТИ, МИН и ОЧОБЪЕД). Таким образом, полная трудоемкость равна О(т log log п) (для любого способа выбора деревьев) при условии отсутствия чистки вне зависимости от стратегии выбора деревьев. Более того, время исполнения алгоритма асимптоти- чески доминируется временем, требуемым для переупорядочения мно- жеств размера log п на шаге 5; если это упорядочение использует точные алгоритмы, то эта версия алгоритма МИНКАРКАС требует 2m log log п + O(m log log log n + m + m) сравнений. Чистка полезна для графов, в которых МИНКАРКАС порождает мно- го избыточных ребер при комбинировании деревьев. К таковым относят- ся плоские и плотные графы, т.е. графы, для которых отношение т/п велико. Чтобы выполнить чистку, присвоим номер i каждой вершине в мно- жестве I. Затем заменяем каждое ребро (v, w) ребром, у которого конце- вые вершины — номера, присвоенные вершинам v и w. (Для каждого нового ребра (v', w') запоминаем соответствующее ребро в исходном гра- фе.) Упорядочиваем новые ребра (v', w') лексикографически, используя двухпроходную цифровую сортировку. Удаляются все новые ребра (v', w') с v' » w' и заменяются экземпляры ребер (v', w’) с v' # w' одним, чей вес наименьший среди весов всех экземпляров. Этот процесс имеет трудоем- кость О(т). Затем заново инициализируются очереди и множества, представляющие деревья леса К Полезный эффект этих операций состоит в сжатии каждого дерева до одной вершины и в удалении петель и кратных ребер. Предположим, что используется представление очереди в виде не- упорядоченного списка. После шага j имеется самое большее n/2;+1 де- ревьев. Таким образом, имеем я/2;+1 новых вершин и (п/2;+|)2 ребер, остающихся после чистки, следующей за шагом /. Если m(z) — число п — 1 п ребер в очереди г, когда исполняется МИН(/), то У т(г) < (/г/2у) s О(и2). /=1 у=о Таким образом, в данном случае МИНКАРКАС имеет трудоемкость O(min(m log n, п2)). Этот вариант алгоритма с однородным выбором де- ревьев есть версия алгоритма Соллина. 3.1.7. Алгоритм отыскания оптимального оркаркаса. Постановка задачи. В отличие от рассмотренной выше задачи построения оптималь- ного каркаса для неориентированных графов, где решение задачи всегда существует, задача построения оптимального оркаркаса решение имеет
114 3.1.8. Алгоритм Эдмондса не всегда. Чтобы ликвидировать этот недостаток, обобщим несколько первоначальную задачу. Лесом называется несвязный граф, каждая компонента связности ко- торого является деревом. Ориентированный лес определяется как обыч- ный лес, но состоящий не из простых деревьев, а из ориентированных. При этом предполагается, что все деревья являются заходящими, т.е. имеющими корень, достижимый из каждой вершины дерева. Оркаркас определен в п. 1.1.8; лес-каркасом (покрывающим ориен- тированным лесом) будем называть частичный граф в виде ориенти- рованного леса (быть может, с одновершинными компонентами), содер- жащий все вершины исходного графа. Поэтому, говоря далее о каркасе орграфа, будем иметь в виду оркаркас, если он существует, или лес-кар- кас — в общем случае. Ниже представлен алгоритм Эдмондса — алгоритм построения мак- симального в смысле наибольшего по весу лес-каркаса. Он может быть также использован для решения следующих задач: А. Построение минимального по весу лес-каркаса (для этого изменя- ется знак веса каждой дуги). Б. Построение максимального по весу оркаркаса (максимальный по весу оркаркас, если он существует, может не совпадать с максимальным по весу лес-каркасом); для этого к весу каждой дуги прибавляется доста- точно большая положительная константа. В. Построение минимального по весу оркаркаса (если он существует); для этого после изменения знаков всех дуг на обратные к весу каждой дуги добавляют достаточно большую по величине положительную кон- станту. Г. Построение максимального по весу оркаркаса с корнем в заданной вершине (если он существует); для этого к графу добавляется фиктивная вершина г, из которой идет дуга в вершину — заданный корень оркарка- са. Д. Построение минимального по весу оркаркаса с корнем в заданной вершине. 3.1.8. Алгоритм Эдмондса. Идея алгоритма состоит в следующем. Последовательно в произвольном порядке просматриваются вершины графа. Просмотр состоит в том, что из дуг, заходящих в данную вершину, выбирается дуга с максимальным весом (поэтому вершина, не имеющая заходящих дуг, может быть вообще исключена из рассмотрения). Вы- бранные дуги помещаются в структуру данных, называемую БУКЕТ. Если добавление новой дуги к уже вошедшим в БУКЕТ не нарушает его свойства образовывать лес, то выбранная дуга вводится в БУКЕТ. В противном случае (когда выбранная дуга образует контур с некоторыми дугами, ранее вошедшими в БУКЕТ) формируется новый уменьшенный граф путем стягивания дуг и вершин выявленного контура в одну вершину. В новом графе веса некоторых дуг соответствующим образом корректируются. Кроме того, для нового графа корректируется состав БУКЕТа вершин и БУКЕТа дуг: в них остаются только те элементы (вершины или дуги), которые присутствуют в новом графе. После прове- денной корректировки процедура просмотра вершин продолжается ана-
3.1.8. Алгоритм Эдмондса 115 логичным образом и заканчивается, когда просмотрены все вершины исходного графа. По окончании процедуры просмотра вершин дуги последнего сфор- мированного БУКЕТа образуют лес-каркас в соответствующем графе. После этого осуществляется переход ко второму этапу алгоритма, состоя- щему в следующем. Граф, полученный по окончании первого этапа, расширяется путем замены фиктивной вершины контуром, который в нее стягивается при соответствующем преобразовании графов. В новый расширенный граф, а также в соответствующий ему БУКЕТ включаются все дуги указанного контура, за исключением одной. Исключенная дуга выбирается так, чтобы дуги, составляющие новый БУКЕТ, образовывали лес в соответствующем графе. Этот процесс последовательного расширения графа продолжается до тех пор, пока не будет восстановлен исходный граф. При этом оказывается, что дуги соответствующего БУКЕТа образуют для исходного графа максимальный ориентированный лес. Алгоритм Вход. Граф G » (V, Е), заданный обратными списками смежности. Выход. Множество S дуг максимального лес-каркаса. проц ЛЕС-КАРКАС (G: граф) = 1. БУКЕТВ :=0; 2. БУКЕТД := 0; 3. i := 0; 4. пока 1БУКЕТВ1 # I VI цикл 5. выбрать вершину у из У\БУКЕТВ; 6. БУКЕТВ := БУКЕТВ U {у}; 7. выбрать дугу и с максимальным весом, заходящую в у; 8. БУКЕТД := БУКЕТД U {и}; 9. если и не замыкает контур Ci то на 5; все 10. выявить контур Ср %определить множество V, = {у, ,...,у; } вершин и множество Е{ 1 Ч 1к. дуг контура Ci % 11. БУКЕТВ := БУКЕТВ\ Vi U {vz}; % эта операция соответствует стягиванию контура С( в новую вершину у. % 12. БУКЕТД :« БУКЕТД\Е,; 13. для всех (х, у) G БУКЕТД цикл 14. если у G У- то заменить дугу (х, у) дугой (х, vz) с весом с(х, vz) в с(х, у) + с(г, s) - c(t, у), где (г, 5) — дуга, имеющая в контуре Ci минимальный вес, a (/, у) — дуга С-, заходящая в вершину у все; 15. если х G Vi то заменить дугу (х, у) дугой (у^ у) все; все; 16. все; 17. для i = I VI до 1 цикл
116 3.1.9. Алгоритм Тарьяна проверки каркаса на оптимальность 18. если vi - 1 является корнем некоторого ордерева в лесе, образуемом дугами из БУ КЕТ Д 19. то удалить из контура С - 1 дугу с наименьшим весом; 20. БУКЕТД := БУ КЕТД U {множество оставшихся дуг контура CF1}; 21. иначе % в этом случае в БУКЕТД имеется единственная дуга (х, vbl), заходящая в вершину ; эта дуга соответствует некоторой дуге (х, у), где у — вершина контура С.-,, стянутого в вершину V/-l% 22. БУКЕТД := БУКЕТД U (Et_x\{(t, у)}; %см. строку 14% все все; 23. S := БУКЕТД; все Пример. Построить максимальный лес-каркас для графа G, представленного на рис. 3.4. Вершины графа просматриваются в их лексикографическом порядке, дуги, включенные в БУКЕТД (рис. 3.5), выделены двойными линиями, веса дуг указаны возле соответствующих дуг. 3.1.9. Алгоритм Тарьяна проверки каркаса на оптимальность. Пусть (7= (У, Е) — граф и Т —- каркас графа G. Возникает вопрос: является ли Т оптимальным каркасом для G? Найти ответ на него помо- гает следующий критерий: А. Каркас Т оптимален тогда и только тогда, когда для каждого ребра (и, w) Т выполняется условие cGz, w) > max{c(x, у) I (х, у) лежит на пути и Для реализации проверки оптимальности каркаса предлагается сле- дующий алгоритм. Вычислим максимальный вес ребра из ребер пути по каркасу, соединяющему вершины каждого ребра, не входящего в дерево, и применим критерий 3.1.9.А. Приводимая ниже реализация этого под- хода в виде процедуры ОЦЕНКА-ПУТЕЙ имеет трудоемкость
3.1.9. Алгоритм Тарьяна проверки каркаса на оптимальность 117 п)), если G имеет т ребер и п вершин. В ней используются следующие операции, реализация которых приведена ниже: ОЦЕНКА(г) — найти корень дерева, содержащего в текущий момент вершину v, скажем г, и максимум меток вершин на пути из v в г; Рис. з.з з
118 3.1.9. Алгоритм Тарьяна проверки каркаса на оптимальность СВЯЗЬ (v, ту) — слить деревья с корнями у и ту в отдельное дерево с помощью добавления ребра (у, ту) так, что новым корнем становится вершина у (это делает v отцом вершины ту); ОБНОВЛЕНИЕМ, х) — заменить I на max(x, Z), если и — корень дерева и и имеет метку Z; НОП(у, ту) — для вершин v и w найти их общего предка в дереве; СЖАТИЕ-ПУ ТИМ) — см. п. 2.1.10. Идея алгоритма сос >ит в следующем. Пусть Т — каркас, выберем произвольно корень каркаса, пусть это будет вершина г. Для каждой пары (у,, ту,), определяющей ребро, не входящее в каркас, найдем вер- шину щ== НОП(ур ту,) и вычислим максимум весов ребер, лежащих на пути из ц в у,, и на пути из ц в Сравнивая эти две оценки, дадим ответ для каждой пары Ц, w). Ниже СЫН (у) есть множество сыновей вер- шины у в Т, ОТЕЦ (у) — предок у в Т. проц ПОИСК (м: вершина) = 1. для каждого сына у вершины и в Т цикл 2. ПОИСК(у) все; 3. для всех (у, ту) из БУКЕТ (и) цикл 4. ОТВЕТ (у, w) := если и в у то ОЦЕНКА(ту) иначе если и s ту то ОЦЕНКАМ) иначе тах(ОЦЕНКАМ), ОЦЕНКА(ту)) все все все; 5. для всех у из СЫН (и) цикл СВЯЗЬ М, у) все все; проц ОЦЕНКА-ПУТЕЙ (г: вершина) = 1. для всех у из V - {г} цикл 2. Z(v) :« (ОТЕЦ(у), у); 3. БУКЕТ(у) :«0 все; 4. для каждого ребра (у, ту), не принадлежащего каркасу Т цикл добавить (у, ту) в БУКЕТ(НОП(у, w)) все; ПОИСК (г) все Очевидно, что трудоемкость алгоритма определяется эффективно- стью реализации указанных операций. Операция НОП(у, ту) . Данная операция реализуется следующим алгоритмом: проц ПОИСК 1 (у: вершина; л: набор) = 1. для всех ту из СЫН (у) цикл 2. ПОИСК 1 (ту); слить тус у в л все; 3. для каждого ребра (у, ту) , не принадлежащего каркасу Т цикл 4. если (у, ту) помечено то 5. снять пометку с (у, ту) 6. иначе НОП(у, ту) := найти ту в л
3.1.9. Алгоритм Тарьяна проверки каркаса на оптимальность 119 все все все; проц НОП = 1. я: набор = {({v}, v): у G V}i 2. Пометить все ребра (v, w), не принадлежащие каркасу Т; 3. ПОИСК (г) все Как легко видеть, процедура ПОИСК1 реализует поиск в глубину. Во время его каждое ребро (у,и>), не принадлежащее каркасу, просматрива- ется дважды: один раз при посещении у, второй — w. Во время второго обхода ребра (y,w) вычисляется НОП(у,и>) и хранится в НОП(у,м>). Трудоемкость операции НОП — О((т + п)а(т + п, п)). Операция ОЦЕНКА(у). Данная операция реализуется следу- ющим алгоритмом: проц СЖАТИЕ (у: вершина) = 1. если ОТЕЦ(ОТЕЦ(у)) # Ото 2. СЖАТИЕ (ОТЕЦ (у)); 3. Z(y) := шах(/(ОТЕЦ(у)), /(у)); 4. ОТЕЦ(у) := ОТЕЦ(ОТЕЦ(у)) все все; функ ОЦЕНКА(у: вершина): вещ = 1. если ОТЕЦ (у) = 0 то 2. ОЦЕНКА := Z(y) 3. иначе СЖАТИЕ (у); 4. ОЦЕНКА := max (/(ОТЕЦ (у), Z(v)) все все Операция СВЯЗЬ (v,w). Пусть каркас Т имеет структуру, показанную на рис. 3.6. Для любого корня г поддерева STj СЫН(гу) = если j<k,w СЫН (г) = = 0, если у = к. Для любого корня г. обозначим через РАЗМЕР (г;) число потомков г в VT (VT — дерево, получающееся из Т после проведения операций СЖАТИЕ и СВЯЗЬ), т.е. к РАЗМЕР (г.) = ]£ IST.I, i=j где I ST-I есть число вершин в ST (для удобства мы будем употреблять для ISTI также выражение СУБРАЗМЕР (г.)). Положим для определен- ности РАЗМЕР (0> = О, тогда СУБРАЗМЕР(г) = РАЗМЕР(г) - РАЗМЕР (СЫН (г)). проц СВЯЗЬ (у, iv) = 1. ОБНОВЛЕНИЕ(»v, Z(v>); 2. РАЗМЕРА) := РАЗМЕР(у) + РАЗМЕР^); 3. s := и»;
120 3.1.9. Алгоритм Тарьяна проверки каркаса на оптимальность 4. если РАЗМЕР(у) > 2* РАЗМЕРОВ то (s, СЫН(у)) := (СЫН(у), $) все; 5. пока s*0 цикл 6. ОТЕЦ($) := у; 7. $:=СЫН(х); все все проц ОБНОВЛЕНИЕ (г, х) = 1. %эта процедура предполагает, что РАЗМЕР(О) = 0 и НО) = » % 2. /(г) := шах(х,/(г)); 3. Ы: пока/(г) >/(СЫН(г)) цикл 4. г1:=СЫН(г); 5. L2: пока Кг) > /(СЫН (г. >) цикл 6. если РАЗМЕР (г.) + РАЗМЕР (СЫН (СЫН (г.))) > > 2* РАЗМЕР (СЫН (г.)) 7. тоОТЕЦ(СЫН(г.)> := г,; 8. СЫН (г, ):= СЫН (СЫН (г,)) 9. иначе РАЗМЕР (СЫН (г.)) := РАЗМЕР(п); 10. rj := ОТЕЦ 09 := СЫН(Г|); все все; 11. Кг.) :=Кг); 12. СЫН(г):-г, все все Рис. 3.6
3.2.1. Алгоритм Винтера. Предварительные сведения 121 Заметим, что выбор Z(0) = «> гарантирует, что L1 не исполняется, если СЫН(г) =0, и L2 не выполняется, когда СЫНС^) =0. Заметим также, что $ исполняется в точности тогда, когда РАЗМЕР (гр + РАЗМЕР(СЫН(СЫН(г1))) > 2 * РАЗМЕРССЫНСгр), т.е. когда СУБРАЗМЕР (г.) = РАЗМЕР (п) - РАЗМЕР (СЫН (г,)) > > РАЗМЕР (СЫН (rj) - РАЗМЕРССЫЩСЫЩг,))) = = СУБРАЗМЕР (СЫН (гр). 3.2. Алгоритмы перечисления всех каркасов 3.2.1. Алгоритм Винтера. Предварительные сведения. Пусть G — связный неориентированный граф с п вершинами и т ребрами. Пусть, далее, Тп — некоторый каркас графа G. Граф называется собственно размеченным, если его вершины занумерованы по следующему правилу. Выберем какой-либо лист каркаса Тп и присвоим ему номер п, удалим этот лист и ребро, инцидентное ему. В полученном дереве Tn_t снова выберем какой-нибудь лист и присвоим ему номер п - 1, удалим лист п - 1 ит.д. Пусть теперь п, — вершина, смежная с вершиной п в собственно размеченном графе G. Пусть граф G п' получается из G с помощью следу- ющих операций. 1. Все ребра, соединяющие вершины п - 1, п - 2,..., «. с п, удаляются из G. 2. Оставшиеся инцидентные п ребра делаются инцидентными вер- шине И;. 3. Вершина п удаляется из G. Будем говорить в этом случае, что G" получается из G собственным втягиванием п в Ясно, что G"» есть собственно размеченный муль- тиграф с п - 1 вершиной с номерами 1,2, ..., и - 1 (параллельные ребра возникают как результат втягивания). Основная идея алгоритма состоит в следующем. Пусть Р — множест- во всех каркасов собственно размеченного мультиграфа Gen верши- нами. Обозначим через Г(м) в {п15 л2,..., nt} множество вершин, смежных сп, и через Р^к, к= 1, 2, ..., t, множество каркасов, у которых имеется ребро (п, пк) (точнее, одно из параллельных ребер, соединяющих п и пк) и нет ребер, соединяющих п с п^2,..., nt, т.е. Рпк= {Т G PI (л, пк) G Т, (и, иж) £ nt) £ Т}. Ясно, что {Р"1, Р”2,...»P"f} есть разбиение Р, и чтобы перечислить все каркасы из Р, нужно вначале перечислить все каркасы из Р , затем из Р”2 и т.д. Пусть G\ к = 1, ..., t, есть мультиграф, полученный из G собственным втягиванием п в пк. Каждому каркасу в GПк соответствует единственный каркас графа G из РПк. Верно и обратное, каждому каркасу графа G из Р Пк соответствует единственный каркас графа GПк. Следова- тельно, каждое множество РПк,к = 1,2,...,/, может быть дальше разбито,
122 3.2.2. Алгоритм Винтера. Описание используя ребра, инцидентные вершине л- 1 в G\ тем же способом, каким Р было разбито, используя ребра, инцидентные п в G. Действуя таким образом, множество Р можно разбить на взаимно различные, непустые подмножества Р*\ Р*\ ...,Ра*, гдеаг, гя 1, 2,..., $, есть последовательность из п - 1 (не обязательно различных) вершин гл, гл_р ..., г2 и гп обозначает вершину в G, в которую была втянута вершина п для получения Gr", обозначает вершину из Gr", в которую была втянута вершина п - 1 для получения (G'")'"-1 = G w*-1, и т.д. Заметим, что i > для каждого л, л - 1, ..., 2 и G“r состоит всего из одной вершины 1. 3.2.2. Алгоритм Винтера. Описание. Пусть G — собственно разме- ченный граф с ребрами, занумерованными числами 1, 2,..., т. Введем следующие обозначения: Gfir— мультиграф, получаемый из G с помощью 1Д_1вЛ, 0 < к < п - 1, последовательных собственных втягиваний, т.е. Вг есть последователь- ность вершин гл, г .,..., гл.^р описанная выше; G?r есть собственно поме- ченный мультиграф сп-к вершинами с номерами 1, 2...., п - к\ 2?(/, 0 — множество ребер из G, соединяющих / и i в G^, / = 2, 3,..., п- Л, ie 1, 2,..., / - 1; предполагается, что E(j, i) организовано в виде простого списка; F(/, 0 — первое ребро в E(j\ i); LQ‘, 0 — последнее ребро в E(j, i); EE(j) — 3, ..., n — к) множество всех E(j, z), ze 1, 2, ..., j- 1, которые не пусты; предполагается, что EE(j) организовано в виде дваж- ды связанного списка. Кроме того, определим FF(j) = г, где E(j> i) — первое множество из EE(j), LL(j) = z, где Eij.i) — последнее множество из EE(j), MM(j) » max{z I Е(/, z) G EE(J)}. Мультиграфы G^ Гп~к генерируются для каждого г 1 < гп_к < п- к, при условии, что Е(п - к, гп_к) G ЕЕ(п - к), в порядке уоывания их меток гп_к. Для получения G^n~k необходимо выполнить следующие шаги. А. Переупорядочить ЕЕ(п - к) так, чтобы все множества, следующие за Е(п - к, гп_к), были уже обработаны. Так как ЕЕ(п - к) есть дважды связанный список, это может быть сделано за время 0(1) при условии, что указатель R(n - к) на множество Е(п - Л, гп_к) в ЕЕ(п - к), обрабо- танное ранее, доступен. Если гп_к = ММ(п - к) (т.е. если ни одно множе- ство из ЕЕ(п - к) еще не обработано), то Е(п - к, гп_к) передвигается в самый хвост ЕЕ(п - к). Б. Представление G^ Гп~к получается путем добавления Е(п - к, z) G G ЕЕ(п - к) к E(rn_ki z) для каждого Е(п - Л, z), встретившегося при про- смотре ЕЕ(п - Л), пока не достигнуто Е(п - к, гп_к). Для каждого встре- тившегося Е(п - кь z) могут иметь место следующие возможности: # 0. В этом случае Е(п - к. z) добавляется в хвост E(rn_ki i). Для того чтобы иметь возможность восстановить G\ когда был обра- ботан G^l-/c, исходный указатель на последний элемент в E(rn_k, z) пе- редвигается в стек. Для данного п- к, 0 Л < л - 1, стек содержит самое
3.2.2. Алгоритм Винтера. Описание 123 большее м-Л-2 элемента. Таким образом, размер стека ограничен сверху величиной п-2 X <п-к-2) = (п~2)(п~ 1)/2. £=0 Заметим, что в течение обработки GP/n~k множество Е(п - Л, гл^) остается неизменным. Б2. E(rn_k, i) = 0. В этом случае создается E(rn_k, i) в Е(п - Л, z). За- метим, что нет необходимости помещать исходный указатель на по- следний элемент в E(rn_ki i) (« 0) на стек, так как пустое множество может быть восстановлено проверкой, выполняется ли равенство F(n - Л, D » »F(rn_*,z). Создание E(rn_k, i) требует, чтобы оно было добавлено к ЕЕ(гп_к), Может случиться, чтоММ(гп_к) < L Если это так, то пустьMM(rn_k) s 1, в то время как исходное значение ММ(гпЧ) помещается в стек. Так как случаи Б1 и Б2 не встречаются одновременно, может быть использован один и тот же стек. Ясно, что и Б1, и Б2 могут быть выполнены за время 0(1). В. Для данного представления G^f^k алгоритм осуществляет (рекур- сивную) обработку G^"-*. По завершении ее представление G^ должно быть восстановлено. Это может быть сделано просмотром элементов, предшествующих Е(п - Л, гп_к) в ЕЕ(п - Л), в обратном порядке. Для каждого встретившегося Е(п - Л, /) может иметь место один из следу- ющих случаев: Bl.F(n - Л, z) * F(rn_ki i). В этом случае исходное E(rn4ci i) не пусто и указатель на последний элемент находится в вершине стека. В2. F(n-k, i) s F(r.n_k, z). В этом случае исходное E(rn_ki z) пусто. Текущее E(rn4ci z) удаляется из ЕЕ(гпЧ). Более того, еслиMM(rn_k) = z, то исходное значение ММ(гпЧ) находится в вершине стека. . Ясно, что и В1, и В2 могут быть выполнены за время 0(1). Г. Когда восстанавливается Cfr из определяется наибольшее z (обозначаемое //_*), встретившееся при просмотре EEGi - к). Это 1*„_к (если оно существует) замещает гп _ к, и Gp/n~k порождается тем же спосо- бом, каким было порождено G^n~k. Если г^_к не существует, возвращаем- ся на шаг назад. Из приведенных выше рассуждений следует, что время, необходимое для получения представления GP/n^k из g\ так же как и время для восстановления G^, равно О (с), где с есть число просмотренных элемен- тов EEfji - к). Ниже приводится описание алгоритма Винтера. В нем для облегчения понимания опущены детали получения G^"-* из GPr и восстановления Gp' из Gfi'"-k, описанные выше. Смысл процедур МЕТКА,- ИНИЦИАЛИ- ЗАЦИЯ и ВЫХОД будет пояснен позже. проц ВТЯГИВАНИЕ (G: граф; к: цел) = 1 • (гп-к^ гп-к> <Л^Л^/г ~ к), п- к); 2. пока гп_к * 0 цикл
124 3.2.2. Алгоритм Винтера. Описание 3. если п - к » 2 то 4. ВЫХОД 5. иначе передвинуть Е(п - Л, rn_k) так, чтобы оно предшествовало Е(п - Л, гл'_р в ЕЕ(п - к); 6. для каждого Е(п - Л, i) такого, что i < гп_к цикл 7. Е^гп-к^ z); 8. ВТЯГИВАНИЕ «7, Л + 1); 9. ^i-O; 10. для каждого Е(п - к, i) такого, что i < rn_k цикл 11. Удалить из Е(гп_к, /) все ребра, принадлежащие Е(п - к, 0; 12. если i > r;t'_kтоrnLk iвсе 13. (гп-к’ гп-к^ ~ ^гп-к' гп-к) все все все все все* проц ПЕРЕЧИСЛЕНИЕ «7: граф) = 1. МЕТКА «7); 2. ИНИЦИАЛИЗАЦИЯ (С); 3. ВТЯГИВАНИЕ (G, 0) все Процедура МЕТКА. Данная процедура обеспечивает собственную разметку графа G. Более того, для уменьшения числа рекурсий рекомен- дуется руководствоваться следующим интуитивным правилом: вершины следует помечать так, чтобы вершины с большей степенью имели бы меньшие номера. Может быть использован следующий подход: начало 1. Выбрать вершину с наибольшей степенью и присвоить ей номер 1; 2. для i от 2 до я цикл 3. среди всех вершин, смежных хотя бы с одной помеченной вершиной, выбрать вершину с наибольшей степенью в G и присвоить ей номер i все конец Эта процедура может быть реализована так, что ее трудоемкость бу- дет равна О(п + т) с требуемой памятью О(п + т). Процедура ИНИЦИАЛИЗАЦИЯ. Эта процедура порождает списки E(j, i) и EE(j) для собственно помеченного графа G. E(j, i) пусто, если вершины / и i не смежны, в противном случае E(j, i) содержит единствен- ное ребро V, D. Если G задан списками смежности, то трудоемкость этой процедуры равна О(т).
3.2.3. Алгоритм Чена генерирования оркаркасов 125 Процедура ВЫХОД. Эта процедура составляет список элементов де- картова произведения E(n, r„) х Е(п- 1, гл_,)х ... х Е(2, 1). Каждое множество из таких п - 1 ребер есть каркас графа G. Общая трудоемкость алгоритма равна О(п + т + nt), где t — число всех каркасов данного графа. 3.2.3. Алгоритм Чена генерирования оркаркасов. Данный алгоритм основан на алгебре Вана, определенной на множестве частичных графов данного графа. Дадим краткое введение в эту алгебру. Пусть G—связный неориентированный граф с вершинами V = {v0, Vj,... ..., vr} и ребрами {Zp /2, •••, 1} и пусть А = {Gp ..., GA, S-H", есть множест- во его частичных графов. Частичный граф без ребер (постой граф) будет обозначаться единицей. Пусть S « {Sp S2,..., Sk}, к = 2 , есть множество всех подмножеств множества А. Оно включает пустое подмножество, обозначаемое 0. Определим коммутативное кольцо над S, являющееся алгеброй множеств частичных графов данного графа. Сложение Кольцевой суммой (симметрической разностью) S, Ф S- для всех St, Sj G S называется множество всех частичных графов, которые содержат- ся либо в Sif либо в S;, но не в обоих вместе. Сложение обладает следующими свойствами: 1) коммутативности: Si ф S. = S- Ф Sy, 2) ассоциативности: Sy ф (Sy ф Sk) = (Si ф Sy) ф Sk, 3) замкнутости: Sy ф Sj G S, 4) существования нуля: 0 ф Sf = Sy, 5) существования отрицательного элемента: Si ф Sy = 0. Умножение Произведением Вана • Sy, Sz, S; G S, называется кольцевая сумма всех частичных графов, каждый из которых есть объединение двух не пересекающихся по ребрам частичных графов, одного из S, и другого из Sy. Умножение обладает следующими свойствами: 1) коммутативности: Sy • S-= S- • Sy, 2) ассоциативности: Sy • (Sj • zk) = (Sy • Sy) • Sk, 3) замкнутости: Sf. • Sy G S, 4) существования единицы: 1 • Sy = Sy, 5) наличия поглощения (I): Sy • Sy = 0 при условии, что Sy не содержит множества 1; 6) существования единицы (II): S2 • Sz = 1 при условии, что S2 со- держит множество 1; 7) наличия поглощения (II): 0 • S, = 0. В приложении к графам это означает, что все частичные графы, со- держащиеся в любом фиксированном множестве Sp имеют одно и то же число ребер. Таким образом, множество Sf может содержать 1 только в случае, когда S£ - 1. Дистрибутивность Имеет место следующее соотношение: A. S, • (S- ф SA = S. • S, ф S, • Sk для любых i, j и к.
126 3.2.4. Алгоритм Чена, Пример Алгебраическое представление частичных гра- фов и множеств частичных графов Имеют место следующие утверждения: Б. Любой частичный граф может быть записан как произведение его ребер, т.е. G. = П • <r.€G. J » В. Любое множество частичных графов может быть записано как кольцевая сумма его элементов: = {Ц> •••> Gt) = к = {GJ Ф {GJ Ф ... Ф {GJ = Ф {(П * }• 7 = 1 VS- Фундаментальные теоремы алгебры Вана связывают между собой различные множества частичных графов, что позволяет генерировать различные виды частичных графов из более простых. При обобщении алгебры Вана на случай ориентированных графов дуги (V;, у) и (у;, у,) при всех операциях рассматриваются как один эле- мент или, более общо, операция умножения переопределяется так, что- бы можно было избежать появления запрещенных конфигураций дуг. Перейдем теперь к изложению алгоритма Чена генерирования всех оркаркасов. Пусть G= (V, Е) — симметричный орграф и пусть S, — множество дуг, исходящих из вершины у? Для удобства дуги (ve, vk) и (у*, уе) будем обозначать et и е'. Справедливо следующее свойство (теорема Чена): Теорема Чена. Пусть для данного симметричного графа G Хг есть произведение Вана (в котором дуги et и е\ рассматриваются как идентичные) множеств Si9 i * г, 1=1 i Тогда множество Т~ pfj Ф {Х2} ф ... Ф да, Г GX,m« 1X1, есть множество оркаркасов с корнем в уг. Как следствие получаем, что для генерации множества каркасов с корнем в заданной вершине для произвольного орграфа достаточно до- полнить его дугами до симметричного графа, а затем удалить из Тг эле- менты, содержащие добавленные дуги. 3.2.4. Алгоритм Чена. Пример. Для графа G (рис. 3.7) соответству- ющий симметричный граф показан на рис. 3.8; дополнительные дуги помечены буквами с двумя штрихами. Множество S, • S2 • для графа G равно:
3.2.5. Генерирование каркасов во взвешенном графе 127 *5*1 * *$2 {#3,е5, е4} • {^2,^3} * {^2, } а {^3^2^4 , ^5^2 е4 ’ ^5^3 ^2» ^5^3 ^4 » ^4 ^3^2) ’ а соответствующее множество каркасов с корнем в вершине v4 есть т4 - {е3'е2'е4"} ф {е3е2е4} Ф ф {е5е3е2} ф -О 3.2.5. Генерирование каркасов во взвешенном графе. В случае взве- шенного графа задача генерирования каркасов ставится как задача ге- нерирования каркасов в порядке увеличения их весов, начиная с оптимального каркаса, j-м минимальным каркасом Г;. будем называть каркас, удовлетворяющий следующему рекурсивному определению: 1) — каркас с наименьшим весом; 2) Г; (j > 2) есть каркас с наименьшим весом, отличный от каркасов Г1? Г2,..., Гу_Р Весом элементарного преобразования каркасов (см. п. 1.1.8) [и, у] (т.е. Г' = Г- и U v) называется величина w[u, у] « w(v) - w(u), таким образом, w(T - и U у) = w(T) + w[u, у]. Имеет место следующее утверждение: А. Каркас имеет наименьший вес, когда для него не существует элементарных преобразований с отрицательным весом. В основе описываемого алгоритма лежит следующее свойство. Б. Пусть Г — каркас с наименьшим весом графа G = (V, Е) и пусть IN С С Г и OUT СЕ-Г, где IN и OUT — данные подмножества Е. Тогда каркас с наименьшим весом, отличный от Г и удовлетворяющий тем же самым ограничениям, получается как Г - и U у, где [w, у] — элементар-
128 3.2.5. Генерирование каркасов во взвешенном графе ное преобразование с минимальным весом, удовлетворяющее условиям izG Т - IN и v G Е-Т - OUT. Пусть Т, — оптимальный каркас. Множества IN, и OUT, определяют- ся следующим образом: 1) INt «0, OUT, ~0; * 2) если Т; « Т, - и U v , то OUT. = OUT. U {v}, IN; = IN. и {/}, OUT; = OUT.. Определим также следующие вспомогательные множества. Предпо- ложим, что первые /- 1 {j> 1) минимальных каркасов уже построены, тогда оставшиеся разбиваются на j - 1 непересекающихся множеств Pf1 » {Тк\к >у- 1, IN. С Т„ OUT. С Е- 7J, /= 1,2,*...,/-1. Кроме того, для i = 1, 2,...,/- 1 положим QJi~l = {([w, v], г) I для каждого v G E-Tf- OUT,., u G Т,. - IN, опре- деляет минимальное элементарное преобразование [u, у] с весом г = w[w, у]}. Заметим, что всякое множество QT1 содержит IЕ - Т, - OUT, I = O(m) меток. Каждое множество РГ1 представляется набором Р'“1 = (Г, [и', V’ ], A., IN., OUT., /), где ([м', у' ], г') есть метка из Q/1 с наименьшим г и tr = w(T) + г' = w(T. - и’ U у'). Л, есть список смежности для Г,, т.е. Л.= {A.(x)lx G V} и А.(х) = {У 1 ребро (х, у) G Т.}. Длина Р'"1 равна О(т), так как 1Л,1 =О(п) и IIN,I + IOUT,I =О(ди). При реализации алгоритма с А,(х) сопоставляется больше информации, считая, что Л,(х) состоит из следующих наборов: А.(х)={(у, w(x, у)), INFLAGI (х, у) Т.}, где INFLAG = 0 означает, что (х, у) £ INp a INFLAG e 1 — что (х, у) G IN? Мы также используем списки смежности графа G: AG — {Лс(х)1х G V}, Ag(x) = {(у, и>(х, у)) I (х, у) GE},
3.2.5. Генерирование каркасов во взвешенном графе 129 а также функции вычисления: ВЫЧИСЛЕНИЕ-21, ВЫЧИСЛЕНИЕ- 22, ВЫЧИСЛЕНИЕ-23, описание которых приведено в п. 3.2.6. проц ГЕНЕРАЦИЯ Рр}, ••• > Q‘j~\ : множество) = 1. Найти Р(.-1 = ((*, [е*,/* ], A*, IN-., OUT,., г*) с наименьшим весом f среди элементов {Pf1 - (/', [e',f ], IN,., OUTp i); i е [!:/>}; 2. если i* • оо то 3. все каркасы построены и G содержит только j - 1 каркасов 4. иначе Aj «- А-> с ребром е , замененным на ребро v , где — список смежности каркаса Ту.; 5. - Q{~1 -{([/, v ], t 6. Q/ «- ВЫЧИСЛЕНИЕ-£)3(Ар IN,-. U v*. OUT,., v, Ql~*); 7. для всех i из (1:;) - {/*} цикл 8. все; 9. если()/.#0то 10. PZ. ♦- (t* + r', [e',v' ], Af., IN,.., OUT,.. U v, , где ([«', v' ], г') есть метка в Q-. с минимальными г и вес t* каркаса Т* может быть вычислен по формуле t - w[e ,v ] 11. иначе РА*- (00,0,0,0,0,1*) все; 12. если Ql * 0 то Р/ - ((* + г'', [е", v'' ], Ау, IN,- U v*, OUT,-., у), где ([е", v" ], г") — метка в Q( с наименьшим г 13. иначе Р< ♦-(<», 0,0, 0,0, г*) все; ф 14. для всех i из [ 1 :/> - {г } цикл р/-р':-1 все все все; , проц КАРКАСЫ (G: граф; к: цел) = 1. %к >2% 2. найти список смежности для оптимального каркаса 7\ и его вес ; 3. если п2 < m • aim. п) то 4. Q\ «- ВЫЧИСЛЕНИЕ-QI 5. иначе Q\ «- ВЫЧИСЛЕНИЕ-22 5 ВЛ. Евстигнеев, В.Н. Касьянов
130 3.2.6. Функции вычисления все; 6. найти минимальное элементарное преобразование <[и', v'], г') bQ}; 7. Р\ - (Г, +r'v [е', v'], Ар 0,0, О; 8. для j от 2 до к цикл 9. ГЕНЕРАЦИЯ (Pf1,...', P>r\, Qj-1,..., }> все все 3.2.6. Функции вычисления. ВЫЧИСЛЕНИЕ-QI. Данная функция вычисляет за О(п2) шагов путем нахождения [u, у] и r = w[w, у] как наименьшего по весу элемен- тарного преобразования для каждого данного ребра у= (х, у) Е Е - Она представляет собой несколько расширенный алгоритм Прима. Рас- смотрим тот шаг алгоритма Прима, когда к текущему фрагменту оп- тимального каркаса добавляется ребро (х, z), где вершина х принадлежит фрагменту, а вершина z нет. Для каждой вершины у из фрагмента обоз- начим через (Л, к) ребро с наибольшим весом на пути у к из у в х по каркасу 1\. Тогда ребро максимального веса на пути у z для у = (х, z) получает- ся путем выбора ребра с наибольшим весом из (х, z) и (Л, к). Эти вычис- ления ребер с наибольшим весом для всех (х, у) таких, что х суть вер- шины из фрагмента, выполняется за время О(п). Так как это может быть повторено п - 1 раз, пока будет построен каркас Г, по методу Прима, одновременно с вычислением ребра с наибольшим весом для каждого v = - (х, у) G Е, полное время вычисления Q} равно О(п2). BbI4HCJIEHHE-Q2. Данная функция представляет собой адаптацию алгоритма Тарьяна (см. п. 3.1.9) с трудоемкостью О (та п)) проверки того, что данный каркас Т неориентированного графа есть оптимальный каркас. Этот алгоритм включает вычисления ребра с наибольшим весом на пути х у для каждого ребра и = (х, у) G Г. Поэтому эта часть его алгоритма может быть использована непосредственно как функция ВЫЧИСЛЕНИЕ-(22 для вычисления Qj. ВЫЧИСЛЕНИЕ-(23. Данная функция служт для получения Q}- за О(т) шагов, когда задано дерево Т.« - и U у*, где [u*, у*} есть наи- меньшее элементарное преобразование b\j Q/”1. ВЫЧИСЛЕНИЕ-фЗ ос- /=1 новывается на следующем свойстве. Свойство. Для Tj и ребра у* » (х*, у), определенных выше, пусть Т;(х*) и Т-(у*) — два дерева, полученные из 7} удалением у*, где х* G G Vj(x^) и / G Vj(y). Здесь V;(x) есть множество вершин в связной ком- поненте Т;(х). Пусть также v = (х, у) есть ребро из Е - - OUT;. Тогда: 1) еслих, у G 1<(х*) илих, у G. V}(y*), то метка ([и, у], г), хранящаяся в Q'r*, содержится также и в Q<;
3.2.6. Функции вычисления 131 2) если х G Vj(x*) и у G то ([u, v], г), хранящаяся в Qj, опре- деляется по формулам: W(u) = тах[тах{Ж(#) lg £ IN;, улежит на пути х* тах{РИ(Л) IЛ £ IN;, h лежит на пути у L r= W(y) - W(u). Для эффективного вычисления ([u, v], г) G Q'b соответствии с при- веденным свойством функция BbI4HCJIEHHE-Q3 предварительно обра- батывает деревья ) и Т.(у) путем вызова подпрограмм EDGEFINDG4;, х*, INp и EDGEFIND(A; у, INp, где А! есть список смежности для Т-{х*) UTj(y). Подпрограмма EDGEFIND(A;', х', INp находит ребро наибольшего веса MAXEDGE *(х) G ТЛх') - IN, на пути х‘ х для каждой вершины х 6 Ту(х). Его вес хранится в Wx(x). (Индекс х* добав- ляется для обозначения MAXEDGE и W, полученных с помощью EDGEFIND(AJ, х*, IN).) Подпрограмма EDGEFIND(Ay, у, INp анало- гична. После этого ([MAXEDGE,/ (z), v], W(v) - W^iz)) добавляется к Q j для каждого ребра v = (х, у) G Е - Т- - OUT; с х G 1<(х*) и у G Щу), где Ww'(z) = тах{(Ир(х), И-p (у)}. Для каждого v = (х, у) G Е - 7} - OUT, с х, у G 7;(х*) или х, у е F}(y*) ([и» v]» г) в Qp1 хранится непосредственно в Qj. проц DFS(Ay, х, у, IN) = 1. для всех z е А'(у) - х таких, что (у, z) £ IN цикл 2. если W(y) '< wty, z) то (MAXEDGE(z), W(z)) «- ((у, z), и>(у, z)) 3. иначе (MAXEDGE(z), W(z)) «- (MAXEDGE(y), W(y)) все; 4. DFS(Ay, у, z, IN) все все; проц EDGEFINDCA;, p , IN) = i. dfs(a;., 0, p , in) все; проц ВЫЧИСЛЕНИЕ-(23(Ау, INy, OUTy, v = (x*, y*), Qf') - 1. (QZ, A'y(x*), Ay(y*)) •*- (0, Aj(x*) - {y*},Aj(y) - {x*}); 2. для всех x * x цикл Ay(x) «- Ay(x) все; 3. для всех х € V ци{сл 4. если х G VAx ) то N(x) 1 иначе N(x) := 0 все; (Ж«(х), Ж «(х), MAXEDGE .(х), MAXEDGE-(х)) «- -<-00,-/0,0) все; t 5. вызвать EDGEFIND(A'-, х , IN ) для получения MAXEDGE »(х) и
132 3.3.1. Построение каркасов с ограничениями на степень вершин И^Чх) для х G Vy(x*); 6. вызвать EDGEFIND(Ay, INy) для получения MAXEDGEy*(y) и Wy*(y) для у G Уу(х*); 7. для всех v - (х, у) из Е - Т - OUT цикл 8. если 7V(x) = А (у) то 9. добавить метку ([u, v], г) из к 10. иначе добавить метку ([MAXEDGE^(z), v], IP(v) - W^iz)) к О'., где z G {x,y} удовлетворяет соотношению (z) » max (Wx* (x), Wy* (y)) 11. % если W^»(z) = oo , то метка не добавляется, так как соответствующее ребро не существует % все все все 3.3. Поиск каркасов с заданными свойствами 3.3.1. Построение каркасов с ограничениями на степень вершин. Постановка проблемы. Среди приложений, особенно при конструиро- вании сетей ЭВМ или сетей связи, встречается следующая задача: для данного взвешенного неориентированного графа найти каркас, у кото- рого степень некоторой вершины г равна заданной константе, deg г s Ь, и который имеет наименьший вес среди всех таких каркасов. Идея решения состоит в последовательном применении элементар- ных преобразований к некоторому начальному каркасу и, следователь- но, в выборе начального каркаса и оптимальной последовательности эле- ментарных преобразований. Пусть г — выделенная вершина в G и R — множество ребер, инциден- тных г. Пусть Тк — множество всех каркасов с deg г - IТ A RI s к. Нам нужно найти каркас из Ть с наименьшей возможной стоимостью. За- метим, что в общем случае для некоторого t > 1 Тк * 0 в точности тогда, когда t < к < IRI. Если Т — каркас с deg г - t, то для получения каркаса с deg г-к могут быть добавлены любые к-t инцидентных г ребер (а другие ребра при этом должны быть удалены). Заметим, что t может быть строго больше единицы, если G\r несвязен. Справедливы следующие свойства. А. Если 7\. # 0 и Т — оптимальное дерево в Тк, то существуют ребра е G Т A R.f Т U R такие, что Т- e+ f есть оптимальное дерево в Т. L Б. Если Тк+1 # 0 и Г -— оптимальное дерево в Тк, то существуют ребра е G Т A R, f G Я\Т такие, что Т - е + / есть оптимальный каркас В. Пусть Т — наименьший по весу каркас в Тк. Если ребра е G Т A R nfiTUR выбраны так, что Т- e~f— каркас и разность c(f) - с(е) — наименьшая для всех таких ребер, то Т- e+f — каркас с наименьшим весом в ТкЛ.
3.3.2. Алгоритм Габова 133 Мы можем найти сокращенное множество ребер, которое содержит наименьшие каркасы во всех Тк. Для этого введем понятие лес-каркаса неориентированного графа, компоненты которого суть каркасы для каж- дой компоненты связности графа. Г. Пусть U — лес-каркас наименьшей стоимости для G - г. Тогда U U R содержит каркас с наименьшим весом в Тк при условии, что # 0. Более общая задача состоит в построении оптимального каркаса, сте- пень каждой вершины которого ограничена сверху. 3.3.2. Построение каркаса с ограничениями на степень вершин. Алгоритм Габова. Основная идея алгоритма состоит в отыскании оп- тимального каркаса, содержащего.R\ потом применяются элементарные преобразования в соответствии со свойством 3.3.1 .В для уменьшения сте- пени deg г до Ь. Для ускорения вычислений найдем сначала минималь- ный лес-каркас U для G - г; потом нужно будет просмотреть только ребра из R U U в соответствии со свойством 3.3.1.Г. Для отыскания элементарных преобразований в соответствии со свойством 3.3.1.В используем систему очередей. Пусть Т — каркас на данном этапе вычислений. Рассмотрим ребро е G Т A R. Элементарное преобразование, которое удаляет е из Т, добавляет ребро/, соединяющее две компоненты связности графа Т - е. Очередь F(e) хранит все такие ребра/. Приоритет/— это его вес с(/). Таким образом, ребро/, которое может заменить е, находится достаточно легко. Очередь X хранит эле- ментарные преобразования [е, /], где для каждого ребра е G Т А к ребро / есть ребро с наименьшим весом, которое может заменить е. Приоритет преобразования [е, /] равен c(f) - с(е). Таким образом, легко находится оптимальное элементарное преобразование. Алгоритм Вход. Граф (7 = <V,E), вершина г, целое b <ТЬ * 0). Выход. Каркас Т с наименьшим весом, для которого deg r=b проц КАРК_ОГР = 1. Найти оптимальный лес-каркас U для G - г; % использовать алгоритм построения оптимального каркаса для каждой компоненты связности графа G - г % 2. R := множество ребер, инцидентных г; 3. Удалить из G все ребра, не принадлежащие U U R\ 4. Т := каркас с наименьшим весом, содержащий 7?; 5. X := пустая очередь с приоритетами; 6. для всех е из R цикл 7. F(e) := очередь с приоритетами, содержащая все ребра/ G U, которые соединяют компоненты графа Т - е; 8. еслир(е)#0то 9. / := наименьшее ребро в F(e); 10. добавить [е, /] к X все все 11. пока deg г > b цикл 12. Удалить элементарное преобразование [е, /] с наименьшим
134 3.3.3. Евклидова задача Штейнера на плоскости весом из X; 13. Удалить f из Г(е); 14. е’ := ребро в R - етакое, что/соединяет компоненты графа Т-е'; 15. Удалить [е', f ] из X; 16. Удалить/из F(e'); 17. Слить очереди F(e) и в новую очередь с приоритетами F(e'); 18. если F(e') * 0 то 19. f := ребро с наименьшим весом в F(e'); 20. Добавить /' ] к X все; 21. Т:=Т-е+/ все все Трудоемкость алгоритма — О(т log log п + п log и), требуемая па- мять — О(т + п). Алгоритм легко модифицируется для решения задачи с ограничением вида deg г > Ъ или deg г < Ь. Трудоемкость модифицированного алго- ритма — О(т log log п + п log п). 3.3.3. Евклидова задача Штейнера на плоскости. Пусть на плоскос- ти задано N точек (для простоты изложения будем считать N четным). Проведем прямую L, разделяющую указанное множество точек на два: Fl и Vr. Соответствующие кратчайшие связывающие сети обозначим MST (VL) и MST (УА). Что получится, если объединить эти деревья в одно? Очевидно, что самая левая часть дерева MST(VA) и самая правая часть дерева MST(VL) вероятнее всего останутся без изменения. Изменятся части деревьев, близкие к разделяющей прямой. Поэтому эффективная реализация процесса слияния деревьев является основой построения кратчайшей связывающей сети методом ”разделяй_и_властвуй”. Процесс слияния включает два вида действий: добавление новых ребер для соединения вершин деревьев MST(VL) и М8Т(УЛ) и удаление ребер указанных деревьев при образовании циклов. Чтобы избежать перебора всех возможных соединений между вершинами обоих деревьев, используется тот факт, что ребра искомого дерева являются ребрами триангуляции Делоне, которая представляет собой фигуру, двойствен- ную диаграмме Вороного, откуда следует, что нужно перебирать только ребра триангуляции Делоне. проц КРАТЧАЙШАЯ-СВЯЗЫВАЮЩАЯ-СЕТЬ (V: множество точек) = 1. Выбрать прямую X - L = 0, перпендикулярную оси ОХ такую, что N/2 точек, где I VI, имеют координату х меньше, чем L, а остальные N/2 точек — больше, чем L. Обозначить эти множества точек через VL и VR соответственно; 2. КРАТЧАЙШАЯ-СВЯЗЫВАЮЩАЯ-СЕТЬ (VL); 3. КРАТЧАЙШАЯ-СВЯЗЫВАЮЩАЯ-СЕТЬ (VR); 4. Найти ребра-кандидаты на соединение деревьев MST (VL) и MST (Ул) из множества ребер триангуляции Делоне. Добавлять эти ребра к деревьям MST( VL) и MST(V^) поочередно снизу вверх. Если при
3.3.4. Евклидова задача Штейнера в 4-мерном пространстве 135 этом образуется цикл, найти и удалить самое длинное ребро в цикле, все Подбор ребер-кандидатов (оператор 4) можно производить с разной эффективностью, используя известные алгоритмы, например, из работы [68]. Отметим также, что построение кратчайшей связывающей сети на плоскости легко реализуется вручную. Трудоемкость алгоритма — O(N log TV). 3.3.4. Евклидова задача Штейнера в Л-мерном пространстве. П ри- водимый ниже алгоритм строит кратчайшую связывающую сеть для мно- жества из N точек в Л-мерном евклидовом пространстве. Метод состоит в организации вначале N одновершинных фрагментов и повторении N - 1 раз конструктивного шага, на котором выбирается фрагмент наименьше- го размера и соединяется с ближайшим фрагментом. Структуры данных: — Л-б/-дерево точек для вычисления минимальных расстояний (описание структуры Л-б/-дерева см. в гл. 7); — очередь с приоритетами фрагментов для выбора фрагментов, реализуемая как связный список (см. п. 3.1.6); — очередь с приоритетами минимальных расстояний до точек вне фрагмента; формируется для каждого фрагмента и реализуется в виде 2-3-деревьев (см. гл. 7). начало 1. Построить оптимизированное Л-б/-дерево для множества точек; 2. для каждой точки р цикл 3. образовать одновершинный фрагмент; 4. образовать очередь расстояний все; % вначале каждый фрагмент содержит только одну вершину и не содержит ребер, каждая очередь расстояний содержит единственный элемент, обозначающий расстояние от точки до ближайшего соседа; чтобы избежать лишних вычислений, считаем вначале ближайшим соседом точки саму точку с расстоянием, равным 0%. 5. Образовать очередь фрагментов в виде очереди размеров фрагментов с приоритетами; % вначале очередь содержит N точек с приоритетами 1 % 6. пока число фрагментов = 1 цикл % кратчайшая связывающая сеть построена, когда число фрагментов равно 1 % 7. Выбрать из очереди фрагментов фрагмент с наименьшим размером; 8. пока элемент с наивысшим приоритетом в очереди расстояний текущего минимального фрагмента нефиктивен цикл % когда вершина присоединяется к фрагменту, некоторые расстояния становятся фиктивными, т.е. ближайщий сосед точки не лежит больше вне фрагментах 9. X :« первая вершина в очереди;
136 3.4. Библиографический комментарий 10. Y := ближайшая точка к X точка вне фрагмента; 11. соединить X с У; 12. удалить фиктивный приоритет вершины X и ввести заново нефиктивные приоритеты в очередь расстояний; все; 13. X := первая вершина из очереди расстояний; 14. У := вершина, соединенная с X; 15. Слить очередь расстояний вершины X с очередью расстояний верщины У; 16. Включить ребро (X, У) во фрагмент, содержащий вершину У; 17. Обновить очередь размеров фрагментов путем удаления элементов, соответствующих прежним размерам фрагментов, содержащих X и У, и добавления нового элемента, соответствующего новому фрагменту, содержащему У; все конец Трудоемкость алгоритма — O(N log М. 3.4. Библиографический комментарий Алгоритмы построения каркасов произвольного неориентированного графа заимствованы из книги [9 ]. Первыми работами, в которых были предложены алгоритмы постро- ения оптимальных каркасов, были работы Краскала [65], Прима [80] и Дейкстры [31 ] (последние два алгоритма реализуют один и тот же под- ход и часто объединяются под именем алгоритма Прима—Дейкстры). Описание этих алгоритмов встречается в большинстве монографий по теории графов и приложениям; предлагаемый здесь алгоритм Краскала заимствован из книги [1] (см. также книгу [6]). Менее известен ал- горитм Соллина, изложенный в книге [14 ]. Связь этих трех алгоритмов исследуется в работе [93] (см. также [46, 61, 69, 77 ]). Следующая волна работ, посвященных данной задаче, связана с появлением алгоритмов с оценками трудоемкости. Среди них укажем на [25, 97 ], предложенные в этих работах алгоритмы имеют трудоемкость в худшем случае О(т log log п), в то время как алгоритм Прима, например, — О(п~). Развитием этого направления является использование новых типов структур дан- ных. Так, использование дереььев в качестве структур данных для реа- лизации очередей с приоритетами дает вариант алгоритма Черитона— Тарьяна с трудоемкостью О(т log log(w/,I+2)/i), а использование в качестве структуры данных фиббоначиевой кучи улучшает эту оценку до О(т • •/?(ди, п)), где/3(т, n) = min{illog(,>(fi) < т/п} [38 ]. В работах [41,42]эта оценка улучшается до О(т log (Нт, п)). Третья волна алгоритмов связа- на с появлением интереса к параллельным алгоритмам [66] и к алго- ритмам для распределенных вычислений [3 ], но это лежит за пределами нашей книги.
3.4. Библиографический комментарий 137 В обзоре [47 ] утверждается, что алгоритм Прима — Дейкстры есть на самом деле переоткрытый алгоритм Ярника, предложенный еще в 1930 г. [51]. Алгоритм построения оптимального оркаркаса принадлежит Эдмонд- су [34] и излагается по книге [10]. Алгоритм построения оркаркаса с трудоемкостью O(mlogn) был предложен также в работе [89 ]. Алгоритм проверки каркаса на оптимальность заимствован из работы [90]. Интерес к алгоритмам генерирования каркасов графов возник, по- видимому, в конце 50-х—начале 60-х гг. в связи с исследованиями тео- ретико-графовых методов анализа электрических цепей [4, 20—22, 24, 35, 36, 43, 50, 56, 70—72, 75, 78, 79, 81, 94 ]. Лучшим из них по трудоем- кости считается алгоритм Габова и Майерса [43 ], его трудоемкость равна О(п + nt + nt). Однако, хотя трудоемкость алгоритма Чара [20 ] в худшем случае равна О(п + т + n(t + /0)>, Джаякумар и Тхуласирам [52], срав- нивая его с алгоритмом Габова и Майерса, пришли к выводу о его боль- шей эффективности, и это преимущество растет с ростом числа каркасов. Дальнейшим развитием алгоритма Габова и Маейрса является изложен- ный в данной главе алгоритм Винтера с трудоемкостью О(п + т + nt) и требуемой памятью О(п2) [96 ]. Алгоритм генерирования оркаркасов принадлежит Чену [22], в его основе лежит алгебра Вана [15, 33, 95]. Реализация алгоритма с по- мощью системы аналитических вычислений была выполнена А.Л.Семе- новым (см. [11, 12, 83]). Оставляя в стороне матричные методы генерации каркасов [23, 24, 71 ], заметим, что наиболее эффективны методы генерации каркасов с использованием элементарных преобразований каркасов, причем имен- но те из них, которые основаны на преобразовании последнего построен- ного каркаса. Возможность существования таких алгоритмов вытекает из гамильтоновости графа каркасов данного графа (см. п. 1.1.8), исследо- ванной в работах [29, 48, 54, 62, 63, 85]. В связи с попыткой уменьшить трудоемкость алгоритма генериро- вания каркасов Майеды и Сешу [72] Део в 1960 г. ввел понятие цент- рального дерева графа. Оно оказалось чрезвычайно полезным при расче- те электрических цепей с помощью законов Кирхгофа. Пусть r[G] — ранг графа G = (V, Е), т.е. ранг его матрицы смежности, и G • S — граф, получаемый из G удалением ребер из множества E-S, SCE. Део [30] определил центральное дерево графа G как каркас Г5, для которого спра- ведливо неравенство r[G • Ts] < r[G • Г], где Т — произвольный каркас графа G, Ts = Е - Ts и Т = Е - Г. Другое эквивалентное определение центрального дерева состоит в следующем [64, 86 ]. Пусть расстояние между каркасами определяется как наимень- шее число элементарных преобразований, требующихся для перехода от одного каркаса к другому, и пусть Т*_— самый дальний для каркаса Т каркас. Пусть d(T) = I Т П 7*1, где Т — дополнение к каркасу Т в G
138 3.4. Библиографический комментарий (кодерево). Тогда Т есть центральное дерево для G, если для него выпол- нено условие d(T) < J(T') для любого каркаса Т графа G. О других методах повышения эффективности генерации каркасов см. [53, 60, 82, 92]. Алгоритм порождения каркасов в порядке возрастания их весов обычно имеет вид алгоритма, порождающего Л-й по весу оптимальный каркас {55, 59, 67 ]. Излагаемый здесь алгоритм заимство- ван из работы [58 ]. Имея трудоемкость O(Km + min(m log log n, n2), он представляет некоторое усиление алгоритма Габова [39] с трудоемко- стью O(Kma (т, п) + т logn), где а есть обратная по Тарьяну функция к функции Аккермана. Среди других работ на эту тему следует указать на [16, 17, 73]. Алгоритм с трудоемкостью О(п2) для решения задачи о каркасе наи- меньшего веса с ограничением на степень выделенной вершины был предложен Гловером и Клингманом в работе [45], описываемый алго- ритм Габова с трудоемкостью О(т log log п + п log п) заимствован из ра- боты [40]. Задача построения кратчайшей связывающей сети для Р точек на евклидовой плоскости (или Р точек в ^-мерном евклидовом пространст- ве) известна как евклидова задача Штейнера. Впервые она была постав- лена как геометрическая задача (см. [5, 7, 44, 74]), в которой нужно множество точек Р на евклидовой плоскости соединить линиями так, чтобы сумма длин отрезков была минимальна. Если не допускаются пересечения любых двух линий в точках вне заданного множества Р, то задача сводится к одной из задач нахождения оптимального каркаса эквивалентного графа на вершинах с матрицей весов, вычисленных как евклидово расстояние между точками множества Р. Если допускается на плоскости введение дополнительных ’’искусственных” вершин (называе- мых точками Штейнера), то длину кратчайшей связывающей сети мож- но уменьшить соответствующим подбором точек. Таким образом, для решения задачи Штейнера можно добавить в любых местах плоскости столько точек Штейнера, сколько необходимо для построения наикрат- чайшего дерева, стягивающего множество из Р точек. Получающееся дерево называют наикратчайшим деревом Штейнера. Задача Штейнера на евклидовой плоскости достаточно хорошо изучена, и известно боль- шое число свойств наикратчайшего дерева Штейнера [6, 27, 28, 44, 74 ]. Бентлей и Фридман [13] предложили два алгоритма для решения евклидовой задачи Штейнера и показали, что в среднем ее трудоемкость равна О(п log и). В работах [57, 76] были предложены улучшенные версии этого алгоритма, а в [57 ] указывалось, что в худшем случае тру- доемкость алгоритма Бентлея и Фридмана равна О(п2 log п). В работе [84 ] показано, что минимальное связывающее дерево на плоскости мо- жет быть извлечено из диаграммы Вороного для заданных точек на пло- скости. Трудоемкость предложенного там алгоритма — О(п log п) в худ- шем случае. В работе [98 ] предложен алгоритм для отыскания кратчай- шей связывающей сети в ^-мерном пространстве с трудоемкостью О(пw(log n),-rta)), где a(k) = 2 </f"1). Эта оценка может быть улучшена до О((п log и)18) для трехмерного пространства. Описанный алгоритм построения с трудоемкостью О(п log п) основан на использовании триан-
Список литературы 139 гуляции Делоне и заимствован из работы [18]. Алгоритм с такой же трудоемкостью описан также в [87 ]. Из других задач, связанных с каркасами, укажем на следующие. Пусть дан граф и каркас в нем и пусть веса ребер произвольно изменяют- ся. Возникает задача исследования чувствительности каркаса к изме- нениям весов, решение ее рассмотрено в работе [91 ]. Другая интересная задача состоит в эффективном преобразовании оптимального каркаса в оптимальный же при изменении весов ребер. Этой задаче посвящены, например, работы [26, 37, 88]. В [37] предлагается новая структура данных, использование которой в задаче генерирования каркасов во взвешенном графе снижает трудоемкость до О(т log log(2+m/n)n+^’/m) при Л = O(V7n). Пусть теперь в графе G = (У, Е] задано подмножество вершин V С Vи пусть Т' есть оптимальный каркас для подграфа G* = (Я', Е'), У' < Я' < У, причем вес каркаса Т наименьший среди всех таких каркасов для под- графов, обладающих указанным свойством. Данная задача известна как задача о минимальной связке, или задача Штейнера на графах. Ее связь с рядом задач теории графов (число всесмежности, неплотность и др.) была исследована В. Г. Визингом в работе [2 ], алгоритмы решения пред- ложены в [8, 19, 32, 49, 65 ]. Однако с вычислительной точки зрения эти алгоритмы являются неэффективными процедурами, хотя они и зна- чительно лучше, чем последовательный просмотр оптимальных карка- сов всех подграфов графа. СПИСОК ЛИТЕРАТУРЫ 1. Ахо А., Хопкрофт Дж., Ульман Дж. Построение и анализ вычислительных алгоритмов. — М.:Мир, 1978. 2. Визинг В.Г. Сводимость ряда задач теории графов к задаче о минимальной связке// Вычислительная математика и вычислительная техника. — Харьков, 1971. — Вып. 2. — С. 52—55. 3. Евстигнеев В. А. О некоторых свойствах локальных алгоритмов на графах// Комбина- торно-алгебраические методы в прикладной математике. — Горький, 1983. — С. 72— 105. 4. Зыков А.А. Теория конечных графов. — Новосибирск: Наука. Сиб. отд-ние, 1969. — 4.1. 5. Кокстер Г.С.М. Введение в геометрию. — М.: Наука, 1966. 6. Кристофидес Н. Теория графов. Алгоритмический подход. — М.: Мир, 1978. 7. Курант Р., Роббинс Г. Что такое математика? — М.: Наука, 1970. 8. Левин А.Ю. Алгоритм кратчайшего соединения группы вершин графа// Докл. АН СССР. — 1971. — Т. 200, № 4. — С. 773—776. 9. Липский В. Комбинаторика для программистов. — М.: Мир, 1988. 10. Майника Э. Алгоритмы оптимизации на сетях и графах. — М.: Мир, 1981. 11. Семенов А.Л. Программа обработки графов на ЭВМ с использованием системы аналити- ческих вычислений и ее применения// Методы и программы решения оптимизацион- ных задач на графах и сетях. Ч. 1. Алгоритмы, программы, применения: Тез. докл. / Все- союз. совещ., Новосибирск, 1984. — Новосибирск, 1984. — С. 204—206. 12. Яблонский Г.С., Евстигнеев В.А., Быков В.И. Графы в химической кинетике// Приме- нение теории графов в химии. — Новосибирск, 1988. — С. 70—143.
140 Список литературы 13. Bentley J.L., Friedman J.H. Fast algorithms for constructing minimal spanning trees in coordinate spaces//IEEE Trans. Computers. — 1978. — Vol. C-27, N 2. — P. 97—105. 14. Berge C., Ghouila-Houri A. Programme, Spiele, Transportnetze. — Leipzig: B.G.Teubner Verlagsgeselschaft, 1967. 15. Berger IM Nathan A. The algebra of sets of trees, X-trees and other configurations//IEEE Trans. Circuit Theory. — 1968. — Vol. CT-15, N 3, — P. 221—228. 16. Burns R.N., Haff C.E. A ranking problem in graphs//Proc. of the 5th Southwest Conf, on Combinatorics, Graph Theory and Computing. — 1974. — P. 461 —470. 17. Camerini P.MM Fratta L., Maffioli F. The К shortest spanning trees of a graph//Int. Rep. 73- 10, IEEE-LCE Politechnico di Milano. — Milan, 1974. 18. Chang R.Cm Lee R.C.T. An O(nlogn) minimal spanning tree algorithm for n points in the plane//BIT. — 1986. — Vol. 26, N 1.— P. 7— 16. 19. Change S.-K. The generation of minimal trees with Steiner topology//! ACM. — 1972. — Vol. 19.—P. 699. 20. Char J.P. Generation of trees, two-trees and storage of master forests//IEEE Trans. Circuit Theory. — 1968.—Vol. CT-15. —P. 128—138. 21. Chase S.M. Analysis of algorithms for finding all spanning trees of a graph//RS3190, IBM T.J.Watson Research Center, Yorktown Heights, N.Y., 1970. 22. Chen Wai-Kai. On directed trees and directed К-trees of a digraph and their generation//J. SIAM Appl. Math. — 1966. — Vol. 14, N 3. — P. 550—560. 23. Chen Wai-Kai. Applied graph theory. — Amsterdam, North-Holland, 1971. 24. Chen Wai-Kai, Li H.-C. Computer generation of directed trees and complete trees//Int. J. Electronics. — 1973. — Vol. 34. — P. 1. 25. Cheriton D., Tarjan R.E. Finding minimum spanning trees//SIAM J. Comput. — 1976. — Vol. 5, N 4. — P. 724—742. 26. Chin F., Houck D. Algorithm for updating minimum spanning trees//! Comput. System Sci. — 1978. — Vol. 16. — P. 333—334. 27. Cockayne E.J. On the efficiency of the algorithm for Steiner minimal trees//! SIAM Appl. Math. — 1970. — Vol. 18. — P. 150. 28. Cockayne E.J., MelzakZ.A. Steiner’s problem set terminals//Quart. Appl. Math. — 1968. — Vol. 26. —P. 231. 29. Cummings R.L. Hamilton circuits in tree graphs//IEEE Trans, on Circuit Theory. — 1966. — Vol. CT-13. —P. 82. 30. Deo N. On central tree//IEEE Trans. Circuit Theory. — 1960. — Vol. CT-13. — P. 439—440. 31. Dijkstra E.W. A note on two problems in connection with graphs//Numer. Math. — 1959. — Vol. l. — P. 269—271. 32. Dreyfus S.Em Wagner R.A. The Steiner problem in graphs// Networks. — 1972. — Vol. 1. — P. 195. 33. Duffin R.J. An analysis of Wang algebra of network//Trans. Am. Math. Soc. — Oct. 1959. — P. 114—130. 34. Edmonds J. Optimum branchings. Mathematics of the decision sciences//Leet. Appl. Math. — 1968. — Vol. 2. — P. 346—361. 35. Farrell E.J. Spanning trees in graphs with cycloma tic numbers 2, 3 and 4//J. Combinatorics, Inform, and Syst. Sci. — 1980. — Vol. 5, N 1. — P. 38—46. 36. Fidler J.K., Horrocks D.N. On the generation of X-trees//! of Electronics. — 1973. — Vol. 34.—P. 185. 3 7. Frederickson G.N. Data structures for on-line updating of minimum spanning trees, with applications//SIAM J. Comput. — 1985. — Vol. 14, N 4. — P. 781 —798.
Список литературы 141 38. Fredman M.L., Tarjan R.E. Fibonacci heaps and their uses in improved network optimization algorithms//;. ACM. — 1987. — Vol. 34, N 3. — P. 596—615. 39. Gabow H.N. Two algorithms for generating weighted spanning trees in order//SIAM J. Comput. — 1977. — Vol. 6. — P.139—150. 40. Gabow H.N. A good algorithm for smallest spanning trees with a degree constraint//Networks. — 1978. — Vol. 8. — P. 201—208. 41. Gabow H.N., Galil Z., Spencer T. Efficient implementation of graph algorithms using contraction//Proc. 25th Annual IEEE Symp. on Foundations of Computing, Singer Island, Fla., Oct. 24-26. — New York, 1984. — P. 338—346. 42. Gabow H.N. Efficient algorithms for finding minimum spanning trees in indirectfed and directed graphs/ZCombinatorica. —1986. — Vol. 6, N 2. — P. 109—122. 43. Gabow H.N., Myers E.W. Finding all spanning trees of directed and undirected graphs//SIAM J. Comput. — 1978. — Vol. 7. — P. 280—287. 44. Gilbert E.N., Pollack H.O. Steiner minimal trees//;. SIAM Appl. Math. — 1968. — Vol. 16. — P. 1. 45. Glover F., Klongman D. Finding minimum spanning trees with a fixed number of links at a nodeZ/Rep. N 74-5, Res. Rep. CS 169, Center for Cybem. Studies. — Austin, Texas, 1974. 46. Gower J.C., Ross G.J.S. Minimum spanning trees and single linkage cluster analysisZ/Appl. Statistics. — 1969. — Vol. 18. — P. 54. 47. Graham R.L., Hell P. On the history of the minimum spanning tree problem//Ann. Hist. Comput. — 1985. — Vol. 7, N 1. — P. 43-57. 48. Hakimi S.L. On trees of a graph and their generation//;. Franklin Inst. — 1961. — Vol. 272, N 5. — P. 347—359. 49. Hakimi S.L. Steiner’s problem in graphs and its implications//Networks. — 1971. — Vol. 1. — P. 113. 50. Hakim' S.L., Green D.G. Generation and realization of trees and k-trees//IEEE Trans. Circuit Theory. — 1964. — Vol. CT-11. — P. 247—255. 51. Jarnik V. О jistem problemu minimalnim//Praca Moravske Prirodovedske Spolecnosti. — 1930. — Vol. 6. — P. 57—63 (на чешек, яз.). 52. Jayakumar R., Thulasiram K. Analysis of a spanning tree enumeration algorithm//Combinatorics and Graph Theory. Leet. Notes in Math. — Springer-Verl., 1980. — N 833. — P. 284—289. 53. Johnson D.B. Priority queues with update and finding minimal spanning trees//Inf. Process. Lett. —1975. —Vol. 4,N1. 54. Kamae T. The existence of Hamiltonian circuits in tree graphs//IEEE Trans. Circuit Theory. — 1967. —Vol. CT-14. —P. 279. 55. Kano M. Maximum and k-th maximal spanning trees of a weighted graph//Combinatorica. — 1987. — Vol. 7. — P. 205—214. 56. Kasahara Y. et al. Topological evaluation of system determinants//Technol. Repts. Osaca Univ. — 1962. — Vol. 12. — P. 239—248. 57. Katajainen J. On the worst case of a minimal spanning tree algorithm for euclidean space//BIT. — 1983. — Vol. 23, N 1. — P. 2—8. 58. Katon N., Ibaraki T., Mine H. An algorithm for finding к minimum spanning trees//SIAM ;. Comput. — 1981. — Vol.,10, N 2. — P. 247—255. 59. Kawamoto T., Kajitani Y., Shinoda S. On the second maximal spanning trees of a weigted graph//Trans. IECE;apan. — 1978. — Vol. 61-a. — P. 988—995. 60. Kershenbaum A., Van Slyke R. Computing minimum spanning trees efficiently//Proc. Ann. Conf. ACM. — Boston, 1972. — P. 518.
*42 Список литературы 61. Kevin V., Whitney М. Algorithm 422 — minimal spanning tree//Comm. ACM. — 1972. — Vol. 15. —P. 273. 62. Kishi G., Kajitani Y. On Hamilton circuits in tree graphs//IEEE Trans. Circuit Theory. — 1968.— Vol. CT-15. —P. 42. 63. Kishi G., Kajitani Y. On the realization of tree graphs// Ibid. — P. 271. 64. Kishi GM Kajitani Y. Generalized topological degree of freedom in analysis of LCR networks // Papers of the Techn. Group on Circuit and System Theory of Inst. Elec. Comm. Eng. Japan, . NCT 71-19, July 1971. — P. 1 — 13. 65. Kruscal J.B., Jr. On the shortest spanning subtree of a graph and the travelling salesman prob- lem//Proc. Amer. Math. Soc. — 1956. — Vol. 7. — P. 48—50. 66. Lavallee I., Roucairol G. A fully distributed (minimal) spanning tree algorithm//Inf. Process. Letters. — 1986. — Vol. 23, N 2. — P. 55—62. 67. Lawler E.L. A procedure for the computing the к best solutions to discrete optimization problems and its application to the shortest path problem//Manag. Sci. — 1972. — Vol. 18. — P. 401 — 405. 68. Lee D.T., Schachter B.J. Two algorithms for constructing Delaunay triangulations//Int. J. Comput. and Inform. Sci. — 1980. — Vol. 9, N3. — P. 219—242. 69. Loberman HM Weinberger A. Formal procedures for connecting terminals with a minimum total wire length//!. ACM. — 1957. — Vol. 4. — P. 428. 70. Mayeda W. Graph Theoty. — New York: Wiley-Intersci., 1972. 71. Mayeda W. etal. Generation of complete trees//IEEE Trans. Circuit Theory. — 1968. — Vol. CT-15.—P. 101. 72. Mayeda W., Sehu S. Generation of trees without duplications//IEEE Trans. Circuit Theory. — 1965. — Vol. CT-12. — P. 181 — 185. 73. Mayr E.W., Plaxton C.G. On the spanning trees of weighted graphs//l£Ct. Notes Comp. Sci. — 1989. — Vol. 344. — P. 394—405. 74. Melzak Z.A. On the problem of Steiner//Canad. Math. Bull. — 1961. — Vol. 4. — P. 335. 75. Minty W. A simple algorithm for listing all the ti 3esof agraph//IEEETrans. Circuit Theory. — 1965. — Vol. CT-12, N 1. — P. 120. 76. Nevelainen O., Ernvall J., Katajainen J. Finding minimal spanning trees in a euclidean space//BIT. — 1981. — Vol. 21., N 1. 77. Obrica A. Algorithm 1 — mintree//Computer Bull. — 1964. — P. 67. 78. Paul A.J., Jr. Generation of directed trees and 2-trees without duplication//IEEE Trans. Circuit Theory. — 1967. — Vol. CT-14. — P. 354. 79. Piekarski M. Listing of all possible trees of linear graph//IEEE Trans. Circuit Theory. — 1965. — Vol. CT-12, N 1. — P. 124— 125. 80. Prim R.C. Shortest connection networksand some generalizations//Bell System Tech. J. — 1957. — Vol. 36. — P. 1389—1401. 81. Read R.C., Tarjan R.E. Bounds on backtrack algorithms for listing cycles, paths and spanning trees//Networks. — 1975. — Vol. 5. — P. 237—252. 82. Scott A. Combinatorial programming, spatial analysis and planning. — London: Methuem, 1971. 83. Semenov A.L., Mel’nikov L.S., Evstigneev V. A. Solving the problems of kinetics of reactions by symbolic algebraic manipulation methods//!. Symbolic Computation. — 1987. — N 3. — P. 303—307. 84. Shamos M.L, Hoey D. Closest point problem//16th Ann. IEEE Symp. on Foundations of Comput Sci.,1975. — P. 173—186.
Список литературы 143 85. Shank Н. Note on Hamilton circuits in tree graphs//IEEE Trans. Circuit Theory. — 1968. — Vol. CT-15. — P.86. 86. ShinodaS., Kawamoto T. On central trees of a graph//Leet. Notes Comp. Sci. — 1981. — Vol. 108.— P. 137—151. 87. Smith J.M., Lee D.T., Liebman J.S. An O(AflogAO heuristic for Steiner minimal tree problems on the Euclidean metric//Networks. — 1981. — Vol. 11, N 1. — P. 23—29. 88. Spira P.M., Pan A. On finding and updating spanning trees and shortest paths//SIAM J. Comput. — 1975. — Vol. 4, N 3. — P. 375—380. 89. Tarjan R.E. Finding optimum branchings//Networks. — 1977. — Vol. 7. — P. 25—35. 90. Tarjan R.E. Applications of path compression on balanced trees//J. ACM. — 1979. — Vol. 26. — P. 690—715. 91. Tarjan R.E. Sensitivity analysis of minimal spanning trees and shortest path trees//Inf. Proc. Lett. — 1982. — Vol. 14, N 1. — P. 30—33. 92. Tarjan R.E. Data structures and networks algorithms// Soc. for Industr. and Appl. Math. — 1983. 93. Terno J. Complexity des Minimalgerustes//24 Intern. Wiss. Koll./ TH Ilmenau, 22.10 — 26.10.1979. — 1979. — Bd 2,3, Heft 5. — P. 23—25. 94. Trent H.M. A note on the enumeration and listing of all possible trees in a connected linear graph//Proc. Nat. Acad. Sci. U.S.A. — 1954. —Vol. 40. — P. 1004. 95. Wang K.T. On a new method for the analysis of electrical networks//Not. Res. Inst. Eng. Acad. Sinica. — 1934. — M. 2. — P. 1 — 11. 96. Winter P. An algorithm for the enumeration of spanning trees//BIT. — 1986. — Vol. 26, N 1. — P. 44—62. 97. Yao A.C. An OCEloglogV) algorithm for finding minimum spanning trees//Inf. Proc. Lett. — 1975. —Vol. 4. — P. 21— 23. 98. Yao A.C. On constructing minimal spanning trees in Л-dimensional space and related problems//SIAM J. Comput. — 1982. — Vol. 11, N 4. — P. 721—736.
ЧАСТЬ II ТРАНСЛЯЦИЯ И ПРЕОБРАЗОВАНИЕ ПРОГРАММ Глава 4 СТРУКТУРНЫЕ ДЕРЕВЬЯ 4.1. Введение и основные определения 4.1.1. Вводные замечания. Задачи анализа структур программ возни- кают во многих системах автоматизации программирования, например в оптимизирующих трансляторах. В этих задачах программа рассматрива- ется и обрабатывается как ориентированный граф специального вида — так называемый управляющий граф (уграф), вершинами которого явля- ются операторы программы, а дуги, соединяющие вершины, отражают возможность передачи управления между операторами программы при ее выполнении. Таким образом, уграф кодирует поток управления в программе и каждому ее выполнению соответствует некоторый путь по уграфу от его начальной вершины (начального оператора). В языках программирования обычно имеется некоторая иерархия операторных конструкций. Например, допускается, как правило, объединение операторов в операторные конструкции более сложного вида: составной оператор, операторы выбора и цикла. Обобщением соот- ветствующих понятий являются специального вида фрагменты уграфа: луч, альт и зона. Важной задачей анализа потока управления в программе является задача регуляризации ее логической структуры — представление уграфа в виде иерархии вложенных фрагментов определенного вида: интерва- лов, зон, альтов и гамаков. К основным задачам анализа структур прог- рамм относятся также задачи построения специальных нумераций угра- фа (так называемых аранжировок и разумных нумераций), задающих порядки обходов операторов программы, определенным образом соответ- ствующие порядкам их прохождения в выполнениях программы, и за- дачи выявления отношений обязательного предшествования и обяза- тельной преемственности между операторами программы. 4.1.2. Управляющий граф (уграф). Фрагменты и подфрагменты. Управляющим графом (уграфом) G - (X, U, pQf qQ) называется ориенти- рованный граф (X, U) с двумя выделенными вершинами: начальной р0 и конечной qQi любая вершина которого принадлежи^ хотя бы одному пути по G от начальной вершины до конечной (рис. 4.1). Любой связный уграф С, являющийся частью уграфа G, называется его фрагментом. Фрагмент С является подфрагментом фрагмента 5, если С — часть 5. Подфрагмент С фрагмента S, отличный от S, называется собственным подфрагментом.
4.1.3. Лучи, зоны и одновходовые у графы 145 Рис. 4.1 Вершина р фрагмента С называется начальной (соответственно вы- ходной) , если либо р » pQ (соответственно р e qQ), либо в р заходит (соот- ветственно из р исходит) дуга уграфа G, не принадлежащая С. Вершина р из С называется входной (или просто входом), если существует путь по G от р0 до р, не содержащий дуг фрагмента С. Вершина р называется конечной для фрагмента С, если р не принадлежит С и является пре- емником хотя бы одной вершины фрагмента С. Например, для фрагмента графа G (см. рис. 4.1), порожденного вершинами {2, 3, 4}, вершина 2 и 4 — начальные, 2 — входная вершина, 4 — выходная, а 5 и 6 — конечные. Свойство. Любой вход фрагмента является его начальной вер- шиной, а для бикомпонент верно и обратное. Вершина р, отличная от р0 и q^, называется граничной вершиной фрагмента С, если р является начальной или выходной вершиной С. Граничная вершина р фрагмента С называется стартовой, если ЗА- ХОД (р) не содержит дуг из С или ИСХОД (р) состоит только из дуг фрагмента С, и финишной, если ЗАХОД (р) состоит только из дуг фраг- мента С или ИСХОД (р) не содержит дуг из С. Например, для подграфа {5, 6. 8, 9, 10, 14, 15} уграфа G, изображен- ного на рис. 4.2, вершины 5 и 6 являются стартовыми, вершины 14 и 15 — финишными, а 8 — такой граничной вершиной, которая не стартовая и не финишная. 4.1.3. Лучи, зоны и одновходовые у графы. Простой путь Р®(р1, ... ..., pr), г > 1, по уграфу G называется линейным участком (лучом), если ПРЕЕМ (р.) s 1 для любого / Е (1:г) иПРЕД(р;) = 1 для любого/G (1:г ]. Например, в графе G (см. рис. 4.1) лучами являются: (1), (2), (3), (4), (5), (6), (7), (8), (2, 3).
146 4.1.4. Альты, интервалы, гамаки и линейные компоненты Нетривиальный сильно связный подграф угпафа называется сильно связной областью (зоной). Зона называется многовходовой, если она имеет не менее двух входов. Уграф называется одновходовым, если он не содержит многовходо- вых зон. Например, уграф G (см. рис. 4.1) содержит три зоны {7}, {2, 3}, {4,5}, каждая из которых имеет по одному входу. Справедливы следующие свойства. А. Максимальные многовходовые зоны попарно не пересекаются. Б. Вершина р является начальной вершиной максимальной много- входовой зоны тогда и только тогда, когда р является ее входом. 4.1.4. Альты, интервалы, гамаки и линейные компоненты. Альт — это подграф с единственной начальной вершиной. Интервал — это такой альт, начальная вершина которого принад- лежит каждому его контуру. Гамак — это такой альт, множество конечных вершин которого либо пусто, либо состоит из одной вершины, являющейся преемником каждой выходной вершины альта й не являющейся предшественником его на- чальной вершины. Линейной компонентой уграфа G называется гамак С, удовлетворя- ющий следующим свойствам: начальная и конечная (если она есть) вершины С принадлежат каждому пути по G от р0 до qQ; из конечной
4.1.5. Правильные, простые и первичные фрагменты 147 вершины гамака С не достижима в G начальная вершина гамака С; С не содержит собственного подграфа, который был бы гамаком и обладал первыми двумя свойствами. Например, в графе G (см. рис. 4.1) подграфы [1:7], [1:8], [2:6], {2,3}, [4:6 ], {5}, {4}, {8} - гамаки, {1}, {2}, {3}, {4}, {5}, {7}, {8}, {2, 3}, {4, 6}, [4:6 ] — интервалы, а [1:7 ], {8} — линейные компоненты. А. Множество всех максимальных интервалов уграфа задает разби- ение множества его вершин. Б. Если С — гамак, aS — зона, то либо S С С, либо S = С, либо С U U {<?} С S, где q — конечная вершина гамака С. В. Вершина р является начальной вершиной некоторого макси- мального интервала уграфа G тогда и только тогда, когда либо р = р0, либо р является конечной вершиной хотя бы одного максимального интервала уграфа G. Г. Подграф С уграфа G является интервалом с начальной вершиной р тогда и только тогда, когда существует такой обход F подграфа С, начинающийся ср, что для любого i G (1:г], гдег- ICI, ПРЕД(В(О) £ £F[1:H]. Д. Пусть N — обратная нумерация уграфа G. Тогда для любой вершины рЕХи любого гамака Н либо (р) С Н, либо Н П N{p) ~ = 0, либо Н U {<?} С N{p), где q — конечная вершина Н. Е. Множество всех линейных компонент уграфа задает разбиение множества его вершин. 4.1.5. Правильные, простые и первичные фрагменты. Фрагмент на- зывается правильным, если он имеет в точности две граничные вершины, одна из которых — стартовая, а вторая — финишная. Правильный фраг- мент называется простым, если он содержит одну дугу. Правильный фрагмент, не являющийся простым, называется первич- ным, если все его собственные правильные подфрагменты являются про- стыми. Пример. Рассмотрим фрагменты Sp S2, S3 и SA уграфа G, изобра- женные на рис. 4.3. Фрагмент Sx не является правильным, S3 — простой правильный фрагмент, a S2 и S4 — первичные фрагменты. Объединение S3 и S4 — правильный фрагмент, который не является ни простым, ни первичным. 4.1.6. Стягивание альтов уграфа и вершины. Фактор-уграфы. Пусть R — некоторое множество попарно непересекающихся альтов уграфа G= (X, £/), образующих разбиение {Хр Х2,..., Хг} некоторого подмноже- ства Y С X, и пусть Х^ = X- Y. Говорят, что уграф Gl = (X1, U*, р\, q^), в котором X1 = {Xj, Х2,..., Xr} U U ХгН, получается стягиванием альтов R в вершины (обозначение G1 = R(G)), если начальной (соответственно конечной) вершиной уграфа G1 является либо начальная вершина р0 (соответственно конечная вершина ?0) уграфа G, либо альт из R, содержащий р0 (соответственно q0), а для любых А и В из X1 пара (А, В) принадлежит множеству U' тогда и только тогда, когда справедливо одно из следующих свойств: А, В G Х^ и (А, В) G G А 6 X^j, В G R и А соединена дугой в G с некоторой вершиной из В; A G В, В G Х^( и некоторая вершина из А соединена дугой с вершиной В;
148 4.1.7. Отношения обязательного предшествования и обязательной преемственности л, В е R и некоторая вершина из А соединена в G с некоторой вершиной из В дугой, не принадлежащей ни Л, ни В. G1 называется фактор-угра- фом уграфа G относительно R. Ро Пример. Рассмотрим уграф G, изображенный на рис. 4.1, и пусть jRs {{2, 3}, {4,5}}. Уграф jR(G), в котором вершина 1 — начальная, а 8 — конечная, имеет вид, изображенный на рис. 4.4. Здесь и ниже в качестве обозначений вершин уграфа jR(G), соответствующих альтам исходной схемы G, используются обозначения начальных вершин этих альтов. А. Фактор-уграф любого уграфа G относительно множества всех нетривиальных линейных компонент G является линейным. Б. Если уграф G является одновходовым, то для любого множест- ва R попарно непересекающихся альтов уграф R(G) также будет одно- входовым. 4.1.7. Отношения обязательного предшествования и обязательной преемственности. Вершина р обязательно предшествует вершине q в у графе G = (X, U, р0, ?0), если р принадлежит каждому пути по G от р0 до q. Она обязательно следует за вершиной q, если р принадлежит каждому пути по G от q до qQ.
4.1.8. F-лучи, F-области и правильная нумерация 149 А. Отношение обязательного предшествования (обязательной преемственности) задает линейный порядок на множестве всех обяза- тельных предшественников (преемников) любой вершины. Б. Вершина р является единственной входной вершиной фрагмента С уграфа G тогда и только тогда, когда р принадлежит С и обязатель- но предшествует в G любой вершине из С. В. Пусть G — аранжируемый у граф uF— некоторая его аранжиров- ка (см. п. 4.1.10). Вершина р обязательно предшествует вершине qeG тогда и только тогда, когда р принадлежит каждому простому F-nymu от pQ до q. Ближайший <в смысле свойства А) к данной вершине р обязательный ее предшественник (преемник), отличный от р, называется непосредст- венным обязательным предшественником (преемником) вершины р. На рис. 4.5 изображены деревья и Z>2, кодирующие отношения непосредственного обязательного предшествования и непосредственной обязательной преемственности для вершин уграфа G, приведенного на рис. 4.1. 4.1.8. F-лучи, /’-области и правильная нумерация. Луч (р{, ..., р), г > 1, уграфа G называется F-лучом, где F — нумерация G, если для любого i G [ 1 :г) справедливо F(p.) = F(pi+i) - 1. Нумерация /’называется правильной нумерацией уграфа G, если лю- бой луч уграфа является F-лучом. А. Прямая и обратная нумерации уграфа являются правильными. Для нумерации F уграфа G и его вершины р подграф уграфа G, мно- жеством вершин которого являются все те вершины, из которых дос- тижима р в подграфе F[i: 1X1 ], называется F-областью и обозначается через F{p) или где i = F(p).
150 4Л .9. Алгоритм выделения Г-области Рис. 4.5 Пусть N и М — пара связанных базисных нумераций уграфа G. Тогда: Б. Для любой вершины р уграфа G и любой вершины q G N{p) следу- ющие свойства эквивалентны: q — начальная вершина 7У(р); q — входная вершина N{p); в q заходит N-прямая дуга из вершины, N-номер которой меньше N(р). В. Для любой вершины р уграфа G подграф N(p) является сильно связным, ар — его начальная вершина. Г. Для любой вершины р уграфа G каждая вершина q G N{p) являет- ся М-достижимой из р и М(р) - min{M(<?): q €= N{p)}. Д. Для любых двух различных вершин р и q уграфа G либо подграфы N{p) и N{q) не пересекаются, либо один из них является собствен- ным подграфом другого. Е. Подграф S уграфа G является бикомпонентой moedaji только тогда, когда существует такая вершина р, 4moS- N(p) и р G N(q) для всех q, где N(q) < N(p). Пример. Рассмотрим уграф G, изображенный на рис. 4.1. Если F — такая нумерация G, что F(i) « i для любого i G [1:8], то F(2) « {2, 3], F(4)»{4,6},F(6)»{6}. 4.1.9. Алгоритм выделения F-области. Задача Объекты. Уграф G, каждая вершина которого может находиться в одном из двух состояний: ’’помечена”, ’’непомечена”. Дано. Вершина р и некоторая нумерация F уграфа G, все вершины которого помечены. Т ребуется. Выделить F{p), сохраняя состояния вершин уграфа G.
4.1.10. Аранжировка 151 Решение Программа функ ОБЛАСТЬ (F: нумерация; р: вершина) » 1. А: список = {р}; В: список s {р}; 2. пока А цикл 3. q := ЭА; 4. для всех г из ПРЕД (q) цикл 5. еслиСР(г) >Г(р)) л (г непомечена) то 6. А <- г; В г; пометить г; все все все; 7. для всех q из В цикл 8. А <- q\ убрать пометку с q все; 9. возврат А все Свойство. Временная сложность процедуры ОБЛАСТЬ составля- ет О (Z + к), где I обозначает число вершин в Г(р), а Л — число дуг графа G, заходящих в вершины из 4.1.10. Аранжировка. Нумерация F альта С, при которой каждый простой путь по С от его начальной вершины является F-путем, называ- ется аранжировкой. клът называется аранжируемым, если существует его аранжировка, и неаранжируемым в противном случае. На рис. 4.6 приведены примеры аранжируемого и неаранжируемого альтов Cj и С2, в которых начальной является вершина 1. Рис. 4.6
152 4.1.12. Факторизация А. Любой интервал аранжируем. Б. Дуга (p,q) является F-обратной для аранжировки F уграфа G тогда и только тогда, когда вершина q обязательно предшествует вершине р. В. Если существует некоторое множество R попарно непересека- ющихся и аранжируемых альтов уграфа G таких, что уграф R(G) аранжируемый, то уграф G является аранжируемым. Г. Уграф G является аранжируемым тогда и только тогда, когда G — одновходовый уграф. 4.1.11. Дуги вперед и назад. Глубина нумерации и аранжируемого графа. Разумные нумерации. Дуга аранжируемого уграфа G называется дугой назад, если она является F-обратной дугой для любой аранжировки F уграфа G, и дугой вперед, если она является F-прямой для любой аранжировки F уграфа G. А. Каждая дуга аранжируемого уграфа G является либо дугой вперед, либо дугой назад. Глубиной, или числом несоответствия нумерации F уграфа G, назы- вается наибольшее число F-обратных дуг, принадлежащих простому пути по уграфу G. Глубиной аранжируемого уграфа G (обозначение d{G)) называется глубина его любой аранжировки (см. свойство 4.1.10.Б). Например, глубина где С, — уграф с рис. 4.6, равна трем, поскольку простой путь (6, 5, 7, 2, 3) содержит все три дуги назад (6, 5), (7, 2) и (2, 3) уграфа Нумерация F уграфа G называется разумной, если справедливы сле- дующие два свойства: F(p) < F(q) для любых двух таких различных вер- шин р и q, что р обязательно предшествует q\ если G — аранжируемый уграф, то F является аранжировкой. Б. Обратная нумерация уграфа является его разумной нумерацией. 4.1.12. Факторизация. Факторизация — это прием реализации ал- горитма обработки программы серией применений алгоритмов, базиру- ющихся на представлении обрабатываемой программы в виде иерархии вложенных фрагментов определенного вида. Каждое такое применение осуществляет независимую обработку одного фрагмента иерархии, при которой фрагменты, непосредственно вложенные в данный, выступают как элементарные операторы. Факторизация позволяет применять более сложные и мощные алгоритмы анализа и преобразования программ, пос- кольку существенно сокращается объем одновременно рассматриваемой информации о программе, а также использовать более эффективные спе- циализированные алгоритмы, ориентированные на определенную струк- туру фрагмента. Например, ни в одном из оптимизирующих трансляторов глобальная оптимизация не применяется без ее факторизации по лучам. Не менее естественной единицей факторизации является альт. Если программа регуляризуема, то подмножество ее альтов образует зонно-интервальное представление программы (см. п. 4.2). Его достоинство — это явное выде- ление циклической структуры программы. Любая программа представи-
4.1.13. Т-нумерация 153 ма в виде иерархии альтов, являющихся гамаками (см. п. 4.3), а также в виде иерархии первичных фрагментов (см. п. 4.5). 4.1.13. Т-нумерация. Пусть заданы уграф G и его обратная нуме- рация М Вершина р называется N-вершиной, если для любого i < N(p) справедливо р G N(i). Т-нумерацией называется такая нумерация вершин уграфа G, что для любой А-вершины р множество Т[Т(р) : Т(р) + \N(p)\ ~ 1 ] совпадает с а для любых двух А-вершин pnq справедливо Т(р) < T(q) тогда и только тогда, когда Af(p) < N(q). А-вершина р называется точкой сочленения уграфа (7, если не суще- ствует такой дуги (q{, q2), что T{q{) < Т(р) < T(q2). На рис. 4.7 приведен пример графа и его Л/-, N- и Т-нумераций. Здесь Л/-номера идентифицируют вершины, a N- и Т-номера указаны в скоб- ках рядом с соответствующими вершинами. Свойство. Подграф Н является линейной компонентой с на- чальной вершиной р и конечной q тогда и только тогда, когда для некоторой нумерации Т вершины р и q являются точками сочленения такими, чтоН = Т[Т(р) : T(q) - 1 ] и среди вершин из Т[Т(р) + 1 : T(q) - 1 ] нет точек сочленения. 4.1.14. Алгоритм Т-нумерации, выделения бикомпонент и линейных компонент. Задача Дано. Уграф G = (X, U, pQ, qQ) и его обратная нумерация N. Требуется. Построить Т-нумерацию уграфа G, выделить все его бикомпоненты и линейные компоненты. Решение Программа проц ЛИНЕЙНЫЕ-КОМПОНЕНТЫ (G: уграф; N: нумерация) = 1. Г: нумерация = {(p,Q): р G X}; 2. АТ:= 1; 3. для Л от 1 до и цикл
154 4.2.1. Вводные замечания 4. p:=AT!(«; 5. если Т(р) = Q то 6. Пометить р как А-вершину; 7. (Т(р), NT):« (NT, NT + 1); 8. ОБЛАСТЬ (N,k) — бикомпонента; 9. для всех q из ОБЛАСТЬ (N, к) - {р} цикл 10. (T(q), NT) := (NT, NT + 1) все все все; 11. (р, МНП) := (р0, 1); 12. для г от 1 до п - 1 цикл 13. (v, q) :=(Г! (гЬТ’Чг+П); 14. МНП :« шах(МНП, {T(w): w G ПРЕЕМ(р)}); 15. если (МНП « г + 1) л (q помечена) то 16. . Т[Т(р) : г] — линейная компонента с конечной вершиной q и начальной р; 17. Рq все все; 18. {<7о} — линейная компонента с начальной вершиной <у0 и без конечной вершины все Пояснение. Операторы 1 — 10 осуществляют Т-нумерацию уг- рафа G и выделяют его А-вершины и бикомпоненты на основе свойств 4.1.8.В, Г. Переменная NT хранит число Т-занумерованных вершин плюс единица. Выделение линейных компонент осуществляется опера- торами 11 — 18 на основе свойства из п. 4.1.13. Свойство. Временная сложность алгоритма составляет О(ш) вре- мени, где m — число дуг уграфа G. 4.2. Иерархические представления регуляризуемых уграфов 4.2.1. Вводные замечания. Многие задачи создания и обработки про- граммы значительно упрощаются, если программы имеют регулярную структуру, допускают представление в виде иерархий вложенных фраг- ментов специального вида. Например, структурное программирование в качестве базовых рассматривает разные типы композиции операторов, но все они порождают только интервалы. Разрешив брать в качестве базовых любые интервалы, получаем класс программ с регуляризуемы- ми у графами. Важным свойством этого кг^лса является существование алгоритма преобразования любой программы в эквивалентную ей с регу- ляризуемым уграфом. Для решения задач анализа и преобразования программ разработан ряд алгоритмов, эффективно их решающих в том случае, когда уграф программы удовлетворяет определенным свойствам. Оказалось, что эти свойства выделяют один и тот же класс уграфов — класс регуляризуемых уграфов.
4.2.2. Класс регуляризуемых уграфов 155 4.2.2. Класс регуляризуемых уграфов. Уграф G называется регуля- ризуемым (обобщенно-сводимым), если существует последователь- ность уграфов G0 = G, Gn .... Gri называемая последовательностью сведения G, в которой Gr — тривиальный уграф, а каждый следующий член последовательности G- получается из предыдущего Ghi стяги- ванием некоторого непустого множества попарно непересекающихся интервалов в вершины. На рис. 4.8 приведен пример регуляризуемого уграфа G вместе с по- следовательностью его сведения, в которой интервалы, стягиваемые в вершины, выделяются штриховыми линиями. Уграф G, изображенный на рис. 4.9, не является регуляризуемым. 4 Рис. 4.9
156 4.2.3. Интервально-сводимые уграфы А. Уграф является регуляризуемым тогда и только тогда, когда он аранжируемый. Б. Для любой обратной нумерации N уграфа G каждая N-область N{p) имеет единственную начальную вершину тогда и только тогда, когда G — регуляризуемый уграф. 4.2.3. Интервально-сводимые уграфы. Пусть G — некоторый уграф и к > 0. Л-производный уграф Gk от уграфа G (обозначение Gk = Ik(G)) определяется по следующим правилам: Go = G и для любого к > 0 уграф Gk получается из уграфа Gk{ стягиванием его максимальных интервалов в вершины (в силу свойства 4.1.4.А это определение корректно). Предельным уграфом от G называется такой его ^-производный уграф Gk, что = /^,(G). Уграф G называется (интервально) сводимым, если тривиален пре- дельный уграф от уграфа G, и (интервально) несводимым в противном случае. На рис. 4.10 приведен пример сводимого графа G, для которого I3(G) является предельным графом. Уграф G на рис. 4.9 совпадает со своим предельным графом и не является сводимым. Рис. 4.10 А. Уграф G является сводимым тогда и только тогда, когда он регуляризуемый. Б. Если (р, q) является дугой назад в аранжируемом уграфе G, то ершина q является начальной вершиной некоторого максимального интервала уграфа G. Длина последовательности сведения интервально-сводимого уграфа G (обозначается /(G)) — это такое минимальное число г, что Ir(G) явля- ется предельным уграфом от G. В. Для любого аранжируемого уграфа G справедливы неравенства d(Ix(G)) > d(G) -lnd(G) < KG), гдей(С) —это глубина уграфа G (см. п. 4.1.11).
4.2.4. Алгоритм выделения максимальных интервалов 157 4.2.4. Алгоритм выделения максимальных интервалов. Задача Дано. Уграф G » (X, U, р0> qQ). Требуется. Разметить уграф G, сопоставляя каждой вершине р уграфа G ту вершину, которая является начальной у максимального интервала уграфа G, содержащего р. Решение Программа проц МАКСИМАЛЬНЫЕ-ИНТЕРВАЛЫ = 1. КНД: разметка - {(р, ПРЕД(р)): р GX}; 2. НАЧАЛО: разметка я {(р, Q): р * р0} U {(р0, р0)}; 3. НАЧВЕР: список я {р0} ; 4. пока НАЧВЕР # 0 цикл 5. р :я Э НАЧВЕРМ :я {р}; В := 0 ; 6. повторять q :я ЭА; 7. для всех v из ПРЕЕМ (?) цикл 8. КНД(у) :яКНД(у)-1; 9. . если (КНД(у) = 0) А (НАЧАЛО (v) = Q) то 10. НАЧАЛО(у) :яр;А«-р 11. иначе В*-у все все 12. до А =0все; 13. пока В цикл 14. q := ЭВ; 15. если НАЧАЛО (q) = Q то 16. НАЧАЛО(<?) :я q; НАЧВЕР <- q все все все все Пояснения. Разметка КНД задает для каждой вершины р количество еще не обработанных дуг, заходящих в р, а НАЧВЕР состоит из всех тех необработанных начальных вершин q максимальных интер- валов, что либо q = p^ либо обработана хотя бы одна из дуг, заходящих в q. Алгоритм опирается на свойства 4.1.4.В, Г. Работа алгоритма состоит в том, что, начиная с НАЧВЕР я {р0} (оператор 3), он для каждой р G НАЧВЕР выделяет максимальный интервал с начальной вершиной р (операторы 5—11). После выделения интервала множество В содержит некоторые вершины данного интервала и все его конечные вершины. Операторы 13—16 включают в НАЧВЕР все те конечные вершины выде- ленного интервала, которые туда не включались. Свойство. Временная сложность алгоритма составляет О(т), где т — число дуг уграфа G.
158 4.2.5. Иерархия вложенных зон 4.2.5. Иерархия вложенных зон. Множество Л зон уграфа G образует иерархию вложенных зон, если справедливы следующие два свойства: любая пара зон Sj, S2 из А не пересекается либо одна из этих зон целиком содержится в другой; для любой зоны S, уграфа G существует такая зона S2 G А, что Sj С S2 и у зон Sj и S2 есть общая входная вершина. Например, для уграфа G (рис. 4.11) множество {[2:5 ], [3:5 ]} образует иерархию вложенных зон. Свойство. Множество всех нетривиальных графов из Z = {М{рУ- р G X}, где N — обратная нумерация уграфа G = (X, U, pQ, qQ), является иерархией вложенных зон уграфа G. На основе данного свойства построение иерархии вложенных зон уг- рафа G можно осуществить, выполняя следующую функцию: функ ИЕРАРХИЯ-ВЛОЖЕННЫХ-ЗОН (G: уграф) = 1. Z: множество зон = 0 ; 2. Построить обратную нумерацию N уграфа G, выполняя алгоритм 2.2.16; 3. для всех р из множества вершин уграфа G цикл 4. Включить в Z нетривиальную зону N{p), выделенную с помощью алгоритма 4.1.9 все; 5. возврат Z все Временная сложность такого построения не превышает О(тп), где п и т — это количества вершин и дуг уграфа (7. Другой способ построения иерархии вложенных г эн описывается сле- дующей функцией. функ ИЕРАРХИЯ-ВЛОЖЕННЫХ-ЗОН-1 (С: уграф; р: вершина) = 1. Z: множество зон = 0 ; 2. Включить в Z все нетривиальные бикомпоненты графа, полученного из С удалением всех дуг, заходящих в р, выполняя алгоритм 4.1.14; 3. для всех S из Z цикл 4. Пусть q — одна из начальных вершин S; 5. Z <= ИЕРАРХИЯ-ВЛОЖЕННЫХ-ЗОН-1 (S, q) все; 6. возврат Z все
4.2.6. Зонно-интервальное представление 159 Обращение ИЕРАРХИЯ-ВЛОЖЕННЫХ-ЗОН-KG, р0) позволяет осуществлять построение иерархии вложенных зон за время, не превы- шающее О(тп). 4.2.6. Зонно-интервальное представление. Последовательность раз- личных уграфов Go - G, Gp ..., Сказывается зонно-интервальным пред- ставлением уграфа G, если уграф Gr не содержит зон, а для любого z уграф G- получается из Gtl стягиванием в вершины элементов непустого множества попарно непересекающихся интервалов, являющихся зона- ми. Пусть Z обозначает множество всех нетривиальных графов из {N(p): р G X}; в силу свойства 4.1.8.В Z — это множество зон уграфа. Для каждой зоны S G Z ее уровень (обозначение h(S)) определяется по следу- ющим правилам: если множество А = {5\ G Z: S, С 5} пусто, то h(S) = 0; в противном случае (когда множество А непусто) Л(5) = max {6(5,): S G А} + 1. Пусть г — максимальный уровень зон из Z. Для любого i G [0:г ] через Z, обозначается множество всех таких S G Z, что h(S) < i и не существует зон Sj G Z, для которых S С 5, hA(Sj) < z. Свойство. Уграф G является регуляризуемым тогда и только тог- да, когда Go = G, Z0(G), ..., Zbl(G), ..., Z/G) является зонно-интерваль- ным представлением уграфа G. Таким образом, алгоритмы выделения в уграфе G иерархии сложен- ных зон (см. п. 4.2.5) могут использоваться для построения его зонно- интервального представления. 4.2.7. Алгоритм проверки регуляризуемости уграфа. Задача Дано. Уграф Gs (X, G, р0, <у0). Т ребуется. Определить, является ли уграф G регуляризуемым или нет. Решение Программа функ ПРОВЕРКА-РЕГУЛЯРИЗУЕМОСТИ = 1. А: список « 0; В: набор s {({р},р):р G X}; 2. Установить обратную нумерацию А уграфа G, выполнив алгоритм 2.2.16; 3. для к от п до 1 через -1 цикл 4. р := ДГ1 (к); 5. для всех q из ПРЕД (р) цикл 6. и := найти q* 7. если W(u) > А(р) то 8. А «- и; слить и с р все все; 9. пока А #0 цикл 10. q := ЭА; 11. для всех и из ПРЕД (q) цикл
160 4.2.7. Алгоритм проверки регуляризуемости уграфа 12. v:= найти и* 13. если ЛЧу) < 2V(p) то 14. возврат ’уграф нерегуляризуемый’ 15. иначе если N(v) > N(p) то 16. А <- v; слить vcp все все все все все; 17. возврат ’уграф регуляризуемый’ все Пояснение. Алгоритм опирается на свойства 4.2.2.Б,Ги4.1.16.Б, В. Список А используется в теле цикла 3—15 для хранения всех тех необработанных вершин из N{p), отличных от р, предшественники кото- рых нужно просмотреть при выделении N{p) для заданной вершины рв Аг1 (к) уграфа операторами 5—17. При этом для любого к G. [1:п ] перед выполнением оператора 4 некоторая вершина q принадлежит мно- жеству набора В с именем v тогда и только тогда, когда ?/(v) e minfAXw): N(u) > к, q G N{u)}. Свойство. Временная сложность алгоритма составляет О(т • а(т, п)) времени. Замечание. Алгоритм ПРОВЕРКА-РЕГУЛЯРИЗУЕМОСТИ легко модифицировать таким образом, чтобы он, сохраняя временную сложность О(т • а(т, п)), в процессе своей работы строил зонно-интер- вальное представление уграфа G. Каждой вершине р уграфа G следует приписать атрибуты ОБЪЕМ и ГОЛОВА, значения которых определяют- ся по следующим правилам (см. в качестве примера на рис. 4.12 уграф G, для которого N(p) *= р для любой вершины р; здесь истинные значения атрибута ГОЛОВА только у двух вершин: 2 и 3, а значение атрибута ОБЪЕМ указано штриховой стрелкой): р.ГОЛОВА хранит значение логического выражения N{p) G Z, а р.ОБЪЕМ « q тогда и только тогда, когда N(q) = max(l, {NM: N(v) < N(p) нрЕ A^v)}), т.е. q — начальная вершина минимальной зоны N{q)> содержащей вершину р, либо q = p^ если таких зон нет. Операторы вычисления атрибута ГОЛОВА помеща- ются в цикл 5—8, а атрибута ОБЪЕМ — в цикл 9—16 и за цикл 3—16.
4.2.8. Разборность уграфа. Запрещенный подграф и каркас уграфа 161 4.2.8. Разборность уграфа. Запрещенный подграф и каркас уграфа. Разборность уграфа G определяется как возможность получения из него тривиального уграфа с помощью следующих преобразований: Т1 — уда- ление петли и 72 — слияние двух вершин. Преобразование Т1 определе- но для любой вершины р уграфа и состоит в удалении дуги (р, р) из уграфа. Преобразование Т2 определено только для такой пары вершин р и q, что вершина q имеет единственным предшественником вершину р; результатом применения Т2 является удаление вершины q и дуги (р, q), добавление множества ПРЕЕМ (q) в множество ПРЕЕМ (р) и объявление р конечной вершиной, если q~ Р^> На рис. 4.13 приведен пример разборного уграфа G; в последователь- ности Gj e G, G2, G3, G4, G5, G6 каждый следующий уграф (за исклю- чением G4) получается из предыдущего применением 72; уграф G3 пре- образуется в G4 применением 71. Рис. 4.13 Говорят, что уграф G содержит запрещенный подграф (рис. 4.14), если в G существуют такие различные вершины рр р2 и р3, что найдутся попарно непересекающиеся по внутренним вершинам простые пути Р01. Р. 2, Р. 3, Р2 3, Р3 2, где Ри обозначает путь от вершины pi до вершины р, /, /ё [0:3]. ’ ’ 6 ВА Евстигнеев, В.Н. Касьянов
162 4.2.9. Преобразование нерегуляризуемых у графов Каркасом уграфа G называется такой ациклический уграф К, что К — остов уграфа G и добавление в К еще одной любой дуги из G нарушает ацикличность К. На рис.4.15 изображен уграф G и два его каркаса — К{ и К2. А. Уграф разборен тогда и только тогда, когда он регуляризуем. Б. Уграф содержит запрещенный подграф тогда и только тогда, когда он не является регуляризуемым. В. Для любого простого пути PnoGom pQ существует такой каркас К уграфа G, что Р является путем по К. Г. Каркас любого аранжируемого уграфа G может быть получен из G удалением всех дуг назад. Д. Уграф G является регуляризуемым тогда и только тогда, когда имеет единственный каркас. Е. Уграф G является регуляризуемым тогда и только тогда, когда существует такое разбиение множества его дуг U на два подмножест- ва и U2, что U{ образует каркас уграфа, а для любой дуги (р, q) G U2 вершина q обязательно предшествует вершине р eG. 4.2.9. Преобразование нерегуляризуемых уграфов. Если исходный уграф G нерегуляризуемый, его можно преобразовать за счет дублиро- вания (копирования) некоторых вершин в такой регуляризуемый уграф (7И что G и эквивалентны, т.е. являются уграфами эквивалентных программ. Такое эквивалентное дублирование позволяет осуществлять регуляризацию программы без увеличения времени счета по программе и без привлечения другой информации о программе, кроме ее уграфа. Примером эквивалентного дублирования является преобразование ТЗ, называемое расщеплением вершин. Применение ТЗ возможно к лю- бой такой вершине р уграфа G, что р * pQ и G не имеет петли (р, р); в результате применения ТЗ к вершине р вершина р заменяется на г экзем- пляров, где г = I ЗАХОД (р) I, по одному экземпляру для каждой заходя- щей в р дуги (см. рис. 4.16, где приведен пример регуляризуемого уграфа G2, полученного из нерегуляризуемого Gt расщеплением вершины 2). А. Любой уграф с помощью преобразований Т\, Т2 и ТЗ сводится к тривиальному. Б. Существует алгоритм, который по любому уграфу G за счет эквивалентного дублирования строит регуляризуемый уграф, име- ющий не более 2"~2 + 1 вершину, где п — число вершин G.
4.2.10. Характеристики уграфов реальных программ 163 Рис. 4.16 В. Существует такой уграф G, что любой регуляризуемый уграф, полученный из G за счет эквивалентного дублирования его вершин, содержит не менее чем 2п~2 + 1 вершину. Для любой вершины р уграфа G обозначим через т(р) количество различных многовходовых зон уграфа G, содержащих р, а через к(р) — минимальное число такое, что имеется множество, состоящее из к(р) вершин и включающее хотя бы по одной вершине каждой из тех много- входовых зон уграфа G, которые целиком лежат в максимальной много- входовой зоне, содержащей вершину р. Г. Существует алгоритм, который эквивалентными дублировани- ями преобразует любой уграф G в такой регуляризуемый уграф, в кото- ром имеется не более чем 2®,n(w<p>’ kw экземпляров любой вершины р уграфа G. 4.2.10. Характеристики уграфов реальных программ. Большинство современных языков высокого уровня являются языками структурного программирования и, таким образом, ориентированными на написание регуляризуемых программ. Что касается других языков, основным из которых является Фортран, то исследования характеристик реальных Фортран-программ показывают, что 90% уграфов регуляризуемы, при- чем в среднем 1(G) ~ 2,75, а зоны занимают небольшую часть программы (около 4%). Отсюда в силу свойства 4.2.9.Г можно сделать вывод о том, что в реальных случаях даже для языков ’’неструктурного’’ программи- рования, как правило, уграф регуляризуем, а если нет, то его преобразо- вание для получения регуляризуемости не потребует даже двукратного увеличения его размера при сохранении времени счета по программе. 4.3. Гамачное представление уграфов 4.3.1. Иерархия вложенных альтов. Любая программа представима в виде иерархии альтов, являющихся простыми и составными гамаками (см. ниже). Помимо универсальной применимости, такое гамачное пред- ставление программы обладает следующими важными чертами: оно од- нозначно, не требует изменения алгоритма обработки программ при его факторизации, а также выделяет фрагменты, способные к перемещению в программе.
164 4.3.1. Иерархия вложенных альтов Пусть А — некоторое множество альтов уграфа G, содержащее альты и Я2. Альт непосредственно вложен в Н2 относительно А, если Я, С Н2 и в А не существует альта Я3 такого, что Я1 С Я3 С Я2. Альт Я1 называется внутренним альтом относительно А, если в А не существует альтов, непосредственно вложенных в Яр и внешним альтом относи- тельно А, если в А не существует альта, в который Я1 непосредственно вложен. Множество нетривиальных альтов А называется иерархией вложен- ных альтов уграфа G, если G G А и для любых двух альтов из А либо их пересечение пусто, либо один из них целиком содержится в другом. Последовательность уграфов Go, б\,..., <7,называется представлением уграфа G в виде иерархии вложенных альтов А (A-представлением угра- фа G), если Go = G, Gr — тривиальный уграф и для любого i G [1:г ] вы- полняется G, = Д(С7), где Bt — множество всех внешних альтов отно- сительно U {А : j G [1:/]}; А; — множество всех внутренних альтов отно- сительно А - U{A;: j G [1:0}. Пример. Пусть G обозначает уграф, представленный на рис. 4.17 и пусть А ={[1:4], {2,4}, [5:12], [13:15], [7:9], {6,12}, {10}, {11}, [1:16], [7:11 ]}. Тогда Aj = {{2,4}, {6,12}, [7:9], [13:15], {10}, {11}}, А2 = {[1:4], [7:11]}, А3 = {[5:12]}, А4= {[1:16]}, В. =АР В2 = А2 U {{6,12}, [13:15]}, B3 = A3U {[1:4], [13:15]}, В4 = А4. Множество всех гамаков уграфа может содержать пересекающиеся гамаки, каждый из которых не является подграфом другого (например, во всех линейных уграфах с числом вершин больше двух). Гамак уграфа называется разложимым, если его можно представить как объединение двух непересекающихся гамаков, и неразложимым (или простым) в противном случае. Максимальный разложимый гамак называется сос- тавным. Например, уграф G (см. рис. 4.17) содержит 11 простых гамаков: [1:4], {2,4}, {3}, [5:12], [13:15], [7:9], {6,12}, {8}, {10}, {11}, {16} идва составных: [1:16], [7:11]. Пусть Гс обозначает множество всех нетривиальных простых и сос- тавных гамаков. A. G G TG и если два гамака из TG пересекаются, то один из них целиком содержится в другом.
4.3.1. Иерархия вложенных альтов 165 Б. Подграф Н2 является нетривиальной линейной компонентой со- ставного гамака тогда и только тогда, когда Н2 — гамак, непосред- ственно вложенный в относительно Гс. В. Не существует таких двух составных гамаков, один из которых непосредственно вложен в другой относительно TG. Г. Подграф Н является нетривиальным гамаком уграфа G тогда и только тогда, когда либо Н Е Гс, либо Н образован вершинами такой непустой последовательности линейных компонент Н{, ..., Нг неко- торого составного гамака, что для любого i G (1 :г] начальная вершина Hi является конечной вершиной Hhv Гамачным представлением уграфа G называется его ^-представле- ние. Например, на рис. 4.18 приведены уграфы Gp G2, G3, G4 гамачного представления уграфа G (см. рис. 4.17). Пусть А — некоторая иерархия вложенных альтов уграфа G. Спе- циальная реализация Л-представления уграфа G в виде одного графа GA = = (У, Z), называемого А-графом, кодирует всю последовательность Go, Gt,..., Gt. Множество вершин У — объединение множеств вершин Хо, Х{,... ..., Хг всех уграфов Go, Gp ..., Gr, а множество дуг Z распадается на подмножества Z', Z" и Z'" внутренних, внешних и фиктивных дуг соот- ветственно и строится по следующим трем правилам: (q, р) Z’, если для некоторого i Е (0:г) дуга (q, р) принадлежит альту уграфа Ghl, стягиваемому в вершину при переходе к уграфу Gf; (q, р) G. Z", если для некоторого i Е (0:г] в графе Gl{ имеется дуга, соединяющая вершину q с начальной вершиной альта, который при пере- ходе от Gi{ к G- стягивается в вершину р; (q, р) G. Z"', если для некоторого i G (0:г] альт с начальной верши- ной р уграфа Grl стягивается в вершину q уграфа G,. Пример. Гамачное представление уграфа G (см. рис. 4.17) будет реализовывать Л-граф, представленный на рис. 4.19. Здесь фиктивные дуги графа изображены штриховыми линиями и используются следу-
166 4.3.2. Нумерации К и L ющие обозначения вершин: 1—16 — вершины уграфа G; 17, 18, 20—22 и 24 — вершины уграфа G,, соответствующие альтам {2, 4}, {6, 12}, [7:9 ], {10}, {11} и [13:15]; 25 и 19 — вершины уграфа G2, соответствующие альтам [1:4 ] и [7:10]; 23 — вершина уграфа G3, соответствующая альту [5:12 ], а 26 — вершина уграфа G4, соответствующая альту [1:16 ]. Рис. 4.19 4.3.2. Нумерации К и L. Нумерация К уграфа G, в котором п = 1X1, определяется как последний член Кп последовательности нумераций , К2, в которой — обратная нумерация уграфа G и для любых i G [1 :п) и р, q G X справедливы следующие два свойства: если р G KtД1: i - 1 ], то Х/+1(р) = Х-(р); если р, qE КДг:п], то Х1+1(р) < K^(q) тогда и только тогда, когда либо р G X/i), либо Kt(p) < X^q) и {р, </} С С или {р, q} A в 0. Пример. Рассмотрим уграф G, представленный на рис.4.20, а, име- нами вершин которого являются их Л?-номера, а нумерация К задается расположением вершин. Нумерация К для G показана на рис.4.20, б. Здесь X, = К2 = ЛГ, К3 = К4 = Х5 = К6 = Х7 = К. Пусть F — некоторая нумерация уграфа G и iJE [1:п]. F-линией в [/:/] называется множество всех тех вершин подграфа F[i:j], из которых
4.3.3. Алгоритм A-нумерации 167 в нем F-достижимы выходные вершины. F-ранг вершины q в [/:;] равен max(z, {F(p): р G Л}), где А — множество всех тех вершин F-линий в [z:j], из которых F-достижима вершина q. Пример. Для уграфа G (см. рис. 4.20, б) К-линией в [2:6 ] является множество вершин {2, 4, 5}, /f-ранг вершин 2—6 в [2:6 ] равен 2, 2, 4, 5, 5 соответственно. Нумерация L уграфа G определяется как последний член Lo последо- вательности Ln, Ln_^ .... Lq, в которой Ln = К и для_любых i G [1:и ] и р, q G X справедливы следующие два свойства: если р G L, [г: i + I L-(z) I - 1 ], то Lbl (р) = L/p); если q.pt [z: i + I Li (z) I - 1 ], то (р) < Lhl (q) тогда и только тогда, когда либо р и q имеют один и тот же L-ранг в [z: i + I L/z) I - 1 ] и L-(p) < Lt(q), либо L-ранг вершины q превышает L.-ранг вершины р в [z: i + I L/z)! - 1 ]. Пример. Для уграфа G и его некоторой нумерации К (см. рис. 4.20, б) L-нумерация представлена на рис. 4.20, в. Здесь L7 = L6 = L5 = L4 = L3 = L, = X, L( =£>□ = £, причемL,[2: 2 + IZ^<2>I - 1]= [2:6]. 4.3.3. Алгоритм /f-нумерации. Задача Дано. Уграф (7= (X, U, р0, qQ), состоящий из п вершин и т дуг. Требуется. Построить нумерацию К.
168 4.3.4. Алгоритм L-нумерации Решение Программа проц ПЕРЕНУМЕРАЦИЯ-1 (i: цел; F, Н: нумерация) = 1. А:- ОБЛАСТЬ (Г, к := г, I := i + IAI; 2. для г от i до п цикл 3. q Г-1 (г); 4. если q G А то (H(q), к) := (к, к + 1) 5. иначе (Ж0, /):=(/,/ + 1) все все; 6. (Л Н) := (Н, F) все; функ А-НУМЕРАЦИЯ (G: уграф) - 1. F, Н: нумерация; 2. Вычислить в Fобратную нумерацию уграфа G, выполняя алгоритм 2.2.16; 3. для i от 1 до п цикл ПЕРЕНУМЕРАЦИЯ-1 (л, F, Н) все; 4. возврат F все Свойство. Временная сложность алгоритма составляет О (пт) времени. 4.3.4. Алгоритм /.-нумерации Задача Дано. Уграф G (X, U, р0, q0), состоящий из п вершин и т дуг. Т ребуется. Построить нумерацию L. Решение Программа функ РАНГ (г, /: цел; F: нумерация) = 1. ЛИНИЯ = {р €= х: р — выход /’[к/]}; _ 2. R: разметка - {(р, /): р G F[i:j]} U {(р, Q): р G F[i:j]}; 3. для г от j до i через -1 цикл 4. p:=F~l(r); 5. если р е ЛИНИЯ то 6. для всех q из ПРЕД(р) цикл 7. если F(q) G [z:r] то ЛИНИЯ «- q все все все все; 8. для г от i до j цикл 9. р := F~l (г); 10. если р G ЛИНИЯ то /?(р) := F(p) все; 11. для всех q из ПРЕЕМ (р) цикл
4.3.5. Свойства нумераций Kv\L 169 12. если£(#) е [г7]тоЖ?) :в тах(/?(#), R(p)) все все все; 13; возврат/? все; проц ПЕРЕНУМЕРАЦИЯ-2 (/: цел; F, Я: нумерация) = 1. /:-i + I ОБЛАСТЬ (F,^1 (0)1 - 1; 2. R :-РАНГ(1,Л F); 3. ЧИСЛО = {(Л, 0): к € [г:/ + 1 ]}; 4. для всех р из F[i:j] цикл 5. ЧИСЛО (Я (р) + 1) := ЧИСЛО (Я (р) + 1) + 1 все; 6. для г от i до j цикл 7. ЧИСЛО(г + 1) := ЧИСЛОМ + 1) + ЧИСЛО(г) все; 8. для г от 1 до п цикл 9. р:=/^(г); 10. если г G [Z:/]to 11. (Я(р), ЧИСЛО (Я (р))) := (г + ЧИСЛО (Я (р)), ЧИСЛО (Я (р)) + 1) 12. иначе Я(р) = Ftp) все все; 13. (Я, Я):=(Я, Я все; функ L-НУМЕРАЦИЯ (G: уграф)= 1. F, Я: нумерация; 2. F := /С-НУМЕРАЦИЯ(С); 3. для г от п до 1 через -1 цикл 4. ПЕРЕНУМЕРАЦИЯ-2 (г, Я, Я) все; 5. возврат F все Пояснение. Построение нумерации L осуществляется в соответ- ствии с ее определением (см. п. 4.3.2). Функция РАНГ вычисляет F-ранг вершин в [/:/], используя переменную ЛИНИЯ для хранения F-линии в [/:/]. Процедура ПЕРЕНУМЕРАЦИЯ-2 перевычисляет нумерацию F, осуществляя переход от £. к Lt_v В ней переменная ЧИСЛО имеет следу- ющий смысл: для любого t G [/:;] значением ЧИСЛО(г) в момент перехо- да от оператора 9 к оператору 10 является количество тех вершин р G F[i:j], у которых либо Я(р) < /, либо Я(р) = t и Ftp) < t. Свойство. Временная сложность алгоритма L-нумерации состав- ляет О (пт) единиц времени. 4.3.5. Свойства нумераций К и L. Пусть М и N — пара связанных базисных нумераций уграфа G, на основе которых построены нумерации К2, Кп = К = Ln, Ln_l9 Lo = L.
170 4.3.6. Алгоритм выделения гамаков А. Для любого z G [1:п ] и любой вершины р G X справедливо K/jp) = = W). Б. Для любой дуги (р, q) уграфа G эквивалентны следующие свойст- ва: N(p) < N(q); К^р} < K^q) для любого z G [l:n ]; £,(р) < L.(q) для лю- бого i G [О:лг ]. В. Для любых z G [ 1 :п ] и j G [0:и ] нумерации KuL являются разум- ными. Пусть для любого фрагмента S и любой вершины р уграфа G определены: МНОЖ 1(S, p) = {vG ПРЕЕМ (iv): w G 5 и M(v) < М(р)}, МНОЖ2(5,р) = {vG ПРЕД^):^ G 5, w* pnL(v) < £(p)}, МНОЖЗСЯ, p) = {v G ПРЕЕМ(w): w G 5, M(v) > M(p) и L(v) < L(p)}, MAKC1 (S, p) = = max(£(p), {£(v): v G ПРЕЕМ(и>), w G S и M(v) > M(p)}), MAKC2CS, p) = = max(£(p), {L(v): v G ПРЕДМ, w G S и w * p}). Г. Подграф H уграфа G является гамаком с начальной вершиной р и конечной q тогда и только тогда, когда выполняются следующие условия: H = L[UpY.L(p) +Н - 1Д;Л/(р) < M(v) для всех v G Я; МН0Ж2(Я, р) = = МНОЖЗ(Я, р) =0; р G ПРЕЕМ(^); МАКС2(Я, р) < IЯ1 + £(р); либо МНОЖ1СЯ, р)=0 и МАКС 1 (Я, р) =£(р) + 1Я1 =£(</), либо МНОЖ1(Я,р) = {?} нМАКС1(Я,р) < £(р) + 1Я1. Д. Пусть для подграфа S = £[£(р): £(р) + /], где t > 0, справедливо хотя бы одно из следующих условий: МНОЖ2(5, р) # 0, МНОЖЗ(5, р) * 0, M(q) < М(р) для конечной вершины q гамака S, S имеет не- сколько конечных вершин, причем М-номер одной из них — меньше М(р). Тогда для любого г такого, что r> t, не существует гамака £[£(р):£(р)+г]. 4.3.6. Алгоритм выделения гамаков. Задача Дано. Уграф G = (X, U, р0, #0). Требуется. Выделить все гамаки уграфа (7. Решение Программа проц ГАМАКИ «7: уграф) = 1. Построить нумерации М и £ уграфа G, выполняя алгоритм 4.3.4; 2. для всех р из X цикл 3. (МАКС1, МАКС2, МН0Ж1) := (£(р), L(q), истина); 4. Пометить каждую вершину из ПРЕД (р); 5. ВЫДЕЛЕНИЕ: для к от £(р) до п цикл 6. w:=£"l(A:); 7. для всех v из ПРЕЕМ (w) цикл 8. если A/(v) < М(р) то 9. если-МНОЖ 1 то 10. завершить ВЫДЕЛЕНИЕ при q Ф v 11. иначе (q, МН0Ж1) := (v, ложь) все 12. иначе завершить ВЫДЕЛЕНИЕ при £(v) < £(р);
4.4.1. Вводные замечания 171 13. МАКС1 := max (МАКС 1, LM) все все; 14. еслии>#рто 15. для всех v из ПРЕД(и>) цикл 16. завершить ВЫДЕЛЕНИЕ при £(v) < L(p); 17. МАКС2 := max(MAKC2, £(v)) все все; 18. если-МНОЖ 1 то 19. если (МАКС1 < к) л(МАКС2 < к) л 20. (q не помечена) 21. то £ [£ (р) :к ] — гамак; 22. завершить ВЫДЕЛЕНИЕ все 23. иначе если к = п то 24. £[£(р):и ] — гамак 25. иначе если (МАКС1 = £+ 1) л (МАКС2 < к) л 26. (вершина £‘ (к + 1) не помечена) 27. то L[L(p):k ] — гамак все все все все; 28. Убрать пометки с вершин из ПРЕД(р) все все Пояснение. Основывается на свойствах 4.3.5.Г, Д нумераций Л/ и £ уграфа (7. Гамак L[L(p):k ], выделяемый оператором 21, имеет конеч- ную вершину <7, гамак £[£(р) :£ ], выделяемый оператором 27, имеет ко- нечную вершину £ 1 (к + 1), а гамак £[£(/?) :п ]» выделяемый оператором 21, не имеет конечных вершин. Свойство. Алгоритм затрачивает О(тп) времени на выделение всех гамаков уграфа <7, где пит — количества вершин и дуг уграфа G. 4.4. Выявление отношения обязательного предшествования 4.4.1. Вводные замечания. Здесь описываются алгоритмы отыскания непосредственных обязательных предшественников для каждой вер- шины уграфа как в общем случае (см. пп. 4.4.3 — 4.4.6), так и для случая, когда уграф регуляризуемый (см. п. 4.4.2). Предполагается, что в уграфе G = (X, U, р0, qQ) выполнен обход в глубину (см. пп. 1.1.12 — 1.1.14), в результате чего все вершины по- лучили М- и A-номера, а все дуги оказались разбитыми на классы дре- весных, прямых, обратных и поперечных дуг. Через Т будет обозначать- ся дерево обхода (7 в глубину, начиная с р0.
172 4.4.3. Семидоминаторы 4.4.2. Алгоритм выделения отношения обязательного предшество- вания в регуляризуемом уграфе. Задача Дано. Регуляризуемый уграф G = (X, U, р0, </0) из. и вершин и tn дуг, каждая вершина идентифицируется своим TV-номером в некоторой обратной нумерации уграфа (7. Т ребуется. Для каждой вершины р уграфа G вычислить такую шкалу, (/-я компонента которой равна единице, если q обязательно пред- шествует вершине р, и нулю в противном случае. Решение Программа функ ОБЯЗАТЕЛЬНОЕ-ПРЕДШЕСТВОВАНИЕ (С: уграф) = 1. /):разметка = {(р, (О^1, 1, О'* р)): р е X}; 2. для Л от 2 др и цикл 3. р := *Tik)\R := (1"); 4. для всех q из ПРЕД(р) цикл 5. если Niq) < Nip) то R := R ® Diq) все все; 6. D(p) := Dip) О R все; 7. возврат D все Пояснение. Базируется на свойстве 4.1.10» В и использует по- компонентные логические операции дизъюнкции © и конъюнкции 0 над шкалами, в которых единица представляет значение истина, и нуль — ложь. Свойство. Алгоритм осуществляет вычисление обязательных предшественников за Oim) расширенных (покомпонентных) и обычных операций. 4.4.3. Семидоминаторы. Пусть GU) — уграф, образованный из Т до- бавлением всех не древесных дуг (7, заходящих в вершины р, где Mip) > i. Тогда i-м семидоминатором СД (/, р) вершины р называется ее непосред- ственный обязательный предшественник в уграфе Gii). А. Если р * р0 и Mip) < z, mo CJ\ii, р) есть отец вершины р в дереве Г. Б. Если р * pG, то для всех i вершина CJ\ii, р) достижима из CJ\ii - 1, р) в дереве 7. В. Если р * pQ и СД(/, р) = z, то М~'Ц) — непосредственный обяза- тельный предшественник вершины р eG, Г. Если р * р0 и i < Mip), то либо СД(/, р) — непосредственный обязательный предшественник р в G, либо вершина с М-номером i дос- тижима из СД(/, р) в Т, Д. Если и не обязательно предшествует вершине v eG и дуга iu,v) в G заменена дугой iw, v), где w — непосредственный обязательный пред- шественник и eG icM. п. 4.4.4), то р обязательно предшествует q eG
4.4.4. Преобразования дуг 173 тогда и только тогда, когда р обязательно предшествует q в резуль- тирующем графе. Е. Пусть р — вершина в G такая, что в нее заходит самое большее две дуги — древесная (и, р) и, возможно, прямая (ту, р). Если ни одна прямая дуга не заходит в р, то СЩМ(р) - 1, у) = СД(М(р), у) для всех у. Если в р заходит прямая дуга (ту, р), то СД(Л/(р) - 1, у) = w для всех таких у, что у достижима из р в Т и в Т найдется путь из w в и, содержащий СЩМ(р), у), и CR(M(p) - 1, у) = СД(М(р), у) всех осталь- ных вершин у. Ж. Для любых вершин р и q вершина р — непосредственный обяза- тельный предшественникqeGтогда и только тогда, когдар = СД(0, q). 4.4.4. Преобразования дуг. Для каждой вершины у G X через ЕМ обозначается множество всех таких вершин w, отличных от у, что суще- ствует вершина и, достижимая из w по древесным дугам по пути, прохо- дящему через у, и такая, что (и, w) — обратная дуга. Если Е(у) # 0, через Я(у) обозначается вершина, имеющая наибольший Л/-номер в £(у). (Здесь и далее используются только М-номера вершин уграфа G, причем при необходимости вершины из X идентифицируются своими Л/-номерами.) А. Вершина H(v) достижима из w по Т, если ту G E(v). Преобразование П1 замены обратных дуг — это переход от G к угра- фу G' (обозначается G' = П1((7)), получаемому из G удалением всех обратных дуг и добавлением новых обратных дуг (у, Я(у)) для каждой вершины у, для которой Ж у) определено. П р и м е р. В графе G (рис. 4.21, а) в качестве обозначений вершин выступают их Л/-номера, древесные дуги изображены двойными лини- ями, прямые — сплошными одинарными, обратные — волнистыми, по- перечные — штриховыми. После замены обратных дуг (см. рис. 4.21, б) вершина 5 потеряла обратную дугу, а вершины 2—4 приобрели. Рис. 4.21 Б. Если (и, ту) — обратная дуга в G и в Т существует путь из w в и, содержащий вершину у, то в П1(О существует путь из v в ту, содер- жащий только обратные дуги.
174 4.4.5. Отыскание непосредственных обязательных предшественников В. Вершина w обязательно предшествует вершине v в G тогда и только тогда, ко^За w обязательно предшествует вершине v в П1 (СТ). Г. Уграф G' = П1 (G) совпадает с уграфом П1 (G'). Пусть (и, v) и (w, v) — две прямые дуги в G такие, что М(и) < ММ). Переход от G к уграфу G', получаемому из G удалением дуги (w, v), называется удалением прямой дуги и обозначается через П2, т.е. (7 = П2(Сг). Д. Если G=ni(G), то вершина q обязательно предшествует вершине р eG тогда и только тогда, когда q обязательно предшеству- ет р в П2«7). Пусть v — вершина G такая, что из нее выходит одна обратная дуга (v, Я(у>), а в нее заходит самое большее одна прямая дуга и не заходят ни поперечная, ни обратная дуги. Преобразование ПЗ — удаление обрат- ной дуги — в применении к v состоит в удалении обратной дуги (v, Я(у» и добавлении дуги (и, НМ), если дуга (и, v) существует в G и М(и) <М(НМ), т.е. (и, НМ) —это обратная дуга. Е. Пусть G’ — уграф, полученный из G применением ПЗ к некоторой вершине v, и w — некоторая вершина такая, что ММ) < ММ- Тогда вершина q обязательно предшествует w в G тогда и только тогда, когда q обязательно предшествует weG'. Пусть (и, v) — поперечная дуга в уграфе G. Преобразование П4 заме- ны поперечной дуги в применении к (и, v) состоит в удалении (u,v) и добавлении дуги (СД(ММ, и), v). Ж. Пусть G’ — уграф, полученный из G применением П4. Тогда вершина р обязательно предшествует вершине q в G тогда и только тогда, когда р обязательно предшествует q в G'. 3. Пусть G' — уграф, получаемый из уграфа G применением одного из преобразований: удаление прямой дуги, удаление обратной дуги и замена поперечной дуги. Тогда множества семидоминаторов вершин в G и G' совпадают. 4.4.5. Общий вид алгоритма отыскания непосредственных обяза- тельных предшественников. Полный текст алгоритма включает в себя процедуру поиска в глубину и базируется на свойствах 4.4.3. Ж и 4.4.4. В. функ ДЕРЕВО-ПРЕДШЕСТВОВАНИЯ (G: уграф) = 1. Применить алгоритм 2.2.16 для построения прямой нумерации и классификации дуг уграфа G; 2. Вычислить Н(р) для всех р G X; 3. Осуществить замену обратных дуг в G, т.е. G := П1 (G); 4. Вычислить СД(/, р) для всех р G X и i G [0:и ], устанавливая НД (р) равным СД(0, р); 5. возврат НД все Прямой алгоритм для вычисления Н(р) для всех р G X (оператор 2) имеет временную сложность О(п2). Более эффективный алгоритм, с вре- менной сложностью О(п log п + т), получается, если использовать та- кую структуру данных, как набор:
4 4.6. Алгоритм отыскания семидоминаторов 175 начало 2.1. я: набор = {({р},р):р G X}; 2.2. Я: разметка = {(р, 0): р G X}; 2.3. для к от п до 1 через -1 цикл 2.4. и^ЛГЧЛ); 2.5. для всех (w, w) из множества обратных дуг цикл 2.6. пока w не достижима из и в Т цикл 2.7. х := найти ОТЕЦ (и) в я; 2.8. если Жм)= Ото 2.9. Я (и) := w; слить х с ОТЕЦ(х) в я все; 2.10. и := х все все все конец Обработка обратной дуги (u, w) состоит в нахождении множества содержащего отца вершины и в Т, множества ^содержащего отца вер- шины и т.д., пока не достигнем множества иг, такого, что из иг дос- тижима w в Т. Вершины Ир и2, ..., и, возможно, и суть вершины на пути в дереве Т из w в и, для которых не вычислено значение Я. В качестве значения Я для этих вершин берется w и производится объе- динение множеств с именами ир и2,..., м^р иг и, возможно, и, ему дается имя иг. 4.4.6. Алгоритм отыскания семидоминаторов. При вычислении се- мидоминаторов в операторе 4 общего алгоритма 4.4.5 строится дерево обязательного предшествования от листьев к корню: в любой момент часть дерева, которая уже построена, будет состоять из отдельных вер- шин и их потомков. Пусть это множество поддеревьев есть F. Для хра- нения информации об F используется набор а на множестве вершин уграфа G. Если у— вершина в F, то убудет храниться в множестве набора а, именем которого является корень того поддерева F, которое содержит у. При этом, каждый раз когда вычисляется непосредственный обяза- тельный предшественник НОП (у) для новой вершины у, выполняется слить ус НОП(у). Преобразование по удалению прямых дуг реализуется оператором цикла 4.3.—4.4. (см. ниже), а оператор цикла 4.5—4.11 осуществляет замену поперечных дуг на основе свойств 4.4.3.В,Г. Для замены дуги (и, р) прямой дугой сначала находится имя множества х, содержащего и. При этом либо (х, р) является прямой дугой, либо р достижима из СД (р, х), и дальнейшее применение замены поперечных дуг дает прямую дугу. Оператор 4.11 проверяет, заходят ли в р теперь две прямые дуги и, если да, удаляет одну из них. Семидоминаторы вычисляются, начиная с n-х и кончая нулевыми, которые и берутся в качестве значения НОП для соответствующих вер- шин. Собственно вычисление семидоминаторов осуществляют операторы 4.12—4.22. При этом, поскольку для большинства вершин СД(р — 1, у) =
176 4.4.6. Алгоритм отыскания семидоминаторов = СД(р, v), на этом шаге вычисляются только те семидоминаторы, кото- рые изменяются при изменении р (заметим, что здесь и в дальнейшем вершины уграфа идентифицируются их Af-номерами). В качестве струк- тур данных для этих вычислений используются очереди с приоритетами ОЧЕРЕДЬ(р) для каждой вершины р G X. Очередь для вершины р содержит множества МНОЖ, каждое из кото- рых есть множество потомков вершины р. Все вершины w в некотором МНОЖ будут иметь одно и то же значение СД(р, и>), которое будет приоритетом данного МНОЖ в очереди В множество МНОЖ включаются только те вершины, для которых значения НОП еще не известны. Таким образом, если СД(у, it) является приоритетом некоторого множества МНОЖ в очереди для вершины у, то вершина v достижима из СД(у, it) в Т. Чтобы модифицировать семидоминаторы в процессе обработки вер- шины р, через (НИЗ(р), р) обозначается прямая дуга (если она есть), заходящая в р. Все сыновья р в Г к этому моменту уже обработаны. Сначала (оператор 4.12) конструируется приоритетная очередь для р объединением очередей сыновей р. Каждое множество МНОЖ в новой очереди имеет приоритет, соответствующий некоторому предку р. Уда- ляется (см. оператор 4.14—4.16) из ОЧЕРЕДЬ(р) каждое множество МНОЖ, имеющее приоритет р — наибольший возможный приоритет в ОЧЕРЕДЬ (р). Для каждой вершины из удаленного множества МНОЖ значение НОП равно р по свойству 4.4.3, В. Если р имеет заходящую в нее прямую дугу, то (см. операторы 4.20—4.21) из ОЧЕРЕДЬ (р) удаля- ются все множества, приоритет которых больше или равен НИЗ(р), их элементы объединяются и вместе с р добавляются в качестве нового эле- мента в ОЧЕРЕДЬ(р) с приоритетом НИЗ(р). Оператор 4.18—4.21 ис- пользует свойство 4.4.3, Е. начало 4.1. ст: набор = {({р}, р): р G X}; 4.2. ОЧЕРЕДЬ: разметка приоритетными-очередями = {(р, 0): р G X}; 4.3. для всех р из X цикл 4.4. из всех прямых дуг, заходящих в р, оставить только одну дугу (НИЗ(р), р), в которой НИЗ(р) обозначает минимальную возможную вершину все; 4.5. для р от п до 1 через -1 цикл 4.6. для каждой поперечной дуги (и, р) цикл 4.7. х := найти ива; 4.8. если р не достижима из х в Г то 4.9. в качестве х взять приоритет множества в ОЧЕРЕДЬ (р), содержащего х все; 4.10. заменить (и, р) на (х, р); 4.11. если НИЗ(р) достижима из х в Г то НИЗ(р) := х все все; 4.12. для каждого сына w вершины рвТ цикл
4.4.6. Алгоритм отыскания семидоминаторов 177 4.13. ОЧЕРЕДЬ(р) <= ОЧЕРЕДЬ (и>) все; 4.14. пока наивысший приоритет множества в ОЧЕРЕДЬ (р) равен р цикл 4.15. Удалить из ОЧЕРЕДЬ (р) то множество МНОЖ, которое в нем имеет наивысший приоритет р; 4.16. для всех v из МНОЖ цикл 4.17. НОП(у) :«р; слить уср вег все все; 4.18. еслиНИЗ(р) > рто 4.19. добавить в ОЧЕРЕДЬ (р) множество, состоящее из одного элемента р и имеющее приоритетом ОТЕЦ(р) 4.20. иначе пусть МНОЖ — это множество {р} с приоритетом НИЗ(р) пока НИЗ(р) меньше или равен наивысшему приоритету множества в ОЧЕРЕДЬ (р) цикл 4.21. удалить множество с наивысшим приоритетом из ОЧЕРЕДЬ (р), включив все его элементы в МНОЖ все* 4.22. ОЧЕРЕДЬ(р) <- МНОЖ все все конец На рис. 4.22 представлен вид уграфа G (см. рис. 4.21, а) после выпол- нения над ним всех преобразований, входящих в функцию ДЕРЕВО- ПРЕДШЕСТВОВАНИЯ. Рядом с вершинами уграфа указаны соответст- вующие им значения НОП. Рис. 4.22
178 4.5. Библиографический комментарий ' 4.4.7. Сложность общего алгоритма отыскания непосредственных обязательных предшественников. Легко проверить, что емкостная сложность алгоритма составляет О(п + т). Оценка О(п + т) также верна и для временной сложности, если игнорировать операции над множест- вами и очередями. При выполнении алгоритма производится О(п) объе- динений в а и О(т) поисков в а, а также О(п) операций объединений и О (и) поисков множеств в очередях. Поскольку в любой очереди множе- ства попарно не пересекаются, использование реализации в виде набора позволяет выполнить все эти операции за время О(п log п + т). Алго- ритм в процессе своей работы осуществляет О(п) раз объединение очере- дей, О(п) раз — добавление в очередь и О(п) раз — удаление из очереди. Подходящая реализация приоритетных очередей в виде сбалансирован- ных деревьев (см., например, п. 7.1) позволяет реализовать все эти дейс- твия с очередями за время О(п log п + /и). Таким образом, временная сложность общего алгоритма отыскания непосредственных обязательных предшественников составляет О(п log п + т). 4.5. Библиографический комментарий Задачам анализа структур программ посвящена обширная библиогра- фия, привести которую здесь не представляется возможным. Ссылки на наиболее важные работы по этим вопросам читатель найдет в работах [1—3, 12, 14, 16, 17, 28] и обзорах [13, 15]. Данная глава написана по книге [16 ] с использованием материала статей [39, 41 ]. Понятие уграфа как модели программы, описывающей структуру ее управляющих связей, впервые рассматривалось в работах [18, 19]. Там же были введены понятия закрытого и замкнутого подграфов {закрытый подграф — это альт, а замкнутый — фрагмент с одной начальной и одной выходной вершинами), а также построены эффективные алгорит- мы их выделения. Понятие начальных, конечных, входных и выходных вершин фрагмента были введены в работах [7, 10 ], а граничных, старто- вых и финишных — в [41 ]. Идея рассмотрения линейных участков была выдвинута в работе [20], зон — в [23], гамаков и линейных компонент — в [4, 21 ], простых и составных гамаков — в [14 ], фактор-уграфов — в [12], гамачного представления и А-графа — в [14]. Одновходовость уграфов была введена в работе [6], интервальная сводимость — в [24], регуляризуемость — в [14], а аранжируемость — в [21 ]. По- нятие F-области и Т-, К- и L-нумераций были предложены в рабо- тах [9, 10]; там же были приведены эффективные алгоритмы их построения. Отношения доминируемости (обязательного предшест- вования и обязательной преемственности) впервые рассматрива- лись в работе [36 ], а разумные нумерации — в [27 ]; работы [14, 35, 39 ] содержат эффективные алгоритмы выявления отношения обяза- тельного предшествования. Различным направлениям в теории регуляризуемости уграфов посвя- щены работы [1—3, 7—16, 22, 24, 26—31,33, 34, 40]. Иерархия вложен- ных зон рассматривалась в работах [23, 25], глубина интервально- сводимого уграфа и ее связь с длиной последовательности сведения — в
Библиографический комментарий 179 работе [29 ]. Понятие зонно-интервального представления было введено в работе [6], разборности — в [29], а каркаса уграфа — в [30]. Задача преобразования нерегуляризуемых уграфов решается в работах [7, 24 ]. В работе [41 ] введено понятие разбора первичных фрагментов уграфа как процесса, который редуцирует уграф многократной заменой некото- рого первичного фрагмента на дугу, соединяющую его стартовую вер- шину с финишной (пример такого процесса для уграфа представлен на рис. 4.23, где новые дуги изображены штриховыми линиями), рассмотре- но дерево разбора, представляющего все возможные разборы первичных фрагментов заданного уграфа. (Заметим, что любой уграф или содержит единственную дугу, или не содержит первичных фрагментов, или ре- дуцируется, причем, как правило, не единственным образом, к уграфу, удовлетворяющему одному из первых двух свойств.) Показано, что зада- ча построения дерева разбора уграфа и задача выделения трехсвязных компонент графа линейно сводятся одна к другой. Связный мультиграф G называется двухсвязным, если для каждой тройки различных его вершин р, q и v существует путь от р до q, не содержащий вершину у. Если в G найдутся такие различные вершины р, q и у, что у лежит на каждом пути от р до q, то у называется разделяющей (сочленяющей) вершиной G. Максимальная двухсвязная часть G назы- вается его двухсвязной компонентой. Разбиение G на двухсвязные ком- поненты единственно и может быть выполнено за время О(п + т), где п — число вершин, а ди — число ребер G (см. [38]), причем каждая дуга G принадлежит ровно одной двухсвязной компоненте G, а каждая вершина — либо двум двухсвязным компонентам G, если она разделяющая вершина G, либо только одной — в противном случае. Пусть {р, q} — пара вершин двухсвязного мультиграфа G. Предпо- ложим, что дуги G разбиты на классы эквивалентности Е{, ..., Ег такие, что любые две дуги, лежащие на общем пути, все внутренние вершины которого отличны от р и q, принадлежат одному и тому же классу. Клас- сы Д называются классами разделения G относительно {р, q}. G называ- ется трехсвязным, если в нем не существует разделяющих пар — таких {р, q}, что в G имеется больше одного класса разделения относительно {р, q}, причем множество классов таково, что оно не состоит из двух классов, один из которых одноэлементен, и не состоит из трех одноэлементных классов. Для графа G', представленного на рис. 4.24, разделяющими являются пары {1,10}, {4, 9}, {2, 8} и {3, 7}. Пусть {р, q] — разделяющая пара G; Д, Д, ..., Ег — классы разде- ления G относительно {р, q} и пусть множества Е’ = Д U ... U Д и Е’' = Д+! U ... U Д содержат не менее чем по два ребра. Тогда графы Д и G2, образованные множествами дуг Е' U {р, </} иЕ" U {р, q} соответст- венно, называются графами расщепления G относительно {р, q}, а ребро {р, #}, добавленное в G{ и G2, виртуальным ребром. Рис. 4.24 показывает пример графа G и его трехсвязных компонент А, В, С, D, Е, F и Н, однозначно получаемых по любому мультиграфу специального вида его расщеплениями. В общем случае трехсвязными компонентами являются графы расщепления трех видов: многоугольники, тройные узлы и трех-
180 Библиографический комментарий связные графы, состоящие не менее чем из четырех вершин. На рис. 4.24 ребра G изображены сплошными линиями, а виртуальные ребра, добав- ляемые при расщеплении, — штриховыми; среди графов расщепления G графы Л, Е и Н — тройные узлы, В, D и F — многоугольники, а С — 1 т I i В работе [32 ] описывается алгоритм выделения трехсвязных компо- нент графа за время О(п + т).
Список литературы 181 СПИСОК ЛИТЕРАТУРЫ 1. Ахо А., Ульман Дж. Теория синтаксического анализа, перевода и компиляции. — М.: Мир, 1978. —Т.2. 2. Евстигнеев В.А. Теория графов и программирование. — Новосибирск: Изд-во Новосиб. ун-та, 1978. 3. Евстигнеев В.А. Применение теории графов в программировании. — М.: Наука, 1985. 4. Ершов А.П. Универсальный программирующий процессор// Проблемы прикл. мате- матики и механики. — М., 1971. — С. 103—116. 5. Ершов А.П. Введение в теоретическое программирование. — М.: Наука, 1977. 6. Касьянов В.Н. Анализ управляющих графов программ// Системное программирова- ние. — Новосибирск, 1973. — 4.1. — С. 133—154. 7. Касьянов В.Н.Экономное преобразование несводимых графов/ / Системное и теоретическое программирование. — Новосибирск, 1973. — С. 143—172.
182 Список литературы 8. Касьянов В.Н. Об одном алгоритме выделения бикомпонент в ориентированном графе // Системное и теоретическое программирование. — 1974. — С.235—243. 9. Касьянов В.Н. Выделение гамаков в ориентированном графе// Докл. АН СССР. — 1975. — Т.221, № 5. — С. 1020— 1022. 10. Касьянов В.Н. Анализ структур программ// Кибернетика. — 1980. — № 1. — С.48—61. 11. Касьянов В.Н. Быстрый алгоритм выделения максимальных линейных участков в прог- рамме // Математическая теория и практика систем программного обеспечения. — Но- восибирск, 1982. — С.81—87. 12. Касьянов В.Н. Методы анализа программ. — Новосибирск: Изд-во Новосиб. ун-та, 1982. 13. Касьянов В.Н. Оптимизация программ// Прикладная информатика. — М.: Финансы и статистика, 1983. — Вып.2. — С.38—75. 14. Касьянов В.Н. Введение в теорию оптимизации программ. Оптимизирующие преобра- зования программ и их обоснование. — Новосибирск: ВЦ СО АН СССР, 1985. 15. Касьянов В.Н. Теоретико-графовые задачи анализа управляющих графов транслиру- емых программ// Исследования по прикладной теории графов. — Новосибирск: Наука. Сиб. отд-ние, 1986. — С.9—26. 16. Касьянов В.Н. Оптимизирующие преобразования программ. — М.: Наука, 1988. 17. ЛипаевВ.В. Тестирование программ. —М.: Радио и связь, 1986. 18. Мартынюк В.В. Выделение цепей в схемах алгоритмов// Журн. вычисл. математики и мат. физики. — 1961. — Т. 1, № 1. — С. 151 — 162. 19. Мартынюк В.В. Об анализе графа переходов для операторной схемы// Там же. — 1965. — Т.5, №2. —С.298—310. 20. Поддерюгин В.Д. Программа контроля для ' Стрелы-3” (луч). — М.: ВЦ АН СССР, 1960. 21. Потгосин И.В. О линеаризации программы и частичном ее упорядочении// Системное и теоретическое программирование. — Новосибирск, 1972. — С.278—286. 22. Aho A., Ullman J.D. Node listings for reducible flow graphs// J.Comput. and System. Sci. — 1976. — Vol. 13, N 3. — P. 286—299. 23. Allen F.E. Program optimization// Ann. Rev. Automat. Program. — 1969. — Vol. 5. — P. 239—307. 24. Cocke J. Global common subexpression elimination// SFGPLAN Notices. - 1970. — Vol. 5, N 7. — P. 20—24. 25. Earnest C.P., Balke K.G., Anderson J. Analysis of graphs by ordering of nodes// J. ACM. — 1972. — Vol. 19, N 1. — P.23—42. 26. Fong A., Ullman J.D. Finding the depth of a flow graph// J. Comput. and System. Sci. — 1977. — Vol. 15, N 4. — P.300—309. 27. Hecht M.S. Topological sorting and flow graphs// Proc. IFIP Congress 74, Amsterdam. — Amsterdam, 1974. — P.494—499. 28. Hecht M.S. Flow analysis of computer programs. — New York: Elsevier, 1977. 29. Hecht M.S., Ullman J.D. Flow graph reducibility// SIAM J. Comput. — 1972. — Vol. 1, N 2. — P. 188—202. 30. Hecht M.S., Ullman J.D. Characterization of reducible flow graphs// J. ACM. — 1974. — Vol. 21, N3. — P.367—375. 31. Hecht M.S., Ullman J.D. A simple algorithm for global data flow analysis problems// SIAM J. Comput. — 1975. — Vol. 4, N 4. — P.519—532. 32. Hopcroft J.E., Tarjan R.E. Dividing a graph into triconnected components// SIAM J. Comput. — 1973. — Vol. 2, N 3. — P. 135— 168. 33. Kasyanov V.N. Some properties of fully reducible graphs// Inf. Proc. Lett. — 1973. — Vol. 2, N4. —P.113—117.
Список литературы 183 34. Knuth D.E. An empirical study of Fortran programs// Software — Practice and Experience. — 1971. —Vol. 1, N 2. — P.105—133. 35. Lengauer T., Tarjan R.E. A fast algorithm for finding dominators in a flow graphs// ACM Trans. Prog. Lang. Syst. — 1979. — Vol. 1, N3. —P.121 —141. 36. Lowry E., Medlock C.M. Object code optimization// Comm. ACM. — 1969. — Vol. 12, N1. — P.13—22. 37. Markowsky G., Tarjan R.E. Lower bounds on the length of node sequences in directed graphs// Discrete Math. — 1976. — Vol. 16. — P.329—337. 38. Tarjan R.E. Depth first search and linear graph algorithms// SIAM J. Comput. — 1972. — Vol. 1, N2. — P.146—160. 39. Tarjan R.E. Finding dominators in directed graph// Ibid. — 1974. — Vol. 3, N 1. — P.62—89. 40. Tarjan R.E. Testing flow graph reducibility// J. Comput. and Syst. Sci. — 1974. — Vol. 9, N 3. — P.355—365. 41. Tarjan R.E., Valdest J. Prime subprogram parsing of a program// Conf. Record of the 7th Ann. ACM Symp. on Principles of Programm. Languages. — Las Vegas, Nevada, 1980. — P.95— 105.
Глава 5 ИЗОМОРФИЗМ, УНИФИКАЦИЯ И СИСТЕМЫ ПЕРЕПИСЫВАНИЯ ТЕРМОВ 5.1. Изоморфизм деревьев 5.1.1. Определение изоморфизма. Пусть Т s (У, Е) — дерево и Р(е, v, w) — его инцидентор, т.е. предикат, равный единице в том и только в том случае, когда ребро е инцидентно вершинам v и w. Дерево 7\ - (Ур называется изоморфным дереву Т2 = (У2, Е2), если между вершинами деревьев, а также между их ребрами можно уста- новить взаимно однозначное соответствие У, о У2, Et о Е2, сохраняющее инцидентор, т.е. такое, что (Vv, w G Ур ( Vv', w' G V2) (Ve G Et) (Уе G E2) (v v' & w ** w '& &e* e' => [P(e, v, w) => P(e’, v', и»') ]). Другими словами, два дерева изоморфны, если между их вершинами можно установить взаимно однозначное соответствие, сохраняющее от- ношение инцидентности (смежности). На рис. 5.1 представлены изоморфные деревья. Нетрудно заметить, что они отличаются лишь способом представления (например, способом изображения на плоскости). Изоморфизм деревьев обозначается знаком = : Т{ = Т2. Отношение изоморфизма деревьев рефлексивно, симметрично и транзитивно, т.е. представляет собой эквивалентность. Матрицы смежности изоморфных деревьев могут быть переведены одна в другую перестановкой рядов, т.е. одновременной одинаковой пе- рестановкой строк и столбцов. Два корневых дерева (см. п. 1.1.5) называются изоморфными, если существует взаимно однозначная функция, которая отображает множе- ство вершин одного дерева на множество другого и не только сохраняет смежность, но и переводит корень одного дерева в корень другого. Изоморфное отображение дерева Т на себя называется автоморфиз- мом дерева. Совокупность всех автоморфизмов дерева Т, обозначаемая
5.1.2. Алгоритм Ахо—Хопкрофта—Ульмана 185 Г(Т), образует группу, называемую группой дерева Т. Таким образом, элементы группы Г(7) являются подстановками, действующими на мно- жестве К Порядок s(T) группы Г(Т) есть число симметрий дерева Т. Дерево Т называется асимметричным, если его группа автоморфиз- мов есть единичная группа, т.е. s(T) « 1. Примеры асимметричных деревьев порядков 7, 8 и 9 показаны на рис. 5.2. Два плоских дерева (см. п. 1.1.2) называются изоморфными, если суще- ствует гомеоморфное отображение плоскости на себя, сохраняющее ориентацию, и такое, что оно отображает одно из этих деревьев на другое. Два помеченных дерева (см. п. 1.1.2) называются изоморфными, если существует взаимно однозначная функция, отображающая множество вершин одного дерева на множество вершин другого, которая не только- сохраняет смежность, но и переводит вершину с меткой а в вершину с той же меткой. 5.1.2. Алгоритм Ахо—Хопкрофта—Ульмана. Данный алгоритм при- писывает целые числа узлам двух заданных корневых деревьев Г, и Т2 с корнями Fj и г2, начиная с вершин уровня 0 и двигаясь вверх до корней, так что деревья 7\ и Т2 изоморфны тогда и только тогда, когда их корням при- писано одно и то же число. Алгоритм Вход. Деревья 7\ и Т2, заданные в виде, обеспечивающем эффективную реализацию поиска в глубину. Выход. Ответ на вопрос об изоморфизме деревьев Т{ и Т2. начало 1. А, := глубина дерева 7\; 2. Aj := глубина дерева Т2; 3. если Aj * Лз то СТОП % деревья неизоморфны; % 4. иначе начиная с корня, методом поиска в глубину приписать вершинам деревьев Г, и Т2 номера уровней, считая, что уровень корня г. дерева Г, равен глубине А, дерева; % это требует О(п) шагов, где п — число вершин в дереве %
186 5.1.2. Алгоритм Ахо—Хопкрофта—Ульмана 5. для z = 1 до 2 цикл 6. если v — висячая вершина (лист) дерева Г., то Кv) := 0 все; 7. для j от 0 до Л цикл % Л — общее значение глубин деревьев Т\ и Т2 % 8. L- := список вершин v уровня /дерева Т;, упорядоченных в порядке неубывания приписанных им меток Z(v); 9. для каждой вершины w на уровне /, отличной от листа цикл 10. приписать w кортеж S(и», j) путем просмотра _ j, поместив туда метки потомков вершины w, расположенные в порядке неубывания; 11. S-:= последовательность кортежей S(w, j); 12. упорядочить S- с помощью метода быстрого упорядочения цепочек в порядке их неубывания; 13. S- :« упорядоченная последовательность S#; 14. приписать метку Z, равную 1, тем вершинам уровня /, отличным от_листа, которые представлены первым кортежем в S-, метку 2 — вершинам, представленным вторым кортежем_и т.д.; 15. построить список L- вершин уровня у, упорядоченный по неубыванию меток Z; % список L- строится путем приписывания в начале списка L- всех листьев дерева Т. на уровне j % все все все все 16. если /(rj) = Z(r2) то деревья изоморфны все; конец Пример. уровень 3 уровень 2 уровень 1 уровень 0 уровень 3 уровень 2 уровень 1 уровень 0 Дерево Т2
5.1.2. Алгоритм Ахо—Хопкрофта—Ульмана 187 Так как 3, производится первоначальная расстановка меток: Дерево 7/ Дерево Т2 Приписывание кортежей и меток вершинам уровня 1, отличным от листьев: Приписывание кортежей и меток вершинам уровня 2, отличным от листьев: Приписывание кортежа и метки корню дерева и решение вопроса об изоморфизме:
188 5.1.4. Алгоритм Земляченко 5.1.3. Замечания к алгоритму Ахо—Хопкрофта—Ульмана. А. После нахождения упорядоченных последовательностей кортежей S1; и У2; можно проводить их сравнение, что потребует несколько из- менить алгоритм, и продолжать исследование изоморфизма только в слу- чае их совпадения. Б. Трудоемкость алгоритма равна О(п). В самом деле, можно заме- тить, что приписывание меток (т.е. целых чисел) вершинам, отличным от листьев, на уровне j занимает время, пропорциональное числу узлов уровня j - 1. Суммирование по всем уровням дает время О(п). Работа по приписыванию чисел листьям также пропорциональна и, и, таким обра- зом, весь алгоритм занимает время О(м). В. Рассмотрим помеченные деревья (см. п. 1.1.2) и допустим, что мет- ками вершин служат целые числа между 1 и и. Тогда изоморфизм двух помеченных деревьев можно распознать за линейное время, т.е. за О(п), если включить метку каждой вершины в качестве первой компоненты кор- тежа, приписываемого этой вершине приведенным выше алгоритмом. 5.1.4. Алгоритм Земляченко. Алгоритм предназначен для установ- ления изоморфизма между двумя помеченными некорневыми деревь- ями, заданными списками ребер, и заключается в приведении обоих де- ревьев к некоторому каноническому виду и в последующем сравнении канонических представлений. Алгоритм состоит из нескольких подал- горитмов, описываемых отдельно. Алгоритм А 34 (ранжирования вершин) начало 1. для каждой вершины v G V цикл 2. сформировать множество I(v) вершин, смежных с v; все; З. Я0 :»0; VI := V; 4. для i от 1 шаг 1 пока VI * 0 цикл 5. Я,: = {v: l/(v)\ 1=1}; 6. VI « VI \ Я-; все; 7. найти центр или бицентр дерева; % определение центра (бицентра) см. п. 1.1.4 % 8. для каждой вершины v G V, отличной от центра цикл 9. построить отображение Г по правилу: вершина v отображается в ту, смежную с ней вершину, которая имеет наибольший ранг R; % тем самым все ребра дерева оказываются ориентированными к центру % все 10. для каждой вершины v G V цикл 11. сформировать массив Г~‘; все конец Пример. Для деревьев 7\ и Т2 результат применения алгоритма А 34 показан на рис. 5.3.
5.1.4. Алгоритм Земляченко 189 Бицентр Тг- f g Ro.0 Rj - {a, b, c, f, g,j, k, m} R2 - {d, h, 1} R3-{e,n} 1(a) - {d} 1(b) - {d} 1(c) - {d} 1(d) - {a, b, c, e) Ke) - {d, n) I(q)-{h} I(h)-ff,q,n} I(m) - {n} I(k) - {1} r'd - {a, b, c} Г-'е - {d} T-'h -ff,g} r-'i-{j,k} j к /(y)={£} Rd) =Ш 1(e) - {a, ft, 9} Kv)-{Y,d, 6} Г-‘0 ={«,$,>?} Г"1г={ж, Л, p} r-4=M I^)={V) /(A)={v} /(г)={<А,д,|} /(«)={». v} Puc. 5.3 Алгоритм A 3/2 (приписывания вершинам индексов a) начало _ 1. для каждой вершины v е Я, цикл a(v) := 1 все 2. для i от 2 до IЯI шаг I цикл % IЯI — ранг центра %
190 5.1.4. Алгоритм Земляченко если г- = г-} то а (у.) = а иначе г, = г, . + 1 все % ниже множества Г71 рассматриваются как слова, в которых имя вершины считается одной буквой % 3. а (у) := слово, получаемое из Г^1 заменой каждой буквы у ее индексом а (у); 4. Я*:={а(у) IvG Я}; % пусть Л (у, У) обозначает вхождение символа у в слово Y % 5. определить на R* отношения эквивалентности и порядка следующим образом: V х, у G R* x = у о Vр(к(р, х) = к(р, у)), V х, у G R* х > у о 3 р (V а> (со > р) => (к(а>, х) = = (со, у)) & (£(р, х) > к(р,у))\ % отношение порядка для букв совпадает с соответствующим отношением дл*я отвечающих им чисел % 6. упорядочить Л* в соответствии с введенным порядком; % упорядочение производится в порядке неубывания % 7. если г, — первое слово в R* и ytl — вершина из /?., соответствующая слову rzl, то 8. a(yzl) = 1 + шах а (у); все 9. для j от 2 до v шаг 1 цикл 10. “' ' 11. все все конец Будем говорить, что дерево представлено в каноническом виде, если для каждой вершины у G V выполнены следующие условия: а) множество Г-1 разбито на массивы вершин, имеющих одинаковые индексы; б) совокупность этих массивов упорядочивается по возрастанию соот- ветствующих им индексов. Алгоритм А 33 (установления изоморфизма) начало 1. привести деревья к каноническому виду; 2. для / от IRI до 1 шаг -1 цикл 3. построить изоморфное отображение вершин ранга i дерева 7\ в вершины ранга i дерева Т2, сопоставляя друг другу вершины одинакового индекса; 4. если такое отображение построить нельзя то СТОП; % деревья неизоморфны % все конец Пример (продолжение) — рис. 5.4. : а (а) = a(b) = а (с) = a(f) = a(g) = а(к) = а{т) = 1
5.1.5. Изоморфизм помеченных лесов 191 R2 = {d,h,l} a(d) = 111 Я‘2 = {11, 11, 111} а(Л)= 11 а(Л) = 2 a(l) = 11 a(l) = 2 a(d) = 3 R3 = {e, n} a(e) = 3 Rj = {212,3} a(n) = 212 a(n) = 4,a(e)=5 Puc. 5.4 5.1.5. Изоморфизм помеченных лесов. Все алгоритмы установления изоморфизма деревьев могут быть применены для установления изо- морфизма лесов (определение леса см. пп. 1.1.2, 3.1.7). Здесь мы вкратце укажем на особенности выявления изоморфизма помеченных лесов, мет- ки которых представляют собой строки целых чисел. Трудоемкость ал- горитмов в этом случае линейна относительно размера леса плюс сумма длин меток. Вначале все метки сортируются вычерпыванием и им присваивается целочисленный ранг в отсортированном списке (о сортировке вычерпы- ванием см., например, [1 ]). На рис. 5.5 показан лес, состоящий из двух помеченных деревьев, и представлен ранжированный список меток. Буквы рядом с вершинами
192 5.1.5. Изоморфизм помеченных лесов Рис. 5.5 Затем каждая вершина в лесу получает целый z-номер по следующей схеме. Начиная с вершин максимальной глубины в лесу каждой вершине присваивается рабочая метка, которая состоит из ранга исходной метки, за которым следуют /-номера в возрастающем порядке всех ее потомков. Рабочие метки на текущем уровне упорядочиваются (также в порядке возрастания), и /-номера каждой вершины становятся рангами их ра- бочих меток внутри упорядоченного списка рабочих меток. Этот процесс продолжается до тех пор, пока корни всех деревьев не получат /-номера (см. рис. 5.6; справа от вершины вверху указан ее /-номер, внизу — рабочая метка). Рис. 5.6
5.1.6. Автоморфизное разбиение деревьев 193 Полная проверка изоморфизма состоит в организации параллельной /-ну- мерации двух помеченных лесов, проверке на каждом уровне множеств ра- бочих меток, которые должны быть одними и теми же в обоих лесах. Если на каком-то уровне возникает несовпадение, леса не могут быть изоморфными и алгоритм заканчивается фиксацией неизоморфности лесов. 5.1.6. Автоморфизное разбиение деревьев. Пусть дана группа авто- морфизмов дерева Т (или группа дерева Г). Две вершины х и у называют- ся подобными. если существует автоморфизм, переводящий х в у. По- добие вершин есть отношение эквивалентности на множестве V вершин дерева Г, классы эквивалентности которого образуют автоморфизное разбиение Т. Пусть Т — помеченный /-занумерованный лес. Известно, что вер- шины х и у подобны тогда и только тогда, когда они имеют одну и ту же глубину и одни и те же /-номера и их предки (если они существуют) подобны. Отсюда вытекает, что автоморфизное разбиение дерева всегда явля- ется уточнением разбиения вершин по их /-номерам. Для того чтобы вычислить автоморфизное разбиение произвольного дерева, необходимо вначале найти его центр и принять последний корень (в случае бицентра между центральными вершинами помещается вспомогательная верши- на, которая и принимается за корень). Присваиваем вершинам /-номера методом, описанным в предыдущем пункте. Двигаясь сверху вниз, т.е. от корня, приписываем вершинам целочисленные /-номера следующим об- разом. На каждом уровне, начиная с корня (или с корня, если имеем дело с лесом), вершинам сопоставляются метки, которые состоят из /-номера вершины, за которым следует /-номер предка (см. рис. 5.7). Эти рабочие метки на каждом уровне упорядочиваются в порядке возрастания, и в качестве /-номера вершины берется ранг рабочей метки в упорядоченном списке рабочих меток. На рис. 5.7 изображено автоморфизное разбиение леса из двух де- ревьев; справа от вершин стоят их /-номера (сверху) и рабочие метки (снизу). Можно показать, что /-номера плюс информация о глубине вершины определяют разбиение вершин на классы подобия. Для леса на рис. 5.7 классами подобия являются следующие множества вершин: [л, с, d. у, z ], [Z>, ,v], [е, и], [Л Л, к. т. п. р. г. /], [#, /, о, s ], [/, ? ], [/, у]. Трудоемкость алгоритма есть О(п). 5.1.7. Алгоритм Корнеля—Готлиба. Данный алгоритм установления изоморфизма деревьев является частным случаем более общего алго- ритма и основан на использовании автоморфизного разбиения вершин. Для установления изоморфизма двух графов для них строятся и исследу- ются два новых графа: граф-представитель и порядковый граф. Если графы-представители исследуемых графов не идентичны, то исходные графы не изоморфны, в противном случае сравниваются порядковые гра- фы. Если они идентичны, то и исходные графы изоморфны. При определении графа-представителя необходимо некоторое спе- циальное разбиение множества вершин Уна d кластеров, d > 1, /-й кла- ? ВА Евстигнеев, В.Н. Касьянов
194 5.1.7. Алгоритм Корнеля—Готлиба стер будет обозначаться через V\ 1 < ; < с/. Алгоритм (разбиениявершин) начало 1. упорядочить вершины в порядке невозрастания их степеней; 2. разбить вершины на группы так, чтобы вершины в группе имели равные степени; 3. упорядочить группы в порядке убывания степеней вершин; 4. принять упорядоченное множество {VJ} групп вершин в качестве начального разбиения; 5. для каждой вершины v G V цикл 6. сопоставить у список L(y) = (ар ad), где а- равно числу вершин V/ G V7 таких, что (у, у,) GE, 1 < j < d; все; 7. d := число кластеров;
5.1.8. Алгоритм Джовановича и Даниловича 195 9. упорядочить вершины в кластере VJ в лексикографическом порядке списков L, сопоставленных им; 10. если хотя бы две вершины имеют разные списки то 1ЕЛ:= 1; 12. повторять 13. у := первая вершина в упорядоченном кластере; 14. отнести к Л-му подкластеру VJk вершину у и все те вершины, которые имеют одинаковый с у список; 15. удалить вершины подкластера VJk из VJ\ 16. Л:=Л+1; 17. пока не будет исчерпан весь кластер Vj все; 18. перенумеровать все кластеры V7, рассматривая подкластеры VJk кластера Vj как новые кластеры именно в том порядке, в котором они создавались; 19. переход к шагу 5; 20. /:я/+1; все 21. если j > diQ СТОП; % получено измельченное разбиение % 22. иначе переход к шагу 9; конец Для представления измельченного разбиения множества вершин V введем в рассмотрение ориентированный долевой граф Q такой, что: а) множество вершин есть множество целых чисел от 1 до /, где f — число кластеров в результирующем разбиении; б) в Q из вершины i в вершину j ведет дуга с весом Z, если вершина v G V1 смежна в Vj в точности с I вершинами (Z равно я в окончательном списке, сопоставленном у). Так как вершинам сопоставлены однозначно определенные целочис- ленные номера, долевые графы изоморфны тогда и только тогда, когда они тождественны. Имеет место следующее утверждение. Пусть 7\ и Т2 — два конечных неориентированных дерева с долевыми графами Qi и Q2. Тогда 7\ = Т2, если Qt = Q2. 5.1.8. Алгоритм Джовановича и Даниловича. Данный алгоритм по- рождает каноническое представление дерева упорядоченной последова- тельностью Dc его степеней вершин. Алгоритм рассчитан на непомечен- ные деревья. Пусть е(у) обозначает эксцентриситет вершины у, У'(у) — множество r-соседей вершины у, т.е. множество вершин, отстоящих от у на рассто- яние г, У/у) — множество r-потомков вершины у, т.е. подмножество ее r-соседей, отстоящих от центра дальше, чем у. Алгоритм TRISO начало 1. найти центры Vlc и V2c деревьев 7\ и 7\; 2. если I Vlcl * IV2cl то СТОП; % деревья неизоморфны % 3. иначе найти канонические разметки Dlc и D2c деревьев 7\ и 7\, применяя к ним процедуру CANCOD;
196 5.1.8. Алгоритм Джовановича и Даниловича 4. если Dlc = D2c то деревья изоморфны 5. иначе деревья неизоморфны все все конец Каноническая разметка делается в виде строк целых чисел Dc = (dt, d2, ..., dt), элементы которой суть степени вершин в V. Алгоритм раз- метки содержит ряд правил для одновременного переупорядочения и разбиения вершин. Два первых правила переводят V в форму V={VQ(VC), ^(ур,..., где УО(УС) » Vc и Е — эксцентриситет вершин из Vc. Если некоторое под- множество У/Ис) содержит две или более вершины с равными степенями, совместное разбиение таких вершин требует привлечения понятия сте- пени подобия. Степень подобия sty, vk) вершину и vk определяется следующими тремя правилами. SIMDEG1 s(v;, vk) = 1, если: a) deg(y) =deg(vfc); б) для Vp vk G Vc> Vp vk G Vt (V;), у, G У. SIMDEG2 $(Ур ур = п > 1, если: а) было уже установлено равенство s(v;, vk) = п - 1; б) строки Dn(Vj) и Dn(vk) степеней вершин упорядоченных множеств Vn(Vj) и Vn<vk), чье упорядочение получается алгоритмом разметки CANCOD, лексикографически равны. SIMDEG3 s(Vp vk) = 0 в остальных случаях. Способ применения понятия степени подобия для финального раз- биения дается еще одним (четвертым) правилом алгоритма. Понимание этого правила облегчается, если заметить, что: — вершины у и vk вместе разбиты после начальной обработки, если s(Vp vk) =0; — s(yp vk) < Е - г - 1 для Ур vk G Vr( Vc); — max 5(y., vk) « E - 1, когда y;, vk G Vc. Алгоритм CANCOD для канонической разметки дерева с непомечен- ными вершинами может быть представлен в виде следующих пяти правил. CANCOD 1 Определяем центр дерева Т. Расположим вершины Ус и их степени в порядке невозрастания значений степеней на первых местах в V и D соответственно. В последующих правилах рассматриваем УО(УС) - Ус. Дальнейшие упорядочивания и переупорядочивания V и D, вытекающие из применения других правил CANCOD, применяем одновременно к У и D, так что отношение cZf - deg(y2) сохраняется.
5.1.9. Задача подграфового изоморфизма для ориентированных деревьев 197 CANCOD 2 Выполняем следующие действия: а) для r= 1, 2, Е- 1 группируем вершины дерева в множества г- соседей Ус, и помещаем их в V следом за Vrl (Ус), так что частично упорядоченное множество 0е”0 получается в виде V<£-,)= {УО(УС), У,(УС), .... VE-t(Vc)}-, б) положим г = 1. CANCOD 3 Выполняем следующие действия: а) группируем вершины Уг(Ус) в подмножества Vq первых потомков вершин в и упорядочиваем множества Vq внутри Vr(Vc) в соот- ветствии с упорядочением их предков в Vr_t (Vc); б) для #= 1,2, (Vr_x(Vc)Y. — упорядочим вершины внутри каждого множества Vq в порядке невозрастания величин их степеней, — когда две или более вершины внутри Vq имеют одинаковые сте- пени, они имеют степень подобия 1 и одновременно не разбиты. CANCOD 4 Для i = г - 1, г - 2, ..., О рассмотрим подмножества V\ С 1<(УС), вершин, для которых была установлена степень подобия $ = г - 1; а) сравним лексикографические значения строк Dr_{(V) всех вершин v G V/; б) переупорядочим строки Dr_{(V) внутри Dr(Vc) путем упорядочения по невозрастанию их лексикографических значений; в) строки Dr_{(V) со взаимно равными лексикографическими зна- чениями устанавливают степень подобия 5+1 для вершин v Е кото- рым они принадлежат. CANCOD 5 Выполняем следующие действия: а) когда г < Е- 1: — увеличим г на единицу, — применим правило CANCOD 3; б) когда r-E - 1, строка Z>(£ l), которая к этому моменту сформи- рована, есть код Dc, который канонически помечает дерево 7. Число элементов пс в кодовой строке Dc равно (что следует из CANCOD 2) пс = и - (У£(УС)). 5.1.9. Задача подграфового изоморфизма для ориентированных де- ревьев. Данная задача состоит в следующем: даны два корневых дерева 7\ и Т2; определить, является ли 7\ изоморфным какому-либо поддереву дерева Т2. В основе предлагаемого ниже алгоритма лежит.кодирование
198 5.1.9. Задача подграфового изоморфизма для ориентированных деревьев деревьев и сопоставление строковых образцов, его трудоемкость равна О(т + п), где т — число вершин в Тр а п — число вершин в Т2. Рассмотрим код Закса (см. п. 1.2.14) для представления упорядочен- ных бинарных деревьев. Этот код использует только 2п + 1 разрядов для дерева с п внутренними вершинами. Напомним, что код Закса может быть охарактеризован следующим образом. Битовая строка есть код Закса, если и только если выполнены следу- ющие три условия: 1) строка начинается с единицы, 2) число нулей на единицу больше числа единиц, 3) никакой собственный префикс строки не обладает свойством 2). Кодовое слово поддерева не зависит от его позиции. Таким образом, использование кода Закса сводит задачу подграфового изоморфизма для ориентированных бинарных деревьев к задаче сопоставления со строко- вым образцом. Другими словами, решение исходной задачи сводится к задаче выяснения, имеет ли место вхождение кодового слова дерева 7\ в кодовое слово дерева Т2. (Как показано в [57 ], прежде чем вычислять код Закса, дерево надо расширить введением дополнительных висячих вершин так, чтобы каждая вершина исходного дерева, исключая корень, имела бы двух потомков.) Рассмотрим теперь данную проблему для произвольных деревьев. Она сводится к рассмотренной выше с помощью специального представления дерева бинарным упорядоченным деревом следующим образом. Пусть х — вершина произвольного дерева, имеющая потомков хи х2, ..., хп, перечисленных слева направо. В соответствующем бинарном пред- ставлении вершина, содержащая х, имеет только два указателя. Левый указатель адресует первого потомка х, а правый адресует братьев (см. п. 7.1.9) х, если таковые есть. Аналогично левый указатель Xj адресует его первого потомка, а правый — х2 и т.д. Пример построения бинарного представления дерева показан на рис. 5.8. Ясно, что это преобразование сохраняет идентичность структур де- ревьев. Однако если произвольное дерево Т\ изоморфно поддереву про- вольного дерева Т2, то тогда бинарное представление Ь(7\) изоморфно представлению поддерева Ь(Т2) только в том случае, когда изоморфное поддерево есть самый правый брат на некотором уровне. Следовательно, сведение к задаче сопоставления образцам строк не столь прямолинейно, как в случае бинарных деревьев. Поддерево данного произвольного дерева представляется в соответст- вующем бинарном дереве как вершина плюс ее левое поддерево (или единственной вершиной, если поддерево состоит только из одной верши- ны). С другой стороны, дерево которое следует отобразить в кодо- вую строку, всегда имеет пустое правое поддерево. В проблеме сопостав- ления образцу, рассматривающей коды Закса Ь(7\) и Z>(T2), образец не является выполнимой строкой Закса, тем не менее он имеет вид 1х, где х есть код Закса, соответствующий левому поддереву Ь(7\). Следователь- но, мы игнорируем пустое правое поддерево корня Ь(7\) и правое подде- рево вершины, которая может служить корнем возможного изоморфного поддерева в Т2.
5.2.2. Термы, вхождения, подстановки и унификаторы 199 5.2. Задача унификации 5.2.1. Вводные замечания.Задача унификации возникает и изучает- ся во многих приложениях, таких как, например, доказательство теорем, логическое программирование, обработка естественных языков, вычис- лительная сложность и теория вычислимости. В наиболее общем виде задача унификации формулируется следу- ющим образом. По двум описаниям X и Y определить, можно ли найти объект Z, который удовлетворяет обоим описаниям? Эта задача обычно уточняется как задача нахождения по данным двум термам, содержащим переменные, такой подстановки термов вме- сто переменных, которая превратила бы исходные термы в идентичные. 5.2.2. Термы, вхождения, подстановки и унификаторы. Пусть S — алфавит, образованный элементами попарно непересекающихся мно- жеств переменных V и символов r-арных функций Sr, где г =0,1, ... — арность функции (количество ее ’’аргументов”). Элементы из So называ- ются константами. Множество термов T(S), переменных V(t) в терме /GT(S), вхож- дений O(t) подтермов в терм t G:T(S) и подтерм it и терма 1 GT(S) по некоторому вхождению и G О (О определяются следующими правилами:
200 5.2.2. Термы, вхождения, подстановки и унификаторы 1) если Z = x GV, то t G T(S), V(t) = {х}, O(t) = {e}, где e— пустая последовательность, и tie = х; 2) если t = f G So, то t G T(S), V(t) = 0, O(t) = {e} и tie = /; 3) если t = f(t{, ..., Zn), где f G Szl и zp ... ,tn G T(S), to t & T(S), f называется внешним (корневым) символом терма Z, п V(t) ==/У1У(^)’ 0(0 = № и : и е где iu обозначает конкатенацию i с последовательностью и, tlе = /(Zp ..., Z„), tliu = z/u. Для любых s, t GT(S) и и G O(t) через t[u *- $] обозначается терм, полученный в результате замены в терме t подтерма t/и на терм $. Пример. Рассмотрим терм t = f(h(g(x) ,у), у), Z, Л(у, z)). Здесь и в даль- нейшем х, у, z — переменные, &f,h,g,l — функциональные символы. Для t имеем V(t) = {х, у, z} и O(t) = {е, 1,2, 3,11, 12, 32, 31, 111}, причем tie = Z, z/1 =&(g(x),y), Z/ll =#(х), Z/111 = xhZ[3*- g(l) ]= f(h(g(x), y),l,g(l)). Терм t G T(S) называется линейным, если каждая переменная из V(t) встречается (текстуально) в терме t один раз (т.е. для любых и2 G G O(t), если t/ui G V, то tlu{ * t!и2), и замкнутым, если V(t) = 0. Отображение v : V Т(£) называется подстановкой. Подстановку v можно расширить на все множество термов T(S), определив отображе- ние v' следующим образом: 1) если t = х G V, tov'(Z) = v(x); 2) если Z = /G So, тоv'(t) =/; 3) если t = /(Zp ..., tn), где/G и tx, ..., tn G T(S), tov'(t) =/(v'(/1), ... ...,v'(/„)). Терм vf(t) называется результатом применения подстановки v к терму t и обозначается через tv. В дальнейшем будем рассматривать подстановки, не тождественные лишь на конечном числе переменных, и обозначать их в виде v = (xt <- tx, ... ..., xk *- tk) или v = {(Zp xp, ..., (tk, xj}, где Z, — термы, a xt — попарно различные переменные. Композиция двух подстановок Vj • v2 — это такая подстановка v3, что v3(Z) = vt(v2(t)) для всех Z G T(S). Два терма s и Z называются унифицируемыми, если существует такая подстановка v (так называемый унификатор), которая делает указанные два терма идентичными, т.е. sv = Zv. Унификатор v термов s и Z называет- ся их наибольшим общим унификатором (НОУ), если для любого друго- го унификатора 0 термов s и Z найдется такая подстановка у, что т] • v = 0. Если термы унифицируемы, то существует и единственен их наибольший общий унификатор. Пример. Термы $=/(х, g(a, у)) nt=f(h(z), g (v, у)) унифицируемы наибольшим общим унификатором v = {(h(z), х), (a, v)}. Термы 5 = f(g(a, у), х) и Z= f(h(z), g(v, у)) неунифицируемы.
5.2.3. Унификация как решение множества уравнений 201 5.2.3. Унификация как решение множества уравнений, формула ввда s = t, где s, t G T(S), называется уравнением (равенством), множество решений которого состоит из всех унификаторов термов snt. Унификатором множества уравнений s- = где j G [1 : к ], называет- ся любая подстановка v, которая является решением каждого уравнения множества. Два множества уравнений называются эквивалентными, если совпа- дают множества их унификаторов. Множество уравнений 5 находится в разрешенной форме, если каж- дое уравнение в S имеет вид х;= а каждая переменная х«, образующая левую часть одного из уравнений в S, не имеет других вхождений в термы из S. Множество уравнений S = {х; = : / G [1 : Л]}, представленное в раз- решенной форме, имеет унификатором подстановку v = {(/р xt), ..., (tk, х*)}, которая является наибольшим общим унификатором у S; любой другой унификатор а множества S может быть получен объединением v и а (т.е. сг = v U а), где а — подстановка, не затрагивающая переменных Хр ..., Пусть S — некоторое множество уравнений. Замена в S некоторого уравнения f(tv, ..., tn) = f(s{, ..., stl), где n > 0, на n уравнений tj = Sj,j G [ 1 : n ], называется редукцией термов. Если п = 0, то редукция термов означает простое удаление уравнения f = /. Пусть х = t — одно из уравнений S. Тогда переход от S к множеству уравнений, получающихся применением подстановки v = {(/, х)} ко всем термам уравнений, отличных отданного (без уничтожения уравнения х = t), называется преобразованием элиминации переменной. Справедливы следующие свойства. А. Пусть множество S содержит уравнение f(slt ..., sfl) = g(tJf ..., tm). Если g f, mo S не имеет унификатора; в противном случае S эквива- лентно множеству уравнений, получающемуся из S применением к дан- ному уравнению преобразования редукции термов. Б. Пусть S' — множество уравнений, полученное применением пре- образования элиминации переменной к некоторому уравнению х = t множества S. Если переменная х входит в терм t (но t не является переменной х), то S не имеет унификатора*, в противном случае S и S' эквивалентны. 5.2.4. Недетерминированный алгоритм решения множества уравнений. Задача Дано. Множество уравнений 5. Т ребуется. Перевести 5 в разрешенную форму. Решение проц НОУ (S: система уравнений) = 1. пока истинно условие применимости хотя бы одного из преобразований, перечисленных ниже цикл
202 5.2.4. Недетерминированный алгоритм решения множества уравнений 2. выбор любого из преобразований, условие применимости 3. которого истинно из Преобразование А: 4. если существует уравнение вида t = х, где t не является 5. переменной, ах — переменная то заменяется это уравнение на уравнение х = t 6. все, Преобразование В: 7. если существует уравнение вида х = х, где х — некоторая 8. переменная то удаляется это уравнение из S 9. все, Преобразование С: 10. если существует уравнение вида f = f', в котором t' и f' 11. не являются переменными то если корневые функции из термов f и t" различны 12. то возврат ’неудача’ 13. иначе осуществить преобразование редукции термов 14. все все, Преобразование D: 15. если существует уравнение вида х = t такое, что пере- 16. менная х не входит в другие уравнения системы S и терм t отличен от х то если переменная х входит в t то 17. возврат ’неудача’ 18. иначе осуществить преобразование элиминации переменной все все все все; 19.возврат ’успех’ все Пояснения. В качестве примера рассмотрим следующую систему уравнений: S = {#(х2) = хи х2) = /(g(x3), х4, х3)}. Возможна следующая последовательность шагов алгоритма. Приме- нение преобразования С ко второму уравнению преобразует S в множе- ство {g(x2) = xt, Xj = g(x3), Лир = x4, x2 = x3}. Это множество в результате применения преобразования D ко второму уравнению примет вид {#(х2)=#(х3), x^gUp, h(g(x3)) = х4, х2 = х3}. Затем можно применить пре- образование С к первому уравнению и преобразование А к третьему; в результате получается множество {х2 = х3, xt = g(x3), х4 = A(g(x3)), х2 = х3}. Наконец, применяя преобразование D к первому уравнению и преобра-
5.2.5. Мультиуравнения 203 зование В к последнему, можно получить {х2 = х3, х, = g(x3), х4 = h(g(x3))}, к которому уже ни одно из преобразований Л, В, С, D не применимо, и таким образом завершить выполнение алгоритма с успехом. Свойства. 1. Алгоритм останавливается всегда, вне зависимости от того, как реализуется выбор в операторе 2—18. 2. Алгоритм завершается с неудачей, если исходное множество урав- нений S не имеет унификатора. Если алгоритм завершается успехом, то S преобразуется в эквивалентное этой системе множество уравнений, имеющее разрешенную форму. 5.2.5. Мультиуравнения. Формула вида S = Af, где S — непустое мно- жество переменных, а М — произвольное семейство термов, отличных от переменных, называется мультиуравнением, левой частью которого яв- ляется S, а правой — М. Решением (унификатором) мультиуравнения S = М называется любая подстановка, делающая идентичными все тер- мы из S и А/. Например, мультиуравнение {хр х2, х3} = (Л(с), а) не имеет унификатора. Пусть SE — некоторое множество уравнений, и пусть отношение RSE на множестве пар термов определяется таким образом, что тогДа и только тогда, когда = t2 принадлежит SE. Говорят, что множество SE соответствует мультиуравнению S = М, если все термы_£Е принадле- жат S U Af и для всех tr, ts G S U Af справедливо t,RSEts, где RSE обозначает рефлексивное, симметричное и транзитивное замыкание отношения RSE. Например, множество уравнений {х, = х2, х3 = хр = хр х2 = /2, = /2} соответствует мультиуравнению {хр х2, х3} = (Zp Z2). Аналогичное опре- деление может быть сформулировано для множества мультиуравнений Z, если рассмотреть отношение Rz между парами термов, которые при- надлежат одному и тому же мультиуравнению. Множество_уравнений SE соответствует множеству мультиуравнений Z, если ttRSEt- тогда и только тогда, когда для любых термов Лиз SE и Z. 5.2.6. Преобразования мультиуравнений. Пусть М — семейство тер- мов (отличных от переменных или нет). Общей частью М называется терм, который получается путем совмещения всех термов из Af, начиная с их корня, и взятия той части, которая является общей для всех из них. Например, для семейства термов (/(хр g(a, f(x5, Z>))), /(Л(с), g(x2, j\b, x5))),/(A(x4), g(x6, x3))) общей частью является терм/(хр g(x2, х3)). Границей М называется множество мультиуравнений, в котором каж- дое мультиуравнение ассоциируется с некоторым листом общей части и состоит из всех подтермов (один для каждого терма из АО, соответству- ющих этому листу. Например, для описанного выше семейства термов граница имеет вид {{xj = (А(с), А(х4)), {х2, х6} = (а), {х3} = (/(х5, b),f(b, х5))}. Для нахождения общей части и границы множества термов Af можно воспользоваться следующей функцией (вычисляемый ею результат — это либо ’’неуспех”, если М не имеет ни общей части, ни границы, либо пара (С (АО, F(AO), где С (АО — общая часть Af, a F(M) — граница АО: функ ДЕС (Af: множество термов) = 1. если существует такой терм t в Af, который является переменной
204 5.2.7. Решение систем мультиуравнений 2. то пусть R обозначает мультиуравнение, чья левая часть — это множество всех переменных из Л/, а правая часть — семейст- во всех тех термов из М, которые не являются переменными; 3. возврат (/, R) 4. иначе если внешним символом всех термов из М является один и тот же функциональный символ / G Ап 5. то если п = 0. 6. то возврат (f, 0) 7. иначе если для всех i G [1 : п ] не является неуспешным применением функции ДЕС к множеству М-= U{/;: /=/(/р ..., Q GM} 8. то возврат ),..., С (Л/н)), U{F(M,) : / G [1 : п ]}> 9. иначе возврат ’неуспех’ все все 10. иначе возврат ’неуспех’ все все все Пусть Z — множество мультиуравнений, содержащее такое муль- тиуравнение 5 = Л/, что М не является пустым и имеет общую часть С и границу F. Тогда редукция мулыпиуравнения S = Mb Z состоит в перехо- де к такому Z', что Z' = (Z - {S = Л/}) U {S = (С)} U F. Справедливо следующее свойство. Пусть S — М, где Л/ # 0 — некоторое мультиуравнение из множе- ства Z. Если М не имеет общей части либо некоторая переменная из 5 входит в левую часть некоторого мультиуравнения границы Fсемейст- ва М, то Z не имеет унификатора*, в противном случае Z эквивалентно множеству Z’, получаемому из Z редукцией мультиуравнения 8 = М. Множество мультиуравнений Z называется компактным, если мно- жества левых частей уравнений из Z попарно не пересекаются. Пусть Z — некоторое некомпактное множество мультиуравнений и пусть R — отношение между парами уравнений из Z такое, что (S = M)R(S' = Л/') 5 A S' = 0 и R— транзитивное замыкание R. Пере- ход от Z к эквивалентному ему множеству Z', в котором слиты (путем объединения их левых и правых частей) все уравнения, принадлежащие одному и тому же классу эквивалентности относительно R, называется преобразованием компактификации. 5.2.7. Решение систем мультиуравнений. Системой мультиуравне- ний R называется пара (7, U), в которой Т является такой последова- тельностью, a U таким (возможно пустым) множеством мультиуравне- ний, что справедливы следующие три свойства: — множества переменных, образующих левые части всех мультиурав- нений как в Т, так и в U, содержат все переменные и не пересекаются; — правые части всех мультиуравнений в Т состоят из не более чем одного терма;
5.2.7. Решение систем мультиуравнений 205 — переменные, входящие в левую часть некоторого мультиуравнения из Г, могут входить в правые части только таких мультиуравнений из Т, которые предшествуют данному. Алгоритм решения некоторой данной системы мультиуравнений R работает следующим образом. Начиная вычисление с пустой части Т и выполняя на каждом шаге "перемещение” некоторого мультиуравнения из {/-части, являющейся неразрешенной частью системы R, в Т-часть, которая называется триангулярной (разрешенной) частью R, алгоритм завершает свою работу в тот момент, когда пустой становится {/-часть системы R. В этот момент система, по существу, решена, поскольку ее решение получается обратной подстановкой переменных. Следует за- метить, что хранение разрешенной системы в триангулярной форме поз- воляет эффективно осуществлять унификацию даже тогда, когда наи- больший общий унификатор имеет размер, экспоненциальный относи- тельно размера исходной системы. Например, наибольшим общим уни- фикатором системы {{х,} в0, {х2} =0, {х4} = (Л(х3, Л(х2,х2)), h(h(h(xi9 Xj), х2), х3)), {х3} =0} является {(Л(хр х,), х2), (Л(Л(хр х,), Л(хр х^), х3), (Л(Л(Л(хр хр, Л(хр хр), Л(Л(хр Xj), Л(Хр х,))), х4)}. Однако мы можем дать эквивалентную разрешенную систему с пустой {/-частью, у которой Т-часть имеет вид ({х4} = (Л(х3, х3)), {-х3} « (Л(х2, х2)), {х2} = = (Л(Хр Xj)), {xj =0) и может использоваться для получения наиболь- шего общего унификатора с помощью обратной подстановки. функ РЕШЕНИЕ (Z: множество мультиуравнений) ; 1. Пусть R = (Т, U) — система мультиуравнений, в которой Т = 0 и {/ = Z; 2. повторять 3. Пусть S = M — такое мультиуравнение в {/, что А/ # 0; 4. Вычислить общую часть С и границу F множества М; 5. если левые части границы F содержат некоторую переменную из S 6. то возврат ’неудача’ все; 7. Преобразовать {/, осуществляя в нем редукцию выбранного мультиуравнения и его компактификацию; 8. Пусть S = {хр ..., хп}. Применить подстановку v = {(С, Xj),..., (С, х„)} ко всем термам правых частей мультиуравнений Г; 9. Перенести мультиуравнение S = (С) из U в конец Г; 10. до {/-часть системы R содержит только такие уравнения, если они есть, у которых пустые правые части все 11. Перенести все мультиуравнения из U (все с М = 0) в конец Г; 12. возврат ’успех’ все Понятно, что для того, чтобы использовать алгоритм для унификации двух термов и t2, следует построить начальную систему мультиурав- нений {{х} = (Гр /2), {xj =0, {х2} =0, ..., {хл} =0}, гдехр ..., хп — все переменные, входящие в и Г2, а х — новая переменная, не имеющая вхождений в Zj и Г2.
206 5.2.7. Решение систем мультиуравнений Например, в процессе обработки термов =/(х,, g(x2, х3), х2, Ь) и « =/(#(Л(а, х5), х2), л,, h(a, х4), х4) алгоритм проходит следующие состоя- ния. Начальная система мультиуравнений R имеет вид: U: {{х} = </(х,, §(хг, х3),х,, A),/(g(A(a, х5) х2), х(, h(a, х4), х4)), {хД = 0, {хД = 0, {х,} = = 0, U4}=0, {хД=0}; Г: О. После первой итерации цикла 2—10 она примет вид U : {{*.} = (g<h(a, х.), х,), g(x,, х,)>, {х,} = (Л(а, х4)), W = 0, {х4} - (Ъ), {х5}=0}; Т : ({х} = </(х,, х(, х2, х4))). Элиминация переменной х2 приводит к U: {{хД - (g(h(a, х5), h(a, xj),g(h<a, х4), х3)), {х3}=0, {х4} = (й), {хД -0); Г : ({х} = </(Хр Хр х2, х4)), {х2} - (Л, (а, х4)>). Элиминация переменной х, преобразует R к виду U : {{х3} = h(a, х4>), {х4, х5} = (А)}; Т : ({х} = </(Хр Хр х2, х4)), {хД -Л(а, х4)), {-*,} = g(h(a, х4), х3)>). Наконец, путем элиминации сначала множества {х4, х5}, а затем {х3} R принимает разрешенную форму t/:0; Г : ({х} = </(Хр Хр х,, х4>), {х3} = (й(а, х4)>, Ц} = (g(h(a, х4), х3)), {х4, хД = (Л), {хД = h(a, b)>). Справедливо следующее свойство. А. Алгоритм РЕШЕНИЕ всегда останавливается. Если он завер- шается с неудачей, то исходная система не имеет унификатора. Если же он завершается с успехом, то результирующая система эквивален- тна исходной системе и имеет пустую неразрешенную часть. Пусть R — некоторая система мультиуравнений и пусть Vv — под- множество переменных, полученное объединением всех левых частей S,
5.2.7. Решение систем мультиуравнений 207 мультиуравнений в {/-части системы R. Поскольку множества S- попарно не пересекаются, они определяют разбиение множества Уи. Отношение <* определяется как транзитивное замыкание отношения <, удовлетворя- ющего следующему свойству: для любых двух частей S2 и S. справедливо Sf < Sy тогда и только тогда, когда найдется такая переменная в Sf, кото- рая входит в некоторый терм правой части мультиуравнения, левой частью которого является Sy. Справедливы следующие свойства: Б. Если система R имеет унификатор, то<* является отношением частичного упорядочения. В. Если система R имеет унификатор и ее U-часть не является пустой, в R существует мультиуравнение S-М такое, что перемен- ные из S не имеют других вхождений в U. функ УНИФИКАЦИЯ (R : система мультиуравнений) = 1. Пусть/?- (Т, U); 2. повторять 3. если в U не существует такого мультиуравнения S = М, что переменные из S не имеют других вхождений в U 4. то возврат ’неуспех’ 5. иначе выбрать одно из таких мультиуравнений S = М все; 6. если М = 0 7. то перенести это мультуравнение из U в конец Т 8. иначе если М не имеет общей части 9. то возврат’неудача’ 10. иначе вычислить общую часть С и границу /'для М все; 11. Преобразовать U, используя редукцию по выбранному мультиуравнению и компактификацию; 12. Перенести мультиуравнение S = (С) из U в конец Т все 13. до часть U системы R является пустой все; 14. возврат ’успех’ все Функция УНИФИКАЦИЯ является таким уточнением недетермини- рованной функции РЕШЕНИЕ, в котором за счет подходящего выбора, обрабатываемого в цикле 2—10 мультиуравнения S = А/,ликвидируются операторы 8 и 5. Следует заметить, что оператор 8 функции РЕШЕНИЕ наиболее трудоемкий в ней и может осуществлять многократное копи- рование больших термов. В процессе применения функции УНИФИКАЦИЯ к системе, на ос- нове которой демонстрировалась работа функции РЕШЕНИЕ, сначала элиминируется переменная х, затем переменная хр далее переменные х2 и х3 вместе и, наконец, переменные х4 и х5 вместе. В результате система примет вид {/: 0 Г : ({х} = </(хр хр х2, х4)),
208 5.2.8. Эффективный выбор мулыиуравнения {*,} - (g(xv х3)), {х2, х3} « (Л(а, х4)), {х4, х5} - (Ь)). Следует отметить, что это решение, полученное функцией УНИФИ- КАЦИЯ, является более точным, чем полученное с помощью функции РЕШЕНИЕ. Во-первых, выяснено, что переменные х2 и х3 эквивалент- ны, а во-вторых, правая часть с переменной х, более факторизована. Этот результат не является случайным, а присущ алгоритму УНИФИ- КАЦИЯ.' Суммируя, можно сказать, что алгоритм УНИФИКАЦИЯ основыва- ется на двух идеях: хранения решения в факторизованной форме и выбо- ра на каждом шаге такого мультиуравнения, чтобы совсем не требова- лось подстановок. В силу этого размер результирующей системы не мо- жет превысить ее начальный размер. Более того, операция выбора муль- тиуравнения завершается неудачей, если есть циклы среди переменных; и таким образом, так называемая проверка вхождений встраивается в алгоритм вместо того, чтобы выполняться на последнем шаге алгоритма, как это имеет место в других алгоритмах. 5.2.8. Эффективный выбор мультиуравнения. Эффективная реали- зация операции выбора мультиуравнения, ’’головного” в смысле частич- ного упорядочения (оператор 2—5 функции УНИФИКАЦИЯ), заданно- го на мультиуравнениях, может быть осуществлена, если ассоциировать с каждым мультиуравнением специальный счетчик для хранения-числа других вхождений в U переменных его левой части. Этот счетчик ини- циализируется путем начального сканирования всей {/-части. Понятно, что то мультиуравнение, у которого счетчик равен нулю, является голо- вным относительно частичного упорядочения. Например, для системы R, рассмотренной ранее, имеем LZ : {[0]{х} = (/(хр g(xv х3), х2, b).f(g{h(a, х5), Х2), Хр Л(<7, х4), х4)), [2]{x1}s0, [3]{xJ«0, (1]{Л'3}=0, [2]{х4}=0, [1]{х5}=0; Т: (). Здесь счетчики, ассоциированные с мультиуравнениями, заключены в квадратные скобки. Поскольку только у первого мультиуравнения счетчик равен нулю, оно и выбирается оператором 2—5. Счетчики дру- гих мультиуравнений очевидным образом изменяются (уменьшаются) в тот момент, когда некоторое вхождение соответствующей переменной возникает в левой части мультиуравнения границы, вычисленной опера- тором 8—10. Когда два или больше мультиуравнения из U сливаются в про- цессе компактификации, счетчик, ассоциируемый с новым мультиурав-
5.2.9. Улучшение алгоритма унификации при обработке («унифицируемых данных 209 нением, очевидно устанавливается равным сумме значений счетчиков сливаемых мультиуравнений. Следующие шаги алгоритма приводят к системе вида U: {10]{Х|} - х5), х2), g(x2, х3)), [2] {х2} “ (Л(а, х4)), [1]{х3}-0, [1 ] {х4} - (Ь), [1]{х5}«0}; Г : ({х} в (/(Хр хр х2, х4))). U : {[0] {х2, х3} = (Л(а, х4), Л(я, х5)), [l]{x4J-(W, [1]{х5}«0}; т : ({х} я (/(хр Хр х2, Х4)), {*1} w <#(*2’ U : {[0] {х4, х5} я (/>)}; Т : ({х} s </(Хр Хр х2, х4)), {•М в <^2’ ^з^» {х2, х3} « (Л(л, х4))). U : 0; Т : ({х} = </(Хр Хр х2, х4», {*1} “ <^2» {х2, х3} « (Л (а, х4)), {х4, х5} «(&)). . 5.2.9. Улучшение алгоритма унификации при обработке неунифицируемых данных. В случае неуфицированных данных результатом алгоритма УНИФИКАЦИЯ является неуспех, выданный оператором 4, если най- ден цикл, либо оператором 9, если возникает несовместимость. Неудачу последнего вида можно обнаружить на более ранней стадии унификации без изменения структуры алгоритма. Введем следующее определение. Два терма называются согласован- ными тогда и только тогда, когда либо хотя бы один из них является переменной, либо они оба нетривиальные термы, имеющие один и тот же корневой символ и попарно согласованные аргументы. Термы, число ко- торых больше двух, называются согласованными. если они все попарно согласуются. Например, три терма/(х, g(a. у)),/(А, х) и/(х, у) согласуют- ся, но не являются унифицируемыми. Можно рассмотреть такую модель алгоритма УНИФИКАЦИЯ, в ко- торой для каждого мультиуравнения все термы, находящиеся в его пра- вой части, согласуются. Эта новая версия является корректной, посколь- ку, если найдется пара несогласуемых термов в одном и том же мульти- уравнении, эти термы никогда не унифицируются. Действуя этим способом, имеющиеся несоответствия алгоритм обна- ружит на более ранней стадии. Действительно, функция УНИФИКА-
210 5.2.9. Улучнюнрюалгоррп^унификац^ при обработке неунифицируемых данных ЦИЯ может обнаружить несоответствие лишь в момент вычисления об- щей части и границы правой части выбранного мультиуравнения, в то время как в новой версии это несоответствие обнаруживается на фазе компактификации, осуществляемой на предыдущей итерации основ- ного цикла. Для эффективной реализации проверки согласованности при слия- нии двух мультиуравнений можно использовать представление правых частей мультиуравнений в виде мультитермов, определяемых по следу- ющим правилам. Мультитерм либо является пустым, либо имеет вид /(Рр ...» Рл), где /Е2И и Р., i G [1 : п ], есть пара (S,, А/}, состоящая из множества пере- менных S; и мультитерма которые не являются пустыми одновремен- но. Например, семейство термов (/(х, g(a, у)), f(b, х), F (х, у)) можно представить мультитермом /<<W. Ь), {х, y},g<{0, а), <{у}, 0))). Представление правых частей таким способом не приводит к потере информации, поскольку единственными операциями, которые необхо- димо выполнять над правыми частями, являются операция слияния двух правых частей и операция вычисления общей части и границы, а их можно переформулировать следующим образом: функ СЛИТЬ (Ml, М2 : мультитерм) = 1. выбор Ml из 2. 0: возврат М2; 3. г«5*„ М\)....: 4. выбор М2 из 5. 0: возврат Ml; 6. /«St .... (S’.Af-)): 7. если/ -f и для всех i G [1 : и] слияние СЛИТЬ (М*, М^) не завершается неудачей 8. то возврат/(($; U Sj, СЛИТЬ (Mj, М2)),..., (S' U S2, СЛИТЬ (Mt М2))) 9. иначе возврат ’неудача’ все все все все; функ ОБЩАЯ-ЧАСТЬ(М : мультитерм) = 1. ПустьМ = /«S1,M1), ...,(5Л, Мл»; 2. для всех i из [1 : п ] цикл 3. если S- = 0 то
5.2.10. Алгоритм проверки унифицируемости 211 4. 7», :«• ОБЩАЯ-ЧАСТЬ (Л/,) 5. иначе Р(- := э S,. все все; 6. возврат/(Рр ..., Рн) все; функ ГРАНИЦАСЛ/: мультитерм) = 1. ПустьМ=/«5p MX ..., (Sn, Мц)); 2. для всех / из [1 : п j цикл 3. если 5 =0 то 4. Fj := ГРАНИЦА(Mz) 5. иначе F. := {£. = д/.} все все; 6. возврат Fj U F2 U ... U Ftl все Следует отметить, что общая часть и граница определяются только для непустых мультитермов и они всегда существуют. 5.2.10. Алгоритм проверки унифицируемости, основанный на пред- ставлении термов дэгами. Естественно представлять термы ориентиро- ванными деревьями, вершины которых помечены переменными и симво- лами функций. Однако при таком представлении экспоненциально рас- тет размер деревьев, которые можно ожидать в качестве результата уни- фикации. Например, множество пар термов {(Лл-,, х,), х2), {F(x2, х,), х3), <F(x„_p xn.,), x,,)} унифицируемо, но образ хп в наибольшем унификаторе — это терм, получаемый последовательностью подстановок хп *- F(xn_v х <- «- F(xn_2, хп_Х..., х2 F(xv хр и, таким образом, содержащий^'- вхож- дений хг Более экономное представление множества унифицируемых термов основывается на ориентированных ациклических графах (дэгах), позво- ляющих представлять единственным подграфом общие подвыражения термов. Например, множество пар термов {<f’(xl, х2), F(G(x2), G(x3»)} и их наибольший общий унификатор представляются дэгами F
212 5.2.10. Алгоритм проверки унифицируемости В дэге вершина, помеченная Л-арным функциональным символом (к > Обмазывается функциональной вершиной и имеет степень исхода Л; при к > 1 исходящие из нее дуги различаются, а вершины, в которые они заходят, называются соответственно первым сыном, вторым сыном и т.д. Вершина, помеченная переменной, называется переменной вершиной и имеет степень исхода 0; в дэге есть только одна переменная вершина для каждой переменной. Любая вершина дэга, не имеющая заходящих дуг, называется корнем. Отношение эквивалентности, заданное на вершинах дэга, называется допустимым, если справедливы следующие три условия: — соответствующие сыновья двух функциональных вершин попарно эквивалентны; — каждый класс эквивалентности является гомогенным, т.е. он не содержит двух вершин с различными функциональными символами; — классы эквивалентности могут быть частично упорядочены час- тичным порядком на дэге. Первые два из этих условий гарантируют то, что при стягивании каждого класса эквивалентности в вершину результирующий редуци- рованный граф может быть согласованно помечен символами подходя- щей арности, а последнее — это условие ацикличности редуцированного графа. Справедливо следующее свойство. А. Вершины и и v унифицированы тогда и только тогда, когда и = v для некоторого допустимого отношения эквивалентности. Если это так, то имеется единственное минимальное допустимое отношение эквивалентноет и. На его основе можно сформулировать следующий алгоритм проверки унифицируемости двух термов: функ ТЕСТ (и, v: терм) « 1. Представить и и удэгом и установить и s у; 2. пока существует в дэге такая пара вершин и и у, что и = у и для некоторого i нет отношения эквивалентности между /-ми сыновьями и' и у' вершин и и у 3. цикл установить, что и’ = у' все; 4. если отношение эквивалентности ”= ” допустимо 5. то возврат ’унифицируемы’ 6. иначе возврат ’неунифируемы’ все все Корневой класс — это класс эквивалентности вершин дэга, содер- жащий только корни. Справедливо следующее свойство. Б. Любое непустое отношение эквивалентности, удовлетворяю- щее третьему условию в определении допустимости, имеет корневой класс. На основе свойства Б алгоритм проверки унифицируемости можно переформулировать следующим образом:
5.2.11. Линейный алгоритм унификации Патерсона—Вегмана 213 функ ТЕСТ l(u, v: терм) = 1. Построить дэг по и и v и установить и = v; 2. НОУ = 0; % наибольший общий унификатор % 3. пока существует корневой класс R цикл 4. если R не гомогенный то 5. возврат ’неунифицируемы’ все; 6. Пусть R - {гj,..., rk), где, если R содержит функциональную вершину, то rj является функциональной вершиной; 7. для i от 2 до Л цикл 8. если г. является переменной вершиной то 9. НОУ*- 10. иначе для /от 1 до I ИСХОД (q) I цикл 11. Установить эквивалентность у-х сыновей вершин г. и q все все все; 12. Уничтожить все вершины из R вместе с исходящими из них дугами все; 13. если остались дуги то возврат ’неунифицируемы’ 14. иначе возврат ’унифицируемы’ все все 5.2.11. Линейный алгоритм унификации Патерсона—Вегмана. Задача Объекты. Рассматриваются дэги, представляющие термы (см. п. 5.2.10). Каждой вершине дэга сопоставляются следующие атрибуты: СИМВОЛ, значением которого является функциональный символ или символ переменной; УКАЗ, значением которого является имя любой вер- шины; ОТЦЫ, представляющий собой список отцов вершины; ДУГИ, являющийся списком неориентированных дуг, инцидентных данной вер- шине, а также (если вершина функциональная) атрибут СЫНЫ, пред- ставляющий собой массив имен сыновей вершины. При этом каждая вершина и каждая дуга дэга могут находиться в одном из двух состояний: ’’существует” и ’’удалена”. Операции. Операция СОЗДАТЬ-ДУГУ соединяет неориен- тированной дугой две указанные вершины дэга, а операции УДАЛИТЬ- ДУГУ и УДАЛИТЬ-ВЕРШИНУ переводят в состояние ’’удалена” соот- ветственно указанную неориентированную дугу или указанную верши- ну вместе с индидентными ей дугами. Дано. У любой вершины не определено значение атрибута УКАЗ и пуст список ДУГИ; выделены две вершины и и v.
214 5.2.11. Линейный алгоритм унификации Патерсона—Вегмана Т ребуется. Проверить, являются ли унифицированными термы, соответствующие деревьям с корнями и и у, а в случае их унифици- руемости построить наибольший общий унификатор. Решение Программа: проц ФИНИШ (г: вершина) « 1. 2. 3. 4. 5. 6. 7. S : стек вершин « 0; если г.УКАЗ Q то вывод (’неудача : цикл’); стоп иначе г.УКАЗ :« г, S г; пока S *_0 цикл s :вэ5; если /-.СИМВОЛ и ^.СИМВОЛ — различные функцио- нальные символы 8. 9. 10. то вывод (’неудача : конфликт’); стоп все; для всех существующих t из 5.ОТЦЫ цикл ФИНИШ(/) все; 11. 12. 13. 14. пока существует (s, t) из ДУГИ($) цикл если /.УКАЗ = Q то /.УКАЗ := г все; если /.УКАЗ # / то вывод (’неудача : цикл’); стоп все; 15. УДАЛИТЬ-ДУГУ($, /); S *- / все; 16. 17. 18. 19; если s # г то если ^.СИМВОЛ — переменная то ВЫВОД ($, г) иначе для /от 1 до 1 ИСХОД (s) 1 цикл 20. СОЗДАТЬ-ДУГУ (г.СЫНЫ [/], 5.СЫНЫ [/ ]) все; 21. УДАЛИТЬ-ВЕРШИНУ($) все все все; 22. УДАЛИТЬ-ВЕРШИНУ(г) все все; проц TECT2(u, v: вершина) « 1. Пусть ФВ и ПВ — списки функциональных и переменных вершин соответственно; 2. СОЗ ДАТЬ-ДУ ГУ (u, v); 3. пока существует г из ФВ цикл ФИНИШ (г) все; 4. пока существует г из ПВ цикл ФИНИШ (г) все; 5. вывод (’унифицируема’) все
5.2.11. Линейный алгоритм унификации Патерсона—Вегмана 215 Пояснения. Данный алгоритм является уточнением алгоритма ТЕСТ, описанного в п. 5.2.10. Основные шаги алгоритма при обработке пары термов {{А(В(у), С (и, v)), C(w, D(x, у)))} выполняются в следующей последователь- ности. Вначале создается дэг и добавляется неориентированная дуга, со- единяющая корни: Предположим: D(x, у) — первая встреченная функциональная вершина, что отражается в иллюстрирующих рисунках добавлением числа 1 в ка- честве верхнего индекса пометки этой вершины (см. ниже). Тогда указа- тель вершины устанавливается на нее самое, и осуществляется переход к ее отцу С путем рекурсивного общения к процедуре ФИНИШ. Затем указатель вершины С метится числом 2, и опять происходит рекурсивное обращение для исследования А, отца вершины С, помечающее А числом 3. (Здесь выбираются числа в качестве указателей в силу их единствен- ности.) Так как у А нет отца, происходит переход к другой вершине А и приписывание ей числа 3. Проводятся неориентированные дуги между соответствующими их сыновьями, удаляются вершины А вместе со всеми инцидентными им дугами (удаляемые вершины зачеркиваются, а удаля- емые дуги изображаются штриховыми линиями): Поскольку завершается вызов ФИНИШ (Л), происходит возврат к обработке класса эквивалентности, который в конечном итоге пометится числом 2. Осуществляется переход к другой вершине С, рисуются нео- риентированные дуги между соответствующими сыновьями, удаляются вершины С вместе с инцидентными им дугами:
216 5.2.11. Линейный алгоритм унификации Патерсона—Вегмана Происходит возврат к вершине D. Осуществляется прохождение к у, но перед уничтожением вершины v рассматривается ее отец. Этот шаг ал- горитма необходим, чтобы не пропустить тот факт, что D и у должны унифицироваться с и и и>. Он завершается следующим состоянием: Наконец, заканчивается обработка того первого класса, с которого все началось, а также классов, содержащих х и у:
5.2.12. Алгоритм Уэ 217 Свойство. Временная сложность алгоритма ТЕСТ2 является ли- нейной по отношению к ’’вершины + дуги’’ дэга. 5.2 Л2. Алгоритм Уэ. Задача Объекты. Рассматриваются дэги, представляющие термы. Каждой вершине сопоставляются следующие атрибуты: СИМВОЛ, значением которого является функциональный символ или символ переменной; КЛАСС, значением которого является имя вершины, представляющей класс эквивалентности, содержащий данную вершину, и называемой корневой вершиной класса эквивалентности, представленного ею; а так- же, если вершина функциональная, атрибут СЫНЫ, представляющий собой массив имен сыновей данной вершины. Дано. У любой вершины не определено значение атрибута КЛАСС; зафиксированы две вершины и г2. Т ребуется. Проверить, являются ли унифицируемыми термы, соответствующие вершинам и /2, ив случае положительного ответа на этот вопрос построить наибольший общий их унификатор. Решение Программа функ ТЕСТЗОр t2 : вершина) « 1. ПАРЫ: стек « {(Гр Г2>); 2. для всех вершин z цикл г.КЛАСС :- z все; 3. пока ПАРЫ * 0 цикл 4. (х,у) ПАРЫ; и :в найти х; v :в найти у; 5. если и # у то 6. если «.СИМВОЛ и у.СИМВОЛ — различные функцио- нальные символы 7. то возврат ’неудачажонфликт’ 8. иначе слить и с у; 9. если и.СИМВОЛ — переменная то и.КЛАСС :в у все; 10. если ни «.СИМВОЛ, ни у.СИМВОЛ не являются переменными 11. то для j от 1 до I ИСХОД (5) I цикл 12. ПАРЫ («.СЫНЫ [у], у.СЫНЬК/]) все все все все все; 13. Сформулировать новый граф, образованный из корневых вершин классов эквивалентности; этот граф является результатом унификации; 14. если граф имеет цикл то 15. возврат ’неудача : цикл’
218 5.2.13. Сравнение алгоритмов унификации 16. иначе возврат’унифицируемы’; 17. % Наибольшим общим унификатором является подста- новка а, которая каждой переменной сопоставляет корневую вершину класса эквивалентности, содержащую переменную % все все ' Пояснения. Алгоритм Уэ является уточнением функции ТЕСТ; он поддерживает множество классов эквивалентности с помощью набо- ра, позволяющего хранить непересекающиеся множества и эффективно выполнять операции слить и найти. Сначала каждая вершина образует свой собственный класс, а затем в процессе унификации некоторые из классов объединяются. Если вершины, чьи классы должны объединяться, имеют разные функциональные символы, возникает конфликт, означа- ющий неунифицируемость термов. В конце концов, если процесс завер- шается, классы эквивалентности, разбивающие множество всех вершин, формируют редуцированный граф, который является результатом уни- фикации. Свойство. Временной сложностью алгоритма Уэ является О(м • а(л)>, где п — количество вершин, а а (и) — очень медленно расту- щая функция Тарьяна. 5.2 .13. Сравнение алгоритмов унификации. Описанный в пп. 5.2.3 — 5.2.9 алгоритм УНИФИКАЦИЯ не является линейным (его временная сложность — О(п + т logm), где п — суммарное количество символов в унифицируемых термах, а т — число различных переменных в этих термах) и поэтому уступает по оценкам как алгоритму Уэ, который име- ет почти линейную сложность, так и алгоритму Патерсона—Вегмана, который является линейным, т.е. теоретически наилучшим. Вместе с тем в ряде практических приложений, как показывает сравнение этих трех алгоритмов, более эффективным оказывается алгоритм УНИФИКАЦИЯ. Нетрудно видеть, что рассмотрение алгоритмов Уэ и Патерсона—Вег- мана как алгоритмов решения уравнений приводит к следующей их фор- мулировке. Оба алгоритма являются некоторыми уточнениями алгорит- ма РЕШЕНИЕ и работают с множествами мультиуравнений таких, что их левые части попарно не пересекаются, а правые состоят из единствен- ного терма глубины один, имеющего вид /(хр ..., хм), где х15 ..., хн — переменные. Например, {Л-,} =/(лг, Л-3, х4); {л'2} = й; {r3} = g(x2); {*4} = й; {Х6} = й; {.r7} =g(x8); {х8}=0.
5.2.13. Сравнение алгоритмов унификации 219 Кроме того, рассматривается множество уравнений S, в каждом из которых обе части образованы переменными; например, S : {jq = х5}. Шаг выполнения любого из алгоритмов состоит в выборе одного урав- нения из S, слияния двух соответствующих мультиуравнений и добав- ления новых уравнений, полученных в результате слияния. Например, после первого шага вычисляется {•*!> х$} “ /Cv2, х3, х4), {*2} = {х3} = g(x2); {*4} в я; W в {х7}=Д); U8}=0. S : {л-2-х6,л-3 = х7,х4 = л'8}. Алгоритм различается способом выбора уравнения из S. В алгоритме Уэ S является списком; на каждом шаге выбирается первый элемент из списка, а новые уравнения добавляются в конец списка S. Алгоритм останавливается, когда S является пустым, и достигает этого состояния без проверки отсутствия циклов. Таким образом, имеется последний шаг, на котором проверяется, являются ли результирующие мульти- уравнения частично упорядоченными. Источник нелинейного поведения этого алгоритма тот же, что и в алгоритме УНИФИКАЦИЯ: доступ к мультиуравнениям после их сли- яния. Чтобы избежать этого, Патерсон и Вегман выбирают для слияния два мультиуравнения только тогда, когда их переменные в дальнейшем не доступны. Например, из описанного выше состояния алгоритм Патер- сона—Вегмана переходит к Ц,Л'5} =./(х5,л3,х4); {*,} “ а; {х3, л-7} -g(x2); {*<} ш а; 41 = Ц} = 0; S: {x2-x,,x2-x4,x4-x8}, выбирая уравнение л3 s х7, поскольку х2 и х8 еще доступны из третьего и шестого мультиуравнений соответственно. Для того чтобы выбрать мультиуравнения для слияния, этот алгоритм ’’поднимается" по частичному упорядочению мультиуравнений до тех пор, пока не находит мультиуравнения, находящегося ’’наверху". Таким образом, обнаружение циклов присуще этому алгоритму. Для сравнения рассмотрим, как работает алгоритм УНИФИКАЦИЯ для того же примера. Начальная система мультиуравнений примет вид
220 5.2.13. Сравнение алгоритмов унификации и . { [0] {х,, xs} “/(«х2, х6}, 0), <{х3, X,}, 0), <{х4, х8}, 0)) [2]{хг}-а, 0)), [1 ] {х4} - а, [1] W-^({x8}, 0)), [2]{х8}=0}; Т: О. На следующем шаге: и.{ [1]{х2,х6}-а, [0 ] {*з> -«7} = g({{x2, Х8}, 0>), [1 ] {х4, х8} - а}-, Т А {х,,х5} “/(х2,х3,х4)), и т.д. В этом алгоритме уравнения, содержащие те пары переменных, кото- рые будут унифицироваться, хранятся в мультиуравнениях, и слияния осуществляются до элиминации соответствующего мультиуравнения. Важным отличием алгоритма УНИФИКАЦИЯ от двух других явля- ется то, что он может использовать термы произвольной глубины. Это приводит к некоторому выигрышу с точки зрения эффективности, пос- кольку очевидно проще вычислять общую часть и границу глубоких тер- мов, чем последовательно сливать мультиуравнения. Следует отметить, однако, что эти возможности можно также добавить к другим ал- горитмам. Например, путем добавления к алгоритму Патерсона — Вег- мана способности обрабатывать глубокие термы можно получить линей- ный алгоритм Мартелли—Монтанари. Для того чтобы сравнить характеристики трех алгоритмов, следует отметить, что каждый из алгоритмов может завершить свою работу либо успешно, либо с неудачей из-за обнаружения цикла или несогла- сованности. Пусть рс и pt обозначают вероятности остановки ал- горитма по этим трем событиям соответственно. Возможны три крайних случая. ' Случай 1: рт » рс, р,, т.е. очень высока вероятность успешного завершения алгоритма. Асимптотически наилучшим является алгоритм Патерсона—Вегмана, поскольку он имеет линейную временную слож- ность, а два других алгоритма — сравнимую нелинейную сложность. Однако в типичных приложениях, таких как, например, доказательство теорем, алгоритм унификации не используется для обработки очень больших термов, но для унификации небольших термов в каждой задаче применяется многократно. В этом случае асимптоматически растущее различие между линейным и нелинейными алгоритмами не столь суще- ственно, и вычислительные сложности трех алгоритмов будут сравни- мыми в зависимости от эффективности реализации.
5.2.13. Сравнение алгоритмов унификации 221 Экспериментальное сравнение трех алгоритмов между собой, выпол- ненное в [42], осуществлено для реализации их на языке Паскаль с использованием подобных структур данных. На пяти различных классах унифицируемых тестовых данных, для которых проводилось сравнение, наименьшее время работал алгоритм УНИФИКАЦИЯ. Это объясняется тем, что он в отличие от алгоритма Уэ не выполняет в конце проверку ацикличности и использует более простые структуры данных, чем ал- горитм Патерсона—Вегмана. Случай 2: рс » р{ » рш, т.е. очень высока вероятность обнару- жения цикла. Алгоритм Патерсона—Вегмана является наилучшим, пос- кольку он начинает сливать два мультиуравнения только тогда, когда уверен, что среди них нет циклов. Также хорош алгоритм УНИФИКА- ЦИЯ, поскольку обнаружение цикла в него встроено. В отличие от них алгоритм Уэ должен завершить все слияния прежде, чем он будет в сос- тоянии обнаружить цикл, и, таким образом, он имеет очень низкую производительность. Случай 3: pt » рс » р,„, т.е. очень высока вероятность обнару- жения несогласованности. Алгоритм Уэ является наилучшим, поскольку он останавливается при обнаружении несогласованности без каких-ни- будь затрат на обнаружение цикла. Алгоритм УНИФИКАЦИЯ в этом случае эффективней алгоритма Патерсона—Вегмана, так как несогласо- ванности обнаруживаются им во время слияния мультиуравнений и не- которые мультиуравнения он сливает ранее (подобно {л*2, х6} и {л*4, х8} в описанном выше примере). С другой стороны, те слияния, которые осу- ществляются алгоритмом УНИФИКАЦИЯ в процессе размещения их в мультитермах, не могут быть выполнены другим алгоритмом, так как они ссылаются на мультиуравнения, которые еще доступны. Это раз- личие в производительности двух алгоритмов может быть очень боль- шим, если разрешены термы любой глуоины. 5.3 . Системы переписывания термов 5.3.1. Вводные замечания. Теория СПТ — систем переписывания (подстановок) термов — является мощным и удобным формальным ап- паратом, получившим все более широкое применение для решения раз- личных задач математики и программирования. Изучение СПТ берет начало от классической задачи алгебры, получившей название проблемы тождеств и связанной с построением разрешающих алгоритмов для эк- вациональных (алгебраических) теорий, формулами которых служат ра- венства термов. В дальнейшем сфера применения СПТ расширилась на теории первого порядка, началось использование методов СПТ для авто- матического доказательства теорем, имеющего многочисленные прило- жения в программировании: искусственном интеллекте, логическом про- граммировании и т.д. Алгебраические методы спецификации, основан- ные на задании посредством равенств абстрактных свойств операций, занимают важное место среди средств спецификации программ и дан- ных. СПТ допускают определение операционной семантики таких спе-
222 5.3.2. Эквациональные спецификации цификаций, сопоставляя каждому выражению (терму) цепочку вычис- лений (редукций), и могут рассматриваться в качестве абстрактного ин- терпретатора языка алгебраических спецификаций. Поэтому к сфере применения СПТ можно отнести синтез, верификацию, оптимизацию и другие области программирования, в которых используются алгебраи- ческие методы спецификации. Важной сферой применения СПТ являются программные системы аналитических преобразований. 5.3.2. Эквациональные спецификации. Эквационалъной специфи- кацией (теорией) называется пара (S, Е), где S — сигнатура, т.е. ал- фавит, состоящий из элементов счетного множества переменных и непу- стого множества функциональных символов, а Е — множество равенств s = t между термами s, t G T(S). Пример. Эквационалъной спецификацией аддитивной группы является пара (Sp Е{), в которой 5^ содержит функциональные символы О (нульарный), (унарный), "+” (бинарный), а Ех состоит из следую- щих равенств: 0 + х в х, (-х) + х = О, (х + у) + z = х + (у + z), в которых используется инфиксная запись для ”+”. Пусть (2, Е) — некоторая эквациональная спецификация, а $ = t — некоторое равенство между термами s, t G Т(£). Если s = t выводимо из Е, используется обозначение (S, Е) Нs « t или $ = Выводимость определяется посредством системы следующих правил вывода: A. (S, Е) I— S = если $ = t G Е\ _ (S, £) Hs = Z Б. ; ------— для каждой подстановки а; (2, Е) f-a(s) = a(t) (Z, Е) Hs, =/,...МЧЧ B- (Z,E)l-f(s..................<„) ДЛ’ KiWr° '"аРМГ° ФУ“' ционального символа F G S; Г. (S, Е) 1-Г = Г; (^»Д) ' = ^2’ Е) ' ^2 = ^3 Д- (S,£)Hq = Z3 ; (S,£)l-s = f (2, Е) t-t = s' Пусть S — некоторая сигнатура. ^-алгеброй называется некоторое множество МА вместе с функциями fA : М"А ->МА для каждого n-арного функционального символа /G S; если /— константа, то/л G МА. Например, для эквациональной спецификации аддитивной группы (Sp £j) можно рассмотреть 2\-алгебру Ар образованную из МА = {а, Ь, с}, константы а и функций -л> и +л>, определены следующей табл. 5.1:
5.3.2. Эквациональные спецификации 223 Таблица 5.1 Значение функции - Л1 Значение функции а ь с а а b С а а b b с а b С с с а b с Ь Пусть 2 — некоторая сигнатура и А — некоторая S-алгебра. Всякое равенство s «t между термами из Т(2) получает значение в А путем интерпретации функциональных символов в s и t соответствующими функциями из А. Переменные в $ = t являются (неявно) универсально квантифицированными. Например, значением равенства (-х) + х = 0 в Sj-алгебре At является Vx Е М+л1(-(х), х) = а. Очевидно, что высказывание Vx Е МА^ (-лЧх), х) = а является истинным. Говорят, что равенство выполняется для взятой в качестве интерпретации, a At есть модель равенства (~х) + х = 0 (удовлетворяет этому равенству), и используется обозначение Д k= (-х) + х = 0. 2-алгебра А является моделью множества равенств Е между термами Г(2) (обозначение A t= Е), если каждое равенство s = t из Е выполняется для Л. Пусть (2, Е) — эквациональная спецификация. Говорят, что (2, Е) определяют класс всех S-алгебр А таких, что А \=Е, и используют обозначение (S, Е) k= F для множества F равенств между термами из Т(2), если Л 1= /'для любой S-алгебры Л, определен- ной спецификацией (2, Е). Проблема тождеств для спецификации (2, Е) формируется следу- ющим образом: для любого заданного равенства s = t между термами из Г(2) определить, верно или нет, что (2, Е) ^=s = t. Следующая теорема устанавливает эквивалентность двух рассмот- ренных подходов к определению семантики эквациональной специфи- кации: синтаксического (через понятие выводимости) и семантического (через понятие модели). Теорема Биркхоффа. Пусть (2, Е) — некоторая эквациональная спецификация. Тогда для любых термов s и t из Т(2) справедливо (2, Е) Нs = t в том и только в том случае, когда (2, Е) \=s = t. Существуют неразрешимые эквациональные теории, для которых проблема тождеств алгоритмически неразрешима. Например, не сущест- вует алгоритма, доказывающего или опровергающего равенство любых двух термов, построенных из бинарной операции ’применение’ (•) и констант S, К, /, относительно следующего множества равенств (так называемая комбинаторная логика): ((S • х) * у) • z = (х • z) • (у • z), (К • х) • у = х, I • х = х.
224 5.3.3. Понятие СПТ 5.3.3. Понятие«СПТ. Пусть 2 — некоторая сигнатура. Идея СПТ состоит в рассмотрении ’’несимметричных”, или ’’однонаправленных" ра- венств. Правилом переписывания термов над 2 называется такая упоря- доченная пара термов 5, t G 7(2), обычно записываемая в виде $ Z, что 5 £ V и V(t) С У($). Системой переписывания термов (СПТ) называется пара (2, R), в которой R — некоторое конечное множество правил пер- еписывания над 2. В дальнейшем для обозначения СПТ (2, R) обычно будет использоваться R, поскольку сигнатура 2 фиксирована, а прави- лам переписывания в R иногда будут даваться имена, например, г в виде г : s -* t или s -* Л СПТ R порождает на 7(2) бинарное отношение -*Л, называемое от- ношением редукции, которое можно определить как множество пар, вы- водимых из R посредством правил 5.3.2.Б и 5.3.2.В, в которых символ ”s” заменен на Говорят, что терм редуцируется в терм 12 по вхождению и и обозна- чается Z2, если существуют такие и G O(Q и (s -* t) G R, что для некоторой подстановки а справедливо a(s) ^tjunt2^ [и «- a(t) ]. Например, для {f(z, h(y>) -* g(h(y))} терм = f(f(a, Л(х)), h(b)) редуцируется в терм f(g(h(x», h(b)) по вхождению и - 1 и с использо- ванием подстановки <?e {(a, z), (х, у)}, а также редуцируется в терм g(h(b)) по вхождению и в е и с использованием подстановки о = {(/(а, Л(х)), х), (5, у)}. Транзитивное, транзитивно-рефлексивное, транзитивно-рефлексив- но-симметричное замыкания отношения т* обозначаются соответственно л ’ и 7Г Отношение я совпадает с отношением =, где Е получено из R заменой всех правил переписывания на соответствующие равенства; го- ворят, что СПТ R порождает отношение эквивалентности =. Терм t называется редуцируемым (относительно R), если существует такой терм 5 G 7(2), что t $, и нередуцируемым (или тупиковым) в противном случае. Если t s и 5 нередуцируемый, то 5 называется нор- мальной формой терма 1 и обозначается 5 - t | R. Термы $ и t называют- ся конвергентными, если $ 1 R-t 1 R. 5.3.4. Свойство Черча—Россера, конфлюэнтность, нетеровость и полнота СПТ. Пусть R — некоторая СПТ. Следующие два эквивалентных свойства R формулируются в тер- минах отношения =, порождаемого данной СПТ: — R обладает свойством Черча—Россера, если для любых t2 G G 7(2) выполняется Zt = Z2 тогда и только тогда, когда существует t3 G 7(2) такой, что Zj -j* t3 и t2 t3; — R называется конфлюэнтной, если для любых Z,, t2, t3 G 7(2) таких, что Л ? и /. •? t3, найдется терм t4 G 7(2), для которого t2 + t4 и t3 + t4.
5.3.5. Локальная конфлюэнтность. Критические пары 225 Свойство конфлюэнтности иллюстрируется на рис. 5.9. Здесь и ниже отношение изображено сплошной стрелкой, а отношение — штрихо- вой. Очевидно, что в случае конфлюэнтной СПТ нормальная форма любо- го терма, если она существует, является единственной. Условием, га- рантирующим ее существование для любого терма, является следующее важное свойство СПТ: R называется нетеровой (или конечно заверши- мой), если не существует бесконечной цепочки редукций t2-*t3.-*.... Нетеровая и конфлюэнтная СПТ называется полной (конвергент- ной, канонической). В случае полной СПТ нормальная форма любого терма всегда сущест- вует и единственна. Отношение = в этом случае разрешимо: для выяс- нения эквивалентности термов необходимо проверить совпадение их нормальных форм. В силу нетеровости СПТ и конечности R процесс нахождения нормальной формы эффективен. Справедливы следующие свойства: А. Свойства конфлюэнтности и нетеровости СПТ являются ал- горитмически неразрешимыми. Б. Разрешима проблема нетеровости в классе СПТ, состоящих из правил, не содержащих переменных. 5.3.5. Локальная конфлюэнтность. Критические пары. Оказывается, что для нетеровых СПТ свойство конфлюэнтности разрешимо. Разреша- ющий алгоритм опирается на понятия локальной конфлюэнтности и кри- тической пары. Пусть R — некоторая СПТ. R называется локально-конфлюэнтной, если для любых термов , t2, t3 G T(2) таких, что tx j* t2 и f, t3, найдется терм /4 G Т(Е), для которо- г° /2 £ и £ Ц. Свойства конфлюэнтности и локальной конфлюэнтности иллюстри- руются на рис. 5.9, би а соответственно, в ВА. Евстигнеев, В.Н. Касьянов
226 5.3.5. Локальная конфлюэнтность. Критические пары В общем случае локальная конфлюэнтность не означает конфлюэнт- ности СПТ (см., например, рис. 5.10, на котором изображено локально- конфлюэнтное, но не конфлюэнтное отношение редукции), однако спра- ведливо следующее утверждение. Рис. 5.10 Теорема Ньюмена. Для нетеровой СПТ свойства конфлюэнтное- ти и локальной конфлюэнтности эквивалентны. Ключевым для анализа локальной конфлюэнтности является поня- тие критической пары. Пусть и s2 -♦ t2 — два правила переписывания из R, которые без потери общности (можно считать) не имеют общих переменных, т.е. Hsj) П К($2) =0 (последнего условия всегда можно достичь переимено- ванием переменных в одном из правил). Пусть и — некоторое такое вхождение терма в что терм sju не является переменной и унифи- цируем с s2. Тогда пара термов uUJw *- /2]) и сг(/1), где о — наиболее общий унификатор st/u и $2, называется критической парой R. получен- ной в результате совмещения правил s2 -> t2 и s, Например, пусть R содержит правила переписывания fifiy, z), iv) -» /О’, /<2, >v)) и /(а, у) -> у. Переименовав переменную у во втором пра- виле, получаем/(л, х) -> х. Подтерм/(у, z) левой части первого правила унифицируем с левой частью второго; их наиболее общим унификатором является а = {(«, у), (х, z)}. Исходные два правила порождают критичес- кую пару /(х, 10 и f(a,f(x, 10). Содержательный смысл критических пар поясняет тот факт, что для любых двух правил (^ -*/,), (s2 t2) G R термы p = <7(5, [и <- t2 ]) и q =
5.3.6. Построение полных СПТ для эквациональных теорий 227 = <?(/!), образующие критическую пару, являются результатами редук- ции терма er (s'!) по вхождениям и и е и применения правил s2 t2 и -» соответственно (и, следовательно, р = Поэтому вполне естественно, что множество критических пар СПТ (R) дает исчерпывающую инфор- мацию для проверки локальной конфлюэнтности СПТ, что подтвержда- ется следующей теоремой. Теорема Кнута—Бендикса- -Уэ. СПТ R локально-конфлюэнтна тогда и только тогда, когда для каждой ее критической пары и t2 существует терм t такой, что ti-% t и t2-* t. lx lx Таким образом, если СПТ нетерова, то для выяснения локальной конфлюэнтности (а следовательно, конфлюэнтности — теорема Ньюме- на, а также полноты) можно применить следующую разрешающую про- цедуру: для каждой критической пары и t2 СПТ R (их конечное число) сравнить Zj | R и t2 | R. В случае совпадения каждой такой пары заклю- чаем, что система конфлюэнтна (т.е. полна); в противном случае — R неконфлюэнтна. Пример. Пусть R = {(х • у) • z -♦ х • (у • z)}. Единственное пра- вило в R порождает единственную нетривиальную критическую пару = = (х • (у • z)) • w) и t2 = (х • у) • (z • w). Так как \ -+ х • ((у • z) • w)) £ х • (у • (z • w)) и t2 j* х • (у • (z • w)), то R локально-конфлюэнтна. 5.3.6. Построение полных СПТ для эквациональных теорий. Особый интерес представляет задача построения по заданной системе равенств Е такой полной СПТ R, что = совпадает с =. В этом случае эквациональ- к h ная теория разрешима, поскольку s = t тогда и только тогда, когда 5 | R = = t I Я. Обратное утверждение неверно: существуют разрешимые эквацио- нальные теории Этакие, что нет полных СПТ R, для которых == совпада- ет с =. Например, это имеет место для так называемой теории АИ, состо- ящей из законов ассоциативности и идемпотентности: (х • у) • z = х • (у • z), X • X = X. Теория АИ разрешима, так как очевидный алгоритм переводит любой терм t в нормальную форму f, в которой все скобки расположены слева, а строка, полученная из !' удалением всех скобок, не содержит двух идентичных рядом расположенных подстрок. Однако для АИ не сущест- вует полной СПТ R такой, что = совпадает с =; при доказательстве отсутствия такой R используется следующая Теорема Шмитта. Пусть Е — отношение эквивалентности на T(Z), R — множество правил переписывания термов такое, что R обладает свойствами конфлюэнтности и конечной завершаемости, = совпадает с == и не существует такого конечного подмножества Ro
228 5.3.6. Построение полных СПТ для эквациональных теорий множества R, которое образует полную СПТ и для которого = совпа- хо дает с =. Тогда не существует полной СПТ Rv для которой = совпада- ет с =. Теоремы Ньюмена и Кнута—Бендикса—Уэ (см. п. 5.3.5) уже содер- жат идею метода нахождения по эквациональной теории Е такой полной СПТ Л, что = совпадает с =. Осуществляется ориентация равенств из Е путем их преобразования в правила переписывания таким образом, чтобы текущая СПТ была не- теровой. Пусть Л, полученная таким образом, является нетеровой СПТ. Мно- жество КП (Я) — критических пар системы R — конечно. Для каждой пары {/, из КП (Я) можно сформировать нормальные формы f и s' термов t й s соответственно. Если для всех (/, s) G КП (7?) справедливо V e s' (т.е. t и s конвергентны), то R является конфлюэнтной, иначе — нет. Если R не является конфлюэнтной, а /' и $' — нормальные формы критической пары, можно попытаться добавить к R либо f s', либо s' Повторяя этот процесс, можно надеяться на получение в конце концов конфлюэнтцого множества правил переписывания. Если таким процессом достигается множество правил переписывания 7?хобладающее свойствами конфлюэнтности и конечной завершаемое™, R называется пополнением СПТ R. Указанный метод позволяет осуществить построение полной СПТ для эквациональной спецификации аддитивной группы, рассмотренной в п. 5.3.2, следующим образом. На первом шаге придается равенствам ’’разумная” ориентация: г, : 0 + х -» х, г2: (-х) + х О, г3: (х + у) + z -* х + (у + z). Следует отметить, что ориентация в правилах и г2 фиксируется свойствами правил переписывания, что же касается правила г3, то обрат- ная ориентация в ней столь же "разумна”. Полученная СПТ R = {гр г2, г3} не является конфлюэнтной. Правила г3 и г2 образуют критическую пару, состоящую из неконвергентных тер- мов: ((-х) + х) + z г2 / <3 О + z (—х) + (х + z) Термы этой пары имеют нормальные формы 0 + z и (-х) + (х + z). Все множество критических пар правил гр г2 и г3 состоит из: х + гиО + (x + z) дляг, иг3, О + Z и (~х) + (х + z) для г2 и г3,
5.3.6. Построение полных СПТ для эквациональных теорий 229 (х + (у + z)) + W и (х + у) + (z + w) для г3 и г3. В первой и третьей критических парах термы имеют одну и ту же нор- мальную форму: г 0+(x + z)-^x + z (х + (у + z)) + w (х + у) + (z + w) "1 x+((y + z) + V) / / гз гз / (х+ (у + (z + w)) Таким образом, к R добавляется новое правило г4: (~х) + (х + z) -» z. Полученная СПТ все еще не является конфлюэнтной, поскольку г, и г4 порождают неконвергентную критическую пар»у (-0) + (0 + z) (-0) + z z К R добавляется новое правило г5: (-0) + z -> z. Правила гг и г4 порожда- ют еще одну критическую пару (-(-х)) + ((-х) + х) Г2 / х))+0 х термы которой не могут быть редуцированы. В результате к R добавляет- ся правило г6: (—(—х)) + 0 -* х. Совмещая правила г6 и г3, можно получить ((-С-х)) + 0 + z Г6 / \гз x + z (—(—х)) + (0 + z) Терм (~(~х)) + (0 + z) редуцируется к (-(-х)) + z. В результате к R до- бавляется правило r7: (—(—х) > + z -* х + z, которое позволяет упростить правило г6, поскольку (-(-х)) + 0 -> х + 0. Следовательно, г6 заменяется на г8: х + 0 -> 0. Совмещение правил г8 и г5 дает (-0) + 0 Г8 / V -о о
230 5.3.6. Построение полных СПТ для эквациональных теорий В результате возникает новое правило г9: -0 -* 0. Теперь правило г5 ста- новится излишним, поскольку (-(-х)) + 0 х + 0. Если рассмотреть сов- мещение правил г8 и г7, можно получить (-х)-х»+0 -(-х) х + 0 Получается новое правило г10: -(-х) х, делающее правило г7 из- Г|° о лишним: (-(-х)) + z x+z. Совмещение г10 с г2 имеет вид (-(-х)) + (-у) ГЮ / \Г2 х + (—х) 0 Критическая пара (х + (-х), 0) не является конвергентной, и к СПТ добавляется правило гн: х+ (~х) 0. Совмещение правил гп и г3 воз- можно двумя способами: (х + (~х)) + z (х + у) + (-(х + у)) и / 0 х+ (у + (-(х + у))) Результатом совмещения гн и г3 являются правила г12: х + ((-х) + z) z и г13: х + (у + (-(х + у))) -* 0. Совмещение правил г13 и г4 может быть осуществлено следующим образом: (-х) + (х+ (у+(—(х + у)))) г13 / 4 4/4 (~х) + 0 у + (-(х + у)) -х Чтобы сделать конвергентными термы критической пары (~х) + 0 и у + (-(х + у)), к R можно добавить правило г14: у + (-(х + у)) -х. Тогда правило г13 станет излишним, поскольку х + (у + (~U + у))) х + (~х) 0.
5.3.1. Методы доказательства нетеровости. основанные на упорядочении 231 Совмещение правил г|4 и г4 дает (-у) + (у+ (-(* + ?))) Г14 / (-у) + (~х) -(л- + у) В результате к R добавляется правило г|5: -(х + у) (~у) + (~х), а правило г14 удаляется из R, поскольку оно становится излишним: у + + (~(х + у)) -* у + ((-у) + (-х)) -х. В этот момент R является нетеровой, имеет только попарно конвер- гентные критические пары и, таким образом, является полной. 5.3.7. Методы доказательства нетеровости, основанные на упорядо- чении. Проблема нетеровости СПТ в общем случае является нераз- решимой (см. 5.3.4.А), поэтому задача состоит в отыскании набора ус- ловий, гарантирующих нетеровость как можно более широких классов СПТ. Пусть > обозначает некоторое отношение частичного порядка на множестве Т(2), т.е. > — транзитивное, рефлексивное и антисиммет- ричное отношение. Отношение > называется линейным упорядочением на T(Z), если > t2 или t2 > для любых термов , t2 G T(S). Как обыч- но, через > обозначается отношение строгого порядка, т.е. > t2, если > > t2 и * t2. Отношение называется нетеровым (или вполне-фундированным), ес- ли не существует бесконечно убывающих цепей > t2 > t3 > ... > tn > ... . Под предупорядочением понимаются такие частичные упорядочения >, которые не обязательно удовлетворяют условию антисимметричнос- ти, т.е. > t2 и t2 > могут быть истинными для термов t2 таких, что # /2. С предупорядочением > обычно ассоциируется отношение эк- вивалентности связывающее такие и /2, что tt > t2 и t2 > Таким образом, предупорядочение является частичным упорядочением тогда и только тогда, когда ~ является отношением равенства. Если > является предупорядочением, то используется обозначение > /2, если tA > t2 и не верно ~ t2. Для предупорядочения > вводится более сильное понятие, чем впол- не-фундируемость: отношение > называется вполне-предупорядочением, если для любой бесконечной последовательности термов /2, ... tH, ... существуют такие j и Л, что j > к и > tk. Очевидно, что предупорядочение является вполне-предупорядочени- ем тогда и только тогда, когда оно является вполне-фундированным и не содержит бесконечных множеств попарно несравнимых элементов. Предупорядочение >, заданное на множестве T(S), называется моно- тонным, если для всех термов /, s, ..., и функциональных символов / f(t^ Л ..., tn) >f{tx, ..., ^,5,//+1, ..., tH), если t > s. Справедливо свойство. А. Пусть > является монотонным вполне-предупорядочением на Т(£) и пусть R — некоторая СПТ на 2. Если для каждого правила (t-* s) G
232 5.3.7. Методы доказательства нетеровости, основанные на упорядочении G. R и любой подстановки а выполняется a(t) > a(s), то R является нетеровой. Монотонное предупорядочение, которое для заданной СПТ R удов- летворяет условию свойства А, называется конечно-завершимым (нете- ровым) предупорядочением для R. Отношение > называется редукционным упорядочением, если > — вполне-фундированное и монотонное отношение строгого порядка, за- данное на Т(£), такое, что a(s) > o(t) при s> t для любых термов s, t Е G Т® и подстановки а. Простой способ гарантировать то, что предупорядочение является вполне-предупорядочением, состоит в требовании выполнения подтерм- ного свойства. Говорят, что отношение упорядочения >, заданное на T(Z), удовлет- воряет подтермному свойству, если/0р ..., ..., tn) > ( для любого терма /(Гр ..., ..., /„) Е Т(Х). Упрощающим предупорядочением называется монотонное предупорядочение, удовлетворяющее подтермному свойст- ву. Справедливы свойства. Б. Упрощающее предупорядочение на T(Z), где S — конечно, явля- ется вполне-предупорядочением. В. Пусть > является упрощающим предупорядочением на Т(Х) и пусть является вполне-предупорядочением на S, удовлетворяющим условию замены операций относительно [>=, т-е. для любых f, gGZ арности пит соответственно и термов Zp...,Zn, Sp...,sw имеем f(t{, ... ..., tn) > #($р ..., sm), если/= g, п > ти существует набор индексов 1 < < j\ < ... < jm < п такой, что для всех i. Тогда > является впол- не-предупорядочением. Подтермное свойство не является необходимым условием того, чтобы монотонное упорядочение являлось вполне-фундированным. Вместе с тем справедливо свойство Г. Если > — линейное монотонное упорядочение на T(Z), то > является вполне-фундированным тогда и только тогда, когда > обла- дает подтермным свойством. Пусть ь обозначает предупорядочение, заданное на S. Предупорядо- чение Крушкаля и= на множестве T(S) определяется таким образом, что Z=/(Zp ...» tn) h= $ = £($!, ..., s„) тогда и только тогда, когда справедливо одно из следующих свойств: s = t; f и= g и существуют такие индексы 1 < < j\ < ... < jm < п, что t. и= $ для всех i; tj h= $ для некоторого j. Теорема Крушкаля—Наша—Виллиамса. Отношение Крушкаля >= является вполне-предупорядочением на T(Z) тогда и только тогда, когда и= — вполне-предупорядочение на S. Конкретным примером упрощающих упорядочений является класс упорядочений, получивших название упорядочений рекурсивных путей и основанных на следующей идее упорядочения мультимножеств. Пусть > обозначает частичное упорядочение на некотором множестве S. Отно-
5.3.8. Алгоритм Кнута-Бен дикса 233 шение » на множестве конечных последовательностей элементов из S определяется таким образом, что (Zp tn) » ($р ...» sm) тогда и только тогда, когда справедливо одно из следующих условий: п > 0 и т в 0; для любого j G [1 : т ] существует такое i G [1 : и], что Z, > существуют такие i G [1 : п ] и j G [1 : т ], что » Z,- (т.е. Sj» или Z, « s;), Z, >> и (Zp ..., tn) - Zz » (sp ..., sn) - s? где формула a — а обозначает такую по- следовательность элементов из S, которая получается из заданной после- довательности а удалением самого левого вхождения элемента а. Справедливо свойство . Д. У порядочение мультимножеств » вполне-фундировано тогда и только тогда, когда вполне-фундировано то упорядочение >, на основе которого оно построено. Упорядочение мультимножеств может быть использовано для постро- ения вполне фундированного отношения на Т(2). Пусть > — некоторое частичное упорядочение на множестве 2. Отно- шение > является упорядочением рекурсивного пути, если для любых 5 = #($,, ...» sn) и t = /(Zp ..., Zm) справедливо t > s, когда выполняется одно из следующих трех условий: /= g и (zp ..., tm) » ($р ..., $п); /> g и (Z) » » (5Р ..., $„); неверно, что/-£или/> gn (Zp ..., tm) >> (а). 5.3.8. Алгоритм Кнута-Бендикса. Наибольшую трудность в реа- лизации метода СПТ, описанного в п. 5.3.6, представляет проблема под- держания нетеровости расширяющихся множеств правил переписыва- ния. Одним из простых решений этой проблемы является фиксация зара- нее некоторого конечно-завершимого предупорядочения > для R и до- бавления нового правила только тогда, когда оно не противоречит задан- ному предупорядочению. Эта идея приводит к следующему алгоритму, предложенному Кнутом и Бендиксом (здесь он приводится в своей про- стейшей форме): функ ПОПОЛНЕНИЕ (R: множество правил переписывания) = 1. Пусть > обозначает конечно-завершаемое предупорядочение для R; 2. Пусть КП — множество критических пар для R; 3. пока КП 0цикл 4. (Z, := В КП; 5. Z' := Z 1 R; s' :=s | R; 6. если f * s' то 7. если cr(Z') > a(s') для всех подстановок о то 8. Добавить к КП все критические пары между R и t' s'; 9. R - (f s') 10. иначе если a(s') > a(t') для всех подстановок а 11. то Добавить к КП все критические пары между R и s' Z'; 12. /?-($'-> Z') 13. иначе возврат ’неудача: встретилось неориентируемое равенство’ все
234 5.3.8. Алгоритм Кнута—Бендикса все все все; 14. возврат ’успех’ все Имеется три возможности при выполнении функции ПОПОЛНЕ- НИЕ: 1) функция завершается успешно; 2) цикл выполняется бесконеч- но; 3) встретилась такая пара термов, которая не может быть ориен- тирована. Последняя возможность определяет наиболее принципиаль- ное ограничение алгоритма Кнута—Бендикса: нельзя построить полную СПТ для эквациональной спецификации с коммутативными операция- ми. Однако если функция завершается успешно, то результирующая СПТ является конфлюэнтной. Функция ПОПОЛНЕНИЕ не ’’упрощает” сами правила переписы- вания. Но такая оптимизация может быть выполнена после завершения функции. СПТ R называется несводимой, если для каждого его правила пере- писывания s -* t справедливы следующие свойства: t-t[Rns-s[{R- Справедлива Теорема Метивиера. Пусть R является полной СПТ. Тогда сущест- вует такая несводимая полная СПТ R', что отношения = и =, совпа- ду. к. дают. Описанный ниже вариант алгоритма Кнута—Бендикса упрощает правила переписывания сразу, как это возможно. Причина выполнения упрощений во время процесса пополнения, а не после его завершения — это эффективизация процесса пополнения. Другая оптимизация, реа- лизованная в данном варианте алгоритма, — это инкрементальность процесса пополнения, позволяющего не вычислять критические пары между теми правилами, которые уже рассматривались на предыдущих шагах работы алгоритма: функ ПОПОЛНЕНИЕ 1 (Е : множество равенств) = 1. Пусть > — редукционное отношение на множестве термов T(S) 2. Ео := Е\ Яо := 0; i := 0; р := 0; 3. цикл 4. пока Е ¥ 0 цикл 5. °/0 Редукция равенства % 6. Пусть s = t — некоторое равенство из Е.\ 7. s' := s | R* f := s 1 Rt; 8. если5'=/'то 9. £+1 := Я “{$ = '}; *+| := i := * + 1 10. иначе если (s' > /') v (/' > s') то 11. если s' > f то а := s';/? := /' 12. иначе а := /';/?:« s' все;
Библиографический ком.ментарий 235 13. % Добавление нового правила % 14. Пусть К — множество меток правил из чья левая часть sk редуцируется правилом скажем, к 15. Д-+гв “ {$ = 4 U {$/ = 4 I кб К — номер правила sk tk}; 16. р := р + 1; _ 17. Л1+1 := {у : s’ I j: s; -♦ Z; e Rit ]'ёКи1/~ нормальная форма терма t относительно Rt, U {a ft}} U {p : a p}\ 18. Правила, попавшие в Ri+{ из Я-, остаются помеченными либо непомеченными, а новое правило а /3 является непомеченным; 19. /:=/+1 20. иначе возврат ’неудача: встретилось неориенти- руемое равенство’ все; все все; 21. % Вычисление критических пар % 22. если все правила в R.t помечены то 23. возврат Rt 24. иначе Пусть к — номер непомеченного правила в /?•; 25. — множество всех критических пар, получаемых совмещением правила к с любым правилом из Я., имеющим номер, не превышающий Л; 26. Ri+i — то же множество, что и Я-, за исключением того, что в нем правило к помечено; 27. i := i + 1 все все все 5.4. Библиографический комментарий По всей видимости, первый эффективный алгоритм для установления изоморфизма деревьев был предложен Эдмондсоном в начале 60-х гг. (опубликован в [2]) на основе канонической нумерации деревьев. Этот метод был переоткрыт многими другими исследователями (см., напри- мер, [44, 57, 60]). Вариант алгоритма Эдмондсона, приведенный здесь, заимствован из [1 ], где также дано доказательство его линейности. Этот же алгоритм был ранее опубликован в работе Хопкрофта и Тарьяна [9 ]. Алгоритм Земляченко изложен в соответствии с [5] (см. также [4]). Алгоритм на основе кодирования деревьев принадлежит Джовановичу и Даниловичу [38] (см. также их более ранние работы [19, 36], а также обзор [37 ]). Общему анализу состояния проблемы изоморфизма графов посвящена фундаментальная работа В. Н. Земляченко, Н. М. Корниенко
236 Библиографический комментарий и Р. И. Тышкевич ’’Проблема изоморфизма графов” [6 ], содержащая об- ширную библиографию. Вариант алгоритма Эдмондсона для установ- ления изоморфизма помеченных лесов заимствован из [15]; в соответ- ствии с этой же работой изложена проблема автоморфизного разбиения деревьев. К более ранним в этом направлении относятся работы Вейнбер- га [61, 62 ], а также [17, 24, 34 ]. Алгоритм Корнеля и Готлиба заимство- ван из [18 ]. Свойства групп автоморфизмов деревьев изучались в [7, 10, 59]. Что касается подграфового изоморфизма для произвольных деревьев, то известен алгоритм для решения этой проблемы с трудоемкостью О(тп2) [54 ], причем для специальных случаев трудоемкость может быть понижена до О(тп) [28]. Алгоритм установления подграфового изо- морфизма для ориентированных деревьев изложен в работах [23, 25, 45 ]. Близка к проблеме подграфового изоморфизма проблема вложения де- ревьев в соответствии с различными критериями качества вложения. Обзор состояния проблемы и относящуюся к данной теме библиографию можно найти в [29], где, в частности, приведены результаты, касаю- щиеся вложения полного тернарного дерева Т(Л) высоты Л в полное бина- рное дерево B(2h) высоты 2Л. Проблема вложения в заданный граф се- мейства деревьев малого по отношению к графу размера тесно примыка- ет к этим вопросам. О вложении семейства деревьев заданных размеров в полный граф см. [27 ], о некоторых других результатах в этом направ- лении см. [29 ]. Эрбран в 1930 г. (в диссертации) предложил недетерминированный алгоритм вычисления унификатора двух термов. Эта работа была вызва- на интересом к решению уравнений. Однако современное использование и понятие унификации принадлежат Робинсону. В своей пионерской ра- боте [55 ] Робинсон предложил метод доказательства теорем, основан- ный на резолюции — некотором мощном правиле вывода. Центральной в методе была унификация термов первого порядка. Робинсон доказал, что два терма первого порядка, если они унифицируемы, имеют единствен- ный наибольший общий унификатор (НОУ). Он предложил алгоритм для вычисления НОУ и доказал его корректность. Этот алгоритм был крайне неэффективен, имел экспоненциальную временную и емкостную сложность, поэтому в дальнейшем большие усилия многих авторов были направлены на улучшение алгоритма унификации. Они завершились разработкой ряда эффективных алгоритмов [30, 33, 41, 46, 52], основ- ные три из которых приведены в п. 5.2. Корбин и Бидуа [16] ’’реаби- литировали” исходный алгоритм Робинсона путем использования в нем новых структур данных. Они понизили его экспоненциальную времен- ную сложность до О(п2), утверждая, что этот алгоритм более прост, чем алгоритм Мартелли—Монтанари, и на практике превосходит его по эф- фективности. Задача унификации и ряд ее вариантов рассматривается в обзорной работе [41 ]. В ней обсуждаются различные алгоритмы и структуры дан- ных, дается обзор исследований по унификации, возникающих в таких областях информатики, как доказательство теорем, логическое програм-
Библиографический комментарий 237 мирование и обработка естественных языков. Работа содержит примеры, освещающие конкретные использования унификации и встречающиеся там специальные проблемы. Среди рассматриваемых тем — резолюция, логика высших порядков, проверка вхождений, бесконечные термы, эк- вациональные теории, параллельные алгоритмы, структуры и другие приложения унификации. Семи-унификация является обобщением как поиска по образцу, так и обычной унификации: для некоторой заданной пары термов s и t нужно найти две такие подстановки р и а, что р(а($)) ва(0. В статье [40 ] представлена разрешающая процедура для семи-уни- фикации, которая основана на технике, аналогичной используемой в процедуре пополнения Кнута—Бендикса. Когда ее входные термы семи- унифицируемы, процедура строит каноническую СПТ, из которой под- становки р и а легко извлекаются. Хотя она работает в экспоненциальное время, время работы разрешающей процедуры, как показывают авторы, может быть сделано полиномиальным. Существует целый ряд обзорных работ [3, 8, 13, 14, 31, 56], посвя- щенных наиболее важным результатам, методам и открытым проблемам теории систем переписывания. Доказательство теоремы Биркхоффа может быть найдено в работе [12], теоремы Ньюмена — в [50], теоремы Кнута—Бендикса—Уэ — в [30, 42], теоремы Крушкаля—Наша—Вилиамса — в [43, 49], теоремы Метивиера — в [47 ] и теоремы Шмитта — в [56 ]. Обзором методов обращения с равенствами в процедурах револю- ционного типа является работа [32 ]. В ней рассматриваются различные стратегии унификации и процедуры в стиле алгоритма Кнута—Бендик- са, используемые при автоматическом доказательстве теорем. Прямые методы доказательства нетеровости СПТ, не требующие подходящего упорядочения на функциональных символах, рассматрива- ются в [21, 26]. Эти методы основаны на непосредственном анализе правил переписывания и являются более "алгоритмическими”, но при- менимы для меньшего числа СПТ. Разрешимость свойства конфлюэнт- ности для СПТ, правила которых не содержат переменных, показана в [51]. Наряду с равенствами для спецификации абстрактных типов данных и в других приложениях используются так называемые условные равен- ства, т.е. формулы вида S| = Z| A ... A Sn = ttl s,l+1 = Zn+|. Использование аксиом такого вида не нарушает ’’хороших” свойств спе- цификации (существование инициальной модели), но дает более удоб- ное и мощное средство [58 ]. Для реализации таких спецификаций раз- вивается аппарат условных СПТ [22, 39, 48 ]. Уже отмечалось, что алгоритм пополнения, кроме успешного завер- шения, может работать бесконечно долго или останавливаться ”с неуспе-
238 Список литературы хом" ввиду невозможности ориентировать равенство. Причина бесконеч- ной работы может быть устранена введением дополнительных функцио- нальных символов [26, 42], а причина остановки "с неуспехом” (на- пример, наличие закона коммутативности /(х, у) = /(у, х» связана с прин- ципиальным недостатком всего алгоритма. Для преодоления этого недо- статка имеется ряд модификаций алгоритма Кнута-Бендикса, основан- ных на идее выделения равенств типа ассоциативности-коммутативнос- ти в отдельную теорию Т и рассмотрении равенств термов с точностью до эквивалентности ”=” [32, 35, 53 ]. Методам доказательства нетеровости, основанным на упорядочении, посвящено большое число работ, ссылки на которые могут быть найдены в [8, 20, 56]. Отметим среди них лишь [11], содержащую мощный и элегантный метод доказательства корректности больших классов "Кну- та—Бендикса-подобных" алгоритмов пополнения. СПИСОК ЛИТЕРАТУРЫ 1. Ахо А., Хопкрофт Дж., Ульман Дж. Построение и анализ вычислительных алгоритмов. — М.:Мир, 1979. 2. Басакер Р., Саати Т. Конечные графы и сети. — М.: Наука, 1974. 3. Дегтярев А.И., Воронков А. А. Методы управления равенством в машинном доказательст- ве теорем// Кибернетика. — 1986. — № 3. — С. 34—41,49. 4. Земляченко В.Н. Каноническая нумерация деревьев// Тр. семинара по комбинаторному анализу. — М.: Изд-во Моск, ун-та, 1970. — С. 31—38. 5. Земляченко В.Н. Установление изоморфизма деревьев// Вопросы кибернетики. — М., 1973.—С. 54—60. 6. Земляченко В.Н., Корниенко Н.М., Тышкевич Р.И. Проблема изоморфизма графов// Зап. науч, семинаров ЛОМИ/ Мат. ин-тим. В.А.Стеклова, Ленингр. отд-ние. — 1982. — Т. 118. —С. 83—158. 7. Знойко Д.В. Фактор-графы бесконечных деревьев и их группы автоморфизмов// Вопро- сы кибернетики. — М., 1975. — С. 41—44. 8. Кучеров Г.А. Системы подстановок термов. — Новосибирск, 1985. — 46 с. — (Препр./ АН СССР, Сиб. отд-ние. ВЦ; 601). 9. Хопкрофт Дж., Тарьян Р.Е. Изоморфизм планарных графов// Кибернет. сб. — 1975. — Вып. 12.—С. 39—61. 10. Фейнберг В.З. Группы автоморфизмов деревьев// Докл. АН БССР. — 1969. — Т. XII, №12.—С. 1065—1067. 11. Bachmair L., Dershowitz N., Hsiang J. Ordering for equational proofs//Proc. IEEE Symp. on Logic in Comput. Sci. — Cambridge, 1986. — P. 346—357. 12. Birkhoff G. On the structure of abstract algebras// Proc. Cambridge Philos. Soc. — 1935. — Vol. 31. —P. 433—454. 1 3. Buchberger B. History and basic features of the critical-pair/compilation procedure//! Symbolic Comput. — 1987. — Vol. 3. — P. 3-38. 14. Buchberger B., Loos R. Algebraic simplification//Computer Algebra - Symbolic and Algebraic Comput. — Springer Veil., 1982. — P. 11 —43. 15. Colbourn C.J., Booth K.S. Linear time automorphism algorithms for trees, interval graphs and planar graphs//SIAM J. Comput. — 1981. — Vol. 10, N 1. — P. 203—225.
Список литературы 239 16. Corbin J., Bidoit M. A rehabilitation of Robinson’s unification algorithm/Inf. Proc. 83. — North-Holland, 1983. — P. 73—79. 17. Corneil D.G. Graph isomorphism: Ph.D. Thesis. — University of Toronto, 1968. 18. Corneil D.G., Gotlieb C.C. An efficient algorithm for graph isomorphism//J. ACM. — 1970. — Vol. 17,N 1. —P.51—64. 19. Danilovic D.Z., Jovanovic A. Improvment and computer realization of Edmond’s algorithm for tree isomorphism/ZProc. Jugosl. Conf. Jahorina, p. 302/1. — Sarajevo, Faculty of Elecr. Eng, 1978. 20. DershowitzN.Terminationofrewriting//J. SymbolicComput. — 1987. — Vol. 3. — P. 69—116. 21. Dershowitz N. Termination of linear rewriting systems//Lect. Notes Comput. Sci. — 1981. — Vol. 5. — P. 448—458. 22. Droster K. Towards executable specification using conditional axioms//Ibid. — 1984. — Vol. 166. —P. 85—96. 23. Dublish P. Some comments on the subtree isomorphism problem for ordered trees//Inf. Process. Let. — 1990. — Vol. 36. — P. 273—275. 24. FontetM. Linear algorithms for testing isomorphism of planar graphs//Proc. 3Colloq. on Automata, Languagesand Programming. — 1976. — P. 411—423. 25. Grossi R. Futher comments on the subtree isomorphism for ordered trees//Inf. Process. Let. — 1991.— Vol. 40. — P. 255—256. 26. Guttag J. V., Kapur D., Musser D.R. On proving uniform termination and restricted termination of rewriting systems//SIAM J. Comput. — 1983.—Vol. 12,N1. — P. 189—214. 27. Gyarfas A., Lehel J. Parking trees of different order into K//Colloqua Math. Soc. — 1976. — Vol. 18. —P. 463—469. 28. Hoffmann C.M., O’Donnell M.J. Pattern matching in trees//J. ACM. — 1982. — Vol. 29. — P. 68—95. 29. Hong Jia-Wei, Mehlhorn K., Rosenberg A.L. Cost tradeoffs in graph embeddings with applications//Leet. Notes Comput. Sci. — 1981. — Vol. 115. — P. 41—55. 30. Huet G. Resolution d’equations dans les languages d’ordre 1, 2, ... w: Ph.D. dis. — Univ. Paris VII, 1976. 31. Huet G. Confluent reductions: abstract properties and applications to term rewriting systems//J. ACM. — 1980. — Vol. 27, N 4. — P. 797—821. 32. Huet G., Oppen D.C. Equationsand rewrite rules: a survey//Formal Languages Theory: Perspectives and Open Problems. — New York: Acad. Press, 1980. 33. Jaffar J. Efficient unification over infinite terms//New Generation Comput. — 1984. — Vol. 2. — P. 123—171. 34. James R.K., Riha W. Algorithm for description and ordering of trees: Techn. Report N 54. — Leeds, England: Univ, of Leeds, 1974. 35. Jouannaud J.P., Kirchner H. Completion of a set of rules modulo a set of equations//SIAM J. Comput. — 1986. — Vol. 15. — 1155—1194. 36. Jovanovic A., Danilovic D. A new algorithm for solving the tree isomorphism problem//Proc. 22 Conf. ETAN. — Beograd, 1978. — P. 1 — 177. 37. Jovanovic A., Danilovic D. Survey of algorithms for examining isomorphism of rtees//Proc. 25 Conf. ETAN. — Beograd, 1981. — P. 1—295. 38. Jovanovic A., Danilovic D. A new algorithm for solving the tree isomorphism prob- lem//Computing. — 1984. — Vol. 32, N 3. — P. 187—198. 39. Kaplan S. Condition rewrite rules//Theor. Comput. Sci. — 1984. — Vol. 33, N 2/3.— P. 139—174.
240 Список литературы 40. Kapur D., Mousser D., Narendran P„ Stillman J. Semi-unification//Lect. Notes Comput. Sci. — 1988. — Vol. 338. — P. 435—454. 41. Knight K. Unification: a multidisciplinary survey//ACM Comput. Surveys. — 1989. — Vol. 21, N 1. — P. 93—124. 42. Knuth D., Bendix P. Simple word problems in universal algebras//Computational Problems in Abstract Algebra. - New York: Pergamon Press, 1970. — P. 263—297. 43. Krushkal J. B. Well-quasi-orderings, the tree theorem, and Vazsonyis’s conjecture//Trans. Amer. Soc. — 1960. — Vol. 95. — P. 210—225. 44. Lederberg J. Notational algorithms for tree structures//NASA Techn. Rep. CR 57-029,1964. 45. Maekinen E. On the subtree isomorphism problem for ordered trees//Inform. Process. Let. — 1989. — Vol. 32, N 5. — P.271 —273. 46. Martelli A., Montanary U. An efficient unification algorithm//ACM Trans, on Program. Languages and Systems. — 1982. — Vol. 4, N 2. — P. 258—282. 47. Metivier Y. About the rewriting systems produced by the Knuth-Bendix completion algo- rithm//Inf. Process. Let. — 1983. — Vol. 26, N 6. — P. 31—34. 48. Nararro M., Orejas F. On the equivalence of hierarchical and non-hierarchical rewriting on conditional term rewriting systems//Leet. Notes Comput. Sci. — 1984. — Vol. 174. — P. 74—85. 49. Nash-Williams C. St J. A. On well-quasi-ordering finite trees// Proc. Cambridge Philos. Soc. — 1963. — Vol. 59. — P.833—835. 50. Newmam M. H. A. On theories with a combinatorial definition of "equivalence"//Annals of Math. — 1942. — Vol. 43. — P. 223—243. 51. Oyamaguchi M. The Cherch-Rosser property for ground term-rewriting systems is dicedable//Theor. Comput. Sci. — 1987. — Vol. 49, N 1. — P. 43—79. 52. Paterson M.S., Wegman M.N. Linear unification//). Comput. System Sci. — 1978. — Vol. 16, N 2. — P. 158—167. 53. Oeterson G., Stickel M. Complete sets of reductions for some equational theories//!. ACM. — Vol. 28, N 2. — P. 233—264. 54. Reyer S.W. An analysis of a good algorithm for the subtree problem//SIAM J. Comput. — 1977. — Vol. 6. — P. 730—732. 55. Robinson J. A. A machine-oriented logic based on the resolution principle//!. ACM. — 1965. — Vol. 12, Nl.— P.23—41. 56. Schmitt P.H. A survey of rewrite systems//Leet. Notes Comput. Sci. — 1987. — Vol. 329. — P. 235—262. 57. Scoins H.I. Placing trees in lexicographic order//Machine Intelligence. — 1968. — Vol. 3. — P. 43—60. 58. Thatcher !.W., Wagner E.G., Wright J.B. Datatype specification: parametrization and the power of specification techniques//ACM Trans, on Program Languages Systems. — 1982. — Vol. 4. —P. 711—732. 59. Tirs J. Sur le groupe des automorphismes d’un arbre//EssaysTopol, and Relat. Topics. — Berlin, 1970. —P. 188—211. 60. Weinberg L. Algorithms for determining automorphism groups of planar graphs//Proc. Third Annual Allerton Conf, on Circuit and System Theory'. — 1965. — P. 913—929. 61. Weinberg L. Alternative algorithms for determining isomorphisms and automorphism groups of planar grephs//Proc. Fourth Annual Allerton Conf, on Circuitsand System Theory', 1966. — P. 444—455. 62. Weinberg L. On the maximum order of the automorphism group of a planar triply-connected graph//SIAM !. Appl. Math. — 1966. — Vol. 14. — P. 729—738.
Глава 6 СИНТАКСИЧЕСКИЕ ДЕРЕВЬЯ 6.1. Синтаксис языка и задача синтаксического анализа 6.1.1. Синтаксис языка, лексемы и понятия. Всякий язык програм- мирования можно определить как множество предложений — некоторое множество цепочек или конечных последовательностей элементарных единиц из некоторого непустого конечного множества символов, называ- емого словарем (алфавитом). Само собой разумеется, что при таком рассмотрении языка программирования задается множество символов, которые можно использовать для записи программы, а также класс до- пустимых (синтаксически правильных) программ, и при этом никак не рассматривается вопрос задания смысла каждой синтаксически правиль- ной программы. Очевидно, что невозможно и нежелательно задавать множество до- пустимых программ исчерпывающим их перечислением. Нужно, чтобы описание языка было обозримым (заведомо конечным), хотя описывае- мый язык может быть и бесконечным. Обычный подход, удовлетворя- ющий этому требованию, состоит в том, что предложения языка образу- ются по определенным правилам, в совокупности составляющим то, что называют грамматикой языка. Эти грамматические правила приписы- вают предложениям языка некоторую синтаксическую структуру, кото- рая может использоваться при задании и определении смысла предло- жений. Грамматика языка обычно реализуется одним из следующих двух основных способов: либо в виде порождающей грамматики, либо в виде распознавателя. Первый способ основан на том, что грамматика имеет вид порождающей системы (разрешения производить некоторые дейст- вия), используя которую, можно получить (породить) все предложения языка и только их. Примером порождающей грамматики является способ описания синтаксиса языка Алгол-60 в форме записи, получившей на- звание нормальной формы Бэкуса или формы Бэкуса—Наура (сокра- щенно БНФ). Этот способ задания языка программирования ориенти- руется на человека, поскольку человек использует язык программиро- вания для создания (порождения) программ, решающих поставленную задачу. Однако эти программы предназначены главным образом для их решения на ЭВМ, и возникает задача распознавания синтаксической структуры уже написанных программ. Второй распространенный метод описания языка связан с использо- ванием в качестве грамматики некоторого алгоритма (предписания про- изводить некоторые действия), который дает возможность для произ- вольной цепочки (в соответствующем словаре) получить ответ на воп- рос, принадлежит ли эта цепочка языку, т.е. является ли она его предло- жением. Схематизированные устройства, используемые для представ- ления таких алгоритмов, получили название распознавателей. Приме- ром распознавателя является машина Тьюринга. Алфавит, используемый для записи языка программирования, огра- ничивается сравнительно небольшим множеством литер, доступных на
242 6.1.2. Лексический и синтаксический анализ устройствах ввода-вывода. Поэтому для записи данных, операций, фун- кций, лежащих даже на нижнем уровне иерархии языковых конструк- ций, используются не отдельные литеры, а цепочки литер, называемые лексемами. При этом символы, образующие лексему (например, иден- тификатор, служебное слово и т.д.), теряют свою индивидуальность: смысловое значение, приписываемое этой строке семантикой, не вытека- ет из смысловых значений составляющих ее символов. Текст программы можно рассматривать как цепочку в алфавите лек- сем, которая получи; а название лексической свертки программы. Для записи более сложных конструкций языка используются такие понятия, как, например, ’’арифметическое выражение” или "оператор присваивания". Понятиями называются такие грамматические элементы языка, каждому вхождению которых в программу правила языка однозначно сопоставляют его синтаксическое значение — некоторую цепочку в ал- фавите лексем. При этом одному и тому же понятию, как правило, соот- ветствует целое множество значений, а для любых двух вхождений по- нятий их значения либо не имеют общих подцепочек лексической свертки программы (независимость), либо одно значение входит полностью в другое (включение). Например, большинство языков в строке А *В + С выделяют три идентификатора, разделенных двумя знаками операций, и два вхождения понятия "арифметическое выражение" со значениями Л *ВпА* В + С. 6.1.2. Лексический и синтаксический анализ. Входом транслятора является длинная цепочка, анализ которой транслятор должен прово- дить литера за литерой, несмотря на то, что с точки зрения семантики входной программы представляются совершенно несущественными ко- дировки, используемые для записи разных лексем языка. Первый шаг, который должен выполнить транслятор, — это преобразовать исходную цепочку в последовательность внутренних кодировок и набор таблиц лексем, образующих лексическую свертку входной программы. В лек- сической свертке каждая лексема приводится к единому формату и пред- ставляется посредством дескриптора, содержащего два вида информа- ции: тип (или класс) лексемы как синтаксической единицы ( иденти- фикатор, служебное слово и т.п.), а также местоположение данной конк- ретной лексемы (вход в таблицу идентификаторов, номер в таблице слу- жебных слов и т.п.). Синтаксис лексем описывается в рамках наиболее простых автомат- ных грамматик, тем не менее этот этап трансляции (так называемый этап лексического анализа) часто занимает больше времени, чем любой другой, из-за необходимости политерной обработки входной строки и разбиения ее на вхождения подстрок из практически неограниченного множества. Выходом лексического анализа является лексическая свертка тран- слируемой программы. Следующий шаг трансляции — этап синтаксиче- ского анализа (или разбора), осуществляющий выявление в лексической свертке программы структуры вхождений лексем и понятий и проверку, удовлетворяет ли эта структура синтаксису языка. Синтаксическая
6.2.2. Цепочки и языки 243 структура программы показывает существующие в ней связи между со- ответствующими частями и тем самым помогает вскрывать смысл этой программы. Так, рассматривая арифметическое выражение А + В ♦ С в языке Паскаль и отмечая скобками вхождения понятий, мы приходим к следующей его структуре: (Л+(В*С)), в которой явно показывается, какие части арифметического выражения связаны знаком плюс, а какие — знаком умножения. Если бы соответствующая структура имела вид ((А + В) ♦ С), то арифметическое выражение было бы совершенно друго- го смысла (с другой семантикой). Обычно предполагается, что выявляемые при синтаксическом ана- лизе структуры описываются с помощью некоторой контекстно-свобод- ной (КС) грамматики, нетерминальными символами которой являются понятия языка, а терминальными — отдельные лексемы (например, слу- жебное слово BEGIN в Паскале) и типы лексем (например, такой тип лексем, как идентификатор). Результатом синтаксического анализа яв- ляется построение дерева разбора транслируемой программы (см. п. 6.2.5). 6.2. Порождающие грамматики 6.2.1. Вводные замечания. Даже с синтаксической точки зрения язык программирования — это не просто множество текстов, записанных с помощью некоторого набора символов — алфавита языка. Важным при определении языка программирования является описание тех синтак- сических структур, которые приписываются языком каждому из этих текстов (предложений). Синтаксическая структура предложений — это тот (пока) единственный мост, который может использоваться при за- дании и определении смысла программ. Порождающие грамматики, широко используемой формой записи ко- торых является БНФ, позволяют задавать не только множество предло- жений языка программирования, но и их синтаксическую структуру. 6.2.2. Цепочки и языки. Алфавит есть любое конечное множество символов, называемых буквами (или знаками алфавита). Если написать последовательность символов, располагая их один за другим, то получа- ется цепочка (а также слово или строка) символов. Например, 001111 — цепочка в бинарном алфавите {0,1}. Через е будет обозначаться пустая цепочка, т.е. цепочка, которая не содержит ни одного символа. S* обоз- начает множество всех цепочек в алфавите S, включая е, а 2* - {е}. Длина цепочки х (обозначаем 1x1) — это число символов в ней. Выделяются две операции над цепочками. Если х и у — две цепочки, то цепочка ху называется конкатенацией (или сцеплением) х и у. На- пример, для любой цепочки х всегда хе = ех = х. Обращением цепочки х называется цепочка х, записанная в обратном порядке. Для любого символа а через обозначается его ^-кратная конкате- нация (например, I3 обозначает цепочку 111). Пусть х, у и z — произвольные цепочки в некотором алфавите 2. Цепочка х называется префиксом цепочки ху, z — подцепочкой цепочки xzy, ay — суффиксом цепочки ху, в частности, пустая цепочка является префиксом, суффиксом и подцепочкой любой цепочки. Если х # у и х —
244 6.2\3. Грамматики составляющих префикс (суффикс) цепочки у, то х называется собственным префиксом (соответственно суффиксом) цепочки у. Языком в алфавите 2 называется любое подмножество множества S*. Так как язык — подмножество, операции объединения, пересечения, нахождения разности и дополнения применимы и к языкам. Кроме этих операций над языками рассматривают еще операции конкатенации, ите- рации и позитивной итерации. Пусть £, — язык в алфавите L2 — язык в алфавите Е2. Тогда язык, состоящий из всех таких цепочек ху, что х G и у G Л, называется конкатенацией (а также сцеплением, или произведением) языков и L2 и обозначается через L^. Для любого неотрицательного к определена Л-итерация языка L, обо- значаемая через Lk, по следующим правилам: L°s {е}; Lk - LL^ для лю- бого к > 1. Позитивная итерация языка L, обозначаемая через ZZ, — это язык, получаемый объединением языков Lk для всех к > 1; L* = L+ U L° называется итерацией языка. 6.2.3. Грамматики составляющих. Под (порождающей) граммати- кой понимается четверка Г e (V, W, Е, Р), в которой V — алфавит тер- минальных символов, или терминалов (тех символов, которые можно использовать для записи предложений языка), W — непересекающийся с V алфавит нетерминальных символов, или нетерминалов (иногда назы- ваемых вспомогательными символами, металингвистическими или синтаксическими переменными), Е — выделенный символ из Ж, назы- ваемый начальным символом (или аксиомой), а Р — множество правил (или продукций), имеющих вид а /3, где а и/3 — различные цепочки в алфавите V U W, а — символ, не входящий в V U W. Заметим, что мы здесь ограничиваемся рассмотрением класса порождающих грам- матик, предложенных Н.Хомским и получившим название грамматик Хомского (или грамматик составляющих). Примером грамматики служит четверка ({0,1}, {ШКАЛА, БИТ, Е}, Е, Р), в которой Р состоит из правил: Е -* БИТ ШКАЛА, ШКАЛА БИТ ШКАЛА, ШКАЛА е, БИТ -> 0, БИТ 1. Нетерминальными символами являются Е, БИТ и ШКАЛА, а тер- миналами — 0 и 1. Грамматика Г для любой цепочки си = a(fy задает множество выво- димых из нее цепочек. Это множество рекурсивно можно определить следующим образом: если [} д содержится в Р, то цепочка т = сфу не- посредственно выводима из си (обозначается си => т); если i] выводима из си и rj => т, то т нетривиально выводима из си (обозначается си => + т); если си =>+ т или си = т, то т выводима из си (обозначается си =>* т). Последова-
6.2.4. Контекстно-свободные языки 245 тельность применений правил => а2 => ... => ак называется выводом цепочки а, если « Е,ак = а. Цепочка, выводимая из Е, называется сентенциальной формой. Сен- тенциальная форма, не содержащая нетерминалов, называется предло- жением. Множество предложений образует язык, порожденный грам- матикой Г (обозначается L(D). Для предыдущего примера грамматики существует вывод Е => БИТ ШКАЛА => 1 ШКАЛА => 1. Таким образом, Е=>+1, Е=>*1 и цепочка 1 принадлежит языку L(D. Можно проверить, что L(T) содержит все непу- стые цепочки в алфавите {0, 1}. В дальнейшем для обозначения k правил <*-0k будет использоваться запись а -> 1^21... Ijfy. Грамматики можно классифицировать по виду их правил. Пусть Г = = (V, Ж, Е, Р) — некоторая грамматика. Грамматика Г называется грамматикой: типа 3 (или автоматной грамматикой), если каждое правило из Р имеет вид А хВ или А -* х, где х Е V, {А, В} С Ж; типа 2 (или контекстно-свободной грамматикой), если каждое пра- вило из Р имеет вид А а, где A G W, а а — цепочка в алфавите V U Ж; типа 1 (или контекстно-зависимой грамматикой), если каждое пра- вило из Р имеет вид а где длина цепочки а не превышает длины цепочки/3; типа 0 (или грамматикой с фразовой структурой) в общем случае. Указанные четыре типа грамматик и языков, связанных с соответст- вующими типами грамматик, часто называют иерархией Хомского. Автоматные языки описываются наиболее простым классом грам- матик, и алгоритм распознавания их чрезвычайно прост. Автоматные грамматики используются при трансляции, главным образом, при пред- варительном преобразовании программ с целью их представления в фор- ме, более удобной для дальнейшей обработки. 6.2.4. Контекстно-свободные языки. Из четырех классов грамматик Хомского наиболее важным с точки зрения приложений к языкам прог- раммирования является класс КС-грамматик. Это связано с тем, что средствами КС-грамматик удается достаточно полно описать синтакси- ческие структуры существующих языков программирования, а также с тем, что имеются достаточно хорошо разработанные алгоритмы распоз- навания КС-языков, которые составляют важную часть транслятора — этап синтаксического анализа. Здесь и ниже под распознаванием КС- языка понимается распознавание принадлежности некоторой цепочки к данному КС-языку и в случае обнаружения этой принадлежности — определение ее синтаксической структуры.
246 6.2.4. Контекстно-свободные языки КС-грамматики обладают свойством локальности и независимости подстановок в том смысле, что подстановка, ьыполняемая в некоторой области (подцепочке) данной цепочки, никак не зависит от подстановок, выполняемых вне этой области, а результаты подстановки остаются вну- три той же области. Это позволяет построение предложений и их анализ разбивать на подчасти, не зависимые друг от друга, что также приводит к существованию эквивалентных выводов в КС-грамматиках в том смыс- ле, что во всех них применяются одни и те же правила в одних и тех же местах, но в различном порядке. Применение к цепочке правил подстановки, по существу, является двумерным процессом из-за независимости порядка выполнения подста- новок в различных частях цепочки, поэтому удобно использование гра- фического представления класса всех эквивалентных выводов, называе- мого деревом вывода (или деревом разбора, когда все висячие вершины дерева помечены терминалами и символом е). Дерево вывода в КС-грамматике — это помеченное упорядоченное дерево, удовлетворяющее следующим свойствам: вершины дерева помечены символами из V U W U {е}, причем корень дерева помечен символом Е; для любой внутренней вершины qQ дерева и списка ее сыновей q{, q2, ... ..., qr, перечисленных в порядке их упорядоченности, множество правил грамматики Р содержит такое правило А -> а^.^а^ что А, ах, а2, ..., аг являются пометками вершин qQ, qi9 q2f.,qr соответственно. В качестве примера рассмотрим грамматику ({а, +,*, (,)}, {F, Е, Г}, Е, Р), в которой Р состоит из следующих правил: E-+E+TIT, Т-*Т* FIF, F -> (Е) I а. Вот примеры двух эквивалентных выводов в этой грамматике: Е=>Е+Т=*Е+Т*Е=*Т+Т*Е. Эти эквивалентные выводы цепочки Т + Т * F представляются в виде дерева вывода, изображенного на рис. 6.1. Здесь и в дальнейших приме- рах упорядочение сыновей вершин отражается их расположением слева направо. Грамматика, рассмотренная в данном примере, не раз еще бу- дет использоваться при дальнейшем изложении; мы всегда будем обозна- чать ее через Го. Поскольку любое дерево вывода является упорядоченным, для его висячих вершин существует единственное линейное упорядочение. Вы- писывая пометки висячих вершин в этой упорядоченности, можно по- лучить цепочку, выводы которой представлены этим деревом. Такую цепочку называют кроной дерева. Часть кроны дерева, являющаяся кро- ной некоторого его поддерева, называется фразой. Основа — это самая левая фраза, не содержащая других (не совпадающих с ней) фраз. На- пример, изображенное выше дерево вывода в грамматике Го имеет три
6.2.5. Эквивалентные преобразования грамматик 247 фра^ы: Т, Т * Г и Т + Т ♦ F, из которых фраза Т является основой. Среди множества эквивалентных выводов одной и той же цепочки обычно выделяют так называемые правый и левый выводы. Вывод => => а2 =>...=> аг является левым (соответственно правым), если для любого i цепочка а/+1 получается из ai применением правила к ее самому левому (соответственно к самому правому) вхождению нетерминала левой (со- ответственно правой) подстановкой. Широко используемой формой записи правил КС-грамматик являет- ся форма Бэкуса—Наура (БНФ). В ней вместо символа используется символ а металингвистические переменные представляют собой сло- ва или группы русских (или других) слов, заключенные в специальные кавычки о, такие как, например, <программа> или <арифметическое выражением Правила грамматики, записанные в БНФ, обычно называ- ются (металингвистическими) формулами. В последнее время все боль- шее распространение получают различные расширения БНФ (например, часто в правой части формулы допускают задание регулярного выра- жения) или ее модификации (например, в качестве металингвистичес- ких переменных рассматриваются слова, состоящие из русских строчных букв и дефисов). 6.2.5. Эквивалентные преобразования грамматик. С разных точек зрение может оказаться желательным преобразование заданной грам- матики в такую эквивалентную ей грамматику (эквивалентную в том смысле, что она порождает тот же язык, что и исходная грамматика), которая удовлетворяет определенным свойствам (заметим, что нет обще- го алгоритмического метода, осуществляющего любую желаемую моди- фикацию грамматики). Например, может возникнуть необходимость ис- ключить так называемую левую рекурсию или удалить все правила с пустой правой частью.
248 6.2.5. Эквивалентные преобразования грамматик Однако для достижения той или иной цели не всякое эквивалентное преобразование грамматики будет допустимым, поскольку приходится заботиться о сохранении ряда свойств исходной грамматики. Например, переход от грамматики Го к эквивалентной грамматике, содержащей не- сколько другой набор правил Е Е + Т\Е * Т1Т;Т (Е)\а, нельзя при- знать допустимым, поскольку после такой модификации структура вы- ражений а + а * а и а ♦ а + а подразумевает тот же порядок выполнения операций, что и в выражениях {а + а) * а и (а * а) + а соответственно. Одним из важных свойств грамматики с точки зрения трансляции является ее однозначность, означающая то, что не существует предло- жения, являющегося кроной двух или более деревьев вывода в данной грамматике. (Неоднозначность грамматики нельзя путать с неоднознач- ностью языка, порождаемого грамматикой. Язык неоднозначен, если его нельзя породить ни одной однозначной грамматикой. Таков, например, язык, состоящий из всех цепочек в которых либо п в т, либо т = кд Свойство однозначности грамматики может быть нарушено в резуль- тате эквивалентного преобразования. Например, для однозначной грам- матики Го эквивалентной является неоднозначная грамматика, имею- щая следующий набор правил: Е Е + El Е ♦ El (Е) I а. Действительно, для выражения а + а ♦ а можно построить два разных дерева вывода (рис. 6.2). Содержательно это означает следующее: нельзя сказать, что выпол- няется в выражении а + а * а раньше — умножение или сложение. Пре- образование, нарушающее однозначность грамматики, почти всегда бу- дет недопустимым. Существуют преобразования, являющиеся эквивалентными для лю- бой КС-грамматики и всегда допустимые. Они связаны с добавлением или удалением так называемых бесполезных символов. Это такие симво- лы, которые либо не появляются ни в одной сентенциальной форме, либо не могут порождать терминальных цепочек и, таким образом, не участ- вуют в порождении предложений языка в данной грамматике. Ясно, что при описании синтаксиса реальных языков программирования не ис- пользуются грамматики с бесполезными символами. Кроме того, сущест- вует достаточно простой алгоритм определения для любой КС-грамма- тики всех ее бесполезных символов. Он позволяет по любой КС-грам-
6.2.5. Эквивалентные преобразования грамматик 249 матике строить эквивалентную ей приведенную (без бесполезных симво- лов) грамматику. В качестве допустимых обычно используются также следующие эк- вивалентные преобразования грамматик. А. Подстановка правил. Данное преобразование осуще- ствляет некоторую такую эквивалентную модификацию грамматик, при которой добавляется новое правило А а, где а выводимо из А в исход- ной грамматике, а также удаляются некоторые правила, участвующие в выводах А =>+а. В своем простейшем виде подстановка правил означает замену некоторого правила А -> аВр множеством правил А ауР для всех таких у, что В у — правило исходной грамматики (например, подстановка в правило Е сЕаЕ преобразует грамматику Е сЕаЕ\ b в грамматику Е cEab\cEacEaE\b либо в грамматику Е -> cbaE\ccEaEaE\b). Следует заметить, что в результате подстановки символ В может стать бесполезным. Б. Добавление нетерминала. В своем простейшем виде означает замену некоторого правила А -* ару на два правила: А -> аВу и В р, где В не входит в исходную грамматику. Нетрудно заметить, что, осуществляя добавление относительно нескольких правил А-* «Ду I... ...1аДу, мы как бы склеиваем эти правила в одно, получая А аВу и В-Д1...1Д. В. Изменение направления рекурсии. Пусть ис- ходная грамматика не содержит символа В и пусть А -> Aaf I Аа2\... ... I Аак\Pi Iр21...\р& I — все ее правила, у которых А является левой час- тью, причем ни одна из цепочек Д не начинается с А. Тогда изменение направления рекурсии состоит в замене указанных правил на правила А -Д1Д21...1Д|ДВ1^2В1...1ДВ, В -* ajaj ..Лак\а{В\а2В\ ...1а^. Например, в результате изменения направления рекурсии можно преобразовать грамматику Го в эквивалентную ей грамматику Г2 с правилами Е+ Т\ТЕ\ Е' -* + TI + ТЕ', Т-* F\FT\ Т -> ♦ FI ♦ FT, F (Е)\ а. Рассмотренный выше набор допустимых преобразований является до- статочно мощным и в большинстве реальных ситуаций позволяет полу- чать грамматики, обладающие нужным набором свойств. В частности, он позволяет переходить к таким КС-грамматикам, для которых выполня- ются следующие свойства, обычно используемые при трансляции. Неукорачивающая грамматика (или грамматика без е-правил). Это означает, что либо грамматика совсем не содержит правила вида А е, либо в ней имеется ровно одно правило с пустой цепочкой в правой части
250 6.3.1. Стратегии разбора Е -* е, но Е не встречается в правых частях остальных правил грам- матики. Грамматика без цепных правил — в ней нет правил вида Л -* В. Грамматика без циклов — в ней нет выводов А =>+ А. Нормальная форма Хомского, когда грамматика не содержит е-пра- вил и каждое ее правило, отличное от Е е, имеет вид А -> ВС или А -» а для некоторого терминала а и нетерминалов В и С, отличных от Е. Грамматика без левой рекурсии — в ней нет выводов А => Ма. Нормальная форма Грейбах. Грамматика не содержит ^-правил, и каждое ее правило, отличное от Е е, имеет вид Л аа, где а — некото- рый терминал, а а — цепочка, состоящая из нетерминалов. 6.3. Синтаксический анализ 6.3.1. Стратегии разбора. Выходом лексического анализатора (ска- нера) является лексическая свертка транслируемой программы. Процесс дальнейшей трансляции состоит в разборе (или синтаксическом анали- зе) структуры вхождений понятий в лексическую свертку программы и проверке, удовлетворяет ли эта структура синтаксису языка. То, что в качестве результата (и задачи) синтаксического анализа рассматривает- ся построение дерева разбора, ни в коей мере не означает, что в некото- рый момент трансляции это дерево будет физически построено. Тем не менее, рассматривая выполнение любого алгоритма синтаксического анализа, можно всегда проследить в нем процесс построения дерева раз- бора. В процессе синтаксического анализа лексическая свертка программы обычно просматривается слева направо (и мы ограничимся рассмотре- нием только таких алгоритмов). Если программа допустима, то этот про- цесс завершается построением одного из ее деревьев разбора. Узнавая на каждом следующем шаге все большее число символов из лексической свертки транслируемой программы (и, таким образом, узнавая все боль- шее число висячих вершин ее дерева разбора), анализатор пытается по- строить дерево разбора (возможно, не одно, а несколько — все или часть из тех, которые согласуются с уже имеющейся информацией о програм- ме) , как бы заполняя его внутренними вершинами в некотором порядке. В принципе, возможен выбор произвольного порядка заполнения дерева в процессе анализа. Однако этот порядок может в большей степени вли- ять на эффективность разбора в смысле как трудоемкости, так и работы с ошибками (по отношению к той или иной конкретной грамматике). Этот порядок также тесно связан со всем процессом трансляции. В большинстве существующих методов разбора порядок заполнения дерева сводится к одному из двух основных вариантов (или стратегий): сверху вниз и снизу вверх. При заполнении сверху вниз (стратегия так называемого нисходящего анализа) все предшественники каждой запол- няемой в дереве внутренней вершины к этому моменту уже заполнены. Заполнение снизу вверх (стратегия так называемого восходящего ана- лиза) характеризуется тем, что все преемники каждой заполняемой в дереве вершины уже принадлежат построенной части дерева. Таким
6.3.2. Автоматы с магазинной памятью 251 образом, при заполнении дерева при нисходящем анализе движение осу- ществляется от его корня к висячим вершинам, а при восходящем — от висячих вершин к корню. В последнее время стали появляться алго- ритмы разбора, у которых стратегия заполнения вершинами дерева раз- бора характеризуется тем, что на каждом шаге работы такого алгоритма все предшественники каждой заполненной вершины дерева (в том числе и каждой висячей вершины) уже заполнены. Таким образом, эти ал- горитмы в чистом виде не реализуют ни восходящего, ни нисходящего разбора. Описанную стратегию называют стратегией горизонтального анализа, В каждой из перечисленных стратегий можно реализовать алгоритм анализа для произвольного КС-языка. Однако такой разбор не будет столь эффективным, чтобы быть применимым на практике, и будет со- держать большое количество проб и ошибок. Впрочем, можно определить ограниченные классы грамматик, которые поддаются более эффективно- му анализу в той или иной из указанных стратегий. Естественно, эти ограниченные классы грамматик являются менее гибкими как с точки зрения получаемых языков, так и по способам порождения предложений. Следует заметить, что при разработке языков программирования обычно стремятся к простоте записи программ на этом языке (а также к простоте реализации языка), поэтому синтаксис большинства существу- ющих языков программирования допускает задание грамматиками, при- надлежащими одному из указанных ограниченных классов. 6.3.2. Автоматы с магазинной памятью. Автомат с магазинной па- мятью (МП-автомат) — это распознаватель, состоящий из трех частей (рис. 6.3): входной ленты, управляющего устройства с конечной памятью и вспомогательной памяти, используемой в режиме магазина (стека), т.е. в каждый момент доступен только верхний элемент магазина. МП- автомат представляет собой естественную модель синтаксических анализаторов КС-языков. Язык контекстно-свободен тогда и только тог- да, когда он допускается недетерминированным МП-автоматом. Особен- но важным с точки зрения анализируемое™ языков является подкласс КС-языков, состоящий из детерминированных КС-языков, т.е. языков, распознаваемых детерминированными МП-автоматами. Входная лента — это потенциально неограниченная вправо линей- ная последовательность клеток (или ячеек), каждая из которых может содержать любой символ из некоторого заданного входного алфавита. Входная головка в каждый момент обозревает входную ячейку, содер- жимое которой доступно для чтения в данный момент. За один такт работы МП-автомата входная головка может сдвинуться на одну ячейку вправо или остаться неподвижной. Управляющее устройство МП-распознавателя состоит из конечного множества внутренних состояний, среди которых выделены начальное состояние и множество заключительных состояний; а также из управля- ющего отображения, описывающего, в какое внутреннее состояние пе- рейти, какую информацию поместить в магазин и как изменить поло- жение входной головки в соответствии с обозреваемым входным симво- лом, текущим внутренним состоянием и информацией, извлеченной из магазина.
252 6.3.2. Автоматы с магазинной памятью Входная лента Магазин Конфигурация МП-распознавателя — это состояние управляющего устройства, непрочитанная часть входной цепочки, самый левый сим- вол, который обозревается входной головкой, а также содержимое ма- газина. Среди множества всех конфигураций выделяются множества на- чальных и заключительных конфигураций. В начальной конфигурации входная головка обозревает левый символ входной цепочки, управляю- щее устройство находится в начальном состоянии, а магазин содержит специальный начальный символ Н, принадлежащий алфавиту магазин- ных символов МП-автомата. В заключительной конфигурации входная головка обозревает ячейку, расположенную справа от входной цепочки, управляющее устройство находится в одном из заключительных состо- яний, а магазин — пуст. МП-распознаватель работает, проделывая некоторую последователь- ность шагов (тактов) и переходя от одной конфигурации к другой в соот- ветствии с управляющим отображением. При этом распознаватель назы- вается детерминированным, если для каждой конфигурации существует не более одного допустимого шага, и недетерминированным, если таких шагов может быть несколько. Говорят, что МП-распознаватель допускает входную цепочку а, ес- ли, начиная с начальной конфигурации, в которой а записана на входной ленте, он может проделать в соответствии с управляющим отображением последовательность шагов, заканчивающуюся заключительной конфи- гурацией. Язык, определяемый МП-распознавателем, — это множество всех цепочек, которые он допускает. Управляющее отображение МП-распознавателя задается в виде пос- ледовательности команд (Л, a, b) -* (<5, С, а), где А — текущее внутрен- нее состояние; а — обозреваемый головкой символ; b — символ, нахо- дящийся в верхушке магазина и извлекаемый на этом такте; <5 = 1, если входная головка сдвигается вправо, и д « 0, если она сохраняет свое поло- жение; С — следующее состояние; а — цепочка во внутреннем алфа- вите, записываемая в магазин на этом такте (ее правый символ записы- вается первым).
6.3.2. Автоматы с магазинной памятью 253 Например, распознаватель, допускающий язык Е(Г0), где Го — грам- матика арифметических выражений (см. п. 6.2.4), может иметь следу- ющий вид. Набор команд определяется множеством схем команд, в кото- рых Л обозначает любой символ из множества {а, +, ♦, (,)}: (Л, Ь. Н) -* {(О, С, ЕЯ)}, (С, Л, Е) -* {(О, С, Е+ Г), (О, С, Т)}, (С, Л, Т) -> {(О, С, Т*Е),(0, С, Г)}, (С, й, Г) -* {(О, С, (Е)), (О, С, л)}, (С, А, Ь) -* {(1, С, <?)}, (С, В, Я) {(О, D, е)}. Например, первая схема команд определяет такие пять команд МП- распознавателя: (Л, а, Я) -* {(О, С, ЕЯ)}, (Л,+, Я) - {(О, С, ЕЯ)}, (Л,«*,Я) {(О, С, ЕЯ)}, (Л, (,Я) - {(О, С, ЕЯ)}, (Л, ),Я) -> {(О, С, ЕЯ)}. В МП-распознавателе состояние А является начальным, a {D} — это множество заключительных состояний. Обозначим конфигурацию распознавателя тройкой (С, а, /?), где С — состояние, а — неиспользованная часть входной цепочки, /3 — содер- жимое магазина (самый левый символ цепочки /3 является верхним сим- волом магазина). Получаем, что для входной цепочки а + а ♦ а возможна среди других следующая последовательность конфигураций: (Л, я + а * а. Н). (С, а + а ♦ «, ЕЯ), (С, а + а ♦ а, Е + TH). (С, а + а ♦ а. Т+ TH). (С, а + + а* a. F+ TH). (С, а+а ♦ а. а + ТН). (С. +а * а. +ТН). (С.a* a. TH). (С, а* а. Т* FH). (С. a* a. F * FH). (С. a* a. a* FH). (C.*a*FH). (С. а. FH). (С. а. аН). (С, е. Н). (D. е. е). По существу, этот распознаватель недетерминированно порождает все предложения языка и сравнивает их с входной цепочкой, попадая в заключительную конфигурацию (т.е. конфигурацию вида (D. е. е). где D — заключительное состояние) тогда и только тогда, когда одно из порождаемых предложений совпадает с входной цепочкой. Можно рассматривать различные обобщения понятия МП-распозна- вателя. Одно из таких обобщений связано с тем, что на каждом такте МП-распознаватель может извлекать из магазина ограниченной длины цепочку верхних символов магазина (в частности, пустую цепочку). Та- кой обобщенный распознаватель для языка Е(Г0) может иметь следую- щую последовательность схем команд: (Л, Ь.Н) -* {(1, С, bh)}. (С. Ь. е) -* {(1,С, Ь)}. (С, d. Т) -> {(О, С, Е)}, (С, </, Е+Т) {(О, С, Е)},
254 6.3.3. Нисходящий МП-распознаватель <C,d, Т * F) {(О, С, Г)}, (С, tZ, F) -> {(О, С, Т)}, (С, J, (Е)) {(О, С, F)}, (С, d, а) -* {(О, С, F)}, (С, В, ЕН} -> {(О, D, е)} для всех b G {а, +, ♦, (,)} и б/6 {«, +, (,), В}. Здесь А — начальное состояние, a {D} — множество заключительных. Для входа а + а ♦ а рас- познаватель может пройти следующую последовательность конфигура- ций: (Л, а + а ♦ а, Н), (С,+ а* а, аН), (С, +а ♦ a, FH), (С, + а ♦ л, TH), (С, а * а, +ТН), (С, *а, а+ТН), (С, *а, F+TH), (С, a, ♦F + TH), (С, е, a*F+TH), (С, е, F* F+TH), (С, е, Т* F+TH), (С, е, Т + ТН), (С, е, Е+ТН), (С, е, ЕН), (D, е, е). Поскольку при таком обобщении из магазина извлекаются цепочки ограниченной длины в конечном наборе символов, т.е. такие, которые можно рассматривать как коды символов некоторого другого конечного набора символов, то это обобщение не увеличивает класса допускаемых языков. 6.3.3. Нисходящий МП-распознаватель. Алгоритмы нисходящего синтаксического анализа связаны с моделированием так называемого нисходящего МП-распознавателя, который осуществляет распознавание путем недетерминированного порождения левого вывода предложения языка и сравнения его с распознаваемой цепочкой. Пример такого МП- распознавателя для грамматики Го приведен в п. 6.3.2. Рассмотрим дерево левых выводов некоторой грамматики Г = (V, Ж, Е, Р). Это дерево рекурсивно определяется следующим образом: корню дерева сопоставлена цепочка, состоящая из единственного символа Е; если цепочка а сопоставлена некоторой вершине р дерева, то для каждой цепочки fl, получаемой левой подстановкой из а, заводится вершина дерева и объявляется преемником вершины р. Введем также следующие термины. Терминальным префиксом некоторой цепочки а будем назы- вать наибольшей длины префикс цепочки а, состоящий из терминалов. Будем говорить, что цепочка а согласуется с цепочкой fl, если терми- нальный префикс цепочки а является префиксом цепочки fl либо fl явля- ется префиксом цепочки а. В терминах дерева левых выводов работа нисходящего МП-распозна- вателя может быть описана следующим образом. Если распознается предложение, то, начиная с корня этого дерева, распознаватель на каж- дом шаге недетерминированно переходит к одному из преемников изуча- емой вершины до тех пор, пока цепочка этой вершины не совпадает с распознаваемым предложением. Если же распознаваемая цепочка не яв- ляется предложением, то распознаватель убеждается в том, что в дереве левых выводов нет вершины, цепочка которой совпадала бы с рассмат- риваемой цепочкой. Обычный подход к моделированию нисходящего распознавателя свя- зан с реализацией специального обхода тех вершин дерева левых выво- дов, цепочки которых согласуются с входной цепочкой. Такие вершины
6.3.3. Нисходящий МП-распознаватель 255 называются достижимыми относительно данной входной цепочки. При этом используется очевидное свойство, что преемник недостижимой вер- шины является также недостижимой вершиной. При описании алгоритма будем предполагать, что все преемники каждой вершины дерева левых выводов каким-то образом упорядочены. Алгоритм ИНИЦИАЛИЗАЦИЯ. Объявляем корень дерева левых выводов рас- сматриваемой вершиной и переходим на ШАГ. ШАГ. Если цепочка рассматриваемой вершины совпадает с входной цепочкой, то на УСПЕХ; в противном случае выбираем среди преем- ников рассматриваемой вершины первую достижимую вершину, которая ранее не рассматривалась. Если такая вершина найдется, то объявляем ее рассматриваемой и переходим на ШАГ; иначе переходим на ВОЗ- ВРАТ. ВОЗВРАТ. Если рассматриваемая вершина имеет предшественника, то объявляем его рассматриваемой вершиной и переходим на ШАГ; в противном случае переходим на НЕУСПЕХ. УСПЕХ. Входная цепочка является предложением. НЕУСПЕХ. Входная цепочка не является предложением. Сделаем несколько замечаний к алгоритму. А. Дерево вывода. При движении по дереву левых выводов мы всегда можем иметь дерево вывода цепочки рассматриваемой вер- шины. При этом переход от рассматриваемой вершины к рассмотрению ее достижимого преемника соответствует добавлению всех преемников к первой висячей вершине дерева вывода, помеченной нетерминалом, а переход к предшественнику рассматриваемой вершины — удалению ви- сячих вершин дерева вывода, образующих основу. Далее мы можем за- нумеровать все правила и упорядочить всех преемников каждой вер- шины дерева левых выводов в соответствии с номерами применяемых правил. Это означает, что если каждую вершину дерева вывода метить номером правила, с помощью которого мы последний раз пытались до- бавить преемников к этой вершине, то действия каждого шага работы алгоритма полностью определяются в терминах текущего состояния пос- троенного дерева вывода и его пометок. Б. Проблема остановки. Время работы нисходящего ал- горитма по распознаванию некоторой цепочки а связано с числом вер- шин дерева левых выводов, достижимых относительно а. Нетрудно ви- деть, что таких вершин может быть бесконечно много даже для одноз- начной грамматики, если она является рекурсивной слева, поскольку может существовать левый выводе =>* rjA/З =>^ у Ад, где rj согласуется с <5. Поэтому, чтобы гарантировать конечность любого пути по дереву левых выводов от его корня до первой вершины, у которой цепочка либо не согласуется с исходной цепочкой, либо совпадает с ней, мы должны пот- ребовать, чтобы грамматика не являлась рекурсивной слева. В. Локализация ошибок. Описанный алгоритм обладает слабыми возможностями в смысле локализации ошибок — если входная цепочка не является предложением, то он просто объявит о том, что программа недопустима (нельзя отличить возврат, вызванный ошибкой,
256 6.3.4. LL-грамматики и //-распознаватель от возврата, возникшего из-за неправильной попытки). Чтобы получить более подробную информацию, можно добавить в грамматику специаль- ные правила, порождающие распространенные ошибки, и использовать их появление в выводе как сигнал появления ошибки во входной цепоч- ке. Однако этот прием нельзя признать достаточно практичным. Г. Приемы эффективизации алгоритма. Известен ряд приемов, позволяющих слегка ускорить описанный алгоритм. На- пример, если грамматика не содержит е-правил, мы можем не рассмат- ривать те вершины дерева левых выводов, длины цепочек которых пре- вышают длину входной цепочки, и таким образом исключить зацик- ливание алгоритма анализа даже для рекурсивных слева грамматик. Можно уменьшить число возвратов при распознавании предложения языка, упорядочивая правила грамматики (см. замечание 6.3.3.А) таким образом, чтобы проверять наиболее вероятные альтернативы первыми. Перед каждым достроением дерева вывода можно также осуществлять заглядывание вперед по входной цепочке на несколько символов й опре- делять, надо ли пытаться использовать рассматриваемое правило для достроения в текущей ситуации или нет, если из него (из правой части этого правила) не выводится цепочка, префиксом которой являются эти символы. Однако все эти и другие известные приемы в общем случае не делают алгоритм существенно более эффективным, и число шагов, необ- ходимых для разбора с помощью этого алгоритма, может быть огромным. Ниже мы увидим, что для ограниченных классов грамматик с помощью заглядывания вперед можно полностью устранить необходимость воз- вратов. 6.3.4. LL-грамматики и LL-распознаватель. Рассмотрим более под- робно модификацию алгоритма нисходящего разбора, связанную с загля- дыванием вперед на к символов. В этом случае каждая вершина дерева левых выводов р снабжается последовательностью так называемых кон- текстных множеств М^р), М2(р), ..., М^р), где Z — число преемников у р. Эти контекстные множества для некоторой вершины р определяются следующим образом. Пусть /3 — терминальный префикс цепочки, сопо- ставленной вершине р, тогда некоторая у принадлежит Mt(p) в том и только том случае, если из z-го преемника вершины р достижима вер- шина, цепочка которой содержит только терминалы и представима в виде /Зуц, где либо q — пустая цепочка и I у I < к, либо I у I « к и q * е. Модификация общего нисходящего алгоритма (получившая название LL-анализатора) связана с изменением понятия достижимости некото- рой вершины дерева левых выводов относительно цепочки а, В LL-ана- лизаторе понятие достижимости определяется следующим образом. Ко- рень дерева достижим относительно а, если его контекстные множества содержат цепочку, являющуюся префиксом цепочки а; вершина р с предшественником q достижима относительно а, если цепочка а пред- ставима в виде (3yq, где /? — терминальный префикс цепочки, сопостав- ленной вершине q, а у принадлежит множеству А/.(#), если р — /-й преемник у q. Ясно, что таким образом модифицированный алгоритм будет безвоз- вратным при распознавании предложения (или, что то же самое, де-
6.3.5. Восходящий МП-распознаватель 257 терминированным) тогда и только тогда, когда не будут пересекаться два любых контекстных множества каждой вершины дерева левых выво- дов*. Грамматики, удовлетворяющие этому свойству, получили назва- ние LIAk)-грамматик. Грамматика называется LL-грамматикой, если она LL(k)-грамматика для некоторого к. Заметим, что, так изменив понятие достижимости и работая с LL- грамматикой, мы тем не менее можем прийти к выполнению ВОЗВРАТа. Однако это возможно в том и только в том случае, когда входная цепочка не является предложением; причем первый переход на ВОЗВРАТ осуще- ствляется сразу же, как только рассматриваемая часть входной цепочки перестает быть префиксом предложения в данной LL-грамматике. Это делает LL-анализатор (в ВОЗВРАТе которого сгруппированы действия, связанные с обработкой ошибок) удобным для работы с недопустимыми программами. Рассмотрим частный случай LLAk) -грамматик, в которых к - 1 и нет е-правил. Ясно, что при таких ограничениях для любых двух правил с одинаковой левой частью справедливо следующее. Пусть а и [5 — правые части этих правил, тогда любая цепочка, выводимая из а, не начинается с терминала, с которого может начинаться цепочка, выводимая из /2. Это дает возможность организовать анализатор в виде набора процедур: по одной процедуре для каждого нетерминала и по одной процедуре для каждого вхождения терминала в правые части правил грамматики. Каж- дая процедура, связанная с некоторым вхождением терминала, осущест- вляет сравнение указанного терминала с первым символом входной стро- ки и в случае их несовпадения сигнализирует об ошибке (и может осу- ществить некоторые другие действия, связанные с обработкой данной ошибки), а в случае совпадения удаляет первый символ из входной стро- ки. Процедура, связанная с некоторым нетерминалом А, имеет вид опе- ратора выбора, число альтернатив которого — это число правил, у кото- рых А — левая часть плюс единица. Выбор состоит в рассмотрении перво- го символа входной строки и переходе к альтернативе, либо обрабатыва- ющей соответствующее правило, либо содержащей обработку ошибки. Обработка некоторого правила А -> а{а2...аг представляет собой последо- вательность вызовов процедур, связанных с а2, ..., а$ соответственно. Поскольку возможно, что а- = А для некоторого /, эта процедура в общем случае является рекурсивной. Работа анализатора, построенного таким образом (получившая название рекурсивного спуска), начинается с вы- зова процедуры, ассоциированной с символом программы. Эта процеду- ра в процессе своего выполнения осуществляет рекурсивные вызовы дру- гих процедур; а пустота входной строки в момент ее нормального завер- шения говорит о том, что разбираемая цепочка является предложением. 6.3.5. Восходящий МП-распознаватель. Алгоритмы синтаксического анализа, реализующие восходящую стратегию, связаны с моде- * Заметим, что этим ликвидируются не только явные возвраты нисходящего анализа при распознавании предложения (т.е. те, которые вынесены в ВОЗВРАТ), но и неявные, которые связаны с поиском достижимого преемника рассматриваемой вершины при выполнении ШАГа. 9 ВА. Евстигнеев, В.Н. Касьянов
258 6.3.5. Восходящий МП-распознаватель лированием так называемого восходящего МП-распознавателя, в кото- ром правила подстановки недетерминированно и "в обратном направ- лении” применяются к входной цепочке с тем, чтобы породить такую последовательность цепочек ар...,аш, что ее обращение (т.е. последова- тельность ат => атА => ...=> ах) представляет собой правый выход входной цепочки. Пусть некоторая цепочка а имеет вид y/3q и пусть в грамматике существует правило А -* /3. Тогда будем говорить, что редукция цепочки а относительно правила А -*/3 определена, если цепочка у не содержит нетерминалов; эта редукция состоит в преобразовании цепочки а в це- почку уКтр При этом будем называть у — левым, а г\ —.правым контек- стами данной редукции. Понятно, что если существует правый вывод Е =>* уА?! => yfl?j, то /3 является основой дерева вывода, представляющего данный вывод. Рассмотрим дерево редукций некоторой входной цепочки а, определя- емое следующим образом: корню дерева соответствует цепочка а; если некоторая цепочка /3 сопоставлена некоторой вершине р, то для каждой возможной редукции цепочки /3 заводится новая вершина дерева — пре- емник вершины р, которому ставится в соответствие цепочка, получае- мая в результате этой редукции. В терминах дерева редукций работа восходящего МП-распознавателя описывается следующим образом. На- чиная с корня дерева и недетерминированно переходя на каждом шаге к рассмотрению одного из преемников рассматриваемой вершины, распоз- наватель либо достигает вершины, которой соответствует цепочка Е, если а — предложение, либо убеждается, что в дереве нет такой вер- шины, если а не является предложением. Обычный подход к моделированию работы восходящего МП-распоз- навателя с некоторой цепочкой а связан с реализацией поиска в глубину по дереву редукций цепочки а. Предполагается упорядоченность правил грамматики, на основе которой определяется порядок преемников каж- дой вершины дерева редукций следующим образом. Вершина р предше- ствует вершине q тогда и только тогда, когда для редукций Р(р) и P(q), соответствующих вершинам р и q, выполнено одно из следующих свойств: правый контекст редукции Р(р) превышает по длине правый контекст редукции P(q); длины правых контекстов редукций Р(р) и P(q) совпадают, но правило, относительно которого осуществляется редукция Р(р), предшествует соответствующему правилу редукции P(q). Алгоритм ИНИЦИАЛИЗАЦИЯ. Объявляем рассматриваемой вершиной корень дерева редукций входной цепочки и переходим на ШАГ. ШАГ. Если Е — цепочка рассматриваемой вершины, то на УСПЕХ; в противном случае либо объявляем рассматриваемым первый, ранее не рассмотренный преемник рассматриваемой вершины и переходим на ШАГ, если нерассмотренный преемник есть, либо переходим на ВОЗВРАТ, если его нет. ВОЗВРАТ. Если рассматривая вершина имеет предшественника, то объявляем его рассматриваемой вершиной и переходим на ШАГ; в про- тивном случае переходим на НЕУСПЕХ.
6.3.6. Грамматики предшествования 259 НЕУСПЕХ. Входная цепочка не является предложением. УСПЕХ. Входная цепочка является предложением. Сделаем несколько замечаний. А. Дерево вывода. Можно переформулировать работу алго- ритма в терминах работы с деревом вывода. При этом переход от рас- сматриваемой вершины к рассмотрению ее преемника связан с добав- лением вершины в дерево, а выполнение ВОЗВРАТа — удалением вер- шины из дерева. Б. Проблема остановки. Алгоритм не зацикливается, если грамматика не содержит ^-правил и не существует А =>+ А, что связано с наличием цепных правил в грамматике. В. Проблема возвратов. Из-за громадного количества воз- можных возвратов алгоритм восходящего анализа в чистом виде являет- ся очень неэффективным; он также плохо приспособлен для обработки недопустимых программ. Для преодоления возвратов восходящий ана- лиз должен быть организован таким образом, чтобы по префиксу любой правовыводимой цепочки, содержащему основу этой цепочки, он мог однозначно определять необходимую редукцию, т.е. основу цепочки и то правило грамматики, которое должно быть применимо. В общем случае это сделать невозможно и возвраты сохраняются, хотя можно указать ряд методов, которые несколько уменьшают их количество» Однако, если рассматривать более ограниченные классы, чем КС-языки, то можно указать довольно простые критерии, позволяющие восходящему анализу избегать возвратов. 6.3.6. Грамматики предшествования. Рассмотрим следующие отно- шения между символами грамматики. Первое отношение, обозначаемое символом =, состоит из множества всех таких пар символов А и D (обо- значаем А = D), которые расположены рядом (в указанном порядке) в основе некоторой правовыводимой цепочки*. Два символа А и D нахо- дятся в отношении, записываемом в виде А <• D, тогда и только тогда, когда А и D расположены рядом в некоторой правовыводимой цепочке таким образом, что А — непосредственно предшествует основе, a D — первый символ основы. Последнее отношение •> определяется аналогич- но отношению <• с тем отличием, что A если А завершает основу некоторой правовыводимой цепочки, a D в этой цепочке следует непос- редственно за основой**. На первый взгляд кажется, что нахождение этих отношений для некоторой грамматики требует рассмотрения всех ее правых выводов, однако довольно простые для проверки условия их вы- полнения можно сформулировать в терминах грамматических правил (см. п. 6.4.1). Понятно, что если между любыми двумя символами грамматики вы- полняется не более одного отношения и в грамматике нет ^-правил, то в процессе восходящего анализа предложения языка мы всегда будем пра- ♦ Заметим, что отношение не обязательно симметрично, т.е. если А - D, то у нас нет причин утверждать, что D - А. ♦♦ Если А •> D, то D — терминал.
260 6.3.6. Грамматики предшествования вильно выделять основу; причем, если в грамматике также не будет двух правил с одинаковыми правыми частями, возвратов не потребуется. Грамматики, удовлетворяющие указанным двум условиям, получили название грамматик простого предшествования. Например, грамматика Го не является грамматикой простого предшест- вования, поскольку в ней + = Т и + <• Т, а также (=Е и (<• Е. Однако путем добавления нетерминалов она может быть преобразована в грамматику D, D-*T\D+7\ Т-* К, К-+ F\К ♦ Г, F (£) I а, которая является грамматикой простого предшествования. Алгоритм восходящего анализа для рассматриваемого класса грам- матик очень прост. Работа его начинается с исполнения СДВИГа при пустом рабочем СТЕКе и ВХОДе, содержащем разбираемую цепочку. Алгоритм СДВИГ. Помещаем первый символ из ВХОДа в С JEK и переходим на СРАВНЕНИЕ СРАВНЕНИЕ. Если ВХОД пуст, то переходим на РЕДУКЦИЮ; в противном случае рассматриваем А — верхний символ СТЕКа и D — первый символ\ВХОДа. Если А = D или А <• £>, то переходим на СДВИГ; иначе переходим на РЕДУКЦИЮ, если A •>£>, и на НЕУСПЕХ в про- тивном случае. РЕДУКЦИЯ. Пусть Аг..Ак — содержимое СТЕКа, где At — его верх- ний символ. Если не существует такого /, что Ai >А-+1, то переходим на ЗАВЕРШЕНИЕ; иначе выбираем минимальное /, обладающее этим свойством. Если не существует правила А А{А2...А^ то переходим на НЕУСПЕХ; в противном случае заменяем в СТЕКе цепочку AlA2...Ai символом А и переходим на СРАВНЕНИЕ. ЗАВЕРШЕНИЕ. Переходим на УСПЕХ, если ВХОД пуст, а в СТЕКе содержится цепочка, непосредственно выводимая из символа Е, и на НЕУСПЕХ в противном случае. УСПЕХ. Входная цепочка является предложением. НЕУСПЕХ. Входная цепочка не является предложением. При практической реализации описанного алгоритма возникает воп- рос хранения указанных отношений. Занумеровав символы грамматики, можно хранить указанные отно- шения в виде так называемой матрицы предшествования — квадратно- го массива, содержащего т2 элементов, где т — число символов грам- матики. Однако в реальных языках программирования число символов грамматики довольно велико (например, для языка Алгол-60 при син- таксическом анализе различается не менее 70 грамматических элемен- тов, а в описании языка их 226), поэтому матрица предшествования на практике может быть довольно большой. Следует заметить, что обычно
6.3.7. Горизонтальный разбор 261 отношения определены не для всех пар символов грамматики. Это дает возможность за счет увеличения времени поиска информации экономить память, используя различные методы сжатия разреженных матриц. Другой подход к хранению отношений предшествования связан с ис- пользованием так называемых функций предшествования Ф1 и Ф2. Эти функции приписывают числовые значения символам грамматики таким образом, что для любых символов А и D из выполнения одного из соотно- шений Л = £>, А <• Du А > D следует соответственно Ф|(Л)«Ф2(1», Ф/Л) < <Ф2(Л) иФ2(Л) >Ф2(1>). Понятно, что функции предшествования для своего хранения требу- ют существенно меньших объемов памяти, поскольку они могут быть заданы двумя векторами по т элементов каждый. Однако эти функции существуют не для всех грамматик простого предшествования. Другим очень важным недостатком функции предшествования является то, что они задают отношения предшествования между каждой парой символов и, таким образом, затрудняют работу с недопустимыми программами. В грамматике простого предшествования для определения основы ис- пользовалось по одному символу из ее правого и левого контекстов. Мож- но увеличить число рассматриваемых символов и таким образом рас- ширить класс языков, распознаваемых с помощью описанного алгорит- ма. Например, для определения начала основы можно рассматривать не один, а два символа, предшествующих основе, а для определения ее конца — два символа, следующих за основой (так называемые грам- матики (2.1) (1.2)-предшествования), или еще больший контекст. Одна- ко для транслятора хранение отношений, связывающих три и более сим- вола, становится обременительным с точки зрения объема памяти. Поэ- тому в том случае, когда между двумя символами существует более одно- го отношения, на практике либо перестраивают грамматику, вводя в нее новые символы, либо отношения по двум символам дополняют отно- шениями по трем символам для тех пар, для которых существуют кон- фликтные ситуации. 6.3.7. Горизонтальный разбор. Как восходящий, так и нисходящий разбор в общем случае работает с возвратами. Можно избежать возвра- тов при нисходящем разборе, если осуществить параллельное движение по дереву левых выводов, когда на каждом шаге рассматривается не одна, а некоторое множество ее вершин. Однако такой способ, при кото- ром все попытки разбора производятся параллельно, связан с вопросом конечного кодирования бесконечного числа возможных деревьев. Этот вопрос решается в горизонтальном разборе. Алгоритмы горизонтального анализа связаны со специальным спосо- бом рассмотрения вершин дерева разбора исходного предложения (в про- цессе чтения его символов слева направо). Этот способ, который мы бу- дем называть горизонтальным движением, характеризуется тем, что не- которая вершина р рассматривается тогда и только тогда, когда р являет- ся либо висячей вершиной, соответствующей читаемому символу вход- ного предложения, либо предшественником рассматриваемой вершины. А Э ВА. Евстигнеев, В.Н. Касьянов
262 6.3.7. Горизонтальный разбор В качестве примера рассмотрим простую грамматику {Е -» ЕВ\а, В be I d} и дерево разбора для некоторого предложения abed, которое мы будем изображать специальным образом (рис. 6.4). Если под этим деревом поместить исходное предложение, а границы шагов движения отметить штриховыми линиями, перейдем к картине (рис. 6.5), из кото- рой видно, что непосредственно после выполнения первого шага, на ко- тором был прочитан символ а, мы закончили рассмотрение двух вершин дерева и собираемся перейти к рассмотрению еще двух вершин. Е Е В Е В а b с d Рис. 6 4 Поскольку при горизонтальном движении рассмотрение некоторой вершины предполагает одновременное рассмотрение ее преемников, это движение определяет также движение по правой части каждого правила, участвующего в выводе исходного предложения. Например, после перво- го шага (при движении по дереву разбора предложения abed} полностью пройдены правая часть правила Е а и один символ в правой части правила Е ЕВ. 0 12 3 4 i i i i i । i 1 i i Е I В Е i в а ь с i i d i i i i i a j b ; c ; d Puc. 6.5 С каждым z-м шагом горизонтального движения связывается множе- ство состояний £., описывающих положения при движении по правилам грамматики непосредственно перед выполнением z-ro шага. Каждое со- стояние из 5,. — это пара [Л а * /31 /], состоящая из некоторого пра- вила А -» а • /3, в которой точка разделяет правую часть правила на две части — ту часть, которая уже пройдена до z-ro шага, и ту часть, которую
6.3.7. Горизонтальный разбор 263 предстоит пройти на следующих шагах, а также из числа I — номера шага, на котором начинается движение по данному правилу. Для нашего примера множества состояний имеют следующий вид: 50= {[Е-+ ЕВ\0], [Е-+ <210]}, S^UE^E - BIO], [Е-> а- 10], [ВBell]}, S2 = {[B-+b • ell]}, S3= {[В -+ be-11 ], {Е-» EB-10], [E-> E • BIO], [B -> -dl3]}, S4={[B-> J-13], [E EBIO]}. На первый взгляд кажется, что рассмотренные множества состояний не дают полного описания горизонтального движения, поскольку, на- пример, в нашем примере 50 никак не отражает того факта, что на пер- вом шаге начинается рассмотрение нескольких вершин, каждая из кото- рых имеет пометку Е и преемников с пометками Е и В, а состояние S2 не содержит информации о том, что непосредственно перед вторым шагом рассматриваем три вершины дерева. Тем не менее для любого предло- жения совместное рассмотрение его состояний позволяет восстановить дерево разбора данного предложения (см. ниже). Справедливы следующие свойства состояний, описывающих последо- вательность шагов горизонтального движения. А. Множество So содержит некоторое состояние [Е -» 10 ]. Б. Для любого i, если Si содержит некоторое состояние {В а - Aft I к ], где А — нетерминал, St также содержит некоторое состояние [А-* -ylz]. В. Для любого I > 0, если а — читаемый символ на i-м шаге и SiA содержит некоторое состояние [А -> а • а(3\ Л], то множество St со- держит состояние [А -» аа • /?1£]. Г. Для любого z > 0 из того, что некоторое состояние [А -> а • I к ] содержится в и существует некоторое состояние [В -» у • At] 11 ] в Sk, следует, что S, содержит состояние [В -» у А • ц I /]. Д. Если п — длина исходного предложения, то Sn содержит некото- рое состояние [Е -» а • 10 ]. Е. Для любого i некоторое состояние [А -> а • (3 I к ] принадлежит Si только в том случае, если выполнено одно из следующих свойств: 1) k = i, а = е и Sj содержит некоторое состояние [С > г/ ’ Ад I /]; 2) k < v, а = = т]Ь, где b — читаемый на i-м шаге символ, a Si { содержит состояние [А г] • bft\k}. (При выполнении этого условия мы будем называть состояние [А -+ г/ • Ь/3\к] "сестрой" состояния [А -* а • /3\к], еслиг] & ед; 3) к = 0, z = 0, А = Е и а = е; 4) к < i; а = г]В, где В — нетерминал, содержит некоторое состояние [В d -1/], a S, содержит состояние [А т] • В/3\к]. (При выполнении этого условия мы будем говорить, что состояние [В -» д • 11 ] является "дочерью" состояния [А -» а Д\к],а также называть состояние [А т] • В/3\к] "сестрой" состояния [А -» а • /3 г к ], если т] ед Пусть 50, ..., 8п — последовательность состояний горизонтального движения по дереву разбора исходного предложения. Добавим к этим состояниям фиктивное состояние [Е -* Е-10 ], дочерью которого объявим
264 6.3.8. Алгоритм Эрли состояние [Е -> а • 10 ], принадлежащее множеству 5Л; и рассмотрим дво- ичное дерево состояний с отношениями дочь и сестра, корнем которого является фиктивное состояние. Это двоичное дерево состояний для на- шего примера будет иметь вид, приведенный на рис. 6.6. Здесь штрихо- вая стрелка связывает состояние с его дочерью, а сплошная — с его сестрой. [Е-ЕЦ) ] [£*£-В|0] [£*££• 10 j [Е-Е'В |0] [Е+ЕВ-10] [В-я|3] [Е-я-10] [В-дс-|1] Рис. 6.6 [В*д-с|1] По существу, указанное двоичное дерево — это другая форма дерева разбора, пометкой вершины которого является символ, расположенный в состоянии перед точкой; отношение ’’дочь" указывает на последнего (младшего) сына данной вершины; а отношение "сестра" связывает по- следующего сына с предыдущим, т.е. вершину с ее старшим братом. 6.3.8. Алгоритм Эрли. Алгоритм горизонтального разбора в общем случае считывает символы входной цепочки слева направо и реализует одновременное горизонтальное движение по всем тем деревьям разбора, которые согласуются с уже рассмотренным префиксом входной цепочки. Содержательно множество состояний после п шагов алгоритма, на кото- рых была прочитана цепочка г/, является объединением всех множеств состояний, которые можно получить, осуществив п шагов горизонталь- ного движения по каждому из деревьев разбора предложений с префик- сом Понятно, что так определенное множество всегда будет конечным, поскольку существует только конечное число различных пар [А а • /3I к ], в которых 0 < к < п. Алгоритм ИНИЦИАЛИЗАЦИЯ. В пустое множество 50 включаем для каждого правила Е -+ а состояние [Е -» • а 10 ]; устанавливаем номер шага i рав- ным нулю и переходим на ПОСТРОЕНИЕ ВНИЗ. ПОСТРОЕНИЕ ВНИЗ. Определяем минимальное множество состо- яний, содержащее Si и удовлетворяющее свойству, описанному в 6.3.7.Б. Это множество берем в качестве Si и переходим на СДВИГ и ПОСТРОЕ- НИЕ ВВЕРХ. СДВИГ и ПОСТРОЕНИЕ ВВЕРХ. Если мы прочитали всю входную цепочку, то на ЗАВЕРШЕНИЕ; иначе считываем следующий символ из входной цепочки и увеличиваем значение i на единицу. В качестве S-
6.3.9. ЛЯ-грамматики 265 рассматриваем минимальное множество, удовлетворяющее свойству 6.3.7.В. Если некоторое состояние вида [А -> а - 1Л] содержится* в S-, то увеличиваем Si таким образом, чтобы выполнялось свойство 6.3.7.Г, а каждое добавляемое состояние удовлетворяло свойству 4 из 6.З.7.Е. Пе- реходим на ПОСТРОЕНИЕ ВНИЗ. ЗАВЕРШЕНИЕ. Если множество 5, содержит некоторое состояние вида [£-»«• 10], то входная цепочка является предложением; в про- тивном же случае не,является. Таким образом, внутри каждого шага работы алгоритма горизонталь- ного разбора в общем случае осуществляются попытки достроения дерева разбора как сверху вниз, так и снизу вверх, при этом отсекаются те вершины (те попытки), которые могут быть построены при движении только снизу вверх или только сверху вниз. Время работы описанного алгоритма пропорционально дг?, где т — длина входной цепочки, причем для однозначных грамматик временная граница пропорциональна т2, а для некоторых достаточно больших под- множеств однозначных грамматик даже линейна. Следует заметить, что для нисходящего (или восходящего) анализа временная граница пропор- циональна с"1, где с — некоторая константа. Однако эти верхние оценки трудоемкости не доказывают, что один метод практически быстрее дру- гого. 6.3.9. AR-грамматики. Алгоритм горизонтального разбора осуществ- ляет одновременное горизонтальное движение по всем деревьям разбора, отсекая на каждом шаге те из них, которые не согласуются с префиксом входной цепочки, рассмотренным к этому шагу. Этот алгоритм можно модифицировать, включив в него заглядывание вперед на к символов по входной цепочке, чтобы расширить возможности алгоритма заранее отсекать попытки (деревья), обреченные на неудачу. Каждое правило грамматики А -» а можно снабдить множеством ^-сим- вольных префиксов правых контекстов редукций относительно данного правила. Теперь предположим, что на каждом шаге алгоритма (при вы- полнении СДВИГ и ПОСТРОЕНИЕ ВВЕРХ) к множеству нужно до- бавить некоторое состояние [А-> а • I /]. Однако нам известен возможный контекст правила А-* а и мы можем проверить, образуют ли к первых непрочитанных символов (из входной цепочки) цепочку из этого кон- текста. Если нет, то состояние [А-> а • I /] можно не включать в S-. Понятно, что с ростом числа к способность к раннему отсечению у так модифицированного алгоритма увеличивается. Однако одновременно с ростом к довольно быстро увеличивается объем памяти, необходимый для хранения контекстов правил, число символов в котором оценивается величиной к • М, где N — число терминалов в грамматике. Эти допол- нительные затраты с ростом к довольно быстро компенсируют те преиму- * Наличие в 5; некоторого состояния вида {А -♦ а • I £] говорит о том, что существует правый вывод Е =>* fiat] =>* в котором 5 — префикс входной цепочки, состоящий из i символов, а а — основа цепочки fiat].
266 6.3.10. £Л-анализатор щества, которые получаются за счет раннего отсечения бесполезных по- пыток. Можно рассмотреть класс грамматик (так называемые PR (к) -грам- матики), для которых описанная выше модификация горизонтального анализа осуществляет полное отсечение деревьев, обреченных на неуда- чу. Этот класс грамматик довольно широк, поскольку в момент опреде- ления редукции алгоритм неявно использует информацию, полученную из ее левого контекста, а также к символов правого контекста. Однако существует более широкий класс грамматик, поддающийся эффективно- му анализу. Этот класс, называемый LR. в точности порождает класс языков, распознаваемых детерминированными МП-распознавателями. Для него имеется возможность определения редукции, если известны полный контекст и правый контекст длины к предполагамой основы. Грамматика является-грамматикой, если для любых двух пра- вых выводов Е’ =>* (ЗАд => и Е' =>* аВа> => /Зуг] в пополненной грам- матике, полученной из исходной путем добавления нового начального символа Ег и правила* Е' -* Е, из того, что ^-символьный префикс це- почки у совпадает с ^-символьным префиксом цепочки д, следует, что А = В, а = (3 и д=тр Грамматика является LR-грамматикой, если она LR (к) -грамматика для некоторого к. Следует также заметить, что для любой LR (к) -грамматики существу- ет АЯ(1)-грамматика, порождающая тот же язык. 6.3.10. ER-анализатор. По любой LR (к)-грамматике можно автома- тически построить так называемый LR(k)-анализатор, осуществляющий разбор, чередуя сдвиги и редукции, с помощью двух магазинов (см. п. 6.4.4). Один из магазинов, который мы будем обозначать МАГ1, служит для хранения цепочки (внутренних) состояний анализатора, а второй — МАГ2 — для хранения редуцированного префикса входной цепочки. При своей работе анализатор использует две функции — действия и перехо- дов. Пусть X — множество состояний, а У — множество терминальных цепочек, длина каждой из которых не превышает к, а /={1,2,..., п}, где п — число правил грамматики; тогда функция действия отображает мно- жество пар X х У в множество пар / U {сдвиг, ошибка, допуск}, а функ- ция перехода отображает множество пар X х (V U W) в множество X U U {ошибка}. В качестве небольшого примера рассмотрим следующую грамматику Г3: 1) S, 2) S -> SaSb, 3) S-e. Она, как нетрудно заметить, является LR(k)-грамматикой. Функции действия и перехода для нее можно задать таблицами, приведенными на рис. 6.7. Здесь С — сдвиг, О — ошибка, D — допуск, {То, 7\, Т2, Т3, Т4, * Если символ Е не встречается в правых частях правил исходной грамматики, то в определении LR(k)-грамматики вместо Е' можно взять Е (т.е. рассматривать правые выводы в исходной, а не в пополненной грамматике).
6.3.10. ЛЯ-анализатор 267 Т5, Т6, Т7} — множество состояний, То — начальное состояние. а b е S а b То 3 0 3 То 7| 0 0 71 С 0 D 7| 0 Т2 0 Т2 3 3 0 72 Тз 0 0 7з С С 0 7з 0 74 Т5 74 3 3 0 74 Те 0 0 75 2 0 2 75 0 0 0 76 С с 0 76 0 74 77 77 2 2 0 77 0 0 0 Рис. 6.7 Перед началом работы алгоритма магазин МАГ2 пуст, входная СТРОКА содержит входную цепочку, а МАГ1 — символ начального сос- тояния. Выполнение шага ДЕЙСТВИЕ начинает работу алгоритма. Алгоритм ДЕЙСТВИЕ. Определяем цепочку а, состоящую из к очередных сим- волов из СТРОКИ (или менее чем из к символов, если СТРОКА не содержит к символов). Применяем функцию действия к состоянию, рас- положенному наверху МАГ1, и к цепочке а и осуществляем указанное действие. Сдвиг. Если СТРОКА не пуста, то переносим первый символ из СТРОКИ в МАГ2 и переходим на НОВОЕ СОСТОЯНИЕ, иначе пере- ходим на НЕУСПЕХ; Число /. Если I — число символов в правой части правила с номером /, а А — левая часть этого правила, то удаляем по I символов из МАГ1 и МАГ2, записываем А в МАГ2 и переходим на НОВОЕ СОСТОЯНИЕ; Ошибка. Переходим на НЕУСПЕХ; Допуск. Переходим на УСПЕХ. НОВОЕ СОСТОЯНИЕ. Применяем функцию состояния к символам, расположенным наверху МАГ1 и МАГ2; полученное состояние записы- ваем в МАГ1 и переходим на ДЕЙСТВИЕ. НЕУСПЕХ. Входная цепочка не является предложением. УСПЕХ. Входная цепочка является предложением. Сделаем два замечания. Если входная строка является предложением, то указанный анализа- тор проводит разбор снизу вверх, моделируя в обратном порядке ее пра- вый вывод. Построение AR-анализатора по некоторой грамматике, по существу, состоит в осуществлении горизонтального движения одновременно по всем деревьям разбора всех предложений, заданных данной граммати- кой. В этом случае, когда исходная грамматика является AR-грамма- тикой, такое движение позволяет выделить все возможные множества
268 6.3.11. Обработка синтаксических ошибок состояний, а также получить довольно простые правила движения по этим состояниям в зависимости от конкретного предложения. 6.3.11. Обработка синтаксических ошибок. В большинстве трансля- торов обнаружение и диагностика ошибок концентрируется вокруг синтаксического анализатора. Это связано, в первую очередь, с большой степенью точности, которую можно достичь в синтаксическом опреде- лении языка программирования с помощью КС-грамматики, а также возможностью по любой КС-грамматике автоматически строить распоз- наватель, допускающий в точности тот язык, который описывается дан- ной грамматикой. Термин "синтаксическая ошибка" употребляется для обозначения си- туации, когда синтаксический анализатор попадает в конфигурацию, которая не является законной (допустимой) при разборе ни одной син- таксически правильной программы. В идеале обработка ошибки анализа- тором должна состоять в том, что он не только дает диагностическое сообщение, но и нейтрализует ошибку: определяет ошибку и ее место- нахождение, исправляет ошибку, изменяет свою текущую конфигура- цию и продолжает разбор с тем, чтобы обнаружить и другие ошибки, имеющиеся в программе. Существующие подходы к обработке синтак- сических ошибок лишь направлены на достижение этой цели и предпола- гают возобновление разбора после обнаружения ошибки, но заведомо не дают никакой гарантии, что ошибка будет успешно исправлена во всех ситуациях (исправление следует признать более успешным, если оно по отношению к другому исправлению позволит обнаружить в исходной программе больше ошибок и приведет к меньшему числу сообщений о несуществующих ошибках). Существует несколько простых стратегий нейтрализации ошибок, которые обычно применяются на практике. А. Режим переполоха. Под режимом переполоха понимает- ся следующая стратегия обработки анализатором недопустимого входно- го символа. Сначала анализатор игнорирует (пропускает) недопустимый символ и все последующие символы, отличные от определенных, так называемых опорных, символов, как правило, являющихся ограничите- лями операторов (например, точка с запятой или символ END являются опорными для языка Паскаль). Затем анализатор удаляет из стека все элементы до тех пор, пока не будет найден элемент, с которого анализа- тор может продолжить разбор, имея данный опорный символ на входе. Данная стратегия проста для реализации, не приводит никогда к за- цикливанию анализатора, но имеет серьезный недостаток, заключаю- щийся в том, что игнорируемые (не анализируемые) последовательности входных символов могут быть достаточно большой длины. Б. Исключение символов. Некоторой модификацией опи- санного выше метода переполоха является простое (без изменения стека) игнорирование недопустимых входных символов до тех пор, пока не встре- тится допустимый. Хотя можно привести много ситуаций, когда такая стратегия дает хорошие результаты (например, в строке X := 3 + у + Z) * (Ж + V) Паскаль-программы, в которой закрывающая скобка является
6.3.11. Обработка синтаксических ошибок 269 недопустимым символом), тем не менее ее следует применять с осторож- ностью (по крайней мере, не игнорируя при этом опорных символов). В. Вставка символов. В ряде случаев оправдано исправле- ние входной программы путем вставки некоторого символа перед те- кущим недопустимым символом. Например, последовательность END BEGIN всегда является недопустимой для языка Паскаль, и включение между символами END и BEGIN точки с запятой следует признать иде- альным исправлением этой ошибки. Следует отметить, что в отличие от предыдущих стратегий вставка символов, если она никак не ограничивается, может привести к зацик- ливанию анализатора. Г. Правила для ошибок. Стратегия нейтрализации очень часто встречающихся ошибок может состоять в расширении синтаксиче- ского определения языка программирования за счет включения в него программ, содержащих данные ошибки. При таком подходе обработка соответствующих ошибок переносится на анализатор в трансдукторы (генерационные процедуры) при тех синтаксических правилах, которые включены в грамматику для описания программ с ошибками. Такая стратегия является идеальной для таких ошибок, как, например, исполь- зование в языке Алгол-68 точки с запятой перед END. При применении данной стратегии следует следить за тем, чтобы грамматика при расширении оставалась однозначной. Можно указать только два вида обнаружения ошибки в анализаторе простого предшествования: отсутствие отношения предшествования между символом, находящимся наверху стека, и текущим входным сим- волом; основа выделена, но нет правила, для которого она является пра- вой частью. Обработка ошибок второго вида обычно осуществляется по правилам минимальной коррекции: среди правил ищется то, которое является бли- жайшим к выделенной основе. При нейтрализации ошибок первого вида требуется осуществить одно из обычных действий: изменение символов, вставку символов во входную цепочку или стек, удаление символов из входной цепочки или стека. Эти действия (подпрограммы) по обработке ошибок должны быть заранее выбраны и указаны для всех незаполнен- ных элементов матрицы предшествования (причем для разных элемен- тов может использоваться одна и та же подпрограмма). Например, пусть между символом в стеке b и текущим входным сим- волом с нет отношения предшествования. Тогда возможные решения (здесь через а мы обозначаем символ в стеке, находящийся под 5, а через d — входной символ, следующий за а): если а <* с (т.е. а <• с или а = с), то можно удалить b из стека; если Ь <• то можно удалить с из входной цепочки; если найдется такой символ Л, что b <• h и h <* с, то символ h можно поместить перед с. Любое из этих решений приводит к конфигу- рации с отношением предшествования для входного символа, что га- рантирует конечность работы анализатора, несмотря на изменения и вставки символов, осуществляемые им при нейтрализации ошибок. В отличие от анализатора предшествования LL- и ^-анализаторы обладают важным свойством правильности прочитанного префикса
270 6.4.1. Этапы трансляции и конструкторы входной цепочки — они обнаруживают ошибку сразу же, на первом символе, который не должен следовать за обработанной к этому времени частью входной цепочки. Следует, однако, заметить, что, хотя это свой- ство позволяет как можно раньше обнаружить наличие ошибки, тем не менее оно не гарантирует обнаружения ошибки в том месте, где она реально была допущена в программе. Проектирование подпрограмм обработки ошибок в этих анализаторах требует исследования всех входов в таблицу, связанных с ошибками, и выделения для каждого из них тех наиболее вероятных программистских ошибок, которые проявляются в этой ошибке при работе анализатора. Следует отметить и альтернативный подход к обработке ошибок, ко- торый состоит в реализации некоторого систематического способа их нейтрализации. Например, в LL-анализаторе может быть реализовано исправление ошибок на основе режима переполоха следующим образом. При встрече недопустимого символа в анализаторе последовательно вы- полняются следующие действия: удаляются из входной цепочки все сим- волы до первого опорного; происходит удаление символов из стека до тех пор, пока не встретится символ Л, из которого выводится данный опор- ный символ; если А не совпадает с опорным, то производится вывод из А и символы предопределенным образом помещаются в стек до тех пор, пока нужный опорный символ не окажется вверху стека. После выпол- нения этих действий возобновляется нормальная работа анализатора. 6.4. Перевод и конструкторы анализаторов 6.4.1. Этапы трансляции и конструкторы. Процесс трансляции ес- тественным образом разбивается на последовательность этапов транс- ляции, включающую лексический, синтаксический, контекстный ана- лиз и генерацию. Каждый из этих этапов определяет некоторый перевод (отношение между цепочками), а композиция всех этапов определяет перевод, образуемый парами: исходная программа, объектная програм- ма. Если не особенно стремиться к эффективности, то некоторые из эта- пов трансляции можно рассматривать как отдельные промежуточные трансляторы, реализующие связанные с ними переводы независимо, без объединения функций различных этапов на одном просмотре представ- ления транслируемой программы. Проблема задания конечными средствами бесконечного множества пар, образующих перевод, аналогична проблеме задания бесконечного языка. Для определения перевода можно использовать грамматику, снабдив ее механизмом, обеспечивающим выход для каждой порождае- мой цепочки, или расширить возможности распознавателя, позволив ему выдавать на каждом такте цепочку выходных символов. Синтаксический анализ — один из наиболее понятных этапов транс- ляции. По любой совокупности синтаксических правил можно автома- тически (с помощью некоторого универсального конструктора) постро- ить синтаксический анализатор, который будет определять, имеет ли входная программа синтаксическую структуру, определяемую правила- ми. Однако, с одной стороны, любой универсальный конструктор ана-
6.4.2. Понятие перевода, СУ-схемы и преобразователя 271 лизаторов не сможет во всех нужных случаях строить достаточно эф- фективные трансляторы, а с другой -г синтаксические структуры языков программирования достаточно просты и естественно выражаются в тер- минах более узких классов грамматик, чем класс всех грамматик. Поэто- му на практике обычно используются конструкторы, области примене- ния которых ограничены некоторыми подмножествами КС-грамматик, как правило, LL- или AR-грамматиками. Такие конструкторы не только строят эффективные трансляторы для широких классов языков, но и позволяют предусмотреть удовлетворительные методы обработки син- таксических ошибок. Например, построение анализатора для грамматики простого пред- шествования сводится к определению по грамматике простого предшест- вования Г отношений между символами грамматики. Это вычисление осуществляется простым алгоритмом, использующим следующие свой- ства отношений предшествования для любых Хи Y из W US: X <• Y тогда и только тогда, когда в Г есть правило А -» аХВ(3 и В =>+ Уу; X = Y тогда и только тогда, когда в Г есть правило А -» aXY{3\ X >Y тогда и только тогда, когда Y G 2 и в Г есть такое правило А -* аВС{3, что В =>+ уХ и С =>* Ут. 6.4.2. Понятие перевода, СУ-схемы и преобразователя. Пусть 2 — входной алфавит и А — выходной алфавит. Переводом с языка С 2* на язык АС А* называется отношение Т из Г в А*, для которого А, — область определения, а А — множество значений. Если (а, /?) G Т, то цепочка (3 называется выходом для цепочки а, а цепочка а — входом для цепочки /3. Перевод, предназначенный для описания языка программи- рования, является функцией, т.е. для каждого входа имеется не более одного выхода. Примером перевода, реализуемого почти в любом трансляторе, явля- ется отображение обычной (инфиксной) записи арифметических выра- жений в префиксную и/или постфиксную запись. Схема синтаксически управляемого перевода (сокращенно СУ-схе- ма) представляет собой грамматику, в которой к каждому правилу при- соединяется элемент перевода. Предполагается, что всякий раз, когда правило участвует в выходе входной цепочки, элемент перевода исполь- зуется для вычисления той части выходной цепочки, которая соответст- вует порожденной этим правилом части входной цепочки. Более точно, СУ-схема Т — это пятерка (РУ, S, A, R, А), где W — алфавит нетерминалов, Е — начальный символ, a R — конечное множе- ство правил вида А -» а, /3, где A G W, а Е (S ОРУ)*, /3 G (2 U А )* и вхождения нетерминалов в цепочку/3 образуют перестановку вхождений нетерминалов в цепочку а. Пусть А -> а, (3 — правило. Каждому вхож- дению нетерминала в цепочку а соответствует некоторое вхождение того же нетерминала в цепочку /?. СУ-схема Т называется простой, если для каждого правила А -► а, /3 из Т соответствующие друг другу вхождения нетерминалов встречаются в а и (3 в одном и том же порядке. Определим множество выводимых пар цепочек схемы Т по следу- ющим правилам: (А, Е) — выводимая пара, в которой вхождения симво-
272 6.4.2. Понятие перевода, СУ-схемы и преобразователя ла Ё соответствуют друг другу; если (аЛ/?, уАа>) — выводимая пара, в которой два выделенных вхождения нетерминала А соответствуют друг другу и А д, т) G Г, то (ad/?, yiyco) — выводимая пара, в которой соот- ветствие вхождений нетерминалов определяется их соответствием в паре (аЛ/?, уАо) и в правиле А -» d, г]. Переводом, определяемым схемой Т (обозначается т(Т)), называют множество таких выводимых пар (а, /3), что а 6 Г и/) 6 А*. Рассмотрим язык арифметических выражений Е(Г0), введенный в п. 6.2. Следующая простая СУ-схема отображает арифметические выражения из языка Е(Г0) в соответствующие постфиксные польские записи: Е -> Е + Т, ЕТ+, Е-*Т,Т, Т -» Т * f TF*, Т + F,F, F-> (Е),Е, F -> а, а. Например, можно рассмотреть следующую последовательность вы- водимых пар данной СУ-схемы: (Е, Е), (Е+Т, ЕТ+), (Т+Т, 7Т+), (Е + Т, FT+), (а + Г, аТ+), (а + Т * F, аТЕ*+), (а + F * F, aFF*+), (а + a* F, aaF*+), (а + а * а, ааа*+). Преобразователи — это распознаватели, которые дополняются вы- ходной лентой и на каждом шаге распознавания могут выдавать на вы- ходную ленту цепочки выходных символов ограниченной длины. В качестве примера рассмотрим МП-преобразователь (МП-распозна- ватель с выходом), осуществляющий перевод арифметических выра- жений из языка Е(Г0) в соответствующие префиксные записи. Он имеет набор команд, получающийся из следующих схем команд: (Л, b, Н) -> {(О, С, ЕН, е)}, (С, b, Е) {(О, С, Е+Т, +), (О, С, Т, е)}, (С, b, Т) {О, С, Т * F, *), (О, С, F, е)}, (С, b, F) {(О, С, (Е), е), (О, С, а, е)}, (C,d,d) -> {(1,С, е, е)}, (С, а, а) -» {(1, С, е, а)}, (С, В, Н) -» {(О, D, е, е)} всевозможными заменами b на символы из {а, +, *, (,)} и d на символы из {+, *, (> )}• В МП-преобразователе Л — это начальное состояние, {£>} — множество заключительных состояний, а последний элемент в четверке правой части правила — это строка, печатаемая на входную ленту. Для входной строки а + а * а возможна следующая последовательность кон- фигураций: (Л, а + а * а, Н, е), (С, а + а * а, ЕН, е), (С, а + а * а, Е + TH, +), (С, а + а * а, а + TH , +), (С, а * а, +ТН, +а), (С, а * а, TH, +а),
6.4.3. Конструктор LL-преобразователя 273 (С, а ♦ а, Т * FH, +а*), (С, а ♦ a. F ♦ FH, +а*), (С, а ♦ а, а ♦ FH, +д, ♦), (С, *а, *ГЯ, +а ♦ а), (С, a, FH, +а* а), (С, а, аН, +а* а), (С, е, Я, +я * аа), (D, е, е, +а ♦ аа). 6.4.3. Конструктор LL-преобразователя. Определим более точно МП-преобразователь, который мы хотим построить для любой LL-грам- матики. Он должен реализовать перевод {(a, a G £(Г), а z^.../, — цепочка номеров правил грамматики, выписанных в порядке их приме- нения в левом выводе цепочки а}. Например, для грамматики Tt с пра- вилами 1) аАЕ, 2) Е -> Ь, 3) А а, 4) А -+ ЬЕА, которая, как нетрудно увидеть, является LL(\)-грамматикой, элементом перевода будет пара (abbab, 14232). Легко заметить, что цепочка номеров правил, построенных преобра- зователем, однозначно определяет соответствующее дерево разбора. Предполагается, что преобразователь использует входную ленту, ма- газин и выходную ленту. Конфигурацию преобразователя будем пред- ставлять в виде тройки (а, ХрН, у), где а — неиспользованная часть входной цепочки, XflH — цепочка в магазине (X — верхний символ, а Я — специальный символ, применяемый в качестве дна магазина) и у — цепочка на выходной ленте. Через М будем обозначать алфавит ма- газинных символов без символа Я. Работой преобразователя руководит управляющая таблица Т, задаю- щая отображение (М U {Я} х Г в множество, в которое входят: УС- ПЕХ; НЕУСПЕХ; СДВИГ; пары (a, z), где a G АГ, z — номер правила (предполагается, что а — это либо правая часть z-ro правила, либо неко- торое его представление). При этом считается, что Т(Н, е) = УСПЕХ. Работа преобразователя происходит в соответствии со следующими тремя правилами. Если возникает конфигурация (е, Н, л), то работа преобразователя успешно завершается ил — его выход. Пусть (а, Х/3, л) — текущая конфигурация и си — £-префикс входной цепочки а (см. ниже). Тогда: а) если Т(Х, а>) = НЕУСПЕХ, то разбор прекращается и выдается сообщение об ошибке; б) если Т(Х, uj) = СДВИГ, то происходит переход к конфигурации (у, /2, л), где а = Ху; в) если Т(Х, а>) = (ст, z), то происходит переход к конфигурации (а, а/?, yz). Работа преобразователя начинается с конфигурации (т, ЕН, е), где т — входная цепочка. Например, для LL(\)-грамматики Г, управляющая таблица преобра- зователя изображена на рис. 6.8.
274 6.4.3. Конструктор ZJL-преобразователя Префикс входной цепочки Верхний символ магазина b Е аАЕ, 1 6,2 ОШИБКА А а, 3 ЬЕА, 4 ОШИБКА а СДВИГ ОШИБКА ОШИБКА b ОШИБКА СДВИГ ОШИБКА Н ОШИБКА ОШИБКА УСПЕХ Рис. 6.8 В соответствии с ней возможна следующая последовательность кон- фигураций: (abbab, ЕН, е), (abbab, аАЕН, 1), (bbab, ЬЕАЕН, 14), (bab, ЕЛЕН, 14), (bab, ЬАЕН, 142), (ab, АЕН, 142), (ab, аЕН, 1423), (Ь, ЕН, 1423), (Ь, ЬН, 14232), (е, Н, 14232). Таким образом, задача построения по LL(k)-грамматике Г соответст- вующего преобразователя состоит в построении управляющей таблицы Т нужного вида. Введем следующие обозначения. Цепочка а является ^-префиксом цепочки /3, если либо 1/31 < к и а = /?, либо 1/31 > к и ау = /3 для некоторой цепочки у. Для любых множество ^-префиксов всех цепочек из L{L2 обозначим через ф L^. Для любой a G S* обозначим через ПЕРВ(а) множество ^-префиксов всех терминальных цепочек, вы- водимых из а. Если из а выводима пустая цепочка, то считается, что ПЕРВ(а) содержит е. к Для любых A G 1Уи £С Г рассмотрим таблицу ТА L, которая каждой к цепочке a G Г сопоставляет либо символ ОШИБКА, если в Г нет такого правила А /3, что a G ПЕРВЕЗ) ф L, либо пару (А -> /3, У), где А -> /3— единственное правило из Г, для которого a G ПЕРВЕЗ) ф L, a Yопреде- ляется следующим образом: а) если (3 = a0A1a1A2...Awa„1, где m > О, A;G W и то У=(УИ ..., УД где ^ = ПЕРВ(аД+1аж...АЛ1) ф L; б) если/3 G £*, то У— пустое множество. Содержательно это означает следующее: если TAL(a} = ОШИБКА, то в Г невозможен вывод вида Ао> =>+ ау для а> G L и у G £*; если ТА/(а) = = (А -» /3, (Уп ..., Ym)), то найдется в точности одно правило А -» Д кото- рое можно применить на первом шаге вывода Аси =>+ ау для си G L и у G € Е*, а каждое множество Yi дает всевозможные ^-префиксы, которые могут в дальнейшем при выводе следовать за подцепочкой, выводимой из А;. Заметим, что ТА^(а) всегда определена в силу того, чтз Г является LL(k) -грамматикой.
6.4.3. Конструктор LL-преобразователя 275 В качестве примера рассмотрим LL(2) -грамматику Г2 с правилами {Е -* аЕаа \ bAba, А b I е}. Значения элементов таблицы ТЕ{е}, отличные от значения ОШИБКА, приведены на рис. 6.9. В качестве магазинных нетерминальных символов преобразователя для грамматики Г рассматривается множество таблиц J, которое стро- ится по следующим правилам: в пустое множество J включается таблица если некоторая таблица из J имеет значением (А-^ a0Alal ...Amam, (Ур ..., Ytn)) и J не содержит таблицы ТА Y, то ТА Y включается в J. Нетрудно видеть, что это множество таблиц для грамматики Г2 будет состоять из трех элементов, приведенных на рис. 6.9 и обозначенных а ТЕ,{е}(а) аа (Е -> аАаа, <{аа}>) ab (Е -> аАаа, <{яя}>) bb (Е bAba, <{Ьа}>) а Та,{аа} (а) Ьа (А - Ь, 0) аа (Л - е, 0) а Та,{Ьо} («) Ьа (А -* е, 0) bb (А - Ь, 0) Рис. 6.9 Множество J U 2 U {Я} является магазинным алфавитом преобразо- вателя для грамматики Г, таблица ТЕ{е} — начальным состоянием, а для любых магазинного символа X и цепочки /3 G Г значение Т(Х, (3) опре- деляется по следующим правилам: а) еслиX = ТА±и ТАЬф) = (А Т(Х,/3) = = («0 ТА' аР..Тл о, где i — номер правила А -> a()Aial ...Ama б) если X = Я и (3 = е, то Т(Х, /?) - УСПЕХ; в) если X G Z и 0 = Ха, то Т(Х, 0) = СДВИГ; г) в остальных случаях Т(Х, 0) = ОШИБКА. Например, для LL(2) -грамматики Г2 рассмотренный конструктор построит управляющую таблицу, изображенную на рис. 6.10. аа ab a ba bb b е То аТ\аа, 1 аТ\аа, 1 ОШИБКА ОШИБКА ЬТгЬа, 2 ОШИБКА ОШИБКА Г1 е, 4 ОШИБКА ОШИБКА ь,з ОШИБКА ОШИБКА ОШИБКА Т2 ОШИБКА ОШИБКА ОШИБКА е, 4 5,3 ОШИБКА ОШИБКА а СДВИГ СДВИГ СДВИГ ОШИБКА ОШИБКА ОШИБКА ОШИБКА b ОШИБКА ОШИБКА ОШИБКА СДВИГ СДВИГ СДВИГ ОШИБКА Н ОШИБКА ОШИБКА ОШИБКА ОШИБКА ОШИБКА ОШИБКА УСПЕХ Рис. 6.10
276 6.4.4. Конструктор £Л-преобразователя Замечания. А. Число шагов, выполняемых преобразователем с управляющей таб- лицей, построенной описанным выше конструктором по LL-грамматике, линейно зависит от длины входной цепочки. Б. Важным частным случаем LL-грамматик являются LL(1)-грам- матики. Пусть Г является LL(l)-грамматикой и для любого A G Wопре- делено множество СЛЕД (А) = {а: Е =>* аА/3 иаЕ ПЕРВ(/3)}. Управляю- щая таблица преобразователя для Г может быть построена следующим образом. Множество W U S U {Н} образует алфавит магазинных симво- лов, Е — начальное состояние, а для любых ХЕ (Ж U S U {Н}) и а Е 6 (2 U {е}) значение Т(Х, а) определяется по следующим правилам: если X -» а — правило из Г с номером i и либо a G ПЕРВ(а), либо е G Е ПЕРВ(а) и а G СЛЕД (а), то Т(Х, а) = (а, 0; если X = Н и а = е, то Т(Х, а) = УСПЕХ; если X = а, то Т(Х, а) = СДВИГ; в остальных случаях Т(Х, а) = ОШИБКА. В. Для уменьшения размера таблиц для LL(1)-распознавателя обыч- но применяются следующие два метода: обработка правила А аа и входного символа а реализуется загрузкой а в магазин и сдвигом входа на один символ, что позволяет уменьшить магазинный алфавит; использу- ется один терминал с "индикатором" для нескольких нетерминалов с одинаковыми действиями разбора. 6.4.4. Конструктор АК-преобразователя. LR (к) -анализатор доста- точно подробно описан в п. 6.3.10. В отличие от него преобразователь, конструируемый описываемым ниже конструктором, содержит выход- ную ленту и при выполнении шага с именем ЧИСЛО/ дополнительно осуществляет запись на выходную ленту числа /. Рассмотрим работу преобразователя такого вида для пополненной грамматики Г3, приведен- ной в п. 6.3.10, с использованием функций действия и перехода, описан- ных там же. В результате обработки входа aabb на выходе этого преобра- зователя будет получена цепочка 33322, однозначно определяющая пра- вый вывод цепочки aabb в исходной грамматике. Магазинными символами будут множества LR(k)-ситуаций для Г (или просто ситуаций), каждая из которых имеет вид [А -» /3 • у, а ], где a G 2* , А -> Ру — правило из Г. Причем будут рассматриваться только ситуации [А /3 • у, а ], для которых существует такой правый вывод Е =>* соАа => а>Руа, что a G ПЕРВ(о) и а>р — активный префикс некото- рой правовыводимой цепочки, т.е. он не выходит за правый конец ее основы (такая ситуация называется допустимой для о>/3). Алфавит магазинных символов & состоит из множества ситуаций ^(у) для активных префиксов у грамматики Г. Рассмотрим метод построения ^(у) для некоторого у = X1X2...XZI как объединение множеств , &\Хр, &\Х{Х2),..., ^(X^X2...Xt). — это минимальное множество ситуаций, содержащее [Е -а, е] для любого правила Е а из Г и удовлетворяющее следующему свойству: если &(е) содержит ситуацию [А Ва, /3] и В -* а — правило грамматики, то любая ситуация [В -» -а, а>], где а) G ПЕРВ(а^З), также содержится в &(е). Для каждого i < п множество &{Х{Х2...Х) равно ШАГ(^ХХ1Х2...Х/_1),
6.4.4. Конструктор ЛЯ-преобразователя 277 X), где = ШАГС^, X) — минимальное множество, удовлетворяющее следующим свойствам: если [А а • Ха, /3 ] G то содержит состо- яние [А -» аХ • a, /$]; если [А -* а • Во, (3]Е. и В -* д — правило грамматики, то содержит ситуацию [В -* д, а> ] для каждой цепочки а) G ПЕРВ(^). Например, для LL(1)-грамматики Г3 имеем = {[£-> S, е], [S-> -SaSb, е], [S -* -SaSb, а], [S-* -е,е], [S-* -е,а]}, ^(S) = {[E^S-,e], [S-» S • aSb,e], [S-> S • aSb,a]}, $HSd) = {[S -> Sa • Sb, e], [S-+Sa - Sb, a], [S -» -SaSb, a], [S-^ -SaSb, 6], [S->e-,a], [S->e-,Z>]}. Таким образом, построение $г(у) связано с горизонтальным движе- нием по всем деревьям разбора таких правовыводимых цепочек, для которых у является активным префиксом. Это множество содержит всю информацию, необходимую для продолжения разбора любой правовы- водимой цепочки, для которой у — активный префикс. Так как грамматика Г содержит конечное множество правил, число множеств ситуаций в &тоже конечно, но часто бывает очень большим. Построение Сможет быть осуществлено по следующим правилам: вклю- чить То = -М в пустое множество &и считать его необработанным; осу- ществить обработку каждого необработанного Г. из &, вычисляя Т- = ШАГ(7}, X) для каждого X G (W U S) и включая Т- в качестве необработанного множества в если Т- не пусто и еще не содержится в Например, для LL(1)-грамматики Г3 получаем Т0 = ;Яе), Т1=ШАГ(7ПО, S)=^(S), ШАГ(Т0, а) = ШАГ(Т0, Ь) =0, Г^ШАПГр a) =^(Sa), ШАГ(ГР S) = = ШАГ(ТР Ь) = 0. Кроме То, и Т3 в &попадают также множества Т3 = = {[S -» Sa • Sb, е], [S SaS • b, a], [S -> S • aSb, a], [S -> S • aSb, 5]}; T4= {[S Sa • Sb, a], [S -> Sa • Sb, Л], [S -> -SaSb, a], [S -> -SaSb, b], [S-> -e, a], [S^ e, 5]}; T5 = {[S -> SaSb-, 5], [S -> SaSb-, a]}; T6 = = {[S -> SaS • b, a], [S -» SaS • b, b], [S -> S • aSb, a], [S -> S • aSb, 5]}; T7 = {[S -» SaSb-, a], [S -* SaSb-, />]}. После того как найдено, можно осуществить вычисления функций действия/и перехода g, используемых в LR(к)-распознавателе. Для любого Т- G .^и 5? значение f(T-, а) определяется по следу- ющим правилам: если Т содержит такое состояние [А /3 • у,а> ], что у — не пустая цепочка и а является ^-префиксом некоторой правовыводимой из уа> цепочки ао (т.е. a G ПЕРВ(уаО), на последнем шаге вывода кото- рой не применяется ^-правило, то /(Г., а) = СДВИГ; если Т- содержит состояние [А -> (3- ,е]иА /3 имеет номер I, то /(Г., а) = ЧИСЛО/; если Т- содержит состояние [Е* , е] и а = е, то/(Т., а) = ДОПУСК; в осталь- ных случаях/(7V а) = ОШИБКА. Для любых Т,Е .:Fh X С (S U IK) значение g(7\ X) равно ШАГ(Т;, X), если множество ШАГ(Т;, X) не пусто, и равно ОШИБКА в остальных случаях.
278 6.5. Библиографический комментарий Замечания, А. Если вычислять функции f и g по описанным правилам для грам- матики Г3, то результатом этого вычисления будут соответствующие функции, приведенные в п. 6.3.10. Б. Число шагов, выполненных преобразователем, построенным опи- санным выше £Я-конструктором, линейно зависит от длины входной цепочки. В. Описанный конструктор строит так называемый канонический LR- анализатор. Существуют конструкторы, которые могут построить LR- анализаторы меньшего объема, однако важным свойством канонического анализатора является его способность объявлять об ошибке при первой же возможности в ходе считывания входной цепочки слева направо. 6.4.5. Использование конструкторов. Каждый из описанных выше конструкторов может быть расширен таким образом, чтобы он проверял принадлежность входной грамматики соответствующему классу грам- матик. Грамматики простого предшествования — один из первых методов, используемых в трансляторах для эффективного синтаксического ана- лиза. Однако, как правило, реальные языки программирования если и описываются этими грамматиками, то требуют для своего описания серь- езных преобразований исходной грамматики. Кроме того, анализатор простого предшествования уступает LL- и ^-анализаторам в смысле ранней диагностики ошибок, а также простоты модификации при изме- нении языка. Поэтому конструкторы для грамматик простого предшест- вования используются достаточно редко. Объем работы конструктора для £7?-грамматик резко возрастает с увеличением размера грамматики и ростом к. Для реальных грамматик объем этих вычислений часто оказывается неприемлемо большим даже при к - 1. Поэтому обычно на практике используются конструкторы для некоторых подклассов ЛЯ-грамматик, которые строят, например, SLR (1) -анализаторы или LALR (1) -анализаторы. Наиболее широко используется конструктор LL(\)-анализаторов, ко- торые достаточно мощны, выразительны, эффективны и достаточно ес- тественно согласуются с другими этапами трансляции. Как правило, ес- ли исходная грамматика языка программирования не является LL(D- грамматикой, то она может быть преобразована в LL(\)-грамматику с помощью преобразований ’’добавление нетерминала” и ’’изменение на- правления рекурсии”. 6.5. Библиографический комментарий Синтаксическому описанию и анализу языков программирования по- священа обширная литература, в том числе монографического плана [1—27 ]. Книги (3—12 ] систематизируют значительную часть результа- тов, касающихся этих вопросов, и могут быть рекомендованы как основ- ная литература для обстоятельного и глубокого изучения предмета. Ос- новой для данной главы послужил материал монографии [10 ].
Список литературы 279 СПИСОК ЛИТЕРАТУРЫ 1. Агафонов В.Н. Синтаксический анализ языков программирования. — Новосибирск: Изд-во Новосиб. ун-та, 1981. 2. АЛГОЛ-68. Методы реализации/ Под ред. Г.С.Цейтина. — Л.: Изд-во Ленингр. ун-та, 1976. 3. Ахо А., Ульман Дж. Теория синтаксического анализа, перевода и компиляции. — М.: Мир, 1978. —Т. 1,2. 4. Болье Л. Методы построения компиляторов// Языки программирования. — М.: Мир, 1972. 5. Братчиков И.А. Синтаксис языков программирования. — М.: Наука, 1975. 6. Гинзбург С. Математическая теория контекстно-свободных языков. — М.: Мир, 1970. 7. Гладкий А.В. Формальные грамматики и языки. — М.: Наука, 1973. 8. Глушков В.М., Цейтлин Г.Е., Ющенко Е.Л. Алгебра. Языки. Программирование. — Киев: Наук, думка, 1989. 9. Грис Д. Конструирование компиляторов для цифровых вычислительных машин. — М.: Мир, 1975. 10. Касьянов В.Н., Потгосин И.В. Методы построения трансляторов. — Новосибирск: Нау- ка. Сиб. отд-ние, 1986. 11. Льюис Ф., Розенкранц Дм Стирнз Р. Теоретические основы построения трансляторов. — М.:Мир, 1979. 1 2. Маккиман У., Хорнинг Дж., Уортман Д. Генератор компиляторов. — М.: Статистика, 1980. 1 3. Меристе М.Б. Методы реализации атрибутных схем в системах построения транслято- ров// Программирование. — 1980. — №5. — С. 40—49. 14. Параметрические транслирующие системы/ М. Г. Гонца, М. Н. Маричук, Г. А. Бостан, Г. А. Магариу. — Кишинев: Штиинца, 1974. — Т. 1,2. 15. Пеньям Я.Э. Синтез грамматического процессора по атрибутной грамматике// Прог- раммирование. — 1983. — № 1. — С. 50—60. 16. Семантика языков программирования. — М.: Мир, 1980. 1 7. Трахтенгерц Э.А. Введение в теорию анализа и распараллеливания программ ЭВМ в процессе трансляции. — М.: Наука, 1981. 1 8. Труды Всесоюзного симпозиума по методам реализации алгоритмических языков. — Новосибирск, 1975. — Ч. I, II. 19. Фельдман Дж., Грис Д. Системы построения трансляторов// Алгоритмические языки/ ' ВЦ АН СССР. — М., 1971—Вып.5. — С. 105—214. 20. Фишер Ф.П., Суиндл Д.Ф. Системы программирования. — М.: Статистика, 1971. 21. Фуксман А.Л. и др. Основы разработки трансляторов. — Ростов н/Д: Изд-во Ростов, ун- та, 1974. 22. Хантер Р. Проектирование и конструирование компиляторов. — М.: Финансы и статистика. 1984. 23. Хопгуд Ф. Методы компиляции. — М.: Мир, 1972. 24. Graham S.L., Harrison М.А., Ruzzo W.L. An improved context-free recognizer// ACM. Trans. Program. Languages Systems. — 1980. — Vol. 2, N 3. — P. 415—462. 25. Nijholt A. Parsing strategies: a concise survey// Leet. Notes Comput. Sci. — 1981. — Vol. 118. — P. 103—120. 26. Rieks op den Akker. On LC(O) grammars and languages// Theor. Comput. Sci. — 1989. — Vol. 66. N 1. —P. 65—85. 27. Seite B. A YACC extension for LR grammar parsing//Theor. Comput. Sci. — 1987. — Vol. 52, N 1. —P.91 —143.
Часть III ПОИСК И ХРАНЕНИЕ ИНФОРМАЦИИ Глава 7 ИНФОРМАЦИОННЫЕ ДЕРЕВЬЯ 7.1. Балансированные деревья 7.1.1. Дерево сортировки. Обозначим через W = {И^, Wn} множе- ство слов с введенным на нем отношением порядка, например, лекси- кографическим. Бинарным деревом сортировки или просто деревом сортировки над множеством слов W называется бинарное n-вершинное дерево ТЛ, каж- дой вершине которого сопоставлено слово из множества Ж, причем для каждой вершины х выполнено условие: все слова левого поддерева Т{(х) предшествуют слову, сопоставленному вершине х, а все слова правого поддерева Тг(х) следуют за словом в вершине х. На рис. 7.1 показаны три дерева сортировки над множеством слов {А, В, С, D} с корнями, помеченными словами D, В и С соответственно Будем называть в дальнейшем слово РИ, сопоставленное вершине х, значением вершины х и обозначать Р/(х). 7.1.2. Построение дерева сортировки. Как видно из рис.7.1, конфи- гурация дерева сортировки существенно зависит от того, какое слово является значением корня дерева. Опишем алгоритм построения дерева сортировки в предположении, что корню сопоставляется слово Ж,, далее происходит одновременное наращивание дерева и сопоставление слов РК2, ..., Wn в порядке их вхождения в множество W вершинам дерева. Очевидно, что построение дерева начинается с создания вершины v0 — корня дерева; после сопоставления ему слова W\ создаются две вершины ПРАВСЫН(у0) и ЛЕВСЫН(р0). Эти вершины будем называть свобод- ными в отличие от корня, которому присвоено значение. Для удоб- ства будем считать, что у свободных вершин х значение Ж(х) равно Q. функ ПОСТРОЕНИЕ-ДЕРЕВА (5:список) =
7.1.3. Поиск в дереве сортировки 281 1. В качестве Т взять одновершинное дерево, значение корня которого равно Q; 2. пока5#0цикл 3. W1 := э 5; р := КОРЕНЬ(Т); 4. ОБХОД: пока Ж(р) # Q цикл 5. если W1 < Ж(р) то 6. р:=ЛЕВСЫН(р) 7. иначе если ИИ > Ж(р) то 8. р := ПРАВСЫН(р) 9. иначе завершить ОБХОД все все; все; 10. Значением вершины р сделать 1У1; 11. Создать в Т вершины ЛЕВСЫН(р) и ПРАВСЫН(р) со значениями Q все; 12. возврат Т все Заметим, что для произвольно взятого множества слов W дерево мо- жет расти крайне неравномерно. Легко представить себе ситуацию, когда дерево вырождается в линейный список. 7.1.3. Поиск в дереве сортировки. Поиск в дереве сортировки состоит в_поиске вершины х, значение которой W(x) равно заданному значению W. Поиск является частью построения дерева, поэтому алгоритм поиска в значительной мере повторяет алгоритм из п. 7.1.2. функ ПОИСК-В-ДЕРЕВЕ (Т:дерево; ИН:слово) = 1. р :=КОРЕНЬ(П; 2. ОБХОД: пока (W(p) * Q) V (W(p) * ИЛ) цикл 3. если ИЛ < W(p) то 4.. р := ЛЕВСЫН(р) 5. иначе если ИЛ > W(p) то 6. р := ПРАВСЫН(р) 7. иначе завершить ОБХОД 8. % поиск успешен % все все все; 9. возврат/? %поиск успешен тогда и только тогда, когда W(p) * Q% все 7.1.4. Балансированные по высоте деревья. АВЛ-деревья. Бинарное дерево называется балансированным по высоте, или АВЛ-деревом, если для любой его вершины высота правого поддерева отличается от высоты левого не более чем на единицу.
282 7.1.4. Балансированные по высоте деревья. АВЛ-деревья Трудоемкость поиска по АВЛ-дереву оценивается исходя из его сле- дующего свойства: максимальная высота n-вершинного АВЛ-дерева не превышает (3/2)logn. Это — оценка в худшем случае. В среднем имеет место оценка i,04iogn (для больших и). Включение новой вершины (или удаление ненужной) может привести к нарушению баланса дерева, т.е. получаемое дерево уже не будет АВЛ -деревом. Сохранение структуры АВЛ-дерева требует в случае нарушения структуры выполнения восстанавливающих операций: про- стого и двойного вращения. Простое вращение. Выполняется, когда подвешивание новой вершины х происходит со стороны длинной ветви, в результате чего в вершине v0 разность высот правого и левого поддеревьев становится рав- ной двум (рис. 7.2), при этом путь из v0 в новую вершину состоит только из левых или только из правых дуг. Двойное вращение. Выполняется, когда путь из v0 (вершины, где нарушается баланс между высотами поддеревьев) в новую вершину содержит и левые, и правые ребра (рис. 7.3). Поиск и вставка новых вершин в АВЛ-дереве выполняются в соот- ветствии с алгоритмом из п.7.1.2, дополненным процедурами проверки
7.1.5. Балансированные по весу деревья (ВВ-деревья) 283 балансов вершин и восстановления баланса. За подробным описанием пополненного алгоритма отсылаем к книге Д.Кнута ’’Искусство програм- мирования для ЭВМ. Сортировка и поиск” (см. п. 5.2.3). 7.1.5. Балансированные по весу деревья (ВВ-деревья). Они образу- ют класс бинарных деревьев, в которых ограничение на высоты подде- ревьев заменено ограничением на число вершин в поддеревьях. Хотя эти деревья базируются на других принципах и не сравнимы с АВЛ-деревь- ями (эти классы не пересекаются и не содержат друг друга), они облада- ют схожими свойствами. От АВЛ-деревьев они отличаются в основном тем, что содержат параметр, который может изменяться так, что комп- ромисс между скоростью поиска и допустимым дисбалансом может быть выбран произвольно. Пусть Тп = (Tj, v, Т) — бинарное дерево с корнем у, где Т{ и Тг — левое и правое бинарные поддеревья с nt и пг вершинами соответственно, п{ + пг = п — 1, п1 > 0, пг > 0. Корневым балансом р(Тп) дерева Тп = (Т,, у, Тг) называется величина и, +1 Для корневого баланса всегда выполняются неравенства 0<р(Т„)<1. Дерево Тп называется балансированным по весу деревом U3 В-де ре- вом, бинарным деревом с ограниченным балансом) с балансом а, 0 < < а < 1/2, если оно удовлетворяет следующим свойствам: а) а < р(Тп) < 1 - а; б) Tj и Тг — балансированные по весу деревья с балансом а. Класс бинарных деревьев с балансом а будем обозначать через ВВ [а ]. Полностью балансированные деревья Тп на п = 2к - 1 вершинах при- надлежат классу ВВ[1/2 ], в то время как деревья Фиббоначи, определя-1 емые соотношениями Fo — пусто, Л = • , Fi+2 = Д Л Лм принадлежат ВВ [ 1 /3 ]. В балансах деревьев имеется пробел, а именно: для всех а в интервале 1/3<а < 1/2 ВВ[а] = ВВ [1/2]. Оценку для средней длины поиска в Тп дает формула: если Тп G G ВВ[а ], то 1Г"1 - + 1)log(n + 0 - , где
284 7.1.6. Включение нового слова в ЯВ-дерево Hia) = -aloga - (1 -a)log(l - а). Оценку для длины поиска по худшему случаю дает оценка для высо- ты дерева: если Тп G ВВ[а ], то высота дерева Тп не больше log(n 4- 1) - 1 log(l/(l -а))’ Все указанные оценки точны: они достигаются на деревьях, у которых все поддеревья имеют корневой баланс 1/2, т.е. на полностью балан- сированных (2*- 1)-вершинных деревьях. 7.1.6. Включение нового слова в ВВ-дерево. Это включение проис- ходит следующим образом. Пусть каждой вершине х дерева сопоставлено число Six), равное числу вершин в поддереве Tix) с корнем в вершине х. Двигаясь по ребрам дерева, идем, как и при построении дерева сор- тировки, влево, если слово W меньше слова в вершине, и вправо — в противном случае. На каждом шаге поиска проверяем, нарушит ли_до- бавление вершины баланс дерева; если нет, то добавляем единицу к Six) и продолжаем движение по дереву. Если же добавление вершины нару- шает баланс, то, прежде чем двигаться дальше, проводим преобразо- вания, аналогичные описанным в п. 7.1.4. Заметим, что, модифицируя дерево, мы можем не знать, находится ли слово W уже в дереве. В таком случае возвращаемся по пройденному пути назад к корню, восстанавливая прежние значения величин Six), но не проводя обратной перестройки дерева; перестройка дерева не ухудша- ет его качества. Простое вращение. Схема преобразования и формулы для пересчета балансов в вершинах представлены на рис. 7.4. Нарушение баланса про- исходит в вершине А, Рис. 7.4
7.1.6. Включение нового слова в ВВ-дерево 285 Двойное вращение. Схема преобразования показана на рис.7.5. Нару- шение баланса происходит в вершине А. Pa-PJ А + а-Ж &-£(!-&> / (1-W Д? “ А * < 1 Алгоритм Обозначения: U(х) — левый потомок вершины х, RL(x) — правый потомок вершины х, Six) — число вершин в поддереве Т(х), Wix) — значение вершины х, R — указатель на вершину, где может храниться новое слово Ж, RP — указатель на предка вершины, на которую направлен указа- тель R, S — переменная со значениями L или R и SL есть либо LL, либо RL, смотря по тому, каково значение переменной 5. Значение 5 вместе со значением RP позволяет выяснить, какой ука- затель должен быть модифицирован во время восстановления баланса дерева. проц МОДИФИКАЦИЯ (Г : дерево; 1У1 : слово) = 1.. а := баланс дерева Г; 2. R := КОРЕНЬ (Т); 3. noxajyi # WiR) цикл 4. v := iSiLLiR)) + 1)/(5(Д) +2) 5. % вычисляется баланс v первой вершины на пути от корня к новой вершине после включения новой вершины для слова W1 % 6. если W1 < WiR) то 7. 5 := Ц 8. % новая вершина включена в левое поддерево вершины R % 9. если a <v < 1 - а то
286 7.1.7. Удаление слов ия вЯ-депевьев 10. 5(Л) :=_S(R) + 1 11. иначе если 5 (R) = 2 то 12. Использовать вращение без учета новой вершины 13. иначе вычислить баланс /3 правого поддерева с учетом новой вершины; 14. если 1 — /3 < <1 — 2а)/(1 -а) то 17. Применить простое вращение 16. иначе Применить двойное вращение все все все 17. иначе 18. % новая вершина включена в правое поддерево % 19. если а < v <_1 - а то 20. SCK) :=SCK) + 1 21. иначе если 5(B) = 2 то 22. Использовать простое вращение без учета новой вершины 23. иначе Вычислить баланс /3 нового поддерева с учетом новой вершины 24. если/3 < (1 - 2а)/(1 -а) то 25. Применить простое вращение; 26. иначе Применить двойное вращение все все все все 27. если SL(R) # 0 то 28. R := SL(R) 29. иначе Создать новую вершину Q := SL(R); 30. W(Q) := W1 все все все Замечание. Если цикл закончился в результате нахождения сло- ва W в дереве, то необходимо еще раз_повторить процедуру поиска в дереве слова W и вычесть из величины 5(х) каждой встретившейся вер- шины единицу. 7.1.7. Удаление слов из ВВ-деревьев. Удаление слов, или, другими словами, вершин из ВВ-дерева, происходит аналогично их включению в дерево. А именно, следуя по ребрам вниз по дереву, уменьшаем на еди- ницу значение S(x) для каждой пройденной вершины. Если в таком слу- чае дерево становится несбалансированным, применяем соответствую- щие преобразования и движемся дальше. Когда достигнем вершины которую намерены удалить, может встретиться один из трех случаев. Если xN — висячая вершина, то просто удаляем ее. Если xN имеет только
7.1.8. 2-3-деревья 287 одного потомка, соединяем предка вершины xN ребром с потомком вер- шины xN и, таким образом, удаляем вершину xN. В противном случае находим последователя (предшественника) вершины xN, ставим его на место вершины xN, заботясь о соответствующих изменениях величин S(x) и ребер. Снова, если преобразования были сделаны, а затем вы- яснилось, что вершины, которую собирались удалить, нет в дереве, ис- правляем величины 5 (х), но не реконструируем дерево. 7.1.8. 2-3-деревья. 2-3-деревом называется дерево, в котором каждая невисячая вершина имеет двух или трех потомков (сыновей), а длины всех путей из корня в листьях одинаковы. На рис. 7.6 показаны два 2-3-дерева с шестью листьями. Пусть 5 — линейно упорядоченное множество, например множество целых чисел от 1 до п. Припишем эти числа листьям дерева в порядке их возрастания слева направо. В каждой невисячей вершине v — узле — потребуется для обеспечения поиска два данных: L(v) иМ(у) (L(v) —это наибольший элемент множества 5 в поддереве, корнем которого служит самый левый сын узла v; ММ — это наибольший элемент в поддереве, корнем которого служит второй сын узла v (см. рис. 7.6)). Значения LM и ММ, приписанные узлам, позволяют искать элемент, начиная с кор- ня, способом, аналогичным двоичному поиску. Время обнаружения про- извольного элемента пропорционально высоте дерева, т.е. O(logn) для п-элементного множества 5. Рис. 7.6 В общем случае на порядок, в котором приписываются листьям эле- менты множества 5, не налагается никаких ограничений. Тогда для оты- скания листа, хранящего нужный элемент, необходим вспомогательный механизм. С этой целью рассмотрим следующие наборы операций: 1. ВСТАВИТЬ, УДАЛИТЬ, ПРИНАДЛЕЖАТЬ. 2. ВСТАВИТЬ, УДАЛИТЬ, MIN. 3. ВСТАВИТЬ, УДАЛИТЬ, ОБЪЕДИНИТЬ, MIN. / 4. ВСТАВИТЬ, УДАЛИТЬ, НАЙТИ, СЦЕПИТЬ, РАСЦЕПИТЬ. Структура данных, обеспечивающая выполнение операций из перво- го множества, называется словарем, из второго — очередью с приорите- тами, из третьего — сливаемым деревом, из четвертого — сцепляемой очередью. Использование 2-3-деревьев позволяет реализовать эти струк- туры данных с трудоемкостью O(logn) на одну операцию.
288 7.1.9. Словари: реализация 2-3-деревьями 7.1.9. Словари: реализация 2-3-деревьями. В данном пункте предпо- лагается, что элементы множества 5 приписаны листьям 2-3-дерева в порядке возрастания слева направо и в каждом узле определены функ- ции L(v) и М(у), введенные в предыдущем пункте. Операция ПРИНАДЛЕЖАТЬ Чтобы определить принадлежность элемента к данному словарю, ор- ганизованному в виде 2-3-дерева, необходимо провести поиск в дереве по приводимому ниже алгоритму. Алгоритм представляет собой очевидное обобщение процедуры поиска в дереве сортировки. проц ПОИСК(г : вершина; а : элемент) = 1. % г — корень 2-3-дерева, в котором ищется элемент а % 2. если все сыновья вершины г — листья то 3. если а есть среди значений листьев г то 4. возврат лист со значением а 5. иначе возврат % неуспех % все 6. иначе Пусть s- — i-й сын вершины г; 7. если а < L(r) то ПОИСК(sp а) 8. иначе если у г два сына или а < М(г) то 9. ПОИСКА, а) 10. иначе ПОИСК($3, а) все все все все Операция ВСТАВИТЬ Чтобы в 2-3-дерево вставить новый элемент а. надо найти место для нового листа /, который будет содержать элемент а. Для этого проводится поиск элемента а в дереве. Если дерево содержит более одного элемента, то поиск а закончится в узле у, имеющем двух или трех сыновей, каждый из которых является листом. Возможны два случая: узел v имеет двух сыновей (/, и /2) и узел у имеет сыновей (Zp 12 и /3). В первом случае I делаем третьим сыном узла у. Лист I становится самым левым сыном узла у, если а < (при этом полагаем L(v) = а и М(у) = средним сыном, если МЩ) < а< W(l2) (при этом полагаем М(у) = а), и наконец, самым правым сыном, если а > W(l2) (при этом, возможно, надо будет изменить значения L и М у некоторых предков узла v). Во втором случае, поступая как и выше, получаем ситуацию, в кото- рой узел у имеет четырех сыновей. Чтобы сохранить свойство дерева быть 2-3-деревом, образуем новый узел g. Два левых сына оставим сы- новьям узла у, а два правых сделаем сыновьями узла g, а сам узел g — сыном отца узла у (в используемой терминологии узел g становится бра- том узла у). Если отец узла у имел до подключения узла g двух сыновей, то процедура заканчивается, в противном случае повторяем процедуру расщепления вершины с четырьмя сыновьями.
7.1.9. Словари: реализация 2-3-деревьями 289 проц ДОБАВСЫНА(у : вершина; а : элемент) = 1. % у - вершина непустого 2гЗ-дерева Т, не содержащего элемента а % 2. Образовать новую вершину у'; 3. Сделать двух самых правых сыновей вершины у левым и правым сыновьями вершины v'; 4. если у v нет отца то 5< % у — корень дерева Т% 6. Образовать новый корень г, левым сыном которого сделать у, а правым у' 7. иначе Пусть f— отец вершины у; 8. Сделать у' сыном узла /, расположенным непосредственно справа от у; 9. если у /стало четыре сына то 10. ДОБАВСЫНА(/, а) все все все проц ВСТАВКА(Т : дерево; а : элемент) = 1. если Т состоит из одной вершины I с меткой b 2. то Образуем новый корень г'; 3. Образуем новую вершину у с меткой а 4. Делаем / и у сыновьями корня г', причем I будет левым сыном, если Ь < а, и правым — в противном случае 5. иначе /:« ПОИСК (г, а); 6. если / не лист то 7. % неудачное завершение поиска % 8. Образовать новый лист / с меткой а\ 9. если у/два сына с метками Ьх и Ь2 то 10. если а < то 11. Сделать I самым левым сыном вершины / 12. иначе если < а < Ь2 то 13. Сделать / средним сыном вершины/ 14. иначе Сделать I правым сыном вершины / все все 15. иначе Пусть у / три сына с метками Ь{, Ь2 и Ь3, 16. еслиас/^то 17. Сделать / самым левым сыном вершины / 18. иначе если Ь{ < а < Ь2 то 19. Сделать I вторым слева сыном вершины / 20. если Ь2 < а < Ь3 то 21. Сделать I третьим слева сыном вершины / 22. иначе Сделать I правым сыном вершины / все все все; 23. ДОБАВСЫНА(/, я);
290 7.1.10. Очереди с приоритетами: реализация 2-3-деревьями 24. Скорректировать значения функций L и М на пути из листа с меткой а в корень все все все все Замечание. Часть коррекции значений функций L и М может быть выполнена в процедуре ДОБАВСЫНА и в строках 9—22 процедуры ВСТАВКА. Операция УДАЛИТЬ Эта операция — обратная операции ВСТАВИТЬ, поэтому ограни- чимся наброском алгоритма. Процедурой ПОИСК(я, г), где г — корень дерева, находим лист I с меткой а. Возможны три случая. Случай 1. Если / — корень, удаляем его. (В этом случае а был единственным элементом в дереве.) Случай 2. Если I — сын узла, имеющего трех сыновей, удаляем его с соответствующей коррекцией значений L и М. Случай 3. Если I — сын узла /, имеющего двух сыновей s и /, то может быть одно из двух: а) узел /— корень; удаляем I и/и делаем корнем второго сына s; б) узел / — не корень; пусть g — брат узла f и пусть для определен- ности g— правый брат (случай, когда g находится слева, рассматривает- ся аналогично). Если у g только два сына, делаем узел s самым левым сыном узла g, удаляем I и рекурсивно вызываем процедуру удаления, чтобы удалить/. Если у g три сына, то самого левого сына делаем правым сыном узла f и удаляем /. После выполнения операции УДАЛИТЬ выполняется корректировка значений функций L и М на пути из листа / в корень дерева. 7.1.10. Очереди с приоритетами: реализация 2-3-деревьями. В дан- ном пункте предполагается, что элементы множества 5 приписаны лис- тьям 2-3-дерева в порядке возрастания слева направо и в каждом узле определены функции L(v) и M(v), введенные в п. 7.1.8. Операция ПРИНАДЛЕЖАТЬ (см. п. 7.1.9) Операция ВКЛЮЧИТЬ (см. п.7.1.9) Операция MIN. Наименьший элемент в 2-3-дереве находится в самом левом листе, который отыскивается процедурой ПОИСК путем выбора в каждом узле самого левого сына. Замечание. Нетрудно убедиться, что для реализации очередей с приоритетом годны также и АВЛ-деревья (см. п.7.1.4). 7.1.11. Сливаемые деревья. Сливаемые деревья — это структура дан- ных, в которой множество листьев не упорядочено, как это предполага- лось впп.7.1.9и7.1.10,ис помощью которой можно выполнить последо- вательность операций ВСТАВИТЬ, УДАЛИТЬ, ОБЪЕДИНИТЬ и MIN за время O(/ilogn). Каждый узел v этого дерева помечен значением
7.1.11. Сливаемые деревья 291 НАИМЕНЬШИЙ [у], т.е. значением наименьшего элемента, храняще- гося в поддереве с корнем у. Функции L и М в этом случае не используются. Операция ВСТАВИТЬ Новый элемент а вставляется в дерево Т в произвольном месте, добав- ляя новый лист с соответствующим значением, после чего вызывается, если нужно, процедура ДОБАВСЫНА, а также производится кор- ректировка значений функции НАИМЕНЬШИЙ. Предполагается, одна- ко, что для такого дерева параллельно создается вспомогательный сло- варь в виде того же 2-3-дерева, листья которого содержат указатели на листья дерева Т. Словарь нужно корректировать всякий раз, когда вы- полняется операция ВСТАВИТЬ, но это требует не более O(logn) шагов. Операция УДАЛИТЬ В тех приложениях, когда нужно удалить наименьший элемент, не- обходимо воспользоваться операцией MIN, в противном случае осущест- вляется поиск во вспомогательном 2-3-словаре для отыскания нужного листа. В остальном удаление листа производится так же, как и в п.7.1.9. После удаления листа из Т нужно для каждого его предка пересчитать значение функции НАИМЕНЬШИЙ. Новым значением для НАИ- МЕНЬШИЙ [у ] будет наименьшее из значений НАИМЕНЬШИЙ [s ] для двух или трех сыновей s узла у. Если всегда пересчитывать снизу вверх, то индукцией по числу пересчетов можно показать, что каждое вычисление дает для функции НАИМЕНЬШИЙ правильный ответ. Операция MIN Наименьший элемент множества 5 можно найти, если двигаться по деревуТ, начиная с корня, если каждый раз, находясь во внутреннем узле у, переходить к сыну узла у, помеченному наименьшим значением функции НАИМЕНЬШИЙ. Операция ОБЪЕДИНИТЬ Данная операция сливает два множества и 53, каждое представлен- ное соответствующим 2-3-деревом Т( и 7\, в одно множество следующим образом. Пусть высота дерева Ti равна Л,- и пусть h{ > Z^. Найдем на самом правом пути в 7\ узел у высотой /г2 и сделаем корень дерева Т2 его самым правым братом. Если у отца f узла у окажется четыре сына, то вызывается процедура ДОБАВСЫНА(/). Значения функции НАИ- МЕНЬШИЙ на узлах, потомки которых изменяются в процессе выпол- нения процедуры слияния, можно скорректировать тем же способом, что и в операции УДАЛИТЬ. функ СЛИЯНИЕ (Тр Т2 : дерево) = 1. % Строит наименьшей высоты дерево Г, содержащее деревья Т1 и Т2% 2. Пусть Л1 и Л2 — высоты деревьев 7Т и Т2 3. если hl = Л2 то Образовать новый корень г, сделав КОРЕНЬ (7\) и КОРЕНЬ(7\) соответственно левым и правым сыновьями вершины г 4. иначе если Л1 < Л2 то Переименовываем деревья все; 5. ГЛУБИНА(КОРЕНЬ(Т1)) :=0; у:= КОРЕНЬ(Л);
292 7.1.12. Сцепляемые очереди 6. пока ГЛУБИНА(v) # h\ - hl цикл 7. v := самый правый сын v; 8. ГЛУБИНА(р) := ГЛУБИНА(р) + 1 все; 9. Сделать КОРЕНЬ(Т2) сыном отца /вершины у, расположив его непосредственно справа от у; 10. если у /теперь четыре сына то 11. ДОБАВСЫНА(/) все все все 7.1.12. Сцепляемые очереди. Это структуры данных в виде 2-3-дере- ва, с помощью которых можно выполнять операции ВСТАВИТЬ, УДА- ЛИТЬ, НАЙТИ, СЦЕПИТЬ и РАСЦЕПИТЬ. Предположим, что эле- менты множества S расположены в листьях 2-3-дерева в порядке возра- стания слева направо и для каждого узла вычислены значения L(v) и М(у). Для сцепляемых очередей операции ВСТАВИТЬ, УДАЛИТЬ полно- стью те же самые, что и в п.7.1.9, а операция НАЙТИ совпадает с опе- рацией ПРИНАДЛЕЖАТЬ. Операция СЦЕПИТЬ Данная операция объединяет в одну очередь две последовательности элементов 5, и S2 таких, что каждый элемент из St меньше каждого элемента из S2, давая на выходе конкатенацию этих последовательно- стей, т.е. SjS2. Если Sj и S2 представлены 2-3-деревьями Т\ и Т2, то результатом операции СЦЕПИТЬ должно быть 2-3-дерево Т, листьями которого являются листья дерева 7\ и следующие за ним листья дерева Т2 в их первоначальном порядке. Это можно осуществить, используя проце- дуру ИМПЛАНТАЦИЯ (Тр Т2) следующим образом. Если h{ h^ то применяем процедуру ИМПЛАНТАЦИЯ без изменений, в противном случае используем ’’зеркальный” вариант процедуры, заменив все вхож- дения слова ’’левый” на "правый”, и наоборот. Операция РАСЦЕПИТЬ Операция РАСЦЕПИТЬ (a, S) разбивает упорядоченное множество S на две последовательности: SP элементы которой не больше а, и S2, элементы которой больше а, т.е. Sj = {b I b < a, b G S} и S2 = {b I Ь > а, b G S}. Если S задана в виде 2-3-дерева Г, то данная операция расцепля- ет дерево Т на два таких 2-3-дерева 7\ и Т2, что метки всех листьев в Т{ не больше а, а метки всех листьев в Т{ больше а. Способ, которым можно осуществить это расцепление, следующий. Двигаясь по пути из корня дерева Т в лист, где хранится элемент а, разбиваем наше дерево на поддеревья, корнями которых служат не сами узлы, лежащие на этом пути, а их сыновья (рис. 7.7). Эти деревья естественным образом раз- биваются на две группы: деревья, лежащие слева от пути, и деревья — справа от пути. На рис. 7.7 первую группу образуют поддеревья Т1? Т2, Т3 и тривиальное дерево, состоящее из одной вершины у1? а вторую — де- ревья Т4, Т5 и v2.
7.1.12. Сцепляемые очереди 293 Деревья слева от рассматриваемого пути и дерево, состоящее из одной вершины а, соединяются с помощью операции СЦЕПИТЬ. Аналогично соединяются деревья, расположенные справа от пути. проц ДЕЛЕНИЕ (Т : дерево; а : элемент) = 1. % Строит по 2-3-дереву Т и элементу а дерево 7,, у которого метки листьев не больше а, и дерево 72, у которого метки листьев больше а% 2. Найти путь в Т от корня к листу с меткой а\ 3. Удалить из Т все вершины этого пути, кроме листа с меткой а 4. % В данный момент дерево Т оказалось разделенным на два леса — левый, состоящий из всех деревьев, листья которых лежат слева от а, и из вершины а, и правый, состоящий из всех деревьев, листья которых лежат справа от а % 5. пока в левом лесу не более одного дерева цикл 6. Пусть Т и 7" — два самых правых дерева в левом лесу 7. 7"':=СЛИЯНИЕ(7', 7"); 8. 7"' отнести к левому лесу все; 9. пока в правом лесу более одного дерева цикл 10. Пусть 7' и 7 — два самых левых дерева в правом лесу; 11. Т'1' -СЛИЯНИЕМ', 7"); 12. 7" отнести к правому лесу все все Заметим, что с помощью сцепляемой очереди последовательность S2 можно вставить между парой элементов последовательности 5, за время CXmaxOogi^! I, loglS2l). Если S2 = b2, ..., bn, == л,, а2, ..., а1П и S2 нужно вставить между элементами ц и то нужно применить опе- рацию РАСЦЕПИТЬ(лр 5,) и разбить по элементу at на две последо- вательности ..., at и 5/= ..., ат. Затем применить операцию
294 7.1.13. Выровненные деревья СЦЕПИТЬ(5р S2), результатом которой будет последовательность S3 = = at, ..., ц, bif ...» bn, и наконец, применить операцию СЦЕПИТЬ(53, S"), дающую нужную последовательность. 7.1.13. Выровненные деревья. Под выровненными деревьями понима- ются бинарные (а также другие типы деревьев, например 2-3-деревья), у которых все висячие вершины (листья) расположены на одном уровне, ин- формация хранится только в листьях, а в остальных вершинах хранится вспомогательная информация, облегчающая поиск. К выровненным дере- вьям, кроме упомянутых выше 2-3-деревьев, относятся: Н-деревья, или де- ревья соседства, НВ-деревья, или братские, HS-деревья (расширение клас- са ЯВ-деревьев), 1-2-брсипские деревья, бинарные деревья малой высоты, или к-деревья, RB-деревья, или правые братские деревья, и др. А. Бинарное дерево называется Н-деревом (деревом соседства), если все висячие вершины находятся на одном уровне и каждая вершина с единственным потомком имеет правого соседа с двумя потомками. Пример Я-дерева приведен на рис. 7.8. Напомним, что вершина х называется непосредственно правым (не- посредственно левым) соседом вершины у, если х и у — вершины одного и того же уровня и вершина л* появляется непосредственно справа (слева) от вершины у в графическом изображении дерева, содержащего х и у в качестве своих вершин. Пусть Я-дерево имеет по крайней мере две висячие вершины. Добав- ление новой вершины может быть произведено лишь на самом нижнем уровне, т.е. добавлением нового листа. При этом у некоторой вершины может оказаться три потомка, восстановление структуры Я-дерева про- исходит с помощью процедуры, аналогичной процедуре ДОБАВСЫНА из п. 7.1.9. Необходимость в восстановлении структуры дерева возникает и при удалении вершины, когда может появиться висячая вершина на уровне выше уровня листьев. Б. Бинарное дерево называется НВ-деревом (деревом братства), ес- ли все висячие вершины находятся на одном уровне и каждая вершина с одним потомком имеет брата с двумя потомками. Напомним, что брат вершины v — это вершина с общим с v отцом в отличие от соседней с ней вершины в определении Я-дерева. Пример ЯВ-дерева приведен на рис. 7.9.
7.1.14. ^-деревья малой высоты 295 Сравнение ЯВ-дерсвьев с Я-деревьями показывает, что существуют Я-деревья, не являющиеся ЯВ-деревьями, и наоборот, существуют ЯВ- деревья, не являющиеся Я-деревьями. В. Бинарное дерево называется ЯS-деревом, если справедливы два условия: все висячие вершины находятся на одном уровне и единствен- ный потомок любой вершины либо является листом, либо сам имеет двух потомков. Пример НS-дерева приведен на рис. 7.10. Очевидно, что каждое ЯВ-дерево является также ЯВ-деревом, но об- ратное неверно, т.е. класс Я5-деревьев есть расширение класса НВ-пе- ревьев. 7.1.14. ^-деревья малой высоты. Бинарное дерево называется к-дере- вом малой высоты, если: а) все висячие вершины располагаются на одном и том же уровне; б) вершина с одним потомком имеет по крайней мере одного правого соседа и первые к правых соседей (или все правые соседи, если их число меньше к) этой вершины имеют двух потомков. Замечание. Требование иметь хотя бы одного соседа гарантирует отсутствие вырожденных деревьев с единственной висячей вершиной. Любое Л-дерево есть i'-дерево для к' < к. 1-дерево — это в точности Я-дерево. На рис. 7.11 изображены 1-дерево, 2-дерево и дерево, не явля- ющееся ^-деревом ни для какого к. Трудоемкость алгоритмов включения и исключения вершин для £-де- рева пропорциональна его высоте, относительно которой справедливо следующее: для каждого е > 0 существует такое к, что класс Л-деревьев есть класс выровненных бинарных деревьев высоты h < (1 + £)10grt + 1, где п — число листьев. 7.1.15. 1-2-братские деревья. Промежуточное положение между ба лансированными по высоте или весу и выровненными деревьями занима- ют 1-2-братские деревья, которые, с одной стороны, обладают структу- рой выровненного дерева, а с другой — хранят информацию во внут- ренних вершинах — узлах, а нс в листьях, причем узлы с двумя потом-
296 7.1.15. 1-2-братские деревья ками содержат одно слово из множества S, а узлы с одним потомком слов Рис. 7 J ] Итак, бинарное дерево называется 1 2-братским деревом, если: а> все висячие вершины располагаются на одном уровне; б) каждая вершина с одним сыном имеет брата с двумя сыновьями; в) элементы множества 5 хранятся в узлах дерева так, как это описа- но выше: г) для каждого узла ус двумя сыновьями слова в левом поддереве узла у меньше слова в у, которое, в свою очередь, меньше слов в правом поддереве Пример 1-2-братского дерева, представляющего множество 5 = {2, 3. 5, 7, 8 10, 13}, приведен на рис. 7.12. Для описания операций ВСТАВИТЬ, ПРИНАДЛЕЖАТЬ, УДА- ЛИТЬ используем следующие обозначения: Av — левый сын узла v; рv — правый сын; оу — единственный сын; Фу — отец узла у. Операция ПРИНАДЛЕЖАТЬ
7.1.15. 1-2-братские деревья 297 Для отыскания элемента а в 1-2-братском дереве Т используется сле- дующая процедура ПОИСК. проц ПОИСК (v: вершина; а : элемент) = 1. если v — лист то 1. возврат у; 3. % элемента а в дереве нет % 4. иначе если v имеет одного сына то 5. ПОИСК(оу, а) 6. иначе если W(v) > <2 то ПОИСК(Лу, а) иначе если W(v) = а то возврат а иначе ПОИСК (ру, а) все все все все все Операция ВКЛЮЧИТЬ Для осуществления вставки нового слова нужно вначале осуществить поиск этого слова в дереве; если поиск безуспешен, т.е. заканчивается в листе, запоминаем вершину р — отца этого узла, создаем новый узел и производим реконструкцию дерева для сохранения его свойства быть 1-2-братским деревом. Реконструкция дерева производится с помощью процедуры UP(p, m, а), которая вызывается в одном из следующих трех случаев: а) узел р имеет двух сыновей / = Лр и г=рр, которые являются кор- нями 1-2-братских деревьев; б) вершина пг есть либо лист, либо имеет только одного сына, который является корнем 1-2-братского дерева, и высота поддерева с корнем m равна высотам поддеревьев с корнями Хр ирр (см. рис. 7.13); Рис. 7.13 в) либо а < W(p), если m есть лист, либо W(T{) <а< WiT^) < W(p) < WIT), где W(Tb) — множество слов в поддереве с корнем й, в противном случае. проц UP(p, m : вершина; х : элемент) в 1. если р имеет левого брата q с двумя сыновьями 10 В.А. Евстигнеев, В.Н. Касьянов
298 7.1.15. 1-2-братские деревья 2. то %3десь предполагается, что /, т и г не являются листьями. В противном случае следует учитывать, что ат не существует, а Кх, К2 и К3 — пустые слова (рис. 7.14) % Рис. 7.14 3. Создать новую вершину т’ и сделать ее сыном вершины Фр, расположенным между q и р; 4. Сделать I « Лр единственным сыном вершины т'; 5. Сделать т левым сыном вершины р; 6. Запомнить слово b из вершины Фр; 7. Ж(Фр) := х все 8. если р имеет правого брата с двумя сыновьями то 9. Выполнить преобразования (рис. 7.15); 10. £7Р(Фр, ет',/0 11. завершить UP все 12. если р имеет левого брата с одним сыном то 13. Выполнить преобразования (рис. 7.16); 14. завершить UP все; 15. если р имеет правого брата с одним сыном то 16. Выполнить преобразования (рис. 7.17); 17. завершить UP все; 18. если р не имеет братьев то 19. % в этом случае р — либо корень, либо единственный сын своего отца % 20. Выполнить преобразования (рис. 7.18); все все;
7.1.15. 1 -2-братские деревья 299 Рис. 7.15 Рис. 7.16 Рис. 7.17
300 7.1.15. 1-2-братские деревья Рис. 7.18 проц ВКЛЮЧЕНИЕ-ЭЛЕМЕНТА(Т : дерево; а : элемент) в 1. % Дерево Т имеет по крайней мере корень и один элемент % 2. р :» ОТЕЦ(ПОИСК(КОРЕНЬ(Т), л))); 3. если р имеет только одного сына то 4. % в р не хранится ни один элемент % 5. Подвешивается к р второй лист; 6, W(p) а 7. % (см. рис. 7.13)% 8. иначе Создается новый лист m между Хр ирр\ 9. UP(p, m, а) все все Операция УДАЛИТЬ Эта операция также требует восстановления структуры 1-2-братского дерева после удаления вершины с элементом а, что всегда соответствует удалению вершины с двумя сыновьями. проц УДАЛЕНИЕ (р : вершина) в 1. % всякий раз, когда вызывается эта процедура, выполняется одно из следующих условий: а) р имеет только одного сына, который является либо листом, либо корнем 1-2-братского дерева; б) р потеряла свое значение;
7.1.15. 1 -2-братские деревья 301 в) для всех вершин q в дереве, кроме р и /?р (брата р, если таковой существует), если д имеет одного сына, то д имеет брата с двумя сыновьями % 2. если р имеет брата с двумя сыновьями то 3. завершить УДАЛЕНИЕ 4. иначе если р имеет брата с одним сыном, то 5. Выполнить преобразование, показанное на рис. 7.19; 6. УДАЛЕНИЕ(Фр); %случай, когда р есть левый сын своего отца, рассматривается аналогично % все все; 7. если р не имеет братьев, то 8. если р —' корень то 9. Удалить р, сделав единственного сына р новым корнем; 10. завершить УДАЛЕНИЕ все; 11. если р — единственный сын своего отца Фр то 12. % В этом случае Фр имеет брата /?<1р с двумя сыновьями % 13. если А/ЗФр имеет одного сына то 14. Выполнить преобразования, показанные на рис. 7.20 15. УДАЛЕНИЕ(Ф<1р); %случай, когдар/?Фр имеет только одного сына, и все симметричные подслучаи преобразования на рис. 7.20 рассматриваются аналогично % все все; 16. если Л/fap ир/fclp имеют двух сыновей то 17. % Предположим для определенности, что Фр левый сын своего отца; симметричный случай рассматривается аналогично % 18. Выполнить преобразования (см. рис. 7.21); 19. завершить УДАЛЕНИЕ все
302 7.1.15. 1 -2-братские деревья проц УДАЛЕНИЕ-ЭЛЕМЕНТА(Т : дерево; а : элемент) « 1. р := ПОИСК(КОРЕНЬ(Т), л); 2. если оба сына р — листья то 3. Удалить один из листьев; 4. Удалить слово а из р; 5. УДАЛЕНИЕ (р) 6. иначе % В этом случае в силу определения 1-2-братского дерева либо/эр, либо Яр является вершиной с двумя сыновьями, предположим для определенности, чторр — бинарная вершина % 7. q := самая правая бинарная вершина левого поддерева со значением W(q) = у 8. если оба сына q — листья то %см. рис. 7.22% 9. W(p) := у; W(q) := Ф;
7.1.15. 1 -2-братские деревья 303 10. Удалить одного из сыновей q\ 11. УДАЛЕНИЕ^) 12. иначе % В этом случае q имеет левого сына г с двумя сыновьями — листьями и с W(r) s z и правого сына с одним листом (см. рис. 7.23) % 13. W(p) := у; W(q) := z; W(r) := Ф; 14. Удалить одного из сыновей вершины г; 15. УДАЛЕНИЕ(г) все все все Операции ВСТАВИТЬ, ПРИНАДЛЕЖАТЬ и УДАЛИТЬ могут быть реализованы для 1-2-братского дерева, представляющего «-элементное множество, с трудоемкостью О (log (« + 1)). Рис. 7.23
304 7.2.1. Многомерное дерево сортировки 7.2. Многомерные деревья, или Л-с/-деревья 7.2.1. Многомерное дерево сортировки. Пусть имеется множество записей, характеризующихся к ключами ..., Ккл. Каждая такая за- пись может рассматриваться как точка в Л-мерном пространстве. Много- мерные деревья предназначены для организации словарей для таких множеств. Бинарное дерево называется многомерным деревом сортировки или k-d-деревом сортировки, если: а) каждой вершине v сопоставлен дискриминатор DISC(v) так, что дискриминатор корня равен нулю, дискриминаторы его сыновей равны единице и, вообще, дискриминатор вершины на уровне / равен /(mod k); б) для каждой вершины v с дискриминатором j выполнено условие: левый потомок Av имеет /-й ключ KyUv) меньше /-го ключа Xy(v) в вершине v, а правый потомок рv имеет /-й ключ К^(р v) больше /-го ключа в вершине v, т.е. KyUv) < Xy(v) < Kj(pv). В случае равенства ключей можно поступать по-разному, но для большинства приложений полезным оказывается следующий прием. Определим для вершины v /-й суперключ W<(v), положив Wj(v) = A}(v)Xy+1 (v)...КЬ1 (v)... KjA (v), т.е. приняв в качестве суперключа циклическую конкатенацию ключей, начинающуюся с ключа Ку. Тогда условие б) в определении многомерно- го дерева сортировки Заменяется условием б') для каждой вершины v с дискриминатором / выполнено условие: левый потомок имеет /-й суперключ меньше /-го суперключа W<(v) в вершине v, а правый потомок имеет/-й суперключ больше /-го суперклю- ча в вершине v. Пример. Пусть записи представляют собой точки в двумерном евклидовом пространстве (рис. 7.24), где прямоугольники изображают размер поддеревьев. Соответствующее 2-J-дерево показано на рис. 7.25. 7.2.2. Включение новой записи в Л- J-дерево. Включение новой вер- шины в Л-J-дерево принципиально не отличается от аналогичной проце- дуры, определенной в п. 7.1.2 для дерева сортировки. Построение дерева также начинается с создания вершины г — корня дерева; после сопостав- ления ему записи W(r) создаются две свободные вершины: ПРАВСЫН(г) и ЛЕВСЫН(г), значение которых равно Ф. Для включения новой записи в Л-б/-дерево производится поиск, если записи в дереве нет, то поиск заканчивается в листе Z, значение которого равно Ф. Сопоставляем вно- симую запись данному листу и превращаем его во внутреннюю вершину подвешиванием к нему двух листьев. проц ВКЛЮЧЕНИЕ(7: дерево; W: запись) = 1. % Процедура в £-б/-дерево Т включает запись ^=(Х0Л1,...,^.1)°/о 2. р := корень дерева 7; /:» DISC(p); 3. пока W(p) * Ф цикл 4. если W\p) s IFто 5. завершить ВКЛЮЧЕНИЕ % запись W есть в дереве 7%
7.2.2. Включение новой записи в A-d-дерево 305 чо г* оо OS иначе если W < WAp) то р := ЛЕВСЫЩр); (К,, 1С(, иначе р := ПРАВСЫН(р) Ко,.... все % 10. 11. 12. все все; W(p) Ж; DISC(p) := (DISC(p) + 1) mod k; Создать вершины ЛЕВСЫН(р) и ПРАВСЫН(р); ИЧЛЕВСЫЩр)) := Ж(ПРАВСЫН(р)) :=Ф; все
306 7.2.3. Поиск в ^-tZ-дереве Нетрудно проверить, что 2-г/-дерево (см. рис. 7.25) может быть полу- чено последовательной вставкой записей в порядке Л, В, С, D, Е, F, G. 7.2.3. Поиск в к- J-дереве. Поиск состоит в нахождении множества записей, удовлетворяющих данному запросу. Запрос может иметь раз- личный вид, от простого, например {Р I К3(р) сложного, напри- мер {Р I (1 < К2(Р) < 5) & (2 < К5(Р) < 4)} V (К7(Р) = 8)}. Ниже рас- сматриваются три, все более усложняющихся типа запросов, каждый из которых есть обобщение предыдущего. Точный поиск записи. Это простейший вид запроса, он сос- тоит в проверке, находится ли запись W = (Ао, ..., в дереве. Обработка этого запроса ничем не отличается от реализации операции ПРИНАДЛЕЖАТЬ. Если этот тип запроса — единственный допускае- мый, то использование Л-б/-дерева в качестве структуры данных ничем не оправдывается, достаточно обойтись каким-либо типом дерева сор- тировки из предыдущего пункта, рассматривая суперключ Ж-Хо, в качестве единственного ключа. Поиск по множеству ключей. При этом виде запроса задаются набор ключей и их значения и требуется найти множество записей, у которых специфицированные ключи принимают указанные значения. Пусть {sj и {у-} — такие множества, что специфицированные ключи суть Ks^ ..., Ks, а значения, которые они должны иметь, суть vs , ...,vs. Тогда искомым множеством записей будет {Р I KS (P) = vsii 1 < i < /}. Алгоритм поиска будет описан ниже; идея же поиска состоит в следу- ющем. Пусть на некотором шаге алгоритма мы попали в вершину Р. Если W(P) удовлетворяет запросу, то Р заносится в множество-ответ. В про- тивном случае допустим, что дискриминатор вершины Р равен /. Тогда возможны два случая: /= \ для некоторого i, 1 < i < /, и j £ {$}. В пер- вом случае продолжаем поиск в левом поддереве вершины Р, если vsi < К-(Р), и в правом, если vsi > К-(Р). (Если имеет место равенство vsi = Kj (P), то переход к правому или левому поддереву определяется приня- тыми соглашениями.) Если j £ {sj, то мы должны продолжить поиск в обоих поддеревьях. При этом предполагается, что поддеревья не пусты. Поиск в ограниченной области. Более общий тип за- проса — поиск в ограниченной области — предполагает задание границ изменения значений специфицированных запросом ключей. При этом не требуется знать определение области, в которой ведется поиск, доста- точно знать значения (или уметь вычислять) двух функций: В-ОБЛА- СТИ и ПЕРЕСЕЧЕНИЕ-ГР АНИЦЫ-ОБЛАСТИ. Первая указывает для каждой рассматриваемой в данный момент вершины, находится ли она в области или нет, вторая оценивает значение ключей и отмечает выход за пределы области. Поиск ближайшего соседа. Несколько особняком стоит запрос следующего вида. Для данной функции расстояния D, семейства точек В в Л-мерном пространстве и точки Р (в том же пространстве)
7.2.4. AjiropiriT'vi поиска ь oujiuCih 307 необходимо найти в В ближайшего соседа точки Р. Ближайший сосед — это такая точка Q, что (VP Е B)(R * Q) => (D(P, Р) > D(Q, Р)). Аналогичный запрос можно сформулировать и для нахождения т ближайших соседей вершины Р. 7.2.4. Алгоритм поиска в области. Данный алгоритм также решает задачу поиска по множеству ключей. Сделаем предварительно одно за- мечание. Ключи всех вершин в поддереве любой вершины, скажем Р, ограничены рамками, определяемыми позицией Р в k-tZ-дереве. Напри- мер, если Р находится в правом поддереве любой вершины Q и дис- криминант Q равен /, то все вершины в этом поддереве, включая Р, /-больше Q, т.е. если R в этом поддереве, то К-(Р) > Ky(Q), и если к тому же R лежит в правом поддереве вершины Р, то Kj(R) >К^Р). Чтобы учесть эти сведения в алгоритме поиска, определим граничный массив для хранения такой информации. Если В — граничный массив, сопостав- ленный вершине Р, то В имеет 2К элементов В(0), ..., В(1К- 1), причем если Q — потомок Р, то для всех целых / е [0 : К - 1 ] справедливо нера- венство В(2/) < Kj(Q) < B(2j + 1). Граничный массив считается задан- ным, если вначале для всех / G [0 : К - 1 ] B(2j) =-оо и B(2j + 1) = +<». Например, граничный массив для вершины С (см. рис. 7.25) есть (50, 100, 0, 100). Это означает, что значения ключая Ао в этом поддереве заключены между 50 и 100, а все значения ключа К{ — между 0 и 100. Алгоритм Вход. к-б/-дерево Т, область поиска в виде гиперпрямоугольника, определяемого граничным массивом RECDEF. Выход. Множество вершины дерева из этой области. функ В-ОБЛАСТИ(р : вершина) = 1. % вырабатывает истинное значение, если р принадлежит специфицированной области % 2. для I от 1 до к - 1 цикл 3. если К^р) < RECDEF(3 • /) то возврат ложь все; 4. если Kf(p) > RECDEF(2 ♦ I + 1) то возврат ложь все все; 5. возврат истина все; функ ПЕРЕСЕЧЕНИЕ-ГРАНИЦЫ-ОБЛАСТИ(В : массив) = 1. % выдает истинное значение, если гиперпрямоугольник, определяемый массивом В, пересекает гиперпрямоугольник, определяемый массивом RECDEF% 2. для I от 0 до 2(к - 1) через 2 цикл 3. если В [/ ] > RECDEF(/ + 1) то возврат ложь все; 4. если В [1 + 1 ] < RECDEF(/) то возврат ложь все все; 5. возврат истина все;
308 7.2.5. Удаление вершины из £-с/-дерева проц НАЙТИ (р : вершина) = 1. % процедура сообщает, что р лежит в специфицированной области; вид сообщения определяется реализацией % все; начало 1. р:= КОРЕНЬ (Г); 2. если В-ОБЛАСТИ (р) то НАЙТИ (р) все; 3. Создать граничные массивы BL и Вн и скопировать В в оба массива; BL — для ЛЕВСЫН(р), Вн — для ПРАВСЫН(р)% 4. j :=DlSC(p); 5. BL(2 • j+ 1) :=K(p); 6. Вн(2 • j) % Производится модификация граничных массивов, исходя из того факта, что ключ К^(р) является верхней границей для ключей А в вершинах из левого поддерева вершины р и нижней границей для ключей А. в вершинах из правого поддерева вершины р% 7. если (ЛЕВПОДДЕРЕВО(р) # 0) & ПЕРЕСЕЧЕНИЕ-ГРАНИЦЫ-ОБЛАСТИ(Вр 8. то ПОИСК-В-ОБЛАСТИСЛЕВСЫН(р), BL) все; 9. если (ПРАВПОДДЕРЕВО(р) # 0) & ПЕРЕСЕЧЕНИЕ-ГРАНИЦЫ-ОБЛАСТЙ(ВЯ) 10. то ПОИСК-В-ОБЛАСТИ(ПРАВСЫНСр), BL) все конец Аналогичные процедуры могут быть написаны для других по форме областей с применением логических функций И, ИЛИ, НЕ. 7.2.5. Удаление вершины из k-d-дерева. Удаление вершины будем рассматривать как удаление корня некоторого поддерева. Если Р не име- ет поддеревьев, то просто удаляем Р. Если Р имеет потомков, то он может быть заменен одним из них, скажем Q, который сохранит порядок, ин- дуцированный вершиной Р. Иными словами, все вершины из правого поддерева вершины Р должны быть в правом поддереве вершины Q и то же самое должно быть относительно левого поддерева. Предположим, что дискриминатор вершины Р равен /’. Тогда Q должен быть /-макси- мальным элементом (вершиной, в которой ключ К- имеет наибольшее значение среди всех вершин поддерева) в левом поддереве вершины Р (или /-минимальным в правом поддереве вершины Р). Когда Q найдена, она может служить новым корнем вместо Р, нужно только провести необ- ходимую реорганизацию дерева для удаления Q из прежней позиции в дереве. Алгоритм Вход. £-б/-дерево Т, вершина Р. Выход. Модифицированное Л-J-дерево. проц УДАЛЕНИЕ (Р : вершина) = 1. если (ЛЕВПОДДЕРЕВО(Р) = 0) & (ПРАВПОДДЕРЕВО(Р) = 0) то 2. Удалить Р из дерева
7.2.6. Оптимизированные ^-d-деревья 309 3. завершить УДАЛЕНИЕ 4. иначе j := DISC (Р); 5. если ПРАВПОДДЕРЕВО(Р) = 0 то 6. Q := /-минимальная вершина в ПРАВПОДДЕРЕВО(Р) % Здесь используется алгоритм поиска в области с соответствующими уточнениями % 7. QF :« отец вершины Q; 8. QS := ЛЕВСЫН или ПРАВСЫН, смотря по тому, левый или правый сын вершины Q у своего отца; 9. иначе Q := /-максимальная вершина в ЛЕВПОДДЕРЕВО(Р); 10. QF :» отец вершины Q; 11. QS :в ЛЕВСЫН или ПРАВСЫН, смотря по тому, левый или правый сын вершина Q у своего отца все; 12. УДАЛЕНИЕ(QS(QF)); % Этот рекурсивный вызов делает вершину Q свободной, так что она может становиться новым корнем взамен Р% 13. DISC(Q) :=/; 14. ЛЕВПОДДЕРЕВО(б) := ЛЕВПОДДЕРЕВО(Р); 15. ПРАВПОДДЕРЕВО(О) := ПРАВПОДДЕРЕВО(Р) все все Условный оператор в строке 5 является источником многих непри- ятностей, так как при последовательном удалении вершин из дерева он все время заставляет удалять вершины из правого поддерева. Это про- должается до тех пор, пока не будет исчерпано все дерево, что приводит к резко деформированному дереву. Чтобы избежать этого, используются различные стратегии. Например, выбирают вершину из большего по раз- меру поддерева, поочередно из правого и левого поддеревьев, выбирают дерево с помощью датчиков случайных чисел. 7.2.6. Оптимизированные к-d-деревья. В некоторых применениях использовать Л-гУ-деревья, получаемые последовательным включением слов, подаваемых на вход алгоритма в произвольном порядке, достаточ- но невыгодно из-за возникающей конфигурации дерева (возможно, не- удачной). К ним относятся случаи, когда нужно выполнить большое ко- личество поисковых операций при малом количестве включений и ис- ключений, а также когда известно, в каком порядке будут встречаться вершины. К счастью, возможно, хотя это отразится на времени обра- ботки дерева, так оптимизировать Л-гУ-дерево, что все листья будут рас- полагаться на двух смежных уровнях. Приводимый ниже алгоритм строит Л-сУ-дерево таким образом, что число вершин в правом поддереве каждой вершины будет отличаться от числа вершин в левом поддереве не более чем на единицу. Чтобы по- строить оптимизированное £-гУ-дерево, используется процедура ОПТИ- МИЗАЦИЯ-ДЕРЕВА с параметрами А и/, где А — множество записей, заданное, например, в виде связанного списка, и/ = {0, 1, ...,£ - 1} — множество значений дискриминатора.
310 7.2.7. Свойства k-d-деревьев Алгоритм проц ОПТИМИЗАЦИЯ-ДЕРЕВА (А : множество; j: целое; v: вершина) - 1. если А # 0 то 2. Р := /-медиана множества А; % это элемент множества А, специфицированный ключом А, с номером [ IАI /2 ] или [IAI /2 + 1 ]% 3. А; := {a G А; а /-меньше Р}\ 4. Ан := {я G А; а /-больше Р}; %Al и Ан — семейства вершин, из которых конструируются левое и правое поддеревья соответственно; их мощность различается не более чем на единицу % 5. W(v) := Р\ DISC(v) := /; И := (/ + Dmod к\ 6. ОПТИМИЗАЦИЯ-ДЕРЕВА(Az, М, ЛЕВСЫН(у)); 7. ОПТИМИЗАЦИЯ-ДЕРЕВА (Ая, М, ПРАВСЫН(у)) все все; проц ПОСТРОЕНИЕ (А : множество) = 1. В качестве Т взять одновершинное дерево, значение корня которого равно Q; 2. у := КОРЕНЬ(Т); 3. ОПТИМИЗАЦИЯ-ДЕРЕВА(А, 0, у) все 7.2.7. Свойства £-с/-деревьев. Достоинство £-с/-деревьев состоит в воз- можности их использования для обработки различных типов запросов, а также в небольшой трудоемкости алгоритмов для них. Так, включение новой вершины в n-вершинное дерево имеет в среднем трудоемкость, равную O(logn). Поиск по множеству ключей может быть организован с трудоемкостью O(n(k~t)/k), где t — число специфицированных в запросе ключей. Удаление корневой вершины имеет трудоемкость О(/1<ы>/*), а удаление произвольной вершины — O(log и). Трудоемкость построения оптимизированного дерева составляет O(/ilog/i), при этом опти- мизированное дерево гарантирует логарифмическую трудоемкость поиска. 7.3. Библиографический комментарий По существу, первой работой по сбалансированным деревьям с целью применения их для организации больших массивов информации была работа Г.М.Адельсона-Вельского и Е.М.Ландиса [1 ]. Введенные ими ба- лансированные по высоте деревья были позднее названы АВЛ-деревьями [5 ]. Их описание включено в большинство издаваемых книг по вопросам хранения информации и организации поиска (см., например, [4—7], а также библиографию к обзору [3]). ВВ-деревья были введены в работе [12] и подробно охарактеризованы в [4,7]. Описание 2-3-деревьев заимствовано из [2 ]. Я-деревья и ЯВ-деревья, а также Я5-деревья были введены в работах [11, 13], A-деревья малой высоты — в [10], 1-2- братские деревья — в [14 ]. Развитие данного направления и достаточно
Список литературы 311 подробная библиография представлены в обзоре [3 ]. Л-с/-деревья были введены в [8 ], о возможностях их дальнейших применений изложено в [9 ] и последующих работах этого же автора. СПИСОК ЛИТЕРАТУРЫ 1. Адельсон-Вельский Г.М., Ландис Е.М. Один алгоритм организации информации// Докл. АН СССР. — 1962. — Т. 146, № 2. — С.263-266. 2. Ахо А., Хопкрофт Дж., Ульман Дж. Построение и анализ вычислительных алгоритмов. — М.:Мир, 1979. 3. Евстигнеев В. А. Применение бинарных деревьев для организации больших массивов ин- формации (обзор)//Прикладная информатика. — М., 1981. — Вып. 1. — С. 170—211. 4. Евстигнеев В.А. Применение теории графов в программировании. — М.: Наука, 1985. 5. Кнут Д. Искусство программирования для ЭВМ. Т. 3. Сортировка и поиск. — М.: Мир, 1978. 6. Лавров С.С., Гончарова Л.И. Автоматическая обработка данных. Хранение информации в памяти ЭВМ. — М.: Наука, 1971. 7. Рейнголд Эм Нивергельт Ю., Део Н. Комбинаторные алгоритмы. Теория и практика. — М.: Мир, 1980. 8. Bentley J.L. Multidimensional binary search trees used for associative searching//Comm. ACM. — 1975. — Vol. 18, № 9. — P. 509—519. 9. Bentley J.L. Multidimensional binary search trees in database applications//lEEE Trans, on Software Eng. — 1979. — Vol. SE-5, N 4. — P. 333—340. 10. Maurer H. A., Ottman Th., Six H.-W. Implementing dictionaries using binary trees of very small height//Inf. Proc. Lett. — 1976. — Vol. 5, N 1. — P. 11—14. 11. Maurer H.A., Wood D. Zur Manipulation von Zahlenmengen// Angewandte Informatik. — 1976. — Bd 18, N 4. — S. 143— 149. 12. Nievergelt J., Reingold E.M. Binary search trees of bounded balance//SIAM J. Comput. — 1973. — Vol. 2, N 1. — P. 33—43. 1 3. Ottman Th., Six H.-W. Eine neue Klasse von ausgeglichenen Binarba umen//Angewandte Informatik. — 1976. — Bd 18, N 9. — S. 395—400. 14. Ottman Th., Wood D. 1-2 brother trees or AVL trees revisited//Comp. Sci. Techn.Rep. 79- CS-11. — Hamilton: McMaster Univ., 1979.
Глава 8 ДЕРЕВЬЯ ДЛЯ МНОГОУРОВНЕВОЙ ПАМЯТИ 8.1. В-деревья 8.1.1. Деревья и проблема двухуровневой памяти. Существует одна весьма практическая область применения деревьев, выводящая нас за пределы бинарных деревьев. Это — формирование и поддержание круп- номасштабных деревьев поиска, в которых необходимо и включение но- вых элементов, и удаление старых, но для которых либо не хватает опе- ративной памяти, либо она слишком дорога, чтобы использовать ее для долговременного хранения. В этом случае имеет смысл считать, что вершины дерева должны храниться во внешней (вторичной) памяти, скажем, на диске. Если ис- пользовать для множества данных, включающих, например, миллион элементов, двоичное дерево, то потребуется в среднем приблизительно log (106), т.е. 20 шагов поиска. Поскольку теперь каждый шаг включает обращение к диску (в таком дереве ссылки представляют собой адреса на диске, а не в оперативной памяти), крайне желательна организация па- мяти, требующая меньшего числа обращений. Идеальное решение этой проблемы состоит в использовании так называемых сильно ветвящихся (или ш-арных) деревьев, каждая вершина которых имеет не более гп потомков, так как если происходит обращение к одному элементу во внешней памяти, то без больших дополнительных затрат можно обра- титься и к целой группе элементов. Это предполагает, что дерево разбито на поддеревья, и эти поддеревья — как раз те группы, которые доступны одновременно. Мы будем называть такие поддеревья страницами. На рис. 8.1 показано разбитое на страницы двоичное дерево (каждая из страниц содержит 7 вершин). Рис. 8.1
8.1.2. Сильно ветвящиеся, или гп-арные деревья 313 Поскольку каждое обращение к странице требует лишь одного обра- щения к диску, то экономия на числе таких обращений может быть суще- ственной. Представим себе, что каждая страница содержит 100 вершин (это вполне разумное число), в этом случае поиск в дереве с миллионом элементов будет в среднем требовать log100( 106) обращений к страницам (т.е. всего около трех, а не 20). Конечно, если дерево растет случайным образом, то в худшем случае может потребоваться даже и 104 обращений. Поэтому ясно, что для сильно ветвящихся деревьев почти обязательна некоторая схема управления их ростом. 8.1.2. Сильно ветвящиеся, или ди-арные деревья. Выровненное (см. п. 1.1.7) дерево называется т-арным деревом, если оно удовлетворяет следующим условиям: а) каждая вершина имеет не более т потомков; б) каждая вершина, кроме корня и висячих вершин, имеет не менее т/2 потомков; в) корень, если он не является висячей вершиной, имеет не менее двух потомков. Вершину v с единственным потомком cjv будем называть унарной, вершину с двумя потомками — бинарной. Будем называть также верши- ну, имеющую наибольшее возможное число потомков или являющуюся висячей, насыщенной; в противном случае будем говорить о ней как о ненасыщенной. Некоторое ди-арное дерево называется г-плотным, где г — натураль- ное число из отрезка [1 : т - 1 ], если выполнены следующие условия: а) корень дерева по крайней мере бинарен; б) каждая ненасыщенная вершина, отличная от корня, имеет не ме- нее г насыщенных братьев; в) все висячие вершины располагаются на одном уровне. Примечание. Определение брата вершины см. в п. 7.1.9. Сфор- мулируем некоторые следствия из данного определения. А. Если вершина v есть единственный потомок своего предка — вер- шины <pv, то она должна быть насыщенной. Б. Если вершина v имеет к потомков, г < к < т, то существует самое большее одна ненасыщенная вершина среди этих потомков при к < г и не менее г насыщенных потомков при к > г + 1. Класс ди-арных деревьев называется плотным, если он представляет собой класс r-плотных дп-арных деревьев для некоторого г. Класс 1-плот- ных деревьев будет также называться классом слабо плотных деревьев, а класс (т- 1)-плотных ди-арных деревьев — классом сильно плотных деревьев. Заметим, что существует только один класс плотных бинарных деревьев и он совпадает с классом братских деревьев, или ЯВ-деревьев (см. п. 7.13.6). Существуют два класса плотных тернарных деревьев. На рис. 8.2 показаны два тернарных дерева; первое представляет собой пример сильно плотного, а второе — слабо плотного дерева. Оба имеют по 11 висячих вершин.
314 8.1.3. В-деревья: определение и организация поиска Рис. 8.2 8.1.3. В-деревья: определение и организация поиска. В-деревом по- рядка т называется /n-арное выровненное дерево, у которого: а) каждая вершина (страница) содержит не более т слов (ключей); б) каждая страница, кроме корневой, содержит не менее т/1 ключей; в) каждая страница представляет собой висячую вершину (лист) или имеет k + 1 потомков, где к — число ключей на этой странице; г) все вершины-листья располагаются на одном уровне; д) корень имеет не менее двух потомков. Каждая страница В-дерева содержит ключи и указатели на своих потомков, для листьев значениями указателей служат служебные слова NIL. Структуру вершины, содержащей /ключей и / + 1 указателей, мож- но представить в виде где < W2 <...< W-. а указатель р. указывает на поддерево, в котором хранятся слова, больше Wi и меньше И<+|. На рис. 8.3 представлены два В-дерева порядка пяти. Размещение ключей в вершине в возрастающем порядке слева напра- во представляет собой естественное развитие принципа двоичных де- ревьев и определяет метод поиска элементов с заданными ключами. Поиск в В-дереве организуется следующим образом. Вначале в опе- ративную память считывается корень дерева и в нем ищется требуемое слово Ж; если его там нет, то в оперативную память считывается вер- шина, на которую указывает указатель р- такой, что < W < Wi+l. Ис- пользуется указатель р0, если требуемое слово меньше W\, и указатель р; (считаем, что в вершине хранятся /слов) — если требуемое слово больше Wj, Если значение указателя на некотором шаге поиска становится рав- ным NIL, то поиск неудачен — слова W в дереве нет.
8.1.4. Включение нового слова в В-дерево 315 8.1.4. Включение нового слова в В-дерево. Включение нового слова W в В-дерево происходит в три этапа: Этап 1. Производится поиск слова W; если слово уже есть в дереве, то поиск заканчивается удачно и алгоритм заканчивается. В противном случае поиск заканчивается неудачей в листе L1. Этап 2. Новое слово включается в лист L1 с соблюдением лексико- графического порядка и добавлением еще одного указателя. Если общее число слов в вершине L1 после этого не превосходит т - 1 для дерева порядка т9 то процедура включения слова заканчивается. В противном случае требуется процедура восстановления структуры В-дерева. Этап 3. Если в вершине LA стало т слов, то ее расщепляют на две вершины:______________________________________________________ ( Pt)’' Wp-^[m/2]-pP[m/2]-l ) U ( Р[т/2]> W[>n/2j+l>'-’'Wm iPm ) . а слово помещают в вершину-предка <f>LA. Таким образом, указа- тель р в вершине <р1Л заменяется последовательностью р; р', что в свою очередь может привести к расщеплению и т.д., вплоть до необ- ходимости расщепления корня. Если нужно расщепить корень дерева, который не имеет предка, то просто создают новый корень и помещают в него единственное слово Ж(„1/2р Дерево в таком случае становится выше на единицу. Данная процедура включения слов сохраняет свойства В-дерева. Пример включения слова z в дерево, изображенное на рис. 8.3, а9 показан на рис. 8.4. На рис. 8.5 приведен пример последовательного построения В-дерева, изображенного на рис. 8.3, б; включаемые ключи идут в таком порядке:
316 8.1.4. Включение нового слова в 5-дерево 20; 40 10 30 15; 35 7 26 18 22; 5; 42 13 46 27 8 32 38 24 45 25; Здесь точкой с запятой отмечаются моменты появления новых стра- ниц. Включение последнего ключа приводит к двум разделениям и появ- лению трех новых страниц. Рис. 8.4 Рис. 8.5
8.1.5. Удаление слов из 5-дерева 317 8.1.5. Удаление слов из В-дерева. Исключение слова из В-дерева — процесс довольно прямолинейный, хотя и усложненный в деталях. Здесь можно выделить два случая: а) исключаемое слово находится в листе, б) исключаемое слово находится во внутренней вершине. В случае а) предпринимаем следующие шаги. 1. Удалить слово из вершины вместе со следующим за ним указате- лем. Если количество слов в странице остается в пределах допустимого, то алгоритм заканчивается. В противном случае требуется исправление структуры дерева. 2. Если в вершине остается меньше положенного слов, то слить ее со своим братом по правилу: Wk-1 -’Pk W Если при слиянии вершин ограничение на количество слов не нару- шается, то алгоритм заканчивается. В противном случае выполняется разделение этой страницы по правилу, описанному в предыдущем пункте. В случае б) предпринимаем следующие шаги. 1. Удалить слово из вершины (пусть это будет W) вместе с указате- лями р и р', слив одновременно вершины, адресуемые указателями р и р', по правилу: W; р; W;p';lV W; р; W 2. Слить вершины LA и £2, адресуемые указателями рк и рк+1, ока- завшиеся после слияния расположенными рядом, и заменить указатели рЛ. и рк+1 одним указателем на слитые вершины LA и £2. Продолжить процесс слияния вершин, пока не будут слиты висячие вершины.
318 8.1.5. Удаление слов из В-дерева 3. Для каждой слитой вершины, начиная с висячей, проверить выпол- нение ограничения на максимальное число содержащихся в ней слов. В случае нарушения ограничения применить операцию разделения вер- шин по правилу, применяемому при включении слов. Пример удаления слова U из дерева, показанного на рис. 8.3, а, при- веден на рис. 8 6. На рис. 8.7 показан процесс “деградации” дерева, пред- ставленного на рис. 8.3, б, при следующем порядке удаления ключей (точки с запятой по-прежнему означают моменты перестройки дерева): 25; 45, 24, 38, 32; 8, 27, 46, 13, 42, 5; 22; 18, 26, 7, 35, 15. Примечание. Предложенный алгоритм исключения слова не является единственно возможным; структура В-дерева позволяет варь- ировать стратегию при удалении слова. Например, можно рассмотреть подход, при котором при удалении слова из внутренней вершины оно заменяется наименьшим словом из поддерева, на которое указывает ука- затель, соответствующий удаляемому слову. Рис. 8.6 Недостатком В-дерсвьев является слабая заполняемость их вершин словами. Увеличить заполняемость можно с помощью перехода к деревь- ям, у которых каждая вершина, отличная от корня, имеет не менее [ (2дм - 1) /3 ] потомков, а корень — не менее двух и не более т потомков (так называемые В*-деревья).
8.1.5. Удаление слов из 5-дерева 319 41 10 20 30 40 Рис. 8.7
320 8.1.6. Организация поиска слов внутри вершин В-дерева Другой подход к увеличению заполняемости вершин основан на ис- пользовании в качестве базы при построений В-деревьев плотных /п-ар- ных деревьев. Способ хранения информации в таком дереве аналогичен способу хранения ее в обычном В-дереве. Каждое r-плотное ди-арное дерево над множеством из п слов есть дерево высоты А, где h < logw(n + 1). Недостатком таких деревьев является более сложная процедура восста- новления структуры дерева при включении и удалении слов. 8.1.6. Организация поиска слов внутри вершин В-дерева. Так как порядок В-дерева и тем самым количество слов, хранимых в одной вер- шине, не ограничивается сверху, можно представить себе ситуацию, ког- да количество слов в одной вершине будет составлять несколько сотен. В таких случаях нужна организация эффективного поиска слов внутри вершин. Для этого массив слов в вершине можно организовать в виде списков, списков с двойными связями или в виде балансированного дере- ва. Соответствующие В-деревья будем называть B-S-, В-L- или В-Т-де- ревьями. Последний тип допускает обобщение на случай, когда структу- ра данных в виде В-дерева используется одновременно несколькими пользователями. Как уже говорилось выше, когда вершина в В-дереве порядка т пере- полняется (в ней оказывается т слъь), она распадается на две, каждая из которых имеет не менее [ди/2] - 1 слов. В B-S-дереве с последователь- ным расположением слов в вершине разбиение может быть произведено с трудоемкостью О(т) обычными способами. Когда же вершина орга- низована как балансированное дерево, процесс разделения вершины уже не так прост (если она не представлена 2-3-деревьями, см. пп. 7.1.8, 7.1.11), как бы этого хотелось, хотя и имеет ту же трудоемкость. Это приводит к необходимости обобщить понятие В-дерева, ослабив требо- вание относительно минимального числа слов в вершине и добившись этим облегчения разделения вершины на две. Этой цели служит вво- димое в следующем разделе понятие /(ди)-дерева. 8.1.7. /(ди)-дерево. Пусть f:N + N — функция, заданная на множе- стве натуральных чисел, такая, что для всех т > 3 справедливо неравен- ство 2 < f(m) < [т/2]. f(m)-деревом называется страничное дерево, обладающее следующи- ми свойствами: 1) каждая вершина имеет не более т потомков; 2) каждая вершина, исключая корень и висячие вершины, имеет по крайней мере потомков; 3) корень имеет не менее дьух потомков; 4) все висячие вершины располагаются на одном уровне; 5) каждая вершина с j словами имеет следующий вид: __________1___________ ( Рп; р,; W2 р,.,; W,; Pj J V-J \ v где pi — указатель на вершину-потомка (для висячей вершины pi = NIL).
8.1.7. /Он)-дерево 321 Как видно из этого определения, в отличие от В-дерева в/(т)-дереве минимальное число потомков у вершины может изменяться от 2 до в зависимости от функции /(ди). Если функция f такова, что f(m) = Гш/2"|, то получаем обычное В-дерево порядка т. Для монотонно возрастающей функции f класс /(/и)-деревьев ведет себя очень хорошо: минимальное число слов в вершине растет вместе с ростом параметра т. Поиск, включение и удаление слов в /(ди)-деревьях практически не отличаются от аналогичных алгоритмов для В-деревьев. Если при вклю- чении слова вершина становится насыщенной, т.е. содержащей т слов, то она, как и в случае В-деревьев, распадается на две вершины с одним отличием: разбивается на вершину с $ - 1 и вершину с т ~ s словами, где s G \f(m) : [ди/2]]. Процесс удаления слова не отличается от соответствующего процесса для В-деревьев, исключая те шаги, где встречается нижняя граница чис- ла слов. Изменения тривиальны. S-деревом (L-деревом) порядка т называется /(ди)-дерево, в котором все вершинные массивы слов организованы как последовательный спи- сок (список с двойными связями). В 5-деревьях операция ИСКАТЬ может быть осуществлена за время О (log ди), в то время как операции ВКЛЮЧИТЬ и УДАЛИТЬ требуют О(т) времени. Для L-деревьев операции ВКЛЮЧИТЬ и УДАЛИТЬ тре- буют 0(1) времени, тогда как операция ИСКАТЬ — О(т) времени. В любом случае внутривершинные операции требуют О(т) времени, так как прежде чем включить или удалить слово, мы применяем операцию ИСКАТЬ. Операции СЛИТЬ и РАСЩЕПИТЬ не содержат ничего, кро- ме простой пересылки слов из одной вершины в другую, и поэтому требу- ют О(т) времени и для 5- и для L-деревьев. Трудоемкость О(т) для внутривершинных операций является серь- езным недостатком для 5- и L-деревьев. Это приводит к мысли использо- вать для внутренней организации массива слов в вершинах деревьев (АВЛ-деревья (п. 7.1.4), 2-3-деревья (п. 7.1.8) и др.), что приводит к понятию Т-дерева. Т-деревом порядка т называется/(ди)-дерево, в котором все вершины представляют собой балансированные деревья частного типа (таким об- разом, различают 7\вл-деревья, Т2.3-деревья и т.д.). Очевидно, что поиск, включение и удаление слов в Т-дереве те же самые, что и для /(ди)-деревьев, за исключением того, что мы должны точно объяснить, как работают элементарные операции ИСКАТЬ, ВКЛЮЧИТЬ, УДАЛИТЬ, РАСЩЕПИТЬ и СЛИТЬ. Для операций ИСКАТЬ, ВКЛЮЧИТЬ и УДАЛИТЬ могут быть ис- пользованы стандартные алгоритмы для выбранного типа балансирован- ных деревьев. Они требуют в худшем случае O(logm) времени. При вы- полнении операции СЛИТЬ вначале пересылаем слова из вершины в ее брата, смежного с ней, что требует О(т) времени, а потом производим слияние двух балансированных деревьев и включение разделительного слова из вершины, являющейся предком обеих вершин, за время O(logm). Все это дает оценку О(т).
322 8.2.1. Слабые /?-депевья РАСЩЕПИТЬ — самая трудная из этих элементарных операций. Одним из способов выполнения этой операции является следующий: 1) . Выделить разделяющее слово (медиану в случае В-Т-дерева). Это можно сделать за время О(т). 2) . Расщепить балансированное дерево на два балансированных дере- ва слева и справа от И'. Это требует O(logm) времени. 3) . Скопировать одно поддерево в новую вершину за время О(лл). И хотя с помощью более совершенной техники нахождение разделя- ющего слова можно довести до операции с трудоемкостью O(logw), пол- ная трудоемкость операции РАСЩЕПИТЬ остается равной О(т). Основываясь на анализе элементарных операций, можно заключить, что Т-деревья лучше подходят для организации больших массивов информации, нежели 5-, L- и, в частности, В-деревья. 8.2. Обобщения В-деревьев 8.2.1. Слабые В-деревья. Пустьр(у) обозначает число потомков вер- шины v. Пусть, далее, а и b — целые числа, удовлетворяющие неравенст- вам а > 2 и 2а - 1 < Ь. Дерево Г называется (а,Ь) -деревом, если: а) все висячие вершины находятся на одном и том же уровне; б) для всех вершин vp(v) < b; в) для всех вершин у, кроме корня, р (у) > а; г) для корня г справедливор (г) > 2. Для b = 2a- 1 класс (а,Ь) -деревьев совпадает с классом В-деревьев порядка а. Для b > 2а (а,Ь)-деревья называются слабыми В-деревьями. Величина [Ь/2 ] - 2 для (а,Ь) -дерева называется гистерезисом. В приме- рах ниже рассматриваются (2,4)-деревья; они известны в литературе как ’’симметричные бинарные В-деревья” и как ”2-3-4-деревья". Глубина (а,Ь) -дерева логарифмически зависит от числа висячих вер- шин. Это следует из соотношения 2 • d"' < п < где h — глубина (а, Ь) -дерева, ал — число висячих вершин в Т (л > 2). Операции включения и удаления слов для (а,Ь) -дерева совершенно аналогичны соответствующим операциям для В-деревьев. Разница со- стоит лишь в операциях восстановления структуры дерева, так как в отличие от В-деревьев информация в (а,Ь)-деревьях хранится в висячих вершинах, а во внутренних хранится только вспомогательная инфор- мация, подобно 2-3-деревьям (см. п. 7.1.8). На рис. 8.8 показано (2,4)- дерево слов {2,4,7,10,11,15,17,21}. Операция включения новой висячей вершины требует s + 1 расширений и s расщеплений вершин для некото- рого 5 > 0. Это дает время исполнения операции 0(1 + s) (см. рис. 8.8, б). Удаление висячей вершины требует 5 + 1 сокращений и 5 слияний вершин для некоторого s > 0 и, возможно, одной операции перераспре- деления потомков. Это дает время исполнения 0(1 + s). На рис. 8.9 пока- зано удаление висячей вершины из (2,4)-дерева.
8.2.1. Слабые 5-деревья 323 Рис. 8.9
324 8.2.1. Слабые В-деревья Оценим полную стоимость последовательности включений и удале- ний слов в (а,Ь) -дереве в предположении, что мы начинаем с пустого дерева. Пусть b > 2а. Рассмотрим произвольную последовательность включений и удалений в первоначально пустое дерево. Пусть SP есть полное число расщепляемых вершин, F— полное число слияний вершин и SH — полное число операций перераспределения потомков. Тогда: a) SH < п, б) SP+7 < n+(l+ |_(n-2)/(a-l)j). Следовательно, полная последовательность включений и удалений имеет стоимость О(п). Приведем набросок доказательства этого утверждения. Пусть для вершины у, отличной от корня (а,Ъ)-дерева, баланс/Г(у) определяется следующим образом: -1, о, 1, /3-(р)= если р (у)=а — 1 илир(у) = b + 1; еслир(у)=аилир(у) = 5; если а+1 < р(у) < b + 1. Для корня г баланс/Г (г) определяется аналогично: -1, о, 1, ^(0= еслир(г) = 1 илир(г) = b + 1; еслир(г)=2 илир(г) = Ь\ если 3 < р(г) < b - 1. Дерево (7,у) есть частично балансированное (а,Ь)-дерево относитель- но вершины v, если: а) а - 1 < p(v) <5+1; б) а< p(w) < b для всех w # г, у; в) 2 < r(w) < 5, если у # г. Пусть (7,у) — частично балансированное (а,5)-дерево. Тогда баланс /Г (7) дерева Т определяется как сумма балансов его вершин, т.е. Р\Т)= 1 p\V)+p\r). v£r Справедливы следующие утверждения, из которых вытекает оценка сто- имости полной последовательности включений и удалений. Пусть Т — (а,5)-дерево, и пусть 7' получается из 7 добавлением или удалением висячей вершины. Тогда/Г(7') > /Г(7) - 1. Пусть (7, у) — частично балансированное относительно вершины v (а,5)-дерево сp(v) = 5 + 1. Расщепление у и расширение вершины х — предка вершины v — порождает дерево 7' с/Г(7') > /Г(7) + 1. Пусть (7,у) — частично балансированное (а,5)-дерево ср (у) = а - 1 и у # г. Пусть, далее, у — брат у и х — предок у. Тогда: а) если р(у) = а и Т — дерево, получаемое слиянием у и у и сокра- щением х, то/Г (7') >/Г(7); б) если р(у) > а и 7'— дерево, получаемое перераспределением по- томков, а именно переброской р(у) - а потомков от у к у, то /Г (7') > >£*(7). Пусть 7 — (а,Ь) -дерево с менее чем п висячими вершинами. Тогда
8.2.1. Слабые Я-деревья 325 О </Т(Г) < (1 + [(и- D/U- DJ). Рассмотрим теперь построение слабого В-дерева, начиная с произ- вольного начального дерева. Пусть Т — произвольное (а,Ь)-дерево. Предположим, что мы произ- водим последовательность включений и исключений вершин. Интуи- тивно ясно, что при таких действиях затронутыми оказываются только те вершины, которые' лежат на пути из корня в то место, где надлежит подключить новую вершину, или на пути из корня в удаляемую вер- шину. Можно оценить число таких вершин. Очевидно, что изменяется баланс только этих вершин, и, следовательно, их число определяет раз- ницу между балансами начального и конечного деревьев. Для того чтобы облегчить обсуждение данного вопроса, введем следу- ющее условие: если из (а,й)-дерева удаляется лист, то он остается как фантом (призрак) (см. рис. 8.10). При описании алгоритмов восстанов- ления балансов фантомы не учитываются. Пусть b > 2а и пусть Т — некоторое (а,Ь)-дерево с п листьями. Пред- положим, что последовательность s включений и t удалений приводит к дереву Т. Тогда Т имеет п + s листьев, t из которых являются фанто- мами. Пусть р,, ..., ps + , — позиции s + t новых листьев и фантомов в Г', р, > р2 > ... >pj + r Пусть, далее, SH — полное число перераспределений потомков, SP — полное число разделений вершин, F — полное число слияний вершин в реализации этой последовательности. Тогда: a) SH < t, s +1 6)SP + F< 2(riog(n + s)l +2n°g(P/-ft-i+1)~| + (s + 0).
326 8.2.2. Применения слабых Я-деревьев Доказательство этого утверждения существенно опирается на пред- положение 2а < Ь. Для обычных В-деревьев (Ь = 2а - 1) это утверждение неверно. 8.2.2. Применения слабых В-деревьев. 1. Представление списков с указателями. Пусть L — линейный список с п эле- ментами, упорядоченными в порядке возрастания, и пусть Т — (а.Ь)-де- рево с п листьями. Говорят, что Т представляет L, если: а) элементы из L хранятся в п листьях дерева Т в порядке возрастания слева направо; б) в каждой внутренней вершине vдерева Т хранитсяр(у) - 1 ключей; f-й ключ в v есть наибольший ключ в i-м поддереве вершины у. Пример такого дерева дан на рис. 8.8. Указатели в списке L могут быть использованы для обозначения обла- стей наибольшей активности в L. (а,Ь) -деревья, как они определены вы- ше, нс обеспечивают эффективного поиска вблизи указателей. Это приводит к тому, что соседние элементы оказываются связанными очень длинными путями. Поэтому имеет смысл ввести связанные по уровням (я,Z0-деревья. В связанном по уровням ш,Ь)-дереве, или, короче, связанном (я,5)- дереве, все древесные дуги делаются проходимыми в обоих направле- ниях (т.е. ребрами, в терминологии теории графов), и, кроме того, каж- дая вершина связывается ребрами с соседями по уровню. Пример связан- ного по уровням (2,4)-дерева для списка (2,4,7,10,11,15,17,21,22,24) дан на рис. 8.11. Указатель в связанном («,5)-дереве направлен на лист. Связанное (л,Ь) -дерево допускает очень быстрый поиск в окрестности указателя. Относительно трудоемкости операций имеют место следующие утверж- дения. Рис. 8. н
8.2.3. Сильные ^-деревья 327 Пусть р — указатель в (а,Ь) -дереве Т. Поиск ключа К, занимающего d-ю позицию от р, требует 0(1 + logc/) времени. Включение нового листа в данную позицию в связанном (а,Ь) -дереве требует 0(1 + s) времени, где s есть число проведенных разбиений вер- шин. Удаление листа из связанного (л,5)-дерева требует 0(1 + /) времени, где /— число произведенных слияний вершин. 2. Операция объединения множеств. Связанные (л,й)-деревья эффективны для реализации следующей операции объе- динения множеств: для упорядоченных множеств А и В организовать множество С s A U В — {некоторые элементы из А А В}. 8.2.3. Сильные В-деревья. (u,v)-деревом для 2 < u < [v/2] называет- ся m-арное дерево, в котором: а) все листья находятся на одном уровне; б) каждая внутренняя вершина, отличная от корня, имеет т потом- ков, где и < т < v; в) корень имеет т' потомков, где min(2, ITI) < т' < у (здесь ITI есть число листьев в Г). Величина r = у + 1 -2и называется устойчивостью, а величина p=([”v/2l - и) —гистерезисом (и,у)-дерева. Сильным В-деревом называется (и,у)-дерево с у > 2и. Из этого определения непосредственно вытекает, что высота Л(и,у)- дерева Т есть Odogl Т\), так как для h > IT имеет не меньше 2нЛ | и не больше у,’ вершин. Алгоритмы для работы с сильными В-деревьями практически те же, что и для работы с обычными В-деревьями, но для них существует боль- ше вариантов проведения преобразований, восстанавливающих баланс. Алгоритмы для (и,у)-деревьев характеризуются четырьмя парамет- рами. Порог слияния Z, 0 < t < у - 2u + 1, определяет, должно ли про- водиться слияние вершин или их разделение при недогрузке. Ситуация недогрузки выбирает, какого из братьев вершины следует использовать при возникновении недогрузки. Стратегия расщепления вершины опре- деляет способ разделения потомков между результирующими верши- нами. Стратегия включения возможна в двух вариантах: стратегия Zs для s > 1 предусматривает передачу $ потомков недогруженной вершине, а стратегия Zo — как можно более равномерное распределение потомков между результирующими вершинами. Пусть Alg(r) обозначает класс всех алгоритмов для данного множест- ва (и,у)-деревьев с порогом слияния /. Alg(f, Z-), i > 0, есть класс ал- горитмов с использованием стратегии Z-. Alg(Z, $mjn) есть класс алгорит- мов с порогом слияния t и гистерезисом перемещения $min. Значение smin определяется для любой стратегии включения в (и,у)-деревья, как мини- мум, по зсем операциям включения величины min(x, у) - и + 1, где х и у — два множества потомков, созданных при включении. Такий образом, ^min min(s, t + 2 - s) для стратегии Z, 1 + [ t/2 J для стратегии Zo.
328 8.2.4. Сильные В*-деревья Пусть В (к) = B(£,T,S) есть полное число восстанавливающих баланс операций, которые необходимы при первых к операциях обновления данных в дереве (включение новых или удаление старых) в последова- тельности из S таких операций для начального дерева Т. Имеют место следующие утверждения. Пусть р = |~v/2"] - и > 1 есть гистерезис (н,у)-дерева. Тогда В(к) > > к/p + О(1Т1) для любого алгоритма (и,г)-дерева из множества ал- горитмов AlgG, smin) с начальным деревом Tcv>2u+l,f> [Зр/2] - 1 и S.nin Гр/2]. Для любого алгоритма из множества алгоритмов Alg(O) для (m,v)-де- рева с v > 2и имеет место неравенство В(к) > ЗЛ/2 + О(1Т1). Пусть v 2и - 1, р = Гр/2"| - и и t < ГЗр/2"| - 1 или smin < [р/2"|. Пусть, далее, w = min(2(Z + 1)/3, 2smin). Тогда для алгоритмов из Alg(r, smin) для (м, v)-дерева имеет место оценка В(Ю < K/w + O(\T\). Для взвешенных операций по восстановлению баланса В (К) опреде- ляется как сумма стоимостей операций. Пусть расщепление, слияние и перераспределение потомков имеют стоимости Ср с2 и с3 соответственно. Рассмотрим класс (и, у)-деревьев с гистерезисом р < \у/и ] и алгоритм из AlgG, s,nin). Пусть с' = (ct + с2)/2, d = 1 + с3/2с' и w = min((/ + 1)/J, 2c's,nin/c3). Тогда: а) В(к) < с'kip + 0(1 Т\), если t > [dp"] - 1 и^.п > [c^^c'Y б) В(к) < c’k/w + О(1Т1), если/< [cip\ - 1 или t = р и v четно. Для уменьшения блокирования при мультипроцессорной обработке, а также при использовании деревьев в многомерных применениях, где стоимость операций восстановления баланса растет экспоненциально с высотой дерева, важно знать распределение таких операций по уровням дерева. Следующее утверждение показывает, что количество их в (u,v)- дереве убывает экспоненциально с высотой дерева. Пусть В>'<к) — число операций восстановления баланса, которые дол- жны быть проведены на уровне h при к обновлениях, примененных к пустому начальному дереву. Для класса (u, у)-деревьев с устойчивостью г=у-2й+1и гистерезисом р = [г /2 ] и алгоритмов из Alg (/, s,nin) имеем: а) в!'(к) < к/(р + 1)А, если t > I Зр/21 и sinin > 1+[р/2 ]; б) В!1(к) < Л(^);,_| в (2,4)-деревьях с t = 0; в) Bf'kk) < к/(г+ 1)А-1, если t = 0 и и > [(у + 3)/4 ]. 8.2.4. Сильные В*-деревья . Пусть BSTAR — стандартный алгоритм построения В*-дерева (см. [3 ]), который работает со структурой данных в виде (м,у)-дерева, где и = = 2/ + 1 и v = 3/ + 1. Тогда справедливо следующее: при применении алгоритма BSTAR к начальному (и, у)-дереву Т име- ют место оценки: а) В (к) > О(к log( I 74)— в худшем случае, если 3(и- 1) = 2(у - 1);
8.3.1. Определение многомерного 5-дерева 329 б) В (к) < 2Л + 0(1 ТО, если 3(zz - 1) <2(v- 1). 8.3. Многомерные В-деревья 8.3.1. Определение многомерного В-дерева. Пусть D есть база дан- ных, в которой все записи снабжены п различными атрибутами. Каждая запись в D может рассматриваться как упорядоченный набор (К19 К2,... ..МХ„) значений, которые соответствуют атрибутам Лр Л2, ..., Лл. Пусть Vp 1, 2, ..., м, есть число различных значений атрибута Л;. (ранг ат- рибута Лу). Организация базы данных предусматривает, кроме О, еще справоч- ник, содержащий значения, которые должны быть присвоены атрибутам, и их ассоциативные указатели. Будем предполагать, что и D, и спра- вочник находятся на внешних запоминающих устройствах и что стра- ница есть единица пересылаемой информации между внешней и опе- ративной памятью. Числа доступа суть указатели в справочнике, кото- рые фиксируют размещение записей в соответствующих страницах данных. Каждый из п атрибутов Л;, который должен*быть индексирован, пред- ставляется в нашем дереве-справочнике отдельным уровнем (см. п. 7.2.1). Однако каждая вершина в нашем дереве сама изображает слож- ную структуру, а именно В-дерево. Основная структура многомерного В-дерева, или, короче, MDBT, представлена на рис. 8.12, где вершины, изображаемые треугольниками, суть В-деревья, необязательно одного и того же порядка и размера. Более формально, значения атрибута (клю- ча) Д организованы в виде В-дерева порядка где каждая вершина содержит (m, - 1) значений атрибута и (2mf - 1) указателей. Структура вершины в В-дереве для Д имеет вид F ft ^2' ' ^2 Pnirl> ^тг1^ Здесь Kj — /-е значение атрибута Д; Р; указывает на вершину на следующем уровне того же самого В-дерева, содержащую значения ат- рибута Л, в интервале между Kj и Ку + |; Д. указывает на В-дерево на уровне (z + 1), которое содержит множество значений атрибута Л| + 1, встречающегося вместе с А- в базе данных D. Множество значений атрибута Л/ + р которые имеют одного и того же предка на уровне z, называется сыновьим множеством (на уровне z + 1), а соответственно Д, j » 1,2, ..., - 1, называются указателями сыновьих множеств (на уровне z). Часть конструкции MDBT, показанной на рис. 8.12 (заключенная в прямоугольник), детализируется на рис. 8.13 для иллю- страции использования типов Р и F. F-указатели изображаются сплош- ными линиями, в то время как Р-указатели — штриховыми. ХК^, ХК{,..., ХК4 суть некоторые значения в В-дереве X, a FXKQ, FXK{>..., FXK4 — соот- ветствующие сыновьи множества. Заметим, что на n-м уровне F-указатели могли бы прямо указывать на записи в базе данных D, если существует однозначное соответствие записей комбинации значений атрибутов или если база данных разбита на кластеры. Однако, так как кластеризация не существенна для нашего И В А. Евстигнеев, B.H. Касьянов
330 8.3.1. Определение многомерного Я-дерева случая, предполагаем, что все F-указатели на n-м уровне представляют адреса страниц доступа, т.е. страниц, содержащих указатели, не соответ- ствующие записи данных. Более того, будем предполагать, что все числа доступа для данной комбинации значений атрибутов помещены в одну страницу. Уровень / Атрибут А Уровень 2 О----- Атрибут А Страницы Рис. 8.12 Уровень 3 О------- Атрибут А3 FXK FXK2 FXKt Для того чтобы позволить прямой доступ к любому уровню i дерева MDBT, все сыновьи множества на уровне i связаны вместе, а указатель LEVEL(f) обеспечивает начало просмотра каждого такого связанного списка. Корневая вершина каждого В-дерева включает дополнительный указатель NEXT, который обеспечивает связь с корнем следующего в списке В-дерева. В дополнение к указателю NEXT корневая вершина каждого В-дерева содержит два других указателя: LEFT и RIGHT. Для данного В-дерева X указатели LEFT и RIGHT идентифицируют соответ- ственно самое левое и самое правое сыновьи множества на уровне i: + 1 с предками, расположенными в X. Эти указатели изображены на рис. 8.12 и 8.13. Как увидим далее, они могут быть использованы для ликвидации необязательного поиска при ответе на частичные и ранговые запросы (см. п. 7.2.3), если упорядочение, обрисованное в общих чертах ниже,
8.3.1. Определение многомерного Я-депевя 331 Пусть L — связный список, чье начало задается указателем В, и пусть хну — два элемента из списка L. Будем говорить, что х предшествует у, если элемент х встречается прежде элемента у при последовательном просмотре списка L от входной точки В. Пусть X и У — два В-дерева на уровне /, как показано на рис. 8.12. Обозначим через {ХК0, XKV ..., XKt} и {УК0, YKn ..., YKp} подмножества значений атрибута Д, содержащихся в X и У соответственно. Кроме того, FXKi и FYK- обозначают сыновьи множества на уровне i: + 1, ассоциирован- ные со значениями ХК; и УК. для i" 0,1, ..., /и/ - 0,1,..., р. Упорядочение, определенное на MDBT, удовлетворяет следующим условиям: а) если Х^ меньше, чем XKj для i # / и i, j G {0,1, ..., Z}, T0 FXKi предшествует FXK- в связанном списке с указателем LEVELS + 1); б) если FXKi предшествует Z и Z предшествует FXK-, iy j G {0,1,...,/}, то Z = FXKq для некоторого t G {0,1, ..., Z}. Другими словами, сыновьи множества, обозначаемые как FXKt для i G {0,1, ..., /}, последовательно связаны. (Заметим, что свойства а) и б) справедливые также для YKt и FYKt, i G {0,1, ..., р}.); в) для i G {0,1, ..., Z} и для j G {0,1, ..., р} РХК^ предшествует FYK^ в связанном списке с указателем LEVELS +1) тогда и только тогда, когда X предшествует У в списке с указателем LEVEL(f).
8.3.2. Стратегии поиска п дереве MDBT Предположим, что множество значений {А7С0, ХКх, ...» ХК} в В-дере- ве X упорядочивается следующим образом: ХК^ХКр если i< j для {0,1, ..., /}, т.е. ХК0 и ХК, являются соответственно наименьшим и наибольшим значениями в множестве. Тогда в соответствии с упорядо- чением, определенным выше, сыновьи множества, обозначаемые FXKi для i е {0,1,..., /}, последовательно связаны в список с указателем LEVELG + 1) и, кроме того, FXK^ — самый левый среди сыновьих мно- жеств, a FXKl — самый правый среди сыновьих множеств дерева X (см. рис. 8.13). (Заметим, что страницы доступа могут интерпретироваться как сыновьи множества, расположенные на уровне п + 1. Следовательно, определения связывания и упорядочения, обсуждавшиеся выше, при- менимы также к спискам доступа.) 8.3*2. Стратегии поиска в дереве MDBT. Здесь рассматриваются следующие типы запросов: а) на точный поиск — специфицирует значение каждого индексиро- ванного атрибута; б) с частичным соответствием — специфицирует значения для <1 < п индексированных атрибутов; в) объемный — в нем специфицируется для каждого индексированно- го атрибута интервал : ц ] значений. Для дерева MDBT, у которого размеры всех комбинаций сыновьих множеств предполагаются равновероятными, временные трудоемкости обработки указанных выше запросов имеют следующие значения: — точный поиск — трудоемкость в худшем случае O(logjV); — частичное соответствие — трудоемкость в худшем случае O(Mogtf7AT); — объемный запрос (с ц. - “ 2 для всех /) — трудоемкость в среднем OdogAO. Здесь, обозначив через S, средний размер сыновьего множества на уровне /, имеем N = П S. *«i и 7V’ = П S. Для запроса на точный поиск, очевидно, достаточно иметь доступ только к одному В-дереву на каждом уровне для того, чтобы найти един- ственную страницу доступа, соответствующую данной комбинации зна- чений. В-дерево, к которому должен быть обеспечен доступ на уровне г, определяется F-указателем, сопоставленным значению в В-дереве, в ко- торое был осуществлен доступ на уровне (г - 1) в соответствии с запро- сом. Дерево MDBT имеет особенности, обеспечивающие эффективную стратегию поиска при обработке запроса с частичным соответствием. Во-первых, заметим, что может быть обеспечен прямой доступ на любой
8.3.3. Включение новой записи 333 уровень i благодаря тому, что сыновьи множества на одном и том же уровне связаны вместе в список с указателем LEVEL(O. Во-вторых, пол- ный перебор на уровне, соответствующем неспецифицированному ат- рибуту, устраняется благодаря упорядочению, реализованному на сы- новьих множествах, и специальным указателям, предусмотренным для корня каждого дерева. Например, предположим, что атрибуты Ai и (z < j) были специфицированы запросом с частичным соответствием, в то время как атрибуты, соответствующие уровням i + 1, i: + 2, ..., j - 1, оста- вались неспецифицированными. Тогда В-деревья, в которых должен осу- ществляться поиск на уровне j для каждого значения X, удовлетворяю- щего запросу на уровне i, определяется следующим образом. В-указа- тель, ассоциированный с X, указывает на В-дерево уровня i + 1, содержа- щее множество значений, которые квалифицированы в соответствии с запросом, так как атрибут не специфицирован. Однако в нашей стра- тегии поиска достаточно иметь доступ только к корню В-дерева, чтобы восстановить указатели LEFT и RIGHT, которые определяют границы отрезка списка на уровне i + 2, могущего удовлетворить запрос. Более того, если j не равно i + 2, то этот весь подсписок квалифицируется как соответствующий запрос; и должен быть обеспечен только доступ к кор- ням самого левого В-дерева и самого правого В-дерева в этом подсписке, чтобы восстановить два указателя, которые определяют границы отрезка связанного списка сыновьих множеств на уровне i + 3, который релеван- тен нашему поиску. Этот процесс продолжается аналогичным образом, пока не будет достигнут уровень /. Объемный запрос — это запрос, в котором для каждого атрибута спе- цифицируется отрезок [Д: f/J. Упорядочение, установленное для сы- новьих множеств на данном уровне, делает достаточным осуществление поиска только для двух значений в сыновьем множестве (В-дереве) на уровне i: которое равно Lt (или это есть ближайшее значение, большее L), и ц, которое равно Ц (или это есть ближайшее значение, меньшее Ц). Снова F-указатели, ассоциированные с /• и будут определять гра- ницы подсписка В-деревьев на уровне i + 1, релевантных нашему проце- ссу поиска. Таким образом, упорядочение, определенное на сыновьих множествах на каждом уровне, есть важная особенность MDBT. Ниже будет показано, как реализуется это упорядочение при наличии дина- мических изменений. 8.3.3. Включение новой записи. Пусть а,, а3, ..., ап — значения, спе- цифицированные для атрибутов Лр Л2, ..., Ап соответственно, в записи, предназначенной для включения в базу данных. Если комбинация я,, а2, •••’ ап Уже существует в справочнике, никаких изменений в него вно- сить не нужно, исключая добавление указателя доступа. С другой сторо- ны, предположим, что комбинация а19 а2, ..., ai4 существует в справоч- нике (2 < i < м), а аг а2, ..., ам, — нет. Другими словами, а,- не со- держится в сыновьем множестве для ahl. Если Вр В2,..., Fhl обозначают сыновьи множества для av а2, ..., ahl соответственно, то д. должно быть включено в В}.,. (Заметим, что В, будет также использоваться для обозна- чения адреса корня соответствующего В-дерева.)
8.3.3. Включение новой ззписи Рис. 8.14 После включения а, в Fhl, как показано на рис. 8.14, сыновье множе- ство для ai9 обозначаемое содержит единственное значение а1+1 и дол- жно быть включено как одностраничное В-дерево в подходящее место внутри связного списка сыновьих множеств на уровне i + 1. Таким обра- зом, вопрос состоит в том, как локализовать сыновье множество F*, кото- рое должно предшествовать Fi на уровне i + 1. Предположим сейчас, что at не есть наименьшее значение в F^ этот случай мы рассмотрим позже. Тогда из имеющего место в дереве MDBT упорядочения вытекает, что В* есть сыновье множество, ассоциированное с наибольшим значением в
8.3.3. Включение новой записи 335 ГЬ1, младшим по отношению к а» скажем а*. Следовательно, в процессе включения at нам требуется осуществить также поиск и а*. Заметим, однако, что этот поиск не требует никаких дополнительных доступов, так как а* располагается на пути, ведущем в то место, где должно быть включено at. На уровне i + 2 сыновье множество для а.+1, обозначаемое ^.+1, будет образовывать другое одностраничное В-дерево. Указатель на сыновье мно- жество на уровне i + 2, которое должно предшествовать Fi+i, размещается в корне F* (см. рис. 8.14). Этот процесс повторяется до уровня п +1. Если а. становится наибольшим значением в сыновьем множестве Fhl, нужен дополнительный шаг. В этом случае Fi — сыновье множество для я- — становится последним в связном списке сыновьих множеств на уров- не i + 1, которые ассоциированы с Fhl. Это влечет за собой изменение указателя RIGHT в корне Fhl, и в результате — включает в себя один дополнительный доступ. На последующих уровнях никакие изменения не нужны. Прежде чем обсудить случай, когда а- становится наименьшим зна- чением в Fhi, введем одно определение. Для данного ключа в В-дереве X назовем ближайшим левым сосе- дом, — наибольший ключ, меньший чем в X, если он существует; будем обозначать его через а*. Заметим, кроме того, что если Р обозначает корень В-дерева в нашей структуре, то LEFT(P) и RIGHT (Р) суть функции, которые порождают соответственно указатели LEFT и RIGHT. Рассмотрим теперь случай, когда а. становится наименьшим значе- нием в Р._р что иллюстрируется рис. 8.15. Для того чтобы включить В-дерево Fi с единственной страницей на подходящее место на уровне i: + 1, необходимо иметь доступ к корню В-дерева F. Очевидно, что нет пути, чтобы достигнуть F из Р-_г Но, как представлено на рис. 8.15, если aiA имеет ближайшего левого соседа и указатель сыновьего множества F*_p соответствующий а*_1? сохраняется во время поиска сверху вниз по струк- туре дерева MDBT, то корень дерева F достижим с одним дополнитель- ным доступом. В самом деле, в этом случае F может быть получен приме- нением функции RIGHT к корню Предположим, что ни один из ближайших левых соседей а* не сущест- вует на уровнях /, к< j < i. Другими словами, Uj для к <j < i есть на- именьшее значение в соответствующем В-дереве, а ак есть последнее значение на нашем пути поиска, имеющее ближайшего левого соседа ак. Эта ситуация иллюстрируется на рис. 8.16. Тогда из тех же самых сооб- ражений ясно, что если указатель сыновьего множества X = Fk, сопостав- ленный ак, сохранен, то доступ к корню F был бы возможен. Чтобы достичь F}, достаточно применить функцию RIGHT (i-k+ 1) раз, что соответствует i - к + 1 дополнительным доступам. Количество применений функции RIGHT определяет число необхо- димых дополнительных доступов, когда ц. становится наименьшим зна- чением в Fhi. Ее запуск, однако, происходит после того, как эффективно достигнут уровень i. Это делает возможным уменьшить число необхо- димых дополнительных доступов, как это иллюстрируется рис. 8.16, б;
336 8.3 3 Включение новой записи если а* не существует на уровнях к < j < /, но существует а* (к < I < i), то стал бы указателем, направленным в данный момент в X, Эта мо- дификация X не требует дополнительных затрат, а количество приме- нений функции RIGHT будет уменьшено до i - 1+ 1. Чтобы суммировать сказанное, введем следующее определение. Рис. 8.15
8.3.3. Включение новой записи 337 Рис. 8.16
338 8.3.3. Включение новой записи Положим если ак существует, а а* не существует для к < j < i (RIGHT будет применяться i: - к + 1 раз, чтобы получить предшественника F); если я* существует (Fi должно быть включено после рр. Один дополнительный шаг, двойник описанному, реализующийся, когда at становится наибольшим значением, необходим, когда at стано- вится наименьшим значением в Ft_v Указатель LEFT в корне Fhl должен быть изменен, чтобы отразить тот факт, что сыновье множество Fi для становится первым множеством в подсписке сыновьих множеств на уров- не z + 1 с предком в Ft_v Наконец заметим, что число доступов из уровня z + 1 на уровень п одно и то же во всех случаях. Ниже дается алгоритм, который для данной записи с комбинацией ключей aif ..., ап проверяет, существует ли эта комбинация в спра- вочнике и, если нет, то включает ее в структуру MDBT. Алгоритм использует следующие переменные: Р := указатель на корень В-дерева, в котором в настоящий момент осуществляется поиск; В(Р) :=В-дерево, адресованное указателем Р; Fk := F-указатель, ассоциированный с ключом ак, F*k := P-указатель, ассоциированный с ключом ак; X := указатель на корень В-дерева, определенный выше. (Заметим, что для упрощения алгоритма предполагаются выполнен- ными следующие соглашения относительно применимости функций RIGHT и NEXT к вершине X, чей адрес дается указателем LEVEL(z): RIGHT (X) = LEVEL(z + 1) и NEXT(X) = X.) Алгоритм 1. (Инициализация) 1.1. X *- LEVEL(l); 1.2. Р *- корень дерева MDBT; 1.3. z *- 1. 2. (Поиск наибольшего префикса а2, ..., а1{ комбинации ап а2, ..., ан, существующего в справочнике.) 2.1. пока z < п цикл 2.2. если at в В(Р) то Р *- Fi 2.3. иначе начать включение: 2.4. если а* в В(Р) то X «- Р*; 2.5. z*-z+l; 2.6. конец цикла; 3. (Включение д- и нахождение правильной позиции на уровне i + 1 для размещения р..) 3.1. включить ц. в В(Р). 3.2. Запросить память для п + 1 - i страниц с адресами Р-, .., Рп. 3.3. если at в В(Р) то X *- Р* 3.4. иначе % at становится наименьшим значением %
8.3.4. Удаление записи 339 3.5. пока NEXT(X) # LEFT(P) цикл 3.6. X «- RIGHT(X) 3.7. конец цикла; 3.8. LEFT(P)«-FI; 3.9. если а- — самое большое значение в Б(Р) то RIGHT (Р) Ft; 4. (Включение значений ai+i, ..., ап+1 в справочник.) 4.1. пока i < п + 1 цикл 4.2. включить ai+l в F-; 4.3. NEXT(F;) +- NEXT(X); 4.4. NEXT(X) 4.5. X«-RIGHT(X); 4.6. LEFT(PJ) <- RIGHT (F.) *- Fl+1; 4.7. i <- i + 1; 4.8. конец цикла; Средняя трудоемкость включения записи в базу данных D равна О(р logJV), где N — число записей в базе данных, а р = max(log2/logc.), где ci — среднее число потомков в Б-дереве порядка 8.3.4. Удаление записи. Пусть av а,,..., ап — значения, которые встре- чаются в подлежащей удалению записи R. Предположим, что ai+l, а-+2, ..., ап — единственные элементы в соответствующих Б-деревьях, так что последние могут быть сведены к своим корням, которые содержат по единственному ключу. Тогда, если удаление R приведет в результате к пустой странице доступа, все ключи ait ai+l, ..., ап станут "негодными” из-за удаления R, так как не будет существовать ни одной записи с комбинацией а{, а2, ..., а-+1, ..., ап. Но существуют записи с префиксом а,, а2, ..., ahl. Следовательно, страницы, соответствующие а/+1, ..., ап, и страницы доступа могли бы быть возвращены в свободный резерв. Если мы находим, что может быть сделано восстановление хранения, то на этом шаге наша стратегия совершенно аналогична стратегии, при- нятой в алгоритме включения. Как показано на рис. 8.17, страница Fz может быть легко восстановлена, так как ее предшественник X = F* есть сыновье множество, ассоциированное с а* — ближайшим левым соседом а-. В противоположность этому, если а* не существует, но существует а*_,, то X получается применением функции RIGHT к корню — сыновьего множества, ассоциированного с а*_г Общий случай включает тот же са- мый' процесс модификации X, что и в алгоритме включения. Ниже описывается алгоритм удаления. Алгоритм DELETE 1. (Инициализация) 1.1. Х*- LEVEL(l); 1.2. Р <- корень дерева MDBT; 1.3. /^1. 2. (Поиск а. и a*, i = 1, ..., и.) 2.1. пока i < п цикл 2.2. если я- в В(Р) то Р *- F-; 2.3. если at — не единственное значение в В(Р) то
340 8.3.4. Удаление записи 2.4. j Р; % / следует за i % 2.5. иначе возврат ("значение отсутствует"); 2.6. если а* в В(Р) то X <- Р*; 2.7. i*- i+l; 2.8. конец цикла; % В конце этого цикла Q указывает на В-дерево, содержащее для которого все В-деревья, открытые для доступа на последую- щих уровнях, содержат только одно значение % 3. (Удаление ан+1 из соответствующей страницы доступа и, если она становится пустой, то удаление также и а..) 3.1. удалить ал+1 из В(Р); 3.2. если В(Р) не пусто то СТОП; 3.3. удалить aj из B(Q); 3.4. если а* нет в B(Q) то 3.5. noxaNEXT(X) # LEFT(Q) цикл 3.6. X*-RIGHT(X); 3.7. конец цикла; 4. (Возвращение в свободный резерв одностраничных В-деревьев, если таковые есть.) 4.1. /*-/’+1; 4.2. пока j < п + 1 цикл 4.3. у- NEXT (NEXT (X)); 4.4. освободить страницу NEXT(X); 4.5. NEXT(X)«-y; 4.6. X*-RIGHT(X); 4.7. конец цикла;
8.3.5. АВ-деревья 341 Трудоемкость алгоритма удаления составляет O(plogW), где N — чис- ло записей в базе данных, а р имеет тот же смысл, что и выше. 8.3.5. £В-деревья. Эти деревья порядка m, т > 1, являются обоб- щением В-деревьев порядка т для хранения многомерных данных. Они почти полностью аналогичны рассматривавшимся выше деревьям MDBT, поэтому ограничимся здесь лишь краткими пояснениями. Можно легко увидеть, что IB-деревья порядка т суть те же самые В-деревья порядка т. В В-деревьях порядка т каждая вершина, исключая корень, содержит s ключей, [т/2] < s < т. В ЛВ-деревьях, однако могут суще- ствовать вершины, содержащие менее \т!21 ключей (представляющие собой структурные нарушения), при условии, что эти структурные нару- шения ’’поддерживаются" EQSON-поддеревьями на единицу меньшей размерности основного дерева, которые присоединены к вершинам, где имеют место структурные нарушения. Структурное нарушение, вызыва- емое вершиной N на высоте Л, поддерживается поддеревом, если высота поддерева равна h или больше. На рис. 8.18, а изображено 2В-дерево порядка единицы, т.е. двумер- ное 2-3-дерево. Это дерево хранит следующие элементы данных:
342 8.4.1. Структура дерева МАТ (а, 1), (а, 3), (а, 7), (а, 9), (Z>, 2), (6, 4), (5, 5), (с, 1), (с, 2), W, 1), W, 3). Как и в 2-3-дереве, вершина Af, хранящая г ключей, имеет г + 1 под- деревьев, которые все хранят ключи той же самой размерности, что и хранящиеся в N. Кроме того, каждый двумерный ключ в вершине имеет одномерное EQSON-поддерево. Таким образом, поддеревья с корнями в вершинах ВиС (см. рис. 8.18, а) суть EQSON-поддеревья ключей а и Ь соответственно. Заметим, что левое и среднее поддеревья вершины А пусты. На рис. 8.18, б показано то же самое двумерное 2-3-дерево, что и на рис. 8.18, а, за исключением того, что каждое пустое левое, среднее или правое поддерево вершины N высоты h представляется цепью из h -1 унарных вершин без ключей (показаны на рисунке перекрещенными вершинами). На рис. 8.18, б видно, что поддерево с корнем в В есть ’’присоединенное поддерево на единицу меньшей размерности” вершин Р, Q, R и 5. Аналогично, поддерево с корнем в С есть "присоединенное поддерево на единицу меньшей размерности” вершин Р, 5, Т и D. Струк- турные нарушения, имеющие место в вершинах Р, Q, Р, 5, Г, U и V, допускаются из-за того, что каждое из этих нарушений структуры под- держивается соответствующим присоединенным EQSON-поддеревом меньшей размерности. 8.4. Деревья множественных атрибутов 8.4.1. Структура дерева МАТ. Дерево множественных атрибутов определяется следующим образом: Л-мерное дерево множественных атрибутов (МАТ) для множества записей, характеризующихся к атрибутами ..., Ак> есть дерево глу- бины к со следующими свойствами: а) МАТ имеет корень на уровне 0; б) каждый потомок корня есть (Л-1)-мерный МАТ на (Л-1) атрибутах А2, ..., Ак для подмножества записей, имеющих один и тот же атрибут это значение атрибута At есть значение корня соответствующего (Л-1) - мерного дерева МАТ; в) вершины — потомки корня — упорядочены в соответствии с возра- станием их значений; это множество вершин-потомков называется сы- новьим множеством. На рис. 8.19, а показано множество записей, а соответствующее ему дерево МАТ — на рис. 8.19, в. Заметим, что корень на уровне 0 не имеет никакого значения. Каждая вершина на уровне z, z = 1, 2, ..., Л, соответ- ствует значению атрибута А-, и это значение есть значение вершины. Таким образом, атрибуты Л2, ..., Ак формируют иерархию уровней от 1 до Л. Важным свойством структуры МАТ является то, что каждое сы- новье множество упорядочено. Это есть результат того свойства, что сортировка множества записей по атрибутам естественно индуцирует деревообразную структуру, как показано на рис. 8.19, б. Следовательно, абстрактное дерево МАТ может рассматриваться как дерево, построен- ное следующим образом:
8.4.1. Структура дерева МАТ 343 а Ai А2 А3 *4 Указатель на запись 1 1 3 3 1 1 2 1 2 2 1 1 4 1 3 1 1 2 6 4 2 3 5 7 5 1 1 3 5 6 1 2 5 6 7 2 3 5 1 8 б А1 А2 Аз А4 Указатель на запись 4 1 6 3 2 7 8 5 в Уровень Фиктивная вершина Атрибут а) записи сортируются в порядке возрастания по их атрибутам;
344 8.4.2. Генерация справочника б) начиная с первого атрибута, все элементы атрибута, имеющие одно и то же значение, объединяются в вершину. Этот процесс рекурсивно исполняется для каждого подмножества записей, которые имеют одно и то же значение первого атрибута. Конструкцию МАТ можно пояснить в терминах геометрических понятий. Поддерево МАТ на атрибутах А,, А3,..., Ак, порожденное спосо- бом, указанным в п. б) определения МАТ, соответствует множеству то- чек, которые лежат в гиперплоскости в пространстве данных. Уравнение этой гиперплоскости есть А, « , где а{ — значение атрибута At, соответ- ствующее корню поддерева МАТ. Так как гиперплоскость в пространстве размерности к соответствует (£-1)-мерному подпространству, каждое рекурсивное порождение поддерева МАТ выполняется на пространстве меньшей размерности. Тот же самый эффект обнаруживается в алго- ритмах поиска, которые работают рекурсивно на пространствах меньшей размерности. Другое важное свойство состоит в том, что каждая запись или точка представляются единственным путем из корня в соответствующую кон- цевую вершину. Из-за этого свойства профиль МАТ для данного множе- ства записей полностью зависит от появления различных значений атрибута в записях. В общем случае размеры различных сыновьих мно- жеств зависят от множества входных записей и соответствующих зна- чений атрибутов. В случае симметричных деревьев МАТ, у которых рас- пределение данных симметрично относительно атрибутов, средний раз- мер сыновьего множества равен О(N'/k), где А « 8.4.2. Генерация справочника. Структура данных МАТ линеаризует- ся для формирования справочника. Справочник определяет способ ор- ганизации уровней и реализации сыновьих множеств. Структуры дан- ных, такие как MAT, MDBT, ЛВ-деревья и другие, могут быть реализова- ны с использованием указателей. Ответ на запрос вызывает прохож- дение указателей. В общем случае не делается никаких предположений о способе организации указателей. Реализация с использованием указате- лей эффективна, когда структура данных размещена в оперативной па- мяти. Но когда справочник размещен во внешней памяти, где передача информации осуществляется страницами, случайность в организации реализации указателей приводит к хранению многих ненужных стра- ниц. Например, рассмотрим случай, когда вершины сыновьего множест- ва располагаются в различных страницах во внешней памяти. Эта ситу- ация может возникнуть, когда сыновье множество порождается дина- мическими включениями записей после завершения построения стати- ческой структуры. В этом случае поиск в сыновьем множестве размера $ может привести к обращению к O(logs) страницам во внешней памяти. Но если сыновье множество реализуется на одной странице или на посто- янном числе страниц, то тогда поиск включает 0(1) обращений к стра- ницам внешней памяти. Так как страница внешней памяти загружена в оперативную память, поиск может быть выполнен в сыновьем множестве для требуемого значения. Эта ситуация возникает во многих приложе- ниях (графика, вычислительная геометрия и т.д.), где большой размер данных вынуждает хранить информацию во внешней памяти.
8.4.2. Генерация справочника 345 Хотя абстрактная структура МАТ может быть реализована с исполь- зованием указателей, рассмотрим такую организацию, в которой вер- шины, соответствующие сыновьему множеству, хранятся вместе. Основ- ная идея состоит в объединении в кластер вершин, к которым, вероятно, может потребоваться доступ при ответе на запрос. В запросе с полным соответствием вершины в сыновьем множестве ищутся по значению. В запросе с частичным соответствием либо для заданного значения ищется сыновье множество, либо в сыновьем множестве проводится поиск. В объемном запросе ищутся вершины внутри специфицированного интер- вала. Для того чтобы ответить на приведенные выше запросы, введем понятие линеаризации, которая даст нам возможность хранить структу- ру данных в форме таблицы. Существует два типа линеаризации: по поиску в глубину и по поиску в ширину. Любая из них может делаться как сверху вниз, так и снизу вверх. Метод сверху вниз более эффек- тивен, нежели снизу вверх. Поскольку при ответе на запрос метод сверху вниз требует просмотра меньшего числа вершин. При линеаризации по поиску в глубину вершины, соответствующие полям записи, хранятся вместе, как показано на рис. 8.20, а. Числа рядом с вершиной указывают номера вершин в справочнике. Это эффективная техника для обработки запросов на точный поиск, когда в лучшем случае ответ может быть получен за одно обращение к внешней памяти (в предположении, что на одной странице может храниться к вершин). Однако в худшем случае необходимо к обращений. Но это не делает естественным поддержку запросов с частичным соответствием и объемных запросов, при которых элементы сыновьего множества не хранятся вместе. По линеаризации по поиску в ширину вершины, соответствующие сыновьему множеству, хранятся вместе, как показано на рис. 8.20, б. Этот метод естественно поддерживает запросы с частичным соответствием и объемные запросы. В табл. 8.1, 8.2 даны справочники, соответствующие линеаризации по поиску в глубину и по поиску в ширину, где каждый элемент спра- вочника имеет следующий вид: элемент справочника = record номер_вершины: /...Л/ значение: /...Л/ первый_сын/брат: /...Л/ последний_сын/кузен: I...M Поля, соответствующие вершине Т на уровне /, определяются следу- ющим образом: значение: значение вершины Т; первый_сын: — номер вершины первого элемента множества сыновей вершины Т для j « 1, 2, ..., к - 1; — указатель на запись для /«'А; последний_сын: — номер_вершины последнего элемента множества сыновей вершины Тдля /«1,2, ..., к - 1; — 0 для/«Л;
346 8.4.2. Генерация справочника брат: номер_вершины, следующей за вершиной Т в принятом упоря- дочении вершин для /-1,2, к\ кузен: номер_вершины первой вершины в сыновьем множестве сле- дующей за Т вершины для j = 1, ... , Поля первый_сын и последний_сын используются при линеаризации по поиску в ширину. Поля брат и кузен используются по линеаризации по поиску в глубину. Ниже будет описан алгоритм для создания спра- вочника на основе поиска в ширину. Таблица 8.1 Таблица 8.2 Номер вершины Значение Брат Кузен Номер вершины Значение Первый сын Последний сын 1 2 3 4 1 2 3 4 1 1 15 - 1 1 3 4 2 1 10 16 2 2 • 5 5 3 2 5 И 3 1 6 8 4 6 - 6 4 2 9 10
8.4.3. Алгоритм DIR-GEN 347 8.4.3. Алгоритм DIR-GEN. Прежде чем дать описание алгоритма, предназначенного для построения справочника на основе линеаризации по поиску в ширину, рассмотрим некоторые особенности его работы. Шаг 2 алгоритма DIR-GEN вычисляет переменную base[i], z= 1, 2, ..., £ + 1, такую, что каждая вершина справочника лежит между и base[i + 1 ]- 1. Эти переменные нужны для хранения полей значений первый_сын и последний_сын в алгоритме DIR-GEN. Основной вклад в трудоемкость алгоритма дает сортировка. После ввода записей и сортировки делается два прохода по отсортированным записям, один для алгоритма COMPUTE-BASE и один для строк 3-11 алгоритма DIR-GEN. Если вводимые данные располагаются в оперативной памяти, то сор- тировка требует O(kN\og(kN)) сравнений. Алгоритм COMPUTE-BASE требует О (kN) сравнений или доступов к памяти. Это объясняется тем, что строка 6 алгоритма COMPUTE-BASE и строка 6 алгоритма DIR-GEN включают каждая самое большее к сравнений для каждой записи. Мы можем показать, что строка 8 алгоритма COMPUTE-BASE и строки 8 и 9 алгоритма DIR-GEN будут исполняться самое большее к раз для каждой записи. Следовательно, сложность алгоритма DIR-GEN равна O((kN)iog(kN) + 2kN) = O((kN)log UM). Если каждое сравнение запи- сей тратит единицу времени, то сложность равна O(NlogN). Если вводимые данные располагаются во внешней памяти, то трудо- емкость определяется доступами к страницам во время сортировки. Дру-
348 8.4.4. Алгоритмы поиска гие части алгоритма делают два последовательных прохода по отсор- тированным данным, и в течение этих двух проходов производится О(т) обращений к странице, где т есть число страниц, в которых хранятся данные. Следовательно, используя стандартную технику внешней сор- тировки, генерация справочника может быть сделана с O(mlogm) обра- щениями к страницам. Алгоритм DIR-GEN начало 1. отсортировать файл входных данных по всем к атрибутам; 2. COMPUTE-BASE; 3. читать первую запись; 4. повторять 5. читать следующую запись; 6. сравнить ее с предыдущей записью, чтобы получить L — наибольший уровень, на котором значения атрибута различны; 7. для j от L до к цикл 8. заполнить поле значение; все 9. для j от L + 1 до к цикл 10. заполнить поля первый_сын и последний_сын; все 11. пока все записи обработаны; конец Алгоритм COMPUTE-BASE начало 1. для i от 1 до к + 1 цикл 2. base[i]:^i\ все 3. читать первую запись; 4. повторять 5. читать следующую запись; 6. сравнить ее с предыдущей записью, чтобы получить L — наибольший уровень, на котором значения атрибута различны; 7. для j от L до к + 1 цикл 8. base [/] : base [/ ] + 1; все 9. пока все записи обработаны; 10. для /от 2 до к 1 цикл 11. base [/ ] e base [/ ] + base [/-!]; все конец 8.4.4. Алгоритмы поиска. Алгоритмы поиска в структуре МАТ для всех видов запросов используют понятие кластеризации данных для улучшения эффективности в среднем различных поисковых алгоритмов. Это достигается хранением вместе вершин, которые с большой долей вероятности могут понадобиться при ответе на запрос. Анализ эффек-
8.4.4. Алгоритмы поиска 349 тивности проводится для двух случаев: когда справочник располагается в оперативной памяти (а) и во внешней (б). Линеаризация по поиску в ширину гарантирует, что сыновьи множе- ства располагаются последовательно в оперативной памяти и на них воз- можен бинарный поиск. Когда справочник располагается во внешней памяти, эта кластеризация помогает в уменьшении числа просматривае- мых страниц. Мы предполагаем, что каждое сыновье множество окку- пирует не более константного числа страниц во внешней памяти. Пред- полагаем также, что сыновье множество может быть полностью загруже- но в оперативную память, когда формируется ответ на запрос. Можно показать, что, когда справочник располагается в оперативной памяти, МАТ также эффективен, как и другие структуры типа ЛВ-деревьев, MDBT и т.д., но эффективнее, когда справочник располагается во внеш- ней памяти. Определим запрос Q как Q=A 4i, 1 = 1 где qi есть классификатор атрибута Az. Для запроса с точным соответ- ствием определяет значение i = 1, 2, ..., к. Для объемного запроса специфицирует интервал [Zz, i/J для атрибута Az, /“1,2,..., к, где и ui специфицируют нижнюю и верхнюю границы изменения атрибута соот- ветственно. Для запроса с частичным соответствием каждый уровень может быть как специфицирован,так и нет. Для специфицированного уровня /, / =1,2, ..., А, «у,- определяет значение Az. Для неспецифициро- ванного уровня не накладывает никакого ограничения на Az. Говоря об ответе на запрос, будем считать, что гфостранство записей с к атрибу- тами порождает Л-мерное пространство, а объемный запрос описывает ориентированный по координатным осям гиперпараллелепипед. Ответ на объемный запрос соответствует отысканию точек, содержащихся в таком гиперпараллелепипеде. В структуре МАТ при ответе на любой запрос обработка любого атрибуту уменьшает размерность пространства, в котором должен быть произведен поиск, на единицу. Основным понятием при поиске в МАТ является понятие ’’иерархиче- ского спуска”, когда запрос обрабатывается уровень за уровнем, начиная с корня. На каждом уровне/, /= 1, ..., к, вершины, которые удовлетворя- ют ’’частичному” запросу П </,, 4 = 1 агрегируются. Эти вершины называются классифицированными. Клас- сифицированные вершины на уровне к содержат указатели на физи- ческие записи, которые удовлетворяют запросу. При дальнейшем обсуж- дении этого вопроса мы ограничимся линеаризацией по поиску в ши- рину. Алгоритм MAT-SEARCH qnodes) начало
350 8.4.4. Алгоритмы поиска 1. temp set :=0; 2. для каждой п Е qnodes цикл 3. добавить к tempset всех сыновей п, которые удовлетворяют qievei\ все 4. если level < к то 5. MAT-SEARCH (level + 1, tempset); 6. иначе начало 7. для каждой п Е /empse/дикл 8. отыскать указатель на запись; все 9. конец; 10. MAT-SEARCHH, {root}); конец В алгоритме MAT-SEARCH строка 10 соответствует инициализи- рующему вызову. Когда справочник располагается во внешней памяти, исполнение строк 2 и 3 критично по отношению к числу обращений к страницам. Множество qnodes упорядочено, и обращение к нему идет в этом порядке. Это приводит в результате к тому, что доступ к сыновьим множествам в структуре МАТ осуществляется последовательно слева направо. Этот тип доступа эффективен, когда все множества небольшого размера и в одной странице их может собраться несколько штук. Такой сценарий встречается при ответе на объемный запрос. Фактически, используя упорядочение в соответствии с поиском в ширину и упорядо- ченное множество qnodes^ можно эффективно поддерживать последова- тельные доступы к справочнику. Запрос на точный поиск. Для запроса на точный поиск на любом уровне /существует только одна вершина, которая удовлетворяет j частичному запросу П q^ так как последний специфицирует единст- i=i венную комбинацию значений атрибутов в ’’частичном” МАТ, ограни- ченном первыми / уровнями. Следовательно, строка 3 алгоритма MAT- SEARCH исполняется только раз для каждого уровня. Для каждого ис- полнения строки 3 выполняется бинарный поиск на сыновьем множестве для специфицированного значения атрибута. Следовательно, в худшем случае сложность запроса на точный поиск равна O(klogN), а в среднем — O(logA). Если справочник располагается во внешней памяти, то на каждом уровне проводим поиск не более чем на с страницах, соответствующих сыновьему множеству классифицированной вершины на предыдущем уровне. Следовательно, число обращений к страницам для точного поис- ка равно О(ск) = О (к). При использовании поиска в ширину для любого запроса на точный поиск всегда просматривается ск страниц. При ис- пользовании поиска в глубину в лучшем случае для ответа на запрос о точном поиске достаточно одной страницы. В этом случае все класси- фицированные вершины, соответствующие запросу, лежат в одной стра- нице. Но в худшем случае нужно просмотреть + s2 +... + sk) страниц. В этом случае классифицированные вершины являются последними вер-
8.4.4. Алгоритмы поиска 351 шинами в их сыновьих множествах. Используя характеризацию в сред- нем, можно утверждать, что в худшем случае число доступов к стра- ницам для запроса на точный поиск равно O(kN'/k). Интересно отметить, что при реализации МАТ с использованием указателей и без предполо- жения о кластеризации вершин необходимо много доступов к страницам. Запрос на поиск с частичным соответствием (частичный поиск). Максимальное число записей, удовлетворя- ющих частичному запросу, который специфицирует t уровней, равно ♦ /2 • ... • tk, где = 1, если А- специфицировано, и = у. ( число значений атрибута А), если Ai не специфицировано. Можно показать, что число записей, которые удовлетворяют данному частичному запросу, равно O(Nii/k) для однородно распределенных дан- ных. В строке 3 алгоритма MAT-SEARCH для специфицированных уров- ней выполняется бинарный поиск в сыновьих множествах. Для неспе- цифицированных уровней классифицируем целиком сыновье множест- во. В худшем случае для нашего алгоритма первые к - t атрибутов не специфицированы, а каждая классифицированная вершина на уровне к -1 дает увеличение на одну классифицированную вершину на каждом последующем уровне. Следовательно, для каждого уровня /, (к ~ t + 1) < j < Л, имеем O(N'~*'k) множеств, где нужно провести поиск, и на каждом уров- не могут быть O(Nl~l/k) классифицированных вершин. Таким образом, стоимость ответа на частичный запрос равна 0(s1s2...5w(log5^+1+...+logsp) = O(tNll/k logW17*)). Заметим, что это выражение стремится к O(logJV) с ростом числа специфицированных атрибутов. Если справочник располагается во внешней памяти, то число досту- пов к страницам, соответствующим первым к - t неспецифицированным уровням, равно O(Nl~(t~l)/k) — по одному доступу к странице на каждое сыновье множество. Число доступов к страницам на последующих t спе- цифицированных уровнях равно O(tN'~(‘~')/k). Следовательно, полное число доступов к страницам равно O(tNl(tl)/k). С ростом числа специ- фицированных уровней это выражение стремится к O(kN'/k). Если лине- аризация не предполагается, то каждая классифицированная вершина может вызвать увеличение числа доступов к страницам и, таким обра- зом, оно становится равным O(tN{ t/k log(A,/<r)). Если для линеаризации используется упорядочение в соответствии с поиском в глубину, то мож- но показать, что число доступов к страницам равно Реали- зация линеаризации по поиску в ширину незначительно лучше лине- аризацйи по поиску в глубину. Однако обе линеаризации более эффек- тивны, чем произвольная реализация. Объемный запрос. Анализ эффективности объемного запроса в худшем случае носит чисто теоретический характер, поскольку полу- чается, что в худшем случае теоретически требуется просмотр всех N записей, что совершенно нереально на практике.
352 8.5. Библиографический комментарий Пусть а — наибольшее число классифицированных вершин в каждом сыновьем множестве, где был произведен поиск при объемном запросе, и пусть классифицированная доля р определяется как а -Ь А2 4- ,.. -Ь л (а* - 1) Р ~ N ~ (а - 1) W ’ Для достаточно больших а имеем р = ct / N. Классифицированная доля р дает среднее число классифицирован- ных вершин и поэтому определяет стоимость объемного поиска. Средние стоимости объемного поиска сведены в приводимую ниже табл. 8.3 обозначает число классифицируемых записей). Таблица 8.3 Классифицированная доля р Стоимость запроса по памяти оперативной внешней (N\ OWl'*/*logW1/*) + Ki) OWH/‘) (log \ N / CXlogN + Ki) O(logJV) (log log \ N ) OUogW'^+logW) +Ki) O(logW,/fc+logA0) (jv) OdogW'^) +K1) OdogW17*» 8.5. Библиографический комментарий В-деревья были введены в рассмотрение Р.Бейером и К.Мак-Крайтом в 1972 г. [4 ] и подробно исследовались в [3 ] (см. также [2 ]). Там же были введены В*-деревья, позволяющие использовать до 2/3 имеющегося в каждой вершине пространства. Вопросы программирования алгоритмов работы с В-деревьями рассматривались в [3] и [1 ] (Модула-2). Следует отметить также работу [9], где рассматривались формальные специфи- кации бинарных деревьев и В-деревьев и алгоритмы для работы с ними. Плотные /n-арные деревья основаны на понятии братского дерева (см. п. 7.1.12) и позволяют строить деревья с наперед заданной плотностью за- полнения вершин. Этот тип деревьев был предложен в 1979 г. в работе [8 ]. Организация поиска слов внутри вершин В-дерева изучалась в рабо- те [16 ]. Слабые В-деревья были введены К.Мельхорном и изучались в рабо- тах [12, 19 ]. Сильные В-деревья были введены в рассмотрение в работе [11]. Кроме этих типов деревьев известны также компактные В-деревья
8.5. Библиографический комментарий 353 [7, 25 ], а также цифровые В-деревья [17]. Компактные В-деревья — это деревья, у которых число страниц минимально. Алгоритм конструиро- вания компактного В-дерева для случая упорядоченных ключей предло- жен в [7 ]. Этот алгоритм удобно использовать, например, для реструк- турирования упорядоченных структур данных или слияния двух В-де- ревьев, просматривая их параллельно и одновременно строя новое дере- во. Цифровым В-деревом называется такая организация файловых ин- дексов, которая обеспечивает эффективное выполнение как последова- тельных, так и случайных операций доступа. Во многих отношениях они аналогичны обычным В-деревьям. Их преимущество состоит в том, что они допускают значительно более мощное ветвление в каждой вершине, уменьшая тем самым высоту дерева для заданного размера файла. Ре- зультатом этого является сокращение стоимости случайного поиска в файле. Ветвление вершин В-дерева существенно увеличивается за счет введения многостраничных вершин. Уникальной особенностью цифро- вого В-дерева является то, что для каждой операции поиска должна ис- следоваться только одна страница вершины. Для этого используется ме- тод, аналогичный используемому в расширенном хешировании, но кото- рый не требует выполнения операций хеширования. Интерес представляет также страничное АВЛ-дерево, изучавшееся в [6]. Использование АВЛ-деревьев для двухуровневой памяти требует разбиения их на поддеревья, каждое из которых хранится в отдельной странице памяти. Количество страниц, которое нужно пройти при дви- жении от корня к вершине, называется страничной длиной пути; стра- ничной высотой дерева, или p-высотой, называется наибольшая из стра- ничных длин его вершин. Страничное АВЛ-дерево обладает тем свойст- вом, что все листья имеют одну и ту же страничную длину пути, которая, в свою очередь, равна p-высоте дерева без единицы. Для дерева с п вер- шинами p-высота удовлетворяет неравенству м, где п — наибольшее число вершин на странице, а пл — число вершин в левом поддереве, причем n, » F^ - 1, где ВЬ2 есть число Фибоначчи, определяемое из условия Fk < п + 2 < А г Страничное АВЛ-дерево во многом близко к В-деревьям; при некото- рых условиях они подобны в том смысле, что одни и те же ключи груп- пируются одним и тем же способом в страницы и имеют одну и ту же страничную структуру. Более того, В-деревья могут быть преобразованы в подобные страничные АВЛ-деревья. Главное отличие между ними со- стоит в выборе "среднего" ключа при расщеплении страницы. В В-деревь- ях страница делится на две одинаковые части, в страничных АВЛ-де- ревьях в качестве "среднего" ключа берется корень поддерева, храняще- гося в странице. Имея примерно одинаковые характеристики, странич- ные АВЛ-деревья допускают более легкое изменение данных, нежели В-деревья с последовательной организацией страницы.
354 Список литературы Укажем также на работу [20 ], где рассматриваются В-деревья с новой мерой оптимальности, равной количеству просматриваемых вершин (AV-оптимальные В-деревья). Поведение В-деревьев в среднем изуча- лось в работе [18 ]. Анализу В-деревьев посвящены также работы [5, 21, 22,24,28 ]. Описание деревьев MDBT дано по работе [23], структуры МАТ— в обзоре [13 ], содержащем анализ современного состояния теории и прак- тики многомерных деревьев и обширнейшую библиографию по этому вопросу. Первоначально деревья МАТ были рассмотрены в работах [14, 26 ]; ЛВ-деревья были введены в работах [10, 15 ]. Следует также упомя- нуть работу [27 ], в которой были введены и исследованы многомерные АВЛ-деревья. СПИСОК ЛИТЕРАТУРЫ 1. Вирт Н. Алгоритмы и структуры данных. — M.: Мир, 1989. 2. Евстигнеев В.А. Применение теории графов в программировании. — M.: Наука, 1985. 3. Кнут Д. Искусство программирования для ЭВМ. — M.: Мир, 1978.— Т. 3: Сортировка и поиск. 4. Bayer R., McCreight С. Organization and maitenance of large ordered indexes//Acta Inform. — 1972. — Vol. 1, N 3. — P. 173—189. 5. Brown M.R. Some observations on random 2-3 trees//Inform. Process. Let. — 1979. — Vol. 9. — P.57—59. 6. CasariniF., Soda G. Binary trees paging//Inform. Systems. —1982. — Vol. 7, N 4.— P. 337—344. 7. Cesarini F., Soda G. An algorithm to construct a compactZMree in case of ordered keys//Inform. Process. Let. — 1983. — Vol. 17, N 3. — P. 13—16. 8. Culic K., OttmanTh., Wood D. Dense multiway trees.— Comp. Sci. Tech. Rep. 79-CS-5. McMaster Univ., Ontario, 1979. 9. Fielding E., Jones C. Program design by data refinement//D.Bjorner, C.B.Jones. Formal Specification and Software Development. Chapt. 10. — Prentice-Hall Intern., 1982. — P. 323—352. 10. Gueting R.H., Kriegel H.P. Multidimensional В-tree: an efficient dynamic file structure for exact match queries//Proc. lOthGl Annual Conf., Informatic Fachberichte. — Springer Verb, 1980.—P. 375—388. 11. Huddleston S., Mehlhorn K. Robust balancing in B-trees//Lect. Notes Comput. Sci. — 1981. — Vol. 104.—P. 235—244. 12. Huddleston S., Mehlhorn K. A new data structure for representing sorted lists//Acta Inform. — 1982. —Vol. 2, —P. 157—184. 1 3. Iyengar S.S. a.e. Multidimensional data structures: review and outlook//Adv. Comput. — 1988. — Vol. 27. — P. 69—119. 14. Kashyap R.L., Subas S.K.C., Yao S.B. Analysis of multiattribute tree database organization//IEEE Trans. Softw. Eng. — 1977. — Vol. SE-2.N 6. — P. 451—467. 15. Kriegel H.P., Vaishnavi V.K. Weighted multidimensional B-trees used as nearly optimal dynamic dictionaries//Proc. lOthlnt’lSymp. on Math. Found, of Comput. Sci. — 1981. — P. 410—417. 16. Kwong Y.S., Wood D. T-trees: a variant of B-trees. — Comp. Sci. Tech. Rep. 78-CS-18, McMaster Univ., Ontario, 1978. 17. LometD.B. Digital B-trees//7th Int'l Conf. Very Large Data Bases, Cannes, Sept. 9-11,1981. — P. 333—344.
Список литературы 355 18. Maruyama К. Index structures for virtual memory — comparison between B-trees and M- trees//IBM Res. Rep. RC 5258,1975. 19. Mehlhorn K. A new data structure for representing sorted lists//Lect. Notes Comput. Sci. — 1981. — Vol. 100. —P. 90—112. 20. Miller R.E., Pippenger N., Rosenberg A.L., Snyder L. Optimal 2-3 trees//SIAM J. Comput. — 1979. — Vol. 8. — P. 42—59. 21. Mizoguchi T. On required space for random split files//Proc. 17th Annual Allerton Conf., 1979. —P.211—217. 22. Ouskel M., Scheuermann P. Multidimensional B-trees: analysis of dynamic behavior//BIT. — 1981. — Bd 21, N 4. — P. 401—418. 23. Quitzow K.H., Klopproge M.R. Space utilization and access path length in Z?-trees//Inform. Systems. — 1980. — Vol. 5. — P. 7—16. 24. Rosenberg A.L., Snyder L. Time and space optimality in B-trees//ACM TODS. — 1981.— Vol.7,Nl. —P. 174—183. 25. Subas S.K.C., Kashyap R.L. Database organization — an access and storage method. — Tech. Rep. TREE 75-32, School of Engineering, Purdue Univ., 1976. 26. Vaishnavi V.K. Multidimensional height-balanced trees//IEEE Trans. Comput. — 1984. — Vol. C-33, N 4. — P. 334-343. 27. Yao A.C.C. On random 2-3 trees//Acta Inform. — 1978. — Vol. 9. — P. 159—170.
356 Список дополнительной литературы СПИСОК ДОПОЛНИТЕЛЬНОЙ ЛИТЕРАТУРЫ 1. Адельсон-Вельский Г.М., Диниц Е.А., Карзанов А.В. Потоковые алгоритмы. — М.: На- ука, 1975. 2. Алгоритмы и программы решения задач на графах и сетях/ М.И. Нечепуренко, В.К. Попков, С.М. Майнагашёв и др. — Новосибирск: Наука, Сиб. отд-ние, 1990. 3. Басакер Р., Саати Т. Конечные графы и сети. — М.: Наука, 1974. 4. Белов В.В., Воробьев Е.М., Шаталов В.Е. Теория графов. — М.: Высш, шк., 1976. 5. Берж К, Теория графов и ее применения. — М.: Изд-во иностр, лит., 1962. 6. Вирг Н. Алгоритмы+структуры данных - программы. — М.: Мир, 1985. 7. Дискретная математика и математические вопросы кибернетики/ Под общ. ред. С.В. Яблонского, О.Б. Лупанова. — М.: Наука, 1974. — Т. 1. 8. Евстигнеев В.А. Теория графов и программирование. - Новосибирск: Изд-во Новосиб. ун-та, 1978. 9. Евстигнеев В.А. Применение теории графов в программировании. — М.: Наука, 1985. 10. Исследования по прикладной теории графов/ Под ред. А.С. Алексеева. —- Новосибирск: Наука, 1986. 11. Касьянов В.Н, Методы анализа программ. — Новосибирск: Изд-во Новосиб. ун-та, 1982. 12. Касьянов В.Н. Введение в теорию оптимизации программ. — Новосибирск: ВЦ СО АН СССР, 1985. 13. Касьянов В.Н. Оптимизирующие преобразования программ. — М.: Наука, 1988. 14. Кристофидес Н. Теория графов. Алгоритмический подход. — М.: Мир, 1978. 15. Кофман А. Введение в прикладную комбинаторику. — М.: Наука, 1975. 16. Лекции по теории графов/В.А. Емеличев, О.И. Мельников, В.И. Сарванов, Р.И. Тыш- кевич. — М.: Наука, 1990. 17. Липский В. Комбинаторика для программистов. — М.: Мир, 1988. 18. Майника Э. Алгоритмы оптимизации на сетях и графах. — М.: Мир, 1981. 19. Оре О. Теория графов. — М.: Наука, 1968. 20. Райзер Г.Дж. Комбинаторная математика. — М.: Мир, 1966. 21. Свами М., Тхуласимаран К. Графы, сети и алгоритмы. — М.: Мир, 1984. 22. Сешу С., Рид М.Б. Линейные графы и электрические цепи. — М.: Высш, шк:, 1971. 23. Сибуя М., Ямамото Т. Алгоритмы обработки данных. — М.: Мир, 1986. 22. Форд Л., Фалкерсон Д. Потоки в сетях. — М.: Мир, 1966. 23. Харари Ф. Теория графов. — М.: Мир, 1973.
Предметный указатель 357 ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ А АВЛ-дерево 1 .1.7, 7.1.4 Автомат с магазинной памятью 6.3.2 Автоморфизм 5.1.1 Автоморфизное разбиение 5.1.6 Алгоритм Кнута-Бендикса 5.3.8 Алфавит 6.2.2 Альт 4.1.4 — аранжируемый 4.1.10 Аранжировка 4.1.10 LL-анализатор 6.3.4 LR (к) -анализатор 6.3.9 — канонический 6.4.4 Б Баланс вершины 8.2.1 — корневой 7.1.5 Брат вершины 7.1.13 Буква алфавита 6.2.2 В Вектор-каркас 1.1.8 Вершина бинарная 8.1.2 — классифицированная 8.4.4 — насыщенная 8.1.2 — ненасыщенная 8.1.2 — переменная 5.2.10 — унарная 8.1.2 — фрагмента входная 4.1.2 выходная 4.1.2 граничная 4.1.5 конечная 4.1.2 начальная 4.1.2 стартовая 4.1.2 . финишная 4.1.2 — функциональная 5.2.10 Вполне-предупорядочение 5.3.7 Вращение двойное 7.1.4 — простое 7.1.4 Вхождение подтерма 5.2.2 Вывод 6.2.2 — левый 6.2.4 — правый 6.2.4 Выводимость 5.3.2 Высота дерева 1.1.5 Я-вектор Г 1.2.18 Гамак 4.1.4 — простой 4.3.1 — составной 4.3.1 Гистерезис 8.2.1,8.2.3 — перемещений 8.2.3 Глубина аранжируемого графа 4.1.11 — нумерации 4.1.11 Грамматика 6.2.3 — автоматная 6.2.3 — без левой рекурсии 6.2.5 цепных правил 6.2.5 циклов 6.2.5 — контекстно-зависимая 6.2.3 — контекстно-свободная 6.2.3 — неукорачивающая 6.2.5 — простого предшествования 6.3.6 — с фразовой структурой 6.2.3 — составляющих 6.2.2 — типа 0 6.2.3 — типа 1 6.2.3 — типа 2 6.2.3 — типа 3 6.2.3 — Хомского 6.2.3 — (2,1) (1,2)-предшествования 6.3.6 LL-грамматика 6.3.4 LL(k) -грамматика 6.3.4 LR (к) -грамматика 6.3.9 РК(к) -грамматика 6.3.9 Граница 5.2.6 Граф данных 1.2.4 — каркасов 1.1.8 — управляющий 4.1.2 А-граф 4.3.1 Группа автоморфизмов 5.1.1 — дерева 5.1.1 д Дерево 1.1.2 — асимметричное 5.1.1 — бесконечное 1.1.2 — бинарное 1.1.6
358 Предметный указатель Дерево бинарное Т-дерево 8.1.7 балансированное 1. 1.7, 7.1.4 (u, v)-дерево 8.2.3 по весу 1. 1.7, 7.1.5 2-3-дерево 7.1.8 выровненное 1.1.7 Диаметр 1.1.4 сортировки 7.1.1 Дискриминатор 7.2.1 — бицентральное 1.1.4 Длина цепочки 6.2.2 — братства 7.1.13 Добавление нетерминала 6.2.5 — входящее 1.1.5 Дре вескость 1.1.5 — вывода 6.2.4 Дуга вперед 4.1.11 — выровненное 7.1.13 — древесная 1.1.14 — вырожденное 1.1.2 — назад 4.1.11 — выходящее 1.1.5 — обратная 1.1.14 — глубинное остовное 1.1.14 — поперечная 1.1.14 — гомеоморфно несводимое 1.1.2 — прямая 1.1.14 — двоично-поисковое 1.1.6 5- дуга 1.1.11 — конечное 1.1.2 Дэг (DAG) 5.2.10 — корневое 1.1.5 — левостороннее — множественных атрибутов 1.1.6 3 Задача труднорешаемая 2.1.5 (МАТ) 8.4.1 — ориентированное 1.1 .5, 1.1.10 — АР-полная 2.1.5 — плоское 1. 1.2, 1.1.6 Запрос на точный поиск 8.3.2 — пустое 1.1.2 — объемный 8.3.2 — разбора 6.2.4 — с частичным соответствием 8.3.2 — растущее 1.1.5 Знак алфавита 6.2.2 — свободное 1.1.5 Значение вершины 7.1.1 — сильно ветвящееся 8.1.2 Зона 4.1.3 плотное 8.1.2 — слабо плотное 8.1.2 И — сливаемое 7.1.8 Иерархия вложенных альтов 4.3.1 — сортировки 7.1.1 зон 4.2.5 многомерное 7.2.1 7.1.13 1.1.8 1.1.2 Изменение направления рекурсии 6.2.5 — соседства — стягивающее — тривиальное Изоморфизм — корневых деревьев — плоских деревьев 5.1.1 5.1.1 5.1.1 — упорядоченное — Фиббоначи — т-арное — г-плотное — 1-2-братское (а, Ь)-дерево 1.1.6 7.1.5 8.1.2 8.1.2 7.1.15 8.2.1 — помеченных деревьев Интервал Итерация языка позитивная ^-итерация языка 5.1.1 4.1.4 6.2.2 6.2.2 6.2.2 — связанное по уровням 8.2.2 V — частично-балансированное 8.2.1 IV 5-дерево 8.1.3 Каркас 1.1.8 — многомерное 8.3.1 — оптимальный 3.1.1 — сильное 8.2.3 — уграфа 4.2.8 — симметричное бинарное 8.2.1 Класс корневой 5.2.10 — слабое 8.2.1 Код Гапта 1.2.16 55-дерево 7.1.5 — Закса 1.2.14 5-5-дерево 8.1.6 — Ли 1.2.15 EQSON- дерево 8.3.5 — линейный 1.2.8 /(/и)-дерево 8.1.7 — Прюфера 1.2.5 //-дерево 1.1.7 — ротационный 1.2.13 НВ-дерево 1.1.7 — с дублированием вершин 1.2.9 HS-де ре во 1.1.7 — свободный от повторений 1.2.10 ^-дерево 1.1.7 — уровневый 1.2.12 ^5-дерево 8.3.5 Комбинаторная логика 5.3.2 £-</-дерево 7.2.1 Компактификация 5.2.6 L-дерево 8.1.7 Конкатенация 6.2.2 MDBT-дерево 8.3.1 — языков 6.2.2 5-дерево 8.1.7 Конфигурация 6.3.2
Предметный указатель 359 Корень дерева 1.1.5 Остов 1.1.8 Кратчайшая связывающая сеть 3.1.1 Отображение управляющее 6.3.2 Критическая пара 5.3.5 Отношение вполне-фундированное 5.3.7 Крона дерева 6.2.4 — нетерово 5.3.7 КС-язык детерминированный 6.3.2 — редукции — эквивалентности, 5.3.3 Л порожденные СПТ 5.3.3 Лексема 6.1.1 Очередь с приоритетами — сцепляемая 7.1.8 7.1.8 Лента входная 6.3.2 F-область 4.1.8 Лес 1 .1.2, 3.1.7 — обхода 1.1.11 п — ориентированный 3.1.7 6.4.2 покрывающий 3.1.7 Пара выводимая Лес-каркас 3.1.7 Перевод 6.4.2 Линейная компонента 4.1.4 Подграф запрещенный 4.2.8 Линейное упорядочение 5.3.7 Подстановка 5.2.2 Линейный участок 4.1.3 — правил 6.2.5 Лист 1.1.5 Подтерм 5.2.2 Луч 4.1.3 Подцепочка 6.2.2 F-луч 4.1.8 Пополнение СПТ 5.3.6 Порог слияния 8.2.3 М Порядок дерева 1.1.2 Матрица предшествования 6.3.6 — обхода 2.2.8 инфиксный 2.2.8 — смежности 1.2.2 постфиксный 2.2.8 Множество уравнений 5.2.3 префиксный 2.2.8 в разрешенной форме Правило переписывания 5.3.3 компактное 5.2.6 Предложение 6.2.2 эквивалентное 5.2.3 Представление зонно-интервальное 4.2.6 МП-автомат 6.3.2 Предупорядочение 5.3.7 Мультиуравнение 5.2.5 — конечно-завершимое 5.3.7 тт — Крушкаля 5.3.7 н — монотонное 5.3.7 Неоднозначность языка 6.2.5 — нетерово 5.3.7 Нетерминал Нормальная форма Грейсбах 6.2.3 6.2.5 — упрощающее Предшественник обязательный 5.3.7 4.1.7 терма Хомского 5.3.3 непосредственный 4.1.7 6^25 Преемник обязательный 4.1.7 Нумерация — базисная 1.1.11 непосредственный 4.1.7 1.1.12 Преобразователь 6.4.3 — обратная — правильная — прямая — разумная 1.1.12 4.1.8 1.1.12 4.1.11 Префикс — активный Произведение языков F-путь 6.2.2 6.4.4 6.2.2 1.1.11 Х-нумерация 4.3.2 п L-нумерация 4.3.2 г Л/-нумерация 1.1.12 Равенство 5.2.3 ^нумерация 1.1.12 Радиус 1.1.4 Т-нумерация 4.1.13 Разметка 1.1.11 РАМ 2.1.2 О Ранг атрибута 8.3.1 Обход в глубину 1.1.13 Распознаватель детерминированный 6.3.2 — в ширину 1.1.13 — недетерминированный Однозначность грамматики Оркаркас — входящий — выходящий 6.2.5 1.1.8 1.1.8 1.1.8 Расстояние между вершинами Ребро древесное — обратное 1.1.4 1.1.13 1.1.13 — заходящий Основа 1.1.8 6.2.4 Редукция термов Решение мультиуравнения 5.2.3 5.2.5
360 Предметный указатель С Точка сочленения 4.1.13 Свертка программы лексическая 6.1.2 у Свойство подтермное 5.3.7 — Черча—Россера 5.3.4 Уграф 4.1.2 Семидоминатор 4.4.3 — интервально-сводимый 4.2.3 Сентенциальная форма 6.2.3 — одновходовый 4.1.3 Сигнатура 5.3.2 — предельный 4.2.3 Сильно связная область 4.1.3 — регуляризуемый 4.2.2 Символ бесполезный 6.2.5 — сводимый 4.2.3 — терма внешний Указатель сыновьего множества 8.3.1 (корневой) 5.2.2 Укладка 1.1.11 Система мультиуравнений 5.2.7 Унификатор 5.2.2 переписывания термов — мультиуравнения 5.2.5 (СПТ) 5.3.3 — наибольший общий 5.2.2 каноническая 5.3.4 Упорядочение конвергентная 5.3.4 — линейное 5.3.7 конечно-завершимая 5.3.4 — редукционное 5.3.7 конфлюэнтная 5.3.4 — рекурсивных путей 5.3.7 локально-конфлюэнтная 5.3.5 Уравнение 5.2.3 несводимая 5.3.8 Устойчивость (и,v)-дерева 8.2.3 нетерова 5.3.4 Устройство управляющее 6.3.2 полная 5.3.4 Ситуация недогрузки 8.2.3 Ф Словарь Слово 7.1.8 6.2.2 Фактор-уграф 4.1.6 Сложность 2.1.3 Фантом 8.2.1 — в лучшем случае 2.1.3 Фрагмент 4.1.2 — в среднем 2.1.3 — первичный 4.1.5 — в худшем случае 2.1.3 — правильный 4.1.5 — временная — емкостная 2.1.3 2.1.3 — простой Фраза 4.1.5 6.2.4 Совмещение правил 5.3.5 Спецификация эквациональная 5.3.2 ц Списки смежности 1.2.3 Центр Центральная вершина Центроид 1.1.4 1.1.4 1.1.4 Спуск рекурсивный Страница 6.3.4 8.1.1 — доступа 8.3.1 Цепочка 6.2.2 Стратегия включения 8.2.3 — выводимая 6.2.3 — восходящего анализа 6.3.1 — горизонтального анализа 6.3.1 ч — нисходящего анализа 6.3.1 — расщепления 8.2.3 Часть общая 5.2.6 Строка 6.2.2 Число симметрий дерева 5.1.1 Суперключ 7.2.1 Суффикс 6.2.2 Э СУ-схема 6.4.2 Сцепление языков 6.2.2 Эксцентриситет 1.1.4 Сыновье множество 8.3.1,8.4.1 Элементарное преобразование 1.1.8 каркасов Т Элиминация переменной 5.2.3 Терм 5.2.2 Я — замкнутый 5.2.2 Язык 6.2.2 — конвергентный 5.3.3 — линейный 5.2.2 — автоматный 6.2.3 — нередуцируемый 5.3.3 — редуцируемый 5.3.3 — тупиковый 5.3.3 — унифицируемый 5.2.2 Терминал 6.2.3
ОГЛАВЛЕНИЕ Предисловие............................................................... 3 Часть I. Основные понятия и алгоритмы .................................... 5 Глава 1. Деревья и их свойства ........................................... — 1.1. Введение и основные определения .............................. — 1.2. Представление деревьев ...................................... 20 1.3. Перечисление и подсчет деревьев.............................. 38 1.4. Библиографический комментарий ............................... 44 Список литературы ................................................ 45 Глава 2. Модели вычислений, сложность и основные алгоритмы .............. 46 2.1. Введение и язык представления алгоритмов...................... — 2.2. Обходы графов и деревьев в глубину и ширину.................. 57 2.3. Генерация деревьев........................................... 82 2.4. Библиографический комментарий .............................. 100 Список литературы ................................................. 102 Г л а в а 3. Каркасы.................................................... 105 3.1. Задача об отыскании оптимального каркаса...................... — 3.2. Алгоритмы перечисления всех каркасов.......................... 121 3.3. Поиск каркасов с заданными свойствами ...................... 132 3.4. Библиографический комментарий .............................. 136 Список литературы ................................................. 139 Часть II. Трансляция и преобразование программ ......................... 144 Глава 4. Структурные деревья.............................................. — 4.1. Введение и основные определения .............................. — 4.2. Иерархические представления регуляризуемых уграфов ......... 154 4.3. Гамачное представление уграфов.............................. 163 4.4. Выявление отношения обязательного предшествования .......... 171 4.5. Библиографический комментарий .............................. 178 Список литературы ............................................... 181 Глава 5. Изоморфизм, унификация и системы переписывания термов.......... 184 5.1. Изоморфизм деревьев........................................... — 5.2. Задача унификации .......................................... 199 5.3. Системы переписывания термов ............................... 221 5.4. Библиографический комментарий .............................. 235 Список литературы ............................................... 238 Глава 6. Синтаксические деревья......................................... 241 6.1. Синтаксис языка и задача синтаксического анализа.............. — 6.2. Порождающие грамматики ..................................... 243 6.3. Синтаксический анализ ...................................... 250 6.4. Перевод и конструкторы анализаторов......................... 270 6.5. Библиографический комментарий .............................. 278 Список литературы ............................................... 279 Часть III. Поиск и хранение информации ................................. 280 Глава 7. Информационные деревья........................................... — 7.1. Балансированные деревья ...................................... — 7.2. Многомерные деревья, или £-</-деревья ...................... 304 7.3. Библиографический комментарий .............................. 310 Список литературы ............................................... 311 Глава 8. Деревья для многоуровневой памяти ............................. 312 8.1. В-деревья .................................................... — 8.2. Обобщения В-деревьев........................................ 322 8.3. Многомерные В-деревья ...................................... 329 8.4. Деревья множественных атрибутов............................. 342 8.5. Библиографический комментарий .............................. 352 Список литературы ............................................... 354 Список дополнительной литературы........................................ 356 Предметный указатель.................................................... 357
0 «НАУКА» НОВОСИБИРСК