Download as pdf or txt
Download as pdf or txt
You are on page 1of 18

6 Strukturë të Dhënash |1

Kapitulli 6

Tipet Kryesore Abstrakte të të Dhënës - LISTA

6.1 Përcaktimet Kryesore

Lista është një strukturë fleksibël sepse ajo mund të shtohet dhe pakësohet sipas kërkesës,
dhe elementët mund të kapen, futen, ose fshihen në çdo pozicion brenda saj. Listat
gjithashtu mund të lidhen së bashku ose të zbërthehen në nën-lista.

Listat përbëhen nga objekte që krijohen gjatë ekzekutimit të programit, pra ato janë
struktura dinamike. Ky është tipari thelbësor që i dallon ato nga strukturat e tjera si array,
record-i, etj., që janë struktura statike të krijuara në kohën e kompilimit të programit.
Matematikisht, një listë është një varg me zero ose më tepër elementësh të një tipi të dhëne
(të cilin në përgjithësi e quajmë elementtype). Në këtë varg dallohet koka e listës (një
element) dhe pjesa tjetër e vargut (mbetja e listës) që në vetvete është gjithashtu një listë.

Shpesh paraqesim një listë të tillë si një varg elementësh të ndarë me presje:

a1, a2, a3, …, an ku n >= 0, dhe çdo ai është e tipit elementtype.

Numri n i elementeve quhet gjatësia e listës. Duke supozuar qe n >= 1, themi që a1 është
elementi i parë dhe an është elementi i fundit. Në qoftë se n = 0, do të thotë që kemi një listë
boshe, e cila nuk ka elemente.

Një veçori e rëndësishme e një liste është që elementët e saj mund të organizohen në formë
lineare, që radhiten sipas pozicionit tyre në listë. Themi që ai paraprin ai +1 për i = 1, 2, …,
n-1, dhe ai ndjek ai-1 për i = 2, 3, ..., n. Gjithashtu, themi që elementi ai është në pozicionin
i. Është gjithashtu e volitshme të pranohet ekzistenca e një pozicioni që ndjek elementin e
fundit në një listë. Funksioni END(L) do të kthejë pozicionin që vjen pas pozicionit n në një
liste L prej n-elementësh. Shënojmë që pozicioni END(L) ka një distancë nga fillimi i listës
që ndryshon ndërkohë që lista shtohet ose pakësohet (shkurtohet), ndërkohë që të gjithë
pozicionet e tjera kanë një distancë fikse nga fillimi i listës.

Më poshtë prezantohen bashkësia e veprimeve që mund të bëhen me listat. Në veprimet e


mëposhtme do të përdorim shënimin L, një listë objektesh të tipit elementtype, x është një
objekt i këtij tipi, si dhe p është e tipit position. Shënojmë që position është një tjetër tip të
dhëne, paraqitja e të cilit do të ndryshoj në varësi të mënyrës së implementimit të listës.
Megjithëse ne do t’i mendojmë pozicionet si të plotë, në praktikë, ato mund të kenë paraqitje
tjetër.

B. Vika & Dh. Tole


6 Strukturë të Dhënash |2

1. INSERT(x, p, L) – Shton elementin x në pozicionin p të listës L, duke zhvendosur


elementët nga pozicioni p dhe deri në fund të listës, tek një pozicion ngjitur më pas. Çka
do të thotë që në qoftë se L është a1, a2, …, an , atëherë L do të bëhet a1, a2, …, ap-1, x,
ap, …, an. Në qoftë se p është END(L), atëherë L bëhet a1, a2, …, an, x. Në qoftë se lista
L nuk ka pozicion p, atëherë rezultati është i papërcaktuar.
2. LOCATE (x, L) -- Ky funksion kthen pozicionin e elementit x në listën L. Në qoftë se x
shfaqet më shumë se njëherë, atëherë do të kthehet pozicioni i rastit të parë të ndeshur.
Në qoftë se x nuk shfaqet fare, atëherë do të kthehet vlera END(L).
3. RETRIEVE (p, L) -- Ky funksion kthen elementin e pozicionit p në listën L. Rezultati
është i papërcaktuar në qoftë se p = END(L) ose në qoftë se L nuk ka pozicion p.
4. DELETE (p, L) -- Fshin elementin e pozicionit p në listën L. Nëse L është a1, a2, …, an,
atëherë L bëhet a1, a2, …, ap-1, ap+1, …, an. Rezultati është i papërcaktuar në qoftë se L
nuk ka pozicion p ose p = END(L).
5. NEXT(p, L) dhe PREVIOUS(p, L) -- kthejnë përkatësisht pozicionet pasardhëse dhe
paraardhëse të pozicionit p në listën L. Në qoftë se p është pozicioni i fundit në L, atëherë
NEXT(p, L) = END(L). NEXT është i papërcaktuar nëse p është END(L). PREVIOUS
është i papërcaktuar në qoftë se p është 1. Që të dy funksionet janë të papërcaktuar nëse
L nuk ka pozicion p.
6. MAKENULL(L) -- Ky funksion e kthen listën L në listë boshe dhe kthen pozicionin
END(L).
7. FIRST(L) -- Ky funksion kthen pozicionin e parë në listën L. Nëse L është boshe,
pozicioni që kthehet është END(L).
8. PRINTLIST(L) -- Afishon elementët e listës L sipas radhës në të cilën ato ndodhën në
listë.

