Ulancane Liste

35
VISOKA POSLOVNA ŠKOLA STRUKOVNIH STUDIJA BLACE SEMINARSKI RAD PREDMET: Algoritmi i strukture podataka TEMA: Ulančane liste u java progranskom jeziku

description

liste

Transcript of Ulancane Liste

Page 1: Ulancane Liste

VISOKA POSLOVNA ŠKOLA STRUKOVNIH STUDIJA

BLACE

SEMINARSKI RAD

PREDMET: Algoritmi i strukture podataka

TEMA: Ulančane liste u java progranskom jeziku

Student:

Marijana Nicic 30/11r

Blace, 2013.

Profesor:

dr Branislav Jevtović

Page 2: Ulancane Liste

Ulančane liste

Sadržaj:

1. Osnovni pojmovi i osobine...............................................................................................3

2. Dinamička alokacija..........................................................................................................4

3. Primene ulančanih lista.....................................................................................................6

3.1 Predstavljanje retkih nizova..........................................................................................6

3.2 Predstavljanje skupova..................................................................................................9

3.3 Predstavljanje polinoma..............................................................................................11

4. Operacije sa...........................................................................................................................13

2

Page 3: Ulancane Liste

Ulančane liste

1. Osnovni pojmovi i osobine

Ulančana implementacija linearne liste se naziva ulančanom listom (linked list). Dok su u sekvencijalnoj reprezentaciji uzastopni elementi linearne liste susedni u memoriji, a početne adrese su na fiksnom rastojanju određenom veličinom elementa, u ulančanoj reprezentaciji oni mogu biti bilo gde u memoriji. Kako se logički poredak elemenata ne može izvesti iz fizičkog poretka, mora da postoji drugi način za održavanje ovog poretka. Ovo se postiže tako što element liste sadrži eksplicitnu adresu narednog elementa - pokazivač na njega. Zato svaki element liste (uobičajeni naziv - čvor) pored informacionog sadržaja elementa (oznaka info) sadrži i pokazivač (oznaka next) na sledbenika - čvor koji je sledeći u logičkom poretku (slika 3.1). Kao i ranije, informacioni sadržaj može biti bilo kojeg skalarnog ili strukturiranog tipa, ali je najčešće zapis. Listi se pristupa preko jednog spoljašnjeg pokazivača koji pokazuje na prvi čvor, a koji nije deo liste (oznaka list). Prvi čvor se obično naziva glavom (head) liste. Ukoliko je lista prazna, onda pokazivač list ne ukazuje nikuda i ima vrednost praznog pokazivača (list = nil). Poslednji čvor se obično naziva repom (tail) liste. On nema svoga sledbenika, pa sadrži prazan pokazivač, što je i oznaka kraja liste.

lis t in fo in fo in fon ex t n ex t n ex t

Slika 3.1 Jednostruko ulančana lista

Postoji više vrsta lista u zavisnosti od načina povezivanja. Lista sa slike 3.1, kod koje svaki čvor ukazuje samo na svog sledbenika, naziva se jednostruko ulančanom listom. Ukoliko se po informacionom sadržaju liste info ili nekom njegovom delu može definisati funkcija poređenja i ako su čvorovi uvezani po rastućim (ili opadajućim) vrednostima, kaže se da je lista uređena. U suprotnom, kada poredak ne zavisi od vrednosti sadržaja, lista je neuređena. Ukoliko je lista povezana tako da poslednji čvor ukazuje na prvi čvor, lista je kružna. Lista u kojoj svaki čvor, osim na sledbenika, ukazuje dodatnim pokazivačem (oznaka prev) i na prethodnika je dvostruko ulančana lista. Lista je najčešće homogena što znači da su čvorovi istog tipa. Prilikom izlaganja o operacijama sa listama usvojena je sledeća notacija. Ako je p pokazivač na neki čvor liste, onda info(p) predstavlja korisni sadržaj ovog čvora, next(p) je pokazivač na sledbenika, a prev(p) je pokazivač na prethodnika.

Ulančana lista je veoma fleksibilna reprezentacija opšteg tipa linearne liste koja više ili manje efikasno podržava sve ranije pomenute operacije. Ove operacije se kasnije posebno razmatraju za različite vrste lista.

2. Dinamička alokacija

3

Page 4: Ulancane Liste

Ulančane liste

Ulančana lista je dinamička struktura čiji broj čvorova varira saglasno operacijama umetanja i brisanja. Za razliku od sekvencijalne alokacije, gde se unapred rezerviše prostor za sve elemente strukture, kod ulančane liste prostor za neki čvor se alocira tek kad je to stvarno potrebno, prilikom operacije umetanja tog čvora u listu. Za razliku od umetanja, prilikom operacije brisanja zauzeti prostor treba da se oslobodi i učini raspoloživim za neku naknadnu primenu. Prema tome, kod ulančane reprezentacije neophodno je postojanje nekog mehanizma koji vrši dinamičku alokaciju i dealokaciju prostora.

Pošto ovo izlaganje o listama nije vezano za konkretan jezik i sistem, ovde se uvode neke pretpostavke u skladu sa prethodnim definicijama. Neka je raspoloživi slobodni prostor (storage pool) podeljen u jedinice koje imaju strukturu čvora pretpostavljene liste. Pri formiranju novog čvora liste poziva se posebna funkcija GETNODE koja uzima jedan slobodan čvor i stavlja ga na raspolaganje algoritmu vraćajući njegovu adresu u memoriji (pokazivač na njega).

Kada bi broj slobodnih čvorova bio beskonačan, ne bi bilo potrebe za oslobađanjem prostora koji zauzima čvor kada se on briše iz liste. Međutim, kako je slobodni prostor ograničen, ako ništa drugo onda ograničenom memorijom, potrebno je da se zauzeti čvor, koji se izbacuje iz liste, vrati u slobodan prostor i tako učini raspoloživim za ponovno korišćenje. Za tu svrhu predviđena je procedura FREENODE(p) koja oslobađa čvor sa zadatom adresom p.

Postavlja se pitanje kakva je organizacija slobodnog prostora najpogodnija. Sa stanovišta alokacije bilo bi dovoljno organizovati slobodni prostor kao niz slobodnih čvorova, pa vršiti dodelu od početka tako što bi postojao pokazivač na prvi slobodni čvor. Međutim, kako se čvorovi mogu dealocirati proizvoljnim redom i pošto ih treba učiniti raspoloživim za ponovnu upotrebu, slobodni prostor više nije kontinualan i teško je voditi evidenciju o slobodnim ulazima. Zato je vrlo pogodno da slobodni prostor bude organizovan upravo u vidu ulančane liste slobodnih čvorova.

Prema tome, na početku se svi slobodni čvorovi, obično redom, uvežu u jednostruko ulančanu listu na koju ukazuje globalni pokazivač avail. Funkcija GETNODE izvlači prvi slobodan čvor iz liste, postavlja polje pokazivača na nultu vrednost (nil), vraća njegovu adresu i ažurira pokazivač avail.

GETNODE

if (avail = nil) then

