Algoritmike - 2011 - Leksion 3 - Kerkimi

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 6

program kerkim_sekuencial_1;

{Ky eshte nje program ne Pascal qellimi i te cilit eshte ilustrimi i implementimit ne gjuhe programimi i}
{algoritmit te kerkimit sekuencial}
const
n = 100 {numri i elementeve te tabeles} ;
kerkim_pasukses = -1 {vlera e kthimit ne rast deshtimi te kerkimit} ;
type
{tabelen dhe elementet perberes i deklarojme si tip me qellim abstraksioni dhe per te mos ndryshuar kodin nese}
{duam te shqyrtojme tabele karakteresh apo cfaredolloj tipi tjeter por te ndryshojme vetem deklarimin e tipit}
tabele_numrash = array[1..n] of integer;
tip_elementi = integer;
var
A : tabele_numrash {tabele numrash te plote} ;
function kerkim_sek_1 (var A : tabele_numrash;
element : tip_elementi ) : tip_elementi;
{Ky funksion merr si argumenta tabelen me reference dhe elementin qe kerkohet me vlere dhe kthen pozicionin e}
{elementit ne tabele nese ai gjendet ose vleren e konstantes kerkim_pasukses}
var
i : integer {variabel qe sherben per bredhje ne tabele} ;
ugjet : boolean {variabel qe tregon suksesin ose jo te kerkimit} ;
begin
A eshte i domosdoshem variabli boolean ugjet?
{inicializimi} Nuk eshte. Roli i tij eshte qe te nderprese ciklin ne
ugjet := false; rast se elementi gjendet (ne rast se do ta
eleminonim nga kodi do te benim nga 1 deri ne n
i := 1; kerkime te kota ne rast se elementi gjendej) . Nje
while (i<=n) and not ugjet do artifice per eleminimin e tij (por jo funksionin qe
{vazhdo bredhjen ne tabele derisa te kemi arritur ne fund} kryen) do te ishte qe ne rast gjetjeje t’i jepnim
variablit i nje vlere qe s’mund ta marre ne asnje rast
{ose derisa ta kemi gjetur elementin} tjeter (p.sh. -1 ose n+2). Mirepo kodi qe do te
if element = A[i] then rezultonte nuk do te ishte kaq i lexueshem sa
c’eshte ekzistuesi dhe ja vlen te shpenzojme 1 bit
ugjet := true hapesire kujtese qofte edhe vetem per kete fakt.
else
i := i + 1;
if ugjet then
kerkim_sek_1 := i {kerkim i suksesshem vlera e kthimit te funksionit eshte pozicioni i elementit}
else
kerkim_sek_1 := kerkim_pasukses {kerkim i pasuksesshem kthe nje konstante te paradeklaruar}
end;
begin {MAIN}
Japim ne hyrje nje tabele dhe nje vlere per kerkim;
Therrasim funksionin e kerkimit sekeuencial;
Japim ne dalje vleren e kthimit te funksionit;
end.

Ku mund ta permiresojme kete algoritem? Kuptohet qe vendi me i mire per te kerkuar eshte
cikli while sepse cdo permiresim (apo perkeqesim!) aty shumefishohet n here. Duke
shqyrtuar ciklin veme re se aty kemi 2 krahasime ne cdo hap (i<=n) dhe (element=A[i]).
Krahasimi i dyte eshte i domosdoshem prandaj kandidati i vetem per eleminim eshte
krahasimi i pare. Krahasimi (i<=n) do te ishte i panevojshme nese ne do ta dinim me siguri
qe elementi ne kerkim ndodhet ne tabele. Po sikur ne ta shtojme elementin ne kerkim ne
fund te tabeles si roje te kufijve te saj (sentinel)?

