1 / 23

Zadaci

Zadaci. U memoriji oblikovati linearnu listu (pomoću pokazivača) . U pojedini čvor liste upisati : - matični broj studenta (int) - ime i prezime (30+1 znakova) - ocjena (int) - pokazivač na sljedeći čvor

talbot
Download Presentation

Zadaci

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Zadaci • U memoriji oblikovati linearnu listu (pomoću pokazivača). U pojedini čvor liste upisati: - matični broj studenta (int) - ime i prezime (30+1 znakova) - ocjena (int) - pokazivač na sljedeći čvor Napisati funkciju koja će iz liste ispisati sve zapise koji sadrže određenu ocjenu (samo 2, 3, 4 ili 5). Rješava: Janko Ulaga • Strukturu red realizirati kao memorijski rezidentnu listu (upotreba pokazivača). Jedan element sadrži šifru (cijeli broj) i naziv (15+1 znakova). Treba napisati funkciju koja dodaje i funkciju koja briše element iz reda, te funkciju za ispis elementa na kojem se obavlja operacija. Ako je operacija uspjela, funkcija vraća vrijednost 1, a ako nije, vraća 0. Napomena: Novi element dodaje sena kraj liste i pamti se pokazivač na zadnji element, a elementi se skidaju iz redaod glaveliste. Preuzela: Sandra Krivačić

  2. 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 preuzeo Andrej Vidak

  3. Sortiranje pomoću hrpe (heapsort) • Na prijašnjim vježbama već smo radili dva algoritma sortiranja (sortiranje umetanjem - Insertion sort i mjehuričasto sortiranje - Bubble sort) koji su ulazni niz od n elemenata sortirali u vremenu proporcionalnom s n2. • Sad ćemo obraditi još jedan algoritam sortiranja – sortiranje pomoću hrpe - Heapsort – koji je efikasniji od Insertion sorta i Bubble sorta. Ovaj algoritam polje od n elemenata sortira u vremenu O(n*log n). • Prije nego izložimo algoritam za ovo sortiranje, ponoviti ćemo najosnovnije o stablastoj strukturi podataka zvanoj hrpa. • Potpuno binarno stablo T je hrpa (heap) ako su ispunjeni uvjeti: - čvorovi od T su označeni podacima nekog tipa za koje je definiran totalni uređaj - neka je i bilo koji čvor od T. Tada je oznaka od i manja ili jednaka od oznake bilo kojeg djeteta od i – minimalna hrpa • ali pazi sad, može biti isto tako: - neka je i bilo koji čvor od T. Tada je oznaka od i veća ili jednaka od oznake bilo kojeg djeteta od i –maksimalna hrpa Općenito: uređaj među podacima može biti i neki drugi, pa se može promijeniti i relacija roditelj - djeca

  4. uzimamo da je oznaka roditelja veća ili jednaka od oznaka svih potomaka • Hrpa je struktura podataka koja se obično implementira pomoću polja • elementi hrpe spremljeni su u polje koje promatramo kao potpuno binarno stablo (jer je svaki nivo stabla, osim posljednjega, do kraja ispunjen, a čvorovi na posljednjem nivou su "gurnuti" u lijevu stranu) • Lako je vidjeti da se lijevo dijete čvora i nalazi na poziciji 2*i+1, a desno na poziciji 2*i+2. Roditelj čvora i nalazi se na poziciji (i-1)/2 • Za svaki čvor u stablu, definiramo njegovu visinu kao broj grana na najdužem putu od tog čvora do nekog lista. Visinu stabla definiramo kao visinu njegovog korijena • Budući da je n-elementna hrpa posebni slučaj potpunog binarnog stabla, njezina visina je jednaka log2 n. Osnovna operacija za rad s hrpom (Heapify) svoj posao obavlja u vremenu koje je, u najgorem slučaju, proporcionalno visini stabla i stoga se izvršava u vremenu proporcionalnom log2 n • Operacije za rad s hrpom su sljedeće: • Funkcija Heapify koja je ključna za očuvanje uređenosti hrpe (log2 n) • Funkcija BuildHeap koja od neuređenog ulaznog polja stvara hrpu (n*log2 n) • Funkcija HeapSort koja sortira polje (n*log2 n)

  5. Implementacija strukture podataka HeapType u C-u • definiramo novi tip podataka, HeapType, kao strukturu koja sadrži: struct heaptype { int * Elements; //pokazivač na polje elemenata hrpe int Size; //veličina hrpe }; typedef struct heaptype HeapType; • Funkcija MakeEmptyHeap stvara praznu hrpu zadane veličine, dok funkcija FreeHeap oslobodi memoriju koju je neka hrpa zauzimala: HeapType MakeEmptyHeap(int size) { HeapType heap; heap.Elements = malloc(size * sizeof(int)); heap.Size = size; return heap; } void FreeHeap(HeapType * hptr) { free(hptr->Elements); }

  6. Operacija Heapify • Heapify je operacija koja kao ulazni parametar prima pokazivač na strukturu HeapType i index i nekog elementa u polju Elements. U času pozivanja funkcije Heapify pretpostavlja se da i lijevo i desno podstablo čvora i zadovoljavaju svojstvo uređenosti hrpe, ali da je element s indeksom i (eventualno) manji od svoje djece i time (eventualno) narušava uređenost hrpe • Funkcija Heapify "pomiče" element upisan u čvor i prema dolje tako da na kraju podstablo hrpe kojemu je korijen čvor i postane ispravna podhrpa (tj. podhrpa koja zadovoljava svojstvo uređenosti hrpe) • Left i Right su jednostavne pomoćne funkcije koje vraćaju indeks lijevog odnosno desnog djeteta čvora i: int Left(int i) { int Right(int i) { return 2*i + 1; return 2*i+2; } }

  7. void Heapify(HeapType * hptr, int i) { int largest; int lft; int rht; int next = 1; do { lft = Left(i); rht = Right(i); if(lft < hptr->Size && hptr->Elements[lft] > hptr->Elements[i]) largest = lft; else largest = i; if(rht < hptr->Size && hptr->Elements[rht] > hptr->Elements[largest]) largest = rht; if(largest != i) { int temp = hptr->Elements[i]; hptr->Elements[i] = hptr->Elements[largest]; hptr->Elements[largest] = temp; i = largest; } else next = 0; } while(next); }

  8. Operacija BuldHeap • Sukcesivnom upotrebom operacije Heapify možemo od "neispravne" hrpe načiniti ispravnu (koja zadovoljava uređenost hrpe). Funkcija izgleda ovako: void BuildHeap(HeapType * heapptr) { for (int i = ParentOfLastElement(heapptr); i >= 0; i--) Heapify(heapptr, i); } • BuildHeap koristi pomoćnu funkciju ParentOfLastElement koja vraća indeks roditelja posljednjeg elementa u hrpi. Ta funkcija izgleda ovako: int ParentOfLastElement(HeapType * h) { return Parent(h->Size - 1); } int Parent(int k) { return (k - 1) / 2; }

  9. Algoritam HeapSort • Algoritam Heapsort najprije pomoću funkcije BuildHeap od ulaznog polja stvori ispravnu hrpu. Nakon toga, stvorenu hrpu pretvara u uzlazno sortirano polje. Funkcija izgleda ovako: void HeapSort(int a[], int n) { HeapType heap; heap.Elements = a; heap.Size = n; BuildHeap(&heap); for(int i = n - 1; i > 0; i--) { int temp = heap.Elements[i]; heap.Elements[i] = heap.Elements[0]; heap.Elements[0] = temp; heap.Size--; Heapify(&heap, 0); } }

  10. Vidimo da algoritam najprije poziva BuildHeap (što traje proporcionalno s n*log2 n) a zatim u osnovi "vrti petlju" u kojoj se n-1 puta obavljaju neke jednostavne operacije i poziva funkcija Heapify koja traje proporcionalno s log2 n . Sveukupno, stoga, funkcija HeapSort se izvršava u vremenu proporcionalnim s n*log2 n, što je bitno bolje od sortiranja umetanjem (Insertion sort) ili mjehuričastog sortiranja (Buble sort) čije je vrijeme izvršavanja dano s n2 . • Kompletan kod za sortiranje pomoću hrpe: primjer • Napisati program koji od ulaznog polja cijelih brojeva izgradi hrpu, te ispiše polje u kojem su spremljeni elementi hrpe. Također napraviti sortiranje polja cijelih brojeva upotrebom sortiranja pomoću hrpe.

  11. #include <stdio.h> #include <stdlib.h> #define MaxSize 20 struct heaptype{ int * Elements; int Size; }; typedef struct heaptype HeapType; int Left(int k){ return 2*k + 1; } int Right(int k){ return 2*k + 2; } int Parent(int k){ return (k - 1) / 2; } int ParentOfLastElement(HeapType * h){ return Parent(h->Size - 1); }

  12. HeapType MakeEmptyHeap(int size){ HeapType heap; heap.Elements = malloc(size * sizeof(int)); heap.Size = size; return heap; } void FreeHeap(HeapType * heapptr){ free(heapptr->Elements); } void Heapify(HeapType * heapptr, int i){ int largest, lft, rht, dalje = 1; do { lft = Left(i); rht = Right(i); if(lft < heapptr->Size && heapptr->Elements[lft] > heapptr->Elements[i]) largest = lft; else largest = i; if(rht < heapptr->Size && heapptr->Elements[rht] > heapptr->Elements[largest]) largest = rht; if(largest != i) { int temp = heapptr->Elements[i]; heapptr->Elements[i] = heapptr->Elements[largest]; heapptr->Elements[largest] = temp; i = largest; } else dalje = 0; } while(dalje); }

  13. void BuildHeap(HeapType * heapptr) { for(int i = ParentOfLastElement(heapptr); i >= 0; i--) Heapify(heapptr, i); } void HeapSort(int a[], int n) { HeapType heap; heap.Elements = a; heap.Size = n; BuildHeap(&heap); for(int i = n - 1; i > 0; i--) { // u korijenu je najveći element hrpe int temp = heap.Elements[i]; heap.Elements[i] = heap.Elements[0]; // korijen stavljamo na kraj polja heap.Elements[0] = temp; // zadnji element polja ide u korijen heap.Size--; // smanjimo hrpu za 1 Heapify(&heap, 0); // slozi se nova hrpa s n-1 čvorova } }

  14. int main(){ int i, a[MaxSize] = {4,0,11,1,21,-3,26,2,5,16,17,9,10,13,14,25,8,3,7,-9}; HeapType myheap = MakeEmptyHeap(MaxSize); for(i = 0; i < myheap.Size; i++) myheap.Elements[i] = a[i]; printf("Ulazno polje:\n"); for(i = 0; i < myheap.Size; i++) printf("%i ", myheap.Elements[i]); printf("\n\n"); BuildHeap(&myheap); printf("Nakon kreiranja hrpe:\n"); for(i = 0; i < myheap.Size; i++) printf("%i ", myheap.Elements[i]); printf("\n\n\n"); FreeHeap(&myheap); printf("Prije sortiranja:\n"); int b[MaxSize] = {4,0,11,1,21,-3,26,2,5,16,17,9,10,13,14,25,8,3,7,-9}; for(i = 0; i < MaxSize; i++) printf("%i ", b[i]); printf("\n\n"); HeapSort(b, MaxSize); printf("Nakon sortiranja:\n"); for(i = 0; i < MaxSize; i++) printf("%i ", b[i]); printf("\n"); return 0; }

  15. Drugi primjer izvedbe hrpe • Jednostavan kod koji od elemenata polja stvori hrpu, koristi se jednostavnija struktura podataka (samo polje) • Ovdje se pretpostavlja da je prvi element hrpe u ćeliji polja indeksa 1 (prva ćelija polja indeksa 0 se ne koristi), pa je roditelj i-tog čvora na mjestu i/2 • Na "dno" (list) hrpe dodaje se član koji se onda uspoređuje i zamjenjuje sa svojim roditeljem, praroditeljem, prapraroditeljem itd. dok ne postane manji ili jednak nekoj od tih vrijednosti.

  16. #include <stdio.h> #include <math.h> //za funkciju pow() #define MAXGOM 100 typedef int tip; void ubaci (tip A[], int k) {// ubacuje vrijednost iz A[k] na hrpu pohranjenu u A[1:k-1] int i, j; tip novi; j = k; i = k/2; novi = A[k]; while ((i > 0) && (A[i] < novi)) { A[j] = A[i]; // povecaj razinu za roditelja j = i; i /= 2; // roditelj od A[i] je na A[i/2] } A[j] = novi; } void main(void) { FILE *fi; int i, j, k; tip A[MAXGOM];

  17. fi = fopen ("UlazZaHrpu.txt", "r"); if (fi) { j = 1; while (j < MAXGOM && fscanf(fi, "%d", &A[j]) != EOF) { printf ("%d. ulazni podatak je %d\n", j, A [j]); ubaci (A, j); j++; } fclose (fi); // ispisi hrpu po retcima i = 1; k = 1; while (i < j) { // petlja do zadnjeg u hrpi // pisi do maksimalnog u hrpi razine k for (; i <= pow (2, k) - 1 && i < j; i++) { printf(" %d ", A[i]); } k++; // povecaj razinu printf ("\n"); } } else { printf ("Nema ulazne datoteke\n"); } exit(0); }

  18. Za analizu najgoreg slučaja algoritma uzmimo nelemenata. Na i-toj razini potpunog binarnog stabla ima najviše 2i-1 čvorova. Na svim nižim razinama do tada ima ukupno 2i-1 - 1čvorova, za i > 1. Stablo s k razina ima najviše 2k-1 čvorova. Stablo s k-1 razinom ima najviše 2k-1-1 čvorova. Ako je stablo potpuno, započeta je posljednja razina, pa vrijedi 2k-1 - 1 < n ≤2k - 1 • Iz ovoga slijedi: • 2k-1 < n + 1  (k – 1) log 2 < log (n + 1)  k < log2 (n + 1) + 1 n + 1 ≤2k log (n+1) ≤ k log2 log2 (n+1) ≤ k log2 (n+1) ≤ k < log2 (n+1) + 1 odnosno k = log2(n+1) • Na primjer: • za n = 14 treba log2 15 = ln15/ln 2 = 2.70805/0.693147 = 3.9 = 4 razine • za n = 15 treba log2 16 = 4 = 4 razine • za n = 16 treba log2 17 = 4.087 = 5 razina • U najgorem slučaju, whilepetlja se izvršava proporcionalno broju razina u gomili. Skup podataka koji predstavlja najgori slučaj za ovaj algoritam je polje s rastućim podacima. Tada svaki novi element, onaj koji se ubacuje u gomilu pozivom funkcije ubaci, postaje korijen pa se kroz krazina obavlja zamjena. Vrijeme izvođenja je tadaO(n log2 n).Za prosječne podatke vrijeme za stvaranje gomile iz skupa podataka jeO(n), što je za red veličine bolje.

  19. Za poboljšanje brzine obavljanja zadanih operacija stvoren je algoritam koji kreće od krajnjih čvorova prema korijenu, razinu po razinu. Samo podatak u korijenu može narušavati svojstvo gomile, dok podstabla zadržavaju to svojstvo. Tada je samo potrebno tu nepravilnost ispraviti i opet dobivamo željenu gomilu. To čini funkcijapodesiu slijedećem primjeru. Za krajnje čvorove svojstvo gomile je zadovoljeno, pa treba ustvori_hrpu funkciji provesti popravljanje svojstva gomile samo za korijen stabla (identični postupak prvom primjeru za hrpu) • Funkcija podesi(): potpuna binarna stabla s korijenima A[2*i] i A[2*i+1]kombiniraju se s A[i] formirajuci jedinstvenu hrpu

  20. #include <stdio.h> #include <math.h> #define MAXGOM 100 typedef int tip; // potpuna binarna stabla s korijenima A[2*i] i A[2*i+1]kombiniraju se s // A[i] formirajuci jedinstvenu hrpu, 1 <= i <= n void podesi (tip A[], int i, int n) { int j; tip stavka; j = 2*i; stavka = A[i]; while (j <= n ) { // Usporedi lijevo i desno dijete (ako ga ima) if ((j < n) && (A[j] < A[j+1])) j++; // j pokazuje na vece dijete if (stavka >= A[j]) break; // stavka je na dobrom mjestu A[j/2] = A[j]; // vece dijete podigni za razinu j *=2; } A[j/2] = stavka; } // premjesti elemente A[1:n] da tvore gomilu void StvoriHrpu (tip A[], int n) { int i; for (i = n/2; i >= 1; i--) podesi (A, i, n); }

  21. void main(void) { FILE *fi; int i, j, k, n; tip A[MAXGOM]; fi = fopen ("UlazZaHrpu.txt", "r"); if (fi) { j = 1; while (j < MAXGOM && fscanf (fi, "%d", &A[j]) != EOF) { printf ("%d. ulazni podatak je %d \n", j, A[j]); j++;} fclose (fi); // podesi broj elemenata i stvori hrpu n = j - 1; StvoriHrpu (A, n); // pisi hrpu po retcima i = 1;k = 1; while (i < j) { // petlja do zadnjeg u hrpi // pisi do maksimalnog u hrpi razine k for (; i <= pow (2, k) - 1 && i < j; i++) { printf(" %d ", A[i]); }k++; // povecaj razinu printf ("\n");} } else { printf ("Nema ulazne datoteke\n");} exit(0);}

  22. 10 10 • Stvaranje hrpe za ulazni niz podataka: 10,19,18,71,12,51,32 19 18 19 51 71 12 51 32 71 12 18 32 10 71 71 51 19 51 19 12 18 32 10 12 18 32

  23. Za npodataka, 2k-1  n < 2k , broj razina je k =log2(n+1) . Za najgori slučaj broj iteracija upodesi iznosi k-i za čvor na raziniigdje ima najviše 2i-1čvorova. Slijedi da je, vrijeme izvođenja zaStvoriHrpu: k  2i-1 (k-i) . Uočimo da se eksponent mijenja od 0 do k -1, a faktor od k -1 do 0. i=1 Slijedi ekvivalentni izraz kad se izbaci faktor 0 i obrne redosljed sumacije: k-1 k-1 = i 2k-i-1 = 2k -1 i 2-i i=1 i=1 S obzirom da je 2k-1  n, k-1  n i/2i 2 n = O(n), jer suma reda teži prema 2. i=1 • Vrijeme izvođenja za najgori slučaj algoritmaStvoriHrpu je O(n), što je za red veličine bolje od O(n log2 n) za uzastopno korištenje ubaci funkcije. • Funkcija StvoriHrputraži da su svi elementi za stvaranje hrpe već prisutni, dok ubacimože ubaciti novi element u hrpu bilo kada. Funkcije koje hrpa treba brzo obaviti i radi kojih je napravljena ta struktura podataka su ubacivanje novih i brisanje najvećeg elementa iz skupa podataka. Brisanje najvećeg podatka se obavlja izbacivanjem korijena i pozivanjem funkcije podesi, a ubacivanje novih se radi funkcijom ubaci. Tako se postiže da se obje željene funkcije obavljaju uO(log2 n) vremenu.

More Related