Vous êtes sur la page 1sur 151

JU UNIVERZITET U TUZLI

Prirodno matematiki fakultet


Odsjek matematika

II godina studija Matematike










ALGORITMI
I
PROGRAMIRANJE
Radni materijal za vjebe










Autori :
Dr.sc. Esmir Pilav
Zoran Jasak, Mr.sci.math.





Decembar 2013. godine
Uvod

Ovaj tekst je namijenjen studentima druge godine dodiplomskog studija Prirodno
matematikog fakulteta u Tuzli na Odsjeku za matematiku kao dio materijala za predmet
Algoritmi i programiranje u zimskom semestru akademske 2013/2014. godine. Namjena
teksta je da prui osnovne informacije iz ove oblasti kao podloga za dalji samostalni rad
studenata.

Tekst obuhvata teorijski dio poglavlja koja su predviena planom ovog predmeta. Tekst ne
obuhvata zadatke koji su raeni kao praktini primjeri pojedinih vrsta algoritama. Njihova
namjena je bila izgraditi analitiki pristup u rjeavanju praktinih matematikih problema.

NAPOMENA : Tekst i dijelovi teksta ne mogu biti reprodukovani ili preuzimani bez znanja i
saglasnosti autora.

Autori :

Esmir Pilav, Dr.sci.,
Zoran Jasak, Mr.sci.math.,
jasak_z@bih.net.ba

