POKAZIVAI Zoran Hercigonja prof Pokazivai ULAZ Unijeti N

  • Slides: 60
Download presentation
POKAZIVAČI Zoran Hercigonja, prof.

POKAZIVAČI Zoran Hercigonja, prof.

Pokazivači ULAZ: Unijeti N prirodnih brojeva, gdje N nije unaprijed poznat niti se može

Pokazivači ULAZ: Unijeti N prirodnih brojeva, gdje N nije unaprijed poznat niti se može ograničiti. Prirodni se brojevi unose sve dok se ne unese broj 0. IZLAZ: Ispisati brojeve obrnutim redoslijedom.

Pokazivači Mogli bismo kreirati polje, no time bismo morali zanemariti zahtjev da N ne

Pokazivači Mogli bismo kreirati polje, no time bismo morali zanemariti zahtjev da N ne može biti unaprijed ograničen odozgo. Ono što je ideja ovdje je da se ne alocira memorija za sve elemente unaprijed, već da se memorija alocira kada zatreba.

Pokazivači Za ovo nam je potreban mehanizam koji će nam omogućiti da tijekom rada

Pokazivači Za ovo nam je potreban mehanizam koji će nam omogućiti da tijekom rada programa alociramo memoriju po potrebi. Taj se mehanizam naziva pokazivač. Pokazivač je varijabla koja sadrži memorijsku adresu neke druge varijable

Pokazivači Sintaksa: tip podataka *ime; Tip podataka je potreban kako bi se znalo koliko

Pokazivači Sintaksa: tip podataka *ime; Tip podataka je potreban kako bi se znalo koliko je velika varijabla u memorijskom prostoru na koji tip pokazivač i kako bi Zašto podatakapokazuje za varijablu se znalo koliko se memorije treba alocirati. koja sadrži memorijsku adresu?

Pokazivači Ono što želimo učiniti jest za svaki broj koji se unosi posebno alocirati

Pokazivači Ono što želimo učiniti jest za svaki broj koji se unosi posebno alocirati memorijski prostor No, na taj način ne možemo garantirati da će uzastopni elementi biti na uzastopnim memorijskim lokacijama Stoga elemente moramo međusobno povezati tako da svaki element ima vezu prema prethodno unešenom elementu. Ove ćemo veze izvesti pomoću pokazivača.

Pokazivači Recimo da su unešeni brojevi 23, 31, 21, 15, 55. Tada ćemo napraviti

Pokazivači Recimo da su unešeni brojevi 23, 31, 21, 15, 55. Tada ćemo napraviti sljedeću strukturu: 55 15 21 31 23

Pokazivači Svaki element treba biti slog koji će, osim unešene vrijednosti sadržavati i pokazivač

Pokazivači Svaki element treba biti slog koji će, osim unešene vrijednosti sadržavati i pokazivač na prethodno unešeni element. Strukture koje se generiraju pomoću pokazivača i alociranja memorije koje oni omogućuju nazivaju se dinamičke strukture. Struktura koju smo opisali na prethodnom slajdu naziva se vezana lista.

Pokazivači Slog treba izgledati ovako: struct element { int vrijednost; element *sljedeci; }; typedef

Pokazivači Slog treba izgledati ovako: struct element { int vrijednost; element *sljedeci; }; typedef element *lista; Ovom naredbom definiramo novi tip podataka lista, koji je pokazivač na strukturu tipa element;

Pokazivači 1. 2. Učitati brojeve Ispisati brojeve

Pokazivači 1. 2. Učitati brojeve Ispisati brojeve

Pokazivači 1. 2. 3. 4. 5. 6. 7. 8. Radi Učitaj prirodni broj Ako

Pokazivači 1. 2. 3. 4. 5. 6. 7. 8. Radi Učitaj prirodni broj Ako je broj > 0 Alociraj prostor za novi element liste Upiši vrijednost u novi element liste Poveži novi element na početak liste inače end = true

Pokazivači 1. 9. Učitati brojeve Ispisati brojeve

Pokazivači 1. 9. Učitati brojeve Ispisati brojeve

Pokazivači 9. 10. 11. Dok još postoji elemenata u listi Ispiši vrijednost Izbaci element

Pokazivači 9. 10. 11. Dok još postoji elemenata u listi Ispiši vrijednost Izbaci element iz liste

Pokazivači #include <iostream> using namespace std; struct element { int vrijednost; element *sljedeci; };

Pokazivači #include <iostream> using namespace std; struct element { int vrijednost; element *sljedeci; }; nul-pokazivač typedef element *lista; int main () { lista l = NULL;