ERROR(Nema slobodnog čvora)

end_if

q = avail

avail = next(avail)

next(q) = nil

return q

4

Page 5: Ulancane Liste

Ulančane liste

Pošto funkcija vodi računa da li ima slobodnih čvorova ili ne, operacija umetanja, koja poziva GETNODE, ne vodi eksplicitno o ovome računa. U ovom slučaju, kao i kasnije u drugim algoritmima pri sličnim situacijama kada se dogodi neuspešan ishod, pretpostavlja se postojanje procedure ERROR koja vrši obradu greške nezavisno od algoritma, javlja odgovarajuću poruku i prekida izvršavanje.

Procedura FREENODE(p) vraća oslobođeni čvor takođe na početak liste, pa se pokazivač avail postavlja na njegovu adresu.

FREENODE( p )

next(p) = avail

avail = p

Kao što će se kasnije videti, opisani način upravo odgovara ulančanoj reprezentaciji steka, pa se ovakva struktura obično naziva stek slobodnog prostora (availability stack). Iako je ova sistemska struktura logički nezavisna od korisničke ulančane liste zauzetih čvorova, posle izvesnog broja operacija one se mogu fizički isprepletati, kao što je prikazano na slici 3.2. Čvorovi u listi slobodnog prostora su predstavljeni kao osenčeni.

lis t

a va il

Slika 3.2 Korisnička lista na koju ukazuje pokazivač list i lista slobodnog prostora na koju ukazuje pokazivač avail

3. Operacije sa jednosruko ulan čanim listama

Tipične operacije sa listom su: pretraživanje, umetanje i brisanje. Operacija kreiranja liste se ne izdvaja posebno, jer se, polazeći od prazne liste, ona izgrađuje uzastopnim operacijama umetanja elementa.

Operacije sa listom najvećim delom manipulišu sa pokazivačima, jer oni održavaju integritet liste kao strukture podataka. Zbog toga treba, na samom početku, definisati legalne manipulacije sa pokazivačima imajući u vidu da su to memorijske adrese. Ovde se pretpostavlja da su sa pokazivačima dozvoljene sledeće aktivnosti:

testiranje pokazivača na nil,

provera na jednakost pokazivača sa drugim pokazivačem,

postavljanje pokazivača na nil,

5

Page 6: Ulancane Liste

Ulančane liste

dodela vrednosti drugog pokazivača ili adrese datom pokazivaču.

3.1 Umetanje u listu

Umetanje novog čvora u neuređenu listu može da bude izvršeno na bilo kojem mestu u listi (početak, sredina, kraj). Umetanje na početak i na kraj su specijalni slučajevi koji će se razmatrati u narednim glavama kada se bude izlagala primena lista u implementaciji steka i reda. Operacija INSERT-AFTER(p, x) umeće u listu novi čvor sa sadržajem x iza čvora čija je adresa zadata sa p.

INSERT-AFTER( p , x )

q = GETNODE

info(q) = x

next(q) = next(p)

next(p) = q

Pošto se dinamički alocira prostor za novi čvor, upiše se polje sadržaja u njega, a zatim sledbenik prethodnog čvora postaje sledbenik novog čvora, dok sam novi čvor postaje sledbenik prethodnog čvora (slika 3.3). Ove dve poslednje operacije obavezno moraju da se jave u datom poretku. Za razliku od sekvencijalne reprezentacije, umetanje ima uticaja samo na dva čvora, na novi čvor i njegovog prethodnika, bez obzira na dužinu liste. Prikazana operacija radi ispravno i u slučaju da se čvor ukazan sa p nalazi na kraju liste.

y z

p

q

y z

p

q

x

Slika 3.3 Umetanje čvora sa sadržajem x iza čvora na koji ukazuje p

Ukoliko se javi potreba za umetanjem novog čvora ispred tekućeg čvora u listi (operacija INSERT-BEFORE), onda mora da se pristupi prethodnom čvoru, jer njegov pokazivač treba povezati na novi čvor. Ovo se na prvi pogled čini nemogućim, jer u nekružnoj jednostruko ulančanoj listi od tekućeg elementa nikako ne može da se pređe na prethodni. Međutim, efektivno se ovakvo umetanje u homogenoj listi ipak može izvršiti tako što se novi čvor prvo ubaci iza tekućeg čvora, a onda oni zamene informacione sadržaje. Na taj način se postiže efekt kao da je novi čvor ubačen ispred ukazanog čvora. Na slici 3.4 je prikazano umetanje čvora sa sadržajem x ispred čvora na adresi p sa sadržajem y.

INSERT-BEFORE( p , x )

q = GETNODE

next(q) = next(p)

info(q) = info(p)

info(p) = x

next(p) = q

6

Page 7: Ulancane Liste

Ulančane liste

y z

p

q

x z

p

q

y

Slika 3.4 Umetanje čvora sa sadržajem x ispred čvora na koji ukazuje p

Problem umetanja u uređenu listu će biti obrađen kada se bude govorilo o implementaciji prioritetnog reda u vidu ulančane liste (poglavlje 5.3.2).

3.2 Brisanje

Operacija brisanja može da ukloni čvor sa bilo kojeg mesta u listi. Kod ulančane reprezentacije steka i reda se razmatra brisanje prvog čvora, a ovde se prikazuje operacija brisanja iz sredine i sa kraja liste. U tom slučaju treba da se preveže lista tako da prethodnik čvora koji se uklanja pokazuje na njegovog sledbenika. Zbog toga, kod nekružne jednostruko ulančane liste, strogo gledano, nije moguće brisati čvor na koji pokazuje pokazivač, jer nema načina da se dođe do njegovog prethodnika da bi mu se ažuriralo polje pokazivača. Zato je pri brisanju tekućeg čvora u operaciji DELETE-AFTER(p) potrebno dati pokazivač p na njegovog prethodnika. Na slici 3.5 je prikazano brisanje čvora sa sadržajem y ispred kojeg se nalazi čvor ukazan sa p.

DELETE-AFTER( p ) q = next(p)next(p) = next(q) FREENODE(q)

x

p

zy

x

p

z

Slika 3.5 Brisanje čvora iza čvora na koji ukazuje pokazivač p

Ukoliko čvor koji se uklanja nije na kraju liste i ako je lista homogena, sličnom dosetkom kao kod umetanja ispred tekućeg čvora, može da se reši problem brisanja čvora na koji pokazuje pokazivač p (operacija DELETE(p)). U tom slučaju treba prvo sačuvati adresu sledećeg čvora q, prepisati njegov sadržaj u čvor na koji ukazuje p, čime se ukazani čvor efektivno briše, a lista prevezuje, da bi se, na kraju, uklonio oslobođeni čvor (slika 3.6).

DELETE( p ) q = next(p)next(p) = next(q) info(p) = info(q) FREENODE(q)

7

Page 8: Ulancane Liste

Ulančane liste

x

p

y

q

y

p

Slika 3.6 Efektivno brisanje čvora na koji pokazuje pokazivač p

3.4 Pretraživanje

