You are on page 1of 25

PROGRAMIRANJE 2

LABORATORIJSKE VJEBE

LV 11
Pretraivanje i sortiranje podataka

Fakultet elektrotehnike raunarstva i


informacijskih tehnologija Osijek
Kneza Trpimira 2b
www.etfos.unios.hr
1 UVOD

Pretraivanje podataka moemo definirati kao traenje (lociranje) odreenog podatka


iz nekog skupa podataka (unutar liste ili neke druge strukture podataka kao to je niz,
vektor, matrica i slino).

U ovoj vjebi obradit emo nekoliko algoritama za pretraivanje podataka. Vidjet emo
da neki od algoritama za pretraivanje podataka zahtijevaju ve sortirano polje podataka
pa emo takoer obraditi i neke od algoritama za sortiranje podataka. Na primjerima emo
vidjeti brzinu i efikasnost pojedinog algoritma.
2 PRETRAIVANJE PODATAKA

Ve smo rekli u uvodu, pretraivanje je postupak traenja odreenog podatka iz


nekog skupa podataka, a u ovoj vjebi pretraivat e se polje cijelih brojeva. Efikasnost
pretraivanja uglavnom se mjeri prosjenim brojem usporedbi koje je potrebno izvesti u
postupku traenja razliitih vrijednosti u danom skupu. U pravilu, to je algoritam bri, to je
kompleksniji i koristi vie radne memorije.
Neki od razloga za pretraivanje su: utvrivanje nalazi li se odreeni element u listi,
pronalaenje pozicije za umetanje novog elementa ako je lista sortirana te pronalaenje
lokacije elementa za brisanje.
U ovoj vjebi obradit emo 3 osnovna algoritma pretraivanja:
1. Sekvencijalno (linearno) pretraivanje
2. Binarno pretraivanje
3. Interpolacijsko pretraivanje

2.1 SEKVENCIJALNO (LINEARNO) PRETRAIVANJE

Sekvencijalno pretraivanje se jo naziva i linearno pretraivanje, a predstavlja proces


traenja podatka u nekom nizu na nain da se redom, od prvog do zadnjeg, usporeuju svi
elementi tog niza s elementom kojeg traimo dok se ne naie na traeni element ili dok se
ne doe do kraja tog niza. Prilikom sekvencijalne pretrage podatka, skup podataka koji se
pretrauje ne treba biti sortiran. Ova pretraga ujedno predstavlja i najjednostavniji nain
pretrage skupa podataka, a nedostatak joj je veliko vrijeme izvravanja.

Ova se vrsta pretrage naziva i linearna jer ovisnost vremena pretrage o broju
elemenata u nizu predstavlja funkciju koja ima linearni rast.
Primjer:
Imamo zadan niz od 5 cijelih brojeva te broj a koji se trai unutar niza.
niz[5] = {-2, 4, 1, 5, 3}, a=5

niz[0] niz[1] niz[2] niz[3] niz[4]

-2 4 1 5 3

-2 4 1 5 3

-2 4 1 5 3

-2 4 1 5 3

Tablica 1. Primjer sekvencijalnog pretraivanja

Primjer:

#include <stdio.h>

int main() {

int niz[] = {-2, 4, 1, 5, 3}; // inicijalizacija polja


int a = 5; // traeni broj
int n, pronasli = 0, br = 0;

n = sizeof(niz) / sizeof(int); // broj elemenata polja

while(!pronasli && br<n) { // prolazak kroz polje dok


if (niz[br] == a) pronasli = 1; // se element ne nae ili dok
else br++; // se ne doe do kraja polja
}

if (pronasli) printf ("Element je pronadjen na %d. mjestu.\n", br+1);


else printf ("Element nije pronadjen.\n");

printf ("\n\n");
return 0;
}

Ili:

#include <stdio.h>

int main() {

int niz[] = {-2, 4, 1, 5, 3}; // inicijalizacija polja


int a = 5; // traeni broj
int i, n, pronasli = 0, br = 0;

n = sizeof(niz) / sizeof(int); // broj elemenata polja


for (i=0; i<n; i++) { // prolazak kroz polje dok
if (niz[i] == a) { // se element ne nae ili dok
pronasli = 1; // se ne doe do kraja polja
break;
}
br++;
}

if (pronasli) printf ("Element je pronadjen na %d. mjestu.\n", br+1);


else printf ("Element nije pronadjen.\n");

printf ("\n\n");
return 0;
}

U ovom primjeru kreemo od prvog elementa prema zadnjem i provjeravamo


jednakost trenutnog elementa u nizu sa brojem koji se trai. Kada se ispostavi da je
trenutni element niza jednak traenom broju program e izai iz petlje te e se ispisati
poruka da je element pronaen i na kojem indeks tog polja. Ukoliko se prou svi elementi
niza, a ne nae se traeni broj, ispisuje se da element nije pronaen.

Prednosti:
- jednostavnost algoritma
- elementi liste mogu biti u bilo kojem poretku
Nedostatci:
- algoritam je neefikasan (spor)
- za listu od N elemenata u prosjeku se mora provjeriti N/2 elementa
- moraju se provjeriti svi elementi u listi da bi se utvrdilo da se traena
vrijednost ne nalazi u listi

2.2 BINARNO PRETRAIVANJE

Binarna pretraga je algoritam za pretraivanje odreene vrijednosti u nizu koji mora


