end;
Включение элемента в дерево реализуется путем во-первых, поиска вершины √ предка нового элемента, во-вторых, непосредственным включением элемента в дерево по найденной позиции. Опишем процедуру поиска предка для нового элемента.
function SearchNode( Elem: TypeOfElem; var Tree, Result: Assoc): Boolean;
var
ServiceVar1, ServiceVar2: Assoc;
b: Boolean;
begin
b:= False;
ServiceVar1:= Tree;
if Tree <> nil then
repeat
ServiceVar2:= ServiceVar1;
if ServiceVar1^.Elem= Elem then {элемент найден} b:= True
else begin
{запоминание обрабатываемой вершины}
if Elem < ServiceVar1^.Elem then ServiceVar1:=
ServiceVar1^.Left
else ServiceVar1:= ServiceVar1^.Right
end
until b or ( ServiceVar1= nil );
SearchNode:= b;
Result:= ServiceVar2
Как видно из описания, эта функция подобна ранее рассмотренной функции поиска элемента дерева (FoundInTree), но в качестве побочного эффекта фиксируется ссылка на вершину, в которой был найден заданный элемент (в случае успешного поиска), или ссылка на вершину, после обработки которой поиск прекращен (в случае неуспешного поиска). Сама процедура включения элемента в дерево будет иметь следующее описание.
procedure IncludeInTree( Elem: TypeOfElem; var Tree: Assoc );
Result, Node: Assoc;
if not SearchNode( Elem, Tree, Result ) then begin
{формирование новой вершины в дереве}
new( Node );
Node^.Elem:= Elem;
Node^.Left:= nil;
Node^.Right:= nil;
if Tree= nil then
{если дерево пусто, то созданный элемент сделать вершиной дерева}
Tree:= Node
else
{подсоединить новую вершину к дереву}
if Elem < Result^.Elem then Result^.Left:= Node
else Result^.Right:= Node
Двоичное дерево можно рассматривать как рекурсивную структуру данных, состоящую из корневой записи, указывающей на левое и правое поддерево. Оба поддерева имеют такую же структуру: корень поддерева и правое и левое поддеревья. При этом, для представления дерева рекурсивной динамической структурой целесообразно модифицировать описание типа дерева, данное выше. А именно, удобнее изменить тип ссылок на левое и правое поддеревья с нетипизированного (Pointer) на типизированный:
type
TypeOfElem1= {};
Assoc1= ^ElemOfTree1;
ElemOfTree1= record
Elem: TypeOfElem1;
Left, Right: Assoc1
Опишем процедуру вставки элемента рекурсивно.
procedure IncludeInTree2( NewElem: Assoc1; var SubTree: Assoc1 );
if SubTree= nil then begin
SubTree:= NewElem;
NewElem^.Left:= nil;
NewElem^.Right:= nil;
if NewElem^.Elem < SubTree^.Elem then
IncludeInTree2( NewElem, SubTree^.Left )
IncludeInTree2( NewElem, SubTree^.Right )
Проблема реализации данной операции состоит в том, что в общем случае, в удаляемую вершину входит одна связь, а выходят две. Поэтому, необходимо найти подходящий элемент дерева, который можно было бы вставить на место удаляемого. Этот элемент является либо самым правым элементом левого поддерева (для достижения этого элемента необходимо перейти в следующую вершину по левой ветви, а затем, переходить в очередные вершины по правым ветвям до тех пор, пока очередная такая ссылка не будет равна nil), либо самый левый элемент правого поддерева (для достижения этого элемента необходимо перейти в следующую вершину по правой ветви, а затем, переходить в очередные вершины по левым ветвям до тех пор, пока очередная такая ссылка не будет равна nil). Процедура исключения элемента из двоичного дерева должна различать тои случая:
1. элемента с заданной информативной частью в дереве нет; 2. элемент с заданной информативной частью имеет не более одной ветви; 3. элемент с заданной информативной частью имеет две ветви.
procedure DeleteElemOfTree( var Tree: Assoc1; Elem: TypeOfElem1 );
ServiceVar1: Assoc1;
procedure Del( var ServiceVar2: Assoc1 );
if ServiceVar2^.Right= nil then begin
ServiceVar1^.Elem:= ServiceVar2^.Elem;
ServiceVar1:= ServiceVar2;
ServiceVar2:=ServiceVar2^.Left
else Del( ServiceVar2^.Right )
{удаление элемента с информативным полем равным Elem из дерева Tree}
{первый случай процедуры удаления}
writeln( 'Элемент не найден' )
{поиск элемента с заданным ключом}
if Elem < Tree^.Elem then DeleteElemOfTree( Tree^.Left, Elem )
if Elem > Tree^.Elem then
DeleteElemOfTree( Tree^.Right, Elem )
{элемент найден, необходимо его удалить}
{второй случай процедуры удаления}
if ServiceVar1^.Right= nil then
Tree:= ServiceVar1^.Left
if ServiceVar1^.Left= nil then
Tree:= ServiceVar1^.Right
{третий случай процедуры удаления}
Del( ServiceVar1^.Left )
Вспомогательная рекурсивная процедура Del вызывается лишь в третьем случае процедуры удаления. Она переходит к самому правому элементу левого поддерева удаляемого элемента, а затем заменяет информационное поле удаляемого на значение поля найденного элемента.
Данная задача также может быть решена с помощью механизма рекурсии.
procedure PrintTree( Tree: Pointer);
ServiceVar: Assoc1;
ServiceVar:= Tree;
writeln( ServiceVar^.Elem );
if ServiceVar^.Right <> nil then PrintTree(ServiceVar^.Right);
if ServiceVar^.Left <> nil then PrintTree(ServiceVar^.Left);
Разберем решение типичной задачи, связанной с обработкой двоичных деревьев.
Текст задания
Описать процедуру copy( T, T1) которая строит T1 √ копию дерева T.
Решение
procedure CopyTree( T: Tree; var T1: Tree );
if T= nil then T1:= nil
new( T1 );
T1^.Elem:= T^.Elem;
CopyTree( T^.Left, T1^.Left );
CopyTree( T^.Right, T1^.Right )
Постановка задачи. Составить программу калькулятор.
Листинг программы
program Kalkulator;
M:array[1..50] of string;
j,i,n:integer;
s,s1,s2,s3:string;
x,y:real;
writeln('BBeDi OPeRAciy');
readln(s);
n:=length(s);
for i:=0 to n-1 do
M[i]:=copy(s,i,1);
if (m[i]='+')or(m[i]='-')or(m[i]='*')or(m[i]='/') then j:=i;
s1:=copy(s,0,j-1);
s2:=copy(s,j,1);
s3:=copy(s,j+1,n);
val(s1,x,n);
val(s3,y,n);
if s2='+' then writeln(x+y:4:1);
if s2='-' then writeln(x-y:4:1);
if s2='*' then writeln(x*y:4:1);
if s2='/' then writeln(x/y:4:1);
readln;
end.
Блок-схема
Пояснение к блок-схеме
№ блока
Назначение
1
Начало программы
2
Ввод/вывод данных
3
Выполнение операции N:=length(s)
4
Цикл i:=0 to n-1
5
Тело цикла, выполнение операции M[i]:=copy(s,i,1)
6
Тело цикла, условие (m[i]=’+’) or (m[i]=’-‘) or (m[i]=’*’) or m[i]=’/’)
7
Тело цикла выполнение операции j:=i
8
Выполнение операции s1:=copy (s,o,j-1); s2:=copy (s,j,1); s3:=copy (s,j+1,n)
9
Выполнение операции val(s1,x,n); val(s3,y,n)
10
Блок условия s2=’+’
11
Ввод/вывод данных x+y
12
Блок условия s2=’-‘
13
Ввод/вывод данных x-y
14
Блок условия s2=’*’
15
Ввод/вывод данных x*y
16
Блок условия s2=’/’
17
Ввод/вывод данных x/y
18
Конец программы
Протокол программы
BBeDi OPeRaciy
56*9
504,0
Постановка задачи. Составить программу которая, сортирует буквы латинского алфавита по алфавиту.
program Alfavit;
b:boolean;
s,tmp:string;
writeln('BBeDu TekcT');
b:=true;
while b do
b:=false;
for i:=1 to n-1 do
if m[i] > m[i+1] then
tmp:= m[i];
m[i]:=m[i+1];
m[i+1]:=tmp;
for i:=0 to n-1 do begin;
write(m[i],' ');
Ввод/вывод данных n:=length(s)
Тело цикла M:=copy(s,i,1)
Выполнение операции b:=true
Выполнение операции b:=false
Цикл i:=1 to n-1
Тело цикла, условие m[i]>m[i+1]
Выполнение операции tmp:=m[i]; m[i]:=m[i+1]; m[i+1]:=tmp; b:=true
Цикл i:=o to n-1
Ввод/вывод данных m[i]
BBeDu TekcT
abrakadabra
aaaaabbdkr
Рис. 1. Линейный список (связанный список)
Рис. 2. Двунаправленный список
Рис. 3. Однонаправленный циклический список.
Рис. 4. Двунаправленный циклический список.
Рис. 5. Организация дека на основе линейного списка.
Рис. 6. Организация стека на основе линейного списка.
Рис. 7. Представление бинарного дерева в виде списковой структуры.
1. Рапаков Г. Г. и Ржецукая С. Ю.. Turbo Pascal для студентов и школьников. BHV – С.-Петербург 2004
2. Меженный О. А. Turbo Pascal: учитель программирования. Диалектива 2001.
3. Культин Н.. Программирование в Turbo Pascal и Delphi. BHV 2003
4. Фаронов В. В. Turbo Pascal: учебное пособие. BHV 2006
Страницы: 1, 2, 3, 4, 5