Rekurzija i rekurzivne funkcije Informacioni inženjering 1
Rekurzija Rekurzija nastaje kada se pojam definiše pomoću sebe samog Javlja se u različitim oblastima, od lingvistike i logike, preko matematike i računarstva, do umetnosti Primeri: Binarno pretraživanje, faktorijel, fraktali, Fibonačijev niz, trougao Sierpinskog, Hanojske kule,... Informacioni inženjering 2
Rekurzija u umetnosti Informacioni inženjering 3
Trougao Sierpinskog Postupak konstrukcije: Informacioni inženjering 4
Iteracija i rekurzija Iterativna funkcija je ona koja koristi iteracije kako bi izvršila određeni kod veći broj puta, dok rekurzivna funkcija poziva samu sebe kako bi izvršila određeni kod veći broj puta Svaka iteracija može se pretvoriti u rekurziju i obratno Rekurzija se na nivou izvršavanja programa modeluje putem petlji (tj. uslovnih i bezuslovnih skokova) i steka Informacioni inženjering 5
Rekurzija u matematici Klasa objekata ili metoda ponaša se rekurzivno kada se može definisati pomoću sledeća dva svojstva: 1. Jednostavan osnovni slučaj poseban slučaj koji ne koristi rekurziju kako bi proizveo odgovor 2. Skup pravila kojim se svi ostali slučajevi redukuju na osnovni slučaj Rekurzivni procesi linearni i u vidu stabla Rekurzivni i iterativni procesi iterativna realizacija rekurzivnih problema Informacioni inženjering 6
Rekurzija u matematici Primeri: Računanje faktorijela ìn ( n- 1)!, n> 0 n! = í î 1, n = 0 Fibonačijev niz F n ì 0, n = 0 ï = í 1, n = 1 ï îfn-1+ Fn-2, n³ 2 Informacioni inženjering 7
Rekurzivne funkcije Situacija u kojoj je funkcija sama sebi i nadređena i podređena, tj. situacija kada funkcija poziva samu sebe DEO KOJI SE IZVRŠAVA U DUBINU Postoje tri dela rekurzivne funkcije: deo koji se izvršava u dubinu uslov za ponovno pozivanje rekurzivne funkcije deo koji se izvršava ka površini USLOV ZA PONOVNO POZIVANJE REKURZIVNE FUNKCIJE DEO KOJI SE IZVRŠAVA KA POVRŠINI DEO KOJI SE IZVRŠAVA U DUBINU USLOV ZA PONOVNO POZIVANJE REKURZIVNE FUNKCIJE DEO KOJI SE IZVRŠAVA KA POVRŠINI DEO KOJI SE IZVRŠAVA U DUBINU USLOV ZA PONOVNO POZIVANJE REKURZIVNE FUNKCIJE DEO KOJI SE IZVRŠAVA KA POVRŠINI (ISPUNJEN) (ISPUNJEN) (NIJE ISPUNJEN) Informacioni inženjering 8
Rekurzivne funkcije primer Program za ispisivanje svih celih brojeva koji slede nakon navedenog broja do nule (isključujući nulu) printf( %d, n); ispisibroj(n); void ispisibroj(unsigned n) { printf("%d ", n); ispisibroj(n); // rekurzivni poziv Šta nije ispravno u kodu ove rekurzivne funkcije? printf( %d, n); ispisibroj(n); printf( %d, n); ispisibroj(n); Informacioni inženjering 9
Rekurzivne funkcije primer Tačno rešenje: void ispisibroj(unsigned n) { unsigned s = --n; if (s > 0) ispisibroj(s); //rekurzivni poziv printf("%d ", n); Primer poziva: int main( ) { ispisibroj(3); void ispisibroj( 3 ) { unsigned s = --n; if (s > 0) ispisibroj( s ); printf("%d ", n); void ispisibroj( 2 ) { unsigned s = --n; if (s > 0) ispisibroj( s ); printf("%d ", n); void ispisibroj( 1 ) { unsigned s = --n; if (s > 0) ispisibroj( s ); printf("%d ", n); (ISPUNJEN) (ISPUNJEN) (NIJE ISPUNJEN) Informacioni inženjering 10
Rekurzija faktorijel Rekurzivna definicija faktorijela: ìn ( n- 1)!, n> 0 n! = í î 1, n = 0 Izlazak iz rekurzije omogućen je osnovnim slučajem (n = 0) Rekurzivna funkcija za računanje faktorijela: int faktorijel(int n) { if (n <= 1) return 1; else return n*faktorijel(n-1); // rekurzivni poziv Informacioni inženjering 11
Rekurzija faktorijel Linearni rekurzivni proces Informacioni inženjering 12
Rekurzija faktorijel Iterativna funkcija za računanje faktorijela: int faktorijel(int n) { int i; int fakt = 1; if (n == 1) return fakt; for (i = 2; i <= n; i++) { fakt*=i; return fakt; Informacioni inženjering 13
Rekurzija Fibonačijev niz Fibonačijevi brojevi ì 0, n = 0 ï Fn = í 1, n = 1 ï îfn-1+ Fn-2, n³ 2 Rekurzivni proces u vidu stabla (engl. tree recursion): Informacioni inženjering 14
Rekurzija Fibonačijev niz Rekurzivna funkcija za generisanje Fibonačijevog niza: int fibonaccirekurzivno(int n) { if (n == 0) return 0; if (n == 1) return 1; return fibonaccirekurzivno(n - 1)+fibonacciRekurzivno(n - 2); Informacioni inženjering 15
Rekurzija Fibonačijev niz Iterativna funkcija za generisanje Fibonačijevog niza: int fibonacciiterativno(int n) { if (n == 0) return 0; if (n == 1) return 1; int pretpret = 0, pret = 1, rezultat = 0; for (int i = 2; i <= n; i++) { rezultat = pret + pretpret; pretpret = pret; pret = rezultat; return rezultat; Informacioni inženjering 16
Rekurzija binarno pretraživanje Binarno pretraživanje niza (engl. binary search) 1 2 3 4 5 6 7 8 Podeli-pa-vladaj (engl. divide-and-conquer) algoritam bsearch() deo standardne C biblioteke - stdlib.h Različite podvarijante npr. uniformno binarno pretraživanje Informacioni inženjering 17
Rekurzija binarno pretraživanje int trazi(int *podaci, int broj, int brojac) { // pocetak = 0 (pocetni indeks) kraj = brojac - 1 (krajnji indeks) return binarnopretrazivanje(podaci, broj, 0, brojac-1); int binarnopretrazivanje(int *podaci, int broj, int pocetak, int kraj) { //pronadji sredinu int sredina = pocetak + (kraj - pocetak)/2; //celobrojno deljenje //uslov za zaustavljanje if (pocetak > kraj) return -1; else if (podaci[sredina] == broj) //pronadjen? return sredina; else if (podaci[sredina] > broj) //pod. veći od broja, trazi u nizoj polovini return binarnopretrazivanje(podaci, broj, pocetak, sredina-1); else //pod. je manji od broja, trazi u visoj polovini return binarnopretrazivanje(podaci, broj, sredina+1, kraj); Informacioni inženjering 18
Rekurzija Hanojske kule Tri štapa i diskovi različite veličine Cilj je prebaciti sve diskove sa jednog na drugi štap poštujući sledeća pravila: Svakim potezom pomera se samo po jedan disk Svaki potez sastoji se od uzimanja najvišeg diska sa jednog štapa i njegovog prebacivanja na vrh drugog štapa Nijedan disk ne sme biti stavljen na manji disk h n ì 1, n = 1 = í î2hn -1 + 1, n> 1 Informacioni inženjering 19
Rekurzija Hanojske kule Izvor: https://commons.wikimedia.org/wiki/file:iterative_algorithm_solving_a_6_disks_tower_of_hanoi.gif Informacioni inženjering 20
#include <stdio.h> Rekurzija Hanojske kule void hanojskekule(int, char, char, char); int main(){ int broj; printf("unesite broj diskova: "); scanf("%d", &broj); printf("redosled poteza je:\n"); hanojskekule(broj, 'A', 'C', 'B'); return 0; void hanojskekule(int broj, char sastapa, char nastap, char pomocustapa){ if (broj == 1){ printf("\n Prebaci disk 1 sa stapa %c na stap %c", sastapa, nastap); return; hanojskekule(broj - 1, sastapa, pomocustapa, nastap); printf("\n Prebaci disk %d sa stapa %c na stap %c", broj, sastapa, nastap); hanojskekule(broj - 1, pomocustapa, nastap, sastapa); Informacioni inženjering 21
Datoteke Informacioni inženjering 22
Osnovno o datotekama Koncept datoteke (engl. file) razdvaja upotrebu sadržaja (podataka) od njihove organizacije Služe za dugotrajno čuvanje podataka, čine ih strukture podataka smeštene u masovnoj memoriji Prema načinu pristupa podacima, datoteke se dele na: sekvencijalne direktne (sa slučajnim pristupom) Prema organizaciji podataka, datoteke se dele na: sekvencijalne direktne indeks-sekvencijalne (indeksi (heševi) + podaci (zapisi u tabelama)) Prema prirodi podataka koje sadrže, datoteke se dele na: tekstualne binarne Informacioni inženjering 23
Sistemi sa rad sa datotekama Sistem za rad sa datotekama (engl. filesystem) kontroliše kako se čuvaju podaci i kako im se pristupa Globalno definiše način na koji računar organizuje, imenuje, čuva i manipuliše datotekama Bez sistema za rad sa datotekama, podaci zapisani na memorijskom medijumu predstavljali bi jedinstvenu celinu, tj. ne bi mogli da kažemo gde se neka informacija završava, a sledeća počinje Primeri sistema za rad sa datotekama: FAT (FAT16, FAT32), NTFS, ext (2, 3, 4), UDF, Informacioni inženjering 24
Primer Linux filesystem (ext) Izvor:https://freedompenguin.com/articles/how-to/learning-the-linux-file-system/ Informacioni inženjering 25
Tok rada sa datotekama u jeziku C 1. Deklarisanje datotečne promenljive FILE *datprom; 2. Otvaranje datoteke FILE *fopen(const char *nazivdatoteke, const char *rezim); Režimi rada r / rt rb w / wt wb a / at ab r+ / rt+ ili rb+ w+ / wt+ ili wb+ a+ / at+ ili ab+ Otvori za čitanje tekstualnu ili binarnu datoteku, pozicioniraj se na početak datoteke. Ako datoteka ne postoji, vraća NULL. Otvori za pisanje tekstualnu ili binarnu datoteku, pozicioniraj se na početak datoteke. Gubi se stari zapis. Ako datoteka ne postoji, kreira se nova. Otvori za dodavanje tekstualnu ili binarnu datoteku, pozicioniraj se na kraj datoteke i omogući dodavanje novih zapisa. Čuva se stari zapis. Ako datoteka ne postoji, kreira se nova. Čitanje i pisanje od početka. Gubi se stari zapis. Čitanje i pisanje od početka. Gubi se stari zapis. Čitanje i pisanje od kraja. Čuva stari zapis. Informacioni inženjering 26
Tok rada sa datotekama u jeziku C 3. Čitanje ili pisanje podataka u datoteku koriste se različite funkcije u zavisnosti od vrste datoteke čitanje do kraja pomeranjem internog pokazivača datoteke: int *feof(file *datprom); 4. Zatvaranje datoteke int fclose(file *datprom) Informacioni inženjering 27
Definisana u zaglavlju stdio.h Struktura FILE Direktorijum (folder) je samo specijalna vrsta fajla fajl fajlova Pruža neophodne informacije o datoteci ili toku koji obavlja ulazne i/ili izlazne operacije, primer iz K&R: typedef struct { short level; short token; short bsize; char fd; unsigned flags; unsigned char hold; unsigned char *buffer; unsigned char *curp; unsigned istemp; FILE; Deskriptor datoteke sadrži atribute datoteke: naziv, veličina, redni brojevi blokova, vreme nastanka, izmene, pristupa,... Informacioni inženjering 28
Tekstualne datoteke Sadržaj se interpretira kao ASCII, čak i kontrolni karakteri Funkcije za prenos znakova sa konverzijom: int fscanf(file *datprom, const char *format [,adresa,...]) int fprintf(file *datprom, const char *format [,prom,...]) isto kao i odgovarajuće funkcije za rad sa stdin i stdout navodi se datotečna promenljiva kako bi se znalo odakle se čita, tj. gde se piše Informacioni inženjering 29
Tekstualne datoteke Funkcije za prenos karaktera (bez konverzije): int fgetc(file *datprom) int getc(file *fajlprom) int fputc(int znak, FILE *fajlprom) int putc(int znak, FILE *fajlprom) char *fgets(char *str, int n, FILE *stream) int fputs(const char *str, FILE *fajlprom) Funkcije Funkcija koja čita iz tekstualne datoteke jedan karakter koji vraća svojim identifikatorom Makro koji čita iz tekstualne datoteke jedan karakter koji vraća svojim identifikatorom Funkcija koja upisuje znak u tekstualnu datoteku, dok svojim identifikatorom vraća taj isti znak ili kod greške Makro koji upisuje znak u tekstualnu datoteku, dok svojim identifikatorom vraća taj isti znak ili kod greške Funkcija koja čita iz tekstualne datoteke niz od n-1 znakova ili dok ne naiđe na znak '\0'. Funkcija koja upisuje u tekstualnu datoteku niz znakova sa '\0' terminatorom Informacioni inženjering 30
Tekstualne datoteke primeri Zadatak 1: Napisati program koji učitava tekst iz tekstualnog fajla i isti ispisuje na ekran. Pretpostaviti da u jednom redu tekstualnog fajla može biti maksimalno 255 karaktera. Vežba 1: Proširiti program tako da omogući korisniku unos naziva tekstualnog fajla. Vežba 2: Napisati program koji omogućuje korisniku da unosi tekst sa tastature, koji će se potom čuvati u tekstualnom fajlu sa imenom po izboru korisnika. Vežba 3: Napisati program koji kopira sadržaj jednog tekstualnog fajla u drugi sa imenom po izboru korisnika. Informacioni inženjering 31
Tekstualne datoteke Zadatak 1 #include <stdio.h> #include <stdlib.h> int main() { FILE *ulaz; char nazivdat[31] = "poruka.txt"; char red[256]; if ((ulaz = fopen(nazivdat,"r")) == NULL)// Otvaranje datoteke sa proverom prava na citanje (r) { printf("\ngreska prilikom otvaranja datoteke \'%s\' za citanje.\n", nazivdat); exit(exit_failure); // Prevremeni izlaz iz programa while (fgets(red, 255, ulaz)!= NULL) printf("%s", red); // Citanje stringova max duzine 255 iz ulazne datoteke printf("\n"); fclose(ulaz); return 0; // Zatvaranje datoteke Informacioni inženjering 32
Binarne datoteke Sadržaj se interpretira kao n-torka bitova (najčešće celobrojni umnožak bajta) Može se tumačiti da je organizovana kao struct Sadržaj binarne datoteke čita se pomoću funkcije: int fread(void *lokacija, int velblok, int brblok, FILE *datprom) Čita od trenutne pozicije internog pokazivača datoteke označenog sa datprom Čita se brblok blokova, gde je svaki blok veličine velblok Pročitane vrednosti smeštaju se u memoriju počev od adrese lokacija Informacioni inženjering 33
Binarne datoteke U binarnu datoteku se piše pomoću funkcije: int fwrite(void *lokacija, int velblok, int brblok, FILE *datprom) Piše se od trenutne pozicije internog pokazivača datoteke označenog sa datprom Upisuje se brblok blokova, gde je svaki blok veličine velblok Vrednosti koje treba upisati u datoteku, čitaju se iz memorije počev od adrese lokacija Informacioni inženjering 34
Pozicioniranje unutar datoteke Moguće je manipulisati internim pokazivačem datoteke Pozicija internog pokazivača saznaje se upotrebom funkcije: long ftell(file *datprom) Interni pokazivač se na početak datoteke pomera pomoću funkcije: void rewind(file *datprom) Funkcija za pomeranje internog pokazivača datoteke: int fseek(file *datprom, long offset, int reper) Moguće vrednosti parametra reper SEEK_SET SEEK_CUR SEEK_END offset se računa u odnosu na početak fajla offset se računa u odnosu na trenutnu poziciju internog pokazivača offset se računa u odnosu na kraj fajla Informacioni inženjering 35
Binarne datoteke primeri Zadatak 2: Napisati program koji upisuje elemente niza sa 10 prirodnih brojeva u binarnu datoteku. Zadatak 3: Napisati program koji čita elemente niza sa 10 prirodnih brojeva iz binarne datoteke (sačuvane u prethodnom primeru). Vežba 4: Napisati program koji vodi evidenciju o polaznicima kursa. Maksimalno ima 40 polaznika. Svaki polaznik opisan je JMBG-om (koji ga jedinstveno identifikuje), imenom, prezimenom i nizom u kojem se čuva informacija o kursevima koje polaže. Prilikom izlaska iz programa, podaci se memorišu u binarnu datoteku. Prilikom pokretanja programa, podaci se učitavaju iz binarne datoteke u niz. Omogućiti korisniku da unosi, briše i modifikuje podatke o polaznicima kursa, kao i da prikaže podatke o svim polaznicima. Informacioni inženjering 36
Binarne datoteke Zadatak 2 #include <stdio.h> #include <stdlib.h> #define VELICINA 10 int main() { int i, niz[velicina]; FILE *izlaz; for (i = 0; i < VELICINA; i++) niz[i] = i + 1; if ((izlaz = fopen("podaci.dat", "wb")) == NULL) { fprintf(stderr, "Greska pri otvaranju datoteke."); exit(1); if (fwrite(niz, sizeof(int), VELICINA, izlaz)!= VELICINA) { fprintf(stderr, "Greska pri ispisu u datoteku."); exit(1); fclose(izlaz); return 0; // Inicijalizacija niza niz[] // Otvaranje datoteke u binarnom modu // Ispis niza u datoteku Informacioni inženjering 37
Binarne datoteke Zadatak 3 #include <stdio.h> #include <stdlib.h> #define VELICINA 10 int main() { int i, niz[velicina]; FILE *ulaz; if ((ulaz = fopen("podaci.dat", "rb")) == NULL) { fprintf(stderr, "Greska pri otvaranju datoteke."); exit(1); // Otvaranje datoteke za citanje u binarnom modu if (fread(niz, sizeof(int), VELICINA, ulaz)!= VELICINA) // Unos podataka u niz niz[] { fprintf(stderr, "Greska pri citanju datoteke."); exit(1); fclose(ulaz); puts("brojevi u datoteci PODACI.DAT su:"); for (i = 0; i < VELICINA; i++) printf("\t%d\n", niz[i]); return 0; // Ispis podataka na ekran Informacioni inženjering 38