biti sortiran. Takoer moramo znati i duinu niza. Ovaj algoritam spada u grupu podijeli pa
vladaj algoritama.

To je vrlo brz nain pretraivanja polja, osobito bitan za polja s velikim brojem
lanova. Jednostavan primjer logike binarnog pretraivanja je dobro poznata igra
pogaanja zamiljenog broja. U toj igri zapie se neki broj npr. izmeu 1 i 100. Da bi se
pronaao zapisani (ili zamiljeni) broj potrebno je redom postavljati pitanja. Mora se znati
jedino u kojem se intervalu nalazi zamiljeni broj (taj interval je [1,100]). Prvo je razumno
podijeliti interval na polovicu i upitati je li broj vei od 50. Ako je odgovor da, onda je
zapisani broj izmeu 50 i 100. Ponovno se interval [50, 100] dijeli na polovicu (polovica je
75) i postavlja isto pitanje je li broj vei od 75. Svaki odgovor doputa podjelu intervala u
kojem se nalazi zapisani broj na polovicu. Interval se smanjuje i na koncu interval postaje
samo jedan broj, a on je zapisani ili zamiljeni broj.

Primjer:
Zapisuje se 44. Kako binarnim pretraivanjem pronai zapisani broj (44) prikazuje sljedea
tablica:
Interval moguih
Traeni
Broj koraka Rezultat vrijednosti
broj
1 100
0
1 49
1 50 Broj je velik
26 49
2 25 Broj je mali
38 49
3 37 Broj je mali
44 49
4 43 Broj je mali
44 45
5 46 Broj je velik

6 44 Tono

Tablica 2. Primjer binarnog pretraivanja

Zapisani broj (44) pronalazi se u est koraka. Broj koraka moe biti i manji ako bi se
zapisao drugi broj, npr. 50. Tada je dovoljan samo jedan korak. Broj koraka moe biti i vei,
npr. broj 45 se pronalazi u 7 koraka.

U prosjeku, ako su elementi sortirani, binarna pretraga ini oko 2 () usporedbi,


gdje je n broj elemenata niza. Binarna pretraga je daleko efikasnija od sekvencijalne pa
tako npr. za gornji primjer vidimo e binarna pretraga pronai traeni broj u 6 koraka, dok
e linearna napraviti 44 provjere i znatno sporije pronai traeni element.

Dakle, preduvjet za rad algoritma za binarno pretraivanje je da su podaci koji se


pretrauju (polje cijelih brojeva) sortirano. Algoritam radi tako da se odrede donja i gornja
granica pretraivanja. U prvom koraku je donja granica dg = 0 i gornja granica gg = N 1,
gdje je N broj podataka u polju. Zatim se rauna indeks sredine intervala koji se pretrauje
na slijedei nain: s = ( dg + gg ) / 2. Promatramo element polja koji se nalazi na s-tom
mjestu, odnosno V[s]. Sada mogu nastupiti tri sluaja:
1. traeni broj > V[s] u ovom sluaju vrijednost donje granice intervala koji se
pretrauje se pomie na slijedei nain: dg = s + 1, i pretraivanje se nastavlja,
2. traeni broj < V[s] u ovom sluaju vrijednost gornje granice intervala koji se
pretrauje se pomie na slijedei nain: gg = s - 1, i pretraivanje se nastavlja,
3. traeni broj = V[s] pronaen je traeni broj i pretraivanje se prekida.

Pretraivanje se prekida i ako je zadovoljen uvjet dg = gg.

Pseudokod:
uitaj broj N i polje V[]
poredaj polje V uzlazno
uitavaj brojeve X i za svaki uitani X radi:
dg = 0, gg = N 1
dok ( dg < gg ) radi:
s = ( dg + gg ) / 2
ako ( V[s] > X ) onda: gg = s - 1
ako ( V[s] < X ) onda: dg = s + 1
inae: ispii: Broj je pronadjen!

Prekid petlje Dok

Primjer:

#include <stdio.h>
int main(void){
int V[] = {1, 2, 5, 7, 8, 9, 11, 14, 17, 19,
21, 23, 27, 28, 29, 30, 32, 34, 35, 36,
38, 40, 41, 43, 44, 45, 46, 48, 49, 50};
int n, x, brk=0;
int dg, gg, s;

n = sizeof(niz)/sizeof(int);
printf ("Unesi broj koji zelis pronaci u intervalu 1-50: ");
scanf("%d", &x);
dg = 0;
gg = n-1;

while (dg<=gg) {
s = (dg+gg)/2;

if (x == V[s]) {
printf ("Broj je pronadjen na %d. mjestu u %d koraka!", s,
brk);
break;
}
else if (x>V[s]) {
dg = s+1;
brk++;
}
else if (x<V[s]) {
gg = s-1;
brk++;
}
}
if (dg>gg) printf ("\nBroj nije pronadjen!");

printf ("\n\n");

return 0;
}

U ovom primjeru inicijaliziran je niz elemenata koji su unaprijed sortirani uzlazno.


Nakon toga odreujemo veliinu tog niza te traimo od korisnika unos broja kojeg eli
pronai. Prolazimo kroz niz koristei algoritam binarnog pretraivanja te na kraju
ispisujemo mjesto u nizu na kojem se traeni element nalazi, odnosno ako nije u nizu,
ispisujemo da element nije pronaen.