Često se javlja potreba lociranja čvora u listi koji ima zadati sadržaj radi pristupa. Struktura liste uslovljava potpuno sekvencijalno pretraživanje počevši od glave liste sledeći lanac pokazivača. Tako operacija SEARCH(list, x) pretražuje neuređenu listu na koju ukazuje pokazivač list i, ukoliko postoji bar jedan čvor sa zadatim sadržajem x, vraća adresu prvog takvog čvora, a ako ne postoji, vraća nil.

SEARCH( list , x ) p = listwhile (p nil) and (info(p) x) do

p = next(p) end_whilereturn p

Dok se kod neuređene liste pri neuspešnom pretraživanju mora proći čitava lista, ako je lista uređena (na primer, neopadajuće) neuspešno pretraživanje se može proglasiti čim se dođe do prvog čvora sa većim sadržajem, a do tada se ne pronađe zadati čvor. Ovu operaciju realizuje funkcija SEARCH-ORD(list, x).

SEARCH-ORD( list , x ) p = listwhile (p nil) and (info(p) < x) do

p = next(p) end_whileif (p nil) and (info(p) > x) then

p = nilend_ifreturn p

Održavanje neuređene liste omogućava brže umetanje, jer se novi čvor može umetati na početak liste. Međutim, neuspešno pretraživanje duže traje, jer se mora proći čitava lista da bi se utvrdilo da traženog čvora nema. S druge strane, kod uređene liste umetanje je složenije, jer se mora ispitati u proseku polovina čvorova, dok kod pretraživanja, kako neuspešnog tako i uspešnog, isto tako treba proći prosečno pola liste. Prema tome, odluka, da li održavati listu uređenom ili ne, treba da se donese na osnovu poznavanja karakteristika aplikacije, zavisno od očekivane frekvencije umetanja ili pretraživanja.

8

Page 9: Ulancane Liste

Ulančane liste

3.5 Ostale operacije

Ponekad se javlja potreba i za nekim drugim korisnim operacijama sa ulančanim listama kao što su: inverzija poretka čvorova u listi, povezivanje dve liste u jednu, nalaženje i-tog čvora, razbijanje jedne liste u dve liste, kopiranje, itd. Ovde su prikazane prve dve pomenute operacije.

Operacija INVERT(list) obrće poredak čvorova u listi na čiji prvi čvor ukazuje pokazivač list tako da prvi čvor postaje poslednji, drugi postaje pretposlednji, itd. Ova operacija koristi tri pokazivača koji se sukcesivno pomeraju od početka do kraja liste, tako da p pokazuje na sledbenika čvora ukazanog sa q, a r na prethodnika čvora ukazanog sa q. U svakoj iteraciji se polje pokazivača čvora ukazanog sa q prebaci sa sledbenika p na prethodnika r i sva tri tekuća pokazivača se pomere za po jedan čvor. Na slici 3.7a je dat izgled liste od tri čvora, a na slikama 3.7b,c i d stanje liste nakon svake od tri iteracije algoritma.

INVERT( list ) p = listq = nilwhile (p nil) do

r = qq = pp = next(p)next(q) = r

end_whilelist = q

Operacija CONCATENATE(list1, list2) nadovezuje listu na koju pokazuje list2 na listu ukazanu sa list1. Prvo se ispitaju specijalni slučajevi kad je jedna ili druga ulazna lista prazna, a ako to nije slučaj, onda se dođe do kraja prve liste, pa se napravi da poslednji čvor prve liste pokazuje na prvi čvor druge liste.

CONCATENATE( list 1, list 2) if list1 = nil then

list1 = list2return

else if list2 = nil thenreturn

end_ifp = list1while (next(p) nil) do

p = next(p)end_whilenext(p) = list2

9

Page 10: Ulancane Liste

Ulančane liste

p

lis t

lis t

q pr

lis t

r q p

lis t

r q p

c )

d )

a )

b )

Slika 3.7 Ilustracija operacije inverzije poretka čvorova liste - izgled liste: a) pre početka operacije, b) posle prve, c)posle druge i d) posle treće iteracije

4. Operacije sa kružno ulančanim listama

Jedan od najvećih nedostataka jednostruke liste je mogućnost kretanja samo u jednom smeru, od glave ka repu. Ako je dat pokazivač na neki čvor, od njega se ne može doći do bilo kojeg čvora u listi ispred njega. Jedan način da se ovaj nedostatak otkloni, a da se ne menja struktura čvora, je pretvaranje liste u kružnu. Umesto da poslednji čvor sadrži prazan pokazivač, on ukazuje na prvi čvor (slika 3.8). Zato je u kružnoj listi moguće iz bilo kojeg čvora doći do bilo kojeg drugog čvora, nezavisno od njegovog položaja.

in fo in fo in fon ex t n ex t n ex tlis t

Slika 3.8 Jednostruko ulančana kružna lista

Zbog osobine simetričnosti kružne liste termini “prvi” i “poslednji” čvor su sada nešto manje prirodni. Ako se pojam prvog i poslednjeg čvora sačuva, postavlja se i pitanje da li je najkorisnije da spoljašnji pokazivač list pokazuje na prvi čvor liste. Analizom operacija može da se dođe do zaključka da je kod kružne liste korisnije da ovaj pokazivač pokazuje na poslednji čvor liste, jer to operacije umetanja čvora na početak i kraj liste, kao i brisanja čvora sa početka i kraja, čini vrlo efikasnim. U ovom slučaju se i operacije umetanja i brisanja na kraju liste izvršavaju u konstantnom vremenu nezavisnom od broja čvorova liste. Zbog toga se ova konvencija najčešće koristi.

10

Page 11: Ulancane Liste

Ulančane liste

Operacija umetanja iza čvora pokazanog pokazivačem p je slična kao i u nekružnoj listi. Jedina razlika se javlja u slučaju kada se ubacuje novi čvor iza poslednjeg čvora u listi na kojeg ukazuje spoljašnji pokazivač. Tada novi čvor postaje poslednji, a spoljašnji pokazivač list treba da pokazuje na njega, pa operacija INSERT-AFTER-C(p, x) mora da ga ažurira. Ovakva situacija je ilustrovana slikom 3.9.

INSERT-AFTER-C( p , x )

q = GETNODE

info(q) = x

next(q) = next(p)

next(p) = q

if (list = p) then

list = q

end_if

lis t

y

y x

lis t

Slika 3.9 Umetanje na kraj kružne liste kod koje spoljašnji pokazivač ukazuje na poslednji čvor

Sličan problem se javlja kod operacije brisanja čvora iza čvora pokazanog pokazivačem p. Ukoliko se briše poslednji čvor u listi, pretposlednji čvor (na koji ukazuje p) postaje poslednji, pa na njega treba premestiti pokazivač list. Ovde se javlja i dodatni logički problem brisanja iza čvora ukazanog sa p ako lista ima samo jedan čvor. Kod nekružne liste je next(p) = nil, pa nema brisanja. Kod kružne liste je next(p) = p, pa praktično treba obrisati sam ukazani čvor. Pošto to semantički ne odgovara ovoj operaciji, obično se u takvoj situaciji brisanje izbegava.

