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

Центрированный порядок обхода (лкп)

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

void centralstack(bt t) // в центрированном порядке (ЛКП)

{ stack<bt> s; bt p=t;

do // помещаем в стек узел и переходим к левому сыну

{ if (p) { s.push(p); p=left(p);}

else // дошли до левого листа, будем извлекать узлы

{if (!s.isnull())p=s.pop(); else return;

visit(p); // любая обработка узла p

p=right(p); //правое поддерево проходим после корня

}

}

while (true);

В табл. 3.7 представлено содержимое стека перед каждым извлечением очередного элемента.

Таблица 3.7

Содержимое стека при центрированном порядке обхода

№ итерации

Извлекаемый узел

Содержимое стека

4

D

dba

5

b

ba

8

G

gea

9

E

ea

10

A

a

12

C

c

14

F

f

В данном алгоритме обход дерева из семи узлов выполняется за 14 итераций, поскольку на каждой итерации в стек заносится или из него извлекается один узел (итерации, на которых в стек заносится узел, в таблице не показаны).

Обратный порядок обхода (лпк)

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

  1. Вместо обработки узла (корня поддерева) будем помещать его в еще один, дополнительный стек (назовем его стеком вывода sout). Тогда на заключительном этапе алгоритма элементы дополнительного стека будут обработаны в порядке, обратном тому, в котором они поступили в стек.

  2. Поскольку обратный порядок означает ЛПК, а не ПЛК (правое-левое-корень — такой порядок действительно обрабатывал бы узлы в противоположном по отношение к прямому порядке), то внесем еще одно изменение — сначала будем помещать в стек указатель на левого сына, а затем на правого.

Функция обратного обхода может иметь вид:

void reversestack(bt t) // обход в обратном порядке (ЛПК)

// используем дополнительный стек sout

{ stack<bt> s,sout;

s.push(t); bt p;

while (!s.isnull())

{p=s.pop();

sout.push(p);//вместо обработки узла помещаем его в стек

if(left(p)) s.push(left(p));

if(right(p)) s.push(right(p));

}

while (!sout.isnull())// извлекаем узлы из стека

{p=sout.pop(); visit(p);}//любая обработка

}

Обход в ширину

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

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

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

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

Напомним основные операции:

enqueue,dequeue – помещение элемента в очередь и удаление из нее;

isnull – проверка на пустоту.

void widthstack(bt t) // обход в ширину

{ queue<bt> q; // шаблон queue должен быть реализован!

q.enqueue(t); bt p;

while (!q.isnull())

{ p=q.dequeue();

cout << root(p)<<" ";

if(left(p)) q.enqueue (left(p));

if(right(p)) q.enqueue (right(p));

}

}

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