Prednosti:
- puno uinkovitije od sekvencijalnog pretraivanja
Nedostatci:
- niz mora biti sortiran
- moramo imati direktan pristup elementima (preko indeksa)

2.3 INTERPOLACIJSKO PRETRAIVANJE

Interpolacijsko pretraivanje je algoritam za pretraivanje dane vrijednosti u poljima


koja su indeksirana i sortirana po vrijednostima kljueva. Ovaj algoritam pretraivanja
moemo uporediti s nainom na koji ljudi pretrauju telefonski imenik. Npr. ako traimo
broj neke osobe ije prezime i ime poinje s nekim od zadnjih slova abecede kao to je
eljko iki, logino je da cemo imenik otvoriti pri kraju. Interpolacijska pretraga je ustvari
modificirana binarna pretraga.

U interpolacijskoj pretrazi srednji element nije sredina niza kao to je sluaj kod
binarne pretrage. Srednji element se izraunava na osnovu vrijednosti koja se trai i
vrijednosti krajnjih elemenata u trenutnom segmentu koji se pretrauje tako da se pokua
procijeniti gdje bi u takvom sortiranom segmentu mogao biti traeni podatak. To se
izvrava uz pomo vrijednosti kljueva elemenata koji se nalaze na granicama preostalog
prostora za pretraivanje. Taj prostor za pretraivanje je na poetku cijeli niz ili lista i on se
svakom sljedeom iteracijom algoritma smanjuje za pola. Na sljedeoj slici prikazan je
odabir srednjeg (middle) elementa.
Slika 1. Interpolacija indeksa middle

Vrijednost kljua proraunate pozicije se usporeuje s vrijednou koja se


pretrauje. Ako se ne podudaraju, preostali prostor za pretraivanje se smanjuje. Preostali
prostor za pretraivanje postaje dio prije ili poslije proraunate pozicije, ovisno o usporedbi
vrijednosti za pretraivanje i srednjeg elementa. Ako je srednji element manji od traenog
elementa, lijeva strana niza se odbacuje i pretraivanje se nastavlja u desnom dijelu niza i
obrnuto.

U prosjeku, ako su elementi sortirani, interpolacijska pretraga ini oko log(log(n))


usporedbi, gdje je n broj elemenata koji se moraju provjeriti. U najgorem sluaju moe doi
i do n provjera. U prosjeku interpolacijska pretraga je uspjenija i daje bolje rezultate od
binarnog pretraivanja.

Primjer:

#include <stdio.h>

int interpolacijskaPretraga (int K[ ], int key, int length){


int bottom = 0, top = length - 1, middle;
while (K[bottom] < key && K[top] >= key) {
middle = bottom + ((key - K[bottom]) * (top - bottom)) / (K[top] -
K[bottom]);
if (K[middle] < key)
bottom = middle + 1;
else if (K[middle] > key)
top = middle - 1;
else
return middle;
} //kraj while petlje
if (K[bottom] == key)
return bottom;
else
return -1;
}

int main(void){
int niz[30] = {1, 2, 5, 7, 8, 9, 11, 14, 17, 19,
21, 23, 27, 28, 29, 30, 32, 34, 35, 36,
38, 40, 41, 43, 44, 45, 46, 48, 49, 50};
int n, f;

n = sizeof(niz)/sizeof(int);
printf ("Unesi broj koji zelis pronaci u intervalu 1-50: ");
scanf("%d", &x);

f = interpolacijskaPretraga(niz, x, n);

if (f!=(-1)) printf ("\nBroj je pronadjen na %d. mjestu!", f);


else printf ("\nBroj nije pronadjen!");

printf ("\n\n");

return 0;
}

U ovom primjeru inicijaliziran je niz elemenata koji su unaprijed sortirani uzlazno.


Nakon toga odreujemo veliinu niza te traimo od korisnika unos broja kojeg eli pronai.
Nakon toga pozivamo implementiranu funkciju za interpolacijsko pretraivanje te na kraju
ispisujemo mjesto u nizu na kojem se traeni element nalazi, odnosno ako nije u nizu,
ispisujemo da element nije pronaen.

Prednosti:
- jo efikasniji od binarnog pretraivanja
Nedostatci:
- niz mora biti sortiran
- moramo imati direktan pristup elementima (preko indeksa)
3 SORTIRANJE PODATAKA

Sortiranje je postupak kojim se elementi nekog niza poredaju po nekom odreenom


pravilu. Sortiranje polja moe se izvri uzlazno ili silazno. Uzlazno sortiranje preureuje
polje tako da elementi budu poredani u rastuem redoslijedu od najmanjeg prema
najveem dok je silazno sortiranje suprotno od navedenog. Postoji puno metoda sortiranja
(bubble sort, selection sort, quick sort, insertion sort, shell sort, merge sort) i svaka od
tih metoda vri zamjenu elemenata u skladu s traenim poretkom, ime se mijenja poloaj
pojedinih elemenata u polju. Mi emo u ovoj vjebi spomenuti nekoliko jednostavnijih
algoritama.

3.1 SORTIRANJE ZAMJENOM SUSJEDNIH ELEMENATA (BUBBLE SORT)

Prolazimo poljem od poetka prema kraju i usporeujemo susjedne elemente. Ako je


