Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Структуры и алгоритмы обработки данных.doc
Скачиваний:
365
Добавлен:
12.03.2015
Размер:
1.81 Mб
Скачать

7.2. Двоичные деревья с дополнительными указателями

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

В таком дереве каждая вершина имеет дополнительное поле – указатель на своего родителя. Описание соответствующей структуры данных:

TypeTp = ^TNode;

TNode = record

Inf : <описание>;

Left, right, parent : Tp;

end;

Parent = nil

Инф. часть

left

right

Parent

Инф. часть

left

right

Parent

Инф. часть

nil

right

Parent

Инф. часть

nil

nil

Parent

Инф. часть

nil

nil

Parent

Инф. часть

nil

nil

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

Недостатками являются:

  • Увеличение затрат памяти на поддержку в каждой вершине дополнительного указателя (4 байта на вершину), т.е. в каждой вершине 12 байт занимает служебная информация, что при большом числе вершин (сотни тысяч) может стать весьма ощутимым

  • Увеличивается число операций при добавлении и удалении вершин за счет поддержки дополнительных ссылочных полей

Использование таких деревьев позволяет упростить процедуры обработки деревьев, прежде всего – обхода и удаления вершин. Отпадает необходимость явного использования рекурсии или ее замены стековыми операциями, поскольку возврат от текущей вершины к ее родителю можно выполнить непосредственно по дополнительному ссылочному полю.

7.3. Деревья общего вида (не двоичные).

Особенность таких деревьев – заранее неизвестноечисло потомков вершин, что не позволяет объявить в каждой вершине какое-то разумное количество ссылочных полей.

Подобные деревья используются реже двоичных, но тем не менее есть круг задач, где они необходимы. Существует несколько способов описания подобных деревьев, например – представление их через набор двоичных деревьев. Другой способ использует понятие сложной списковой структуры. Сначала создаётся основнойлинейныйсписок, содержащий всевершины-родители(не терминальные). С каждой родительской вершиной дополнительно связываетсясписок ее потомков.

1

2

3

4

5

6

7

8

10

11

12

9

1

3

4

7

2

3

4

5

6

7

8

9

10

11

12

Исходное недвоичное дерево

Представление в виде списка списков

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

Type Tp = ^ TNode;

TNode = record

Inf : <описание>;

NextParent, NextChild : Tp;

end;

В списках потомков ссылочное поле NextParentв простейшем случае просто не используется (устанавливается вnil). Как вариант, можно в этом поле хранить указатель на одноименную вершину в родительском списке.

4

Par

Child

1

Par

Child

3

Par

Child

7

nil

Child

2

nil

Child

5

nil

Child

9

nil

nil

10

nil

Child

3

Par

Child

6

nil

Child

11

nil

Child

4

Par

nil

7

Par

Child

12

nil

nil

8

Par

nil

Схематично рассмотрим реализацию основных операций с подобным списковым представлением недвоичных деревьев.

  1. Вывод списка родителей с соответствующими списками потомков реализуется двойным циклом: внешний цикл идет по списку родителей, а внутренний позволяет для каждого родителя вывести список его потомков

PCurrentParent := pRoot;

While pCurrentParent <> nil do

begin

“обработка вершины pCurrentParent^”;

pCurrentChild := pCurrentParent^.NextChild;

while pCurrentChild <> nil do

begin

“обработка вершины pCurrentChild^”;

pCurrentChild := pCurrentChild^.NextChild;

end;

pCurrentParent := pCurrentParent^.NextParent;

end;

  1. Добавление вершины X как потомка вершины Y:

  • “поиск вершины Y обходом всех вершин”;

  • if “вершина Y найдена в списке родителей” then “добавляем X в список потомков вершины Y”;

  • if “вершина Y найдена в списке потомков” then

    • “добавляем Y в список родителей”;

    • “создаем у вершины Y список потомков с вершиной X”;

  1. Удаление вершины X, если она не корневая для всего дерева:

  • “поиск вершины X обходом всех вершин”;

  • if “вершина X найдена в списке родителей” then

    • “просмотром всех списков найти родителя вершины X”;

    • “удалить X из списка потомков”;

    • “к родителю X добавить список всех потомков X”;

  • if “вершина X есть только в списке потомков” then

    • “удалить X из списка потомков”;

    • if “список потомков пуст, то удалить родителя из списка родителей”;