program tree; (***************************************************************************** B O G D A N W I E R C Z Y N S K I 1 0 . 0 1 . 1 9 8 9 Przedstawiony program umozliwia tworzenie drzewa BST oraz jego modyfikacje w celach dydaktycznych. Udostepnia cztery podstawowe operacje na tej strukturze danych:insert,delete,minimum i maximum. Struktora drzewa jest wyswietlana na ekranie i kazda akcja powodujaca jej zmiane wiaze sie ze zmiana drzewa na ekranie. ******************************************************************************) unit BST:class; (* Klasa implementujaca BST jako abstrakcyjny typ danych z podstawowymi operacjami zwiazanymi z ta struktora. *) unit vertex:class; var key:integer, left,right:vertex; end vertex; unit find:class(x:real;inout v:vertex); (* Wyszukanie w drzewie o korzeniu v wierzcholka z kluczem o wartosci x *) var father,(* Wskazanie na ojca szukanegoelementu *) znaleziony,(* Wskazanie na wierzcholek ktorego klucz ma wartosc x *) vpom:vertex,(* Zmienna pomocnicza *) lson:boolean;(* Zmienna informujaca ze znaleziony element jest lewym synem *) begin vpom:=v; father,znaleziony:=none; while vpom=/=none do if xvpom.key then father:=vpom;vpom:=vpom.right;lson:=false else znaleziony:=vpom;exit fi fi od; end find; unit delete:find procedure; (* Kasowanie wierzcholka ktorego wartosc klucza jest parametrem x w find *) begin if znaleziony=/=none then if znaleziony.left=znaleziony.right then (* Usuwany element jest lisciem *) kill(znaleziony) else if znaleziony.right=none then if father=none then v:=v.left (* Usuwany element jest korzeniem drzewa *) else if lson then father.left:=znaleziony.left else father.right:=znaleziony.left fi fi; kill(znaleziony) else vpom:=znaleziony.right; while vpom.left=/=none do vpom:=vpom.left od; znaleziony.key:=vpom.key; if vpom.right=none then kill(vpom) else znaleziony:=vpom.right; (* Wykorzystanie zmiennej znaleziony jako zmiennej pomocniczej *) vpom.key:=znaleziony.key; vpom.left:=znaleziony.left; vpom.right:=znaleziony.right; kill(znaleziony) fi fi fi fi end delete; unit insert:procedure(x:integer;inout v:vertex); (* Wstawienie do drzewa BST o korzeniu v elementu ktorego wartosc klucza bedzie rowna x *) var vpom:vertex; begin if v=none then v:=new vertex; v.key:=x (* Puste drzewo *) else vpom:=v; do if x<=vpom.key then if vpom.left=/=none then vpom:=vpom.left else vpom.left:=new vertex; vpom.left.key:=x; exit fi else if vpom.right=/=none then vpom:=vpom.right else vpom.right:=new vertex; vpom.right.key:=x; exit fi fi od fi end insert; unit minimum:function(v:vertex):integer; (* Znalezienie elementu o najmniejszym kluczu *) begin while v.left =/= none do v:=v.left; od; result:=v.key; end minimum; unit maximum:function(v:vertex):integer; (* Znalezienie elementu o najwiekszym kluczu *) begin while v.right=/= none do v:=v.right; od; result:=v.key; end maximum; end BST; unit SetCursor: procedure(x,y:integer); var i,j:integer, c,d,e,f:char; begin i:= x div 10; j:= x mod 10; c:=chr(48+i); d:=chr(48+j); i:=y div 10; j:=y mod 10; e:=chr(48+i); f:=chr(48+j); write(chr(27),"[",c,d,";",e,f,"H") end SetCursor; unit inchar : IIUWgraph function : integer; (*podaj nr znaku przeslanego z klawiatury *) var i : integer; begin do i := inkey; if i <> 0 then exit fi; od; result := i; end inchar; unit ClearScreen: procedure; begin write(chr(27),"[2J") end ClearScreen; begin pref BST block unit OpenWindow:procedure(x,y,height,width:integer); (* Otwarcie okienka ktorege lewy gorny rog ma wspolrzedne (x,y) i o wymiarach height x width (wysokosc x szerokosc) *) var i,j:integer; begin call SetCursor(x,y); write(chr(218)); for j:=2 to width-1 do write(chr(196)) od; write(chr(191)); for i:=2 to height-1 do call SetCursor(x+i-1,y); write(chr(179)); for j:=2 to width-1 do write(" ") od; write(chr(179)); od; call SetCursor(x+height-1,y); write(chr(192)); for j:=2 to width-1 do write(chr(196)) od; write(chr(217)); call SetCursor(x+1,y+1); end OpenWindow; unit CloseWindow:procedure(x,y,height,width:integer); (* Zamkniecie okienka ktorege lewy gorny rog ma wspolrzedne (x,y) i o wymiarach height x width (wysokosc x szerokosc) *) var i,j:integer; begin for i:=0 to height-1 do call SetCursor(x+i,y); for j:=1 to width do write(" ") od; od; end CloseWindow; unit negative:procedure; begin write(chr(27),"[7m"); end negative; unit positive:procedure; begin write(chr(27),"[0m"); end positive; unit MenuType:class; var beginingX,beginingY:integer, Name:string; end MenuType; unit Inic:procedure; (* Zainicjowanie systemu,utorzenie odpowiednich danych, ich zainicjowanie, wyswietlenie menu . *) var i:integer; begin AktPoz:=0; array Menu dim(0:4); for i:=0 to 4 do (* Wypelnienie tablicy menu *) Menu(i):=new MenuType; Menu(i).beginingX:=2; (* Wspolrzedne peczatku napisu opcji w menu *) Menu(i).beginingY:=8+i*16; case i (* Wstawienie odpowiedniego tekstu *) when 0: Menu(i).Name:="INSERT"; when 1: Menu(i).Name:="DELETE"; when 2: Menu(i).Name:="MINIMUM"; when 3: Menu(i).Name:="MAXIMUM"; when 4: Menu(i).Name:="EXIT"; esac; od; call ClearScreen; call SetCursor(1,1); for i:=1 to 80 do write(chr(196)) od; call negative; call SetCursor(Menu(0).beginingX,Menu(0).beginingY); write(Menu(0).Name); call positive; for i:=1 to 4 do call SetCursor(Menu(i).beginingX,Menu(i).beginingY); write(Menu(i).Name); od; call SetCursor(3,1); for i:=1 to 80 do write(chr(196)) od; call SetCursor(Menu(0).beginingX,Menu(0).beginingY); end Inic; unit printclass:class; (* Klasa ktora zajmuje sie wyswietlaniem drzewa na ekranie . (Mozna ja traktowac w pewnym sensie jak pprocedure) *) const X=1, Y=2; var i,j,last,przes,NumberOfVert:integer, VertCoord:array_of array_of integer,(*Tablica zawierajaca wspolrzedne wyswietlanych elementow *) queueForPrint:array_of vertex;(*kolejka elementow do wyswietlenia*) unit printTree:procedure(v:vertex); (* Procedura wyswietlajaca drzewo o podanym korzeniu *) var first:integer, isleft,isright:boolean; begin if v=/=none then first,last:=1; queueForPrint(last):=v; while first<=31 do (* Wstawianie 31 kolejnych wierzcholkow do kolejki i drukowanie ich.(Tylko tyle miesci sie na monitorze *) if first<=15 then if queueForPrint(first)=none then queueForPrint(last+1),queueForPrint(last+2):=none; (*Niema synow wiec wstawiamy none *) else queueForPrint(last+1):=queueForPrint(first).left; queueForPrint(last+2):=queueForPrint(first).right; isleft:=queueForPrint(first).left=/=none; isright:=queueForPrint(first).right=/=none; call Setcursor(VertCoord(X,first),VertCoord(Y,first)-1); (* Wypisanie elementu drzewa w odpowiednim formacie *) call format(queueForPrint(first).key); if isleft or_if isright then call Setcursor(VertCoord(X,first)+1,VertCoord(Y,first)); write(chr(179)); if isleft then call Setcursor(VertCoord(X,first*2)-1,VertCoord(Y,2*first)); write(chr(179)); call Setcursor(VertCoord(X,first*2)-2,VertCoord(Y,2*first)); write(chr(218)); for i:=1 to ( VertCoord(Y,first)-VertCoord(Y,2*first)-1) do write(chr(196)); od; fi; if isleft and isright then write(chr(193)) else if isleft then write(chr(217)) else call Setcursor(VertCoord(X,first)+2,VertCoord(Y,first)); write(chr(192)); fi; fi; if isright then for i:=1 to ( VertCoord(Y,2*first+1)-VertCoord(Y,first)-1) do write(chr(196)); od; write(chr(191)); call Setcursor(VertCoord(X,first*2+1)-1, VertCoord(Y,2*first+1)); write(chr(179)); fi; fi; fi; last:=last+2 else if queueForPrint(first)=/=none then call SetCursor(VertCoord(X,first),VertCoord(Y,first)-1); (* Wypisanie elementu drzewa w odpowiednim formacie *) call format(queueForPrint(first).key); if queueForPrint(first).left=/=none or_if queueForPrint(first).right=/=none then call Setcursor(VertCoord(X,first)+1,VertCoord(Y,first)); write(chr(25)); fi; fi; fi; first:=first+1 od; fi; end printTree; unit format:procedure(x:integer); (* Procedura wybiera odpowiedni format wydruku w zaleznosci od liczby cyfr w liczbie x i wypisuje ja na ekran *) begin if x>=0 then if x>999 then write(x:4) else if x>99 then write(x:3) else write(x:2) fi fi else if x<-99 then write(x:4) else if x<-9 then write(x:3) else write(x:2) fi fi fi end format; begin array VertCoord dim(1:2); for i:=1 to 2 do array VertCoord(i) dim(1:31);od; array queueForPrint dim(1:31); przes:=40; last,NumberOfVert:=1; (* Wypelnienie tablicy VertCoord wspolrzednymi wszystkich elementow ktore moga byc wyswietlone na ekranie *) for i:=0 to 4 do for j:=1 to NumberOfVert do if i=/=4 then VertCoord(Y,last):=przes+(j-1)*2*przes; fi; VertCoord(X,last):=i*4+7; last:=last+1 od; NumberOfVert:=NumberOfVert*2; przes:=przes div 2 od; przes:=0; for last:=16 to 31 do VertCoord(Y,last):=2+przes; przes:=przes+5 od; end printclass; const IndicatorLeft=-75,(* Kody znakow wykorzystywanych przy poslugiwaniu *) IndicatorRight=-77,(* sie menu. *) Enter=13, Esc=27, ConstInsert=0,(* Indeksy tablicy Menu odpowiadajace opcjom *) ConstDelete=1, ConstMinimum=2, ConstMaximum=3, ConstExit=4; var i,znak,AktPoz,key:integer, root:vertex,(* Korzen drzewa BST *) print:printclass, Menu :array_of MenuType; (********** POCZATEK PROGRAMU GLOWNEGO **********) begin print:=new printclass; call Inic; do znak:=inchar; case znak when IndicatorRight:call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); write(Menu(AktPoz).Name); AktPoz:=(AktPoz+1) mod 5; call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); call negative; write(Menu(AktPoz).Name); call positive; call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); when IndicatorLeft: call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); write(Menu(AktPoz).Name); AktPoz:=(AktPoz+4) mod 5; call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); call negative; write(Menu(AktPoz).Name); call positive; call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); when Enter: if Aktpoz=ConstExit then call endrun else call OpenWindow(3,Menu(AktPoz).beginingY,3,22); case Aktpoz when ConstInsert:write("VALUE: "); readln(key); call insert(key,root); call print.printtree(root); call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); when ConstDelete:write("VALUE: "); readln(key); call delete(key,root); call CloseWindow(7,1,18,80); call print.printtree(root); call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); when ConstMinimum:if root =/= none then write(minimum(root):4," ") else write("Empty Tree "); fi; write("press Esc"); do if inchar=Esc then exit fi; od; call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); when ConstMaximum:if root =/= none then write(maximum(root):4," ") else write("Empty Tree "); fi; write("press Esc"); do if inchar=Esc then exit fi; od; call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); esac; call CloseWindow(3,Menu(AktPoz).beginingY,3,22); call SetCursor(Menu(AktPoz).beginingX+1, Menu(AktPoz).beginingY); for i:=1 to 22 do write(chr(196)) od; call SetCursor(Menu(AktPoz).beginingX, Menu(AktPoz).beginingY); fi; esac; od; end ; end tree