neki element vei od sljedeeg elementa, zamijenimo im vrijednosti. Kad na taj nain
doemo do kraja polja, najvea vrijednost doi e na posljednje mjesto. Nakon toga
ponavljamo postupak na skraenom polju (bez zadnjeg elementa). Algoritam se smije
zaustaviti im se u nekom prolazu ustanovi da nema parova elemenata koje bi trebalo
zamijeniti.
Primjer sortiranja zamjenom susjednih elemenata (bubble sort) dan je na slici 3.2. U
svakom koraku dva susjedna elementa koji trebaju zamijeniti vrijednosti oznaeni su
sjenanjem. Promatrani dio polja nalazi se s lijeve strane dvostruke okomite crte. esti
prolaz slui zato da se ustanovi da vie nema parova susjednih elemenata koje bi trebalo
zamijeniti.
Slika 3.1. Primjer sortiranja algoritmom zamjene susjednih elemenata

Sljedea funkcija bubbleSort() implementira algoritam sortiranja zamjenom susjednih


elemenata (bubble sort) u jeziku C. Funkcija prima kao argumente cjelobrojno polje a[] i
njegovu duljinu n, te mijenja polje a[ ] tako da ono postane sortirano. Koristi se pomona
funkcija swap() za zamjenu vrijednosti dviju cjelobrojnih varijabli.

void swap (int *x, int *y) {


int aux;
aux = *x;
*x = *y;
*y = aux;
}

void bubbleSort (int a[], int n) {


int i, j;
for (i = 0; i < n-1; i++)
for (j = 0; j < n-1-i; j++)
if (a[j+1] < a[j])
swap(&a[j], &a[j+1]);
}

Implementacija se moe poboljati tako da se postupak zaustavi im se ustanovi da


