Реализация древовидной структуры
1. Элемент дерева, как и элемент списка, представляет собой запись, содержащую информационные поля и адресные поля. В случае двоичного дерева это адреса левого и правого поддеревьев
Type Uk=^Tree;
Tree=record
Inf:integer;
Left, right:Uk;
End;
Для работы с деревом, расположенным в динамической области, необходим по крайней мере один указатель – указатель на корень дерева (Root).
2. Процедуры обработки деревьев:
· Поиск элемента в дереве;
· Добавление элемента в дерево;
· Удаление элемента из дерева;
· Обход дерева.
Рассмотрим основные процедуры обработки дерева. В начале программы следует сделать инициализацию дерева:
procedure Init(var root:Uk);
begin
root:=nil;
end;
Добавление элемента в деревосостоит из трех шагов:
· создание вершины (выделение области памяти, заполнение информационных и адресных полей),
· поиск вершины, к которой можно присоединить новую вершину, не нарушая правила построения дерева,
· присоединение вершины, т.е. организация связи между родительской вершиной и вставляемой вершиной.
Основное назначение двоичного дерева поиска поиск данных.
Function Poisk (var root:Uk; a:integer):Uk;
{а- искомое значение}
Begin
p:=root;
while (p<>nil) and (p^.inf<>a) do
if a<p^.inf then p:=p^.left
else p:=p^.right;
Poisk:=p;
End;
Данная функция поиска возвращает адрес найденного элемента или нулевой адрес, если искомого элемента в дереве нет.
2.3 Удаление вершины
Непосредственное удаление вершины реализуется в зависимости от того, какая вершина удаляется:
§ Удаляемая вершина не содержит поддеревьев (лист). При этом удаляется ссылка на удаляемую вершину из родительской вершины.
§ Удаляемая вершина содержит одну ветвь. Для удаления необходимо скорректировать соответствующую ссылку в родительской вершине, заменив адрес удаляемой вершины адресом вершины, из нее исходящей.
§ Удаляемая вершина содержит две ветви. В этом случае нужно найти подходящую вершину, которую можно вставить на место удаляемой, причем эта вершина должна легко перемещаться. Такая вершина всегда существует: либо это самый правый элемент левого поддерева, либо – самый левый элемент правого поддерева.
Procedure Delete(var r:Uk; a:integer);
{r-указатель на корень, а - искомое значение }
{внутренняя процедура поиска заменяющей вершины в левом поддереве}
Procedure DEL(var r:Uk; q:Uk);
{r- адрес корня левого поддерева, q- адрес заменяемой вершины }
Var q1:Uk;
Begin
if r^.right=nil then {заменяющая вершина найдена}
begin
q^.inf:=r^.inf; {копируем значение}
q1:=r;
r:=r^.left; {запоминаем адрес левого поддерева}
dispose(q1); {удаляем заменяющую вершину}
end
else DEL(r^.right,q); {идем на правое поддерево}
End;
Var q:Uk;
Begin
if r=nil then writeln('элемент не найден')
else {поиск элемента с заданным ключом}
if a<r^.inf then {если меньше, то налево}
DELETE(r^.left,a)
else
if a>r^.inf then {если больше, то направо}
DELETE (r^.right,a)
else
begin
{удаление листа или корня с одним поддеревом}
if r^.right=nil then
{нет правого поддерева}
begin
q:=r;
r:=r^.left;
dispose(q);
end
else
if r^.left=nil then {нет левого поддерева}
begin
q:=r;
r:=r^.right;
dispose(q);
end
else
{удаление корня с двумя поддеревьями}
DEL(r^.left,r);
end;
end;
2.4 Удаление всего дерева. Для высвобождения памяти дерево удаляется целиком. Для этого используется обход дерева снизу вверх Postorder.
Procedure Del_tree (var beg:Uk);
Begin
If beg<>nil then begin
Del_tree(beg^.left)
Del_tree(beg^.right);
Dispose(beg);
Beg:=nil;
End;
End;
Устройство программы
Итак, наша программа начинается с названия – Цветочный магазин. Я не стал ее называть по-другому, так как название программы должно отображать задание. После названия обязательно нужно объявить тип запись, так как элемент дерева, как и элемент списка, представляет собой запись, содержащую информационные поля и адресные поля. В нашем случае представлено именно дерево поиска, следовательно, в двоичном дереве это адреса левого и правого поддеревьев. Все это выполняется вот так:
type uk=^derev;
derev=record
inf:string;
cen:integer;
cena:integer;
im:string;
l,r:uk;
spisok:ukaz;
end;
Далее, в разделе переменных Var мы объявляем все переменные, которые будут задействованы в нашей программе:
var root:uk;
Затем мы делаем очень важную процедуру, которую необходимо сделать в самом начале нашей программы – Инициализация дерева:
Procedure Init(var root:Uk);
begin
root:=nil;
end;
Затем мы приступаем к основным задачам программы. К ним относится – Поиск по названию цветка:
procedure poisk_imja(var p:uk);
var g:ukaz;
begin
if p<> nil then
begin
poisk_imja(p^.r);
g:=p^.spisok;
while g<>nil do
begin
if g^.imja=s then
begin
writeln(g^.imja:3);
writeln(g^.strana:3);
writeln(g^.koli4estvo:3);
writeln(g^.cena:3);
fl:=true;
end;
g:=g^.next;
end;
poisk_imja(p^.l) ;
if fl=false then writeln(' Такого Цветка Нет !');
if s<p^.im then poisk_imja(p^.l)
else poisk_imja(p^.r);
end;
end;
Поиск по стране поставщику:
procedure poisk_strana(var p:uk);
var g:ukaz;
begin
if p<> nil then
begin
poisk_strana(p^.r);
g:=p^.spisok;
while g<>nil do
begin
if g^.strana=f then
begin
writeln(g^.imja:3);
writeln(g^.strana:3);
writeln(g^.koli4estvo:3);
writeln(g^.cena:3);
fl:=true;
end;
g:=g^.next;
end;
poisk_strana(p^.r);
end;
if fl=false then writeln(' Из Такой Страны Цветов Нет !');
end;
Поиск по цене цветов в магазине:
procedure poisk_cena(p:uk);
var g:ukaz;
begin
if p<> nil then
begin
poisk_cena(p^.l);
g:=p^.spisok;
while g<>nil do
begin
if g^.cena=k then
begin
writeln(p^.im);
writeln(g^.imja:3);
writeln(g^.strana:3);
writeln(g^.koli4estvo:3);
writeln(g^.cena:3);
fl:=true;
end;
g:=g^.next;
end;
poisk_cena(p^.r);
end;
if fl=false then writeln(' По Такой Цене Цветов Нет !'); end;
Поиск по наличию цветов в магазине:
procedure poisk_koli4estvo(p:uk);
var g:ukaz;
koli4estvo:integer;
begin
if p<> nil then
begin
poisk_koli4estvo(p^.l);
g:=p^.spisok;
while g<>nil do
begin
if g^.koli4estvo=m then
begin
writeln(g^.imja:3);
writeln(g^.strana:3);
writeln(g^.koli4estvo:3);
writeln(g^.cena:3);
fl:=true;
end;
g:=g^.next;
end;
poisk_koli4estvo(p^.r);
end;
if fl=false then writeln('Столько Цветов Нет !');
end;
Затем мы делаем обход дерева, чтобы наши записи были не спутаны и отсортированы. Дерево, в нашем случае, мы обойдем с помощью обхода:
Сверху вниз (preorder): вершина, левое поддерево, правое поддерево.
Procedure PREORDER(var p:Uk);
Begin
if p<>nil then
begin
writeln(p^.inf);
PREORDER(p^.l);
PREORDER(p^.r);
end;
End;
Так же, мы позаботились и о том, чтобы вывести наше дерево на экран монитора, но не просто вывести, а вывести: По цене цветов, по их названию, по количеству штук, по стране поставщику.
procedure vivod(p:uk);
var g:ukaz;
begin
if p<>nil then
begin
vivod(p^.r);
g:=p^.spisok;
writeln(p^.im);
while g<>nil do
begin
writeln(g^.imja:5);
writeln(g^.strana:5);
writeln(g^.cena:5);
writeln(g^.koli4estvo:5);
g:=g^.next;
end;
vivod(p^.r);
end;
end;
begin
writeln(' Вывод По Цене --- ');
readln(k);
poisk_cena(root);
writeln(' Вывод По Имени --- ');
readln(s);
poisk_imja(root);
writeln(' Вывод По Количеству Штук --- ');
readln(m);
poisk_koli4estvo(root);
writeln(' Вывод По Стране --- ');
readln(f);
poisk_strana(root);
end;
Так же, есть и вывод в файл для простоты и удобства действий:
procedure vivod_v_fail(p:uk);
var g:ukaz;
begin
if p<>nil then
begin
vivod_v_fail(p^.l);
g:=p^.spisok;
while g<>nil do
begin
writeln(x,g^.imja:3);
writeln(x,g^.strana:3);
writeln(x,g^.koli4estvo:3);
writeln(x,g^.cena:3);
g:=g^.next;
end;
vivod_v_fail(p^.r);
end;
end;
Теперь, разложив программу на составляющие части, мы делаем меню и подменю нашей программы:
procedure menu1;
begin
writeln( ' МЕНЮ : ');
writeln(' 1 Добавление Новой Записи');
writeln(' 2 Поиск');
writeln(' 3 Редактирование ');
writeln(' 4 Вывод ');
writeln(' 5 Сохранение В Файл ');
writeln(' 6 Сохранение Базы ');
end;
procedure podmenu;
begin
writeln(' 1 поиск по имени');
writeln(' 2 поиск по стране');
writeln(' 3 поиск по цене');
writeln(' 4 поиск по количеству');
end;
procedure podmenu2;
begin
writeln('1 - Введите имя цветка');
poisk_imja(root);
writeln(' 2 - Введите количество штук');
poisk_koli4estvo(root);
end;
Доделываем необходимые действия и всё - наша программа готова! Вот так, подробно разработав, описав и разобрав наш магазин, мы создали этот мини-шедевр.
Листинг программы
Program Cvetochny_Magazin;
uses crt;
type ukaz=^spisok;
spisok=record
imja:string;
strana:string;
cena,koli4estvo:integer;
next:ukaz;
end;
type uk=^derev;
derev=record
inf:string;
cen:integer;
cena:integer;
im:string;
l,r:uk;
spisok:ukaz;
end;
var root:uk;
p:ukaz;
a,m:integer;
k:byte;
f,s:string;
fl:boolean;
x:text;
procedure Init(var root:Uk);
begin
root:=nil;
end;
procedure add_1(var temp:uk);
var w:ukaz;
begin
new(w);
with w^ do
begin
write(' Введите Имя Цветка ---> ');
readln(imja);
write(' Введите Страну ---> ');
readln(strana);
write( ' Введите Цену ---> ');
readln(cena);
write( ' Введите Количество Штук ---> ');
readln(koli4estvo);
next:=nil;
end;
if temp^.spisok=nil then
temp^.spisok:=w
else
begin
w^.next:=temp^.spisok;
temp^.spisok:=w;
end;
end;
procedure add(var root:uk);
var p,p1,w:uk;
n:integer;
begin
new(w);
with w^ do
begin
spisok:=nil;
l:=nil;
r:=nil;
end;
read(n);
while n=1 do
begin
add_1(w);
readln(n);
end;
if root=nil then root:=w
else
begin
p:=root;
while p<>nil do
begin
p1:=p;
if w^.cen<p^.cen then p:=p^.l
else p:=p^.r;
end;
if w^.cena<p1^.cena then p1^.l:=w
else p1^.r:=w;
end;
end;
procedure poisk_imja(var p:uk);
var g:ukaz;
begin
if p<> nil then
begin
poisk_imja(p^.r);
g:=p^.spisok;
while g<>nil do
begin
if g^.imja=s then
begin
writeln(g^.imja:3);
writeln(g^.strana:3);
writeln(g^.koli4estvo:3);
writeln(g^.cena:3);
fl:=true;
end;
g:=g^.next;
end;
poisk_imja(p^.l) ;
if fl=false then writeln(' Такого Цветка Нет !');
if s<p^.im then poisk_imja(p^.l)
else poisk_imja(p^.r);
end;
end;
procedure poisk_strana(var p:uk);
var g:ukaz;
begin
if p<> nil then
begin
poisk_strana(p^.r);
g:=p^.spisok;
while g<>nil do
begin
if g^.strana=f then
begin
writeln(g^.imja:3);
writeln(g^.strana:3);
writeln(g^.koli4estvo:3);
writeln(g^.cena:3);
fl:=true;
end;
g:=g^.next;
end;
poisk_strana(p^.r);
end;
if fl=false then writeln(' Из Такой Страны Цветов Нет !');
end;
procedure poisk_cena(p:uk);
var g:ukaz;
begin
if p<> nil then
begin
poisk_cena(p^.l);
g:=p^.spisok;
while g<>nil do
begin
if g^.cena=k then
begin
writeln(p^.im);
writeln(g^.imja:3);
writeln(g^.strana:3);
writeln(g^.koli4estvo:3);
writeln(g^.cena:3);
fl:=true;
end;
g:=g^.next;
end;
poisk_cena(p^.r);
end;
if fl=false then writeln(' По Такой Цене Цветов Нет !');
end;
procedure poisk_koli4estvo(p:uk);
var g:ukaz;
koli4estvo:integer;
begin
if p<> nil then
begin
poisk_koli4estvo(p^.l);
g:=p^.spisok;
while g<>nil do
begin
if g^.koli4estvo=m then
begin
writeln(g^.imja:3);
writeln(g^.strana:3);
writeln(g^.koli4estvo:3);
writeln(g^.cena:3);
fl:=true;
end;
g:=g^.next;
end;
poisk_koli4estvo(p^.r);
end;
if fl=false then writeln('Столько Цветов Нет !');
end;
Procedure PREORDER(var p:Uk);
Begin
if p<>nil then
begin
writeln(p^.inf);
PREORDER(p^.l);
PREORDER(p^.r);
end;
End;
procedure vivod(p:uk);
var g:ukaz;
begin
if p<>nil then
begin
vivod(p^.r);
g:=p^.spisok;
writeln(p^.im);
while g<>nil do
begin
writeln(g^.imja:5);
writeln(g^.strana:5);
writeln(g^.cena:5);
writeln(g^.koli4estvo:5);
g:=g^.next;
end;
vivod(p^.r);
end;
end;
procedure vivod_v_fail(p:uk);
var g:ukaz;
begin
if p<>nil then
begin
vivod_v_fail(p^.l);
g:=p^.spisok;
while g<>nil do
begin
writeln(x,g^.imja:3);
writeln(x,g^.strana:3);
writeln(x,g^.koli4estvo:3);
writeln(x,g^.cena:3);
g:=g^.next;
end;
vivod_v_fail(p^.r);
end;
end;
procedure menu1;
begin
writeln( ' МЕНЮ : ');
writeln(' 1 Добавление Новой Записи');
writeln(' 2 Поиск');
writeln(' 3 Вывод Базы ');
writeln(' 4 Сохранение В Файл ');
writeln(' 5 Выход ');
end;
procedure podmenu;
begin
writeln(' 1 поиск по имени');
writeln(' 2 поиск по стране');
writeln(' 3 поиск по цене');
writeln(' 4 поиск по количеству');
end;
begin
fl:=false;
repeat
menu1;
readln(a);
case a of
1:add(root);
2:begin
repeat
podmenu;
readln(a);
case a of
1:begin
writeln(' Введите Имя Цветка ---> ');
readln(s);
poisk_imja(root);
preorder(root);
end;
2:begin
writeln(' Введите Страну ---> ');
readln(f);
poisk_strana(root);
end;
3:begin
writeln(' Введите Цену ---> ');
poisk_cena(root);
readln(k);
end;
4:begin
writeln(' Введите Количество ---> ');
poisk_koli4estvo(root);
readln(m);
end;
end;
until a>4;
end;
3:begin
writeln(' Вывод По Цене: Введите Цену --- ');
readln(k);
poisk_cena(root);
writeln(' Вывод По Имени: ВВедите Название Цветка --- ');
readln(s);
poisk_imja(root);
writeln(' Вывод По Количеству Штук: ВВедите Количество Цветов --- ');
readln(m);
poisk_koli4estvo(root);
writeln(' Вывод По Стране: ВВедите Страну --- ');
readln(f);
poisk_strana(root);
end;
4:begin
assign(x,' Цветочный Магазин.txt ');
rewrite(x);
vivod_v_fail(root);
close(x);
end;
5:vivod(root);
end;
until a=5;
end.
5. Протокол выполнения программы Главное Меню:
Добавление Новой Записи:
Поиск:
Вывод Базы:
Выход:
Список используемой литературы:
1. Г.С. Иванова. Основы программирования. М.: Издательство МГТУ им. Н.Э. Баумана. 2001 г.
2. А.в. Могилев, Н.И. Пак, Е.К. Хеннер. Информатика: Учеб. пособие.М.: Изд. Центр «Академия», 2000 г.
3. Информатика: Базовый курс / С.В. Симонович и др. – СПб.: Питер, 2001 г.
4. Климова Л.М. Pascal 7.0. Практическое программирование. Решение типовых задач. – М.: КУДИЦ-ОБРАЗ, 2000 г.