300 likes | 656 Views
Pemet e Kerkimit Binar. Leksion 9. Perkufizime. Një pemë ( tree ) është një strukturë të dhënash e kapshme duke filluar nga rrënja ( root ). Çdo nyje ( node ) është ose një gjethe ( leaf ) ose një nyje e brendshme ( internal node ).
E N D
Pemet e Kerkimit Binar Leksion 9
Perkufizime • Një pemë (tree) është një strukturë të dhënash e kapshme duke filluar nga rrënja (root). Çdo nyje (node) është ose një gjethe (leaf) ose një nyje e brendshme (internalnode). • Një nyje e brendshme ka një bir (child)ose më shumë dhe quhet prindi (parent)i nyjeve bija të veta. • Të gjithë bijtë e të njëjtës nyje janë të të njëjtit brez (siblings). • Rrënja është elementi i dallueshëm fillestar ose bazë i një peme. Rrënja është i vetmi element që nuk ka prind.
Perkufizime • Një nyje është një njësi reference në një strukturë të dhënash. • Një gjethe është një element fundor i një peme. Një gjethe është një element pa bij. Ndryshe, një gjethe quhet nyje e jashtme (external node) ose nyje fundore (terminalnode). • Një nyje e brendshme është një nyje peme që ka një ose më shumë bij (nyje bija). Një nyje e brendshme është një nyje peme që nuk është gjethe.
Perkufizime • Një bir është një element i pemës i cili referohet nga elementi prind. Çdo element përveç rrënjës është biri i ndonjë prindi. • Prindi i një nyjeje është nyja e pemës konceptualisht sipër ose më afër rrënjës se nyja dhe e cila ka një lidhje (link) me nyjen. Sipas përkufizimit një nyje prind është një nyje e brendshme. • Një lidhje është një referencë, shënjues (pointer) apo mënyrë kapjeje për tek një tjetër pjesë e strukturës së të dhënave. Shpesh, një adresë kujtese.Një nyje në një pemë e cila ka të njëjtin prind me një nyje tjetër quhet e të njëjtit brez me të.
Perkufizime • Një pemë binare (binarytree) është një pemë me të shumtën dy bij për çdo nyje. • Një pemëe kërkimit binar (binary search tree) është një pemë binare ku çdo nënpemë e majtë e nyjes ka çelësa më të vegjël se çelësi (key) i nyjes dhe çdo nënpemë e djathtë ka çelësa më të mëdhenj se çelësi i nyjes. • Një nënpemë është pema bijë e një nyjeje. • Një çelës është pjesa e një grupi të dhënash me anë të së cilës ai (grupi i të dhënave) renditet, indeksohet, referohet etj.
program pemet_BST; {Ky eshte nje program ne Pascal qellimi i te cilit eshte ilustrimi i pemeve te} { kerkimit binar (Binary Search Tree – BST)} const max_lartesi_BST = 32 {lartesia maksimale e pemes BST – nje peme BST} {mund te kete maksimalisht 2lartesia elemente} ; type {E deklarojme pemen e kerkimit binar – BST - si tip te dhenash rekursiv } {bazuar ne perkufizimin: Nje peme e kerkimit binar – BST - eshte boshe} {ose perbehet prej rrenjes, nenpemes (BST) se saj te majte dhe te nenpemes } {(BST) se saj te djathte} tip_elementi = integer; peme = ^nyje_peme; nyje_peme = record element : tip_elementi; lidhje : array [1..2] of peme; end; tabele_peme =record rrenja : peme; numri : integer; end; var p : peme ; t : tabele_peme;
procedure inicializo (var t : tabele_peme); {kjo procedure krijon nje peme te kerkimit binar – BST- boshe} begin {inicializo} t.rrenja := nil; t.numri := 0 ; end {inicializo}; function bosh (var p : peme) : boolean; {ky funksion kthen true n.q.s. pema BST p eshte boshe dhe false ne te kundert} begin {bosh} bosh := p = nil; end {bosh};
procedure bredhje_pararendore (p : peme); {bredhje ne te gjithe elementet e nenpemes p – metoda pararendore (pre-order)} begin ifnot bosh(p) then begin writeln (p^.element); bredhje_pararendore (p^.lidhje[1]) ; bredhje_pararendore (p^.lidhje[2]) ; end end {bredhje_pararendore}; procedure bredhje_pasrendore (p : peme); {bredhje ne te gjithe elementet e nenpemes p – metoda pasrendore (post-order)} begin ifnot bosh(p) then begin bredhje_pasrendore (p^.lidhje[1]) ; bredhje_pasrendore (p^.lidhje[2]) ; writeln (p^.element); end end {bredhje_pasrendore};
procedure bredhje_nder_rendore (p : peme); {bredhje ne te gjithe elementet e nenpemes p – metoda nder-rendore (in-order)} begin ifnot bosh(p) then begin bredhje_nder_rendore (p^.lidhje[1]) ; writeln (p^.element); bredhje_nder_rendore (p^.lidhje[2]) ; end end {bredhje_nder_rendore}; function numri (p : peme) : integer; {ky funksion kthen numrin e elementeve te nenpemes p} begin {numri} if p = nil then numri := 0 else numri := numri (p^.lidhje[1]) + 1 + numri (p^.lidhje[2]); end {numri};
procedure lexo_BST (var p : peme; var t : tabele_peme); {shton elementet ne nje peme te tipit BST, duke u bazuar pikerisht ne } { cilesite e pemes se kerkimit binar – BST} var {ne elm ruajme elementin per tu shtuar, akoma tregon nese kemi } { akoma elemente per shqyrtim; ugjet tregon elementi kandidat per t’u } { shtuar ekziston ne peme apo jo; p eshte shenjuesi mbi elementin e ri } { per tu shtuar dhe q prindi i tij (nese ka te tille) ne pemen t; drejtimi } { tregon kahun e vendndodhjes se p (birit te q)} elm : tip_elementi; akoma, ugjet : boolean; q : peme; drejtimi : integer; procedure perfto (var elm : tip_elementi; var akoma : boolean); {perftojme elementin e rradhes dhe shqyrtojme nese ka akoma {elemente te tjere} const fund = -1; begin readln (elm); akoma := elm <> fund end {perfto};
begin {inicializimi} elm := 0; akoma := true; perfto (elm, akoma); while akoma do {derisa te mos kemi si input elm=-1} begin {bredhim pemen me ane te shenjuesit p duke ruajtur ne q prindin e } { p dhe tek drejtimi kahun e zbritjes ne pemen t} q := nil; p := t.rrenja; ugjet := false; while ((p <> nil) and not(ugjet)) do if p^.element = elm then ugjet := true {nese elementi tashme ekziston mos bej asgje} else begin if p^.element > elm then drejtimi := 1 else drejtimi := 2; q := p; p := p^.lidhje[drejtimi] end;
If not(ugjet) then begin new (p); p^.element := elm; p^.lidhje[1] := nil; p^.lidhje[2] := nil; if q <> nil then q^.lidhje[drejtimi] := p else t.rrenja := p; {q=nil dmth shto ne rrenje} t.numri := t.numri +1 ; end ; perfto (elm, akoma); end; end {lexo_BST};
begin {MAIN} inicializo (t); p := nil; lexo_BST(p,t) ; p := t.rrenja bredhje_nder_rendore(p) ; p := t.rrenja numri(p) ; end {MAIN}.
Nje efekt anesor i metodes se zakonshme te shtimit ne nje peme te kerkimit binary (BST), sipas implementimit ne proceduren e meparshme, eshte se elementet e shtuar me vone tentojne te jene me larg nga rrenja dhe prandaj duhet me shume kohe per ti gjetur ata ne krahasim me elementet e shtuar para tyre. Nese te gjithe elementet kane te njejtat gjasa per te qene kandidate te nje kerkimi atehere ky fakt nuk eshte i rendesishem, por nese jemi ne rastet e disa modeleve te perdorimit komun ku elementet e shtuar me vone tentohen te kerkohen me shpesh se ata me te hershem (nga kendveshtrimi i shtimit ne peme) atehere kemi te bejme me nje problem jo te vogel. • Nje skeme alternative per shtimin, skeme e cila adreson edhe problemin e siperpermendur, eshte skema e shtimit nga rrenja. Sipas ketij algoritmi, nyja e re vendoset gjithmone ne rrenje te pemes. Duke ndjekur nje seri shtimesh te tilla nyjet e futura me vone kane tendence te jene me afer rrenjes se nyjet e tjera.
Si nje perpjekje te pare per implementimin e kesaj ideje, ne mund te perpiqemi ta bejme nyjen e re si rrenje te pemes dhe ta kthejme rrenjen e vjeter si nje nga bijte e saj. • Per fat te keq, ky perafrim apo ndonje tjeter i ngjashem me te, nuk do te funksionoje sepse nuk ka garanci qe nyjet ne pemen ekzistuese kane te gjitha vlera me te medha apo me te vogla se nyja e re. • Nje perafrim qe funksionon eshte kryerja e nje shtimi konvencional si nje nyje gjethe sipas algoritmit tashme te pershkruar te shtimit dhe pastaj kryerja e nje serie rrotullimesh per ta levizur nyjen e re drejt rrenjes.
Shtimi ne BST nga rrenja • Rregulli i pergjithshem ndjek modelin e treguar ne prezantim. Neqoftese ne zbritem majtas nga nje nyje x gjate kerkimit per shtim ne kryejme nje rrotullim djathtas mbi x. Neqoftese zbritem djathtas atehere rrotullojme majtas. • Implementimi i algoritmit bazohet ne memorizimin e nyjeve te bredhura gjate kerkimit te nje pike futjeje dhe me tej ne kryerjen e rrotullimeve ne rend te kundert me bredhjen fillestare.
function shtim_BST_rrenja (var t : tabele_peme; elm : tip_elementi) : peme; {shton elementet ne nje peme te tipit BST - metoda e shtimit nga rrenja} var ugjet : boolean; k : integer; p, q : peme; pa : array [1 . . max_lartesi_BST] of peme; da : array [1 . . max_lartesi_BST] of integer; begin pa[1] := t.rrenja; p := t.rrenja; da[1] := 1 ; k := 2 ; ugjet := false;
while ((p <> nil) and not(ugjet)) do if p^.element = elm then ugjet := true else begin {shqyrto rastin k>max_lartesi_BST} pa[k] := p; if p^.element > elm then da[k] := 1 else da[k] := 2; p := p^.lidhje[da[k]]; k := k + 1; end;
if not(ugjet) then begin new (p); p^.element := elm; p^.lidhje[1] := nil; p^.lidhje[2] := nil; pa[k-1]^.lidhje[da[k-1]] := p ; {shqyrto rastin pema boshe pra t.rrenja=nil} t.numri := t.numri +1 ; while k > 2 do begin q := pa[k-1]; q^.lidhje[da[k-1]] := p^.lidhje[3-da[k-1]] ; p^.lidhje[3-da[k-1]] := q ; pa[k-2]^.lidhje[da[k-2]] := p; k:=k-1; end; t.rrenja := p ; end; shtim_BST_rrenja := p end {shtim_BST_rrenja};
function gjej (t : tabele_peme; var p, q : peme ; var d : integer ; elm : tip_elementi) : boolean ; {gjen vendndodhjen e nyjes se pemes me vlere elm ne pemen t duke ruajtur ne p} {shenjuesin mbi kete nyje peme (ose nil nese ajo nuk ekziston), ne q prindin e p (ose } {nil nese prindi nuk ekziston) dhe ne d kahun e birit (1 nese eshte bir i majte dhe/ose} {2 nese eshte bir i djathte)} var ugjet : boolean; begin ugjet := false; p := t.rrenja; q := nil ; while (not(ugjet) and (p <> nil)) do if p^.element = elm then ugjet := true else begin if p^.element > elm then d := 1 else d := 2; q := p; p := p^.lidhje[d] end ; gjej := ugjet end {gjej};