Pokazivači Za razliku od ostalih varijabli, za pokazivače možemo definirati da ne sadrže nikakvu

Pokazivači Za razliku od ostalih varijabli, za pokazivače možemo definirati da ne sadrže nikakvu memorijsku adresu. Nepostojeća se memorijska adresa definira pomoću konstante NULL je konstanta iz biblioteke cstdlib, koji predstavlja naziv za broj 0.

Pokazivači 2. 3. 4. 5. 6. 7. 8. bool end = false; do {

Pokazivači 2. 3. 4. 5. 6. 7. 8. bool end = false; do { Učitaj prirodni broj Ako je broj > 0 Alociraj prostor za novi element liste Zapiši vrijednost u alocirani element liste Poveži novi element na početak liste inače end = true } while (!end);

Pokazivači 3. 4. 5. 6. 7. 8. bool end = false; do { int

Pokazivači 3. 4. 5. 6. 7. 8. bool end = false; do { int A; do { cout << "A = "; cin >> A; } while (A < 0); Ako je broj > 0 Alociraj prostor za novi element liste Zapiši vrijednost u novi element liste Poveži novi element na početak liste inače end = true } while (!end);

Pokazivači 3. 4. 5. 6. 7. bool end = false; do { int A;

Pokazivači 3. 4. 5. 6. 7. bool end = false; do { int A; do { cout << "A = "; cin >> A; } while (A < 0); Ako je broj > 0 Alociraj prostor za novi element liste Zapiši vrijednost u novi element liste Poveži novi element na početak liste inače end = true; } while (!end);

Pokazivači 4. 5. 6. bool end = false; do { int A; do {

Pokazivači 4. 5. 6. bool end = false; do { int A; do { cout << "A = "; cin >> A; } while (A < 0); if (A > 0) { Alociraj prostor za novi element liste Zapiši vrijednost u novi element liste Poveži novi element na početak liste } else end = true; } while (!end);

Pokazivači 3. 4. 5. bool end = false; do { int A; do {

Pokazivači 3. 4. 5. bool end = false; do { int A; do { cout << "A = "; cin >> A; } while (A < 0); if (A > 0) { Alociraj prostor za novi element liste Zapiši vrijednost u novi element Poveži novi element na početak liste } else end = true; } while (!end);

Pokazivači Deklariranjem pokazivačke varijable nije alociran memorijski prostor na koji ona pokazuje. To treba

Pokazivači Deklariranjem pokazivačke varijable nije alociran memorijski prostor na koji ona pokazuje. To treba učiniti sam korisnik, pomoću narede new.

Pokazivači 4. 5. bool end = false; do { Ova naredba new alocira int

Pokazivači 4. 5. bool end = false; do { Ova naredba new alocira int A; prostor za novu varijablu do { tipa element i vraća njenu cout << "A = "; memorijsku adresu. Tu cin >> A; ćemo adresu pridružiti } while (A < 0); pokazivaču el. if (A > 0) { element *el; el = new element; Upiši vrijednost u novi element liste Poveži novi element na početak liste } else end = true; } while (!end);

Pokazivači 5. bool end = false; do { int A; do { cout <<

Pokazivači 5. bool end = false; do { int A; do { cout << "A = "; cin >> A; } while (A < 0); if (A > 0) { element *el; el = new element; (*el). vrijednost = A; Poveži novi element na početak liste } else end = true; } while (!end);

Pokazivači Iako smo alocirali prostor na koji pokazuje pokazivač el i možemo ga koristiti

Pokazivači Iako smo alocirali prostor na koji pokazuje pokazivač el i možemo ga koristiti na isti način kao i svaku drugu varijablu, on nema ime. Da bismo mu pristupili, moramo to učiniti preko pokazivača koji na nj pokazuje. Da bismo pristupili memorijskom prostoru na koji pokazuje neki pokazivač koristimo tzv. operator dereferencijacije *. Primijetimo da se u izrazu *el nalazi u zagradama. To je zato što se C++ izrazi interpretiraju zdesna na lijevo, pa bi bez zagrade operator dereferencijacije značio podatak na koji pokazuje pokazivač el. vrijednost.

Pokazivači 5. bool end = false; element *el; do { int A; do {

Pokazivači 5. bool end = false; element *el; do { int A; do { cout << "A = "; cin >> A; } while (A < 0); if (A > 0) { el = new element; (*el). vrijednost = A; Poveži novi element na početak liste } else end = true; } while (!end);

Pokazivači Na početak liste uvijek pokazuje pokazivač l. Dakle, pokazivač l moramo preusmeriti (dodijeliti

Pokazivači Na početak liste uvijek pokazuje pokazivač l. Dakle, pokazivač l moramo preusmeriti (dodijeliti mu vrijednost) na adresu na kkoju pokazuje pokazivač el. No, kako ne bismo izgubili vrijednost na koju je prije pokazivao pokazivač l, prvo moramo pokazivač sljedeći u sloogu na koji pokazuje pokazivač el promijeniti tako da pokazuje na adresu na koju pokazuje l.

Pokazivači bool end = false; element *el; do { int A; do { cout

Pokazivači bool end = false; element *el; do { int A; do { cout << "A = "; cin >> A; } while (A < 0); if (A > 0) { el = new element; (*el). vrijednost = A; (*el). sljedeci = l; l = el; } else end = true; } while (!end);

Pokazivači 9. 10. 11. Dok još postoji elemenata u listi Ispiši vrijednost Izbaci element

Pokazivači 9. 10. 11. Dok još postoji elemenata u listi Ispiši vrijednost Izbaci element iz liste

Pokazivači Prije početka punjenja liste pokazivač l smo postavili na NULL i nakon toga

Pokazivači Prije početka punjenja liste pokazivač l smo postavili na NULL i nakon toga smo u svakom koraku u (*el). sljedeci zapisivali vrijednost poazivača l, a u l vrijednost pokazivača el. Stoga će posljednji element vezane liste sadržavati pokazivač koji će imati vrijednost NULL. U svakom koraku ćemo vrijednost pojkazivača l postaviti na (*l). sljedeci i na taj način izbaciti iz liste prvi element. No, elemente koje smo ručno alocirali treba ručno i dealocirati. Stoga ćemo morati čuvati staru vrijednost pokazivača l kako bismo ga "obrisali"

Pokazivači 9. 10. 11. Dok još postoji elemenata u listi Ispiši vrijednost Izbaci element

Pokazivači 9. 10. 11. Dok još postoji elemenata u listi Ispiši vrijednost Izbaci element iz liste

Pokazivači while (l != NULL) { cout << (*l). vrijednost << " "; el

Pokazivači while (l != NULL) { cout << (*l). vrijednost << " "; el = l; l = (*l). sljedeci; delete el; } Naredba za dealociranje memorijskog prostora na return 0; } koji pokazuje pokazivač

Polja i pokazivači Do sada smo duljinu polja definirali fiksno, unaprijed. Pokazivači nam omogućuju

Polja i pokazivači Do sada smo duljinu polja definirali fiksno, unaprijed. Pokazivači nam omogućuju da duljinu polja definiramo ovisno o parametru u programu. Prije no što pokažemo kako se to radi, dajmo još jedan jednostavni primjer, koji će pokazati u kakvoj su vezi polja i pokazivači.

Polja i pokazivači ULAZ: N cijelih brojeva, N<=50. IZLAZ: Poredati brojeve tako da na

Polja i pokazivači ULAZ: N cijelih brojeva, N<=50. IZLAZ: Poredati brojeve tako da na početku polja dolaze neparni brojevi poredani uzlazno, a nakon toga parni brojevi poredani silazno

Polja i pokazivači Radit ćemo dvostruko sortiranje umetanjem, tako da ćemo neparne brojeve umetati

Polja i pokazivači Radit ćemo dvostruko sortiranje umetanjem, tako da ćemo neparne brojeve umetati s početka polja, a parne s kraja. Imat ćemo dva brojača i i j. Brojač i će služiti da bi se znalo gdje je kraj sortiranog dijela neparnih brojeva, a j da bi se znalo gdje je početak sortiranog dijela parnih brojeva. Ovi će se kursori pomicati jedan prema drugome sve dok i ne premaši j. U svakom ćemo koraku i-ti element polja umetnuti u jedno od sortiranih dijelova polja i taj će se dio povećati za 1.

Polja i pokazivači 1. 2. 3. 4. 5. 6. 7. Učitati n brojeva i=0,

Polja i pokazivači 1. 2. 3. 4. 5. 6. 7. Učitati n brojeva i=0, j = n-1 Sve dok je i<=j radi Ako je a[i] neparan, onda ga umetni u sortirani dio polja na početku polja inače ga umetni u sortirani dio na kraju polja ispiši polje

Polja i pokazivači #include <iostream> using namespace std; int main () { Učitati n

Polja i pokazivači #include <iostream> using namespace std; int main () { Učitati n brojeva i=0, j = n-1 Sve dok je i<=j radi Ako je a[i] neparan, onda ga umetni u sortirani dio na početku polja inače ga umetni u sortirani dio na kraju polja ispiši polje return 0; } polja

Polja i pokazivači U ovom ćemo primjeru pokazati drugačiji način korištenja polja. Recimo da

Polja i pokazivači U ovom ćemo primjeru pokazati drugačiji način korištenja polja. Recimo da je deklarirano polje int a[50]; Znamo da je a[0] 0 -ti element tog polja, No, što je samo a?

Polja i pokazivači a je pokazivač na 0 -ti element polja. Dakle, a[0] je

Polja i pokazivači a je pokazivač na 0 -ti element polja. Dakle, a[0] je isto što i *a!

Polja i pokazivači Aritmetika s pokazivačima Pokazivaču je moguće dodati ili oduzeti cijeli broj!

Polja i pokazivači Aritmetika s pokazivačima Pokazivaču je moguće dodati ili oduzeti cijeli broj! Dakle dozoljeni su samo operatori + i -! Osim toga, u aritmetičkom izrazu smije biti samo jedna pokazivačka varijabla. Ako je a = 0 x 1000, koliko će biti a+1? Bit će 0 x 1004!!! Pokazivaču se ne dodaje jedan, već jedan integer!!!!

Polja i pokazivači #include <iostream> using namespace std; int main () { int n,

Polja i pokazivači #include <iostream> using namespace std; int main () { int n, a[50]; do { cout << "N = "; cin >> n; } while (n<1 || n>50); for (int i = 0; i < n; i++) cout << "A[" << i << "] = "; cin >> *(a+i);

Polja i pokazivači #include <iostream> using namespace std; int main () { Učitati n

Polja i pokazivači #include <iostream> using namespace std; int main () { Učitati n brojeva i=0, j = n-1 Sve dok je i<=j radi Ako je a[i] neparan, onda ga umetni u sortirani dio na početku polja inače ga umetni u sortirani dio na kraju polja return 0; } polja

Polja i pokazivači 3. 4. 5. 6. 7. 8. 9. 10. i=0, j =

Polja i pokazivači 3. 4. 5. 6. 7. 8. 9. 10. i=0, j = n-1 Sve dok je i<=j radi Ako je a[i] neparan umetni a[i] u sortirani dio s početka polja i=i+1 inače umetni a[i] u sortirani dio na kraju polja j=j-1

Polja i pokazivači 5. 6. 7. 8. 9. 10. int i=0, j = n-1

Polja i pokazivači 5. 6. 7. 8. 9. 10. int i=0, j = n-1 while (i<=j) { Ako je a[i] neparan umetni a[i] u sortirani dio s početka polja i=i+1 inače umetni a[i] u sortirani dio na kraju polja j=j-1 }

Polja i pokazivači 6. 7. 9. 10. int i=0, j = n-1 while (i<=j)

Polja i pokazivači 6. 7. 9. 10. int i=0, j = n-1 while (i<=j) { if (*(a+i)%2) { umetni a[i] u sortirani dio s početka polja i=i+1 } else { umetni a[i] u sortirani dio na kraju polja j=j-1 } }

Polja i pokazivači 6. 9. int i=0, j = n-1 while (i<=j) { if

Polja i pokazivači 6. 9. int i=0, j = n-1 while (i<=j) { if (*(a+i)%2) { umetni a[i] u sortirani dio s početka polja i++; } else { umetni a[i] u sortirani dio na kraju polja j--; } }

Polja i pokazivači if (*(a+i)%2) { int pom = *(a+i); int l = i-1;

Polja i pokazivači if (*(a+i)%2) { int pom = *(a+i); int l = i-1; while (l>=0 && *(a+l) > pom) *(a+l+1) = *(a+l--); *(a+l+1) = pom; i++; }

Polja i pokazivači 6. 9. int i=0, j = n-1 while (i<=j) { if

Polja i pokazivači 6. 9. int i=0, j = n-1 while (i<=j) { if (*(a+i)%2) { umetni a[i] u sortirani dio s početka polja i++; } else { umetni a[i] u sortirani dio na kraju polja j--; } }

Polja i pokazivači if (*(a+i)%2) { int pom = *(a+i); *(a+i) = *(a+k); int

Polja i pokazivači if (*(a+i)%2) { int pom = *(a+i); *(a+i) = *(a+k); int l = k+1; while (l>=0 && *(a+l) > pom) *(a+l-1) = *(a+l++); *(a+l-1) = pom; j--; } }

Polja i pokazivači for (i = 0; i < n; i++) cout << *(a+i)

Polja i pokazivači for (i = 0; i < n; i++) cout << *(a+i) << " "; cout << endl; return 0; }

Pokazivači i polja ULAZ: N brojeva. Svaki broj mora biti između 0 i 100.

Pokazivači i polja ULAZ: N brojeva. Svaki broj mora biti između 0 i 100. IZLAZ: Poredati brojeve po veličini.

Pokazivači i polja Ako je interval iz kojeg elementi poprimaju vrijednosti relativno mali, onda

Pokazivači i polja Ako je interval iz kojeg elementi poprimaju vrijednosti relativno mali, onda se može koristiti jednostavan ali efikasan algoritam sortiranja: Generira se pomoćno polje tipa koje ima onoliko elemenata koliko ima različitih vrijednosti koje elementi glavnog polja mogu poprimiti. Svi se elementi pomoćnog polja iniciraju na 0 Prođe se jednom po glavnom polju i ako je vrijednost i-tog elementa glavnog polja jednaka j, onda se j-ti element pomoćnog polja poveća za 1. Na kraju će i-ti element pomoćnog polja sadržavati broj pojava vrijednosti i u glavnom polju.

Pokazivači i polja 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.

Pokazivači i polja 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. Učitaj glavno polje A Deklariraj pomoćno polje od P[101] Postavi sve elemente pomoćnog polja na 0 Za i=0. . N radi P[A[i]]=P[A[i]]+1 k=0 Za i=0. . 100 radi Za j=1. . P[i] A[k] = i k=k+1 Ispiši polja A

Pokazivači i polja 1. 2. 3. 4. Učitaj N Deklariraj polje A cijelih brojeva

Pokazivači i polja 1. 2. 3. 4. Učitaj N Deklariraj polje A cijelih brojeva veličine N Za i=0. . N-1 radi Učitaj A[i]

Pokazivači i polja 1. 2. 3. 4. 5. 6. Učitaj N Deklariraj polje A

Pokazivači i polja 1. 2. 3. 4. 5. 6. Učitaj N Deklariraj polje A cijelih brojeva veličine N Za i=0. . N-1 radi Radi Učitaj A[i] dok A[i] nije unutar 0. . 100

Pokazivači i polja #include <iostream> using namespace std; int main () { int n;

Pokazivači i polja #include <iostream> using namespace std; int main () { int n; Dinamička alokacija do { polja od n elemenata cout << "N = "; cin >> n; } while (n<1 || n>100); int *A = new int [N]; for (int i = 0; i<n; i++) do { cout << "A[" << i << "] = "; cin >> A[i]; } while (A[i]<0 || A[i]>100);

Pokazivači i polja 1. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.

Pokazivači i polja 1. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. Učitaj glavno polje A Deklariraj pomoćno polje od P[101] Postavi sve elemente pomoćnog polja na 0 Za i=0. . N radi P[A[i]]=P[A[i]]+1 k=0 Za i=0. . 100 radi Za j=1. . P[i] A[k] = i k=k+1 Ispiši polja A

Pokazivači i polja int P[101]; for (int i=0; i<101; i++) P[i] = 0; for

Pokazivači i polja int P[101]; for (int i=0; i<101; i++) P[i] = 0; for (int i=0; i<n; i++) P[A[i]]++; int k = 0; for (int i=0; i<101; i++) for (int j=1; j<=P[i]; j++) A[k++] = i;

Pokazivači i polja 1. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.

Pokazivači i polja 1. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. Učitaj glavno polje A Deklariraj pomoćno polje od P[101] Postavi sve elemente pomoćnog polja na 0 Za i=0. . N radi P[A[i]]=P[A[i]]+1 k=0 Za i=0. . 100 radi Za j=1. . P[i] A[k] = i k=k+1 Ispiši polja A

Pokazivači i polja for (int i=0; i<n; i++) cout << A[i] << " ";

Pokazivači i polja for (int i=0; i<n; i++) cout << A[i] << " "; cout << endl; delete [] A; return 0; } Dealociranje polja

Polja i pokazivači Ovaj se algoritam sortiranja naziva sortiranje prebrojavanjem. Nedostaci: � Ovo sortiranje

Polja i pokazivači Ovaj se algoritam sortiranja naziva sortiranje prebrojavanjem. Nedostaci: � Ovo sortiranje nije efikasno ako elementi glavnog polja poprimaju vrijednosti iz velikog intervala cijelih brojeva � Nije primjenjivo na decimalne brojeve