Shembull 6.1 Le të shkruajmë, duke përdorur këto veprime, një procedurë PURGE (Pastro)
që merr një listë si argument, të dhënë input dhe eliminon përsëritjet – dublikatat nga lista.

Elementët e listës janë të tipit elementtype. Një listë e përbërë nga të tillë elemente ka tipin
LIST, një marrëveshje që do ta përdorim në vazhdim në këtë kapitull. Supozojmë që kemi
një funksion:

Function same(x, y: elementtype): Boolean,

Që merr vlerën True nëse x dhe y janë “të njëjtë apo identikë” dhe False në të kundërt.
Nocioni i të qenit të njëjtë qëllimisht është lënë i pacaktuar. Nëse elementtype është Real,
për shembull, mund të kërkojmë që same(x, y) të jetë True nëse dhe vetëm nëse është i
vërtetë kushti x = y. Megjithatë, nëse elementtype është një record që përmban numrin e
llogarisë, emrin dhe adresën e një nënshkruesi si në deklarimin më poshtë:

Type elementtype
Declare acct_no: Integer

B. Vika & Dh. Tole


6 Strukturë të Dhënash |3

Declare name: String


Declare address: Array [1..50] of Char
EndType

Në këtë rast, ne mund të duam që same(x, y) të jetë True nëse x.acct_no = y.acct_no.

Më poshtë paraqitet kodi për procedurën PURGE. Variablat p dhe q, të tipit position, janë
përdorur për të treguar dy pozicione në listë. Ndërsa programi ekzekutohet, çdo element që
ndodhet majtas pozicionit p dhe është dublikatë e elementin që ndodhet në p fshihet nga
lista. Në një përsëritje të ciklit nga instruksioni (2) deri në atë (11), q përdoret për të skanuar
listën që nga pozicioni pasues i p-së, për të fshirë të gjitha kopjet e njëjta të elementit në
pozicionin p. Më pas p zhvendoset në pozicionin pasardhës dhe procesi përsëritet.

Procedure PURGE(L: List)


Declare p, q: position
(1) p  FIRST(L)
(2) While p <> END(L)
(3) q  NEXT(p, L);
(4) While q<>END(L)
(5) If same(RETRIEVE(p, L), RETRIEVE(q, L)) then
(6) DELETE(q, L)
(7) Else
(8) q  NEXT(q, L)
(9) EndIf
(10) EndWhile
(11) p  NEXT(p, L)
(12) EndWhile
EndProcedure //{PURGE}

Siç është shkruar algoritmi është i pavarur nga mënyra në të cilën janë implementuar listat.
Një çështje me vlerë për t’u evidentuar lidhet me trupin e ciklit të brendshëm, rreshtat (4)
deri te (10) në skemën e mësipërme. Kur ne fshijmë elementin e pozicionit q në rreshtin (6),
elementët që ishin në pozicionet q+1, q+2, ... , e me radhë, zhvendosen një pozicion më
përpara në listë. Në veçanti, mund të ndodh që q të jetë pozicioni i fundit në L, vlera e q-të
do të bëhet END(L). Në rastin kur ekzekutohet rreshti (8), NEXT(END(L)) do të prodhojë
një rezultat të papërcaktuar. Për këtë arsye, është e rëndësishme që brenda ciklit me kushtin
q = END(L) në rreshtin (4), të ekzekutohet ose (6) ose (8), por kurrë të dy instruksionet
njëra pas tjetrës.

6.2 Paraqitja e Listave

