Professional Documents
Culture Documents
US - Uvod U Algoritme I Strukture Podataka
US - Uvod U Algoritme I Strukture Podataka
Dejan ivkovi
U VOD U ALGOR IT ME I
S T RUKT URE P ODATAK A
Prvo izdanje
Beograd, 2010.
Autor:
Prof. dr Dejan ivkovi
Recenzent:
Prof. dr Dragan Cvetkovi
Izdava:
UNIVERZITET SINGIDUNUM
Beograd, Danijelova 32
www.singidunum.ac.rs
Za izdavaa:
Prof. dr Milovan Stanii
Tehnika obrada:
Dejan ivkovi
Dizajn korica:
Dragan Cvetkovi
Godina izdanja:
2010.
Tira:
240 primeraka
tampa:
Mladost Grup
Loznica
ISBN: 978-86-7912-239-1
Predgovor
Oblast algoritama i struktura podataka potvrdila je svoje mesto u rac unarstvu zbog prakticne vanosti i teorijske elegancije. Sa jedne strane,
prakticari mogu da neposredno koriste dobre algoritme i ekasne strukture podataka u sloenim programskim projektima. Sa druge strane, za
istraivace su algoritmi vaan alat kojim se meri stepen sloenosti nekog
racunarskog problema. Algoritmi i strukture podataka se nalaze u centru
svih metodologija koje se koriste u radu sa savremenim racunarima. Mada
na prvi pogled moda tako ne izgleda, neka napredna metodologija sigurno
se temelji na sosticiranim algoritmima i strukturama podataka.
Cilj ove knjige je da c itaocima predstavi osnove ove fascinantne oblasti
racunarstva. Radi toga se u knjizi prevashodno razmatraju neke od najosnovnijih metoda i paradigmi za dizajniranje i analiziranje struktura podataka i algoritama. Pri tome je pokuano da se naglasak stavi na idejama
i lakem razumevanju koncepata, a ne na implementacionim detaljima.
Ova knjiga je primarno zamiljena kao fakultetski udbenik za prvo
upoznavanje sa algoritmima i strukturama podataka na prvoj ili drugoj
godini studija racunarstva. Razumevanje materijala iz knjige zahteva bazicno predznanje iz racunarstva i matematike. Konkretnije, od c italaca
se ocekuje da imaju iskustva u pisanju programa na nekom programskom
jeziku vieg nivoa kao to su Pascal, C ili Java. Pretpostavlja se i da c itaoci
poznaju osnovne matematicke koncepte u koje spadaju skupovi, funkcije i
indukcija.
U knjizi se nalazi preko 150 slika i tabela koje slue za ilustraciju
materijala. Algoritmi u tekstu su navedeni na jednostavnom pseudo jeziku
tako da c itaoci ne moraju da uci novi programski jezik da bi razumeli
kako algoritmi rade. Dodatno, na kraju svakog poglavlja se nalazi vie
zadataka c ija teina ide u rasponu od prostih vebi za utvrdivanje
izloenog
ii
Predgovor
Sadraj
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
2
4
8
10
15
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
17
18
21
28
40
43
43
54
66
Uvod
1.1 Podaci . . . . . . .
1.2 Algoritmi . . . . .
1.3 Racunarski model
1.4 Zapis algoritama .
Zadaci . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
71
. 71
. 73
. 88
. 96
. 98
. 101
Rekurzivni algoritmi
5.1 Iterativni i rekurzivni algoritmi
5.2 Analiza rekurzivnih algoritama .
5.3 Rekurentne jednacine . . . . . . .
Zadaci . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
107
108
116
128
140
iv
6
Sadraj
Stabla
6.1 Korenska stabla . . . . .
6.2 Binarna stabla . . . . . .
6.3 Binarna stabla pretrage
6.4 Binarni hipovi . . . . . .
6.5 Primene stabala . . . . .
Zadaci . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
145
145
151
155
165
174
181
Grafovi
7.1 Osnovni pojmovi i denicije
7.2 Predstavljanje grafova . . .
7.3 Obilazak grafa . . . . . . . .
7.4 Obilazak usmerenog grafa .
Zadaci . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
185
186
191
194
209
218
Teinski grafovi
8.1 Osnovni pojmovi . . . . . . . . . . . .
8.2 Minimalno povezujuce stablo . . . .
8.3 Najkraci putevi od jednog c vora . . .
8.4 Najkraci putevi izmedu
svih c vorova
Zadaci . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
223
224
225
236
243
247
.
.
.
.
.
.
Literatura
251
Indeks
253
G LAVA
1
Uvod
posmatra se iz vrlo opteg ugla, uglavnom bez neke konkretne interpretacije podataka na umu. U najoptijem smislu, termin struktura podataka
koristi se za nacin organizacije odredenih
podataka u programu, a termin
Uvod
1.1 Podaci
Manipulisanje podacima je glavna svrha rada softverskih sistema i zato
je neophodno na samom pocetku razjasniti sam pojam podataka. U stvari,
u ovom kontekstu se c esto koriste termini tip podataka (ili samo kratko
tip), apstraktni tip podataka i struktura podataka, koji slicno zvuce i
zato je korisno ukazati na njihove specicnosti.
Pod tipom podataka se podrazumeva skup nekih vrednosti zajedno sa
skupom operacija koje su dozvoljene nad tim vrednostima. Tako logicki tip
podataka sadri samo dve vrednosti true i false, a dozvoljene operacije
nad njima su uobicajene logicke operacije negacije, konjunkcije, disjunkcije
i tako dalje. Slicno, tip podataka pod imenom string sadri vrednosti koje
predstavljaju niske znakova, a dozvoljene operacije nad njima su spajanje
dve niske, odredivanje
duina jedne niske, poredenje
dve niske i tako dalje.
racunaru. Apstrakcija problema omogucava dakle postupan pristup reavanju sloenog problema, jer se softverski sistem moe izgraditi deo po
1.1. Podaci
Uvod
u steku se mogu dobiti i skinuti samo sa vrha steka. Ako komade mesa
apstrahujemo kao podatke i icu ranjica kao stek, primetimo da postupak
rada sa podacima u steku tacno odgovara nacinu na koji se postupa sa
komadima mesa na ici ranjica: dodaju se na vrh ice i odatle se skidaju.
Naravno, stek kao logicki model podataka nije karakteristican samo za
banalan primer ranjica, pa vanost steka proizilazi iz toga to se moe
prepoznati u mnogim drugim primenama.
S druge strane, stek kao struktura podataka posmatra se sa stanovita
programske realizacije njegove apstraktne organizacije podataka. Pitanja
na koja treba odgovoriti u tom slucaju su, recimo, da li je stek bolje realizovati pomocu niza ili povezane liste, kolika je ekasnost operacija dodavanja
i uklanjanja podataka iz steka u pojedinim slucajevima i tako dalje.
Apstraktni tip podataka denie interfejs izmedu
programera i podataka i zaokruuje neki model podataka u smislu da je implementacija tog
modela lokalizovana u jednom delu programa. To je od velike prakticne
vanosti, jer ako elimo da promenimo realizaciju odgovarajuce strukture
podataka, najpre znamo gde to treba uciniti. Takode
znamo da ako promenimo jedan mali deo programa, time necemo izazvati teko uocljive greke
u nekom drugom delu koji nema veze sa odgovarajucim tipom podataka.
Na kraju, sa podacima apstraktnog tipa moemo raditi kao da su primitivnog tipa i ne obracati panju na njihovu konkretnu realizaciju.
Apstraktni tipovi podataka imaju dva poeljna svojstva, generalizaciju
i enkapsulaciju, koje nam omogucavaju da ispunimo vaan cilj softverskog
inenjerstva viekratnu upotrebljivost. Naime, poto implementiramo
apstraktni tip podataka, moemo ga koristiti u razlicitim programima.
Moemo dakle zakljuciti da podaci u racunarstvu imaju dva pojavna
oblika: logicki i zicki. Njihov logicki oblik se odreduje
denicijom ap
straktnog tipa podataka, dok se zicki oblik dobija implementacijom odgovarajuce strukture podataka. Ovo zapaanje je ilustrovano na slici 1.1.
1.2 Algoritmi
Spomenuli smo da su algoritmi u tesnoj vezi sa strukturama podataka
i da se koriste za programsku realizaciju dozvoljenih operacija nekog apstraktnog tipa podataka. To je ipak samo jedna specicna primena algoritama, a da bismo ih posmatrali optije, moramo poci od racunarskih
problema koje algoritmi reavaju.
1.2. Algoritmi
Tip podataka
ATP:
skup podataka
skup operacija
Struktura podataka:
memorijska reprezentacija
algoritamska reprezentacija
logicka forma
zicka forma
Pod (racunarskim) problemom se podrazumeva zadatak koji treba izvriti na racunaru. Takav zadatak se opisuje preciznom specikacijom
eljenog ulazno-izlaznog odnosa kojim se izraava priroda problema. Na
primer, problem sortiranja niza brojeva moe se opisati na sledeci nacin:
ulaz je niz brojeva u proizvoljnom redosledu, a izlaz je niz istih brojeva koji
su preuredeni
tako da se pojavljuju u rastucem redosledu od najmanjeg
Uvod
1.2. Algoritmi
Algoritam
ulaz
algoritamski
koraci
izlaz
S LIKA 1.2: Pojednostavljena slika algoritma.
Drugo, algoritam reava neki problem ukoliko se na ulazu algoritma
pretpostavlja ulaz tog problema i na izlazu algoritma se dobija reenje tog
problema za svaku instancu problema. Na primer, algoritam koji reava
problem sortiranja na ulazu dobija neureden
niz brojeva i kao rezultat na
izlazu proizvodi niz istih brojeva u rastucem redosledu.
Algoritam za neki problem je dakle precizno naveden niz instrukcija
koje racunar treba da izvri radi reavanja tog problema, odnosno radi
transformisanja svake instance problema u njeno reenje. Naravno, jedan
problem moe imati vie algoritama koji ga reavaju.
Na osnovu svega do sada recenog moemo sumirati glavne odlike svakog algoritma:
Algoritam mora biti postupak koji se sastoji od konacno mnogo koraka koji se mogu izvriti na racunaru.
Algoritam mora biti postupak po kojem je nedvosmisleno odreden
Uvod
1.3 Racunarski
model
Ono to je ostalo nedoreceno iz prethodne diskusije o algoritmima jesu
racunarske instrukcije (ili koraci) koje c ine algoritam. Iako je to, nadamo
se, intuitivno jasno c itaocima koji imaju programersko iskustvo, radi vece
jasnoce potrebno je ipak neto vie reci o tome koje nam instrukcije tacno
stoje na raspolaganju kada piemo neki algoritam. Drugim recima, potrebno je malo detaljnije opisati model racunara na kojem se izvravaju
algoritmi o kojima smo govorili u prethodnom odeljku.
Uopteno govoreci, racunarski modeli su pojednostavljeni opisi stvarnih racunara kojima se zanemaruje njihova puna sloenost, osim nekoliko
svojstava za koje se smatra da najbolje odslikavaju fenomen koji se izucava.
Poto je merenje racunarskih resursa (vreme i prostor) koje algoritmi koriste jedan od predmeta naeg izucavanja, to znaci da najpre treba precizno
formulisati model racunarske maine na kojoj se algoritmi izvravaju i denisati primitivne operacije koje se koriste prilikom izvravanja. Medutim,
necemo ici u toliko detalja za opis formalnog racunarskog modela, vec c emo
u nastavku samo neformalno opisati glavne odlike racunarskog modela sa
kojim radimo. To je dovoljno za nau svrhu, jer c e nas interesovati asimptotske performanse algoritama, odnosno njihova ekasnost za veliki broj
1.3. Racunarski
model
10
Uvod
11
racunaru, pa se zato pie na nekom programskom jeziku potujuci njegova striktna pravila. Znamo da su tu vani svako slovo, svaka zapeta
i svaki simbol, tako da nemamo pravo na greku prilikom pisanja ako
hocemo da napisani program izvrimo na racunaru. Za algoritme nam
ne treba takav apsolutni formalizam na kraju krajeva, algoritmi se ne
izvravaju na pravim i glupim racunarima. Algoritmi se mogu zamisliti
da se izvravaju na jednoj vrsti idealizovanog racunara sa neogranicenom
memorijom. Oni su u stvari matematicki objekti koji se mogu analizirati
da bi se prepoznali sutinski delovi sloenih problema. Stoga, vrlo je bitno
da moemo apstrahovati nevane detalje programskog jezika. Jo jedna
razlika izmedu
algoritama i pravih programa je da nam kod algoritama
nisu bitna pitanja softverskog inenjerstva. Na primer, da bi se sutina
algoritama prenela to jasnije i jezgrovitije, obrada greaka kod algoritama
se obicno zanemaruje.
Algoritmi su obicno mali po velicini ili se sastoje od kratkih delova
naredbi proetih tekstom koji objanjava glavne ideje ili naglaava kljucne
tacke. Ovo je uglavnom prvi korak za reavanje problema na racunaru
poto sitni, nevani detalji programskih jezika mogu samo da smetaju za
dobijanje prave slike problema. Ovo ne znaci da algoritam sme da sadri
bilo kakve dvosmislenosti u vezi sa vrstom naredbi koje treba izvriti ili
sa njihovim tacnim redosledom izvravanja. To samo znaci da moemo biti
nemarni da li neki znak dolazi ovde ili onde, ako to nece zbuniti onoga koji
pokuava da razume algoritam. Pored toga, neki elementi koji su formalno
neophodni kod racunarskih programa, na primer, tipovi podataka, obicno
se podrazumevaju iz konteksta bez navodenja.
Zbog ovih razloga se algoritmi najcece neformalno izraavaju na pseudo jeziku koji sadri elemente kako prirodnog tako i programskog jezika.
U stvari, u ovoj knjizi se c esto obicnim jezikom najpre opisuje glavna ideja
algoritma, a zatim se prelazi na pseudo jezik da bi se pojasnili neki kljucni
detalji algoritma.
Pseudo jezik koji koristimo u ovoj knjizi za zapis algoritama sadri
elemente programskih jezika C, Pascal i Java, tako da c italac koji je programirao na ovim jezicima nece imati nikakvih problema da razume napisane
algoritme. U tom pseudo jeziku se koriste uobicajeni koncepti programskih
jezika kao to su promenljive, izrazi, uslovi, naredbe i procedure. Ovde nec emo pokuavati da damo precizne denicije sintakse i semantike pseudo
jezika koji se koristi u knjizi, poto to nije potrebno za nau svrhu i svakako
prevazilazi namenu ove knjige. Umesto toga, u nastavku navodimo samo
kratak spisak konvencija u koricenom pseudo jeziku:
12
Uvod
13
14
Uvod
Algoritam swap slui prvenstveno za ilustraciju zapisa na pseudo jeziku, jer je njegov postupak za reenje problema zamene vrednosti dve
promenljive ocigledan.
element niza
Primer: najveci
Ako je dat niz a od n neuredenih
brojeva a 1, a 2 , . . ., a n , problem je naci
// najve
ci element na
den do sada
// indeks najve
ceg elementa
i = 2;
// proveriti ostale elemente niza
while (i <= n) do
if (m < a[i]) then // na
den ve
ci element od privremeno najve
ceg
m = a[i];
// zapamtiti ve
ci element
j = i;
// ... i njegov indeks
i = i + 1; // pre
ci na slede
ci element niza
return j;
Primetimo da se postupak algoritma max zasniva na induktivnom rezonovanju: ako znamo da je element a j najveci u podnizu a 1 , . . ., a i , da bismo
15
Zadaci
1. Problem pretrage niza je:
Ulaz: Broj n, niz a od n neuredenih
brojeva a 1 , a 2, . . ., a n , broj x.
G LAVA
2
Dizajn i analiza algoritama
Prilikom pisanja algoritama se mora obratiti posebna panja na njihova dva aspekta: ispravnost i ekasnost. Kod dizajna algoritama se
obraca posebna panja na prvo pitanje ispravnosti (korektnosti) algoritama. To je narocito vano za sloene algoritme kod kojih njihova ispravnost nije ocigledna, vec zahteva paljiv matematicki dokaz. Cilj analize
algoritama su kvantitativne ocene ekasnosti algoritama. To je takode
18
lake pretvoriti u racunarske programe, jer dobijeni programi tada najverovatnije nemaju skrivenih greaka koje se manifestuju tek u proizvodnom
okruenju. Naravno, algoritam je bolji ukoliko je lako razumljiv onome
ko c ita njegov opis na pseudo jeziku. Naalost, u praksi ovaj zahtev za
ekasnim i jednostavnim algoritmima je c esto kontradiktoran, pa moramo
pronaci balans izmedu
njih kada piemo algoritme.
U vrlo optim crtama, postupak dobijanja dobrih algoritama za vecinu
problema obuhvata ova tri koraka:
1. Najpre se eleminiu svi nevani i remetilacki detalji prakticnog problema koji se reava, kako bi se dobio racunarski problem u to c istijem obliku. To obicno znaci da se problem predstavlja u apstraktnim
terminima prostih matematickih pojmova kao to su skupovi, funkcije,
grafovi i slicno.
2. Poto je problem jasno matematicki denisan, pie se algoritam koji ga
reava i dokazuje se njegova ispravnost. Ovo se vecim delom izvodi uz
pomoc poznatih algoritamskih paradigmi i matematickih alata.
3. Na kraju se sprovodi analiza algoritma da bi se ustanovila njegova ekasnost. Pri tome se, poto ocena ekasnosti algoritma moe biti vrlo
komplikovana, primenjuju odredene
tehnike kojima se znatno pojedno
stavljuje analiza. O ovome c e biti vie reci u ostalom delu knjige.
Naravno, ovi koraci nisu potpuno nezavisni jedan od drugog i c esto
se medusobno
preplicu. Isto tako, za prostije probleme nisu potrebni svi
2.1
Dizajn algoritama
19
mora da zadovolji jeste da ispravno reava dati problem. Na putu dokazivanja ispravnosti algoritma postoje mnoge prepreke, kako prakticne tako i
teorijske. to se tice prakticnih tekoca, one su u vezi sa c injenicom da se
vecina programa pie tako da zadovoljavaju neke neformalne specikacije,
koje su i same nepotpune ili protivrecne. Prepreke na teorijskoj strani su
to to, uprkos brojnim pokuajima da se formalno denie znacenje programa, nije se iskristalisao opte prihvaceni formalizam kojim se pokazuje
ispravnost netrivijalnih algoritama.
U svakom slucaju, za skoro sve algoritme je potrebno istaci i pokazati
njihove bitne odlike. Za jednostavne algoritme je obicno dovoljno kratko
objanjenje njihovih glavnih odlika. Odlike o kojima je rec su najcece
formalna tvrdenja
koje odslikavaju nacin na koji konkretan algoritam radi.
Onaj ko pie algoritam bi bar trebao da ima u vidu te odlike, iako je moda
neprakticno da se one dokazuju u svim detaljima. Te odlike treba da slue
i kao odreden
vodic u kreativnom procesu pisanja nekog algoritma.
zajednicki
delilac
Primer: najveci
Da bismo prethodnu diskusiju ilustrovali jednim prostim primerom,
razmotrimo problem izracunavanja najveceg zajednickog delioca dva pozitivna cela broja x i y. Najveci zajednicki delilac za par pozitivnih celih
brojeva x i y oznacava se sa nzd(x, y) i predstavlja najveci ceo broj koji
bez ostatka deli oba broja x i y. To jest, najveci zajednicki delilac je broj
d = nzd(x, y) koji deli i x i y bez ostatka, pa x = md i y = nd za neke brojeve
m, n N,1 i svaki drugi takav zajednicki delilac brojeva x i y je manji od d.
Da li je ovo dobra denicija? Drugim recima, da li svaki par pozitivnih
celih brojeva ima najveci zajednicki delilac? Jasno je da svaki par pozitivnih celih brojeva ima broj 1 za zajednickog delioca, a najveci broj koji
istovremeno moe da deli x i y bez ostataka je onaj broj koji je minimum
od x i y. Dakle, nzd(x, y) uvek postoji i lei negde u intervalu izmedu
1i
min{ x, y}.
Ovo zapaanje moemo iskoristiti za postupak kojim se trai nzd(x, y)
tako to se redom proveravaju svi potencijalni kandidati za najveci zajednicki delilac brojeva x i y. Ovi kandidati su uzastopni celi brojevi od
broja jedan do minimuma brojeva x i y. Pri tome se ti brojevi proveravaju
obrnutim redom da li je neki od njih zajednicki delilac za x i y, sve dok se ne
otkrije prvi zajednicki delilac. Poto se provera obavlja obrnutim redom od
1 U ovoj knjizi sa N oznacavamo skup {0,1,2,... } nenegativnih celih brojeva.
20
i najveci.
// Ulaz: pozitivni celi brojevi x i y
// Izlaz: nzd(x, y)
algorithm gcd(x, y)
d = min{x,y};
while ((x % d != 0) || (y % d != 0)) do
d = d - 1;
return d;
uslove. Neophodan uslov za svaku petlju je da njen izlazni uslov bude zadovoljen u jednom trenutku kako bi se izvravanje petlje sigurno zavrilo.
Druga vrsta uslova su oni c ija se tacnost ne menja izvravanjem petlje.
Takav jedan uslov se naziva invarijanta petlje i predstavlja formalni iskaz
koji je tacan pre svake iteracije petlje. To znaci da c e invarijanta petlje biti
tacna nakon izvravanja poslednje iteracije petlje (ili pre prve neizvrene
iteracije), odnosno ona c e biti tacna nakon zavretka rada cele petlje. Prepoznati pravu invarijantu petlje je vana vetina, jer znajuci invarijantu
petlje i izlazni uslov petlje obicno moemo zakljuciti neto korisno o ispravnosti samog algoritma.
Da bismo pokazali da se invarijanta petlje ne menja izvravanjem petlje, moramo pokazati dve c injenice o invarijanti petlje:
1. Invarijanta petlje je tacna pre prve iteracije petlje.
2. Ako je invarijanta petlje tacna pre neke iteracije petlje, ona ostaje
tacna i nakon izvravanja te iteracije petlje (to jest, pre izvravanja
sledece iteracije).
Prema tome, u konkretnom slucaju algoritma gcd pokaimo najpre da
se while petlja sigurno zavrava, odnosno da nije beskonacna. Primetimo
da se izlaznim uslovom te petlje proverava da li d nije delilac broja x ili
broja y bez ostatka. Ako je to slucaj, telo petlje se ponavlja; u suprotnom
21
slucaju, petlja se zavrava. Da bismo videli zato c e izlazni uslov naposletku postati netacan, primetimo da je pocetno d = min{ x, y}, a da se d
u svakoj iteraciji smanjuje za 1. Ovim uzastopnim smanjivanjem c e d u
najgorem slucaju postati jednako 1, izlazni uslov c e onda biti netacan poto
je istovremeno x % 1 = 0 i y % 1 = 0, pa c e se petlja tada zavriti.
Sada jo moramo pokazati tacnost izracunavanja nzd(x, y) u algoritmu
gcd. Odgovarajuca invarijanta while petlje je uslov d nzd(x, y). Jasno je
da je ovaj uslov zadovoljen pre prve iteracije te petlje, jer d pocetno dobija
vrednost min{ x, y} i uvek je min{ x, y} nzd(x, y). Dalje, treba pokazati da
ako ovaj uslov vai pre neke iteracije, on c e vaiti i posle izvravanja te
iteracije. Zato pretpostavimo da je vrednost promenljive d veca ili jednaka
vrednosti nzd(x, y) pre neke iteracije, i pretpostavimo da je ta iteracija
while petlje izvrena. To znaci da je izlazni uslov petlje bio tacan i da se
vrednost promenljive d smanjila za 1. Poto je izlazni uslov bio tacan, stara
vrednost promeljive d nije bila delilac oba broja x i y, pa zato stara vrednost
promeljive d nije jednaka nzd(x, y) nego je striktno veca od nzd(x, y). Poto
je nova vrednost promenljive d za jedan manja od njene stare vrednosti,
moemo zakljuciti da je nova vrednost promenljive d opet veca ili jednaka
vrednosti nzd(x, y) pre sledece iteracije. Ovim je dokazano da d nzd(x, y)
predstavlja invarijantni uslov while petlje u algoritmu gcd.
Na kraju, ispitajmo koji uslov vai kada se while petlja zavri. Iz
uslova prekida te petlje vidimo da se ona zavrava kada je vrednost promenljive d delilac oba broja x i y. Poto je nzd(x, y) najveci delilac oba broja
x i y, sledi da nakon zavretka while petlje vai d nzd(x, y). Ali poto
nakon zavretka while petlje vai i invarijanta petlje d nzd(x, y), sledi
da mora biti d = nzd(x, y). Poto se ova vrednost promeljive d vraca kao
rezultat algoritma gcd, to pokazuje da ovaj algoritam ispravno izracunava
nzd(x, y).
2.2
Analiza algoritama
koje taj algoritam koristi tokom izvravanja. Ovaj zadatak ocene ekasnosti nekog algoritma se naziva analiza algoritma. To ne treba shvatiti
kao nezavisan i odvojen proces od dizajna algoritma, vec se oni medusobno
proimaju i podjednako doprinose krajnjem cilju dobijanja ispravnih, ekasnih i elegantnih algoritama.
22
algoritama memorijski zahtevi bice pomenuti samo ako nisu u normalnim granicama. Drugim recima, ekasnost algoritma identikujemo sa
duinom njegovog vremena izvravanja.
Kako moemo odrediti vreme izvravanja nekog algoritma? Dva glavna
nacina da se to uradi su empirijski i analiticki. Empirijski nacin podrazumeva da se prosto izmeri stvarno vreme rada odgovarajuceg programa
na racunaru. Analiticko odredivanje
vremena izvravanja zasniva se na
ciljeva. Zbog toga se, naravno, ne dobija apsolutno precizna ocena vremena
izvravanja, ali je ona dovoljno dobra da steknemo optu sliku o ekasnosti
algoritama.
Vreme izvravanja nekog algoritma skoro uvek zavisi od broja ulaznih podataka koje treba obraditi. Tako, prirodno je ocekivati da sortiranje 10 000 brojeva zahteva vie vremena nego sortiranje samo 10 brojeva.
23
ulaz
T(n)
izlaz
Medutim,
tacno vreme izvravanja algoritma za neki konkretni ulaz,
pored njegove velicine n, zavisi i od drugih faktora kao to su brzina procesora racunara ili struktura samih ulaznih podataka. Zato da bismo pojednostavili analizu i da bi denicija funkcije T(n) imala smisla, pretpostavljamo da se sve osnovne instrukcije algoritma izvravaju za jednu vremensku jedinicu i uzimamo najgori slucaj ulaznih podataka. Onda da bismo
dobili funkciju vremena izvravanja T(n) nekog algoritma treba da prosto
prebrojimo osnovne instrukcije koje c e se u algoritmu izvriti u najgorem
24
aritmeticke operacije;
logicke operacije;
ulazno/izlazne operacije.
Jedno upozorenje: ove instrukcije se ponekad ne mogu smatrati jedinicnim instrukcijama u algoritmu. Na primer, neka aritmeticka operacija koja izgleda naivno kao to je to na primer sabiranje, nije jedinicna
instrukcija ukoliko je velicina operanada aritmeticke operacije velika. U
tom slucaju, vreme potrebno za njeno izvravanje se povecava sa velicinom
njenih operanada, pa se ne moe ograniciti nekom konstantom nezavisnom
od velicine podataka. Imajuci ovo na umu, ipak c emo prethodne instrukcije
smatrati jedinicnim sem ako to nije realisticno za dati problem.
Prethodnu diskusiju o analizi algoritama moemo pretociti u prakticni
postupak za odredivanje
vremenske sloenosti algoritama ukoliko prime
timo da je najgori slucaj izvravanja algoritma onaj u kojem se izvrava
najveci broj jedinicnih instrukcija. Kao jednostavan primer, razmotrimo
25
A1:
1
2
3
4
5
n = 5;
repeat
read(m);
n = n - 1;
until ((m == 0) || (n == 0));
A2:
1
2
3
4
5
read(n);
repeat
read(m);
n = n - 1;
until ((m == 0) || (n == 0));
skup ulaznih podataka date velicine. Drugo, najgori slucaj je mnogo laki
za analizu (cesto i jedino moguci) nego drugi kriterijumi ekasnosti algoritama.
Prebrojavanje broja jedinicnih instrukcija u najgorem slucaju izvravanja algoritma kako bi se dobilo vreme izvravanja tog algoritma moe
se umnogome pojednostaviti ako znamo vremenske relacije tipicnih algoritamskih konstrukcija. Naime, vreme izvravanja sloenijih konstrukcija moemo izvesti na osnovu vremena izvravanja njihovih sastavnih
delova. U tabeli 2.1 su sumirana vremena izvravanja osnovnih algoritamskih konstrukcija, pri c emu je sa T B oznaceno vreme izvravanja (u
najgorem slucaju) bloka naredbi B. Tom tabelom nije obuhvacena rekurzija, poto c e o njoj biti vie reci u poglavlju 5.
U tabele 2.1 je ocigledno da je vreme izvravanja serije dva bloka naredbi jednako zbiru vremena izvravanja pojedinih blokova. Isto tako,
jasno je da je vreme izvravanja alternative dva bloka naredbi jednako
duem vremenu izvravanja jednog od ta dva bloka, jer se posmatra najgori
slucaj izvravanja.
Najvanije pravilo u ovoj tabeli jeste da je vreme izvravanja petlje
jednako vremenu izvravanja naredbi u telu petlje pomnoenim sa najve-
26
Konstrukcija
Naredba serije S:
P; Q;
Naredba grananja S:
if C then P; else Q;
Vreme izvravanja
T S = T P + TQ
T S = T C + max{T P , TQ }
Naredba petlje S:
(1) while C do P;
(2) repeat P; until C;
TS = n TP
n najveci broj iteracija petlje
(3) for i = j to k do P;
T ABELA 2.1: Vremenska sloenost osnovnih algoritamskih konstrukcija.
naredbi u telu najunutranjije petlje pomnoeno sa proizvodom broja iteracija svih petlji. Na primer, posmatrajmo ovaj algoritamski fragment:
1
2
3
4
for i = 1 to n do
for j = 1 to n do
if (i < j) then
swap(a[i,j], a[j,i]);
// jedini
cna instrukcija
27
Jedan od njih je probabilisticka analiza srednjeg vremena izvravanja nekog algoritma. Prosecno vreme izvravanja je funkcija Tp (n) koja daje srednju vrednost vremena izvravanja algoritma za slucajne ulazne podatke
velicine n. Prosecno vreme izvravanja je realisticnija mera performansi
algoritma u praksi, ali je c esto to mnogo tee odrediti nego vreme izvravanja u najgorem slucaju. Razlog za to je da moramo znati raspodelu
verovatnoce slucajnih ulaznih podataka, to je teko zamislivo u praksi.
Ali da bismo ipak mogli lake izvesti matematicka izracunavanja, obicno
pretpostavljamo da su svi ulazi velicine n jednako verovatni, to u nekom
konkretnom slucaju moda i nije pravo stanje stvari.
Probabilisticku analizu deterministickih algoritama treba razlikovati
od analize takozvanih randomiziranih algoritama. Randomizirani algoritmi su po svojoj prirodi slucajni jer se u toku njihovog izvravanja donose slucajne odluke. Njihovo vreme izvravanja zavisi od slucajnih ishoda
tih odluka i zato predstavlja slucajnu vrednost. Za randomizirane algoritme se odreduje
ocekivano vreme izvravanja, pri c emu se matematicko
28
naci indeks (prvog) najmanjeg elementa tog niza. Algoritam min za ovaj
problem je zato jednostavna modikacija algoritma max kojim se nalazi
indeks najveceg elementa niza. Naime, za nalaenje globalno najmanjeg
elementa niza, svi elementi niza se redom proveravaju da li su manji od
najmanjeg elementa koji je naden
do odgovarajuceg trenutka provere.
// Ulaz: niz a, broj elemenata n niza a
// Izlaz: indeks najmanjeg elementa niza a
algorithm min(a, n)
m = a[1];
j = 1;
29
// najmanji element na
den do sada
// indeks najmanjeg elementa
i = 2;
// proveriti ostale elemente niza
while (i <= n) do
if (m > a[i]) then // na
den manji element od privremeno najmanjeg
m = a[i];
// zapamtiti manji element
j = i;
// ... i njegov indeks
i = i + 1; // pre
ci na slede
ci element niza
return j;
Analizu jednostavnog algoritma min nije teko izvriti. Poto broj iteracija tela while petlje iznosi n 1, a telo te pelje se sastoji od if naredbe
i naredbe dodele, vreme izvravanja algoritma min je:
T(n) = 1 + 1 + 1 + (n 1)(3 + 1) + 1
= 4 + 4(n 1)
= 4n .
U ovom izrazu za funkciju T(n) u prvom redu, prve tri jedinice u zbiru su
vremena izvravanja prve tri naredbe dodele u algoritmu min, faktor (3 + 1)
predstavlja vreme jednog izvravanja tela while petlje (provera uslova i
dve naredbe dodele u if naredbi, kao i naredba dodela na kraju tela petlje),
a poslednjom jedinicom je obuhvaceno vreme izvravanja return naredbe.
U izrazu 4n za funkciju T(n) vremena izvravanja algoritma min se
velicina ulaza n (tj. broj elemenata ulaznog niza) pojavljuje na prvi stepen.
Zato za taj algoritam kaemo da je linearni algoritam. Primetimo jo da
je vreme izvravanja algoritma max iz odeljka 1.4 takode
T(n) = 4n, jer su
algoritmi min i max prakticno isti.
30
j
ak .
k= i
31
Nula na desnoj strani ove jednakosti je potrebna zato to bez ove nule
jednakost ne bi bila tacna kada se dati niz sastoji samo od negativnih elemenata. Ali radi jednostavnijeg pisanja, u daljem tekstu pretpostavljamo
da implicitno uvek uzimamo 0 kao maksimalnu sumu u tom specijalnom
slucaju. Tako, prethodnu jednakost piemo saetije:
M = max S i, j .
1 i j n
32
for j = i to n do
s = s + a[j];
if (m < s) then
m = s;
return m;
// S i, j = S i, j 1 + a j
// na
dena ve
ca suma
// aurirati maksimalnu sumu
// vratiti b i
Sada je lako napisati algoritam kojim se nalazi maksimalna suma podniza datog niza: algoritmom B treba najpre redom izracunati sve elemente
33
3(n i + 2) + 1 + (4n + 1) + 1
i =1
n
=3
i =1
(n i) + 7n + 4n + 2
(n 1)n
+ 11n + 2
2
= 1.5n2 + 9.5n + 2 .
=3
Podsetimo se da funkcija T(n) predstavlja vreme izvravanja (u najgorem slucaju) nekog algoritma za sve ulazne podatke tog algoritma velicine
n. Poto se promenljiva n u prethodnom izrazu za funkciju T(n) vremena
izvravanja algoritma mcss pojavljuje na drugi stepen, za taj algoritam
kaemo da je kvadratni algoritam.
Primetimo da je moguce poboljati ovaj algoritam ukoliko eljeni maksimum M elemenata b i izracunavamo u hodu. Naime, umesto da maksimum elemenata b i traimo nakon to sve te elemente izracunamo, moemo
da odredujemo
njihov privremeni maksimum kako ih redom izracunavamo.
Pored toga, na ovaj nacin nam ne treba poseban niz za c uvanje elemenata
b i , pa zato u ovom slucaju tedimo na memorijskom prostoru.
U stvari, ovaj pristup moemo dalje poboljati ukoliko odredujemo
pri
vremeni maksimum ne od elemenata b i vec od suma S i, j kako ih redom
izracunavamo. Postupak na pseudo jeziku za ovu tedljivu verziju algoritma mcss je:
3 Ime algoritma mcss je skracenica od engleskog termina za problem najvece sume
neprekidnog podniza: the maximum contiguous subsequence sum problem.
34
Citaocima
se za vebu ostavlja da se uvere da ova varijanta nije bra
od prvobitne, odnosno da je i dalje rec o kvadratnom algoritmu.
Preciznije, za dati niz a od n elemenata a 1 , a 2, . . ., a n treba naci permutaciju svih indeksa elemenata niza i 1 , i 2 , . . ., i n tako da novi prvi element a i 1 ,
novi drugi element a i 2 i tako dalje, novi n-ti element a i n u nizu zadovoljavaju uslov a i 1 a i 2 a i n .
Za reavanje problema sortiranja niza c emo pokazati tri jednostavna
algoritma. To su klasicni algoritmi koji priblino imaju isto vreme izvravanja koje kvadratno zavisi od velicine ulaza (tj. broja elemenata niza). U
nastavku knjige c emo upoznati ekasnije metode sortiranja.
Sortiranje zamenjivanjem (bubble-sort). Najbolji nacin za razumevanje osnovne ideje prvog metoda sortiranja, koji se popularno naziva sortiranje zamenjivanjem (engl. bubble-sort), jeste da zamislimo da je dati
niz potopljen u vodu i okrenut vertikalno. Ako dalje zamislimo da su
elementi datog niza sa malim vrednostima laki po teini, onda c e oni
ovim metodom isplivavati na vrh proizvodeci mehurice. Ova analogija
je upravo razlog za (interesantan?) engleski naziv ovog metoda.
Postupak sortiranja zamenjivanjem se sastoji od viestrukih prolaza
du datog niza od dna ka vrhu. Pri tome, ako dva susedna elementa
nisu u dobrom redosledu (laki element je ispod teeg), zamenjujemo
im mesta. Efekat ovog zamenjivanja je da se u prvom prolazu najlaki
35
i=2
i=3
i=4
i=5
17
23
17
23
17
11
23
17
11
11
11
23
17
17
11
11
23
23
36
bubble-sort. Citaoci
mogu lako proveriti da za ksnu vrednost brojaca i =
1, 2, . . ., n 1 spoljanje for petlje, telo unutranje for petlje c e se izvriti
tacno n i puta. Zbog toga ukupan broj izvravanja tela unutranje petlje
iznosi:
n
1
(n 1)n
(n 1) + (n 2) + + 2 + 1 =
i=
.
2
i =1
Prema tome, ako uzmemo u obzir i naredbu return na kraju, ukupno
vreme izvravanja algoritma bubble-sort je:
T(n) =
(n 1)n
2 + 1 = n2 n + 1 .
2
se izvrava za konstantno vreme smatramo jedinicnom instrukcijom, jer tacna vrednost tog
konstantnog vremena nije bitna.
37
Citaocima
se za vebu ostavlja da se uvere da je u najgorem slucaju
poboljana verzija algoritma bubble-sort i dalje kvadratni algoritam, ali
u najboljem slucaju je to linearni algoritam. Ovde je interesantno napomenuti da je ovaj nacin jedan od najbrih metoda sortiranja u slucaju kada se
unapred zna da je samo mali broj elemenata van svog mesta u rastucem
redosledu (recimo, kada se vec sortiranom nizu dodaju dva-tri elementa).
Sortiranje umetanjem (insert-sort). Drugi metod za sortiranje niza
a od n elemenata a 1, a 2 , . . ., a n popularno se naziva sortiranje umetanjem
(engl. insert-sort). Ovaj metod se sastoji od n iteracija, pri c emu se u itoj iteraciji umece element a i na njegovo pravo mesto izmedu
prvih i 1
najmanjih elemenata prethodno vec uredenih
u rastucem redosledu. Ovaj
38
i 1
// Ulaz:
niz a, broj elemenata n niza a
// Izlaz: niz a sortiran u rastu
cem redosledu
algorithm insert-sort(a, n)
a[0] = -;
for i = 1 to n do
j = i
while (a[j] < a[j-1]) do
swap(a[j], a[j-1]);
j = j - 1;
return a;
while
kao za algoritam bubble-sort. Dodue, broj iteracija ugnjedene
petlje nije odmah ocigledan, ali moemo primetiti da taj broj nije veci od
i 1. To je zato to promenljiva j dobija pocetnu vrednost jednaku vrednosti promenljive i pre pocetka while petlje, a j se smanjuje za jedan u
svakoj iteraciji te petlje do zavretka rada petlje. A while petlja se sigurno
zavrava kada je j = 1, jer je onda a j 1 = a 0 = , c ime uslov nastavka te
petlje postaje netacan. U najgorem slucaju dakle, iteracije while petlja se
izvravaju za sve uzastopne vrednosti j od i do 2, pa je broj tih iteracija
najvie i 1.
Prema tome, u algoritmu insert-sort se izvrava n iteracija spoljanje for petlje, a u svakoj od tih iteracija za i = 1, 2, . . ., n izvrava se
najvie i 1 iteracija unutranje while petlje. Poto se telo unutranje
while petlje izvrava za 2 vremenske jedinice, ukupno vreme izvravanja
algoritma insert-sort je:
T(n) = 1 +
= 1+
1 + 2(i 1) + 1
i =1
n
i =1
1+2
= 1+n+2
n
i =1
(i 1) + 1
(n 1)n
+1
2
39
= n2 + 2 .
je 0. Citaoci
mogu lako proveriti da je onda vreme izvravanja algoritma
insert-sort jednako 2n + 2, to je mnogo bolje nego u najgorem slucaju.
Sortiranje izborom (select-sort). Metod sortiranja niza a od n elemenata a 1 , a 2 , . . ., a n , koji se popularno naziva sortiranje izborom (engl. selectsort), zasniva se kao i prethodni metodi na ponavljanju odredenog
postupka
nad datim nizom. Taj postupak u ovom metodu je da se u i-toj iteraciji uzima najmanji element medu
elementima a i , a i+1 , . . ., a n i zamenjuje
sa elementom a i . Ovaj nacin sortiranja u i-toj iteraciji je ilustrovan na
slici 2.4.
i 1
40
j = minr(a, i, n);
swap(a[i], a[j]);
return a;
Algoritam minr, koji se u algoritmu select-sort koristi kao potprogram, kao rezultat daje indeks najmanjeg elementa desnog podniza a i ,
a i+1 , . . ., a n datog niza a. Taj algoritam je mala modikacija algoritma min
n
1
4(n i + 2) + 2 + 1
i =1
n
1
i =1
4(n i) + 10 + 1
(n 1)n
+ 10(n 1) + 1
2
= 2n2 + 8n 9 .
=4
Zadaci
1. Koristeci odgovarajucu invarijantu petlje, pokaite ispravnost algoritma
za problem pretrage niza u 1. zadatku prethodnog poglavlja. Pored toga,
odredite vreme izvravanja tog algoritma.
2. Koristeci odgovarajucu invarijantu petlje, pokaite ispravnost algoritma
za problem preostalog dela kredita u 2. zadatku prethodnog poglavlja.
(Savet: Iznos kredita koji preostaje nakon i-te iteracija petlje je p i .)
Pored toga, odredite vreme izvravanja tog algoritma.
3. Odredite vreme izvravanja sledecih algoritamskih fragmenata:
41
a)
if (x == 0) then
for i = 1 to n do
a[i] = i;
b)
i = 1;
repeat
a[i] = b[i] + c[i];
i = i + 1;
until (i == n);
c)
if (x == 0) then
for i = 1 to n do
for j = 1 to n do
a[i,j] = 0;
else
for i = 1 to n do
a[i,i] = 1;
d)
for i = 1 to n do
for j = 1 to n do
for k = 1 to j do
if (i == j) then
a[k,k] = 0;
4. Ako niz brojeva predstavimo u prirodnom horizontalnom poloaju, postupak sortiranja zamenjivanjem (bubble-sort) na strani 34 sastoji se od
ponavljanja prolaza du datog niza od najveceg potrebnog indeksa niza
do najmanjeg, odnosno ti prolazi uvek idu u smeru zdesna na levo.
a) Napiite algoritam za sortiranja zamenjivanjem u kojem se du datog niza uvek prolazi u smeru sleva na desno.
b) Napiite algoritam za sortiranja zamenjivanjem u kojem se du datog niza naizmenicno prolazi u oba smera.
G LAVA
3
Vreme izvravanja algoritma
3.1
44
jednostavnijeg asimptotskog vremena izvravanja, opravdano je iz tri ra1 U racunarstvu se logaritam skoro uvek uzima za osnovu 2, a ne za osnovu 10 ili e. U
45
zloga. Prvo, brzina algoritama je narocito bitna kada je broj ulaznih podataka veliki, jer se vreme izvravanja (skoro) svakog algoritma povecava
sa brojem ulaznih podataka. Ako za isti problem imamo vie algoritama i
treba da odlucimo koji od njih da primenimo za njegovo reavanje, onda je
vano za koje vreme oni reavaju taj problem kada je broj ulaznih podataka
vrlo veliki. Naime, obicno je svaki algoritam dovoljno ekasan za mali broj
ulaznih podataka. To jest, uglavnom je irelevantno da li neki algoritam
radi, recimo, jednu milisekundu ili pet mikrosekundi za desetak ulaznih
podataka. Ta dva vremena su ionako neprimetna za ljude, ali to da li
algoritam radi pet minuta ili tri meseca za milion ulaznih podataka jeste
svakako znacajno za odluku da li c emo ga primeniti za reavanje datog
problema.
Drugo, za dovoljno velike vrednosti argumenta, vrednost funkcije vremena izvravanja je preovladuju
ce odredena
njenim dominantnim termom.
n3
T2 (n)
n log n
46
2n
5n2
100n
A1
100
1 s
10
1024
500
1000
10
100
100
50000
10000
100
21000
5 106
100000
1000
1000
A2
5 s 100 s
1 ms 0,5 ms
70
A3
1 ms
0,05 s
0,01 s
2970 g
5s
0,1 s
47
for i = 1 to n do
for j = 1 to n do
a[i,j] = 0;
for i = 1 to n do
a[i,i] = 1;
Vreme izvravanja T(n) ovog fragmenta jednako je zbiru vremena izvravanja dve petlje: prve for petlje u prvom redu i druge for petlje
for petlju u
u c etvrtom redu. Kako prva for petlja sadri ugnjedenu
drugom redu, isto kao ranije moramo najpre odrediti broj iteracija ovih
petlji i vreme jednog izvravanja tela unutranje petlje, a zatim pomnoiti
ove tri vrednosti.
Poto se telo unutranje petlje u trecem redu izvrava za konstantno
vreme, a broj iteracija spoljanje i unutranje petlje jednak je n, ukupno
vreme izvravanja for petlje u prvom redu je neka konstanta pomnoena
zanemariti kada je n veliko, pa
sa n2 . Ovu konstantu moemo medutim
for i = 1 to n do
for j = 1 to n
if (i == j)
a[i,j] =
else
a[i,j] =
do
then
1;
0;
48
Vreme izvravanja T(n) ovog fragmenta jednako je vremenu izvrafor petlje u prvom i drugom redu. Kako se telo
vanja dve ugnjedene
brojeva sortiran u rastucem redosledu: a 1 a 2 a n . Ovu pretpostavku da je niz sortiran moemo iskoristiti da bismo pretragu broja x u
nizu znatno ubrzali.
Metod koji se primenjuje u specijalnom slucaju sortiranog niza naziva
se binarna pretraga i slican je nacinu na koji se trai neka osoba u debelom
telefonskom imeniku. Naime, da bismo dato ime i prezime neke osobe
pronali u imeniku, najpre bismo imenik otvorili negde na sredini imenika
49
i tu pokuali da pronademo
eljenu osobu. Ako je tu nema, onda bismo
prezime traene osobe uporedili sa prezimenima osoba na toj srednjoj stranici. Ukoliko je prvo slovo prezimena traene osobe po azbucnom redu iza
prvog slova prezimena osoba na srednjoj stranici imenika, pretragu bismo
usmerili na drugu polovinu imenika. Naime, traena osoba se sigurno ne
moe nalaziti u prvoj polovini imenika poto su osobe u imeniku poredane
po azbucnom redu njihovih prezimena (tj. sortirane su u rastucem redosledu). Naravno, u drugom slucaju kada je prvo slovo prezimena traene
osobe po azbucnom redu ispred prvog slova prezimena osoba na srednjoj
stranici imenika, pretragu bismo usmerili na prvu polovinu imenika.
U drugom koraku bismo pretragu nastavili u odgovarajucoj polovini
imenika ponavljanjem slicnog postupka. Negde na polovini odgovarajuce
polovine bismo pokuali da pronademo
eljenu osobu, pa ako je tu nema,
50
a
oblast pretrage
ako je x < a k
x = ak ?
oblast pretrage
ako je x > a k
se petlja zavrava kada uslov i j nije ispunjen ili je traeni broj x naden,
51
nademo
odmah u prvom koraku ili u nekom koraku posle toga, ali se nije
teko uveriti da se najveci broj iteracija while petlje izvrava kada se broj x
ne nalazi u nizu a. Onda se naime prolazi kroz ceo ciklus suavanja oblasti
pretrage od celog niza, zatim jedne polovine niza, pa jedne c etvrtine niza,
pa jedne osmine niza i tako dalje, na kraju do oblasti pretrage od samo
jednog elementa niza, posle c ega vie ne vai uslov i j i petlja se zavrava.
Koliki je onda najveci broj iteracija while petlje u tom slucaju kada se
broj x ne nalazi u nizu a? Obratite panju na to da na ovo pitanje moemo
ne razmiljajuci mnogo odgovoriti da je taj broj najvie n, jer se nikad neki
element niza ne ispituje vie od jednom. To je tacno, ali onda bismo mogli
reci i da je taj broj najvie n2 ili n3 ili neto slicno. Ovde se srecemo sa jo
jednim svojstvom asimptotskog vremena izvravanja algoritma: iako se
njegova analiza umnogome pojednostavljuje, ipak se trudimo da dobijemo
to tacniju ocenu pravog vremena izvravanja algoritma.
Da bismo tacnije odredili najveci broj iteracija while petlje, moramo na
neki nacin naci dobru meru onoga to se zaista deava prilikom izvravanja
te petlje u algoritmu bin-search. U postupku binarne pretrage sutina je
da duina oblasti pretrage pocetno iznosi n, a na pocetku svake iteracije
osim prve, duina oblasti pretrage jednaka je otprilike polovini duine
oblasti pretrage na pocetku prethodne iteracije. Drugim recima, ako m
oznacava ukupan broj iteracija while petlje kada se broj x ne nalazi u nizu
a, onda:
na pocetku prve iteracije, duina oblasti pretrage iznosi n;
na pocetku druge iteracije, duina oblasti pretrage iznosi otprilike
n/2 = n/21;
na pocetku trece iteracije, duina oblasti pretrage iznosi otprilike
(n/2)/2 = n/4 = n/22;
na pocetku c etvrte iteracije, duina oblasti pretrage iznosi otprilike
(n/4)/2 = n/8 = n/23;
i tako dalje . . .
na pocetku poslednje m-te iteracije, duina oblasti pretrage iznosi
otprilike n/2m1.
= 1,
52
odnosno
n = 2 m 1 .
Tipicne
funkcije vremena izvravanja
Pojednostavljenom analizom algoritma, c iji je cilj odredivanje
njegovog
Neformalno ime
konstantna funkcija
log n
logaritamska funkcija
linearna funkcija
n log n
linearno-logaritamska funkcija
n3
2
kvadratna funkcija
kubna funkcija
eksponencijalna funkcija
53
2n
n3 n2
n log n n
log n
54
3.2
Asimptotska notacija
prema njihovim funkcijama asimptotskog vremena izvravanja: to je takva funkcija manja, to je algoritam bolji (bri). Obicno je jasno da li
je neka funkcija manja od druge, ali za sloenije slucajeve je potrebno
imati precizniju deniciju toga to se podrazumeva kada se tvrdi da je neka
funkcija manja od druge. Asimptotska notacija omogucava upravo da se
na precizan nacin uvede relativni poredak za funkcije.
Asimptotska notacija ima c etiri oblika: O-zapis (veliko o), -zapis (veliko omega), -zapis (veliko teta) i o-zapis (malo o). S obzirom na to da
se u praksi najcece koristi O-zapis, u ovom odeljku c emo najvecu panju
posvetiti tom zapisu. Ali iako u ostalom delu knjige skoro iskljucivo koristimo O-zapis, u nastavku c emo se kratko osvrnuti i na ostale varijante
asimptotske notacije radi kompletnosti.
Jedna napomena: nekim c itaocima c e ovo poglavlje izgledati kao suva
matematika naalost ili na srecu, to je najbolji nacin da se precizno
izrazi ono o c emu se govori.
O-zapis
O-zapis se koristi za precizno denisanje svojstva da je neka funkcija
manja od druge. Na pocetku napomenimo da za sve funkcije o kojima govorimo, podrazumevamo da su to pozitivne (ili tacnije, nenegativne) funkcije, a nenegativnost se podrazumeva i za njihove argumente. Preciznije
55
g(n)
f (n)
n0
56
2. Dominantni termi su najvaniji: ako je T(n) = O f (n) + g(n) i g(n) =
O( f (n)), onda je T(n) = O( f (n)). Na primer, opet u slucaju algoritma
bubble-sort, odmah moemo zakljuciti da je T(n) = O(n2 ), jer je ocigledno n2 n = O(n2 ) i 1 = O(n2 ).
3. Pravilo zbira: O f (n) + g(n) = O( f (n)) + O(g(n)). Na primer, ako je
T(n) = O(n) + O(17), onda je T(n) = O(n + 17), odnosno T(n) = O(n) prema
prethodnom pravili jer je 17 = O(n).
4. Pravilo proizvoda: O f (n) g(n) = O( f (n)) O(g(n)). Na primer, ako je
T(n) = n O(1), onda je T(n) = n O(1) = O(n) O(1) = O(n).
2 Pravilo da konstante nisu vane ne treba pogreno razumeti. Prakticni programeri
ponekad danima pokuavaju da jedan algoritam ubrzaju za neki vrlo mali faktor. Ovde
je rec samo o tome da elimo dobru optu sliku o algoritmima, koja bez jednostavnosti
asimptotske notacije ne bi bila moguca.
57
vani, moemo bez kraja navoditi blie granice, recimo T(n) = O(0.01n2 ) ili
T(n) = O(0.0001n2 ) i tako dalje.
Da bismo razreili ovaj naizgled kontradiktoran problem, uvek kada je
to moguce koristimo O-zapis koji je najprostiji. To znaci da je on izraen
jednim termom i da je konstantni faktor uz taj term jednak broju 1. Treba
ipak imati na umu da su jednostavnost i najbolja ocena u nekim slucajevima suprostavljeni ciljevi, ali ti slucajevi su srecom retki u praksi.
Na kraju, primetimo da u radu zloupotrebljavamo simbol =, jer znak
jednakosti nije zapravo simetrican (reeksivan) kada se koristi O-zapis.
To znaci da ako je f 1 (n) = O(g(n)) i f 2 (n) = O(g(n)), onda to ne implicira
da je f 1 (n) = f 2 (n). Striktno govoreci, za nenegativnu funkciju g : N R+ ,
O(g(n)) treba denisati kao klasu nenegativnih funkcija:
O(g(n)) = f : N R+ | ( c > 0)( n 0 N)( n n 0 ) f (n) c g(n) .
58
Medutim,
radi jednostavnosti se nautrb preciznosti tradicionalno vie ko
risti prostija denicija koju smo naveli. Nadamo se da to nece zbuniti
c itaoce koji su vie naklonjeni matematickoj korektnosti.
f (n)
= 0.
g(n)
59
Intuitivno znacenje
f (n) = O(g(n))
f g
f (n) = (g(n))
f g
f (n) = (g(n))
f g
f (n) = o(g(n))
f
g
1
1
+
c.
n n2
LIMESA )
f (n)
= c > 0 f (n) = (g(n))
n g(n)
f (n)
lim
= c 0 f (n) = O(g(n))
n g(n)
lim
60
f (n) =
n3 , ako je n parno
n,
ako je n neparno
g(n) =
n,
ako je n parno
n , ako je n neparno
61
62
T(n) = (y) = 2n2 = 2n/2 .
r, odnosno najveci ceo broj manji ili jednak r. Prema tome,
7.51 = 7 i
7 = 7. Slicno, r
(engl. ceiling) oznacava najmanji ceo broj veci ili jednak r. Prema tome, 7.51 = 8 i 7 = 7.
63
zajednicki delioci jednaki. U tom cilju, svaki ceo broj koji deli oba broja x
i y bez ostatka, mora deliti bez ostatka i brojeve y i x%y = x k y, (k N).
Obrnuto, svaki ceo broj koji deli bez ostatka i y i x%y = x k y, (k N), mora
deliti bez ostatka kako x = x%y + k y, (k N), tako i y.
Uz primedbu da svaki pozitivan ceo broj x deli broj 0 bez ostatka i da
zato nzd(x, 0) = x, najveci zajednicki delilac dva broja moemo lako izrac unati uzastopnim ponavljanjem jednakosti iz Euklidove teoreme. Neki
primeri tog izracunavanja za razne parove brojeva su:
nzd(1055, 15) = nzd(15, 5) = nzd(5, 0) = 5
nzd(400, 24) = nzd(24, 16) = nzd(16, 8) = nzd(8, 0) = 8
nzd(101, 100) = nzd(100, 1) = nzd(1, 0) = 1
nzd(34, 17) = nzd(17, 0) = 17
nzd(89, 55) = nzd(55, 34) = nzd(34, 21) = nzd(21, 13) =
= nzd(13, 8) = nzd(8, 5) = nzd(5, 3) =
= nzd(3, 2) = nzd(2, 1) = nzd(1, 0) = 1
64
x = y;
y = z;
return x;
Kako bismo sada ocenili broj iteracija while petlje m, najpre c emo
oceniti proizvod parova brojeva x i yi primenjujuci prethodnu lemu vie
puta:
65
66
Zadaci
1. Odredite (asimptotsko) vreme izvravanja sledecih algoritamskih fragmenata:
a)
if (x == 0) then
for i = 1 to n do
a[i] = i;
b)
i = 1;
repeat
a[i] = b[i] + c[i];
i = i + 1;
until (i == n);
c)
if (x == 0) then
for i = 1 to n do
for j = 1 to n do
a[i,j] = 0;
else
for i = 1 to n do
a[i,i] = 1;
d)
for i = 1 to n do
for j = 1 to n do
for k = 1 to j do
if (i == j) then
a[k,k] = 0;
e)
i = 0; k
while (k
k = 2
i = i
= 1;
<= n) do
* k;
+ 1;
f)
for i = 1 to n/2 do
for j = i downto 1 do
if (j % 2 == 0) then
a[i,j] = b[i] + c[j];
2. Napiite ekasan algoritam za nalaenje najveceg i drugog najveceg elementa niza a od n brojeva. Odredite vreme izvravanja tog algoritma.
3. Ternarna pretraga. Binarnu pretragu na nalaenje broja x u sortiranom nizu a od n brojeva moemo modikovati na sledeci nacin. Ako
je oblast pretrage u sortiranom nizu a indeksirana od i do j, najpre
izracunavamo tacku k koja se nalazi na otprilike 1/3 te oblasti, tj. k =
(2 i + j)/3, a zatim uporedujemo
traenu vrednost x sa elementom
67
crveno
belo
S LIKA 3.6.
Navedite bar dva algoritma za reenje ovog problema i odredite vreme
izvravanja svakog od njih.
5. Srpska zastava. Posmatrajmo niz a velicine n koji sadri crvene, plave i
bele elemente u proizvoljnom redosledu. Pretpostavljajuci da je proveravanje boje nekog elementa jedinicna instrukcija, cilj je da se niz preuredi
tako da se svi crveni elementi nalaze na pocetku, svi plavi elementi da
se nalaze u sredini, a svi beli elementi da se nalaze na kraju niza a. Na
slici 3.7 je ilustrovan zavrni rezultat.
a
crveno
plavo
belo
S LIKA 3.7.
Navedite bar dva algoritma za reenje ovog problema i odredite vreme
izvravanja svakog od njih.
6. Dokaite pravilo limesa na strani 59.
68
g(n) = n + 200
g(n) = n2/3
g(n) = n + log2 n
d) f (n) = n log n,
g(n) = log 3n
f) f (n) = n / log n,
g) f (n) = (log n)log n ,
g(n) = n log2 n
g(n) = n
2
log n
h) f (n) = (log n)
, g(n) = 2log
i) f (n) = n, g(n) = log3 n
j) f (n) = nlog n ,
k) f (n) = n2n ,
l) f (n) = 2n ,
m) f (n) = n!,
g(n) = 2n
g(n) = 3n
g(n) = 2n/2
g(n) = 2n
argumenta n:
n, log n, loglog n, log2 n,
log n
n
, (1/3)n , (3/2)n , 17
, n! , n log2 n, 2
log n
69
b) Cini
se da smo u koraku 2 zaboravili slucaj kada su oba broja x i y
parna. Pokaite da se to nikad ne moe desiti.
c) Pokaite da se ovaj modikovan Euklidov algoritam uvek zavrava
tacnim odgovorom.
d) Pokaite da se proizvod dva aktuelna broja u promenljivim x i
y smanjuje za faktor dva u bar jednoj od svake dve sukcesivne
iteracije prethodnog postupka. Drugim recima, ako je (x0 , y0 ) par
brojeva u koraku 1 neke iteracije tog postupka i (x2 , y2 ) par brojeva
70
zbir dva proizvoda: jedan sabirak je proizvod broja x i nekog celog broja,
a drugi sabirak je proizvod broja y i nekog drugog celog broja. Koristeci
ovo zapaanje dokaite sledecu c injenicu:
T EOREMA nzd(x, y) se moe predstaviti kao linearna kombinacija brojeva x i y u obliku nzd(x, y) = ax + b y, gde su a i b celi brojevi (koji ne
moraju biti pozitivni).
Napiite proireni Euklidov algoritam koji izracunava ne samo nzd(x, y),
nego i cele brojeve a i b iz prethodne teoreme za koje vai nzd(x, y) =
ax + b y.
G LAVA
4
Osnovne strukture podataka
4.1
Opte napomene
72
programskog jezika kao gradivnih elemenata i koricenje raspoloivih mehanizama strukturiranja za njihovo grupisanje. Na taj nacin se dobija odgovarajuca struktura podataka, odnosno kolekcija elemenata povezanih na
odreden
nacin i skup operacija dozvoljenih nad tom kolekcijom elemenata.
Pod elementom se ovde podrazumeva podatak kome tip nije preciziran zato
to nije bitan.
Operacije koje su denisane nad strukturama podataka se veoma razlikuju od strukture do strukture, ali sve strukture imaju bar dve zajednicke operacije: jednu za dodavanje novih elemenata kolekciji postojecih
elemenata koji sacinjavaju odgovarajucu strukturu podataka, kao i onu za
uklanjanje starih elemenata iz kolekcije elemenata. Ovde bi mogli dodati i
operaciju za konstruisanje potpuno nove, prazne strukture podataka. Medutim,
ona umnogome zavisi od konkretnog programskog jezika, a poto su
broja elemenata strukture podataka (tj. njene velicine) i tako dalje. Uopteno govoreci, operacije nad strukturama podataka se mogu podeliti u dve
kategorije: (a) upite, koji kao rezultat daju neku informaciju o strukturi
podataka ne menjajuci je, i (b) modikujuce operacije, koje menjaju sadraj
strukture podataka.
Vreme za izvravanje neke operacije nad strukturom podataka izraava se u funkciji od velicine strukture podataka. To ima smisla, jer je prirodno pretpostaviti da vreme za neku operaciju zavisi od broja elemenata
u strukturi podataka nad kojima se primenjuje. Na primer, ako niz ima
n elemenata, vreme za operaciju kojom se odreduje
da li se dati element
4.2. Nizovi
73
U prezentaciji neke strukture podataka uglavnom primenjujemo proceduralni pristup, mada koristimo i neke rudimentarne koncepte objektno
orijentisanog programiranja. Naime, poto se elementi struktura podataka
obicno sastoje od vie delova, pogodno ih je smatrati objektima koji sadre
unutranja polja za razlicite podatke. (Medutim,
mogucnost da objekti
4.2 Nizovi
Niz (engl. array) je osnovni nacin strukturiranja podataka u programiranju i zato se koristi u skoro svim programskim jezicima. Pretpostavljamo
da su se c itaoci vec sretali u programiranju sa nizovima i zbog toga o njima
ovde necemo govoriti na elementarnom nivou. U stvari, nizove smo vec
intezivno koristili u prethodnom poglavlju i nadamo se da c itaoci bez predznanja o nizovima nisu imali problema da razumeju njihovu jednostavnu
prirodu. Ipak, s obzirom na to da su primene nizova brojne i raznovrsne,
ovde c emo radi kompletnosti istaci njihove konceptualne osobine. Pored
toga, u ovom odeljku c emo pokazati jo dva interesantna primera njihove
primene, a u drugim odeljcima njihovu primenu u realizaciji sloenijih
struktura podataka.
Niz je struktura podataka koja predstavlja sekvencu elemenata istog
tipa. Sekvencijalna uredenost
niza ogleda se u numeraciji njegovih eleme
nata, redom, od prvog do poslednjeg. Redni broj nekog elementa u nizu
se naziva indeks elementa. Ime niza grupno oznacava sve elemente niza
kao jednu celinu. Za oznacavanje pojedinacnih elemenata niza koristi se
zapis koji se sastoji od imena niza i indeksa odgovarajuceg elementa niza.
(Podsetimo se da u ovoj knjizi indeksi niza pocinju od 1 i da koristimo zapis
indeksa u uglastim zagradama.) Ukupan broj elemenata niza se naziva
2 Citaoci
koji poznaju Javu mogu ovde prepoznati elemente tog programskog jezika.
74
duina ili velicina niza. Na primer, niz a duine 100 se sastoji od 100
elemenata istog tipa c iji je izgled prikazan na slici 4.1.
a
a[1]
a[2]
a[3]
a[100]
Ove dve vrednosti su unapred poznate, jer se duina niza mora unapred
naznaciti, a velicina jednog elementa je poznata na osnovu tipa elemenata
niza. Ali ono to je jo vanije, lokacija svakog elementa niza se lako
izracunava, nezavisno od indeksa elementa: ako je prvi element na lokaciji
a i velicina jednog elementa je b bajtova, onda se i-ti element niza nalazi
na lokaciji a + (i 1)b. Ovo znaci da je vreme pristupa svim elementima
niza konstantno, odnosno da se u algoritmima operacija c itanja ili pisanja
nekog elementa niza moe smatrati jedinicnom instrukcijom.
Prema tome, niz je koncepcijski jednostavna i ekasna struktura podataka koju treba koristiti kad god je to moguce. Treba ipak imati u vidu
da je struktura niza neprakticna u slucajevima kada se radi o elementima
razlicitih tipova ili njihov priblian ukupan broj nije unapred poznat. Ovaj
drugi nedostatak se moe prevazici zadavanjem neke maksimalne duine
niza, ali to obicno dovodi do loe iskoricenosti memorijskog prostora rezervisanog za niz. Pored toga, operacije dodavanja ili uklanjanja elemenata
na proizvoljnoj poziciji niza nisu ekasne, jer dovode do pomeranja svih
elemenata od date lokacije do kraja niza za jedno mesto udesno ili ulevo.
4.2. Nizovi
75
Podsetimo se da se kvadratni algoritam za reenje ovog problema sastoji od dva koraka. U prvom koraku se odreduje
drugi niz b od n eleme
nata b 1 , b 2 , . . ., b n , pri c emu je element b i jednak parcijalnom maksimumu
suma elementa od i-te pozicije niza:
b i = max S i,i , S i,i+1 , . . ., S i,n = max S i, j .
j = i,...,n
M = max { b 1 , b 2 , . . ., b n } = max b i .
i=1,...,n
poboljanje, medutim,
zahteva bolji uvid u izracunavanje maksimuma M
76
k1 k
S i,k1 0
S k,r
Onda je
b k = S k,r
S i,k1 + S k,r , jer S i,k1 0 po pretpostavci
= S i,r
bi,
to je trebalo pokazati.
jer b i = max S i, j ,
j = i,...,n
4.2. Nizovi
77
j j+1
S i, j < 0
S j +1,r
78
b j +1 ,
to je trebalo pokazati.
Ova lema implicira da, tokom izracunavanja bilo kog elementa b i , prvi
put kada otkrijemo S i, j < 0 moemo bezbedno prekinuti to izracunavanje
i nastaviti sa izracunavanjem elemenata b j +1 , . . . , b n . Naime, ukoliko je
element b i jednak jednoj od suma S i,i , S i,i+1 , . . ., S i, j 1 , onda svakako ne
moramo ispitivati dalje sume S i, j +1 , S i, j +2 , . . ., S i,n . U suprotnom slucaju,
ukoliko je element b i jednak nekoj daljoj sumi od pozicije j, onda je prema
prethodnoj lemi b i b j +1. To znaci da je element b i nevaan za izracunavanje maksimuma niza b, pa zato izracunavanje elementa b i moemo
potpuno zanemariti i nastaviti sa izracunavanjem elemenata b j +1, . . ., b n .
Postupak koji se zasniva na prethodnim zapaanjima na pseudo jeziku
je:
// Ulaz: niz a, broj elemenata n niza a
// Izlaz: maksimalna suma podniza M
algorithm mcss(a, n)
M = 0;
// maksimalna suma podniza
i = 1;
while i < n do
// izra
cunati b i
s = 0;
for j = i to n do
// izra
cunati S i, j
s = s + a[j];
// S i, j = S i, j 1 + a j
if (s < 0) then
// da li je S i, j < 0?
return M;
4.2. Nizovi
79
Matrice
Do sada smo govorili, u stvari, o najcece koricenom obliku niza koji se
optije naziva jednodimenzionalni niz (ili ponekad i vektor). Generalizacija
tog oblika se moe dobiti ukoliko se uzme da su sami elementi jednodimenzionalnog niza opet jednodimenzionalni nizovi. (Podsetimo se da za
tip elemenata nizova ne postoji nikakvo ogranicenje u vezi sa njihovom
sloenocu.) Tako se dobija dvodimenzionalni niz ili matrica elemenata.
Matrica elemenata predstavlja koncepcijski tabelu tih elemenata koja
ima odreden
broj vrsta i kolona. Elementi matrice imaju zato dvostruke indekse: prvi indeks ukazuje na vrstu i drugi na kolonu u kojima se element
nalazi u matrici. Pored toga, za matricu elemenata se unapred moraju
zadati brojevi njenih vrsta i njenih kolona koji se nazivaju velicina matrice. Velicina matrice ne moe se menjati, to proizilazi iz nepromenljivosti velicine jednodimenzionalnog niza. Na primer, na slici 4.2 je prikazana
matrica elemenata velicine 34 koja ima tri vrste i c etiri kolone.
a
a[1,1]
a[1,2]
a[1,3]
a[1,4]
a[2,1]
a[2,2]
a[2,3]
a[2,4]
a[3,1]
a[3,2]
a[3,3]
a[3,4]
80
4.2. Nizovi
81
Y : y, x, z, u
Z : x, u, z, y
U : u, z, x, y
x : X , Y , Z,U
y : U, Z, Y , X
z : Y , Z, X ,U
u : Z,U, X , Y
1
z
y
x
u
2
y
x
u
z
3
x
z
z
x
4
u
u
y
y
devojke
x
y
z
u
1
X
U
Y
Z
2
Y
Z
Z
U
3
Z
Y
X
X
4
U
X
U
Y
osoba q od osobe r suprotnog pola ukoliko se q nalazi pre r na listi naklonosti osobe p. Tako u prethodnom primeru, devojci z se vie svida
Y od U
i mladicu Y se vie svida
x
od
z.
82
nestabilno zbog X
i z. Sada se mladicu X vie svida
z od x, a devojci z se vie svida
X od
U. Ovaj postupak sukcesivnih razvoda i vezivanja nezadovoljnih parova
moemo nastaviti, ali nije teko smisliti primer u kojem se ovim pristupom
vrtimo u krug i nikad ne dobijamo stabilno vezivanje.
Posle ovoga se odmah postavlja pitanje postojanja stabilnog vezivanja
u svakoj instanci problema stabilnih brakova. To jest, ako su date proizvoljne liste naklonosti svih mladica i devojaka, da li uvek postoji bar
jedno stabilno vezivanje? Odgovor na ovo pitanje je potvrdan i, donekle
iznenaduju
ce, dokaz toga je sasvim konstruktivan. U stvari, dokaz se
4.2. Nizovi
83
84
petlje imamo slobodnog mladica koji moe ostati slobodan ukoliko ga odbije
4.2. Nizovi
85
radi na svoju vecu alost: prvi put prosi svoju najvecu ljubav, zatim prosi
devojku koja je njegov drugi izbor, pa treci izbor i tako dalje. Devojke sa
druge strane svaki put kada promene verenike, rade to na svoju vecu srecu.
Slobodna devojka od trenutka kada prihvati ponudu nekog mladica koji
ju je zaprosio, nikad vie ne postaje slobodna ona moe samo promeniti
svog verenika ako dobije bolju ponudu iz njenog ugla gledanja, odnosno ako
je zaprosi mladic koji joj se vie svida
od aktuelnog verenika.
L EMA 2 Svaki slobodan mladic na pocetku while petlje u algoritmu smp
ima devojku koju jo nije zaprosio.
Dokaz: Primetimo najpre da je na pocetku izvravanja svake iteracije
while petlje u algoritmu smp broj slobodnih mladica jednak broju slobodnih
devojaka. To je, u stvari, invarijanta te petlje, odnosno uslov koji ostaje
86
4.2. Nizovi
87
takode
koji bolje poznaju strukture
dodaje na kraj tog niza. (Citaoci
podataka mogu prepoznati da ovim simuliramo stek, mada se moe
koristiti i red za c ekanje.)
Za predstavljanje listi naklonosti svih mladica moemo koristiti n n
matricu m tako da i-ti red te tabele predstavlja listu naklonosti mladica i, sortiranu od najvie do najmanje eljene devojke za mladica i.
Tako m i, j = k znaci da je devojka k na j-tom mestu u listi naklonosti
mladica i.
Za predstavljanje ranga devojke koju je neki mladic poslednje zaprosio moemo koristiti niz r od n elemenata tako da r i = j oznacava da
se poslednja devojka koju je mladic i zaprosio nalazi na j-tom mestu
u njegovoj listi naklonosti, odnosno to je devojka m i, j . Na ovaj nacin
moemo lako odrediti prvu devojku koju neki mladic treba da zaprosi.
Za predstavljanje listi naklonosti svih devojaka moemo koristiti nn
matricu rangiranja d tako da d i, j oznacava rang mladica j za devojku i u njenoj listi naklonosti. Tako d i, j = k oznacava da se mladic
j nalazi na k-tom mestu u listi naklonosti devojke i. Razlog ove
asimetricnosti u odnosu na liste naklonosti mladica je u tome to na
ovaj nacin moemo lako proveriti da li se devojci i vie svida
mladic
j 1 od mladica j 2 .
88
4.3 Liste
Lista (tacnije povezana lista) je struktura podataka koja je slicna nizu
jer predstavlja sekvencu elemenata istog tipa. Medutim,
za razliku od
x2
xn
4.3. Liste
89
pokazivaca
klju
c sled
klju
c sled
klju
c sled
90
b
x
4.3. Liste
91
vor x, c
vor p u listi l
// Ulaz: novi c
// Izlaz: lista l sa
cvorom x iza
cvora p
algorithm list-insert(x, p, l)
if (p == null) then
x.sled = l;
l = x;
else
x.sled = p.sled;
p.sled = x;
// novi
cvor dodati na po
cetak
// novi
cvor dodati iza p
return l;
Uklanjanje cvora
iz liste. Slicno kao kod dodavanja c vora u listu, za
uklanjanje c vora iz liste mora se znati c vor liste iza koga se uklanja postojeci c vor kako bi se lokalne veze mogle preurediti i zadrati sekvencijalna
uredenost
liste.
Ako je dat (pokazivac na) c vor p liste c ijeg sledbenika treba ukloniti,
veza izmedu
tog c vora i njegovog sledbenika x u listi se raskida, a uspostavlja se nova veza izmedu
c vora p i sledbenika starog sledbenika x. Na
slici 4.6 su prikazane neophodne manipulacije pokazivacima radi uklanjanja c vora x iz liste koji se nalazi iza c vora p.
x
p
a
92
null.
// Ulaz: lista l , klju
c k
// Izlaz:
cvor x u listi sa klju
cem k ili vrednost null
algorithm list-search(l, k)
x = l;
while ((x != null) && (x.klju
c != k)) do
x = x.sled;
return x;
uklonimo c vor iza nekog c vora u listi sa datim kljucem. U takvom slucaju
4.3. Liste
93
zato ne moemo neposredno iskoristiti date algoritme za dodavanje ili uklanjanje c vora, nego najpre moramo koristiti algoritam list-search radi
nalaenja c vora sa datim kljucem i zatim prethodnim algoritmima dodati
ili ukloniti c vor iza pronadenog
c vora. Prema tome, vreme izvravanja ovih
c sled
pret klju
94
// x nije prvi
cvor
// x nije poslednji
cvor
return l;
nizova
Implementacija liste pomocu
Implementacija liste pomocu pokazivaca je vrlo prirodna i jednostavna.
Neki programski jezici medutim
ne omogucavaju direktan rad sa pokaziva
c ima, pa c emo u ovom odeljku kratko opisati kako se liste mogu predstaviti
pomocu nizova i kako se pokazivaci mogu simulirati pomocu indeksa elemenata nizova.4
Cvorovi
liste (ili optije bilo koji objekti) sa istim poljima mogu se najjednostavnije predstaviti pomocu posebnog niza za svako polje. Specicno,
jednostruko povezana lista se predstavlja pomocu dva niza, a dvostruko
povezana lista pomocu tri niza. Kod dvostruko povezane liste na primer,
jedan niz, recimo k, sadri vrednosti polja kljuca c vorova liste, a preostala
dva niza, recimo s i p, simuliraju polja pokazivaca na sledbenika i prethodnika. Na slici 4.9 je prikazano moguce stanje ovih nizova za dvostruku
4 Rec simulirati treba shvatiti uslovno, poto se u racunarima pokazivaci zaista reali-
zuju pomocu indeksa (memorijskih adresa) elemenata jednog velikog niza (glavne memorije).
4.3. Liste
95
2
2
0
a
5
c
96
polja klju
c, sled i prev u nekom c voru na slici 4.10 su 0, 1 i 2. Stoga,
za dobijanje vrednosti polja x.prev ukoliko je data vrednost pokazivaca x,
treba najpre dodati relativnu poziciju 2 polja prev na vrednost pokazivaca
x, a zatim treba procitati sadraj elementa niza m[x+2].
1
10
a 13 0 d 0 19
11
12
13
14
15
b 19 4
16
17
18
19
20
21
7 13
4.4
Stekovi
Stek (engl. stack) je specijalna vrsta liste kod koje se dodavanja i uklanjanja elemenata obavljaju samo na jednom kraju koji se naziva vrh steka.
Intuitivni model strukture podataka steka su naslagani posluavnici u restoranu ili komadici mesa poredani
na ranjicu. U oba primera je pogodno
ukloniti samo onaj element (posluavnik ili komadic mesa) koji se nalazi na
vrhu steka, kao i dodati novi element samo na vrh steka. Drugim recima,
poredak elemenata po kojem se oni uklanjaju sa steka je obrnut onom po
kojem su oni dodati na stek. Operacija dodavanja elemenata na stek se
tradicionalno zove push, a operacija uklanjanja elemenata iz steka zove se
pop.
Sve implementacije liste o kojima smo govorili u prethodnom odeljku
mogu se iskoristiti i za stek, poto je stek sa svojim operacijama specijalni slucaj liste sa svojim operacijama. U programskom okruenju koje
obezbeduje
rad sa pokazivacima, implementacija liste prakticno ne mora
4.4. Stekovi
97
23
17
20
10
8
20
17
23
// Ulaz: stek s
// Izlaz: ta
cno ako je s prazan, ina
ce neta
cno
algorithm stack-empty(s)
98
if (s.v == 0)
return true;
else
return false;
// Ulaz: stek s
// Izlaz: ta
cno ako je s pun, ina
ce neta
cno
algorithm stack-full(s)
if (s.v == n)
return true;
else
return false;
// Ulaz: stek s
// Izlaz: element x uklonjen sa vrha steka s
algorithm pop(s)
// Pretpostavlja se da stek nije prazan
x = s.a[s.v];
s.v = s.v - 1;
return x;
Citaoci
se lako mogu uveriti da se svi navedeni algoritmi izvravaju za
konstantno vreme.
4.5
Redovi za cekanje
Red za c ekanje (engl. queue) je druga specijalna vrsta povezane liste kod
koje se elementi dodaju na jednom kraju liste i uklanjaju sa drugog kraja
liste. Mesto na kojem se elementi dodaju logicki predstavlja kraj reda, a
mesto gde se elementi dodaju oznacava pocetak reda. Prema tome, kada
4.5. Redovi za cekanje
99
1
2
a
100
komplikovana. Citaoci
se lako mogu uveriti da se svi navedeni algoritmi
izvravaju za konstantno vreme.
// Ulaz: red q
// Izlaz: po
cetno stanje reda q
algorithm queue-make(q)
q.g = 1;
q.r = n;
q.l = 0;
return;
// Ulaz: red q
// Izlaz: ta
cno ako je q prazan, ina
ce neta
cno
algorithm queue-empty(q)
if (q.l == 0)
return true;
else
4.5. Redovi za cekanje
101
return false;
// Ulaz: red q
// Izlaz: ta
cno ako je q pun, ina
ce neta
cno
algorithm queue-full(q)
if (q.l == n)
return true;
else
return false;
// Ulaz: novi element x, red q
// Izlaz: red q sa elementom x na kraju
algorithm enqueue(x, q)
// Pretpostavlja se da red nije pun
q.r = q.r % n + 1;
q.a[q.r] = x;
q.l = q.l + 1;
return;
// Ulaz: red q
// Izlaz: element x uklonjen iz reda q na po
cetku
algorithm dequeue(q)
// Pretpostavlja se da red nije prazan
x = q.a[q.g];
q.g = q.g % n + 1;
q.l = q.l - 1;
return x;
Zadaci
1. Virtuelna inicijalizacija niza. Ako je dat niz a 1 , . . ., a n duine n, naivni
nacin za inicijalizaciju svih elemenata niza nekom vrednocu x je:
algorithm array-init(a, n, x)
for i = 1 to n do
a[i] = x;
return a;
102
Ovaj algoritam ocigledno zahteva vreme O(n) za izvravanje i konstantni memorijski prostor (pored prostora potrebnog za sam niz). Pri tome,
obe operacije za pristup nekom elementu niza a koje su realizovane
algoritmima array-read(a,i), kojim se c ita vrednost i-tog elementa
niza a, i array-write(a,i,x), kojim se upisuje vrednost x u i-ti element niza a, izvravaju se za konstantno vreme:
algorithm array-read(a, i)
algorithm array-write(a, i, x)
return a[i];
a[i] = x;
return a;
U nekim primenama je linearno vreme za inicijalizaciju niza neprihvatljivo dugo, pa je potrebno virtuelno inicijalizovati niz za konstantno
vreme. To je posebno znacajno u slucajevima kada se tokom rada programa koristi zapravo samo mali deo nekog velikog niza. Napiite algoritme array-init(a,n,x), array-read(a,i) i array-write(a,i,x)
koji rade tacno ono to treba, ali svaki od njih se izvrava za konstantno
vreme. (Savet: Koristite dva dodatna niza velicine n, pri c emu jedan od
njih simulira stek.)
4.5. Redovi za cekanje
mladici
X
Y
Z
U
V
1
x
y
z
u
v
2
y
z
u
v
x
3
z
u
v
x
y
103
4
u
v
x
y
z
5
v
x
y
z
u
devojke
x
y
z
u
v
1
Y
Z
U
V
X
2
Z
U
V
X
Y
3
U
V
X
Y
Z
4
V
X
Y
Z
U
5
X
Y
Z
U
V
104
teniraju) dve liste l 1 i l 2 u trecu listu l 3 . Pretpostavite da su liste implementirane pomocu pokazivaca i analizirajte vreme izvravanja svog
algoritma.
12. Jedan niz se moe iskoristiti za predstavljanje dva steka, jedan koji
raste udesno od pocetka niza i drugi koji raste ulevo od kraja niza.
Implementirajte operacije nad stekom koristeci ovu reprezentaciju dva
steka pomocu jednog niza. Analizirajte vreme izvravanja tih operacija.
15. Skup kao struktura podataka je konacna kolekcija elemenata (ili c lanova) istog tipa. Dve konceptualne osobine skupa su da su svi njegovi
elementi medusobno
razliciti i da ne postoji nikakva relacija uredenosti
medu
elementima skupa. Jedan lak nacin za predstavljanje skupa je
pomocu povezane liste njegovih elemenata. Na primer, na slici 4.13 je
prikazan skup S = { x1 , x2 , . . ., xn } predstavljen povezanom listom s.
4.5. Redovi za cekanje
x1
105
x2
xn
Tipicne skupovne operacije su dodavanje datog elementa skupu, uklanjanje datog elementa iz skupa i provera da li dati element pripada
skupu.
a) Pretpostavljajuci implementaciju skupa pomocu liste njegovih elemenata, napiite algoritme set-insert(x,s), set-delete(x,s)
i set-member(x,s) kojima se realizuju prethodne skupovne operacije. Za sve algoritme odredite vreme njihovog izvravanja.
b) Ako se elementi skupa mogu medusobno
uporedivati,
druga mo
gucnost za predstavljanje skupa pomocu liste je da se skupovni elementi u listi smetaju u rastucem redosledu. Ponovite prethodni
zadatak pretpostavljajuci ovakvu implementaciju skupa pomocu
sortirane liste njegovih elemenata.
16. Napiite algoritme za operacije unije i preseka dva skupa pretpostavljajuci implementaciju skupova pomocu a) nesortiranih listi i b) sortiranih
listi.
G LAVA
5
Rekurzivni algoritmi
108
Rekurzivni algoritmi
5.1
ili ne. U sutini dakle, rekurzivni i iterativni algoritmi predstavljaju razlic ite zapise za opis viestrukog ponavljanja jednog istog postupka.
Svaki problem koji se moe reiti rekurzivno moe se reiti i iterativno,
kao i obrnuto. Obratite ipak panju na to da postupak koji se ponavlja u
rekurzivnom i iterativnom algoritmu za isti problem ne mora biti identic an.
Razmotrimo, na primer, izracunavanje stepena x n , gde je x neki realan
broj razlicit od nule i n ceo broj veci ili jednak nuli. Iterativni nacin za reenje ovog problema sastoji se od uzastopnog mnoenja broja x sa parcijalno
izracunatim stepenima x i za i = 0, 1, . . ., n 1. Naredni iterativni algoritam
power1 koristi for petlju radi realizacije ovog postupka:
// Ulaz: realan broj x, ceo broj n 0
// Izlaz: broj x n
algorithm power1(x, n)
y = 1;
for i = 1 to n do
y = x * y;
return y;
Pored ovog klasicnog iterativnog nacina, za izracunavanje stepena moemo primeniti drugaciji, rekurzivni pristup ukoliko uocimo da je x0 = 1 za
stepen n = 0 i x n = x x n1 za stepen n veci od nule. Drugim recima, ako je
stepen n = 0, rezultat je uvek 1, dok za stepen n > 0 rezultat dobijamo ako
x pomnoimo sa (n 1)-im stepenom broja x. Naredni rekurzivni algoritam
power2 koristi ovaj nacin za izracunavanje n-tog stepena broja x:
// Ulaz: realan broj x, ceo broj n 0
// Izlaz: broj x n
algorithm power2(x, n)
109
if (n == 0)
return 1;
else
return x * power2(x,n-1);
Obratite panju na to da, za izracunavanje n-tog stepena broja x, rekurzivni algoritam power2 u drugoj naredbi return poziva sam sebe radi
izracunavanja (n 1)-og stepena broja x.
Rekurzivni algoritam je algoritam koji poziva sam sebe, bilo direktno
ili indirektno. Algoritam direktno poziva sam sebe (kao recimo power2)
ukoliko se u njegovoj deniciji nalazi poziv samog algoritma koji se denie. Algoritam indirektno poziva sebe ukoliko se u njegovoj deniciji
nalazi poziv drugog algoritma koji sa svoje strane poziva polazni algoritam
koji se denie (bilo direktno ili indirektno).
Mehanizam pozivanja rekurzivnih algoritama se ne razlikuje od standardnog mehanizma za obicne algoritme: argumenti u pozivu algoritma
se najpre dodeljuju parametrima algoritma kao pocetne vrednosti i zatim
se izvrava telo pozvanog algoritma. Medutim,
ovde je vano primetiti
power2(1.5,2)
power2(1.5,1)
return 1.5*power2(1.5,2)
return 1.5*power2(1.5,1)
return 1.5*power2(1.5,0)
3.75
2.25
1.5
power2(1.5,0)
return 1
1
110
Rekurzivni algoritmi
se u telu algoritma power2 izvrava deo else naredbe if, odnosno naredba
return u kojoj se argument za broj x mnoi sa odgovarajucim rezultatom
poziva algoritma. Tek u poslednjem pozivu je argument za stepen jednak nuli, pa se izvravanjem dela then naredbe if kao rezultat dobija
broj 1. Nakon toga se lanac rekurzivnih poziva odmotava u obrnutom
smeru, kako to pokazuju donje strelice na slici 5.1. Pri tome se izvravanje
aktuelnog poziva sastoji od mnoenja rezultata odgovarajuceg zavrenog
poziva sa vrednocu parametra x i dobijena vrednost se kao rezultat vraca
prethodnom pozivu.
Generalno, rekurzivni algoritmi reavaju neki zadatak svodenjem
tog
111
U ovom algoritmu u drugoj naredbi return primetimo da su u rekurzivnom pozivu nzd(y, x % y) oba argumenta manja od polaznih brojeva x
i y. To znaci da se tim pozivom zaista reava prostiji zadatak izracunavanja najveceg zajednickog delioca za par manjih brojeva. Ostatak pri
celobrojnom deljenju u lancu rekurzivnih poziva se dakle stalno smanjuje
i zato u jednom trenutku mora biti nula. Tada c e se lanac prekinuti,
jer se onda rezultat neposredno dobija kao vrednost drugog argumenta
poslednjeg poziva u lancu.
Primer: Fibonacijev
niz brojeva
Fibonacijev niz brojeva ima brojne primene u umetnosti, matematici i
racunarstvu. Prva dva broja Fibonacijevog niza brojeva su 1 i 1, a svaki
sledeci broj u nizu se zatim dobija kao zbir prethodna dva broja niza. Tako,
treci broj niza je zbir drugog i prvog, odnosno 1 + 1 = 2; c etvrti broj niza je
zbir treceg i drugog, odnosno 2 + 1 = 3; peti broj niza je zbir c etvrtog i treceg,
odnosno 3 + 2 = 5; i tako dalje. Prema tome, pocetni deo Fibonacijevog niza
brojeva je:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, . . .
Za izracunavanje n-tog broja Fibonacijevog niza moe se poceti od prva
dva broja tog niza i zatim primeniti iterativni postupak u kojem se u svakom koraku redom izracunava naredni broj u nizu dok se ne dobije traeni
112
Rekurzivni algoritmi
n-ti broj. U nastavku je predstavljen iterativni algoritam u kojem se koriste tri promenljive koje u svakom koraku sadre prethodna dva broja niza
(promenljive x i y) i naredni broj niza (promenljiva z):
// Ulaz: n 1
// Izlaz: n-ti broj Fibona
cijevog niza
algorithm fib1(n)
x = 1; y = 1; z = 1;
for i = 3 to n do
z = x + y;
x = y;
y = z;
return z;
Ako brojeve Fibonacijevog niza oznacimo sa f 1 , f 2 , f 3 , . . ., onda je ocevidno rekurzivna denicija za n-ti broj Fibonacijevog niza:
f 1 = 1, f 2 = 1
f n = f n 1 + f n 2 ,
n > 2.
113
redosledu svoje velicine od podnoja tog stuba ka vrhu. Na slici 5.2 je prikazana pocetna konguracija ove igre za n = 5 diskova ukoliko zamislimo
da su tri stuba trougaono rasporedeni.
114
Rekurzivni algoritmi
115
2.
3.
4.
A
// Ulaz: n 1, po
cetni, pomo
cni i ciljni stub
// Izlaz: niz poteza za n diskova problema Hanojskih kula
algorithm toh(n, a, b, c)
if (n == 1) // bazni slu
caj
move(a,c);
else
// opti slu
caj
toh(n-1,a,c,b);
move(a,c);
toh(n-1,b,a,c);
return;
1 Ime algoritma toh je skracenica od engleskog naziva za igru Hanojskih kula: the
Towers of Hanoi.
116
Rekurzivni algoritmi
5.2
117
dobijanje reenja neke rekurentne jednacine je primena tzv. postupka viestruke zamene u kojem se sukcesivno zamenjuje opti izraz za T(n) umesto
vrednosti T(m) za neko m < n na desnoj strani rekurentne jednacine, sve
dok se ne eliminiu sve takve vrednosti i ne dobije pocetni uslov.
Na primer, ukoliko se primeni ovaj postupak na rekurentnu jednacinu
(5.1) za vreme izvravanja algoritma toh, opti izraz za T(n) treba zameniti
umesto T(n 1), T(n 2), . . ., T(2) na desnoj strani rekurentne jednacine
(5.1) za n > 1. Na kraju treba zameniti pocetni uslov T(1) i pojednostaviti
rezultujucu formulu. Na taj nacin se dobija sledece reenje za T(n):
T(n) = 2 T(n 1) + 1
= 2 2T(n 2) + 1 + 1 = 22 T(n 2) + 2 + 1
= 22 2T(n 3) + 1 + 2 + 1 = 23 T(n 3) + 22 + 2 + 1
..
.
= 2n1 T(1) + 2n2 + + 22 + 2 + 1
= 2 n 1 1 +
n
2
i =0
2 i = 2 n 1 +
2 n 1 1
= 2 2 n 1 1
21
= 2 1.
Primetimo da je reenje T(n) = 2n 1 zapravo broj poteza u reenju problema Hanojskih kula za n diskova, jer izvravanje algoritma move predstavlja upravo jedan potez u reenju.
Da bismo bolje uvebali rekurzivni nacin reavanja problema i analizu
odgovarajucih rekurzivnih algoritama, u nastavku c emo pokazati jo neke
primere rekurzivne tehnike.
118
Rekurzivni algoritmi
Objediniti dve sortirane liste u trecem koraku sortiranja objedinjavanjem znaci proizvesti jedinstvenu sortiranu listu koja sadri sve elemente
datih listi (i nijedan drugi element). Na primer, ako su date dve sortirane
liste 1, 2, 3, 7, 8 i 1, 2, 6, 9, jedinstvena sortirana lista dobijena njihovim
objedinjavanjem je 1, 1, 2, 2, 3, 6, 7, 8, 9. Obratite panju na to da se kod
objedinjavanja dve liste uvek podrazumeva da su one vec sortirane.
Jednostavan postupak za objedinjavanje dve sortirane liste jeste da se
obe liste paralelno ispituju redom od pocetka do kraja. Pri tome se u svakom koraku uporeduju
glave dve liste, bira se manji element od njih (ako su
119
120
Rekurzivni algoritmi
elementa polazne liste, odnosno prva lista sadri neparne, a druga parne
elemente polazne liste. Konkretno, l 1 = 89213 i l 2 = 6217. Zatim se ove
polovicne liste rekurzivno sortiraju istim algoritmom, to kao rezultat daje
liste l 1 = 12389 i l 2 = 1267. Na kraju, algoritam list-merge proizvodi
objedinjenu sortiranu listu l = 112236789.
Nema, naravno, nita magicnog kod sortiranja dve manje liste, vec se
to dobija sistematicnom primenom rekurzivnog algoritma. Naime, algoritmom merge-sort se najpre deli ulazna lista na dve manje liste, a zatim
se nastavlja ovo rekurzivno deljenje manjih lista sve dok se ne dobije to da
svaka lista ima po jedan element. Na slici 5.4(a) je prikazano ovo rekurzivno deljenje listi iz primera. Zatim se dobijene manje liste objedinjuju
u parovima, iduci odozdo uz stablo, dok se cela lista ne dobije sortirana.
Ovaj proces je prikazan na slici 5.4(b). Medutim,
vredno je uociti da je ovo
869221173
89213
823
83
91
12389
6217
61
238
27
38
(a) deljenje
1267
19
16
27
(b) objedinjavanje
Analiza algoritma merge-sort. Neka je T(n) vreme izvravanja algoritma merge-sort za ulaznu listu l od n elemenata. Na osnovu dizajna
tog algoritma moemo zakljuciti da vreme njegovog izvravanja zavisi od
dva slucaja: kada ulazna lista ima jedan element (n = 1) i kada ima vie od
jednog elementa (n > 1).
Ako je n = 1, u tom algoritmu se izvrava konstantan broj instrukcija
za proveravanje uslova naredbe if i izvravanje naredbe return. Ukoliko
121
T(n) =
ako je n = 1
c1,
T(n) =
c,
ako je n = 1
(5.2)
Uzgred, obratite panju na jo jedno suptilno pojednostavljenje u jednacini (5.2). Naime, duina listi l 1 i l 2 u rekurzivnim pozivima algoritma
merge-sort nije uvek jednaka n/2. Paljivi c itaoci mogu lako proveriti da
u jedna
cini (5.2) za n > 1 na desu te duine zapravo n/2
1 i
n/2,pa bi
snoj strani trebalo da stoji T n/2 1 + T
n/2 + 2cn. Kako je
uvek n/2
1
n/2, ovu desnu stranu moemo pojednostaviti piuci 2T
n/2 + 2cn.
(Ovde prirodno pretpostavljamo da je T(n) rastuca funkcija i, radi jednostavnosti, koristimo jednakost umesto preciznije nejednakosti .) U stvari,
ovo c emo dalje pojednostaviti i potpuno zanemariti rad sa celobrojnim delovima realnih vrednosti, kako u jednacini (5.2) tako i u preostalom delu
knjige. To ima opravdanja jer se paljivijom analizom moe pokazati da to
moemo uvek uraditi bez gubitka optosti, pa radi jednostavnosti namerno
biramo da budemo malo neprecizniji nautrb formalne tacnosti.
122
Rekurzivni algoritmi
T(n) = 2 2T n/22 + 2c n/2 + 2cn
= 22 T n/22 + 4cn .
U ovoj jednacini zamenjujuci dalje optu jednacinu za T n/22 na desnoj
strani dobijamo novu jednacinu:
T(n) = 22 2T n/23 + 2c n/22 + 4cn
= 23 T n/23 + 6cn .
Nastavljajuci ovaj postupak zamene na desnoj strani prethodnih jednac ina, nije teko prepoznati obrazac po kojem se dobija opti oblik na desnoj
strani izraza za T(n):
T(n) = 2 i T n/2 i + 2icn,
i = 1, 2, 3, . . .
123
k +1
a
ai p
ai > p
124
Rekurzivni algoritmi
p
p
>p
p
>p
njihove vrednosti. Ovaj isti postupak se ponavlja sve dok je i < j. Kada se
indeksi i i j preklope (tj. i j), to znaci da je ispitan ceo podniz. Ono to
preostaje je da se medusobno
zamene elementi a l i a j da bi se pivot element
125
podnizu.
// Ulaz: podniz niza a ograni
cen indeksima od l do r
// Izlaz: preure
den podniz i njegov indeks u kome se nalazi pivot
algorithm partition(a, l, r)
// Pretpostavlja se da je a r+1 = +
p = a[l];
i = l + 1; j = r;
while (i < j) do
while (a[i] <= p) do i = i + 1;
while (a[j] > p) do j = j - 1;
swap(a[i],a[j]);
swap(a[l],a[j]);
return j;
U algoritmu partition imamo jedan tehnicki problem koji smo razreili tako to smo ga ignorisali. Naime, kada se po prvi put redom ispituje
podniz, pocinjuci od levog kraja i traeci element koji je veci od pivota p,
postoji mogucnost da se prede
preko desnog kraja podniza. To se deava
ukoliko je pivot najveci element podniza ili su svi elementi podniza jednaki.
Da bismo u algoritmu partition izbegli proveravanje ovih uslova i tako
pokvarili njegovu jednostavnost, unapred smo pretpostavili da uvek postoji
granicni element podniza na desnom kraju tako da je a r+1 = +. Aktuelni
detalji reenja ovog tehnickog problema se preputaju c itaocima za laku
vebu.
Razmotrimo sada razdvajanje niza kada se bira njegov poslednji element za pivota. U ovom slucaju se niz redom ispituje samo u jednom
smeru (sleva na desno) i deli u c etiri (moguce prazne) oblasti kao to je
to prikazano na slici 5.7.
r
a
p
>p
=p
126
Rekurzivni algoritmi
Bilo koju od dve prethodne verzije algoritma partition moemo koristiti da bismo napisali algoritam quick-sort(a,l,r) koji razdvajanjem
elemenata sortira podniz a l , . . ., a r , gde je 1 l r n. Eksplicitne granice
podniza su potrebne kao parametri ovog algoritma zbog njegove rekurzivne
prirode. Naravno, ukoliko elimo da sortiramo ceo niz a duine n, to moemo u programu uraditi pozivom quick-sort(a,1,n).
// Ulaz: podniz niza a ograni
cen indeksima od l do r
// Izlaz: sortiran podniz
algorithm quick-sort(a, l, r)
if (l < r) then
k = partition(a,l,r);
quick-sort(a,l,k-1);
quick-sort(a,k+1,r);
return a;
Analiza algoritma quick-sort. Izvravanje algoritma quick-sort zavisi od toga da li su razdvojeni delovi podnizova uravnoteeni po velicini,
to sa svoje strane zavisi od ranga2 elementa izabranog za pivota. Ako
su podnizovi na svakom nivou stabla rekurzije otprilike jednako podeljeni,
sortiranje razdvajanjem se asimptotski izvrava kao i sortiranje objedinjavanjem za vreme O(n log n). Sa druge strane, ako je razdvajanje podnizova
2 Rang nekog elementa jednak je njegovoj poziciji u sortiranom nizu.
127
u odnosu na
do O n2 . Srecom, u proseku, dobre podele preovladuju
128
Rekurzivni algoritmi
da dobijemo mnogo vie dobrih podela nego loih, poto naa neformalna
analiza nagovetava da su naizgled loe podele zapravo dobre. Dakle, c ak i
kada se neka vrlo loa podela dobije pre dobrih podela, odgovarajuci podniz
c e se brzo sortirati. Naime, dodatni posao zbog loe podele se ne odraava
na dodatne rekurzivne pozive, nego je dominiran dodatnim razdvajanjem
koje se apsorbuje u ukupno vreme izvravanja.
5.3. Rekurentne jednacine
129
velicine ulaza manje od n. Zadatak je naci formulu (ili bar gornju granicu)
za T(n) izraenu samo pomocu velicine ulaza n.
Kroz primere u prethodnom odeljku smo upoznali i metod viestruke
zamene za reavanje nekih rekurentnih jednacina. Pokazali smo da se
metod viestruke zamene sastoji od zamenjivanja vrednosti T(m) za m < n
optim oblikom rekurentnog dela jednacine za T(n). Pri tome nakon nekoliko zamena ocekujemo da moemo odrediti opti obrazac za T(n) i da
moemo odrediti kada taj opti oblik prelazi u bazni slucaj.
Sa matematicke tacke gledita, postoji trenutak kada kod metoda viestruke zamene dolazi do malo opasnog logickog skoka. To se dogada
u
trenutku kada o optem obliku reenja zakljucujemo na osnovu obrasca
ta se dogada
na svakom nivou rekurzije. Kod primene metoda stabla
rekurzije, rekurentna jednacina se predstavlja stablom u kojem nas svaka
zamena rekurentnog dela polazne jednacine dovodi do jednog nivoa dublje
u stablu.
Glavnu ideju metoda stabla rekurzije za reavanje rekurentnih jednac ina objasnicemo na primeru rekurentne jednacine (5.2) za vreme izvravanja algoritma merge-sort na strani 121 (koju smo dalje pojednostavili
130
Rekurzivni algoritmi
1,
ako je n = 1
(5.3)
Podsetimo se algoritamske interpretacije ove jednacine: da bismo niz duine n sortirali objedinjavanjem, moramo sortirati objedinjavanjem dva
podniza duine n/2 i uraditi n jedinica dodatnog posla za njihovo nerekurzivno objedinjavanje. Za rekurentnu jednacinu sortiranja objedinjavanjem
crtamo stablo rekurzije sa korenom koji predstavlja polazni problem i koren oznacavamo vremenom za reavanje tog problema u nerekurzivnom
Stablo rekurzije
n/4
n/4
2 (n/2) = n
1n = n
n/2
n/2
Jedinice
rada
n/2
n/4
n/4
4 (n/4) = n
n/4
n/2 i
1
i
i
2 (n/2 ) = n
log n + 1
nivoa
n1 = n
5.3. Rekurentne jednacine
131
T(n) =
c,
ako je n = 1
(5.4)
Ukoliko zanemarimo bazni slucaj, rekurentnu jednacinu (5.4) moemo interpretirati na sledeci nacin: da bismo reili problem velicine n, reavamo
3 potproblema velicine n/2 i radimo n2 jedinica dodatnog posla. Kada
crtamo stablo rekurzije, svaki c vor opet oznacavamo iznosom dodatnog (nerekurzivnog) vremena za odgovarajucu velicinu potproblema. Na najviem
nivou 0, za dodatni posao treba n2 jedinica vremena. Na nivou 1 imamo
tri c vora po (n/2)2 jedinica dodatnog vremena, to za taj nivo daje ukupno
vreme 3(n/2)2 = (3/4)n2 . Na nivou 2 imamo devet c vorova po (n/4)2 jedinica
2
= (3/4)2 n2 .
dodatnog vremena, to za taj nivo daje ukupno vreme 9(n/4)
i
i 2
jedinica
Ovo je lako nastaviti za nivo i, gde imamo 3 cvorova po n/2
i
i 2
dodatnog vremena, to za taj nivo daje ukupno vreme 3 n/2 = (3/4) i n2 .
Nivo na dnu je drugaciji od ostalih nivoa. U ostalim nivoima, vreme po
c voru dobijamo na osnovu rekurzivnog dela T(n) = 3T(n/2) + n2 rekurentne
jednacine. U najniem nivou, vreme po c voru dobijamo na osnovu baznog
slucaja T(1) = c rekurentne jednacine. Na slici 5.9 je prikazano stablo
rekurzije koje se dobija za rekurentnu jednacinu (5.4).
Naravno, da bismo dobili ukupno vreme za celo stablo rekurzije, tj.
reenje jednacine (5.4), sabiramo vremena po svim nivoima stabla. Poto je
132
Rekurzivni algoritmi
Velicina
problema
Stablo rekurzije
Jedinice
rada
1 n2 = n2
n/2
(n/2)2
(n/2)2
n/4
(n/2)2
3(n/2)2 = (3/4)n2
9(n/4)2 = (3/4)2 n2
3 i (n/2 i )2 = (3/4) i n2
n/2 i
1
3log n c
log
n 1
i =0
(3/4) i + c3log n
(3/4)log n 1
+ c3log n
3/4 1
1 nlog 3 /n2
= n2
+ cnlog3
1/4
= 4n2 4nlog 3 + cnlog3
= n2
= 4n2 + (c 4)nlog3 .
U ovom izvodenju
smo koristili jednakost alogb n = nlogb a , kao i formulu za
xi =
x m +1 1
,
x1
(x = 1) .
kako je log2 3 1.58 to je T(n) = O n2 .
Metod nagadanja
5.3. Rekurentne jednacine
133
u tome da se najpre promiljeno pretpostavi reenje date rekurentne jednacine, a zatim da se ta pretpostavka potvrdi, obicno indukcijom. Naravno,
primenom ovog metoda moda moramo da probamo nekoliko reenja dok
ne dobijemo dobru gornju granicu za datu rekurentnu jednacinu. Drugim
recima, ako ne uspevamo da verikujemo aktuelno pretpostavljeno reenje,
verovatno treba probati neku funkciju koja bre raste. Ali i ako uspemo u
tome uz relativno malo truda, verovatno treba probati i neku funkciju koja
sporije raste.
Na primer, posmatrajmo sledecu rekurentnu jednacinu (gde su a i b
neke pozitivne konstante):
a,
ako je n = 1
(5.5)
T(n) =
2T(n/2) + bn log n, ako je n > 1 .
Ovo izgleda vrlo slicno rekurentnoj jednacini za sortiranje objedinjavanjem, pa naa prva pretpostavka moe biti da je reenje T(n) = O(n log n).
Zatim, u sledecem koraku elimo da verikujemo indukcijom da je reenje
rekurentne jednacine (5.5) zaista T(n) cn log n za neku pozitivnu konstantu c i dovoljno veliko n.
Sigurno moemo izabrati dovoljno velike konstante c i n 0 tako da nae
pretpostavljeno reenje zadovoljava bazni slucaj n = n 0. Naime, ako uzmemo c = a + b i n 0 = 2, tada je:
T(2) = 2T(1) + b 2 log 2 = 2a + 2b = 2(a + b) = 2c = c 2 log 2 .
Za indukcijski korak kada je n > n 0, ako po indukcijskoj pretpostavci uzmemo da je nae prvo reenje tacno za vrednosti argumenta manjih od n,
tada za argument jednak n moemo pisati:
T(n) = 2T(n/2) + bn log n
n
n
2 c log
+ bn log n
2
2
= cn(log n log 2) + bn log n
= cn log n cn + bn log n .
134
Rekurzivni algoritmi
Zato kao drugo reenje za T(n) moramo probati neku funkciju koja bre
raste, na primer, T(n) = O n2 . U tom slucaju, da bismo pokazali T(n)
cn2 za neku pozitivnu konstantu c i dovoljno veliko n, moemo uzeti c =
2(a + b) i n 0 = 1 i lako videti da bazni slucaj vai. Za indukcijski korak kada
je n > n 0 , ako po indukcijskoj pretpostavci uzmemo da je nae drugo reenje
tacno za vrednosti argumenta manjih od n, tada za argument jednak n
imamo:
T(n) = 2T(n/2) + bn log n
n2
+ bn log n
4
n2 c 2
c
+ n
2 2
= cn2 .
2 c
reenje lako dobiti, probacemo jo jednu (tj. pravu) funkciju koja ne raste
tako brzo: T(n) = O n log2 n . Sada, da bismo pokazali T(n) cn log2 n za
neku pozitivnu konstantu c i dovoljno veliko n, moemo uzeti c = a + b i
n 0 = 2 i opet lako videti da bazni slucaj vai. Za indukcijski korak kada je
n > n 0 imamo:
T(n) = 2T(n/2) + bn log n
n
n
2 c log2
+ bn log n
2
2
= cn(log2 n 2 log n + 1) + bn log n
cn log2 n 2cn log n + cn + cn log n
= cn log2 n cn log n + cn
= cn log2 n cn(log n 1)
cn log2 n .
Ovo dokazuje da je T(n) zaista O n log2 n .
Opti metod
Prethodni nacini za reavanje rekurentnih jednacina zahtevaju odredeno
matematicko predznanje (recimo, primenu indukcije) da bi se mogli
5.3. Rekurentne jednacine
135
slucaja i neposredno daje reenje u svakom od njih. Ovaj opti metod sadri
formulu na osnovu koje se moe odrediti asimptotsko reenje velike klase
rekurentnih jednacina u obliku:
T(n) = aT(n/b) + f (n) ,
gde su a 1 i b > 1 konstante, a f (n) je asimptotski pozitivna funkcija.
Ovaj oblik rekurentne jednacine opisuje vreme izvravanja rekurzivnog
algoritma u kome se problem velicine n deli u a nezavisnih potproblema
velicine najvie n/b svaki, zatim reava svaki od ovih potproblema rekurzivno i, na kraju, kombinuju reenja ovih potproblema u reenje celog
problema. Ukupno vreme za deljenje polaznog problema u potprobleme i
za kombinovanje njihovih reenja je izraeno funkcijom f (n). Prema tome,
ovo je zaista opti oblik za rekurentne jednacine rekurzivnih algoritama.
Opti metod zahteva prepoznavanje tri slucaja u jednoj teoremi, ali se
zato reenje mnogih rekurentnih jednacina dobija prilicno lako i c esto se
svodi samo na ispisivanje odgovora. Odgovarajuci slucaj na osnovu koga
se dobija reenje prepoznaje se poredenjem
funkcije f (n) sa specijalnom
logb a
. Pomenutu teoremu medutim
necemo navoditi u njenoj
funkcijom n
punoj optosti, jer je prilicno tehnicke prirode i ima vie teorijski znacaj.
U praksi se c ece koristi njena pojednostavljena verzija u kojoj je f (n) u
sutini polinomska funkcija po n.
T EOREMA Neka je nenegativna funkcija T(n) denisana rekurentnom jednacinom
d,
n n0
T(n) =
k
aT(n/b) + cn , n > n 0
gde je n 0 1 celobrojna konstanta, a a 1, b > 1, c > 0, d > 0 i k 0 su
realne konstante.
Slucaj
1: Ako je a = b k , tada je T(n) = n k log n .
Slucaj
2: Ako je a < b k , tada je T(n) = n k .
Slucaj
3: Ako je a > b k , tada je T(n) = nlogb a .
Dokaz: Radi jednostavnosti pretpostavljamo da je n stepen broja b i n 0 =
1, kako ne bismo zamaglili osnovnu sliku nepotrebnim detaljima. Ipak
naglaavamo da time ne gubimo na optosti i ideja dokaza se prenosi za
bilo koje n. Ako radi lakeg pisanja uvedemo oznaku f (n) = cn k , primenom
viestruke zamene na datu rekurentnu jednacinu dobijamo:
T(n) = aT(n/b) + f (n)
136
Rekurzivni algoritmi
= a aT n/b2 + f (n/b) + f (n)
= a2 T n/b2 + a f (n/b) + f (n)
= a3 T n/b3 + a2 f n/b2 + a f (n/b) + f (n)
..
.
= alogb n T(1) +
= nlogb a d +
log
b n 1
a i f n/b i
i =0
log
b n 1
a i f n/b i ,
i =0
log
b n 1
i =0
= dnlogb a + cn k
k
a i c n/b i
log
b n 1
i =0
i
bk
T(n) = dn k + cn k logb n = n k log n .
T(n) = dn
logb a
+ cn
a/b k
logb n
a/b k 1
Dakle, ako je a < b k , odnosno k > logb a i 0 < a/b k < 1, onda je
T(n) = dnlogb a + cn k (1) = n k ,
i
poto je drugi izraz dominantan i m
i=0 x = (1) za 0 < x < 1.
U trecem slucaju, ako je a > b k odnosno a/b k > 1, poto za x > 1 imamo
i
m
i=0 x = (x ), dobijamo:
logb n
logb a
k
k
+ cn a/b
T(n) = dn
m
5.3. Rekurentne jednacine
137
logb a
= dn
+ cn
log a
= n b ,
nlogb a
nk
2
2
= n .
hodne teoreme odmah moemo zakljuciti da je T(n) = n
Kao drugi primer, razmotrimo rekurentnu jednacinu:
T(n) = 2T
n + log n = 2T n1/2 + log n .
T 2m = 2T 2m/2 + m .
138
Rekurzivni algoritmi
i Y = C2n/2 + D .
Y=
63852
42189
19001
32000
(5.6)
5.3. Rekurentne jednacine
139
Ova formula nagovetava jednostavan rekurzivni algoritam za izracunavanje proizvoda A B : podeliti n-bitne brojeve X i Y na pola, zatim rekurzivno
izracunati proizvode u kojima ucestvuju te polovine u (5.6) (naime AC, AD,
BC i BD) i, na kraju, dobijene meduproizvode
pomnoiti i sabrati prema
log 4
teoreme, odmah dobijamo da je T(n) = n 2 = n2 . Naalost, ovo nije
nita bolje od uobicajenog algoritma za mnoenje.
Na osnovu opteg metoda ipak moemo steci uvid u to kako da ubrzamo
rekurzivni algoritam. Ako bismo nekako uspeli da smanjimo broj rekurzivnih poziva a, tada bismo dobili sporiju specijalnu funkciju nlogb a koja
ucestvuje u reenju rekurentne jednacine, odnosno vremenu izvravanja.
Moda zvuci iznenaduju
ce ako kaemo da to zaista moemo postici, ali
(5.7)
Mora se priznati da zaista deluje c udno zato se posmatra ba ovaj proizvod, ali uporeduju
ci formulu (5.6) vidimo da proizvod (5.7) u razvijenoj
140
Rekurzivni algoritmi
T(n) = O nlog2 3 = O n1.585 ,
to je bolje od O n2 .
Pisanje aktuelnog rekurzivnog algoritma na pseudo jeziku za mnoenje
dva n-bitna cela broja po formuli (5.8) ostavljamo c itaocima za laku vebu.
Zadaci
1. Jedna igra sa etonima se sastoji od ukupno n etona podeljenih u nekoliko grupa. Pretpostavlja se da je broj etona n neki stepen broja 2 i
da je broj grupa u koje su etoni podeljeni proizvoljan. Jedan potez ove
igre se sastoji od toga da se najpre biraju dve grupe etona A i B i zatim
ako grupa A ima a etona i grupa B ima b etona i ako je, recimo, a b,
premeta se b etona iz grupe A u grupu B. Cilj igre je da se odredenim
nizom ovakvih poteza svi etoni premeste u samo jednu grupu na kraju.
Navedite algoritam kojim se reava problem ove igre i odredite njegovo
vreme izvravanja (tj. broj poteza) izraeno u funkciji broja etona n.
2. Napiite algoritam partition za sortiranje razdvajanjem kojim se za
pivota bira srednji element podnizova. Obrazloite c injenicu da ovakav
izbor pivot elementa ne utice na smanjenje vremena izvravanja algoritma za sortiranje razdvajanjem.
5.3. Rekurentne jednacine
141
1,
ako x i poznaje x j
0, ako x i ne poznaje x j
0 1
M=
1 1
142
Rekurzivni algoritmi
7. U neuredenom
nizu a od n razlicitih brojeva, par razlicitih elemenata
1,
n<3
2
4T(n/3) + n ,
n3
koristeci metod
a) viestruke zamene;
b) stabla rekurzije;
c) opte teoreme.
11. Posmatrajmo sledeci algoritam koji izracunava proizvod dva nenegativna cela broja x i y:
// Ulaz: celi brojevi x 0 i y 0
// Izlaz: x y
5.3. Rekurentne jednacine
143
algorithm multiply(x, y)
p = 0;
while (x > 0) do
if (x % 2 != 0) then
p = p + y;
x = x / 2;
y = 2 * y;
// p = x y
// x je neparan
return p;
144
Rekurzivni algoritmi
i
B n (x) = b n x n + b n1 x n1 + + b 1 x + b 0 .
G LAVA
6
Stabla
6.1
Korenska stabla
146
Stabla
v1
v3
v2
v6
v7
v5
v4
v8
v9
v10
v11
paru koji predstavlja granu. Ipak se radi lakeg crtanja koristi linija za
granu, a ne strelica, jer se redosled c vorova grane ukazuje time to se prvi
c vor na crteima uvek prikazuje iznad drugog c vora. Tako se na slici 6.1
podrazumeva da je, recimo, (v2 , v7 ) grana stabla, a ne obrnuto.
Terminologija u vezi sa stablima je uglavnom pozajmljena iz njihove
primene u predstavljanju rodoslova neke porodice, gde se granama uspostavlja medusobni
odnos roditelj-dete izmedu
Cvor
u stablu moe imati nula ili vie dece, ali svaki c vor razlicit od
korena ima tacno jednog roditelja i koren stabla je jedini c vor bez roditelja.
Ova osobina je upravo ona koja karakterie stablo i koristi se za formalnu
deniciju (korenskog) stabla: stablo T je skup c vorova i skup grana izmedu
147
1. Ako je T neprazno stablo, ono ima jedinstven poseban c vor (koren) koji
nema roditeljski c vor.
2. Svaki c vor u u T osim korena ima jedinstven roditeljski c vor v.
Primetimo da na osnovu ove formalne denicije stablo moe biti prazno, to znaci da takvo stablo nema nijedan c vor (i nijednu granu). To
omogucava da se stablo denie i rekurzivno na nacin kojim se veca stabla
konstruiu od manjih: stablo T je prazno ili se sastoji od c vora r, koji se
naziva koren stabla T, i (moguce praznog) skupa stabala T1 , T2 , . . ., T k c iji
su koreni deca c vora r. Na slici 6.2 je ilustrovana ova rekurzivna denicija
stabla.
T
r1
r2
T2
T1
rk
Tk
148
Stabla
daju roditelja, sasvim levog deteta ili desnog brata datog c vora. Radi lakeg
programiranja korisno bi bilo realizovati i upitne operacije koje odreduju
149
stabla, odredivanje
visine stabla i tako dalje. Medutim,
ukoliko se koristi
stablima, odnosno broj dece po c voru moe biti vrlo razlicit i nije unapred
ogranicen, ovaj pristup nije najbolji jer proizvodi loe iskoricenje memorijskog prostora. Zato se obicno koriste dva druga nacina za predstavljanje
optih stabala o kojima govorimo u nastavku.
150
Stabla
T
1
10
7
8
9
10
10
Kao to se vidi sa slike 6.4, u ovoj reprezentaciji stabla imamo jedan niz
pokazivaca t c iji elementi predstavljaju c vorove i zato je njegova velicina
jednaka ukupnom broju c vorova u stablu. Pored toga, svaki element niza
t pokazuje na pocetak povezane liste c vorova stabla. Pri tome, elementi
liste na koju pokazuje element niza t i su c vorovi-deca c vora i tako da
poredak elemenata u listi odgovara poretku dece sleva na desno u stablu.
Na primer, na slici 6.4 element t 5 pokazuje na listu 8 9 poto su c vorovi
8 i 9, time redom, deca c vora 5.
Jedan nedostatak ovog nacina predstavljanja stabla je to to ne moemo lako da konstruiemo veca stabla od manjih. To je posledica toga
to svako stablo ima svoj niz pokazivaca za svoje c vorove. Prema tome, da
bismo napravili novo stablo, recimo, od datog c vora kao korena i dva data
podstabla T1 i T2 , morali bismo da kopiramo T1 i T2 u trece stablo i da
dodamo listu za novi koren c ija su deca koreni za T1 i T2 .
cvorova.
Drugo reenje za problem predstavljanja optih stabala je predstavljanje sasvim levog deteta i desnog brata svakog c vora stabla. U ovoj
reprezentaciji svaki c vor pored kljuca sadri samo jo dva pokazivaca: jedan pokazuje na njegovog sasvim levog deteta i drugi na njegovog desnog
brata. Naravno, ovi pokazivaci imaju specijalnu vrednost null ukoliko
c vor nema dece ili nema desnog brata.
Ovaj nacin predstavljanja opteg stabla je ilustrovan u desnom delu na
slici 6.5 za stablo koje je prikazano u levom delu. Na toj slici je za svaki
151
152
Stabla
1
2
4
5
(a)
(b)
(c)
levo
desno
klju
c
2
3
2
4
153
3
T
Td
preorder
3
T
Td
inorder
2
T
Td
postorder
154
Stabla
postorder obilazak c vorova stabla T sastoji se najpre od rekurzivnog obilaska c vorova stabla T u postorder redosledu, zatim
od rekurzivnog obilaska c vorova stabla T d u postorder redosledu i na kraju od posete korena r.
preorder:
1, 2, 4, 7, 8, 5, 9, 3, 6
inorder:
7, 4, 8, 2, 5, 9, 1, 6, 3
postorder:
7, 8, 4, 9, 5, 2, 6, 3, 1
Obratite panju na to da je rekurzivni algoritam bt-inorder neposredna implementacija rekurzivne denicije inorder obilaska binarnog stabla. Pri tome, obrada svakog c vora prilikom njegovog posecivanja sastoji
se od prostog prikazivanja kljuca c vora.
155
Cesto
c emo jednostavne algoritme, kao to je to algoritam bt-inorder,
izraavati u rekurzivnom obliku. Naravno, svaki rekurzivni algoritam se
moe napisati iterativno, ako nita drugo simulirajuci rekurziju pomocu
steka. U stvari, u praksi je bolje pisati algoritme na iterativni nego na
rekurzivni nacin, jer se tako dobija na ekasnosti izbegavanjem dodatnih
implicitnih operacija koje svaka rekurzija namece. Na primer, iterativnu
verziju istog algoritma bt-inorder moemo napisati na sledeci nacin:
// Ulaz:
cvor t binarnog stabla
// Izlaz: lista klju
ceva podstabla sa korenom t u inorder redosledu
algorithm bt-inorder(t)
stack-make(s); // inicijalizacija praznog steka s
repeat
while (t != null) do
push(t,s);
t = t.levo;
t = pop(s);
print(t.klju
c);
t = t.desno;
until (stack-empty(s) && (t == null));
return;
6.3
156
Stabla
elementima je denisana relacija manje od. Primeri ovih skupova obuhvataju skupove celih i realnih brojeva sa uobicajenom relacijom poretka
brojeva, kao i skup znakovnih stringova sa leksikografskim poretkom.
Na slici 6.10 su prikazana dva binarna stabla pretrage koja sadre isti
skup vrednosti kljuceva. Kao to c emo videti, vreme izvravanja vecine
operacija nad binarnim stablom pretrage je proporcionalno visini stabla.
U tom smislu, desno stablo na slici 6.10 je manje ekasno.
3
7
5
3
5
8
8
9
BSP operacije
Tipicne operacije nad binarnim stablom pretrage su traenje, dodavanje i uklanjanje c vora iz takvog stabla.
Traenje cvora.
Najpre c emo panju posvetiti problemu traenja c vora
sa datim kljucem x u binarnom stablu pretrage T. Da bismo brzo locirali
c vor sa kljucem x u stablu T, ili utvrdili da se c vor sa tim kljucem ne nalazi
u stablu, koristimo BSP svojstvo. Naime, ukoliko uporedimo x sa kljucem
korena stabla T, razlikuju se tri slucaja.
157
Prvi, najlaki slucaj je ako je kljuc korena stabla T jednak x, jer smo
onda nali traeni c vor i moemo zavriti pretragu. U drugom slucaju, ako
je kljuc korena stabla T veci od x, prema BSP svojstvu moemo zakljuciti
da se c vor sa kljucem x moe naci samo u levom podstablu korena stabla T,
jer su u desnom podstablu svi kljucevi veci od kljuca korena, pa time i od x.
Zbog toga pretragu rekurzivno nastavljamo na isti nacin od korena levog
podstabla korena stabla T. Najzad, u trecem slucaju koji je simetrican
drugom, ako je kljuc korena stabla T manji od x, onda se c vor sa kljucem x
moe naci samo u desnom podstablu korena stabla T. Zbog toga pretragu
rekurzivno nastavljamo na isti nacin od korena desnog podstabla korena
stabla T.
Ovaj neformalni opis operacije traenja c vora u binarnom stablu pretrage preciziran je rekurzivnim algoritmom bst-search u nastavku. Ako
su dati pokazivac t na neki c vor u binarnom stablu pretrage i kljuc x,
algoritam bst-search kao rezultat vraca pokazivac na c vor sa kljucem
x, ukoliko se takav c vor nalazi u podstablu c iji je koren t; u suprotnom
slucaju, ukoliko takav c vor ne postoji, ovaj algoritam vraca pokazivac null.
// Ulaz:
cvor t binarnog stabla pretrage, klju
c x
// Izlaz: pokaziva
c na
cvor sa klju
cem x, ili null
algorithm bst-search(t, x)
if ((t == null) || (t.klju
c == x)) then
return t;
else if (t.klju
c > x) then
bst-search(t.levo, x);
else
bst-search(t.desno, x);
21
11
9
7
18
23
15
13
16
158
Stabla
Kao to se vidi sa slike 6.11, u algoritmu bst-search se pretraga zapoc inje od korena stabla i prelazi se odreden
put nadole du grana i c vorova
u stablu. Za svaki c vor na tom putu, u algoritmu se uporeduje
kljuc tog
Dodavanje cvora.
Operacija dodavanja (kao i uklanjanja) c vora modikuje binarno stablo pretrage tako da moramo paziti da ne naruimo BSP
svojstvo u rezultujucem stablu. Imajuci to u vidu, dodavanje novog c vora
u binarno stablo pretrage moe se ipak uraditi na relativno jednostavan
nacin.
Da bismo novi c vor p dodali u binarno stablo pretrage T, u sutini
najpre pokuavamo da lociramo kljuc c vora p u T primenjujuci postupak
traenja tog kljuca. Ako ga nademo,
ne treba nita drugo da radimo, jer
159
da polje p.klju
c vec sadri eljeni kljuc i da polja p.levo i p.desno sadre
vrednost null.
vor t binarnog stabla pretrage, novi
// Ulaz: c
cvor p
// Izlaz:
cvor p dodat u podstablo sa korenom t
algorithm bst-insert(t, p)
if (t == null) then
t = p;
else if (p.klju
c < t.klju
c) then
t.levo = bst-insert(t.levo, p);
else if (p.klju
c > t.klju
c) then
t.desno = bst-insert(t.desno, p);
else
; // duplikati se ne dodaju
return t;
23
11
27
21
19
22
25
160
Stabla
aurira. Kod svih ostalih c vorova algoritam vraca isti pokazivac koji je
primio, tako da kod tih c vorova fakticki nema stvarnih promena.
Uklanjanje cvora.
Uklanjanje c vora p iz binarnog stabla pretrage
malo komplikovanije od traenja ili dodavanja c vora. Pre svega, ako
p spoljanji c vor (list) u stablu, moemo jednostavno ukloniti taj c vor
stabla. Na slici 6.13 je prikazano uklanjanje spoljanjeg c vora (lista)
jednog binarnog stabla pretrage.
17
17
23
11
10
je
je
iz
iz
21
19
27
22
23
11
25
21
20
27
22
25
20
c emo time prekinuti strukturu stabla. Zbog toga, stablo se mora restrukturirati tako da c vor p bude uklonjen, ali i da BSP svojstvo za preostale
c vorove ne bude narueno. A da bi se to postiglo, razlikuju se dva opta
slucaja. U prvom slucaju, kada c vor p ima samo jedno dete q, c vor p
moe se zameniti tim detetom. Preciznije, dete q se povezuje tako da bude
novo dete roditelja c vora p umesto starog deteta c vora p. Ova opta
transformacija binarnog stabla pretrage je ilustrovana na slici 6.14.
161
17
23
11
21
10
19
27
22
23
11
25
10
21
20
27
22
25
20
<p
<q
>p
q
>q
>q
q
>q
162
Stabla
17
19
23
11
10
5
27
21
19
22
25
23
11
10
27
21
20
22
25
20
163
t
>p
p
>p
treba ukloniti. U algoritmu se zatim uklanja taj c vor primenjujuci odgovarajuci postupak zavisno od broja njegove dece. Najgori slucaj je kada c vor
za uklanjanje ima dvoje dece, jer se tada u algoritmu prelazi dodatni put
dalje niz stablo da bi se pronaao najmanji c vor u desnom podstablu c vora
164
Stabla
koji se uklanja. U svakom slucaju dakle, put koji se prelazi nije dui od
visine stabla. Prema tome, kao i za operacije traenja i dodavanja c vora,
vreme izvravanja algoritma bst-delete je O(h) za stablo visine h.
Ekasnost BSP operacija. Pokazali smo da se sve tri osnovne operacije
nad binarnim stablom pretrage izvravaju za vreme O(h), pri c emu je h
visina stabla. Medutim,
visina binarnog stabla pretrage se menja kako se
165
11 10
166
Stabla
v.klju
c < u.klju
c i v.klju
c < w.klju
c. Ovo svojstvo se naziva hip
svojstvo.
Obratite panju na to da hip svojstvo implicira da je kljuc svakog c vora
v u hipu manji od kljuceva svih c vorova u podstablu sa korenom v. Pored
toga, najmanji c vor (tj. c vor sa minimalnim kljucem) mora biti koren hipa,
ali manji c vorovi ne moraju biti na manjoj dubini od vecih c vorova. Na
primer, u binarnom hipu na slici 6.21 c vorovi 4, 5 i 6 se nalaze na vecoj
dubini od c vora 7. Drugo zapaanje je da se c vorovi na svakom putu od
nekog c vora nadole niz stablo nalaze u sortiranom rastucem redosledu.
U stvari, hipovi koji zadovoljavaju prethodno navedeno hip svojstvo
nazivaju se preciznije min-hipovi. Mogli bismo isto tako da deniemo
max-hipove kod kojih je kljuc svakog c vora veci od kljuceva njegove dece.
Nema nita posebno to izdvaja min-hipove u odnosu na max-hipove. Oba
oblika hipova se ravnopravno koriste u praksi i sva zapaanja uz ocigledne
izmene vae u oba slucaja.
Hip operacije
Tipicne operacije nad hipom su uklanjanje najmanjeg c vora (i vracanje
njegovog kljuca), dodavanje novog c vora u hip, kao i stvaranje hipa od
kompletnog binarnog stabla c iji se c vorovi nalaze u proizvoljnom poretku.
U nastavku ovog odeljka govorimo o tome kako se ove operacije mogu
realizovati.
ako prosto uklonimo koren, vie necemo imati stablo. Zbog toga moramo
nekako naci novi kljuc za koren tako da stablo i dalje bude skoro puno, ali i
da hip svojstvo ne bude narueno. Ovo obezbedujemo
sledecim postupkom
167
Preciznije, pretpostavimo da je x aktuelni c vor koji naruava hip svojstvo. To znaci da je x veci od jednog ili oba svoja deteta. Kljuc c vora
x moemo zameniti kljucem jednog od njegova dva deteta, ali pri tome
moramo biti paljivi. Ako x zamenimo sa manjim od njegova dva deteta,
sigurno necemo naruiti hip svojstvo izmedu
dva ranija deteta, od kojih je
jedan sada postao roditelj drugog. Ponavljajuci ovaj postupak za pocetni
kljuc, taj kljuc c e na kraju doci ili do nekog lista ili do c vora c ija oba
deteta imaju veci kljuc. Na slici 6.22 je ilustrovan ovaj postupak uklanjanja
najmanjeg c vora iz hipa sa slike 6.21.
1
10
11 10
zameniti
stari koren
11
spustiti
novi koren
10
11
Dodavanje cvora.
Razmotrimo sada kako se moe dodati novi c vor u
binarni hip, imajuci u vidu da dobijeni hip mora biti skoro pun i da hip
svojstvo u njemu mora ostati na snazi. Jedan nacin je da se novi c vor doda
na poslednjem nivou na prvom mestu koje je sasvim levo moguce, pocinjuci
novi nivo ako je poslednji nivo trenutno popunjen.
Time je kompletnost rezultujuceg stabla sacuvana, ali hip svojstvo roditelja novog c vora moe biti narueno. Zato se opet pokuava da se to
neutralie guranjem navie novog kljuca uz stablo. To znaci da se medu
sobno zamenjuju novi kljuc aktuelnog c vora i kljuc roditelja tog c vora, ako
roditelj ima manji kljuc. Ovo zamenjivanje se ponavlja sve dok novi kljuc
ne dode
ili do korena ili do c vora c iji roditelj ima manji kljuc. Na slici 6.23
je ilustrovan postupak dodavanja c vora 2 hipu sa slike 6.21.
168
Stabla
1
11 10
podici
novi c vor
11 10
Vreme izvravanja potrebno za operaciju dodavanja c vora u hip je proporcionalno duini puta koji novi c vor prelazi od pocetnog mesta na poslednjem nivou do svog pravog mesta. Ta duina puta je ocigledno ogranicena
visinom stabla hipa, pa je vreme izvravanja jednako O(log n) za hip od n
c vorova.
Konstruisanje hipa. Pretpostavimo da je dato kompletno binarno stablo c iji su c vorovi proizvoljno razmeteni tako da njihovi kljucevi ne zadovoljavaju hip svojstvo. Operacija konstruisanja hipa sastoji se od preuredi
vanja kljuceva tog stabla tako da ono na kraju bude hip.
Jedan ocigledan nacin da se ovo postigne je da se pocne od praznog
hipa i da mu se zatim redom dodaju c vorovi datog kompletnog binarnog
stabla jedan po jedan. (Pri tome se, recimo, c vorovi datog stabla uzimaju
tokom obilaska tog stabla jednim od tri standardna metoda.) Kako svaka
operacija dodavanja c vora u hip proizvodi stablo koje je takode
binarni hip,
to c e se posle dodavanja svih c vorova na kraju dobiti traeni hip.
Medutim,
ovaj postupak nije mnogo ekasan, jer bi za stablo od n
c vorova njegovo vreme izvravanja bilo O(n log n). To je zato to se njime
obavlja n operacija dodavanja c vora, a svaka od tih operacija se izvrava
za vreme O(log n) (to smo pokazali u prethodnom odeljku). Postoji bolje
reenje za ovaj problem c ije je vreme izvravanja samo O(n). O njemu
c emo vie govoriti u narednom odeljku koje je posveceno jednoj konkretnoj
realizaciji binarnog hipa.
niza
Predstavljanje hipa pomocu
Poto je hip skoro puno binarno stablo, ono se moe ekasno predstaviti
na neobican nacin pomocu niza. Ideja ove reprezentacije je pozajmljena
od nacina na koji bi se c vorovi stabla poredali
po nivoima. To znaci da
169
a[2]
a[4]
a[8]
a[3]
a[5]
a[9]
a[6]
a[7]
a[10]
170
Stabla
// a j je roditelj
cvora a i
// a j je levo dete
cvora a i
171
Sada je lako napisati algoritam kojim se iz min-hipa od n c vorova predstavljenog nizom a uklanja najmanji c vor (koren) i vraca njegov kljuc.
// Ulaz: hip predstavljen nizom a
// Izlaz: klju
c uklonjenog korena hipa predstavljenog nizom a
algorithm heap-deletemin(a)
x = a[1];
a[1] = a[n];
n = n - 1;
heap-siftdown(a,1);
return x;
172
Stabla
4. korak
prosejati
3. korak
prosejati
2. korak
prosejati
1. korak
prosejati
10
prosejati
173
n/16 n/8
n/4
n/2
h
+1
i =1
2 h +1 i i
= 2 h +1
+1
h
i =1
2i
i =1
2i
1 2 3 4
+ + +
+
2 4 8 16
174
Stabla
1 1
1 1 1
1
1
1
1
1
+
+
+
+ +
+
+
+
+
+ .
2
4 4
8 8 8
16 16 16 16
i zato
i =1
2i
h
+1
i =1
2i
1
i =0
2i
i
i =1
2i
=2 ,
=2 .
to je trebalo pokazati.
6.5
Primene stabala
Od mnogobrojnih primena stabala u racunarstvo u ovom odeljku navodimo samo dva primera koja koristimo u daljem tekstu u poglavlju 8.
175
Redovi sa prioritetima
Red za c ekanje sa prioritetima elemenata predstavlja strukturu podataka u kojoj je svakom elementu ove strukture pridruena odredena
vanost i zato se klasikuju prema svom prioritetu. Najvii prioritet verovatno imaju sistemski procesi kao to su upravljacki programi za tastaturu
ili mrenu karticu. Zatim po vanosti dolaze korisnicki procesi u kojima se
izvravaju interaktivne aplikacije. Na kraju dolaze pozadinski procesi kao
to su neki program za pravljenje rezervnih kopija datoteka ili program za
neko dugacko izracunavanje koji je namenski predviden
da radi sa niskim
prioritetom.
Svaki proces u sistemu se zato predstavlja jednim objektom koji pored
ostalih polja koja blie opisuju proces sadri jo dva polja: jedno celobrojno
polje za identikacioni broj procesa i jedno celobrojno polje za prioritet
procesa. Operativni sistem sa deljenjem vremena rasporeduje
ove procese
176
Stabla
Q su:
1. Operacija dodavanja pq-insert(Q,x) kojom se se u red sa prioritetima Q dodaje novi element x.
2. Operacija uklanjanja pq-deletemin(Q) kojom se u redu sa prioritetima Q najpre pronalazi element najnieg prioriteta, a zatim se taj
element uklanja iz reda Q i kao dodatni rezultat vraca se prioritet
tog najmanjeg elementa.
Jedan ekasan nacin za implementaciju reda sa prioritetima je pomocu
binarnog hipa o kome smo govorili u odeljku 6.4. Osnovne operacije dodavanja i uklanjanja elemenata za red sa prioritetima odgovaraju bez izmena algoritmima heap-insert i heap-deletemin, odnosno operacijama
dodavanja i uklanjanja elemenata za binarni hip. Primetimo i da je vreme
izvravanja ovih operacija logaritamsko, odnosno O(log n) za red sa prioritetima od n elemenata.
U praksi je struktura podataka reda sa prioritetima obicno sloenija
zbog toga to treba obezbediti dodatne operacije za sloenije algoritme koji
koriste neki red sa prioritetima. Nepotpun spisak ovih dodatnih operacija
je:
pq-make(Q,a): formirati red sa prioritetima Q od datih elemenata u
nizu a.
pq-changekey(Q,x,p): promeniti prioritet datog elementa x u redu
sa prioritetima Q tako da bude jednak p.
pq-delete(Q,x): ukloniti dati proizvoljni element x iz reda sa prioritetima Q.
Ako se podsetimo strukture podataka binarnog hipa iz odeljka 6.4, moemo primetiti da se sve ove dodatne operacije mogu ekasno realizovati
ukoliko je red sa prioritetima predstavljen binarnim hipom u obliku niza.
Naime, da bismo konstruisali red sa prioritetima od datih elemenata, moemo iskoristiti algoritam heap-make koji se izvrava za linearno vreme.
Da bismo promenili prioritet datog elementa koji se nalazi negde unutar
binarnog hipa, moemo iskoristiti algoritam heap-siftdown za njegovo pomeranje nadole ako mu se prioritet povecava, ili algoritam heap-bubbleup
za njegovo pomeranje navie ako mu se prioritet smanjuje. Da bismo uklonili proizvoljni element iz binarnog hipa, moemo primeniti postupak slic an onom koji se koristi za uklanjanje minimalnog elementa. Obratite
panju na to da u svim ovim operacijama dolazi do zamenjivanja elemenata
du jednog puta u hipu, u najgorem slucaju od vrha hipa pa sve do njegovog
177
logaritamsko.
Disjunktni skupovi
U nekim primenama je potrebno da podaci budu organizovani u vie
grupa pri c emu su vane dve operacije: jedna kojom se odreduje
kojoj grupi
pripada neki podatak i druga kojom se objedinjuju dve date grupe u jednu.
U tim slucajevima dolazi do izraaja struktura podataka disjunktnih skupova.
Apstraktna struktura podataka disjunktnih skupova predstavlja n elemenata grupisanih u kolekciju od najvie n disjunktnih skupova. Svaki
skup u kolekciji sadri dakle medusobno
razlicite elemente koji su objekti
istog tipa. Ekasne operacije potrebne za rad sa ovom strukturom podataka su:
Konstruisanje skupa od jednog elementa. Operacijom ds-make(x)
se konstruie novi skup c iji je jedini c lan dati element x. Poto su
skupovi u kolekciji disjunktni, podrazumeva se da se x ne nalazi vec
u nekom drugom skupu.
Odredivanje
maticnog skupa. Operacijom ds-find(x) se dobija iden
tikacija jedinstvenog skupa u kolekciji koji sadri dati element x.
Objedinjavanje dva skupa. Za data dva elementa x i y koji pripadaju
razlicitim disjunktnim skupovima S x i S y u kolekciji, operacijom
ds-union(x,y) objedinjuju se skupovi S x i S y u jedan novi skup
koji predstavlja njihovu uniju. Preciznije, formira se treci skup S z
takav da je S z = S x S y , a kako skupovi u kolekciji moraju biti
disjunktni, skupovi S x i S y se uklanjaju iz kolekcije nakon njihovog
objedinjavanja.
Primenom operacije odredivanja
maticnog skupa datog elementa kao
rezultat se dobija identikacija (ili ime) tog skupa. Tacna priroda identikacije skupova u kolekciji disjunktnih skupova je prilicno eksibilna
pod uslovom da je dosledna. To znaci da rezultat operacija ds-find(x) i
ds-find(y) mora biti jednak ukoliko elementi x i y pripadaju istom skupu,
a razlicit u suprotnom slucaju. Obicno se svaki skup u kolekciji identikuje
nekim svojim c lanom koji se naziva predstavnik tog skupa.
178
Stabla
e
c
h
i
k
j
179
pridruiti informaciju o njegovoj visini. Zbog toga svaki c vor x sadri celobrojno polje h za visinu tog c vora. Pored toga, svaki c vor x sadri polje
klju
c u kome se nalazi odgovarajuci element skupa, kao i polje p u kome
se nalazi pokazivac na roditelja c vora x. Naravno, ovo pokazivacko polje
korena svakog stabla sadri vrednost null.
Kada se operacijom ds-make konstruie stablo od jednog c vora, pocetna
visina tog c vora je 0. Operacijom ds-find se visine c vorova stabla uopte
ne menjaju. Kod primene operacije ds-union mogu se desiti dva slucaja
zavisno od visina korena stabala koja se objedinjuju. U prvom slucaju u
kojem ovi koreni imaju nejednake visine, koren vece visine postaje roditelj
korena manje visine, ali same visine ostaju nepromenjene. U drugom
slucaju u kojem ovi koreni imaju jednake visine, proizvoljno se bira jedan
od korena da bude roditelj drugog, ali se njegova visina uvecava za jedan.
// Ulaz: objekat x sa odgovaraju
cim elementom skupa
// Izlaz:
cvor x stabla u kolekciji stabala
algorithm ds-make(x)
x.h = 0;
x.p = null;
return x;
// Ulaz:
cvor x u kolekciji stabala
// Izlaz: predstavnik (identifikacija) skupa koji sadri element x
algorithm ds-find(x)
while (x.p != null) do
x = x.p;
return x;
180
Stabla
T2
T1
181
Na osnovu ovog zapaanja sledi da ako neko stablo u kolekciji stabala koja predstavljaju disjunktne skupove ima m c vorova i visinu h, onda
mora biti m 2h . Logaritmovanjem obe strane ove nejednakosti dobijamo
h log m. Stoga vreme potrebno za prelaenje puta od nekog c vora u
tom stablu do njegovog korena je O(log m). Prema tome, ako kolekcija
disjunktnih skupova sadri ukupno n elemenata, onda je naravno m n,
pa je vreme izvravanja algoritma ds-find jednako O(log n).
Zadaci
1. Odogovorite na sledeca pitanja u vezi sa stablom na slici 6.29.
a) Koji c vorovi su listovi?
b) Koji c vor je koren?
c) Koji c vor je roditelj c vora C?
d) Koji c vorovi su deca c vora C?
e) Koji c vorovi su preci c vora E?
f) Koji c vorovi su potomci c vora E?
g) Koja je dubina c vora C?
h) Koja je visina c vora C?
A
B
D
C
E
F
J
I
M
H
K
S LIKA 6.29.
3. Nacrtajte reprezentaciju izraza (a + b) + c (d + e) + f (g + h) u obliku
stabla.
182
Stabla
183
184
Stabla
a) U kojem redosledu treba izlistati c vorove u drugoj fazi ovog algoritma preorder, inorder ili postorder?
b) Koliko je vreme izvravanja za fazu listanja?
c) Ako je ulazni niz brojeva vec sortiran, koliko je ukupno vreme
izvravanja ovog algoritma?
d) Ako se koristi binarni hip umesto binarnog stabla pretrage, koliko
je vreme izvravanja za fazu dodavanja ovog algoritma?
e) Kako treba modikovati fazu listanja u slucaju binarnog hipa?
f) Koliko je vreme izvravanja za ovu modikovanu fazu listanja?
18. Napiite algoritam heap-sort(a,n) kojim se niz a od n neuredenih
G LAVA
7
Grafovi
186
Grafovi
diktiran nacinom na koji se obavljaju operacije pretrage, dodavanja i uklanjanja c vorova u tim stablima. Medutim,
priroda mnogih vanih problema
NS
ZR
BG
SD
PO
VA
KG
K
CA
NI
KV
187
188
Grafovi
prost put ne racunajuci prvi i poslednji c vor. Graf koji nema nijedan ciklus
se naziva aciklicki graf.
189
190
Grafovi
Slobodna stabla. Povezan graf koji nema nijedan ciklus naziva se slobodno stablo. Slobodna stabla se razlikuju od korenskih stabala o kojima
smo govorili u poglavlju 6 jedino po tome to su kod slobodnih stabala svi
c vorovi ravnopravni, odnosno slobodna stabla nemaju jedan poseban c vor
koji se zove koren.
Neko slobodno stablo se lako moe transformisati u korensko stablo
ukoliko se najpre izabere proizvoljni c vor za koren i zatim se poveu svi
c vorovi na drugom kraju svih grana koje idu od tog korena, zatim poveu
svi c vorovi svih grana koje idu od prethodnih c vorova (dece korena) i tako
dalje. Slikovitiji nacin za razumevanje ovog postupka je da zamislimo da
grane u slobodnom stablu predstavljaju konce kojima su povezani c vorovi
i da se to stablo podigne da visi u vazduhu dreci ga za izabrani koren.
Tako, na primer, dva crtea na slici 7.5 predstavljaju zapravo isto stablo, tj.
isti parovi c vorova su spojeni granama, ali crte na levoj strani je slobodno
stablo i crte na desnoj strani je to stablo transformisano u korensko stablo
sa c vorom 1 kao korenom.
3
1
4
7
2
1
6
191
10
7.2
Predstavljanje grafova
Da bi se grafovi mogli ekasno koristiti u racunaru, moraju se predstaviti u programima na nacin koji obezbeduje
lako manipulisanje c voro
vima i granama grafova. Najprostija struktura podataka koja se koristi za
predstavljanje grafova je matrica susedstva. Matrica susedstva je obican
dvodimenzionalni niz c iji su brojevi redova i kolona jednaki broju c vorova
grafa. Obratite panju na to da za matricu susedstva grafa nisu bitne
oznake c vorova u grafu kojim su oni obeleeni, vec je bitan samo njihov
ukupan broj.
Matrica susedstva za usmeren graf G = (V , E) od n c vorova koji su
numerisani u proizvoljnom redosledu tako da je V = {v1 , . . ., vn } jeste dakle
n n matrica a takva da je a i, j = 1 ako postoji usmerena grana od c vora
v i do c vora v j , a u suprotnom slucaju je a i, j = 0. Na slici 7.7 je prikazan
primer usmerenog grafa i njegova matrica susedstva.
Matrica susedstva za neusmeren graf se obrazuje na slican nacin tako
to se jedna neusmerena grana izmedu
dva c vora predstavlja zapravo dvema usmerenim granama jednom usmerenom granom od prvog do drugog
c vora i drugom usmerenom granom od drugog do prvog c vora. To znaci da
je matrica susedstva neusmerenog grafa simetricna, odnosno a i, j = a j,i za
svako i i j. Pored toga, za matricu susedstva neusmerenog grafa vai da
je a i,i = 0 za svako i, jer neusmeren graf ne sadri grane-petlje od nekog
192
Grafovi
1
2
3
4
5
1
0
0
1
0
0
2
1
0
1
0
1
3
1
0
0
0
0
4
0
1
0
0
0
5
0
0
1
1
0
1
2
3
4
1
0
1
1
0
2
1
0
1
1
3
1
1
0
1
4
0
1
1
0
193
194
Grafovi
racuna svaka grana, taj zbir je 2m. Drugim recima, ukupna duina svih
listi susedstva je 2m, odnosno memorijski prostor za sve liste susedstva je
velicine (2m) = (m).
Velicina memorijskog prostora (n + m) za niz listi susedstva je mnogo
manja od (n2 ) za matricu susedstva u slucaju retkih grafova. Sa druge
strane, treba imati u vidu da potencijalni nedostatak reprezentacije nizom
listi susedstva moe biti vreme od (n) koje je potrebno za proveravanje
da li postoji odredena
grana izmedu
U poglavlju 6 smo upoznali tri nacina za obilazak binarnog stabla pomocu kojih se svi c vorovi nekog stabla mogu sistematicno posetiti kretanjem du grana stabla od c vora do c vora. Kod grafova se slican problem
tradicionalno naziva pretraga grafova i reava se primenom dva metoda
koji se nazivaju pretraga u irinu i pretraga u dubinu. Znacaj ovih postupaka pretrage grafova je u tome to se na njima zasnivaju mnogi algoritmi
za reavanje prakticnih problema koji se prirodno predstavljaju grafovima.
Jedan od takvih osnovnih algoritamskih problema za graf je pitanje
povezanosti dva c vora. Za graf G i dva njegova konkretna c vora s i t,
problem s-t povezanosti sastoji se u nalaenju ekasnog algoritma koji
daje odgovor na sledece pitanje: da li postoji put u grafu G od c vora s
do c vora t? Ovo prosto pitanje o tome da li postoji put izmedu
dva c vora
moe se proiriti pitanjem da li postoji kratak put izmedu
njih. Naime, u
mnogim primenama grafova potrebno je pronaci put izmedu
dva c vora koji
ima najmanje skokova. Kod transportnih ili komunikacionih mrea, na
primer, vrlo je vano znati najkraci put izmedu
dve tacke.
Zbog toga se uvodi pojam rastojanja izmedu
dva c vora u grafu koje
se denie da bude duina najkraceg puta izmedu
njih. (Ako ne postoji
nijedan put izmedu
dva c vora, za njihovo rastojanje se obicno uzima da je
beskonacno.) Primetimo da pojam rastojanja u grafovima ne mora odgovarati geografskom znacenju tog pojma dva c vora mogu biti na kratkom
rastojanju u grafu iako predstavljaju tacke koje geografski mogu biti vrlo
udaljene.
195
Pretraga u irinu
Moda najprostiji algoritam za odredivanje
s-t povezanosti u grafu je
1
3
2
5
8
6
9
11
Talas W1 : 2, 3, 4
4
7
10
Talas W2 : 5, 6
Talas W3 : 8, 9, 10, 7
Talas W4 : 11
196
Grafovi
W[0] = s;
p[s] = true;
i = 0;
197
// talas W0 po
cetno sadri
cvor s
// polazni
cvor s je otkriven
// broja
c talasa
cvorova
while (W[i] != ) do
// prethodni talas Wi nije prazan
W[i+1] = ;
// naredni talas Wi+1 je po
cetno prazan
for (svaki
cvor u u talasu Wi ) do
// Ispitati susede
cvora u
for (svaki
cvor v u listi susedstva G za
cvor u) do
if (p[v] == false) then
p[v] = true;
//
cvor v je novootkriven (pose
cen)
W[i+1] = W[i+1] + v;
// dodati v talasu Wi+1
i = i + 1;
return;
racija ove while petlje nije lako odrediti, pa c emo postupiti na drugaciji
nacin i analizirati iteracije prve (spoljanje) for petlje tokom izvravanja
svih iteracija while petlje u algoritmu.
Pre toga, poto se u svakoj iteraciji while petlje na pocetku konstruie
prazna lista za aktuelni talas i na kraju uvecava brojac talasa, potrebno je
odrediti ukupno vreme potrebno za ta dva koraka. To je lako oceniti ukoliko
se primeti da su talasi disjunktni skupovi c vorova tako da ih najvie moe
biti n. To znaci da je u algoritmu potrebno konstruisati najvie n praznih
listi i izvriti najvie n operacija inkrementa brojaca, pa je ukupno vreme
potrebno za to jednako O(n).
Da bismo sada ocenili vreme izvravanja spoljanje for petlje, primetimo da se svaki c vor moe naci najvie jedanput u nekom talasu. Stoga se
tokom izvravanja svih iteracija while petlje u algoritmu, telo spoljanje
for petlje izvrava najvie jedanput za svaki c vor u grafa. Pored toga, ako
n u oznacava broj suseda (stepen) c vora u, onda je broj iteracija unutranje
for petlje jednak n u . Kako se dalje jedna iteracija te unutranje for petlje
ocevidno izvrava za konstantno vreme, to je vreme izvravanja unutranje
198
Grafovi
for petlje za svaki c vor u jednako O(n u ). Ukoliko ovo vreme saberemo po
svim c vorovima grafa, dobijamo dakle ukupno vreme izvravanja spoljanje for petlje tokom izvravanja svih iteracija while petlje:
u V
O(n u ) = O
u V
n u = O(2m) = O(m) .
stabla.
199
// Ulaz:
cvor s u grafu G predstavljen listama susedstva
// Izlaz: pretraga u irinu G od s i stablo pretrage u irinu T
algorithm bfs(s)
W[0] = s;
p[s] = true;
i = 0;
T = s;
//
//
//
//
talas W0 po
cetno sadri
cvor s
polazni
cvor s je otkriven
broja
c talasa
cvorova
koren stabla T je
cvor s
while (W[i] != ) do
// prethodni talas Wi nije prazan
W[i+1] = ;
// naredni talas Wi+1 je po
cetno prazan
for (svaki
cvor u u talasu Wi ) do
// Ispitati susede
cvora u
for (svaki
cvor v u listi susedstva G za
cvor u) do
if (p[v] == false) then
p[v] = true;
//
cvor v je novootkriven (pose
cen)
W[i+1] = W[i+1] + v;
// dodati v talasu Wi+1
T = T + v + {u,v};
// dodati v i granu { u, v} stablu T
i = i + 1;
return;
1
2
1
3
5
8
6
9
11
2
7
3
5
10
4
6
10
11
200
Grafovi
Pretraga u dubinu
Drugi sistematican nacin za obilazak svih c vorova grafa je pretraga
u dubinu grafa (engl. depth-rst search, DFS) koja je uoptenje postupka
obilaska c vorova stabla u preorder redosledu. Ime ovog metoda potice od
toga to se ide sve dublje u grafu od pocetnog c vora, du nekog puta sve dok
se taj put vie ne moe nastaviti, bilo zato to poslednji c vor nema grana
koje vode od njega ili zato to sve grane od njega vode do vec posecenih
c vorova.
Pretraga u dubinu grafa podseca na postupak koji se prirodno primenjuje kada se trai izlaz iz nekog lavirinta. Ukoliko c vorove i grane
grafa zamislimo kao lavirint medusobno
povezanih prolaza kroz koje treba
pronaci izlaz od pocetnog c vora s, onda je prirodno probati prvu granu koja
vodi od s. Ako nas to vodi do nekog c vora v, onda bismo dalje sledili prvu
granu koja vodi od v. Ovaj postupak bismo zatim slicno nastavili od c vora
u koji smo doli od c vora v, sve dok moemo i ne dodemo
u corsokak,
odnosno do c vora c ije smo sve susede vec probali. Onda bismo se vratili
putem kojim smo doli do prvog c vora c ije sve susede jo nismo probali i
zatim bismo odatle ponovili isti postupak.
Primetimo da se od svakog c vora ponavlja ista aktivnost: slediti prvu
granu koja vodi do nekog susednog c vora koji nije vec posecen. Zato se
pretraga u dubinu moe najlake opisati u rekurzivnom obliku u kojem
201
// Ulaz:
cvor u u grafu G predstavljen listama susedstva
// Izlaz: pretraga u dubinu grafa G od
cvora u
algorithm dfs(u)
p[u] = true;
//
cvor u je pose
cen
// Ispitati susede
cvora u
for (svaki
cvor v u listi susedstva G za
cvor u) do
if (p[v] == false) then
dfs(v);
// rekurzivna pretraga u dubinu od
cvora v
return;
202
Grafovi
1
3
2
5
8
6
9
11
4
7
10
dfs(1)
dfs(2)
dfs(3)
dfs(6)
dfs(10)
dfs(7)
dfs(4)
dfs(9)
dfs(8)
dfs(5)
dfs(11)
203
u V
u V
u V
204
Grafovi
u i v dodaju stablu T. Drugim recima, c vor u postaje roditelj c vora
v u stablu T, jer je c vor u odgovoran za posecivanje c vora v. Tako
se u stablu T c vorovi koji su deca c vora u nalaze, sleva na desno, u
redosledu po kojem se algoritam dfs direktno poziva za te c vorove
tokom izvravanja poziva dfs(u).
Slicno proirenom algoritmu za pretragu u irinu grafa, osnovni algoritam dfs za pretragu u dubinu grafa G moe se lako proiriti kako bi se
usput konstruisalo stabla pretrage u dubinu. Ukoliko je to stablo pocetno
prazno, ono se u narednom prilagodenom
algoritmu dfs postupno proiruje
//
cvor u je pose
cen
// dodati
cvor u stablu T
// Ispitati susede
cvora u
for (svaki
cvor v u listi susedstva G za
cvor u) do
if (p[v] == false) then
dfs(v);
// rekurzivna pretraga u dubinu od
cvora v
T = T + {u,v};
// dodati granu { u, v} stablu T
return;
205
T
1
3
2
2
4
6
7
10
10
7
11
5
11
206
Grafovi
L EMA Povezane komponente bilo koja dva c vora s i t u grafu su ili identicne
ili disjunktne.
Dokaz: Tvrdenje
leme je inuitivno ocigledno kada se graf nacrta, jer
zavretka druge pretrage od t jo uvek postoji neki c vor v koji nije bio
posecen prethodnim pretragama, isti postupak se ponavlja i od c vora v,
i tako dalje sve dok se ne posete svi c vorovi grafa.
Nije teko proveriti da je vreme izvravanja ovog algoritma za nalaenje povezanih komponenti grafa od n c vorova i m grana jednako O(n + m).
U ovom obliku smo ranije izrazili vremena izvravanja algoritama za pretrage u irinu i dubinu grafa, ali to vreme je zapravo manje jer se u tim
algoritmima koriste samo c vorovi i grane povezane komponente koja sadri
pocetni c vor pretrage. Mada se pretraga grafa u prethodnom algoritmu za
nalaenje svih povezanih komponenti grafa moe ponavljati vie puta, za
207
svaku granu ili c vor obavlja se aktivnost konstantnog vremena ipak samo
u iteraciji u kojoj se konstruie povezana komponete kojoj oni pripadaju.
Zbog toga je vreme izvravanja prethodnog algoritma za nalaenje svih
povezanih komponenti grafa ukupno jednako O(n + m).
208
Grafovi
// broja
c povezanih komponenti grafa G
// Ispitati sve
cvorove grafa G
for (svaki
cvor v u nizu listi susedstva G ) do
if (p[v] == false) then
k = k + 1;
//
cvor v je u novoj komponenti grafa G
dfs-cc(v);
// nova pretraga u dubinu od
cvora v
return c;
// Ulaz:
cvor u u grafu G predstavljen listama susedstva
// Izlaz: broj c u dodeljen svim
cvorovima komponente
cvora u
algorithm dfs-cc(u)
p[u] = true;
c[u] = k;
//
cvor u je pose
cen
//
cvor u pripada aktuelnoj komponenti
209
// Ispitati susede
cvora u
for (svaki
cvor v u listi susedstva G za
cvor u) do
if (p[v] == false) then
dfs-cc(v);
// rekurzivna pretraga od
cvora v
return;
Pregledanje Interneta se onda svodi na pracenje niza grana u ovom usmerenom grafu, pri c emu je smer grana od sutinske vanosti jer obicno nije
moguce unazad pratiti hiperlinkove koji vode to date strane.
Vanost smera grana odraava se dakle na bitno drugaciji pojam povezanosti u usmerenim grafovima nego u neusmerenim grafovima. U usmerenom grafu je moguce da od c vora s postoji put do c vora t, ali ne i put
od t do s. To se onda prenosi na sloeniji pojam povezanih komponenti
usmerenog grafa i zato se posmatra svojstvo jake povezanosti usmerenih
grafova. Jaka povezanost usmerenih grafova otprilike odgovara obicnoj
povezanosti neusmerenih grafova: usmeren graf je jako povezan ako za
svaka dva njegova c vora postoji put od jednog do drugog c vora, ali i obrnut
put od drugog do prvog c vora.
Skoro svi drugi osnovni pojmovi i algoritmi za neusmerene grafove ipak
se vrlo prirodno mogu prilagoditi za usmerene grafove. Ovo specicno vai
i za algoritme za pretragu u dubinu i irinu, koji se uz neznatne izmene
mogu primeniti za usmerene grafove.
Pretraga usmerenih grafova se konceptualno ne razlikuje od pretrage
neusmerenih grafova, jer se jedino menja interpretacija pojma susedni
c vor. Kod usmerenog grafa, c vor v je susedan c voru u ako postoji usmerena grana (u, v). Ali c vor u nije automatski susedan c voru v, osim ako ne
210
Grafovi
postoji i grana (v, u). Ako se uzme u obzir ova promena interpretacije relacije susedstva, osnovni algoritmi bfs i dfs mogu se bez izmene primeniti i
za usmerene grafove. Pored toga, na identican nacin se moe pokazati da je
njihovo vreme izvravanja za usmeren graf sa n c vorova i m grana takode
2
5
8
6
9
11
4
7
10
dfs(1)
dfs(2)
dfs(4)
dfs(6)
dfs(9)
dfs(11)
dfs(8)
dfs(5)
dfs(3)
dfs(10)
dfs(7)
211
T
2
5
8
4
6
4
6
10
11
10
8
11
5
3
vih predaka u stablu. Drugim recima, grane neusmerenog grafa koje nisu
grane stabla uvek su povratne grane. Sa druge strane, grane usmerenog
grafa G u odnosu na njegovo stablo pretrage u dubinu T mogu biti jednog
od sledeca tri tipa:
1. Direktna grana. To je usmerena grana (u, v) u G koja nije grana stabla
T takva da je c vor v pravi potomak c vora u, ali nije dete c vora u u T.
Na primer, na slici 7.17 grana (4, 7) je direktna grana.
2. Povratna grana. To je usmerena grana (u, v) u G koja nije grana stabla
T takva da je c vor v predak c vora u u T (u = v je dozvoljeno). Na primer,
na slici 7.17 grana (3, 6) je povratna grana. Obratite panju na to da se
petlje, koje su dozvoljene u usmerenih grafovima, smatraju povratnim
granama.
3. Poprecna grana. To je usmerena grana (u, v) u G koja nije grana stabla
T takva da c vor v nije ni predak ni potomak c vora u u T. Drugacije
receno, poprecna grana je preostali tip usmerenih grana u G koje nisu
grane stabla T. Na primer, na slici 7.17 grana (7, 10) je poprecna grana.
Primetimo da poprecne grane mogu povezivati c vorove razlicitih stabala
u umi. Zato u optem slucaju za odredenu
poprecnu granu (u, v) ne
212
Grafovi
Pored toga, na slici 7.17 se uocava da poprecna grana (7, 10) ima
smer zdesna na levo. To nije slucajnost i vai u optem slucaju: svaka
poprecna grana ima smer zdesna na levo, c ak i u umi stabala pretrage
u dubinu.
Da bismo to pokazali, neka je (u, v) poprecna grana i posmatrajmo
poziv dfs(u). Ocevidno je c vor v potomak c vora u u stablu pretrage u
dubinu ako i samo ako je c vor v dodat u stablo izmedu
vremena pocetka
izvravanja dfs(u) i vremena zavretka izvravanja dfs(u). U tom
vremenskom intervalu, do trenutka kada se tokom izvravanja dfs(u)
proverava grana (u, v), c vor v je morao biti vec posecen, jer (u, v) nije
grana stabla. Prema tome, c vor v je morao biti posecen ranije u toku
izvravanja dfs(u) ili pre poziva dfs(u). Ali prvi slucaj je nemoguc,
jer bi u suprotnom slucaju c vor v bio potomak c vora u. Dakle, v je bio
dodat u stablo pretrage u dubinu pre c vora u, a poto se c vorovi dodaju
u redosledu sleva na desno, v mora biti levo od u.
grafovi
Usmereni aciklicki
Ako neusmeren graf nema nijedan ciklus, onda ima vrlo prostu strukturu ume: sve njegove povezane komponente su stabla. Ali za usmeren
graf je moguce da nema nijedan (usmeren) ciklus i da ima sloenu strukturu. Na primer, usmeren graf bez ciklusa sa n c vorova moe imati veliki
broj grana reda (n2 ), dok stablo (neusmeren graf bez ciklusa) sa n c vorova
ima samo n 1 granu. Usmeren graf bez ciklusa se standardno naziva
usmeren aciklicki graf i jedan primer takvog grafa je prikazan na slici 7.18.
6
213
c
e
imala smisla, dobijeni usmeren graf G mora biti aciklicki, jer ukoliko G
sadri neki ciklus C, onda ne postoji nacin da se uradi nijedan zadatak u
C. Naime, kako svaki zadatak u ciklusu C ima neki drugi zadatak koji
se prethodno mora zavriti, nijedan zadatak u C se ne moe obaviti jer se
nijedan zadatak ne moe zapoceti.
Ukoliko usmeren graf zavisnosti zadataka nema cikluse, prirodno je
onda traiti redosled tih zadataka po kojem se oni mogu obaviti tako da
sve medusobne
zavisnosti zadataka budu potovane. Takav ispravan redo
sled zadataka se naziva topoloki redosled. Preciznije, topoloki redosled
usmerenog aciklickog grafa G sa n c vorova je neki linerani poredak njegovih c vorova u nizu v1 , v2 , . . ., vn tako da za svaku granu (v i , v j ) vai i < j.
Slikovito receno, sve grane grafa G su usmerene sleva na desno ukoliko
se njegovi c vorovi nacrtaju du horizontalno linije u topolokom redosledu.
214
Grafovi
dakle redosled po kojem se oni mogu bezbedno uraditi kada treba poceti
neki zadatak, svi zadaci koji su njegovi preduslovi sigurno su vec zavreni.
U stvari, posmatrano iz apstraktnijeg ugla, topoloki redosled usmerenog
grafa predstavlja dokaz da je graf aciklicki.
L EMA Ako usmeren graf G ima topoloki redosled, onda G nema nijedan
ciklus.
Dokaz: Pretpostavimo, radi kontradikcije, da G ima jedan topoloki redosled svojih c vorova v1 , v2 , . . ., vn i da u G postoji ciklus C. Neka je v j
c vor u C sa najmanjim indeksom i neka je v i c vor u C koji neposredno
prethodi c voru v j . To znaci da je (v i , v j ) jedna od grana u G. Ali to dovodi do
protivrecnosti, jer onda mora biti tacno da je i < j zato to svaka grana za
topoloki redosled c vorova ide od c vora sa manjim indeksom prema c voru
sa vecim indeksom, kao i da je j < i zato to su v j i v i c vorovi u C i v j je
c vor u C sa najmanjim indeksom.
Prema tome, postojanje topolokog redosleda usmerenog grafa je dovoljan uslov da taj graf nema cikluse. Taj kriterijum moe ponekad biti vrlo
koristan, jer se vizuelno moe lako pokazati da je graf aciklicki. Na primer,
nije odmah jasno to da graf na slici 7.18 nema cikluse, ali ako se isti graf
prikae u topolokom redosledu kao na slici 7.21, onda je to ocigledno poto
sve grane idu sleva na desno.
Nalaenje topolokog redosleda. Tee pitanje za usmeren aciklicki
graf je obrnuto od onog na koje odgovor daje poslednja lema: da li svaki
usmeren aciklicki graf ima topoloki redosled? Ako je to slucaj, dodatno
bi bilo vrlo korisno imati ekasan algoritam za nalaenje jednog topolokog redosleda datog usmerenog aciklickog grafa, jer onda bi se za svaku
relaciju zavisnosti nad skupom zadataka bez ciklusa mogao ekasno naci
215
redosled po kojem se ti zadaci mogu bezbedno obaviti. Odgovor na prethodno pitanje je potvrdan i, u stvari, to c emo pokazati na konstruktivan
nacin. Drugim recima, pokazacemo jedan ekasan algoritam kojim se za
dati usmeren aciklicki graf pronalazi njegov topoloki redosled.
Algoritam za nalaenje topolokog redosleda usmerenog aciklickog grafa G slican je algoritmu za nalaenje povezanih komponenti neusmerenog
grafa, osim to nije svejedno koja pretraga grafa se koristi nego se mora
koristiti pretraga u dubinu. Opti pristup je dakle da se najpre izabere
proizvoljni c vor s u G i da se zatim pretragom u dubinu od c vora s posete
svi c vorovi u G koji su dostupni od tog pocetnog c vora. Isti postupak se
zatim ponavlja od proizvoljnog c vora t koji nije bio posecen prethodnom
pretragom od c vora s, ukoliko se takav c vor t uopte moe naci. Ako posle
zavretka druge pretrage od t jo uvek postoji neki c vor v koji nije bio
posecen prethodnim pretragama, isti postupak se ponavlja i od c vora v, i
tako dalje sve dok se ne posete svi c vorovi grafa. Na ovaj nacin se indukuje
uma stabala pretrage u dubinu sa korenima s, t i tako dalje.
Za razumevanje ovog algoritma je najvanija c injenica to da jedno stablo pretrage u dubinu u sutini predstavlja stablo rekurzivnih poziva algoritma dfs od pocetnog poziva tog algoritma za neki c vor. Kako se za
svaki c vor v pocetak i zavretak poziva dfs(v) odigravaju u diskretnim
vremenskim trenucima, to se na vremenskoj osi moe pratiti izvravanje
celokupnog prethodno opisanog postupka za nalaenje topolokog redosleda. Na primer, na slici 7.22 su na vremenskoj osi prikazani intervali
trajanja svih poziva algoritma dfs tokom viestruke pretrage u dubinu
grafa na slici 7.19 od c vora b i od c vora a. Pravougaoni oblik c vorova na toj
slici ukazuje na interval izmedu
pocetka i zavretka poziva algoritma dfs
za odgovarajuci c vor.
Podsetimo se da se tokom (viestruke) pretrage u dubinu grafa algoritam dfs poziva tacno jedanput za svaki c vor grafa. Zbog toga je vreme
Pretpozavretka poziva dfs(v) za svaki c vor v nedvosmisleno odredeno.
216
Grafovi
e
1
9 10
217
// l je po
cetno prazna lista
// Ispitati sve
cvorove grafa G
for (svaki
cvor v u nizu listi susedstva G ) do
if (p[v] == false) then
dfs-to(v);
// nova pretraga u dubinu od
cvora v
return l;
//
cvor u je pose
cen
// Ispitati susede
cvora u
for (svaki
cvor v u listi susedstva G za
cvor u) do
if (p[v] == false) then
dfs-to(v);
// rekurzivna pretraga od
cvora v
list-insert(u,null,l);
return;
// dodati
cvor u na po
cetak liste l
218
Grafovi
Vreme izvravanja algoritma topological-ordering za topoloki redosled usmerenog aciklickog grafa G sa n c vorova i m grana asimptotski je
ocigledno jednako O(n + m).
Zadaci
1. Za usmeren graf G na slici 7.23 odgovorite na sledeca pitanja.
a) Koliko c vorova i grana ima graf G?
b) Navedite sve proste puteve od a do b u G.
c) Navedite sve susede c vora b u G.
d) Navedite sve cikluse od c vora b u G.
G
b
a
c
f
e
d
S LIKA 7.23.
219
8. Cvor
s usmerenog grafa G sa n c vorova naziva se ponor ukoliko je ulazni
stepen c vora s jednak n 1 i njegov izlazni stepen jednak 0. Drugim
recima, za svaki c vor v u G razlicit od s postoji grana (v, s) i ne postoji
grana (s, v). Napiite algoritam vremenske sloenosti O(n) koji odreduje
220
Grafovi
G
b
a
c
h
e
g
d
f
S LIKA 7.24.
S LIKA 7.25.
a) Pokaite da je svako slobodno stablo jedan bipartitan graf.
b) Napiite ekasan algoritam kojim se proverava da li je dati neusmeren graf bipartitan. (Savet: Koristite pretragu u irinu.)
13. Za usmeren graf G na slici 7.24, kao i za njegovu neusmerenu verziju,
odgovorite na sledeca pitanja.
a) Navedite sve rekurzivne pozive algoritma dfs za graf G koji se
dobijaju za pocetni poziv dfs(a) i uvlacenjem naznacite njihov
odnos. Pretpostavite da ako treba izabrati neki c vor izmedu
vie
njih, onda se od mogucih bira prvi c vor po abecednom redosledu.
b) Konstruiite odgovarajuce stablo (umu) pretrage u dubinu.
c) Klasikujte sve grane grafa G u odnosu na konstruisano stablo
prema tome da li predstavljaju grane stabla, direktne grane, povratne grane ili poprecne grane.
221
222
Grafovi
b) Dokaite indukcijom po broju c vorova grafa da G ima topoloki
redosled. (Savet: U dokazu indukcijskog koraka uocite graf G {v}
dobijen uklanjanjem c vora v bez ulaznih grana.)
c) Koristeci indukcijski dokaz napiite drugi algoritam za nalaenje
topolokog redosleda grafa G.
21. Prost put u grafu je Hamiltonov ako prolazi kroz sve c vorove grafa. Napiite ekasan algoritam kojim se odreduje
da li dati usmeren aciklicki
G LAVA
8
Teinski grafovi
odgovarajuci.
Graf moe predstavljati, na primer, neku racunarsku mreu (kao to je
Internet) sa racunarima kao c vorovima tog grafa i komunikacionim linkovima izmedu
pojedinih racunara kao granama tog grafa. Ako je cilj naci
najbri nacin za usmeravanje paketa podataka izmedu
neka dva racunara
u mrei, onda se to svodi na nalaenja najkraceg puta izmedu
dva c vora
koji oznacavaju date racunare u grafu. Ali u ovom slucaju nije prirodno
da sve grane grafa budu ravnopravne poto su neke veze u mrei racunara obicno mnogo bre od drugih neke grane mogu predstavljati spore
telefonske linije, dok druge predstavljaju brze opticke veze.
Da bismo slicne probleme modelirali grafovima, u ovom poglavlju proirujemo pojam grafa i posmatramo (usmerene ili neusmerene) grafove
c ije grane imaju pridruenu numericku vrednost. Ove vrednosti dodeljene
granama nazivaju se teine grana, a odgovarajuci grafovi teinski grafovi.
224
Teinski grafovi
8.1
Osnovni pojmovi
Teinski graf je obican (usmeren ili neusmeren) graf c ije sve grane
imaju teinu u obliku numericke vrednosti. Primetimo da su teine grana
neutralni naziv za brojeve koji su pridrueni granama, ali u prakticnim
primenama ti brojevi mogu predstavljati razne druge zicke velicine kao
to su duina, vreme, cena, brzina ili neka druga mera odnosa dva c vora.
Primer jednog teinskog grafa je prikazan na slici 8.1.
a
100
200
120
350
300
da obican graf moemo smatrati teinskim grafom c ije su sve teine grana
jednake (na primer, moemo uzeti da su sve teine jednake 1), jasno je da
svi osnovni pojmovi za obicne grafove imaju smisla i za teinske grafove.
Cak
se i dve reprezentacije obicnih grafova u racunarima, matrica susedstva i niz listi susedstva, mogu lako prilagoditi za predstavljanje teinskih grafova. Podsetimo se da elementi matrice susedstva za obican graf
mogu biti brojevi 1 ili 0 c ime se odreduje
da li grana izmedu
stablo
8.2. Minimalno povezujuce
a
b
c
d
200
b
100
80
225
c
120
d
350
300
Niz listi susedstva za predstavljajnje obicnog grafa moe se lako prilagoditi za predstavljajnje teinskog grafa ukoliko se teina neke grane
e prikljuci elementu povezane liste koji odreduje
drugi kraj grane e. Na
b 100
c 120
80
d 300
d 350
b
c
a 200
stablo
8.2 Minimalno povezujuce
Da bismo uveli pojam minimalnog povezujuceg stabla nekog teinskog
grafa, razmotrimo najpre jedan praktican primer. Pretpostavimo da neka
kompanije ima vie predstavnitva u razlicitim gradovima koje treba da
povee u jedinstvenu mreu. Da bi povezala sva svoja predstavnitva u
integrisanu mreu, za kompaniju je vano da odredi najmanju cenu iznajmljivanja telekomunikacionih linija izmedu
svojih predstavnitava.
Ovaj problem se moe predstaviti teinskim grafom sa c vorovima koji
oznacavaju predstavnitva kompanije i granama sa numerickim vrednostima koje odgovaraju cenama zakupljenih prenosnih veza izmedu
pojedinih predstavnitava. Na slici 8.4(a) je prikazan hipoteticki graf koji predstavlja sve moguce zakupljene linije izmedu
odgovarajucih predstavnitava
i njihove cene.
226
Teinski grafovi
20
10
20
10
2
5
3
6
d
(a)
3
6
d
(b)
stablo
8.2. Minimalno povezujuce
227
228
Teinski grafovi
V2
v1
v1
e
v2
v2
stablo
8.2. Minimalno povezujuce
229
Kruskalov algoritam
Radi konstruisanja minimalnog povezujuceg stabla teinskog grafa G =
(V , E), u Kruskalovom algoritmu se polazi od ume (V , ) koja se sastoji od
svih c vorova grafa G i nema nijednu granu. Drugim recima, pocetna uma
se sastoji od stabala koja c ine pojedinacni c vorovi sami za sebe.
U algoritmu se zatim redom ispituju grane grafa u rastucem redosledu
njihovih teina. U svakom koraku kako se dolazi do neke grane e u ovom
redosledu, proverava se da li e proizvodi ciklus ukoliko se doda granama
koje su do tada izabrane za minimalno povezujuce stablo. Tacnije, ako
grana e povezuje dva c vora iz dva razlicita stabla do tada konstruisane
ume, onda se e dodaje skupu izabranih grana i ta dva stabla se objedinjuju
u jedno stablo. U suprotnom, ako e povezuje dva c vora iz istog stabla do
tada konstruisane ume, onda se e odbacuje jer bi proizvela ciklus. Na
slici 8.6 je prikazano postupno izvravanje Kruskalovog algoritma za graf
na slici 8.4(a).
(0)
(1)
(2)
f
2
b
1
(3)
(4)
(5)
b
1
b
1
230
Teinski grafovi
L EMA Kruskalov algoritam konstruie minimalno povezujuce stablo povezanog teinskog grafa G.
Dokaz: Pretpostavimo privremeno da su sve teine grana u grafu G =
(V , E) medusobno
razlicite, a na kraju c emo pokazati kako moemo elimi
nisati ovu pretpostavku.
Razmotrimo bilo koju granu e = { u, v} koja je u Kruskalovom algoritmu
dodata umi (stablu) T u k-tom koraku. Neka je A skup svih c vorova
povezanih putem sa c vorom u u T i B skup svih c vorova povezanih putem
sa c vorom v u T u trenutku neposredno pre dodavanja grane e. Ocigledno
su A i B disjunktni skupovi, jer bi se u suprotnom slucaju dodavanjem
grane e obrazovao ciklus u T.
Neka je V1 = A i V2 = V A, pa je u V1 i v V2 . Drugim recima, V1 i V2
su neprazni disjunktni podskupovi c vorova takvi da je V = V1 V2 . Pored
toga, nijedna druga grana pre k-tog koraka nije imala jedan kraj u V1 i
drugi kraj u V2 , jer bi u suprotnom takva grana bila vec dodata poto ne
obrazuje ciklus u T. Zato je e grana najmanje teine izmedu
V1 i V2 u grafu
G, a uz to je i jedinstvena s tom osobinom jer su sve teine grana razlicite.
Prema svojstvu podele grafa dakle, grana e pripada svakom povezujucem
stablu grafa G.
Stoga ukoliko jo pokaemo da je zavrna uma T koja je rezultat Kruskalovog algoritma zapravo povezujuce stablo grafa G, onda c e to automatski znaciti da je T ujedno i minimalno povezujuce stablo. Ocigledno je
da T ne sadri nijedan ciklus, jer se u Kruskalovom algoritmu eksplicitno
odbacuju grane koje obrazuju neki ciklus. Isto tako, zavrna uma T ne
moe se sastojati od dva nepovezana disjunktna stabla T i T (ili vie
njih), jer je graf G povezan i postoji bar jedna grana izmedu
T i T , pa
c e se u algoritmu od tih grana dodati u T ona prva na koju se naide
u
rastucem redosledu teina.
Ostalo je jo da pokaemo optimalnost Kruskalovog algoritma u slucaju
kada neke grane grafa G imaju jednake teine. U tom slucaju zamislimo da
smo od grafa G obrazovali novi teinksi graf G tako to smo teinama svih
grana sa jednakim teinama u G dodali razlicite ekstremno male vrednosti
kako bi njihove nove teine bile medusobno
razlicite. Takve vrednosti uvek
stablo
8.2. Minimalno povezujuce
231
strukturu, ti grafovi imaju ista povezujuca stabla. Ali ako bi stara cena
stabla T bila veca od stare cene nekog drugog povezujuceg stabla grafa G,
onda za dovoljno male promene teina grana ne bi cena tog drugog stabla
mogla da se uveca toliko da stablo T bude bolje sa novim teinama u G . To
pokazuje da je T minimalno povezujuce stablo i za graf G. Kako su teine
razlicite, Kruskalov algoritam c e prema
grana novog grafa G medusobno
prethodnom delu dokaza konstruisati njegovo minimalno povezujuce stablo T koje je optimalno i za originalni graf G.
Implementacija Kruskalovog algoritma. U Kruskalovom algoritmu
se polazi od ume stabala koja se sastoje samo od pojedinacnih c vorova
grafa bez ijedne grane. Ova pocetna trivijalna stabla u umi se zatim
proiruju dodavanjem grana koje nikad ne proizvode ciklus.
U realizaciji Kruskalovog algoritma potrebno je zato voditi priciznu evideniciju o tome koji disjunktni podskupovi c vorova grafa pripadaju kojim
stablima u umi koja se postupno transformie u minimalno povezujuce
stablo. Pored toga, kako se neka grana e = { u, v} ispituje u svakom koraku,
potrebno je ekasno odrediti kojim stablima u umi pripadaju njeni krajevi
u i v. Ako su ova stabla razlicita, onda se grana e dodaje jer ne proizvodi
ciklus i dva odgovarajuca skupa c vorova se objedinjuju u jedan skup koji
odgovara novom stablu u umi. Ako krajevi u i v grane e pripadaju istom
stablu, onda se grana e preskace jer bi proizvela ciklus u tom stablu.
Za ekasnu realizaciju Kruskalovog algoritma potrebno je dakle tacno
ono to obezbeduje
struktura podataka disjunktnih skupova o kojoj smo
232
Teinski grafovi
Obrazovati obi
can niz od grana grafa G sa pridruenim teinama;
Preurediti taj niz u rastu
cem redosledu teina grana.
Neka je e 1 , e 2 ,... , e m dobijeni niz sortiranih grana;
T =
// uma T je po
cetno bez grana
// ... ali svi
cvorovi su njena stabla
for (svaki
cvor v u grafu G ) do
ds-make(v);
for i = 1 to m do
Neka je e i = { u, v};
a = ds-find(u);
b = ds-find(v);
if (a != b) then
T = T + ei;
ds-union(a,b);
//
//
//
//
//
return T;
Vreme izvravanja prve for petlje u kojoj se inicijalizuje n disjunktnih skupova iznosi O(n), jer za inicijalizaciju jednog skupa treba
konstantno vreme.
Telo druge for petlje se izvrava m puta, a svaka iteracija se izvrava
za vreme O(log n) ukoliko su operacije sa disjunktnim skupovima
realizovane onako kako smo to opisali na strani 177. Prema tome,
ukupno vreme izvravanja druge for petlje je O(m log n).
Kako za povezan graf vai da je m n 1, to je n = O(m). Takode,
poto uvek vai m n2 , to je log m = O(log n). Uzimajuci sve u obzir dakle,
ukupno vreme izvravanja algoritma mst-kruskal je:
O(m) + O(m log m) + O(n) + O(m log n) =
O(m) + O(m log n) + O(m) + O(m log n) = O(m log n) .
stablo
8.2. Minimalno povezujuce
233
Primov algoritam
U Kruskalovom algoritmu se pohlepno biraju grane najmanje teine
bez mnogo obzira na to u kakvom odnosu stoje sa prethodno izabranim
granama, osim to se pazi da se ne formira ciklus. Na ovaj nacin se dobija uma stabala koja se ire prilicno nasumicno dok se ne stope u jedno
zavrno stablo.
Nasuprot tome, u Primovom algoritmu se dobija minimalno povezujuce
stablo tako to se pocetno najprostije stablo postupno proiruje. To pocetno
stablo je neki proizvoljno izabran c vor s, a u svakom koraku se delimicno
konstruisanom stablu dodaje novi c vor na drugom kraju grane najmanje
teine koja izlazi iz tog stabla. Preciznije, u svakom koraku se obrazuje
podskup c vorova S V nad kojim je delimicno konstruisano povezujuce
stablo. Pocetno je S = { s} i zatim se S postupno uvecava za jedan c vor v
kojim se minimizuje cena uvecanja skupa S:
min w(e).
e={u,v}
uS,vS
S
v
234
Teinski grafovi
(0)
(1)
(2)
a
f
a
f
(3)
(4)
(5)
a
f
a
f
8
2
b
1
stablo
8.2. Minimalno povezujuce
235
236
Teinski grafovi
e = pq-deletemin(Q);
Neka je e = { u, v};
T = T + e ; // granu e dodati granama delimi
cnog stabla
S = S + v; // drugi kraj v grane e dodati
cvorovima
// delimi
cnog stabla
for (svaka grana e = {v, x} za koju x S ) do
pq-insert(Q,(w(e), e ));
return T;
8.3 Najkraci
Grafovi se c esto koriste za modeliranje mrea u kojima se prelazi neki
put od jedne tacke do druge na primer, od jednog grada do drugog preko
puteva kojima su gradovi povezani ili od jednog racunara do drugog preko
komunikacionih linkova kojima su racunari povezani. Zbog toga je jedan
od osnovnih algoritamskih problema za grafove nalaenje najkracih puteva
izmedu
c vorova u grafu.
Neka je dat povezan teinski graf G = (V , E). U vezi sa problemom
nalaenja najkracih puteva u grafu G prirodnije je podrazumevati da numericke vrednosti pridruene granama grafa predstavljaju njihovu duinu,
a ne teinu. (Naravno, duina ili teina mogu stvarno predstavljati neto
sasvim trece, recimo, vreme ili cenu.) Tome c emo se prilagoditi u izlaganju
8.3. Najkraci
237
k
1
i =1
(e i ) .
Dijkstrin algoritam
Podsetimo se da se problem nalaenja najkracih puteva od jednog c vora
u specijalnom slucaju obicnog grafa, kod koga su sve grane jednake duine,
moe reiti pretragom u irinu. U Dijkstrinom algoritmu se ovaj pristup
generalizuje za teinski graf tako to se na odreden
nacin primenjuje ponderisana pretraga u irinu od datog c vora. Radi jednostavnijeg izlaganja
Dijkstrinog algoritma, najpre c emo pojednostaviti problem i pretpostaviti
da se trae samo duine najkracih puteva od c vora s do svih ostalih c vorova
u grafu same najkrace puteve je u algoritmu lako rekonstruisati.
Sutinska odlika Dijkstrinog algoritma je da se najkraci putevi od datog c vora s do ostalih c vorova otkrivaju u rastucem redosledu duina najkracih puteva. U algoritmu se postupno konstruie skup c vorova S takav
da je za svaki c vor u u S odredena
duina najkraceg puta d(u) od c vora s.
238
Teinski grafovi
G
S
reeni
c vorovi
s
specijalni
put
velicina
(v) = min d(u) + (e).
e={u,v}
u S
Nakon toga, radi proirenja skupa S, bira se c vor x za koji se ova velicina
minimizuje, odnosno bira se c vor x takav da je (x) = minvV S (v). Taj
c vor se dodaje skupu S i za njegovu duinu najkraceg puta d(x) uzima se
(x). Skup S se proiruje na ovaj nacin za jedan c vor sve dok se ne obuhvate
svi c vorovi iz skupa V grafa G.
Verovatno nije odmah jasno zato je ovaj postupak ispravan. Zato da
bismo ga bolje razumeli, posmatrajmo jedno moguce stanje izvravanja
Dijkstrinog algoritma koje je prikazano na slici 8.10.
1
4
x
2
2
3
8.3. Najkraci
239
x
u
s
v
240
Teinski grafovi
da je tvrdenje
tacno kada S ima k 1 c vorova i pokaimo da ono vai i za
8.3. Najkraci
241
s
d(s) = 0
d(x) = 11
d(v) = 20
d(v) = 17
s
d(s) = 0
242
Teinski grafovi
20
10
7
5
3
2
4
4
6
iteracija
d(1)
d(2)
d(3)
d(4)
d(5)
d(6)
{1}
20
10
{1, 6}
20
10
12
11
{1, 3, 6}
17
10
12
11
{1, 3, 5, 6}
17
10
12
11
{1, 3, 4, 5, 6}
13
10
12
11
{1, 2, 3, 4, 5, 6}
13
10
12
11
putevi izmedu
8.4. Najkraci
svih cvorova
243
putevi izmedu
8.4 Najkraci
svih cvorova
Problem najkracih puteva izmedu
svih c vorova sastoji se u nalaenju
najkracih puteva izmedu
svaka dva c vora u teinskom grafu G. Ako u
grafu nema negativnih grana, onda se ovaj problem moe reiti viestrukim izvravanjem Dijkstrinog algoritma od svakog c vora grafa. Ukoliko
G ima n c vorova i m grana, vreme potrebno za ovo reenje je O(nm log n),
pod pretpostavkom da je graf G povezan i predstavljen nizom listi susedstva. U najgorem slucaju kada je ulazni graf gust, odnosno m = (n2 ), ovo
vreme iznosi O(n3 log n). U najboljem slucaju kada je graf redak, odnosno
m = (n), ovo vreme iznosi O(n2 log n).
U ovom odeljku c emo pokazati drugi nacin za reavanje problema nalaenja najkracih puteva izmedu
svih c vorova koji se moe primeniti c ak
i u slucaju kada graf sadri grane negativne duine (ali ne i cikluse negativne duine). Taj nacin se po svom autoru naziva Flojdov algoritam
i pripada kategoriji algortama dinamickog programiranja. U ovom algoritmu se pretpostavlja da je ulazni graf predstavljen matricom susedstva i
njegovo vreme izvravanja je O(n3 ).
244
Teinski grafovi
0,
D(i, j, 0) = (v i , v j ),
ako i = j
ako (v i , v j ) E
inace
a za k = 1, 2, . . ., n,
D(i, j, k) = min D(i, j, k 1), D(i, k, k 1) + D(k, j, k 1) .
prolazi kroz cvorove iz Vk . Ako bi postojao takav kraci put koji ne sadri
c vor vk , tada bi to protivrecilo deniciji D(i, j, k 1), a ako bi postojao takav
kraci put koji sadri c vor vk , tada bi to protivrecilo deniciji D(i, k, k 1) ili
putevi izmedu
8.4. Najkraci
svih cvorova
245
D(k, j, k 1). U stvari, lako se proverava da ovo vai i ukoliko postoje grane
grafa G negativne duine, ali ne i ciklusi negativne duine.
Na slici 8.14 je ilustrovano izracunavanje duine D(i, j, k) prema prethodnim formulama. Na toj slici, krajnji c vorovi v i i v j mogu pripadati ili
ne pripadati skupu Vk koji je predstavljen sivim delom grafa G.
G
vi
V Vk
Vk
vj
246
Teinski grafovi
Obratite panju na to da se u Flojdovom algoritmu izracunava trodimenzionalna matrica D(i, j, k), ali to se moe zamisliti kao izracunavanje
niza dvodimenzionalnih matrica D k (i, j) za k = 1, 2, . . ., n. Matrica D k se
izracunava u k-toj iteraciji prve od tri ugnjedene
for petlje. U nastavku
20
f
10
2
5
1
4
3
D0
10
20
10
20
D1
D2
10
20
10
11
12
20
28
28
10
10
11
31
12
32
20
28
20
28
31
32
D3
D4
10
11
11
12
10
11
11
12
10
10
11
10
11
10
11
11
12
10
12
10
D5
D6
10
11
11
12
10
11
11
12
10
10
11
11
11
11
12
12
putevi izmedu
8.4. Najkraci
svih cvorova
247
O n3 . To sledi na osnovu toga to je u algoritmu vremenski dominantno
for petlji.
izvravanje trostruko ugnjedenih
Zadaci
1. Odredite sva povezujuca stabla grafa G na slici 8.15.
G
S LIKA 8.15.
248
Teinski grafovi
putevi izmedu
8.4. Najkraci
svih cvorova
249
G
25
a
10
10
30
40
15
23
20
e
17
S LIKA 8.16.
9. Odredite vreme izvravanja algoritma dijkstra ukoliko se koristi matrica susedstva za ulazni graf G, povezane liste za skupove S i V S,
kao i niz d za duine najkracih puteva od datog c vora s.
10. Napiite i analizirajte algoritam za problem najkracih puteva od jednog
c vora u teinskom usmerenom aciklickom grafu.
11. Napiite Flojdov algoritam u kome se koristi samo jedna dvodimenzionalna matrica za duine najkracih puteva izmedu
svaka dva c vora grafa
sa nenegativnim granama.
12. Voralov algoritam. Problem povezanosti obicnog (neteinskog) usmerenog grafa G sastoji se od utvrdivanja
da li postoji put izmedu
svaka
dva c vora. Ako je graf G predstavljen matricom susedstva M, problem
povezanosti grafa G svodi se na izracunavanje druge matrice P takve da
je P(i, j) = 1 ukoliko postoji put od c vora v i do c vora v j i P(i, j) = 0 u suprotnom slucaju. Napiite i analizirajte algoritam kojim se izracunava
matrica P. (Savet: Modikujte Flojdov algoritam.)
Literatura
[1]
Alfred V. Aho, John E. Hopcroft, and Jeffrey D. Ullman. Data Structures and Algorithms. Addison-Wesley, 1987.
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
Indeks
A
aciklicki graf, 188
algoritam, 4
analiza, 8, 2128
denicija, 6
dizajn, 8, 18
funkcija vremena izvravanja, 24
ispravnost i ekasnost, 17
iterativni, 108
izlaz, 6
jedinicna instrukcija, 24
jednostavnost i jasnoca, 17
osnovne konstrukcije, 25
pojednostavljena analiza, 46
primeri, 2840
pseudo jezik, 1113
rekurzivni, 108
ulaz, 6
velicina, 23
vreme izvravanja, 24, 43
najgori slucaj, 24
vremenska sloenost, 24
asimptotska notacija, 5458, 66
O-zapis, 54
-zapis, -zapis, o-zapis, 58
asimptotsko vreme izvravanja, 43
B
bencmark podaci, 27
binarna pretraga, 48
binarni hip, 165
hip svojstvo, 166
operacije, 166
dodavanje c vora, 167
konstruisanje hipa, 168
uklanjanje najmanjeg c vora, 166
predstavljanje pomocu niza, 168
binarno stablo, 151
D
Dijkstrin algoritam, 237
implementacija, 240
poputanje, 241
reeni c vorovi, 237
specijalni put, 237
disjunktni skupovi, 177
operacije
konstruisanje skupa od jednog elementa, 177
objedinjavanje dva skupa, 177
odredivanje
maticnog skupa, 177
E
ekasnost BSP operacija, 164
ekscentricnost c vora, 221
Euklidov algoritam, 60
254
Indeks
rekurzivni, 110
F
Fibonacijev niz brojeva, 111
Flojdov algoritam, 243
funkcija vremena izvravanja algoritma,
24
G
graf, 186
aciklicki, 188
ciklus, 188
incidentna grana, 186
minimalno povezujuce stablo, 225
neusmeren, 187
bipartitan, 219
obilazak, 194
podgraf, 189
povezan, 189
povezana komponenta, 189
povezane komponente
nalaenje, 205
povezujuce stablo, 227
minimalno, 227
predstavljanje, 191
liste susedstva, 192
matrica susedstva, 191
pretraga u irinu, 195
analiza, 197
implementacija, 196
stablo, 198
pretraga u dubinu, 200
analiza, 202
stablo, 203
prost put, 188
Hamiltonov, 222
put, 188
duina, 188
rastojanje c vorova, 194
redak, 192
s-t povezanost, 194
stepen c vora, 187, 188
izlazni, 188
ulazni, 188
susedi c vora, 187
susedni c vorovi, 186
uma, 191
teinski, 223
usmeren, 187
H
Hanojske kule, 113
hip, Vidi binarni hip
hip operacije, 166
hip svojstvo, 166
I
implementacija pretrage u irinu, 196
incidentna grana, 186
invarijanta petlje, 20
inverzija niza, 142
iterativni algoritam, 108
izlazni stepen c vora, 188
J
jaka povezanost, 209
jako povezan graf, 190
jedinicna instrukcija, 24
jedinicni model sloenosti, 9
K
kompletno binarno stablo, 165
korensko stablo, 145
kruni turnir, 142
Kruskalov algoritam, 229
implementacija, 231
kursor, 95
L
lista, 88
dvostruko povezana, 93
implementacija
pomocu nizova, 94
pomocu pokazivaca, 89
liste susedstva, 192
M
maksimalna suma podniza, 2934
kvadratni algoritam, 29
linearni algoritam, 75
rekurzivni algoritam, 142
Indeks
matrica, 79
matrica susedstva, 191
metod nagadanja,
132
N
najgori slucaj izvravanja algoritma, 24
najkraci putevi izmedu
svih c vorova, 243
Flojdov algoritam, 243
najkraci putevi od jednog c vora, 236
Dijkstrin algoritam, 237
najmanji element niza, 2829
najveci element niza, 1415
najveci zajednicki delilac, 19
neprekidni podniz, 30
neuporedive funkcije, 60
neusmeren graf, 187
bipartitan, 219
matrica susedstva, 191
niz listi susedstva, 193
niz, 73
O
obilazak binarnog stabla, 153
inorder, 153
postorder, 154
preorder, 153
obilazak grafa, 194
obilazak usmerenog grafa, 209
opti metod, 134
osnovne algoritamske konstrukcije, 25
osnovne strukture podataka, 71101
P
podaci, 2
podgraf, 189
pojednostavljena analiza algoritama, 46
ponor, 219
poputanje, 241
povezan graf, 189
255
R
racunar sa proizvoljnim pristupom memoriji (RAM), 9
racunarski model, 810
racunarski problem, Vidi problem
randomizirani algoritam, 27
rastojanje c vorova, 194
red sa prioritetima, 175
implementacija
binarni hip, 176
red za c ekanje, 98
redak graf, 192
rekurentne jednacine, 116, 128
metod nagadanja,
132
256
S
s-t povezanost, 194
skup, 104
skup povezanih komponenti, 205
nalaenje, 205
slobodno stablo, 190
sortiranje niza, 34
sortiranje izborom (select-sort), 39
sortiranje objedinjavanjem (mergesort), 117
analiza algoritma, 120
sortiranje razdvajanjem (quick-sort),
122
analiza algoritma, 126
medijana, 124
pivot, 123
sortiranje umetanjem (insert-sort),
37
sortiranje upotrebom hipa (heap-sort),
184
sortiranje zamenjivanjem (bubble-sort),
34
sportski navijac, 67
srpska zastava, 67
stabilno vezivanje, 82
stablo, 145
c vorovi, 145
braca (sestre), 147
dete, 146
dubina, 148
listovi, 147
potomak, 148
predak, 148
roditelj, 146
spoljanji, 147
unutranji, 147
visina, 148
binarno, 151
obilazak, 153
binarno stablo pretrage, 155
denicija
formalna, 146
rekurzivna, 147
Indeks
grane, 145
koren, 146
korensko, 145
podstablo, 148
reprezentacija
pomocu listi dece c vorova, 149
pomocu sasvim levog deteta i desnog brata c vorova, 150
slobodno, 190
stepen c vora, 182
struktura podataka, 148
visina, 148
stablo pretrage u irinu, 198
stablo pretrage u dubinu, 203, 210
direktna grana, 211
grana stabla, 204, 210
poprecna grana, 211
povratna grana, 204, 211
stablo rekurzije, 129
stek, 96
operacija pop, 96
operacija push, 96
potkoracenje, 97
prazan, 97
prekoracenje, 97
pun, 97
vrh, 96
stepen c vora, 182, 187, 188
strukture podataka
disjunktni skupovi, 177
lista, 88
matrica, 79
niz, 73
osnovne, 71
red sa prioritetima, 175
red za c ekanje, 98
skup, 104
stablo, 148
stek, 96
susedi c vora, 187
susedni c vorovi, 186
svojstvo ciklusa grafa, 248
svojstvo podele grafa, 227
uma, 191
Indeks
T
teinski grafovi, 223247
ternarna pretraga, 66
tipicne funkcije vremena izvravanja, 52
topoloki redosled, 213
nalaenje, 214
U
ulazni stepen c vora, 188
usmeren aciklicki graf, 212
topoloki redosled, 213
nalaenje, 214
usmeren graf, 187
aciklicki, 212
jaka povezanost, 209
jako povezan, 190
matrica susedstva, 191
niz listi susedstva, 193
obilazak, 209
ponor, 219
pretraga u dubinu
stablo, 210
V
velicina ulaza, 23
vezivanje
savreno, 80
stabilno, 82
virtuelna inicijalizacija niza, 101
Voralov algoritam, 249
vreme izvravanja algoritma, 24
asimptotsko, 43
najgori slucaj, 24
ocekivano, 27
prosecno, 27
vremenska sloenost algoritma, 24
Z
zamena vrednosti dve promenljive, 13
zapis algoritama, 1013
257
CIP -
,
004.421(075.8)
510.5(075.8)
004.6(075.8)
, , 1956Uvod u algoritme i strukture podataka /
Dejan ivkovi. - 1. izd. - Beograd :
Univerzitet Singidunum, 2010 (Loznica :
Mladost Grup). - IV, 257 str. : ilustr. ; 24
cm
Tira 240. - Bibliograja: str. 251. Registar.
ISBN 978-86-7912-239-1
a) b) ()
COBISS.SR-ID 172433420
2010.
Sva prava zadrana. Ni jedan deo ove publikacije ne moe biti reprodukovan u bilo kom
vidu i putem bilo kog medija, u delovima ili celini bez prethodne pismene saglasnosti
izdavaa.