Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции Delphi (Колосов).pdf
Скачиваний:
77
Добавлен:
11.05.2015
Размер:
2.57 Mб
Скачать

End else If p^.PL1=nil then Begin// Удалять нужно последний элемент

P^.PL2^.PL1:=nil;

// Второй элемент очереди теперь не должен иметь впереди стоящего

Dispose(P);

// Освобождаем память

P:=pt;

// Возвращаем указатель на конец очереди

S:=’’;

// Строку поиска полагаем равной пустой строке

End else Begin

// Удалять нужно средний элемент очереди

p^.PL2^.PL1:=p^.PL1; // В сзади стоящем элементе очереди записыва– // ем указатель на впереди стоящий элемент

p^.PL1^.PL2:=p^.PL2;

// Во впереди стоящем элементе записываем

// указатель на новый, сзади стоящий элемент очереди

dispose(p);

// Освобождаем память

s:=’’;

// Очищаем строку поиска

p:=pt;

// Возвращаем указатель на конец очереди

end;

 

 

End;

// Закончили блок удаления элемента очереди

//Выходим из процедуры, если был удален элемент очереди

If s:=’’ then exit;

P:=p^.PL1; // Переходим на просмотр впереди стоящего элемента очереди End; // Конец цикла просмотра элементов очереди

End;

16.4. Работа с деревьями

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

Прародитель всех узлов называется корнем дерева. Узлы, не имеющие дочерних узлов, называются листьями. Промежуточные узлы называются ветвями. Степень дерева – максимальный порядок его узлов. Глубина дерева – это максимальная глубина его узлов.

Древовидное размещение списка данных (abcdefgkl) можно изобразить, например, следующим образом:

 

 

а

 

Корневой узел (корень)

 

b

c

 

Узлы второго уровня

d

e

f

g

d, e, g, k, l листья

k l

Рис.16.3. Структура дерева Дерево, представленное выше, имеет степень 3 (троичное), глубину 4, корневой узел а.

Для работы, например, с двоичным деревом можно определить следующие типы:

74

Type Tpz=^Tz; // Указатель на запись Tz=Record // Запись узла дерева

Inf:string; // Информационная часть узла дерева Kl:integer; // Уникальный ключ узла дерева P1,P2:Tpz; // Указатели на дочерние узлы дерева

End;

Для работы с деревьями в основном используют рекурсивные процедуры

процедуры, которые вызывают сами себя. Они позволяют проходить по всему дереву только по одному вызову таких процедур.

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

Компонент TTreeView предназначен для отображения ветвящихся иерархических структур в виде горизонтальных деревьев, например каталогов файловой системы дисков. Основным свойством этого компонента является Items, которое представляет собой массив элементов типа TTreeNode, каждый из которых описывает один узел дерева. Всего в Items – count узлов. Рассмотрим некоторые методы класса TTreeNodes:

Function AddFirst(Node:TTreeNode; const S:String):TTreeNode; – этот метод создает первый дочерний узел у узла Node. Если Node=Nil, то создается корневой узел. S – это строка содержания узла. Функция возвращает указатель на созданный узел;

Function AddChild(Node:TTreeNode; const S:String):TTreeNode; – эта функция добавляет очередной дочерний узел к узлу Node;

Procedure Clear; – этот метод очищает список узлов, описанных в свойстве Items;

Function DisplayRect(TextOnly: Boolean): TRect; – позволяет получить прямоугольник на канве компонента TTreeView, в котором описан текст узла TTreeNode, если аргумент TextOnly равен «True», иначе весь прямоугольник узла.

Вкачестве примера рассмотрим проект, который создает дерево, отображает его в компоненте TTreeView, находит узел по ключу и может очистить дерево. На форме будут располагаться: Button1 – для создания дерева, Button2 – для удаления дерева, Button3 – для поиска узла по ключу и TTreeView

для графического отображения дерева:

unit U1; // Текст модуля interface

// подключаемые модули uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, ComCtrls;

Type // Класс формы

TForm1 = class(TForm) Button1: TButton;

75

TreeView1: TTreeView; Button2: TButton; Button3: TButton;

procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private

{Private declarations } public

{Public declarations } end;

Type Tpz=^Tz;

// Тип указателя на запись

Tz=Record

// Определение типа записи узла дерева

Inf:string;

// Информационная часть узла

kl:integer;

// Ключ узла дерева

pl,pr:tpz;

// Указатели на исходящие ветви узла дерева

end;

var Form1: TForm1;

Proot:Tpz; // Указатель на корень дерева Level:integer; // Уровень узла дерева

Kluch:integer;// Ключ узла дерева

skluch:string; // Строка ключа узла дерева при поиске sitem:string; // Строка информационной части узла при поиске

implementation {$R *.dfm}

//Рекурсивная процедура создания и отображения дерева в TreeView

Procedure CreateTree(var p,ppar:Tpz);

//p – Указатель на текущий узел дерева

