достигается сразу же после применения первого предложения процедуры внутри. С другой стороны, цель

внутри( d, T)

будет успешно достигнута только после нескольких рекурсивных обращений. Аналогично цель

внутри( e, T)

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

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

Рис. 9.6. Двоичный справочник. Элемент 6 найден после прохода по отмеченному пути 5→8→6.

Будем говорить, что непустое дерево дер( Лев, X, Прав) упорядочено слева направо, если

(1) все вершины левого поддерева Лев меньше X;

(2) все вершины правого поддерева Прав больше X;

(3) оба поддерева упорядочены.

Будем называть такое двоичное дерево двоичным справочником. Пример показан на рис. 9.6.

Преимущество упорядочивания состоит в том, что для поиска некоторого объекта в двоичном справочнике всегда достаточно просмотреть не более одного поддерева. Экономия при поиске объекта X достигается за счет того, что, сравнив X с корнем, мы можем сразу же отбросить одно из поддеревьев. Например, пусть мы ищем элемент 6 в дереве, изображенной на рис. 9.6. Мы начинаем с корня 5, сравниваем 6 с 5, получаем 6 > 5. Поскольку все элементы данных в левом поддереве должны быть меньше, чем 5, единственная область, в которой еще осталась возможность найти элемент 6, — это правое поддерево. Продолжаем поиск в правом поддереве, переходя к вершине 8, и т.д.

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

Для того, чтобы найти элемент X в справочнике Д, необходимо:

• если X — это корень справочника Д, то считать, что X уже найден, иначе

• если X меньше, чем корень, то искать X в левом поддереве, иначе

• искать X в правом поддереве;

• если справочник Д пуст, то поиск терпит неудачу.

Эти правила запрограммированы в виде процедуры, показанной на рис. 9.7. Отношение больше( X, Y), означает, что X больше, чем Y. Если элементы, хранимые в дереве, — это числа, то под "больше, чем" имеется в виду просто X > Y.

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

?- внутри( 5, Д), внутри( 3, Д), внутри( 8, Д).

Д = дер( дер( Д1, 3, Д2), 5, дер( Д3, 8, Д4) ).

Переменные Д1, Д2, Д3 и Д4 соответствуют четырем неопределенным поддеревьям. Какими бы они ни были, все равно дерево Д будет содержать заданные элементы 3, 5 и 8. Структура построенного дерева зависит от того порядка, в котором указываются цели (рис. 9.8).

внутри( X, дер( _, X, _ ).

внутри( X, дер( Лев, Корень, Прав) ) :-

 больше( Корень, X), % Корень больше, чем X

внутри( X, Лев).     % Поиск в левом поддереве

внутри( X, дер( Лев, Корень, Прав) ) :-

 больше( X, Корень), % X больше, чем корень

 внутри( X, Прав).   % Поиск в правом поддереве

Рис. 9.7. Поиск элемента X в двоичном справочнике.

Рис. 9.8. (а) Дерево Д, построенное как результат достижения целей: внутри( 5, Д), внутри( 3, Д), внутри( 8, Д). (b) Дерево, полученное при другом порядке целей: внутри( 5, Д), внутри( 3, Д), внутри( 8, Д).

Здесь уместно сделать несколько замечаний относительно эффективности поиска в справочниках. Вообще говоря, поиск элемента в справочнике эффективнее, чем поиск в списке. Но насколько? Пусть n — число элементов множества. Если множество представлено списком, то ожидаемое время поиска будет пропорционально его длине n. В среднем нам придется просмотреть примерно половину списка. Если множество представлено двоичным деревом, то время поиска будет пропорционально глубине дерева. Глубина дерева — это длина самого длинного пути между корнем и листом дерева. Однако следует помнить, что глубина дерева зависит от его формы.

Перейти на страницу:

Похожие книги