БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ
ИНФОРМАТИКИ И РАДИОЭЛЕКТРОНИКИ
Кафедра программного обеспечения информационных технологий
Факультет КСиС
Специальность ПОИТ
Индивидуальная практическая работа №2
по дисциплине «Структуры и алгоритмы обработки данных»
Выполнил студент: Бордон Е.С.
группа 991051
Зачетная книжка № 99105004
Минск 2020
Задание №1:
Ввести 10-15 целых чисел и построить из них с помощью указателей бинарное дерево поиска. Обойти его прямым, симметричным и обратным способами. Реализовать процедуры поиска, вставки и удаления элементов бинарного дерева поиска.
Программа реализована на языке Delphi в программной среде Lazarus.
Процедура добавления вершин в дерево:
type
TData = Integer; //Тип ключа (тип основных данных) узла дерева.
TPNode = ^TNode; //Тип указателя на узел.
TNode = record //Тип узла дерева.
Data : TData; //Ключ (основные данные) узла дерева.
PLeft, PRight : TPNode; //Указатели на левый и правый узел.
end;
{Добавление узла с ключом aData в двоичное дерево поиска.}
procedure AddNode(var aPNode : TPNode; const aData : TData);
begin
if aPNode = nil then //Вставка узла.
begin
New(aPNode); //Выделяем память для узла.
aPNode^.Data := aData; //Записываем в узел значение ключа.
aPNode^.PLeft := nil; //Обнуление указателя на левого потомка.
aPNode^.PRight := nil; //Обнуление указателя на правого потомка.
end
else if aData <= aPNode^.Data then //Поиск места вставки в левом поддереве.
AddNode(aPNode^.PLeft, aData)
else if aData > aPNode^.Data then //Поиск места вставки в правом поддереве.
AddNode(aPNode^.PRight, aData);
Процедура поиска вершины:
procedure TForm2.find(const aPNode : TPNode; const aName : String);
begin
if aPNode <> nil then
begin
if edit2.text = inttostr(aPNode^.Data) then
rez:=aName;
find(aPNode^.PLeft, aName + '1'); //Рекурсивный вызов для левого поддерева.
find(aPNode^.PRight, aName + '2'); //Рекурсивный вызов для правого поддерева.
end;
end;
procedure TForm2.Button5Click(Sender: TObject); // Поиск
begin
if edit2.text = '' then begin
showmessage ('Ошибка! Введите значение');
exit;
end;
if FPTree = nil then begin
showmessage ('Дерево пустое!');
exit;
end;
rez:='';
find (FPTree,'0'); // Поиск
if rez = '' then
Memo1.Lines.Add('Вершина: ' + edit2.text + '; Не найдена!')
else
Memo1.Lines.Add('Вершина: ' + edit2.text + '; Адрес: ' + rez);
edit2.clear;
end;
Рис 1. Скриншоты работы программы Задание 1
Листинг всей программы приведен в конце работ.
Задание №2:
Ввести 10-15 целых чисел и построить из них АВЛ-дерево. Выполнить операцию поиска указанных элементов в АВЛ-дереве.
Программа реализована на языке Delphi в программной среде Lazarus.
Процедура добавления и перестановки вершин:
procedure Add(x : Integer; var p : TPNode; var h : boolean);
begin
if (p = nil)
then
begin
new(p);
h := true;
p^.Data := x;
p^.Pleft := nil;
p^.Pright := nil;
p^.depth := 0;
end
else
if (x < p^.Data) then begin
Add(x, p^.Pleft, h);
if h then
case p^.depth of
1: begin
p^.depth := 0;
h := false;
end;
0: p^.depth:=-1;
-1: begin
if (p^.Pleft^.depth = -1) then
PrightTurn(p)
else
PrightPleftTurn(p);
p^.depth := 0;
h := false;
end;
end;
end
else
if (x > p^.Data) then
begin
Add(x, p^.Pright, h);
if h then
case p^.depth of
-1: begin
p^.depth := 0;
h := false;
end ;
0: p^.depth:=1;
1: begin
if (p^.Pright^.depth = 1) then
PleftTurn(p)
else
PleftPrightTurn(p);
p^.depth := 0;
h:= false;
end;
end;
end
else
h := false;
end;
procedure PrightTurn(var p : TPNode);
var
tmp : TPNode;
begin
tmp := p^.Pleft;
p^.Pleft := tmp^.Pright;
tmp^.Pright := p;
p^.depth := 0;
p := tmp;
end;
procedure PleftTurn(var p : TPNode);
var
tmp : TPNode;
begin
tmp := p^.Pright;
p^.Pright := tmp^.Pleft;
tmp^.Pleft := p;
p^.depth := 0;
p := tmp;
end;
procedure PrightPleftTurn(var p : TPNode);
var
tmp : TPNode;
t : TPNode;
begin
tmp := p^.Pleft;
t := tmp^.Pright;
tmp^.Pright := t^.Pleft;
t^.Pleft := tmp;
p^.Pleft := t^.Pright;
t^.Pright := p;
if (t^.depth = -1) then
p^.depth := 1 else
p^.depth := 0;
if (t^.depth = 1) then
tmp^.depth := -1 else
tmp^.depth := 0;
p := t;
end;
procedure PleftPrightTurn(var p : TPNode);
var
tmp : TPNode;
t : TPNode;
begin
tmp := p^.Pright;
t := tmp^.Pleft;
tmp^.Pleft := t^.Pright;
t^.Pright := tmp;
p^.Pright := t^.Pleft;
t^.Pleft := p;
if (t^.depth = 1) then
p^.depth := -1 else
p^.depth := 0;
if (t^.depth = -1) then
tmp^.depth := 1 else
tmp^.depth := 0;
p := t;
end;
Листинг всей программы приведен в конце работы.
Рис 2. Скриншот работы программы задание 2
Задание №3:
Представить ориентированный граф, состоящий из 7-10 вершин, с помощью матрицы смежности. Указать вершину-источник, а затем решить следующие задачи.
1. Кратчайшие пути от вершины-источника до всех вершин орграфа на основе алгоритма Дейкстры.
2. Кратчайшие расстояния между каждой парой вершин орграфа на основе алгоритма Флойда.
Программа реализована на языке Delphi в программной среде Lazarus.
Основные процедуры, задействованные в программе:
procedure Floid(n : integer);
var
k,i,j:integer;
begin
for k:=0 to n - 1 do
for i:=0 to n - 1 do
for j:=0 to n - 1 do
g[i,j] := Min(g[i,j], g[i,k] + g[k,j]);
end;
procedure Dijkstra(s : longint; n : longint);
var
i, bliz, x :integer;
begin
setlength(dist,Length(dist)+n);
setlength(done,Length(done)+n);
for i:=0 to n - 1 do
begin
dist[i] := maxlongint;
done[i] := false;
end;
dist[s] := 0;
for i:=0 to n - 1 do
begin
bliz := -1;
for x:=0 to n - 1 do
if ((not done[x]) and ((bliz = -1) or (dist[x] < dist[bliz]))) then bliz := x;
if dist[bliz] = maxlongint then break;
done[bliz] := true;
for x:=0 to n - 1 do
if (g[bliz,x] <> maxlongint)
then begin
if (dist[bliz] + g[bliz,x] < dist[x]) then dist[x] := dist[bliz] + g[bliz,x];
end;
end;
end;
Листинг всей программы приведен в конце работы.
Рис 3. Скриншот работы программы.
Листинг программы Задание 1:
unit Unit2;
{$mode objfpc}{$H+}
Interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
Menus;
type
//Тип ключа (тип основных данных) узла дерева.
TData = Integer;
//Тип указателя на узел.
TPNode = ^TNode;
//Тип узла дерева.
TNode = record
Data : TData; //Ключ (основные данные) узла дерева.
PLeft, PRight : TPNode; //Указатели на левый и правый узел.
end;
{ TForm2 }
TForm2 = class(TForm)
Button1: TButton;
Button2: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
Edit1: TEdit;
Edit2: TEdit;
Image1: TImage;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
MainMenu1: TMainMenu;
Memo1: TMemo;
MenuItem1: TMenuItem;
MenuItem2: TMenuItem;
PaintBox1: TPaintBox;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
procedure Edit1KeyPress(Sender: TObject; var Key: char);
procedure Edit2KeyPress(Sender: TObject; var Key: char);
procedure FormClose(Sender: TObject);
procedure Draw(aName : String);
procedure DrawText (aName, aPNode_date : String);
procedure MenuItem2Click(Sender: TObject);
procedure TreeFree(var aPNode : TPNode);
procedure AddNode(var aPNode : TPNode; const aData : TData);
procedure TreeWriteln(const aPNode : TPNode; const aName : String; aSL : TStrings);
procedure find(const aPNode : TPNode; const aName : String);
procedure Del_tree (var x : TPNode; y:integer);
private
public
FPTree : TPNode;
end;
var
Form2: TForm2;
rez:string;
Implementation
{$R *.lfm}
{ TForm2 }
//Процедура для освобождения памяти, занятой деревом. (Удаление дерева).
procedure TForm2.TreeFree(var aPNode : TPNode);
begin
if aPNode = nil then
Exit;
TreeFree(aPNode^.PLeft); //Рекурсивный вызов для освобождения памяти в левом поддереве.
TreeFree(aPNode^.PRight); //Рекурсивный вызов для освобождения памяти в правом поддереве.
Dispose(aPNode); //Освобождение памяти, занятой для текущего узла.
aPNode := nil; //Обнуление указателя на текущий узел.
end;
{Добавление узла с ключом aData в двоичное дерево поиска.}
procedure TForm2.AddNode(var aPNode : TPNode; const aData : TData);
begin
if aPNode = nil then //Вставка узла.
begin
New(aPNode); //Выделяем память для узла.
aPNode^.Data := aData; //Записываем в узел значение ключа.
aPNode^.PLeft := nil; //Обнуление указателя на левого потомка.
aPNode^.PRight := nil; //Обнуление указателя на правого потомка.
end
else if aData <= aPNode^.Data then //Поиск места вставки в левом поддереве.
AddNode(aPNode^.PLeft, aData)
else if aData > aPNode^.Data then //Поиск места вставки в правом поддереве.
AddNode(aPNode^.PRight, aData);
end;
procedure TForm2.TreeWriteln(const aPNode : TPNode; const aName : String; aSL : TStrings);
var
arrname: array of array of string;
i:integer;
begin
i:=0;
if aPNode <> nil then
begin
setlength(arrname,Length(arrname)+1,2);
arrname[i,0]:= aName;
arrname[i,1]:= IntToStr(aPNode^.Data);
inc(i);
aSL.Add(aName + ': ' + IntToStr(aPNode^.Data));
TreeWriteln(aPNode^.PLeft, aName + '1', aSL); //Рекурсивный вызов для левого поддерева.
TreeWriteln(aPNode^.PRight, aName + '2', aSL); //Рекурсивный вызов для правого поддерева.
end;
for i:=0 to Length(arrname)-1 do begin
Form2.Draw (arrname[i,0]);
Form2.DrawText (arrname[i,0], arrname[i,1]);
end;
arrname:=nil;
end;
procedure TForm2.Draw (aName : String); // Рисунок дерева
const
LevelHeight = 50;
var
s,s1:string;
i,x,y,dx:integer;
begin
PaintBox1.Canvas.Pen.Width:=3; // толщина линий
dx:= round(PaintBox1.Width / 5);
x:= round(PaintBox1.Width / 2);
y:=25;
s:='';
s1:='';
for i:=1 to length(aName) do begin
s:=copy(aName,i,1);
s1:=copy (aName,i-1,1);
if s='0' then begin
PaintBox1.Canvas.MoveTo(x,y);
end;
if s='1' then
begin
if s1='0' then
begin
x:= x-dx;
y:=y+LevelHeight;
dx:=round(dx/2);
PaintBox1.Canvas.lineTo(x,y) ;
PaintBox1.Canvas.Ellipse((x+(dx*2))-20,(y-LevelHeight)-20,(x+(dx*2))+20,(y-LevelHeight)+20);
PaintBox1.Canvas.Ellipse(x-20,y-20,x+20,y+20);
end;
if s1='1' then
begin
PaintBox1.Canvas.MoveTo(x,y);
x:= x-dx;
y:=y+LevelHeight;
dx:=round(dx/2);
PaintBox1.Canvas.lineTo(x,y);
PaintBox1.Canvas.Ellipse((x+(dx*2))-20,(y-LevelHeight)-20,(x+(dx*2))+20,(y-LevelHeight)+20);
PaintBox1.Canvas.Ellipse(x-20,y-20,x+20,y+20);
end;
if s1='2' then
begin
PaintBox1.Canvas.MoveTo(x,y);
x:= x-dx;
y:=y+LevelHeight;
dx:=round(dx/2);
PaintBox1.Canvas.lineTo(x,y);
PaintBox1.Canvas.Ellipse((x+(dx*2))-20,(y-LevelHeight)-20,(x+(dx*2))+20,(y-LevelHeight)+20);
PaintBox1.Canvas.Ellipse(x-20,y-20,x+20,y+20);
end;
end;
if s='2' then
begin
if s1='0' then
begin
x:= x+dx;
y:=y+LevelHeight;
dx:=round(dx/2);
PaintBox1.Canvas.lineTo(x,y) ;
PaintBox1.Canvas.Ellipse((x-(dx*2))-20,(y-LevelHeight)-20,(x-(dx*2))+20,(y-LevelHeight)+20);
PaintBox1.Canvas.Ellipse(x-20,y-20,x+20,y+20);
end;
if s1='1' then
begin
PaintBox1.Canvas.MoveTo(x,y);
x:= x+dx;
y:=y+LevelHeight;
dx:=round(dx/2);
PaintBox1.Canvas.lineTo(x,y);
PaintBox1.Canvas.Ellipse((x-(dx*2))-20,(y-LevelHeight)-20,(x-(dx*2))+20,(y-LevelHeight)+20);
PaintBox1.Canvas.Ellipse(x-20,y-20,x+20,y+20);
end;
if s1='2' then
begin
PaintBox1.Canvas.MoveTo(x,y);
x:= x+dx;
y:=y+LevelHeight;
dx:=round(dx/2);
PaintBox1.Canvas.lineTo(x,y);
PaintBox1.Canvas.Ellipse((x-(dx*2))-20,(y-LevelHeight)-20,(x-(dx*2))+20,(y-LevelHeight)+20);
PaintBox1.Canvas.Ellipse(x-20,y-20,x+20,y+20);
end;
end;
end;
end;
procedure TForm2.DrawText (aName, aPNode_date : String); // Рисунок TEXT на дереве
const
LevelHeight = 50;
var
s,s1:string;
i,x,y,dx:integer;
begin
PaintBox1.Canvas.Font.Size := 8;
PaintBox1.Canvas.Font.Name := 'courier';
dx:= round(PaintBox1.Width / 5);
x:= round(PaintBox1.Width / 2);
y:=25;
s:='';
s1:='';
if length(aName) = 1 then begin
PaintBox1.Canvas.Ellipse(x-20,y-20,x+20,y+20);
PaintBox1.Canvas.TextOut(x-5,y-5,aPNode_date);
end;
for i:=1 to length(aName) do begin
s:=copy(aName,i,1);
s1:=copy (aName,i-1,1);
if s='1' then
begin
if s1='0' then
begin
x:= x-dx;
y:=y+LevelHeight;
dx:=round(dx/2);
if i = length(aName) then
PaintBox1.Canvas.TextOut(x-5,y-5,aPNode_date);
end;
if s1='1' then
begin
x:= x-dx;
y:=y+LevelHeight;
dx:=round(dx/2);
if i = length(aName) then
PaintBox1.Canvas.TextOut(x-5,y-5,aPNode_date);
end;
if s1='2' then
begin
x:= x-dx;
y:=y+LevelHeight;
dx:=round(dx/2);
if i = length(aName) then
PaintBox1.Canvas.TextOut(x-5,y-5,aPNode_date);
end;
end;
if s='2' then
begin
if s1='0' then
begin
x:= x+dx;
y:=y+LevelHeight;
dx:=round(dx/2);
if i = length(aName) then
PaintBox1.Canvas.TextOut(x-5,y-5,aPNode_date);
end;
if s1='1' then
begin
x:= x+dx;
y:=y+LevelHeight;
dx:=round(dx/2);
if i = length(aName) then
PaintBox1.Canvas.TextOut(x-5,y-5,aPNode_date);
end;
if s1='2' then
begin
x:= x+dx;
y:=y+LevelHeight;
dx:=round(dx/2);
if i = length(aName) then
PaintBox1.Canvas.TextOut(x-5,y-5,aPNode_date);
end;
end;
end;
end;
procedure TForm2.MenuItem2Click(Sender: TObject); // Задание
begin
Showmessage(' Ввести 10-15 целых чисел и построить из них с помощью ука'+
'зателей бинарное дерево поиска. Обойти его прямым, симметричным и об'+
'ратным способами. Реализовать процедуры поиска, вставки и удаления эле'+
'ментов бинарного дерева поиска.');
end;
procedure TForm2.Button1Click(Sender: TObject); //Добавление узла в дерево.
var
Data : TData;
begin
if TryStrToInt(Edit1.Text, Data) then
begin
AddNode(FPTree, Data);
Label1.Caption := IntToStr(Data);
end
else
begin
Showmessage('Ошибка! Введите целое число');
Label1.Caption := 'Ошибка!';
end;
edit1.clear;
end;
procedure TForm2.Button2Click(Sender: TObject); //Распечатка дерева.
begin
Memo1.Lines.Add('-----');
Memo1.Lines.Add('Дерево:');
if FPTree = nil then
Memo1.Lines.Add('Дерево пустое.')
else
TreeWriteln(FPTree, '0', Memo1.Lines);
end;
procedure TForm2.Button4Click(Sender: TObject); // очистить дерево
begin
TreeFree(FPTree); //Освобождение памяти, занятой для элементов дерева (очистка дерева).
Memo1.clear;
Memo1.Lines.Add('Память, выделенная для дерева - освобождена.');
PaintBox1.Invalidate; // Очищает рисунок фон оставляет прозрачным
end;
procedure TForm2.find(const aPNode : TPNode; const aName : String);
begin
if aPNode <> nil then
begin
if edit2.text = inttostr(aPNode^.Data) then
rez:=aName;
find(aPNode^.PLeft, aName + '1'); //Рекурсивный вызов для левого поддерева.
find(aPNode^.PRight, aName + '2'); //Рекурсивный вызов для правого поддерева.
end;
end;
procedure TForm2.Button5Click(Sender: TObject); // Поиск
begin
if edit2.text = '' then begin
showmessage ('Ошибка! Введите значение');
exit;
end;
if FPTree = nil then begin
showmessage ('Дерево пустое!');
exit;
end;
rez:='';
find (FPTree,'0'); // Поиск
if rez = '' then
Memo1.Lines.Add('Вершина: ' + edit2.text + '; Не найдена!')
else
Memo1.Lines.Add('Вершина: ' + edit2.text + '; Адрес: ' + rez);
edit2.clear;
end;
procedure TForm2.Button6Click(Sender: TObject); // Удалить вершину
begin
if edit2.text = '' then begin
showmessage ('Ошибка! Введите значение');
exit;
end;
if FPTree = nil then begin
showmessage ('Дерево пустое!');
exit;
end;
find (FPTree,'0'); // Поиск
if rez = '' then begin
Memo1.Lines.Add('Вершина: ' + edit2.text + ' - Не найдена!');
exit
end
else begin
Memo1.Lines.Add('-----');
Memo1.Lines.Add('Вершина: ' + edit2.text + ' - Адрес: ' + rez + ' Удалена!');
Del_tree(FPTree, strtoint(edit2.text));
PaintBox1.Refresh; // Очищает рисунок фон оставляет прозрачным
Button2Click(Sender);
end;
edit2.clear;
end;
procedure TForm2.Edit1KeyPress(Sender: TObject; var Key: char); // Ограничение ввода
begin
if not (Key in ['0'..'9', #8]) then
if not (Key in ['-', #8]) then
Key := #0;
end;
procedure TForm2.Edit2KeyPress(Sender: TObject; var Key: char);
begin
if not (Key in ['0'..'9', #8]) then
if not (Key in ['-', #8]) then
Key := #0;
end;
procedure TForm2.Del_tree (var x : TPNode; y:integer); // Удаление элемента
var q:TPNode;
{Поиск самого правого элемента в дереве}
procedure Del (var w : TPNode);
begin
if w^.PRight<>nil then Del(w^.PRight)
else begin
q:=w; {Запоминается адрес для освобождения места в «куче» }
x^.data:=w^.data;
w:=w^.PLeft;
end;
end;
begin
if x<>nil then
if y<x^.data then Del_tree (x^.PLeft, y)
else if y>x^.data then Del_tree (x^.PRight, y)
else Begin
q:=x;
{Правого поддерева нет}
if x^.PRight=nil then x:=x^.PLeft
{Левого поддерева нет}
else if x^.PLeft=nil then x:=x^.PRight
else del(x^.PLeft); {Поиск самого правого элемента в левом поддереве}
dispose(q);
end;
end;
procedure TForm2.FormClose(Sender: TObject);
begin
TreeFree(FPTree); //Освобождение памяти, занятой для элементов дерева (очистка дерева).
end;
end.
Листинг программы Задание 2:
unit Unit3;
{$mode objfpc}{$H+}