Mënyra e paraqitjes së listave është e lidhur në një farë mase me trajtimin që do t’i bëhet
kësaj strukture në një situatë konkrete: në rastet kur do të ketë shumë heqje ose shtime

B. Vika & Dh. Tole


6 Strukturë të Dhënash |4

elementësh të rinj, atëherë do të përdoret një strukturë dinamike për paraqitjen e tyre
nëpërmjet pointerave. Në rastin tjetër, kur lista qëndron në kujtesë dhe përdoret vetëm si
burim informacioni, pa hequr ose shtuar elementë të rinj, rezervimi dinamik i saj nuk është
i nevojshëm, prandaj që mënyra më e mirë për ta paraqitur listën është me anë të tabelës.
Në vijim të këtij seksioni do të ilustrojmë karakteristikat për dy mënyrat e paraqitjes së
listës.

6.1 Paraqitja me anë të tabelës.

Në paraqitjen e listës nëpërmjet tabelës, elementët ruhen në qeliza të njëpasnjëshme të një


tabele.
Në këtë lloj paraqitjeje, e përcaktojmë tipin LIST si një record që ka dy fusha. Fusha e parë
është një tabelë me elemente, gjatësia e së cilës është e mjaftueshme për të mbajtur listën
me madhësinë maksimale të nevojshme për problemin që do të përdoret. Fusha e dytë është
një numër i plotë (Integer), last që tregon pozicionin e elementit të fundit të listës në tabelë.
Elementi i i-të i listës është në qelizën e i-të të tabelës, për 1=< i = last. Pozicionet në listë
paraqiten nga numra të plotë, pozicioni i i-të paraqitet nga numri i plotë i. Funksioni END(L)
kthen vetëm last+1, pra në rastin e paraqitjes së listës me vektorë kthen indeksin e pozicionit
të lirë pas elementit të fundit të listës.
1 Elem.i pare
2 Elem.i dyte

Elementët e
listë në një
moment të
caktuar
last Elem.i fundit

Hapsirë e
lirë që mund
gjmaks
të përdoret
elements për listën
Figura 6.1: Vizualizimi i paraqitjes së listes me tabele

Deklarimet e rëndësishme që duhen paraqitur në këtë rast janë si më poshtë:

Constant gjmaks = 100 // {vlerë konstante e përshtatshme}


Type LIST
Declare elements: Array [1... gjmaks] Of Elementtype
Declare last: Integer
EndType
Type position = Integer

B. Vika & Dh. Tole


6 Strukturë të Dhënash |5

Function END(L: LIST) : position


Return (L.last +1)
EndFunction // {FUNDI}

Më poshtë jepen implementimet për veprimet INSERT, DELETE dhe LOCATE mbështetur
në paraqitjen e listës nëpërmjet tabelës.

a) INSERT zhvendos elementët e pozicioneve p, p+1, …, last respektivisht në pozicionet


p+1, p+2, …, last+1 dhe më pas vendoset elementi i ri në pozicionin p. Në rast se nuk
ka vend në tabelë për të shtuar një element, atëherë thërritet rutina error , e cila bën që
të printohen argumentet e saj, dhe më pas ndërpritet ekzekutimi i programit.

Procedure INSERT ( x:elementtype, p:position, L:LIST)


// shton x në pozicionin p të listës L që konsiderohet e krijuar
If L.last >= gjmaks Then
error (“Lista eshte plot.”)
Else If (p > L.last+1) or (p < 1) Then
error (“Pozicioni nuk ekziston.”)
Else
For q  L.last downto p
L.element[q+1]  L.element[q]
Next q
L.last  L.last+1
L.element[p]  x
EndIf
EndIf
EndProcedure //{INSERT}

b) DELETE fshin elementin në pozicionin p duke lëvizur elementët nga pozicionet p+1,
p+2, …, last në pozicionet p, p+1, …, last-1.

Procedure DELETE ( p:position , L: LIST);


//Fshin elementin që ndodhet në pozicionin p të listës L
If (p > L.last) or (p < 1) Then
error (“ Pozicioni nuk ekziston. “)
Else
L.last  L.last – 1
For q  p To L.last
L.element[q]  L.element [ q+1]
Next q
EndIf
EndProcedure //{DELETE}

B. Vika & Dh. Tole


6 Strukturë të Dhënash |6

