Professional Documents
Culture Documents
Slgoritem 3 Perca Sundo
Slgoritem 3 Perca Sundo
Slgoritem 3 Perca Sundo
RENDITJA ME PERZIERJE
RENDITJA E SHPEJTE
1
DİZENJİMİ İ ALGORİTMEVE
Ka disa menyra per ndertimin e algoritmeve. Rendtja me
nderfutje perdor metoden inkrementale: Duke patur te renditur
nenvektorin A[1..j - 1], ne nderfutim elementin A[j] ne vendin e
vet, duke perftuar keshtu nenvektorin e renditur A[1 j].
Ne kete mesim do te shohim nje metode alternative te dizenjimit,
te njohur si “Perça-e-Sundo” .
Ne do ta perdorim metoden “Perça-e-Sundo” per te dizenjuar nje
algoritem renditjeje per te cilin koha e ekzekutimit ne rastin me te
keq eshte shume me e shkurter se ajo e renditjes me nderfutje.
2
METODA “PERÇA-E-SUNDO” .
3
METODA “PERÇA-E-SUNDO” .
4
RENDİTJA ME PERZİERJE (MERGE
SORT )
5
RENDİTJA ME PERZİERJE - PSEUDOKODİ
6
RENDİTJA ME PERZİERJE – SHEMBULL PER N=8
7
RENDİTJA ME PERZİERJE – SHEMBULL PER N=11
8
RENDİTJA ME PERZİERJE (MERGE
SORT )
Veprimi baze i renditjes me perzierje eshte perzierja e dy
sekuencave, ne hapin “Kombino”
9
RENDİTJA ME PERZİERJE (MERGE
SORT )
Procedura MERGE kerkon nje kohe ekzekutimi te rendit Θ(n),
ku n = r - p + 1 eshte numri i elementeve qe po renditen dhe funksionon
si me poshte: Duke iu kthyer lojes me letra, supozojme se:
Kemi dy stiva me letra mbi tavoline, ku selica stive eshte e renditur, me
letren me te vogel ne maje te stives.
Ne deshirojme qe t’i perziejme dy stivat ne nje stive te vetme output.
10
RENDİTJA ME PERZİERJE (MERGE
SORT )
Nuk kemi nevoje qe te kontrollojme nese stiva eshte bosh ne çdo hap baze.
• Vendos ne fund te seciles stive input nje leter te veçante sentinel, qe
permban nje vlere te veçante qe e perdorim per te thjeshtuar kodin.
• Ne perdorim ∞, qe ta kemi te sigurt qe “do ta humbim” kete vlere.
• Kur ∞ eshte ne maje te seciles stive, te gjitha letrat josentinel jane vendosur
tashme ne stiven output.
• Ne e dime qe me perpara se ka saktesisht r − p + 1 letra josentinel
⇒ndalojme kur kemi kryer r − p + 1 hapa baze. Pra nuk na nevojitet kurre
qe te kontrollojme per sentinelet, meqe ato gjithmone humbin.
• Ne vend qe te numerojme hapat baze, mjafton te mbushim vektorin output
nga indeksi p deri tek dhe duke perfshire indeksin r .
11
RENDİTJA ME PERZİERJE - PSEUDOKODİ
12
SHEMBULL: THİRRJA E MERGE(9, 12, 16)
13
SHEMBULL: THİRRJA E MERGE(9, 12, 16) - VAZHDİM
14
ANALIZA E RENDITJES ME PERZIERJE
(1)
Per thjeshtesi supozojme se n eshte fuqi e 2, pra cdo hap “perca” na con ne dy
nenprobleme, secili me madhesi saktesisht n/2
Hapi baze ndodh kur n = 1.
Kur n ≥ 2, duhen hapat per Merge Sort:
Perca: Llogaritet q si mesatare e p dhe r , pra Θ(n) = (1).
Sundo: Zgjidhen dy nenproblemet ne menyre rekursive, secili me madhesi
n/2, pra 2T (n/2).
Kombino: MERGE per nje nenvektor me n elemente kerkon nje kohe (n),
pra C(n) = (n).
Meqe Θ(n) = (1) dhe C(n) = (n), te dy se bashku sjellin nje funksion qe eshte
linear ne n: (n) Pra rekursiviteti per kohen e ekzekutimit te merge sort eshte
15
ANALIZA E RENDITJES ME PERZIERJE
(2)
Le te jete c nje konstante qe pershkruan kohen e
ekzekutimit per rastin baze dhe gjithashtu eshte
koha per element vektori per hapat perça e sundo
(natyrisht nuk eshte e domosdoshme qe te perdoret
e njejta konstante per te dyja). Per kete kemi:
16
ANALIZA E RENDITJES ME PERZIERJE
(3)
• Per secilin nga nenproblemet me madhesi n/2, kemi nje kosto prej
cn/2, plus dy nenproblemet, ku secili kushton T (n/4):
17
ANALIZA E RENDITJES ME PERZIERJE
(4)
• Vazhdojme te zgjerojme pemen derisa madhesia e problemit te behet 1:
• Secili nivel ka koston cn.
• Niveli me i larte ka koston cn.
• Niveli pasardhes me poshte ka
2 nenprobleme, me kosto cn/2
secili
• Niveli pasardhes ka 4
nenprobleme, me kosto cn/4
secili.
• Sa here qe ulemi me nje nivel,
numri i nenproblemeve
dyfishohet por kostoja per
gjysmat e nenproblemeve ⇒
kostoja per nivek mbetet e
njejte.
• Ka lg n + 1 nivele (lartesia
eshte lg n).
18
ANALIZA E RENDITJES ME PERZIERJE
(5)
Duke perdorur induksionin kemi:
Rasti baze: n = 1⇒1 nivel, dhe lg 1 + 1 = 0 + 1 = 1.
20
DETYRE SHTEPIE
Bazuar ne algoritmin ne pseudokod per renditjen me
perzierje, ndertoni nje program ne C++ per kete
algoritme.
Modifikojeni algoritmin menyre qe ai t’i rendise vektoret
ne rendin zbrites.
21
RENDITJA E SHPEJTE (QUICKSORT)
Renditja e shpejte (quicksort).
Deri tani kemi studiuar dy metoda klasike (iterative) të
renditjes dhe kemi vërejtur se ato janë të rendit O(n2).
Nga ana tjetër, kemi studiuar rekursivitetin dhe ajo çka do të
perpiqemi të bëjmë është të ndërtojmë një algoritëm rekursiv
për renditjen.
Çelësi, si gjithmonë me rekursivitetin, është të menduarit e
reduktimit të çdo rasti në një version më të thjeshtë të të njëjtit
problem duke arritur, eventualisht deri në bazë.
22
RENDITJA E SHPEJTE (QUICKSORT)
Të rendisësh një tabelë që është boshe ose përmban një element është e
thjeshtë : mos bëj asgjë.
Por si të arrijmë deri tek një apo zero elementë ?
23
SHEMBULL
Le të zgjedhim (pa u menduar se pse
për momentin) elementin e fundit të
1 2 3 4 5 6 7 8 tabelës si bosht. Atëherë detyra jonë
është që ta ndajmë tabelën në dy
10 0 50 80 90 50 30 60 pjesë të tilla që e majta përmban
elementët jo më të mëdhenj se
boshti dhe e djathta ata jo më të
vegjël se boshti e më tej ta vendosim
1 2 3 4 5 6 7 8 boshtin në mes të këtyre dy pjesëve.
10 0 50 30 50 60 80 90
Pjesa e majtë Pjesa e
djathtë
25
PARTICIONIM
Particionimi (partition).
Pra arritëm ta ndajmë problemin fillestar në dy
nënprobleme më të thjeshta dhe gjithashtu përcaktuam
edhe bazën apo pikën e ndalimit të rekursivitetit.
Çfarë na mbetet është të ndërtojmë algoritmin që
realizon particionimin (proçesin e ndarjes në dy pjesë të
tilla që elementët në pjesën e majtë të jenë në të majtë
dhe jo më të mëdhenj se boshti dhe elementët në pjesën e
djathtë të jenë në të djathtë dhe jo më të vegjël se boshti.
26
PARTICIONIM
Le të vazhdojmë ta marrim të mirëqenë faktin që
zgjedhja e elementit të fundit të tabelës si bosht është
zgjedhja e duhur.
Detyra jonë është që çdo element në të majtë të elementit
tonë bosht që është më i madh se boshti të lëvizet në të
dajthtë. Në mënyrë të ngjashme, çdo element në të
djathtë që është më i vogël duhet të lëvizet në të majtë të
boshtit.
Një nga mënyrat për ta bërë këtë përshkruhet vizualisht
më poshtë (version i Robert Sedgewick bazuar në
metodën origjinale të C.A.R. Hoare).
27
PARTICIONIM
Elementi i fundit në tabelë është
zgjedhur si bosht. Fillojmë në anën
e majtë të tabelës dhe lëvizim
djathtas derisa të gjendet një
element të paktën po aq i madh sa
boshti.
Pastaj lëvizim majtas nga ana e
djathtë e tabelës derisa të gjendet
një element të paktën po aq i vogël
sa boshti - shiko (a) tek figura
majtas.
Tani i shkëmbejmë këto dy elemntë
dhe e përsërim proçesin. Mirëpo,
ne nuk kemi nevojë të shkojmë
përsëri krejt mbrapa deri në skajet
e majtë dhe të të djathtë; mjafton
që ne të vazhdojmë aty ku e lamë –
shiko (b) tek figura majtas.
28
PARTICIONIM
Ne e vazhdojmë këtë proçes derisa lëvizjet tona nga e
majta dhe nga e djathta ose takohen në të njëtën pikë (në
të njëjtin element) ose kryqëzohen – shiko (c) tek figura
majtas.
Më pas, e vetmja gjë që na ka mbetur për të bërë është të
vendosim boshtin në vendin e tij përfundimtar në tabelën
e renditur.
Këtë e realizojmë duke shkëmbyer boshtin me elementin
që ndodhet aty ku shënjon indeksi i bredhjes djathtas në
anën e majtë.
29
PARTICIONIM
Problemi jonë fillestar (renditja e të gjithë tabelës) u nda
në dy nënprobleme më të thjeshta (renditja e nëntabelës
majtas boshtit dhe nëntabelës djathtas boshtit).
Thirrjet rekursive do të ndalojnë atëherë kur nëntabelat
që do të formohen në vazhdimësi do të përmbajnë 0 ose
1 elementë.
E vetmja çështje për tu sqaruar mbetet zgjedhja e boshtit.
30
ZGJEDHJA E BOSHTIT (PIVOT)
Duke qenë se ne po supozojmë që elementi A[0] në një
tabelë është i papërdorur ne mund ta vendosim vlerën
bosht aty dhe të kemi kështu një sentinel (roje kufijsh) në
skajin e majtë (tashmë e kemi theksuar se pse na shërben
një sentinel dhe nëse ka dobi përdorimi përkatës).
Por çfarë të bëjmë me skajin e djathtë të tabelës?
31
ZGJEDHJA E BOSHTIT (PIVOT)
Pra, në realitet do të kishim vlerën e boshtit si në elementin në
ekstremin e majtë ashtu dhe në elementin në ekstremin e djathtë
duke qenë kështu gjithmonë të sigurtë se nuk do të dalim jashtë
kufijve në të dy krahët.
Po mirë, po a është e arsyeshme ta zgjedhim elementin e fundit
si bosht?
Faktikisht ne nuk mund të jemi të sigurtë se cili prej elementëve
është më i miri.
Idealja do të ishte po qe se do të mund të zgjidhnim elementin
që përkon me të mesmin e elementeve të tabelës për nga
madhësia (medianën) por pa i patur elementët sipas një rendi të
caktuar ne nuk jemi në gjendje ta gjejmë atë (nënkuptohet që
n.q.s. elementët do të ishin sipas një renditje të caktuar ne nuk
do të përpiqeshim ta rendisim atë).
32
ZGJEDHJA E BOSHTIT (PIVOT)
Ne mund të provonim zgjedhje të tjera si indeksi i mesit por
përsëri duhet vërejtur se elementi korrespondues mund të jetë më
i vogli, më i madhi – një element i një madhësie çfarëdo në
përgjithësi – në varësi të vendosjes fillestare të elementeve në
tabelën origjinale.
Pra, zgjedhja e elementit të parë, të mesit apo të fundit (nga
pikëpamja e vendndodhjes së tyre në tabelë dhe jo nga pikëpamja
e madhësisë së tyre relative) nuk do të na jepte ndonjë avantazh të
dukshëm për momentin e për rrjedhojë ne do të zgjedhim
elementin e fundit si bosht sepse në këtë mënyrë kemi nevojë të
përkujdesemi vetëm për një sentinel në skajin e majtë (n.q.s. do të
zgjidhnim si bosht një element çfarëdo të tabelës të ndryshëm nga
elementi i parë apo i fundit atëherë do të duhej që të merrnim
masa për vendosjen e dy sentinelave në të dy skajet e tabelës).
33
QUICKSORT-PSEUDOKODI
QuickSort(A, fillim, fund)
begin
If (fillim < fund)
ndares = Particiono(A,fillim, fund);
QuickSort(A, fillim, ndares-1);
QuickSort(A, ndares+1, fund);
end.
Particiono(A,fillim, fund)
begin {inicializimi}
i fillim – 1;
boshti A[fund]; {pergatit dy seksionet perreth boshtit}
for j fillim to fund-1 do {shqyrton dhe shkemben}
if A[j] <= boshti;
i i+1
{shkemben elementet ku jemi pozicionuar}
shkembe (A[i], A[j])
end; { for};
{kthen mbrapsht shkembimin e fundit}
shkembe (A[i+1], A[fund]);
return i+1
end { Particiono }; 34
SHEMBULL PARTICIONIMI (QUICKSORT)
35
{pergatit dy seksionet perreth boshtit}
program renditje_shpejt; repeat {shqyrton dhe shkemben}
{Implementim ne Pascal i algoritmit te renditjes se tabeles me ane te metodes se shpejte, ose {shqyrton djathtas}
e} {ashtuquajtura quick sort} repeat
deklarojme konstantet, tipet dhe variblat njesoj si tek kerkim_binar_1 majtas := majtas +1
var until A[majtas] > boshti;
ndares : integer; {shqyrton majtas}
repeat
procedure rendit_shpejt (var A : tabele_numrash; fillim, fund : integer); djathtas := djathtas - 1
{kjo procedure merr si parameter nje tabele me reference dhe kryen renditjen e saj ne vend until A[djathtas] <= boshti;
me} {ane te metodes se shpejte, e ashtuquajtura quick sort}
{shkemben elementet ku jemi pozicionuar}
shkembe (A[majtas], A[djathtas])
procedure particion (var ndares : integer);
until majtas > djathtas;
{me particion do te kuptojme procesin e ndarjes ne pjese referuar nje boshti (pivot); kjo}
{procedure particionon (ndan ne pjese) A[fillim] .. A[fund] tek indeksi ndares duke {kthen mbrapsht shkembimin e fundit}
perdorur} {A[fund] si pike reference} shkembe (A[majtas], A[djathtas]);
{percakton ndaresin dhe boshtin e ri}
var ndares := majtas;
majtas, djathtas : integer; A[fund] := A[ndares];
boshti : tip_elementi; A[ndares] := boshti;
end {particion};
procedure shkembe (var a, b : tip_elementi);
var begin {quicksort}
t : tip_elementi; if fillim < fund then
begin {shkembe} begin
t := a; particion (ndares);
a := b; rendit_shpejt (A, fillim, ndares -1);
b := t; rendit_shpejt (A, ndares +1, fund);
end {shkembe}; end
end {quicksort};
begin {particion} begin {MAIN}
{inicializimi} ndares := n;
majtas := fillim – 1; rendit_shpejt (A, 1, n);
djathtas := fund; end.
boshti := A[djathtas];
36
EFIKASITETI (ANALIZA E KOMPLEKSITETIT).
38
EFIKASITETI (ANALIZA E KOMPLEKSITETIT).
39
PYETJE
40