Neke druge operacije su, takođe, efikasnije sa kružnom listom gde spoljašnji pokazivač list pokazuje na poslednji čvor u listi. Ukoliko se održava posebna lista slobodnog prostora iz koje se vrši alokacija operacijom GETNODE pri umetanju, mnogo je lakša dealokacija prostora pri brisanju čitave kružne liste nego nekružne. Dok se kod nekružne liste mora proći čitava lista, kod kružne liste se odjednom može osloboditi čitava lista jednostavnim ažuriranjem pokazivača tako što pokazivači avail i next(list) samo razmene vrednosti.

Operacija spajanja dve liste CONCATENATE-C(list1, list2) sada, takođe, ne zahteva prolazak do kraja prve liste pošto pokazivač list1 ukazuje na poslednji čvor. Na kraju operacije pokazivač list1 ukazuje na poslednji čvor objedinjene liste.

11

Page 12: Ulancane Liste

Ulančane liste

CONCATENATE-C( list 1, list 2)

if (list1 = nil) then

list1 = list2

return

else if (list 2 = nil) then

return

end_if

p = next(list1)

next(list1) = next(list2)

next(list2) = p

list1 = list2

Na slici 3.10 ilustrovana je operacija spajanja dve kružne liste u jednu.

lis t2

+

lis t1

lis t1

Slika 3.10 Spajanje dve kružne liste u jednu

4.1 Kružna lista sa zaglavljem

Ako se vrši pretraživanje kružne liste počevši od prvog čvora, pri neuspešnom pretraživanju dolazi do beskonačne petlje jer nema načina da se detektuje kraj liste (ranije je to bio prazan pokazivač u poslednjem čvoru). Prelazak na čelo liste je moguće prepoznati jedino kad se sačuva spoljašnji pokazivač na prvi čvor, sa kojim se tekući pokazivač stalno upoređuje pri pomeranju kroz listu. Zbog toga se, obično, na početak liste ubacuje poseban čvor koji se naziva zaglavlje liste (slika 3.11a). Ovaj čvor ukazuje na prvi čvor liste, a razlikuje se od drugih po posebnoj vrednosti u polju info koja ne može biti validni sadržaj nekog čvora. Drugi način je postavljanje posebne oznake koja govori da je čvor zaglavlje. U tom slučaju u polje info se mogu smestiti i neke informacije o samoj listi, kao što je broj elemenata, itd.

12

Page 13: Ulancane Liste

Ulančane liste

lis tH

H

a )

b )lis t

Slika 3.11 Jednostruko ulančana kružna lista sa zaglavljem: a) sa čvorovima sadržaja i b) bez čvorova sadržaja

Spoljašnji pokazivač list sada ukazuje na zaglavlje. Zato je ubacivanje novog čvora na početak liste u operaciji INSERT-CH(list, x) malo drugačije.

INSERT-CH( list , x )

p = GETNODE

info(p) = x

next(p) = next(list)

next(list) = p

Kružna lista sa zaglavljem nikada ne može da bude prazna što pojednostavljuje određene operacije, jer nije potrebno detektovati poseban slučaj prazne liste. Kod liste bez ostalih čvorova zaglavlje ukazuje samo na sebe - next(list) = list (slika 3.11b).

5. Operacije sa dvostruko ulančanim listama

Iako se u kružnoj listi od svakog čvora može doći do svakog drugog, prelazak može da bude vrlo neefikasan. Na primer, ako treba od jednog čvora doći do njegovog prethodnika mora se preći čitava lista. Zbog toga je korisno da svaki čvor, pored pokazivača na sledeći čvor, sadrži i pokazivač na prethodni čvor, što znači da je lista dvostruko ulančana. S obzirom na simetričnost liste, pojmovi “prethodnik” i “sledbenik” pomalo gube smisao (možda su prirodniji termini “levi” i “desni”), ali se iz tradicionalnih razloga oni ipak zadržavaju. Kod dvostruko ulančane liste jednako je efikasno kretati se po listi u oba smera, što pokazuje sledeća jednakost (p je pokazivač na neki čvor)

next(prev(p)) = p = prev(next(p)) .

Ovakva lista, takođe, može da bude nekružna ili kružna, sa zaglavljem ili bez njega. Ako p ukazuje na prvi čvor, a q na poslednji čvor, u nekružnoj listi (slika 3.12a) je tada

prev(p) = next(q) = nil

a u kružnoj (slika 3.12b) je

prev(p) = qnext(q) = p .

13

Page 14: Ulancane Liste

Ulančane liste

p q

in fop re v n ex t

in fop re v n ex tp q

Slika 3.12 Dvostruko ulančana lista: a) nekružna i b) kružna

Ako kružna lista ima i zaglavlje, onda je

prev(list) = qnext(list) = pprev(p) = next(q) = list .

Kod kružne liste sa zaglavljem koja nema drugih čvorova oba pokazivača u zaglavlju ukazuju na samo zaglavlje

prev(list) = list = next(list) .

Sa dvostrukom listom su moguće sve ranije razmatrane operacije. One se mogu vrlo fleksibilno izvesti, s tim što su malo složenije, jer treba ažurirati oba pokazivača. Neka je dvostruko ulančana lista kružna i neka ima zaglavlje. Tada se operacija umetanja novog čvora sa informacionim sadržajem x iza čvora ukazanog pokazivačem p, INSERT-AFTER-D(p, x), realizuje kao

INSERT-AFTER-D( p , x )

q = GETNODE

info(q) = x

r = next(p)

prev(q) = p

next(q) = r

next(p) = q

prev(r) = q

Operacija umetanja u opštem slučaju menja pokazivače u tri čvora. Pri ovoj operaciji redosled aktivnosti, označen brojevima na slici 3.13, je takav da se ne izgubi prethodna povezanost liste. Pošto se alocira (1) i inicira sadržaj novog čvora (2), njegovi pokazivači se postave tako da pokazuju na prethodnika p (3) i ranijeg sledbenika čvora p, čvor r, (4). Na kraju se postavi da čvor p ukazuje na novi čvor kao sledbenika (5), a raniji sledbenik od p (čvor r) takođe ukazuje na novi čvor, ali kao na prethodnika (6). Pretpostavke da lista ima zaglavlje i da je kružna veoma pojednostavljuju ovu operaciju. Postojanje zaglavlja omogućava da lista nikada nije prazna, pa ovaj algoritam radi i kada se lista sastoji samo od zaglavlja. Pored toga, kružnost liste oslobađa potrebe da se vodi računa o

14

Page 15: Ulancane Liste

Ulančane liste

graničnim slučajevima. Ukoliko lista ne bi bila kružna, onda bi se moralo voditi računa da li se čvor umeće na kraj liste, a još ako ne bi imala ni zaglavlje, morala bi se predvideti i posebna operacija za ubacivanje na početak liste.

p

q

y z

p

q

y z

x

r

4653

21

Slika 3.13 Umetanje čvora u dvostruko ulančanu listu