//ppar – Указатель на родительский узел дерева

var pt1:Tpz; // Временный указатель на узел дерева

Begin with form1 do Begin inc(level);

//При входе в процедуру увеличиваем уровень узла if p=nil then Begin

//Если p=nil, то можно создать новый узел

//С помощью типового диалога решаем, создавать ли узел дерева case messagedlg(’Создать новый элемент дерева уровня’

+’ ’+inttostr(level)+’ с ключом ’+inttostr(Kluch+1), mtConfirmation,[mbok,mbno],0) of

mrok:Begin // Создаем новый узел new(pt1); // Выделяем узлу память

//С помощью типового диалога вводим информацию в узел pt1^.Inf:=inputbox('Ввод инф. части дерева',

76

'Введите текст элемента дерева','');

inc(kluch); // Увеличиваем номер узла на единицу pt1^.kl:=kluch; // Запоминаем этот номер, как ключ pt1^.pl:=nil;

//Записываем nil для дочернего левого узла pt1^.pr:=nil;

//Записываем nil для дочернего правого узла

//Если kluch=1, т.е. это корень дерева, то используем метод

//AddFirst для отображения этого узла, иначе метод AddChild

if kluch=1 then Treeview1.Items.AddFirst(nil,Pt1^.inf+ ’ ’+inttostr(kluch))

else Treeview1.Items.Addchild(treeview1.Items[ppar^.kl-1], Pt1^.inf+’ ’+inttostr(kluch));

Treeview1.FullExpand;

// Раскрываем все дерево

createtree(pt1.pl,pt1); // Создаем левую ветвь дерева createtree(pt1.pr,pt1); // Создаем правую ветвь дерева p:=pt1;

// Программа будет возвращать указатель на новый узел дереваend; mrno:Begin // В случае ответа «нет», ничего не делаем

end;

end;

end;

dec(level);

// При выходе из подпрограммы уменьшаем текущий уровень узла дерева end;

end;

//Обработчик нажатия кнопки "Создать дерево" procedure TForm1.Button1Click(Sender: TObject); begin

createtree(proot,proot);

end;

//Отработчик события создания формы

procedure TForm1.FormCreate(Sender: TObject); begin

Proot:=nil; // Указатель на корень дерева полагаем равным константе nil Level:=0; // Текущий уровень узла дерева зануляем

Kluch:=0; // Текущий номер узла дерева зануляем end;

//Процедура освобождения памяти для дерева

Procedure DeleteTree(var p:Tpz);

//Здесь P указатель на удаляемую ветвь дереваBegin

77

If p=nil then exit;

if ((p^.pl=nil)and(p^.pr=nil))then Begin

//Если у узла нет дочерних узлов, то его можно удалить

Dispose(p);

p:=nil;

exit;

end;

//Если у узла есть дочерние узлы, то следует сначала их удалить

//с помощью программы DeleteTree

if p^.pl<>nil then deleteTree(p^.pl); if p^.pr<>nil then deleteTree(p^.pr); end;

//Обработчик нажания кнопки «Удалить дерево» procedure TForm1.Button2Click(Sender: TObject); begin

//Удаляем дерево с корневого узла

DeleteTree(proot);

proot:=nil;

level:=0;

kluch:=0;

//Очищаем компонент TreeView

TreeView1.Items.Clear;

end;

//Процедура поиска в дереве узла с заданным ключом

Procedure SeekTree(var p:Tpz;s:string);

//Здесь P указатель на узел дерева

//S искомый ключ узла дерева

var i:integer; Begin

if p=nil then exit;

if s=inttostr(p^.kl) then Begin skluch:=s;

sitem:=p^.inf;

end;

if p^.pr<>nil then seektree(p^.pr,s); if p^.pl<>nil then seektree(p^.pl,s); end;

// Обработчик нажатия кнопки "Поиск узла" procedure TForm1.Button3Click(Sender: TObject); var s:String;

rect1:Trect; // Прямоугольник для узла дерева Color1:Tcolor; // Цвет шрифта узла дерева

78

begin skluch:=''; sitem:='';

s:=Inputbox('Поиск узла', 'Введите ключ искомого узла',''); if length(s)>0 then Begin

SeekTree(Proot,s); // Ищем узел с ключом s

if length(skluch)>0 then with treeview1 do Begin

// Отметим красным цветом найденный узел for i:=0 to items.count-1 do Begin

if pos(s,items[i].text)>0 then Begin rect1:=items[i].DisplayRect(true); color1:=canvas.font.color; canvas.font.Color:=clred; canvas.FillRect(rect1);

canvas.

TextOut(rect1.Left,rect1.Top,items[i].text);

canvas.Font.Color:=color1;

break;

end; end

Showmessage('Найден узел с ключом ' +skluch+' и полем inf='+sitem)

else Showmessage('Узла с ключом '+skluch+ ' нет в дереве!');

end;

end;

end.

79