c) LOCATE në mënyrë të njëpasnjëshme skanon tabelën për të parë për një element të
dhënë. Në rast se elementi nuk gjendet, LOCATE kthen last+1.
Function LOCATE ( x:elementtype, L:LIST) Returns position;
//kthen pozicionin e x në listën L
For q  1 To L.last
If L.element[q] = x Then
Return(q)
EndIf
Next q
Return (L.last+1) //nese nuk gjendet
EndFunction //LOCATE

6.2 Shembuj mbi implementimin e listës me array

1. Inicializimi i një liste L: 3. Kontrolli nëse një listë L e krijuar është


Procedure CREATE (L:LIST) plot ose jo:
L.last  0 Function FULL (L:LIST) Returns
EndProcedure Boolean
If L.last = gjmaks Then
2. Kontrolli nëse një listë L e krijuar është Return True
bosh ose jo: Else Return False
Function EMPTY (L:LIST) Returns EndFunction
Boolean
If L.last = 0 Then 4. Gjetja e numrit të elementëve
Return True (madhësisë) për një listë ekzistuese L:
Else Return False Function SIZE (L:LIST) Returns
EndFunction Integer
Return L.last
EndFunction

5. Shtimi i një elementi x: elementtype në krye të listës L ekzistuese:


Procedure SHTO_KRYE( x:elementtype, L:LIST)
If L.last >= gjmaks Then
error (‘Lista plot’)
Else
For q  L.last DownTo 1
L.element [q+1]  L.element[q]
Next q
L.last  L.last + 1
L.element[1]  x
EndIf
EndProcedure

Të shihet si një ushtrim shtimi i një elementi x: elementtype në fund të listës ekzistuese L.
B. Vika & Dh. Tole
6 Strukturë të Dhënash |7

6. Fshirja e elementit të parë të listës së krijuar L:


Procedure FSHI_I_PARI (L:LIST)
L.last  L.last - 1
For q  1 To L.last
L.element[q]  L.element[q+1]
Next q
EndProcedure

Të shihet si një ushtrim fshirja e elementit të fundit të listës ekzistuese L.

6.3 Paraqitja e LISTAVE me anë të shënjuesve (Lista e lidhur - Linked List)

Kjo lloj paraqitjeje na shpëton nga përdorimi i vazhdueshëm i memories për ruajtjen e një
liste dhe si pasojë edhe nga zhvendosja e elementëve për të liruar hapësirë për elementët e
rinj ose për të mbyllur boshllëqet e krijuara nga fshirja e elementëve. Megjithatë, ne e
paguajmë një çmim, atë të hapësirës plotësuese për pointer-in.

Në këtë paraqitje, një listë është e përbërë nga qeliza, ku secila prej tyre përbëhet nga një
element i listës dhe një pointer që shënon tek qeliza tjetër fqinjë në listë. Në qoftë se lista
është a1, a2, …, an qeliza që mban ai ka një pointer që shënjon qelizën që mban ai+1, për
i=1, 2, …, n-1. Qeliza që mban an ka një pointer vlera e së cilës është NULL (hiç, zero).
Ka gjithashtu një qelizë header (koka apo kreu), kjo për paraqitjen me qelizë Dummy, që
shënon tek qeliza që mban a1; koka nuk mban element. Në rastin e një liste boshe, pointer-
i i qelizës header-it është NULL, dhe nuk ka qeliza të tjera.

Figura më poshtë paraqet një listë të kësaj forme.

header
a1 a2 an NULL

Figura 6.Error! No text of specified style in document..2:Vizualizimi i paraqitjes së listës me pointer

Në rastin e kësaj paraqitjeje është e përshtatshme të përdoret një përcaktim i pozicionit që


është diçka ndryshe nga përcaktimi i pozicionit në paraqitjen me anë të tabelës. Këtu,
pozicioni i do të jetë një qelizë pointer që mban adresën e elementit ai për i=2, 3, …, n.
Pozicioni 1 është një pointer që ka të njëjtën vlerë adrese me atë të pointer-it në header, dhe
pozicioni END(L) është një pointer në qelizën e fundit të listës L. Tipi i një liste ndodh të
jetë i ngjashëm me atë të pozicionit – është një pointer në një qelizë. Formalisht mund të
përcaktojmë pjesët kryesore të një strukture të dhënash të tipit listë si më poshtë.

B. Vika & Dh. Tole


6 Strukturë të Dhënash |8

Type tipqelize
Declare element : elementype
Declare pas : ^ tipqelize
endType

Type LIST = ^ tipqelize


