E N D
Napisati funkciju za punjenje memorijski rezidentnog binarnog stabla u čije čvorove treba upisati: cijena artikla (realni broj) i naziv artikla (15+1 znakova). Stablo treba sortirati po cijeni artikala; lijevi jeftiniji, desni skuplji. Napisati funkciju za ispis elementa za koju je ulazni argument korijen stabla. Ispis treba biti poredan po cijeni od najjeftinijeg do najskupljeg artikla. Napisati funkciju koja ispiše sve proizvode čija je cijena manja od neke određene vrijednosti koja se unese u glavnoj funkciji programa tijekom izvršavanja programa. Zadatak preuzeo Danijel Markić • U memoriji napraviti binarno stablo traženja u čije čvorove se upisuju 2 podatka: prvi tipa int i drugi tipa float. Stablo se sortira prema cjelobrojnom podatku (lijevo manji, desno veći). Ispisati BST po algoritmu INORDER. Napisati funkcije MIN() i MAX() koje u najmanjem mogućem broju koraka (u najkraćem mogućem vremenu izvršavanja) moraju naći i ispisati zapise koji odgovaraju najmanjoj i najvećoj cjelobrojnoj vrijednosti (nije dopušteno pročitati zapise u svim čvorovima). U programu zatim izbrisati čvorove koji odgovaraju tim zapisima te ispisati tako nastalo BST u INORDER algoritmu. Napisati funkciju koja izračuna i ispiše prosječnu vrijednost varijable tipa float u BST. Zadatak slobodan
Napisati program koji od ulaznog polja cijelih brojeva izgradi minimalnu hrpu (u korijenu je najmanji element), te ispiše polje u kojem su spremljeni elementi hrpe. Također napraviti silazno sortiranje (od najvećeg elementa prema najmanjem) polja cijelih brojeva upotrebom sortiranja pomoću hrpe. Zadatak preuzeo: David Mihoci • Na web stranici kolegija (lnrpc2.irb.hr/soya/nastava/studenti.html) nalazi se popis svih studenata ovog kolegija koji su bili prisutni na bar jednom održavanju nastave, ukupno 29 studenata. Napisati program koji će iz datoteke pročitati imena i prezimena studenata i upisati ih po abecedi (po prezimenima) u listu čiji su elementi oblika ime (20 znakova), prezime (20 znakova). Elemente te liste treba prekopirati i složiti u red upotrebom generatora slučajnih brojeva (npr. prvi generirani broj je 13, tada je prvi element reda student koji je na poziciji 13 u listi, pa drugi generirani broj 7 daje da je drugi student u redu onaj koji je 7 u listi itd) tako da se svaki student pojavljuje na samo jednom mjestu u redu. Elementi reda su oblika ime (20 znakova), prezime (20 znakova), zadatak (short). Vrijednost varijable zadatak (kratki cijeli broj) za svaki element liste mora biti od 1 do 40 i njih treba upisati (svaki broj samo jednom, bez ponavljanja istih brojeva) u red također koristeći generator slučajnih brojeva (npr. ako je prvi generirani broj 17 tada taj broj ide uz studenta koji je prvi u redu itd). Tako dobiven red treba ispisati u obliku: ime, prezime, zadatak. Zadatak slobodan
Još primjera rekurzije (s predavanja) #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXA 10 // ispis znaka c u zadanoj duljini n void nznak (int c, int n) { while (--n >= 0) putchar(c); } // ispis polja void ispisi(int A[], int n) { int i; printf("\n"); for (i = 0; i < n; i++) printf(" A[%d]",i); printf("\n"); for (i = 0; i < n; i++) printf("%5d", A[i]); printf("\n"); }
// Rekurzivno trazenje indeksa clana u polju int trazi (int A[], int x, int n, int i) {// A-polje x-trazeni i-indeks od kojeg se trazi int ret; nznak(' ', i*5); printf("^^^^^\n"); if (i >= n) ret = -1; else if (A[i] == x) ret = i; else ret = trazi (A, x, n, i+1); nznak(' ', i*5); printf("%5d\n", ret); return ret; } // Rekurzivno trazenje indeksa clana u polju s ogranicivacem int trazi1 (int A[], int x, int i){ int ret; nznak(' ', i*5); printf("^^^^^\n"); if(A[i] == x) ret = i; else ret= trazi1 (A, x, i+1); nznak(' ', i*5); printf("%5d\n", ret); return ret; }
// Rekurzivno trazenje najveceg clana polja int maxclan (int A[], int i, int n) { int imax; if (i >= n-1) return n-1; imax = maxclan (A, i + 1, n); if (A[i] > A[imax]) return i; return imax; } // Rekurzivno trazenje najveceg clana polja - strukturirano int maxclan1 (int A[], int i, int n) { int imax, ret; printf ("max(%d) -> ", i); if (i >= n-1) { printf ("\n"); ret = n-1; } else { imax = maxclan1 (A, i + 1, n); if (A[i] > A[imax]) ret = i; else ret = imax; } printf ("<- max(%d)=%d ", i, ret); return ret;}
// macro naredba za vecu od dvije vrijednosti #define maxof(a,b) ((a) > (b) ? (a) : (b)) // Funkcija s macro naredbom koja vraca vrijednost najveceg clana int maxclan2 (int A[], int i, int n) { int m; if (i >= n-1) return A[i]; m = maxclan2 (A, i + 1, n); return maxof(A[i], m); } // Primjer neispravne rekurzije int los (int n, int *dubina) { int r; (*dubina)++; printf ("n = %d, dubina rekurzije = %d\n", n, *dubina); if (n == 0) r = 0; else r = los (n / 3 + 1, dubina) + n - 1; return r; }
void main (void) { int A[MAXA], x, i, n, dubina; FILE *fi; fi = fopen ("UlazZaRekurzije.txt", "r"); if (!fi) exit (1); n = 0; while (n < MAXA - 1 && fscanf (fi, "%d", &A[n]) != EOF) n++; fclose (fi); ispisi (A, n); printf ("Upisite vrijednost za x =");scanf ("%d", &x); printf ("\nRekurzivno trazenje indeksa clana\n"); ispisi (A, n); if ((i = trazi (A, x, n, 0)) < 0) { printf ("Vrijednost %d ne postoji u polju\n", x); } else { printf ("A [%d] = %d\n", i, A [i]); } printf ("\nRekurzivno trazenje ... s ogranicivacem\n"); A [n] = x; // postavljanje ogranicivaca ispisi (A, n+1); if ((i = trazi1 (A, x, 0)) == n) { printf ("Vrijednost %d ne postoji u polju", x); } else { printf ("A [%d] = %d\n", i, A [i]); }
printf ("\nRekurzivno trazenje najveceg...\n"); ispisi(A, n); if ((i = maxclan (A, 0, n)) != maxclan1 (A, 0, n)) { printf ("Pogreska: Strukturirana i nestrukturirana funkcija daju razlicite rezultate!\n"); exit (0); } printf ("\nNajveci clan A [%d] = %d\n",i, A [i]); printf ("Funkcija s macro naredbom je nasla najveci clan %d\n", maxclan2 (A, 0, n)); printf ("\nPozivam neispravnu rekurziju\n"); while (1) { dubina = 0; printf ("Upisite vrijednost za n ="); scanf ("%d", &n); i = los (n, &dubina); printf ("\ni = %d", i); } exit(0); }
Sortiranje spajanjem (merge sort) • Algoritam sortiranja sažimanjem: ulaz je lista a1, …, an , izlaz sortirana lista 1. podijeli listu na dva jednaka dijela 2. sortiraj listu a1, …, an/2 3. sortiraj listu an/2+1, …, an 4. spoji liste a1, …, an/2 i an/2+1, …, an • Algoritam sažimanja: ulaz su dvije sortirane liste b1, …, bk i c1, …, cl , izlaz je sortirana lista a1, …, ak+l 1. i = 1, j = 1 2. ponavljaj korak 3 sve dok je i ≤ k i j ≤ l 3. ako je bi < cj onda ai+j-1 = bi, i=i+1, inače ai+j-1 = cj, j=j+1 4. ponavljaj korak 5 sve dok je i ≤ k 5. ai+j-1 = bi, i=i+1 6. ponavljaj korak 7 sve dok je j ≤ l 7. ai+j-1 = cj, j=j+1 • Složenost ovog algoritma je O(n lg n) • Nedostatak: potrebno pomoćno polje
#include <stdlib.h> #include <stdio.h> #include <time.h> typedef int tip; // udruzivanje LPoz:LijeviKraj i DPoz:DesniKraj void Merge (tip A [], tip PomPolje [], int LPoz, int DPoz, int DesniKraj) { int i, LijeviKraj, BrojClanova, PomPoz; LijeviKraj = DPoz - 1; PomPoz = LPoz; BrojClanova = DesniKraj - LPoz + 1; while (LPoz <= LijeviKraj && DPoz <= DesniKraj) {// glavna petlja if (A [LPoz] <= A [DPoz]) PomPolje [PomPoz++] = A [LPoz++]; else PomPolje [PomPoz++] = A [DPoz++]; } while (LPoz <= LijeviKraj) // Kopiraj ostatak prve polovice PomPolje [PomPoz++] = A [LPoz++]; while (DPoz <= DesniKraj) // Kopiraj ostatak druge polovice PomPolje [PomPoz++] = A [DPoz++]; for (i = 0; i < BrojClanova; i++, DesniKraj--) // Kopiraj PomPolje natrag A [DesniKraj] = PomPolje [DesniKraj]; }
// MergeSort - rekurzivno sortiranje podpolja void MSort (tip A [], tip PomPolje[], int lijevo, int desno ) { int sredina; if (lijevo < desno) { sredina = (lijevo + desno) / 2; MSort (A, PomPolje, lijevo, sredina); MSort (A, PomPolje, sredina + 1, desno); Merge (A, PomPolje, lijevo, sredina + 1, desno); } } // MergeSort - sort udruzivanjem void MergeSort (tip A [], int N) { tip *PomPolje; PomPolje = malloc (N * sizeof (tip)); if (PomPolje != NULL) { MSort (A, PomPolje, 0, N - 1); free (PomPolje); } else { printf ("Nema mjesta za PomPolje!"); exit(1);} }
void main (void) { tip *Polje1,maxcl; int Duljina,brojac; printf ("Unesi broj clanova polja >"); scanf ("%d", &Duljina); if ((Polje1 = (tip *) malloc (Duljina * sizeof (tip)))== NULL) { printf("\nNema dovoljno memorije!\n"); exit(1); } srand(time(NULL)); printf("\nUnesi maksimalnu vrijednost clanova>"); scanf("%d", &maxcl); for (brojac=0; brojac<Duljina; brojac++){ Polje1[brojac]=(tip) maxcl * ((float)rand() / (RAND_MAX + 1));} printf("\n Prije sortiranja:\n"); for (brojac=0; brojac<Duljina; brojac++) printf("Polje[%d]=%d ",brojac,Polje1[brojac]); printf("\n"); MergeSort(Polje1,Duljina); printf("\n Nakon sortiranja:\n"); for (brojac=0; brojac<Duljina; brojac++) printf("Polje[%d]=%d ",brojac,Polje1[brojac]); printf("\n"); exit(0);}
Problem hanojskih tornjeva • Napisati program koji rješava problem hanojskih tornjeva: • Štapovi S (source, izvor), D (destination, odredište), T(temp, pomoćni) • Na prvom štapu (S) ima n diskova različite veličine postavljenih tako da veći nikad ne dolazi iznad manjeg. Preseliti sve diskove na D, jedan po jedan, uvijek postavljajući manji na veći • Problem je zadao francuski matematičar Edouard Lucas 1883 godine • Školski primjer uspjeha rekurzivnog postupka • Algoritam rješenja: • Ignorirati donji (najveći) disk i riješiti problem za n-1 disk, ali sa štapa S na štap T koristeći D kao pomoćni. • Sada se najveći disk nalazi na S, a ostalih n-1 na T. • Preseliti najveći disk sa S na D. • Preseliti n-1 disk sa T na D koristeći S kao pomoćni (problem je već riješen za n-1 disk).
#include <stdio.h> #include <stdlib.h> void hanoii(char src, char dest, char tmp, int n) { if (n > 0) { hanoii(src, tmp, dest, n - 1); printf("\nPrebacujem element %d s tornja %c na toranj %c", n, src, dest); hanoii(tmp, dest, src, n - 1); } } int main() { int n ; printf("\nHanojski tornjevi:"); printf("\n Unesi broj elemenata na tornjevima>"); scanf("%d",&n); hanoii('S', 'D', 'T', n); return 0; }
Analiza algoritma: označimo s TN minimalan broj poteza potreban da se riješi problem s N diskova • za N=3, T3=7; za N=2, T2=3; N=1, T1=1 (T0=0) • Izloženi rekurzivni algoritam uključuje dva puta po N-1 pomicanje s jednog štapa na drugi i još jedno završno pomicanje diska. Ovo prebacivanje nije moguće obaviti u manje koraka, jer do trenutka kad je na štapu D ostao samo najdonji disk, potrebno je prebaciti N-1 diskova sa štapa S na štap T, a to se može obaviti u najmanje N-1 prebacivanja. Zatim se u jednom prebacivanju najdonji disk složi na štap D, a da bi se prebacilo N-1 diskova na štap D potrebno je opet najmanje N-1 koraka. Dakle vrijedi: TN= 2TN-1+1, T0=0, T1=1 • uvedemosupstituciju Sn = TN +1 i slijedi rekurzivna relacija Sn= 2Sn-1, S0=0 • Karakteristična jdba je x – 2 = 0 i njeno rješenje je x = 2, a rješenje homogene rekurzivne jdbe je Sn= 2n , pa je TN= 2N -1, N ≥ 0
Dakle, našli smo da vrijeme izvršavanja ovog algoritma raste eksponencijalno s brojem diskova • Stara legenda: u indijskom hramu stoje 3 stupa s 64 zlatna diska na jednom stupu. Svećenici u hramu imaju zadatak (dan od stvoritelja) da prebace diskove poštujući gornja pravila. Kad uspiju riješiti zadatak, svijet će propasti. Kad bi uspijevali prebacivati diskove brzinom od jednog diska u sekundi i to po algoritmu koji zahtjeva najmanji broj prebacivanja, bilo bi im potrebno 264-1 sekundi što je 585 milijardi godina (današnja starost svemira je oko 14 milijardi godina).