Professional Documents
Culture Documents
LV11 PDF
LV11 PDF
LABORATORIJSKE VJEBE
LV 11
Pretraivanje i sortiranje podataka
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
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
-2 4 1 5 3
-2 4 1 5 3
-2 4 1 5 3
-2 4 1 5 3
Primjer:
#include <stdio.h>
int main() {
printf ("\n\n");
return 0;
}
Ili:
#include <stdio.h>
int main() {
printf ("\n\n");
return 0;
}
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
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
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.
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!
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;
}
Prednosti:
- puno uinkovitije od sekvencijalnog pretraivanja
Nedostatci:
- niz mora biti sortiran
- moramo imati direktan pristup elementima (preko indeksa)
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
Primjer:
#include <stdio.h>
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);
printf ("\n\n");
return 0;
}
Prednosti:
- jo efikasniji od binarnog pretraivanja
Nedostatci:
- niz mora biti sortiran
- moramo imati direktan pristup elementima (preko indeksa)
3 SORTIRANJE PODATAKA
Slika 3.2. Primjer sortiranja algoritmom izbora najmanjeg elementa (selection sort)
Primjer. Zamislite da imamo zadan niz = {50, 21, 17, 16, 18, 13, 2}. n = 7.
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:
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 }
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:
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:
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:
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