Problem brisanja tekućeg čvora se efikasno rešava kod dvostruko ulančanih lista, jer se direktno pristupa i prethodnom i sledećem čvoru pri prevezivanju liste. Operacija brisanja čvora na koji pokazuje pokazivač p, DELETE-D(p), se realizuje na sledeći način:

DELETE-D( p )

q = prev(p)

r = next(p)

next(q) = r

prev(r) = q

FREENODE(p)

Ova operacija, takođe, obrađuje tri čvora: onaj koji se briše, njegovog sledbenika i prethodnika, kao što je prikazano na slici 3.14. Pri brisanju tekućeg čvora njegov raniji sledbenik r postaje sledbenik njegovog ranijeg prethodnika q, a njegov prethodnik postaje prethodnik njegovog sledbenika. Pretpostavka postojanja zaglavlja i kružnost su, opet, bitni za pojednostavljenje operacije, inače bi se moralo voditi računa o specijalnim slučajevima brisanja sa početka i kraja liste.

q rp

y zx

q r

zx

Slika 3.14 Brisanje čvora iz dvostruko ulančane liste

15

Page 16: Ulancane Liste

Ulančane liste

U uslovima ograničenog prostora, kada držanje oba pokazivača u čvoru nije prihvatljivo, a ono je logički potrebno, postoje načini za kompresiju ova dva pokazivača u jedno polje. Na primer, jedno pokazivačko polje ptr u čvoru može da sadrži zbir pokazivača na prethodni i sledeći čvor. Naravno, operacija sabiranja pokazivača mora biti podržana u samom jeziku. Za realizaciju operacija sa listom u ovoj implementaciji neophodno je imati dva spoljašnja pokazivača na dva susedna čvora u listi. Na primer, ako pokazivač p ukazuje na neki čvor u listi, a q ukazuje na njegovog sledbenika, onda se pokazivač na sledbenika s čvora q može izačunati kao s = ptr(q) – p, a prethodnik r čvora p kao r = ptr(p) – q (slika 3.15). Sada je moguće ubaciti čvor ispred čvora p, iza čvora q ili između njih i prebaciti pokazivač p ili q na umetnuti čvor. Takođe je moguće obrisati čvor pokazan sa p ili sa q i postaviti pokazivač na prethodni ili sledeći čvor.

in fo in fo in fop tr p tr p tr

r

in fo p tr

sqp

r+ q p + s

Slika 3.15 Kompresija dva pokazivača u jedno pokazivačko polje

6. Poređenje ulančane i sekvencijalne reprezentacije linearnih listaPošto su prikazane i sekvencijalna reprezentacija linearnih lista u vidu niza i ulančana

reprezentacija u vidu ulančane liste, mogu se izvesti neka komparativna razmatranja njihovih prednosti i nedostataka u pogledu iskorišćenja prostora, efikasnosti operacija sa njima, itd.

Ako se razmatra iskorišćenje prostora, odmah se može primetiti da ulančana reprezentacija traži dodatni prostor za jedan ili dva pokazivača. Međutim, i pored toga, ulančana reprezentacija često troši manje prostora iz sledećih razloga. Ukoliko se informacioni sadržaj elementa sastoji od više polja, pokazivači zauzimaju procentualno mali deo prostora potrebnog za čvor. S druge strane, sekvencijalna reprezentacija zahteva obično fiksnu alokaciju prostora dimenzionisanog na maksimalni mogući broj članova linearne liste, tako da u realnom slučaju dosta prostora može ostati neiskorišćeno. Ulančana reprezentacija koristi dinamičku alokaciju i prostor se odvaja samo kada je stvarno potreban, bez rezervisanja unapred. Kasnije, pri razmatranju implementacije redova i stekova će biti pokazano da je navedena prednost posebno izrazita kada više struktura navedenih tipova treba istovremeno da se realizuju.

Ulančane liste dozvoljavaju efikasno umetanje i brisanje elementa na proizvoljnom mestu, jer se pritom zahteva samo prevezivanje malog broja pokazivača. U tom smislu nizovi su vrlo nepogodni, jer takve operacije zahtevaju pomeranje određenog broja elemenata koji linearno zavisi od ukupnog broja elemenata. Zbog toga je ulančana implementacija uređenih struktura mnogo pogodnija. Ulančane liste po pravilu omogućavaju lakše spajanje dve strukture u jednu, kao i razbijanje jedne strukture u dve.

Međutim, postoje i operacije koje favorizuju sekvencijalnu reprezentaciju. Takva je operacija pristupa proizvoljnom elementu (na primer, i-tom elementu strukture). Dok pristup proizvoljnom elementu niza zahteva fiksno vreme, ulančana lista onemogućava direktan pristup i zahteva sekvencijalno praćenje pokazivača do traženog elementa.

16

Page 17: Ulancane Liste

Ulančane liste

Ulančana reprezentacija dozvoljava mnogo veću fleksibilnost i pogodnosti u implementaciji raznovrsnih struktura kao što su nehomogene liste, liste promenljive dužine, višestruko uvezane liste, itd. Kasnije će posebno biti istaknuta pogodnost ulančane reprezentacije za implementaciju nelinearnih struktura tipa stabla i grafa.

6.1 Vektorska implementacija ulančanih lista

Osnovno sredstvo za ulančanu reprezentaciju predstavljaju pokazivači. U jeziku koji ne podržava pokazivače ipak je moguće realizovati logičku strukturu liste, tako što se njeni čvorovi smeštaju u ulaze rezervisanog vektora L[1:n], gde n predstavlja najveći broj čvorova liste. Svaki ulaz ima polje info, a pokazivači se u polju next simuliraju celobrojnim vrednostima koje predstavljaju indekse u vektoru. Prazan pokazivač se simulira vrednošću 0, jer je to nepostojeći indeks u nizu L. Za listu postoji i jedna spoljašnja celobrojna promenljiva list koja pamti indeks ulaza prvog čvora. Na slici 3.16 je prikazana jedna ovako implementirana lista gde se čvorovi redom nalaze u trećem, petom, prvom, drugom, šestom i četvrtom ulazu.

Sa ovakvom listom se mogu raditi sve operacije kao i sa ulančanom listom sa pokazivačima. Pri umetanju novog čvora u listu uzima se jedan slobodan ulaz, inicijalizuje njegov sadržaj i uveže u listu preko polja next. Brisanje prevezuje listu i oslobađa ulaz vektora.

lis t

in fo

3

n ex t

4

10

5

6

21

2

345

6

Slika 3.16 Vektorska implementacija ulančane liste

