Опубликован: 12.02.2014 | Доступ: свободный | Студентов: 924 / 239 | Длительность: 11:22:00
Специальности: Программист
Лекция 9:

Деревья

< Лекция 8 || Лекция 9: 123 || Лекция 10 >

9.2. Произвольное дерево

В произвольном корневом дереве каждая вершина может иметь любое количество поддеревьев (рис. 9.1 (b)).

Полиморфный домен таких деревьев так же, как и в предыдущем случае, определяется рекурсивно:

domains
    tree{Elem} = t(Elem, tree{Elem}*).

Бинарная структура хранит элемент дерева и список его поддеревьев.

В следующей программе рекурсивно строится дерево потомков человека. Дерево строит предикат createTree/1. Определение этого предиката содержит всего одно правило. Список поддеревьев получается как результат применения предиката высшего порядка list::map/2 к списку "детей" корня дерева. Он строит для каждой вершины поддерево с корнем в этой вершине.

Дерево выводится на печать (предикат print/1), при этом корень дерева располагается слева, а поддеревья справа. Вершины одного уровня находятся на одинаковом расстоянии от левой границы окна консоли. В определении этого предиката участвует предикат второго порядка list::forAll/2.

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

class predicates
    createTree: (string Name) -> tree{string}.
    createTreeList: (string Name*) -> tree{string}*.
clauses
    createTree(X) = t(X, createTreeList([Y || parent(X, Y)])).

    createTreeList([X | L]) = [createTree(X) | createTreeList(L)].
    createTreeList([]) = [].

class predicates
    print: (tree{Elem}).
    print: (tree{Elem}, charCount).
    printTreeList: (tree{Elem}*, charCount).
clauses
    print(Tree):-
        print(Tree, 0).

    print(t(X, TreeList), N):-
        write(string::create(N, "\t"), X), nl,
        printTreeList(TreeList, N + 1).

    printTreeList([T | L], N):-
        print(T, N),
        printTreeList(L, N).
    printTreeList([], _).

В программе также строится список вершин дерева. Предикат get_nd/1 недетерминированно возвращает произвольную вершину дерева.

class facts - rel
    parent: (string Родитель, string Ребенок).
    male: (string).
    female: (string).

domains
    tree{Elem} = t(Elem, tree{Elem}*).

class predicates    % построение дерева потомков
    createTree: (string Name) -> tree{string}.
clauses
    createTree(X) =
        t(X, list::map([Y || parent(X, Y)], {(Z) = createTree(Z)})).

class predicates    % печать дерева
    print: (tree{Elem}).
    print: (tree{Elem}, charCount).
clauses
    print(Tree):-
        print(Tree, 0).

    print(t(X, TreeList), N):-
        write(string::create(N, "\t"), X), nl,
        list::forAll(TreeList, {(T):- print(T, N + 1)}).

class predicates    % обход дерева
    get_nd: (tree{Elem}) -> Elem multi.
clauses
    get_nd(t(A, _)) = A.
    get_nd(t(_, TreeList)) = get_nd(list::getMember_nd(TreeList)).

    run():-
        file::consult("fam.txt", rel),
        Tree = createTree("Иван"),
        print(Tree), nl,
        write([Elem || Elem = get_nd(Tree)]),
        _ = readLine().
Пример 9.4. Дерево потомков

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

    open core, console, list

domains
    tree{Elem} = t(Elem, tree{Elem}*).

class facts
    arc: (unsigned, unsigned).
clauses
    arc(1, 2).    arc(1, 3).    arc(1, 4).     arc(2, 5).    arc(2, 6).
    arc(3, 7).    arc(7, 8).    arc(7, 9).     arc(7, 10).  arc(9, 11).

class predicates
    createTree: (unsigned) -> tree{unsigned}.
    print: (tree{Elem}).
    print: (tree{Elem}, charCount).
clauses
    createTree(X) = 
        t(X, map([Y || arc(X, Y)], {(Z) = createTree(Z)})).

    print(Tree):-
        print(Tree, 0).

    print(t(X, TreeList), N):-
        write(string::create(N, "\t"), X), nl,
        forAll(TreeList, {(T):- print(T, N + 1)}).