u nekom prolazu nije bilo ni jedne zamjene susjednih elemenata. Poboljana verzija funkcije
bubbleSort() izgleda ovako.
void bubbleSort (int a[], int n) {
int i, j, chg;
for (i = 0, chg = 1; chg; i++) {
chg = 0;
for (j = 0; j < n-1-i; j++)
if (a[j+1] < a[j]) {
swap(&a[j], &a[j+1]);
chg = 1;
}
}

3.2 SORTIRANJE IZBOROM NAJMANJEG ELEMENTA (SELECTION SORT)

Algoritam radi na sljedei nain. Proe se poljem i pronae se najmanji element.


Zatim se najmanji element zamijeni s poetnim. Dalje se promatra ostatak polja (bez
poetnog elementa) i ponavlja isti postupak. Da bi se cijelo polje sortiralo potrebno je n 1
prolazaka.

Slika 3.2. Primjer sortiranja algoritmom izbora najmanjeg elementa (selection sort)

Algoritam sortiranja izborom najmanjeg elementa (selection sort) moe se u jeziku


C realizirati sljedeom funkcijom selectionSort(). Ta funkcija prima kao argumente
cjelobrojno polje a[ ] i njegovu duljinu n. Funkcija mijenja polje a[ ] tako da ono postane
sortirano. Pomona funkcija swap(), kao i prije, slui za zamjenu vrijednosti dviju
cjelobrojnih varijabli sa zadanim adresama.
Primjer:

void swap (int *x, int *y) {


int aux;
aux = *x;
*x = *y;
*y = aux;
}

void selectionSort (int a[], int n) {


int i, j, min;
for (i = 0; i < n; i++) {
min = i;
for (j = i+1; j < n; j++)
if (a[j] < a[min]) min = j;
swap(&a[i], &a[min]);
}
}

3.3 BRZO SORTIRANJE (QUICK SORT)

Quick sort je jedan od najstarijih, ali i jedan od najbrih i najire upotrebljavanih


algoritama za sortiranje. Ovdje je rije o rekurzivnom algoritmu za sortiranje. Odabere se
jedan element u polju, takozvani stoer. Svi ostali elementi razvrstaju se ispred (lijevo od)
odnosno iza (desno od) stoera ovisno o tome da li su ili od stoera. Ideja je ilustrirana
slikom 3.3.

Slika 3.3. Brzo sortiranje uinak razvrstavanja


Oigledno, nakon ovakvog razvrstavanja stoer se nalazi na svom konanom
mjestu u smislu traenog sortiranog poretka. Da bi se polje sortiralo do kraja, dovoljno je
zasebno (neovisno) sortirati potpolje lijevo odnosno desno od stoera. Sortiranje potpolja
postie se rekurzivnim pozivima istog algoritma.

Slika 3.4. Brzo sortiranje - detalji postupka razvrstavanja

Samo razvrstavanje elemenata lijevo odnosno desno od stoera efikasno se obavlja


u skladu sa slikom 3.4, tako da pomiemo kazaljku s lijevog odnosno desnog kraja polja, sve
dok su tekui elementi odnosno od stoera. Kad se obje kazaljke zaustave, nali smo
element slijeva koji je > od stoera i element s desna koji je < od stoera. Ta dva elementa
na krivim stranama meusobno zamijenimo i zatim nastavimo s pomicanjem kazaljki.
Razvrstavanje je zavreno kad se kazaljke prekrie.
Algoritam brzog sortiranja (quick sort) moe se implementirati u jeziku C na vie
naina s obzirom na razne mogunosti izbora stoera. Sljedea rekurzivna funkcija
quickSort( ) predstavlja najjednostavniju varijantu implementacije, gdje se u svakom
rekurzivnom pozivu kao stoer bira srednja vrijednost pod-polja kojeg upravo treba
sortirati. Opet se koristi pomona funkcija swap() za zamjenu vrijednosti dviju cjelobrojnih
varijabli. Da bi sortirao polje a[ ] duljine n, glavni program mora pozvati quickSort( ) sa
sljedeim argumentima: quickSort(a, 0, n-1).

void quickSort(int a[], int low, int high) {


int i = low, j = high;
int s = a[(low + high) / 2];
while (i <= j) {
while (a[i] < s) {
i++;
}
while (a[j] > s)
{
j--;
}
if (i <= j) {
swap(&a[i], &a[j]);
i++;
j--;
}
}
if (low < j)
quickSort(a, low, j);
if (i < high)
quickSort(a, i, high);
}

Primjer. Zamislite da imamo zadan niz = {50, 21, 17, 16, 18, 13, 2}. n = 7.

Za ovaj primjer funkciju quicksort pozivamo s parametrima quicksort (niz, 0, n-1).


Postupak sortiranja je sljedei:

1. korak 50 21 17 16 18 13 2 poetno stanje


s
2. korak 50 21 17 16 18 13 2 pomicanje i zaustavljanje kazaljki
L s D i=0; j=6
3. korak 2 21 17 16 18 13 50 zamjena elemenata
s
4. korak 2 21 17 16 18 13 50 pomicanje i zaustavljanje kazaljki
L s D i=1; j=5
5. korak 2 13 17 16 18 21 50 zamjena elemenata
s
6. korak 2 13 17 16 18 21 50 pomicanje i zaustavljanje kazaljki
L s D i=2; j=3
7. korak 2 13 16 17 18 21 50 zamjena elemenata
s
8. korak 2 13 16 17 18 21 50 pomicanje i zaustavljanje kazaljki
s D L i=3; j=2; i>j kraj while petlje
Razvrstavanje je zavreno, kazaljke su se preklopile, zavrila je while petlja. Sada se
provjeravaju uvjeti:

if (low < j)
quickSort(a, low, j);
if (i < high)
quickSort(a, i, high);

Prvi uvjet je ispunjen, 0<2, ponovno se poziva funkcija quicksort, sada s parametrima
quicksort(niz, 0, 2) za lijevo potpolje te se sortiranje nastavlja:

1. korak 2 13 16 poetno stanje


s
2. korak 2 13 16 pomicanje i zaustavljanje
L s D i=1; j=1;
3. korak 2 13 16 zamjena elemenata
D s L i=2; j=0; - kraj while petlje
Razvrstavanje je zavreno, kazaljke su se preklopile, zavrila je while petlja. Sada se
ponovno provjeravaju uvjeti :

if (low < j)
quickSort(a, low, j);
if (i < high)
quickSort(a, i, high);
Sada vie prvi uvjet nije ispunjen, ali drugi je te se ponovno poziva funkcija
quicksort, ali sada za desno potpolje i sortira se analogno ovome to smo dosad vidjeli.

4 RIJEENI PRIMJERI

Primjer 1. Napisati program koji e ponuditi uitavanje 10 znakova u polje i nakon toga znak
koji se trai u polju. Ispisati pojavljuje li se znak u polju i koliko puta.

1 #include <stdio.h>
2
3 int main() {
4 char zn[10], znak;
5 int brojac=0, i;
6
7 for(i=0; i<10; i++) {
8 printf("\nUcitaj %d. znak: ", i+1);
9 scanf(" %c", &zn[i]);
10 }
11
12 printf("\nUcitaj znak koji trazimo:");
13 scanf(" %c", &znak);
14
15 for(i=0; i<10; i++)
16 if(zn[i] == znak)
17 brojac++;
18
19 if(brojac == 0)
20 printf("\nZnak %c se ne nalazi u polju", znak);
21 else
22 printf("\nZnak %c se pojavljuje %d puta", znak, brojac);
23
24 printf("\n\n");
25 return 0;

Kratko obrazloenje [Primjer 1]: Program nudi unos znakova i sprema ih u polje zn. Nakon
toga sekvencijalno prolazi kroz cijelo polje, usporeujete i-ti znak s traenim znakom te
ukoliko se podudaraju poveava broja za 1. Nakon pretrage ispisujemo pojavljuje li se
traeni znak u polju i koliko puta.
Primjer 2. Napisati C program koji e unijeti broj n te nakon toga unijeti n brojeva u polje.
Pomou funkcije sortirati polje uzlazno ili izlazno, ovisno o predanom parametru funkcije.

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 /* Klasicni bubble sort koji koristi pokaziva na funkciju kao argument
6 pomocu kojeg se odredjuje ulazno/silazno sortiranje */
7
8 /*funkcija prima polje koje treba sortirati, broj elemenata polja i pokazivac na
funkciju koja odredjuje sortira li se uzlazno ili silazno*/
9
10 int *bubble_sort(int *numbers, int count, int (*cmp)(int,int)){
11 int temp = 0;
12 int i = 0;
13 int j = 0;
14 //alokacija memorije za polje target
15 int *target = (int*)malloc(count * sizeof(int));
16
17 //kopiranje brojeva iz polja numbers u polje target
18 memcpy(target, numbers, count * sizeof(int));
19
20 for(i = 0; i < count; i++) {
21 for(j = 0; j < count - 1; j++) {
22 //poziv funkcije za ulazno/silazno sortiranje susjedna 2 broja
23 if(cmp(target[j], target[j+1]) > 0) {
24 temp = target[j+1];
25 target[j+1] = target[j];
26 target[j] = temp;
27 }
28 }
29 }
30 return target;
31 }
32 //uzlazno sortiranje
33 int sorted_order(int a, int b){
34 return a - b;
35 }
36 //silazno sortiranje
37 int reverse_order(int a, int b){
38 return b - a;
39 }
40 //ispis rezultata sortiranja
41 void print_sorting(int *numbers, int count, int (*cmp)(int,int)){
42 int i = 0;
43 int *sorted = bubble_sort(numbers, count, cmp);
44
45 if(!sorted) printf("Sortiranje nije uspjelo.");
46
47 for(i = 0; i < count; i++) {
48 printf("%d ", sorted[i]);
49 }
50 printf("\n");
51
52 free(sorted);
53 }
54 int main(){
55 int count=0, i=0;
56 printf("Koliko brojeva zelite sortirati?\n");
57 scanf("%d",&count);
58 //alokacija memorije za polje brojeva numbers
59 int *numbers = (int*) malloc(count * sizeof(int));
60
61 printf("Unesite brojeve za sortiranje?\n");
62 for(i = 0; i < count; i++) {
63 scanf("%d",&numbers[i]);
64 }
65
66 //poziv funkcije za uzlazno sortiranje
67 print_sorting(numbers, count, sorted_order);
68 //poziv funkcije za silazno sortiranje
69 print_sorting(numbers, count, reverse_order);
70
71 free(numbers);
72
73 return 0;
74 }

Kratko obrazloenje [Primjer 2]: Program je pojanjen kroz komentare u programu.

Primjer 3. Napisati program u kojem ete inicijalizirati sortirano polje od 30 cijelih brojeva, a
zatim kreirati funkcije za sekvencijalno binarno i interpolacijsko pretraivanje. Zatraiti od
korisnika unos broja koji se trai, pomou sve 3 funkcije pretraiti polje i ispisati koliko je
koraka potrebno svakoj od tih funkcija za pronalazak traenog broja.

1 #include <stdio.h>
2
3 int sekvencijalnapretraga (int K[], int x, int length, int *brk) {
4 int i;
5 for (i=0; i<length; i++) {
6 (*brk)++;
7 if (K[i] == x) return i;
8 }
9 return -1;
10 }
11
12 int binarnapretraga (int K[], int x, int length, int *brk) {
13 int dg, gg, s;
14
15 dg = 0;
16 gg = length-1;
17
18 while (dg<=gg) {
19 s = (dg+gg)/2;
20 (*brk)++;
21 if (x == K[s]) {
22 return s;
23 }
24 else if (x>K[s])
25 dg = s+1;
26
27 else if (x<K[s])
28 gg = s-1;
29 }
30 if (dg>gg) return -1;
31 }
32
33 int interpolacijskaPretraga (int K[ ], int key, int length, int *brk){
34 int bottom = 0, top = length - 1, middle;
35 while (K[bottom] < key && K[top] >= key) {
36 (*brk)++;
37 middle = bottom + ((key - K[bottom]) * (top - bottom)) / (K[top] -
K[bottom]);
38 if (K[middle] < key)
39 bottom = middle + 1;
40 else if (K[middle] > key)
41 top = middle - 1;
42 else
43 return middle;
44 } //kraj while petlje
45 if (K[bottom] == key)
46 return bottom;
47 else
48 return -1;
49 }
50
51 int main(void){
52 int niz[30] = {1, 2, 5, 7, 8, 9, 11, 14, 17, 19,
53 21, 23, 27, 28, 29, 30, 32, 34, 35, 36,
54 38, 40, 41, 43, 44, 45, 46, 48, 49, 50};
55 int n, x, brks=0, brkb=0, brki=0;
56 int sp, bp, ip;
57
58 n = sizeof(niz)/sizeof(int);
59 printf ("Unesi broj koji zelis pronaci u intervalu 1-50: ");
60 scanf("%d", &x);
61
62 sp = sekvencijalnapretraga(niz, x, n, &brks);
63 bp = binarnapretraga(niz, x, n, &brkb);
64 ip = interpolacijskaPretraga(niz, x, n, &brki);
65
66 if (sp!=(-1)) printf ("\nSekvencijalno: broj je pronadjen na %d. mjestu u %d
koraka!", sp, brks);
67 else printf ("\nBroj nije pronadjen!");
68 if (bp!=(-1)) printf ("\nBinarno: broj je pronadjen na %d. mjestu u %d koraka!",
bp, brkb);
69 else printf ("\nBroj nije pronadjen!");
70 if (ip!=(-1)) printf ("\nInterpolacijsko: broj je pronadjen na %d. mjestu u %d
koraka!", ip, brki);
71 else printf ("\nBroj nije pronadjen!");
72
73 printf ("\n\n");
74
75 return 0;
76 }

Rezultat izvoenja:

Sekvencijalno: broj je pronaen na 17. mjestu u 18 koraka!


Binarno: broj je pronaen na 17. mjestu u 5 koraka!
Interpolacijsko: broj je pronaen na 17. mjestu u 2 koraka!

Kratko obrazloenje [Primjer 3]: U programu je inicijalizirano sortirano polje cijelih


brojeva. Zatim se funkcijom sizeof() odreuje broj elemenata polja koji emo zatim
proslijediti funkcijama za pretragu. Od korisnika se trai unos broja koji se trai to takoer
moramo proslijediti funkcijama. Svaka od traenih funkcija kao povratnu vrijednost vraa
indeks na kojem se pronaeni element nalazi ili -1 ako element nije pronaen. Obzirom da
funkcije mogu vratiti samo jednu povratnu vrijednost, a nas osim indeksa na kojem se
element nalazi, zanima jo i broj koraka koji je bilo potrebno izvriti za pronalazak traene
vrijednosti, kao etvrti parametar svakoj od funkcija proslijedili smo pokaziva na int
varijablu iz glavnog dijela programa kojoj emo u svakom koraku pretrage vrijednost
poveati za 1. Funkcije za pretragu implementirane su po ve spomenutim algoritmima, a
na kraju za svaku od funkcija ispisujemo na kojem je mjestu pronala traeni element i
koliko koraka joj je trebalo.

Primjer 4. Napisati program u kojem ete generirati 30000 cijelih brojeva u rasponu od 1-
30000. implementirati funkcije za selection sort, bubble sort i quick sort. Pozivati naizmjence
pojedine funkcije za sortiranje tog istog generiranog polja te izmjeriti vrijeme potrebno da
svaka od tih funkcija sortira generirano polje.

1 #include <stdio.h>
2 #include <time.h>
3 #include <stdlib.h>
4
5 void swap (int *x, int *y) { // funkcija za zamjenu 2 vrijednosti
6 int aux;
7 aux = *x;
8 *x = *y;
9 *y = aux;
10 }
11 void generiranjepolja (int A[]) { // funkcija generira 30000 random brojeva
12 int i; // u rasponu od 1-30000 i sprema ih u polje A
13 FILE *f; // te zapisuje u datoteku polje.txt
14 f = fopen ("polje.txt", "w");
15 printf ("\nKoliko zelite elemenata u polju?");
16 for (i=0; i<30000; i++){
17 A[i]=(rand()%30000+1);
18 fprintf(f, "%d ", A[i]);
19 }
20 fclose(f);
21 }
22 void ucitavanjepolja (int A[]) { // funkcija ucitava 30000 brojeva iz datoteke
23 int i; // i sprema ih u polje A
24 FILE *f;
25 f = fopen ("polje.txt", "r");
26 for (i=0; i<30000; i++){
27 fscanf(f, "%d", &A[i]);
28 }
29 fclose(f);
30 }
31 void spremanjepolja (int A[], int n) { // funkcija za zapis sortiranog polja A u
32 int i; // datoteku spolje.txt
33 FILE *f;
34 f = fopen ("spolje.txt", "w");
35 for (i=0; i<n; i++){
36 fprintf(f, "%d ", A[i]);
37 }
38 fclose(f);
39 }
40 void ispispolja (int A[], int n) {
41 int i; // funkcija za ispis cijelog polja
42 for (i=0; i<n; i++) { // na ekran
43 printf ("%d ", A[i]);
44 }
45 }
46 void selectionSort (int a[], int n) { // funkcija koja obavlja sortiranje
47 int i, j, min, br=0; // izborom najmanjeg elementa
48 for (i = 0; i < n; i++) {
49 min = i;
50 for (j = i+1; j < n; j++)
51 if (a[j] < a[min]) min = j;
52 swap(&a[i], &a[min]);
53 }
54 }
55 void bubbleSort (int a[], int n) { // funkcija koja obavlja sortiranje
56 int i, j, chg, br=0; // zamjenom susjednih elemenata
57 for (i = 0, chg = 1; chg; i++) {
58 chg = 0;
59 for (j = 0; j < n-1-i; j++)
60 if (a[j+1] < a[j]) {
61 swap(&a[j], &a[j+1]);
62 chg = 1;
63 }
64 }
65 }
66 void quickSort(int a[], int low, int high) {
67 int i = low, j = high; // funkcija koja obavlja rekurzivno
68 int s = a[(low + high) / 2]; // sortiranje algoritmom brzog
69 while (i <= j) { // sortiranja
70 while (a[i] < s) {
71 i++;
72 }
73 while (a[j] > s)
74 {
75 j--;
76 }
77 if (i <= j) {
78 swap(&a[i], &a[j]);
79 i++; j--;
80 }
81 }
82 if (low < j)
83 quickSort(a, low, j);
84 if (i < high)
85 quickSort(a, i, high);
86 }
87
88 int main() {
89 int niz[30000];
90 int izbor, n=30000;
91 float seconds;
92 clock_t start, end;
93 do {
94 printf("\nIzaberite broj 1-8:\n");
95 printf("1. Generiranje polja i spremanje u polje.txt\n");
96 printf("2. Ucitavanje polja iz datoteke polje.txt u spremanje u polje
podataka\n");
97 printf("3. Bubble Sort\n");
98 printf("4. Selection sort\n");
99 printf("5. Quick Sort\n");
100 printf("6. Ispis polja\n");
101 printf("7. Spremanje polja iz memorije u datoteku spolje.txt\n");
102 printf("8. Kraj\n");
103 scanf("%d", &izbor);
104 switch (izbor) {
105 case 1:
106 generiranjepolja(niz);
107 break;
108 case 2:
109 ucitavanjepolja(niz);
110 break;
111 case 3:
112 start = clock();
113 bubbleSort(niz, n);
114 end = clock();
115 seconds = (float)(end - start) / CLOCKS_PER_SEC;
116 printf ("Vrijeme izvoenja: %.8lfs.\n", seconds );
117 break;
118 case 4:
119 start = clock();
120 selectionSort(niz, n);
121 end = clock();
122 seconds = (float)(end - start) / CLOCKS_PER_SEC;
123 printf ("Vrijeme izvoenja: %.8lfs\n", seconds );
124 break;
125 case 5:
126 start = clock();
127 quickSort(niz, 0, n-1);
128 end = clock();
129 seconds = (float)(end - start) / CLOCKS_PER_SEC;
130 printf ("Vrijeme izvoenja: %.8lfs.\n", seconds );
131 break;
132 case 6:
133 ispispolja(niz, n);
134 break;
135 case 7:
136 spremanjepolja(niz, n);
137 break;
138 case 8:
139 break;
140 }
141 } while (izbor!=8);
142 printf ("\n\n");
143 return 0;
144 }

Rezultat izvoenja:

Za generirano polje od 30000 elemenata u rasponu od 1-30000 vrijeme sortiranja pomou


pojedinih funkcija je sljedee:

Bubble sort: 8,93s


Selection sort: 1,615s
Quick sort: 0,007s

Kratko obrazloenje [Primjer 4]: Funkcije programa su pojanjene kroz komentare u


programu. U glavnom dijelu programa korisniku je omoguen slobodan izbor poziva
pojedinih funkcija kroz switch-case izbornik. Kod poziva svake od navedenih funkcija za
sortiranje mjeri se procesorsko vrijeme potrebno za izvoenje te funkcije.
5 ZADACI

Pri rjeavanju zadataka potrebno je ispisati rezultate u tono odreenom formatu. Budui
da sustav automatski provjerava ispravnost rjeenja, sustav oekuje tekst REZULTATI: u
jednom redu, a nakon njega tono formatiran ispis rezultata na nain koji e biti naveden u
tekstu zadatka. Sav tekst koji se ispie prije teksta REZULTATI: sustav e ignorirati, kao i sav
tekst koji se ispie nakon oekivanog izlaza.

Zadatke je potrebno predati preko aktivnosti na Loomenu u koju e Vas uputiti nastavnici
na vjebama.

1. Napisati C program koji iz datoteke in1.txt u polje uitava 500 cijelih brojeva u
rasponu 0 1000. Uitati broj N s tipkovnice koji takoer mora biti vei od 0 i manji
od 1000 te provjeriti sekvencijalnim pretraivanjem nalazi li se taj broj u ranije
uitanom polju. Ukoliko je broj pronaen ispisati poruku Broj %d je pronadjen
nakon %d koraka. Ukoliko broj nije pronaen ispisati poruku Broj %d nije
pronadjen.
Primjeri ispisa:

REZULTATI: REZULTATI:

Broj 5 je pronadjen nakon 239 koraka. Broj 4 nije pronadjen.

2. Napisati C program koji s tipkovnice uitava 5 cijelih brojeva u rasponu od 1 do


1000. Zatim se uitava 500 cijelih brojeva iz datoteke in1.txt. Izvriti pretragu
svakog od unesenih brojeva s tipkovnice u uitanom polju koristei metode
sekvencijalnog i binarnog pretraivanja. Na kraju je potrebno izraunati i ispisati
srednji broj pretraivanja za svaku metodu pojedinano (pri izraunu srednjeg broja
pretraivanja uzeti u obzir samo ona pretraivanja koja su bila pozitivna). Ispis na
ekran prilagoditi formatu koji je definiran unutar testnih sluajeva.
Primjer ispisa: (za unesene brojeve 23, 67, 45, 89, 347)
REZULTATI:
Sekvencijalno:
1. broj 23 je pronadjen u 377 koraka.
2. broj 67 nije pronadjen.
3. broj 45 nije pronadjen.
4. broj 89 nije pronadjen.
5. broj 347 nije pronadjen.

Binarno:
1. broj 23 je pronadjen u 9 koraka.
2. broj 67 nije pronadjen.
3. broj 45 nije pronadjen.
4. broj 89 nije pronadjen.
5. broj 347 nije pronadjen.
Srednji broj koraka za sekvencijalno pretrazivanje je: 377.00
Srednji broj koraka za binarno pretrazivanje je: 9.00

3. Bonus zadatak: nije ga potrebno predati preko Loomena


Napisati C program koji u kojem ete implementirati funkcije za selection sort i
bubble sort. Program iz datoteke ulaz.txt prvo uitava jedan broj koji oznaava koliko
elemenata slijedi, a nakon toga program treba uitati n cijelih brojeva u polje.
Omoguiti korisniku izbornik u kojem e imati mogunost:
1. ispisati uitano polje, 2. sortirati ga koristei bubble sort uzlazno, 3. sortirati ga
koristei bubble sort silazno, 4. sortirati ga koristei selection sort uzlazno, 5. sortirati
ga koristei selection sort silazno, 6. zapisati polje u datoteku izlaz.txt, 7. Kraj
Funkcije za sortiranje primaju pokaziva na polje, duljinu polja te parametar koji
kazuje treba li vriti uzlazno ili silazno sortiranje. Ovaj zadatak ne predajete preko
VPL-a.

You might also like