Professional Documents
Culture Documents
Programski Jazik
Programski Jazik
Programski jezik C
— Zadaci sa vežbi —
Milena Vujošević-Janičić
www.matf.bg.ac.yu/~milena
1
Sadržaj
2 Datoteke 7
3 Bitski operatori 19
4 Vežbanje 30
4.1 Polinomi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.2 Veliki brojevi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5 Sortiranje 40
5.1 Vremenska složenost . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.2 Selection sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
5.3 Bubble sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.4 Insertion sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.5 Razni zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6 Pokazivači 58
6.1 Pokazivačka aritmetika — primeri . . . . . . . . . . . . . . . . . . . . 59
6.2 Niska karaktera i pokazivač na konstantnu nisku . . . . . . . . . . . . 64
6.3 Pokazivači na pokazivače . . . . . . . . . . . . . . . . . . . . . . . . . 65
6.4 Nizovi pokazivača . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
7 Rekurzija 69
7.1 Osnovni primeri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
7.2 Binarna pretraga . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
7.3 MergeSort algoritam . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
7.4 QuickSort algoritam . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
8 Pokazivači na funkcije 86
8.1 Funkcija qsort iz standardne biblioteke . . . . . . . . . . . . . . . . . 89
8.2 Funkcija bsearch iz standardne biblioteke . . . . . . . . . . . . . . . 93
8.3 Funkcije lsearch i lfind . . . . . . . . . . . . . . . . . . . . . . . . 97
8.4 Pokazivači . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
2
SADRŽAJ SADRŽAJ
10 Liste 118
10.1 Implementacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
10.2 Kružna (ciklična) lista . . . . . . . . . . . . . . . . . . . . . . . . . . 143
10.3 Red . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
10.4 Stek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
10.5 Dvostruko povezane liste . . . . . . . . . . . . . . . . . . . . . . . . . 160
11 Stabla 166
11.1 Binarno pretraživačko stablo . . . . . . . . . . . . . . . . . . . . . . . 167
12 Grafovi 209
3
Glava 1
#include <stdio.h>
4
Milena Vujošević–Janičić Argumenti komandne linije
#include <stdio.h>
main(int argc, char** argv)
{
/* Za svaki argument komande linije, pocevsi od argv[1]
(preskacemo ime programa) */
int i;
for (i = 1; i < argc; i++)
{
/* Ukoliko i-ti argument pocinje crticom */
if (argv[i][0] == ’-’)
{
/* Ispisujemo sva njegova slova pocevsi od pozicije 1 */
int j;
for (j = 1; argv[i][j] != ’\0’; j++)
printf("Prisutna je opcija : %c\n", argv[i][j]);
}
/* Ukoliko ne pocinje crticom, prekidamo */
else
break;
}
}
Izlaz:
Prisutna opcija : a
Prisutna opcija : b
Prisutna opcija : c
Prisutna opcija : d
Prisutna opcija : f
Prisutna opcija : g
Primer 1.3 Program ispisuje opcije navedene u komandnoj liniji. K&R rešenje.
#include <stdio.h>
5
Milena Vujošević–Janičić Argumenti komandne linije
6
Glava 2
Datoteke
Primer 2.1 Program demonstrira otvaranje datoteka ("r" - read i "w" - write mod)
i osnovne tehnike rada sa datotekama.
/* U datoteku se upisuje prvih 10 prirodnih
brojeva, a zatim se iz iste datoteke
citaju brojevi dok se ne stigne do kraja i
ispisuju se na standardni izlaz */
#include <stdio.h>
#include <stdlib.h>
main()
{
int i;
/* Zatvaramo datoteku */
7
Milena Vujošević–Janičić Datoteke
fclose(f);
/* Zatvaramo datoteku */
fclose(f);
}
Pokazivači stdin, stdout i stderr su definisani u okviru stdio.h i mogu se
koristiti za pisanje na standardni ulaz, izlaz i izlaz za grešku.
FILE* stdin;
FILE* stdout;
FILE* stderr;
Primer 2.2 Program demonstrira ”a” - append mod datoteka - nadovezivanje.
#include <stdio.h>
8
Milena Vujošević–Janičić Datoteke
#include <stdlib.h>
main()
{
FILE* datoteka;
/* Zatvaramo datoteku */
fclose(datoteka);
}
Primer 2.3 Program kopira sadrzaj datoteke ulaz.txt u datoteku izlaz.txt.
#include <stdio.h>
#include <stdlib.h>
main()
{
int c;
FILE *in, *out;
9
Milena Vujošević–Janičić Datoteke
exit(1);
}
/* Zatvaramo datoteke */
fclose(in);
fclose(out);
}
Primer 2.4 Program kopira n puta sadrzaj datoteke ulaz.txt u datoteku izlaz.txt.
#include <stdio.h>
#include <stdlib.h>
main()
{
int c, n;
FILE *in, *out;
10
Milena Vujošević–Janičić Datoteke
}
/* Zatvaramo datoteke */
fclose(in);
fclose(out);
}
Primer 2.5 Program ilustruje rad sa datotekama. Program kopira datoteku čije se
ime zadaje kao prvi argument komandne linije u datoteku čije se ime zadaje kao
drugi argument komandne linije. Uz svaku liniju se zapisuje i njen redni broj.
#include <stdio.h>
#include <stdlib.h>
char line[MAX_LINE];
FILE *in, *out;
int line_num;
if (argc != 3) {
fprintf(stderr,"Neispravna upotreba programa!\n
Pravilna upotreba:
%s ulazna_datoteka izlazna_datoteka\n",argv[0]);
11
Milena Vujošević–Janičić Datoteke
exit(1);
}
line_num = 1;
/* Zatvaramo datoteke */
fclose(in);
fclose(out);
}
Primer 2.6 Prodavnica - ilustruje čitanje niza struktura iz tektsualne datoteke.
/* Datoteka, cije se ime zadaje kao argument komandne linije
ili ako se ne zada onda se ime unosi sa standardnog
ulaza, sadrzi podatke o proizvodima koji se prodaju
u okviru odredjene prodavnice. Svaki
proizvod se odlikuje sledecim podacima:
bar-kod - petocifreni pozitivan broj
ime - niska karaktera
cena - realan broj zaokruzen na dve decimale
pdv - stopa poreza - realan broj zaokruzen na dve decimale
Pretpostavljamo da su podaci u datoteci
korektno zadati.
Pretpostavljamo da se u prodavnici ne
prodaje vise od 1000 razlicitih artikala
Na standardni izlaz ispisujemo podatke o
12
Milena Vujošević–Janičić Datoteke
#include <stdio.h>
#include <stdlib.h>
/* Prijavljujemo uspeh */
return 1;
}
13
Milena Vujošević–Janičić Datoteke
14
Milena Vujošević–Janičić Datoteke
br_artikala=0;
/* Ucitavamo artikle */
while (ucitaj_artikal(f, &artikli[br_artikala]))
br_artikala++;
/* Zatvara se datoteka*/
fclose(f);
}
Primer 2.7 Program u datoteku čije se ime zadaje kao prvi argument komandne
linije upisuje prvih N prirodnih brojeva (N se zadaje sa standardnog ulaza) i zatim
izračunava dužinu datoteke u bajtovima.
#include <stdio.h>
#include <stdlib.h>
void main()
{
FILE *f;
int i, n;
15
Milena Vujošević–Janičić Datoteke
Primer 2.8 Napisati program koji u datoteci čije se ime zadaje kao prvi argument
16
Milena Vujošević–Janičić Datoteke
komandne linije zamenjuje sva pojavljivanja niske koja se zadaje kao drugi argument
komandne linije niskom koja se zadaje kao treći argument komandne linije (pret-
postaviti da ce obe niske iste dužine i da nisu duze od 20 karaktera). Na primer, ako
se program pokrene sa
a.out datoteka.txt ana Ana
tada se svako pojavljivanje reči ana u datoteci datoteka.txt zamenjuje sa Ana.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
17
Milena Vujošević–Janičić Datoteke
18
Glava 3
Bitski operatori
main()
{ printf("%o %o\n",255,15);
printf( "255 & 15 = %d\n", 255 & 15 );
printf( "255 | 15 = %d\n", 255 | 15 );
printf( "255 ^ 15 = %d\n", 255 ^ 15 );
printf( "2 << 2 = %d\n", 2 << 2 );
printf( "16 >> 2 = %d\n", 16 >> 2 );
}
19
Milena Vujošević–Janičić Bitski operatori
void print_bits(int x)
{
/* Broj bitova tipa unsigned */
int wl = sizeof(int)*8;
unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);
putchar(’\n’);
}
main()
{
print_bits(127);
print_bits(128);
print_bits(0x00FF00FF);
print_bits(0xFFFFFFFF);
}
Izlaz iz programa:
00000000000000000000000001111111
00000000000000000000000010000000
00000000111111110000000011111111
11111111111111111111111111111111
Primer 3.3 Program proverava da li se na k-tom mestu broja n nalazi bit koji ima
vrednost 1.
#include <stdio.h>
20
Milena Vujošević–Janičić Bitski operatori
bit: ... 0 0 0 1 1 1 0 0 1 1 0 */
main()
{
int n,k;
printf("Unesite broj i poziciju tog broja koju zelite da proverite:\n");
scanf("%d%d",&n,&k);
if ((n & (1 << k))!=0)
printf("Bit je 1\n");
else
printf("Bit je 0\n");
}
Primer 3.4 Program postavlja na k-to mesto broja n bit 1.
#include <stdio.h>
void print_bits(int x)
{
/* Broj bitova tipa unsigned */
int wl = sizeof(int)*8;
unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);
putchar(’\n’);
}
main(){
int n,k;
printf("Unesite broj i poziciju tog broja koju zelite da postavite na 1:\n");
scanf("%d%d",&n,&k);
printf("Binarno, uneseni broj je\n");
print_bits(n);
printf("Novi broj je %d\n",(n |(1<<k)));
printf("Binarno, novi broj je\n");
print_bits((n |(1<<k)));
}
Izrazom a>>b vrši se pomeranje sadržaja operanda a predstavljenog u binarnom
obliku za b mesta u desno. Popunjavanje upražnjenih mesta na levoj strani zavisi od
tipa podataka i vrste računara. Ako se pomeranje primenjuje nad operandom tipa
unsigned popunjavanje je nulama. Ako se radi o označenom operandu popunjavanje
je jedinicama kada je u krajnjem levom bitu jedinica, a nulama kada je u krajnjem
levom bitu nula.
21
Milena Vujošević–Janičić Bitski operatori
unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);
putchar(’\n’);
}
int sum_of_bits(unsigned x)
{
int br;
for (br = 0; x; x>>=1)
if (x&1)
br++;
/* Drugo resenje:
int wl = sizeof(unsigned)*8;
int br = 0;
unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
if(x&mask) br++ ;
*/
return br;
}
22
Milena Vujošević–Janičić Bitski operatori
main()
{
printf("Binarni zapis broja 127 je\n");
print_bits(127);
printf("Suma bitova broja 127 je %d\n",sum_of_bits(127));
printf("Binarni zapis broja 128 je\n");
print_bits(128);
printf("Suma bitova broja 128 je %d\n",sum_of_bits(128));
printf("Binarni zapis broja 0x00FF00FF je\n");
print_bits(0x00FF00FF);
printf("Suma bitova broja 0x00FF00FF je %d\n",sum_of_bits(0x00FF00FF));
printf("Binarni zapis broja 0xFFFFFFFF je\n");
print_bits(0xFFFFFFFF);
printf("Suma bitova broja 0xFFFFFFFF je %d\n",sum_of_bits(0xFFFFFFFF));
}
Izlaz iz programa:
Binarni zapis broja 127 je
00000000000000000000000001111111
Suma bitova broja 127 je 7
Binarni zapis broja 128 je
00000000000000000000000010000000
Suma bitova broja 128 je 1
Binarni zapis broja 0x00FF00FF je
00000000111111110000000011111111
Suma bitova broja 0x00FF00FF je 16
Binarni zapis broja 0xFFFFFFFF je
11111111111111111111111111111111
Suma bitova broja 0xFFFFFFFF je 32
Primer 3.6 get_bits, set_bits, invert_bits - izdvajanje, postavljanje i inver-
tovanje pojedinačnih bitova.
#include <stdio.h>
unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);
putchar(’\n’);
}
23
Milena Vujošević–Janičić Bitski operatori
24
Milena Vujošević–Janičić Bitski operatori
main()
{
unsigned x = 0x0AA0AFA0;
print_bits(x);
Izlaz iz programa:
00001010101000001010111110100000
00000000000000000000000010101111
00001010101000001111111110100000
00001010101000000101000010100000
Primer 3.7 right_rotate_bits, mirror_bits - rotiranje i simetrija bitova.
#include <stdio.h>
unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);
putchar(’\n’);
}
25
Milena Vujošević–Janičić Bitski operatori
{
/* Poslednji bit broja x */
unsigned last_bit = x & 1;
x |= last_bit<<wl-1;
}
return x;
}
main()
{
unsigned x = 0xFAF0FAF0;
print_bits(x);
26
Milena Vujošević–Janičić Bitski operatori
print_bits(mirror(x));
print_bits(right_rotate(x, 2));
}
Izlaz iz programa:
11111010111100001111101011110000
00001111010111110000111101011111
00111110101111000011111010111100
Primer 3.8 Promeljiva c je tipa char. Šta ce biti vrednost promenljive c posle izraza
dodele
• c=(15|3)>>1;?
• c=(15 & 3)<<1; ?
Primer 3.9 Napisati program koji sa standardnog ulaza učcitava pozitivan ceo broj,
a na standardni izlaz ispisuje vrednost tog broja sa razmenjenim vrednostima bitova
na pozicijama i, j. Pozicije i, j se učitavaju kao parametri komandne linije. Sma-
trati da je krajnji desni bit binarne reprezentacije 0-ti bit. Pri rešavanju nije dozvol-
jeno koristiti pomoćni niz niti aritmeticke operatore +,-,/,*,%.
#include <stdio.h>
#include <stdlib.h>
27
Milena Vujošević–Janičić Bitski operatori
rezultat |= mask_i;
/* Ako je na j-tom mestu 0, upisujemo
to na i-to mesto*/
else
rezultat &= ~mask_i;
return rezultat;
}
printf("Unesi broj\n");
scanf("%u", &n);
m = razmeni(n, i, j);
int par_nepar(int n)
{
28
Milena Vujošević–Janičić Bitski operatori
29
Glava 4
Vežbanje
4.1 Polinomi
Primer 4.1 Program ilustruje rad sa polinomima.
#include <stdio.h>
#include <math.h>
#define max(a, b) ((a) > (b) ? (a) : (b))
/*
* Polinom 3*x^3 + 2*x + 1.5 se predstavlja kao:
* stepen -> 3
* koeficijenti -> 1.5 2 0 3 x x x x x ... x
*/
typedef struct polinom
{
float koeficijenti[21];
int stepen;
} Polinom;
/*
* Funkcija vraca koeficijent uz x^i u polinomu p
* Zbog efikasnosti ne prenosimo celu strukturu vec
* samo pokazivac na strukturu.
*/
float vratiKoeficijent(Polinom* p, int i)
{
return i <= p->stepen ? p->koeficijenti[i] : 0.0f;
}
/*
* Funkcija postavlja koeficijent uz x^i u polinomu p na
* dati koeficijent k
30
Milena Vujošević–Janičić 4.1 Polinomi
*/
void postaviKoeficijent(Polinom* p, int i, float k)
{
int j;
/*
Ukoliko je stepen polinoma bio manji, postavljamo
sve koeficijente izmedju na 0.0 i uvecavamo stepen
*/
if (i > p->stepen)
{
for (j = p->stepen+1; j < i; j++)
p->koeficijenti[j] = 0.0f;
p->stepen = i;
}
p->koeficijenti[i] = k;
}
/*
* Funkcija kreira polinom datog stepena sa datim nizom
* koeficijenata. Pretpostavlja se da su koeficijenti
* u datom nizu koeficijenti[] uredjeni opadajuce po stepenima
* polinoma.
*/
Polinom napraviPolinom(int stepen, float koeficijenti[])
{
int i;
Polinom p;
p.stepen = stepen;
for (i = 0; i <= stepen; i++)
{
postaviKoeficijent(&p, i, koeficijenti[stepen - i]);
}
return p;
}
/*
* Funkcija ispisuje polinom u citljivijem obliku.
* Na primer: 3.0*x^3 + 0.0*x^2 + 2.0*x^1 + 1.5*x^0
*/
void ispisiPolinom(Polinom* p)
{
int i;
for (i = p->stepen; i >= 0; i--)
31
Milena Vujošević–Janičić 4.1 Polinomi
{
printf("%.2f*x^%d", vratiKoeficijent(p, i), i);
if (i > 0)
printf(" + ");
}
printf("\n");
}
/*
* Funkcija izracunava vrednost polinoma u tacki x
* Hornerovom shemom. Na primer,
* 3*x^3 + 2*x + 1.5 =
* (((0*x + 3)*x + 0)*x + 2)*x + 1.5
* Postupak izracunavanja p(10):
* 0.0
* 10 * 0.0 + 3 = 3.0
* 10 * 3.0 + 0 = 30.0
* 10 * 30.0 + 2 = 302.0
* 10 * 302.0 + 1.5 = 3021.5
*/
float vrednost(Polinom* p, float x)
{
int i;
float suma = 0.0f;
for (i = p->stepen; i >= 0; i--)
{
suma = suma*x + vratiKoeficijent(p, i);
}
return suma;
}
/*
* Funkcija sabira dva polinoma
*/
Polinom saberi(Polinom* p, Polinom* q)
{
int i;
Polinom zbir;
zbir.stepen = max(p->stepen, q->stepen);
for (i = 0; i <= zbir.stepen; i++)
postaviKoeficijent(&zbir, i,
vratiKoeficijent(p, i)
+ vratiKoeficijent(q, i));
return zbir;
32
Milena Vujošević–Janičić 4.1 Polinomi
/*
* Funkcija mnozi dva polinoma. Na primer,
*
* 1*x^2 + 2*x + 3
* 4*x + 7
*
* 0.0*x^3 + 0.0*x^2 + 0.0*x + 0.0
* 0.0*x^3 + 0.0*x^2 + 0.0*x + 21.0 i=0 j=0
* 0.0*x^3 + 0.0*x^2 + 12.0*x + 21.0 i=0 j=1
* 0.0*x^3 + 0.0*x^2 + 26.0*x + 21.0 i=1 j=0
* 0.0*x^3 + 8.0*x^2 + 26.0*x + 21.0 i=1 j=1
* 0.0*x^3 + 15.0*x^2 + 26.0*x + 21.0 i=2 j=0
* 4.0*x^3 + 15.0*x^2 + 26.0*x + 21.0 i=2 j=1
*/
Polinom pomnozi(Polinom* p, Polinom* q)
{
int i, j;
Polinom proizvod;
proizvod.stepen = p->stepen + q->stepen;
for (i = 0; i <= proizvod.stepen; i++)
{
postaviKoeficijent(&proizvod, i, 0.0f);
}
for (i = 0; i <= p->stepen; i++)
{
for (j = 0; j <= q->stepen; j++)
{
/* r[i+j] = r[i+j] + p[i]*q[j] */
postaviKoeficijent(&proizvod, i+j,
vratiKoeficijent(&proizvod, i+j) +
vratiKoeficijent(p, i) * vratiKoeficijent(q, j));
}
}
return proizvod;
}
main()
{
float pkoeficijenti[] = {1.0f, 2.0f, 1.0f};
Polinom p = napraviPolinom(2, pkoeficijenti);
float qkoeficijenti[] = {1.0f, 1.0f};
Polinom q = napraviPolinom(1, qkoeficijenti);
Polinom r = pomnozi(&p, &q);
33
Milena Vujošević–Janičić 4.2 Veliki brojevi
ispisiPolinom(&r);
}
34
Milena Vujošević–Janičić 4.2 Veliki brojevi
{
int i;
for (i=duzina-1; i>=0; i--)
printf("%d",cifre[i]);
putchar(’\n’);
}
return 1;
}
35
Milena Vujošević–Janičić 4.2 Veliki brojevi
return 1;
if (a[i] < b[i])
return -1;
}
return 0;
}
36
Milena Vujošević–Janičić 4.2 Veliki brojevi
rezultat[i] = prenos;
*duzina_rezultata = i+1;
}
}
else
*duzina_rezultata=i;
return;
}
/* Funkcija mnozi broj, dat svojim nizom cifara i duzinom, datom cifrom c */
void pomnozi_cifrom (int a[], int duzina_a, int cifra,
int rezultat[],
int* duzina_rezultata)
{
int i, prenos = 0;
37
Milena Vujošević–Janičić 4.2 Veliki brojevi
*duzina_rezultata = duzina_a;
}
*duzina_rezultata = 0;
/*
b=351 * a=123
---------------
1 korak ===> rez: 351 * 3 = 1053
2 korak ===> 351 * 2 = 702
------------------
rez: 8073
3 korak ===> 351 * 1 = 351
------------------
rez: 43173
*/
/* Za svaku cifru broja a */
for (i=0; i<duzina_a; i++)
{
/* vrsimo mnozenje broja b i-tom cifrom broja a */
pomnozi_cifrom(b, duzina_b, a[i], pom, &duzina_pom);
38
Milena Vujošević–Janičić 4.2 Veliki brojevi
}
if (prenos)
{
rezultat[i+k] = prenos;
*duzina_rezultata = i+k+1;
}
else
*duzina_rezultata = i+k;
}
}
/* Ucitavaju se brojevi */
printf("Unesite prvi broj : ");
duzina_a = uzmi_broj(a,MAX_CIFRE);
39
Glava 5
Sortiranje
• rastućem poretku:
niz[0] < niz[1] < ... < niz[i] < niz[i + 1] < ... < niz[n − 1]
• neopadajućem poretku:
niz[0] ≤ niz[1] ≤ ... ≤ niz[i] ≤ niz[i + 1] ≤ ... ≤ niz[n − 1]
• nerastućem poretku:
niz[0] ≥ niz[1] ≥ ... ≥ niz[i] ≥ niz[i + 1] ≥ ... ≥ niz[n − 1]
40
Milena Vujošević–Janičić 5.2 Selection sort
/*Sortiranje*/
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]<a[j])
{
pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}
main()
{
/* Niz od maksimalno MAXDUZ elemenata*/
41
Milena Vujošević–Janičić 5.2 Selection sort
int a[MAXDUZ];
if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n\n");
exit(1);
}
selection(a,n);
/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);
putchar(’\n’);
}
Primer 5.2 (Selection sort2) Modifikacija prethodnog rešenja radi dobijanja na
efikasnosti. Ne vrše se zamene svaki put već samo jednom, kada se pronad̄e odgo-
varajući element u nizu sa kojim treba izvršiti zamenu tako da u nizu bude postavljen
trenutno najveći element na odgovarajuće mesto.
Primer sortiranja:
n = 6 a: 1 3 5 2 6 8
-------------
i = 0 => a: 8 1 5 2 6 3
-------------
i = 1 => a: 8 6 5 2 1 3
-------------
i = 2 => a: 8 6 5 2 1 3
-------------
42
Milena Vujošević–Janičić 5.3 Bubble sort
...
void selection2(int a[], int n)
{
int i, j, max;
43
Milena Vujošević–Janičić 5.3 Bubble sort
i = 4 j = 0 => a: 5 3 2 6 8 1
...
zam=1;
for(i=n-1; zam && i>0; i--)
for(zam=0,j=0; j<i; j++)
if(a[j]<a[j+1])
{
/* Zamena odgovarajucih clanova niza */
pom=a[j];
a[j]=a[j+1];
a[j+1]=pom;
44
Milena Vujošević–Janičić 5.4 Insertion sort
Primer 5.6 (Insertion sort 2) Broj dodela se moze redukovati tako sto se umesto
stalnih zamena koristi dodela privremenoj promenljivoj — elemente niza pomeramo
za jedno mesto sve dok ne nad̄emo poziciju na koju treba da postavimo dati element
(koji je sačuvan u privremenoj promenljivoj).
void insertion2(int a[], int n)
{
int i, j, tmp;
for (i = 1; i < n; i++)
{
int tmp = a[i];
45
Milena Vujošević–Janičić 5.5 Razni zadaci
return k;
}
46
Milena Vujošević–Janičić 5.5 Razni zadaci
main() {
int a[] = {1, 5, 6, 9, 13};
int b[] = {2, 3, 7, 11, 12, 15};
int c[30];
int na = sizeof(a)/sizeof(int);
int nb = sizeof(b)/sizeof(int);
int nc = merge(a, na, b, nb, c);
int i;
#define MAX_IME 20
while (isspace(c=getchar()))
;
word[i]=’\0’;
47
Milena Vujošević–Janičić 5.5 Razni zadaci
else return i;
main()
{
student studenti[100];
48
Milena Vujošević–Janičić 5.5 Razni zadaci
SelectionSort(studenti, br_studenata);
IspisiPodatke(studenti, br_studenata);
}
Primer 5.9 Program učitava informacije o studentima iz datoteke čije se ime zadaje
iz komandne linije, i koja je u formatu:
n
prezime1 ime1 smer1 prosek1
prezime2 ime2 smer2 prosek2
...
prezimen imen smern prosekn
Studenti se sortiraju leksikografski po prezimenima i imenima, a zatim se njihovi
podaci tako sortirani ispisuju na izlaz, ili u izlazni fajl, ako je njegovo ime zadato u
komandnoj liniji.
#include <stdio.h>
#include <string.h>
#define MAX_IME 20
#define MAX_PREZIME 30
#define MAX_SMER 10
char ime[MAX_IME];
char prezime[MAX_PREZIME];
char smer[MAX_SMER];
double prosek;
} Student;
49
Milena Vujošević–Janičić 5.5 Razni zadaci
if (min != i)
{
pom = studenti[i];
studenti[i] = studenti[min];
studenti[min] = pom;
}
}
}
50
Milena Vujošević–Janičić 5.5 Razni zadaci
/* Funkcija main */
int main (int argc, char ** argv)
{
int n, i;
FILE *in = stdin, *out = stdout;
Student studenti[MAX_STUDENATA];
51
Milena Vujošević–Janičić 5.5 Razni zadaci
fclose(in);
fclose(out);
return 0;
}
Primer 5.10 Program utvrd̄uje da li su dve niske karaktera anagrami. Dve niske
su anagrami ako se sastoje od istog broja istih karaktera. Na primer, niske ”trave”
i ”vetar” jesu anagrami, dok ”vetar” i ”vatra” nisu.
#include <stdio.h>
#include <string.h>
if (min != i)
{
pom = s[i];
s[i] = s[min];
s[min] = pom;
}
}
52
Milena Vujošević–Janičić 5.5 Razni zadaci
/* Test program */
int main ()
{
53
Milena Vujošević–Janičić 5.5 Razni zadaci
return 0;
}
Primer 5.11 Interpolaciona pretraga se može porediti sa pretragom rečnika:
ako neko traži reč na slovo B, sigurno neće da otvori rečnik na polovini, već verovatno
negde bliže početku.
/* Funkcija trazi u SORTIRANOM nizu a[] duzine n
broj x. Vraca indeks pozicije nadjenog elementa
ili -1, ako element nije pronadjen */
int interpolaciona_pretraga (int a[], int n, int x)
{
int l = 0;
int d = n - 1;
int s;
54
Milena Vujošević–Janičić 5.5 Razni zadaci
55
Milena Vujošević–Janičić 5.5 Razni zadaci
i++;
/* Ako je element niza b manji, tada u tom nizu prelazimo
na sledeci element */
else
j++;
}
/* Vracamo broj elemenata preseka */
return k;
56
Milena Vujošević–Janičić 5.5 Razni zadaci
c[k++] = a[i++];
57
Glava 6
Pokazivači
main()
{
void *pp; /* Ovaj pokazivac moze da pokazuje na adrese
na kojima se nalaze razliciti tipovi
podataka. */
int x=2;
58
Milena Vujošević–Janičić 6.1 Pokazivačka aritmetika — primeri
char c=’a’;
/*
Adresa od x je 0012FF78
17 i 0012FF78
Adresa od c je 0012FF74
a i 0012FF74
*/
#include <stdio.h>
59
Milena Vujošević–Janičić 6.1 Pokazivačka aritmetika — primeri
main()
{
int a[]={1,2,3,4,5,6,7,8};
int* poz=nadjiint(a,sizeof(a)/sizeof(int),4);
if (poz!=NULL)
printf("Element pronadjen na poziciji %d\n",poz-a);
}
60
Milena Vujošević–Janičić 6.1 Pokazivačka aritmetika — primeri
}
*dest = ’\0’;
*/
Primer 6.5 Nadovezuje string t na kraj stringa s. Pretpostavlja da u s ima do-
voljno prostora.
void string_concatenate(char *s, char *t)
{
/* Pronalazimo kraj stringa s */
while (*s) /* while (*s != 0)*/
s++;
/* Nakon prethodne petlje, s pokazuje na ’\0’, kopiranje
pocinje od tog mesta, tako da ce znak ’\0’ biti prepisan. */
/* Kopiranje se vrisi slicno funkciji string_copy */
while (*s++ = *t++)
;
}
Primer 6.6 Funkcija strcmp vrši leksikografsko pored̄enje dva stringa. Vraća:
0 — ukoliko su stringovi jednaki
<0 — ukoliko je s leksikografski ispred t
>0 — ukoliko je s leksikografski iza t
return *s - *t;
}
Primer 6.7 Pronalazi prvu poziciju karaktera c u stringu s, i vraća pokazivač na
nju, odnosno NULL ukoliko s ne sadrži c.
char* string_char(char *s, char c)
{
61
Milena Vujošević–Janičić 6.1 Pokazivačka aritmetika — primeri
int i;
for (; *s; s++)
if (*s == c)
return s;
/* Nije nadjeno */
return NULL;
}
/* Nije nadjeno */
return NULL;
}
Primer 6.9 Za svaku liniju ucitanu sa ulaza proverava se da li sadrži reč zdravo.
#include <stdio.h>
62
Milena Vujošević–Janičić 6.1 Pokazivačka aritmetika — primeri
/* Nije nadjeno */
return NULL;
}
if (c==’\n’)
*s++ = c;
*s = ’\0’;
return s - line;
}
main()
{
char rec[]="zdravo";
char linija[100];
while (getline(linija, 100))
if (sadrzi_string_pok(linija, rec))
63
Milena Vujošević–Janičić 6.2 Niska karaktera i pokazivač na konstantnu nisku
printf("%s",linija);
}
64
Milena Vujošević–Janičić 6.3 Pokazivači na pokazivače
65
Milena Vujošević–Janičić 6.4 Nizovi pokazivača
Primer 6.11 Program ucitava linije iz fajla ulaz.txt i zatim ih ispisuje na stan-
dardnom izlazu sortirane po dužini, počev od najkraće linije.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main()
{
char redovi[MAX_REDOVA][MAX_RED];
char *p_redovi[MAX_REDOVA];
int i, n;
FILE * in;
/* Otvaramo fajl */
in = fopen("ulaz.txt", "r");
n = i;
66
Milena Vujošević–Janičić 6.4 Nizovi pokazivača
/* Zatavaramo fajl */
fclose(in);
return 0;
}
p = *s;
*s = *t;
*t = p;
}
67
Milena Vujošević–Janičić 6.4 Nizovi pokazivača
if(min != i)
{
razmeni(&redovi[min], &redovi[i]);
}
}
}
68
Glava 7
Rekurzija
Funkcija1 moze da poziva samu sebe, neposredno ili posredno. Ova pojava se zove
rekurzija. Ovakav pristup se cesto koristi prilikom resavanja problema koji imaju
prirodnu rekurzivnu definiciju, tj. kod kojih se problem dimenzije n moze jednos-
tavno svesti na problem dimenzije n-1 ili neke druge manje dimenzije. Rekurzija je
analogna matematickoj indukciji.
Ono sto je potencijalni problem kod razumevanja rekurzije je to sto se u jednom
trenutku mogu izvrsavati vise poziva jedne iste funkcije. Na primer, ako funkcija
f() prilikom svog izvrsavanja pozove samu sebe, tada se zapocinje novi poziv iste
funkcije. Prethodni poziv ceka da se zavrsi tekuci, a zatim nastavlja sa radom. Poziv
rekurzivne funkcije koji je zapocet, a cije izvrsavanje jos nije zavrseno nazivamo
aktivni poziv. Svaki poziv funkcije izvrsava se nezavisno od svih ostalih aktivnih
poziva u tom trenutku, zahvaljujuci cinjenici da svaki od aktivnih poziva ima svoje
sopostvene kopije formalnih parametara i lokalnih podataka. Kada se neki od poziva
zavrsi, njegove kopije nestaju iz memorije, ali kopije ostalih poziva i dalje postoje u
memoriji. Posledica ovog pristupa je da kada rekurzivna funkcija promeni vrednosti
svojih lokalnih podataka, ove promene ne uticu na ostale aktivne pozive, zato sto
oni imaju svoje lokalne kopije istih podataka.
Kreiranje i odrzavanje lokalnih kopija se jednostavno i efikasno ostvaruje zah-
valjujuci tome sto su parametri funkcije i lokalne nestaticke promenljive smestene
na sistemskom steku — u pitanju je struktura podataka u kojoj se novi podaci uvek
smestaju na vrh a prilikom uklanjanja podataka takodje se uklanja podatak sa vrha,
tj. podatak koji je poslednji dodat (LIFO struktura — last in, first out). Prilikom
pozivanja bilo koje funkcije najpre se na stek smeste njeni argumenti (one vrednosti
koje su predate prilikom poziva) a zatim se na vrh steka smeste i lokalne promenljive.
Nakon toga se zapocne izvrsavanje tela funkcije. Ako se tom prilikom pozove neka
druga funkcija (ili ta ista, ako je rekurzija u pitanju) tada se na vrh steka dodaju
argumenti ovog poziva, kao i lokalne promenljive te funkcije, itd. Kada se funkci-
jski poziv zavrsi, tada se sa vrha steka skidaju njegove lokalne promenljive, kao i
parametri poziva, nakon cega na vrhu steka ostaju lokalne promenljive prethodnog
poziva itd.
1 Tekst preuzet sa www.matf.bg.ac.rs/m̃ilan
69
Milena Vujošević–Janičić 7.1 Osnovni primeri
/* Alternativni zapis:
return n == 0 ? 1 : n*faktorijel(n-1); */
main()
{
int n;
unsigned long f;
printf("Unesite n\n");
scanf("%d", &n);
f = faktorijel(n);
70
Milena Vujošević–Janičić 7.1 Osnovni primeri
printf("f = %d\n",f);
}
main()
{
int s,n;
printf("Unesite n\n");
scanf("%d", &n);
s = suma(n);
printf("s = %d\n",s);
}
71
Milena Vujošević–Janičić 7.1 Osnovni primeri
int main()
{
long int b=-1234;
printb(b);
putchar(’\n’);
return 0;
}
Kad funkcija rekurzivno pozove sebe, svakim pozivom pojavljuje se novi skup svih
automatskih promenljivih, koji je nezavisan od prethodonog skupa. Prva funkcija
printb kao argument dobija broj -12345, ona prenosi 1234 u drugu printb funkciju,
koja dalje prenosi 123 u treću, i tako redom do poslednje koja prima 1 kao argument.
Ta funkcija štampa 1 i završava sa radom tako da se vraća na prethodni nivo, na
kome se štampa dva i tako redom.
Primer 7.5 Stepenovanje prirodnog broja
• iterativno
• rekurzivno, koristeći činjenicu da je xk = x · xk−1 i x0 = 1
k k−1
• rekurzivno, koristeći činjenicu da je xk = (x2 ) 2 ako je k parno ili xk = x(x2 ) 2
ako je k neparno, i x0 = 1 i x1 = x.
#include <stdio.h>
72
Milena Vujošević–Janičić 7.1 Osnovni primeri
int s = 1;
for (i = 0; i<k; i++)
s*=x;
return s;
}
if (k == 0)
return 1;
else
return x*stepen(x, k-1);
73
Milena Vujošević–Janičić 7.1 Osnovni primeri
{
p = stepen(n, k/2);
if(k%2 == 0) s = p*p;
else s = p*p*n;
}
return s;
}
*/
main()
{
printf("Stepen je: %d\n", stepen(2, 8));
printf("------------------\n");
printf("Stepen je: %d\n", stepen2(2, 8));
}
/* Izlaz iz programa:
Racunam stepen(2, 8)
Racunam stepen(2, 7)
Racunam stepen(2, 6)
Racunam stepen(2, 5)
Racunam stepen(2, 4)
Racunam stepen(2, 3)
Racunam stepen(2, 2)
Racunam stepen(2, 1)
Racunam stepen(2, 0)
Stepen je: 256
------------------
Racunam stepen2(2, 8)
Racunam stepen2(4, 4)
Racunam stepen2(16, 2)
Racunam stepen2(256, 1)
Stepen je: 256
*/
Primer 7.6 Fibonačijevi brojevi se definišu rekurentno na sledeći način:
f(0) = 1, f(1) = 1, f(n) = f(n-1) + f(n-2)
Napisati funkciju koja izračunava n-ti Fibonačijev broj.
#include <stdio.h>
#include <stdlib.h>
74
Milena Vujošević–Janičić 7.1 Osnovni primeri
if((n==0)||(n==1))
return 1;
else
return(Fib(n-1)+Fib(n-2));
/* Alternativni zapis:
return (n == 0 || n == 1) ? 1 : Fib(n-1) + Fib(n-2); */
}
75
Milena Vujošević–Janičić 7.1 Osnovni primeri
Racunam Fib(1)
Fib(5) = 8
Fib(5)?
=> 8 = 5+3
/ \
/ \
/ \
Fib(4)? Fib(3)?
=> 5=3+2 => 3=2+1
/ \ / \
Fib(3)? Fib(2)? Fib(2)? Fib(1)?
=> 3=2+1 => 2=1+1 => 2=1+1 |
/ \ / \ / \ 1
Fib(2)? Fib(1) Fib(1) Fib(0) Fib(1) Fib(0)
=> 2=1+1 | | | | |
/ \ 1 1 1 1 1
Fib(1) Fib(0)
| |
1 1
_______________________________________________________________
*/
Primer 7.7 U slučaju da se rekurzijom problem svodi na više manjih podproblema
koji se mogu preklapati, postoji opasnost da se pojedini podproblemi manjih dimenz-
ija rešavaju veći broj puta. Na primer,
fibonacci(20) = fibonacci(19) + fibonacci(18)
fibonacci(19) = fibonacci(18) + fibonacci(17)
tj. problem fibonacci(18) se resava dva puta. Problemi manjih dimenzija će se
rešavati još veći broj puta. Rešenje za ovaj problem je kombinacija rekurzije sa tzv.
”dinamičkim programiranjem” – podproblemi se rešavaju samo jednom, a njihova
rešenja se pamte u memoriji (obično u nizovima ili matricama), odakle se koriste
ako tokom rešavanja ponovo budu potrebni.
#include <stdio.h>
#include <stdlib.h>
#define MAX 50
76
Milena Vujošević–Janičić 7.1 Osnovni primeri
/* Izlaz iz rekurzije */
if(n < 2)
return f[n] = 1;
else
/* Rekurzivni pozivi */
return f[n] = fibonacci(n - 1) + fibonacci(n - 2);
}
/* Test program */
int main()
{
int n, i;
/*Inicijalizuje se niz*/
for(i=0; i<MAX; i++)
f[i] = 0;
scanf("%d", &n);
printf("%d\n", fibonacci(n));
return 0;
}
Primer 7.8 Program rešava problem tzv. ”hanojskih kula”: data su tri vertikalna
štapa, na jednom se nalazi n diskova poluprečnika 1,2,3,... do n, tako da se najveći
nalazi na dnu, a najmanji na vrhu. Ostala dva štapa su prazna. Potrebno je pre-
mestiti diskove na drugi štap tako da budu u istom redosledu, premeštajući jedan po
jedan disk, pri čemu se ni u jednom trenutku ne sme staviti veći disk preko manjeg.
77
Milena Vujošević–Janičić 7.1 Osnovni primeri
/*
| | |
=== | |
===== | |
======= | |
========= | |
----------- ----------- -----------
X Y Z
===>
...
| | |
| | |
| | ===
| | =====
========= | =======
----------- ----------- -----------
X Y Z
...
===>
| | |
| === |
| ===== |
| ======= |
| ========= |
----------- ----------- -----------
X Y Z
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
78
Milena Vujošević–Janičić 7.1 Osnovni primeri
/* Funkcija premesta jedan disk sa vrha prve kule na vrh druge kule */
void move(Tower *from, Tower * to)
{
/* Proveravamo da li je potez ispravan */
if(from->n == 0 || (to->n > 0 && from->s[from->n - 1] >= to->s[to->n - 1]))
{
/* Premestanje diska */
to->s[to->n++] = from->s[--from->n];
79
Milena Vujošević–Janičić 7.1 Osnovni primeri
}
}
/* Test program */
int main()
{
Tower x, y, z;
int n;
80
Milena Vujošević–Janičić 7.2 Binarna pretraga
print_tower(&z);
return 0;
}
main()
81
Milena Vujošević–Janičić 7.3 MergeSort algoritam
{
int a[] = {3, 5, 7, 9, 11, 13, 15};
int x;
int i;
if (i==-1)
printf("Elementa %d nema\n", x);
else
printf("Pronadjen na poziciji %d\n", i);
}
/* sortiranje ucesljavanjem */
void merge_sort (int a[], int l, int d)
{
int s;
int b[MAX]; /* pomocni niz */
int i, j, k;
/* Izlaz iz rekurzije */
if (l >= d)
return;
/* rekurzivni pozivi */
merge_sort (a, l, s);
merge_sort (a, s + 1, d);
82
Milena Vujošević–Janičić 7.3 MergeSort algoritam
while(i <= s)
b[k++] = a[i++];
while(j <= d)
b[k++] = a[j++];
/* Test program */
int main(int argc, char ** argv)
{
int a[MAX];
int n, i;
int x;
/* Poziv funkcije */
merge_sort(a, 0, n - 1);
/* Prikaz niza */
for(i = 0; i < n; i++)
printf("%d ", a[i]);
83
Milena Vujošević–Janičić 7.4 QuickSort algoritam
putchar(’\n’);
return 0;
}
84
Milena Vujošević–Janičić 7.4 QuickSort algoritam
/* Zahtevanu konfiguraciju < < < < pivot > > > > dobijamo tako
sto zamenimo mesto pivotu i poslednjem elementu manjem od njega */
swap(a, l, last);
main()
{
int a[] = {5, 8, 2, 4, 1, 9, 3, 7, 6};
int n = sizeof(a)/sizeof(int);
int i;
quick_sort(a, 0, n-1);
85
Glava 8
Pokazivači na funkcije
Binarne instrukcije koje čine funkciju su takod̄e negde u memoriji, i imaju svoju
adresu. Zato je moguće je definisati pokazivač na funkciju. Na primer, deklaracija:
int (*fp)(int);
definiše promenljivu f, koja je tipa ”pokazivač na funkciju koja prihvata argument
tipa int, i vraca vrednost tipa int”. Ova promenljiva sadrži adresu neke funkcije
tog tipa. Na primer, ako je deklarisana funkcija:
int f(int a);
Tada je moguce dodeliti:
fp = &f; /* Operator adrese nije neophodan. */
Promenljiva fp sadrži adresu funkcije f. Funkcija f se sada može pozivati derefer-
enciranjem pokazivača fp:
(*fp)(3);
Zagrade oko izraza *fp su neophodne zbog prioriteta operatora. Dereferenciranjem
pokazivača na funkciju dobija se funkcija, koja se onda poziva na uobičajen način.
int kvadrat(int n)
{
return n*n;
}
int kub(int n)
{
return n*n*n;
}
86
Milena Vujošević–Janičić Pokazivači na funkcije
int parni_broj(int n)
{
return 2*n;
}
return suma;
}
main()
{
/* Ili:
printf("Suma kvadrata brojeva od jedan do 3 je %d\n", sumiraj(&kvadrat,3));
printf("Suma kubova brojeva od jedan do 3 je %d\n", sumiraj(&kub,3));
printf("Suma prvih pet parnih brojeva je %d\n", sumiraj(&parni_broj,5));
*/
}
/*Izlaz:
Suma kvadrata brojeva od jedan do 3 je 14
Suma kubova brojeva od jedan do 3 je 36
Suma prvih pet parnih brojeva je 30
*/
87
Milena Vujošević–Janičić Pokazivači na funkcije
/*
Zaglavlje math.h sadrzi deklaracije razih matematickih funkcija. Izmedju
ostalog, to su sledece funkcije:
double sin(double x);
double cos(double x);
double tan(double x);
double asin(double x);
double acos(double x);
double atan(double x);
double atan2(double y, double x);
double sinh(double x);
double cosh(double x);
double tanh(double x);
double exp(double x);
double log(double x);
double log10(double x);
double pow(double x, double y);
double sqrt(double x);
double ceil(double x);
double floor(double x);
double fabs(double x);
*/
printf("-----------------------\n");
for(x = a; x <= b; x+=h)
printf("| %8.3f | %8.3f |\n", x, (*f)(x));
printf("-----------------------\n");
88
Milena Vujošević–Janičić 8.1 Funkcija qsort iz standardne biblioteke
/* Funkcija main */
int main()
{
double a, b, h;
/* Unosimo korak */
printf("Uneti korak: ");
scanf("%lf", &h);
return 0;
}
89
Milena Vujošević–Janičić 8.1 Funkcija qsort iz standardne biblioteke
vraća pozitivnu vrednost ako je prvi manji, 0 ako su jednaki i negativnu vrednost
ako je prvi veci).
Kvalifikator const
Kljucna rec const u programskom jeziku C sluzi za definisanje konstanti. Ako
napisemo:
const int a = 2;
tada se u daljem toku programa promenljivoj a ne moze dodeljivati vrednost. Za
razliku od konstanti definisanih define direktivom ova konstanta ima jasno definisan
tip koji prevodilac proverava prilikom upotrebe.
Treba naglasiti, medjutim, da ako se napiše:
const int * p = &a;
tada se const ne odnosi na promenljivu p, vec na podatak tipa int na koji p
pokazuje. Dakle, nije pokazivač konstantan, već on pokazuje na konstantan podatak.
Na primer:
int b;
p = &b;
je dozvoljeno, ali:
*p = 4;
nije dozvoljeno, zato sto je p pokazivač na konstantan int (odnosno, kroz pokazivač
p nije moguće menjati vrednost koja se nalazi na adresi na koju on ukazuje). Ovo
se moze razumeti tako sto se deklaracija pročita sa desna u levo:
const int * p; /* p je pokazivac na int koji je konstantan*/
Slično bi bilo i ako napišemo:
int const * p; /* p je pokazivac na konstantan int. */
Med̄utim, ako napišemo:
int * const p; /* p je konstantan pokazivac na int. */
Kombinacija ovoga je:
const int * const p; /* p je konstantan pokazivac na int
koji je konstantan.*/
Dakle, u ovom poslednjem slučaju konstantni su i pokazivač i ono na sta on pokazuje.
90
Milena Vujošević–Janičić 8.1 Funkcija qsort iz standardne biblioteke
Upotreba qsort
Primer 8.3 Upotrebom qsort funkcije iz standardne biblioteke izvršiti sortiranje
niza celih i niza realnih brojeva.
/* Ilustracija upotrebe funkcije qsort iz stdlib.h
Sortira se niz celih brojeva.
*/
#include <stdlib.h>
#include <stdio.h>
return br_a-br_b;
*/
return *((int*)a)-*((int*)b);
}
main()
{
int i;
int niz[]={3,8,7,1,2,3,5,6,9};
float nizf[]={3.0,8.7,7.8,1.9,2.1,3.3,6.6,9.9};
int n=sizeof(niz)/sizeof(int);
qsort((void*)niz, n, sizeof(int), poredi);
for(i=0; i<n; i++)
printf("%d",niz[i]);
91
Milena Vujošević–Janičić 8.1 Funkcija qsort iz standardne biblioteke
n=sizeof(nizf)/sizeof(float);
qsort((void*)nizf, n, sizeof(float), poredi_float);
for(i=0; i<n; i++)
printf("%f",nizf[i]);
}
Primer 8.4 Sortiranje reči. Ako se sortira niz stringova, onda svaki element je
sam po sebi pokazivač tipa char *, te funkcija pored̄enja tada prima podatke tipa
char ** koji se konvertuju u svoj tip i derefenciraju radi dobijanja podataka tipa
char *.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
main()
{
int i;
char* nizreci[]={"Jabuka","Kruska","Sljiva","Dinja","Lubenica"};
92
Milena Vujošević–Janičić 8.2 Funkcija bsearch iz standardne biblioteke
qsort((void*)nizreci, sizeof(nizreci),
sizeof(char*), poredi_leksikografski);
printf("Sortirano:\n");
for (i=0; i<sizeof(nizreci); i++)
printf("%s\n",nizreci[i]);
}
/*
Izlaz:
Dinja Jabuka Kruska Lubenica Sljiva
Sortirano:
Lubenica Kruska Jabuka Sljiva Dinja
*/
93
Milena Vujošević–Janičić 8.2 Funkcija bsearch iz standardne biblioteke
main()
{
int x=-1;
int niz[]={1,2,3,4,5,6,7,8,9,10,11,12};
int* elem=(int*)bsearch((void*)&x,
(void*)niz,
sizeof(niz)/sizeof(int),
sizeof(int),
poredi);
if (elem==NULL)
printf("Element nije pronadjen\n");
else
printf("Element postoji na poziciji %d\n",elem-niz);
}
Primer 8.6 Sa ulaza se unose reči. Program broji pojavljivanja svake od ključnih
reči programskog jezika C. Na kraju se reči ispisuju opadajuće po broju pojavljivanja.
#include <stdio.h>
#include <stdlib.h>
94
Milena Vujošević–Janičić 8.2 Funkcija bsearch iz standardne biblioteke
word[i]=’\0’;
return i;
}
95
Milena Vujošević–Janičić 8.2 Funkcija bsearch iz standardne biblioteke
main()
{
char word[80];
int i;
/* Citamo reci */
while (getword(word,80)!=-1)
{
/* Trazimo rec u spisku kljucnih reci binarnom pretragom */
/* Prvi argument funkcije bsearch treba da bude pokazivac
na rec koju trazimo. Posto je word tipa niza karaktera, tada
uzimanjem adrese od word dobijamo istu vrednost kao i word,
tj nema razlike izmedju word i &word. Zbog toga se u funkciji
poredjenja koristi dreferenciranje na sledeci nacin
strcmp((char*)a, (*(keyword*)b).word); }
Da je word tipa char*, tada bi poziv funkcije bsearch
sa argumentom &word povlacilo da funkcija poredjenja
koristi dereferenciranje na sledeci nacin
strcmp(*(char**)a, (*(keyword*)b).word); }
*/
keyword* k=(keyword*)bsearch((void*)word,
(void*)keywords,
num_of_keywords,
sizeof(keyword),
cmp);
/* Ukoliko je pronadjena uvecavamo broj pojavljivanja */
if (k!=NULL)
(*k).num++;
}
/* Vrsimo ispis */
for (i=0; i<num_of_keywords; i++)
96
Milena Vujošević–Janičić 8.3 Funkcije lsearch i lfind
8.4 Pokazivači
Primer 8.7 Različite deklaracije:
int *p; pokazivac na int
int **p; pokazivac na pokazivac na tip int
97
Milena Vujošević–Janičić 8.4 Pokazivači
98
Glava 9
99
Milena Vujošević–Janičić Dinamička alokacija memorije
main()
{
int n;
int i;
int *a;
100
Milena Vujošević–Janičić Dinamička alokacija memorije
/* Oslobadjamo memoriju*/
free(a);
}
Primer 9.2 Demonstracija funkcije calloc - funkcija inicijalizuje sadrzaj memo-
rije na 0.
#include <stdio.h>
#include <stdlib.h>
main()
{
int *m, *c, i, n;
101
Milena Vujošević–Janičić Dinamička alokacija memorije
/*Odstampace se nule*/
for (i = 0; i<n; i++)
printf("c[%d] = %d\n", i, c[i]);
102
Milena Vujošević–Janičić Dinamička alokacija memorije
/* Vracamo p */
return p;
}
int main()
{
char * p = NULL;
char s[MAX], t[MAX];
/* Ucitavamo stringove */
scanf("%s", s);
scanf("%s", t);
/* Nadovezujemo stringove */
p = nadovezi_stringove(s,t);
/* Prikazujemo rezultat */
printf("%s\n", p);
/* Oslobadjamo memoriju*/
free(p);
return 0;
}
Primer 9.4 Niz pokazivača na nizove različitih dužina.
#include <stdio.h>
#include <stdlib.h>
main()
{
/* Niz od tri elemenata tipa int*/
int nizi[3];
103
Milena Vujošević–Janičić Dinamička alokacija memorije
printf("%d", nizip[1][1]);
104
Milena Vujošević–Janičić 9.1 Matrice
*(nizip[2]) = 2;
printf("%d", *(nizip[2]));
/* Oslobadjamo memoriju. */
free(nizip[0]);
free(nizip[1]);
free(nizip[2]);
}
9.1 Matrice
Primer 9.5 Statička alokacija prostora za matricu.
#include <stdio.h>
main()
{
int i, j;
printf("%d\n", a[1][1]); /* 22 */
105
Milena Vujošević–Janičić 9.1 Matrice
}
}
Ukoliko je potrebna veća fleksibilnost, tj. da se dimenzije matrice mogu uneti kao
parametri programa, tada je neophodno koristiti dinamičku alokaciju memorije.
Primer 9.6 Implementacija matrice preko niza.
#include <stdlib.h>
#include <stdio.h>
main()
{
/* Dimenzije matrice */
int m, n;
/* Matrica */
int *a;
int i,j;
/* Unos i alokacija */
printf("Unesi broj vrsta matrice : ");
scanf("%d",&m);
106
Milena Vujošević–Janičić 9.1 Matrice
scanf("%d",&a(i,j));
}
/* Oslobadjamo memoriju */
free(a);
}
Primer 9.7 Druga opcija za implementaciju matrice je koristći pokazivač na pokazivač.
1. Definišemo pokazivač na pokazivač na int:
int **p;
Ovaj pokazivač će čuvati adresu prvog u nizu dinamički alociranih pokazivača
na int-ove.
2. Dinamički alociramo niz od m pokazivača na int-ove, i adresu prvog u nizu
smeštamo u promenljivu p:
p = (int**) malloc(sizeof(int*) * m));
Ovi pokazivači služe da pokazuju na prve elemente nizova int-ova koji pred-
stavljaju dinamički alocirane vrste.
3. Svaku vrstu alociramo posebnim malloc-om, i povratnu adresu smeštamo u i-ti
pokazivač u malopre alociranom nizu pokazivača.
for(i = 0; i < m; i++)
p[i] = malloc(sizeof(int) * n);
Primetimo da nizovi int-ova koji se alociraju nisu morali biti jednakih dimen-
zija (ne moraju svi biti duzine n, kao što je ovde rečeno). Ovo može da bude
korisno, ako znamo da će u nekoj vrsti biti korišćeno samo nekoliko prvih ele-
menata, tada možemo alocirati manje za tu vrstu, i tako uštedeti prostor.
107
Milena Vujošević–Janičić 9.1 Matrice
#include <stdio.h>
#include <stdlib.h>
int main()
{
int **p;
int m, n;
int i, j;
108
Milena Vujošević–Janičić 9.1 Matrice
/* Ispis matrice */
for(i = 0; i < m ; i++)
{
for(j = 0; j < n; j++)
printf("%3d ", p[i][j]);
putchar(’\n’);
}
return 0;
}
Primer 9.8 Program ilustruje rad sa kvadratnim matricama i relacijama. Kôd za
alokaciju i dealokaciju memorije je izdvojen u funkcije. Element i je u relaciji sa
elementom j ako je m[i][j] = 1, a nisu u relaciji ako je m[i][j] = 0.
#include <stdlib.h>
#include <stdio.h>
109
Milena Vujošević–Janičić 9.1 Matrice
{
int k;
printf("Greska prilikom alokacije memorije!\n");
for(k=0;k<i;k++)
free(m[k]);
free(m);
exit(1);
}
}
return m;
}
/* Ispis matrice /
void ispisi_matricu(int** m, int n)
{
int i, j;
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
printf("%d ",m[i][j]);
printf("\n");
}
}
return 1;
}
110
Milena Vujošević–Janičić 9.1 Matrice
main()
{
int **m;
111
Milena Vujošević–Janičić 9.1 Matrice
int n;
int i,j;
ispisi_matricu(m,n);
if (refleksivna(m,n))
printf("Relacija je refleksivna\n");
if (simetricna(m,n))
printf("Relacija je simetricna\n");
if (tranzitivna(m,n))
printf("Relacija je tranzitivna\n");
simetricno_zatvorenje(m,n);
ispisi_matricu(m,n);
obrisi(m,n);
}
Primer 9.9 Izračunati vrednost determinante matrice preko Laplasovog razvoja.
#include <stdio.h>
#include <stdlib.h>
112
Milena Vujošević–Janičić 9.1 Matrice
{
m[i]=malloc(n*sizeof(int));
if (m[i] == NULL)
{
int k;
for(k=0;k<i;k++)
free(m[k]);
printf("Greska prilikom alokacije memorije!\n");
free(m);
exit(1);
}
}
return m;
}
113
Milena Vujošević–Janičić 9.2 Realokacija memorije
det+= znak*matrica[0][i]*determinanta(podmatrica,n-1);
znak*=-1;
}
deallocate(podmatrica,n-1);
return det;
}
main()
{
int **matrica;
int n;
scanf("%d", &n);
matrica = allocate(n);
ucitaj_matricu(matrica, n);
printf("Determinanta je : %d\n",determinanta(matrica,n));
deallocate(matrica, n);
}
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
114
Milena Vujošević–Janičić 9.2 Realokacija memorije
while (isspace(c=getchar()))
;
word[i]=’\0’;
main()
{
char procitana_rec[80];
int i;
115
Milena Vujošević–Janičić 9.2 Realokacija memorije
while (getword(procitana_rec,80)!=-1)
{
/* Proveravamo da li rec vec postoji u nizu */
for (i=0; i<duzina; i++)
/* Ako bismo uporedili procitana_rec == niz_reci[i].ime
bili bi uporedjeni pokazivaci a ne odgovarajuci sadrzaji.
Zato koristimo strcmp. */
if (strcmp(procitana_rec, niz_reci[i].ime)==0)
{
niz_reci[i].br_pojavljivanja++;
break;
}
if (novi_niz == NULL)
{
free(niz_reci);
printf("Greska prilikom alokacije memorije");
exit(1);
}
116
Milena Vujošević–Janičić 9.2 Realokacija memorije
free(niz_reci);
}
117
Glava 10
Liste
10.1 Implementacija
Prilikom promene liste (dodavanje novog elementa, brisanje elementa, premestanje
elemenata, itd.) postoji mogućnost da glava liste bude promenjena, tj. da to postane
neki drugi čvor (sa drugom adresom). U tom slučaju se pokazivač na glavu liste mora
ažurirati. Kada promenu liste obavljamo u posebnoj funkciji (kao što je bio slučaj u
prethodnom primeru, gde smo za dodavanje i brisanje imali posebne funkcije) onda
je potrebno da se pozivajućoj funkciji vrati informacija o promeni adrese glave,
kako bi pozivajuća funkcija mogla da ažurira svoju pokazivačku promenljivu. Ovo
se može uraditi na dva načina:
1. Pozvana funkcija koja vrši promenu na listi vraća kao povratnu vrednost adresu
glave nakon promene. Ova adresa može biti ista kao i pre promene (ako glava
nije dirana) a može se i razlikovati. U svakom slučaju, ta adresa treba da se
dodeli pokazivačkoj promenljivoj koja čuva adresu glave u pozivajućoj funkciji.
1 Tekst preuzet sa sajta www.matf.bg.ac.rs/ milan
118
Milena Vujošević–Janičić 10.1 Implementacija
novi->vrednost = broj;
novi->sledeci = NULL;
119
Milena Vujošević–Janičić 10.1 Implementacija
return novi;
}
/* Ako lista nije prazna, tada se krecemo duz liste sve dok
ne dodjemo do poslednjeg cvora (tj. do cvora ciji pokazivac
na sledeci pokazuje na NULL) */
while(tekuci->sledeci != NULL)
tekuci = tekuci->sledeci;
120
Milena Vujošević–Janičić 10.1 Implementacija
/* Ako lista nije prazna, tada se krecemo duz liste sve dok
ne dodjemo do poslednjeg cvora (tj. do cvora ciji pokazivac
na sledeci pokazuje na NULL) */
while(tekuci->sledeci != NULL)
tekuci = tekuci->sledeci;
return NULL;
}
121
Milena Vujošević–Janičić 10.1 Implementacija
{
putchar(’[’);
for(;glava != NULL; glava = glava->sledeci)
printf("%d ", glava->vrednost);
putchar(’]’);
putchar(’\n’);
}
while(glava != NULL)
{
/* moramo najpre zapamtiti adresu sledeceg
elementa, a tek onda osloboditi glavu */
pomocni = glava->sledeci;
free(glava);
glava = pomocni;
}
return NULL;
}
while(*glava != NULL)
{
/* moramo najpre zapamtiti adresu sledeceg
elementa, a tek onda osloboditi glavu */
pomocni = (*glava)->sledeci;
free(*glava);
*glava = pomocni;
}
}
*/
122
Milena Vujošević–Janičić 10.1 Implementacija
123
Milena Vujošević–Janičić 10.1 Implementacija
*glava = novi;
return;
}
124
Milena Vujošević–Janičić 10.1 Implementacija
NULL */
if(glava == NULL) return NULL;
125
Milena Vujošević–Janičić 10.1 Implementacija
return;
}
*/
/* test program */
int main()
{
126
Milena Vujošević–Janičić 10.1 Implementacija
printf("-------------------------------------------------------\n");
printf("---------------- Testiranje pretrage ------------------\n");
printf("-------------------------------------------------------\n");
printf("Prikaz trenutnog sadrzaja liste:\n");
prikazi_listu(glava);
printf("-------------------------------------------------------\n");
printf("Uneti broj koji se trazi: ");
scanf("%d",&broj);
glava = oslobodi_listu(glava);
/*oslobodi_listu(&glava);*/
127
Milena Vujošević–Janičić 10.1 Implementacija
glava = oslobodi_listu(glava);
/*oslobodi_listu(&glava);*/
glava = oslobodi_listu(glava);
/*oslobodi_listu(&glava);*/
return 0;
}
Primer 10.2 Sve funkcije iz prethodnih primera, za koje to ima smisla, definisane
su rekurzivno. Primetno je da su ove rekurzivne varijante mnogo jednostavnije.
Razlog je to što su liste po svojoj prirodi rekurzivne strukture. Naime, liste se mogu
rekurzivno definisati na sledeći način:
• objekat označen sa [] je lista (prazna lista)
• ako je L lista, i G neki element, tada je ured̄eni par (G,L) takod̄e lista. Element
G nazivamo glavom liste, a listu L repom liste.
Na primer, uredjeni par (2, []) je lista, i po dogovoru cemo je zapisivati kao [2].
Takodje par (3,[2]) je lista koju možemo zapisati kao [3 2], itd.
U opstem slucaju, ako je L=[a1 a2 a3 ... an] lista, i ako je b neki element,
tada je uredjeni par (b,L) takod̄e lista, koju možemo zapisati kao [b a1 a2 ... an].
128
Milena Vujošević–Janičić 10.1 Implementacija
Glava liste je b, a rep liste je lista L. Sada se obrada liste može razdvojiti na dva
dela:
• Izvršiti operaciju nad glavom liste
• Izvršiti rekurzivni postupak nad repom liste (koji je takod̄e lista).
Za testiranje narednog programa može se koristiti main funkcija iz primera 10.1.
#include <stdio.h>
#include <stdlib.h>
novi->vrednost = broj;
novi->sledeci = NULL;
return novi;
}
129
Milena Vujošević–Janičić 10.1 Implementacija
}
/*
void dodaj_na_pocetak_liste(Cvor **glava, int broj)
{
Cvor * novi = napravi_cvor(broj);
novi->sledeci = *glava;
*glava = novi;
}
*/
/*
void dodaj_na_kraj_liste(Cvor **glava, int broj)
{
/* Izlaz iz rekurzije: slucaj prazne liste.
U tom slucaju je glava nove liste upravo novi cvor. */
if(*glava == NULL)
*glava = napravi_cvor(broj);
else
/* U slucaju da je lista neprazna, tada ona ima glavu i rep,
pri cemu je rep opet lista. Tada je dodavanje na kraj
liste ekvivalentno dodavanju na kraj repa liste, sto
130
Milena Vujošević–Janičić 10.1 Implementacija
*/
/*
void dodaj_sortirano(Cvor **glava, int broj)
{
131
Milena Vujošević–Janičić 10.1 Implementacija
132
Milena Vujošević–Janičić 10.1 Implementacija
/*
void obrisi_element(Cvor **glava, int broj)
{
133
Milena Vujošević–Janičić 10.1 Implementacija
if(*glava->vrednost == broj)
{
Cvor *pomocni = *glava;
*glava = *glava->sledeci;
free(pomocni);
}
}
*/
/* Izlaz iz rekurzije */
if(glava == NULL) return;
/* Prikaz glave */
printf("%d ", glava->vrednost);
prikazi_listu_r(glava);
putchar(’]’);
putchar(’\n’);
}
134
Milena Vujošević–Janičić 10.1 Implementacija
return NULL;
}
/*
void oslobodi_listu(Cvor **glava)
{
/* Izlaz iz rekurzije */
if(*glava == NULL) return;
*glava = NULL;
}
*/
Primer 10.3 Program ispisuje broj pojavljivanja za svaku od reči koja se pojavila u
tekstu unetom sa standardnog ulaza. Verzija sa (sortiranom) listom.
#include <stdlib.h>
#include <stdio.h>
135
Milena Vujošević–Janičić 10.1 Implementacija
strcpy(novi->ime, rec);
novi->br_pojavljivanja = 1;
novi->sledeci = NULL;
return novi;
}
136
Milena Vujošević–Janičić 10.1 Implementacija
return napravi_cvor(rec);
if (c==EOF)
return -1;
do
{ word[i++]=c;
}while (i<lim-1 && isalpha(c=getchar()));
word[i]=’\0’;
return i;
}
137
Milena Vujošević–Janičić 10.1 Implementacija
main()
{
cvor* lista=NULL;
char procitana_rec[80];
cvor* pronadjen;
while(getword(procitana_rec,80)!=-1)
lista=ubaci_sortirano(lista,procitana_rec);
pronadjen=nadji_rec(lista,"programiranje");
if (pronadjen!=NULL)
printf("Rec programiranje se javlja u listi!\n");
else
printf("Rec programiranje se ne javlja u listi!\n");
ispisi_listu(lista);
obrisi_listu(lista);
}
Primer 10.4 Primer ilustruje sortiranje liste. Lista moze biti sortirana na dva
načina. Prvi način je da se premeštaju čvorovi u listi (što zahteva prevezivanje
pokazivača), a drugi je da se premeštaju vrednosti koje čvorovi sadrže. Prvi način
je komplikovaniji, ali je često efikasniji, naročito ako su objekti koji se čuvaju kao
podaci u čvorovima veliki.
U oba slučaja se može koristiti rekurzija, a može se realizovati i iterativno. U
ovom primeru ilustrujemo oba načina sortiranja lista (prvi rekurzivno, a drugi iter-
ativno).
#include <stdio.h>
#include <stdlib.h>
138
Milena Vujošević–Janičić 10.1 Implementacija
#include <time.h>
novi->vrednost = broj;
novi->sledeci = NULL;
return novi;
}
139
Milena Vujošević–Janičić 10.1 Implementacija
/* Izlaz iz rekurzije */
if(glava == NULL) return;
/* Prikaz glave */
printf("%d ", glava->vrednost);
prikazi_listu_r(glava);
putchar(’]’);
putchar(’\n’);
}
return NULL;
}
140
Milena Vujošević–Janičić 10.1 Implementacija
{
/* u slucaju da je lista prazna, ili da je vrednost
glave veca ili jednaka od vrednosti broja koji
umecemo, tada se novi cvor umece na pocetak liste. */
if(glava == NULL || glava->vrednost >= novi->vrednost)
{
novi->sledeci = glava;
return novi;
}
/* vracamo glavu */
return glava;
}
/* Izlaz iz rekurzije */
if(glava == NULL)
return NULL;
141
Milena Vujošević–Janičić 10.1 Implementacija
/* Vracamo glavu */
return glava;
}
/* test program */
int main()
{
Cvor *glava = NULL;
int n = 10;
142
Milena Vujošević–Janičić 10.2 Kružna (ciklična) lista
srand(time(NULL));
/* Sortiramo listu */
glava = sortiraj_listu(glava);
/* glava = sortiraj_listu2(glava); */
/* Oslobadjamo listu */
glava = oslobodi_listu(glava);
return 0;
}
A B C ... Z
Primer 10.5 (februar 2006.) Grupa od n plesača (na čijim kostimima su u smeru
kazaljke na satu redom brojevi od 1 do n) izvodi svoju plesnu tačku tako što formiraju
krug iz kog najpre izlazi k-ti plesač (odbrojava se počev od plesača označenog brojem
1 u smeru kretanja kazaljke na satu). Preostali plesači obrazuju manji krug iz kog
opet izlazi k-ti plesač (odbrojava se pocev od sledećeg suseda prethodno izbačenog,
opet u smeru kazaljke na satu). Izlasci iz kruga se nastavljaju sve dok svi plesači
143
Milena Vujošević–Janičić 10.3 Red
10.3 Red
A B ... X NULL
novi element
početak reda
novi kraj reda
A B ... X Y NULL
B ... X Y NULL
Red (eng. queue) je struktura podataka nad kojom su definisane sledece operacije:
• Dodavanje elementa – kazemo da je element dodat na kraj reda (eng. enqueue()
operacija)
• Uklanjanje elementa koji je prvi dodat – kazemo da je element skinut sa pocetka
reda (eng. dequeue() operacija)
• Ocitavanje vrednosti elementa koji je na pocetku reda (eng. front() operacija)
Red spada u FIFO strukture (eng. First In First Out). Moze se implementirati
na vise nacina. Najjednostavniji nacin je da se definise kao niz. Medjutim, tada
je ogranicen max. broj elemenata u redu dimenzijom niza. Zbog toga se obicno
pribegava koriscenju lista za implementaciju reda, gde se enqueue() operacija svodi
na dodavanje na kraj liste, a dequeue() operacija se svodi na uklanjanje glave liste.
144
Milena Vujošević–Janičić 10.3 Red
strcpy(novi->ime_fajla, ime_fajla);
novi->sledeci = NULL;
return novi;
}
145
Milena Vujošević–Janičić 10.3 Red
if(*kraj != NULL)
{
(*kraj)->sledeci = novi;
*kraj = novi;
}
else /* ako je red prazan */
{
*pocetak = novi;
*kraj = novi;
}
}
if(*pocetak == NULL)
return 0;
if(ime_fajla != NULL)
strcpy(ime_fajla, (*pocetak)->ime_fajla);
pomocni = *pocetak;
*pocetak = (*pocetak)->sledeci;
free(pomocni);
if(*pocetak == NULL)
*kraj = NULL;
return 1;
}
146
Milena Vujošević–Janičić 10.3 Red
while(*pocetak != NULL)
{
pomocni = *pocetak;
*pocetak = (*pocetak)->sledeci;
free(pomocni);
}
*kraj = NULL;
}
/* Glavni program */
int main(int argc, char ** argv)
{
Cvor * pocetak = NULL, * kraj = NULL;
FILE *in = NULL;
char ime_fajla[MAX];
int x, y;
int pronadjen = 0;
147
Milena Vujošević–Janičić 10.3 Red
/* Trazeni broj x */
x = atoi(argv[2]);
}
/* Zatvaramo fajl */
fclose(in);
}
148
Milena Vujošević–Janičić 10.3 Red
/* Oslobadjamo red */
oslobodi_red(&pocetak, &kraj);
return 0;
}
Primer 10.7 Program formira celobrojni red i ispisuje sadržaj reda na standardni
izlaz.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
if(*kraj != NULL)
{
149
Milena Vujošević–Janičić 10.3 Red
(*kraj)->sledeci = novi;
*kraj = novi;
}
else /* ako je red prazan */
{
*pocetak = novi;
*kraj = novi;
}
}
if(*pocetak == NULL)
return 0;
if(broj != NULL)
*broj = (*pocetak)->broj);
pomocni = *pocetak;
*pocetak = (*pocetak)->sledeci;
free(pomocni);
if(*pocetak == NULL)
*kraj = NULL;
return 1;
}
main()
{
Cvor * pocetak = NULL, * kraj = NULL;
int i, broj;
/*Formiranje jednostavnog reda*/
for(i=0; i<100; i++)
dodaj_u_red(&pocetak, &kraj, i);
150
Milena Vujošević–Janičić 10.4 Stek
10.4 Stek
Stek (eng. stack) je struktura podataka nad kojom su definisane sledece operacije:
• Dodavanje elementa – kazemo da je element potisnut na vrh steka (eng. push()
operacija).
• Uklanjanje elementa koji je poslednji dodat – kazemo da je element skinut sa
vrha steka (eng. pop() operacija).
• Ocitavanje vrednosti elementa koji je poslednji dodat (eng. top() operacija).
Stek spada u LIFO strukture (eng. Last In First Out). Moze se implementirati
na vise nacina. Najjednostavniji nacin je da se definise kao niz. Medjutim, tada
je ogranicen max. broj elemenata na steku dimenzijom niza. Zbog toga se obicno
pribegava koriscenju lista za implementaciju steka, gde se push() operacija svodi
na dodavanje na pocetak, a pop() operacija se svodi na uklanjanje glave liste. Obe
operacije se izvode u konstantnom vremenu.
Primer 10.8 Program proverava da li su zagrade (, [, {, }, ] i ) dobro uparene —
statička implementacija steka (pretpostavka da se na ulazu neće naći više od 100
otvorenih zagrada za redom).
#include <stdio.h>
#include <stdlib.h>
#define MAX_ZAGRADA 100
main()
{
int c;
char otv_zagrade[MAX_ZAGRADA];
int br_otv = 0;
while((c=getchar()) != EOF)
{
switch(c)
151
Milena Vujošević–Janičić 10.4 Stek
{
case ’(’:
case ’{’:
case ’[’:
{
otv_zagrade[br_otv] = c;
br_otv++;
break;
}
case ’]’:
case ’}’:
case ’)’:
if (br_otv>0 && odgovarajuce(otv_zagrade[br_otv-1], c))
{
br_otv--;
}
else
{
printf("Visak zatvorenih zagrada: %c u liniji %d\n", c, br_linija);
exit(1);
}
}
}
if (br_otv == 0)
printf("Zagrade su u redu\n");
else
printf("Visak otvorenih zagrada\n");
}
Primer 10.9 Program proverava da li su etikete u datom HTML fajlu dobro up-
arene.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define OTVORENA 1
#define ZATVORENA 2
#define VAN_ETIKETE 0
#define PROCITANO_MANJE 1
152
Milena Vujošević–Janičić 10.4 Stek
X Y ... A NULL
novi element
Y X V ... A NULL
X V ... A NULL
#define U_ETIKETI 2
strcpy(novi->etiketa, etiketa);
novi->sledeci = NULL;
153
Milena Vujošević–Janičić 10.4 Stek
return novi;
}
if(*vrh == NULL)
return 0;
if(etiketa != NULL)
strcpy(etiketa, (*vrh)->etiketa);
pomocni = *vrh;
*vrh = (*vrh)->sledeci;
free(pomocni);
return 1;
}
154
Milena Vujošević–Janičić 10.4 Stek
while(*vrh != NULL)
{
pomocni = *vrh;
*vrh = (*vrh)->sledeci;
free(pomocni);
}
}
155
Milena Vujošević–Janičić 10.4 Stek
{
tip = OTVORENA;
etiketa[i++] = tolower(c);
}
stanje = U_ETIKETI;
break;
case U_ETIKETI:
if(isalpha(c) && i < MAX - 1)
etiketa[i++] = tolower(c);
else {
stanje = VAN_ETIKETE;
etiketa[i]=’\0’;
return tip;
}
break;
}
}
return EOF;
}
/* Test program */
int main(int argc, char **argv)
{
/* Otvaramo datoteku */
if((f = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "fopen() greska!\n");
exit(1);
}
156
Milena Vujošević–Janičić 10.4 Stek
/* Zatvaramo fajl */
fclose(f);
157
Milena Vujošević–Janičić 10.4 Stek
/* Oslobadjamo stek */
oslobodi_stek(&vrh);
return 0;
}
Primer 10.10 Program formira celobrojni stek i ispisuje sadržaj steks na standardni
izlaz.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
158
Milena Vujošević–Janičić 10.4 Stek
if(*vrh == NULL)
return 0;
if(broj != NULL)
*broj = (*vrh)->broj);
pomocni = *vrh;
*vrh = (*vrh)->sledeci;
free(pomocni);
return 1;
}
main()
{
Cvor * vrh = NULL;
int i, broj;
/*Formiranje steka*/
for(i=0; i<100; i++)
potisni_na_stek(&vrh, i);
159
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste
...
NULL A B C ... Z NULL
160
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste
novi->vrednost = broj;
novi->prethodni = NULL;
novi->sledeci = NULL;
return novi;
}
return novi;
}
/* Ako lista nije prazna, tada se krecemo duz liste sve dok
ne dodjemo do poslednjeg cvora (tj. do cvora ciji pokazivac
161
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste
162
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste
if(tekuci->sledeci != NULL)
tekuci->sledeci->prethodni = novi;
tekuci->sledeci = novi;
return NULL;
}
163
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste
putchar(’\n’);
}
164
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste
{
printf("[]\n");
return;
}
putchar(’\n’);
}
while(glava != NULL)
{
/* moramo najpre zapamtiti adresu sledeceg
elementa, a tek onda osloboditi glavu */
pomocni = glava->sledeci;
free(glava);
glava = pomocni;
}
return NULL;
}
165
Glava 11
Stabla
166
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
NULL NULL
NULL NULL
U programiranju se stabla obično koriste kao strukture podataka, tako sto svaki
čvor sadrži po jedan podatak odred̄enog tipa. Način raspored̄ivanja podataka u
stablu zavisi od konkretne primene stabla. S obzirom na rekurzivnu prirodu stabla,
uobičajeno je da se u programiranju stabla obrad̄uju rekurzivno.
167
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
12 21
NULL NULL
5 15
#include <stdio.h>
168
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
novi->broj = b;
novi->l = NULL;
novi->d = NULL;
return novi;
}
if (b < koren->broj)
koren->l = ubaci_u_drvo(koren->l, b);
else
koren->d = ubaci_u_drvo(koren->d, b);
return koren;
}
if (koren->broj == b)
return 1;
if (b < koren->broj)
return pronadji(koren->l, b);
else
return pronadji(koren->d, b);
}
169
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
}
}
170
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
broj_listova(koren->d);
}
return suma_listova(koren->l) +
suma_listova(koren->d);
}
ispisi_listove(koren->l);
ispisi_listove(koren->d);
}
if (koren->d==NULL)
return koren->broj;
return max_vrednost(koren->d);
}
171
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
if (pronadji(koren, 3))
printf("Pronadjeno 3\n");
if (pronadji(koren, 2))
172
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
printf("Pronadjeno 2\n");
if (pronadji(koren, 7))
printf("Pronadjeno 7\n");
ispisi_drvo(koren);
putchar(’\n’);
printf("Suma cvorova : %d\n", suma_cvorova(koren));
printf("Broj cvorova : %d\n", broj_cvorova(koren));
printf("Broj listova : %d\n", broj_listova(koren));
printf("Suma listova : %d\n", suma_listova(koren));
printf("Dubina drveta : %d\n", dubina(koren));
printf("Maximalna vrednost : %d\n", max_vrednost(koren));
ispisi_listove(koren);
obrisi_drvo(koren);
}
/*
Pronadjeno 3
Pronadjeno 7
1 3 5 6 7 8 9
Suma cvorova : 39
Broj cvorova : 7
Broj listova : 3
Suma listova : 18
Dubina drveta : 5
Maximalna vrednost : 9
3 6 9
*/
Primer 11.2 Binarno pretraživačko drvo - funkcije za izračunavanje kopije, unije,
preseka i razlike dva drveta, funkcija za izbacivanje čvora iz drveta.
/* Struktura koja predstavlja cvor drveta */
typedef struct cvor {
} Cvor;
173
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
/* inicijalizacija */
novi->vrednost = broj;
novi->levi = NULL;
novi->desni = NULL;
174
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
175
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
176
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
Cvor * pomocni=NULL;
177
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
178
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
if(koren == NULL)
return;
prikazi_stablo (koren->levi);
printf("%d ", koren->vrednost);
prikazi_stablo (koren->desni);
}
/* Izlaz iz rekurzije */
if(koren == NULL)
return NULL;
return NULL;
}
179
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
180
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
181
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
/* test program */
int main()
{
printf("-------------------------------------------------------\n");
putchar(’\n’);
182
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
183
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
printf("-------------------------------------------------------\n");
putchar(’\n’);
pomocni = kopiraj_stablo(koren);
pomocni = kreiraj_uniju(pomocni, koren_2);
printf("-------------------------------------------------------\n");
printf("Prikaz 1. stabla:\n");
prikazi_stablo (koren);
putchar(’\n’);
printf("-------------------------------------------------------\n");
printf("Prikaz 2. stabla:\n");
prikazi_stablo (koren_2);
putchar(’\n’);
printf("-------------------------------------------------------\n");
printf("Unija ova dva stabla:\n");
prikazi_stablo (pomocni);
putchar(’\n’);
printf("-------------------------------------------------------\n");
pomocni = oslobodi_stablo(pomocni);
pomocni = kopiraj_stablo(koren);
pomocni = kreiraj_presek(pomocni, koren_2);
pomocni = oslobodi_stablo(pomocni);
pomocni = kopiraj_stablo(koren);
pomocni = kreiraj_razliku(pomocni, koren_2);
184
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
return 0;
}
Primer 11.3 Primer demonstrira sortiranje niza pomoću binarnog stabla. Elementi
niza se redom prvo smeste u binarno stablo pretrage, a zatim se elementi ”pokupe”
iz stabla obilazeći ga sa leva u desno (tj. u rastućem poretku). Vremenska složenost
ovakvog algoritma je u ekvivalentna quick_sort()-u. Prostorna slozenost je nesto
veća, jer sortiranje nije ”u mestu”, već se koristi pomoćna struktura – binarno
stablo.
#include <stdio.h>
#include <stdlib.h>
int vrednost;
struct cvor * levi;
struct cvor * desni;
} Cvor;
if (novi == NULL)
{
fprintf (stderr,"malloc() greska\n");
exit (1);
}
novi->vrednost = broj;
novi->levi = NULL;
novi->desni = NULL;
return novi;
185
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
if (koren == NULL)
return napravi_cvor (broj);
return koren;
if(koren == NULL)
return;
oslobodi_stablo (koren->levi);
oslobodi_stablo (koren->desni);
free(koren);
if(koren == NULL)
return 0;
r = kreiraj_niz(koren->levi, a);
186
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
a[r] = koren->vrednost;
s = kreiraj_niz(koren->desni, a + r + 1);
return r + s + 1;
kreiraj_niz(koren, a);
oslobodi_stablo(koren);
/* Test program */
int main()
{
int a[MAX];
int n, i;
187
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
sortiraj(a, n);
return 0;
}
Primer 11.4 Program sa ulaza čita tekst i ispisuje broj pojavljivanja svake od reči
koje su se javljale u tekstu. Radi poboljšanja efikasnosti, prilikom brojanja reči koristi
se struktura podataka pogodna za leksikografsku pretragu — u ovom slučaju binarno
pretraživačko drvo.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* inicijalizacija */
188
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
strcpy(novi->rec, rec);
novi->brojac = 1;
novi->levi = NULL;
novi->desni = NULL;
189
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
/* Izlaz iz rekurzije */
if (koren == NULL)
return NULL;
prikazi_stablo(koren->levi);
printf("%s: %d\n", koren->rec, koren->brojac);
prikazi_stablo(koren->desni);
190
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
if(koren == NULL)
return;
oslobodi_stablo (koren->levi);
oslobodi_stablo (koren->desni);
free(koren);
/* Zatvaramo string */
rec[i] = ’\0’;
/* test program */
int main(int argc, char **argv)
{
191
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
/* Otvaramo datoteku */
if((f = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "fopen() greska\n");
exit(1);
}
/* Oslobadjamo stablo */
oslobodi_stablo(koren);
return 0;
}
Primer 11.5 Mapa je apstraktna struktura podataka koja u sebi sadrzi parove oblika
(kljuc, vrednost). Pri tom su i ključ i vrednost unapred odred̄enog (ne obavezno
istog) tipa (na primer, ključ nam može biti string koji predstavlja ime studenta, a
vrednost je npr. broj koji predstavlja njegov prosek). Operacije koje mapa mora
192
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
193
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
/* inicijalizacija */
strcpy(novi->naziv, naziv);
novi->cena = cena;
novi->levi = NULL;
novi->desni = NULL;
194
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
/* cvor liste */
typedef struct cvor_liste {
char naziv[MAX];
int cena;
struct cvor_liste * sledeci;
} Cvor_liste;
195
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
strcpy(novi->naziv, naziv);
novi->cena = cena;
novi->sledeci = NULL;
return novi;
}
/* Funkcija pronalazi sve nazive cija je cena manja ili jednaka od date,
i formira listu koja sadrzi nadjene parove (naziv, cena) u leksikogra-
fskom poretku po nazivima. Prilikom pocetnog poziva, treci argument
treba da bude NULL. Funkcija obilazi stablo sa desna u levo, kako bi
se prilikom dodavanja na pocetak liste poslednji dodao onaj koji je
leksikografski najmanji (tj. on ce biti na pocetku). */
Cvor_liste * pronadji_manje (Cvor * koren, int cena, Cvor_liste * glava)
{
if(koren == NULL)
return glava;
196
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
return;
glava->sledeci = oslobodi_listu(glava->sledeci);
free(glava);
return NULL;
}
if(koren == NULL)
return NULL;
return NULL;
/* test program */
int main(int argc, char ** argv)
{
Cvor * koren = NULL, * pomocni;
Cvor_liste * glava = NULL;
FILE *f;
char naziv[MAX];
int cena;
197
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
if(argc < 2)
{
fprintf(stderr, "Morate navesti ime datoteke!\n");
exit(0);
}
/* Otvaramo datoteku */
if((f = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "fopen() greska\n");
exit(1);
}
/* Oslobadjanje memorije */
glava = oslobodi_listu(glava);
koren = oslobodi_stablo(koren);
return 0;
}
Primer 11.6 Program broji pojavljivanje svake etikete u tekstu i ispisuje etikete i
njihove frekvencije u opadajućem poretku po frekvencijama.
Radi poboljšanja efikasnosti, prilikom brojanja pojavljivanja etiketa koristi se
198
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
/* Izlaz iz rekurzije */
if(koren == NULL)
{
if((koren = malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska\n");
exit(1);
}
199
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
strcpy(koren->etiketa, etiketa);
koren->brojac = 1;
koren->levi = NULL;
koren->desni = NULL;
return koren;
}
/* Rekurzivni pozivi */
if((cmp = strcmp(koren->etiketa,etiketa)) < 0)
koren->desni = dodaj_leksikografski(koren->desni, etiketa);
else if(cmp > 0)
koren->levi = dodaj_leksikografski(koren->levi, etiketa);
else
koren->brojac++; /* uvecanje brojaca za vec prisutne etikete */
return koren;
}
200
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
{
/* u ovom stanju trazimo prvu sledecu pojavu znaka ’<’ */
case VAN_ETIKETE:
if(c == ’<’)
{
stanje = U_ETIKETI; /* sada smo u etiketi */
i = 0;
}
break;
/* u ovom stanju citamo slova koja slede, i nakon toga
ubacujemo procitanu etiketu u stablo */
case U_ETIKETI:
/* Ako je slovo, i nismo prekoracili duzinu niza
dodajemo slovo u niz */
if(isalpha(c) && i < MAX_ETIKETA - 1)
etiketa[i++] = c;
/* u suprotnom se vracamo u stanje VAN_ETIKETE */
else {
stanje = VAN_ETIKETE;
/* Ako je niz slova nakon ’<’ bio neprazan... */
if(i > 0)
{
etiketa[i]=’\0’;
/* ubacujemo procitanu etiketu u stablo */
koren = dodaj_leksikografski(koren, etiketa);
}
}
break;
}
return koren;
/* Izlaz iz rekurzije */
if(koren == NULL)
201
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
{
if((koren = malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska\n");
exit(1);
}
/* NAPOMENA: s obzirom da dve ili vise etiketa mogu imati isti broj
pojavljivanja, etiketa se mora dodavati u stablo, cak i ako ima
isti broj pojavljivanja sa korenom. Zato cemo u levo podstablo
dodavati etikete koje imaju veci broj pojavljivanja od korena,
dok cemo u desno podstablo dodavati etikete koje imaju manji
ili jednak broj pojavljivanja od korena. */
/* Rekurzivni pozivi */
if(koren->brojac >= broj)
koren->desni = dodaj_po_broju(koren->desni, etiketa, broj);
else if(koren->brojac < broj)
koren->levi = dodaj_po_broju(koren->levi, etiketa, broj);
return koren;
202
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
return novo;
}
ispisi_stablo(koren->levi);
printf("%s: %d\n", koren->etiketa, koren->brojac);
ispisi_stablo(koren->desni);
oslobodi_stablo(koren->levi);
oslobodi_stablo(koren->desni);
free(koren);
}
/* glavni program */
int main(int argc, char **argv)
{
203
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
/* Otvaramo fajl */
if((in = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "fopen() greska\n");
exit(1);
}
/* Oslobadjamo stabla */
oslobodi_stablo(koren);
oslobodi_stablo(resortirano);
return 0;
}
Primer 11.7 Efikasnije sortiranje čorova stabla — formira se niz pokazivača na
čvorove stabla koji se u skladu sa funkcijom pored̄enja sortiraju pomoću bibliotečke
qsort funkcije.
#include <stdlib.h>
#include <stdio.h>
204
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
cvor* razlicite_reci[MAX_BROJ_RAZLICITIH_RECI];
return novi_cvor;
}
205
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
return novi_cvor;
}
206
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
word[i]=’\0’;
return i;
}
if (argc!=2)
{ fprintf(stderr,"Greska :
Ocekivano ime datoteke\n");
207
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo
exit(1);
}
if ((ulaz=fopen(argv[1],"r"))==NULL)
{
fprintf(stderr,"Greska : nisam uspeo da otvorim datoteku %s\n");
exit(1);
}
fclose(ulaz);
}
208
Glava 12
Grafovi
209
Milena Vujošević–Janičić Grafovi
sadrži ime (indeks) čvora i pokazivač na njegovu listu čvorova. Ovakav pristup stedi
memoriju, a omogucava i efikasno dodavanje novih cvorova i grana.
Osnovni problem koji se javlja kod grafova jeste kako polazeci od nekog cvora, kre-
tanjem kroz puteva grafa posetiti sve cvorove. Ovakav postupak se naziva obilazak
grafa. Postoje dva osnovna algoritma za obilazak grafa: pretraga u dubinu (DFS,
skraćenica od depth-first-search) i pretraga u širinu (BFS, skraćenica od breadth-
first-search).
Kod DFS algoritma, obilazak započinje iz proizvoljnog zadatog čvora r koji se
naziva koren pretrage u dubinu. Koren se označava kao posećen. Zatim se bira
proizvoljan neoznačen čvor r1, susedan sa r, pa se iz čvora r1 rekurzivno startuje
pretraga u dubinu. Iz nekog nivoa rekurzije izlazi se kad se naid̄e na čvor v kome su
svi susedi već označeni.
Primer 12.1 Primer reprezentovanja grafa preko matrice povezanosti. U programu
se unosi neorijentisan graf i DFS algoritmom se utvrd̄uju čvrovi koji su dostižni iz
čvora 0.
#include <stdlib.h>
#include <stdio.h>
int** alociraj_matricu(int n)
{ int **matrica;
int i;
matrica=malloc(n*sizeof(int*));
if (matrica==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
210
Milena Vujošević–Janičić Grafovi
int* alociraj_niz(int n)
{ int* niz;
niz=calloc(n,sizeof(int));
if (niz==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
return niz;
}
211
Milena Vujošević–Janičić Grafovi
main()
{
int i, j;
printf("Unesi broj cvorova : ");
scanf("%d",&n);
graf=alociraj_matricu(n);
unesi_graf(graf,n);
ispisi_graf(graf,n);
posecen=alociraj_niz(n);
poseti(0, graf, n);
oslobodi_niz(posecen);
oslobodi_matricu(graf,n);
}
Primer 12.2 Primer demonstrira osnovne algoritme nad grafovima. U ovom primer
grafovi se predstavljaju matricama povezanosti. Zbog jednostavnosti, pretpostavlja se
da je broj cvorova ogranicen nekom fiksiranom konstantom, tako da se odgovarajuce
matrice alociraju staticki. Takod̄e, da bi se pojednostavile liste argumenata pojedinih
funkcija, većina promenljivih u ovom primeru se deklarišu kao globalne, kako bi kao
takve bile dostupne svim funkcijama.
#include <stdio.h>
#include <stdlib.h>
212
Milena Vujošević–Janičić Grafovi
return -1;
213
Milena Vujošević–Janičić Grafovi
int odlazna_numeracija[MAX_CVOROVA];
/* Obelezavanje */
posecen[polazni_cvor] = 1;
/* Ulazna obrada */
dolazna_numeracija[polazni_cvor] = ++brojac_dolazna;
/* Izlazna obrada */
odlazna_numeracija[polazni_cvor] = ++brojac_odlazna;
}
214
Milena Vujošević–Janičić Grafovi
int red[MAX_CVOROVA];
int sledeci_na_redu = 0;
int poslednji_na_redu = -1;
int i;
/* Test program */
int main()
{
int i,j;
int aciklican;
215
Milena Vujošević–Janičić Grafovi
scanf("%d", &graf[i][j]);
}
brojac_dolazna = 0;
brojac_odlazna = 0;
putchar(’\n’);
printf("Odlazna DFS numeracija: ");
for(i = 0; i < broj_cvorova; i++)
printf("%d ", odlazna_numeracija[i]);
putchar(’\n’);
return 0;
}
Primer 12.3 Primer predstavljanja grafa preko niza listi suseda svakog od čvorova
grafa. U programu se unosi graf i DFS algoritmom se utvrdjuje koji su čvorovi
dostižni iz cvora 0.
#include <stdlib.h>
#include <stdio.h>
216
Milena Vujošević–Janičić Grafovi
/* Ispis liste */
void ispisi_listu(cvor_liste* lista)
{ if (lista)
{ printf("%d ",lista->broj);
ispisi_listu(lista->sledeci);
}
}
int posecen[MAX_BROJ_CVOROVA];
217
Milena Vujošević–Janičić Grafovi
{ cvor_liste* sused;
printf("Posecujem cvor %d\n",i);
posecen[i]=1;
for( sused=graf[i]; sused!=NULL; sused=sused->sledeci)
if (!posecen[sused->broj])
poseti(sused->broj);
}
main()
{
int i;
printf("Unesi broj cvorova grafa : ");
scanf("%d",&broj_cvorova);
/*Unos grafa*/
for (i=0; i<broj_cvorova; i++)
{ int br_suseda,j;
graf[i]=NULL;
/*Ispis grafa*/
for (i=0; i<broj_cvorova; i++)
{ printf("%d - ",i);
ispisi_listu(graf[i]);
printf("\n");
218
Milena Vujošević–Janičić Grafovi
}
/*Koji su sve cvorovi dostupni iz cvora 0*/
poseti(0);
/*Oslobadjanje memorije*/
oslobodi_graf(graf, broj_cvorova);
}
Primer 12.4 MINESWEEPER - primer jednostavne igrice.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
/* Dimenzija table */
int n;
219
Milena Vujošević–Janičić Grafovi
int** alociraj(int n)
{
int i;
int** m=(int**)malloc(n*sizeof(int*));
if(m==NULL) {printf("Greska prilikom alokacije memorije\n"); exit(1);}
for (i=0; i<n; i++)
{
m[i]=(int *)calloc(n,sizeof(int));
if(m[i]==NULL)
{printf("Greska prilikom alokacije memorije\n"); exit(1);}
}
return m;
}
free(m);
}
220
Milena Vujošević–Janičić Grafovi
/* Postavljamo bombu */
bombe[vrsta][kolona]=1;
}
}
221
Milena Vujošević–Janičić Grafovi
}
else if (stanje[i][j]==ZASTAVICA)
{ stanje[i][j]=ZATVORENO;
broj_zastavica--;
}
}
return br;
}
222
Milena Vujošević–Janičić Grafovi
223
Milena Vujošević–Janičić Grafovi
main() {
/* Alociramo table */
bombe=alociraj(n);
stanje=alociraj(n);
/* Postavljamo bombe */
postavi_bombe();
224
Milena Vujošević–Janičić Grafovi
scanf("%d",&k);
} while(v<1 || v>n || k<1 || k>n);
/* Reagujemo na akciju */
switch(akcija)
{ case ’o’:
otvori_polje(v-1,k-1);
break;
case ’z’:
postavi_zastavicu(v-1,k-1);
}
}
/* Konstatujemo pobedu */
ispisi_stanje();
printf ("Cestitam! Pobedili ste\n");
obrisi(stanje,n);
obrisi(bombe,n);
}
225