Sadrzaj
1 Opti pojmovi o algoritmima 1
1.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2 Linijski i algoritmi i algoritmi grananja 6
2.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2 Zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3 Zadaci za vjezbu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3 Ciklicni algoritmi 15
3.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.2 Nizovi i matrice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3 Zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.4 Zadaci za vjezbu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4 Analiza kompleksnosti algoritama na primjerima 41
4.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.2 Zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.3 Analiza kompleksnosti nekih tipova algoritama . . . . . . . . . . . . . . . 43
4.3.1 Algoritmi konstantnog vremena . . . . . . . . . . . . . . . . . . . 43
4.3.2 Algoritmi u linearnom vremenu . . . . . . . . . . . . . . . . . . . 44
4.3.3 Algoritmi sa kvadratnim vremenom . . . . . . . . . . . . . . . . . 44
4.3.4 Algoritmi sa logaritamskim vremenom . . . . . . . . . . . . . . . 45
4.3.5 Algoritmi brzine
_
: . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.3.6 Algoritmi sa eksponencijalnim vremenom . . . . . . . . . . . . . . 46
4.3.7 Kombinacije algoritama . . . . . . . . . . . . . . . . . . . . . . . 46
5 Asimptotska procjena slozenosti algoritma 48
5.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.1.1 -notacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.1.2 O-notacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.1.3 -notacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.1.4 Primjeri racunanja slozenosti . . . . . . . . . . . . . . . . . . . . 50
6 Analiza kompleksnosti - nastavak 52
6.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
6.2 Zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
6.3 Zadaci za samostalni rad . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
7 Rekurzije 56
7.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
7.2 Zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
7.3 Zadaci za samostalni rad . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
8 Euklidov algoritam 65
8.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
8.2 Kako radi Euklidov algoritam ? . . . . . . . . . . . . . . . . . . . . . . . 65
8.3 Zadaci za samostalni rad . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
i
9 Tjuringova maina 69
9.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
9.2 Alan Tjuring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
9.3 Alfabet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
9.4 Neformalni opis Tjuringove maine . . . . . . . . . . . . . . . . . . . . . 70
9.5 Formalni opis Tjuringove maine . . . . . . . . . . . . . . . . . . . . . . 72
9.6 Zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
10 Sortiranja 81
10.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
10.2 Sortiranje nizova - osnovne metode . . . . . . . . . . . . . . . . . . . . . 81
10.2.1 Sortiranje putem umetanja (Insertion sort) . . . . . . . . . . . . . 82
10.2.2 Shell sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
10.2.3 Sortiranje putem direktne podjele (Selection sort) . . . . . . . . . 88
10.2.4 Sortiranje putem zamjene (Bubble sort) . . . . . . . . . . . . . . 91
10.3 Poboljane metode (slozenost :log :) . . . . . . . . . . . . . . . . . . . . 96
10.3.1 Merge sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
10.3.2 Quick sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
11 Grafovski algoritmi 104
11.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
11.2 Algoritmi pretrazivanja . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
11.3 Algoritmi najkraceg puta . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
11.3.1 Dijkstra algoritam . . . . . . . . . . . . . . . . . . . . . . . . . . 107
11.4 Pohlepni algoritmi na grafovima . . . . . . . . . . . . . . . . . . . . . . . 109
11.4.1 Kruskalov algoritam . . . . . . . . . . . . . . . . . . . . . . . . . 111
11.4.2 Primov algoritam . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
11.5 Zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
11.6 Zadaci za samostalni rad . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
12 Programski jezik C++ 124
12.1 Rad sa datotekama . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
12.2 Klase i objektno programiranje . . . . . . . . . . . . . . . . . . . . . . . 125
12.3 Zakljucak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
13 NP kompleksnost 135
13.1 Problemi odlucivanja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
13.2 Problemi prepoznavanja jezika . . . . . . . . . . . . . . . . . . . . . . . . 137
13.3 Verikacija polinomijalnog vremena i certikati . . . . . . . . . . . . . . 139
13.3.1 NP klasa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
13.3.2 Problem tri boje . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
13.3.3 Clique pokrivac (cover) (CCov) . . . . . . . . . . . . . . . . . . . 142
13.3.4 Redukcija na polinomijalno vrijeme . . . . . . . . . . . . . . . . . 143
13.4 NP kompletnost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
14 Literatura 147
ii
1 Opti pojmovi o algoritmima
1.1 Uvod
1.01. Termin "algoritam" je nastao po latinskom prevodu imena matematicara iz deve-
tog vijeka, Abu Jafar Muhammad Ibn Musu Al-Khowarizmi, koji se bavio trigonometri-
jom, astronomijom, geograjom, kartograjom, a smatra se ocem algebre jer je denirao
osnovna pravila rjeavanja linearnih i kvadratnih jednadzbi. Njegovi radovi su osnova
razvoja mnogih matematickih i prirodnih disciplina, meu njima i racunarstva.
Prvi zapis algoritma prilagoen racunaru pripada Adi Byron iz 1842, pa se zbog ovoga
smatra prvom programerkom, a racunao je Bernoullijeve brojeve. Racunar za koji je
napisan je bio analiticki stroj koji je zamislio, ali nikad u potpunosti proveo u djelo, Englez
Charles Babbage. Analiticki stroj je trebao biti prvi programabilni racunar, sastavljen
u potpunosti od mehanickih dijelova. Mehanicki dijelovi i zicka glomaznost su glavni
razlozi zato nikad nije zavren
1
.
Algoritam se denie na nekoliko nacina :
Algoritam je skup pravila kojima se provodi kalkulacija bilo rucno bilo putem maine
Algoritam je procedura od konacnog broja koraka kako bi se dobio trazeni rezultat
Algoritam je niz racunskih koraka kojima se ulaz transformie kako bi se dobio izlaz
Algoritam je niz operacija koje se izvode nad podacima koji trebaju biti organizo-
vani u strukturama podataka
Algoritam je apstrakcija programa koji se treba izvesti na zickoj maini (model
izracunavanja)
U tekstu [11] algoritam se denie kao "jasno speciciran matematicki process izracuna-
vanja; skup pravila koji ako se slijede daju zeljeni rezultat". U matematici, racunarstvu,
lingvistici i srodnim disciplinama, algoritam je konacan niz dobro denisanih naredbi
za ostvarenje zadatka, koji ce za dato pocetno stanje zavriti u denisanom konacnom
stanju.
Iz datih denicija se moze zakljuciti da je algoritam skup koraka odnosno postupak kojim
se odreeni problem rjeava u konacnom broju koraka. Istorijski gledano, svi problemi su
rjeavani nekim vidom algoritma ali je proteklo puno vremena da se napravi odgovarajuca
formalizacija.
1.02. Koncept algoritma je potekao kao sredstvo zapisivanja postupaka za rjeavanje
matematickih problema, poput pronalazenja zajednickog djelitelja dva broja ili mnozenja
dva broja. Koncept je formaliziran 1936. u vidu Turingovog stroja Alana Turinga i
lambda racuna Alonza Churcha, koji su jedan za drugim postavili temelje racunarstva.
Najpoznatiji algoritam u istoriji datira mnogo prije vremena starih grka; to je Euklidov
algoritam za racunanje najveceg zajednickog djelioca dva cijela broja.
1.03. Algoritmi imaju slijedeca svojstva:
1
Prije nekoliko godina su britanski inzinjeri uspjeli sastaviti potpuno funkcionalan ureaj koji je
zamislio Charles Babbage.
1
diskretnost : u odvojenim koracima se izvode diskretne operacije algoritma koje
vode ka konacnom cilju;
konacnost : oznacava sposobnost algoritma da nakon konacnog broja koraka daje
izlazne podatke odnosno rezultate;
determiniranost : za iste ulazne podatke algoritam uvijek daje iste rezultate
masovnost : algoritam je primjenjiv na veci broj ulaznih vrijednosti.
Osnovne komponente algoritma su :
Denicija problema
Ulazne velicine
Radne velicine
Postupak rjeavanja
Izlaz
Denicija problema treba biti jasna, sadrzajna i sa dovoljno elemenata kako bi se
problem mogao rijeiti. Problem se denie tekstualno i/ili izrazom. Denicija problema
treba biti egzaktna i nedvosmislena.
Ulazne velicine deniu skup podataka koji su predmet obrade (input). Ove velicine
mogu biti numericke velicine, fajlovi, tekstovi, graka itd.
Radne velicine su promjenljive koje se koriste u postupku rjeavanja problema. Mada
se koncept razlikuje po jezicima, svima im je zajednicko da zahtijevaju deklaraciju i
inicijalizaciju radnih velicina.
Deklaracija denie tip promjenljive a samim tim i njene moguce vrijednosti.
Incijalizacija je postupak davanja pocetnih vrijednosti promjenljivim. Ovo je posebno
vazno u ciklicnim algoritmima. U nekim slucajevima inicijalizacija se vri prvom dodjelom
vrijednosti.
Postupak rjeavanja denie svaki pojedini korak koji je potreban za rjeenje problema,
ukljucujuci deklaracije, inicijalizacije i svaku operaciju koja se obavlja.
Izlaz (output) denie rezultat rada koji moze biti numericka velicina, skup vrijednosti,
datoteka itd.
Svaki algoritam mora imati zavretak. Pravljenje tzv. vjecnih petlji je klasicna pro-
gramerska greka. Potrebno je razlikovati procedure od funkcija. U principu, svaka
procedura ima rezultat ali on ne mora biti vidljiv u svim slucajevima. Primjer je proce-
dura sortiranja koja se moze izvravati kao dio nekog veceg algoritma odnoso uslova za
naredne korake. Funkcija mora imati vrijednost i moze biti clan u operacijama.
1.04. Programski jezik C++. U programskom jeziku C++ svaka velicina koja se
koristi u programu mora biti deklarisana prije same upotrebe. Deklaracija ukljucuje tip
i naziv promjenljive. Osnovni tipovi promjenljivih u C++ su :
2
int : cijeli broj
short int : cijeli broj koji za zapis koristi polovinu prostora od tipa int
long int : cijeli broj koji za zapis koristi dva puta vie prostora od tipa int
long long int : cijeli broj koji za zapis koristi cetiri puta vie prostora od tipa int
float : realni broj u formi pokretnog zareza obicne tacnosti odnosno u obliku
r = : 10
t
gdje je : (0. 1) a t Z. Dosadanji uobicajeni naziv za : je do sada
bio mantisa. U cilju izbjegavanja pogrenih terminolokih tumacenja prihvacen je
termin signikand
double : realni broj u formi pokretnog zareza dvostruke tacnosti tj. koristi dva
puta vie prostora za signikand od tipa oat
long double : realni broj u formi pokretnog zareza dvostruke tacnosti tj. koristi
tri puta vie prostora za signikand od tipa oat
char : promjenljiva koja se uzima kao tekstualni simbol (engleski : character) a ne
broj
Ispred numerickih tipova se moze dodati rijec unsigned kojom se oznacava da broj ne
moze biti negativan. Prostor koji zauzima pojedini numericki tip zavisi od racunara i
instalacije C++ kompajlera. Da bi se dobio taj podatak potrebno je pokrenuti sljedeci
program :
// Primjer 1.1. Podatak o duzinama tipova promjenljivih u programskom jeziku C++
#include <iostream
using namespace std;
int main()
{
cout << "Tip char zauzima " << sizeof(char) << " bajtan";
cout << "Tip short zauzima " << sizeof(short) << " bajtan";
cout << "Tip int zauzima " << sizeof(int) << " bajtan";
cout << "Tip long zauzima " << sizeof(long) << " bajtan";
cout << "Tip long long zauzima " << sizeof(long long) << "
bajtan";
cout << "Tip float zauzima " << sizeof(float) << " bajtan";
cout << "Tip double zauzima " << sizeof(double) << " bajtan";
cout << "Tip long double zauzima " << sizeof(long double) << "
bajtan";
system("PAUSE");
}
U programskom jeziku C++ tip se moze promijeniti u toku izvrenja koraka unutar
programa. Moguce je napisati npr. x=sqrt(float(a)). Ovo znaci da ako je broj c bio
npr. cjelobrojan tada se sa float(a) pretvara u broj u pokretnom zarezu a zatim se
izvrava naredba sqrt().
Inicijalizacija se u programskom jeziku C++ vri na nekoliko nacina od kojih su neki :
3
dodjelom vrijednosti u okviru deklaracije : int i=1;
dodjelom vrijednosti van deklaracije : i=1;
stavljanjem vrijednosti neke druge promjenljive u toku realizacije : i=k;
dodjelom vrijednosti neke funkcije : x=sin(x);
Inicijalizacija je veoma vazan korak jer operacija nad promjenljivom koja nije inicirana
daje potpuno neizvjestan rezultat.
Svaka promjenljiva dobija naziv koji moze biti bilo kakva kombinacija slova, brojeva i
odreenih znakova, jedini je uslov da prvi simbol mora biti slovo.
Programski jezik C++ pravi razliku izmeu velikih i malih slova. Tako su promjenljive
JedanBroj, jedanbroj, Jedanbroj, jedanBroj sa stanovia C++ jezika potpuno razlicite
promjenljive.
Dizajn algoritma ukljucuje obaveznu kontrolu njegove ispravnosti kako bi se ustanovilo
da algoritam daje zeljeni rezultat.
1.05. Algoritme je moguce klasicirati po raznim kriterijima:
Klasikacija s obzirom na tok
Linijski algoritmi se izvravaju korak po korak, bez vracanja na neki od prethod-
nih koraka niti se neki od koraka ili grupa koraka ponavlja u bilo kom smislu. Ovi
algoritmi mogu sadrzavati i grananja, mjesta na kojima se postupak nastavlja nakon
ispitivanja odreenog uslova.
Ciklicni algoritmi se realizuju na nacin da se ponavlja odreeni korak ili grupa
koraka. Ponavljanje se moze realizovati na dva nacina :
- Putem brojaca, kojim se zadaje koliko puta se odabrani korak ili grupa koraka
ponavlja. Bitno je napomenuti da se u ovom tipu ciklusa zadati broj koraka ne
moze mijenjati u toku samog izvrenja
- Putem uslova za koji se ne zna unaprijed koliko puta ce se izvriti. Ovo je slucaj
npr. kada se zeli postici odreena tacnost u racunanju; najcece nije poznato koliko
koraka treba napraviti da bi se tacnost postigla pa se trazi drugi nacin.
Najveca opasnost ciklicnih algoritama je formiranje tzv. vjecitih petlji jer uslov zavretka
nije dobro denisan.
Klasikacija prema implementaciji
Rekurzivni ili iterativni: Rekurzivni algoritam je algoritam koji poziva samog
sebe sve dok se ne postigne odreen uslov. Rekurzivni algoritmi su vrlo cesto
usko vezani uz implementaciju pojedine matematicke funkcije na primjer racunanje
Fibbonacijevih brojeva. Iterativni algoritmi su algoritmi koji ne pozivaju samog
sebe vec se oslanjaju na konstrukcije poput petlji i dodatne strukture podataka
da bi se rijeio problem. Vazno je napomenuti da je svaki rekurzivni algoritam
moguce pretvoriti u iterativni, i da je svaki iterativni algoritam moguce pretvoriti
u rekurzivni, iako ponekad to pretvaranje moze biti vrlo kompleksno.
4
Serijski ili paralelni: Vecina dananjih racunara sadrzi samo jedan procesor te
stoga obavlja naredbe jednu po jednu, to jest serijski. Algoritmi koji su dizajnirani
sa namjerom da se izvravaju u takvom okruzenju shodno tome se nazivaju serijski
algoritmi. Suprotno njima su paralelni algoritmi koji sa sve vecim brojem vieproce-
sorskih racunara dobivaju sve vecu vaznost. Paralelni algoritmi koriste mogucnost
vieprocesorskog sistema na nacin da problem podijele na vie malih potproblema
koje svaki procesor rjeava zasebno te se zatim rezultati spajaju. Paralelni algoritmi
uz resurse potrebne za obradu podataka takoer imaju i malu potronju resursa na
komunkaciju izmeu vie procesora. Algoritmi za sortiranje su jedan od primjera
algoritama koje je moguce znatno poboljati upotrebom paralelnih procesora, dok
je neke probleme sasvim nemoguce rijeiti paralelnim algoritmom.
Deterministicki ili stohasticki: Deterministicki algoritam je algoritam koji ce
pri svakom izvravanju u bilo kojim uslovima od istog unosa doci do istog izlaza
na nacin da svaki put slijedi identican niz naredbi. Stohashicki algoritam barem u
jednom dijelu izvravanja donosi neku odluku slucajnim odabirom.
Tacan ili priblizan: Iako algoritmi u principu daju tacan rezultat, ponekad al-
goritam trazi priblizno rjeenje koje je dovoljno blizu tocnom, ili je tacno rjeenje
nemoguce naci.
Klasikacija prema strategiji rjeavanja
Brute force algoritmi - racunar "cistom silom" isprobava sve mogucnosti i trazi
odgovarajuce rjeenje. Ovo su najneekasnijji algoritmi jer ukazuju na nesistem-
aticnost i neanalitcnost u pristupu.
Podijeli i vladaj algoritmi (Divide and conquer). Problem se dijeli na vie istih,
manjih problema. Podjela tece tako dugo dok se ne doe do malog problema kojeg
je jednostavno rijeiti (obicno rekurzijom).
Dinamicki algoritmi - Metodama dinamickog programiranja rjeavaju se viefazni
procesi, tj. procesi u kojima se donosi niz meusobno zavisnih odluka. Dinamicko
programiranje poznato je i pod nazivom metoda donoenja viefaznih odluka.
Pohlepni algoritmi (greedy) - Pohlepni algoritam koristi metaheuristiku za
rjeavanje problema, takvu da u svakom koraku bira lokalno najbolje rjeenje, u
nadi da ce tako iznaci globalni optimum. Ovi algoritmi cesto ne daju najbolje
rjeenje vec brzu aproksimaciju najboljeg rjeenja.
Algoritmi za sortiranje i pobrojavanje (search and enumeration) - Algoritmi
sortiranja sluze za brzo sortiranje podataka, npr. niza brojeva. Mnogi se problemi
mogu rjeavati teorijom grafova.
1.06. Algoritmi se predstavljaju gracki i tekstualno.
Gracko predstavljanje se realizuje putem standardnih simbola koji predstavljaju po-
jedine korake i koji se povezuju linijama kao prikaz toka operacija. Pritom se dijagram
pravi tako da ide odozgo prema dolje s lijeva na desno.
5
Tekstualno predstavljanje moze biti putem pseudokoda ili putem odabranog program-
skog jezika. Pseudokod nije vezan ni za jedan specican programski jezik. U radu cemo
koristiti sljedece formulacije pseudokoda :
Blokovi odnosno logicki povezani skupovi naredbi se ogranicavaju parom zagrada
{...}
ab: Pridruzivanje koje se cita "na lokaciju promjenljive c (odredite) upisati
vrijednost promjenljive /". u C++ programskom jeziku to se pie kao "a=b" i znaci
da se na lokaciju promjenljive c smjeta sadrzaj promjenljive /. Ovo se razliku je
od forme a==b koja znaci ispitivanje uslova "da li je a jednako b".
Ako je <uslov tada <operacija : Ispituje se <uslov i ako je zadovoljen real-
izuje se <operacija; u suprotnom se realizuje alternativni blok. U programskom
jeziku C++ se prepoznaje kao struktura
if(...)
{...}
else
{...}
Za <promjenljiva od <g1 do <g2 korak <g3 : Pocetak ciklusa u kojem
<promjenljiva mijenja vrijednosti od <g1 do <g2 sa korakom <g3. Ako je
g1<g2 tada korak mora biti pozitivan, u suprotnom je negativan. U programskom
jeziku C++ for ovo je struktura
for(promjenljiva=g
1
;promjenljiva_g
2
;g
2
=g
2
+g
3
)
Primjer :
for(i=1;i_100;i++)
znaci da ce se promjenljiva i imati pocetnu vrijednost 1 (i = 1), da ce se u svakom koraku
povecavati za 1 (i + +, posebna konvencija C++ jezika) sve dok se ne dobije vrijednost
manja ili jednaka 100.
SveDokJe (<uslov) : pocetak ciklusa u kojem, u pravilu, nije poznat broj koraka.
Ciklus se izvrava sve dok vrijedi <uslov. U programskom jeziku C++ ovo je
struktura while(...){...}
IdiNa <labela : Bezuslovni skok. U programskomm jeziku C++ je to goto
naredba
2 Linijski i algoritmi i algoritmi grananja
2.1 Uvod
2.01. Linijski algoritmi su oni koji se izvravaju sukcesivno odnosno oni u kojima se svaki
korak izvrava samo jednom. Algoritam moze sadrzavati grananja ali se ne vri povratak
na bilo od kojih prethodnih koraka.
2.2 Zadaci
Zad. 2.01. Napraviti algoritam za racunanje sljedecih vrijednosti :
6
min r.
max r.
min r. . max r.
Rjeenje. Ulazne velicine za ovaj algoritam su r. . Ako se trazi minimum rezultat ne
bi trebao biti samo odgovor koji od dva broja je manji vec broj koji se kao rezultat
ispitivanja moze iskoristiti za neku drugu funkciju, operaciju ili slicno. Drugim rijecima,
trazi se da rezultat bude u obliku
`i: min r.
Analogno treba vrijediti i za maksimalnu vrijednost.
Algoritam za nalazenje minimalnog od dva data broja je na sljedecem dijagramu.
Nalazenje minimalnog od dva data broja
U nastavku je pseudokod za ovaj algoritam.
Algoritam : Nalazenje minimalnog od dva broja
Ulaz : r.
`i: r
Ako je < `i: tada
{
`i:
}
Izlaz : `i:
Analogni algoritam za nalazenje veceg od dva data broja je na sljedecem dijagramu.
7
Nalazenje veceg od dva data broja
U nastavku je pseudokod za ovaj algoritam.
Algoritam : Nalazenje maksimalnog od dva broja
Ulaz : r.
`cr r
Ako je < `cr tada
{
`cr
}
Izlaz : `cr
Algoritamza istovremeno nalazenje najmanjeg i najveceg od dva data broja je na sljedecem
dijagramu.
Algoritam za istovremeno nalazenje i minimalnog i maksimalnog od dva data broja
Pseudokod za ovaj algoritam je u nastavku.
8
Algoritam : Nalazenje i minimalnog i maksimalnog broja
Ulaz : r.
`i: r
`cr
Ako je < `i: tada
{
`i:
}
Ako je r `cr tada
{
`cr r
}
Izlaz : `i:. `cr
Ono to je karakteristika ovog algoritma je da se rezultat dobija jedino poreenjem datih
velicina.
Zad. 2.02. Data su dva broja c i /. Ako je prvi broj veci od drugog zamijeniti ih
meusobno.
Rjeenje. Uobicajeni postupak njihove zamjene je da se koristi pomocna promjenljiva c.
Pseudokod je dat u nastavku.
// Meusobna zamjena dva broja
AkoJe (c /) Tada
{
c c
c /
/ c
}
Istu operaciju je moguce napraviti bez pomocne promjenljive. Pseudokod je u nastavku.
// Meusobna zamjena dva broja
AkoJe (c /) Tada
{
/ c +/
c / c
/ / c
}
9
Zad. 2.03. Napraviti algoritam rjeavanja kvadratne jednacine.
Rjeenje. Neka je opta kvadratna jednacina data izrazom cr
2
+ /r + c = 0. Ulazne
velicine za algoritam su c. /. c. Najprije se ispituje da li je c ,= 0 : provjera da li zadati
parametri uopte mogu denisati kvadratnu jednacinu. Ako je c 0 prelazi se na racu-
nanje diskriminante. Znak diskriminante odreuje prirodu i broj rjeenja. Na narednom
dijagramu je gracki prikazan algoritam rjeavanja kvadratne jednacine.
Postupak rjeavanja kvadratne jednacine
Na dijagramu je vidljiv tok odozgo nanize, uz dva grananja odnosno mjesta na kojima
se ispituje uslov i donosi odgovarajuca odluka o nastavku. Ovaj isti algoritam se moze
predstaviti pseudokodom koji je u algoritmu Kvadratna jednacina, V.1..
Pseudokod je napisan na nacin da pojedine naredbe odnosno grupe naredbi odgovaraju
sadrzaju simbola na grakonu. Ovdje je simbolom oznaceno da se vrijednost sa desne
strane smjeta na lokaciju na kojoj se nalazi velicina sa lijeve strane znaka.
Isti algoritam je mogao biti ispisan na nacin da se koriste labele, kao to je prikazano na
verziji 2.
Tekst programa napisan u programskom jeziku C++ je dat na prilozenom algoritmu.
10
Algoritam : Kvadratna jednacina, V.1
Ulaz : a,b,c
// Najprije se ispituje da li je a = 0 ili ne
Ako je a=0 tada Kraj
// Izracunavanje diskriminante
D b
2
4ac
Ako je 1 0 tada
{
// Rjeenja su realna i razlicita
x
1
-
/
2c
-
_
1
2c
x
2
-
/
2c
+
_
1
2c
IdiNa Ispis
}
Ina ce
{
//Da li je diskriminanta negativna
Ako je D<0 tada
{
//Rjeenja su kompleksna
Re -
/
2c
Im -
_
1
2c
x
1
(Re. Im)
x
2
(Re. Im)
IdiNa Ispis
}
Ina ce
{
//Rjeenja su jednaka
x
1
=x
2
-
/
2c
IdiNa Ispis
}
}
Ispis : Rjeenja kvadratne jedna cine
Kraj
11
Algoritam : kvadratna jednacina, V.2.
Ulaz : a,b,c
// Najprije se ispituje da li je a = 0 ili ne
Ako je a=0 tada Kraj
// Izracunavanje diskriminante
D b
2
4ac
Ako je (D0) IdiNa Korak1
Ako je (D=0) IdiNa Korak2
// Ako nije ni jedno ni drugo preostaje da je D<0
{
//Rjeenja su kompleksna
Re -
/
2c
Im -
_
1
2c
x
1
(Re. Im)
x
2
(Re. Im)
// Nakon racunanja idi na Ispis i Kraj
IdiNa Ispis
}
Korak1:
{
// Rjeenja su realna i razlicita
x
1
-
/
2c
-
_
1
2c
x
2
-
/
2c
+
_
1
2c
IdiNa Ispis
}
Korak2:
{
//Rjeenja su jednaka
x
1
=x
2
-
/
2c
IdiNa Ispis
}
Ispis : Rjeenja kvadratne jedna cine
Kraj
12
// Zadatak : Rjeavanje kvadratne jednacine
#include <iostream
#include <conio.h
#include <cmath
using namespace std;
int main()
{
float a, b, c, D, real, imag, x1, x2;
cout << "Unesite koeficijent a : " << endl;
cin a;
if(a==0)
{
cout << "Unijet je pogrean podatakn" << endl;
getch();
return(0);
}
cout << "Unesite koeficijent b : " << endl;
cin b;
cout << "Unesite koeficijent c : " << endl;
cin c;
D = pow(b,2)-4*a*c;
if(D<0)
{
cout << "Jedna cina ima kompleksne korijenen" << endl;
real = -b/(2*a);
cout << "Realni dio jen" << real << endl;
imag = sqrt(-D)/(2*a);
cout << "Imaginarni dio jen" << imag << endl;
}
else
{
if(D==0)
{
cout << "Jedna cina ima jednake korijenen" << endl;
x1 = -b/(2*a);
cout << x1 << endl;
}
else
{
cout<<"Jedna cina ima realne i razli cite korijenen"<<endl;
x1 = (-b - sqrt(D))/(2*a);
x2 = (-b + sqrt(D))/(2*a);
cout << "Rjeenje broj 1 : " << x1 << endl;
cout << "Rjeenje broj 2 : " << x2 << endl;
}
}
getch();
return(0);
}
13
2.3 Zadaci za vjezbu
Zad. V.2.01. Dati su realni brojevi r. . Ne koristeci druge operacije osim sabiranja,
oduzimanja i mnozenja izracunati vrijednost izraza
3r
2

2
2r
2
7r
2
4
2
+ 15r + 2r
2
3r + 10 + 6
Ne koristiti vie od osam mnozenja, oduzimanja i sabiranja.
Zad. V.2.02. Dat je realan broj c. Koristeci se samo mnozenjem izracunati
c
4
, sa dvije operacije
c
6
, sa tri operacije
c
7
, sa cetiri operacije
c
8
, sa tri operacije
c
9
, sa cetiri operacije
c
10
, sa cetiri operacije
c
13
, sa pet operacija
c
13
, sa pet operacija
c
21
, sa est operacija
c
28
, sa pet operacija
c
64
, sa est operacija
Zad. V.2.03. Data su tri realna broja c. /. c. Napraviti algoritam koji daje odgovor da
li je moguce konstruisati trougao sa stranama cije su duzine dati brojevi. Ako je moguce
konstruisati trougao dati odgovor na pitanje da li je trougao otrougli.
Zad. V.2.04. Napraviti algoritam i napisati program kojim se rjeava bikvadratna
jednacina
cr
4
+/r
2
+c = 0
Zad. V.2.05. Napraviti algoritam i program kojim se racunaju vrijednosti sljedecih
funkcija
, (r) =
_
r
2
+ 4r + 5 r [2. 2]
1
r
2
+ 4r + 5
r ,= [2. 2]
, (r) =
_
_
_
0 r _ 0
r
2
r 0 < r _ 1
r
2
sin (:r
2
) r 1
Zad. V.2.06. Za dati prirodni broj : _ 99 provjeriti da li je :
2
jednak kubu sume svojih
cifara.
Zad. V.2.07. Za dati prirodni broj : _ 1000 provjeriti koliko ima cifara, kolika je suma
cifara, koja je cifra posljednja.
Zad. V.2.08. Satna kazaljka obrazuje ugao , sa duzi koja prolazi kroz centar i tacku
koja oznacava 12 sati. Izracunati ugao koji obrazuje minutna kazaljka i vrijeme koje
pokazuju te kazaljke (sa cijelim brojem minuta).
14
3 Ciklicni algoritmi
3.1 Uvod
3.1.01. Ciklicni algoritmi su u kojima postoji skup operacija koji se ponavlja. Primjer je
racunanje vrijednosti polinoma jer se mora osigurati da se iskoriste svi koecijenti. Zbog
potrebe konacnosti algoritma, mora se osigurati uslov zavretka. Kod ciklicnih algoritama
taj uslov se osigurava ili putem brojaca koraka ili nekog od uslova, od kojih je najceci
uslov tacnosti.
3.1.02. Ako se koristi brojac koraka mora postojati cjelobrojna velicina koja ima startnu
vrijednost, granicnu vrijednost i korak povecanja ili smanjenja. Ako je brojac npr.
velicina k tada se u pseudokodu koristi jedna od sljedece dvije varijante :
Za <promjenljiva od <g1 do <g2 korak <g3 : Pocetak ciklusa u kojem
<promjenljiva mijenja vrijednosti od <g1 do <g2 sa korakom <g3. Ako je
g1<g2 tada korak mora biti pozitivan, u suprotnom je negativan. U programskom
jeziku C++ for ovo je struktura
for(promjenljiva=g
1
;promjenljiva_g
2
;g
2
=g
2
+g
3
)
Primjer
for(i=1;i_100;i++)
znaci da ce se promjenljiva i imati pocetnu vrijednost 1 (i = 1), da ce se u svakom koraku
povecavati za 1 (i + +, posebna konvencija C++ jezika) sve dok se ne dobije vrijednost
veca ili jednaka 100. Slicno :
for(i=100;i_1;i--)
znaci da ce se promjenljiva i imati pocetnu vrijednost 100 (i = 100), da ce se u svakom
koraku smanjivati za 1 (i , posebna konvencija C++ jezika) sve dok se ne dobije
vrijednost manja ili jednaka 1. Poseban slucaj je struktura
for(;;)
koja znaci da se uslov nalazi unutar petlje odnosno skupa naredbi koje oznacava ova
naredba.
3.1.03. Jedna od varijanti ciklusa je da se ciklus odvija dok se ne zadovolji neki uslov
zavretka. U pseudokodu ovo se oznacava strukturom
SveDokJe (<uslov)
{...}
pocetak ciklusa u kojem, u pravilu, nije poznat broj koraka. Ciklus se izvrava sve dok
vrijedi <uslov. U programskom jeziku C++ ovo je struktura
while(...){...}
Primjer je uslov tacnosti ali to moze biti bilo koji drugi uslov. Algoritmi sa uslovom
tacnosti su oni u kojima je kriterij zaustavljanja zeljeni stepen racunske tacnosti koja se
postize :
Poreenjem dvije uzastopne parcijalne sume
Poreenjem sa nekom vrijednosti koja je referenetna (npr. najblizi cijeli broj)
ili na neki drugi nacin.
Ako postoji potreba da se petlja napusti prije zadatog uslova koristi se naredba break.
15
3.2 Nizovi i matrice
3.2.01. U ciklicnim algoritmima se cesto koriste nizovi. Niz je konacni skup vrijednosti
jedne promjenljive u kojem svaki clan ima svoj redni broj odnosno indeks koji oznacava
dimenziju niza.
Niz se deklarie imenom i dimenzijom. Tako, deklaracije :
int a[25];
float indeksi[12];
znace da je deklarisan niz cijelih brojeva pod nazivom a koji ima 25 elemenata i niz realnih
brojeva pod nazivom indeksi koji ima 12 elemenata. U ovakvom nacinu deklarisanja
mora se navesti dimenzija niza u zagradi. To znaci da dizajner mora unaprijed znati ili
pretpostaviti najvecu mogucu dimenziju niza.
U C++ jeziku se koristi tzv. relativno referenciranje. U tom sistemu prvi clan niza
ima indeks 0 a svi ostali, drugi clan indeks 1 itd. Drugim rijecima, indeks svakog clana
odgovara rastojanju od prvog (nultog) clana.
3.2.02.

Cest prakticni problem je kako unijeti clanove niza, posebno kada je u pitanju
veci broj. Ovaj problem se rjeava na nekoliko nacina:
Unoenjem clan po clan, putem interaktivnog programa
Denisanjem svih clanova niza unutar programa
Preuzimanjem iz nekog izvora, najcece iz neke datoteke
U nastavku je primjer (potpuno funkcionalnog) programa kojim se vri unos clanova niza
sa proizvoljnim brojem clanova.
Niz se moze inicirati nabrajanjem tako da npr.
int a[] ={-2,3,1,6,-3};
predstavlja niz od 5 cijelih brojeva. Referenciranje se vri navoenjem indeksa. S obzirom
na relativno indeksiranje a[3]predstavlja broj 6 tj. a[3]=6; takoe je a[0]=-2 itd.
Umjesto indeksa se moze navesti racunska operacija koja za rezultat daje indeks nekog
od clanova tog niza, npr. a[2*n-1]. Slicno
int mjeseci[]={31,28,31,30,31,30,31,31,30,31,30,31}
predstavlja niz koji predstavlja broj dana po mjesecima u godini. Ovakvom deklaraci-
jom se odreuje i dimenzija niza koja nije navedena u deniciji vec program odreuje
dimenziju nakon ucitavanja.
Ako se u deklaraciji navede dimenzija niza i nabroji manje elemenata od te dimenzije
nedostajuci elementi se inicijaliziraju na nulu. Primjer je niz:
int a[8] ={-2,3,1,6,-3};
U ovom nizu ce posljednja tri clana biti inicijalizirana na nulu.
Primjer unosa clanova niza iz datoteke ce biti objanjen kasnije.
16
// Algoritam za unos prizvoljnog broja clanova niza
#include <iostream
#include <cmath
using namespace std;
int main()
{
// Broj clanova niza
int n;
// Brojac na ucitavanju
int k;
// Deklaracija niza; uzeto je da je niz cjelobrojni
int niz[100];
n=100;
cout << "Unesite broj clanova (najvie 100) : n" << endl;
cin n;
if(n100)
{
cout << "Upisani broj je prevelik...n" << endl;
return(0);
}
for(k=1;k<=n;k++)
{
// Unos, clan po clan
cout << "

Clan broj " << k << " je : " << endl;


cin niz[k];
}
cout << "Ispisuje se upisani niz " << endl;
for(k=1;k<=n;k++)
{
cout << niz[k] << "t";
}
cout << "n";
system("PAUSE");
}
17
3.2.03. Matrice su dvodimenzionalni nizovi tako da vrijede ista pravila u pogledu refer-
enciranja. Ako se matrica inicijalizira nabrajanjem tada se inicijalizacijska lista sastoji
od listi kojima se deklarie svaki red posebno. Primjer je deklaracija
int a[3][4] = {{3, 4, 2, 5}, {4, 1, 2, 3}, {3, 1, 0, 2}};
U ovom slucaju su jasno naznacene grupe brojeva koje predstavljaju pojedine redove.
Ako se neki red ne deklarie stavljaju se zagrade bez sadrzaja. Primjer je deklaracija
int a[3][4] = {{3, 4, 2, 5}, {}, {3, 1, 0, 2}};
Prilikom inicijaliziranih dvodimenzionalnih nizova, prva dimenzija se moze izostaviti, pri
cemu se tada ona automatski odreuje na osnovu broja podlisti za inicijalizaciju redova
unutar inicijalizacione liste. Tako ce, u sljedecem primjeru, prva dimenzija niza biti
automatski postavljena na 3:
int a[][4] = {{3, 4, 2, 5}, {4, 1, 2, 3}, {3, 1, 0, 2}};
Meutim, druga dimenzija se ne smije izostaviti, tj. ne smije se pisati:
int a[][] = {{3, 4, 2, 5}, {4, 1, 2, 3}, {3, 1, 0, 2}};
Zadatak. Program za unos nizova prilagoditi za unos dvodimenzionalne matrice formata
::.
3.3 Zadaci
Zad. 3.01. Izracunati vrijednost izraza
o = 2r
4
3r
3
+ 4r
2
5r + 6
ne koristeci vie od 4 operacije sabiranja, mnozenja i oduzimanja.
Rjeenje. Da bi broj operacija mogao biti maksimalno smanjen dati izraz se napie u
obliku:
o = (((2r 3) r + 4) r 5) r + 6
Racunanje pocinje iz prve unutranje zagrade. Mnozenja koja se koriste se mogu sim-
bolicki prikazati na sljedeci nacin:
c 2 r 3
/ c r + 4
c / r 5
o c r + 6
Ovakav nacin koritenja promjenljivih je neracionalan ako se ima u vidu da se svaka od
njih koristi samo jednom. Ako se suma koja se trazi obiljezi promjenljivom o tada se ona
moze iskoristiti tako da se na svakom koraku u nju upie nova vrijednost. Simbolicki, to
se pie na sljedeci nacin:
o 2 r 3
o o r + 4
o o r 5
o o r + 6
Ovdje je vidljivo da se prvi red racuna na jedan a ostala tri reda na drugi nacin. Ovo se
moze promijeniti na nacin da se u svim koracima koristi isti obrazac sumiranja i mnozenja:
o 0
18
o o r + 2
o o r 3
o o r + 4
o o r 5
o o r + 6
Ovaj nacin je bitan i po tome to se prvom naredbom vri inicijalizacija promjenljive a u
svakom narednom izrazu koecijenti polinoma se pojavljuju kao sabirci. Ako se uzme da
je polinom napisan u sljedecem obliku
o = c
n
r
n
+c
n1
r
n1
+... +c
1
r +c
0
tada se opisani postupak uopteno moze zapisati na sljedeci nacin:
o 0.
o o r +c
k
. / = :. 1. 1
Ovdje / = :. 1. 1 ima znacenje : / se mijenja od : do 1 sa korakom 1. To znaci
da se uzimaju koecijenti polinoma opadajucim redom indeksa pocev od koecijenta za
najveci stepen. Najvaznije u datoj relaciji je da se koriste samo dvije operacije; prva
od njih je dodjela vrijednosti a druga sadrzi jedno mnozenje i jedno sabiranje. Na ovaj
nacin se moze opisati racunanje vrijednosti polinoma proizvoljnog stepena. Na narednom
dijagramu je dat opisani algoritam.
Racunanje polinoma
U nastavku je pseudokod za ovaj algoritam.
Pitanje 1 : Koliko puta se izvri korak u kojem se racuna o o r +c
k
?
Pitanje 2 : Kako bi izgledao algoritam ako bi polinom bio predstavljen u obliku
o = c
0
r
n
+c
1
r
n1
+... +c
n1
r +c
n
U nastavku je C++ program kojim se racuna vrijednost datog polinoma.
Zad. 3.02. Napraviti algoritam za racunanje sume :
19
Racunanje polinoma
//Ra cunanje vrijednosti polinoma
Ulaz : c
k
. / = 0. :
Ulaz : r
//Inicijalizacija
o 0
Za / = : do 0 korak 1
{
o o r +c
k
}
Izlaz : o
// Racunanje vrijednosti polinoma
// Zadatak u skripti
#include <iostream
using namespace std;
int main()
{
// Deklaracija i inicijalizacija niza
int koef[]={2,-3,4,-5,6}, k;
float x, S;
cout << "Unesite broj x :";
cin x;
// Inicijalizacija promjenljive S
S=koef[4];
for(k=3;k=0;k--)
{
S=S*x+koef[k];
}
cout << "Vrijednost polinoma je : " << S << endl;
system("PAUSE");
}
o =
n

i=1
i
2
i + 1
Rjeenje. Jedina ulazna velicina u ovom slucaju je :. Sumiranje se vri u velicinu o
to podrazumijeva potrebu njene inicijalizacije. Kad je u pitanju sumiranje najprirodniji
nacin inicijalizacije je o = 0. Jedna od varijanti algoritma je u nastavku.
20
Algoritam sumiranja
Na dijagramu je vidljivo da se operacija
o o +
/
2
/ + 1
ponavlja onoliko puta koliko / ima razlicitih vrijednosti, u ovom slucaju :, koje se do-
bijaju tako da se / u svakom koraku poveca za 1. Na taj nacin / ima funkciju brojaca.
Pseudokod za ovaj algoritam je u nastavku.
Sumiranje - varijanta 1
//Ra cunanje kona cne sume
Ulaz : :
//Inicijalizacija sume
o 0
Za / = 1 do :
{
o o +
/
2
/ + 1
}
Izlaz : o
Ovakav algoritam se naziva ciklicni zbog cinjenice da se jedan korak ponavlja odreen
broj puta. Pri tome to ponavljanje moze biti unaprijed utvreno (kao u ovom slucaju)
ili se operacija obavlja dok se ne postigne odreeni uslov, npr. tacnost racunanja.
Pitanje : Koliko puta se obavi operacija sumiranja o o +
/
2
/ + 1
?
Isti algoritam je mogao biti napravljen na nacin da se u svakom ciklusu ispituje uslov, u
ovom slucaju da li je / dostigao trazenu vrijednost.
U ovom algoritmu je najinteresantniji korak u kojem se ispituje da li je / _ :. Ovo
je potencijalno najveci (i najceci) izvor greke. Ovaj uslov nece nikada vrijediti ako je
: _ 0, jer tekuca promjenljiva / ide od 1 i u svakom koraku postaje veca, ali je realno da,
pod odreenim uslovima, parametar : bude inicijalno zadat kao : = 0. Da bi se otklonio
ovaj rizik potrebno je odmah provjeriti da li je : _ 0 ili ne.
21
Sumiranje - varijanta 2
Ulaz : :
//Inicijalizacija sume
o 0
1 /
a:o o +
/
2
/ + 1
/ / + 1
Ako je / _ : Idi na korak a:
Izlaz : o
Racunanje sume

Citaocu se preputa da napie pseudokod. Tekst programa napisan u programskom jeziku


C++ je dat na sljedecem algoritmu.
NAPOMENA : U tekstu prilozenog C++ programa bitan je korak m=float(k). Ovim
postupkom se cijeli broj pretvara u broj u pokretnom zarezu. Bez ovoga se /
2
, (/ + 1)
racuna kao cjelobrojni kolicnik to je (veliki) gubitak tacnosti. Naprimjer, rezultat cjelo-
brojnog dijeljenja 25,6 daje rezultat 4 dok dijeljenje u realnoj tacnosti daje drugaciji
rezultat. Ako se program pokrene bez ove konverzije za : = 15 dobije se rezultat o = 105
(zato ?) dok se sa konvezijom dobija rezultat o = 107.381. U pseudokodu ova cinjenica
nije igrala bitnu ulogu ali u realnom programiranju ovo je veoma vazan aspekt rada u
C++ programskom jeziku o kojem se treba voditi racuna jer je cest izvor greaka.
Zad. 3.03. Napraviti algoritam za racunanje prvog izvoda polinoma stepena :.
Rjeenje. Neka je polinom dat u optem obliku
1 (r) = c
n
r
n
+c
n1
r
n1
+... +c
1
r +c
0
Prvi izvod ovog polinoma je
1
0
(r) = :c
n
r
n1
+ (: 1) c
n1
r
n2
+... + 2c
2
r +c
1
22
#include <iostream
using namespace std;
int main()
{
int n, k;
float m, S;
cout << "Unesite broj za sumu :";
cin n;
// Inicijalizacija promjenljive S
S=0;
if(n<=0)
{
cout << "Broj n je pogrean" << endl;
system("PAUSE");
}
for(k=1;k<=n;k++)
{
// Konvertovanje cijelog broja u broj u pokretnom zarezu
m = float(k);
S = S+(k*k)/(k+1);
}
cout << "Trazena suma je : " << S << endl;
system("PAUSE");
}
Najlaki nacin racunanja vrijednosti ovog polinoma za datu vrijednost r je sljedeci:
1
0
(r) = (... (:c
n
r + (: 1) c
n1
) r +... + 2c
2
) r +c
1
Slicno kao u prethodnom primjeru, kalkulacija se provodi koritenjem dvije osnovne op-
eracije
o 0
o o r +/ c
k
. / = :. 0. 1
Opisani algoritam je dat na sljedecem dijagramu.
Racunanje prvog izvoda polinoma
23
Jedina razlika u odnosu na prethodni algoritam je vidljiva u koraku o o r +/ c
k
.
Pitanje 1 : U slucaju da se trazi izvod bilo kojeg reda datog polinoma ta bi bio prvi
korak u dizajniranju ovog algoritma ?
Pitanje 2 : Da li je i na koji nacin povecan broj operacija koje se obavljaju prilikom
racunanja prvog izvoda ?
Zad. 3.04. Napraviti algoritam i napisati pseudokod za nalazenje sume
o =
1
sin 1
+
1
sin 1 + sin 2
+
1
sin 1 + sin 2 + sin 3
+... +
1
sin 1 + sin 2 +... + sin :
Rjeenje. U ovom slucaju se radi o dvije sume. Jedna suma se formira u imeniocima
svakog od sabiraka a druga suma se formira putem sabiranja datih razlomaka. Ovo znaci
i odgovarajuce inicijalizacije za dvije sume; neka su to 1 za imenioce i o za sabirke
konacne sume. Suma u imeniocu se formira izrazom 1 1 + sin i, pri cemu i uzima
vrijednost od 1 do :, koje se unaprijed zadaje. Ovo implicira da : ne bi trebalo biti
manje od 1 tako da se na samom pocetku treba ispitivati vrijednost za :. Algoritam je
dat na sljedecem dijagramu.
Algoritam sumiranja
Kritican korak na dijagramu je o o + 1,1; s obzirom da 1 moze imati i veoma
male vrijednosti tada kolicnik 1,1 moze imati vrijednosti koje prelaze zicke mogucnosti
zapisa, to se mora izbjeci. Iz tog razloga se uvodi korak u kojem se ispituje da li je
24
1 < ; ako jeste ne racuna se vrijednost na sljedecem koraku. Ovo je samo jedan od
mogucih izbora, koji moze zavisiti od konkretnog problema u okviru kojeg se algoritam
pravi. Zbog toga se kao ulazna velicina treba uzeti broj 0 kojim se odreuje kriterij
tacnost. Na sljedecem dijagramu je, iz tehnickih razloga, ova velicina oznacena sa c.
Racunanje sume
Pseudokod za ovaj algoritam je dat u nastavku.
Tekst programa napisan u programskom jeziku C++ je dat na prilozenom algoritmu.
U ovom algoritmu je vrena konverzija /,: jer argumenti trigonometrijskih funkcija u
C++ jeziku moraju biti izrazeni u radijanima. Potpuno drugacija bi se vrijednost dobila
ako bi na tom mjestu umjesto float(k)/PI stajalo float(k/PI). U drugom slucaju bi
se konverzija u tip float vrila nakon izracunavanja kolicnika /,:. U ovoj verziji nije
koritena velicina .
Zad. 3.05. Neka je dat niz brojeva r
k
. / = 1. :. Napraviti algoritam koji racuna :
najmanji od datih brojeva
najveci od datih brojeva
i najmanji i najveci od datih brojeva
25
Racunanje suma razlomaka u kojima su imenioci sume sinusa cijelih brojeva, V.2
Ulaz : N,
//Provjeriti vrijednost za :
AkoJe (: < 1) Tada Kraj
//Inicijalizacija
1 0
o 0
Za / = 1 Do : Korak 1 Raditi
{
1 1 + sin i
Ako je ([1[ _ ) Tada
{
o o + 1,1
}
}
Prikazati o
Kraj
Rjeenje. Zadatakce biti rijeen za slucaj nalazenja minimalnog od datih brojeva. Kao i u
prethodnom zadatku, rezultat, npr. velicina `i:, bi trebao biti broj koji se moze koristiti
kao argument za neku drugu funkciju, operaciju i slicno. Prvi problem je inicijalizacija.
Logicno rjeenje je da se kao inicijalna vrijednost uzme prvi clan datog niza koji se poredi
sa preostalim clanovima. Opisani algoritam je na sljedecem dijagramu.
Nalazenje minimalnog broja u datom nisu
Pseudo kod za ovaj algoritam je dat u nastavku.

Citaocu se preputa da napravi odgovarajuci algoritam za nalazenje najveceg broja datog


niza.
Za nalazenje istovremeno i najveceg i najmanjeg clana datog niza brojeva potrebno je
raditi kao i u prethodnom zadatku sa manjom izmjenom u segmentu ispitivanja.
26
// Zad. 3.04. Racunanje sume
#include <iostream
#include <cmath
using namespace std;
int main()
{
// Denisanje konstante PI
const double PI(3.141592654);
int n, k;
float R, S;
cout << "Unesite broj za sumu :";
cin n;
R=0;
S=0;
if(n<=0)
{
cout << "Broj n je pogrean" << endl;
system("PAUSE");
}
for(k=1;k<=n;k++)
{
// Najprije se izracuna nova vrijednost sume u imeniocu...
R=R+sin(float(k)/PI);
// ...a zatim se racuna suma S
S=S+1/R;
}
cout << "Trazena suma je : " << S << endl;
system("PAUSE");
}
Algoritam : Nalazenje minimalnog broja u nizu
Ulaz : r.
`i: r
1
Za / = 1 do :
{
Ako je r
k
< `i: tada
{
`i: r
k
}
}
Izlaz : `i:
27
Istovremeno nalazenje minimalnog i maksimalnog elementa iz niza brojeva
Pseudokod za ovaj algoritam je prilozen.
Algoritam : Istovremeno nalazenje minimalnog i maksimalnog broja u nizu
Ulaz : r.
`i: r
1
`cr r
1
Za / = 1 do :
{
Ako je r
k
< `i: tada
{
`i: r
k
}
Ina ce
{
Ako je r
k
`cr tada
{
`cr r
k
}
}
}
Izlaz : `i:. `cr
Listing C++ programa za rjeavanje ovog problema je u nastavku.
Zad. 3.06. Napraviti algoritam za racunanje sume
o =
1

i=1
1
i
3
28
// Nalazenje minimalnog i maksimalnog elementa datog niza.
#include <iostream
using namespace std;
int main()
{
int x[]={2,-3,7,1,14,4,8,-1,9,12}
int Mak, Min;
int k;
Mak=x[0];
Min=x[0];
for(k=1;k<10;k++)
{
if(Mak<x[k])
{
Mak=x[k];
}
if(Minx[k])
{
Min=x[k];
}
}
// Sada treba dati odgovarajuce poruke
cout << "Najveci broj je : " << Mak << endl;
cout << "Najmanji broj je : " << Min << endl;
system("PAUSE");
}
29
Rjeenje. U ovom zadatku je osnovni problem kriterij zaustavljanja zbog principa kon-
acnosti - algoritam koji traje beskonacno je besmislen. Kad su u pitanju algoritmi sumi-
ranja redova, osnovni kriterij zaustavljanja je razlika izmeu dvije uzastopne parcijalne
sume. Ako je ta razlika manja od nekog unaprijed zadatog broja postupak sumiranja
se zaustavlja jer dodavanje novih clanova ne povecava bitno tacnost racunanja :
[o
k+1
o
k
[ <
Ovo znaci da je u dizajnu algoritma na svakom koraku potrebno imati dvije uzastopne
parcijalne sume koje se porede. Ulazni parametar za ovaj algoritam, dat na narednom
dijagramu, je broj , odabrani nivo tacnosti racunanja.
Sumiranje redova - varijanta 1
Pseudo kod za ovaj algoritam je dat u nastavku.
Algoritam : Sumiranje redova - varijanta 1
Ulaz :
/ 1
o
1
/
a: o
2
o
1
+
1
/
3
Ako je [o
2
o
1
[ < tada
{
Zavriti
}
Ina ce
{
o
1
o
2
/ / + 1
Idi na a:
}
Izlaz : Suma
Alternativni izgled ovog algoritma je u nastavku.
30
Algoritam : Sumiranje redova - varijanta 1a
Ulaz :
/ 1
o
1
/
a: o
2
o
1
+
1
/
3
Ako je [o
2
o
1
[ < tada Izlaz:
// Ako ne vrijedi gornji uslov nastavljaju se naredbe nakon uslova "Ako ..."
o
1
o
2
/ / + 1
Idi na a:
Izlaz : Suma
Ovakav dizajn je pogodan u slucajevima kada programski jezik omogucava realizaciju
naredbe bezuslovnog skoka "Idi na a:".

Ceci je dizajn dat na narednom dijagramu.
Sumiranje redova - varijanta 2
Pseudo kod za ovaj algoritam je dat u nastavku.
U oba slucaja, broj koraka u kojem se racuna suma je odreen velicinom .
Zad. 3.07. Dat je realni broj r. Izracunati cijeli dio broja (najveci cijeli broj koji nije
veci od r), broj zaokruzen do najblizeg cijelog broja, cjelobrojni dio broja bez decimalnog
dijela. U matematici se ovaj broj obiljezava sa r| (oor). Pri tome se treba koristiti
standardnim operacijama (mnozenje, sabiranje, ...) odnosno smatra se da nisu raspolozive
interne funkcije kao to je [r[ i slicno.
Rjeenje. Da bi se naao cjelobrojni dio najprije se mora naci broj cijelih mjesta. Nakon
toga se trazi cjelobrojni dio unatrag po pozicijama.
Prvi dio zadatka se rjeava tako da se broj dijeli sa 10 (odnosno osnovom brojnog sis-
tema) dok se ne doe do broja koji je manji od 1. Ovo je ekvivalentno pomjeranju
31
Algoritam : Sumiranje reda - varijanta 2
Ulaz :
/ 1
o
1
0
o
2
/
SveDokJe([o
2
o
1
[ )
{
/ / + 1
o
1
o
2
o
2
o
1
+
1
/
3
}
Izlaz : o
2
decimalnog zareza ulijevo za po jednu poziciju prilikom svakog dijeljenja. Algoritam je
dat na sljedecem dijagramu. Funkciju brojaca cifara ima promjenljiva /.
Racunanje broja cifara realnog broja r
Pseudo kod je dat u nastavku
Algoritam : Nalazenje broja cifara realnog broja
Ulaz :
/ 0
c r
SveDokJe(c 1)
{
/ / + 1
c c,10
}
Izlaz : /
Jedno od vaznijih pitanja na ovom mjestu je : koliko puta se obavlja dijeljenje sa 10 da
bi se dobio broj cifara ? Ako se podsjetimo da je karakteristika logaritma realnog broja
jednaka broju cifara cjelobrojnog dijela umanjen za 1 onda je odgovor jasan : da bi se
dobio broj cifara realnog broja potrebno je log r| + 1 dijeljenja.
32
Drugi dio problema, nalazenje cjelobrojnog dijela, je neto kompleksniji jer su mnozenje
i uporeivanje jedini mehanizam. Da bi se problem rijeio potrebno je pripremiti radnu
promjenljivu, nazovimo je c,, i / puta uraditi sljedece :
- Vrijednost c pomnoziti sa 10
- Vrijednost c, postaviti na (c, + 1) 10
- Umanjivati c, za po 1 i na svakom koraku ispitivati da li je c, _ c; ako taj uslov vrijedi
nali smo cijeli broj koji nije veci od c; ovakvih oduzimanja na svakom koraku moze biti
najvie 10
Opisani algoritam je na narednom dijagramu
Nalazenje cjelobrojnog dijela realnog broja r
Pseudo kod ovog algoritma je u nastavku
NAPOMENA. Realni broj r se u racunaru zapisuje u formatu pokretnog zareza odnosno
u formatu koji odgovara zapisu r = r
M
10
x
E
gdje su :
r
M
: Signikand, broj r
M
[0; 1)
r
E
: Eksponent, cijeli (pozitivni ili negativni) broj
U skladu sa standardima, koji su izdati od strane IEEE, u ovoj deniciji je termin "man-
tisa" zamijenjen terminom "signikand" kako bi se izbjegle terminoloke nejasnoce koje
se mogu pojaviti zbog znacenja kojeg termin "mantisa" ima za logaritme. U jednom
broju tekstova se uzima da signikand ima vrijednosti u intervalu [1. 10) ali je znacenje
identicno.
Zad. 3.08. Napraviti program za racunanje proizvoda matrica
33
Algoritam : Nalazenje cjelobrojnog dijela decimalnog broja
Ulaz :
/ 0
c r
SveDokJe(c 1)
{
/ / + 1
c c,10
}
c, 0
Za i = 1 do /
{
c c 10
c, (c, + 1) 10
1 :
SveDokJe(: _ 10)
{
c, c, 1
Ako je c, _ c tada IdiNa b:
}
b:
}
Izlaz : /

mn
1
np
= C
mp
Rjeenje. Dijagram za ovaj problem je dat u nastavku.
34
Ilustracija uz zadatak 3.0. Proizvod matrica
U ovom slucaju je i brojac za redove prve matrice, , je brojac za kolone druge matrice a
/ je brojac za elemente u skalarnom proizvodu (kolone prve matrice). Treba uociti korak
inicijalizacije c (i. ,) = 0 zbira proizvoda. Pseudo kod je lako napraviti na osnovu ovog
dijagrama. U nastavku je C++ program.
3.4 Zadaci za vjezbu
Zad. V.3.01. Dat je prirodan broj :. Izracunati:
o =
_
1 +
1
1
2
__
1 +
1
2
2
_
...
_
1 +
1
:
2
_
o =
_
2 +
_
2 +... +
_
2
. .
n korijena
o =
cos 1
sin 1
+
cos 1 + cos 2
sin 1 + sin 2
+
cos 1 + cos 2 + cos 3
sin 1 + sin 2 + sin 3
+... +
cos 1 + cos 2 +... + cos :
sin 1 + sin 2 +... + sin :
o =

_
3 +
_
6 +
_
9 +... +
_
3 (: 1) +
_
3:
35
// Proizvod matrica
#include <iostream
#include <cmath
using namespace std;
int main()
{
// Denisanje matrica
int a[3][4]={{2,7,3,8},{-2,-1,5,4},{0,-3,7,-2}};
int b[4][2]={{1,3},{-2,-5},{8,-3},{9,4}};
int c[3][2]={{},{},{}};
// Brojaci na ucitavanju
int i, j, k;
// Deklaracija niza; uzeto je da je niz cjelobrojni
cout << "Najprije cemo izlistati matrice A i Bn" << endl;
cout << "Matrica A je : n" << endl;
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
// Ispis jednog reda; clanovi se odvajaju znakom tab
{
cout << a[i][j] << "t";
}
// Novi red nakon ispisanog reda
cout << "n";
}
// Prelazak na novi red
cout << "n" << endl;
// Sacekaj dok se ne pritisne taster
system("PAUSE");
cout << "Matrica B je : n" << endl;
for(i=0;i<4;i++)
{
for(j=0;j<2;j++)
// Ispis jednog reda; clanovi se odvajaju znakom tab
{
cout << b[i][j] << "t";
}
// Novi red nakon ispisanog reda
cout << "n" << endl;
}
// Prelazak na novi red
cout << "n" << endl;
// Sacekaj dok se ne pritisne taster
system("PAUSE");
// Nastavak na sljedecoj strani ....
36
// Nastavak sa prethodne strane
// Sada pocinje zabava
// Za svaki red matrice A...
for(i=1;i<3;i++)
{
// ...uzimamo jedan red matrice B...
for(j=1;i<2;i++)
{
// ...iniciramo sumu...
c[i][j]=0;
for(k=0;k<4;k++)
{
// Racunamo element c(i,j)
c[i][j]=c[i][j]+a[i][k]*b[k][j];
}
}
}
cout << "Matrica C je : n" << endl;
for(i=0;i<3;i++)
{
for(j=0;j<2;j++)
// Ispis jednog reda; clanovi se odvajaju znakom tab
{
cout << c[i][j] << "t";
}
// Novi red nakon ispisanog reda
cout << "n" << endl;
}
// Prelazak na novi red
cout << "n" << endl;
// Sacekamo da vidimo je li sve u redu
system("PAUSE");
}
37
Zad. V.3.02. Dat je realni broj r. Izracunati
1 =
(r 2) (r 4) ... (r 64)
(r 1) (r 3) ... (r 63)
Zad. V.3.03. Dat je realan broj c i prirodni broj :. Izracunati:
1 = c
n
1 = c (c + 1) (c + 2) ... (c +: 1)
o =
1
c
+
1
c (c + 1)
+... +
1
c (c + 1) ... (c +:)
o =
1
c
+
1
c
2
+
1
c
4
+... +
1
c
2
n
1 = c (c :) (c 2:) ... (c :
2
)
Zad. V.3.04. Za dati prirodni broj : izracunati
o =
n

k=1
1
/
o =
n

k=1
1
/
5
o =
n

k=1
1
(1 + 2/)
2
o =
n

k=1
(1)
k
(2/ + 1) /
o =
n

k=1
(1)
k+1
(/ + 1) /
o =
n

k=1
(1)
k
(/ + 1)
/!
o =
n

k=1
/!
1
2
+
1
3
+... +
1
/ + 1
Zad. V.3.05. Dati su pozitivni realni brojevi r. c. .U nizu
1
.
2
. ... koji je formiran po
pravilu

0
= c.
k
=
1
2
_

i1
+
r

i1
_
naci prvi : za koji vrijedi nejednakost

2
i

2
i1

< .
Zad. V.3.06. Neka je
r
0
= 1; r
k
=
2 r
3
k1
5
Naci prvi clan r
n
za koji vrijedi [r
n
r
n1
[ < 10
5
.
Zad. V.3.07. Neka je

0
= 0;
k
=

k1
+ 1

k1
+ 2
38
Za dati realni broj 0 naci prvi clan
n
za kojeg vrijedi
n

n1
< .
Zad. V.3.08. Dat je realni broj c 0. Formiran je niz
r
0
=
_

_
min 2c; 0.95 c _ 1
c
5
1 < c < 25
c
25
inace
r
n
=
4
5
r
n1
+
c
5r
4
n1
. : = 1. 2. ...
Naci prvi clan r
n
za koji vrijedi
5
4
c [r
n+1
r
n
[ < 10
6
. Za pronaenu vrijednost clana
r
n
naci razliku c r
5
n
.
Zad. V.3.09. Za dati realni broj r i prirodni broj : izracunati
r
n
2
,2
n
r
n
3
,3
n
Zad. V.3.10. Za date realne brojeve c. / (/ c) i prirodni broj : izracunati (,
1
+,
2
+... +,
n
)
/ gdje je
/ =
/ c
:
,
i
=
c +
_
i
1
2
_
/
1 +
_
c +
_
i
1
2
_
/
_
2
. i = 1. 2. .... :
Zad. V.3.11. Izracunati beskonacne sume sa datim nivoom tacnosti 0. Smatrati
da je potrebna tacnost dostignuta ako se suma na nekom koraku razlikuje za manje od
od prethodne sume.

i=1
1
i
2

i=1
1
i (i + 1)

i=1
(1)
i
i!

i=1
(2)
i
i!

i=1
(1)
i+1
i (i + 1) (i + 2)

i=1
1
4
i
+ 5
i+2
Zad. V.3.12. Dati su prirodan broj : i realan broj c 0. Niz r
0
. r
1
. r
2
. ... je formiran
po pravilu
r
0
= c. r
k
=
/ 1
/
r
i1
+
c
r
k1
i1
Naci prvu vrijednost r
n
za koju je

r
k
n
c

< 10
4
(Niz r
i

i2N
konvergira ka
k
_
c).
Zad. V.3.13. Dat je realan broj c. Naci:
39
Prvi od brojeva
1. 1 +
1
2
. 1 +
1
2
+
1
3
. ...
koji je veci od c.
Najmanje : za koje vrijedi da je
1 +
1
2
+
1
3
+... +
1
:
c
Zad. V.3.14. Dati su prirodan broj : i realni broj r. Izracunati sume :
o = sin r + sin
2
r + sin
3
r +... + sin
n
r
o = sin r + sin (r
2
) + sin (r
3
) +... + sin (r
n
)
o = sin r + sin sin r +... + sin sin ... sin r
(u posljednjem clanu funkcija sin se primjenjuje : puta).
Zad. V.3.15. Izracunati sljedece proizvode.
1 =
n

k=1
_
1 +
sin (/r)
/!
_
1 =
n

k=1
(1 r)
k+1
+ 1
((/ 1)! + 1)
2
Zad. V.3.16. Sumu
1
1
2
+
1
3
... +
1
9999

1
10000
na sljedeca cetiri nacina:
slijeva udesno clan po clan
slijeva udesno tako da se najprije izracuna suma neparnih clanova
1 +
1
3
+
1
5
+... +
1
9999
zatim suma parnih clanova
1
2
+
1
4
+
1
6
+... +
1
9998
+
1
10000
a zatim napravi razlika te dvije sume.
zdesna na lijevo clan po clan
zdesna na lijevo sume pod tackom b a zatim te dvije sume oduzmu.
Da li se i zato dobijaju razliciti rezultati ?
Zad. V.3.17. Napraviti algoritam koji ce tabelirati vrijednost polinoma
1
n
(r) = c
0
+c
1
r +... +c
n1
r
n1
+c
n
r
n
za vrijednosti argumenta r koji se mijenjaju intervalu (r
a
. r
b
) sa korakom r.
Zad. V.3.18. Napraviti algoritam koji za zadate brojeve : i / racuna velicinu
_
:
/
_
=
:!
/! (: /)!
40
4 Analiza kompleksnosti algoritama na primjerima
4.1 Uvod
U ovom dijelu ce biti naveden jedan broj primjera analize slozenosti algoritama na nacin
da se nae to je moguce tacniji broj koraka. Na taj se dobija podatak o vremenskoj
slozenosti programa odnosno pokazatelju o mogucem vremenu trajanja odreenog algo-
ritma.
4.2 Zadaci
Primjer. Sekvencijalno sumiranje
U nastavku je pseudo kod za jednostavan slucaj sekvencijalnog sumiranja.
# Sumiranje Opis
1 Sumiraj(a,n) Ulaz : niz [c] duzine :
2 on:c 0 Inicijalizacija
3 Za i = 1 do : { Pocetak petlje
4 on:c on:c +c [i] Sumiranje
5 }
Korak na liniji 2 se izvrava jednom. Petlja sa pocetkom na liniji 3 se izvrava : puta;
na svakom koraku te petlje se izvravaju dvije operacije na liniji 4 to znaci da je okvirni
broj koraka dat sa 1 (:) = 2: + 1.
Primjer. Ugnjezdena petlja
U ovom primjeru je prezentirana analiza slucaja kada je jedna petlja unutar druge (ugn-
jezdena petlja).
# Sumiranje Opis
1 Sumiraj(a,n) Ulaz : niz [c] duzine :
2 Za i = 1 do : { Pocetak spoljne petlje
3 on:c 0 Inicijalizacija sume
4 Za , = i + 1 do : { Pocetak unutranje petlje
5 on:c on:c +c [i] Sumiranje
6 }
7 Ispisati : on:c Ispisivanje meu sume
8 }
Spoljanja petlja, koja pocinje na liniji 2, se izvrava : puta. U svakom koraku se izvrava
inicijalizacija na liniji 2, rokoja se racuna kao jedan korak.
Unutranja petlja pocinje na liniji 4. Ako je i = 1 ona se ponavlja : 1 puta; ako je
i = 2 ona se ponavlja : 2 puta itd. U svakom od tih koraka se izvrava linija 5 koja
sadrzi dvije operacije. Linija 7 se izvrava jednom u svakom od : koraka. Ovo znaci da
je broj operacija u ovom algoritmu
1 (:) = 1 + 4: +
n

i=1
2 (i 1) =
41
= 1 + 4: + 2
n

i=1
(i 1) = 1 + 4: + 2
:(: 1)
2
1 (:) = :
2
+ 3: + 1
Zakljucak je da ovaj algoritam ima kvadratnu brzinu : ako se obim niza poveca dva puta
broj koraka se poveca barem 4 puta.
Primjer. Sumiranje
U sljedecem primjeru je prezentirano sumiranje posljednjih pet clanova odabranog niza.
# Sumiranje Opis
1 Sumiraj(a, n) Ulaz : niz [c] duzine :
2 Za i = 5 do : { Pocetak spoljne petlje
3 on:c c [i 4] Iniciranje sume clanom c [i 4]
4 Za , = i 3 do i { Pocetak unutranje petlje
5 on:c on:c +c [,] Sumiranje
6 }
7 Ispisati on:c Ispisivanje on:c
8 }
Spoljanja petlja, koja pocinje na liniji 2, se izvrava : 4 puta. U svakom koraku se
izvrava inicijalizacija vrijednosti on:c i to sa clanom koji je pet pozicija udaljen od
pozicije clana od kojeg pocinje sabiranje. Ako je i = 5 tada je on:c c [1] itd. Ova op-
eracija traje jedan korak. Petlja na liniji 4 se izvrava 4 puta, za c [i 3] . c [i 2] . c [i 1]
i c [i]. U svakom koraku te petlje se izvode dvije operacije na liniji 5. Ispisivanje, na liniji
7, traje jedan korak. To znaci da je okvirni broj operacija u ovom algoritmu
1 (:) = 1 + 10 (: 4) = 10: 39
Zakljucak je da ovaj algoritam ima linearnu brzinu.
Primjer. Binarno pretrazivanje
Ovo je jedan od veoma cestih metoda pretrazivanja. Polazna osnova je niz duzine :
koji je sortiran rastucim redoslijedom i u kojem se treba pronaci vrijednost oznacena sa
1|,nc. Nacin na koji se obavlja ovaj posao je sljedeci:
Nae se "srednji" clan niza i 1|,nc uporedi sa tim clanom
Ako je 1|,nc manji od te vrijednosti tada se pretrazuje prva polovina niza; u
suprotnom pretrazuje se gornja polovina niza
Ovaj postupak se nastavlja sve dok se broj clanova za pretrazivanje ne svede na 1
Opisani postupak je opisan sljedecim pseudo kodom.
42
# Binarno pretrazianje niza Opis
1 BinPret(c. :. 1|,nc) Ulaz : niz [c], : i 1|,nc
2 1o 1 Inicijalna vrijednost za donju granicu
3 Hi : Inicijalna vrijednost za gornju granicu
4 SveDokJe(1o _ Hi){
5 `id
1
2
(1o +Hi) Racunanje indeksa srednjeg clana
6 Ako Je (1|,nc < c (`id)) tada { Ako je trazeni element manji od c (`id) . . .
7 Hi `id 1 `id postaje gornja granica donje polovine niza
8 }
9 Inace Ako Je (1|,nc c (`id)) tada { Ako je trazeni element veci od c (`id). . .
10 1o `id + 1 `id postaje donja granica gornje polovine niza
11 }
12 Inace { Ako je trazeni element jednak c (`id). . .
13 Poruka : 1|,nc = c (`id) Izlaz Pronaen je 1|,nc
14 }
15 }
16 }
17 Poruka : Element nije pronaen 1|,nc nije pronaen
Ako je trazena vrijednost u sredini (sortiranog) niza petlja, koja pocinje na liniji 4, se
izvrava samo jednom.
U prvom prolazu se analizira niz duzine :, u narednom koraku niz duzine :,2, zatim niz
duzine :,2
k
i tako redom do duzine 1. Ovdje / oznacava koliko puta je vreno dijeljenje
sa 2. To znaci da za posljednji korak mora vrijediti
:
2
k
= 1 = : = 2
m
= log : = : log 2 = : =
log :
log 2
= log
2
: := lg 2
Na ovaj nacin je dobijena procjena maksimalnog broja koraka za postupak binarnog
pretrazivanja. Ako bi se broj elemenata povecao dva puta broj pretrazivanja bi bio
mnogo manji odnosno ne bi bio dvostruko veci to je znacajna uteda vremena rada.
4.3 Analiza kompleksnosti nekih tipova algoritama
4.3.1 Algoritmi konstantnog vremena
Primjer algoritma konstantnog vremena je izbor broja iz liste. Nije bitno koliko je lista
dugacka. U jednom koraku se odabire jedan broj i posao se zavrava. Ako se ulaz poveca
: puta vrijeme izvrenja se ne povecava odnosno "mijenja" se za faktor 1. U tom slucaju
se kaze da algoritam ima brzinu O(1).
2
Prosta naredba ima (1) vrijeme to je i razlog za naziv. Niz mnogo jednostavnih naredbi
jo uvijek se izvrava u vremenu (1) .
2
Znacenje ce biti dato u poglavlju o asimptotskoj procjeni kompleksnosti
43
Primjer iz realnog zivota je izbor prvog dokumenta sa vrha gomile. Nije vazno kolika je
gomila. Algoritmi sa konstantnim vremenom su najbolji moguci algoritmi ukoliko vrijeme
same operacije nije predugacko. Primjeri ovih algoritama su:
- Push i Pop operacije na stack-u (koji sadrzi : elemenata);
- Operacije umeatanja i uklanjanja u redu za izvrenje
4.3.2 Algoritmi u linearnom vremenu
Primjeri ovih algoritama su:
- Prolazak kroz listu (povezane liste ili niza) sa : elemenata
- Nalazenje maksimalnog ili minimalnog elementa u listi ili sekvencijalno pretrazivanje
nesortirane liste od : elemenata
- Prolazak stabla sa : cvorova
- Iterativno racunanje faktorijela broja :;
- Iterativno nalazenje :-tog Fibonacijevog broja
- Utvrivanje da li je broj paran ili ne
Linearni algoritmi su veoma uobicajeni u programiranju i generalno su prihvaceni kao
ekasni ako ne postoji bolji poznati nacin za njegovo ubrzanje.
Primjer programskog koda je :
for (int i = 0; i < n; i += c) // O(n)
naredba(s);
Dodavanje konstante c brojacu petlje znaci da vrijeme trajanja petlje raste linearno u
odnosu na maksimalnu vrijednost za :. U ovom slucaju se petlja izvrava tacno :,c puta.
Analogno vrijedi ako se brojac i smanjuje za konstantu c.
4.3.3 Algoritmi sa kvadratnim vremenom
Primjeri ovih algoritama su :
- Neki jednostavniji algoritmi sortiranja npr. selection sort : elemenata
- Poreenje dva dvodimenzinalna niza od po : : elemenata
- Nalazenje duplikata u nesortiranoj listi od : elemenata (implementirano sa dvije ugn-
jezdene petlje)
Broj operacija, u oznaci O(:
2
), je proporcionalan kvadratu dimenzije resursa sa kojim
se radi.
Primjer programskog koda je :
for (int i = 0; i < n * n; i += c) // O(n
2
)
naredba(s);
Maksimum petlje je :
2
tako da je vrijeme izvrenja kvadraticno. U ovom slucaju petlja
se izvrava tacno :
2
,c puta.
Primjer ugnjezdene petlje je :
for (int i = 0; i < n; i += c) { // O(n
2
)
for (int j = 0; j < n; i += c)
{
naredba(s);
}
44
}
Primjeri algoritama brzine C(:
c
), c 1 su:
- Parsiranje putem stablasto udruzenih gramatika (tree-adjoining grammar parsing),
- Maksimalno poklapanje (matching) dva bipartitna grafa
4.3.4 Algoritmi sa logaritamskim vremenom
Primjeri ovih algoritama su
- Binarno pretrazivanje sortirane liste od : elemenata
- Operacije umetanja i nalazenja binarnog stabla sa : cvorova
- Operacije umetanja i uklanjanja u skupu (heap) sa : cvorova
Brzina ovih algoritama, u oznaci O(log :), raste sporije od velicine ulaza. Ako se ulaz
udvostruci vrijeme izvoenja se samo malo produzi. Klasican primjer algoritma u logari-
tamskom vremenu je binarno pretrazivanje. Primjer je poznata igra "pogaanje brojeva".
U toj igri jedan igrac mora pogoditi broj koji zamisli drugi igrac. Na svakom koraku se
vri pogaanje na nacin da saigrac kaze da li je predlozeni broj veci ili manji. Ako je broj
izmeu 1 i 100 prvi prijedlog je 50. Time se prostor pogaanja smanjuje za polovinu.
Naredni korak je predlaganje broja koji je u polovini odgovarajuceg intervala cime se
(grubo) suzava krug brojeva za pogaanje. Ako se u toj igri pocetni opseg udvostruci
broj pogaanja se ne udvostrucava. Ako se ulaz poveca : puta potrebno je log
2
: = lg :
koraka dok se ne doe do inicijalnog opsega.
Primjer programskog koda je :
for (int i = 1; i < n; i *= c) // O(log n)
naredba(s);
Mnozenje brojaca petlje konstantom c znaci da maksimalna vrijednost za : mora rasti
eksponencijalno kako bi se vrijeme izvrenja petlje povecavalo linearno pa je iz tog razloga
vrijeme izvrenja logaritamsko. U ovom slucaju je c
k
= :, gdje je / broj prolaza. Na
osnovu ovoga je / = log
c
:. Analogno vrijedi ako se brojac smanjuje za konstantni faktor
c.
Brzinu O(:log :) = O(log :!) (linearitamsko, loglinear, quasilinear) imaju operacije
provoenja Furijeove transformacije, algoritmi sortiranja, kao to su quick sort, merge
sort heap sort.
4.3.5 Algoritmi brzine
_
:
Ovi algoritmi se izvravaju proporcionalno kvadratnom korijenu od : (velicina ulaza). U
ovom slucaju se izvrava petlja u kojoj i pocinje naprimjer od 1 i pravi se korak koji se
multiplikativno povecava za konstantu dok se ne postigne uslov i + i < :. Ova petlja se
nece izvriti svih : puta vec ce se zaustaviti kada i dostigne
_
:. Stoga ona ima vrijeme
(
_
:).
Primjer ovog algoritma je trazenje odgovora na pitanje da li je broj : prost. Odgovor
se moze dobiti tako da se provjerava da li je djeljiv sa svim brojevima koji su manji od
njega. Ako je : = 100 tada se moze stati ako je djelilac veci od 10 koji je
_
100.
45
4.3.6 Algoritmi sa eksponencijalnim vremenom
Primjeri ovih algoritama su:
- Problem trgovackog putnika
- Rekurzivna implementacija generisanja Fibonacijevih brojeva
- Hanojski tornjevi
- Generisanje svih permutacija od : elemenata
- Racunanje determinante putem racunanja minora
Ba kao to postoje algoritmi na koje povecanje obima ulaza nema uticaja postoje al-
goritmi za koje se cini da vrijeme izvrenja eksplodira. Kaze se da se eksponencijalni
algoritmi izvravaju u C(c
n
) ili eksponencijalnom vremenu.
Klasicni primjer algoritma sa eksponencijalnim vremenom izvrenja je Problem trgov-
ackog putnika (Traveling Salesman Problem - TSP), koji je do sada najvie izucavan u
teoriji algoritama. Zadatak je jednostavan. Dato je : gradova; trgovacki putnik mora
obici svaki grad tacno jednom prije nego ode kuci. Cilj je to uciniti na najbolji moguci
nacin bilo da je u pitanju najjeftiniji ili najkraci put. Pod najoptijim pretpostavkama,
jedini poznati nacin pouzdanog rjeavanja problema je da se ispita svaki moguci put i da
se odabere najbolja. Ne postoji poznati nacin da se eliminie razumni dio putanja bez
provjere svake od njih. Broj putanja je :!.
Algoritme sa eskponencijalnim vremenom izvrenja je potrebno izbjegavati to je vie
moguce. Umjesto direktnog rjeavanja traze se "heuristike" koje su kraci nacini da se
dobiju dobri rezultati ali to nije garancija da su oni i najbolji moguci. Heuristika za
problem trgovackog putnika moze biti : idi na najblizi neposjeceni grad; zatim povezi par
najblizih gradova. Dobra heuristika moze biti teka ali je dobit u programskom rjeenju.
Postoje bitne razlike izmeu pojedinih eksponencijalni algoritama.
Formalno gledano, vrijedi sljedeci odnos brzina algoritama
O(1) < O(log log :) < O(log :) < O(:) < O(:log :) < O(:
2
) < O(:
2
log :) <
O(:
3
) < ... < O(c
n
) < O(:!) < O(:
n
)
4.3.7 Kombinacije algoritama
Nizovi naredbi. Za sekvence naredbi, ukljucujuci moguce cijele blokova naredbi, uzima
se najgore moguce vrijeme izvrenja od svih naredbi. Naprimjer, blok vremena log : iza
kojeg slijedi linearni blok ima ukupno vrijeme koje je linearno; efekat log : petlje naprosto
icezava. Ne treba previe brinuti. Stara engleska izreka kaze : brini o dolarima a centi
ce se brinuti sami za sebe.
Konstrukcije Ako ... inace ... Za ove konstrukcije se uvijek uzima najgori moguci
slucaj ako ne postoji sigurnost ta ce se desiti. Najgori slucaj u bilo kojoj konstrukciji
ovog tipa je da se izvrava bilo Ako bilo ina ce dio, koji god da je od njih najgori. Iz
prakticnih razloga se uzima kako da se deavaju obje strane.
U izboru najgoreg moguceg slucaja mogu se slijediti dva prosta pravila.
1. Ako vrijeme ukljucuje stepen od : kao to je :
2
ili :
1=2
tada je blok sa vecim stepenom
od : gori
2. Ako su stepeni od : jednaki ili ako nema stepena od : blok sa vie log : je loiji
46
Naprimjer, ako se poredi :
_
:lg : sa lg
3
: prvi broj ima stepen :
1;5
dok drugi ima 0 kao
stepen za :. Dakle, prvi od njih je loiji.
Petlje. Vrijeme izvrenja jednostavne petlje (koja sadrzi samo jednostavne naredbe)
zavisi od toga koliko puta se petlja izvrava. Vrijeme petlji u nizu se sabira to znaci da
dominira petlja sa vecim vremenom izvrenja. Primjer je :
for (int i = 0; i < n; i += c) { // O(n)
naredba;
}
for (int i = 0; i < n; i += c) { // O(n log n)
for (int j = 0; j < n; i *= c) {
naredba;
}
}
Ugnjezdeni blokovi. Ako je blok ugraen unutar drugog bloka efekti se multipliciraju.
Ukupno vrijeme izvrenja postaje (:
2
). Primjer je poreenje dvije nesortirane liste
kako bi se vidjelo da li je neka stavka sadrzana u obje liste. Uzima se element prve liste i
poredi sa svakim elementom druge liste to uzima vrijeme reda :. S obzirom da se posao
ponavlja za : elemenata druge liste obavlja se :: = :
2
operacija poreenja. Dupliranje
obima ulaza ima za posljedicu cetiri puta duze vrijeme izvrenja.
47
5 Asimptotska procjena slozenosti algoritma
5.1 Uvod

Cesto je teko, pa i nemoguce, izvesti egzaktnu formulu za broj operacija nekog algoritma.
Zato se proucava asimptotsko ponaanje broja operacija kad velicina ulaznih podataka
neograniceno raste. Najpoznatije asimpotske notacije slozenosti algoritma su: -notacija,
O-notacija i -notacija.
5.1.1 -notacija
Denicija. Neka je q (:) funkcija denisana na nekom podskupu skupa prirodnih brojeva
i ciji je skup vrijednosti neki podskup skupa realnih brojeva. Sa (q (:)) se oznacava
skup funkcija , (:) takvih da postoje pozitivne konstante c
1
, c
2
i prirodan broj :
0
takvi
da je
0 _ c
1
q (:) _ , (:) _ c
2
q (:) za svako : _ :
0
Ovdje oznacava klasu funkcija a , (:) = (q (:)) je oznaka za inkluziju , (:)
(q (:)).
Primjer 1. Neka je , (:) =
2
3
:
2
:, : N. Tada je , (:) = (:
2
). Najprije, vrijedi
c
1
:
2
_
2
3
:
2
: _ c
2
:
2
za svako :
0
_ : ako i samo ako c
1
_
2
3

1
n
_ c
2
za svako
:
0
_ :. Odavdje slijedi da mora biti c
2
_
2
3
. Kako c
1
mora biti pozitivan broj to mora
biti
2
3

1
n
_ 0. To znaci da je dovoljno uzeti :
0
= 3. Iz c
1
_
2
3

1
3
slijedi c
1
_
1
3
. Dakle,
vrijedi da je
1
3
:
2
_ , (:) _
2
3
:
2
za svako : _ 3.
Primjer 2. Neka je , (:) = c:
2
+ /: + c gdje su c. /. c konstante i c 0. Da li je
, (:) = (:
2
) ? Potrebno je odrediti konstante c
1
i c
2
i prirodan broj :
0
takve da je
c
1
:
2
_ c:
2
+/:+c _ c
2
:
2
za svako : :
0
. Neka je c
1
< c i c
2
c. Tada su nejednacine
(c c
1
) :
2
+/: +c _ 0 i (c
2
c) :
2
+/: +c _ 0 zadovoljene za sve prirodne brojeve :
0
takve da je :
0
max r
1
. r
2
.
1
.
2
gdje su r
1
i r
2
nule polinoma (c c
1
) :
2
+/:+c a
1
i
2
nule polinoma (c
2
c) :
2
+/: +c ako postoje; ako ne postoje onda je :
0
= 1. znaci,
vrijedi , (:) (:
2
). Takoe, ako je , (:) polinom stepena : ciji je vodeci koecijent
pozitivan onda je , (:) = (:
m
).
5.1.2 O-notacija
Denicija. Neka je q (:) realna funkcija denisana na nekom podskupu skupa prirod-
nih brojeva. Sa O(q (:)) se oznacava skup realnih funkcija , (:) denisanih na nekom
podskupu skupa realnih brojeva takvih da postoji pozitivna konstanta c i prirodan broj
:
0
takvi da je
0 _ , (:) _ c q (:) . za svako : _ :
0
Ovdje O oznacava klasu funkcija a , (:) = O(q (:)) je oznaka za inkluziju , (:)
O(q (:)). Treba primijetiti da , (:) = (q (:)) povlaci , (:) = O(q (:)).
Velicina O() se tumaci tako da je q (:) gornja granica za , (:). U tom smislu, oznaka
, (:) = O(q (:)) se tumaci da ", ne raste brze od q".
48
Notacija Veliko-O (O) ima dvije glavne oblasti primjene. U matematici se obicno koristi
da opie koliko blisko konacni niz aproksimira datu funkciju, posebno u slucaju skracenog
(truncated) Tejlorovog niza ili asimptotske ekspanzije. U kompjuterskoj nauci je korisna
za analizu algoritama. U obje vrste primjene funkcija koja se pojavljuje unutar C()
tipicno se bira da bude to je moguce jednostavnija, pri cemu se izostavljaju konstantni
faktori i clanovi manjeg reda.
Postoje dva formalno bliska ali bitno razlicita koritenja ove notacije: beskonacna (in-
nite) i innitezimalna asimptotika. Ova razlika je jedino u primjeni ali nije i principijelna.
Formalna denicija za O() je jednaka u oba slucaja sa razlicitim limitima za argumente
funkcije.
U nastavku ce biti navedeno nekoliko jednostavnih ali znacajnih osobina O notacije.
1. Ako je , (:) = O(q (:)) tada je c , (:) = O(q (:)) za svaku konstantu c 0
2. Ako je ,
i
(:) = O(q
i
(:)), i = 1. 2. .... / tada je
,
1
(:) +,
2
(:) +... +,
k
(:) = O((q
1
+q
2
+... +q
k
) (:))
3. Ako je ,
i
(:) = O(q (:)), i = 1. 2. .... / tada je
,
1
(:) +,
2
(:) +... +,
k
(:) = O(q (:))
4. Ako je ,
i
(:) = O(q
i
(:)), i = 1. 2. .... / tada je
,
1
(:) ,
2
(:) ... ,
k
(:) = O(q
1
(:) q
2
(:) ... q
k
(:))
Ako je , (:) monotono rastuca funkcija koja nije ogranicena, c 1 i c 0, tada
, (:)
c
= O
_
c
f(n)
_
Za , (:) = : dobija se :
c
= O(c
n
) a za , (:) = log
a
: dobija se (log
a
:)
c
= O
_
c
log
a
n
_
=
O(:) to znaci da proizvoljan stepen logaritamske funkcije raste spporije od linearne
funkcije.
Primjer. Kako je
lim
n!1
ln :
:

= 0
za svako c 0 tada vrijedi da je ln : = O(:

) za svako c 0.
Primjer. Neka je , (:) broj bita broja :. Tada je , (:) = [log
2
:] + 1. Kako je
lim
n!1
, (:)
log
2
:
= 1
tada vrijedi da je , (:) = O(log
2
:). S obzirom da je log
2
: =
ln n
ln 2
to je , (:) = O(ln :).
5.1.3 -notacija
Denicija. Neka je q (:) realna funkcija denisana na nekom podskupu prirodnih bro-
jeva. Sa (q (:)) se oznacava skup realnih funkcija , (:) denisanih na nekom podskupu
skupa realnih brojeva takvih da postoji konstanta c 0 i prirodan broj :
0
takvi da vrijedi
0 _ c q (:) _ , (:) za svako : _ :
0
.
Ovdje () oznacava klasu funkcija a , (:) = (q (:)) je oznaka za inkluziju , (:)
(q (:)).
49
Velicina () se tumaci tako da je q (:) donja granica za , (:). U tom smislu, oznaka
, (:) = (q (:)) se tumaci da ", raste najmanje kako raste q".
Iz denicije asimpotskih notacija direktno slijedi naredni teorem.
Teorem. Za bilo koje dvije funkcije , (:) i q (:) vrijedi , (:) = (q (:)) ako i samo ako
je , (:) = O(q (:)) i , (:) = (q (:)).
5.1.4 Primjeri racunanja slozenosti
Primjer 1. Sabiranje ili oduzimanje dva :-bitna cijela broja ima kompleksnost O(:).
Za analizu kompleksnosti mnozenja dva broja potreban je kratki prikaz postupka. Jedan
od mogucih nacina mnozenja dva cijela :-bitna broja je tzv. digitalni metod. Neka su
c = (c
2n1
c
2n2
...c
1
c
0
)
2
/ = (/
2n1
/
2n2
.../
1
/
0
)
2
Moze se staviti

1
= (c
2n1
c
2n2
...c
n+1
c
n
)
2
.
0
= (c
n1
c
n2
...c
1
c
0
)
2
1
1
= (/
2n1
/
2n2
.../
n+1
/
n
)
2
. 1
0
= (/
n1
/
n2
.../
1
/
0
)
2
Tada se moze staviti c = 2
n

1
+
0
i / = 2
n
1
1
+1
0
. Odavdje je
c / = (2
2n
+ 2
n
)
1
1
1
+ 2
n
(
1

0
) (1
0
1
1
) + (2
n
+ 1)
0
1
0
Ovo znaci da se za proizvod dva 2:-bitna broja moraju izracunati dvije razlike
1

0
i 1
0
1
1
dva :-bitna broja, tri proizvoda
1
1
1
, (
1

0
) (1
0
1
1
),
0
1
0
a zatim
izvriti pomjeranje ulijevo i sabiranje.
Ako se sa ` (:) oznaci broj bit operacija potrebnih za mnozenje dva :-bitna cijela broja
onda vrijedi
` (2:) _ 3 ` (:) +C :
gdje je C konstanta. Naime, svako mnozenje dva :-bitna cijela broja zahtijeva ` (:)
bitnih operacija a sabiranje, oduzimanje i pomjeranje ulijevo su operacije reda O(:).
Odavdje se dobija relacija
`
_
2
k
_
_ 1
_
3
k
2
k
_
gdje je 1 = max ` (2) . C.
Teorem. Mnozenje dva :-bitna cijela broja moze biti izvedeno koritenjem O
_
:
log
2
3
_
bit operacija.
Dokaz. Za mnozenje dva :-bitna broja je potrebno ` (:) bit operacija. Na osnovu
prethodnih relacija vrijedi:
` (:) = `
_
2
log
2
n
_
_ `
_
2
[log
2
n]+1
_
_ 1
_
3
[log
2
n]+1
2
[log
2
n]+1
_
< 1 3
[log
2
n]+1
_ 3 1
_
3
[log
2
n]
_
_ 31 3
[log
2
n]
= (31) :
log
2
3
50
Odavdje imamo da je ` (:) = O
_
:
log
2
3
_
.
Primjer 2. Naci O(:!).
Rjeenje. Kako je :! = 1 2 ... : = (... ((2 3) 4) 5...) :, za racunanje broja :! je
potrebno : 2 mnozenja. Najprije se mnozi 2 3 pa se dobijeni proizvod pomnozi sa 4,
novi rezultat sa 5 itd dok se ne doe do mnozenja sa :. U koraku (i 1) se i! mnozi sa
i + 1 pa je stoga broj mnozenja jednak : 2. Za odreivanje broja bit operacija treba
se podsjetiti cinjenice da je broj cifara proizvoda dva binarna broja jednak sumi cifara
faktora ili je za 1 manji od te sume. Neka broj : ima / bita. Svaki broj manji od : ima
najvie / bita. Stoga je :!, kao proizvod : brojeva sa najvie / bita, najvie :/ bitni broj.
Broj bita broja :! je manji ili jednak sumi bita svakog faktora to je manje ili jednako
:/. Zbog toga je, za svaki prirodan broj i _ :, broj i! najvie : /-bitni. Za mnozenje i!
sa i potrebno je najvie (:/)/ = :/
2
bit operacija. Kako ovakvih mnozenja ima (: 2)
to je za izracunavanje :! potrebno najvie
(: 2) (:/
2
) = :(: 2) (1 +log
2
:|)
2
= :(: 2) (lg :)
2
= O
_
(:lg :)
2
_
bit operacija.
51
6 Analiza kompleksnosti - nastavak
6.1 Uvod
Cilj analize algoritama je da se predvidi njegovo ponaanje, posebno brzina izvravanja,
bez realizacije na nekom (konkretnom) racunaru. Ideja je da se procijeni brzina rada bez
realizacije samog algoritma tako da procjena vrijedi za svaki racunar.
Tacno ponaanje algoritma je nemoguce predvidjeti osim u najjednostavnijim slucaje-
vima. Na ponaanje utice mnogo faktora pa se u obzir uzimaju samo glavne karakteristike
a zanemaruju se detalji vezani za tacnu realizaciju. Iz tog razloga analiza algoritma je pri-
blizna. Na taj nacin se, ipak, dobijaju znacajne informacije o algoritmu koje omogucavaju
uporeivanje razlicitih algoritama za rjeavanje istog problema.
Logican korak je da se zanemare konstantni faktori jer se brzine izvravanja algoritama
na raznim racunarima razlikuju priblizno za konstantan faktor. Od interesa je ocjena
algoritma kada ulazna velicina tezi beskonacnosti.
U analizi algoritama se za svaki ulaz odreuje njegova velicina (dimenzija) :. Velicina
ulaza nije striktno denisana; obicno je to mjera velicine memorijskog prostora potrebnog
za smjetanje ulaza.
Ocjena vremenske slozenosti algoritma se sastoji u brojanju racunskih koraka koje treba
izvriti. Termin "racunska operacija" moze obuhvatiti vie tipova operacija kao to je
sabiranje i mnozenje. Vrijeme izvravanja zavisi od konkretnog racunara, odabranog
programskog jezika i slicno. Stoga se u algoritmu izdvaja korak koji se ponavlja i koji na
taj nacin postaje osnova analize. Naprimjer, u sortiranju je to uporeivanje.
Osnovna pravila za kalkulisanje slozenosti algoritama su :
Svaka instrukcija u sekvenci se broji kao 1 bez obzira na to koliko je izraz slozen i
koliko se stvarno koristi mainskih instrukcija
Konstrukcija "Za Svaki <..." se broji : + 1 puta ako se tijelo petlje izvri :
puta
Konstrukcija "Ako Je < Tada" se broji kao 1 svaki put kad se "postavi pitanje"
a ono to uslovljava naredba "Ako ..." broji se onoliko puta koliko to zahtijeva
konkretni slucaj
Konstrukcija "Sve Dok(<uslov)" se broji : +1 puta ako se tijelo petlje izvri :
puta
Na nekoliko narednih primjera ce biti pokazan nacin kalkulisanja slozenosti.
6.2 Zadaci
Primjer. Sekvencijalno pretrazivanje.
U ovom primjeru je prezentirana metoda sekvencijalnog pretrazivanja niza u kojem se
trazi vrijednost 1|,nc.
52
# Sekvencijalno trazenje Broj Opis
1 TraziSek(c. :. 1|,nc) Ulaz : niz [c] duzine : i 1|,nc
2 `c:co l 1 Inicijalizacija radne promjenljive
3 Za Sve i = 1 do : { : + 1 Pocetak unutranje petlje
4 Ako je c [i] = 1|,nc Tada { : Postavljanje upita
5 `c:co Postavljanje na drugu vrijednost
6 }
7 }
Ovdje je oznaka da li se realizovao uslov "Ako ...". Na osnovu ovoga se moze zakljuciti
da se slozenost ovog algoritma izrazava izrazom
1 (:) = 2: + 2
Ovo je vrijednost za najgori slucaj, kada se uslov na liniji 3 izvri : puta. Na taj nacin
se zakljucuje da algoritam ima linearnu brzinu odnosno 1 (:) = O(:). Drugim rijecima,
linearno povecanje broja elemenata koji se ispituju znaci linearno povecanje vremena za
njegovo izvrenje.
Primjer. Bubble sort
U ovom primjeru je data analiza slozenosti algoritma tzv. Bubble sorta.
# Sortiranje Broj Opis
1 BubbleSort(c [:]) Sortiranje niza c [:]
2 Za i = 1 do : 1 { : Pocetak vanjske petlje
3 Za , = : 1 do i korak 1 { Pocetak unutranje petlje
4 Ako je (c [,] c [, + 1]) Tada { Upit
5 / c [,] Zamjena vrijednosti
6 c [,] c [, + 1]
7 c [, + 1] /
8 }
9 }
10 }
Korak na liniji 2 se izvodi : puta. Korak na liniji 3 se za i = 1 izvodi : puta, za i = 2
izvodi : 1 puta, ..., sve do i = : 1 kada se izvodi 2 puta. Korak na liniji 4 se izvodi
sekvencijalno : 1. : 2. .... 1 puta za i = 1. : 1. Koraci na linijama 5, 6 i 7 se izvode
isti broj puta kao i korak (upit) na liniji 4. To znaci da je ukupan broj koraka ovog
algoritma
1 (:) = : + (1 + 2 + 3 +... +: 1) + 4 (1 + 2 +... + (: 1))
1 (:) = : +
:(: + 1)
2
1 + 4
:(: 1)
2
1 (:) =
:(5: 6)
2
Ovo je broj za najgori slucaj : kada je pocetni niz sortiran opadajucim redom. Zakljucak
je da je 1 (:) = O(:
2
) odnosno da se algoritam izvodi u kvadratnom vremenu.
Primjer. Sumiranje sa povecanjem inkrementa
Sljedeci primjer ilustruje kompleksnost u slucaju kada se u svakom koraku gornja granica
brojaca povecava dva puta.
53
# Korak Broj Opis
1 Sumiraj(:) Ulaz : broj iteracija (:)
2 / 1 1 Inicijalizacija
3 on:c 0 1 Inicijalizacija sume
4 Za i = 1 do : { : + 1 Pocetak spoljne petlje
5 Za , = 1 do / { Pocetak unutranje petlje
6 on:c on:c +i , 2
n
1 Sumiranje
7 }
8 / / +/ : Dupliranje varijable /
9 }
Najprije cemo napraviti analizu ta ovaj algoritam radi. Ako je i = 1 tada se vri jedno
sumiranje na liniji 6. Ako je i = 2 tada se vre 4 sumiranja na liniji 6. Razlog je u cinjenici
da se linija 8, na kojoj se vrijednost za / udvostrucava, izvrava onoliko puta koliko se
promijeni i odnosno : puta. Na taj nacin unutranja petlja vri uzastopno sumiranje
1. 2. 4. .... 2
n1
clanova. Ne treba izgubiti iz vida da se unutranja petlja izvrava 2
k
+ 1
puta. Na osnovu toga, broj koraka izvrenja ovog algoritma je
1 (:) = 1 + 1 + (: + 1) + (1 + 2 +... + 2
n1
+: 1) + (2
n
1) +:
1 (:) = 3: + 1 + 2 (2
n
1) = 2
n+1
+ 3: 1
Zakljucak je da je 1 (:) = C(2
n
) s obzirom da je 2
n+1
= 2
n
2.
Zadatak. Dokazati da je vrijeme 1 (:) = :
3
+ 20: + 1 jednako O(:
3
).
Dokaz. Prema deniciji O notacije, 1 (:) = O(:
3
) ako je 1 (:) _ c :
3
za neko : _ :
0
.
Ako je :
3
+ 20: + 1 _ c :
3
tada 1 +
20
:
2
+
1
:
3
_ c. Ovo vrijedi za svako : _ :
0
= 1 i
c _ 22. Za vece vrijednosti :
0
potreban je manji broj c (npr. za :
0
= 10 je c _ 1.201)
ali u svakom slucaju vrijedi trazena nejednakost.
Zadatak. Pokazati da vrijeme 1 (:) = :
3
+ 20: + 1 nije O(:
2
).
Dokaz. Prema deniciji O notacije, 1 (:) = O(:
3
) ako je 1 (:) _ c :
3
za neko : _ :
0
.
Ako je :
3
+ 20: + 1 _ c :
3
tada 1 +
20
:
2
+
1
:
3
_ c. Lijeva strana posljednje nejednakosti
raste neograniceno tako da ne postoji konstanta c. Stoga, O uslov ne moze vrijediti u
ovom slucaju.
Zadatak. Pokazati da je vrijeme 1 (:) = :
3
+ 20: + 1 jednako O(:
4
).
Dokaz. Prema deniciji O notacije, 1 (:) = O(:
4
) ako je 1 (:) _ c :
4
za neko : _ :
0
.
Ako je :
3
+ 20: + 1 _ c :
3
tada
1
:
+
20
:
3
+
1
:
4
_ c. Ovo vrijedi za svako : _ :
0
= 1 i
c _ 22. Za vece vrijednosti :
0
potreban je manji broj c (npr. za :
0
= 10 je c _ 1.201)
ali u svakom slucaju vrijedi trazena nejednakost.
Zadatak. Pokazati da je vrijeme 1 (:) = :
3
+ 20: jednako (:
2
).
Dokaz. Prema deniciji notacije, 1 (:) = (:
2
) ako je 1 (:) _ c :
2
za neko : _ :
0
.
Ako je :
3
+ 20: + 1 _ c :
2
tada : +
20
:
_ c. Lijeva strana nejednakosti ima minimalnu
vrijednost 8.94 za : =
_
20. Stoga uslov za vrijedi za svako : _ :
0
= 5 i c _ 9. Za
vece vrijednosti :
0
potreban je veci broj c (npr. za :
0
= 10 je c _ 12.01) ali u svakom
slucaju vrijedi trazena nejednakost.
54
6.3 Zadaci za samostalni rad
Zadatak. Napraviti algoritam i ispitati slozenost u sljedecim slucajevima

100

i=1
50

j=1
1
i +,
2

100

i=1
60

j=1
sin (i
3
+,
4
)

100

i=1
100

j=1
, i + 1
i +,

100

i=1
i

j=1
1
2, +i

k=1
/ (/ + 1) .. /
2

k=1
/
k

k=1
1
(/
2
)!

k=1
(1)
k
(2/
2
+ 1)!
Zadatak. Data je cjelobrojna matrica [c
ij
]
;j=1;;n
. Izracunati /
1
. /
2
. .... /
n
gdje je
/
i
=
n

j=1
c
2
ij
/
i
=
n

j=1
(1)
i+j
c
ij
/
i
=
n

j=1
c
ij
/
i
=
n

j=1
[c
ji
[
/
i
=
n

j=1
c
ij
, gdje je 1 < c
ji
_ :
/
i
= max c
ij
1jn
. /
i
= min c
ji
1jn
55
7 Rekurzije
7.1 Uvod
Rekurzija je situacija kada je za racunanje u jednom koraku potreban rezultat prethodnog
koraka. Postoje brojni primjeri rekurzija u matematici. Primjeri su :
Denicija faktorijela : 0! = 1. :! = (: 1)! :
Fibonacijevi brojevi: 1
n
= 1
n1
+1
n2
, pri cemu je 1
1
= c i 1
2
= /.
U teoriji algoritama pojam rekurzije se odnosi na rutine (funkcije, procedure) koje pozi-
vaju same sebe. One su tipicne za pristupe "podijeli pa vladaj" gdje funkcija ulaz dijeli
na manje dijelove i poziva se na svakom od tih dijelova. Primjer je binarno pretrazivanje
: u svakom koraku se trazi polovina prostora koji je dobijen u prethodnom koraku (npr.
sredina niza).
Ako za clanove niza 1
n
, : = 1. 2. ... vazi jednakost
1
n
= , (1
n1
. 1
n2
. .... 1
1
. :)
kaze se da niz 1
n
zadovoljava diferentnu jednadzbu ili rekurentni izraz. Specijalno, ako
se za neko / _ 1 clan 1
n
izrazava preko / prethodnih clanova niza
1
n
= , (1
n1
. 1
n2
. .... 1
nk
. :)
onda je / red te diferentne jednacine. Matematickom indukcijom se pokazuje da je ovaj
niz jednoznacno odreen sa prvih / clanova niza 1
1
. 1
2
. .... 1
k
.
Jedna od najpoznatijih diferentnih jednacina je ona koja denie Fibonacijev niz
1
n
= 1
n1
+1
n2
. 1
1
= 1
2
= 1
Za racunanje vrijednosti 1
n
potrebno je izvriti :2 koraka sabiranja to je neprakticno
za velike :.
Nacin procjene brzine rekurzivnih algoritmace biti prezentiran na jednom primjeru. Neka
je data rekurzivna relacija
1 (:) = 2 1 (:,2) +:. 1 (1) = 1
Izraz kojim se izracunava svaki clan niza koji se generie zove se rjeenje. U ovom slucaju
je cilj procijeniti gornju granicu za koju je 1 (:) _ , (:). Vrijedi:
1 (:) = 2 1 (:,2) +: =
= 2 [2 1 (:,4) +:,2] +: =
= 4 1 (:,4) + 2: =
= 4 [2 1 (:,8) +:,4] + 2: =
= 8 1 (:,8) + 3:
= ...
= 2
k
1
_
:,2
k
_
+/ :
Zna se da je 1 (1) = 1 i to je nacin da se posao nastavi.

Zelja je da se na desnoj strani
pojavi 1 (1) to znaci da je
56
:,2
k
= 1 = : = 2
k
= / = log
2
:
Na osnovu ovoga se nastavlja prethodna jednacina pa je:
1 (:) = 2
log
2
n
1 (1) +: log
2
: =
= : +: log
2
: = O(:lg :)
Opte rjeenje kojim se daju uslovi procjene vremena rekurentnih algoritama daje Master
teorem, koji je formulisan i dokazan od strane Cormen, Leierson, Rivest i Stein u knjizi
Introduction to Algorithms. Generaliziranu formu Master teorema dali su Akra i Bazzi
1998. godine i on se odnosi na mnogo iru klasu rekuzivnih algoritama.
Teorema. Asimptotsko ponaanje niza 1 (:) rjeenja rekurentnog izraza
1 (:) = c 1
_
:
/
_
+, (:) (1)
u kojem je c _ 1 i / 1 konstante i , (:) asimptotski pozitivna funkcija, dato je
jednakocu
1 (:) =
_
_
_

_
:
log
b
a
_
, (:) = O
_
:
log
b
a"
_
. 0

_
:
log
b
a
log
k+1
:
_
, (:) =
_
:
log
b
a
log
k
:
_
. / _ 0
(, (:)) , (:) =
_
:
log
b
a+"
_
. 0
U posljednjem slucaju , (:) mora zadovoljavati uslov regularnosti c , (:,/) _ c , (:)
za neku konstantu c < 1 i dovoljno veliko :.
Jedna od varijanti formulacije ovog problema je cilj analiza algoritma / pri cemu je broj
operacija 1 (:) za ulaz velicine : (vremenska slozenost) dat rekurentnim izrazom
1 (:) = c 1
_
:
/
_
+c :
k
pri cemu je c. /. c. / 0, / ,= 0 odnosno , (:) = c :
k
i zadata je vrijednost 1 (1).
Ovakva jednacina se dobija za algoritam kod kojeg se obrada ulaza velicine : svodi na
obradu c ulaza velicine :,/ poslije cega je potrebno izvriti jo c :
k
koraka da bi se od
parcijalnih rjeenja konstruisalo rjeenje kompletnog ulaza velicine :. Drugim rijecima,
broj c je broj podproblema na koje se dijeli pocetni problem. Za ove algoritme se kaze
da su tipa "podijeli pa vladaj" (divide-and-conquer) to je drugi naziv za algoritme koji
su zasnovani na dekompoziciji. Uobicajeno je da bude / N.
Dokaz. Dokaz ce biti proveden samo za podniz : = /
m
gdje je : cijeli nenegativni broj.
Mnozenjem izraza (1) sa c
m
,c dobija se rekurentni izraz
t
m
= t
m1
+
m
. t
0
=
1
c
1 (1)
gdje je t
m
=
1
c
c
m
1 (/
m
) i = /
k
,c. Rjeenje je
t
m
= t
0
+
m

i=1

i
57
Za ,= 1 je
m

i=1

i
=
1
m+1
1
1
pa se asimptotsko ponaanje niza t
m
opisuje sljedecim jednakostima
t
m
=
_
_
_
O(:) = 1
O(1) 0 < < 1
O(
m
) 1
S obzirom da je 1 (/
m
) = c c
m
t
m
, : = /
m
odnosno : = log
b
: redom se za 0 < < 1
(/
k
< c), = 1 (/
k
= c odnosno / = log
b
c) i 1 (/
k
c) dobija
1 (:) =
_
_
_
O(c
m
) = O
_
/
mlog
b
a
_
= O
_
:
log
b
a
_
c /
k
O(:c
m
) = O
_
log
b
: :
log
b
a
_
= O
_
:
k
log :
_
c = /
k
O((c)
m
) = O
_
/
mk
_
= O
_
:
k
_
c < /
k
Pogodno je upamtiti neke od narednih relacija.
Rekurzija Algoritam O()
1 (:) = 1 (:,2) +O(1) Binarno pretrazivanje O(log :)
1 (:) = 1 (: 1) +O(1) Sekvencijalno pretrazivanje O(:)
1 (:) = 2 1 (:,2) +O(1) Put po stablu O(:)
1 (:) = 1 (: 1) +O(:) Selection sort O(:
2
)
1 (:) = 2 1 (:,2) +O(:) Merge sort O(:log :)
Table 1: Uporedni pregled brzina algoritama
7.2 Zadaci
Zadatak. Neka je 1 (:) = 8 1
_
:
2
_
+ 1000:
2
.
Rjeenje. Ovdje je c = 8, / = 2, , (:) = 1000:
2
, log
b
c = log
2
8 = 3. Sada se provjerava
da li vrijedi
, (:) = O
_
:
log
b
a"
_
= 1000:
2
= O(:
3"
)
Ako se izabere = 1 tada se dobije 1000:
2
= O(:
2
). S obzirom da ovo vrijedi koristi se
prvi slucaj Master teoreme pa se zakljucuje da je
1 (:) =
_
:
log
b
a
_
= (:
3
)
Tacno rjeenje ovog rekurentnog izraza je 1 (:) = 1001:
3
1000:
2
sa uslovom 1 (1) = 1.
Zadatak. Neka je 1 (:) = 2 1
_
:
2
_
+ 10:.
Rjeenje. Ovdje je c = 2, / = 2, / = 0, , (:) = 10:, log
b
c = log
2
2 = 1. Sada se
provjerava da li vrijedi
, (:) = O
_
:
log
b
a
_
= , (:) = O(:)
58
Sada se koristi drugi slucaj Master teoreme pa se zakljucuje da je
1 (:) =
_
:
log
b
a
log
k+1
:
_
= (:log :)
Tacno rjeenje ovog rekurentnog izraza je 1 (:) = :+10: log
2
: uz uslov da je 1 (1) = 1.
Zadatak. Neka je 1 (:) = 2 1
_
:
2
_
+:
2
.
Rjeenje. Ovdje je c = 2, / = 2, , (:) = :
2
, log
b
c = log
2
2 = 1. Sada se provjerava da li
vrijedi
, (:) =
_
:
log
b
a+"
_
= (:
1+"
)
Ako se izabere = 1 tada se dobije :
2
= (:
2
). Koristi se treci slucaj Master teoreme,
s tim da se najprije provjerava uslov regularnosti :
c ,
_
:
/
_
_ c , (:) = 2
_
:
2
_
2
_ c :
2
Ako se izabere c = 1,2 tada je uslov zadovoljen \: N pa je 1 (:) = (, (:)) odnosno
1 (:) = (:
2
). Tacno rjeenje je 1 (:) = 2:
2
: uz uslov da je 1 (1) = 1.
Zadatak. Neka je 1 (:) = 6 1
_
:
3
_
+:
2
log :.
Rjeenje. U ovom slucaju je
log
b
c = log
3
6 = 1 + log
3
2 < 2
Na osnovu ovoga je
, (:) = :
2
log : =
_
:
1+log
3
2+"
_
S obzirom da se radi o slucaju (3) Master teoreme provjerava se uslov regularnosti:
c ,
_
:
/
_
_ c , (:)
6
_
:
3
_
2
log
:
3
_ c :log :
2
3
(log : log 3) _ c log : =
= c _
2
3

log : log 3
log :
=
2
3

_
1
log 3
log :
_
Ovaj uslov vrijedi za dovoljno veliko : pa se moze pisati da je
1 (:) = (, (:)) = (:
2
log :)
Zadatak. Za sljedece izraze, koritenjem Master teoreme, utvrditi da li su rjeivi :
1 (:) = 3 1
_
:
2
_
+:
2
1 (:) = 4 1
_
:
2
_
+:
2
59
1 (:) = 1
_
:
2
_
+ 2
n
1 (:) = 2
n
1
_
:
2
_
+:
n
1 (:) = 16 1
_
:
4
_
+:
1 (:) = 2 1
_
:
2
_
+:log :
1 (:) = 2 1
_
:
2
_
+
:
log :
1 (:) = 2 1
_
:
4
_
+:
0:51
1 (:) =
1
2
1
_
:
2
_
+
1
:
1 (:) = 16 1
_
:
4
_
+:!
1 (:) =
_
2 1
_
:
4
_
+ log :
1 (:) = 3 1
_
:
2
_
+:
1 (:) = 3 1
_
:
3
_
+
_
:
1 (:) = 4 1
_
:
2
_
+c:
1 (:) = 3 1
_
:
4
_
+:log :
1 (:) = 3 1
_
:
3
_
+
:
2
1 (:) = 4 1
_
:
2
_
+
:
log :
1 (:) = 64 1
_
:
8
_
:
2
log :
1 (:) = 7 1
_
:
3
_
+:
2
1 (:) = 4 1
_
:
2
_
+ log :
1 (:) = 1
_
:
2
_
+:(2 cos :)
Rjeenje.
1 (:) = 3 1
_
:
2
_
+:
2
= 1 (:) = (:
2
) (slucaj 3)
1 (:) = 4 1
_
:
2
_
+:
2
= 1 (:) = (:
2
log :) (slucaj 2)
60
1 (:) = 1
_
:
2
_
+ 2
n
= 1 (:) = (:
2
) (slucaj 3)
1 (:) = 2
n
1
_
:
2
_
+:
n
= ne primjenjuje se (c nije konstanta)
1 (:) = 16 1
_
:
4
_
+: = 1 (:) = (:
2
) (slucaj 1)
1 (:) = 2 1
_
:
2
_
+:log : = 1 (:) =
_
:log
2
:
_
(slucaj 2)
1 (:) = 2 1
_
:
2
_
+
:
log :
=ne primjenjuje se (nepolinomijalna razlika izmeu , (:)
i :
log
b
a
)
1 (:) = 2 1
_
:
4
_
+:
0:51
= 1 (:) = (:
0:51
) (slucaj 3)
1 (:) =
1
2
1
_
:
2
_
+
1
:
=ne primjenjuje se (c < 1)
1 (:) = 16 1
_
:
4
_
+:! = 1 (:) = (:!) (slucaj 3)
1 (:) =
_
2 1
_
:
4
_
+ log : = 1 (:) = (
_
:) (slucaj 1)
1 (:) = 3 1
_
:
2
_
+: = 1 (:) =
_
:
lg 3
_
(slucaj 1)
1 (:) = 3 1
_
:
3
_
+
_
: = 1 (:) = (:) (slucaj 1)
1 (:) = 4 1
_
:
2
_
+c : = 1 (:) = (:
2
) (slucaj 1)
1 (:) = 3 1
_
:
4
_
+:log : = 1 (:) = (:log :) (slucaj 3)
1 (:) = 3 1
_
:
3
_
+
:
2
= 1 (:) = (:log :) (slucaj 2)
1 (:) = 4 1
_
:
2
_
+
:
log :
= 1 (:) = (:
2
) (slucaj 1)
1 (:) = 64 1
_
:
8
_
:
2
log : =ne primjenjuje se jer , (:) nije pozitivna
1 (:) = 7 1
_
:
3
_
+:
2
= 1 (:) = (:
2
) (slucaj 3)
1 (:) = 4 1
_
:
2
_
+ log : = 1 (:) = (:
2
) (slucaj 1)
1 (:) = 1
_
:
2
_
+:(2 cos :) =Ne primjenjuje se. Pripada slucaju 3 ali je naruen
uslov regularnosti (pretpostavimo da je : = 2:/ gdje je / neparan i proizvoljno
veliki. Za svaki takav izbor od : pokazuje se da je c _ 3,2 pa je naruen uslov
regularnosti)
U primjeru 7 razlika izmeu , (:) i :
log
b
a
se moze prikazati kao kolicnik
61
, (:)
:
log
b
a
=
:
log :
:
log
2
2
=
:
: log :
=
1
log :
Jasno je da je
1
log :
< :
"
za bilo koje 0. Stoga razlika nije polinomijalna i ne moze
se primijeniti Master teorema.
7.3 Zadaci za samostalni rad
Zadatak. Neka je
c
0
= 1; c
k
= /c
k1
+ 1,/. / = 1. 2. . .
Za dati prirodni broj : naci c
n
.
Zadatak. Neka je

1
=
2
= 0;
3
= 1.5

i
=
i + 1
i
2
+ 1

i1

i2

i3
Za dati prirodni broj : naci
n
.
Zadatak. Neka je
r
0
= c. r
1
= d
r
k
= r
k1
+: r
k2
+/. / = 1. 2. ...
Za date realne brojeve . :. c. d. / i prirodni broj : izracunati r
n
.
Zadatak. Neka je
n
1
= n
2
= 0.
1
=
2
= 1
n
i
=
n
i1
n
i2

i1

i2
1 +n
2
i1
+
2
i1

i
=
n
i1

i1
[n
i2
+
i1
[ + 2
. i = 3. 4. ...
Za dati prirodni broj : naci
n
.
Zadatak. Neka je
c
0
= c
1
= 1
c
i
= c
i2
+
c
i1
2
i1
. i = 2. 3. ...
Naci proizvod c
0
c
1
... c
14
.
Zadatak. Neka je
c
1
= /
1
= 1
c
k
=
1
2
_
_
/
k1
+
1
2
_
c
k1
_
/
k
= 2c
2
k1
+/
k1
. / = 2. 3. ...
62
Za dati prirodni broj : naci sumu
n

k=1
c
k
/
k
.
Zadatak. Neka je
r
1
=
1
= 1.
r
i
= 0.3 r
i1

i
= r
i1
+
i1
. i = 2. 3. ...
Za dati prirodni broj : naci sumu
n

i=1
r
i
1 +[
i
[
.
Zadatak. Neka je
c
1
= /
1
= 1
c
k
= 3/
k1
+ 2c
k1
/
k
= 2c
k1
+/
k1
. / = 2. 3. ...
Za dati prirodan broj : naci sumu
n

k=1
2
k
(1 +c
2
k
+/
2
k
) /!
Zadatak. Neka je
c
1
= n. /
1
=
c
k
= 2/
k1
+c
k1
/
k
= 2c
2
k1
+/
k1
. / = 2. 3. ...
Za date realne brojeve n. i prirodni broj : naci sumu
n

k=1
c
k
/
k
(/ + 1)!
Zadatak. Neka je
r
1
= r
2
= r
3
= 1
r
i
= r
i1
+r
i3
. i = 4. 5. ...
Naci sumu
100

i=1
r
i
2
j
.
Zadatak. Dat je cijeli broj : 1. Naci najveci cijeli broj / za koji je 4
k
< :.
Zadatak. Dat je prirodni broj :. Naci najmanji broj oblika 2
r
koji prelazi :.
Zadatak. Dat je prirodan broj :. Izracunati
1 2 + 2 3 4 +... +: (: + 1) ... 2:
Zadatak. Izracunati
63
1
1 +
1
3 +
1
5 +
1
...
...
101 +
1
103
Zadatak. Za dati realni broj r ,= 0 izracunati
r
r
2
+
2
r
2
+
4
r
2
+
8
...
... r
2
+
256
r
2
Zadatak. Za dati prirodni broj : i realni broj t izracunati
(2t)
n
:!!
_
:
2
_
[n=2]
.
Zadatak. Niz Fibonacijevih brojeva n
0
. n
1
. n
2
. ... se formira po pravilu n
0
= 0. n
1
=
1. n
i
= n
i1
+n
i2
.
Za dati prirodan broj : izracunati prvih : Fibonacijevih brojeva
Niz ,
0
. ,
2
. ... se formira po pravilu ,
0
= 0. ,
1
= 1. ,
i
= ,
i1
+ ,
i2
+ n
i2
. Za dati
prirodan broj : generisati niz ,
0
. ,
1
. ,
2
. .... ,
n
.
Zadatak. Za zadati prirodni broj : izracunati :!.
Zadatak. Formirati niz Fibonacijevih brojeva
koristeci se neposredno formulom 1
n
= 1
n1
+1
n2
.
koristeci se formulama za :-ti clan
n
k
=
1
_
5
_
1 +
_
5
2
_
n

1
_
5
_
1
_
5
2
_
n
Zadatak. Dati su pozitivni cijeli brojevi :. :. Izracunati (:. :) gdje je
(:. :) =
_
_
_
_
_
:+ 1 : = 0
(: 1. 1) : ,= 0. : = 0
(: 1. (:. :1)) : 0.: 0
_
_
Zadatak. Niz polinoma je zadat na sljedeci nacin 1
0
(r) = 1. 1
1
(r) = r. 1
k
(r) =
2r1
k1
(r) 1
k2
(r). Formirati niz 1
2
. 1
3
. .... 1
8
.
Zadatak. Niz polinoma je zadat na sljedeci nacin H
0
(r) = 1. H
1
(r) = r. H
k
(r) =
rH
k1
(r) (/ 2) H
k2
(r).
Naci polinome H
2
. .... H
6
Za date realne brojeve c
1
. .... c
6
formirati polinom c
0
H
0
(r) +... +c
6
H
6
(r)
Za dati realni broj c izracunati H
0
(c) +... +H
6
(c)
64
8 Euklidov algoritam
8.1 Uvod
Euklidov algoritam je dobio je ime po starogrckom matematicaru Euklidu. To je na-
jekasniji algoritam za odreivanje najveceg zajednickog djelitelja dva ili vie brojeva.
Prvi poznati sacuvani opis Euklidovog algoritma se nalazi u Elementima (oko 300. go-
dine p.n.e.), to ga cini najstarijim numerickim algoritmom koji se jo uvijek aktivno
koristi. U originalu, objanjen je samo za prirodne brojeve i geometrijske duzine (re-
alne brojeve), ali je u 19. stoljecu primjenjen na polinome i na Gaussove cijele brojeve,
to je dovelo do razvoja novih pojmova apstraktne algebre. Euklidov algoritam je dalje
primjenjivan na drugim matematickim strukturama, poput cvorova i polinoma.
Euklidov algoritam ima iroku terijsku i prakticnu primenu. Predstavlja kljucni element
RSA algoritma, metode asimetricne kriptograje koja se u znacajnoj meri primenjuje
u elektronskom poslovanju. Moze se upotrijebiti za konstruiranje veriznih razlomaka,
u Sturmovoj metodi za odreivanje realnih nula polinoma i jo nekoliko suvremenih al-
goritama za faktorizaciju prirodnih brojeva. Na kraju, Euklidov algoritam je osnovno
sredstvo za dokazivanje teorema moderne teorije brojeva, kao to su Lagrangeova teo-
rem o cetiri kvadrata i osnovna teorema aritmetike o jedinstvenoj faktorizaciji prirodnih
brojeva. Euklidov algoritam je ekasan nacin za odreivanje NZD velikih brojeva zbog
toga to mu ne treba vie koraka od petostrukog broja cifara manjeg broja zapisanog sa
osnovom 10, to je dokazao Gabrijel Lame 1844. godine i time oznacio pocetak teorije
kompleksnosti.
U 20. stoljecu su razvijene metode za poboljanje ekasnosti Euklidovog algoritma.
8.2 Kako radi Euklidov algoritam ?
Teorem (Euklidov algoritam)
Neka su c. / Z gdje je c. / 0. c /. Pretpostavimo da je uzastopnom primjenom
teorema o dijeljenju ostatkom dobijen niz jednakosti
c = /
1
+:
1
. 0 < :
1
< /
/ = :
1

2
+:
2
. 0 < :
2
< :
1
...
:
j2
= :
j1

j
+:
j
. 0 < :
j
< :
j1
:
j1
= :
j

j+1
Tada je (c. /) = :
j
odnosno najveci zajednicki djelitelj je jednak posljednjem ostatku koji
je razlicit od nule u Euklidovom algoritmu
Do situacije :
j+1
= 0 se dolazi u konacno mnogo koraka jer :
j+1
= 0 implicira da je
`21(c. /) = `21(c. :
1
) = ... = `21(:
j1
. :
j
) = :
j
.
Na narednom dijagramu je data opta ema ovog algoritma
65
Euklidov algoritam za nalazenje najveceg zajednickog djelioca dva broja
Primjer. Euklidovim algoritmom naci najveci zajednicki djelitelj brojeva 3102 i 4002.
4002 = 1 3102 + 900
3102 = 3 900 + 402
900 = 2 402 + 96
402 = 4 96 + 18
96 = 5 18 + 6
18 = 3 6
= `21(4002. 3102) = 6
Pokazuje se da slozenost Euklidovog algoritma zavisi o logaritamski manjem broju / i to
nezavisno od c _ /.
Pojedine jednadzbe u postupku Euklidovog algoritma, kao u prethodnom primjeru, cemo
zvati Euklidske jednadzbe. Kako se vidi, provedeno je ukupno 10 dijeljenja. Ostaci su
takoe Fibonacijevi brojevi. Ovo je jasno jer iz jednakosti 1
n
= 1 1
n1
+ 1
n2
slijedi
da se dijeljenjem broja 1
n
sa 1
n1
u svakom koraku dobije kvocijent 1 i ostatak 1
n2
. Iz
ovoga generalno vrijedi
Teorem (Euklidov algoritam). Neka su :
0
= c i :
1
= / cijeli brojevi takvi da je c. / 0.
Ako se sukcesivnom primjenom algoritma o dijeljenju cijelih brojeva dobije
:
j
= :
j+1

j+1
+:
j+2
. 0 < :
j+2
< :
j+1
(, = 0. 1. .... : 2) i :
n+1
= 0
tada je `21(c; /) = :
n
tj. posljednji nenulti ostatak je `21(c; /).
Algoritam izlozen u navedenom teoremu naziva se Euklidov algoritam.
Propozicija. U Euklidovom algoritmu za svako i vrijedi :
i+2
<
1
2
:
i
.
Dokaz. Ako je :
i+1
_
1
2
:
i
tada je :
i+2
< :
i+1
_
1
2
:
i
. Neka je :
i+1

1
2
:
i
. Tada je
:
i
< 2:
i+1
. Tada iz :
i
=
i+2
:
i+1
+ :
i+2
slijedi
i+2
= 1 tj. :
i
= :
i+1
+ :
i+2
. Odavdje je
:
i+2
= :
i
:
i+1
<
1
2
:
i
. Dakle, tvrdnja vrijedi i u ovom slucaju
66
Ovaj algoritam vrijedi i za Fibonacijeve brojeve toce biti ilustrovano na dva Fibonacijeva
broja 1
11
= 89 i 1
12
= 144
144 = 1 89 + 55
89 = 1 55 + 34
55 = 1 34 + 21
34 = 1 21 + 13
21 = 1 13 + 8
13 = 1 8 + 5
8 = 1 5 + 3
5 = 1 3 + 2
3 = 1 2 + 1
2 = 1 2 + 0
Teorem. Neka je ,
1
= 1. ,
2
= 1. ,
n
= ,
n1
+ ,
n2
(: _ 3) Fibonacijev niz brojeva Za
svako : _ 2 Euklidov algoritam uzima tacno : dijeljenja za odreivanje GC1(,
n+1
. ,
n+2
).
Dokaz. Polazeci od rekurzivne jednakosti ,
i+2
= ,
i+1
+,
i
(i = 1. 2.) dobijamo
,
n+2
= ,
n+1
1 +,
n
,
n+1
= ,
n
1 +,
n1
...
,
4
= ,
3
1 +,
2
,
3
= ,
2
2
Dakle, Euklidov algoritam za odreivanje GC1(,
n+2
. ,
n+1
) uzima tacno : dijeljenja i
vrijedi GC1(,
n+2
. ,
n+1
) ,
2
1.
Teorem (Lame-ov teorem). Broj dijeljenja potrebnih za odreivanje najveceg zajed-
nickog djelioca prirodnih brojeva c i / ne prelazi petostruku vrijednost broja decimalnih
cifara manjeg od ta dva broja.
Dokaz. Neka je c /. Kada se primijeni Euklidov algoritam za odreivanje najveceg
zajednickog djelioca brojeva c = :
0
i / = :
1
dobija se sljedeci niz relacija:
:
0
= :
1

1
+:
2
. 0 < :
2
< :
1
:
1
= :
2

2
+:
3;
0 < :
3
< :
2
...
:
n2
= :
n1

n1
+:
n
. 0 < :
n
< :
n1
:
n1
= :
n

n
Koristi se : dijeljenja. Potrebno je primijetiti da su svi koecijenti
1
.
2
. ....
n1
veci ili
jednaki 1 i da je
n
_ 2 jer je :
n
< :
n1
. Zbog toga je
:
n
_ 1 = ,
2
:
n1
_ 2:
n
_ 2,
2
= ,
3
:
n2
_ :
n1
+:
n
_ ,
3
+,
2
= ,
4
:
n3
_ :
n2
+:
n1
_ ,
4
+,
3
= ,
5
...
:
2
_ :
3
+:
4
_ ,
n1
+,
n2
= ,
n
/ = :
1
_ :
2
+:
3
_ ,
n
+,
n1
= ,
n+1
67
Dakle, ako imamo : dijeljenja u Euklidovom algoritmu tada je min c. / _ ,
n+1
. Neka
je c =
1 +
_
5
2
. Tada je c
2
= c + 1. Matematickom indukcijom se jednostavno dokazuje
da je ,
n
c
n2
za svako : N, : _ 3. Zbog toga je / _ ,
n+1
c
n1
tj. log /
(: 1) log c. Kako je log c
1
5
to je log /
: 1
5
. Dakle, : 1 < 5 log /. Ako / ima
/ cifara u decimalnom zapisu onda je / < 10
k
pa je log / < /. To znaci da je : < 1 + 5/
odnosno : _ 5/.
8.3 Zadaci za samostalni rad
Zadatak. Dati su prirodni brojevi :. :
1
. :
2
. .... :
m
(: _ 2). Izracunati `21(:
1
. :
2
. .... :
m
)
koristeci se relacijom `21(:
1
. :
2
. .... :
k
) = `21(`21(:
1
. :
2
. .... :
k1
) . :
k
) i algorit-
mom Euklida.
Zadatak. Dati su prirodni brojevi : i :. Koritenjem Euklidovog algoritma naci:
Najveci zajednicki djelitelj (NZD) brojeva : i :
Najmanji zajednicki sadrzalac brojeva : i :
Brojeve j. koji nemaju zajednickih sadrzalaca za koje vrijedi :,: = j,
68
9 Tjuringova maina
9.1 Uvod
Digitalni racunar se na apstraktnom nivou obicno prikazuje kao cjelina sastavljena od
procesora, memorije i ulazno-izlaznih ureaja. Procesor iz memorije pribavlja naredbe
i podatke nad kojima se vri obrada u skladu sa znacenjem naredbi a dobijeni rezultati
se vracaju u memoriju. Podaci koji ce biti obraeni se, preko ulazno-izlaznih ureaja,
unose u memoriju odnosno iz memorije se preuzimaju rezultati obrade i prikazuju na
odgovarajuci nacin. Komunikacija djelova racunara se obavlja preko magistrala.
Tjuringova maina je preteca ovakvog modela racunara, pri cemu su neka svojstva ideali-
zovana. To se odnosi na memoriju za koju se pretpostavlja da je potencijalno beskonacna.
Preciznije, na pocetku izvravanja Tjuringove maine zauzet je samo konacan broj mem-
orijskih registara, a isto vazi i u svakom koraku izracunavanja. Ne postoji ogranicenje
koliki je taj konacan broj registara. U svakom koraku izracunavanja moguce je i zahti-
jevati novi, do tada neiskoriteni memorijski registar i svaki takav zahtjev se ispunjava.
Sa druge strane, Tjuringova maina je restrikcija koncepta savremenog racunara u smislu
operacija koje je u stanju izvravati a koje su elementarne. Zanimljivo je da su te op-
eracije ipak dovoljne za opisivanje proizvoljnih algoritama. Njihova prednost u odnosu
na bogatije programske jezike je upravo u jednostavnosti koja olakava analizu.
9.2 Alan Tjuring
Alan Mathison Turing je bio engleski matematicar, logicar, kriptoanaliticar i kompjuter-
ski naucnik. Ostvari je veliki uticaj na kompjutersku nauku time to je dao formal-
izaciju koncepata "algoritma" i "izracunavanja" putem Tjuringove maine, koja je odi-
grala znacajnu ulogu u kreiranju modernih kompjutera. Za Tjuringa se smatra da je
otac kompjuterske nauke i vjetacke inteligencije. U zickom smislu, imao je mnoge
karakteristike koje upucuju da je imao Aspergerov sindrom
3
.
Tokom drugog svjetskog rata Tjuring je radio za vladinu kolu za kriptograju (GCCS)
u Bletchley Park, Britanskom centru za deifrovanje. Vremenom je postao voa sekcije
koja je bila odgovorna za razbijanje ifara njemacke mornarice. Razvio je niz tehnika za
razbijanje njemackih ifara, ukljucujuci i metod Bombe, elektromehanicke maine koja je
mogla pronaci postavke maine Enigma.
Nakon rata je radio za National Physical Laboratory gdje je kreirao jedan od prvih diza-
jna racunara sa pohranjenim programom, ACE. Godine 1948 se doao u Max Newmans
Computing Laboratory na Manchester University gdje je pomagao u razvoju Manchester
kompjutera i gdje se zainteresovao za matematicku biologiju. Napisao je clanak o hemi-
jskoj osnovi morfogeneze i predvidio oscilatorne hemijske reakcije kao to su reakcija
Bjelousov-

Zabotinski (Belousov-Zhabotinsky oscilating reaction) koja je prvi put uocena


1960. godine.
3
To je poremecaj iz spektra autizma (autism spectrum disorder - ASD) kojeg karakteriu znacajne
tekoce u socijalnoj interakciji, skupa sa ogranicenim i repetitivnim obrascima ponaanja i interesa.
Od drugih tipova autizma se razlikuje po relativno visokom stepenu ocuvanja lingvistickog i kognitivng
razvoja. Mada se ne uzima kao element dijagnoze, cesto se pojavljuju slucajevi zicke "trapaovosti" i
atipicnog koritenja jezika.
69
Tjuringva homoseksualnost je rezultirala kriminalnim progonom godine 1952 kada je ho-
moseksualnost bila ilegalna u Velikoj Britaniji. Prihvatio je tretman zenskim hormonima
(hemijska kastracija) kao alternativu za zatvor. Umro je 1954, nekoliko sedmica prije
svog 42-og roendana, od trovanja cijanidom (gljivama). Istraga je utvrdila da je to
bilo samoubistvo; njegova majka i neki drugi su vjerovali da je umro nesretnim slucajem.
Dana 10.09.2009. godine, nakon Internetske kampanje, Britanski premijer Gordon Brown
je objavio javno izvinjenje u ime Britanske vlade zbog nacina na koji je Alan Tjuring bio
tretiran nakon rata.
9.3 Alfabet
Svaki problem se izrazava u nekom jeziku. Alfabet je skup znakova koji su nedjeljive
cjeline. Rijec na nekom alfabetu je bilo koja konacna sekvenca znakova tog alfabeta.
Sekvenca od nula znakova se naziva prazna rijec. Rijeci se razdvajaju znakom blanko
koji se ne smatra dijelom alfabeta vec pomocnim simbolom.
Jezik je neki poskup skupa svih rijeci odgovarajuceg alfabeta. Rijec t je podrijec rijeci
ako postoje, mozda i prazne, rijeci n i tako da je = nt.
Alfabet je obicno konacan skup znakova jer sve to se moze iskazati beskonacnim pre-
brojivim alfabetom c
1
. c
2
. ... moze se iskazati i najjednostavnijim, unarnim, alfabetom
= 1. Rijeci alfabeta 1. 11. 111. ... se mogu identikovati sa znacima proizvoljnog
beskonacnog alfabeta. Ako se posebno ne naglasi, u nastavku ce biti koriten unarni
alfabet = 1. Pored simbola 1 ce biti koriten i blanko znak za cije oznacavanje ce,
radi preglednosti, biti koriten znak 0.
9.4 Neformalni opis Tjuringove maine
Tjuringova maina se sastoji od :
Trake, koja je podijena u celije, memorijske registre, koja se neograniceno pruza
lijevo i desno; broj celija (tj. duzina trake) je neogranicen; sadrzaj svake celije je ili
znak 1 ili blanko znak (znak 0),
Glave, koja se uvijek nalazi nad tacno jednom celijom trake i moze:
- procitati sadrzaj celije nad kojom se nalazi i
- upisati u celiju nad kojom se nalazi znak 1 ili 0 (blanko znak, tj. obrisati celiju)
ili se pomjeriti za jedan korak u lijevo ili u desno u odnosu na trenutnu poziciju,
Indikatora stanja maine
Tjuringova maina se u svakom trenutku nalazi u tacno jednom od konacno mnogo stanja
koje se eventualno mijenja nakon svakog koraka izracunavanja. Skup svih stanja maine
ce biti oznacen sa o =
1
.
2
. .... Izvravanje maine se izvodi pod dejstvom programa
koji cini neki konacan niz naredbi. Svaka naredba je cetvorka oblika

i
: o
j
70
gde su
i
i
j
neka stanja iz skupa o, : je znak nad kojim se nalazi glava maine a
o 1. 0. 1. 1 je oznaka operacije. U svakom koraku rada maina analizira stanje u
kojem se nalazi i sadrzaj celije nad kojom je glava a zatim izvrava naredbu koja ima
odgovarajuce vrijednosti parametara
i
i :. Efekat izvrenja naredbe je dvojak. Najprije
se, u zavisnosti od vrijednosti parametra o, obavi:
Ako je o = 1 tada se u celiju nad kojom se nalazi glava upisuje znak 1,
Ako je o = 0 tada se u celiju nad kojom se nalazi glava upisuje znak 0,
Ako je o = 1 tada se glava pomjera ulijevo za jednu celiju
Ako je o = 1 tada se glava pomjera udesno za jednu celiju
Nakon toga maina mijenja stanje i prelazi u stanje
j
.
Primjeri naredbi su :

5
0 1
17
: Ako se maina nalazi u stanju
5
a glava nad znakom blanko u celiju se
upisuje znak 1 i prelazi se u stanje
17
;

1
0 0
2
: Ako se maina nalazi u stanju
1
a glava nad znakom blanko u celiju se
upisuje blanko znak i prelazi u stanje
2
. Ovakva naredba sluzi samo za promjenu
stanja maine;

0
1 1
0
: Ako se maina nalazi u stanju
0
a glava nad znakom 1 glava se pomjera
ulijevo a maina ostaje u istom stanju
Ako se zeli da maina radi deterministicki program smije sadrzavati samo jednu naredbu
za svaku kombinaciju stanja
i
i sadrzaja celije : nad kojom je glava. Naprimjer u
programu se ne smiju pojaviti sljedece naredbe :

4
1 1
5

4
1 1
2
jer im se poklapaju vrijednosti parametara
i
i : a vrijednosti parametara o i
j
razlikuju.
U slucaju nedeterministickih maina ovakav zahtjev ne postoji.
Konvencija je da se stanje
0
o zove pocetno stanje. Rijec se na traci prikazuje kao
neprekidan niz celija koje sadrze znak 1 a sa lijeve i desne strane rijeci se nalazi najmanje
po jedan znak blanko odnosno znak 0. U pravilu, na pocetku i kraju glava maine se
nalazi iznad prve celije slijeva koja sadrzi znak 1. Skup stanja o ce biti proiren novim
stanjem
z
koje ce se zvati zavrno stanje. Maina u tom stanju prekida izvrenje.
71
9.5 Formalni opis Tjuringove maine
Neka su :
o : konacan skup stanja

0
: pocetno stanje,
0
o

z
: zavrno stanje,
z
o
= 0. 1 alfabet
o : (o
z
) ( ' 1. 1) o
Tada se Tjuringova maina denie kao ureena petorka (o.
0
.
z
. . o).
Opis trake je preslikavanje 1 : Z tako da ako je u celiji sa indeksom . upisan znak
0 ili 1 tada je 1 (.) = 0 ili 1 (.) = 1.
Konguracija Tjuringove maine ` = (o.
0
.
z
. . o) je trojka (1. . c) gdje su:
1 : opis trake
o : tekuce stanje
c Z : broj celije nad kojom se nalazi glava
Naredba Tjuringove maine ` = (o.
0
.
z
. . o) je cetvorka (
i
. :. o.
j
) gdje je o (
i
. :) =
(o.
j
). Preslikavanje o se naziva program. Pri tome vazi

i
=
0
i
. : = :
0
= o (
i
. :) = o (
0
i
. :
0
)
Racunski korak Tjuringove maine ` = (o.
0
.
z
. . o) za naredbu 1 = (
i
. :. o.
j
) je
svaki par konguracija ((1
0
.
0
. c
0
) . (1
00
.
00
. :
00
)) za koje vazi:

i
=
0
1
0
(c
0
) = :

j
=
00
Ako je operacija o = 1 vazi :
- c
0
= c
00
- 1
0
i 1
00
se poklapaju osim u c
00
gdje je 1
00
(c
00
) = 1
Ako je operacija o = 0 vazi
- c
0
= c
00
- 1
0
i 1
00
se poklapaju osim u c
00
gdje je 1
00
(c
00
) = 0
Ako je operacija o = 1 vazi
- c
0
1 = c
00
- 1
0
i 1
00
se poklapaju
72
Ako je operacija o = 1 vazi
- c
0
+ 1 = c
00
- 1
0
i 1
00
se poklapaju
Da je ((1
0
.
0
. c
0
) . (1
00
.
00
. :
00
)) racunski korak naredbe 1 oznacava se sa (1
0
.
0
. c
0
)
I
(1
00
.
00
. c
00
).
Izracunavanje za Tjuringovu mainu ` = (o.
0
.
z
. . o) i program 1 opisan funkcijom
o je niz konguracija (1
0
.
0
. c
0
), (1
1
.
1
. c
1
), ... , (1
m
.
m
. c
m
) tako da :
(1
0
.
0
. c
0
)
I
1
(1
1
.
1
. c
1
) za neku naredbu 1
1
(programa 1) i stanje
0
=
0
(\/ N) (0 < / < :1)
__
1
k1
.
k1
. c
k1
_

I
k
_
1
k
.
k
. c
k
__
(1
m1
.
m1
. c
m1
)
I
m
(1
m
.
m
. c
m
), za
m
=
m

_
\/ = 1. :1
_ _

k
,=
z
_
c
0
= 0. (\i < 0) (1
0
(i) = 0)
(: 0) (/
1
. .... /
n
) (c
0
_ /
1
< /
2
< ... < /
n
) tako da vazi
- (\i. c
0
_ i _ /
1
) (1
0
(i) = 1. 1
0
(/
1
+ 1) = 0)
- (\i. /
1
+ 1 _ i _ /
2
) (1
0
(i) = 1. 1
0
(/
2
+ 1) = 0)
- ...
- (\i. ) (/
n1
+ 1 _ i _ /
n
) (1
0
(i) = 1)
- (\i. /
n
< i) (1
0
(i) = 0)
1
m
(c
m
) = 1, i (\i < c
m
) (1
m
(i) = 0)
/ _ c
m
:
- (\i. c
m
_ i _ /) (1
m
(i) = 1)
- (\, /) (1
m
(,) = 0)
Varijante Tjuringove maine su :
TM sa bogatijim alfabetom
TM sa vie zavrnih stanja (u kojem svako od njih simbolizuje rezultat rjeavanja
problema)
TM sa lijevo ogranicenom trakom
TM sa vie traka i glavom za svaku od njih
TM sa jednom trakom i vie glava nad njima
TM sa 2D trakom koja je beskonacna po obje dimenzije
TM koje dozvoljavaju u istoj naredbi upis u celiju i pomjeranje glave
73
Nedeterministicke TM (o je relacija a ne funkcija tj. moze postojati vie naredbi
za isto stanje i sadrzaj celije)
Nijedna od ovih varijanti ne proiruje klasu Tjuring izracunljivih funkcija (mogu izracu-
nati samo ono to moze i osnovna verzija TM)
Izracunljiva funkcija je samo ona koja je Tjuring izracunljiva.
9.6 Zadaci
Zadatak. Neka je na traci data samo jedna rijec sastavljena od jedinica (a sve ostale celije
sadrze znak 0); glava je nad krajnjim lijevim znakom. Napisati program koji dopisuje
dva znaka 1 sa desne strane rijeci a zatim se glava vraca ulijevo na pocetak rijeci i maina
staje.
Rjeenje. Osnovni koncept rjeavanja je da se na svakom koraku ispituje tekuci znak.
Ako je to 1 glava se pomice udesno; ako je to 0 znak se mijenja u 1 i glava ponovo pomice
udesno, znak se mijenja u 1; zatim se vri pomjeranje ulijevo sve dok se ne naie na 0;
tada se glava pomjeri jedno mjesto udesno i program zavrava.
Naredba Akcija

0
1 1
0
glava se pomjera udesno na kraj rijeci

0
0 1
1
na mjestu prve 0 se upisuje 1 i prelazi se u stanje
1

1
1 1
2
glava se pomjera udesno

2
0 1
3
na mjestu druge 0 se upisuje 1 i prelazi u stanje
3

3
1 1
3
glava se pomjera ulijevo sve dok ima znakova 1

3
0 1
z
na prvoj 0 glava ide udesno i zaustavlja se
Niz koji opisuje izvravanje ovog programa je dat u nastavku.

0
: 011000...

0
: 011000...

0
: 011000...

1
: 011100...

2
: 011100...

3
: 011110...

3
: 011110...

3
: 011110...

3
: 011110...

3
: 011110...

z
: 011110...
U svakom redu je navedeno stanje a podvucena je pozicija koja odgovara tom stanju.
Ovo se kompaktnije opisuje tabelom.
Stanje 1 0

0

0
1 1
0

0
0 1
1

1

1
1 1
2

2

2
0 1
3

3

3
1 1
3

3
0 1
z
Zadatak. Napraviti program za Tjuringovu mainu koja izracunava funkciju , (r) = 0.
Rjeenje. Zadatak se rjeava tako da se u svakom koraku znak 1 mijenja sa 0. Kraj se
detektuje tako da se ova zamjena izvrava u okviru jednog stanja i da se u okviru istog
stanja ispituje da li je tekuci znak 0.
74
Stanje 1 0

0

0
1 0
1

0
0 0
z

1

1
0 1
0
Zadatak. Napraviti program za Tjuringovu mainu koja racuna nasljednika prirodnog
broja :.
Rjeenje. Nasljednik prirodnog broja je broj koji je za 1 veci od datog broja. Zadatak se
rjeava tako da se glava pomakne jedno mjesto ulijevo, upie znak 1 i zavri posao.
Stanje 1 0

0

0
1 1
1

1

1
0 1
z
Zadatak. Napraviti program za Tjuringovu mainu koja racuna vrijednost funkcije
, (:) = 2:.
Rjeenje. Zadatak se rjeava tako da se tekuci znak 1 zamijeni sa 0, prou svi znaci 1 u
toj rijeci, proe i jedan znak 0 iza te rijeci, prou sve jedinice ako ih eventualno ima iza
te nule, dodaju dva znaka 1, glava vrati preko svih jedinica ulijevo, zatim pree preko
znaka 0 koji razdvaja dvije rijeci, prou sve jedinice pocetne rijeci i doe do prvog znaka
1 te rijeci. Kriterij zaustavljanja je da posljednje stanje, zaduzeno za detekciju jedinica
u prvoj rijeci, detektuje znak 0.
Stanje 1 0

0
0 1
1
0 1
z

1
1 1
1
0 1
2

2
1 1
2
1 1
3

3
1 1
4

4
1 1
4
0 1
5

5
1 1
5
0 1
0
Svaka celija se ovdje cita po sljedecem redu : novi simbol na tekucoj lokaciji (0,1), akcija
(L, R) i novo stanje.
U narednim primjerima Tjuringova maina je data estorkom Q. . . o.
0
. 1 gdje je:
75
Q : konacan skup stanja
: skup ulaznih simbola (alfabet)
: skup simbola na traci ukljucujuci i simbol # za prazno
o : tranzicijska funkcija o : Q Q 1. 1

0
: inicijalno stanje
1 : skup konacnih stanja
Zadatak. Zadata je Tjuringova maina
1` = (
1
.
2
.
3
. 0. 1 . 0. 1. # . o.
0
.
z
)
Maina cita niz znakova i krajnji desni mijenja simbolom #.
Rjeenje. Dijagram za ovaj program je u nastavku.

Citanje niza simbola i ispravka krajnjeg desnog simbola


Ovdje se " 1. 1. 1" cita : Ako je
0
= 1 upisati 1 (1 ostaje 1) i idi desno u stanje
1
" itd.
Program je dat u obliku tabele.
Stanje 1 0 #

0
0. 1.
1
1. 1.
1

1
0. 1.
1
1. 1.
1
#. 1.
2

2
#. 1.
3
#. 1.
3

3
0. 1.
3
1. 1.
3
#. 1.
z
Niz kojim se ilustruje rad ovog programa je u nastavku.

0
: #1110#

1
: #1110#

1
: #1110#

1
: #1110#

1
: #1110#

2
: #1110#

3
: #111##

3
: #111##

3
: #111##

3
: #111##

z
: ##111##
Zadatak. Zadata je Tjuringova maina
76
1` = (
1
.
2
.
3
. 0. 1 . 0. 1. # . o.
0
.
z
)
Napraviti program koji cita niz nula i jedinica i daje podatak o parnosti u nizu. Izlaz je
0 ako je broj jedinica u nizu paran a 1 ako je broj jedinica neparan.
Rjeenje. Akcije koje se obavljaju su :
Trazenje jedinica slijeva udesno
Simboli 0 se citaju ali se ignoriu
Odrzava se brojac ako se naie na simbol 1 u skladu sa tim da li je broj jedinica
paran ili neparan
Kad se naie na znak # izlaz se pie na tekucu poziciju
Skup stanja je sljedeci :

0
indicira da li je broj simbola 1 paran

1
indicira da li je broj simbola 1 neparan
Dijagram za ovaj program je u nastavku.
Brojac pariteta broja jedinica u nizu
Program je dat sljedecoj na tabeli.
Stanje 1 0 #

0
1 1
1
0 1
0
0 1
z

1
1 1
0
0 1
1
1 1
z
Rad je ilustrovan na sljedecem primjeru.

0
: 1011010#

1
: 1011010#

1
: 1011010#

0
: 1011010#

1
: 1011010#

1
: 1011010#

0
: 1011010#

0
: 1011010#

z
: 10110100
77
Zadatak. Zadata je Tjuringova maina
1` = (
1
.
2
.
3
. 0. 1 . 0. 1. # . o.
0
.
z
)
Prethodni primjer modikovati na nacin da se izlaz stavlja nakon simbola # tako da se
dopie jo jedan takav simbol. Drugim rijecima ako je string 01# tada je izlaz u obliku
01#1# a izlaz iz stringa iz prethodnog primjera bi trebao biti 1011010#0#.
Rjeenje. Ovdje je potrebna dodatna akcija za trazenje simbola # i stavljanje izlaza iza
njega. Dijagram za ovaj program je u nastavku.
Modikacija programa za odreivanje pariteta
Program je dat na narednoj tabeli.
Stanje 1 0 #

0
1 1
1
0 1
0
# 1
2

1
1 1
0
0 1
1
# 1
3

2
0 1
z

3
1 1
z
Rad je ilustrovan na sljedecem primjeru.

0
: 1011010##

1
: 1011010##

1
: 1011010##

0
: 1011010##

1
: 1011010##

1
: 1011010##

0
: 1011010##

0
: 1011010##

2
: 1011010##

z
: 1011010#0
Zadatak. Zadata je Tjuringova maina
1` = (
1
.
2
.
3
. 0. 1 . 0. 1. # . o.
0
.
z
)
Napraviti program koji dodaje 1 broju koji je predstavljen binarno, sa mogucim vodecim
nulama.
Rjeenje. Aktivnosti koje se obavljaju su:
Trazenje posljednje znacajne cifre
78
Figure 1: Dodavanje jedinice na binarni zapis broja
Kretanje ulijevo i praviti prenos. Ako je pronaena 0 mijenja se jedinicom i posao
se zaustavlja; Ako je pronaena 1 mijenja se sa 0 i nastavlja sa kontrolom prenosa
Dijagram za ovaj program je u nastavku.
Program je dat na sljedecoj tabeli.
Stanje 1 0 #

0
1 1
0
0 1
0
# 1
1

1
0 1
2
1 1
z
1 1
z

2
0 1
2
1 1
2
# 1
z
Rad programa je ilustrovan na sljedeca dva primjera.
Primjer 1.

0
: ##110#

0
: ##110#

0
: ##110#

0
: ##110#

1
: ##110#

z
: ##111#
Primjer 2.

0
: ##11#

0
: ##11#

0
: ##11#

1
: ##11#

1
: ##10#

1
: ##00#

z
: #100#
Zadatak. Data je Tjuringova maina
1` = (
1
.
2
.
3
.
4
.
5
.
6
. 0. 1. . # . 0. 1. . #. A . o.
0
.
z
)
Napraviti program koji za data dva broja : i : racuna vrijednost max :. :. Svaki broj
je predstavljen nizom jedinica. Pri tome je po jedan simbol postavljen jednu poziciju
ulijevo od kranje lijeve pozicije prvog broja i jednu poziciju desno od krajnje desne pozicije
drugog broja; brojevi su odvojeni jednim znakom # to je i inicijalna pozicija.
Rjeenje. Koncept rjeavanja problema je sljedeci:
pocev od inicijalne pozicije na svakom koraku se po jedna jedinica sa svake strane
zamjenjuje simbolom A
ako se pri kretanju naie na simbol tada se svi znaci A sa te strane znaka #
mijenjaju sa 0, znak # se mijenja u znak svi znaci A sa druge strane znaka #
mijenjaju sa 1
79
Rezultat je broj koji je maksimalni od dva data broja. Navedeni program je dat u obliku
naredne tabele.
# 1 A

0
#. 1.
1

1
A. 1.
3
A. 1.
1
0. 1.
5

2
A. 1.
4
A. 1.
2
0. 1.
6

3
#. 1.
2
A. 1.
3

4
#. 1.
1
A. 1.
4

5
. 1.
5
1. 1.
5
0. 1.
5
. 1.
z

6
. 1.
6
1. 1.
6
0. 1.
6
. 1.
z
80
10 Sortiranja
10.1 Uvod
Algoritmi sortiranja su primjer matematickih algoritama koji se rjeavaju putem mnogih
drugih razlicitih metoda.
U optem slucaju, sortiranje se shvata kao proces pregrupisavanja datog skupa objekata u
nekom odreenom redoslijedu. Cilj sortiranja je olakati pretrazivanje elemenata u tako
sortiranom skupu. To je skoro univerzalni, fundamentalni zadatak. U svakodnevnom
zivotu se srecemo sa puno primjera kao to su telefonski imenici, rijecnici i slicno.
Izbor algoritama za rjeavanje bilo kog problema zavisi od strukture podataka, to je
skoro zakon, a u slucaju sortiranja takva zakonitost je toliko duboka da se odgovarajuce
metode dijele na dvije klase, sortiranje nizova i sortiranje fajlova. Nekada se nazivaju
unutranje i vanjsko sortiranje, s obzirom da se nizovi pohranjuju u brzo internoj memoriji
dok su fajlovi pohranjeni na spoljnim, sporijim ureajima (diskovi,...). Ovo je moguce
ilustrovati na primjeru sortiranja igracih karata. Ako se karte posmatraju u obliku niza
onda su poslozene na stolu i onaj ko ih sortira vidi ih sve pojedinacno i ima neposredan
pristup svakoj od njih. Ako karte obrazuju fajl to podrazumijeva da je vidljiva samo ona
na vrhu svake gomile. Ovakvo ogranicenje ima ozbiljan uticaj na metod sortiranja.
Ako su dati elementi c
1
. c
2
. .... c
n
. ... tada je sortiranje permutacija tih elemenata u niz
c
k
1
. c
k
2
. .... c
k
n
. ... u kojem, po osnovu neke funkcije poretka , vrijedi , (c
k
1
) _ , (c
k
2
) _
... _ , (c
k
n
) _ .... Funkcija poretka se obicno ne racuna po nekom pravilu vec se cuva
kao sastavni dio (polje) svakog elementa. Znacenje te funkcije se naziva kljuc (key).
Metod sortiranja je lokalan (in-place) ako ne koristi dodatne memorijske resurse za sor-
tiranje i stoga je moguce sortirati veoma velike liste bez potrebe alokacije (dodjeljivanja)
dodatnog memorijskog prostora.
Metod sortiranja je stabilan ako se u procesu sortiranja odgovarajuci odnos elemenata sa
jednakim kljucevima ne mijenja. Ovo je cesto pozeljna osobina ako se radi o elementima
koji su vec sortirani nekim metodom koji nema uticaja na kljuc.
10.2 Sortiranje nizova - osnovne metode
Osnovni uslov je da odabrani metod sortiranja nizova ekonomicno koristi dostupnu mem-
oriju. To podrazumijeva da se permutacije kojima se elementi stavljaju u odgovarajuci
poredak obavljaju na tom istom mjestu. Drugim rijecima, metode koje podrazumijevaju
da se elementi niza c premjetaju u niz / predstavljaju bitno manji interes. Zbog ovakvih
ogranicenja algoritmi se klasiciraju po osnovu ekonomicnosti odnosno vremenu rada.
Dobra mjera ekasnosti moze biti C, broj neophodnih uporeivanja kljuceva i `, broj
premjetanja (permutacija) elemenata. Ovi brojevi su funkcija od :, dimenzije niza koji
se sortira.
Mada dobri algoritmi sortiranja trebaju :log : uporeivanja, analiza pocinje od prostijih
i ociglednih algoritama koji se nekada nazivaju direktni. Motiv za ovakav izbor moze biti:
Direktne metode su posebno pogodne za objanjenje karakteristika osnovnih prin-
cipa obima sortiranja
81
Postupci tih metoda se lako pamte i kratki su. Ne treba zaboraviti da i programi
zauzimaju memoriju
Usloznjavanje metoda trebaju manji broj operacija koje su same po sebi dosta
slozene pa su za male : direktne metode brze mada ih ne treba koristiti za velike :
Metode sortiranja na tekucoj poziciji se dijele na :
Sortiranja putem ukljucivanja (insertion)
Sortiranja putem podjele (selection)
Sortiranja putem zamjene (exchange)
Napomena. U narednom izlaganju se koristi tzv. relativno indeksiranje nizova koje
sastoji u tome da prvi clan niza ima indeks 0 a da svi ostali imaju indeks koji odgovara
broju pozicija nakon tog elementa. U takvoj notaciji je c
4
je peti element niza jer je
4 pozicije u odnosu na c
0
. Iz tog razloga je vazno razumjeti da npr. 1n.i:c [c] 1
oznacava, ustvari, indeks posljednjeg a ne pretposljednjeg clana niza.
U tzv. apsolutnom indeksiranju clanovi niza imaju indeks koji odgovara njihovoj stvarnoj
poziciji (c
1
. c
2
. .... c
n
. ...). Pomocu jednostavne transformacije je moguce pretvoriti jednu
notaciju u drugu.
10.2.1 Sortiranje putem umetanja (Insertion sort)
Algoritam sortiranja umetanjem (Insertion sort) se temelji na meusobnom uporeivanju
vrijednosti kljuceva pri cemu se u svakoj iteraciji odrzavaju sortirani i nesortirani dio niza.
U svakom sljedecem koraku se iz nesortiranog dijela uzima jedan element i taj element se
umece na odgovarajuce mjesto u sortiranom dijelu. Prema tome, svakim novim korakom
nesortirani dio niza se smanjuje, dok se sortirani dio niza postepeno povecava.
Insertion sort ce biti objanjen na primjeru sortiranja niza = c
0
. c
1
. .... c
n1
u ras-
tucem poretku. Na pocetku algoritma sortirani dio se sastoji samo od prvog elementa c
0
dok svi ostali elementi cine nesortirani dio niza. U prvom koraku se porede elementi c
1
i
c
0
(drugi i prvi element u nizu). Ako je element c
0
veci od elementa c
1
tada se element
c
1
pohranjuje u privremenu lokaciju j:i, element c
0
se pomjera na drugo mjesto (i = 1)
te se na prvo mjesto u nizu s indeksom i = 0 pohranjuje element c
1
iz privremene lokacije
j:i. U ovom trenutku sortirani dio niza sadrzi dva elementa (c
0
i c
1
) a nesortirani dio
sadrzi : 2 elemenata (c
2
, c
3
,...c
n1
).
Pretpostavimo da je algoritam doao do nekog i-tog koraka. Poslije prethodnog (i 1)-og
koraka u sortiranom dijelu se nalaze elementi c
1
, c
2
,..., c
i1
. Zatim se u i-tom koraku
iz nesortiranog dijela uzima element c
i
nakon cega se prema kraju niza pomjeraju svi
elementi iz sortiranog dijela niza koji su veci od elementa c
i
da bi se oslobodio prostor za
pohranjivanje tog elementa na odgovarajuce mjesto u nizu. Na taj nacin se velicina sorti-
ranog dijela niza povecava sa i 1 na i. Sortiranje se zavrava kada u nesortiranom dijelu
niza nema vie elemenata odnosno kada zadnji element c
n1
zauzme svoju odgovarajucu
poziciju. Algoritam je ilustrovan na primjeru u sljedecoj tabeli.
82
0 1 2 3 4 5 j:i
4 11 2 9 3 10
4 11 2 9 3 10
4 11 9 3 10 2
4 11 9 3 10 2
4 11 9 3 10 2
2 4 11 9 3 10
2 4 11 9 3 10
2 4 11 3 10 9
2 4 11 3 10 9
2 4 9 11 3 10 9
2 4 9 11 3 10
2 4 9 11 10 3
2 4 9 11 10 3
2 4 9 11 10 3
2 4 9 11 10 3
2 3 4 9 11 10
2 3 4 9 11 10
2 3 4 9 11 10
2 3 4 9 11 10
2 3 4 9 10 11
Na tabeli su naglaeni elementi koji u tom algoritmu imaju indeks i. Pseudo kod kojim
se opisuje ovaj algoritam je u nastavku.
Procedura InsertionSortDirektni
Ulaz : :. c
n

Inicirati i. ,. j:i
// Pocetak od prve pozicije
i 1
Za (i _ 1n.i:c [c] 1) raditi
{
// Element ide na rezervnu lokaciju
j:i c [i]
// Umetanje elementa c [i] u sortirani niz c [1. ... , 1]
, i 1
DokVrijedi (, _ 0 & c [,] j:i) raditi
{
// Element se stavi jednu poziciju desno
c [, + 1] c [,]
// Pomjeramo se za jedno mjesto ulijevo
, , 1
}
// Element sa privremene lokacije se smjeta na svoje mjesto
c [, + 1] j:i
}
Izlaz : Sortirani niz c
n

Proces trazenja se moze zavriti u jednom od dva slucaja :


83
Naen je element c
j
sa kljucem koji je manji od kljuca za r
Dostignut je lijevi kraj sortiranog dijela niza
Ovakav tipican slucaj ponavljajuceg procesa sa dva uslova zavretka dozvoljava koritenje
granicnika (sentinel). U ovom slucaju to moze biti element c
0
(to znaci da je dovoljno
raspon indeksa proiriti indeksom 0). Analiza slozenosti ove metode je data dijelom na
sljedecoj tabeli.
Korak Dinamika
0 1 i 1
1 DokVrijedi (i < 1n .i:c [c]) raditi { :
2 j:i c [i] : 1
3 , i 1 : 1
4 DokVrijedi (, _ 0 & c [,] j:i) raditi {
5 c [, + 1] c [,]
6 , , 1
7 }
8 c [i + 1] j:i : 1
9 , , + 1 : 1
10 }
Najbolji slucaj se pojavljuje u situaciji kada je niz vec sortiran pa je za pozicioniranje
svakog elementa potrebna samo jedna operacija poreenja. Tom operacijom se zapravo
samo utvruje da je prethodnik svakog elementa manji od tog elementa, te svi elementi
ostaju na svojim mjestima. To znaci da je u najboljem slucaju ukupan broj operacija
poreenja 1
c
(:) :
1
c
(:) = : 1
Prema tome, vremenska slozenost za najbolji slucaj je O(:).
Najgori slucaj se pojavljuje u situaciji kada je za umetanje svakog elementa iz nesortiranog
dijela niza potrebno porediti taj element sa svim elementima u sortiranom dijelu niza.
Drugim rijecima, najgori slucaj je kada se svaki element trenutno pozicionira na pocetak
sortiranog dijela niza. To se dogaa kada je niz sortiran u obrnutom poretku. Tada je
ukupni broj operacija usporedbi 1
c
(:) :
1
c
(:) =
n

i=1
i =
:(: 1)
2
Na taj nacin se dobija da ovaj algoritam ima kvadratnu zavisnost od velicine niza odnosno
njegova brzina se izrazava sa O(:
2
).
Analiza ove metode putem broja poreenja i premjetanja pokazuje da broj poreenja
kljuceva (C
i
) u i-tom koraku moze biti najvie i 1, najmanje 1 a u prosjeku i,2,
pod pretpostavkom da su sve permutacije od : elemenata jednako vjerovatne. Broj
premjetanja `
i
je jednak C
i
+2 (ukljucujuci barijeru, sentinel). Na tabeli 3. su procjene
brzine ovog algoritma.
Minimalne ocjene se mogu desiti kod vec sortiranih nizova a najgore kada je niz sortiran
opadajucim redoslijedom.
84
C `
min : 1 3 (: 1)
prosjek
:
2
+: 2
4
:
2
+ 9: 10
4
max
:
2
+: 4
4
:
2
+ 3: 4
4
Poboljanja
Kod ovog algoritma se obavlja pretrazivanje sortiranog dijela niza da bi se odredila pozi-
cija umetanja prvog elementa iz nesortiranog dijela niza. Poboljanje ekasnosti postup-
kom da se pozicija umetanja pronalazi binarnim umjesto sekvencijalnim pretrazivanjem
temelji se na svojstvu da je prvi dio niza sortiran, kao to je to slucaj u osnovnoj vari-
janti algoritma. U toj poboljanoj varijanti prosjecan broj operacija poreenja u svakoj
iteraciji se smanjuje sa i,2 na priblizno 1 + log
2
i. To znaci da je u poboljanoj varijanti
vremenska slozenost za operacije poreenja reda O(:log :) to je znatno poboljanje, ali
samo za te operacije. Meutim, ekasnim pronalazenjem mjesta umetanja ne smanjuje
se i broj potrebnih operacija premjetanja koji zapravo ostaje isti kao i u osnovnoj vari-
janti. Taj broj operacija je dominantan u odnosu na broj operacija u poreenju za velike
vrijednosti : pa ukupna vremenska slozenost algoritma ostaje O(:
2
). Pseudo kod za ovu
varijantu algoritma sortiranja je u nastavku.
10.2.2 Shell sort
U osnovnoj varijanti algoritma sortiranja umetanjem elementi se pomjeraju za samo
jednu poziciju, to za posljedicu ima veliki broj premjetanja. Ekasnost algoritma se
moze poboljati na nacin da se porede elementi koji su odvojeni nekim brojem pozicija
pa da se umetanje elemenata obavlja tako da se prave premjetanja elemenata koji su
razdvojeni sa vie od jednog mjesta razmaka. Neka je, na primjer, u nizu element koji ima
neku malu vrijednost koja se prije sortiranja nalazi pri kraju niza i da niz treba sortirati
niz u rastucem poretku. Koristeci osnovnu varijantu algoritma sortiranja umetanjem
bio bi potreban veliki broj operacija poreenja i premjetanja dok taj element ne bi bio
umetnut na odgovarajucu poziciju. Ekasnost se moze poboljati tako da se elementi prvo
pomjeraju prema konacnoj poziciji koristeci velike skokove, tako da bi se, na primjer,
element koji ima malu vrijednost pomjerio prema konacnoj poziciji uz samo nekoliko
operacija poreenja i premjetanja. Poboljanje koje se temelji na prethodno opisanoj
strategiji je predlozio Donald Shell, po kojem je algoritam nazvan Shell sort.
Prethodno je receno da je osnovna varijanta algoritma umetanjem ekasna ako ulazni
niz vec ima visok stepen ureenosti. Algoritam Shell sort razdvaja pocetni niz na grupe
tako to se u svakoj grupi nalaze elementi koji su odvojeni jednakim razmakom, koji ce
biti oznacen sa /
1
. Zatim se svaka grupa sortira posebno primjenom osnovne varijante
sortiranja umetanjem, nakon cega se dobija niz sa vecim stepenom ureenosti u odnosu
na pocetni niz. U sljedecem koraku se uzima razmak /
2
koji je manji od razmaka /
1
. U
ovom koraku je smanjen broj grupa, ali svaka grupa ima veci broj elemenata. Grupe se
ponovo posebno sortiraju primjenom osnovne varijante algoritma sortiranja umetanjem
pa se dobija jo veci stepen ureenosti ulaznog niza. U sljedecim koracima se biraju
sve manji i manji razmaci, a postupak zavrava primjenom zavrnog razmaka /
t
= 1
to zapravo znaci da se u zadnjoj fazi svi elementi tretiraju kao jedna grupa. Drugim
rijecima, u zadnjem koraku, kada je ulazni niz vec gotovo sortiran, primjenjuje se
85
Procedura BinaryInsertion
Ulaz : :. c
n

Izlaz : Sortirani niz c


n

Inicirati i. ,. :. 1. 1. r
Za svaki i = 1. 1n.i:c [c] 1. 1
{
//Uzeti element niza
r c [i]
1 1; 1 1
// Odrediti lijeve i desne granice
DokVrijedi 1 < 1 raditi
{
: = (1 +1) ,2|
Ako je c [:] < r
{
1 :+ 1
}
Inace
{
1 :
}
}
//Pretraziti sortirani niz
Za svaki , = i. 1 + 1. 1
{
c [,] c [, 1]
}
c [1] r
}
osnovna varijanta metoda umetanjem. U opisanim fazama algoritma sortiranja Shell sort
koristi niz razmaka / = [/
1
. /
2
. .... /
t1
] pri cemu je /
i
/
i+1
, i = 1. .... t 2.
Za razumljiviji opis ovog algoritma ce biti koriten konkretan primjer. Neka je zadatak
sortirati sljedeci niz brojeva:
28. 17. 10. 79. 13. 67. 23. 33. 12. 5. 9. 80. 86. 15. 59. 49. 64. 54. 36. 29
Poto algoritam Shell sort poredi brojeve iz niza uzimajuci neki razmak, neka je u pr-
voj fazi taj razmak 7 tj. /
1
= 7. To znaci da ce se porediti i meusobno eventualno
razmjenjivati mjesta sljedeci brojevi: 28, 33 i 59 (jer su razmaknuti za 7 mjesta). Isto
tako, poredice se i eventualno meusobno razmjenjivati mjesta brojevi 17,12 i 49 (jer
su takoer razmaknuti za 7 mjesta). Da bi ovaj proces bio jasnije objanjen, moze se
koristiti drugaciji nacin prikaza. Naime, ako je odabran razmak 7 onda se gornji pocetni
niz brojeva moze prikazati sljedecom tabelom koja ima 7 kolona, pri cemu svaka kolona
sadrzi elemente pojedine grupe koji se posebno sortiraju:
28 17 10 79 13 67 23
33 12 5 9 80 86 15
59 49 64 54 36 29
86
Ovakav prikaz je napravljen samo u cilju vizueliziranja procesa poreenja i sortiranja
pojedinih grupa, koji se obavljaju u pojedinim fazama primjene algoritma Shell sort.
Sada se sortira svaka kolona (grupa) posebno. Rezultirajuca tabela je:
28 12 5 9 13 29 15
33 17 10 54 36 67 23
59 49 64 79 80 86
Ova tabela se sada moze prikazati u obliku jednodimenzionalnog niza, to zapravo i
odgovara stvarnom rasporedu elemenata u memoriji:
28. 12. 5. 9. 13. 29. 15. 33. 17. 10. 54. 36. 67. 23. 59. 49. 64. 79. 80. 86
Moze se primijetiti da rezultirajuci niz u trenutnoj fazi sortiranja, kada je uzet razmak 7,
ima veci stepen ureenosti od pocetnog niza. Vidljivo je pomjeranje elemenata sa vecim
vrijednostima prema kraju niza i elemenata sa manjim vrijednostima prema pocetku niza.
Na primjer, element 29 sa zadnje pozicije se pomjerio na esto mjesto, dok se, na primjer,
element 36 sa predzadnje pozicije pomjerio na dvanaesto mjesto.
Postupak primjene algoritma Shell sort se nastavlja tako to se sada uzme, na primjer,
razmak /
2
= 3. To znaci da se ulazni niz u drugoj fazi za potrebe vizualizacije elemenata
koji se tretiraju kao posebne grupe moze prikazati u obliku sljedece tabele sa 3 kolone:
28 12 5
9 13 29
15 33 17
10 54 36
67 23 59
49 64 79
80 86
Opet se grupe (kolone) sortiraju posebno primjenom osnovne varijante sortiranja umetan-
jem te se dobija sljedeca tabela :
9 12 5
10 13 17
15 23 29
28 33 36
49 54 59
67 64 79
80 86
Gornja tabela zapravo prikazuje sljedeci niz:
9. 12. 5. 10. 13. 17. 15. 23. 29. 28. 33. 36. 49. 54. 59. 67. 64. 79. 80. 86
Rezultujuci niz ima jo veci stepen ureenosti u odnosu na niz u prethodnoj fazi. Naime,
dolo je do daljnjeg pomjeranja vecih brojeva prema kraju niza i manjih brojeva prema
pocetku niza. Rezultujuci niz ipak jo nije sortiran, te je ostalo da se napravi jo jedna faza
nakon cegace niz biti konacno sortiran. Poto je trenutni niz skoro sortiran, razumno je
zapravo uzeti razmak /
3
= 1 a to znaci primijeniti osnovnu varijantu algoritma sortiranja
umetanjem, jer ce biti potreban mali broj poreenja i premjetanja s obzirom da je niz vec
skoro sortiran. Dakle, primjenom algoritma sortiranja umetanjem s razmakom /
3
= 1,
dobija se rezultirajuci sortirani niz:
87
5. 9. 10. 12. 13. 15. 17. 23. 28. 29. 33. 36. 49. 54. 59. 64. 67. 79. 80. 86
Algoritam za Shell Sort je u nastavku. U njemu je H niz razmaka koji se uzimaju na
svakom koraku. U naem primjeru je H = 7. 3. 1.
// Ulaz : Niz c, H
// Niz H je niz koraka za koje se obavlja sortiranje
Za i = 0 do 1n.i:c [/] 1 Raditi
{
/ H [i]
Za , / do 1n.i:c [c] 1 Raditi
{
j:i c [,]
/ , /
SveDokJe (/ _ 0) & (c [/] j:i) Raditi
{
c [/ +/] c [/]
/ / /
}
c [/ +/] j:i
}
}
Analiza ShellSort algoritma je postavila nekoliko veoma tekih matematickih problema
od kojih neki jo nisu rijeeni. Kao najbitnije, nije pokazano koja rastojanja daju najbolji
rezultat. Postoji zacuujuca cinjenica : rastojanja ne smiju biti meusobni mnozitelji.
Ovo dozvoljava da se izbjegne pojava da se formiraju podnizovi koji se ne presijecaju.
Stoga je interakcija dva niza pozeljna to je vie moguce.
Do sortiranog niza ce dovesti primjena bilo kojeg niza razmaka H = /
0
. /
1
. .... /
t1

takvih da je :
/
i
/
i+1
, i = 0. 1. 2. .... t 2
/
t1
= 1
Knut je predlozio niz 1. 4. 13. 40. ... gdje je /
k1
= 3 /
k
+ 1, /
t
= 1, t = log
3
:| 1.
Drugi prijedlog je niz 1. 3. 7. 15. ... gdje je /
k1
= 2 /
k
+ 1, /
t
= 1, t = log
2
:| 1.
Analiza pokazuje da su u posljednjem slucaju rezultati proporcionalni sa :
1:2
. Mada je
ova vrijednost bitno bolja od :
2
to ne znaci da se ne mogu praviti nova poboljanja.
10.2.3 Sortiranje putem direktne podjele (Selection sort)
Jedan od nedostataka algoritma Insertion sort je to to zahtijeva veliki broj operacija
pomjeranja unutar sekvence. Primjer jednostavnog algoritma sortiranja koji je oblikovan
tako da se bitno smanjuje broj premjetanja je Selection sort (sortiranje selekcijom) al-
goritam. Kod ovog algoritma se pomjeranje podataka pri sortiranju obavlja direktno na
njihovu konacnu poziciju u sortiranom nizu.
Slicno kao i kod algoritma Insertion sort, i kod algoritma Selection sort se u procesu
sortiranja razlikuju sortirani i nesortirani dio niza. Na pocetku svi elementi niza
88
= c
0
. c
1
. ...c
i
. c
i+1
. .... c
n1

pripadaju nesortiranom dijelu, a zatim se sekvencijalnim pretrazivanjem pronalazi na-


jmanji element, koji se zatim premjeta na prvu poziciju, dok se prethodni element s
prve pozicije premjeta na poziciju pronaenog minimalnog elementa. Na taj nacin je
u prvom koraku oblikovan sortirani dio niza koji cini element c
0
dok ostali elementi
niza c
1
. c
2
. .... c
n1
cine nesortirani dio niza. Poslije nekog (i 1)-og koraka u sorti-
ranom dijelu niza su elementi c
0
. c
1
. .... c
i2
dok su u nesortiranom dijelu niza elementi
c
i1
. c
i
. .... c
n1
. U sljedecem i-tom koraku se u nesortiranom dijelu niza pronalazi naj-
manji element pa se taj element pozicionira na prvo mjesto u neureenom dijelu niza a
to je pozicija i 1. U tom trenutku sortirani dio niza je c
0
. c
1
. .... c
i1
a nesortirani dio
niza je c
i
. c
i+1
. .... c
n1
. Postupak sortiranja se zavrava kada u nesortiranom dijelu na
poziciji : 1 ostane samo jedan element, koji zapravo ostaje na toj poziciji.
Vazno je primijetiti da se poreenje elemenata kod sortiranja selekcijom obavlja nad
elementima nesortiranog dijela niza, za razliku od sortiranja umetanjem, kod kojeg se
usporedba elemenata obavlja nad elementima sortiranog dijela niza. Ova razlika ima za
posljedicu da postupak sortiranja selekcijom ne moze zapoceti sve dok nisu prisutni svi
elementi koji se trebaju sortirati, to nije slucaj kod sortiranja umetanjem, kod kojeg
elementi koji se sortiraju mogu pristizati jedan za drugim.
Algoritam za sortiranje selekcijom je ilustriran na narednoj slici za niz od 6 elemenata.
0 1 2 3 4 5
4 11 2 9 3 10
2 11 4 9 3 10
2 11 4 9 3 10
2 3 4 9 11 10
2 3 4 9 11 10
2 3 4 9 11 10
2 3 4 9 11 10
2 3 4 9 11 10
2 3 4 9 11 10
2 3 4 9 10 11
Zaokruzena je pozicija niza za koju se u procesu sortiranja u pojedinim fazama selek-
cionira minimalni element iz nesortiranog dijela niza, dok je podvucena pozicija na kojoj
je pronaen minimalni element u nesortiranom dijelu niza. U prvom koraku je oznacena
prva pozicija sa indeksom 0 na kojoj se nalazi element 4 te je pronaen minimalni element
2 na poziciji s indeksom 2. U sljedecem koraku elementi 4 i 2 mijenjaju pozicije te se u
nizu razlikuju sortirani dio niza koji se sastoji samo od elementa 2 i nesortirani dio niza
koji ukljucuje sve ostale elemente. U sljedecem koraku je oznacena pozicija s indeksom
1 na kojoj se nalazi element 11 i pronaen je minimalni element 3 u nesortiranom dijelu
niza, pa elementi 11 i 3 mijenjaju pozicije u nizu. U tom trenutku sortirani dio niza cine
elementi 2 i 3 a elementi 4, 9, 11 i 10 cine nesortirani dio niza.
Ovaj postupak se ponavlja za sve ostale pozicije i (i = 2. 3. .... : 2), sve dok se na
pretposljednje mjesto u nizu ne umetne element 10. Zadnji preostali element 11 zauzima
jedinu mogucu (zadnju) poziciju, pa se postupak zavrava selekcioniranjem elementa za
poziciju i = : 2.
89
// Algoritam : Selection sort
Za i 0 do 1n.i:c [c] 2 raditi
{
:c,: c [i]
j
najm
i
Za , i + 1 do 1n.i:c [c] 1 Raditi
{
AkoJe (c [,] < :c,:) tada
{
:c,: c [,]
j
najm
,
}
}
c [j
najm
] c [i]
c [i] :c,:
}
Algoritam za sortiranje selekcijom je opisan procedurom na dijagramu. Ulazni argument
u proceduru je niz c koji se sortira. Vanjska for petlja omogucuje ponavljanje pos-
tupka pronalazenja minimalnog elementa u nesortiranom dijelu niza za svaku od lokacija
i = 0. 1. 2. .... 1n.i:c [c] 2. Za zadnju lokaciju 1n.i:c[c] 1 nije potrebno ponavljati
postupak, jer se u tom slucaju nesortirani dio niza sastoji samo od jednog elementa, pa
je taj podniz sortiran sam po sebi. U svakoj i-toj iteraciji se prvo inicijaliziraju vrijed-
nosti privremeno minimalnog elementa :c,: i indeksa njegove pozicije j
najm
a zatim se
u sklopu unutarnje for petlje izvode iteracije kojima se u nekom ,-tom prolazu u nesor-
tiranom dijelu niza c, kojeg cine elementi na pozicijama i do 1n.i:c[c] 1, pronalazi
minimalni element. Na kraju svake i-te iteracije vanjske for petlje element na poziciji
j
najm
i prvi element c[i] iz nesortiranog dijela niza izmjenjuju svoje pozicije.
Algoritam sortiranja selekcijom je specican po tome to je i broj pridruzivanja i broj
poreenja uvijek isti, bez obzira na duzinu niza. Algoritam se izvrava u : 1 prolaza
kroz nesortirani dio niza, a svaki prolaz ima jednu zamjenu pozicija koja ukljucuje 3
operacije pridruzivanja. To znaci da je ukupan broj operacija pridruzivanja :
1
a
(:) = 3 (: 1)
Dakle, operacije pridruzivanja kod algoritma sortiranja selekcijom imaju slozenost O(:),
to je znatno poboljanje u odnosu na algoritam sortiranja umetanjem kada su u pitanju
operacije pridruzivanja. U prvom prolazu ima : 1 operacija poreenja, u drugom
prolazu ih ima : 2 a u nekom i-tom prolazu broj poreenja je : i. Dakle, ukupan
broj poreenja je:
1
c
(:) =
n1

i=1
(: i) =
:(: 1)
2
Broj zamjena je minimalno `
min
= 3 (: 1) u slucaju da su kljucevi odmah sortirani
a maksimalno `
max
= (:
2
,4) + 3 (: 1) ako su pocetni kljucevi poredani opadajucim
redom.
90
Za proracun prosjecnog vremena trajanja uzima se da je ocekivani broj premjetanja
jednak sumi H
n
= 1 + 1,: + 1,2 + ... + 1,:. Pri tome su 1,i vjerovatnoce da je i-ti
element manji od prethodnih i 1 elemenata. Ova vrijednost se moze iskazati i sa
H
n
= ln : +q + 1,2: 1,12:
2
+...
gdje je q = 0. 577216... Eulerova konstanta. Za dovoljno veliko : se mogu zanemariti
razlomci u nastavku pa je prosjecan broj premjetanja na i-tom koraku jednak 1
i
=
ln i +q + 1. Prosjecan broj premjetanja, u oznaci `
avg
, je suma svih 1
i
odnosno
`
avg
= : (q + 1) +
n

i=1
ln i
Ova se suma aproksimira integralom
n
_
1
ln rdr = r (ln r 1)[
n
1
= : (ln : 1) : + 1
to na kraju daje `
avg
= : (:ln +q). Odavdje se izvodi zakljucak da je ovaj algoritam
preporucljiviji u odnosu na sortiranje umetanjem. Ako su kljucevi sortirani ili skoro
sortirani insertovanje je neto bolji algoritam.
10.2.4 Sortiranje putem zamjene (Bubble sort)
Ovaj algoritam se zasniva na poreenju i zamjeni mjesta parova susjednih elemenata i
obavljanja ovog postupka dok se ne sortiraju svi elementi. Kao i u metodi selekcije pro-
lazi po nizu se ponavljaju pri cemu se svaki put najmanji element preostalog dijela niza
premjeta na lijevi kraj niza. Ako se nizovi posmatraju vertikalno a ne horizontalno ele-
mente je moguce interpretirati kao mjehure, pri cemu "tezina" svakog elementa odgovara
njegovom kljucu. Na taj nacin se svaki element poput mjehura podize do pozicije koja
mu pripada. Ovaj metod je stoga poznat pod nazivom BubbleSort.
Bubble sort je jedan od najjednostavnijih algoritama sortiranja. Ovaj algoritam radi tako
da vie puta sekvencijalno prolazi kroz niz, pri cemu se pri svakom prolazu uporeuje svaki
element sa elementom koji se nalazi neposredno iza njega. Ako se nakon poreenja utvrdi
da susjedni elementi nisu u zeljenom poretku, onda elementi meusobno izmjenjuju svoje
pozicije, to ima za posljedicu da se prema kraju niza postepeno pomjeraju elementi sa
vecim vrijednostima ako je zeljeni poredak sortiranja rastuci, ili da se prema kraju niza
postepeno pomjeraju elementi sa manjim vrijednostima ako je zeljeni poredak sortiranja
opadajuci.
U prvom prolazu kroz niz na zadnjem mjestuce se sigurno pozicionirati najveci (najmanji)
element. Na taj nacin sortirani dio niza cini element c [: 1] a nesortirani dio niza cine
elementi
c [0] . c [1] . .... c [: 2]
91
U sljedecem, drugom prolazu, porede se elementi na pozicijama 0 do :2, te ce se nakon
tog prolaza na poziciju s indeksom :2 sigurno pozicionirati najveci element iz trenutno
nesortiranog dijela niza c[0..:2]. Opcenito, prije nekog i-tog prolaza, za i 1, sortirani
dio niza cine elementi c [: i + 1] . c [: i + 2] . .... c [: 1] dok nesortirani dio niza cine
elementi c[0]. c[1]. . . . . c[: i]. U nekom i-tom prolazu poreenja i izmjene pozicija
susjednih elemenata ce na (: i)-tu poziciju doci najveci element iz nesortiranog dijela
niza c[0..: i]. Sekvencijalni prolazi kroz niz se nastavljaju sve (: 1)-og prolaza kroz
niz odnosno sve dok se na drugu poziciju u nizu s indeksom 1 ne pozicionira odgovarajuci
element. Naime, :-ti prolaz kroz niz nije ni potreban jer je ostao samo jedan element i
samo jedna dostupna pozicija s indeksom 0 pa je prakticno niz nakon (: 1)-og prolaza
vec sortiran.
Algoritam Bubble sort je ilustriran po koracima na slici za jedan primjer pocetnog ne-
sortiranog niza od 6 elemenata. Algoritam ukljucuje : 1 prolaza kroz nesortirani dio
niza, pri cemu svaki prolaz osigurava smjetanje najveceg elementa iz nesortiranog dijela
na zadnju poziciju tog dijela niza. Ta pozicija je na slici za svaki prolaz istaknuta linijom
s donje strane. Okvirom su oznaceni elementi koji se nalaze u sortiranom dijelu niza,
odnosno, elementi koji se nalaze na svojim konacnim pozicijama. U prvom koraku su
oznacene prva pozicija sa indeksom 0 na kojoj se nalazi element 10 i druga pozicija sa
indeksom 1 na kojoj se nalazi element 11. Poto su elementi 10 i 11 u zeljenom poretku,
ne dolazi do zamjene njihovih pozicija. U sljedecem koraku se porede elementi 11 i 3.
Buduci da se ovi elementi ne nalaze u zeljenom poretku, dolazi do zamjene njihovih pozi-
cija. Prvi prolaz kroz niz se nastavlja sve dok varijabla , ne dostigne vrijednost , = 5.
Nakon prvog prolaza ce se najveci element 11 nalaziti na svojoj konacnoj poziciji s in-
deksom i = 5. U ovom trenutku sortirani dio niza cini jedino element 11 dok svi ostali
elementi predstavljaju nesortirani dio niza.
U drugom prolazu kroz niz (i = 4) na poziciju s indeksom 4 ce se pozicionirati najveci
element iz nesortiranog dijela niza a to je element 10. Nakon drugog prolaza sortirani
dio niza cine elementi 10 i 11, a nesortirani dio niza cine elementi 3, 4, 9 i 2. Opisani
postupak se ponavlja za sve ostale vrijednosti varijable i (i = 3. 2. 1), sve dok se na drugo
mjesto u nizu ne umetne element 3. Jedini preostali element u nesortiranom dijelu niza
je element 2, koji na kraju zauzima jedinu slobodnu poziciju s indeksom 0. Svi koraci
algoritma Bubble sort za ovaj primjer su takoer ilustrirani na slici.
0 10 10 10 10 10 10 10 3 3 3 3 3 3 3 3 3 2
1 11 11 3 3 3 3 3 10 4 4 4 4 4 4 4 2 3
2 3 3 11 4 4 4 4 4 10 9 9 9 9 2 2 4 4
3 4 4 4 11 9 9 9 9 9 10 2 2 2 9 9 9 9
4 9 9 9 9 11 2 2 2 2 2 10 10 10 10 10 10 10
5 2 2 2 2 2 11 11 11 11 11 11 11 11 11 11 11 11
c / c d c , q / i , / | : : o j
Ovaj algoritam je prikazan u obliku procedure u nastavku. Ulaz u proceduru je niz c koji
se sortira. Vanjskom for petljom se implementira 1n.i:c[c] 1 prolaza kroz nesortirani
dio niza, cime se osigurava smjetanje najveceg elementa na zadnju poziciju tog dijela
niza. Unutarnjom for petljom se implementira jedan prolaz u kojem se nakon poreenja
susjednih elemenata i utvrivanja da nisu u zeljenom poretku izmjenjuju njihove pozicije.
92
Za 1 1n.i:c [c] 1 do 1 raditi
{
Za , 1 do i raditi
{
AkoJe (c [, 1] c [,]) tada
{
c [, 1] c [,]
}
}
}
Pretpostavimo da je ulazni niz c vec sortiran. U toj situaciji ce broj potrebnih operacija
ostati opet isti, bez obzira na pocetnu ureenost niza. Meutim, da bi se u odreenoj
mjeri povecala ekasnost, moguce je oblikovati takvu varijantu algoritma Bubble sort
koja ce detektirati prolaz kroz niz u kojem nije dolo ni do jedne zamjene pozicija, to
je zapravo znak da je niz vec sortiran. Nakon takve detekcije proces sortiranja se moze
prekinuti da bi se izbjegle nepotrebne operacije poreenja. Postoji mogucnost da je samo
jedan dio niza vec sortiran pa se ekasnost moze povecati i tako to ce se identicirati
taj dio niza kojeg u sljedecoj iteraciji nece biti potrebno prolaziti. Detekciju prolaza kroz
niz u kojem nije dolo ni do jedne zamjene pozicija, a isto tako i identiciranje dijela
niza koji je vec sortiran, moze se napraviti tako da se u svakom prolazu kroz niz zapamti
pozicija sa najvecim indeksom , na kojoj je izvrena zamjena. Neka se, na primjer, sortira
niz koji ima : = 9 elemenata, te da je nakon treceg prolaza raspored elemenata kao na
slici.
0 1 2 3 4 5 6 7 8
i = 5. , = 1. j = 1 27 24 17 28 31 33 35 38 43 a
i = 5. , = 2. j = 2 24 27 17 28 31 33 35 38 43 b
i = 5. , = 3. j = 2 24 17 27 28 31 33 35 38 43 c
i = 5. , = 4. j = 2 24 17 27 28 31 33 35 38 43 d
i = 5. , = 5. j = 2 24 17 27 28 31 33 35 38 43 e
U cetvrtom prolazu varijabla i ima vrijednost 5 dok se vrijednost varijable , mijenja od
1 do 5. U ovom cetvrtom prolazu zadnja izmjena je izvrena kada je vrijednost varijable
, bila 2 to zapravo znaci da su elementi na pozicijama s indeksom 2, 3, 4 i 5 vec u
pravilnom poretku. Pozicija zadnje zamjene je zapamcena u varijabli j. Nadalje, to znaci
da u sljedecem prolazu nece biti potrebno porediti elemente koji se nalaze na pozicijama
s indeksom vecim ili jednakim od j = 2 pa se zapravo nakon cetvrtog prolaza na svojim
konacnim pozicijama ne nalaze samo 4 vec 7 elemenata. Ako je nakon nekog od prolaza
kroz niz vrijednost varijable j = 0, to je znak da je citav preostali dio niza zapravo vec
sortiran, pa se proces sortiranja moze prekinuti.
Prethodno opisana mogucnost poboljanja je data u narednom algoritmu. Varijabla j se
koristi da se zapamti pozicija iza koje u nekom prolazu kroz niz nije bilo izmjene pozicija.
Prolazi se izvode u sklopu repeat-until petlje, te pri svakom novom prolazu se vrijednost
varijable j postavlja na nulu. Ako se dogodi da u nekom prolazu vec postoji sortiran
poredak elemenata tada ce i na kraju prolaza biti j = 0 pa ce algoritam zavriti svoj
rad. Unutarnjom for petljom ostvaruje se jedan prolaz kroz nesortirani dio niza ali samo
93
do pozicije i = j 1 jer na pozicijama iznad j nije bilo izmjena, pa je taj dio niza vec
sortiran.
j 1n.i:c [c]
Ponavljati
{
i j 1
j 0
Za , 1 do i raditi
{
AkoJe (c [, 1] c [,]) tada
{
c [, 1] c [,]
j
}
}
}
SveDokNije(j = 0)
Treca mogucnost poboljanja je da se premjetanje vri naizmjenicno u oba pravca tako
da se u jednom smjeru premjetaju elementi na "lake" pozicije a u obratnom na "teze"
pozicije. Ilustracija ovog algoritma, pod nazivom ShakerSort je na tabeli 11.
1 2 3 3 4 4
1 8 8 7 7 4
Smjer | | |
44 06 06 06 06 06 06 06
55 44 44 12 12 12 12 12
12 55 12 44 44 18 18 18
42 12 42 42 42 44 44 42
94 42 55 55 55 42 42 44
18 94 18 18 18 55 55 55
06 18 67 67 67 67 67 67
67 67 94 94 94 94 94 94
Pseudokod za ShakerSort algoritam je dat na narednom algoritmu.
Analiza BubbleSort algoritma pokazuje da je u osnovnoj verziji broj poreenja jednak
C = (:
2
:) ,2
dok je minimalni, prosjecni i maksimalni broj zamjena (premjetanja) jednak
`
min
= 0. `
avg
= 3 (:
2
:) ,4. `
max
= 3 (:
2
:) ,2
Analiza poboljanih verzija, posebno ShakerSort-a, je dosta slozena. Minimalni broj
poreenja je C
m
= :1. Knuth smatra da je prosjecan broj prolaza u poboljanom Bub-
bleSort algoritmu proporcionalan sa :/
1
_
: a prosjecan broj poreenja proporcionalan
sa (1,2) (:
2
:(/
2
+ ln :)). Predlozena poboljanja ne uticu na broj premjetanja, oni
94
Procedura ShakerSort
Ulaz : Niz c
n

Izlaz : Sortiran niz c


n

Inicirati ,. /. 1. 1. r
1 2; 1 :; / :
Ponavljati
{
Za , = 1. 1. 1
{
Ako je c [, 1] c [,] tada
{
r c [, 1] ; i:
c [, 1] c [,]
c [,] r
/ 1
}
}
1 / + 1
Za , = 1. 1. 1
{
Ako je c [, 1] c [,] tada
{
r c [, 1] ;
c [, 1] c [,]
c [,] r
/ 1
}
}
1 / 1
}
SveDok vrijedi 1 1
jedino skracuju nepotrebna binarna poreenja. Nazalost, zamjena dva elementa je mnogo
ceca operacija tako da se ne dobiju ocekivana poboljanja. Pokazuje se da je BubbleSort
po karakteristikama negdje izmeu sortiranja umetanjem i sortiranja zamjenom. Fak-
ticki, BubbleSort ne donosi nita novo osim privlacnog naziva. ShakerSort se uspjeno
koristi u slucajevima kada je niz dosta sortiran, to se u praksi dosta rijetko deava.
Moguce je pokazati da je prosjecno rastojanje za koje se pojedini element pomjera jed-
nako :,3 "mjesta". Svi strogi nacini sortiranja fakticki element na pojedinom koraku
pomjeraju za jednu poziciju to je razlog da trebaju C(:
2
) takvih prolaza. U skladu sa
tim, poboljanja se mogu uvesti ako se usvoji princip da se vri razmjena elemenata na
vecem rastojanju.
U nastavku je pregled poboljanja svake od navedene stroge metode sortiranja.
95
10.3 Poboljane metode (slozenost :log :)
10.3.1 Merge sort
Algoritam Merge sort koristi strategiju podijeli-pa-vladaj kod koje se do rjeenja nekog
problema dolazi smanjivanjem na manje dijelove sve dok se on ne reducira na tzv. os-
novni slucaj koji se moze rijeiti direktno. Ovaj algoritam se temelji na ideji da se iz
sortiranih podnizova na ekasan nacin mogu spajanjem tih podnizova dobiti novi sorti-
rani podnizovi. Prije faze spajanja sortiranih podnizova, koja zapravo predstavlja drugu
fazu algoritma, Merge sort u svojoj prvoj fazi dijeli pocetni nesortirani niz na manje i
manje podnizove. Minimalni niz je niz sa samo jednim elementom, pa je takav niz sam
po sebi vec sortiran. Zato algoritam Merge sort dijeli pocetni nesortirani niz na manje i
manje dijelove, sve dok se ne dobiju nizovi sa samo jednim elementom. Nakon te prve faze
dijeljenja, slijedi druga faza spajanja sortiranih podnizova u kojoj se od manjih sortiranih
podnizova njihovim objedinjavanjem stvaraju sve veci i veci sortirani podnizovi, sve dok
se na kraju ove faze ne kreira cijeli sortirani niz.
Merge sort se moze realizovati kao rekurzivni algoritam, pri cemu se na svakom nivou
rekurzije obavljaju sljedeci koraci:
dijeljenje pocetnog nesortiranog niza na dva podniza od kojih svaki ima po :,2
elemenata;
rekurzivno sortiranje dobijena dva podniza koristeci Merge sort;
spajanje sortiranih podnizova.
U nastavku je procedura `c:qcoo:t koja predstavlja rekurzivnu implementaciju algo-
ritma.
// Procedura Merge Sort
`c:qcoo:t(c. |. n)
AkoJe (n |) tada
{
j (| +n 1) ,2|
j + 1
`c:qcoo:t (c. |. j)
`c:qcoo:t (c. . n)
`c:qc (c. |. j. . n)
}
Ulazni argument c predstavlja niz koji se treba sortirati. Argument | oznacava indeks
prve pozicije a argument n oznacava indeks zadnje pozicije podniza c [|..n] koji se sor-
tira. Postupak sortiranja se ostvaruje tako to se ulazni podniz c [|..n] dijeli na dva
podniza a zatim se proces nastavlja rekurzivnim pozivima procedure `c:qcoo:t koji
kao ulazne nizove imaju podnizove nastale dijeljenjem. Dijeljenje ulaznog niza na dva
podniza se ostvaruje izracunavanjem vrijednosti varijabli j i . Varijabla j predstavlja
indeks zadnje pozicije prvog podniza, a vrijednost varijable oznacava prvu poziciju dru-
gog podniza. Na taj nacin ulazni niz c [|..n] je podijeljen na podnizove c [|..j] i c [..n].
96
U proceduri `c:qcoo:t se nalaze dva rekurzivna poziva ove procedure. Prvim pozivom
`c:qcoo:t (c. |. j) proces se nastavlja nad prvom polovinom podijeljenog niza, dok se
pozivom `c:qcoo:t (c. . n) proces nastavlja nad drugom polovinom podijeljenog niza.
Nesortirani niz se rekurzivno dijeli na podnizove, sve dok se ne dobiju podnizovi koji
sadrze samo jedan element, tj. dok vrijedi n |. Nakon povratka iz obje ove proce-
dure na svakom nivou rekurzije se pozivom procedure `c:qc obavlja spajanje sortiranih
podnizova. Taj postupak, opisan procedurom `c:qc, je dat kasnije. Na primjer, nakon
povratka iz obje procedure `c:qcoo:t na zadnjem nivou rekurzije, kada podnizovi nastali
dijeljenjem imaju velicine 1 poziva se procedura `c:qc za spajanje tih podnizova da bi
se kreirao niz velicine 2. Na sljedecem, viem nivou, su dva sortirana niza velicine 2 koji
ce se spojiti u sortirani podniz velicine 4. Ovaj proces se nastavlja sve dok se ne doe do
prvog poziva, koji spaja dva sortirana podniza koji sadrze po pola elemenata pocetnog
nesortiranog niza.
Merge Sort - ilustracija
Na slici je ilustriran proces sortiranja algoritmom Merge sort za niz sa 13 elemenata. Al-
goritam u prvoj fazi dijeli pocetni niz na polovine rekurzivnim procesom sve dok rezultira-
juci podnizovi ne sadrze samo jedan element. Nakon toga se prelazi u drugu fazu, u kojoj
nakon zavravanja rekurzivnih poziva procedure `c:qcoo:t na svakom nivou rekurzije
imamo procese spajanja podnizova. Kretanjem prema prvom rekurzivnom pozivu pod-
nizovi se spajaju, te se oblikuju sve veci i veci sortirani podnizovi.
Kljucni koraci u algoritmu Merge sort su koraci spajanja dva sortirana podniza. Neka su
nizovi / [0..5] i / [6..12] sortirani, naprimjer, u rastucem poretku. Da bi ta dva sortirana
podniza bila spojena u jedan sortirani niz c prvo treba odrediti najmanji element iz oba
podniza. Sigurno je da je najmanji element ili / [0] ili / [6]. Isto tako, najveci element je
ili / [5] ili / [12]. Operacija spajanja pocinje tako da se u c [0] smjesti manji od elemenata
/ [0] ili [6]. Neka je / [0] < / [6] pa je tada c [0] = / [0]. Nisu rasporeeni elementi / [1..5] i
/ [6..12]. Uc [1] se treba smjestiti manji od elemenata na prvim pozicijama nerasporeenih
dijelova podnizova / [1..5] i / [6..12]. Dakle, u c [1] se treba smjestiti manji od elemenata:
97
/ [1] ili / [6]. Neka je manji element / [1] pa je c [1] = / [1]. Sada su nerasporeeni elementi
/ [2..5] i / [6..12].
// Procedura Merge
`c:qc (c. |. j. . n)
i 0
, |
/ |
Za (: 0) do n | raditi
{
/ [:] c [| +:]
}
SveDokJe (i _ j |&, _ n |) raditi
{
AkoJe (/ [i] < / [,]) tada
{
c [/] / [i]
i i + 1
}
Inace
{
c [/] [,]
, , + 1
}
/ / + 1
}
SveDokJe (i _ j 1) raditi
{
c [/] / [i]
/ / + 1
i i + 1
}
SveDokJe (, _ n |) raditi
{
c [/] / [,]
/ / + 1
, , + 1
}
Moze se zakljuciti da za formiranje sortiranog niza c treba mehanizam koji ce omoguciti
oznacavanje rasporeenih i nerasporeenih elemenata iz podnizova / [0..5] i / [6..12]. Ovaj
mehanizam pracenja se realizuje uvoenjem dva indeksa za spomenute podnizove, koji
ce oznacavati poziciju u oba podniza na kojoj se trenutno nalaze kandidati za minimalni
element od preostalih nerasporeenih elemenata. Neka je i indeks za pracenje podniza
/ [0..5] a , indeks za pracenje podniza / [6..12]. Svakim odreivanjem minimalnog ele-
menta taj element se smjeta u niz c a indeks pridruzen podnizu koji je u tom koraku
sadrzavao minimalni element se povecava za 1. Dakle, preostali nerasporeeni elementi u
98
podnizu / [0..5] ce biti elementi / [i..5] a u podnizu / [6..12] ce biti nerasporeeni elementi
/ [,..5]. U jednom trenutku ce se rasporediti svi elementi iz jednog od podnizova pa ce se
preostali elementi iz podniza u kojem je ostalo jo nerasporeenih elemenata jednostavno
nadovezati na spojeni niz. Postupak spajanja je opisan procedurom `c:qc.
Ulazni argument c oznacava niz u kojem su smjeteni podnizovi. Argumenti | i oz-
nacavaju indekse pocetnih pozicija prvog i drugog podniza, respektivno. Argumenti j
i n oznacavaju indekse zadnjih pozicija prvog i drugog podniza, respektivno. Varijabla
i u proceduri `c:qc je varijabla pridruzena prvom podnizu i oznacava indeks pozicije
iznad koje su jo nerasporeeni elementi iz prvog podniza. Varijabla , je pridruzena
drugom podnizu i oznacava indeks pozicije iznad koje su jo nerasporeeni elementi iz
drugog podniza. U proceduri `c:qc se koristi i privremeni niz / u kojem se privremeno
smjetaju sortirani podnizovi koji se trebaju spojiti. Varijabla / oznacava indeks pozicije
u rezultirajucem nizu c na koju ce se smjestiti trenutno odreeni minimalni element iz
sortiranih podnizova.
Iz algoritma se vidi da je na prvom nivou rekurzije za oblikovanje konacnog sortiranog
niza potrebno jo spojiti podnizove / [0..6] i / [6..12]. Algoritam spajanja `c:qc ce biti
ilustrovan za slucaj spajanja na prvom nivou rekurzije, na sljedecoj tabeli.
0 1 2 3 4 5 6 7 8 9 10 11 12
Niz B 4 11 16 18 20 25 5 7 10 14 28 32 35 a
i = 0. , = 6. / = 0 4 b
i = 1. , = 7. / = 1 4 5 c
i = 1. , = 7. / = 2 4 5 7 d
i = 1. , = 8. / = 3 4 5 7 10 e
i = 1. , = 9. / = 4 4 5 7 10 11 f
i = 2. , = 9. / = 5 4 5 7 10 11 14 g
i = 2. , = 10. / = 6 4 5 7 10 11 14 16 h
i = 3. , = 10. / = 7 4 5 7 10 11 14 16 18 i
i = 4. , = 10. / = 8 4 5 7 10 11 14 16 18 20 j
i = 5. , = 10. / = 9 4 5 7 10 11 14 16 18 20 25 k
i = 5. , = 10. / = 10 4 5 7 10 11 14 16 18 20 25 28 l
i = 5. , = 11. / = 11 4 5 7 10 11 14 16 18 20 25 28 32 m
i = 5. , = 12. / = 12 4 5 7 10 11 14 16 18 20 25 28 32 35 n
Varijabla i = 0 na pocetku procesa predstavlja indeks pozicije od koje pocinje prvi
podniz a varijabla , = 6 oznacava indeks pozicije od koje pocinje drugi podniz. Varijabla
/ oznacava poziciju u rezultirajucem nizu c na koju se u nekom od pojedinih koraka
spajanja treba smjestiti manji od elemenata / [i] ili / [,]. Ako je manji element / [i] tada
se u rezultirajuci niz c na poziciju / smjeta taj element a indeks i povecava. Tada podniz
[i..5] predstavlja trenutno nerasporeene elemente iz prvog podniza.
Ako se utvrdi da je manji element / [,] tada se u rezultirajuci niz c na poziciju / smjeta taj
element pa se povecava indeks ,. Tada podniz / [,..12] predstavlja trenutno nerasporeene
elemente iz drugog podniza. Nakon svakog smjetanja elementa u rezultirajuci niz c,
inkrementira se varijabla /. Varijable i i , inicijalno imaju vrijednosti i = 0, , = 6,
/ = 0 (b). Poreenjem elemenata / [0] i / [6] vidi se da je manji element / [0] = 4 pa
se taj element u nizu c smjeta na poziciju / = 0, c[0] = 4. Poto je u ovom koraku
99
izabran element iz prve polovine, inkrementira se varijabla i kao i varijabla /, koja se
inkrementira u svakom pojedinom koraku smjetanja elemenata u rezultirajuci niz c. U
ovom trenutku vrijednosti varijabli su: i = 1, , = 6, / = 1. U sljedecem koraku se izabire
manji od elemenata / [1] i / [6]; vidi se da je manji element / [6] = 5 pa se taj element u
nizu c smjeta na poziciju / = 1, c [1] = 5 (c). Na tabeli su ilustrovani i ostali koraci
spajanja podnizova. U koraku k svi elementi iz prvog podniza (/[0..5]) su vec rasporeeni
u rezultirajuci niz c pa je u nastavku algoritamskog procesa potrebno samo da se preostali
elementi (/[10..12]) jednostavno dodaju u rezultirajuci niz c (l do n).
10.3.2 Quick sort
Ovaj sort radi rekurzivno tako da se iz niza najprije selektira "pivot vrijednost". Zatim
se niz dijeli na elemente koji su manji i koji su veci od pivota a zatim se rekurzivno
sortira svaki od dijelova. Za QuickSort se, generalno, smatra da je najbrzi od algoritama
sortiranja (na modernim mainama). Jedno od objanjenja je da unutranja petlja poredi
elemente sa jednom vrijednosti pivota koja je pohranjena u registru za brz pristup. Drugi
algoritmi porede dva elementa niza. Ovo se naziva algoritmom lokalnog sortiranja jer ne
koristi drugi niz za pohranu. Nije stabilan. Postoji stabilna verzija QuickSort algoritma
ali ona nije lokalna. Ovaj algoritam je (:log :) u ocekivanom i (:
2
) u najgorem
slucaju. Ako je implementiran prikladno, vjerovatnoca dace algoritam trajati asimptotski
duze (pod pretpostavkom da je pivot odabran slucajno) je ekstremno mala za veliko :.
Algoritam Quick sort takoer koristi strategiju podijeli, pa vladaj. Ulazni niz se dijeli
na dva dijela tako to se taj niz reorganizira tako da su svi elementi u prvom donjem
dijelu manji od svih elemenata u drugom gornjem dijelu niza. Ta dva dijela nakon
reorganizacije su nesortirana i razdvojena elementom koji se naziva pivot i koji se nalazi
na nekoj poziciji ,. Dakle, donji dio cine elementi koji imaju vrijednost manju ili jednaku
vrijednosti pivota (c [i] _ jiot, i = 0. 1. . . . . , 1) a gornji dio cine elementi koji imaju
vrijednost vecu ili jednaku vrijednosti pivota (c[i] _ jiot, i = , + 1. , + 2. . . . . : 1).
Moguci su razliciti nacini izbora pivota. Na primjer, pivot se moze napraviti tako da
se uzme prvi element niza koji se dijeli, mada postoje i ekasniji nacini. Idealno, pivot
element bi trebao dijeliti niz na dva podniza sa jednakim brojem elemenata. Zbog nacina
na koji je ulazni niz reorganiziran moze se zakljuciti da je pivot element pozicioniran na
svoju konacnu poziciju , te se u daljnjem postupku vie nece pomjerati. Nadalje, moze
se zakljuciti da se sortiranje moze nastaviti tako da se isti algoritam rekurzivno primijeni
na dobijena dva dijela ulaznog niza. Rekurzivni postupak se nastavlja sve dok se ne
postigne da rezultirajuci dijelovi imaju samo jedan element. Zavretkom rekurzivnog
postupka dobiva se sortirani niz.
Kljucni dio u algoritmu Quick sort je nacin reorganizacije niza na dvije particije odvojene
pivotom, bez koritenja dodatnog pomocnog memorijskog prostora. Taj nacin je opisan
funkcijom 1c:tici,c u tabeli. Funkcija 1c:tici,c vraca indeks pozicije na kojoj je sm-
jeten pivot. Neka se kao pivot koristi prvi element u nizu. U primjeru na tabeli za pivot
se uzima element 42 (oznacen tankom donjom crtom). Funkcijom 1c:tici,c potrebno je
reorganizirati niz tako da se pronae odgovarajuca pozicija za pivota te da svi elementi
manji od njega budu na pozicijama ispred njega a svi veci elementi da budu na pozicijama
iza njega. Na tabeli j oznacava poziciju elemenata koji se trenutno porede sa pivotom.
Kada se pronae prvi element veci od pivota, tada se za oznacavanje pozicija elemenata
koji se trenutno porede sa pivotom koristi oznaka i. Te pozicije su na tabeli istaknute
100
donjom podebljanom crtom. Pocevi od drugog elementa u nizu zapocinje pronalazenje
prvog elementa koji je veci ili jednak pivotu (42) te na poziciji s indeksom 3 pronalazimo
prvi takav element a to je 54. Pronaena pozicija j = 3 se oznacava kao privremeni poce-
tak druge particije (koja ce se nalaziti iza pivota) to je oznaceno osjencenom pozicijom.
Postupak se nastavlja poreenjem pivota i elemenata iz niza (i = j + 1. j + 2. . . . . : 1)
koji se nalaze iza oznacene pozicije. Kada se pronae element koji je veci ili jednak piv-
otu, taj element se ostavlja na svojoj poziciji, te se nastavlja proces poreenja pivota i
elemenata na preostalim pozicijama. Na primjer, na tabeli na poziciji i = 4 je element 49
pa taj element ostaje na svojoj poziciji. Kada se pronae element koji je manji od pivota,
tada taj element i element na poziciji j razmjenjuju pozicije, te se oznaka j povecava za
1 tako da oznaka j pokazuje na novi pocetak druge particije. Na primjer, na poziciji s
indeksom i = 5 se nalazi element 22 koji je manji od pivota (42), pa element 22 razm-
jenjuje poziciju s elementom na poziciji j a to je 54. Istovremeno, privremena vrijednost
indeksa j za pocetak druge particije se povecava za 1 pa sada ima vrijednost j = 4. Ovaj
proces se nastavlja sve dok se ne doe do kraja niza. Svi ostali koraci u reorganizaciji
niza s ciljem njegovog particioniranja su takoer ilustrirani na tabeli.
Pri kraju procesa, kada indeks i dostigne vrijednost 9 (i = :1) pivot se jo uvijek nalazi
na prvoj poziciji. Meutim, niz je prethodno reorganiziran tako da su svi elementi od
pozicije 1 do pozicije 4 (j1) manji od pivota, dok su elementi na pozicijama 5 do 9 (j do
:1) veci od pivota. Poto je cilj da pivot dijeli te dvije grupe elemenata, potrebno je jo
razmjeniti pozicije pivota i elementa na poziciji 4 (j1), cime se zavrava particioniranje
niza. Dakle, na kraju opisanog procesa, pivot element 42 se nalazi na poziciji 4. Svi
elementi na pozicijama s indeksima 0 do 3 su manji od pivot elementa 42 dok su svi
elementi na pozicijama 5 do 9 veci od pivot elementa.
0 1 2 3 4 5 6 7 8 9
j = 1 42 36 17 54 49 22 63 57 20 46
j = 2 42 36 17 54 49 22 63 57 20 46
j = 3 42 36 17 54 49 22 63 57 20 46
j = 3. i = 4 42 36 17 54 49 22 63 57 20 46
j = 3. i = 5 42 36 17 54 49 22 63 57 20 46
j = 4. i = 5 42 36 17 22 49 54 63 57 20 46
j = 4. i = 6 42 36 17 22 49 54 63 57 20 46
j = 4. i = 7 42 36 17 22 49 54 63 57 20 46
j = 4. i = 8 42 36 17 22 49 54 63 57 20 46
j = 5. i = 8 42 36 17 22 20 54 63 57 49 46
j = 5. i = 9 42 36 17 22 20 54 63 57 49 46
, = 4. j = 5 20 36 17 22 42 54 63 57 49 46
Zamjena pozicija pivot elementa i elementa na poziciji j1 mijenja poredak elemenata u
donjoj particiji. Na primjer, na tabeli je nakon izmjene poredak elemenata koji pripadaju
donjoj particiji (36. 17. 22. 20) promijenjen u poredak (20. 36. 17. 22). To, naravno, utice
na izbor pivota u sljedecim fazama algoritma, s tim da u prosjecnom slucaju to ne utice na
ekasnost algoritma. Algoritam kojim se na prethodno opisani nacin moze particionirati
niz dat je u nastavku.
Nakon opisa postupka particioniranja nizova moguce je opisati rekurzivnu implementaciju.
Algoritam je opisan procedurom QuickSort u nastavku. Poto na pocetku citav niz
101
// Procedura Particija
1c:tici,c (c. j:i. .cd:,i)
jiot c [j:i]
j j:i + 1
SveDokJe (j _ .cd:,i&c [j] < jiot) raditi
{
j j + 1
}
ZaSve (i j + 1) do .cd:,i raditi
{
AkoJe (c [i] < jiot) tada
{
c [i] c [j]
j j + 1
}
}
c [j:i] c [j 1]
Vrati j 1
predstavlja jednu particiju, algoritam se poziva sa pocetnim argumentima j:i = 0 i
.cd:,i = : 1.
// Procedura Quick sort
Qnic/oo:t (c. j:i. .cd:,i)
AkoJe (j:i < .cd:,i) tada
{
, 1c:tici,c (c. j:i. .cd:,i)
Qnic/oo:t (c. j:i. , 1)
Qnic/oo:t (c. , + 1. .cd:,i)
}
Mehanizam rada procedure Quick Sort je ilustrovan na slici u nastavku.
102
Inicijalni raspored elemenata niza je prikazan prvim rasporedom na tabeli 13 (na kojoj
je ilustrovan postupak particije) a na slici je raspored elemenata u nizu nakon prve par-
ticije. Izabrani pivot u pojedinim fazama je oznacen pojacno a elementi koji su zauzeli
svoje konacne pozicije su uokvireni obicnom linijom. Isprekidanim linijama su uokvireni
elementi koji u pojedinim fazama izvravanja algoritma cine podnizove koji u nastavku
algoritma ulaze u proces particije. U sljedecem koraku kao pivot se uzima element 20, a
proces particije se nastavlja sa podnizom koji cine elementi koji se nalaze na pozicijama
0 do 3. Rezultat particije je prikazan u liniji c. Pivot element 20 je zauzeo svoje konacno
mjesto na poziciji s indeksom 1, donju particiju cini samo jedan element (17), dok gornju
particiju cine dva elementa (36 i 22). Na linijama d do h su ilustrirane i ostale faze u
radu algoritma.
103
11 Grafovski algoritmi
11.1 Uvod
U cilju potpunog razumijevanja grafovskih algoritama potrebno je denisati odgovarajuce
pojmove i utvrditi konvencije.
Predmet analize su samo prosti grafovi, koji nemaju petlje u pojedinim cvorovima
i nemaju ponavljajucih ivica
Sa : = [\ [ i : = [1[ se oznacava broj cvorova (tjemena, V) i grana (linija, E)
respektivno; svaki cvor je obiljezen brojem od 1 do : osim ako nije potrebno izbjeci
konfuziju
Jedan od prvih problema koji se rjeava kada se racunarski simuliraju grafovski algoritmi
je predstavljanje odnosno na koji nacin tu informaciju prenijeti racunaru. Postoje tri
nacina:
Lista cvorova (edge list) : formira se jednostavna numerisana lista koja u nekim
slucajevima moze biti sortirana
Matrica povezanosti (adjacency matrix) : matrica : : koja se sastoji od 1 i 0 u
zavisnosti od toga da li su dva cvora povezana (1) ili ne (0). Primjer je
=
_
_
_
_
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
_
_
_
_
U ovoj listi vrijedi da je c
ij
= c
ji
to znaci da je graf neusmjeren. U slucaju da je c
ij
,= c
ji
radi se o usmjerenom grafu.
Lista povezanosti (adjacency list) : lista od : elemenata u kojoj je svaki element
lista cvorova koji su povezani sa tim cvorom. Ako se radi o usmjerenom grafu tada
su elementi liste ureeni parovi
Ne postoji "najbolja" grafovska prezentacija jer to bitno zavisi od informacija koje se
prezentiraju putem grafa. Prezentacija je diktirana, prije svega, brojem veza a zatim
ostalim elementima.
Ako se svakoj grani dodijeli neka vrijednost tada se govori tezinskom grafu (ponderisani
graf, weighted graph, ...). "Tezina" je u tom slucaju velicina koja je od interesa kao
npr. rastojanje, cijena, vjerovatnoca i slicno. Namjena ovog teksta nije da se bavi inter-
nom prezentacijom. U tom smislu ce za svaki tip problema biti koritena odgovarajuca
notacija.
104
11.2 Algoritmi pretrazivanja
Problem pretrazivanja se formulie na sljedeci nacin : Ako su data dva cvora . n \ (G)
da li postoji putanja iz do n ? Ako postoji, da li je ta putanja najkraca ?
Podrazumijeva se da je graf G neusmjeren.
Intuitivno, to se radi tako da se graf G pretrazi po svakoj ivici od kako bi se vidjelo da
li se moze doci do n. Ako se radi na taj nacin potrebno je cuvati informaciju o tome koji
cvorovi su posjeceni kako bi se izbjegle beskonacne petlje.
Ideja je da se cvorovi koji jo nisu pretrazeni obiljeze Bijelo a pretrazeni Crno. Kad se
pretrazuju child cvorovi mora se osigurati da se ne obrauju ponovo pa se oznacavaju
kao Sivi. Inicijalno, svi cvorovi su oznaceni Bijelo.
Genericki (opti) algoritam pretrazivanja je u nastavku.
Oznaciti sve cvorove bijelo
Odabrati pocetni cvor i obojiti ga u Sivo
SveDok( postoji Sivi cvor )
{
Odaberi cvor i
Oznaci Bijele susjede Sivo
Obraditi cvor i
Oznaciti ga Crno
}
Kako bi se pokazala korektnost treba primijetiti da se kretanje odvija po principu
BijeloSivoCrno
i svaka iteracija petlje mijenja boju barem jednog cvora tako da se ne pojavljuje beskon-
acna petlja. Algoritam se zavrava samo ako su svi cvorovi oznaceni Bijelo ili Crno. Bilo
koji cvor koji je oznacen Bijelo ne moze biti susjed cvora koji je povezan sa startnim
cvorom (jer bi inace bio oznacen kao Sivo). Bilo koji cvor koji je oznacen Crno mora
biti povezan sa pocetnim cvorom. Stoga, putanja od cvora : do cvora : postoji ako i
samo ako je n oznacen kao Crno na kraju algoritma. U sutini, ovo je nacin da se nau
povezane komponente, zasebne cjeline grafa koje nisu povezane ivicama.
Na taj nacin je prezentiran prvi dio rjeenja problema.
Kad se ovaj algoritam zavri velicina :n:CC sadrzi ukupan broj povezanih komponenti
a cc [i] daje oznaku komponente koja je povezana sa cvorom i. Korak "Uzmi Sivi cvor ,"
se moze raditi na dva nacina:
breadth-rst-search (BFS) : uzeti cvor koji je pronaen najranije. Ovo znaci da se
najprije obrauju svi cvorovi povezani sa startnim cvorom zatim cvorovi na distanci
2 itd.
depth-rst-search (DFS) : uzeti cvor koji je pronaen najkasnije. Ovo znaci da se
najprije istrazuju cvorovi koji su na dugackom lancu (sve dok se ne doe do kraja
lanca)
105
Denisati nizove cc [.] i /o,c [] duzine :
:n:CC 0
ZaSvaki (cvor i)
{
Obojiti Bijelo
}
ZaSvaki

Cvor i od 1 do :
{
AkoJe(/o,c [i]=Bijelo)
{
:n:CC :n:CC + 1
cc [i] :n:CC
/o,c [i] Sivo
SveDokJe (Postoji cvor Sivo)
{
Uzmi Sivi cvor ,
Obojiti sve njegove Bijele susjede Sivo
cc [,] :n:CC
/o,c [,] Crno
}
}
}
Ova dva pristupa se bitno razlikuju po slozenosti i dinamici pretrazivanja i oba pristupa
imaju puno prakticnih primjena.
Prvi od njih ima slozenost O(:
2
) jer se koristi kvadratna matrica. Svaka ivica (grana)
se pretrazuje najvie dva puta. Algoritam ima prednosti ako je ema "rijetka" (engl.
sparse). Putanja koja se formira zove se stablo. Ako je graf pritom povezan to stablo se
zove minimalno razapinjuce stablo.
Drugi algoritam koristi strukturu koja se zove stek (engl. stack). Realizuje se operacijama
"stavi" (engl. push), koja dodaje element na kraj niza (lanca koji se pretrazuje) i "uzmi"
(engl. pop), koji uklanja element sa kraja. Ovo je struktura podataka koja se zove LIFO
(Last-In-First-Out). Postoji i struktura FIFO (First-In-First-Out), koja se ne koristi u
ove svrhe. Kompleksnost ovog algoritma je O(: +:).
Primjena druge verzije ovog algoritma nije odmah ocigledna. Meutim, moze se razmil-
jati kao o skupu cvorova od kojih svaki ima nekoliko konekcija na sebe tako da svaki tako
stvoren lanac ima odreena svojstva "separabilnosti".
Primjer. Neka je data mreza racunara. Potrebno je naci sve kompjutere koji, ako se
uklone, cine da se mreza raspada.
11.3 Algoritmi najkraceg puta
Ocigledna generalizacija problema najkraceg puta ima izvor u cinjenici da grane (ivice)
imaju razlicite "tezine". Formalno, potrebno je imati nacin na koji se "tezine" dodjelju
ivicama. To se cini putem sljedece denicije.
106
Denicija. Tezinski graf je graf G = (\ ; 1) zajedno sa funkcijom n : 1 R. Kaze se
da je n(i. ,) = ako (i. ,) , 1.
Slicno se formalizuje problem "najkraceg puta".
Denicija. Putanja
r = r
0
. r
1
. .... r
m
=
je najkraci put od r do ako ta putanja minimizira
m1

i=0
n(r
i
. r
i+1
)
Duzina najkraceg puta od r do se oznacava sa d (r. ).
Sada se problem najkraceg puta lako formulie.
Problem. Za dati tezinski graf G i dva cvora r i naci d (r. ). Pretpostavka je
n(i. ,) 0.
11.3.1 Dijkstra algoritam
Ovaj algoritam je namijenjen trazenju najkraceg puta u usmjerenim grafovima. Pret-
postavlja se da ivice grafa imaju svoje vrijednosti i cilj je naci najkrace putanje iz jednog
cvora u sve cvorove grafa.
Distanca izmeu dva cvora n i , u oznaci o (n; ), je minimalna duzina putanje od n do
.
Problem najkraceg puta iz jednog cvora (single source shortest path) se denie na sljedeci
nacin. Dat je usmjeren graf sa nenegativnim tezinama ivica G = (\ ; 1) i izdvojenim
pocetnim cvorom : \ . Problem je odrediti distancu pocetnog cvora do svakog cvora u
grafu.
Moguce je imati grafove sa negativnim tezinama ivica ali kako bi najkraci putevi bili
dobro denisani potrebno je dodati zahtjev da uopte nema ciklusa cija je ukupna tezina
negativna (inace bi se mogao napraviti beskonacno kratak put kretanjem zauvijek u tom
ciklusu). Ovdje se naglaava posao racunanja minimalne distance od pocetnog cvora
do svakog cvora. Racunanje stvarne duzine je dosta lagano proirenje problema. Za
svaki cvor se formira pointer j:cd () koji ukazuje na prethodnika. Slijedeci pointere
prethodnika unazad od bilo kojeg cvora konstruie se reverzna slika najkraceg puta do .
Osnovna struktura Dijkstra algoritma je odrzavanje procjena najkraceg puta za svaki
cvor, u oznaci d []. Intuitivno gledano, d [] ce biti duzina najkraceg puta od : do koji
je poznat algoritmu. Ova vrijednosti je uvijek veca ili jednaka sa stvarno najkracim putem
od : do . Inicijalno, putevi su nepoznati tako da je d [] = . Inicijalno je d [:] = 0 a
svi ostali d [] su postavljeni na . Kako algoritam napreduje i kako se ukljucuje vie
cvorova azurira se d [] za svaki cvor u grafu sve ove vrijednosti ne konvergiraju ka stvarno
najkracoj distanci.
107
Proces kojim se vri azuriranje procjene se zove relaksacija. Intuitivno gledano, ako nije
postignuta optimalna vrijednost ona je bliza ka optimumu. Posebno, ako se otkrije put
od : do koji je kraci od d [] tada se vri azuriranje te vrijednosti. Ovaj metod je
zajednicki za veliki broj algoritama optimalizacije.
Posmatra se ivica od cvora n do cvora cija je tezina n(n; ). Pretpostavka je da postoje
procjene za d [n] i d []. Poznato je da postoji put od : do n sa tezinom d [n]. Ako se uzme
ta putanja i ako se slijedi ivica (n; ) dobija se putanja do duzine d [n] + n(n; ). Ako
je ta putanja bolja od postojeceg puta do duzine d [] tada se d [] azurira na vrijednost
d [n] +n(n; ). Potrebno je zapamtiti da najkraci put do prolazi kroz n to se cini tako
da se azurira pointer prethodnika za .
Treba primijetiti da kad god se d [] postavi na konacnu vrijednost uvijek postoji trag
o putanji te duzine. Stoga je d [] _ o (:; ). Ako je d [] = o (:; ) tada naknadne
relaksacije ne mogu promijeniti tu vrijednost.
Nije teko vidjeti da ako se relaksacija provede nad svim ivicama grafa vrijednosti d []
obavezno konvergiraju konacnoj stvarnoj vrijednosti iz :. Cilj svakog dobrog algoritma
nalazenja najkraceg puta je da se azuriranja obavljaju na pametan nacin kako bi konver-
gencija bila to je moguce brza. Posebno, najbolji nacin bi bio da se operacije relaksacije
poredaju na nacin da se posao za svaku ivicu provede tacno jednom. Tacno ovo radi
Dijkstra algoritam.
Dijkstra algoritam je zasnovan na izvravanju ponovljenih relaksacija. On radi tako da
odrzava podskup cvorova, o _ \ , za koji se proglaava da "znamo" stvarnu distancu,
d [] = o (:; ). Inicijalno je o = , prazan skup i stavlja se d [:] = 0 a za sve ostale +.
Jedan po jedan cvor iz \ o se dodaje u o.
Skup o moze biti implementiran koritenjem niza boja koje su dodijeljene cvorovima.
Inicijalno su svi cvorovi bijeli a /o,c [:] = c::c kako bi se naznacilo da o.
Dijkstra je prepoznao da je najbolji nacin relaksacije povecanje poretka distance od izvora.
Na taj nacin, kad god se provodi relaksacija moguce je zakljuciti da rezultat relaksacije
daje konacnu vrijednost distance. Za implementaciju ovog koncepta za svaki cvor n
\ o se odrzava procjena distance d [n]. Pohlepni dio algoritma se odnosi na to da se
uzima cvor iz \ o za koji je d [] minimalno tj. uzima se neobraeni cvor koji je (prema
procjeni) najblizi ka :.
Kako bi se ova selekcija izvrila ekasno, cvorovi iz \ o se stavlja u red prioriteta (tj.
heap - gomila) gdje je kljucna vrijednost svakog cvora n jednaka d [n]. Primjetna je
slicnost sa Primovim algoritmom iako se koriste razlicite vrijednosti. Za svaki cvor je
poznata lokacija u redu prioriteta i svaka stavka u redu prioriteta "poznaje" koji cvor
prezentira.
108
Prikaz Dijkstra algoritma
Zbog slicnosti sa Primovim algoritmom vrijeme izvrenja je jednako, (1 log \ ).
Drugi algoritmi kojima se rjeava problem najkraceg puta su :
- Floyd Warshall-ov algoritam
- Algoritam mravlje kolonije
11.4 Pohlepni algoritmi na grafovima
Uobicajeni problem u komunikacionim mrezama i dizajnu elektricnih kola je povezivanje
skupa cvorova (komunikacionih cvorova ili elemenata elektricnog kola) pomocu najkrace
moguce mreze, lija je duzina suma duzina pojedinih veza. Pretpostavlja se da je mreza
neusmjerena. Kako bi se minimizirala duzina mreze ne smije se dopustiti postojanje petlji.
Rezultat je graf koji je povezan, neusmjeren i aciklican i kao takav se zove slobodno stablo.
Racunski problem se zove problem minimalno razapinjuceg stabla (Minimum Spanning
Tree, krace MST). Formalnije, za dati povezani neusmjereni graf G = (\ ; 1) razapinjuce
stablo je aciklicni skup ivica 1 _ 1 koje povezuju sve cvorove. Pretpostavlja se da svaka
ivica n(n; ) grafa G ima numericku tezinu ili cijenu (koja moze biti negativna ili nula)
cijena stabla 1 se denie kao suma ivica razapinjuceg stabla
n(1) =

(u;v)2T
n(n; )
Minimalno razapinjuce stablo je ono koje ima minimalnu tezinu. Ovo stablo ne mora biti
jedinstveno. Ako sve ivice imaju razlicitu tezinu tada su minimalna razapinjuca stabla
razlicita. Ovo jo nije dokazano vec je cinjenica koja se koristi.
109
Slika prikazuje tri razapinjuca stabla za isti graf. U sredini i desno su su dva minimalna
razapinjuca stabla.
Postoje dva pohlepna algoritma, Kruskalov i Primov, za nalazenje minimalnog razapin-
juceg stabla. Podsjetimo se da je pohlepni algoritam onaj koji rjeenje nalazi ponavljan-
jem selekcije najjetinije (ili generalno lokalno optimalnog izbora) od raspolozivih opcija
na svakoj etapi. Vazna karakteristika pohlepnih algoritama je da prave izbor koji ne
opozivaju. Prije prezentacije potrebne su neke bitne cinjenice o slobodnim stablima.
Lema.
Slobodno stablo sa : cvorova ima tacno : 1 ivica
Postoji jedinstveni put izmeu bilo koja dva cvora slobodnog stabla
Dodavanje bilo koje ivice kreira jedinstveni ciklus. Prekidanje bilo koje ivice tog
ciklusa obnavlja slobodno stablo
Neka je G = (\. 1) neusmjeren povezan graf cije ivice imaju numericke vrijednosti tezine
(pozitivne, negativne ili nula). Intuicija u pozadini pohlepnih MST algoritama je jednos-
tavna : odrzava se podskup ivica koji je inicijalno prazan i dodaje se jedna po jedna
ivica sve dok ne postane MST. Kaze se da je o _ 1 most (prelaz) ako je podskup ivica
nekog MST (ne moze se reci MST jer nije neophodno i jedinstven). Kaze se da je ivica
(n. ) 1 sigurna ako je ' (n. ) prelaz. Drugim rijecima, izbor (n. ) je siguran
izbor tako da jo uvijek moze formirati MST. Ako je prelaz ne moze sadrzavati
ciklus. Izvorni (genericki pohlepni algoritam radi tako da dodaje sigurne ivice na tekuce
razapinjuce stablo. Potrebno je voditi racuna da je prelaznost svojstvo podskupa ivica a
sigurnost svojstvo pojedine ivice.
Neka je o podskup cvorova o _ \ . Podjela (cut) (o. \ o) je particija cvorova u dva
disjunktna podskupa. Ivica (n; ) prelazi podjelu ako je jedna njena krajnja tacka u o a
druga u \ o. Za dati podskup ivica se kaze da podjela potuje ako ne postoje ivice
u koje prelaze podjelu. Nije teko vidjeti zato je potovanje podjele vazno za ovaj
problem. Ako je formiran djelimicni MST i ako se zeli znati koje ivice koje mogu biti
dodate i koje ne formiraju ciklus u tekucem MST, bilo koja ivica koja prelazi potujucu
podjelu je moguci kandidat.
Ivica u 1 je lagana ivica koja prelazi podjelu ako ima minimalnu duzinu od svih ivica
koje prelaze podjelu. Lagana ivica moze ne biti jedinstvena. Prema intuiciji, s obzirom
da sve ivice koje prelaze potujucu podjelu ne formiraju ciklus tada je lagana ivica koja
prelazi podjelu prirodan izbor.
MST Lema. Neka je G = (\. 1) povezan neusmjereni graf sa ivicama realnih vrijednosti.
Neka je prelazni podskup od 1 (odnosno podskup nekog MST) i neka je (o. \ o) bilo
koja podjela koja potuje i neka je (n; ) lagana ivica koja prelazi podjelu. Tada je
(n; ) sigurna za .
110
11.4.1 Kruskalov algoritam
Kruskalov algoritam radi tako da se ivice dodaju na u rastucem redoslijedu tezina
(najprije lake ivice). Ako naredna ivica ne formira ciklus unutar tekuceg skupa ivica
tada se dodaje u . Ako formira ciklus tada se ivica proputa i razmatra se sljedeca ivica
u poretku. Kako algoritam odmice formiraju se stabla u cvorovima. Tokom algoritma
ova stabla se udruzuju sve dok se ne dobije stablo koje sadrzi sve cvorove.
Ova strategija vodi ka korektnom algoritmu. Uzmimo npr. ivicu (n; ) koja se treba
dodati i pretpostavimo da ta ivica ne formira ciklus u . Neka je
0
stablo u umi
koje sadrzi cvor n. Posmatra se Podjela (
0
. \
0
). Svaka ivica koja prelazi podjelu nije
u tako da ta podjela potuje i (n; ) je lagana ivica preko podjele (jer su sve laganije
ivice iskoritene ranije u algoritmu). Stoga je (n; ) sigurna ivica.
Teki dio algoritma je kako ekasno detektovati da li dodavanje ivice kreira ciklus u .
Moze se provesti pretrazivanje podgrafa koji je kreiran ivicama iz skupa ali to uzima
jako puno vremena. Potreban je brz i pouzdan test koji nam daje odgovor na pitanje
da li je n ili u istom stablu . Ovo se moze uraditi putem strukture podataka koja
se zove Unija-Trazenje (Union-Find) dva disjunktna skupa. Ova struktura podrzava tri
operacije:
KreiratiSet(u) : Kreiranje skupa koji sadrzi stavku n.
NaciSet(u) : Nalazenje skupa koji sadrzi datu stavku n.
Union(u;v) : Spojiti skup koji sadrzi n i skup koji sadrzi u zajednicki skup.
Svaka od ovih operacija se izvrava u C(log :) vremenu na skupu velicine :. Ova struk-
tura je zanimljiva jer se niz od : operacija izvrava mnogo brze od O(:log :).
U ovom algoritmu cvorovi grafa su elementi pohranjeni u skupove a skupovi su cvorovi
u svakom stablu . Skup moze biti pohranjen kao jednostavna lista ivica. Primjer je
pokazan na narednoj slici.
Analiza. Koliko dugo traje Kruskalov algoritam ? Kao i obicno, neka je \ broj cvorova
i 1 broj ivica. S obzirom da je graf povezan moze se uzeti da je 1 _ \ 1. Za sortiranje
ivica potrebno je (1 log 1). Petlja se ponavlja 1 puta a svaka iteracija ukljucuje
konstantan broj pristupa Union-Find strukturi na skupu od \ stavki. Stoga, za svaki
pristup treba (\ ) vremena a skupa (1 log \ ). Stoga je ukupno vrijeme izvrenja
jednako njihovoj sumu koja je ((\ +1) log \ ). S obzirom da \ u asimptotskom smislu
nije vece od 1 slijedi da je vrijeme izvrenja (1 log \ ).
111
11.4.2 Primov algoritam
Primov algoritam je drugi pohlepni algoritam za minimalno razapinjuce stablo. Od
Kruskalovog algoritma se razlikuje samo u nacinu odabira naredne sigurne ivice koja
se dodaje na svakom koraku. Vrijeme izvrenja je potpuno jednako kao za Kruskalov
algoritam. Ovaj algoritam pokazuje da postoji vie od jednog nacina da se rijei ovaj
problem. Osim toga, veoma je slican drugom pohlepnom algoritmu, Dijkstra algoritmu,
kojim se rjeava potpuno druga vrsta problema : najkraci put u mrezi.
Kruskalov algoritam radi tako da sortira ivice i umece ih jednu po jednu u razapinjuce
stablo vodeci racuna da se nikada ne formira ciklus. Intuitivno gledano, Kruskalov algo-
ritam radi tako da spaja dva stabla ili ih razdvaja sve dok se sve ivice ne nau u istom
stablu.
Za razliku od njega, Prim-ov algoritam gradi stablo dodavanjem po jednog lista na tekuce
stablo. Startuje se sa korijenskim cvorom : koji moze biti bilo koji. U bilo koje vrijeme
podskup ivica formira jedno stablo (u Kruskalovom algoritmu se formira uma). Trazi
se dodavanje cvora kao lista na stablo. Proces je ilustrovan na narednoj slici.
Primov algoritam
Ako se posmatra skup cvorova o koji je dio stabla i njegov komplement tada postoji
podjela grafa i tekuci skup ivica potuje tu podjelu. MST lema kaze da je sigurno
dodavanje lagane ivice. Na slici to je ivica tezine 4 koja ide u cvor n. Stoga se n dodaje u
cvorove skupa o i dijeli izmjene. Treba primijetiti da neke ivice koje vie ne sijeku podjelu
koju su presijecale prije ovog koraka nestaju a javljaju se nove koje nisu presijecale tu
podjelu.
Lako je vidjeti da je za ekasnu implementaciju Prim-ovog algoritma kljucno ekasno
azuriranje podjele i brzo odreivanje lagane ivice. Da bi se to ucinilo koristi se struktura
podataka prioritetnog reda (priority queue) koja se koristi u Heap sortu. Ova struktura
cuva skup stavki u kojoj je svaka stavka povezana sa vrijednosti koja se zove kljuc.
Naredna slika ilustruje Prim-ov algoritam. Strelice indiciraju pointere (pokazivace) sljed-
nika a numericka vrijednost u svakom cvoru je vrijednost kljuca.
112
Za analizu Prim-ovog algoritma racuna se vrijeme potroeno na svakomcvoru nakon to se
preuzme iz reda prioriteta (priority queue). Ova aktivnost uzima O(log \ ) vremena. Za
svaku ivicu se potroi oko O(log \ ) vremena kako bi se smanjio kljuc susjednih cvorova pa
je vrijeme C(log \ + deg (n) log \ ). Ostali koraci azuriranja se obavljaju u konstantnom
vremenu. Na osnovu ovoga je
1 (\. 1) =

u2V
(log \ + deg (n) log \ ) =

u2V
(1 + deg (n)) log \
= log \

u2V
(1 + deg (n)) = (log \ ) (\ + 21) = ((\ +1) log \ )
S obzirom da je G povezan \ asimptotski nije veci od 1 tako da je rezultat (1 log \ ).
To je tacno jednako sa procjenom za Kruskalov algoritam.
113
11.5 Zadaci
Zadatak 01. Kruskalovim algoritmom naci minimalno razapinjuce stablo na sljedecem
grafu.
Rjeenje je dato na narednoj tabeli.
Korak Raspolozivo Uzeto
1 (c,d) (c,d)
2 (d,e), (c,e) (d,e)
3 (b,c) (b,c)
4 (a,d) (a,d)
Dobijeno je stablo na narednoj slici.
Zadatak 02. Kruskalovim algoritmom naci minimalno razapinjuce stablo na sljedecem
grafu.
114
Rjeenje. Postupak rjeavanja je prikazan na narednoj tabeli.
Korak Raspolozivo Uzeto
1 (c,g), (e,i), (k,l) (c,g)
2 (e,i), (k,i) (e,i)
3 (k,l) (k,l)
4 (a,e), (b,c), (c,d), (d,g), (f,j), (j,k) (a,e)
5 (b,c), (c,d), (d,g), (f,j), (j,k) (b,c)
6 (c,d), (d,g), (f,j), (j,k) (c,d)
7 (f,j), (j,k) (f,j)
8 (j,k) (j,k)
9 (b,f), (e,j), (i,j) (b,f)
10 (e,j), (i,j) (e,j)
11 (h,l) (h,l)
Table 2: Graf 02
Dobijeno je stablo na narednoj slici.
Zadatak. Primovim algoritmom naci minimalno razapinjuce stablo na sljedecem grafu.
115
Rjeenje. Postupak rjeavanja je dat na narednoj tabeli.
Korak

Cvorovi Raspolozivo Uzeto
1 a (a,b), (a,e), (a,f) (a,e)
2 a, e (a,b), (a,f), (e,f), (e,i), (e,j) (e,i)
3 a, e, i (a,b), (a,f), (e,f), (e,j), (i,j) (e,j)
4 a, e, j (a,b), (a,f), (e,f), (j,f), (j,g), (j,k) (j,f)
5 a, f, j (a,b), (f,b), (f,c), (f,g), (j,g), (j,k) (j,k)
6 a, f, j, k (a,b), (f,b), (f,c), (f,g), (j,g), (k,g), (k,l) (k,l)
7 a, f, j, k, l (a,b), (f,b), (f,c), (f,g), (j,g), (k,g), (l,g), (l,h) (f,b)
8 b, f, j, k, l (b,c), (f,c), (f,g), (j,g), (k,g), (l,g), (l,h) (b,c)
9 c, f, j, k, l (c,d), (c,g), (f,g), (j,g), (k,g), (l,g), (l,h) (c,g)
10 c, g, l (c,d), (g,d), (g,h), (l,h) (c,d)
11 d, g,l (d,h), (g,h), (l,h) (l,h)
Dobijeno je stablo na narednoj slici.
U ovom slucaju je dobijeno stablo identicno onome iz prethodnog zadatka. Ovo ne mora
uvijek biti slucaj.
Zadatak. Dijkstra algoritmom naci najkraci put u sljedecem grafu.
116
Rjeenje. Postupak je dat na sljedecoj tabeli.
Korak

Cvorovi Veze Uzeto
1 a b(10), e(2), f(8) (a,e)
2 a, e b(10), f(8), i(3), j(5) (e,i)
3 a, e, i b(10), f(8), j(5) (e,j)
4 a, e, j b(10), f(7), g(11), k(7) (f,j)
5 a, f, j b(10), c(12), g(10), k(7) (j,k)
6 a, f, k b(10), c(12), g(10), l(8) (k,l)
7 a, f, l b(10), c(12), g(10), h(13) (a,b)
8 b, f, l c(12), g(10),h(13) (f,g)
9 b, g, l c(11), d(12), h(13) (c,g)
10 c, g, l d(13), h(13) (d,g)
11 d, g,l h(13) (l,h)
Dobijena je putanja na sljedecoj slici.
Zadatak 03. Dijkstra algoritmom naci najkraci put u sljedecem grafu.
117
Postupak je dat na sljedecoj tabeli.
Korak

Cvorovi Veze Uzeto
1 a b(10), d(5) (a,d)
2 a, d b(8), c(14), e(7) (d,e)
3 a, d, e b(8), c(13) (d,b)
4 b, d, e c(9) (b,c)
Dobijena je putanja na sljedecoj slici.
11.6 Zadaci za samostalni rad
Na sljedecim grafovima odabranim algoritmom naci minimalno razapinjuce stablo i na-
jkraci put. Za pocetni uzimati cvor a.
118
119
120
121
122
123
12 Programski jezik C++
12.1 Rad sa datotekama
Jedan od vaznijih problema u programiranju je kako preuzeti ulazne velicine. Ovo je
posebno vazno rijeiti u situacijama kao to su :
Preuzimanje podataka koji su rezultat neke druge obrade ili procesa
Uzimanje veceg obima podataka kao to su matrice vecih dimenzija
Spremanje rezultata programa radi arhiviranja, kasnijih analiza ili obrada od strane
nekih drugih programa kao to su Excell i slicni
Spremanje rezultata kao jedna od faza u radu istog programa
i slicno. Poseban problem je unos veceg broja podataka kako zbog vremena za unos tako
i zbog mogucih greaka. Jedno od rjeenja je koritenje datoteka za ulaz, meukorake i
izlaz.
Operacije u radu sa datotekama su :
kreiranje datoteka, obicno za izlaz
citanje iz datoteka
upis u datoteku
Ako su datoteke vec kreirane tada se mogu koristiti naredbe open (otvoriti) i close
(zatvoriti).
Svaka datoteka koja se koristi u radu, bilo da se u nju upisuje ili iz nje vri citanje, mora
imati naziv. Na algoritmu 01 je primjer programa koji u datoteku kvadrati.txt upisuje
brojeve od 1 do 100 i njihove kvadrate, odvojene zarezom.
Algoritam 01
#include <fstream
using namespace std;
int main()
{
ofstream izlaz("BROJEVI.TXT");
for(int i = 1; i <= 100; i++)
izlaz << i << ", " << i * i << endl;
return 0;
}
Prva promjena u odnosu na prethodne programe se vidi u prvom redu, u #include
naredbi. Sljedeci bitan element je nacin deklaracije izlazne datoteke pomocu naredbe
ofstream (to se moze tumaciti kao output file stream). Umjesto naredbe cout rezultat
se usmjerava na izlazni tok koji se naziva izlaz. Naziv datoteke se daje prema pravilima
operativnog sistema pod kojim se radi. Ako okolnosti nalazu da ime datoteke sadrzi znak
(backslash) tada se taj znak uduplava. Npr. ako datoteka treba imati naziv
124
"algoritmiprobeproba01.txt"
u programskom kodu se to pie kao
"algoritmiprobeproba01.txt"

Cesta je potreba da naziv datoteke daje (upisuje) korisnik u samom programu (koji mu
postavlja "upit"). Na algoritmu 02 je primjer takvog pristupa.
Algoritam 02
char ime[100];
cout << "Unesite ime datoteke koju zelite kreirati:";
cin.getline(ime, sizeof ime);
ofstream izlaz(ime);
Drugi nacin da se ovo uradi je na algoritmu 03.
Algoritam 03
string ime;
cout << "Unesite ime datoteke koju zelite kreirati:";
getline(cin, ime);
ofstream izlaz(ime.c_str());
U ovom slucaju ofstream kreira izlaznu datoteku ciji naziv se upisuje u promjenljivu ime
a funkcijom ime.c_str() se iz upisanog tekstualnog niza odbacuju evenutalni blankovi
sa pocetka i kraja.
Da bi se provjerilo da li je kreiranje izlazne datoteke uspjelo ili ne koristi se operator
! (negacija). Ako kreiranje nije uspjelo upit "if(!izlaz)" daje rezutat tacno (true) .
Ovo bi trebao biti uobicajeni postupak u radu sa datotekama.
Za ulazne datoteke vrijede ista pravila kao i za izlazne osim to se umjesto naredbe
ofstream koristi ifstream a ulazni tok cin mijenja oznakom ulazne datoteke. Na algo-
ritmu 04 je primjer u kojem se elementi matrice ucitavaju iz datoteke.
Otvaranje datoteke se vri metodom open a zatvaranje metodom close. Druge varijante
rada sa datotekama kao ulaznim odnosno izlaznim tokovima nisu predmet daljeg rada.
Zadatak. Programe iz prethodnih poglavlja prilagoditi tako da podatke preuzimaju iz
datoteke i rezultat smjetaju u datoteku.
12.2 Klase i objektno programiranje
Za cuvanje i rad sa razlicitim tipovima podataka u C jeziku moze se koristiti slozeni tip
promjenljive koji se zove struct. Primjer je rad sa datumima tako da se moze napraviti
denicija data u Algoritmu 05.
Na Algoritmu 06 su primjeri mogucih deklaracija.
125
Algoritam 04
#include <fstream
using namespace std;
int main()
{
ifstream ulaz("PODACI.TXT");
// Ako se ne moze otvoriti tok ulaz tada se treba dati neka poruka...
if(!ulaz)
cout << "Otvaranje datoteke nije uspjelo!n";
else
{
int i, j, broj, a[4][5];
// Ucitava se red po red...
for(i=0;i<4;i++)
{
for(j=0;j<5;j++)
{
// Uzimamo broj iz datoteke; na mjestu metode cin je odrednica ulaz
ulaz broj;
}
}
ulaz.close();
// Ako se ne moze raditi iz bilo kog razloga...
if(ulaz.eof())
// Ako je kraj ...
cout << "Nema vie podataka!n";
// Ako se ne moze raditi dalje
else if(ulaz.bad()) cout << "Datoteka je vjerovatno
otecena!n";
else cout << "Datoteka sadrzi neo cekivane podatke!n";
// Prethodna if struktura nije aktivna ako je citanje zavreno bez greaka
}
return(0);
}
Algoritam 05
struct Datum
{
int dan, mjesec, godina;
};
Algoritam 06
Datum d;
d.dan=33;
d.mjesec=14;
d.godina=2004;
126
Ovaj tip je veoma pogodan za neke upotrebe jer se osigurava bolji kontekst. Sa druge
strane, ocito je, kao u ovom primjeru, da nedostaje mogucnost kontrole sadrzaja u smislu
meusobne veze pojedinih komponenti strukutre. Jedna od mogucnosti da se ovaj prob-
lem, makar djelimicno, rijei je denicija funkcija koje pristupaju poljima strukture na
strogo kontrolisan nacin i koje se koriste za tu svrhu. Jedan od boljih primjera za ilus-
traciju ovih kontrola je rad sa datumima, to ce biti ucinjeno u nastavku.
Prvi tip kontrole u radu sa datumima je provjera smislenosti odnosa pojedinih elemenata.
U tu svrhu mozemo denisati funkciju PostaviDatum koja postavlja elemente datuma
unutar strukture a koja moze imati izgled dat na Algoritmu 07.
Algoritam 07
void PostaviDatum(Datum &d, int dan, int mjesec, int godina)
{
int broj_dana[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(godina % 4 == 0 && godina % 100 != 0 [[ godina % 400 == 0)
broj_dana[1]++;
if(godina < 1 [[ mjesec < 1 [[ mjesec 12 [[ dan < 1 [[ dan
broj_dana[mjesec-1])
throw "Neispravan datum!n";
d.dan = dan; d.mjesec = mjesec; d.godina = godina;
}
Ispravan datum se stavlja u promjenljivu na koju upucuje odrednica &d i to tako da se
napie npr:
Datum dd;
PostaviDatum(dd,33,14,2012);
Ovakav pristup znaci da programer mora koristiti navedenu funkciju ako zeli potpunu
kontrolu jer ga nita ne ogranicava da radi direktno sa elementima strukture, u ovom
slucaju to je struktura Datum. Ovo ne bi bio problem u slucaju kad jedan programer
kontrolie cijeli programski kod ali jeste u slucaju kada na programima rade, nekad veoma
veliki, razvojni timovi, jer je teko (a nekad i nemoguce) mijenjati ili nametati pravila
koja svi moraju potovati kako bi se sacuvao integritet programa. Potreba za timskim
razvojem velikih programa dovela je do razvoja potpuno nove metodologije za razvoj
programa, koja je nazvana objektno orijentisano programiranje (OOP - object oriented
programming). U toj metodologij mnogo veci znacaj se daje samim podacima i tipovima
podataka nego to je to slucaj u klasicnoj metodologiji programiranja, koja je poznata i
pod nazivom proceduralno programiranje.
Osnovu objektno orijentiranog pristupa programiranju cine klase odnosno razredi (engl.
class) koje objedinjuju grupe podataka i postupke koji se mogu primjenjivati nad njima.
Klasa se dobija tako to se unutar strukture dodaju prototipovi funkcija koje se mogu
primjenjivati nad tim podacima. Na primjer, deklaracija na Algoritmu 08 denie klasu
Datum koja pored podataka dan, mjesec i godina sadrzi i prototip funkcije Postavi, koja
ce se primjenjivati nad promjenljivima tipa Datum:
127
Algoritam 08
class Datum
{
int dan, mjesec, godina;
void Postavi(int d, int m, int g);
};
Promjenljive ciji je tip klasa obicno se nazivaju primjerci klase, instance klase ili prosto
objekti. U tom smislu, klasa je apstrakcija koja denie zajednicka svojstva i zajednicke
postupke koji su svojstveni svim objektima nekog tipa.
Funkcije ciji su prototipovi navedeni unutar same klase nazivaju se funkcije clanice klase
ili metode. Njihova namjena je da se primjenjuju nad konkretnim objektima te klase a ne
da im se kao parametri alju objekti te klase. Ovome je prilagoena i sintaksa pozivanja
funkcija clanica. One se uvijek primjenjuju nad nekim konkretnim objektom koritenjem
operatora . (tacka), istog operatora koji se koristi i za pristup atributima unutar klase.
Primjer pozivanja funkcije Postavi na dva konkretna objekta tipa Datum je sljedeci :
Datum d1, d2;
d1.Postavi(14,5,2001);
d2.Postavi(36,14,2012);
Drugi poziv bi trebao dati odnosno odbaciti izuzetak, s obzirom na besmislen datum.
Promjena u sintaksi upucuje i na promjenu nacina razmiljanja. Funkciji PostaviDatum
se kao argument alju objekti d1 i d2, dok se funkcija Postavi primjenjuje nad objektima
d1 i d2.
Jedna od mogucih implementacija funkcije Postavi je na Algoritmu 09.
Algoritam 09
void Datum::Postavi(int d, int m, int g)
{
int broj_dana[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(g % 4 == 0 && g % 100 != 0 [[ g % 400 == 0) broj_dana[1]++;
if(g < 1 [[ d < 1 [[ m < 1 [[ m 12 [[ d broj_dana[m-1])
throw "Neispravan datum!n";
dan = d; mjesec = m; godina = g;
}
Prvo to se uocava je da se ispred imena funkcije nalazi dodatak Datum:: to treba
ukazivati na to da se radi o funkciji clanici klase Datum. Na taj nacin je moguce da
postoje i obicna funkcija i funkcija clanica istog imena, uz dodatnu mogucnost da vie
razlicitih klasa imaju funkcije clanice istih imena. Znak :: (dupla dvotacka) spada u
operatore, i obicno se naziva operator razlucivosti, vidokruga ili dosega (engl. scope oper-
ator). Unutar funkcije clanice direktno se pristupa atributima dan, mjesec i godina bez
navoenja na koji se konkretni objekt ovi atributi odnose. Ovakvu privilegiju, direktnog
pristupa atributima klase, imaju iskljucivo funkcije clanice te klase. Funkcije clanice
klase nikad se ne pozivaju samostalno nego se uvijek primjenjuju nad nekim konkretnim
128
objektom (osim kada se neka funkcija clanica poziva iz druge funkcije clanice iste klase),
tako da se samostalno upotrijebljeni atributi unutar funkcije clanice zapravo odnose na
atribute onog objekta nad kojim je funkcija clanica pozvana. Poziv d1.Postavi(14,
5, 2004) znaci da se atributi dan, mjesec i godina unutar funkcije clanice Postavi
odnose na odgovarajuce atribute objekta d1 tj. interpretiraju se kao d1.dan, d1.mjesec
i d1.godina.
Pristup atributu dan je moguc na dva nacina. Jedan je eksplicitno koritenje pokazivaca
(pointera) this. Funkcija Postavi mogla je biti napisana kao na Algoritmu 10.
Algoritam 10
void Datum::Postavi(int dan, int mjesec, int godina)
{
int broj_dana[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(godina % 4 == 0 && godina % 100 != 0 [[ godina % 400 == 0)
broj_dana[1]++;
if(godina < 1 [[ dan < 1 [[ mjesec < 1 [[ mjesec 12 [[ dan
broj_dana[mjesec -- 1])
throw "Neispravan datum!n";
this-dan = dan; this-mjesec = mjesec; this-godina = godina;
}
Drugi, mnogo ceci, nacin je upotreba operatora razlucivosti ::. Notacija Datum::dan
eksplicitno naglaava da se misli na atribut dan koji pripada klasi Datum. Stoga se metoda
Postavi moze napisati i na nacin dat na Algoritmu 11.
Algoritam 11
void Datum::Postavi(int dan, int mjesec, int godina)
{
int broj_dana[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(godina % 4 == 0 && godina % 100 != 0 [[ godina % 400 == 0)
broj_dana[1]++;
if(godina < 1 [[ dan < 1 [[ mjesec < 1 [[ mjesec 12 [[ dan
broj_dana[mjesec -- 1])
throw "Neispravan datum!n";
Datum::dan = dan; Datum::mjesec = mjesec; Datum::godina = godina;
}
Bitno je istaci razliku izmeu operatora . (tacka) i :: (scope). Operator . se uvijek
primjenjuje na neki konkretan objekt. Tako, d1.dan oznacava atribut dan konkretnog
objekta d1. Sa druge strane, operator :: se primjenjuje nad samom klasom, kao
apstraktnim tipom podataka. Tako, Datum::dan oznacava atribut dan koji pripada klasi
Datum, bez specikacije na koji se konkretan objekt klase Datum taj atribut odnosi. Iz
tog razloga, ovakva upotreba atributa dan moze imati smisla jedino unutar denicije neke
metode.
Kako bi se sprijecila situacija da se metoda Postavi zaobie i direktnom postavkom
atributa dan, mjesec i godina upie besmislen datum uvodi se mehanizam kljucnih rijeci
129
private i public. One se koriste iskljucivo unutar deklaracija klase a iza njih uvijek
slijedi znak : (dvotacka). Njima se specicira privatni i javni dio klase. Neka je
deklaracija klase Datum izmijenjena kao na Algoritmu 12.
Algoritam 12
struct Datum
{
private:
int dan, mjesec, godina;
public:
void Postavi(int d, int m, int g);
};
Na ovaj nacin nisu moguce deklaracije kao to su
d1.dan=20;
cout<<d1.dan;
Privatni atributi su jednostavno nedostupni za ostatak programa osim za funkcije clanice
klase i prijateljske funkcije klase ! Da bi klasa Datum imala smisla, osim postavljanja
datuma se dodaju i druge funkcije odnosno metode. Primjer je metoda Ispisi() koja
ispisuje datum na ekran. Primjer izmjene je na Algoritmu 13.
Algoritam 13
struct Datum
{
private:
int dan, mjesec, godina;
public:
void Postavi(int d, int m, int g);
void Ispisi();
};
Primjer implementacije metode Ispisi je na Algoritmu 14.
Algoritam 14
void Datum::Ispisi()
{
cout << dan << "." << mjesec << "." << godina << ".";
}
Sada je moguce napisati sljedeci niz naredbi:
Datum d;
d.Postavi(14, 5, 2004);
cout << "Upisan je datum ";
130
d.Ispisi();
Klasa Datum se moze sada dopuniti drugim metodama kao to su :
Prikazi dan (u nekim paketima poznato kao funkcija Day())
Prikazi mjesec (u nekim paketima poznato kao funkcija Month())
Prikazi godinu (u nekim paketima poznato kao funkcija Year())
Ocitavanje datuma
Primjer denicije klase Datum sa nekim dodatnim metodama je na Algoritmu 15.
Algoritam 15
class Datum
{
int dan, mjesec, godina;
public:
void Postavi(int d, int m, int g);
void Ocitaj(int &d, int &m, int &g)
{ d = dan; m = mjesec; g = godina;}
int VratiDan() { return dan; }
int VratiMjesec() { return mjesec; }
int VratiGodinu() { return godina; }
char *ImeMjeseca();
void Ispisi() {cout << dan << "." << mjesec << "." << godina
<< ".";}
void IspisiMj();
};
Zadatak. U ovu deklaraciju dodati metode ispisa u formatima :
dd.mm.gggg u kojem su dan i mjesec dati sa dvije a godina sa cetiri cifre
dd/mm/gggg u kojem su dan i mjesec dati sa dvije a godina sa cetiri cifre
mm.dd.gggg u kojem su dan i mjesec dati sa dvije a godina sa cetiri cifre
mm/dd/gggg u kojem su dan i mjesec dati sa dvije a godina sa cetiri cifre
U algoritmu 15 metode su implementirane u okviru deklaracije klase to se naziva in-
line deklaracija. Komplikovanije metode se trebaju implementirati van deklaracije klase,
posebno u slucajevima kada te metode sadrze petlje i komplikovanije uslove. Na algoritmu
16 je dat primjer metode SljedeciDatum().
Na Algoritmu 17 je metoda kojom se ispisuje naziv mjeseca u datumu.
Na algoritmu 18 je metoda kojom se datum ispisuje tako da je naziv mjeseca ispisan
slovima.
131
Algoritam 16
void Datum::SljedeciDatum()
{
int broj_dana[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(godina % 4 == 0 && godina % 100 != 0 [[ godina % 400 == 0)
broj_dana[1]++;
dan++;
if(dan broj_dana[mjesec - 1])
{
dan = 1; mjesec++;
}
if(mjesec 12)
{
mjesec = 1; godina++;
}
}
Algoritam 17
char *Datum::ImeMjeseca() const
{
char *nazivi_mj[] = {"Januar", "Februar", "Mart", "April",
"Maj", "Juni", "Juli", "August", "Septembar", "Oktobar", "Novembar",
"Decembar"};
return nazivi_mj[mjesec - 1];
}
Algoritam 18
void Datum::IspisiMj() const
{
cout << dan << ". " << ImeMjeseca() << " " << godina << ".";
}
132
Sve metode se mogu podijeliti u dvije kategorije : inspektori i mutatori.
Metode iz prve kategorije samo citaju atribute klase, ali ih ne mijenjaju. U naem slucaju
to su Ocitaj, VratiDan, VratiMjesec i slicno. U jeziku C++ se smatra dobrom praksom
posebno oznaciti funkcije inspektore kljucnom rijeci const. Tako oznacene funkcije nazi-
vaju se konstantne funkcije clanice. Na taj nacin se omogucava kompajleru prijava greke u
slucaju da unutar metode za koju je poznato da treba biti inspektor pokua promjena vri-
jednosti nekog od atributa. Pomocu kljucne rijeci const moguce je denirati konstantne
objekte, na isti nacin kao i npr. cjelobrojne konstante.
Metode iz druge kategorije mijenjaju atribute klase nad kojom su primijenjene. U naem
slucaju to je metoda Postavi.
Zadatak. U deklaraciju klase Datum dodati sljedece metode:
Ispis datuma kao redni broj dana u godini i godina. Naprimjer, datum 24.10.2013
se na ovaj nacin prikazuje u obliku 297.2013.
Zadatak. Zadat je datum dd.mm.gggg. Izracunati :
Broj dana u godini tog datuma
Datum koji se dobije kad se na datum doda odabrani broj dana
Datum koji se dobije kad se od datuma oduzme odabrani broj dana
Gregorijanski datum pretvoren u julijanski datum. Poznato je da julijanski kaledar
koristi pravoslavna crkva a Izmeu ova dva kalendara postoji razlika od 13 dana
4
na nacin da je "gregorijanski_datum" - "julijanski_datum" = 13
Zadatak. Zadat je datum dd.::.qqqq, pri cemu je qqqq 1900. Uraditi sljedece :
Odrediti koji dan u sedmici (Ponedjeljak, ..., Nedjelja) odgovara tom datumu.
Pritom je poznato da je 01.01.1901 bio ponedjeljak
Odrediti koliko petaka ima datum 13 u godini tog datuma. Problem generalizirati
za bilo koji datum i dan u sedmici
Na izlaz dati kalendar odabranog mjeseca te godine
Zadatak. Data su dva datuma d1.m1.ggg1 i d2.m2.ggg2. Uraditi sljedece:
Zamjena dva datuma ako je prvi od njih veci od drugog
Broj dana izmeu dva datuma. Na osnovu toga izracunaj svoju starost izrazenu
brojem dana
Broj mjeseci izmeu dva datuma
Broj cijelih godina izmeu dva datuma
4
Da li znate zato je razlika ba 13 dana ?
133
12.3 Zakljucak
Obim i sadrzaj ovog kursa ne daje prostor da se u vecoj mjeri obrauju svojstva i
mogucnosti C++ jezika. Iz tog razloga ovdje su date samo neke glavne karakteristike
koje omogucavaju razumijevanje i pisanje programa na elementarnom nivou.
134
13 NP kompleksnost
Tokom 60-ih godina napravljeni su veliki pomaci u nalazenju ekasnih rjeenja za mnoge
kombinatorne probleme ali je nastala rastuca lista problema za koje se cinilo da ne postoji
ekasno algoritamsko rjeenje. Ljudi su poceli traziti neku nepoznatu paradigmu koja bi
vodila ka rjeenju tih problema ili dokaz da su mozda ti problemi sami po sebi teki za
rjeavanje i da ne postoje algoritamska rjeenja koja rade ispod eksponencijalnog vremena.
Krajem 60-ih napravljeno je veliko otkrice. Mnogi od ovih problema su meusobno
povezani u smislu da ako je bilo koji od njih bilo moguce rijeiti u polinomijalnom vremenu
tada bi se mogao rijeiti svaki od njih. Otkrice je skrenulo paznju na `1-kompletnost
i kreiran je mozda najveci problem u kompjuterskoj nauci : 1 = `1 ? Cilj vie nije
dokazati da problem moze biti ekasno rijeen prezentiranjem algoritma. Umjesto toga
pokuava se pokazati da problem ne moze biti rijeen ekasno. Kako to uciniti ?
Potreban je neki nacin da se klasa ekasno rjeivih problema odvoji od problema koji
ne mogu biti ekasno rijeeni. To se moze uciniti analizom problema koji mogu biti
rijeeni u polinomijalnom vremenu. Zadatak da se dokaze da neto ne moze biti ucinjeno
ekasno mora se analizirati mnogo pazljivije kako se ne ostavila mogucnost bilo kome
da pravila kri na neprihvatljiv nacin i istovremeno tvrdi da postoji ekasno rjeenje ako
takvo rjeenje stvarno ne postoji.
Jedan od pristupa je mjerenje vremena izvrenja algoritama koritenjem scenarija kom-
pleksnosti najgoreg slucaja kao funkcije od :, velicine ulaza. Postoji vie nacina ali im
je zajednicki imenitelj broj bitova (ili bajtova) za prezentaciju ulaza korienjem razumno
ekasnog kodiranja. Naprimjer, brojevi se mogu pisati unarnom notacijom 111111111 =
1002 = 8 umjesto binarnom; grafovi se mogu opisivati na neki neekasan nacin kao to je
lista svih njegovih ciklusa ali je to neprihvatljivo. Pretpostavka je da se brojevi prikazuju
u bazi veceg reda, da su grafovi opisani matricama ili listom itd.
Uobicajeno je da se brojevi ogranice na cijele (kao suprotnost "realnim" brojevima) pa
je jasno da se aritmeticke operacije mogu provoditi ekasno. Pretpostavka je da se op-
eracije sa cijelim brojevima provode u konstantnom vremenu. Radi veceg opreza, moze
se pretpostaviti da aritmeticke operacije zahtijevaju barem onoliko vremena kolika je
preciznost brojeva koji su predmet pohrane.
Denicija. Za algoritam koji zavisi od prirodnih brojeva :
1
. :
2
. .... :
r
od /
1
. /
2
. .... /
r
bita respektivno kaze se da radi u polinomijalnom vremenu ako postoje prirodni brojevi
d
1
. d
2
. .... d
r
takvi da je broj potrebnih bit operacija za njegovo izvrenje O
_
/
d
1
1
. .... /
d
r
r
_
.
Za problem se kaze da je rjeiv u polinomijalnom vremenu ako postoji algoritam koji ga
rjeava u polinomijalnom vremenu.
Neke funkcije koje ne "izgledaju" kao polinomijalne (kao to je O(:log :)) su ogranicne
odozgo polinomima (kao to je O(:
2
)). Neke funkcije koje "izgledaju" kao polinomijalne
ustvari to nisu. Naprimjer, neka je predmet analize algoritam koji ima ulaz graf velicine
: i cijeli broj / koji radi u vremenu O
_
:
k
_
. On nije polinomijalni jer je / ulazna velicina
takva da je korisniku omoguceno da odabere / = : to povlaci da je vrijeme izvrenja
O(:
n
) a to nije polinom po :. Vazno je napomenuti da eksponent mora biti konstanta
nezavisna od :.
135
Naravno, reci da su algoritmi polinomijalnog vremena "ekasni" nije tacna. Algoritam
cije je vrijeme izvrenja C(:
1000
) je sigurno veoma neekasan. Bez obzira na to, ako
algoritam radi loije nego u polinomijalnom vremenu (npr. 2
n
) tada je sigurno da nije
ekasan osim za male vrijednosti :.
Denicija. Algoritam je subeksponencijalni ako je njegova slozenost funkcija oblika
C
_
c
o(n)
_
gdje je : duzina ulaznog podatka.
13.1 Problemi odlucivanja
Mnogi od problema ukljucuju optimalizaciju u nekoj formi : naci najkraci put, naci
najmanje razapinjuce stablo, naci triangulaciju najmanje tezine itd. Iz prevashodno
tehnickih razloga najveci dio `1-problema ce biti nazvan problemom odlucivanja. Prob-
lem se naziva problemom odlucivanja ako je njegov rezultat jedan od odgovora "Da" ili
"Ne".
Mnogi problemi se mogu formulisati kao problemi odlucivanja. Naprimjer, problem na-
jmanjeg razapinjuceg stabla se moze formulisati na sljedeci nacin : Za dati tezinski graf
G i cijeli broj / da li G ima razapinjuce stablo koje je najvie / ?
Ovo se moze ciniti kao mnogo zanimljivija formulacija problema. Ovdje se ne postavlja
pitanje tezine minimalnog razapinjuceg stabla niti za ivice stabla za koje se dostize ova
tezina. Meutim, zadatak je pokazati da odreeni problemi ne mogu biti rijeeni ekasno.
Ako se pokaze da jednostavni problem odlucivanja ne moze biti rijeen ekasno tada je
sigurno da ni mnogo generalniji problem sigurno ne moze biti rijeen ekasno.
U nastavku je nekoliko denicija koje su od pomoci u razumijevanju terminologije koja
se javlja kad su u pitanju algoritmi odlucivanja.
Denicija. Za algoritam se kaze da je decidan ako na postavljeno pitanje uvijek daje
odgovor Da ili Ne. Za algoritam se kaze da je vjerovatnosni (engl. probabilistic) ako
koristi slucajne brojeve.
Denicija. Da-bazirani Monte Carlo algoritam je vjerovatnosni algoritam za decidne
probleme gdje je odgovor Da uvijek tacan ali odgovor Ne moze biti netacan. Obratno
se denie Ne-bazirani algoritam Monte Carlo. Kaze se da Da-bazirani algoritam Monte
Carlo ima greku vjerovatnoce ako je mogucnost da rezultat algoritma bude odgovor
Ne kada bi taj odgovor trebao biti Da najvie .
Denicija. Las Vegas algoritam je vjerovatnosni algoritam koji za odreenu vrstu prob-
lema moze ne dati odgovor sa vjerovatnocom 0 _ < 1. Ako algoritam daje odgovor
onda je taj odgovor uvijek korektan.
Dakle, Las Vegas algoritam moze ne vratiti odgovor ali odgovor koji daje mora biti tacan,
za razliku od Monte Carlo algoritma koji uvijek daje odgovor ali on nije uvijek tacan.
Prema tome, ako se za rjeavanje nekog problema koristi Las Vegas algoritam onda se on
jednostavno iznova pokrece ponovo dok se ne dobije odgovor. Vjerovatnoca da algoritam
ne pruzi odgovor za : pokuaja puta je
m
. Da bi algoritam bio u stanju dati odgovor
broj pokretanja je prosjecno 1, (1 ).
136
13.2 Problemi prepoznavanja jezika
Potrebno je uociti da se o problemu odlucivanja moze razmiljati kao o problemu prepoz-
navanja jezika. Jezik 1 se moze denisati kao
1 = (G; /) [G posjeduje MST tezine najvie /
Ovaj skup se sastoji od parova u kojem je prvi element graf (odnosno matrica kodirana
kao string) a drugi cijeli broj kodiran kao binarni broj. Na prvi pogled moze izgledati
cudno da se graf denie kao string ali je ocigledno da se u racunaru sve predstavlja u
obliku niza (string) bitova.
Ako mu se prezentira string (G; /) algoritam bi trebao dati odgovor "Da" ako (G; /) 1
to povlaci da G posjeduje razapinjuce stablo tezine najvie / i "Ne" u suprotnom slucaju.
U prvom slucaju se kaze da algoritam "prihvata" ulaz a u suprotnom "odbacuje" ulaz.
Za bilo koji dati jezik se moze postaviti pitanje koliko teko je utvrditi da li je dati
string u jeziku ili ne. Naprimjer, u slucaju MST jezika 1 clanstvo se moze lako utvrditi
u polinomijalnom vremenu. Dovoljno je graf pohraniti interno, pokrenuti Kruskalov
algoritam i vidjeti da li je dobijena optimalna tezina najvie / ili ne.
Denicija. Neka je sa 1 oznacen skup svih jezika za koje clanstvo moze biti testirano u
polinomijalnom vremenu.
Potrebno je primijetiti da su jezici skupovi stringova a 1 je skup jezika. 1 je denisan
u terminima kojima se iskazuje koliko je teko racunarski prepoznati clanstvo u jeziku.
Skup jezika koji je denisan u terminima koliko teko je utvrditi clanstvo se zove klasa
kompleksnosti. S obzirom da se moze pronaci minimalno razapinjuce stablo u polinomi-
jalnom vremenu tada vrijedi da je 1 1.
Postoji i tezi jezik
` = (G; /) : G ima jednostavnu putanju tezine barem /
Za dati graf G i cijeli broj / kako bi se prepoznalo da li je on u jeziku ` ? Moze se
pokuati pretrazivanje grafa i traziti jednostavni putevi sve dok se ne nae neki tezine /.
Ako se takav put pronae graf se prihvata i posao se prekida. Meutim, ako se ne nae
moze se potroiti puno vremena u pretrazivanju pa se ne moze dati pravi odgovor.
Prvi korak je da se deniu razne klase slozenosti odlucivanja.
Denicija. Klasa slozenosti 1 je skup problema odlucivanja za koje postoji polinomijalni
algoritam.
U sutini, to je skup svih problema odlucivanja koji mogu biti rijeeni u polinomijalnom
vremenu. Obicno se nazivaju "jednostavni" ili "ekasno rjeivi".
Denicija. Klasa slozenosti `1 se sastoji od svih problema odlucivanja za koje se
odgovor DA moze provjeriti u polinomijalnom vremenu koritenjem neke dodatne infor-
macija zv. certikata. Klasa slozenost co `1 se denie analogno za odgovor NE.
137
To je skup svih problema odlucivanja koji mogu biti vericirani u polinomijalnom vre-
menu. Ova klasa sadrzi 1 kao podskup. Stoga, ona sadrzi veliki broj jednostavnih
problema ali sadrzi i veliki broj problema za koje se vjeruje da ih je teko rijeiti. Oznaka
ne znaci "NePolinomijalni". Izvorno je ovo oznaka za "Nedeterministicko Polinomijalno
vrijeme". Ovaj koncept je mnogo lake objasniti i shvatiti iz perspektive verikacije.
Denicija. Klasa slozenosti `1 tc .c/ (NP-hard) se sastoji od problema za koje vrijedi
da ako se jedan od njih moze rijeiti u polinomijalnom vremenu tada bi svi NP problemi
bili rjeivi u polinomijalnom vremenu.
Unatoc nazivu, NP-teko ne znaci da je problem teko rijeiti. Ako je problem NP-tezak
to ne mora znaciti da je u NP klasi. S obzirom da se vjeruje da nisu svi NP problemi
rjeivi u polinomijalnom vremenu vjeruje se da nijedan NP-tezak problem nije rjeiv u
polinomijalnom vremenu.
Denicija. Problem je `1 /o:j|ctc: ako je (1) NP, (2) NP-tezak.
To znaci da je `1C = `1 `1 tc .c/.
Denicija. Strogo NP-kompletan problem je NP-kompletan problem koji ostaje takav
kada su svi brojevi u ulazu ograniceni nekim polinomom u funkciji duzini ulaza.
Primjeri ovih algoritama su Satisability, Hamiltonov ciklus, Problem tri boje.
Jedan od primjera NP-kompletnog problema je popularna igra Minesweeper [11] koja je
uobicajeni dio instalacije Windows operativnog sistema, sa brojnim varijacijama. Igrac
ove igre ne treba pogaati da li je kvadrat sigurno slobodan. Slicno, igrac markira svaku
minu koja sigurno moze biti identicirana.

Cinjenica da je Minesweeper NP-kompletan
problem znaci da je veoma teko pogoditi kada je moguce sigurno ocistiti neki kvadrat
uz potpuno znanje o tome. Drugim rijecima, potreban je odreeni stepen pogaanja. U
sutini, ako je i unaprijed receno da pogaanje nije potrebno jo uvijek moze biti teko
odluciti kada je kvadrat prazan ili zauzet.
Moguci odnosi problema po kompleksnosti
138
Slika ilustruje jedan od mogucih nacina interpretacije kako bi mogao izgledati odnos
skupova P, NP, NP-tezak, NP-kompletan. Naglaeno je "moguci odnos" jer jo nije
poznato da li su ove klase kompleksnosti disjunktne ili su sve rjeive u polinomijalnom
vremenu. Neki od problema na slici iziskuju dublju diskusiju. Jedna od njih se odnosi na
Izomorzam grafova u kojem se postavlja pitanje da li su dva grafa identicna do nivoa
imena njihovih ivica. Poznato je da je problem NP ali nije poznato da li je u P. Drugi je
QBF to je skracenica za Quantied Boolean Formulas. U tom problemu su date bulovske
formule sa kvantikatorima \ i i potrebno je dati odgovor na pitanje da li je formula
tacna ili ne.
13.3 Verikacija polinomijalnog vremena i certikati
Vazno je dati napomene o algoritmima verikacije. Mnogi problemi prepoznavanja jezika
su teki za rjeavanje ali imaju svojstvo da je lako verikovati da li je string jezik.
Kao primjer ce biti uzet problem Hamiltonovog ciklusa. Za dati neusmjereni graf G se
postavlja pitanje da li postoji ciklus koji obilazi sve cvorove tacno jednom. Ovaj problem
se moze opisati kao problem prepoznavanja jezika
HC = (G) : G ima Hamiltonog ciklus
gdje je sa (G) oznacava graf kao string.

Cini se da je problem Hamiltovnog ciklusa mnogo
tezi i nije poznat algoritam u polinomijalnom vremenu koji rjeava ovaj problem.
Na slici je primjer ciklusa koji je Hamiltonov i jednog koji to nije. Ako se poe od
pretpostavke da je graf imao Hamiltonov ciklus tada bi trebao biti jednostavan zadatak
da se to potvrdi. Ako se uzme ciklus npr.
3
.
7
. ....
13
tada bi se graf mogao ispitati
i provjeriti da li je to stvarno legalan ciklus koji obilazi sve cvorove grafa tacno jednom.
Stoga, iako nije poznat ekasan nacin da se rijei problem Hamiltonovog ciklusa postoji
veoma ekasan nacin verikacije (provjere) da li je dati graf u HC. Dati ciklus je certikat.
To je dio informacije koji omogucava da se verikuje da je dati string jezik.
Formalno, za dati jezik 1 i za r 1 algoritam verikacije je algoritam koji za dato r i
dato , koje se naziva certikat, moze vericirati da je r u jeziku 1 koristeci taj certikat
kao pomoc. Ako r nije u 1 tada nema nicega za verikaciju.
Treba uociti da nemaju svi jezici svojstvo da ih je lako vericirati. Naprimjer, neka su
dati sljedeci jezici :
139
lHC = (G) : G ima jedinstveni Hamiltonov ciklus
HC = (G) : G nema Hamiltonov ciklus
Neka je graf G u jeziku lHC. Koja bi informacija trebala biti data koja bi omogucila
da se verikuje da je G stvarno jezik ? Moze se dati primjer jedinstvenog Hamiltonovog
ciklusa i to bi se moglo vericirati ali koja vrsta certikata je potrebna kako bi se utvrdilo
da je to jedini graf ? Moze se uzeti drugi ciklus koji nije Hamiltonov ali to ne znaci da
nema drugog ciklusa koji jeste Hamiltonov. Moze se pokuati sa svim ciklusima tezine :
ali bi to uopte ne bi bilo ekasno jer postoji ukupno :! ciklusa. Stoga je teko zamisliti
da se moze dati informacija koja bi omogucila da se ekasno uvjerimo da je dati graf u
jeziku.
13.3.1 NP klasa
Kako je receno, NP se denie kao skup svih jezika koji mogu biti vericirani algorit-
mom u polinomijalnom vremenu. Zato je dat naziv NP umjesto VP ? Originalan naziv
je skracenica od "Nedeterministicko Polinomijalno vrijeme". Ovo se odnosi na program
koji se izvrava na nedeterministickom racunaru koji se moze zamisliti. U osnovi, takav
kompjuter bi mogao nedeterministicki pogoditi vrijednost certikata i zatim vericirati
u polinomijalnom vremenu da je string u jeziku. Ovdje je izbjegnuta denicija nedeter-
minizma.
NP je, kao i u slucaju P, skup jezika zasnovan na nekoj mjeri kompleksnosti (komplek-
snost verikacije). Potrebno je uociti da je 1 _ `1. Drugim rijecima, ako se problem
moze rijeiti u polinomijalnom vremenu tada se clanstvo sigurno moze vericirati u poli-
nomijalnom vremenu.
Nije poznato da li je 1 = `1. Ne cini se razumnim da ovo vrijedi. Drugim rijecima, biti
u mogucnosti da se verikuje da se ima ispravno rjeenje ne pomaze mnogo u nalazenju
stvarnog rjeenja. Mnogi eksperti vjeruju da je 1 ,= `1 ali to niko nije dokazao.
Na tabeli je lista NP i odgovarajucih P problema. Na desnoj strani su problemi koji
mogu biti ekasno rijeeni. Na lijevoj strani je skup "tvrdih oraha" koji vec decenijama
odolijevaju naporima za njihovo ekasno rjeenje.
140
Klasa NP kompletnih problema se sastoji od skupa problema odlucivanja (jezika) za koje
niko ne zna. Ako bi bilo poznato rjeenje u polinomijalnom vremenu makar ijednog NP
kompletnog problema tada bi svaki NP problem bio rjeiv u polinomijalnom vremenu.
Za ovo je potrebno uvesti koncept redukcije.
Prije toga je potrebno razmotriti sljedece pitanje. Pretpostavimo da postoje dva problema
H i l. Za H se zna (ili cvrsto vjeruje) da je tezak odnosno da ne moze biti rijeen u
polinomijalnom vremenu. Sa druge strane, kompleksnost za l je nedenisana ali se
sumnja da je jako tezak.

Zeli se dokazati da l ne moze biti rijeen u polinomijalnom
vremenu.

Zeli se pokazati da
(H , 1) = (l , 1)
Da bi se ovo pokazalo dokazuje se suprotna tvrdnja
(l 1) = (H 1)
Drugim rijecima, da bi se pokazalo ad l nije rjeiv u polinomijalnom vremenu pret-
postavlja se da postoji algoritam kojim se l rjeava u polinomijalnom vremenu pa se
izvodi kontradikcija kojom se pokazuje da H moze biti rijeen u polinomijalnom vre-
menu.
Neka je data podutina koja moze rijeiti bilo koju instancu problema l u polinomijalnom
vremenu. Sve to je nuzno u tom slucaju je pokazati da se ta rutina moze koristiti da
se problem H moze rijeti u polinomijalnom vremenu. Time je problem H reduciran na
probleml. Vazno je uociti da je ta pretpostavljena rutina u sutini imaginacija (fantasy).
Zna se (ili se cvrsto vjeruje) da H ne moze biti rijeen u polinomijalnom vremenu pa se
dokaz svodi na to da takva rutina ne moze postojati to povlaci da l ne moze biti rijeen
u polinomijalnom vremenu. Ovo je veoma vazno sa stanovita razumijevanja pojma i
koncepta redukcije.
13.3.2 Problem tri boje
Naredni problem je dobro poznat kao NP kompletan pa se cvrsto vjeruje da ne moze biti
rijeen u polinomijalnom vremenu.
Problem tri boje : Da li svaki cvor datog grafa G moze biti oznacen jednom od tri
razlicite boje tako da ne postoje dva susjedna cvora koji imaju istu boju ?
Ovaj tip problema, obicno u oznaci 3Co|, se javlja u raznim problemima particioniranja
pri cemu je ogranicenje da dva objekta ne mogu biti u istom setu particije. Pojam
"bojenja" dolazi od izvorne primjene u bojenju geografskih karata. Dvije drzave koje
imaju zajednicku granicu bi trebale na mapi biti obojene sa dvije razlicite boje. Dobro je
poznato da grafovi u ravni mogu biti obojene sa cetiri boje i za ovakav problem postoji
algoritam polinomijalnog vremena.

Cini se da je utvrivanje da li je to moguce za tri
boje, cak i za grafove u ravni, tezak problem za koji nije poznat algoritam polinomijalnog
vremena.
141
Na slici su dva grafa od kojih je jedan moguce obojiti na trazeni nacin a drugi ne.
Problem bojenja sa tri boje ima ulogu H problema za koji se sumnja da je moguce
rijeiti u polinomijalnom vremenu.
Neka je l sljedeci problem. Za dati graf G = (\ ; 1) se kaze da podskup cvorova \
0
_ \
formira clique ako za svaki par cvorova n. \
0
(n; ) vrijedi da je n. 1. To znaci
da je podgraf induciran sa \
0
kompletan graf.
13.3.3 Clique pokrivac (cover) (CCov)
Za dati graf G = (\ ; 1) i cijeli broj / skup cvorova se moze podijeliti u podskupove
\
1
. \
2
. .... \
k
takve da je
_
i
\
i
= \ i da je svaki \
i
clique od G.
Problem Clique pokrivaca se javlja u aplikacijama klasteringa
5
. Ivica izmeu dva cvora
se stavlja ako su oni dovoljno slicni da budu klasterisani u istu grupu.

Zeli se znati da li
je moguce klasterisati sve cvorova u / grupa.
Pretpostavimo da se zeli rijeiti CCo problem ali nakon uzaludnih i besplodnih napora ne
moze se naci algoritam polinomijalnog vremena. Kako se moze dokazati da nije izvjesno
da CCo nema rjeenje u polinomijalnom vremenu ? Poznato je da je 3Co| NP kompletan
problem pa strucnjaci vjeruju da 3Co| , 1. Osjeca se da postoji neka veza izmeu ova
dva problema.

Zeli se dati odgovor na pitanje da li vrijedi
(3Co| , 1) = (CCo , 1)
to se pokazuje tako da se dokaze suprotno tvrenje
(CCo 1) = (3Co| 1)
Da bi se ovo dokazalo potrebno je pretpostaviti da postoji pristup podrutini CCo (G; /).
Za dati graf i cijeli broj / ova podrutina vraca odgovor "istina" ako G ima clique velicine
/ i "neistina" u suprotnom, uz cinjenicu da ta rutina radi u polinomijalnom vremenu.
Kako se sada ovakva rutina koristi za rjeenje dobro poznatog tekog 3Co| problema ?
Treba se napisati rutina koja radi u polinomijalnom vremenu za 3Co| i koja moze zvati
rutinu CCo (G; /) za bilo koji graf i bilo koji cijeli /.
5
Klastering je grupisanje po nekoj osobini slicnosti. Pritom se "slicnost" denie u kontekstu problema
(Euklidska duzina, prosjek, ...)
142
Oba problema ukljucuju particioniranje cvorova u grupe. Jedina razlika je to je u jednom
problemu broj klikova dat kao dio ulaza a u drugom je broj klasa ksiran na 3. Da bi dva
cvora u problemu clique bila u istoj grupi moraju biti susjedni. U problemu bojenja dva
cvora ne moraju biti susjedni da bi bili u istoj grupi. Na neki nacin su problemi gotovo
jednaki ali zahtjev da budu susjedni je obratan.
Tvrdimo da se problem tri boje moze reducirati na problem klika na sljedeci nacin. Za
dati graf G za koji se zeli utvrditi mogucnost bojenja sa tri boje rezultat je par
_
G; 3
_
gdje G oznacava komplement od G. To znaci da je G graf na istim cvorovima ali je (n; )
ivica u G ako i samo ako nije ivica u G. Tada se par
_
G; 3
_
moze koristiti kao ulaz u
rutinu za klik.
Ovo je ilustrovano na slici.
Tvrdnja. Graf G je moguce obojiti sa tri boje ako i samo ako komplement G ima
pokrivanje klikom velicine 3. Drugim rijecima
G 3Co| =
_
G; 3
_
CCo
Dokaz: (=) Ako je G moguce obojiti sa 3 boje neka su \
1
. \
2
. \
3
tri klase za svaku od
boja. Tvrdi se da je to klik pokrivac velicine 3 za G s obzirom da ako su n i razliciti
cvorovi u \
i
tada n; , 1 (G) s obzirom da susjedni cvorovi ne mogu biti iste boje.
Ovo povlaci da n; 1
_
G
_
. Stoga svaki par razlicitih cvorova u \
i
cini susjedne u G.
(=) Neka je pretpostavka da G ima klik pokrivac velicine 3 oznacen sa \
1
. \
2
. \
3
. Za
i 1. 2. 3 se daje cvorovima u \
i
boja i. Smatra se da je to legalno bojenje za G s
obzirom da ako su razliciti cvorovi n i u \
i
tada slijedi da je n; 1 (G) s obzirom
da su zajednickom kliku. Ovo povlaci da n; , 1
_
G
_
. Stoga dva cvora iste boje nisu
susjedna.
13.3.4 Redukcija na polinomijalno vrijeme
Sada se ova intuicija prenosi na redukciju jednog problema na drugi putem koritenja
poziva rutine kroz veci stepen formalizacije. U navedenom primjeru je izvrena konverzija
instance problema tri boje na ekvivalentnu instancu problema pokrivaca (G; 3).
Denicija. Kaze se da je jezik (odnosno problem odlucivanja) 1
1
reducibilan na jezik
1
2
sa polinomijalnim vremenom, u oznaci 1
1
_
P
1
2
, ako postoji racunarska funkcija ,
koja radi u polinomijalnom vremenu takva da vrijedi
143
(\r) (r 1
1
= , (r) 1
2
)
U navedenom primjeru je pokazano da 3Co| _
P
CCo. Posebno, vrijedi da je , (G) =
_
G; 3
_
. Treba primijetiti da je lako formirati komplement grafa u O(:
2
) vremenu (tako
to se zamijene 0 i 1 u odgovarajucoj matrici). Stoga je , izracunljiva u polinomijalnom
vremenu.
Intuitivno gledano, kad se kaze 1
1
_
P
1
2
to znaci "Ako je problem 1
2
rjeiv u polinomi-
jalnom vremenu tada to vrijedi i za 1
1
". To je zbog toga to se rutina u polinomijalnom
vremenu za 1
2
moze primijeniti na , (r) kako bi se utvrdilo da li , (r) 1
2
ili ekviva-
lentno, da li r 1
1
. Stoga, u smislu izracunljivosti u polinomijalnom vremenu, 1
1
nije
tezi od 1
2
.
Nacin na koji se ovo koristi NP kompletnost je tacno obrnut. Obicno postoji jak dokaz
da 1
1
nije rjeiv u polinomijalnom vremenu pa je redukcija efektivno ekvivalentna kao
da se kaze "S obzirom da za 1
1
nije izvjesno da je rjeiv u polinomijalnom vremenu tada
ni za 1
2
nije izvjesno da je rjeiv u polinomijalnom vremenu". Stoga je ovo nacin kako
redukcije polinomijalnog vremena mogu biti koritene da se pokaze da su problemi teki
onoliko koliko su teki poznati problemi.
Lema. Ako 1
1
_
P
1
2
i 1
2
1 tada 1
1
1.
Lema. Ako 1
1
_
P
1
2
i 1
2
, 1 tada 1
1
, 1.
Vazna cinjenica po osnovu reducibilnosti je tranzitivnost. Drugim rijecima
Lema. Ako 1
1
_
P
1
2
i 1
2
_
P
1
3
tada 1
1
_
P
1
3
.
Razlog je u tome to ako su dvije funkcije , (r) i q (r) izracunljive u polinomijalnom
vremenu tada je i njihova kompozicija , (q (r)) izracunljiva u polinomijalnom vremenu.
Treba obratiti paznju da se u nekim slucajevima termin "redukcija" mijenja terminom
"transformacija". Razlika u terminolokom smislu mozda nije velika ali treba voditi
racuna o tome.
13.4 NP kompletnost
Skup NP kompletnih problema su svi problemi u klasi kompleksnosti NP za koje je
poznato da ako je jedan rjeiv u polinomijalnom vremenu tada to vrijedi za sve njih i
obratno, ako jedan od njih nije rjeiv u polinomijalnom vremenu tada nijedan od njih
nije rjeiv na taj nacin. Ovo se matematicki formalizuje koritenjem oznaka redukcija
polinomijalnog vremena.
Denicija. Jezik 1 je NP-tezak ako
1
0
_
P
1 za sve 1
0
`1
Ovdje 1 ne mora biti u NP.
Denicija. Jezik 1 je NP-kompletan ako
1 `1
144
1 je NP-tezak
Da bi se pokazalo da je problem NP kompletan alternativa je, kao obicno laki put,
koritenje tranzitivnosti.
Lema. 1 je NP kompletan ako
1 `1
1
0

P
1 za neki poznati NP kompletan jezik 1
0

Cinjenica da su svi 1
00
`1 reducibilni na 1
0
(s obzirom da je 1
0
NP kompletan pa time
i NP tezak) i stoga, zbog tranzitivnosti je 1
00
reducibilan na 1 povlaci da je 1 NP tezak.
Ovo daje nacin za dokaz da su problemi NP kompletni u slucaju da je poznato da je
jedan problem NP kompletan. Nazalost, cini se da je gotovo nemoguce dokazati da je
jedan problem NP kompletan s obzirom da denicija kaze da moramo biti u mogucnosti
svaki problem u NP reducirati na taj problem. Postoji beskonacno takvih problema pa
je teko vjerovati u tako neto. Cook je pokazao da postoji problem pod nazivom SAT
(skracenica za Satisability) da je NP kompletan. Da bi pokazali da je drugi problem NP
kompletan sve to trebamo je pokazati da je na problem NP (a samim tim i reducibilan
na SAT) a zatim pokazati da SAT (ili generalno neki poznat NPC problem) mozemo
reducirati na na problem. Slijedi da je na problem ekvivalentan sa SAT pod uslovom
da se potuje rjeivost u polinomijalnom vremenu.
Ovo je ilustrovano na prilozenoj slici. Ocito je da vrijedi 1 _ `1 i 1 _ co`1. Pitanje
je da li je 1 = `1. Ovo se smatra jednim od najvaznijih matematickih problema i spada
u sedam tzv. Millenium Prize Problems. Vecina eksperata smatra da je odgovor NE ali
to nije i dokazano.
Denicija. Neka su 1
1
i 1
2
dva problema odluke. Kazemo da se 1
1
moze reducirati u
polinomijalnom vremenu na 1
2
, u oznaci 1
1
_ j1
2
ako postoji polinomijalni algoritam za
rjeavanje 1
1
koji kao potrpogram koristi algoritam za rjeavanje problema 1
2
pri cemu
je broj poziva tog programa takoer polinomijalan.
145
Drugim rijecima, ako je 1
1
_ j1
2
tada 1
1
nije bitno tezi od 1
2
.
Denicija. Problem odluke 1 je NP-potpun ako je 1 `1 i 1
1
_ j1 za svaki 1
1
`1.
Klasa svih `1 potpunih problema se oznacava sa `1C.
`1 potpuni problemi su najtezi problemi u klasi `1. Postojanje polinomijalnog algo-
ritma za bilo koji od `1 potpunih problema bi povlacilo da vrijedi 1 = `1. Kako
se vjeruje da ova jednakost ne vrijedi to je i postojanje ovakvog algoritma je jako malo
vjerovatno.
146
14 Literatura
References
[1] Azali Saudi, Analysis of Algorithms, Lecture Notes, July 2008
[2] Hasan Jamak, Teorija brojeva, materijali za nastavu na postdiplomskim studijama
na PMF Tuzla
[3] Miodrag

Zivkovic, Algoritmi, Matematicki fakultet, Beograd, 2000.
[4] S. A. Abramov, G. G. Gnezdilova, E. N. Kapustina, M. I. Selyun, Zadachi po pro-
gramirovaniyu, Bibilotechka programmista, Moskva, "Nauka", 1988
[5] Don Colton, A Quick Guide to Big Oh, Brigham Young University Hawaii
[6] Niklaus Wirth, Algorithms and data structure,
[7] Grzegorz Malewicz, Introduction to Computer Algorithms, Lecture Notes (under-
graduate CS470 course), 2005
[8] Marty Stepp, TCSS 342 Lecture Notes, Course Overview, Review of Math Concepts,
Algorithm Analysis and Big-Oh Notation, University of New York, 2005
[9] David Mount, Design and Analysis of Computer Algorithm, Department of Com-
puter Science, University of Maryland, Fall 2003
[10] www.wikipedia.com
[11] Richard Kaye, Some Mineseeper Congurtions, School of Mathematics, The Univer-
sity of Birmingham, Birmingham, 31.03.2007.
[12] Recommendation for Random Number Generation Using Deterministic Random Bit
Generators (Revised), NIST Special Publication 800-90, Mart 2007
[13] Richard Kaye, Minesweeper and NP-completness,
http://web.mat.bham.ac.uk/R.W.Kaye/minesw/ordmsw.htm
147

Vous aimerez peut-être aussi