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

3.6.2. Ссылочная реализация на основе массива

В разделе 2.5 рассматривался способ ссылочной реализации линейного списка на основе массива (вектора). Вспомним, что в этом случае элементы могут располагаться в массиве не по порядку, но каждый элемент содержит одну или две ссылки на своих соседей. Ссылки представляют собой индексы элементов массива, следовательно, если применять такой принцип к бинарному дереву, то каждый узел можно представить как структуру (запись), в которой хранятся данные и два индекса — ссылка на левого и правого сына (пустой ссылке обычно соответстствует несуществующий индекс, например, 0 или -1).

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

Описание такой структуры может выглядеть, например, так:

typedef int type_of_data; //тип данных, может быть любым

struct node // структура для одного элемента списка

{ type_of_data data; // данные

int left, right; // индекс левого и правого сына

};

const int maxlength=10000; //размеры выбираем, исходя из условия задачи

node bintree[maxlength]; //массив, в котором будет размещено бинарное дерево

int topfree; //ссылка на начало свободной области (индекс)

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

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

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

В начальный момент весь массив представляет собой пустой стек. Дерево формируется «снизу вверх», начиная с листьев, поскольку это самый глубокий уровень вложенности функции consbt. Каждый родитель формируется после того, как сформированы оба его сына. Последним будет сформирован корень, он окажется на границе занятой и свободной части массива, которые непрерывны только до первого удаления какого-либо узла.

Для дерева из рис.3.9. узлы будут сформированы в следующей последовательности f c g e d b a (Это легко проверить, добавив в текст функции consbt вывод значения корня сформированного дерева). Если обозначить пустую ссылку как -1, то содержимое массива будет таким, как изображено в табл. 3.3, а ссылка topfree имеет значение 7.

Таблица 3.3.

Реализация дерева из рис.3.11 с помощью массива

Индекс в

массиве

Значение

data

Левый сын

left

Правый сын

Right

Примечание

0

F

-1

-1

Лист f

1

C

-1

0

Узел c

2

G

-1

-1

Лист g

3

E

-1

2

Узел e

4

D

-1

-1

Лист d

5

B

4

3

Узел b

6

A

5

1

Корень дерева a

7

8

Начало списка сво-бодных элементов

8

9

Свободный элемент

9

-1

Последний свободный элемент

Реализацию приведенных в спецификации базовых функций можно выполнить самостоятельно по аналогии с разделом 2.5. При этом интересно реализовать такие дополнительные функции как вставка и удаление узлов.