Glavni nedostatak je to što se veličina vektora obično statički određuje, pa se mogu desiti slučajevi prekoračenja (kada nema više slobodnih ulaza) ili neefikasnog korišćenja prostora (kada je procenat zauzetih ulaza mali). Pored toga, pristup čvoru liste zahteva izračunavanje adresne funkcije za pristup elementu vektora L[i], dok se to ranije radilo preko pokazivača, bez ikakvog izračunavanja, što je svakako brže. S druge strane, postoje i dve pogodnosti. Prvo, isti vektor se može koristiti za više lista, koje se u njemu “prepliću”. Na taj način alocirani prostor se bolje koristi jer različite liste preraspodeljuju prostor dinamički u skladu sa svojim aktuelnim potrebama. Druga prednost je brže nalaženje prostora za novi čvor (slobodnog ulaza) nego u slučaju dinamičke alokacije kod uobičajene implementacije ulančanih listi koja zahteva pozive sistemskih rutina. U ovom slučaju lista slobodnih ulaza (availability list) se programski održava. Na početku se svi ulazi vektora redom uvežu u listu slobodnih ulaza sledećim programskim segmentom.

avail = 1for i = 1 to n – 1 do

L[i].next = i +1end_forL[n].next = 0

17

Page 18: Ulancane Liste

Ulančane liste

Operacije alokacije i dealokacije čvora GETNODE i FREENODE(p) kasnije veoma efikasno i brzo iz ove liste uzimaju i u nju vraćaju slobodne ulaze. Uzimanje i vraćanje se uvek vrši sa početka liste.

GETNODEif (avail = 0) then

ERROR(Nema prostora)end_ifp = availavail = L[avail].nextreturn p

FREENODE( p ) L[p].next = availavail = p

3.6 Primene ulančanih lista

Ulančane liste imaju mnogostruke primene, pogotovo u slučajevima kada je potrebno efikasno podržati operacije umetanja i brisanja elemenata u dinamičkim skupovima u kojima broj elemenata varira. Ovde se izlažu neke karakteristične primene, kao što su: predstavljanje retkih nizova, predstavljanje skupova i predstavljanje polinoma, a primene u implementaciji drugih linearnih i nelinearnih struktura se razmatraju kasnije, u narednim glavama.

3.6.1 Predstavljanje retkih nizova

U drugoj glavi je već prikazano kako se optimizovanom sekvencijalnom reprezentacijom može uštedeti prostor pri smeštanju retkog niza. Međutim, pokazalo se da je to postignuto na račun smanjene efikasnosti operacija sa takvim nizom. Ulančana reprezentacija retkih nizova pruža mogućnost da se, uz uštedu u prostoru, efikasnost operacija poboljša.

Jedan od glavnih nedostataka vektorske implementacije je to što se pri pojavi novog nenultog elementa ili postavljanju na nulu postojećeg nenultog elementa zahteva pomeranje svih sledećih elemenata u vektoru. Potreba za pomeranjem može da se otkloni ulančavanjem nenultih elemenata i pretvaranjem vektora u listu, pri čemu elementi u listi zadržavaju isti poredak kao u vektoru. Pošto se lista sekvencijalno pretražuje dovoljno je da ona bude jednostruko ulančana. Struktura čvora liste je takva da sadrži n + 2 polja: n polja za indekse po n dimenzija, jedno polje za vrednost elementa i jedno dodatno polje pokazivača na naredni element. Slika 3.17 prikazuje ulančanu reprezentaciju retke matrice sa slike 2.6.

1lis t

3 4 4 5 6 1 12 2

1 9 4 8 7 1 54 54

Slika 3.17 Predstavljanje retke matrice ulančanom listom

18

Page 19: Ulancane Liste

Ulančane liste

Kod ovakvog načina predstavljanja retkog niza umetanje novog elementa i brisanje postojećeg elementa ne zahtevaju nikakvo pomeranje ostalih elemenata, već samo prosto prevezivanje liste. Takva pogodnost je postignuta uz nešto veće zauzeće prostora zbog dodatnog pokazivača. Ovo povećanje je relativno manje ukoliko je dimenzija niza veća (procentualno 100/(n + 1)). S druge strane, kod ulančane reprezentacije prostor se alocira samo za onoliko nenultih elemenata koliko ih trenutno ima, dok vektorska implementacija najčešće zahteva statičko alociranje prostora za maksimalni očekivani broj elemenata.

Međutim, ovakva ulančana reprezentacija nimalo ne doprinosi efikasnosti pristupa proizvoljnom elementu, jer je njeno pretraživanje sekvencijalno. Zbog toga se javlja ideja koja će, zbog jednostavnosti grafičkog predstavljanja, biti ilustrovana na primeru retkih matica, mada se može koristiti i za višedimenzionalne nizove. U ovom slučaju, svaka vrsta i svaka kolona matrice se predstavljaju sa po jednom listom. Liste su kružne, jednostruko ulančane i imaju zaglavlje. Čvorovi liste (osim zaglavlja) predstavljaju samo nenulte elemente matrice i imaju format prikazan na slici 3.18.

ro w co l va l d o w n rig h t

Slika 3.18 Format čvora ulančanih lista za predstavljanje retke matrice

Polje val sadrži vrednost nenultog elementa, polje row indeks vrste, a polje col indeks kolone. Prema tome, ako je X[i,j] 0 onda je za odgovarajući čvor val = X[i,j], row = i, a col = j. Polje right je pokazivač na sledeći nenulti element u istoj vrsti, a polje down pokazivač na sledeći nenulti element u istoj koloni. Tako je svaki čvor, koji nije zaglavlje, član dve kružne liste. Za svaku vrstu i kolonu je predviđena po jedna lista. Zaglavlja lista su organizovana u dva niza R[i] i C[i]. Zaglavlje takve liste ima samo jedno značajno polje koje ukazuje na prvi nenulti element u vrsti (ako je lista za vrstu) ili koloni (ako je lista za kolonu). Ako neka vrsta ili kolona nema nenultih elemenata, odgovarajuća lista je prazna, pa zaglavlje ukazuje samo na sebe. Na slici 3.19 je prikazan izgled ovakve predstave za retku matricu sa slike 2.6.

Operacija pristupa elementu X[i,j] sada ide po listi na koju ukazuje zaglavlje R[i] ispitujući elemente sve dok ne naiđe na takav čvor kod kojeg je col = j, pa uzima njegovu vrednost val. Ukoliko se dođe do elementa čiji je col veći od j ili se vrati do zaglavlja liste, onda je X[i,j] = 0. Operacija upisivanja vrednosti nekog elementa, koja rezultuje umetanjem novog nenultog elementa, mora da ulanča novi čvor u dve liste na tačno određenu poziciju, dok postavljanje postojećeg elementa na nulu mora da izbaci čvor i preveže dve liste. Pri traženju elementa X[i,j] može da se krene i po koloni, od zaglavlja kolone C[j], pogotovo ako je i < j, jer je tada verovatnije da se element nalazi bliže početku kolone nego početku vrste.

Dodatna optimizacija prostora u smislu smanjivanja broja čvorova zaglavlja može da iskoristi činjenicu da su polja down u zaglavljima vrsta, kao i polja right u zaglavljima kolona neiskorišćena. Tako se jedan čvor može iskoristiti istovremeno za zaglavlje vrste i i kolone i. Na ovaj način se broj zaglavlja za matricu M[1:m,1:n] sa m + n smanjuje na max(m, n).

19

Page 20: Ulancane Liste