Type position = ^ tipqelize

Përcaktimi i funksionit END(L) është si më poshtë:

Function END (L: LIST) Returns position


// kthen nje shenjues ne qelizen e fundit te L
qL
While q^.pas <> NULL
q  q^.pas
EndWhile
Return(q)
EndProcedure

Ky funksion punon duke lëvizur shënjuesin q nëpër listë nga koka, derisa të arrijë fundi, i
cili dallohet nga fakti që q tregon tek një qelizë që ka një shënjues NULL. Vëmë re që kjo
paraqitje e funksionit END është jo i efektshëm, pasi kërkon që të kontrollohet e gjithë lista
sa herë që ne na duhet të llogarisim funksionin END(L).
Nëse është e nevojshme të bëhet kjo gjë shpesh, atëherë ne ose 1) mund të përdorim një
paraqitje të listës që përfshin një pointer tek qeliza e fundit, ose 2) të zëvendësojmë
përdorimet e END(L) aty ku është e mundur. P.sh., kushti: p <> END(L) mund të
zëvendësohet me: p^.pas <> NULL.

Le të shohim tani se si paraqiten katër veprimet INSERT, DELETE, LOCATE, dhe


MAKENULL duke përdorur paraqitjen me pointer të listave.

Procedure INSERT (x: elementtype, p: position)


temp  p^.pas (1)
AllocateMemory(p^.pas) (2)
p^.pas^.element  x (3)
p^.pas^.pas  temp (4)
EndProcedure // {INSERT}

B. Vika & Dh. Tole


6 Strukturë të Dhënash |9

p
a b …

(a)

p
a b

(2)
x …

(3) .(4)
p

(1) (b)
Figura 6.Error! No text of specified style in document..3: Diagrama e INSERT

Në diagramën e mësipërme (a) tregon situatën përpara ekzekutimit të INSERT. Ne duam të


fusim një element të ri përballë qelizës që përmban b, kështu që p është një shënjues mbi
qelizën e listës që përmban shënjuesin mbi b.

Në rreshtin (1) , temp vendoset për të treguar qelizën që përmban b. Në rreshtin (2) krijohet
një qelizë e re e listës dhe fusha pas e qelizës që përmban a bëhet që të tregojë mbi këtë
qelizë të re. Në rreshtin (3) fusha element e qelizës së re të krijuar merr vlerën x , dhe në
rreshtin (4) fusha pas merr vlerën temp, pra shënjon mbi qelizën që përmban b. (b) tregon
rezultatin e ekzekutimit të INSERT. Shënjuesit e rinj janë paraqitur me vija të ndërprera
dhe të markuar nga numri që tregon hapin në të cilin ato janë krijuar.

Procedure DELETE (p: position)


p^.pas  p^.pas^.pas
EndProcedure //{DELETE}


p a b c

Figura 6.Error! No text of specified style in document..4: Diagrama e DELETE

Procedura DELETE është më e thjeshtë. Skema e mësipërme tregon përpunimin e


shënjuesve të kësaj procedure. Shënjuesit e vjetër paraqiten me vijë të plotë ndërsa
shënjuesit e rinj me vijë të ndërprerë.

B. Vika & Dh. Tole


6 Strukturë të Dhënash | 10

Function LOCATE ( x:elementtype, L:LIST) Returns position


PL
While p^.pas <> NULL
If p^.pas.element = x Then
return p
Else
p  p^.pas
EndIf
EndWhile
return p //{Nese nuk gjendet}
EndFunction //{LOCATE}

Function MAKENULL ( L:LIST) Returns position


AllocateMemory (L)
L^.pas  NULL
return L
EndFunction // {MAKENULL}

Shembuj mbi listat e lidhura

1. Inicializimi i një liste L (pa qelizë Dummy):

Procedure Inicializo_liste ( L:LIST)


//{inicializon L – boshe}
L  NULL
EndProcedure

2. Krijimi i një liste lineare (pa qelizë Dummy):

Function Krijo_Liste( ) Returns LIST


Declare L: LIST; vazhdo, x: Integer; el_iri: position
L  nil //{krijohet lista boshe}
vazhdo  0
While vazhdo = 0
Input x
AllocateMemory (el_iri)
el_iri^.pas  L
L  el_iri
Input vazhdo
EndWhile
return L
EndFunction

B. Vika & Dh. Tole


6 Strukturë të Dhënash | 11

3. Gjatësia e listës lineare (pa qelizë Dummy):

