40618164-p2

Embed Size (px)

Citation preview

  • 8/4/2019 40618164-p2

    1/139

    Programiranje IIBeleske za predavanja

    Smer Informatika

    Matematicki fakultet, Beograd

    Predrag Janicic i Filip Maric

    2010.

  • 8/4/2019 40618164-p2

    2/139

    2

  • 8/4/2019 40618164-p2

    3/139

    Sadrzaj

    I Osnovi algoritmike 7

    1 Algoritmi i resavanje problema 9

    1.1 Algoritmi intuitivni i formalni pojam . . . . . . . . . . . . . . 91.2 Resavanje problema uz pomoc racunara . . . . . . . . . . . . . . 10

    2 Ispitivanje ispravnosti programa 13

    2.1 Neformalno ispitivanje ispravnosti programa . . . . . . . . . . . . 132.2 Formalno ispitivanje ispravnosti programa . . . . . . . . . . . . . 14

    2.2.1 Formalna specifikacija . . . . . . . . . . . . . . . . . . . . 142.2.2 Razvoj programa u terminima Horovih trojki . . . . . . . 142.2.3 Primeri Horovih trojki . . . . . . . . . . . . . . . . . . . . 142.2.4 Primer dokazivanja ispravnosti sekvencijalnog programa . 152.2.5 Dokazivanje ispravnosti programa koji sadrze petlje i metoda

    induktivne invarijante . . . . . . . . . . . . . . . . . . . . 152.2.6 Primer dokazivanja korektnosti programa koji sadrzi petlju 17

    3 Slozenost algoritama 19

    3.1 Osnove analize algoritama: ,,O notacija; klase slozenosti . . . . 193.2 Red algoritma; analiza najgoreg slucaja; O notacija . . . . . . . . 203.3 Izracunavanje slozenosti algoritama . . . . . . . . . . . . . . . . . 213.4 NP kompletnost . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

    4 Rekurzija, rekurzivne matematicke funkcije i primeri koriscenja

    rekurzije 29

    4.1 Rekurzivne matematicke funkcije . . . . . . . . . . . . . . . . . . 304.2 Matematicka indukcija i rekurzija . . . . . . . . . . . . . . . . . . 304.3 Rekurzija u racunarstvu . . . . . . . . . . . . . . . . . . . . . . . 304.4 Faktorijel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

    4.5 Obrazac trougao . . . . . . . . . . . . . . . . . . . . . . . . . . . 324.6 Kule Hanoja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334.7 Permutacije . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344.8 Particionisanje . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354.9 Uzajamna rekurzija . . . . . . . . . . . . . . . . . . . . . . . . . . 364.10 Nedostaci rekurzije . . . . . . . . . . . . . . . . . . . . . . . . . . 37

  • 8/4/2019 40618164-p2

    4/139

    4 SADR ZAJ

    4.11 Eliminisanje rekurzije . . . . . . . . . . . . . . . . . . . . . . . . 38

    5 Fundamentalni algoritmi 395.1 Pretrazivanje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

    5.1.1 Pronalazenje karaktera u stringu . . . . . . . . . . . . . . 395.1.2 Odredivanje maksimuma . . . . . . . . . . . . . . . . . . . 395.1.3 Linearno pretrazivanje . . . . . . . . . . . . . . . . . . . . 405.1.4 Binarno pretrazivanje . . . . . . . . . . . . . . . . . . . . 42

    5.2 Sortiranje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475.2.1 Sortiranje selekcijom . . . . . . . . . . . . . . . . . . . . . 505.2.2 Sortiranje umetanjem . . . . . . . . . . . . . . . . . . . . 515.2.3 Babl sortiranje . . . . . . . . . . . . . . . . . . . . . . . . 525.2.4 Quick sort . . . . . . . . . . . . . . . . . . . . . . . . . . . 535.2.5 Koriscenje sistemske implementacije quick sort-a . . . . . 56

    5.3 Jednostavni numericki algoritmi . . . . . . . . . . . . . . . . . . . 585.3.1 Stepenovanje . . . . . . . . . . . . . . . . . . . . . . . . . 585.3.2 Izracunavanje vrednosti polinoma . . . . . . . . . . . . . . 595.3.3 Zagradivanje nula funkcije . . . . . . . . . . . . . . . . . . 595.3.4 Odredivanje nula funkcije . . . . . . . . . . . . . . . . . . 61

    II Dinamicki objekti 65

    6 Pokazivaci i adresna aritmetika 67

    6.1 Adresna aritmetika . . . . . . . . . . . . . . . . . . . . . . . . . . 676.2 Visedimenzioni nizovi . . . . . . . . . . . . . . . . . . . . . . . . 686.3 Inicijalizacija nizova pokazivaca . . . . . . . . . . . . . . . . . . . 70

    6.4 Pokazivaci i visedimenzioni nizovi . . . . . . . . . . . . . . . . . . 706.5 Pokazivaci na funkcije . . . . . . . . . . . . . . . . . . . . . . . . 71

    7 Dinamicka alokacija memorije 75

    7.1 Funkcije malloc i calloc . . . . . . . . . . . . . . . . . . . . . . 757.2 Funkcija realloc . . . . . . . . . . . . . . . . . . . . . . . . . . . 777.3 Curenje memorije (memory leaking) . . . . . . . . . . . . . . . . 797.4 Druge ceste greske . . . . . . . . . . . . . . . . . . . . . . . . . . 797.5 Fragmentisanje memorije . . . . . . . . . . . . . . . . . . . . . . 807.6 Implementacija primitivnog alokatora memorije . . . . . . . . . . 817.7 Hip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837.8 Velicina steka i hipa . . . . . . . . . . . . . . . . . . . . . . . . . 837.9 Heap u Win32 sistemima . . . . . . . . . . . . . . . . . . . . . . 84

    7.10 Demonstracija rada debagera . . . . . . . . . . . . . . . . . . . . 85

    8 Dinamicke strukture: liste i stabla 87

    8.1 Liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 878.1.1 Stek (LIFO lista) . . . . . . . . . . . . . . . . . . . . . . . 898.1.2 Red (FIFO lista) . . . . . . . . . . . . . . . . . . . . . . . 89

  • 8/4/2019 40618164-p2

    5/139

    SADRZAJ 5

    8.1.3 Dvostruko povezane (dvostruko ulancane) liste . . . . . . 918.1.4 Kruzne (ciklicne, cirkularne) liste . . . . . . . . . . . . . . 92

    8.1.5 Liste: primer . . . . . . . . . . . . . . . . . . . . . . . . . 938.2 Stabla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

    8.2.1 Binarna stabla . . . . . . . . . . . . . . . . . . . . . . . . 958.2.2 Uredena binarna stabla . . . . . . . . . . . . . . . . . . . 958.2.3 Izrazi u formi stabla . . . . . . . . . . . . . . . . . . . . . 101

    III Principi razvoja programa 103

    9 Strukturna dekompozicija i druga nacela pisanja programa 105

    9.1 Pisanje citljivih programa: vizualni elementi programa . . . . . . 1069.1.1 80 karaktera u liniji . . . . . . . . . . . . . . . . . . . . . 1069.1.2 Broj naredbi po liniji . . . . . . . . . . . . . . . . . . . . . 107

    9.1.3 Nazubljivanje/uvlacenje teksta . . . . . . . . . . . . . . . 1089.2 Imenovanje promenljivih i funkcija . . . . . . . . . . . . . . . . . 1089.3 Komentari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

    9.3.1 Komentari ne treba da objacnjavaju kod . . . . . . . . . . 1109.3.2 Komentari treba da su takvi da ih je moguce odrzavati . . 1109.3.3 Komentari treba da budu koncizni . . . . . . . . . . . . . 1109.3.4 Koriscenje specificnih komentara . . . . . . . . . . . . . . 110

    9.4 Pisanje programa: modularnost i podela na datoteke . . . . . . . 1119.4.1 Deljenje programa u vise datoteka . . . . . . . . . . . . . 1129.4.2 Modularnost . . . . . . . . . . . . . . . . . . . . . . . . . 1129.4.3 Kako koristiti konstante u programu . . . . . . . . . . . . 112

    9.5 Pisanje programa: dizajniranje programa . . . . . . . . . . . . . 113

    9.5.1 Dizajn u vidu tokovnika . . . . . . . . . . . . . . . . . . . 1139.5.2 Funkcijski-orijentisan dizajn . . . . . . . . . . . . . . . . . 1149.5.3 Strukturna dekompozicija . . . . . . . . . . . . . . . . . . 1159.5.4 Strukturalni model sistema . . . . . . . . . . . . . . . . . 118

    10 Programi koji se sastoje o d vise datoteka 121

    10.1 Povezivanje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12110.1.1 Kvalifikator static . . . . . . . . . . . . . . . . . . . . . 12110.1.2 Kvalifikator extern . . . . . . . . . . . . . . . . . . . . . 12210.1.3 Povezivanje vise programskih datoteka . . . . . . . . . . . 122

    10.2 Ukljucivanje datoteka . . . . . . . . . . . . . . . . . . . . . . . . 12410.3 Uslovna ukljucivanja . . . . . . . . . . . . . . . . . . . . . . . . . 125

    11 Uvod u prevodenje programskih jezika: poredjenje interpreterai kompilatora; faze u prevodjenju 127

    11.1 Implementacija programskih jezika . . . . . . . . . . . . . . . . . 12711.2 Kratka istorija razvoja kompilatora . . . . . . . . . . . . . . . . . 12811.3 Moderni kompilatori . . . . . . . . . . . . . . . . . . . . . . . . . 12811.4 Struktura kompilatora . . . . . . . . . . . . . . . . . . . . . . . . 128

  • 8/4/2019 40618164-p2

    6/139

    6 SADR ZAJ

    11.5 Leksicka analiza . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13011.6 Sintaksna analiza . . . . . . . . . . . . . . . . . . . . . . . . . . . 130

    11.7 Primer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

    IV Socijalni aspekti informatike 133

    12 Istorijski i drustveni kontekst racunarstva kao naucne disci-

    pline; drustveni znacaj racunara i Interneta; profesionalizam,

    eticki kodeks; autorska prava; intelektualna svojina, softverska

    piraterija 135

    12.1 Istorijski i drustveni kontekst racunarstva . . . . . . . . . . . . . 13512.2 Profesionalizam i eticki kodeks . . . . . . . . . . . . . . . . . . . 13612.3 Rizici i pouzdanost racunarskih sistema . . . . . . . . . . . . . . 13812.4 Intelektualna svojina i autorska prava . . . . . . . . . . . . . . . 138

    12.5 Privatnost i gradanske slobode . . . . . . . . . . . . . . . . . . . 13812.6 Racunarski kriminal . . . . . . . . . . . . . . . . . . . . . . . . . 13912.7 Ekonomski aspekti racunarstva . . . . . . . . . . . . . . . . . . . 139

  • 8/4/2019 40618164-p2

    7/139

    Deo I

    Osnovi algoritmike

  • 8/4/2019 40618164-p2

    8/139

  • 8/4/2019 40618164-p2

    9/139

    Glava 1

    Algoritmi i resavanjeproblema

    1.1 Algoritmi intuitivni i formalni pojam

    Pojam algoritma1 pripada osnovnim pojmovima matematike. Intuitivno, al-goritam je precizno opisana procedura za resavanje nekog matematickog prob-lema u konacnom broju koraka, koja cesto ukljucuje ponavljanje neke od op-eracija; ili sire, korak po korak odredena procedura za resavanje problema ilidolazenje do nekog cilja.

    Pojedina operacija algoritma naziva se algoritamski korak, a odredeni re-dosled podrazumeva preciznu informaciju o tome koji je algoritamski korakprvi, koji je poslednji (kojim se algoritam zavrsava), i koji algoritamski ko-

    rak sledi za izabranim. Redosled izvrsavanje algoritamskih koraka pri jednomizvrsavanju algoritma odreduje njegovu algoritamsku strukturu. Algoritamskastruktura moze biti linijska, kada se posle jednog algoritamskog koraka mozeizvrsavati samo algoritamski korak koji se jos nije izvrsavao pri tom izvrsavanjualgoritma, i ciklicna, kada se posle jednog algoritamskog koraka moze izvrsavatii algoritamski korak koji se vec izvrsavao pri tom izvrsavanju algoritma. Ulinijskoj algoritamkoj strukturi, dakle, svaki algoritamski korak izvrsava se na-

    jvise jedanput pri jednom izvrsavanju algoritma, dok se kod ciklicne algorita-mske strukture jedan algoritamski korak moze izvrsavati i vise puta pri jednomizvrsavanju algoritma.

    Formalno se algoritam definise u terminima matematickih formalizama kaosto su Tjuringova masina ili rekurzivne funkcije ili Markovljevi algoritmi.

    Cercova teza tvrdi (to se ne moze dokazati) da je intuitivni pojam algoritmaekvivalentan formalnom pojmu algoritma.

    Izgradnja algoritma pored same konstrukcije algoritma, ukljucuje i dokazi-vanje korektnosti, analiza efikasnosti i implementaciju (u nekom programskom

    jeziku).

    1Ovo poglavlje zasnovano je na tekstu Algoritmi prof. dr Gordane Pavlovic-Lazetic.

  • 8/4/2019 40618164-p2

    10/139

    10 1 Algoritmi i resavanje problema

    Problemi koji mogu da nastanu u svakoj od ovih faza uticu na modifikaciju iponovno izvrsenje prethodnih faza. Algoritmi se mogu zapisati u razlicitim no-

    tacijama prirodnim jezikom, dijagramima toka, pseudojezikom, programskimjezikom, itd.

    1.2 Resavanje problema uz pomoc racunara

    Resavanja problema uz pomoc racunara podrazumeva konstruisanje (pisanje)programa na nekom programskom jeziku, cijim izvrsavanjem ce se resavati svakipojedinacni zadatak tog problema. Da bi se program proizveo, potrebno jeodabrati metodu za resavanje problema, poznavati (ili razviti) algoritam zaresavanje problema, poznavati programski jezik, uveriti se u korektnost pro-grama njegovim izvrsavanjem za razne kombinacije ulaznih podataka. Jedini

    jezik na kome racunar moze da izvrsava program jeste masinski jezik tog racunara.

    To je jezik najnizeg nivoa, u kome su sve naredbe(tzv. instrukcije) i po-daci predstavljeni binarnom azbukom, i koji je zbog toga neodgovarajuci zacoveka. Da bi se program izvrsavao, potrebno je imati programske alate koji ceomoguciti rad sa nasim programom, od unosenja u racunar, preko prevodenja namasinski jezik, do testiranja programa i otkrivanja gresaka. Ako su u programuotkrivene greske, program se ispravlja(ponavlja se faza pisanja programa),a ako je potrebno, primenjuje se (ili razvija) drugi algoritam, odnosno menjametoda resavanja problema. Posto se izradi korektan i efikasan program zaresavanje zadatog problema, on se primenjuje krace ili duze vreme, uz eventu-alne povremene modifikacije koje odgovaraju promenama u postavci problema.Dakle, u resavanju problema uz pomoc racunara javlja se veci broj poslova kojetreba obaviti. Poslovi koji se javljaju u procesu resavanja problema uz pomocracunara mogu se, koncepcijski, podeliti u nekoliko faza, koje cine zivotni ciklus

    programa. Zivotni ciklus programa je vreme od pocetka razvoja programa (odpocetka resavanja problema uz pomoc racunara), do kra ja koriscenja programa,a sam termin asocira na ponovljeno (ciklicno) izvrsavanje tih faza, sto i odgovaraprirodi ovog procesa. Te faze su sledece:

    1. specifikovanje problema

    2. projektovanje (eventualno sa analizom slozenosti resenja)

    3. realizacija

    4. testiranje (i, eventualno, dokazivanje korektnosti)

    5. izrada dokumentacije

    6. eksploatacija i odrzavanje

    Specifikovanje problema je postupak opisivanja problema za koji se traziprogramsko resenje. Specifikacijom je potrebno sto preciznije opisati problem,prirodu ulaznih podataka i oblik u kome se zele resenja izlazni rezultati.

  • 8/4/2019 40618164-p2

    11/139

    1.2 Resavanje problema uz pomoc racunara 11

    Specifikacija programa bavi se pitanjem sta program treba da uradi, kojombrzinom, koja mu je maksimalna dozvoljena velicina, itd. Specifikacija se moze

    izraziti raznim jezicima sa razlicitim sintaksama. Mada postoje i posebni jeziciza pisanje formalne specifikacije, ona se moze (u jednostavnijim slucajevima)izraziti i prirodnim jezikom, npr. smestiti u z proizvod brojeva a i b, podpretpostavkom da su a i b celi brojevi i a 0, b 0.

    Projektovanje predstavlja razumevanje problema, izradu matematickog mod-ela i izbor ili razvoj/konstrukciju odgovarajuceg algoritma.

    Realizacija predstavlja implementaciju, ili ostvarenje resenja. Ona ukljucujedetaljnu razradu algoritma, izbor struktura podataka i medija na kojima ce sepodaci drzati (sa kojih ce se unositi ili na koje ce se izdavati), izradu sintak-sno ispravnog programa na izabranom programskom jeziku (programa koji je

    napisan prema pravilima kojima je definisan taj jezik). Da bi se utvrdila sin-taksna ispravnost programa, potrebno je uneti program u racunar (npr. prekoterminala, koriscenjem programa editora), prevesti program na masinski jezik pomocu programa prevodioca (pri cemu se ispituje sintaksna ispravnost)i izvrsiti ga (npr. uz pomoc programa za otkrivanje gresaka debagera), ili gainterpretirati (analizirati sintaksnu ispravnost programa i prevoditi ga deo podeo uz istovremeno izvrsavanje analiziranih delova). Ako se pri prevodenju pro-grama ili njegovom interpretiranju i izvrsavanju ustanovi neka greska, potrebno

    je ispraviti program, ponovo ga prevesti i izvrsiti.

    Testiranje predstavlja, pre svega, proces utvrdivanja semanticke ispravnostiprograma, tj. uveravanja, u sto je moguce vecem stepenu, da program izvrsava

    zeljenu funkciju, tj. da odgovara specifikaciji, tj. da resava postavljeni prob-lem. Ukoliko je formalno dokazana korektnost programa, ili je program razvijenformalnim metodama iz formalne specifikacije, za njega se moze garantovatida je semanticki korektan, do na tipografske greske. Tada je testiranje maksi-malno po jednostavljeno ili nepotrebno. U svim drugim slucajevima, testiranje

    je vazna faza razvoja programa. Testiranje se obavlja visestrukim izvrsavanjemprograma za raznovrsne pripremljene ulazne podatke, za koje su nam poznatiocekivani rezultati. Znacajno je da pripremljeni ulazni podaci budu dobroodabrani tako da se za njihove razne kombinacije, pri raznim izvrsavanjima pro-grama, izvrsavaju (testiraju) sve grane programa. Takvi ulazni podaci nazivajuse test primeri, i oni omogucuju proveru ispravnosti u sto je moguce vecoj meri,tako da program ima veliku verovatnocu ispravnosti u primeni. Ovde je bitnonaglasiti da se test primerima nikako ne moze dokazati korektnost programa,

    ali se mozemo, u visokom stepenu, uveriti da je program ispravan. Pri testi-ranju programa mogu se otkriti greske pri izvrsavanju (npr. deljenje nulom),koje otkriva i prijavljuje sam racunar tj. njegov operativni sistem, ili semantickegreske koje moze otkriti samo covek programer, poredenjem dobijenih rezultataizvrsavanja programa sa ocekivanim rezultatima. To mogu biti greske nastale pripisanju programa (npr. umesto uvecanja promenljive i za 1 omaskom smo naveli

  • 8/4/2019 40618164-p2

    12/139

    12 1 Algoritmi i resavanje problema

    uvecanje promenljive i za 10 u sintaksi C-a, i+ = 10), ali to mogu biti i greskeu algoritmu (npr. sa bro jacem ciklusa, i, posli smo od vrednosti 0 umesto od

    vrednosti 1), ili greske u samom matematickom modelu ili primenjenoj metodi(npr. za resavanje sistema nehomogenih algebarskih jednacina primenjena jemetoda kojom se resava samo sistem homogenih algebarskih jednacina). Ako

    je greska ustanovljena na nivou programa, potrebno je vratiti se na korak re-alizacije. Ako je greska ustanovljena na nivou algoritma ili metode (modela),potrebno je vratiti se na fazu projektovanja, pri cemu se ponavljaju sve narednefaze. Pri testiranju programa pomaze izdavanje tekucih vrednosti promenljivihna karakteristicnim mestima u programu, ili testiranje ulaznih podataka (tzv.logicka kontrola podataka) da bismo se uverili da ce program, kao ispravneulazne podatke, prihvatiti samo podatke odredenog (predvidenog) tipa, oblikai opsega.

    Debager je alat za pracenje izvrsavanja programa radi otkrivanja gresaga(bagova, eng. bugs). To je program napravljen da olaksa detektovanje, lociranjei ispravljanje gresaka u drugom programu. On omogucava programeru da idekorak po korak kroz izvrsavanje programa, prati sadrzaj memorije, vrednostipromenljivih i druge elemente programa.

    Izrada dokumentacije Kada je program dobro i uspesno istestiran, pris-tupa se izradi dobre, pregledne i detaljne dokumentacije. Dokumentacija jeneophodna za uspesno koriscenje programa, i posebno za fazu odrzavanja pro-grama koja prati njegovo koriscenje. Dokumentacija treba da sadrzi specifikacijuproblema, algoritam (globalni i detaljni), citljivo napisan program (uz dobrumeru komentara), nacin zadavanja ulaznih podataka i nacin izdavanja rezultata,znacenje koriscenih imena (promenljivih, datoteka, programa, potprograma,itd.), rezultate testiranja, test primere, uputstva za koriscenje i odrzavanje pro-

    grama. Eksploatacija i odrzavanje je faza koriscenja programa koja moze datraje i duzi niz godina. Odrzavanje programa podrazumeva izvesne modifikacijeprograma u toku njegove eksploatacije, koje su posledica promena samog prob-lema u toku vremena, ili potrebe da se kvalitet programa (prostorna i vremenskaefikasnost, primenljivost) poveca. Odrzavanje programa je lakse ako je programpreglednije napisan i ako je dokumentacija kompletnija, posebno zbog toga stoodrzavanje programa po pravilu ne vrsi lice koje je program pisalo. Svakuizmenu u programu nastalu u fazi odrzavanja programa potrebno je takodedokumentovati, tj. pored odrzavanja programa potrebno je odrzavati i njegovudokumentaciju. Postoje alati koji olaksavaju kreiranje dokumentacije i delom

    je generisu automatski (npr. Doxygen).

  • 8/4/2019 40618164-p2

    13/139

    Glava 2

    Ispitivanje ispravnostiprograma

    Centralno pitanje u razvoju programa je ispitivanje njegove ispravnosti (ko-rektnosti).1 Ukoliko neki program nije ispravan, tj. ukoliko u nekim situaci-

    jama on daje pogresan rezultat, tada taj program ne samo da je nekoristan vecmoze da bude i veoma stetan. Problem neispravnih programa je tokom posled-njih decenija postao jedno od kljucnih pitanja u mnogim poslovnim granama.Znacaj ispravnosti softvera ogleda se ne samo u finansijskim troskovima vec,pre, u situacijama u ko jima od po jedinog programa moze da zavisi ljudski zivot.Takvi su, na primer, programi koji upravljaju medicinskim aparatima, saobra-cajem, kosmickim letilicama i slicno.

    Postupak pokazivanja da je program ispravan naziva se verifikacija. U razvi-

    janju tehnika verifikacije programa, potrebno je najpre precizno formulisati po- jam ispravnosti programa. Ispravnost programa pociva na pojmu specifikacije.Specifikacija je, neformalno, opis ponasanja programa koji treba napisati.

    Verifikacija moze biti formalna i neformalna.U praksi se formalni dokaz ispravnosti programa retko izvodi i to cesto dovodi

    do neispravnog softvera i mnogih problema.

    2.1 Neformalno ispitivanje ispravnosti programa

    Neformalna verifikacija programa zasniva se na testiranju. Specifikacija pro-grama je proveriva testovima ako postoji razumno ocekivanje da se eksperimen-talno moze pokazati da program zadovoljava ili ne zadovoljava zadate uslove.

    Na primer, tvrdenje ,,program ima prosecno vreme izvrsavanja 0.5 sekundi je proverivo testovima kao i tvrdenje ,,prosecno vreme izmedu dva pada pro-grama je najmanje 8 sati sa verovatnocom 95%. Tvrdenje ,,prosecno vreme

    1Ovo poglavlje zasnovano je na tekstu Verifikacija programa Milene Vujosevic-Janicic iJelene Tomasevic.

  • 8/4/2019 40618164-p2

    14/139

    14 2 Ispitivanje ispravnosti programa

    izvrsavanja programa je dobro suvise je neodredeno da bi moglo da bude testi-rano. Primetimo da je, na primer, tvrdenje ,,prosecno vreme izmedu dva pada

    programa je najmanje 8 godina sa verovatnocom 95% u principu proverivotestovima ali nije prakticno izvodivo.

    2.2 Formalno ispitivanje ispravnosti programa

    Formalna verifikacija se ne zasniva na testiranju i eksperimentima, vec namatematickim dokazima. Korektnost programa je dokaziva ako se u okvirunekog formalnog deduktivnog sistema moze izvesti matematicki dokaz da pro-gram zadovoljava zadatu specifikaciju. Matematicki dokaz je izvodenje nekeformule iz skupa aksioma koriscenjem zadatih pravila izvodenja.

    2.2.1 Formalna specifikacija

    Formalna specifikacija problema je zapis oblika

    {}P{}

    gde su {} i {} logicki izrazi, tvrdenja cija je vrednost ili tacno ili netacno, aP je algoritam (tj. program). Trojku (, P, ) nazivamo Horova trojka.

    Interpretacija ovog zapisa specifikacije programa je sledeca: Ako izvrsenjeprograma P pocinje sa vrednostima ulaznih promenljivih (u stanju) koje zado-voljavaju uslov {}, onda se garantuje da ce se P zavrsiti u konacnom vremenusa vrednostima programskih promenljivih (u stanju) koje zadovoljavaju uslov{}. Uslov {} naziva se preduslov za algoritam (program, iskaz) P, a uslov{} naziva se postuslov (pauslov, posleuslov) za algoritam (program, iskaz) P.

    2.2.2 Razvoj programa u terminima Horovih trojki

    Koristeci notaciju Horovih trojki, razvoj softvera moze da se razmatra kaoproces koji se sastoji iz tri dela:

    Prevodenje zahteva korisnika u specifikaciju {}P{}; Pisanje programa P koji zadovoljava konstruisanu specifikaciju; Dokazivanje da vazi {}P{}.

    2.2.3 Primeri Horovih trojki

    Primer 2.1. Primeri Horovih trojki:

    {true}x := 12; {x = 12}

    {x < 40}x := x + 1; {x = 40}

  • 8/4/2019 40618164-p2

    15/139

    2.2 Formalno ispitivanje ispravnosti programa 15

    {m = n

    }j := (m + n)/2;

    {m = j = n

    }Primer 2.2. {X = 1}Y := X; {Y = 1}

    U ovom primeru preduslov je da je X jednako 1, a pauslov da je Y jednako1. Program se sastoji od naredbe dodele, vrednost promenljive Y postaje X. Akose naredba dodele izvrsava nakon sto je ispunjen preduslov i ako se izvrsavanjenaredbe dodele zavrsi, tada ce nakon izvrsenja naredbe biti ispunjen i pauslov.U ovom primeru specifikacija je zadovoljena.

    Primer 2.3. {X = 1}Y := X; {Y = 2}U ovom primeru preduslov je da je X jednako 1, a pauslov da je Y jed-

    nako 2. Program se sastoji od naredbe dodele, vrednost promenljive Y postajeX. Ako se naredba dodele izvrsava nakon sto je ispunjen preduslov i ako se toizvrsavanje zaustavi, tada nakon izvrsenja naredbe nece biti ispunjen pauslov. U

    ovom slucaju specifikacija nije zadovoljena.

    2.2.4 Primer dokazivanja ispravnosti sekvencijalnog pro-grama

    Primer 2.4 (Algoritam razmene vrednosti dveju promenljivih swap). Ovajprimer ilustruje algoritam za koji se dokazuje da odgovara zadatoj specifikaciji.Rec je o razmeni vrednosti dve promenljive, x i y.

    Za swap algoritam sledeceg oblika:swap : t := x; x := y; y := t,vazi

    {x = X

    y = Y

    }swap

    {x = Y

    y = X

    }Interpretacija ovog zapisa je daX, Y, x, y{x = X y = Y}swap{x = Y y = X}.Tacnost ovog tvrdenja sledi iz sledeceg razmatranja:{x = X y = Y}t := x{x = X y = Y t = X}{x = X y = Y t = X}x := y{x = Y y = Y t = X}{x = Y y = Y t = X}y := t{x = Y y = X t = X}

    2.2.5 Dokazivanje ispravnosti programa koji sadrze petljei metoda induktivne invarijante

    Metoda induktivne invarijante je dominantan pristup formalnoj verifikacijiprograma i do sada je dao najbolje rezultate, pa cemo se u nastavku baviti samo

    njom. Ova metoda verifikacije programa se cesto nazova Flojd-Horov2 (Floyd-

    2 Charles Antony Richard Hoare (Tony Hoare), britanski informaticar. Roden je 1934.godine u Kolombu (Sri Lanka), a diplomirao na univerzitetu u Oksfordu 1956. godine. Kon-struisao je, 1960. godine, algoritam za sortiranje quicksort, jedan od najkoriscenijih algori-tama uopste. Razvio je tzv. Horovu logiku i formalni jezik csp za specifikovanje konkurentnihprocesa. Godine 1980. dobio je Tjuringovu nagradu za ,,svoje fundamentalne doprinose

  • 8/4/2019 40618164-p2

    16/139

    16 2 Ispitivanje ispravnosti programa

    Hoare) metoda induktivnih tvrdenja i ima svoje korene u klasicnim radovimaGoldstajna (Goldstine) i Fon Nojmana (von Neumann).

    Korektnost programa P u odnosu na specifikaciju {}P{} moze biti: parcijalna korektnost ako se P zaustavi i ako za ulazne vrednosti vazi{}, tada ce vaziti tvrdenje ;

    totalna korektnost P ce se zaustaviti za ulazne vrednosti za koje vazi{}, i vazice tvrdenje .

    Ukoliko se ne naglasi drugacije, koristicemo pojam Horove trojke u smisluparcijalne korektnosti.

    Za ispitivanje ispravnosti programa posebnu paznju potrebno je posvetitipetljama jer se kroz njih moze proci razlicit broj puta u razlicitim izvrsavanjimaprograma.

    Definicija 1.

    Svojstvo koje vazi svaki put kada se ispituje da li je zadovoljen uslov ulaska upetlju naziva se invarijanta petlje.

    Svaka petlja ima puno invarijanti. Tako je, na primer, x*0=0 invarijantasvake petlje. Medutim, korisna invarijanta je samo ona koja vodi ka pauslovukada uslov petlje vise nije ispunjen.

    Formalna verifikacija programa metodom induktivne invarijante zasniva sena dokazu da se iz preduslova moze uspostaviti invarijanta pre prvog ulaska upetlju, zatim da svaki put kada se ulazi u petlju vazi dati uslov i, na kraju, dapri prestanku vazenja uslova ulaska u petlju on vodi ka ostvarivanju pauslovaprograma.

    Dokaz ispravnosti programa metodom induktivne invarijante se, dakle, sas-

    toji iz tri koraka:

    Uspostavljanje invarijante Odrzavanje invarijante Ostvarivanje zeljenog pauslova

    Na kraju, da bi se dokazala totalna korektnost programa, treba dokazati ida se program zaustavlja.

    Formalni dokazi su interesantni jer mogu da se generisu automatski uz pomocracunara ili barem interaktivno u saradnji coveka sa racunarom. U oba slucaja,formalni dokaz moze da se proveri automatski, dok provera neformalnog dokaza

    nije laka. Takode, kada se program i njegov dokaz istovremeno razvijaju, pro-gramer bolje razume sam program i proces programiranja uopste. Programeri suzainteresovani za formalne dokaze jer metodologija dokaza utice na razmatranje

    definiciji i dizajnu programskih jezika. Poznate su sledece Horove reci: ,,Postoje dva puta zadizajniranje softvera: jedan je napraviti ga tako jednostavnim da ocigledno nema nedostatakai drugi - napraviti ga tako komplikovanim da nema ociglednih nedostataka.

  • 8/4/2019 40618164-p2

    17/139

    2.2 Formalno ispitivanje ispravnosti programa 17

    preciznosti, konzistentnosti i kompletnsoti specifikacije, na jasnocu implement-cije i konzistentnost implementacije i specifikacije. Zahvaljujuci tome dobija se

    pouzdaniji softver, cak i onda kada se formalni dokaz ne izvede eksplicitno.Za neki program moze se dokazati tvrdenje program kao rezultat vraca

    faktorijel ulazne vrednosti. U nekim slucajevima moze se dokazati tvrdenje,,program ima prosecno vreme izvrsavanja 0.5 sekundi. Tvrdenja ,,prosecnovreme izmedu dva pada programa je najmanje 8 sati sa verovatnocom 95% i,,prosecno vreme izvrsavanja programa je dobro ne mogu se formalno dokazati.

    2.2.6 Primer dokazivanja korektnosti programa koji sadrzipetlju

    Konstruisati algoritam koji mnozi dva nenegativna cela bro ja x i y koriscenjemoperatora sabiranja (ne i mnozenja) i smesta rezultat u promenljivu z. Dokazatikorektnost algoritma.

    {

    z = 0 ;

    n = 0 ;

    while (n < x)

    {

    z = z + y;

    n = n + 1;

    }

    }

    Navedeni algoritam P treba da zadovoljava uslov:

    {x 0, y 0}P{z = x y}Da bismo dokazali korektnost ovog algoritma, dokazimo da je relacija

    {z = n y; n x}invarijanta while petlje algoritma:

    induktivna osnova: pre prvog ulaska u petlju vazi

    z = 0 = 0 y = n y, n = 0 xpa su relacije z = n y i n x tacne.

    induktivni korak: Pretpostavimo da je relacija z = n y; n x bila tacnapre jednog ulaska u blok naredbi u okviru while petlja i dokazimo da cebiti tacna i na kraju izvrsavanja tog bloka. Neka su n i z vrednostipromenljivih n i z nakon tog izvrsavanja bloka naredbi. Tada vazi

    z = z + y = n y + y = (n + 1) y = n yDakle, vazi z = n y (naglasimo da je veza z = n y induktivna pret-postavka).

  • 8/4/2019 40618164-p2

    18/139

    18 2 Ispitivanje ispravnosti programa

    Kako je bio ispunjen uslov za ulazak u petlju, vazi n < x, pa je n =n + 1

    x.

    Dakle, vazi z = n y; n x, sto je i trebalo dokazati.

    U svakoj iteraciji, vrednost promenljive n se uvecava za 1, pa ce u konacnombroju koraka biti dostignuta vrednost x. Tada nece biti zadovoljen uslov ulaskau while petlju i program ce zavrsiti rad. Tada ce promenljiva n imati vrednostx, a na osnovu dokazane invarijante petlje vazice:

    z = n y = x y

    sto je i trebalo dokazati.

  • 8/4/2019 40618164-p2

    19/139

    Glava 3

    Slozenost algoritama

    Razmatra se

    vremenska slozenost algoritma; prostorna (memorijska) slozenost algoritma.

    Primer 3.1. Izracunavanje vrednosti faktorijela prirodnog broja zahteva n poredenjain1 mnozenje; to je ukupno 2n1 koraka, te je vremenska slozenost algoritmalinearna.

    Klasu algoritama koji imaju linarnu slozenost oznacavamo sa O(n).Cesto se algoritmi ne izvrsavaju isto za sve ulaze istih velicina, pa je potrebno

    naci nacin za opisivanje i poredenje efikasnosti razlicitih algoritama. Anal-iza najgoreg slucaja zasniva procenu slozenosti algoritma na najgorem slucaju

    (na slucaju za koji se algoritam najduze izvrsava). Ta procena moze da budevarljiva, ali ne postoji bolji opsti nacin za poredenje efikasnosti algoritama. Caki kada bi uvek bilo moguce izracunati prosecno vreme izvrsavanja algoritma, itakva procena bi cesto mogla da bude varljiva.

    Ako algoritam u najgorem slucaju zahteva an2 + bn + c koraka, onda kazemoda je on kvadratne slozenosti i da pripada klasi O(n2).

    Aditivne i multiplikativne konstante ne uticu na klasu ko joj funkcija pripada.

    Primer 3.2. Vazi:

    n2 = O(n2) 3 n2 + 10 = O(n2)

    3.1 Osnove analize algoritama: ,,O notacija;klase slozenosti

    Svojstva programa:

  • 8/4/2019 40618164-p2

    20/139

    20 3 Slozenost algoritama

    zaustavljanje1

    korektnost2

    kompleksnost (slozenost) vremenska

    prostorna (memorijska)

    Primer 3.3. Izracunavanje vrednosti faktorijela prirodnog broja: n poredjenjai n 1 mnozenje; linearna slozenost.Primer 3.4. Odredjivanje najmanjeg elementa u nizu od n prirodnih brojeva:linearna slozenost.

    Primer 3.5. Sortiranje niza od n prirodnih brojeva odredjivanjem najmanjeg u

    tekucem nizu: n(n 1)/2 vremenskih jedinica (kvadratna slozenost).

    3.2 Red algoritma; analiza najgoreg slucaja; Onotacija

    Definicija 2.

    Ako postoje pozitivna konstanta c i prirodan broj N takvi da za funkcije f i gnad prirodnim brojevima vazi

    f(n) c g(n) za sve vrednosti n vece od N

    onda pisemo

    f = O(g)i citamo f je veliko o od g.

    NOTA BENE: O nije funkcija; O oznacava klasu funkcija.Aditivne i multiplikativne konstante ne uticu na klasu ko joj funkcija pripada.

    Primer 3.6. Vazi:

    n2 = O(n2) n2 + 10 = O(n2) 10 n2 + 10 = O(n2)

    10

    n2 + 8n + 10 = O(n2)

    n2 = O(n3)1Tjuring je tridesetih godina dvadesetog veka dokazao da ne posto ji opsti postupak kojim

    se za proizvoljan program moze utvrditi da li se zaustavlja (to je tzv. halting problem). Dakle,postoje funkcije ko je nisu izracunljive.

    2Videti poglavlje o korektnosti programa u skripti za kurs Programiranje I.

  • 8/4/2019 40618164-p2

    21/139

    3.3 Izracunavanje slozenosti algoritama 21

    2n = O(2n)

    2n

    + 10 = O(2n

    )

    10 2n + 10 = O(2n) 2n + n2 = O(2n) 3n + 2n = O(3n) 2n + 2nn = O(2nn)

    Definicija 3.

    Ako je T(n) vreme izvrsavanja algoritam A (ciji ulaz karakterise prirodan brojn), ako vazi T = O(g) i ako u najgorem slucaju vrednost T(n) dostize vrednostc g(n) (gde je c pozitivna konstanta), onda kazemo da je algoritam A slozenosti(ili reda) g i da pripada klasi O(g).

    Cesto se algoritmi ne izvrsavaju isto za sve ulaze istih velicina, pa je potrebnonaci nacin za opisivanje i poredjenje efikasnosti razlicitih algoritama. Anal-iza najgoreg slucaja zasniva procenu slozenosti algoritma na najgorem slucaju(na slucaju za koji se algoritam najduze izvrsava). Ta procena moze da budevarljiva, ali ne postoji bolji opsti nacin za poredjenje efikasnosti algoritama. Caki kada bi uvek bilo moguce izracunati prosecno vreme izvrsavanja algoritma, itakva procena bi cesto mogla da bude varljiva. Analiziranje najboljeg slucaja,naravno, ima jos manje smisla.

    Primer 3.7. Algoritam za izracunavanje vrednosti faktorijela prirodnog broja je redan, tj. pripada klasi O(n), tj. on je linearne slozenosti.

    Primer 3.8. Algoritam za sortiranje niza od n prirodnih brojeva odredjivanjemnajmanjeg u tekucem nizu je reda n2, tj. pripada klasiO(n2), tj. on je kvadratneslozenosti jer vazi

    n(n 1)2

    12

    n2 za sve vrednosti n 1.

    i u najgorem slucaju (za ovaj algoritam svi se slucajevi mogu smatrati najgorim)dostize vrednost koja kvadratno zavisi od n.

    3.3 Izracunavanje slozenosti algoritama

    Primer 3.9. Neka je T(n) vreme izvrsavanja algoritma A za izracunavanjefaktorijela broja n. Vazi T(1) = 1 (tj. za n = 1 algoritam utrosi samo jednuvremensku jedinicu) i

    T(n) = T(n 1) + 2(nakon izracunavanja vrednosti(n1)! algoritam treba da izvrsi jos jedno pored-

    jenje i jos jedno mnozenje; smatramo da i poredjenje i mnozenje trose po jednuvremensku jedinicu; mozemo da smatramo i da poredjenje i mnozenje zajedno

  • 8/4/2019 40618164-p2

    22/139

    22 3 Slozenost algoritama

    trose jednu vremensku jedinicu ili c vremenskih jedinica to ne utice na rezultatkoji govori o redu algoritma A). Dakle,

    T(n) = T(n 1) + 2 = T(n 2) + 2 + 2 = . . . = T(1) + 2 + . . . + 2 n1

    =

    = 1 + 2(n 1) = 2n + 1 = O(n) ,pa je algoritam A reda n (tj. pripada klasi O(n), tj. on je linearne slozenosti).

    Zadatak 1. Ako za vreme izvrsavanja T(n) algoritmaA (gde n odredjuje ulaznuvrednost za algoritam) vazi T(n) = T(n1) + n/2 i T(1) = 1, odrediti slozenostalgoritmaA.

    Resenje:

    T(n) = T(n 1) + n2

    = T(n 2) + n 12

    + n2

    = T(1) + 22

    + . . . + n 12

    + n2

    =

    = T(1) +1

    2(2 + . . . + n) = 1 +

    1

    2

    n(n + 1)

    2 1

    =

    n2 + n + 2

    4,

    pa je algoritam A kvadratne slozenosti.

    Zadatak 2. Ako za vreme izvrsavanja T(n) algoritmaA (gde n odredjuje ulaznuvrednost za algoritam) vazi T(n + 2) = 8T(n + 1) 15T(n) (za n 1) i T(1) =1, T(2) = 4, odrediti slozenost algoritma A.

    Resenje:

    Karakteristicna jednacina za navedenu homogenu rekurentntu vezu drugog

    reda jet2 = 8t 15

    i njeni koreni su t1 = 3 i t2 = 5. Opsti clan niza T(n) moze biti izrazen u obliku

    T(n) = tn1 + tn2 ,tj.

    T(n) = 3n + 5n ,Iz T(1) = 1, T(2) = 4 dobija se sistem

    3 + 5 = 1

    9 +

    25 = 4

    cije je resenje (, ) = (1/6, 1/10). Dakle, vazi

    T(n) =1

    63n +

    1

    105n ,

    pa je algoritam A reda O(5n).

  • 8/4/2019 40618164-p2

    23/139

    3.3 Izracunavanje slozenosti algoritama 23

    (Zaista, za npr. c = 1 vazi

    T(n) = 16

    3n + 110

    5n 16

    5n + 110

    5n 16

    + 110 5n 1 5n = c 5n ,

    pa je T(n) = O(5n).)

    Zadatak 3. Ako za vreme izvrsavanja T(n) algoritmaA (gde n odredjuje ulaznuvrednost za algoritam) vazi T(n + 2) = 4T(n + 1) 4T(n) (za n 1) i T(1) =6, T(2) = 20, odrediti slozenost algoritma A.

    Resenje: Karakteristicna jednacina za navedenu homogenu rekurentntuvezu je

    t2 = 4t 4i njen dvostruki koren je t1 = 2. Opsti clan niza T(n) moze biti izrazen u obliku

    T(n) =

    tn1

    +

    n

    tn2

    .

    tj.T(n) = 2n + n 2n .

    Iz T(1) = 6, T(2) = 20 dobija se sistem

    2 + 2 = 6 4 + 8 = 20

    cije je resenje (, ) = (1, 2), pa je T(n) = 2n + 2 n 2n, odakle sledi da jeT(n) = O(n 2n).Zadatak 4. Odrediti slozenost algoritma za resavanje problema kule Hanoja.

    Resenje:

    Vazi T( 1) = 1 i T(n) = 2T(n 1) + 1 (i T(2) = 2T(1) + 1 = 3). IzT(n) 2T(n 1 ) = 1 = T(n 1) 2T(n 2) (za n > 2) sledi T(n) =3T(n 1) 2T(n 2). Karakteristicna jednacina ove veze je t2 = 3t 2 i njenikoreni su 2 i 1. Iz sistema

    2 + 1 = 1 4 + 1 = 3

    sledi = 1 i = 1, pa jeT(n) = 1 2n + (1) 1n = 2n 1 ,

    sto znaci da je algoritam reda O(2n).

    Zadatak 5. Algoritam A izvrsava se za vrednost n (n > 1) primenom istog

    algoritma za vrednostn1, pri cemu se za svodjenje problema koristi algoritamB za vrednost n 1. Algoritam B izvrsava se za vrednost n (n > 1) trostrukomprimenom istog algoritma za vrednost n 1, pri cemu se za svodjenje problemakoristi algoritam A za vrednost n 1. Algoritmi A i B se za n = 1 izvrsavaju

    jednu vremensku jedinicu. Izracunati vreme izvrsavanja algoritma A za ulaznuvrednost n.

  • 8/4/2019 40618164-p2

    24/139

    24 3 Slozenost algoritama

    Resenje: Neka je A(n) vreme izvrsavanja algoritma A za ulaznu vrednost ni neka je B(n) vreme izvrsavanja algoritma B za ulaznu vrednost n. Na osnovu

    uslova zadatka vazi:A(1) = B(1) = 1 (3.1)

    A(n) = A(n 1) + B(n 1) (3.2)B(n) = 3B(n 1) + A(n 1) (n > 1) (3.3)

    Iz jednakosti (2) imamo:

    B(n) = A(n + 1) A(n) (3.4)

    B(n 1) = A(n) A(n 1) (3.5)pa, uvrstavanjem u jednakost (3), za n > 1 vazi:

    A(n + 1) 4A(n) + 2A(n 1) = 0 (3.6)

    Pomocu ove rekurentne veze i pocetnih uslova: A(1) = 1 i A(2) = A(1)+B(1) =2, mozemo odrediti vrednost A(n). Karakteristicna jednacina relacije (6) je:

    x2 4x + 2 = 0

    Njeni koreni su x1 = 2 +

    2 i x2 = 2

    2, pa je opste resenje rekurentne jednacine (6) oblika:

    A(n) = c1(2 +

    2)n + c2(2

    2)n

    za neke c1

    , c2

    R. Konstante c1

    i c2

    odredjujemo pomocu pocetnih uslova,resavajuci sledeci sistem linearnih jednacina po c1 i c2:

    1 = A(1) = c1(2 +

    2) + c2(2

    2)

    2 = A(2) = c1(2 +

    2)2 + c2(2

    2)2

    Dobija se da je c1 =14(2

    2), a c2 =

    14(2 +

    2), pa je konacno:

    A(n) =1

    2((2 +

    2)n1 + (2

    2)n1)

    Zadatak 6. Problem P ima parametar n (n je prirodan broj) i resava se pri-menom algoritama A i B. Algoritam A resava problem za vrednost n (n > 1).

    primenom algoritma B za vrednost n 1, pri cemu se za svodjenje problematrosi n vremenskih jedinica. AlgoritamB resava problem za vrednost n (n > 1).primenom algoritma A za vrednost n 1, pri cemu se za svodjenje problematrosi n vremenskih jedinica. Problem za n = 1, algoritam A resava trivijalno za

    jednu vremensku jedinicu, a algoritamB za dve vremenske jedinice. Izracunativreme izvrsavanja algoritma A za ulaznu vrednost n.

  • 8/4/2019 40618164-p2

    25/139

    3.3 Izracunavanje slozenosti algoritama 25

    Resenje:

    Oznacimo sa an vreme izvrsavanja algoritma A, a sa bn vreme izvrsavanja

    algoritma B za ulaznu vrednost n. Na osnovu uslova zadatka je:a1 = 1b1 = 2an = bn1 + n (n > 1)bn = an1 + n (n > 1)

    Kako je bn1 = an2 + n 1, zakljucujemo da jean = an2 + n 1 + nPrimenom matematicke indukcije dokazimo da za neparne vrednosti n vazi

    an =n(n+1)

    2 .

    Tvrdjenje vazi za n = 1 jer je a1 = 1 =122 .

    Pretpostavimo da je tvrdjenje tacno za neki neparan broj n i dokazimo davazi i za sledeci neparan broj - n + 2:

    an+2 = bn+1 + n + 2 = an + n + 1 + n + 2an+2 =

    n(n+1)2 + n + 1 + n + 2

    an+2 =n(n+1)+2(n+1)+2(n+2)

    2

    an+2 =(n+1)(n+2)+2(n+2)

    2

    an+2 =(n+2)(n+1+2)

    2

    an+2 =(n+2)(n+3)

    2

    Dakle, na osnovu principa matematicke indukcije tvrdjenje vazi za sve neparnebrojeve.

    Dokazimo da za parne vrednosti n vazi an =n(n+1)

    2 + 1.

    Za n = 2 tvrdjenje je tacno: a2 = b1 + 2 = 2 + 2 =232 + 1.

    Pretpostavimo da je tvrdjenje tacno za neki paran broj n i dokazimo da je

    tacno i za n + 2, tj. za sledeci paran bro j:an+2 = bn+1 + n + 2 = an + n + 1 + n + 2

    an+2 =n(n+1)

    2 + 1 + n + 1 + n + 2

    an+2 =n(n+1)+2(n+1)+2(n+2)

    2 + 1

    an+2 =(n+1)(n+2)+2(n+2)

    2 + 1

    an+2 =(n+2)(n+1+2)

    2 + 1

    an+2 =(n+2)(n+3)

    2 + 1

    Dakle, tvrdjenje je tacno za sve parne brojeve.

    Konacno imamo da je:

    an = n(n+1)

    2 + 1 za n parnon(n+1)

    2 za n neparno

    Teorema 1.

    Resenje rekurentne relacije

    T(n) = aT(n/b) + cnk ,

  • 8/4/2019 40618164-p2

    26/139

    26 3 Slozenost algoritama

    gde su a i b celobrojne konstante (a 1, b 1) i c i k pozitivne konstante je

    T(n) = O(n

    logb a) , ako je a > bkO(nk log n) , ako je a = bk

    O(nk) , ako je a < bk

    3.4 NP kompletnost

    Primer 3.10. Sef protokola na jednom dvoru treba da organizuje bal za pred-stavnike ambasada. Kralj trazi da na bal bude pozvan Peru ili da ne bude pozvanKatar (Qatar). Kraljica zahteva da budu pozvani Katar ili Rumunija (ili i Katari Rumunija). Princ zahteva da ne bude pozvana Rumunija ili da ne bude pozvanPeru (ili da ne budu pozvani ni Rumunija ni Peru). Da li je moguce organizovatibal i zadovoljiti zahteve svih clanova kraljevske porodice?

    Ako su p, q i r bulovske (logicke) promenljive (koje mogu imati vrednostitrue ili false, tj. ili ), navedeni problem moze biti formulisan na sledecinacin: da li je zadovoljivlogicki iskaz

    (p q) (q r) (r p) .

    Zadovoljivost navedenog iskaza moze biti odredjena tako sto bi bile ispitane svemoguce interpretacije sve moguce dodele varijablama p, q i r. Ako je u nekojinterpretaciji vrednost datog logickog iskaza true, onda je dati iskaz zadovoljiv.Za izabranu, fiksiranu interpretaciju moze se u konstantnom vremenu utvrditida li je istinitosna vrednost true. Za tri promenljive ima 2n interpretacija, pa

    je red ovog algoritma za ispitivanje zadovoljivosti logickih iskaza reda O(2n)(algoritam je eksponencijalne slozenosti). Pitanje je da li posto ji algoritam kojinavedeni problem resava u polinomijalnom vremenu.

    Definicija 4.

    Za algoritam sa ulaznom vrednoscu n kazemo da je polinomijalne slozenostiako je njegovo vreme izvrsavanja O(P(n)) gde je P(n) polinom po n. Klasupolinomijalnih algoritama oznacavamo sa P.

    Definicija 5 Pojednostavljena definicija klase NP.

    Ako neki problem moze da se predstavi u vidu najvise eksponencijalno mnogoinstanci i ako za bilo koju instancu moze da bude resen u polinomijalnom vre-menu, onda kazemo da problem pripada klasi N P.

    Definicija 6 Formalna definicija klase NP.

    Ako je U skup svih mogucih ulaznih vrednosti za neki problem odlucivanja (zakoji je potrebno dati odgovor da ili ne) i L U skup svih ulaznih vrednostiza koje je odgovor na problem potvrdan, onda L zovemo jezik koji odgovaraproblemu.

    Kazemo da nedetrministicki algoritamprepoznaje jezik L ako vazi: za zadateulazne vrednosti x, moguce je pretvoriti svaki nd-izbor koji se koristi tokom

  • 8/4/2019 40618164-p2

    27/139

    3.4 NP kompletnost 27

    izvrsavanja algoritma u stvarni izbor takav da ce algoritam prihvatiti x ako isamo ako je x

    L.

    Klasu svih problema za koje postoje nedeterministicki algoritmi cije je vremeizvrsavanja je polinomijalne slozenosti zovemo N P klasa.

    Ocigledno je da vazi P N P, ali se jos uvek ne zna3 da li vazi P = N P:

    P = N P ?

    Ako bi se pokazalo da neki problem iz klase N P nema polinomijalno resenje,onda bi to znacilo da ne vazi P = N P. Ako neki problem iz klase N P imapolinomijalno resenje, onda to jos ne znaci da vazi P = N P. Za probleme izposebne potklase klase N P (to je klasa N P-kompletnih problema) vazi da akoneki od njih ima polinomijalno resenje, onda vazi P = N P.

    Primer 3.11. Problem ispitivanja zadovoljivosti logickih iskaza (SAT) pripadaklasi N P, ali se ne zna da li pripada klasi P.

    Definicija 7.

    Za problem X kazemo da je N P-tezak problem ako je svaki N P problem poli-nomijalno svodljiv na X.

    Definicija 8.

    Za problem X kazemo da je N P-kompletan problem ako pripada klasi N P iako je N P-tezak.

    Teorema 2.

    Ako bilo koji N P-tezak problem pripada klasi P, onda vazi P = N P.

    Teorema 3.

    Problem X je N P-kompletan ako

    X pripada klasi N P Y je polinomijalno svodljiv na X, gde je Y neki N P-kompletan problem.Dakle, ako znamo da je neki problem N P-kompletan, onda na osnovu prethodne

    teoreme mozemo da pokazemo da su i svi N P-problemi na koje ga je mogucesvesti takodje N P-kompletni. Dugo se tragalo za pogodnim N P-kompletnimproblemom za koji bi moglo da se pronadje polinomijalno resenje, sto bi znaciloda vazi P = N P. Zato je bilo vazno otkriti sto vise N P-kompletnih prob-lema. Postavljalo se pitanje da li uopste postoji ijedan N P-kompletan problem(koriscenjem prethodne teoreme moze da se utvrdi da je neki problem N P-

    kompletan samo ako se za neki drugi problem vece zna da je N P-kompletan).Cook je 1971. godine dokazao (neposredno, koristeci formalizam Tjuringovemasine) da je SAT problem N P-kompletan. U godinama koje su sledile za

    3Clay Institute for Mathematical Sciences is offering a one million dollar prize for a completepolynomial-time SAT solver or a proof that such an algorithm does not exist (the P vs N Pproblem).

  • 8/4/2019 40618164-p2

    28/139

    28 3 Slozenost algoritama

    mnoge probleme je utvrdjeno da su takodje N P-kompletni (na jcesce svodjen-jem SAT problema na njih), ali ni za jedan od njih nije pokazano da pripada

    klasi P, pa se jos uvek ne zna da li vazi P = N P (mada se veruje da ne vazi).PSPACEje klasa problema koji mogu biti reseni koriscenjem memorijskog

    prostora koji je polinomijalna funkcija ulaza. Vazi N P PSPACE, ali se nezna da li vazi N P = PSPACE(rasprostranjeno je uverenje da ne vazi).

    Tokom poslednje decenije, pored napora da se dokaze da ne vazi P = N P,radi se i na ispitivanju raspodela najtezih problema u pojedinim klasama N P-kompletnih problema. Dosta se radi i na primeni novih pristupa (npr. na pri-meni genetskih algoritama) u efikasnijem resavanju nekih problema u pojedinimklasama N P-kompletnih problema.

  • 8/4/2019 40618164-p2

    29/139

    Glava 4

    Rekurzija, rekurzivnematematicke funkcije i

    primeri koriscenja rekurzije

    In mathematics and computer science, recursion specifies (or constructs) aclass of objects or methods (or an object from a certain class) by defining a fewvery simple base cases or methods (often just one), and then defining rules tobreak down complex cases into simpler cases.

    For example, the following is a recursive definition of persons ancestors:

    Ones parents are ones ancestors (base case);

    The parents of any ancestor are also ancestors of the person under con-sideration (recursion step).

    It is convenient to think that a recursive definition defines objects in termsof previously definedobjects of the class to define.

    Primer 4.1 (Recursive humour). A common joke is the following definitionofrecursion.

    Recursion See Recursion.

    This is a parody on references in dictionaries, which in some careless cases

    may lead to circular definitions. Every joke has an element of wisdom, andalso an element of misunderstanding. This is also an example of an erroneousrecursive definition of an object, the error being the absence of the terminationcondition (or lack of the initial state, if to look at it from an opposite point ofview). Newcomers to recursion are often bewildered by its apparent circularity,until they learn to appreciate that a termination condition is key.

  • 8/4/2019 40618164-p2

    30/139

    304 Rekurzija, rekurzivne matematicke funkcije i primeri koriscenja

    rekurzije

    4.1 Rekurzivne matematicke funkcije

    A function may be partly defined in terms of itself. A familiar example isthe Fibonacci sequence: F(n) = F(n 1) + F(n 2). For such a definition tobe useful, it must lead to values which are non-recursively defined, in this caseF(0) = 0 and F(1) = 1.

    Another example is factorial. Factorial of a number, say n, is equal to theproduct of all integers from 1 to n. Factorial ofn is denoted by n! = 1 2 3... nor by 1! = 1 and n! = n (n1)!, for n > 1. Eg: 10! = 1 2 3 4 5 6 7 8 9 10.

    4.2 Matematicka indukcija i rekurzija

    Now recall proofs by induction.

    Show that the theorem is true for the smallest case. This can usually bedone by inspection.

    basis

    Show that if the theorem is true for the basis cases, it can be extended toinclude the next case. If the theorem is true for the case k = n 1, showthat it is true for the case k=n.

    Inductive hypothesis assumes that the theorem is true for the casek = n 1.

    Similarity with recursive programming:

    The base case of a recursive method is the case that can be solved withouta recursive call.

    For the general (non-base) case, k = n, we assume that the recursivemethod works for k = n 1.

    Recursion is the programming equivalent of induction.

    4.3 Rekurzija u racunarstvu

    Recursion is an algorithmic technique where a function, in order to accom-plish a task, calls itself with some part of the task.

    Programs using recursion can be made to do all sorts of things, right fromcalculating the factorial of a number, to playing complex games against humanintelligence.

    In normal procedural languages, one can go about defining functions andprocedures, and calling these from the parent functions. Some languages alsoprovide the ability of a function to call itself. This is called recursion.

  • 8/4/2019 40618164-p2

    31/139

    4.4 Faktorijel 31

    4.4 Faktorijel

    The simplest program to calculate factorial of a number is a loop with aproduct variable. Instead, it is possible to give a recursive definition for Factorialas follows:

    (1) If n=1, then Factorial of n = 1

    (2) Otherwise, Factorial of n = product of n and Factorial of (n 1)

    The following code fragment depicts recursion at work.

    int factorial(int n) {

    if (n==1)

    return 1;

    else

    return n*factorial(n-1);}

    The important thing to remember when creating a recursive function is togive an end-condition. We dont want the function to keep calling itself forever.Somehow, it should know when to stop. There are many ways of doing this.One of the simplest is by means of an if condition statement, as above. In theabove example, the recursion stops when n reaches 1. In each instance of thefunction, the value of n keeps decreasing. So it ultimately reaches 1 and ends.Of course, the above function will run infinitely if the initial value of n is lessthan 1. So the function is not perfect. The n==1 condition should be changed

    to n

  • 8/4/2019 40618164-p2

    32/139

    324 Rekurzija, rekurzivne matematicke funkcije i primeri koriscenja

    rekurzije

    4.5 Obrazac trougao

    void triangle(unsigned int m, unsigned int n)

    // Precondition: m n)

    return;

    for(i=0;i

  • 8/4/2019 40618164-p2

    33/139

    4.6 Kule Hanoja 33

    4.6 Kule Hanoja

    Definition: Given three posts (towers) and n disks of decreasing sizes, movethe disks from one post to another one at a time without putting a larger disk ona smaller one. The minimum is 2n-1 moves. The ancient legendwas inventedby De Parville in 1884.

    A solution using recursion is: to move n disks from post A to post B (1)recursively move the top n-1 disks from post A to C, (2) move the n-th diskfrom A to B, and (3) recursively move the n-1 disks from C to B. A solutionusing iteration is: on odd-numbered moves, move the smallest disk clockwise.On even-numbered moves, make the single other move which is possible.

    static void tower(int n, char start, char finish, char spare) {

    if (n

  • 8/4/2019 40618164-p2

    34/139

    344 Rekurzija, rekurzivne matematicke funkcije i primeri koriscenja

    rekurzije

    4.7 Permutacije

    #include

    #define N 3 static int used[N+1]; static int p[N+1];

    void permutation(int n) ;

    main() {

    int i;

    for (i=1;iN)

    {

    for(i=1;i

  • 8/4/2019 40618164-p2

    35/139

    4.8 Particionisanje 35

    #include

    #define N 3 static int p[N+1];

    void permutation(int n) ;

    main() {

    for (i=1;i

  • 8/4/2019 40618164-p2

    36/139

    364 Rekurzija, rekurzivne matematicke funkcije i primeri koriscenja

    rekurzije

    #include

    #define N 10 static int p[N];

    void partition(unsigned int n);

    main() {

    partition(4);

    }

    void partition(unsigned int n) {

    unsigned int i;

    static unsigned int k;

    if(n==0){

    for(i=0;i0;i--)

    {

    p[k]=i;

    k++;

    partition(n-i);

    k--;

    }

    }

    4.9 Uzajamna rekurzija

    So far we have only considered recursive methods that call themselves. An-other type of recursion involves methods that cyclically call each other. Thisis known as cyclical or mutual recursion. In the following example, methods Aand B are mutually recursive.

  • 8/4/2019 40618164-p2

    37/139

    4.10 Nedostaci rekurzije 37

    void A(int n) {

    if (n

  • 8/4/2019 40618164-p2

    38/139

    384 Rekurzija, rekurzivne matematicke funkcije i primeri koriscenja

    rekurzije

    int fib(int n) {

    int f1,f2,tmp,i;

    if (n

  • 8/4/2019 40618164-p2

    39/139

    Glava 5

    Fundamentalni algoritmi

    5.1 Pretrazivanje

    Pod pretrazivanjem za dati niz elemenata (npr. data) i datu vrednost (npr. value)podrazumevamo odredivanje indeksa elementa niza koji je jednak datoj vred-nosti (tj. odredivanje indeksa i takvog da je data[i]==value).

    5.1.1 Pronalazenje karaktera u stringu

    Primer 5.1.

    /* Pronalazi poslednju poziciju karaktera c u stringu s,

    odnosno -1 ukoliko s ne sadrzi c */

    int string_last_char(char s[], char c) {

    Koristeci string_length :

    for (i = string_length(s) - 1; i>0; i--)

    if (s[i] == c)

    return i;

    return -1;

    }

    5.1.2 Odredivanje maksimuma

    Primer 5.2. Maksimum

  • 8/4/2019 40618164-p2

    40/139

    40 5 Fundamentalni algoritmi

    #include #define MAXDUZ 100

    int main() {

    /* Dimenzija niza,pomocna i brojacke promenljive */

    int n, i, max;

    /* Niz od maksimalno MAXDUZ elemenata*/

    int a[MAXDUZ];

    printf("Unesite dimenziju niza\n");

    scanf("%d",&n);

    /* n treba da bude bar 1 i najvise MAXDUZ-1 */

    /* Unos clanova niza */

    for(i=0; i

  • 8/4/2019 40618164-p2

    41/139

    5.1 Pretrazivanje 41

    Linear search can be used to search an unordered list. The more efficient

    binary search can only be used to search an ordered list.

    If more than a small number of searches are needed, it is advisable to usea more efficient data structure. One approach is to sort and then use binarysearches.

    Primer 5.3. Linearna pretraga

    #include

    /* Funkcija proverava da li se dati element x nalazi

    u datom nizu celih brojeva.Funkcija vraca poziciju u nizu na kojoj je x pronadjen

    odnosno -1 ukoliko elementa nema.

    */ int linearna_pretraga(int niz[], int br_elem, int x) {

    int i;

    for (i = 0; i

  • 8/4/2019 40618164-p2

    42/139

    42 5 Fundamentalni algoritmi

    5.1.4 Binarno pretrazivanje

    A binary search algorithm is a technique for finding a particular value ina linear array, by ruling out half of the data at each step, widely but not ex-clusively used in computer science. A binary search finds the median, makesa comparison to determine whether the desired value comes before or after it,and then searches the remaining half in the same manner. A binary search isan example of a divide and conquer algorithm (more specifically a decrease andconquer algorithm) and a dichotomic search.

    The most common application of binary search is to find a specific value ina sorted list. To cast this in the frame of the guessing game, realize that we arenow guessing the index, or numbered place, of the value in the list.

    The search begins by examining the value in the center of the list; becausethe values are sorted, it then knows whether the value occurs before or after the

    center value, and searches through the correct half in the same way.

    Primer 5.4. An example of binary search in action is a simple guessing game inwhich a player has to guess a positive integer selected by another player between1 and N, using only questions answered with yes or no. Supposing N is 16 andthe number 11 is selected, the game might proceed as follows.

    Is the number greater than 8? (Yes)Is the number greater than 12? (No)Is the number greater than 10? (Yes)Is the number greater than 11? (No)Therefore, the number must be 11. At each step, we choose a number right

    in the middle of the range of possible values for the number. For example, oncewe know the number is greater than 8, but less than or equal to 12, we know to

    choose a number in the middle of the range [9, 12] (either 10 or 11 will do).At most questions are required to determine the number, since each question

    halves the search space. Note that one less question (iteration) is required thanfor the general algorithm, since the number is constrained to a particular range.

    Primer 5.5. Even if the number were guessing can be arbitrarily large, inwhich case there is no upper bound N, we can still find the number in at mostO(log k) steps (where k is the (unknown) selected number) by first finding anupper bound by repeated doubling. For example, if the number were 11, we coulduse the following sequence of guesses to find it:

    Is the number greater than 1? (Yes)Is the number greater than 2? (Yes)Is the number greater than 4? (Yes)

    Is the number greater than 8? (Yes)Is the number greater than 16? (No, N=16, proceed as above) ( We know

    the number greater than 8 )Is the number greater than 12? (No)Is the number greater than 10? (Yes)Is the number greater than 11? (No)

  • 8/4/2019 40618164-p2

    43/139

    5.1 Pretrazivanje 43

    Primer 5.6. As one simple application, in revision control systems, it is possi-

    ble to use a binary search to see in which revision a piece of content was addedto a file. We simply do a binary search through the entire version history; ifthe content is not present in a particular version, it appeared later, while if it ispresent it appeared at that version or sooner. This is far quicker than checkingevery difference.

    Primer 5.7. There are many occasions unrelated to computers when a binarychop is the quickest way to isolate a solution we seek. In troubleshooting asingle problem with many possible causes, we can change half the suspects, seeif the problem remains and deduce in which half the culprit is; change half theremaining suspects, and so on.

    Primer 5.8. Binarno pretrazivanje

  • 8/4/2019 40618164-p2

    44/139

    44 5 Fundamentalni algoritmi

    #include

    #define MAXDUZ 100

    int main() {

    /* Dimenzija niza,pomocna i brojacke promenljive */

    int n,pom,i,j;

    /* Niz od maksimalno MAXDUZ elemenata*/

    int a[MAXDUZ];

    /* Elemet koji se trazi i pozicija

    na kojoj se nalazi, ukoliko je u nizu*/

    int x, pozicija;

    /* Pomocne promenljive za pretragu */int donji, gornji, srednji;

    printf("Unsite dimenziju niza\n");

    scanf("%d",&n);

    /* Unos clanova niza */

    for(i=0; i

  • 8/4/2019 40618164-p2

    45/139

    5.1 Pretrazivanje 45

    Primer 5.9.

  • 8/4/2019 40618164-p2

    46/139

    46 5 Fundamentalni algoritmi

    /* Binarna pretraga niza celih brojeva - rekurzivna verzija*/

    #include

    /* Funkcija proverava da li se element x javlja unutar niza

    celih brojeva a.

    Funkcija vraca poziciju na kojoj je element nadjen odnosno

    -1 ako ga nema.

    !!!!! VAZNO !!!!!

    Pretpostavka je da je niz a uredjen po velicini

    */

    int binary_search(int a[], int l, int d, int x) {

    /* Ukoliko je interval prazan, elementa nema */

    if (l > d)return -1;

    /* Srednja pozicija intervala [l, d] */

    int s = (l+d)/2;

    /* Ispitujemo odnos x-a i srednjeg elementa */

    if (x == a[s])

    return s; /* Element je pronadjen */

    else if (x < a[s])

    /* Pretrazujemo interval [l, s-1] */

    return binary_search(a, l, s-1, x);

    else

    /* Pretrazujemo interval [s+1, d] */

    return binary_search(a, s+1, d, x);

    }

    main() {

    int a[] = {3, 5, 7, 9, 11, 13, 15};

    int x;

    int i;

    printf("Unesi element kojega trazimo : ");

    scanf("%d",&x);

    i = binary_search(a, 0, sizeof(a)/sizeof(int)-1, x);

    if (i==-1)

    printf("Elementa %d nema\n", x);

    else

    printf("Pronadjen na poziciji %d\n", i);

    }

  • 8/4/2019 40618164-p2

    47/139

    5.2 Sortiranje 47

    Here is code which determines the index of a given value in a sorted list a

    between indices left and right (if the value is not found, -1 is returned):int binarySearch(int *data, int value, int left, int right) {

    while (left

  • 8/4/2019 40618164-p2

    48/139

    48 5 Fundamentalni algoritmi

    Below are listed seven of the most common sorting algorithms:

    Bubble sort Heap sort Insertion sort Merge sort Quick sort Selection sort Shell sortNeki od algoritama za sortiranje rade in-place (u mestu), tj. sortiraju zadate

    elemente bez koriscenja dodatnog niza. Drugi algoritmi zahtevaju koriscenjepomocnog niza.

    The common sorting algorithms can be divided into two classes by the com-plexity of their algorithms. Algorithmic complexity is a complex subject thatwould take too much time to explain here, but suffice it to say that theres adirect correlation between the complexity of an algorithm and its relative effi-ciency. Algorithmic complexity is generally written in a form known as Big-Onotation, where the O represents the complexity of the algorithm and a value nrepresents the size of the set the algorithm is run against. (videti glavu ??).

    For example, O(n) means that an algorithm has a linear complexity. Inother words, it takes ten times longer to operate on a set of 100 items than itdoes on a set of 10 items (10 10 = 100). If the complexity was O(n2) (quadraticcomplexity), then it would take 100 times longer to operate on a set of 100 itemsthan it does on a set of 10 items.

    The two classes of sorting algorithms are O(n2), which includes the bubble,insertion, selection, and shell sorts; and O(n log n) which includes the heap,merge, and quick sorts.

    In addition to algorithmic complexity, the speed of the various sorts canbe compared with empirical data. Since the speed of a sort can vary greatlydepending on what data set it sorts, accurate empirical results require severalruns of the sort be made and the results averaged together. The empirical datagiven is the average of a hundred runs against random data sets on a single-user250MHz UltraSPARC II. The run times on your system will almost certainlyvary from these results, but the relative speeds should be the same - the selectionsort runs in roughly half the time of the bubble sort on the UltraSPARC II, and

    it should run in roughly half the time on whatever system you use as well.These empirical efficiency graphs (5.1 and 5.1) are kind of like golf - thelowest line is the best. Keep in mind that bestdepends on your situation -the quick sort may look like the fastest sort, but using it to sort a list of 20items is kind of like going after a fly with a sledgehammer.

    As the graph 5.1 pretty plainly shows, the bubble sort is grossly inefficient,and the shell sort blows it out of the water. Notice that the first horizontal line

  • 8/4/2019 40618164-p2

    49/139

    5.2 Sortiranje 49

    Slika 5.1: Rezultati za algoritme sortiranja slozenosti O(n2)

    Slika 5.2: Rezultati za algoritme sortiranja slozenosti O(n log n)

  • 8/4/2019 40618164-p2

    50/139

    50 5 Fundamentalni algoritmi

    in the plot area is 100 seconds - these arent sorts that you want to use for huge

    amounts of data in an interactive application. Even using the shell sort, usersare going to be twiddling their thumbs if you try to sort much more than 10,000data items.

    On the bright side, all of these algorithms are incredibly simple (with thepossible exception of the shell sort). For quick test programs, rapid prototypes,or internal-use software theyre not bad choices unless you really think you needsplit-second efficiency.

    Speaking of split-second efficiency, the O(n log n) sorts (slika 5.2) are whereits at. Notice that the time on this graph is measured in tenths of seconds,instead hundreds of seconds like the O(n2) graph.

    But as with everything else in the real world, there are trade-offs. Thesealgorithms are blazingly fast, but that speed comes at the cost of complexity.

    Recursion, advanced data structures, multiple arrays - these algorithms makeextensive use of those nasty things.

    In the end, the important thing is to pick the sorting algorithm that youthink is appropriate for the task at hand. You should be able to use the sourcecode on this site as a black boxif you need to - you can just use it, withoutunderstanding how it works. Obviously taking the time to understand how thealgorithm you choose works is preferable, but time constraints are a fact of life.

    Zna se da postoje algoritmi za sortiranje koji su slozenosti O(n log n), ali zasada se ne zna da li postoji algoritam manjeg reda: za sada nije otkriven takavalgoritam niti je dokazano da on ne moze da postoji.

    5.2.1 Sortiranje selekcijom

    The selection sort works by selecting the smallest unsorted item remainingin the list, and then swapping it with the item in the next position to be filled.The selection sort has a complexity of O(n2).

    Pros: Simple and easy to implement.

    Cons: Inefficient for large lists, so similar to the more efficient insertion sortthat the insertion sort should be used in its place.

    The selection sort is in the group of n2 sorts. It yields a 60% performanceimprovement over the bubble sort, but the insertion sort is over twice as fastas the bubble sort and is just as easy to implement as the selection sort. In

    short, there really isnt any reason to use the selection sort - use the insertionsort instead.

    If you really want to use the selection sort for some reason, try to avoidsorting lists of more than a 1000 items with it or repetitively sorting lists ofmore than a couple hundred items.

    Below is the basic selection sort algorithm.

  • 8/4/2019 40618164-p2

    51/139

    5.2 Sortiranje 51

    void selectionSort(int numbers[], int array_size) {

    int i, j;int min, temp;

    for (i = 0; i < array_size-1; i++)

    {

    min = i;

    for (j = i+1; j < array_size; j++)

    {

    if (numbers[j] < numbers[min])

    min = j;

    }

    temp = numbers[i];

    numbers[i] = numbers[min];

    numbers[min] = temp;}

    }

    5.2.2 Sortiranje umetanjem

    The insertion sort works just like its name suggests - it inserts each iteminto its proper place in the final list. The simplest implementation of this

    requires two list structures - the source list and the list into which sorted itemsare inserted. To save memory, most implementations use an in-place sort thatworks by moving the current item past the already sorted items and repeatedlyswapping it with the preceding item until it is in place.

    Like the bubble sort, the insertion sort has a complexity of O(n2). Althoughit has the same complexity, the insertion sort is a little over twice as efficient asthe bubble sort.

    Pros: Relatively simple and easy to implement.

    Cons: Inefficient for large lists.

    The insertion sort is a good middle-of-the-road choice for sorting lists of a

    few thousand items or less. The algorithm is significantly simpler than the shellsort, with only a small trade-off in efficiency. At the same time, the insertion sortis over twice as fast as the bubble sort and almost 40% faster than the selectionsort. The insertion sort shouldnt be used for sorting lists larger than a couplethousand items or repetitive sorting of lists larger than a couple hundred items.

    Below is the basic insertion sort algorithm.

  • 8/4/2019 40618164-p2

    52/139

    52 5 Fundamentalni algoritmi

    void insertionSort(int numbers[], int array_size) {

    int i, j, index;

    for (i=1; i < array_size; i++)

    {

    index = numbers[i];

    j = i ;

    while ((j > 0) && (numbers[j-1] > index))

    {

    numbers[j] = numbers[j-1];

    j = j - 1;

    }

    numbers[j] = index;

    }

    }

    5.2.3 Babl sortiranje

    The bubble sort is the oldest and simplest sort in use. Unfortunately, itsalso the slowest.

    The bubble sort works by comparing each item in the list with the item nextto it, and swapping them if required. The algorithm repeats this process untilit makes a pass all the way through the list without swapping any items (inother words, all items are in the correct order). This causes larger values tobubbleto the end of the list while smaller values sinktowards the beginningof the list.

    The bubble sort is generally considered to be the most inefficient sorting algo-rithm in common usage. Under best-case conditions (the list is already sorted),the bubble sort can approach a constant O(n) level of complexity. General-caseis an abysmal O(n2).

    While the insertion, selection, and shell sorts also have O(n2) complexities,they are significantly more efficient than the bubble sort.

    Pros: Simplicity and ease of implementation.

    Cons: Horribly inefficient.

    A fair number of algorithm purists (which means theyve probably neverwritten software for a living) claim that the bubble sort should never be usedfor any reason. Realistically, there isnt a noticeable performance differencebetween the various sorts for 100 items or less, and the simplicity of the bubblesort makes it attractive. The bubble sort shouldnt be used for repetitive sortsor sorts of more than a couple hundred items.

    Below is the basic bubble sort algorithm.

  • 8/4/2019 40618164-p2

    53/139

    5.2 Sortiranje 53

    void bubbleSort(int numbers[], int array_size) {

    int i, j, temp;

    for (i = (array_size - 1); i >= 0; i--)

    {

    for (j = 1; j numbers[j])

    {

    temp = numbers[j-1];

    numbers[j-1] = numbers[j];

    numbers[j] = temp;

    }

    }

    }}

    5.2.4 Quick sort

    The quick sort is an in-place, divide-and-conquer, massively recursive sort.As a normal person would say, its essentially a faster in-place version of themerge sort. The quick sort algorithm is simple in theory, but very difficult toput into code (computer scientists tied themselves into knots for years trying towrite a practical implementation of the algorithm, and it still has that effect onuniversity students).

    The recursive algorithm consists of four steps (which closely resemble the

    merge sort):

    1. If there are one or less elements in the array to be sorted, return immedi-ately.

    2. Pick an element in the array to serve as a pivotpoint. (Usually theleft-most element in the array is used.)

    3. Split the array into two parts - one with elements larger than the pivotand the other with elements smaller than the pivot.

    4. Recursively repeat the algorithm for both halves of the original array.

    The efficiency of the algorithm is majorly impacted by which element is

    choosen as the pivot point. The worst-case efficiency of the quick sort, O(n2

    ),occurs when the list is sorted and the left-most element is chosen. Randomlychoosing a pivot point rather than using the left-most element is recommendedif the data to be sorted isnt random. As long as the pivot point is chosenrandomly, the quick sort has an algorithmic complexity of O(n log n).

    Pros: Extremely fast.Cons: Very complex algorithm, massively recursive.

  • 8/4/2019 40618164-p2

    54/139

    54 5 Fundamentalni algoritmi

    The quick sort is by far the fastest of the common sorting algorithms. Its

    possible to write a special-purpose sorting algorithm that can beat the quicksort for some data sets, but for general-case sorting there isnt anything faster.

    As soon as students figure this out, their immediate implulse is to use the

    quick sort for everything - after all, faster is better, right? Its important toresist this urge - the quick sort isnt always the best choice. As mentionedearlier, its massively recursive (which means that for very large sorts, you canrun the system out of stack space pretty easily). Its also a complex algorithm- a little too complex to make it practical for a one-time sort of 25 items, forexample.

    With that said, in most cases the quick sort is the best choice if speed isimportant (and it almost always is). Use it for repetitive sorting, sorting ofmedium to large lists, and as a default choice when youre not really sure whichsorting algorithm to use. Ironically, the quick sort has horrible efficiency whenoperating on lists that are mostly sorted in either forward or reverse order -avoid it in those situations.

    Below is the basic quick sort algorithm.

  • 8/4/2019 40618164-p2

    55/139

    5.2 Sortiranje 55

    void quickSort(int numbers[], int array_size) {

    q_sort(numbers, 0, array_size - 1);}

    void q_sort(int numbers[], int left, int right) {

    int pivot, l_hold, r_hold;

    l_hold = left;

    r_hold = right;

    pivot = numbers[left];

    while (left < right)

    {

    while ((numbers[right] >= pivot) && (left < right))

    right--;if (left != right)

    {

    numbers[left] = numbers[right];

    left++;

    }

    while ((numbers[left] pivot)

    q_sort(numbers, pivot+1, right);

    }

    Primer 5.10. Ako se uzme da za vreme izvrsavanja T(n) algoritma quicksort

    vazi:T(n) = 2T(n/2) + n ,

    onda na osnovu teoreme 1 vazi T(n) = O(n log n). Medjutim, u najgoremslucaju za quicksort vazi T(n) = T(n 1) + n i tada je T(n) = O(n2). Ipak,za ovaj algoritam cesto se najgori slucaj smatra retkim (i zanemaruje), pa seobicno uzima da je slozenost algoritma quicksort O(n log n).

  • 8/4/2019 40618164-p2

    56/139

    56 5 Fundamentalni algoritmi

    5.2.5 Koriscenje sistemske implementacije quick sort-a

    Funkcija qsort izvrsava quick sort:

    void qsort( void *base, size_t num, size_t width,

    int (*compare )(const void *elem1, const void *elem2 ) );

    Zahteva zaaglavlje: .

    Parameters:

    base: Start of target array

    num: Array size in elements

    width: Element size in bytes

    compare: Comparison function

    elem1, elem2: Pointers to two array elements

    The qsort function implements a quick-sort algorithm to sort an array ofnum elements, each of width bytes. The argument base is a pointer to the baseof the array to be sorted. qsort overwrites this array with the sorted elements.The argument compare is a pointer to a user-supplied routine that comparestwo array elements and returns a value specifying their relationship. qsort calls

    the compare routine one or more times during the sort, passing pointers to twoarray elements on each call:

    compare( (void *) elem1, (void *) elem2 );

    Return Value Description: the routine must compare the elements, thenreturn one of the following values:

    < 0 elem1 less than elem2

    0 elem1 equivalent to elem2

    > 0 elem1 greater than elem2

    The array is sorted in increasing order, as defined by the comparison func-tion. To sort an array in decreasing order, reverse the sense of greater thanandless thanin the comparison function.

    Primer 5.11.

  • 8/4/2019 40618164-p2

    57/139

    5.2 Sortiranje 57

    #include #include

    int poredi_brojeve(const void *i1, const void *i2) {

    if (*(int*)i1 < *(int*)i2)

    return -1;

    else if (*(int*)i1 > *(int*)i2)

    return 1;

    else

    return 0;

    }

    main() {

    int i,niz[10];

    for(i=0;i

  • 8/4/2019 40618164-p2

    58/139

    58 5 Fundamentalni algoritmi

    /* QSORT.C: This program reads the command-line

    * parameters and uses qsort to sort them. It* then displays the sorted arguments.

    */

    #include #include #include

    int compare( const void *arg1, const void *arg2 );

    void main( int argc, char **argv ) {

    int i;

    /* Eliminate argv[0] from sort: */

    argv++;

    argc--;

    /* Sort remaining args using Quicksort algorithm: */

    qsort( (void *)argv, (size_t)argc, sizeof( char * ), compare );

    /* Output sorted list: */

    for( i = 0; i < argc; ++i )

    printf( "%s ", argv[i] );

    printf( "\n" );

    }

    int compare( const void *arg1, const void *arg2 ) {

    /* Compare strings: */

    return strcmp( *(char**)arg1, *(char**)arg2);

    }

    Output:

    [C:\code]qsort every good boy deserves favor boy deserves every favor

    good

    5.3 Jednostavni numericki algoritmi

    5.3.1 Stepenovanje

    Primer 5.13. Izracunavanje nk

  • 8/4/2019 40618164-p2

    59/139

    5.3 Jednostavni numericki algoritmi 59

    /* n>=0, k>=0 */ int stepen_sporo(int n, int k) {

    int i,m=1;

    for(int i=0;i=0, k>=0 */ int stepen_brzo(int n, int k) {

    int m;

    if (k==0)

    return 1;

    if (k%2)

    {

    m = stepen_brzo(n,(k-1)/2);

    return n*m*m;

    }

    else

    {

    m = stepen_brzo(n,k/2);

    return m*m;

    }

    }

    5.3.2 Izracunavanje vrednosti polinoma

    Any polynomial in the form

    P(x) = axn + bxn1 + . . . d x + e

    can be expressed in a form requiring fewer operations. For example:

    P(x) = ax3 + bx2 + cx + d = x(x(ax + b) + c) + d

    5.3.3 Zagradivanje nula funkcije

    We will say that a root is bracketed in the interval (a, b) if f(a) and f(b) haveopposite signs. If the function is continuous, then at least one root must lie inthat interval (the intermediate value theorem). If the function is discontinuous,but bounded, then instead of a root there might be a step discontinuity whichcrosses zero. For numerical purposes, that might as well be a root, since thebehavior is indistinguishable from the case of a continuous function whose zerocrossing occurs in between two adjacentfloating-point numbers in a machines

  • 8/4/2019 40618164-p2

    60/139

    60 5 Fundamentalni algoritmi

    finite-precision representation. Only for functions with singularities is there the

    possibility that a bracketed root is not really there, as for example

    f(x) =1

    x c

    Some root-finding algorithms (e.g., bisection) will readily converge to c. Luckilythere is not much possibility of your mistaking c, or any number x close to it,for a root, since mere evaluation of |f(x)| will give a very large, rather than avery small, result. If you are given a function in a black box, there is no sureway of bracketing its roots, or of even determining that it has roots.

    #include #define FACTOR 1.6 #define NTRY 50

    /* Given a function func and an initial guessed range */ /* x1

    to x2, the routine expands the range geometrically */ /* until a

    root is bracketed by the returned values x1 and */ /* x2 (in which

    case zbrac returns 1) or until the range */ /*becomes

    unacceptably large (in which case zbrac returns 0).*/

    int zbrac(float (*func)(float), float *x1, float *x2) {

    int j;

    float f1,f2;

    if (*x1 == *x2)

    {

    printf("Bad initial range in zbrac");

    return -1;

    }

    f1=(*func)(*x1);

    f2=(*func)(*x2);

    for (j=1;j

  • 8/4/2019 40618164-p2

    61/139

    5.3 Jednostavni numericki algoritmi 61

    float funkcija1(float x) {

    return x*x*x-2;}

    main() {

    float x1,x2;

    x1=5; x2=10;

    printf("x1=%f, x2=%f\n",x1,x2);

    if(zbrac(funkcija1, &x1, &x2)==1)

    printf("x1=%f, x2=%f\n",x1,x2);

    }

    dobija se rezultat:

    x1=5.000000, x2=10.000000 x1=-3.000000, x2=10.000000

    5.3.4 Odredivanje nula funkcije

    Once we know that an interval contains a root, several classical proceduresare available to refine it. These proceed with varying degrees of speed andsureness towards the answer. Unfortunately, the methods that are guaranteedto converge plod along most slowly, while those that rush to the solution in thebest cases can also dash rapidly to infinity without warning if measures are nottaken to avoid such behavior. The bisection method is one that cannot fail. Itis thus not to be sneered at as a method for otherwise badly behaved problems.The idea is simple. Over some interval the function is known to pass throughzero because it changes sign. Evaluate the function at the intervals midpointand examine its sign. Use the midpoint to replace whichever limit has the samesign. After each iteration the bounds containing the root decrease by a factorof two. If after n iterations the root is known to be within an interval of sizen, then after the next iteration it will be bracketed within an interval of size

    n+1 = n/2

    neither more nor less. Thus, we know in advance the number of iterationsrequired to achieve a given tolerance in the solution,

    n = log20

    where 0 is the size of the initially bracketing interval, is the desired endingtolerance.

    Bisection must succeed. If the interval happens to contain two or moreroots, bisection will find one of them. If the interval contains no roots andmerely straddles a singularity, it will converge on the singularity.

  • 8/4/2019 40618164-p2

    62/139

    62 5 Fundamentalni algoritmi

    #include #define JMAX 40 /* Maximum allowed number of

    bisections. */

    /* Using bisection, find the root of a function func */ /* known

    to lie between x1 and x2. The root, returned */ /* as rtbis, will

    be refined until its accuracy is +/-acc.*/

    float rtbis(float (*func)(float), float x1, float x2, float xacc) {

    int j;

    float dx,f,fmid,xmid,rtb;

    f=(*func)(x1);

    fmid=(*func)(x2);

    if (f*fmid >= 0.0)

    {

    printf("Root must be bracketed for bisection in rtbis");return 0.0;

    }

    rtb = f < 0.0 ? (dx=x2-x1,x1) : (dx=x1-x2,x2); /* Orient the search so */

    /* that f>0 lies at x+dx. */

    for (j=1;j

  • 8/4/2019 40618164-p2

    63/139

    5.3 Jednostavni numericki algoritmi 63

    root = 1.259872

    Zaista, (1.259872)3 1.9997664 2.

  • 8/4/2019 40618164-p2

    64/139

    64 5 Fundamentalni algoritmi

  • 8/4/2019 40618164-p2

    65/139

    Deo II

    Dinamicki objekti

  • 8/4/2019 40618164-p2

    66/139

  • 8/4/2019 40618164-p2

    67/139

    Glava 6

    Pokazivaci i adresna

    aritmetika

    6.1 Adresna aritmetika

    If p is a pointer to some element of an array, then p++ increments p to pointto the next element, and p+=i increments it to point i elements beyond where itcurrently does. These and similar constructions are the simples forms of pointeror address arithmetic. C is consistent and regular in its approach to addressarithmetic; its integration of pointers, arrays, and address arithmetic is one ofthe strengths of the language.

    Pointers and integers are not interchangeable.

    Primer 6.1.

    int i, *a, *b;

    ...

    a = b; /* ispravno */

    *a = i; /* ispravno */

    i = a; /* neispravno */

    i = (int)a; /* ispravno, ali izbegavat