Ulančane liste

31

42 1 162

914 844

1 575

4

5

R

C

1

2

3

4

5

1 2 3 4 5 6 7

Slika 3.19 Predstavljanje vrsta i kolona retke matrice ulančanim listama

U mnogim algoritmima koji rade sa matricama, elementi se generišu u poretku rastućih indeksa (na primer, množenje matrica). U tom slučaju je korisno da poredak ulančavanja čvorova po vrstama i kolonama bude obrnut, pa da umesto pokazivača right i down postoje pokazivači left i up. Povezivanje u smeru opadajućih indeksa ima za cilj optimizaciju operacije umetanja nenultih elemenata, jer se tada novi čvor u listu ubacuje odmah iza zaglavlja.

3.6.2 Predstavljanje skupova

Skup je jedna od osnovnih struktura podataka, fundamentalna za mnoge računarske primene, naročito u matematici. Veoma česta je primena skupova za implementaciju mnogih apstraktnih tipova podataka, kao i korišćenje u mnogim algoritmima. Zato će, pre razmatranja načina implementacije, ukratko biti definisane logička struktura skupa i tipične operacije sa skupom.

Skup se jednostavno može definisati kao kolekcija članova ili elemenata, gde je svaki član ili skup ili primitivni, atomski element (celobrojni, znakovni, itd.). Svi članovi jednog skupa su različiti. Sve moguće vrednosti koje članovi skupa mogu imati čine osnovni skup (universal set). Među članovima skupa može (ali ne mora) postojati poredak uređenja zasnovan na relacijama veće, manje i jednako. Skupovna vrednost se obično predstavlja velikim zagradama (na primer, skupovna vrednost sa četiri celobrojna člana {1, 4, 7, 9}).

Osnovna relacija u teoriji skupova je pripadnost elementa skupu (operator ). Ako x pripada osnovnom skupu nad kojim je definisana skupovna vrednost A, onda je relacija x A istinita ako je x član skupa A, na primer 5 {8, 2, 5}. Skup koji nema nijednog člana se naziva prazan skup - . Relacija x je uvek neistinita. Ako je svaki član skupa A takođe i član skupa B, tada je skup A podskup skupa B (A B), a skup B je nadskup skupa A (B A). Prazan skup je podskup svakog skupa. Ako je A podskup od B i B je podskup od A, onda je A = B. Ako je A različito od B i A je podskup od B, onda je A pravi podskup od B (A B).

20

Page 21: Ulancane Liste

Ulančane liste

Osnovne operacije sa skupovima su unija (+), presek(*) i razlika (-). Unija dva skupa je skup sa elementima koji su članovi ili skupa A ili skupa B ili oba skupa:

x (A + B) (x A) or (x B) .

Presek dva skupa čine samo oni elementi koji se nalaze i u jednom i u drugom skupu:

x (A * B) (x A) and (x B) .

Razliku dva skupa čine oni elementi skupa A koji nisu elementi skupa B

x (A - B) (x A) and not (x B) .

Na primer, ako skupovi A i B imaju elemente A = {1, 4, 7, 9} i B = {2, 4, 5}, onda je A + B = {1, 2, 4, 5, 7, 9}, A * B = {4} i A – B = {1, 7, 9}.

Pored ovih operacija javljaju se i operacije umetanja i brisanja pojedinog elementa skupa.

Način reprezentacije skupa se bira na osnovu broja elemenata u skupu i tipičnih operacija. Dve najčešće implementacije su sekvencijalna i ulančana. Zbog poređenja sa ulančanom, ovde se ukratko razmatra i sekvencijalna reprezentacija u vidu vektora bitova. Ako osnovni skup fiksne veličine ima n vrednosti kojima se mogu pridružiti redni brojevi 1..n (vrednosti x1,…, xn), onda se svaki skup A definisan nad ovim osnovnim skupom može predstaviti vektorom bitova dužine n, gde i-ti bit predstavlja i-ti element xi osnovnog skupa. Ako je ovaj bit jednak 1, to znači da xi pripada skupu A, a ako je nula, znači da element xi nije član skupa A.

Osnovna prednost vektorske reprezentacije skupa je efikasna podrška tipičnim operacijama. Tako se operacije ispitivanja prisustva, ubacivanja i brisanja člana izvode u konstantnom vremenu, jednostavnim adresiranjem odgovarajućeg bita u vektoru i njegovom proverom, postavljanjem na vrednosti 1 ili 0, respektivno. Operacije unije, preseka i razlike imaju vremensku složenost srazmernu veličini osnovnog skupa. Ako je osnovni skup dovoljno mali tako da vektor bitova može stati u jednu mašinsku reč, onda su ove operacije direktno podržane logičkim operacijama u mašinskom jeziku. U tom slučaju operacija unije A + B postaje A or B, operacija preseka A * B se realizuje kao A and B, a razlika A - B kao A and (not B). Operacije provere pripadnosti, umetanja i brisanja elementa se, takođe, vrlo jednostavno realizuju postavljanjem odgovarajuće maske bitova.

Osnovni nedostatak vektorske reprezentacije je to što zahteva prostor srazmeran veličini osnovnog skupa, nezavisno od stvarnog broja članova datog skupa. Zato je vektorska predstava pogodna samo za male osnovne skupove. Nedostatak u pogledu iskorišćenja prostora se može prevazići ulančanom reprezentacijom gde je svaki član skupa predstavljen jednim čvorom liste, pa se zahteva samo prostor srazmeran trenutnom broju elemenata skupa koji se predstavlja. Ovaj način je i opštiji jer dozvoljava predstavljanje skupova koji nisu podskupovi nekog konačnog osnovnog skupa. Ukoliko su elementi osnovnog skupa linearno uređeni, ulančana lista takođe može da se održava uređenom, jer to poboljšava efikasnost operacija. U suprotnom, ulančana lista je neuređena.

Efikasnost skupovskih operacija je smanjena u odnosu na vektorsku reprezentaciju i to je cena koja se plaća za bolje iskorišćenje prostora. Performansa veoma zavisi od toga da li je lista uređena ili ne. Tako, na primer, ako se traži presek dva skupa predstavljenih listama i ako su one neuređene, onda se svaki čvor jedne liste mora porediti sa svakim čvorom druge liste, što, pod pretpostavkom da su liste dužine n, daje ukupnu složenost reda O(n2). Međutim, ako su liste uređene, performansa postaje mnogo bolja. Neka su dva skupa predstavljena uređenim jednostruko ulančanim listama sa zaglavljima na koja ukazuju pokazivači A i B. Tada funkcija INTERSECTION(A, B) vraća pokazivač na zaglavlje liste koja predstavlja presek dva polazna skupa.

21

Page 22: Ulancane Liste

Ulančane liste

INTERSECTION( A , B ) r = c= GETNODEp = next(A)q = next(B)while (p nil) and (q nil) do

if (info(p) = info(q)) then

next(c) = GETNODE

c = next(c)info(c) = info(p)p = next(p)q = next(q)

else if (info(p) < info(q)) then