Function GjatL (L:LIST) Returns Integer


Declare Nr: Integer, Sh: ^tipqelize
Nr  0
Sh  L
While Sh <> NULL
Nr  Nr+1
Sh  Sh^.pas;
EndWhile
Return Nr
EndFunction

4. Ndërtimi i një funksioni logjik që tregon nëse në listën L gjendet elementi me vlerë VL:

Function kerko_vl (L:LIST, VL:Integer) Returns Boolean


Declare ugjet: Boolean; sh: ^tipqelize
ugjet  False
If L = NULL Then
ugjet  False
Else
sh  L
While ( sh^.el <> VL ) and (sh^.pas <> nil)
sh  sh^.pas;
EndWhile
ugjet  (sh^.el=VL)
EndIF
return ugjet
EndFunction

6.3 Krahasimi i Metodave

Ne mund të bëjmë pyetjen nëse është më mirë të përdorim një paraqitje me pointer apo një
paraqitje me tabelë të listës në një situatë të caktuar. Shpesh përgjigja varet se cilat veprime
kemi ndërmend të kryejmë, ose cilat do të kryhen më shpesh. Në raste të tjera, vendimi varet
nga fakti se sa gjatë duhet të qëndrojë lista.

Përfundimet kryesore që merren në konsideratë janë si më poshtë:


• Paraqitja me tabelë na kërkon të specifikojmë madhësinë maksimale të një liste në
kohën e kompilimit. Në qoftë se ne nuk mund të vendosim një kufi për gjatësinë në
rritje të listës, ka mundësi që ne më mirë të zgjedhim paraqitjen e listës nëpërmjet
pointer-ve.
B. Vika & Dh. Tole
6 Strukturë të Dhënash | 12

• Disa veprime zgjasin më tepër në një paraqitje se në tjetrën. P.sh., INSERT dhe
DELETE ndjekin një numër konstant, të pandryshueshëm, hapash për një listë të
lidhur, por kërkojnë një kohë në proporcion me numrin e elementëve të
njëpasnjëshëm kur përdoret paraqitje me tabela. Përkundrazi, ekzekutimi i
PREVIOUS dhe END kërkon kohë konstante në paraqitjen me tabelë, por kohë
proporcionale me gjatësinë e listës nëse përdoret paraqitja me pointer.
• Në qoftë se një program thërret për shtim ose fshirje që prek elementin e një
pozicioni të shënuar nga disa variabla të tipit position, dhe vlera e këtij variabli do
të përdoret më vonë, atëherë paraqitja me shënjues nuk mund të përdoret sikurse
ne e kemi përshkruar atë këtu. Si një parim kryesor, pointer-at duhet të përdoren
me kujdes dhe kufizim të madh.
• Paraqitja me tabelë mund të shpenzojë hapësirë, duke qenë se përdorë maksimumin
e hapësirës pavarësisht nga numri i elementëve aktuale në listë në çdo kohë.
Paraqitja me pointer përdor vetëm aq hapësirë sa është e nevojshme për elementët
që ndodhen aktualisht në listë, por kërkon hapësirë për pointer-at në çdo qelizë.

6.4 Listat Lineare të Lidhura me dy-Drejtime

Në një numër aplikimesh ne mund të duam të përshkojmë një listë në mënyrë të efecientë
në të dy drejtimet: nga koka tek fundi dhe anasjelltas. Ose, për një element të dhënë, ne
mund të duam të përcaktojmë shumë shpejt elementët paraardhës dhe pasardhës. Në situata
të tilla ne mund të duam t’i japim çdo qelize në një listë një pointer si për qelizën
paraardhëse ashtu edhe për atë pasardhëse, duke sugjeruar kështu listat lineare me dy-
drejtime.

… …
… …
Figura 6.Error! No text of specified style in document..5: Vizualizimi i paraqitjes së listës me dy-drejtime

Një avantazh i rëndësishëm i listave me dy-drejtime është që ne mund të përdorim një


pointer mbi qelizën që mban elementin e i-të të listës për të paraqitur pozicionin i.
Çmimi i vetëm që ne paguajmë në këtë rast është prezenca e një pointer-i shtesë në secilën
qelizë dhe procedura më të gjata për disa prej veprimeve kryesore me listat. Nëse ne
përdorim pointer-at, ne mund të deklarojmë qelizat të cilat përbehen nga një element dhe
dy pointer-a, si tipi i deklaruar më poshtë:

