Professional Documents
Culture Documents
Laboratorija I (1) Dfsa
Laboratorija I (1) Dfsa
-Mari-Janii;
-Prezentacije (moodle);
-Milo Tomaevi : Algoritmi i strukture podataka;
-Internet;
Plan aktivnosti u semestru:
Od 1.do 8.sedmice P/A/L, u 9.sedmici 1.kolokvijum. Od 10.do 14.sedmice P/A/L, a u
15.sedmici 2.kolokvijum (6.juni).
Ocjenjivanje:
-Laboratorija:
-Kolokvijum I:
-Kolokvijum II:
-Zavrsni ispit:
0-15 bodova;
0-20 bodova (mora biti preko 40%);
0-25 bodova (mora biti preko 40%);
0-40 bodova (mora biti preko 50%);
Predavanje I:
Rekurzija:
Rekurzivna funkcija je funkcija koja poziva samu sebe. 2 su osnovna elementa svake
rekurzije:
1) Bazni ili osnovni sluaj (moe imati vise osnovnih sluaja)(zaustavljanje
funkcije);
2) Rekurzivni korak (nain na koji se funkcija iznova poziva, tako to onaj
sloeniji problem svodi na rjeavanje jednostavnijeg);
Primjer:
x^n={1, n=0 (bazni ili osnovni sluaj);
Primjer, rekurzivna definicija faktorijela:
n!=1*2**n (nerekurzivno ili iterativno)
n!={1, n<=1; n*(n-1)!, n>1
Primjer, rekurentna formula:
Xn=2*Xn-1+3*Xn-2, i bitno je koliko je X0 i X1
Implementacija u C:
Iz primjera x^n:
double stepenovanje(double x, int n)
{
if (n==0)
return 1;
else
return x*stepenovanje(x,n-1);
}
Program:
#include <stdio.h>
double stepenovanje(double x, int n)
{
if (n==0)
return 1;
else
return x*stepenovanje(x,n-1);
}
int main ()
{
printf(2^3= %.2lf\n, stepenovanje(2,3));
return 0;
}
Nain rada prethodno napisane funkcije:
stepenovanje (2,3)
x=2
n=3 > 0 => return 2*stepenovanje(2,2);
Zatim
x=2
n=2 > 0 => return 2*stepenovanje(2,1);
Zatim
x=2
n=1 > 0 => return 2*stepenovanje(2,0);
Zatim
x=2
n=0 => return 1 ;
Proces rada je da se return zadnji vraa prethodnom, redom 2*1, zatim 2*2*1, zatim 2*2*2*1
i to je rezultat.
Proces izvravanja rekurzije:
Sve sto vai za funkcije vai i za rekurzivne. Izvrsni kod je u segment kodu.
Iz prethodnog primjera:
stepenovanje (2,3)
Odozgoo raste stek
Na steku se ostavlja 2 i 3(koja je konvencija pozivanja, zavisi redoslijed njihovog stavljanja
na stek.
Na stek se prvo stavlja 3, odnosno n. Zatim se na stek stavlja 2, odnosno x. Zatim se stavlja
adresa povratka u main() Ovo do sada je kada se udje u funkciju stepenovanje. Ovaj dio
do sada napisan je stek okvir prve funkcije za stepenovanje.
Zatim ide poziv funkcije stepenovanje (2,2). Ide n, zatim x, zatim adresa povratka u
stepenovanje. Ovo je stek okvir 2.stepenovanje funkcije.
I tako dalje. Vracanje poslednje funkcije u prethodnu ona se skida sa steka.
Zatim poslednja funkcija vraca rezultat u main() i brise se.
Heap, dinamika memorija
Data segment stringovi, statike promjenjive
Main() stepenovanje (njihov kod), segment koda Adrese odozdo rastu
1) Zato rekurzija mora da konvergira?
Mora da ide prema jednostavnom sluaju. Ona na stek ostavlja svaki poziv funkcije,
sve dok se ne potroi, odnosno dok ima steka, za razliku od beskonane petlje koja ne
troi memoriju, samo procesorsko vrijeme (for (;;);). Znai pro
2) Zato mora da postoji sliaj za zaustavljanje rekurzije?
Mora da prekine da bi se omoguilo novo zauzimanje steka.
Dobre i loe strane rekurzije:
Kod je kratak, lako se ita, svodi se program na jednostavnije, lako se odrava i lako se
ispravlja. Loe strane su cijena poziva (svaki novi poziv nove funkcije je troenje memorije
steka i usporavanje (ako na stek treba da iskopirate argumente... mi smo time potrosili
vrijeme, nekoliko memorijskih ciklusa). Dolazi do poveanja vremenske i prostorne
sloenosti. Jo jedna strana loa, a to su suvina izraunavanja ili izvravanja. Moe se desiti
da kroz izvrsavanje desi da ste vec neto izvravali.
Primjer suvinog izvravanja, Fibonaijev niz: 1 1 2 3 5 8 13 21 34...
f(n)={1, n<=2; f(n-1)+f(n-2), n>2
Implementacija prethodne rekurzije:
int fibonaci(int n)
{
if (n<=2) return 1;
else
return fibonaci(n-1)+fibonaci(n-2);
}
Ako hoemo da nadjemo 4.clan:
fibonaci(2)+fibonaci(3)
n=2 => return 1; n=3 => fibonaci(1)+fibonaci(2)
n=1 => return 1; n=2 => return 1;
Tehnike za eliminaciju suvinih izvravanja:
1) Memoizacija je tehnika kojom se u odgovarajucoj strukturi podataka pamte
vrijednosti za razliite elemente. Odnosno ona za odgovarajue vrijednosti
argumenata provjerava da li ima izraunato ve. Ako postoji, vraa taj rezultat, ako
ne, rauna.
Modifikacija Fibonaijevog niza sa memoizacijom:
int fibonaci(int n)
{
static int memo[MAX]={0,1,1};
if (memo[n]!=0) return memo[n];
else
return memo[n]=fibonaci(n-1)+fibonaci(n-2);
}
Hanojske kule:
prebaci(n, sa, na, peko);
void prebaci(int n, char SA, char NA, char PREKO)
{
if (n==1)
printf(%c -> %c\n, SA, NA);
else
{
prebaci(n-1,SA , PREKO, NA);
printf(%c -> %c\n, SA, NA);
prebaci(n-1, PREKO, NA, SA);
}
}
Predavanja II
Eliminacija rekurzije:
Repna rekurzija: situacija kada rezultat koji se dobije iz nekog rek. poziva, a da nakon njega
nema dodanih operacija vezanih za njega.
double stepenovanje (double x, int n)
{
if (n == 0)
return 1;
else
return x*stepenovanje(x, n-1);
} //Ovakva rekurzija nije repna, npr.
void f(tip arg) // neka rekurzivna funkcija
{
pocetak:
if (uslov_za_osnovni_slucaj)
osnovni_slucaj;
else
f(novi_arg); ID= >{ arg=novi_arg; goto pocetak;}
}//repna rekurzija
#include <stdio.h>
#include <stdarg.h>
int zbir (int n, )
{
int i, s=0;
va_list args;
va_start (args, n);//va_start(args, ime posljednjeg obaveznog arg)
for ( i = 0; i <= n; i++)
s += va_arg (args, int);
va_end(args);
return s;
}
int main()
{
printf(Zbir (10,20) =%d\n, zbir(2,10,20);
printf(zbir(10,20,30=%d\n, zbir(3,10,20,30);
return 0;
}
STEK raste prema
dole
20
10 =
va_star
t (args,n)
2=n
Return adress u
main (vraanje
adrese povratka)
Kada zavri , sve se
brie.
Pokazivai na funkcije:
Do sada smo imali void *malloc (size_t n);
Deklaracija:
tip (*) (deklaracija argumenata ID= lista tipova)
DATOTEKE
1) otvaranje datoteke,
2) pristup datoteci (itanje iz datoteke, upisivanje u datoteku i pozicioniranje),
3) provjera statusa (provjera statusa pokazivaa, da li je kraj, da li je greka, koja je
pozicija pokazivaa),
4) zatvaranje datoteke;
Otvaranje datoteke:
Koristi se funkcija FILE *fopen (char *ime, char *mode), (vraa pointer na FILE).
*mode je reim rada. Osnovni reim rada/otvaranaj su: r (itanje iz fajla), w (pisanje u
fajl), a (append, ako fajl postoji bie otvoren, i pokaziva e biti na mjestu poslije svega u
datoteci). Postoje i kombinovani reimi r+ (ima mogunost itanja, ali moe i pisanje),
w+ (podrazumjeva se itanje, ali moe i pisanje), a+ (dopisivanje, a moe i itanje (s
poetka)).
Rad sa binarnim datotekama: SVE VAI ISTO KAO I ZA TEKSTUALNO, samo se doda b
na kraj mode.
FILE *fp;
fp = fopen(ime, rb); //otvaranje datoteke (binarne) u reimu za itanje
Tipino za otvaranje:
if (fp = fopen(ime, rb)) != NULL)
{
//uspjesno otvaranje
}
else
printf(Fajl ne moze da se otvori);
itanje i pisanje iz/u tekstualnih datoteka
itati i pisati se moe po jedan znak ili niz znakova.
itanje jednog znaka: int fgetc (FILE *dat).
itanje stringa: char fgets(char *s, int n (maksimalan broj znakova u tom stringu, uklj. nulu
ili e se itati do kraja linije),FILE *dat);
Ima mogunost i formatiranog itanja: int fscanf(FILE *dat, const char *format, );
Upis u datoteku:
Posoji mogunost upisivanja jednog ili vie znakova.
Upis jednog znaka: int fputc (int znak, FILE *dat);
Upis stringa: int fputs(char *s, FILE *dat);
Ima formatiran upis: int fprintf(FILE *dat, const char *format, ...);
Zatvaranje datoteke: int fclose(FILE *dat);
Primjer:
#include <stdio.h>
int main()
{
FILE *fp;
if (fp == fopen(text.txt, w));
{
for (int i = 0; i < 20; i++)
fputc(A+i, fp);
fclose(fp);
SORTIRANJE:
Shell-sort
Gleda ekvidistantne elemente, poredi, i mjenja ako ima potrebe. Zatim taj interval polovi
Primjer:
h=n/2=4
64178532
Prvi prolaz:
64178532
Drugi prolaz:
64178532
Trei prolaz:
64178532
etvrti prolaz:
64128537
h = h / 2 = 2;
Imamo:
64128537
Prvi prolaz:
14628537
Drugi prolaz:
12648537
Trei prolaz:
12648537
etvrti prolaz:
12648537
Peti prolaz:
12643587
esti prolaz:
12643587
h = h / 2 = 1;
Imamo:
12643587
Prvi prolaz:
12643587
Drugi prolaz:
...
12345678
Source code:
void ShellSort(<tip> niz[], int n)
{
int I, j, h;
for (h = n / 2; h >0; h/=2)
{
int j;
for (I = h; i < n; i ++)
{
<tip> pom = niz[i];
for ( j = I; j>=h && pom < niz[j-h]; j -=h;
niz[j] = niz[j h];
niz[j] = pom;
}}}
Analiza sloenosti:
T(n) = O (n^2)
najbolje.
Npr, u zavisnosti od izbora h:
Hibbard (1, 3, 7 2^k 1) O(n^(1.5))
Sechwick (1 5 19 41 119) O (n^1.33)
Merge-sort:
-rekurzivni algoritam (Devide and conquer);
Primjer:
6 4 1 7 8 5 3 2 polazna kolekcija
Dijeli na dvije kolekcije: 6 4 1 7 I 8 5 3 2
Zatim 6 4 I 1 7 I 8 5 I 3 2
Zatim ponaosob svaki.
Zatim se sparuju:
46 I 1 7 I 5 8 I 2 3
Zatim se sparuju:
1467I2358
Zatim:
12345678
void MergeSort (<tip> niz[], int begin, int end)
{
if (begin < end)
{
int sredina = (begin+end) / 2;
MergeSort(niz, begin, sredina);
MergeSort(niz, sredina + 1, end);
merge(niz, begin, sredina, end); //Spaja do sredine i od sredine
}
}
umjesto merge:
<tip> pom[end begin +1];
int I = begin, j = sredina + 1, k = 0;
while (I <= sredina && j <= end)
{
pom [k++] = (niz[i] < niz[j])?niz[i++] : niz[j++];
}
while (I <= sredina)
pom[k ++ ] = niz[I ++];
while (j <= end) pom[k++] = niz[j ++];
for (I = 0; I < len; I ++)
niz[begin + i] = pom [i];
Analiza sloenosti:
T(n) = O(n*log(n));
linearno-logaritamska sloenost;
Bublle-sort:
Primjer:
6417532
Prvi proglaz:
4617532
4167532
4167532
4165732
4165372
4165327
Drugi prolaz:
1465327
1465327
1456327
1453627
1453267
Trei prolaz:
1453267
1453267
1435267
1432567
etvrti prolaz:
1432567
1342567
1324567
Peti prolaz:
1324567
1234567
bubble select insert shell (poredak sloenosti);
Analiza sloenosti:
bubble O(n^2);
void BubbleSort (<tip> niz[], int n)
{
int I, j;
for ( I = 0; I < n 1; I ++ ) /* moglo bi se uslovno vidjeti da li je u medjuvremenu
sortirano*/
for ( j = I; j < n 1 - i; j++)
if (niz[j+1] < niz[j])
{
<tip> pom = niz[j];
niz[j] = niz[j+1];
nizp[j+1] = pom;
}
}
PRETRAIVANJE
niz[i] = pom;
return 0;
}
return -1;
}
Binarno pretraivanje (pretraivanje polovljenjem intervala):
- Kolekcija je ureena
- polovimo interval, i traimo u kojem dalje da pretraujemo.