p = next(p)

elseq =

next(q)end_if

end_ifreturn r

Na početku i posle nalaženja dva ista elementa iz dve liste, kada se formira novi čvor izlazne liste, uzimaju se dva sledeća člana ulaznih lista. Ako su oni različiti, fiksira se veći od njih, a u listi u kojoj se nalazi manji, uzima se naredni član sve dok se ne dođe do jednakog ili do većeg elementa. Ovaj postupak se ponavlja dok se ne dođe do kraja jedne liste. Zahvaljujući uređenosti, presek dve liste se dobija u samo jednom prolazu kroz obe liste, pravilnim naizmeničnim napredovanjem pokazivača kroz njih, što čini vremensku složenost linearnom.

Realizacija operacija unije i razlike je veoma slična kao i kod preseka, jer se na isti način prolazi kroz liste. Kod unije se još pri nejednakosti elemenata manji od njih ubacuje u rezultujuću listu, kao i kada su jednaki. Kod operacije razlike u slučaju jednakosti se ne formira novi element u listi r. Ovakav element se formira samo od članova liste A kada je tekući element manji od tekućeg elementa liste B, kao i od preostalih elemenata iz liste A kada se dođe do kraja liste B.

3.6.3 Predstavljanje polinoma

Potreba za predstavljanjem polinoma u simboličkoj formi i različite operacije sa njima (sabiranje, oduzimanje, množenje, deljenje, diferenciranje, itd.) je veoma česta i u naučnim i u poslovnim aplikacijama. Pošto u programskim jezicima ne postoje tipovi koji direktno podržavaju njihovo predstavljanje, treba da se pronađe takva reprezentacija koja omogućava efikasne operacije.

Neka se, za početak, radi sa polinomima jedne nezavisno promenljive. U ovom slučaju, polinom je algebarski izraz koji se sastoji od zbira članova, pri čemu opšti član ima formu aixi. Prema tome, za svaki član treba pamtiti koeficijent ai i stepen promenljive i. Pri izboru načina predstavljanja treba imati u vidu da polinom može da ima nepredvidljiv broj članova, da članovi koji

22

Page 23: Ulancane Liste

Ulančane liste

odgovaraju mnogim stepenima mogu da izostanu i da pri operacijama sa njima redovno nastaje potreba za ubacivanjem novih članova ili brisanjem postojećih. Ovo su upravo tipične okolnosti u kojima je ulančana reprezentacija bolja od sekvencijalne, pa je prirodno usvojiti predstavu u vidu ulančane liste. Analizom operacija može se utvrditi da se obično kroz polinom prolazi u jednom smeru, tako da je dovoljno usvojiti jednostruko ulančanu kružnu listu sa zaglavljem. Prema tome, čvor liste treba da sadrži polja: c za koeficijent, exp za stepen promenljive x i next za pokazivač na sledeći čvor. Pored toga, zbog efikasnosti operacija pogodno je listu držati uređenom po opadajućoj

vrednosti polja exp. Tako bi, na primer, predstava polinoma 3x15 – 8x7 + 2x - 6 izgledala kao na slici 3.20.

3 1 5 -8 7 2 1 -6 0

c ex p c c cex p ex p ex p n ex tn ex tn ex tn ex t

Slika 3.20 Predstavljanje polinoma ulančanom listom

Sa ovako usvojenom reprezentacijom, algoritam za sabiranje POLY-ADD sabira dva polinoma predstavljena listama na čija zaglavlja ukazuju pokazivači p1 i p2, a vraća pokazivač r na zaglavlje liste koja predstavlja rezultujući polinom. Zbog efikasnijeg rada algoritma pretpostavlja se da polje eksponenta u zaglavlju liste ima vrednost –1. Pretpostavlja se da pomoćna procedura INSERT-AFTER dobija kao argumente adresu čvora t iza kojeg ubacuje novi čvor i oba polja informacionog sadržaja za novi čvor: koeficijent i eksponent.

POLY-ADD( p 1, p 2) r = GETNODEnext(r) = rexp(r) = -1t = rp = next(p1)q = next(p2)while (p p1) and (q p2) do

if (exp(p) = exp(q)) thenif (c(p) + c(q) 0) then

INSERT-AFTER(t, c(p) + c(q), exp(p))

t = next(t)end_ifp = next(p)q = next(q)

else if (exp(p) < exp(q)) thenINSERT-AFTER(t,

c(q), exp(q))q = next(q)t = next(t)

elseINSERT-AFTER(t,

c(p), exp(p))p = next(p)

23

Page 24: Ulancane Liste

Ulančane liste

t = next(t)end_if

end_whilereturn r

Ova operacija sabira članove sa istim eksponentima iz ulaznih lista i formira nove čvorove u izlaznoj listi, a ostale članove iz obe liste samo prepisuje. Polazeći od početka, za tekuće članove iz dve ulazne liste upoređuju se eksponenti. Ukoliko su oni jednaki, a zbir njihovih koeficijenata je različit od nule, onda se na kraju rezultujuće liste formira novi čvor čiji je koeficijent jednak zbiru koeficijenata tekućih članova, a eksponent jednak njihovom stepenu. Ukoliko su stepeni tekućih članova različiti, formira se novi čvor u koji se prepiše tekući član sa većim eksponentom, pa se prelazi na sledbenika tog člana. Tako se naizmenično napreduje kroz obe liste. Zahvaljujući tome što zaglavlje liste u polju eksponenta ima vrednost –1 (što je manje od svih eksponenata članova liste), kada se jedna lista iscrpi, svi članovi druge liste prepišu se u rezultujuću listu. Algoritam se završava kad oba tekuća pokazivača pokazuju na svoja zaglavlja. Čvorovi se u rezultujuću listu dodaju na kraj, što garantuje da će ona, takođe, biti uređena po opadajućim eksponentima članova. Pošto je dovoljan jedan prolaz kroz obe liste, složenost je linearno srazmerna zbiru broja članova oba polinoma.

Ostale operacije sa polinomima predstavljenim u ovoj formi su isto tako efikasne. Oduzimanje se može svesti na gornji algoritam sabiranja ako se svi koeficijenti drugog polinoma uzmu sa negativnim predznakom. Algoritam množenja dva polinoma se, takođe, zasniva na algoritmu sabiranja, jer se prvi polinom množi sa jednim po jednim članom drugog polinoma i parcijalni rezultati se sabiraju.

Ako polinom ima više nezavisno promenljivih (na primer, x, y i z), algoritmi u suštini ostaju isti, samo što je poređenje tekućih članova malo složenije. Liste se sada uređuju tako da je primarni kriterijum opadajući stepen po x, a zatim se članovi kod koji je stepen po x jednak ulančavaju po opadajućem stepenu po y, da bi se, na kraju, članovi kod kojih su stepeni po x i po y jednaki ulančali po opadajućem stepenu z. Saglasno ovom uređenju vrši se i poređenje dva tekuća člana u algoritmu.

24

Page 25: Ulancane Liste

Ulančane liste

4. Literatura

www.wikipedia.org

25