class predicates      % вершины заданного уровня
    get_nd: (tree{Elem}, positive) -> Elem nondeterm.
clauses
    get_nd(t(A, _), 0) = A:- !.
    get_nd(t(_, TrList), N) = get_nd(getMember_nd(TrList), N - 1).

class predicates      % высота дерева
    height: (tree{Elem}) -> integer.
    height_nd: (tree{Elem}, integer) -> integer nondeterm.
clauses
    height(Tree) = maximum([N || N = height_nd(Tree, 0)]).

    height_nd(t(_, []), N) = N.
    height_nd(t(_, TreeList), N) =
        height_nd(getMember_nd(TreeList), N + 1).

class predicates      % подсчеты
    sum: (tree{unsigned}) -> unsigned.
    count: (tree{Elem}) -> positive.
clauses
    % сумма четных вершин
    sum(t(A, TrList)) = C + fold(TrList, {(T, S) = sum(T) + S}, 0):-
        C = if A mod 2 = 0 then A else 0 end if.
    % количество всех вершин
    count(t(_, TrList)) = 1 + fold(TrList, {(T, S) = count(T) + S}, 0).

class predicates      % замена заданных вершин
    replace: (tree{unsigned}, unsigned, unsigned) -> tree{unsigned}.
clauses
    replace(t(V, TreeList), A, B) =
            t(C, map(TreeList, {(T) = replace(T, A, B)})):-
        C = if V = A then B else V end if.

    run():-
        Tree = createTree(1),
        print(Tree),
        write("\n\nПоколение 3: ", [Elem || Elem = get_nd(Tree, 3)]),
        write("\nВысота дерева: ", height(Tree)),
        write("\nСумма четных элементов дерева: ", sum(Tree)),
        write("\nКоличество вершин дерева: ", count(Tree)),
        write("\nЗамена 9 на 100:\n\n"),
        Tree1 = replace(Tree, 9, 100),
        print(Tree1),
        _ = readLine().
Пример 9.5. Обработка произвольных деревьев

Упражнение 2. Определите предикаты sum/1, count/1 и replace/3, которые предназначены для вычисления суммы четных элементов дерева, количества всех вершин дерева и замены одного элемента другим, не используя предикаты высшего порядка fold и map класса list. Введите дополнительные предикаты, которые обрабатывают списки деревьев.

В языке Visual Prolog имеются реализации красно-черных деревьев (класс redBlackTree), цифровых деревьев (класс radixTree) и др.

Упражнения

  1. Замените элементы двоичного дерева заданного уровня на заданный элемент.
  2. Замените элементы произвольного дерева заданного уровня на заданный элемент.
  3. Найдите количество всех вершин двоичного дерева.
  4. Вычислите сумму четных вершин произвольного дерева.
  5. Найдите количество терминальных вершин двоичного дерева.
  6. Составьте список терминальных вершин произвольного дерева.
  7. Вставьте заданное поддерево к заданной вершине произвольного дерева.
  8. Удалите поддеревья у всех вершин произвольного дерева, равных заданному элементу.
  9. Найдите путь от одной вершины к другой в дереве, вершины которого хранят попарно различные элементы.
  10. Вычислите сумму целых чисел, хранящихся в вершинах красного цвета в красно-черном дереве.
  11. Определите "черную" высоту красно-черного дерева.
  12. Выведите на печать красно-черное дерево (см. класс redBlackTree) так, чтобы вершины красного цвета печатались красным цветом.
< Лекция 8 || Лекция 9: 123 || Лекция 10 >
Жаныл Айкын
Жаныл Айкын
Rustam Inatov
Rustam Inatov

Доброго времени суток, подскажите пожалуйста, visual prolog examples, pie, vip7.5 - это все, где я могу скачать? (в смысле) может быть на сайте есть какой-то архив? Увы я не нашел его.

Подскажите, пожалуйста.

С уважением, Рустам.