Type tipqelize
Declare element : elementtype;
Declare pas, para : ^ tipqelize
EndType
Type position = ^ tipqelize;

B. Vika & Dh. Tole


6 Strukturë të Dhënash | 13

Më poshtë po paraqesim procedurën e fshirjes së një elementi në pozicionin p të listës.

Procedure DELETE ( p: position)


If p^.par <> NULL Then
// {fshin nje qelize qe nuk eshte e para}
p^.para^.pas  p^.pas
EndIF
If p^.pas <> NULL Then
//{fshin nje qelize qe nuk eshte e fundit}
p^.pas^.para  p^.para
EndIF
EndProcedure //{DELETE}

p
Figura Error! No text of specified style in document.Error! No text of specified style in
document..6: Veprimi DELETE në listën e lidhur me dy-drejtime

Në figurën e mësipërme shigjetat me vijë të plotë paraqesin pointer-at e vjetër, ndërsa ato
me vijë të ndërprerë pointer-at e rinj.
Së pari, ne përcaktojmë qelizën paraardhëse duke përdorur fushën para. Bëjmë që fusha
pas e kësaj qelize të tregojë tek qeliza që është një pozicion pas elementit të referuar nga
pointer-i p. Më pas bëjmë që fusha para e kësaj qelize pasardhëse të tregojë tek qeliza që
është një pozicion përpara elementit të referuar nga pointer-i p. Qeliza e treguar nga p bëhet
e papërdorshme dhe mund të ripërdoret automatikisht nëse është e nevojshme.

B. Vika & Dh. Tole


6 Strukturë të Dhënash | 14

6.5 Disa zbatime te listave lineare

6.5.1 Matricat e rralla

Matricat e rralla janë matricat ku pjesa dërmuese e elementëve kanë të njëjtën vlerë,
zakonisht zero; kurse elementët e tjerë, të pakët në numër, kane vlera të ndryshme.
Matricat e rralla janë një dukuri e zakonshme në fusha të ndryshme të matematikës, fizikës,
etj.

P.sh. matrica A e mëposhtme është matricë e rrallë:

0 0 0 -3 0
0 0 0 0 0
0 0 5 0 7
A = 0 0 0 0 0
0 0 10 0 0
7 9 0 1 0
0 0 0 0 3

Matrica e rrallë Anxm ka n x m elementë, por vetëm pak prej tyre kanë nevojë për rezervim
të mirëfillte. Në rastin e mësipërm, vetëm 8 prej 35 elementëve kanë nevojë për rezervim.
Nëse matrica e mësipërme do të deklarohej si një tabelë, atëherë për të do të rezervoheshin
35 vende në kujtesë, gjë që do të sillte një shpërdorim të saj. Do të ishte më e efektshme që
në kujtesë të rezervoheshin vetëm elementët që janë të ndryshëm nga zero së bashku me
vendndodhjen e tyre në matricë. Këtë mund ta bëjmë duke përdorur listat.

Elementët e listës do të përmbajnë vlerën e një elementi të matricës si dhe rreshtin dhe
kolonën ku ndodhet ky element në matricë.
Le të shohim më konkretisht teknikën e paraqitjes së një matrice të rrallë nëpërmjet listave
të lidhura.

Së pari ndërtohet një array V me n elementë (aq sa është numri i rreshtave të matricës). Çdo
element në këtë array do të ketë adresën e kokës së listës që mban të gjithë elementët e
ndryshëm nga zero në rreshtin përkatës të matricës, në qoftë se në ketë rresht gjendet të
paktën një element i ndryshëm nga zero. Në rast se ky rresht i ka të gjithë elementët e
barabartë me zero, atëherë në këtë pozicion të array-it vendoset vlera NULL.

B. Vika & Dh. Tole


6 Strukturë të Dhënash | 15

Figura 6.Error! No text of specified style in document..7: paraqitja e matricës së rallë A me listë të lidhur

Paraqitja e një matrice të rrallë me lista

Deklarimi i strukturës së mësipërme do të ishte:

Constant n = 7 // numri i rreshtave


Type el
Declare vl : Integer
Declare sh: Integer
Declare pas: ^el
EndType

Type list = ^ el
Type vshenjues = array[1..n] Of list

Le të shohim procedurën e gjetjes së elementit më të madh si dhe të vendndodhjes së tij në