program kerkim_sekuencial_2;
{Ky eshte nje program ne Pascal qellimi i te cilit eshte ilustrimi i implementimit ne gjuhe programimi i}
{algoritmit te kerkimit sekuencial me “sentinel” ne fund te tabeles}
const
n = 100 {numri i elementeve te tabeles} ;
kerkim_pasukses = -1 {vlera e kthimit ne rast deshtimi te kerkimit} ;
type
{tabelen dhe elementet perberes i deklarojme si tip me qellim abstraksioni dhe per te mos ndryshuar kodin nese}
{duam te shqyrtojme tabele karakteresh apo cfaredolloj tipi tjeter por te ndryshojme vetem deklarimin e tipit}
tabele_numrash = array[1..n+1] of integer;
tip_elementi = integer; ne fund te tabeles vendosim vete elementin qe kerkohet duke
garantuar keshtu mosdaljen jashte kufijve te tabeles e
var rrjedhimisht duke shmangur nje nga krahasimet brenda ciklit
A : tabele_numrash {tabele numrash te plote} ; te funksionit (qe ketu buron edhe emertimi “sentinel” apo
roje e kufijve te tabeles ne kete rast
function kerkim_sek_2 (var A : tabele_numrash;
element : tip_elementi ) : tip_elementi;
{Ky funksion merr si argumenta tabelen me reference dhe elementin qe kerkohet me vlere dhe kthen pozicionin e}
{elementit ne tabele nese ai gjendet ose vleren e konstantes kerkim_pasukses}
var Eleminuam nga 1 deri ne n
krahasime potenciale. Nuk kemi
i : integer {variabel qe sherben per bredhje ne tabele} ; nevoje per ndonje variabel logjik
begin dhe kodi eshte i lexueshem. Por
{inicializimi} me cfare kosto? Nuk ka asgje
falas! Kostoja eshte hapesira
A[n+1] := element {vendos elementin si “sentinel” ne fund te tabeles} ; shtese e kujteses per te mbajtur ne
i := 1; fund te tabeles elementin.
Kompromisi mes kohes se
while element <> A[i] do ekzekutimit dhe hapesires se
{vazhdo bredhjen ne tabele derisa ta kemi gjetur elementin} kujteses se nevojshme do te jete
objekt i perhershem diskutimi ne
i := i + 1; algoritmet qe do te shqyrtojme.
if i < n+1 then
kerkim_sek_2 := i {kerkim i suksesshem vlera e kthimit te funksionit eshte pozicioni i elementit}
else
kerkim_sek_2 := kerkim_pasukses {kerkim i pasuksesshem kthe nje konstante te paradeklaruar}
end;
begin {MAIN}
Japim ne hyrje nje tabele dhe nje vlere per kerkim;
Therrasim funksionin e kerkimit sekeuencial me sentinel;
Japim ne dalje vleren e kthimit te funksionit;
end.

Ku mund ta permiresojme kete algoritem? Kerkimi sekuencial (quhet edhe linear) do te


mund te permiresohej vetem ne pakesimin e kerkimeve ne rast se elementi nuk ekziston. Si?
Te kerkosh sekuencialisht eshte njesoj si te kerkosh nje liber ne nje turre librash te vendosur
horizontalisht permbi njeri-tjetrin. Ne marrim librin e pare nga turra, shohim nese eshte ai
qe kerkojme, ne rast se jo vazhdojme me te dytin ne turre e keshtu me rradhe derisa te
mbarohen librat. Le te supozojme se turra permban revista te renditura kronologjikisht nga
me e reja deri tek me vjetra. Perseri kerkimi sekuencial do te fillonte me shqyrtimin e
revistave por ne ndryshim nga rasti i meparshem kerkimi do te ndalonte ne rast se arrijme
tek nje reviste qe nuk eshte revista qe ne kerkojme dhe eshte me vjeter se ajo. Pra renditja e
revistave na lejon ne qe te eliminojme kerkimet e kota ne rast mosekzistence. Nga ana tjeter,
duhet permendur se renditja nuk e pakeson numrin e kerkimeve ne rast ekzistence te
elementit.

program kerkim_sekuencial_3;
{Implementim ne Pascal i algoritmit te kerkimit sekuencial kur tabela e vlerave eshte e renditur ne rendin rrites}
const
n = 100 {numri i elementeve te tabeles} ;
kerkim_pasukses = -1 {vlera e kthimit ne rast deshtimi te kerkimit} ;
type
tabele_numrash = array[1..n] of integer;
tip_elementi = integer;
var
A : tabele_numrash {tabele numrash te plote} ;
function kerkim_sek_3 (var A : tabele_numrash;
element : tip_elementi ) : tip_elementi;
var
i : integer {variabel qe sherben per bredhje ne tabele} ;
ugjet, ekziston : boolean {ugjet vlen per nderprerjen e kerkimit ne rast gjetjeje}
{ekziston vlen per nderprejen e kerkimit ne rast mosekzistence} ;
begin
{inicializimi}
ugjet := false;
ekziston := true A eshte i domosdoshem variabli boolean
i := 1; ekziston? Nuk eshte. Roli i tij eshte qe te
nderprese ciklin ne rast se bindemi se elementi
while (i<=n) and not ugjet and ekziston do nuk ekziston ne tabele. Njesoj si ne rastin e
{vazhdo bredhjen ne tabele derisa te kemi arritur ne fund} variablit ugjet mund te perdorim nje artifice
{ose derisa ta kemi gjetur elementin} per eleminimin e tij (por jo funksionin qe
kryen) duke i dhene variablit i nje vlere qe
{ose derisa te bindemi se nuk ekziston} s’mund ta marre ne asnje rast tjeter (p.sh.
if element = A[i] then ugjet:=true mund ta zevendesojme me i
:=n+2 dhe ekziston:=false me i:=n+3). Duke i
ugjet := true qendruar besnike argumentit te meparshem
else if element <A[i] then ritheksojme se “lexueshmeria vlen te pakten 2
bit”.
ekziston := false
else
i := i + 1;
if ugjet then
kerkim_sek_3 := i {kerkim i suksesshem vlera e kthimit te funksionit eshte pozicioni i elementit}
else
kerkim_sek_3 := kerkim_pasukses {kerkim i pasuksesshem kthen nje konstante te paradeklaruar}
end;
begin {MAIN}
Japim ne hyrje nje tabele me elemente te renditur ne rendin rrites dhe nje vlere per kerkim;
Therrasim funksionin e kerkimit sekuencial ne nje tabele te renditur;
Japim ne dalje vleren e kthimit te funksionit;
end.

Ku mund ta permiresojme kete algoritem? Nuk kemi nevoje ta “rishpikim rroten”. Do te


perdorim te njejtin perafrim me ate te algoritmit te pare, perafrimin me sentinel.

program kerkim_sekuencial_4;
{Implementim ne Pascal i algoritmit te kerkimit sekuencial me sentinel kur tabela e vlerave eshte e renditur ne}
{rendin rrites}
const
n = 100 {numri i elementeve te tabeles} ;
kerkim_pasukses = -1 {vlera e kthimit ne rast deshtimi te kerkimit} ; Eleminuam 2* n krahasime
type potenciale. Nuk kemi nevoje
per asnje nga variablat logjike
tabele_numrash = array[1..n+1] of integer; te algoritmit te meparshem dhe
tip_elementi = integer; kodi eshte i lexueshem. Perseri
e vetmja kosto eshte hapesira
var shtese per ruajtjen e sentinel-it.
A : tabele_numrash {tabele numrash te plote} ; Eshte e qarte se nese ambienti
(me ambient ne kete rast
function kerkim_sek_4 (var A : tabele_numrash; nenkuptojme gjuhen e
element : tip_elementi ) : tip_elementi; programimit qe perdoret,
hapesiren disponibel te
var kujteses etj) e lejon, perafrimi
i : integer {variabel qe sherben per bredhje ne tabele} ; me sentinel eshte i preferuari
jone. Nje modifikim tjeter i
begin mundshem eshte qe si sentinel
{inicializimi} te vendosim elementin me
madh te mundshem qe lejon
A[n+1] := element {vendos elementin si “sentinel” ne fund te tabeles} ; tipi i variablit (p.sh. maxint ne
i := 1; rastin tone).
while element > A[i] do
{vazhdo bredhjen ne tabele derisa te kemi kapur nje vlere <= me elementin tone}
i := i + 1;
if i < n+1 and element = A[i] then
kerkim_sek_4 := i {kerkim i suksesshem vlera e kthimit te funksionit eshte pozicioni i elementit}
else
kerkim_sek_4 := kerkim_pasukses {kerkim i pasuksesshem kthe nje konstante te paradeklaruar}
end;
begin {MAIN}
Japim ne hyrje nje tabele me elemente te renditur ne rendin rrites dhe nje vlere per kerkim;
Therrasim funksionin e kerkimit sekuencial me sentinel ne nje tabele te renditur;
Japim ne dalje vleren e kthimit te funksionit;
end.

A mund ta permiresojme akoma me tej kete algoritem? E vetmja zgjidhje do te ishte rishikimi i
metodologjise kerkuese. Deri tani shqyrtuam kerkimin sekuencial. Po a ka menyre tjeter me
efikase kerkimi? Ne rast se tabela eshte e renditur po. Le te shqyrtojme pak situaten e meposhtme:
Kemi zgjedhur rastesisht nje numer te plote (7) nga nje bashkesi numrash te plote te
njepasnjeshem qe fillojne nga 1 dhe mbarojne ne 32. Sa eshte numri minimal i pyetjeve qe duhet te
bejme qe te gjejme me siguri numrin e zgjedhur? Kuptohet qe pyetjet duhet te jene te tilla qe te
mund te eleminohen sa me shume mundesi ne cdo hap. Pyetja me natyrshme do te ishte ajo qe e
ndan bashkesine pergjysem duke na pozicionuar ne njerin krah te saj. A eshte numri <=16? Po.
Me tej pyesim a eshte numri <=8? Po. Vazhdojme duke pyetur nese numri <=4. Jo. Pyesim nese
numri <=6. Jo. Pyesim nese numri <=7. Po. Ne kete rast nuk kemi nevoje te pyesim me tej sepse
nga pese pyetjet qe beme kemi informacionin qe numri eshte >6 dhe qe numri<=7 e rrrjedhimisht
jemi te sigurte qe numri i zgjedhur eshte 7. Ne menyre te ngjashme mund te gjendej me siguri cdo
numer nga te 32 numrat e dhene, vetem me 5 pyetje. Pra duke bere pergjysmimin (apo ndryshe
dikotomine) e bashkesise se renditur ne cdo hap arritem te pervijojme ate qe zakonisht quhet
metoda e kerkimit binar apo metoda e kerkimit dikotomik. Dime qe 25=32 dhe per rrjedhoje
log232=5. Nga kjo mund te pergjithesojme se numri minimal i kerkimeve per te gjetur me siguri
nje element ne nje bashkesi te renditur me n elemente eshte log2n.

program kerkim_binar_1;
{Implementim ne Pascal i algoritmit te kerkimit binar kur tabela e vlerave eshte e renditur ne rendin rrites}
const
n = 100 {numri i elementeve te tabeles} ;
kerkim_pasukses = -1 {vlera e kthimit ne rast deshtimi te kerkimit} ;
type
tabele_numrash = array[1..n] of integer;
tip_elementi = integer;
var
A : tabele_numrash {tabele numrash te plote} ;
function kerkim_bin_1 (var A : tabele_numrash;
element : tip_elementi ) : tip_elementi;
var
i, min, max : integer {i per te bredhur ne tabele, min max per te ngushtuar hap pas hapi rangun e kerkimit} ;
ugjet : boolean
begin Variabli logjik ugjet mund te eleminohet (nuk rekomandohet)
ose me metodat e sugjeruara me lart ose duke perdorur
ugjet := false ; komandat e gjuhes qe e transferojne ekzekutimin e programit
min := 1; ne menyre te pakushtezuar ne nje pike tjeter (p.sh. ugjet:=true
mund te zevendesohej me nje komande te nivelit te ulet
max := n; goto<etikete> apo me exit qe i jep fund ekzekutimit te
while min <= max and not ugjet do subprogramit).
Kerkimi binar e ndan pergjysem zonen ne cdo hap. Le te
begin shqyrtojme kerkimin e vleres 14 ne tabelen e meposhtme:
{vazhdo bredhjen ne tabele zona e kerkimit te behet boshe} hapi Ihapi IIhapi IIIhapi
IVzonavarzonavarzonavarzonavar11min11min11111313i1313
i := (min + max) div 2 ; max151515min,i15min,i2020max20max2024i242424313131314
if element = A[i] then 74747475050505069max696969Kerkimi ndalon sepse
max<min (rangu i kerkimit 0) dhe raportohet deshtimi i
ugjet := true kerkimit.
else if element > A[i] then
min := i +1
else
max := i – 1
end;
if ugjet then
kerkim_bin_1 := i {kerkim i suksesshem vlera e kthimit te funksionit eshte pozicioni i elementit}
else
kerkim_bin_1 := kerkim_pasukses {kerkim i pasuksesshem kthe nje konstante te paradeklaruar}
end;
begin {MAIN}
Japim ne hyrje nje tabele me elemente te renditur ne rendin rrites dhe nje vlere per kerkim;
Therrasim funksionin e kerkimit binar ne nje tabele te renditur;
Japim ne dalje vleren e kthimit te funksionit;
end.

Ku mund ta permiresojme kete algoritem? A kemi vertet nevoje per 3 variabla per te realizuar
kerkimin binar? A eshte e mundur qe po te na jepen 2 prej tyre te gjejme te tretin? Po, ne dime
qe i=(min+max)/2 prandaj sa here qe dime 2 prej tyre mund te gjejme te tretin. Le ta shprehim
ndryshe (jo pa qellim) pohimin e mesiperm dhe te themi se na mjafton te dime mesin e zones se
kerkimit (i) dhe hapin e zhvendosjes nga mesi ne te dy anet e zones (m). Pohimi i fundit eshte
edhe baza e algoritmit te kerkimit uniform binar te Knuth-it, nje variant i te cilit jepet ne vijim.

program kerkim_binar_2;
{Implementim ne Pascal i algoritmit te kerkimit binar uniform variant i modifikuar i Knuth-it}

deklarojme konstantet, tipet dhe variblat njesoj si tek kerkim_binar_1

function kerkim_bin_2 (var A : tabele_numrash;


element : tip_elementi ) : tip_elementi;
var
i, m : integer {i per te bredhur ne tabele, m percakton hapin e zhvendosjes} ;
ugjet, ekziston : boolean
begin Tashme e kemi diskutuar menyren (e pakeshillueshme) te
eliminimit te variablave logjike ugjet dhe ekziston.
ugjet := false ; Vereni se eleminimi i variablit te tepert ne percaktimin e zones
ekziston := true; se kerkimit na coi ne nje algoritem me numer me te madh
krahasimesh brenda ciklit si edhe ne nje kod me kompleks (por
i := (n+1) div 2; edhe me “elegant”). Per me teper duhet kontrolluar nese eshte e
m := n div 2; nevojshme vendosja e nje sentinel-e ne fillim te tabeles (per tu
diskutuar).
while ekziston and not ugjet do Ne perfundim nuk mund te themi nese ky algoritem realizon
begin nje kerkim binar “me te mire” (ne terma kohe dhe hapesire) se i
meparshmi apo jo.
if element <A[i] then
if m=0 then
ekziston:=false
else
begin Kur diskutuam mundesine e perdorimit te
i := i – (m + 1) div 2; kerkimit binar ne vend te atij sekuencial
theksuam se kjo mund te ndodhe ne rast se
m:= m div 2 bashkesia e vlerave ne shqyrtim eshte e
end renditur. Mirepo ne situatat reale kjo ndodh
rralle, gje qe do te thote se duhet fillimisht
else if element > A[i] then t’i rendisim elementet e me pas te mund te
if m=0 then perdorim metoden e kerkimit binar. Pame
se kerkimi sekuencial na kushton n kerkime
ekziston:=false kurse ai binar log n kerkime. Le te shohim
2
else tani se si mund ta realizojme renditjen dhe
sa na kushton kjo.
begin
i := i + (m + 1) div 2;
m:= m div 2
end
else if i > 0 then
ugjet := true
end;
if ugjet then
kerkim_bin_1 := i {kerkim i suksesshem vlera e kthimit te funksionit eshte pozicioni i elementit}
else
kerkim_bin_1 := kerkim_pasukses {kerkim i pasuksesshem kthe nje konstante te paradeklaruar}
end;
begin {MAIN}
Japim ne hyrje nje tabele me elemente te renditur ne rendin rrites dhe nje vlere per kerkim;
Therrasim funksionin e kerkimit binar ne nje tabele te renditur;
Japim ne dalje vleren e kthimit te funksionit;
end.

You might also like