Professional Documents
Culture Documents
Skripta Locked
Skripta Locked
algoritmi
II dopunjeno izdanje
1.1. Uvod 14
1.2. Šta su pokazivači? 16
1.2.1. Primer: Čuvanje podataka 16
1.2.2. Definicija pokazivača 18
1.3. Pokazivači u C-u 18
1.4. Neke finese – alijasi, recikliranje, ‘dangling’ pokazivači 19
1.4.1. Alijasi 19
1.4.2. Recikliranje korištenog memorijskog prostora 20
1.4.3. “Viseći” pokazivači (dangling pointers) 21
1.4.4. Vek trajanja dinamičkog memorisanja 21
1.4.5. Dereferenciranje 21
1.5. Predstavljanje pokazivača u dijagramima 22
1.6. Linearna povezana lista 23
1.6.1. Deklaracija tipova podataka za povezane liste 24
1.6.2. Umetanje novog drugog čvora u listu 25
1.6.3. Pretraga liste 26
1.6.4. Brisanje poslednjeg čvora u listi 26
1.6.5. Umetanje novog poslednjeg čvora u listu 27
1.6.6. Štampanje liste 28
1.6.7. Jedan celovit program 28
1.7. Ostale povezane strukture podataka 29
1.8. Primer primene – povezana lista i upravljanje virtualnom memorijom 31
1.9. Saveti na kraju poglavlja 32
0 Uvod
Osim tzv. logičke strukture podataka postoji još jedan pojam vezan za organizovanje
podataka u programu: tip podataka.
Kada govorimo o sintaksi programskih jezika, termin »struktura podataka« sreće se znatno
ređe od termina »tip podataka«. Odnos ova dva termina nije do kraja definisan. Neki autori u
logičku strukturu podataka ne ubrajaju operacije, a s druge strane skup operacija je integralni
deo definicije svakog tipa podataka.
Ukoliko se prihvati činjenica da je skup operacija neodvojivi deo strukture podataka dolazi se do
zaključka da su strukture i tipovi podataka, dva modela ili pogleda istog entiteta: organizacije
podataka.
Tipovi podataka, kao model, koriste se u programskim jezicima, dok se strukture podataka
upotrebljavaju u fazi projektovanja softvera.
Kao što prema nivou apstrakcije razlikujemo logičke i fizičke strukture podataka, tako kod
tipova razlikujemo apstraktne i konkretne tipove podataka. Apstraktni tip podataka obuhvata
definiciju skupova koji u njemu učestvuju, kao i sintaksu i semantiku operacija nad tim
skupovima. Kada se ovom tipu doda konkretna, programska realizacija, dobija se konkretni tip
podataka.
Sintaksni deo koji obuhvata tačke 1,2,3 nosi naziv signura tipa. Kada se signaturi tipa doda opis
semantike dobija se specifikacija tipa, odnosno apstraktni tip.
Tipovi koji imaju druge tipove za parametre zovu se generički ili parametrizovani tipovi.
1
1. Pojam strukture podataka
gde je S skup elemenata (koji i sami mogu biti strukture), a ri, i=1,2,...,n su relacije definisane na
skupu S.
Strukture podataka se klasifikuju na više načina, a ovde će se navesti samo neke klasifikacije.
2
U praksi se najčešće susreću slučajevi struktura podataka sa jednom jedinom relacijom, a i
strukture sa više relacija mogu se posmatrati kao skup struktura sa istim elementima i jednom
relacijom, te ćemo se zadržati na strukturi oblika ( S,r ).
Posmatrana kao uređeni par struktura podataka ne vodi računa o načinu smeštanja u
memoriju već samo o (tzv. logičkim) vezama između elemenata, te iz tog razloga nosi naziv
logička struktura podataka. Fizička struktura podataka predstavlja konkretnu strukturu onako
kako je ona smeštena u memoriju. Logička i fizička struktura po pravilu nisu istovetne.
Podela struktura podataka po mestu nalaženja vrši se iz razloga što je problem obrade
podataka, u slučaju kada su podaci u operativnoj memoriji potpuno različiti od problema
obrade podataka kada se podaci nalaze u masovnoj memoriji. Količina podataka u operativnoj
memoriji je mnogostruko manja od količine podataka u masovnoj memoriji. Takođe, način
pristupa podacima u operativnoj memoriji je suštinski različit od načina pristupa podacima u
masovnoj memoriji.
U slučaju klasifikacije struktura podataka prema tipu relacija, kao model strukture podataka
posmatra se diraf ( orentisani graf ):
(X,U)
gde je :
X skup čvorova digrafa koji odgovara elementima strukture podataka,
U skup grana koje predstavljaju navedenu binarnu relaciju u skupu X.
Linearnu strukturu podataka opisuje digraf ( X , U ) čiji se čvorovi mogu rasporediti u niz:
Ako se navedenom skupu grana priključi i grana (xn, x1) onda se dobija ciklička struktura
podataka.
Struktura tipa stablo ima tu osobinu da svaki čvor, osim jednog, ima tačno jednog
predhodnika. Čvorovi koji nemaju sledbenika nazivaju se listovi. Stablo kod kojeg svaki čvor,
osim listova, ima najviše dva sledbenika naziva se binarno stablo.
Mrežna struktura podataka predstavlja se opštim digrafom u kojem svaki čvor ima
proizvoljan broj sledbenika.
3
0.3 Osnovne operacije nad strukturama podataka
4
Indikator koji ukazuje da li je u pitanju polje, a ne neka druga struktura,
Naziv polja,
Adresu prvog elementa polja,
Najmanje i najveće vrednosti indeksa,
Tip elementa polja,
Broj lokacija po jednom elementu polja izražen u jedinicama adresiranja (bajt, reč).
4.2.1. Stek
Dakle, kod steka se može ukloniti samo onaj element koji je hronološki poslednji dodat u
stek. Zato se stek naziva i LIFO red (Last In First Out).
5
Kod spregnute realizacije steka memorijski prostor dodeljen svakom elementu steka dopunjuje
se ukazivačem (adresom) sledećeg po redu elemenata steka.
4.2.2. Red
Ova struktura je slična steku, isto je linearna, a razlikuje se od steka po mestu dodavanja tj.
uklanjanja elemenata. Kod reda se elementi dodaju na jednom kraju linearne strukture, a
pristupa se ili uklanja na suprotnom kraju, tj. najpre se pristupa onom elementu koji je prvi ušao
u red. Otuda i potiče naziv FIFO (First In First Out).
Kao i kod steka najpoznatije fizičke realizacije reda su sekvencijalna i spregnuta. Operacije nad
redom su praktično identične kao operacije nad stekom s tim što se dodavanje elemenata vrši
iza poslednjeg elementa, a uklanja se prvi element.
4.2.3. Dek
Naziv dek (engl. deque) je akronim od double ended queue (>>red sa dva kraja<<) i po svojim
osobina predstavlja sintezu steka i reda s obzirom da je i pristup, dodavanje i uklanjanje
elemenata dozvoljeno na oba kraja.
6
4.3 Dinamičke strukture podataka
Osnovna karakteristika ovih struktura jeste mogućnost pristupa svakom elementu (čvoru) u
strukturi bez menjanja strukture, kao i mogućnost dodavanja ili uklanjanja čvorova bez ikakvih
ograničenja. Broj čvorova je teorijski neograničen, a u fizičkoj strukturi se logički susedni čvorovi
(čvorovi x i y ili y i x su logički ako su u relaciji) u načelu ne nalaze na fizički susednim
memorijskim lokacijama.
Osnovne dinamičke strukture su liste i stabla.
4.3.1 Liste
Najvažnija primitivna funkcija je funkcija sledeći koja za dati element, kao rezultat daje njegovog
neposrednog sledbenika.
7
Kod strukture podataka,
Naziv liste,
Indeks početka,
Opis elementa,
Broj elemenata u listi.
Dvostruko spregnute liste predstavljaju uopštenje jednostruko spregnutih lista kod kojih se
svakom uređenom paru (a,b) iz relacije r u jednostrukoj spregnutoj listi pridružuje uređeni par
(b,a). Dakle, susedni elementi su povezani u oba smera. Dvostruko spregnuta lista može biti i
cirkularna, ako su prvi i poslednji element spregnuti u oba smera.
4.3.2 Stablo
Pod redom stabla podrazumeva se najveći broj sledbenika nekog elementa. Broj elemenata
najdužeg puta naziva se visina stabla. Svaki element stabla sa svim svojim sledbenicima sve do
listova čini podstablo datog stabla. Pristup elementu stabla vrši se isključivo na osnovu
njegovog informacionog sadržaja. Da bi se obezbedilo da se pristup datom elementu ostvaruje
putem koji vodi ka tom elementu, neophodno je skup sledbenika urediti po određenim
pravilima. Zato postoje funkcije sledeći, funkcija izaberi (koja za skup sledbenika omogućava
izbor jedinstvenog sledećeg elementa na osnovu nekog kriterijuma), funkcija koren (koja ima za
zadatak da odredi koren stabla), funkcija pristupi.
8
5. STRUKTURA PODATAKA SMEŠTENIH NA MASOVNU
MEMORIJU
5.1Osnovni pojmovi
Slog - predstavlja uredjeni skup polja koji se mogu tretirati kao jedinica koju obrađuje
neki program.
Pre nego što se podaci mogu upisati u datoteku, neophodno je uraditi proces kreiranja:
Identifikovati perifernu jedinicu gde će se datoteka smestiti nakon kreiranja,
Dati datoteci naziv, kako bi se mogla identifikovati među ostalim datotekama na
računarskom sistemu,
Definisati veličinu datoteku, kako bi se na medijumu nosača podataka rezervisao prostor
za smeštanje podataka u datoteku,
Definisati nacin organizacije datoteke,
Definisati veličinu bloka,
Definisati veličinu sloga.
9
Ove informacije koje karakterišu datoteku nazivaju se atributi, osim informacije o identifikaciji
periferne jedinice koja se upisuje u zaglavlje (deskriptor) datoteke. Ove operacije se mogu
izvršiti samo ako je datoteka otvorena. Operacija brisanja datoteke omogućava da se data
datoteka ukloni iz sistema i dodeli drugoj datoteci, a ova operacija se može izvršiti samo ako je
zatvorena.
10
5.5 Metode organizacije datoteka
Već je napred napomenuto da je jedna od osnovnih operacija nad strukturom podataka
pristup. Kod struktura na masovnim memorijama ima se u vidu pristup slogu u datoteci, a na
raspolaganju su dve osnovne tehnike pristupa:
Sekvencijalna (redosledna), gde se slogovima pristupa sekvencijalno onim redosledom kako su
smešteni u datoteci,
Slučajna (direktna), gde se slogovima ne pristupa ni prema kakvom unapred ustanovljenom
redosledu, već na slučajan način.
Razvijen je i čitav niz datoteka koje eliminišu nedostatke navedenih, kao na primer:
Indeksne ili indeks nesekvencijalne datoteke,
VSAM (Virtual Sequential Access Method),
Inverzne datoteke.
Kod ovog tipa datoteke slogovi se memorišu neposredno jedan iza drugog i ovde se ne
uspostavlja odnos između mesta sloga u datoteci i sadržaja sloga. Zato su ove datoteke
nezavisne od memorijskih jedinica na kojima se realizuju, tj. mogu se smeštati na raznim
perifernim jedinicama.
Slogovi se smeštaju u datoteku logičkim ili hronološkim redosledom, što znači da se novi slog
može dodati samo na logičkom kraju datoteke. Dakle, svaki slog osim prvog i poslednjeg ima
svog prethodnika i sledbenika. Slogovi se u cilju racionalnog korišćenja prostora na medijumu
nosača podataka, udružuju u blokove.
11
Struktura sekvencijalne datoteke je sledeća:
Blok zaglavlja datoteke, (sadrži potrebne informacije koje koriste programi za
upravljanje datotekom (file system) koji ulaze u sastav operativnih sistema),
Blokovi podataka,
Oznaka logičkog kraja datoteke, (neophodna je da bi se imala informacija o zauzeću
memorijskog prostora koji je dodeljen datoteci),
Oznaka fizičkog kraja datoteke, (da bi se imala informacija posle kojeg bloka više nema
mogućnosti za dodavanje blokova (slogova) u datoteku).
Prvi blok kod relativne datoteke sadrži zaglavlje datoteke. Identifikator koji nosi naziv
relativna adresa i koji služi za adresiranje slogova predstavlja redni broj sloga u datoteci. Slogovi
u relativnoj datoteci se numerišu od 1 do n. Blok koji predstavlja zaglavlje numeriše se sa „0“.
Ako je u datoteci popunjen mali broj ćelija, kaže se da je datoteka retka, a ako je većina ćelija
popunjena, kaže se da je gusto popunjena datoteka.
Da bi se pristupilo datom slogu potrebno je da se broj sloga konvertuje u broj bloka i broj
ćelije u bloku. Neka je
m-broj ćelija u bloku i
k-broj željenog sloga.
𝑘𝑘−1+𝑚𝑚
BrojBloka = [ ]
𝑚𝑚
BrojCelijeUBloku=1+mod((k-1+m)/m)
Direktna organizacija datoteka (rasute ili hash datoteke) su slične relativnim datotekama, ali
su eliminisani neki osnovni nedostaci relativnih datoteka. Kod datoteka sa direktnom
organizacijom slogovi mogu biti različite dužine i u okviru bloka slede neposredno jedan iza
drugog.
12
Najveći nedostatak relativne datoteke je što se zapisu ne pristupa na osnovu vrednost
ključa, već prema vrednosti rednog broja sloga u datoteci, koji nije sastavni deo sloga.
Direktne datoteke predstavljaju način za uspostavljanje veze između ključa koji je sastavni
deo sloga i relativne adrese koja omogućava direktan pristup traženom slogu.
U opštem slučaju postupak za određivanje adrese sloga na osnovu vrednosti njegovog ključa
sastoji se od sledećih koraka:
Pretvaranje alfanumeričke vrednosti ključa u numeričku (ako ključ već nije numerički),
Generisanje pseudoslučajnog broja na bazi numeričke vrednosti ključa,
Pretvaranje pseudoslučajnog broja u relativnu adresu,
Pretvaranje relativne adrese u fizičku (efektivnu) adresu.
Zbog nepostojanja metoda koja vrednost ključa jednoznačno preslikava u relativnu adresu,
dva različita ključa se mogu preslikati u istu relativnu adresu Slogovi čiji se ključevi preslikavaju
u istu adresu nazivaju se slogovi sinonimi. Pojava slogova sinonima se zove kolizija.
Postoji više metoda za razrešavanje problema slogova sinonima. Najčešće korišćena metoda
koristi dve oblasti u adresnom polju datoteke.
Prilikom upisivanja sloga u datoteku, najpre se vrši pokušaj upisivanja u slog u odgovarajući
blok (baket), koji pripada tzv. primarnoj (matičnoj) oblasti. Ukoliko je primarni (matični) blok
popunjen, formira se lanac sinonima organizovan kao jednostruke spregnute strukture i slog se
upisuje u taj lanac. Oblast koja sadrži sve lance sinonima naziva se oblast prekoračenja
(overflow area). Izloženi postupak usložnjava (i poskupljuje) postupak dodavanja sloga u
datoteku. Iz tih razloga, a da bi se poboljšala ekonomičnost u korišćenju memorijskog prostora
na medijumu nosača podataka kod direktnih datoteka se ne dozvoljava sekvencijalno čitanje
sloga iz datoteke. Dakle, kod direktnih datoteka ne postoji relacija prethodni i naredni slog.
13
Slog u okviru indeksa sadrži najveću vrednost ključa i ukazivač na niži nivo indeksa. Prvi niži nivo
indeksa poznat je pod nazivom indeks cilindra, a sledeći niži nivo se zove indeks traga (ili staze).
Slogovi podataka u datoteci sadrže slogove podataka korisnika. Skup podataka na koje
ukazuju ukazivači iz indeksa tragova predstavljaju primarnu oblast prekoračenja. Blokovi koji ne
ulaze u primarnu oblast podataka, a sadrže slogove podataka korisnika obrazuju oblast
prekoračenja. Kod ISAM datoteke oblast prekoračenja sastoji se od oblasti prekoračenja cilindra
i oblasti prekoračenja datoteke.
Oblast prekoračenja cilindra se sastoji od jednog ili više tragova na datom cilindru
namenjenim za prihvatanje slogova koji ne mogu da budu smešteni u primarno oblasti
podataka u datom cilindru. Slogovi u oblasti prekoračenja cilindra povezani su jedan sa drugim
preko rastuće vrednosti ključa, dok je poslednji slog na tragu cilindra u primarnoj oblasti cilindra
povezan sa prvim slogom u oblasti prekoračenja cilindra.
1.1 Uvod
14
Veličina koju tabela ili lista mogu dostići prilikom rada programa može zavisiti od ulaza u
program. Broj ili veličinu tih ulaza tih ulaza nije uvek jednostavno predvideti.
Ipak ponekad smo prinuđeni da alociramo niz određene veličine pre izvršavanja programa.
Ukoliko napravimo pogrešne pretpostavke može se desiti da nam ponestane prostora za neku
tabelu ili listu, dok u nekoj drugoj tabeli postoji neiskorišten prostor.
Možemo koristiti povezane reprezentacije za prevazilaženje ovih problema.
Štaviše, kada nam je data povezana struktura, možemo da dodamo ili izbrišemo određeni blok
podataka dodavanjem ili brisanjem podataka pokazivača koji pokazuje na taj blok. To znači da
povezana reprezentacija može da se uvećava ili smanjuje deo po deo omogućavajući
programeru / korisniku da menja strukturu u malim koracima koristeći samo po nekoliko
pokazivačkih operacija za svaki deo.
Ova mogućnost otvara veoma zanimljivu klasu osobina rasta I kombinovanja za povezanu
reprezentaciju koja je trenutno predmet intezivnih studija računarstva. Pokazivači se često
koriste iz jos dva razloga: (i) ponekad je to način istraživanja određene operacije i (ii) najčešće se
izražavaju u određenom programskom jeziku kompaknijim I efikasnijim kodom nego što se
može uraditi na drugi način.
Klasa povezanih reprezentacija podataka koju je omogućio razvoj ovakvih tehnika može imati
značajne prednosti u odnosu na druge reprezentacije, kakva je sekvencijalna.
U ovom poglavlju ćemo pokazati da se određene više strukture podataka, kao što su liste,
stekovi, skupovi, stabla ili redovi za čekanje , mogu na više načina predstaviti nižim
reprezentacijama podataka. Dve široke klase takvih nižih reprezentacija su sekvencijalna
reprezentacija I povezana reprezentacija.
Na ovaj način se postepeno dolazi do ideje o nivoima apstrakcije podataka. Ta ideja predstavlja
jedan od osnovnih koncepta savremene informatike.
15
Na još nižim nivoima se povezana se povezana reprezentacija može predstaviti na više načina,
na primer pomoću nizova slogova, ugrađenih C pokazivačkih tipova podataka ili paralelnih
nizova.
Slika1.1
Povezanu reprezentaciju podataka može da podrži bilo koji adresibilni memorijski medijum
(RAM, disketa, CD ROM). Sledeći primer pokazuje mogućnost primene pokazivača.
16
Razmotrimo sada čuvanje podataka na flopiju prikazanom na slici 2.1. Na velikom broju
kompijutera je fajl definisan kao konačan niz bajtova. Takav se niz moze podeliti na uzastopne
512- bajtne blokove, koji se dalje mogu upisivati u prazne sektore diskete. Uzastopne blokove
podataka povezujemo tako što u svakom bloku čuvamo adresu sledećeg bloka podataka
odnosno pokazivač.
Uobičajeno je i da se u nekom od praznih sektora diska čuva direktorijum fajlova. Svaki slog
u direktorijumu sadrži ime fajla (npr. Moj Program.c), neke osobine fajla (npr. dužinu fajla u
bajtovima, datum kreiranja kod za prepoznavanje tipa fajla) i pokazivač nan a prvi 512-bajtni
blok od niza povezanih blokova u kojima se fajl čuva. Ukoliko je za smeštanje takvog
direktorijuma više od 512-bajtnog sektora na disku, mogu se alocirati dodatni sektori zbog
priširenja povezati sa krajem direktorijuma. Takva situacija je prikazana na slici 1.3.
17
1.2.2 Definicija pokazivača
Kada sačuvamo adresu α promenljive A unutar memorijske jedinice B, kažemo da B pokazuje na
A i kažemo da je B pokazivač.
Kada želimo da kreiramo pokazivač koji pokazuje na memorijski blok koji sadrži celobrojne
vrenosti, u svim programskim jezicima prvo moramo da deklarišemo pokazivač. U
programskom C jeziku, prvo možemo deklarisati pokazivački tip, pa zatim pokazivače kao
promenljive tog tipa, a možemo izvršiti i direktnu deklaraciju:
Int*A,*B
void*malloc(size_t size)
malloc vraća jedan pokazivač na prostor za jedan objekat veličine size, ili NULL ako potražnja
za memorijom nije zadovoljena. Ovom prostoru nije potrebno dati početnu vrenost.
18
Način kreiranja pokazivača na memorijsku celobrojnu jedinicu vrši se:
B=(int*)malloc(sizeof(int));
Kada želimo dodeliti vrednost memorijskoj jedinici na koju ukazuje npr. A5 ,to vršimo naredbom
dodele *A=5 pri čemu * da se vrednost 5 smesta na adresu smeštenu pokazivačem promenjive
A.
Analogno možemo dodeliti vrednosti memorijskoj jedinici na koju ukazuje B, npr. *B=17
Kada bi bila izvršena naredba A=B, desilo bi se da i A i B pokazuju na polje na kom je smeštena
vrednost 17.
1.4.1 Alijasi
Kada dva pokazivača ukazuju na istu adresu u memoriji (kao A i B na slici 1.5), onda se oni
zovu alijasi (ukoliko želimo da promenimo vrednos 17, svejedno je da li ćemo za pisanje željene
naredbe koristiti pokazivač A ili b).
19
Slika 1.5
Slika 1.6
20
Funkcija free(X) je implementirana u standardnoj biblioteci <stdlib.h> i deklarišemo je i
definišemo na sledeći način:
void free(void *p)
funkcija free oslobađa prostor na koji pokazuje p. U koliko je p NULL, ne radi ništa. P mora biti
jedan pokazivač na jedan prostor, koji je pre alocirao calloc ili malloc.
Osim alijasa, koji ukazuju na isti memorijski blok, postoji još jedna opasnost vezana za
pokazivače. Da vidimo šta će se dogoditi ako krenemo od situacije sa slike 1.6, izvršimo naredbu
free B a zatim pokušamo da izračunamo izraz *A+2. Prvom naredbom će se polje koje sadrži
vrednost 17 “vratiti” u dinamičku memoriju. (Kada se to desi moguće je da će ili vrednost 17 biti
izbrisana, ili će se polje koje je sadrži priključiti nekom većem memorijskom bloku).
Sada A sadrži takozvani “viseći” pokazivač koji pokazuje na istu memorijsku jedinicu na koju je B
pokazivao pre recikliranja. Može se dogoditi da referenca ovakvog pokazivača uopšte više nema
smisla u C-u. Ovakve greške su posebno opasne jer ih ne otkrivaju ni kopmajler, a često ni ostali
ugrađeni C sistemi.
1.4.5 Derefereniciranje
Kada zvezdica (*) prethodi imenu promenljive, kao kod *A, kažemo da je pokazivačka
vrednost A dereferenciran. Kada zvezdica (*) prethodi novom indentifikatoru imena tipa T u
definiciji tipa, ona definira pokazivački tip. Na primer,
Typedef T *TPointer;
Znači da je TPointer skup pokazivača na memorijske jedinice koje sadrže vrednosti tipa T.
Tako zvezdica prethodi pokazivačkim promenljivima kada su one dereferencirane i prethodi
indentifikatorima imena tipa kada se oni definišu. Kada se dereferencirana promenljiva *V,
pojavi na levoj strani naredbe dodele, *V=X, onda ona označava da se kopija vrednosti iz X
upisuje na lokaciju na koju pokazuje vrednost pokazivača V.
21
1.5 Predstavljanje pokazivača u dijagramima
Kada se adrese prikazuju eksplicitno, predstavljaju se slovima grčkog alfabeta (prvi red na
slici 1.7) tada se prikaz elemenata liste sastoji iz dva polja, prvo (info) sadrži vrednost x1, a
drugo (link) sadrži pokazivač, dok grčko slovo ispred elemenata liste predstavlja memorijsku
adresu tog čvora liste.
Postoji i specijalna nulta (NULL je rezervisana c u C-u) adresa koja po konvenciji nije adresa
nijednog polja. Koristi se za označavanje kraja liste ili za prikaz prazne structure. Nulti pokazivač
se još može prikazati i pomoću tačke (drugi i treći red na slici 1.7).
Implicitni prikaz (treći red slike 1.7) se obicno koristi kod komplikovanih dijagrama, inače se
češće koristi eksplicitni prikaz (slika 1.7, drugi red).
Slika 1.7
22
Slika 1.8
Linearna povezana lista (ili skraćeno povezana lista) je niz elemenata, čvorova (node) u kome
svaki od elemenata liste, osim poslednjeg, ukazuje na sledeći. Svaki čvor liste se sastoji iz dva
polja, u jedno se smesta podatak (na engleskom najčešće Item), a u drugo pokazivač (obično se
to polje naziva Link). Pokazivačko polje poslednjeg čvora sadrži nultu pokazivačku vrednost,
NULL, koja označava kaj liste.
Kao primer povezane liste koristićemo plan leta aviona. Na slici 1.8 je primer jedne liste, gde
su DUS, ORD i SAN imena aerodrome (Dizeldorf, O Hara – Čikago i San Dijego). Pokazivačka
promenljiva L sadrzi pokazivač na prvi elemenat u listi. Uobičajeno je i da se cela lista posmatra
kao jedan objekat i u tom smislu da se L naziva vrednošću liste (DUS, ORD, SAN).
23
Slika 1.9
Da bi mogli da manipulišemo listama, prvo treba da deklarišemo tipove podataka koji se u njima
koriste.
Prvo treba da odredimo neki način za prikaz troslovnih aerodromskih kodova. Jedan od
načina da se to uradi u C-u je da se definira tip ŠifraAerodroma kao niz dužine 4 u koji može da
se smesti C niska koja se sastoji od aerodromskog koda (dužine tri) i nultog simbola (0) koji
označava kraj niske.
TypedefcharSifraAerodroma[4];
Dalje, treba da definišemo system emenata i pokazivača pomoću kojih ćemo manipulisati
listom. Zato ćemo definisati tip za čvorove liste ČvorTip na sledeći Način:
Typedef struct Čvorovi {
ŠifraAerodroma Aerodrom;
Struct Čvorovi *Link;
}ČvorTip;
Ovim je definisan ČvorTip kao struktura (struct) sa dva člana (ili komponente, ili polja):
Aerodrom polje koje sadrže troslovni ŠifraAerodroma i Link polje, pokazivač na ČvorTip.
Da bi Link polje Strukture ČvorTip moglo da pokazuje na drugi ČvorTip uvodi se Čvorovi. U C-u
nije dozvoljeno da se definiše struktura koja sadrži samu sebe, ali je dozvoljeno da struktura
sadrži član koje je pokazivač na strukturu istog tipa, kao sto je upravo urađeno. Još treba da
deklarišemo promenljive N i L da sadrže pokazivače na čvorove tipa ČvorTip.
ČvorTip *N, *L;
Bitna ideja je i da se specijalni nulti pokazivač, NULL, automatski smatra vrednošću svakog
pokazivačkog tipa definisanog u C-u. Tako je dozvoljeno napisati naredbu dodele kao L→Link =
NULL;(da bi smestili nulti pokazivač u Link polje čvorova na koji pokazuje pokazivač L), ili pitalicu
if(L→Link == NULL)(da proverimo pokazuje li L na poslednji čvor).
24
1.6.2 Umetanje novog drugog čvora u listu
Pretpostavimo da želimo da dodamo još jedno presedanje listi (planu leta) sa slike 1.8, tako
da let ide iz Dizeldorfa preko Brisla (BRU) pa dalje kao i ranije.
VoidUmetanjeNovogDrugogČvora(void)
{
(deklaristai pokazivač N na čvorove liste)
(alocirati novi čvor koji pokazuje N)
(kopirati nisku “BRU” u N→Aerodrom)
(postaviti N→Link da pokazuje na drugi čvor)
(postaviti L→Link da pokazuje na novi čvor)
}
Još je važno uočiti da je u ovoj funkciji promenljiva N lokalna promenljiva. N postoji samo
tokom izvršavanja funkcije i samo tada i sadrži pokazivač na novolocirani čvor. Pokazivačka
vrednost N se smešta u Link polje prvog čvora liste pre kraja funkcije tako da prvi čvor liste L
pokazuje na novolocirani čvor. Po prestanku izvršavanja funkcije, promenljiva N i njen sadržaj
nestaju, dinamički alocirana memorija za novi drugi čvor liste L tokom izvršavanja funkcije
ostaje i kada funkcija prekine sa radom.
25
1.6.3 Pretraga liste
Opet ćemo pretpostaviti da nam je sve deklarisano na već objašnjen način. Pošto je
poslednji čvor liste određen time što je njegovo Link polje postavljeno na vrednost NULL, Naš je
zadatak da nekako pronađemo pretpostavljeni čvor liste i postavimo u njgovo Link polje NULL.
U ovom rešenju koristimo dve pokazivačke promenljive nazvane PrethodniČvor (P) i
AktuelniČvor (A). Kako napredujemo pokazivačem na čvor koji je neposredno ispred onog na
koji pokazuje AktuelniČvor. Tako ova dva pokazivača “putuju” listom kao pokazivački par.
Kada AktuelniČvor stigne do poslednjeg čvora liste, PrethodniČvor će pokazivati na
pretposlednji. Sada nam još samo preostaje da postavimo vrednost Link polja ovog,
pretposlednjeg čvora na NULL i tako ga proglasimo poslednjim čvorom liste.
26
Da bi ovako rešenje (sa parom pokazivača) moglo da radi, lista mora sadržati barem dva
čvora i to je prvi ulsov koji proveravamo. Ako je lista prazna, ne moramo joj ništa raditi; ako se
lista sastoji samo od jednog čvora, moramo je “isprazniti”.
Strategija je sledeća:
Void BrisanjePoslednjegČvora(&L)
{(deklarisati pokazivače A i P na čvorove liste L)
If (lista L je ne prazna){
If (lista L ima tačno jedan čvor){
(zameni L praznom listom i izaći iz procedure)
}else{ /*inace lista ima bar dva čvora*/
(postaviti pokazivače A i P da pokazuju na drugi prvi čvor liste L redom)
/*pomerase pokazivački par udesno dok se ne dođe do kraja liste L*/
While(A ne pokazuje na posljednji sledeći par čvorova liste L)
}
/*sada AktuelniČvor pokazuje na poslednji čvor,a PrethodniČvor na pretposlednji čvor liste L*/
(poslednji čvor reciklirati, a pretposlednji čvor postaviti kao poslednji)
}
}
}
Neka nam je dat aerodromski kod A i adresa &L promenljive L koja sadrži pokazivač na prvi
čvor liste L. Treba da umetnemo novi čvor koji sadrži kod A na kraj liste.
Void UmetanjeNovogPoslednjegČvoraListe(char *a,ČvorTip **L)
{
(deklarisati pokazivače N, koja pokazuje na novi čvor P koja pokazuje na čvorove liste L)
(alocirati novi čvor na koji pokazuje N, Aerodrom i Link poljima dodeliti vrednost iz A i NULL)
If(lista je prazna){
(postaviti da je N prvi čvor liste L)
}else { (ako lista nije prazna)
(inicijalno postaviti P da pokazuje na prvi čvor L)
While(P ne pokazuje na poslednji čvor liste L){
(postaviti P da pokazuje na sledeći čvor L)
}
(povezati čvor na koji pokazuje N kao poslednji) /*kada smo stigli do kraja liste*/
}
}
27
1.6.6 Stampanje liste
Osnova PrintList funkcije je, opet, while petlja, u kojoj se redom pristupa uzastopnim
čvorovima liste (pomoću pokazivača N). Unutar while petlje aerodromski kodovi se štampaju
naredbom printf(“%s”,N→Aerodrom);. Prelazak na sledeći čvor liste obezbeđuje naredba
N=N→Link;. Da bi odštampali zareze između kodova, ali ne i iza poslednjeg, koristimo
if(N!=NULL) printf(“,”);. Na početku i na kraju liste se štampaju leva i desna zagrada.
{
(deklarisati pokazivač N na čvorove liste L){
(odštampati levu zagradu)
(inicijalno postaviti N da pokazuje na prvi čvor)
While(N ne pokazuje poslednji čvor liste L){
(odštampati sadržaj N→Aerodrom)
(postaviti N da pokazuje na sledeći čvor liste)
If(N nije NULL)(odštampamo “,”)
}
(odštampati desnu zagradu) /*kada smo stigli do kraja liste*/
}
Do sada smo razvili biblioteku blokova korisnih za pisanje programa za povezane liste. Na
kraju možemo da povežemo sve ove procedure u jedan smisleni celoviti program. U narednoj
strategiji je prikazan primer jednog takvog programa:
/*Prvo bi definisali tipove za čvorove liste (tip AerodromskiKod i tip ČvorTIp)*/
/*Zatim ispisujemo funkcije(UmetanjeNovogDrugogČvora,*/
/*BrisanjePoslednjegČvoraListe, UmetanjeNovoPoslednjegČvora i ŠtampanjeListe*/
Int JedanCelovitProgram(void)
{
(deklarisati pokazivač L na čvorove tipa ČvorTipa)
/*Koristimo listu L==(DUS,ORD,SAN) i odštampamo je na sledeći način*/
(postaviti da je L prazna lista)
(umetnuti novi poslednji element aerodromskim kodom DUS)
(umetnuti novi poslednji element aerodromskim kodom ORD)
(umetnuti novi poslednji element aerodromskim kodom SAN)
(odštampati listu) /*pre nego što je izmerimo */
(umetnuti novi poslednji element aerodromskim kodom BRU)
(odštampati listu) /*izmenjenu*/
(obrisati poslednji elemnt liste)
(odštampati listu) /*izmenjenu*/}
28
Ovakav program bi odštampao tri reda:
(DUS, ORD, SAN)
(DUS, BRU, ORD, SAN)
(DUS, BRU, ORD)
Linearne povezane liste koje smo upravo predstavili nisu jedine povezane strukture
podataka. Ako krenemo od elemenata koji sadrže SifraAerodroma i dva pokazivačka polja
LeftLink i RightLink, možemo da konstruišemo povezanu strukturu koristeći veći broj
organizacionih principa. Ovde ćemo ilustrovati samo tri od mnoštvo principa. Prvo treba da
deklarišemo neke tipove podataka:
typedef structCvor{
SifraAerodroma Aerodrom;
structCvor *LeviLink;
structCvor *DesniLink;
}CvorTip;
Slika 1.10
29
Slika 1.11
Slika 1.12
30
1.8 Primer primene – povezana lista i upravljanje virtualnom
memorijom
Operativni sistem mora da vodi računa o slobodnom fižičkom RAM-u da bi mogao da alocira
prostor za stranice koje se unose sa sekundarne jedinice. Ova informacija se čuva u kernel
strukturi podataka koja se naziva Page Frame Database (PFD). Tu se održava i FIFO lista
unešenih stranica (na taj način se odlučuje o odbacivanju).
Fizička stranica može biti u nekoliko stanja, na primer, može biti in-use, free, free but dirty, i
tako redom. PFD ulaz je povezan u dvostruko povezanu listu, u zavisnosti od stanja fižičke
stranice koju predstavlja. Na slici 1.13 prikazane su ove liste povezane kroz PFD.
31
1.9 Saveti na kraju poglavlja
32