matricën e mësipërme.
Bredhja e matricës realizohet duke bredhur fillimisht array-in. Në qoftë se elementi i radhës
në array është i ndryshëm nga NULL atëherë fillon bredhja e listës që përfaqëson rreshtin
përkatës të matricës. Pra matrica bridhet sipas rreshtave që kanë elementë të ndryshëm nga
zero. Bredhja në listë përfundon kur ndeshet fundi i saj, NULL.

B. Vika & Dh. Tole


6 Strukturë të Dhënash | 16

Procedure Max (V: vshenjues)


Declare emax, i, rreshti, shtylla : Integer; p: ^el
emax  -1010
For i  1 to n
If v[i] <> nil Then
p  v[i]
While p <> nil do
If p^.vl > emax Then
emax  p^.vl
rreshti  i
shtylla  p^.sh
EndIf
p  p^.pas
EndWhile
EndIf
Next i
If emax < 0 Then
emax  0
EndProcedure

6.5.2 Paraqitja e një polinomi me anë të një liste lineare të lidhur.

Për të paraqitur një polinom të plotë duhen rezervuar koeficientet dhe fuqitë e x-it.
Paraqitja me matricë do të sillte një shpërdorim të kujtesës, sepse polinomi mund të jetë i
shkallës së lartë dhe numri i koeficienteve të ndryshëm nga zero mund të jetë shume i vogël.

P.sh, polinomi x100 – 35x47 + 34x7 - x2 mund të paraqitej nga një matricë me dy rreshta dhe
101 shtylla. Në këtë matricë rreshti i parë përmban koeficientet e termave kurse rreshti i
dytë fuqitë përkatëse të x-it. Meqenëse polinomi i mësipërm ka shumicën e koeficienteve të
barabartë me zero, matrica përfaqësuese do të ishte një matricë e rrallë. Në këtë mënyrë
edhe polinomi do të paraqitet me një listë. Çdo element i listës do të jetë një regjistrim me
tri fusha: në fushën e parë do të vendoset koeficienti i termit, në të dytën fuqia përkatëse e
x-it, kurse në fushën e tretë adresa e elementit pasardhës.

Për shembull, polinomi P4 = 12x4 - 4x + 1 do të paraqitet nga lista e mëposhtme:

Figura 6.8:Paraqitja e Polinomit me anë të Listë së lidhur

Deklarimi i tipit të listës në këtë rast do të ishte:

B. Vika & Dh. Tole


6 Strukturë të Dhënash | 17

Type el
Declare k : Integer
Declare f : Integer
Declare pas : ^el
EndType
Type list = ^ el

Le të shohim procedurën e krijimit të nj polinomi P:

Procedure krijoP( l: list)


Declare i, f1, f2: Integer; eliri, bishti : ^el
i  0;
Input (f1)
While f1 <> 0 do
Input(f2)
AllocateMemory (eliri)
eliri^.k  f1;
eliri^.f  f2;
If i < 1 Then
eliri^.pas  NULL
l  eliri
bishti  eliri
Else
bishti^.pas  eliri
bishti  eliri
EndIf
Input(f1)
i  i+1
EndWhile
EndProcedure

Le të shohim tani skicën e programit që krijon polinomet P1 dhe P2 dhe afishon


polinomin P = P1+P2.

Procedure Polinomi()
Declare i, f1, f2 :Integer; elr : ^el
krijoP(P1)
krijoP(P2)
i0
While ((P1 <> NULL) and (P2 <> NULL)) do
AllocateMemory (elr)
f1  P1^.f
B. Vika & Dh. Tole
6 Strukturë të Dhënash | 18

f2  P2^.f
If f1 > f2 Then
elr^.k  P1^.k
elr^.f  P1^.f
P1  P1^.pas
Else If f2 > f1 Then
elr^.k  P2^.k
elr^.f  P2^.f
P2  P2^.pas
Else If f2 = f1 Then
elr^.k  P1^.k + P2^.k
elr^.f  P1^.f
P1  P1^.pas
P2  P2^.pas
EndIf
If elr^.k <> 0 Then
elr^.pas  NULL
If i < 1 Then
P  elr
bishti  elr
Else
bishti^.pas  elr
bishti=elr
EndIf
EndIf
i  i+1
EndWhile

If P1 <> nil Then


bishti^.pas  P1
If P2 <> nil Then
bishti^.pas  P2
While P <> nil do
output (P^.k, P^.f)
P  P^.pas
EndWhile
EndProcedure

B. Vika & Dh. Tole

You might also like