1. uvodni zadaci spa.pdf1 1. #0b 1. uvodni zadaci 1.1. pokazivači – osnovni pojmovi 1....

122
1 1. UVODNI ZADACI 1.1. Pokazivači – osnovni pojmovi 1. Promenljive i pokazivači #include <stdio.h> main(){ int x = 3; /* Adresu promenjive x zapamticemo u novoj promeljivoj. Nova promenljiva je tipa pokazivaca na int (int*) */ int* px; printf("Adresa promenljive x je : %p\n", &x); printf("Vrednost promenljive x je : %d\n", x); px = &x; printf("Vrednost promenljive px je (tj. px) : %p\n", px); printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px); /* Menjamo vrednost promenljive na koju ukazuje px */ *px = 6; printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px); /* Posto px sadrzi adresu promenljive x, ona ukazuje na x tako da je posredno promenjena i vrednost promenljive x */ printf("Vrednost promenljive x je : %d\n", x); } 2. Popuniti sledeću tabelu: A B C P1 P2 Init 1 2 3 &A &C *P1 = (*P2)++ 3 2 4 &A &C P1 = P2 3 2 4 &C &C P1 = &B 3 2 4 &B &C *P1 = *P1 - *P2 3 -2 4 &B &C

Upload: others

Post on 07-Feb-2021

7 views

Category:

Documents


0 download

TRANSCRIPT

  • 1

    1. # 0B

    1. UVODNI ZADACI

    1.1. Pokazivači – osnovni pojmovi

    1. Promenljive i pokazivači #include main(){ int x = 3; /* Adresu promenjive x zapamticemo u novoj promeljivoj. Nova promenljiva je tipa pokazivaca na int (int*) */ int* px; printf("Adresa promenljive x je : %p\n", &x);

    printf("Vrednost promenljive x je : %d\n", x); px = &x; printf("Vrednost promenljive px je (tj. px) : %p\n", px); printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px); /* Menjamo vrednost promenljive na koju ukazuje px */ *px = 6; printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px); /* Posto px sadrzi adresu promenljive x, ona ukazuje na x tako da je posredno promenjena i vrednost promenljive x */ printf("Vrednost promenljive x je : %d\n", x); }

    2. Popuniti sledeću tabelu:

    A B C P1 P2 Init 1 2 3 &A &C

    *P1 = (*P2)++ 3 2 4 &A &C P1 = P2 3 2 4 &C &C P1 = &B 3 2 4 &B &C

    *P1 = *P1 - *P2 3 -2 4 &B &C

  • 2

    3. Swap : Demonstracija prenosa argumenata preko pokazivaca

    #include /* Pogresna verzija funkcije swap. Zbog prenosa po vrednosti, funkcija razmenjuje kopije promenljivih iz main-a, a ne samih promenljivih */ void swap_wrong(int x, int y){ int tmp; printf("swap_wrong: "); printf("Funkcija menja vrednosti promenljivim na adresama : \n"); printf("x : %p\n", &x); printf("y : %p\n", &y); tmp = x; x = y; y = tmp; } /* Resenje je prenos argumenata preko pokazivaca */ void swap(int* px, int* py){ int tmp; printf("swap : Funkcija menja vrednosti promenljivim na adresama : \n"); printf("px = %p\n", px); printf("py = %p\n", py); tmp = *px; *px = *py; *py = tmp; } int main(){ int x = 3, y = 5; printf("Adresa promenljive x je %p\n", &x); printf("Vrednost promenljive x je %d\n", x); printf("Adresa promenljive y je %p\n", &y); printf("Vrednost promenljive y je %d\n", y); /* Pokusavamo zamenu koristeci pogresnu verziju funkcije */ swap_wrong(x, y); printf("Posle swap_wrong:\n"); printf("Vrednost promenljive x je %d\n", x); printf("Vrednost promenljive y je %d\n", y); /* Vrsimo ispravnu zamenu. Funkciji swap saljemo adrese promenljvih x i y, a ne njihove vrednosti */ swap(&x, &y); printf("Posle swap:\n"); printf("Vrednost promenljive x je %d\n", x); printf("Vrednost promenljive y je %d\n", y); return 0;

  • 3

    }

    1.2. Pokazivači – veze sa nizovima

    4. Pokazivačka aritmetika

    #include main(){ char s[] = "abcde"; int t[] = { 1, 2, 3, 4, 5 }; /* Inicijalizujmo pokazivace ps i pt na pocetke nizova s i t */ char* ps = &s[0]; int* pt = &t[0]; /* Pokazivace je moguce sabirati sa celim brojevima i od njih je moguce oduzimati cele brojeve*/ /* Ispisimo vrednosti pokazivaca */ printf("ps = %p\n", ps); printf("ps+1 = %p\n", ps + 1); printf("ps+2 = %p\n", ps + 2); printf("ps-1 = %p\n", ps - 1); printf("ps-2 = %p\n", ps - 2); /* Prilikom sabiranja pokazivaca i celih brojeva, dodaje se velicina odgovarajuceg tipa. */ printf("pt = %p\n", pt); printf("pt+1 = %p\n", pt + 1); printf("pt+2 = %p\n", pt + 2); printf("pt-1 = %p\n", pt - 1); printf("pt-2 = %p\n", pt - 2); /* Na pokazivace je moguce primenjivati i operatore ++ i -- */ for (ps = s; *ps; ps++) putchar(*ps); putchar('\n'); /* Slicno, dva pokazivaca istog tipa se mogu oduzimati. Prilikom sracunavanja rezultata, uzima se u obzir velicina tipa. */ ps = &s[3]; printf("s = %p\n", s); printf("ps = %p\n", ps); printf("ps - s = %d\n", ps - s); pt = &t[3]; printf("t = %p\n", t); printf("pt = %p\n", pt); printf("pt - t = %d\n", pt - t); }

  • 4

    5. Veza između pokazivača i nizova

    #include void print_array(int* pa, int n); int main(){ int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int num_of_elements = sizeof(a) / sizeof(int); int* pa; /* Niz je isto sto i adresa prvog elementa */ printf("Niz a : %p\n", a); printf("Adresa prvog elementa niza a (&a[0]) : %p\n", &a[0]); /* Moguce je dodeliti niz pokazivacu odgovarajuceg tipa */ pa = a; printf("Pokazivac pa ukazuje na adresu : %p\n", pa); /* Nizu nije moguce dodeliti pokazivacku promenljivu (nizove mozemo smatrati KONSTANTNIM pokazivacima na prvi element) */ /* a = pa; */ /* Niz je moguce koristiti kao pokazivac tj. vaze pravila pokazivacke aritmetike*/ printf("a + 3 = %p\n", a + 3); /* Vazi da je a + i = &a[i] odnosno *(a + i) = a[i] */ printf("&a[3] = %p\n", &a[3]); /* Identiteti a + i = &a[i] odnosno *(a + i) = a[i] vazi i za pokazivace i za nizove */ /* Pokazivace je na osnovu prethodnog moguce indeksirati kao nizove */ printf("pa[5] = %d\n", pa[5]); printf("*(pa + 5) = %d\n", *(pa + 5)); /* Medjutim, sizeof(pa) je samo velicina pokazivaca, a ne niza */ printf("sizeof(a) = %d\n", sizeof(a)); printf("sizeof(pa) = %d\n", sizeof(pa)); /* Pozivamo funkciju za stampanje niza i saljemo joj niz */ print_array(a, num_of_elements); /* Pozivamo funkciju za stampanje niza i saljemo joj pokazivac na pocetak niza */ print_array(pa, num_of_elements); } /* Proslednjivanje niza u funkciju void print_array(int pa[], int n);

  • 5

    je ekvivalentno prosledjivanju pokazivaca u funkciju void print_array(int* pa, int n); Izmedju ovih konstrukcija nema nikakve razlike. */ void print_array(int* pa, int n){ int i; for (i = 0; i < n; i++) printf("%d ", pa[i]); putchar('\n'); }

    6. Implementiranje funkcija iz biblioteke string.h - strlen, strcpy, strcat, strcmp, strchr, strstr, ... - verzije sa pokazivacima

    #include #include /* Zbog NULL */ /* Izracunava duzinu stringa */ int string_length(char* s) { char* t; for (t = s; *t; t++); return t - s; } /* Kopira string src u string dest. Pretpostavlja da u dest ima dovoljno prostora.*/ void string_copy(char *dest, char *src) { /* Kopira karakter po karakter, sve dok nije iskopiran karakter ’\0’ */ while (*dest++ = *src++); } /* Nadovezuje string t na kraj stringa s. Pretpostavlja da u s ima dovoljno prostor */ void string_concatenate(char *s, char *t) { /*Pronalazimo kraj stringa s*/ while (*s) s++; /*Vrsi se kopiranje, slicno kao u funkciji string_copy*/ while (*s++ = *t++); } /* Vrsi leksikografsko poredjenje dva stringa. Vraca : 0 - ukoliko su stringovi jednaki 0 - ukoliko je s leksikografski iza t */ int string_compare(char* s, char* t) { /* Petlja ide sve dok ne naidjemo na prvi razlicit karakter */ for (; *s == *t; s++, t++) if (*s == '\0') /* Naisli smo na kraj oba stringa, a nismo nasli razliku */ return 0;

  • 6

    /* *s i *t su prvi karakteri u kojima se niske razlikuju. Na osnovu njihovog odnosa, odredjuje se odnos stringova */ return *s - *t; } /* Pronalazi prvu poziciju karaktera c u stringu s, i vraca pokazivac na nju, odnosno NULL ukoliko s ne sadrzi c */ char* string_char(char* s, char c) { for (; *s; s++) if (*s == c) return s; /* Nije nadjeno */ return NULL; } /* Pronalazi poslednju poziciju karaktera c u stringu s, i vraca pokazivac na nju, odnosno NULL ukoliko s ne sadrzi c */ char* string_last_char(char* s, char c) { char* t = s; /* Pronalazimo kraj stringa s */ while (*t++); /* Krecemo od kraja i trazimo c unazad */ for (t--; t >= s; t--) if (*t == c) return t; /* Nije nadjeno */ return NULL; } /* Proverava da li string str sadrzi string sub. Vraca poziciju na kojoj sub pocinje, odnosno -1 ukoliko ga nema */ char* string_string(char* str, char* sub) { char* s, * t; /* Proveravamo da li sub pocinje na svakoj poziciji i */ for (; *str; str++) /* Poredimo sub sa str pocevsi od poziciji i sve dok ne naidjemo na razliku for (s = str, t = sub; *s == *t; s++, t++) /* Nismo naisli na razliku a ispitali smo sve karaktere niske sub */ if (*(t + 1) == '\0') return str; /* Nije nadjeno */ return NULL; } int main(){ char s[100]; char t[] = "Zdravo"; char u[] = " svima"; char r[] = "racunari"; string_copy(s, t); printf("%s\n", s); string_concatenate(s, u); printf("%s\n", s); printf("%d\n", string_char(r, 'n') - r);

  • 7

    printf("%d\n", string_last_char(r, 'a') - r); printf("%d\n", string_string(r, "racun") - r); printf("%d\n", string_string(r, "ari") - r); printf("%d\n", string_string(r, "cun") - r); printf("%p\n", string_string(r, "cna")); return 0; }

  • 8

    2. LINEARNE STRUKTURE PODATAKA

    2.1. 1BPOLJE

    2.1.1. 5BDEFINICIJE I STRUKTURA

    Polje (array) predstavlja linearnu homogenu statičku strukturu podataka i sastoji se od fiksnog

    broja komponenata istog tipa. Svaki element polja se može označiti pomoću indeksa i svakom se

    elementu može direktno pristupati. Ukupan broj komponenti polja određen je pri njegovom opisu i ne

    može se menjati. Polje može biti jednodimenzionalno i višedimenzionalno.

    Adresa i-te komponente vektora A je data jednačinom:

    LR0R+c*(i-1),

    gde su: LR0R – adresa prve reči prvog elementa vektora A, a c – broj reči pridružen svakom elementu.

    Dvodimenzionalna polja se mogu memorisati po vrstama ili kolonama i mogu se prikazati

    ekvivalentnim jednodimenzionalnim vektorom. Adresa elementa A[i,j] dvodimenzionalnog polja

    smeštenog po kolonama data je izrazom:

    LR0R+c*[(j-1)*n + (i-1)],

    gde je n broj vrsta.

    Analogno, adresa elementa A[i,j] dvodimenzionalnog polja smeštenog po vrstama data je

    izrazom:

    LR0R+c*[(i-1)*n + (j-1)].

    Analogno se smeštaju i višedimenzionalna polja u memoriju.

    7. Napisati C program koji sa standardnog ulaza učitava raspored 8 topova na šahovskoj tabli. Raspored se učitava u formi 8 linija sa po 8 brojeva po liniji. Ako na datom polju nema topa, učitava se 0, a inače 1. Program mora da ispita validnost unetog rasporeda ( da li su učitani brojevi ili 0 ili 1, da li ima 8 topova) i ispita da li se u datom rasporedu dva topa tuku.

    #include #include int main() { int tabla[8][8]; /*matrica nula i jedinica cuva raspored 8 topova na tabli */ int suma; /* pamti se suma reda/kolone kao test osobina iz zahteva zadatka */ int i, j; /*brojaci u petljama */ /*ucitavanje podataka o rasporedu topova uz sumiranje broja topova i u slucaju greske stampa se odgovarajuca poruka i okoncava programa */ suma = 0; for (i = 0; i < 8; i++) for (j = 0; j < 8; j++) { scanf("%d", &tabla[i][j]); /*test korektnosti ulaza */ if (tabla[i][j] != 0 && tabla[i][j] != 1) {

  • 9

    printf("\nNekorektni ulazni podaci o rasporedu topova\n"); exit(EXIT_FAILURE); } suma = suma + tabla[i][j]; } /*greska je ako je broj topova na tabli razlicit od 8 */ if (suma != 8) { printf("\nNekorektni ulazni podaci o broju topova\n"); exit(EXIT_FAILURE); } /*proveravanje da li se dva topa nalaze u istom redu , tj. da li je suma clanova nekog reda veca od 1 */ for (i = 0; i < 8; i++) { suma = 0; for (j = 0; j < 8; j++) suma += tabla[i][j]; if (suma > 1) { printf("\nTopovi se tuku\n"); exit(EXIT_SUCCESS); } } /*proveravanje da li se dva topa nalaze u istoj koloni , tj. da li je suma clanova neke kolone veca od 1 */ for (j = 0; j < 8; j++) { suma = 0; for (i = 0; i < 8; i++) suma += tabla[i][j]; if (suma > 1) { printf("\nTopovi se tuku\n"); exit(EXIT_SUCCESS); } } /*inace se topovi ne tuku */ printf("\nTopovi se ne tuku\n"); exit(EXIT_SUCCESS); }

    8. U prvom redu ulazne datoteke se nalazi broj n koji označava broj članova niza. U narednim redovima datoteke se nalaze članovi niza. Nakon učitavanja svakog od elemenata ubaciti ga u niz tako da niz uvek bude sortiran u neopadajućem poretku.

    #pragma warning(disable: 4996) #include #include void umetniUNiz(int value, int niz[], int n) { int i = n-1; while (niz[i] > value && i >= 0) { niz[i + 1] = niz[i]; i--; }

  • 10

    niz[i + 1] = value; } int main() { FILE* f; int niz[100], n, i, trenDuz, value; f = fopen("zad07.txt", "r"); fscanf(f, "%d", &n); trenDuz = 0; for (i = 0; i < n; i++) { fscanf(f, "%d", &value); umetniUNiz(value, niz, trenDuz); trenDuz++; } fclose(f); printf("\nUcitana duzina niza je: %d\n", n); printf("Ucitani niz je:\n"); for (i = 0; i < n; i++) { printf("%d ", niz[i]); } printf("\n"); system("PAUSE"); return 0;

    }

    9. U provom redu ulazne datoteke se nalazi broj članova, a u svakom narednom po jedan član niza. Napisati funkciju int prosekParnih(int [] niz) koja računa i vraća prosek parnih elemenata niza (onih koji imaju parne vrednosti, a ne na parnim mestima u nizu).

    #pragma warning(disable: 4996) #include #include double prosekParnihElemenata(int niz[], int n) { double pv = 0.0; int i, be = 0, zbir = 0; for (i = 0; i < n; i++) { if (niz[i] % 2 == 0) { zbir += niz[i]; be++; } } if (be > 0) { pv = (double)zbir / be; } return pv; } int main() { FILE* f;

  • 11

    int i, n, niz[100]; double pv; f = fopen("zad08.txt", "r"); fscanf(f, "%d", &n); for (i = 0; i < n; i++) { fscanf(f, "%d", &niz[i]); } fclose(f); pv = prosekParnihElemenata(niz, n); printf("Prosecna vrednost parnih elemenata niza je: %.2f\n", pv); system("PAUSE"); return 0;

    }

    10. Izračunati vrednost determinante matrice dimenzija n x n.

    I način: /* Implementacija dinamickih kvadratnih matrica preko pokazivaca na niz pokazivaca

    na kolone */

    #include

    #include

    /* Tip elemenata matrice ce biti float */

    typedef float tip;

    /* Funkcija alocira matricu dimenzije n*n */

    tip** allocate(int n){

    tip **m;

    int i;

    /* Alocira se niz pokazivaca na kolone */

    m=(tip**)malloc(n*sizeof(tip*));

    for (i=0; i

  • 12

    int i,j;

    printf("Unesite dimenziju kvadratne matrice :");

    scanf("%d",pn);

    *matrica=allocate(*pn);

    for (i=0; i

  • 13

    2.2. LANČANE LISTE

    2.2.1. 8B Definicija

    Lančana lista, za razliku od prethodnih struktura koristi lančani (spregnuti) način zauzeća

    memorije. Prednosti korišćenja lančane liste:

    - Količina rezervisane memorije ne mora biti unapred zadata i fiksirana. Tačan iznos zauzete

    memorije će zavisiti isključivo od količine podataka koji se obrađuju.

    - Moguće je brzo i često brisanje i umetanje podataka.

    Elementi lančane liste nisu memorisani u uzastopnim memorijskim lokacijama, već svaki element

    eksplicitno ukazuje na naredni element u memoriji. Postoji nekoliko tipova listi:

    1) jednostruko spregnuta lista

    2) dvostruko spregnuta lista

    3) kružna lista

    2.2.2. 9BJEDNOSTRUKO SPREGNUTA LINEARNA LISTA

    Svaki element ove strukture sadrži dva polja: podatak i pokazivač na naredni element u listi. Glava

    liste je pokazivač koji sadrži adresu prvog elementa liste.

    /* Rad sa jednostruko spregnutom listom - iterativne verzije funkcija za

    rad sa povezanom listom */

    #include

    #include

    typedef struct elem {

    int broj;

    struct elem *sled;

    } Elem; /*Element liste*/

    int duz (Elem *lst); /* Broj elemenata liste. */

    void pisi (Elem *lst); /* Ispisivanje liste. */

    Elem *na_pocetak (Elem *lst, int b); /* Dodavanje na pocetak. */

    Elem *na_kraj (Elem *lst, int b); /* Dodavanje na kraj. */

    Elem *citaj1 (int n); /* Citanje liste stavljajuci brojeve na pocetak. */

    Elem *citaj2 (int n); /* Citanje liste stavljajuci brojeve na kraj. */

    Elem *umetni (Elem *lst, int b); /* Umetanje u uredjenu listu. */

    void brisi (Elem *lst); /* Brisanje svih elemenata liste. */

    Elem *izostavi (Elem *lst, int b);/* Izostavljanje svakog pojavljivanja.*/

    void main () {

    Elem *lst = NULL; int kraj = 0, izbor, broj, n;

    while (!kraj) {

    printf ("\n1. Dodavanje broja na pocetak liste\n"

    "2. Dodavanje broja na kraj liste\n"

    "3. Umetanje broja u uredjenu listu\n"

  • 14

    "4. Izostavljanje broja iz liste\n"

    "5. Brisanje svih elemenata liste\n"

    "6. Citanje uz obrtanje redosleda brojeva\n"

    "7. Citanje uz cuvanje redosleda brojeva\n"

    "8. Odredjivanje duzine liste\n"

    "9. Ispisivanje liste\n"

    "0. Zavrsetak rada\n\n"

    "Vas izbor? "

    );

    scanf ("%d", &izbor);

    switch (izbor) {

    case 1: case 2: case 3: case 4:

    printf ("Broj? "); scanf ("%d", &broj);

    switch (izbor) {

    case 1: /* Dodavanje broja na pocetak liste: */

    lst = na_pocetak (lst, broj); break;

    case 2: /* Dodavanje broja na kraj liste: */

    lst = na_kraj (lst, broj); break;

    case 3: /* Umetanje broja u uredjenu listu: */

    lst = umetni (lst, broj); break;

    case 4: /* Izostavljanje broja iz liste: */

    lst = izostavi (lst, broj); break;

    }

    break;

    case 5: /* Brisanje svih elemenata liste: */

    brisi (lst); lst = NULL; break;

    case 6: case 7: /* Citanje liste: */

    printf ("Duzina? "); scanf ("%d", &n);

    printf ("Elementi? "); brisi (lst);

    switch (izbor) {

    case 6: /* uz obrtanje redosleda brojeva: */

    lst = citaj1 (n); break;

    case 7: /* uz cuvanje redosleda brojeva: */

    lst = citaj2 (n); break;

    }

    break;

    case 8: /* Odredjivanje duzine liste: */

    printf ("Duzina= %d\n", duz (lst)); break;

    case 9: /* Ispisivanje liste: */

    printf ("Lista= "); pisi (lst); putchar ('\n'); break;

    case 0: /* Zavrsetak rada: */

    kraj = 1; break;

    default: /* Pogresan izbor: */

    printf ("*** Neozvoljeni izbor! ***\a\n"); break;

    }

    }

    }

    /* Definicije funkcija za obradu lista (iterativno). */

    int duz (Elem *lst) { /* Broj elemenata liste.

    */

    int n = 0;

    while (lst){

    n++;

    lst = lst->sled;

    } return n;

    }

  • 15

    void pisi (Elem *lst){ /* Ispisivanje liste. */

    while(lst){

    printf("%d ",lst->broj);

    lst = lst -> sled;

    }

    }

    Elem *na_pocetak(Elem *lst, int b){ /* Dodavanje na pocetak. */

    Elem *novi = malloc(sizeof(Elem));

    novi->broj = b; novi->sled = lst;

    return novi;

    }

    Elem *na_kraj (Elem *lst, int b) { /* Dodavanje na kraj. */

    Elem *novi = malloc (sizeof(Elem));

    novi->broj = b; novi->sled = NULL;

    if (!lst) return novi;

    else {

    Elem *tek = lst;

    while (tek->sled) tek = tek->sled;

    tek->sled = novi;

    return lst;

    }

    }

    Elem *citaj1 (int n) { /* Citanje liste stavljajuci brojeve na pocetak. */

    Elem *prvi = NULL; int i;

    for (i=0; ibroj);

    novi->sled = prvi;

    prvi = novi;

    }

    return prvi;

    }

    Elem *citaj2 (int n) { /* Citanje liste stavljajuci brojeve na kraj. */

    Elem *prvi = NULL, *posl = NULL; int i;

    for (i=0; ibroj); novi->sled = NULL;

    if (!prvi)

    prvi = novi;

    else posl->sled = novi;

    posl = novi;

    }

    return prvi;

    }

    Elem *umetni (Elem *lst, int b) { /* Umetanje u uredjenu listu. */

    Elem *tek = lst, *pret = NULL, *novi;

    while(tek && tek->broj < b){

    pret = tek;

    tek = tek->sled;

    }

    novi = malloc (sizeof(Elem));

    novi->broj = b;

    novi->sled = tek;

  • 16

    if(!pret)

    lst = novi;

    else pret->sled = novi;

    return lst;

    }

    void brisi (Elem *lst) { /* Brisanje svih elemenata liste.

    */

    while(lst){

    Elem *stari = lst;

    lst = lst->sled;

    free (stari);

    }

    }

    Elem *izostavi(Elem *lst, int b){ /* Izostavljanje svakog pojavljivanja.

    */

    Elem *tek = lst, *pret = NULL;

    while(tek)

    if (tek->broj != b){

    pret = tek;

    tek = tek->sled;

    }

    else {

    Elem *stari = tek;

    tek = tek->sled;

    if (!pret) lst = tek; else pret->sled = tek;

    free (stari);

    }

    return lst;

    }

    /* Rad sa povezanom listom - REKURZIVNE verzije

    funkcija za rad sa povezanom listom;

    */

    #include

  • 17

    #include

    typedef struct elem { int broj; struct elem *sled; } Elem; /*Element

    liste*/

    int duz (Elem *lst); /* Broj elemenata liste. */

    void pisi (Elem *lst); /* Ispisivanje liste. */

    Elem *na_pocetak (Elem *lst, int b); /* Dodavanje na pocetak. */

    Elem *na_kraj (Elem *lst, int b); /* Dodavanje na kraj. */

    Elem *citaj1 (int n); /* Citanje liste stavljajuci brojeve na pocetak. */

    Elem *citaj2 (int n); /* Citanje liste stavljajuci brojeve na kraj. */

    Elem *umetni (Elem *lst, int b); /* Umetanje u uredjenu listu. */

    void brisi (Elem *lst); /* Brisanje svih elemenata liste. */

    Elem *izostavi (Elem *lst, int b);/* Izostavljanje svakog pojavljivanja.*/

    void main () {

    Elem *lst = NULL; int kraj = 0, izbor, broj, n;

    while (!kraj) {

    printf ("\n1. Dodavanje broja na pocetak liste\n"

    "2. Dodavanje broja na kraj liste\n"

    "3. Umetanje broja u uredjenu listu\n"

    "4. Izostavljanje broja iz liste\n"

    "5. Brisanje svih elemenata liste\n"

    "6. Citanje uz obrtanje redosleda brojeva\n"

    "7. Citanje uz cuvanje redosleda brojeva\n"

    "8. Odredjivanje duzine liste\n"

    "9. Ispisivanje liste\n"

    "0. Zavrsetak rada\n\n"

    "Vas izbor? "

    );

    scanf ("%d", &izbor);

    switch (izbor) {

    case 1: case 2: case 3: case 4:

    printf ("Broj? "); scanf ("%d", &broj);

    switch (izbor) {

    case 1: /* Dodavanje broja na pocetak liste: */

    lst = na_pocetak (lst, broj); break;

    case 2: /* Dodavanje broja na kraj liste: */

    lst = na_kraj (lst, broj); break;

    case 3: /* Umetanje broja u uredjenu listu: */

    lst = umetni (lst, broj); break;

    case 4: /* Izostavljanje broja iz liste: */

    lst = izostavi (lst, broj); break;

    }

    break;

    case 5: /* Brisanje svih elemenata liste: */

    brisi (lst); lst = NULL; break;

    case 6: case 7: /* Citanje liste: */

    printf ("Duzina? "); scanf ("%d", &n);

    printf ("Elementi? "); brisi (lst);

    switch (izbor) {

    case 6: /* uz obrtanje redosleda brojeva: */

    lst = citaj1 (n); break;

    case 7: /* uz cuvanje redosleda brojeva: */

    lst = citaj2 (n); break;

    }

    break;

    case 8: /* Odredjivanje duzine liste: */

  • 18

    printf ("Duzina= %d\n", duz (lst)); break;

    case 9: /* Ispisivanje liste: */

    printf ("Lista= "); pisi (lst); putchar ('\n'); break;

    case 0: /* Zavrsetak rada: */

    kraj = 1; break;

    default: /* Pogresan izbor: */

    printf ("*** Neozvoljeni izbor! ***\a\n"); break;

    }

    }

    }

    /* Definicije funkcija za obradu lista (REKURZIVNO). */

    int duz (Elem *lst) { /* Broj elemenata liste. */

    return lst ? duz (lst->sled) + 1 : 0;

    }

    void pisi (Elem *lst) { /* Ispisivanje liste. */

    if (lst) { printf ("%d ", lst->broj); pisi (lst->sled); }

    }

    Elem *na_pocetak (Elem *lst, int b) { /* Dodavanje na pocetak. */

    Elem *novi = malloc (sizeof(Elem));

    novi->broj = b; novi->sled = lst;

    return novi;

    }

    Elem *na_kraj (Elem *lst, int b) { /* Dodavanje na kraj. */

    if (!lst) {

    lst = malloc (sizeof(Elem));

    lst->broj = b; lst->sled = NULL;

    } else

    lst->sled = na_kraj (lst->sled, b);

    return lst;

    }

    Elem *citaj1 (int n) { /* Citanje liste uz obrtanje redosleda. */

    if (n == 0) return NULL;

    else {

    Elem *novi = malloc (sizeof(Elem));

    novi->sled = citaj1 (n - 1); scanf ("%d", &novi->broj);

    return novi;

    }

    }

    Elem *citaj2 (int n) { /* Citanje liste uz cuvanje redosleda. */

    if (n == 0) return NULL;

    else {

    Elem *novi = malloc (sizeof(Elem));

    scanf ("%d", &novi->broj); novi->sled = citaj2 (n - 1);

    return novi;

    }

    }

    Elem *umetni (Elem *lst, int b) { /* Umetanje u uredjenu listu. */

    if (!lst || lst->broj >= b) {

    Elem *novi = malloc (sizeof(Elem));

    novi->broj = b; novi->sled = lst;

  • 19

    return novi;

    } else {

    lst->sled = umetni (lst->sled, b);

    return lst;

    }

    }

    void brisi (Elem *lst) { /* Brisanje svih elemenata liste. */

    if (lst) { brisi (lst->sled); free (lst); }

    }

    Elem *izostavi (Elem *lst, int b){/* Izostavljanje svakog pojavljivanja.*/

    if (lst) {

    if (lst->broj != b) {

    lst->sled = izostavi (lst->sled, b);

    } else {

    Elem *stari = lst;

    lst = izostavi (lst->sled, b);

    free (stari);

    }

    }

    return lst;

    }

  • 20

    2.2.3. Zadaci

    12. Napisati C program koji će vratiti koliko elemenata liste ima vrednost veću od elementa na početku liste.

    #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include typedef struct elem { int broj; struct elem *sled; } Elem; int prebroj(Elem *lst) { int broj = 0; Elem *pom = lst; while (pom != NULL) { if (pom->broj > lst->broj) broj++; pom = pom->sled; } return broj; } Elem *citaj2(int n) { Elem *prvi = NULL, *posl = NULL; int i; for (i = 0; i < n;i++) { Elem *novi = (Elem*)malloc(sizeof(Elem)); scanf("%d", &novi->broj); novi->sled = NULL; if (!prvi) prvi = novi; else posl->sled = novi; posl = novi; } return prvi; } void main() { Elem *lst = NULL; int n, b; printf("\nBroj elemenata liste? "); scanf("%d", &n); lst = citaj2(n); b = prebroj(lst); printf("\nBroj elemenata liste koji su veci od prvog je: %d\n", b); system("PAUSE"); }

  • 21

    13. Napisati C program koji vraća broj ponavljanja zadate vrednosti u listi.

    #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include typedef struct elem { int broj; struct elem *sled; } Elem; Elem *citaj2(int n) { Elem *prvi = NULL, *posl = NULL; int i; for (i = 0; i < n;i++) { Elem *novi = (Elem*)malloc(sizeof(Elem)); scanf("%d", &novi->broj); novi->sled = NULL; if (!prvi) prvi = novi; else posl->sled = novi; posl = novi; } return prvi; } int brojPonavljanja(Elem *lst, int b) { Elem *pom = lst; int broj = 0; while (pom != NULL) { if (pom->broj == b) broj++; pom = pom->sled; } return broj; } void main() { Elem *lst = NULL; int n, b, br; printf("\nBroj elemenata liste? "); scanf("%d", &n); lst = citaj2(n); printf("\nTrazeni broj? "); scanf("%d", &br); b = brojPonavljanja(lst,br); printf("\nBroj elemenata liste koji su jednaki broju %d je: %d\n",br, b); system("PAUSE"); }

  • 22

    14. Napisati program koji u jednostruko povezanoj linearnoj listi pronalazi i izbacuje element koji se nalazi nakon elementa sa najmanjom vrednošću.

    /* Program koji izbacuje element koji se nalazi iza elementa sa najmanjom vrednoscu. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include typedef struct elem { int broj; struct elem *sled; } Elem; Elem *citaj2(int n) { Elem *prvi = NULL, *posl = NULL; int i; for (i = 0; i < n;i++) { Elem *novi = (Elem*)malloc(sizeof(Elem)); scanf("%d", &novi->broj); novi->sled = NULL; if (!prvi) prvi = novi; else posl->sled = novi; posl = novi; } return prvi; } void pisi(Elem *lst) { while (lst) { printf("%d ", lst->broj); lst = lst->sled; } } void izbaciNakonNajmin(Elem *lst) { Elem *minEl = lst, *pom = lst; while (pom) { if (pom->broj < minEl->broj) minEl = pom; pom = pom->sled; } if (minEl == NULL || minEl->sled == NULL) return; pom = minEl->sled; minEl->sled = minEl->sled->sled; free(pom); } void main() {

  • 23

    Elem *lst = NULL; int n; printf("\nBroj elemenata liste? "); scanf("%d", &n); lst = citaj2(n); printf("\nLista pre izbacivanja:\n"); pisi(lst); izbaciNakonNajmin(lst); printf("\nLista nakon izbacivanja:\n"); pisi(lst); system("PAUSE"); }

    15. Napisati rekurzivnu funkciju koja će u jednostruko spregnutoj linearnoj listi prebrojati pozitivne elemente.

    #pragma warning(disable: 4996) #include #include typedef struct elem { int broj; struct elem *sled; } Elem; Elem *citaj2(int n) { Elem *prvi = NULL, *posl = NULL; Elem *novi; int i; for (i = 0; i < n; i++) { novi = (Elem*)malloc(sizeof(Elem)); scanf("%d", &novi->broj); novi->sled = NULL; if (!prvi) prvi = novi; else posl->sled = novi; posl = novi; } return prvi; } void pisi(Elem *lst) { while (lst) { printf("%d -> ", lst->broj); lst = lst->sled; } } int izbrojPozitivne(Elem *lst) { Elem *pom; pom = lst; if (pom == NULL) return 0; else { if (pom->broj > 0)

  • 24

    return 1 + izbrojPozitivne(pom->sled); else return izbrojPozitivne(pom->sled); } } void main() { Elem *lst = NULL; int n; printf("\nBroj elemenata liste? "); scanf("%d", &n); lst = citaj2(n); printf("\Uneta lista je:\n"); pisi(lst); printf("\nBroj pozitivnih elemenata u listi je: %d\n", izbrojPozitivne(lst)); system("PAUSE");

    }

    16. Napisati funkciju koja će vratiti invertovanu jednostruko spregnutu linearnu listu.

    /* Napisati funkciju koja na osnovu zadate liste pravi drugu, sa elementima u obrnutom redosledu u odnosu na prvu. Lista se zadaje u datoteci na standardni nacin. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include typedef struct elem { int broj; struct elem* sled; } Elem; Elem* ucitaj_listu_iz_datoteteke(FILE* ulaz) { int broj; Elem* prvi = NULL, * kraj, * tmp; fscanf(ulaz, "%d", &broj); prvi = (Elem*)malloc(sizeof(Elem)); prvi->broj = broj; prvi->sled = NULL; kraj = prvi; while (!feof(ulaz)) { fscanf(ulaz, "%d", &broj); tmp = (Elem*)malloc(sizeof(Elem)); tmp->broj = broj; tmp->sled = NULL; kraj->sled = tmp; kraj = tmp;

  • 25

    } return prvi; } void pisi(Elem* lst) { if (lst) { printf("%d ", lst->broj); pisi(lst->sled); } } /* RESENJE ZADATKA */ Elem* invertuj(Elem* lst) { Elem* lst2 = NULL; Elem* pom; while (lst != NULL) { pom = (Elem*)malloc(sizeof(Elem)); pom->broj = lst->broj; pom->sled = lst2; lst2 = pom; lst = lst->sled; } return lst2; }

    17. Metoda koja koja pravi indentičnu kopiju date JSListe

    /* Napisati metodu koja pravi istovetnu kopiju date liste. Lista je zadata standardno u datoteci. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include typedef struct elem { int broj; struct elem* sled; } Elem; Elem* ucitaj_listu_iz_datoteteke(FILE* ulaz) { int broj; Elem* prvi = NULL, * kraj, * tmp; fscanf(ulaz, "%d", &broj); prvi = (Elem*)malloc(sizeof(Elem)); prvi->broj = broj; prvi->sled = NULL; kraj = prvi; while (!feof(ulaz)) { fscanf(ulaz, "%d", &broj); tmp = (Elem*)malloc(sizeof(Elem));

  • 26

    tmp->broj = broj; tmp->sled = NULL; kraj->sled = tmp; kraj = tmp; } return prvi; } void pisi(Elem* lst) { if (lst) { printf("%d ", lst->broj); pisi(lst->sled); } } /* RESENJE ZADATKA */ Elem* kopirajListu(Elem* lst) { Elem* lst2 = NULL; Elem *newEl, *pom; while (lst != NULL) { newEl = (Elem*)malloc(sizeof(Elem)); newEl->broj = lst->broj; newEl->sled = NULL; if (lst2 == NULL) lst2 = newEl; else { pom = lst2; while (pom->sled != NULL) pom = pom->sled; pom->sled = newEl; } lst = lst->sled; } return lst2; } int main() { FILE* ulaz; Elem* lst = NULL, * lst2; ulaz = fopen("zad16.txt", "r"); lst = ucitaj_listu_iz_datoteteke(ulaz); fclose(ulaz); printf("\nUcitana lista:\n"); pisi(lst); printf("\n"); lst2 = kopirajListu(lst); printf("\nKopirana lista:\n"); pisi(lst2); printf("\n"); return 0; }

  • 27

    18. Metoda koja od JSListe pravi niz

    public int[] transform(JSLista l) { int br = 0;

    CvorJSListe pomocni = l.prvi;

    while (pomocni != null) { br++;

    pomocni = pomocni.sledeci;

    }

    pomocni = l.prvi;

    int[] stack = new int[br];

    for (int i = 0; i < stack.length; i++) { stack[i] = pomocni.podatak;

    pomocni = pomocni.sledeci;

    }

    return stack;

    }

    19. Napisati program koji od date dve jednostruko spregnute liste pravi trecu koja predstavlja uniju elemenata date dve liste.

    #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include typedef struct elem { int broj; struct elem *sled; } Elem; Elem *citaj2(int n) { Elem *prvi = NULL, *posl = NULL; int i; for (i = 0; i < n;i++) { Elem *novi = (Elem*)malloc(sizeof(Elem)); scanf("%d", &novi->broj); novi->sled = NULL; if (!prvi) prvi = novi; else posl->sled = novi; posl = novi; } return prvi; } void pisi(Elem *lst) { while (lst) { printf("%d ", lst->broj); lst = lst->sled;

  • 28

    } } int postoji(Elem *lst, int b) { while (lst) { if (lst->broj == b) return 1; lst = lst->sled; } return 0; } Elem* unija(Elem *lst1, Elem *lst2) { Elem *novaLista = NULL, *pom; if (lst1 == NULL && lst2 == NULL) return NULL; while (lst1 != NULL) { if (!postoji(novaLista, lst1->broj)) { pom = (Elem*)malloc(sizeof(Elem)); pom->broj = lst1->broj; pom->sled = novaLista; novaLista = pom; } lst1 = lst1->sled; } while (lst2 != NULL) { if (!postoji(novaLista, lst2->broj)) { pom = (Elem*)malloc(sizeof(Elem)); pom->broj = lst2->broj; pom->sled = novaLista; novaLista = pom; } lst2 = lst2->sled; } return novaLista; } void main() { Elem *lst1 = NULL, *lst2 = NULL, *lst3 = NULL; int n1, n2; printf("\nBroj elemenata prve liste? "); scanf("%d", &n1); lst1 = citaj2(n1); printf("\nBroj elemenata druge liste? "); scanf("%d", &n2); lst2 = citaj2(n2); lst3 = unija(lst1, lst2); printf("\nPrva lista:\n"); pisi(lst1); printf("\nDruga lista:\n"); pisi(lst2);

  • 29

    printf("\nUnija:\n"); pisi(lst3); system("PAUSE");

    }

    20. Napisati program koji dodaje čvor u listi nakon čvora sa zadatom vrednošću. U prvom redu datoteke zad1.in je zadat broj n koji označava broj elemenata liste. U narednih n redova je dato n celih brojeva koji će predstavljati elemente liste. U narednom redu je zadat broj m iza čijeg prvog pojavljivanja je potrebno dodati broj k koji se nalazi u poslednjem redu datoteke. Ukoliko se broj m ne nalazi u listi, broj k dodati na početak liste. Rezultujuću listu zapisati u datoteku zad1.out.

    21. Dati su brojevi d, m, n i jednostruko povezana lista celih brojeva. Naći broj podlisti date liste, sastavljene od susednih elemenata početne liste koje su dužine m, a zbir elemenata podliste je jednak d. U prva dva reda ulazne datoteke zad1.in se nalaze brojevi d i m, a u narednom redu n, dok se u narednih n redova nalazi n celih brojeva koji predstavljaju elemente liste. Rezultat zapisati u datoteku zad1.out. Primer:

    3

    2

    5

    1 2 1 3 2

    2

    Objašnjenje: Postoje 2 podliste date liste koje imaju po 2 elementa, a zbir tih elemenata je 3.

    2.2.4. KRUŽNO SPREGNUTA LINEARNA LISTA

    Kod ovog tipa liste pokazivač poslednjeg elementa nema NULL vrednost već ukazuje na prvi

    element liste. Prednosti ovog tipa liste su:

    - Svakom elementu se može pristupiti polazeći od bilo kog elementa liste.

    - Jednostavnije pronalaženje elemenata liste.

    - Efikasnije operacije dodavanja i brisanja elemenata iz liste.

    Kod ovog tipa liste neophodno je znati prvi ili poslednji element. To možemo rešiti na dva načina:

    1) Pokazivač na glavu liste

    2) Označavanje početnog elementa liste. Npr. ostaviti prazno polje za podatak, ili u njega upisati

    specijalni simbol... itd.

  • 30

    2.2.5. DVOSTRUKO POVEZANA LINEARNA LISTA

    Kod ovog tipa listi, svaki element ima dva pokazivača koji ukazuju na prethodni i naredni element

    (levi i desni ukazivač).

    Levi ukazivač krajnjeg levog i desni pokazivač krajnjeg desnog elementa su NULL.

  • 31

    22. NCP koji iz neprazne datoteke broj.txt ucitava paran broj celih brojeva x[1], x[2],...,x[n], gde n nije unapred poznato. Ispisati poruku na standardni izlaz da li vazi da x[1]==x[n], x[2]==x[n-1],..., x[k]=x[k+1], k=1..n/2

    #include

    #include

    typedef struct listacv dvlista;

    /*dvostruko povezana linearna lista*/

    struct listacv{

    int broj; /*informaciono polje je clan niza x*/

    dvlista *sledeci, *prethodni;

    };

    dvlista *ubaci(dvlista *kraj, int broj){

    dvlista *novi; /*novi cvor za umetanje u listu*/

    novi=(dvlista *)malloc(sizeof(dvlista)); /*alokacija memorije za novi

    cvor liste*/

    novi->broj=broj; /*inicijalizacija polja broj u cvoru novi */

    novi->sledeci=NULL;

    novi->prethodni=kraj; /*novi element se dodaje na kraj postojece liste*/

    kraj->sledeci=novi; /* do tada poslednji cvor kraj je ispred clana

    novi*/

    kraj=novi; /*poslednji dodat element je novi kraj liste*/

    return kraj;

    }

    main()

    {

    dvlista *prvi, *kraj; /*prvi i poslednji cvor dvostruke liste*/

    int n; /*broj ucitanih celih brojeva*/

    int broj; /*tekuci broj sa ulaza*/

    int jednak; /*indikator jednakosti dva clana - cuva vrednost 0 ili 1 */

    FILE *ulaz;

    int i; /*brojacka promenljiva*/

    /*otvaranje datoteke za citanje i upis brojeva iz datoteke u

    dvostruku povezanu listu */

    ulaz=fopen("broj.txt", "r");

    fscanf(ulaz, "%d", &broj);

    /*kreiranje prvog cvora liste za prvi ucitan broj */

    prvi=(dvlista*)malloc(sizeof(dvlista));

    prvi->broj=broj;

    prvi->sledeci=NULL;

    prvi->prethodni=NULL;

    kraj=prvi; n=1; //za sada ucita je samo jedan clan

  • 32

    /*formiranje liste od brojeva koji se ucitavaju sve do kraja datoteke -

    feof(ulaz) */

    while (!feof(ulaz))

    { fscanf(ulaz, "%d", &broj);

    kraj=ubaci (kraj, broj);

    n++;

    }

    fclose(ulaz);

    /*testiranje jednakih parova uz pomeranje tekuceg prvog clana i tekuceg

    poslednjeg

    clana ka sredini liste*/

    jednak=1;

    for(i=1; ibroj==kraj->broj);

    prvi=prvi->sledeci; /*pomeranje ka sredini liste */

    kraj=kraj->prethodni; /*pomeranje ka sredini liste */

    }

    printf("Za unete broje jednakost ");

    if(!jednak) printf("ne ");

    printf("vazi\n");

    return 0;

    }

    II nacin:

    #include

    #include

    typedef struct listacv {

    int broj;

    struct listacv *sledeci;

    struct listacv *prethodni;

    } dvlista;

    dvlista *ubaci(dvlista *kraj, int broj){

    dvlista *novi;

    novi = (dvlista *)malloc(sizeof(dvlista));

    novi->broj = broj;

    novi->sledeci = NULL;

    novi->prethodni =kraj;

    if(kraj)

    kraj->sledeci = novi;

    kraj = novi;

    return kraj;

    }

    int main(){

    dvlista *prvi, *kraj;

    int n;

    int broj;

    int jednak;

    FILE *ulaz;

    int i;

    ulaz = fopen("zad045.in", "r");

  • 33

    fscanf(ulaz,"%d", &n);

    kraj = NULL;

    for(i = 0; ibroj);

    pom = pom->prethodni;

    }

    /*********** kraj stampe liste *************/

    /********** trazimo prvi element ***********/

    prvi = kraj;

    while(prvi->prethodni)

    prvi = prvi->prethodni;

    /********** nasli smo prvi element ********/

    jednak = 1;

    for(i=1; ibroj == kraj->broj);

    prvi = prvi->sledeci;

    kraj = kraj->prethodni;

    }

    printf("\nZA UNETE BROJEVE JEDNAKOST ");

    if(!jednak)

    printf("NE ");

    printf("VAZI\n");

    return 0;

    }

    2.2.6. PRIMENE SPREGNUTIH LINEARNIH LISTI

    Prikaz polinoma

    Pretpostavimo da imamo polinom od tri promenljive: 3X2 + 4XY + Y2 + XYZ

    Svaki element liste koji prikazuje jedan član polinoma dat je na sledećoj slici:

    Spregnuta lista za prikaz ovog polinoma izgledala bi:

    Odgovarajuća struktura elementa bi bila:

  • 34

    typedef struct elem element;

    struct elem{

    int expx;

    int expy;

    int expz;

    int koef;

    element *naredni;

    }

    23. NCP-e za sabiranje, oduzimanje i množenje polinoma jedne promenljive. /* NCP za sabiranje, oduzimanje i mnozenje polinoma jedne promenljive. */

    #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include struct pnode { double coef; long power; struct pnode *link; }; typedef struct pnode poly; #define COEF(a) ((a)->coef) #define POWER(a) ((a)->power) #define LINK(a) ((a)->link) poly *addElem(poly *p, double coef, long pow) { poly *c, *newel, *pret = NULL; c = p; while (c && POWER(c) > pow) { pret = c; c = LINK(c); } if (!c || POWER(c) < pow) { newel = (poly*)malloc(sizeof(poly)); COEF(newel) = coef; POWER(newel) = pow; LINK(newel) = c; if (!pret) p = newel; else LINK(pret) = newel; return p; } if (POWER(c) == pow) { COEF(c) += coef;

  • 35

    return p; } return p; } poly *create() { int pow; double c; poly *p = NULL; printf("\nUnesite polinom pocev od najveceg stepena:\n"); while (1) { printf("\nKoeficijent: "); scanf("%lf", &c); printf("\nStepen: "); scanf("%d", &pow); if (c == 0) break; p = addElem(p, c, pow); if (pow == 0) break; } return p; } void display(poly *p) { poly *cur = p; if (cur) { printf(" %c %.2f * X^%d", COEF(cur) < 0 ? '-' : ' ', fabs(COEF(cur)), POWER(cur)); cur = LINK(cur); } while(cur != NULL){ printf(" %c %.2f * X^%d", COEF(cur) < 0 ? '-' : '+', fabs(COEF(cur)), POWER(cur)); cur = LINK(cur); } } void brisi(poly *p) { poly *stari; while (p) { stari = p; p = LINK(p); free(stari); } } poly *polyadd(poly *p1, poly* p2) { poly *p, *res = NULL; p = p1; while (p) { res = addElem(res, COEF(p), POWER(p)); p = LINK(p); } p = p2;

  • 36

    while (p) { res = addElem(res, COEF(p), POWER(p)); p = LINK(p); } return res; } poly *polysub(poly *p1, poly* p2) { poly *p, *res = NULL; p = p1; while (p) { res = addElem(res, COEF(p), POWER(p)); p = LINK(p); } p = p2; while (p) { res = addElem(res, -COEF(p), POWER(p)); p = LINK(p); } return res; } poly *polymul(poly *p1, poly *p2) { poly *pom1, *pom2, *res = NULL; pom1 = p1; while (pom1) { pom2 = p2; while (pom2) { res = addElem(res, COEF(pom1)*COEF(pom2), POWER(pom1) + POWER(pom2)); pom2 = LINK(pom2); } pom1 = LINK(pom1); } return res; } poly *polydif(poly* p1) { poly *pom1, *res = NULL; pom1 = p1; while (pom1) { if (POWER(pom1) != 0) res = addElem(res, COEF(pom1)*POWER(pom1), POWER(pom1) - 1); pom1 = LINK(pom1); } return res; } void main() { int ch; poly *poly1, *poly2, *poly3; poly1 = poly2 = poly3 = NULL; printf("\nUnesite prvi polinom:\n");

  • 37

    poly1 = create(); display(poly1); printf("\nUnesite drugi polinom:\n"); poly2 = create(); display(poly2); while (1) { printf("\n************************\n" "\nOdaberi operaciju:\n" "1.Sabiranje\n" "2.Oduzimanje\n" "3.Mnozenje\n" "4.Izvod\n" "5.Izlaz\n"); scanf("%d", &ch); switch (ch) { case 1: poly3 = polyadd(poly1, poly2); display(poly3); break; case 2: poly3 = polysub(poly1, poly2); display(poly3); break; case 3: poly3 = polymul(poly1, poly2); display(poly3); break; case 4: poly3 = polydif(poly1); display(poly3); break; default: exit(1); } } brisi(poly1); brisi(poly2); brisi(poly3); system("PAUSE"); }

    24. Napisati C program koji prebacuje čvor sa najvećom vrednošću na početak dvostruko spregnute linearne liste. Elementi liste se nalaze u datoteci broj.txt.

    #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include typedef struct listacv DSLlista;

  • 38

    struct listacv { int broj; DSLlista *sledeci; DSLlista *prethodni; }; DSLlista *ubaci(DSLlista *kraj, int broj) { DSLlista *novi; novi = (DSLlista *)malloc(sizeof(DSLlista)); novi->broj = broj; novi->sledeci = NULL; novi->prethodni = kraj; kraj->sledeci = novi; kraj = novi; return kraj; } void print(DSLlista *pocetak) { DSLlista *pom = pocetak; while (pom) { printf("%d -> ", pom->broj); pom = pom->sledeci; } printf("NULL\n"); } //Funkcija vraca pokazivac na prvi element DSLliste DSLlista *prebaciMaxElement(DSLlista *kraj) { DSLlista *pom = kraj, *max = kraj; while (pom->prethodni != NULL) { pom = pom->prethodni; if (pom->broj > max->broj) { max = pom; } } if (max->prethodni == NULL) return max; max->prethodni->sledeci = max->sledeci; if (max->sledeci != NULL) max->sledeci->prethodni = max->prethodni; max->prethodni = NULL; max->sledeci = pom; pom->prethodni = max; return max; } void main() { DSLlista *prvi, *kraj; int n, broj; FILE *ulaz; ulaz = fopen("broj.txt", "r");

  • 39

    fscanf(ulaz, "%d", &broj); prvi = (DSLlista*)malloc(sizeof(DSLlista)); prvi->broj = broj; prvi->sledeci = NULL; prvi->prethodni = NULL; kraj = prvi; n = 0; while (!feof(ulaz)) { fscanf(ulaz, "%d", &broj); kraj = ubaci(kraj, broj); n++; } fclose(ulaz); print(prvi); prvi = prebaciMaxElement(kraj); print(prvi); system("PAUSE"); }

    25. Dat je pokazivač p na neki čvor dvostruko spregnute linearne liste. Napisati metodu koja prikazuje onu polovinu liste koja ima veći zbir, u odnosu na element na koga ukazuje p.

    #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include typedef struct listacv DSLlista; struct listacv { int broj; DSLlista *sledeci; DSLlista *prethodni; }; DSLlista *ubaci(DSLlista *kraj, int broj) { DSLlista *novi; novi = (DSLlista *)malloc(sizeof(DSLlista)); novi->broj = broj; novi->sledeci = NULL; novi->prethodni = kraj; kraj->sledeci = novi; kraj = novi; return kraj; } int veciZbir(DSLlista *p) { DSLlista *pom; int sumaLevo, sumaDesno;

  • 40

    sumaLevo = 0; sumaDesno = 0; pom = p->prethodni; while (pom != NULL) { sumaLevo += pom->broj; pom = pom->prethodni; } pom = p->sledeci; while (pom != NULL) { sumaDesno += pom->broj; pom = pom->sledeci; } if (sumaLevo > sumaDesno) return 1; else if (sumaLevo < sumaDesno) return -1; else return 0; } void prikaziPodlistu(DSLlista *p, int veci) { DSLlista *pom=NULL; if (veci == 0) { printf("Zbir elemenata u listama s leva i s desna je jednak!"); return; } if (veci == 1) pom = p->prethodni; else if(veci == -1) pom = p->sledeci; while (pom != NULL) { printf("%d -> ", pom->broj); if (veci == 1) pom = pom->prethodni; else if (veci == -1) pom = pom->sledeci; } printf("NULL\n"); } void print(DSLlista *pocetak) { DSLlista *pom = pocetak; while (pom) { printf("%d -> ", pom->broj); pom = pom->sledeci; } printf("NULL\n"); }

  • 41

    void main() { DSLlista *prvi, *kraj, *sredina=NULL; int n, broj; FILE *ulaz; ulaz = fopen("broj.txt", "r"); fscanf(ulaz, "%d", &broj); prvi = (DSLlista*)malloc(sizeof(DSLlista)); prvi->broj = broj; prvi->sledeci = NULL; prvi->prethodni = NULL; kraj = prvi; n = 0; while (!feof(ulaz)) { fscanf(ulaz, "%d", &broj); kraj = ubaci(kraj, broj); if (n == 4) sredina = kraj; n++; } fclose(ulaz); print(prvi); printf("\nVrednost u sredini je: %d\n", sredina->broj); prikaziPodlistu(sredina,veciZbir(sredina)); system("PAUSE"); }

    26. Dat je pokazivač na prvi element dvostruko spregnute liste čiji elementi predstavljaju elemente reči (slovo ili prazno mesto). Napisati metodu koja proverava da li je data rečenica (reč) palindrom. Palindrom je reč (rečenica) koja se čita isto s obe strane (i sleva na desno i s desna na levo).

    #pragma warning(disable: 4996) #include #include #include typedef struct listacv dvlista; struct listacv { char ch; dvlista *prethodni; dvlista *sledeci; }; dvlista *ubaci(dvlista *kraj, char c) { dvlista *novi; novi = (dvlista *)malloc(sizeof(dvlista)); novi->ch = c; novi->sledeci = NULL;

  • 42

    novi->prethodni = kraj; kraj->sledeci = novi; kraj = novi; return kraj; } int daLiJePalindromDS(dvlista *poc, dvlista *kraj) { dvlista *pom1 = poc, *pom2 = kraj; if (poc == NULL) return 1; //ignorisemo razmake na pocetku i kraju while (pom1 != NULL && pom1->ch == ' ') pom1 = pom1->sledeci; while (pom2 != NULL && pom2->ch == ' ') pom2 = pom2->prethodni; while (pom2 != NULL || pom1 != NULL) { if (pom1->ch == ' ') pom1 = pom1->sledeci; if (pom2->ch == ' ') pom2 = pom2->prethodni; if (pom1->ch == pom2->ch) { pom1 = pom1->sledeci; pom2 = pom2->prethodni; } else { return 0; } } return 1; } void main() { char recenica[] = "ANA VOLI MILOVANABBB"; dvlista *pocrec = NULL, *krajrec = NULL, *novi, *pom; int i, pal; novi = (dvlista *)malloc(sizeof(dvlista)); novi->ch = recenica[0]; novi->prethodni = NULL; novi->sledeci = NULL; pocrec = novi; krajrec = novi; for (i = 1; i < (int)strlen(recenica); i++) krajrec = ubaci(krajrec, recenica[i]); pom = pocrec; while (pom) { printf("%c -> ", pom->ch); pom = pom->sledeci; } pal = daLiJePalindromDS(pocrec, krajrec); if (pal)

  • 43

    printf("\nRECENICA JE PALINDROM\n"); else printf("\nRECENICA NIJE PALINDROM\n"); system("PAUSE"); }

    27. Data je dvostruko spregnuta (DS) lista čiji su elementi čvorova pokazivači na početak jednostruko spregnute (JS) liste. Napisati klasu koja opisuje čvor ovakve DS liste, a zatim napisati algoritam za ubacivanje novog elementa u ovako definisanu strukturu, koji funkcioniše po sledećem principu: kreće se od početka DS liste. Ako je element koji se ubacuje manji od prvog elementa JS liste trenutnog čvora DS liste, onda se taj element ubacuje na kraj te JS liste. U suprotnom, prelazi se na sledeći čvor DS liste i algoritam se ponavlja. Ako se stigne do kraja DS liste, onda se kreira novi čvor i u njegovu JS listu se ubacuje novi element. Početna metoda prihvata pokazivač na početak DS liste i ceo broj koji se ubacuje.

    public class CvorListe { private CvorListe sledeci; private CvorListe prethodni; private CvorJSListe prvi;

    public void ubaci(CvorListe p, int pod) {

    if (p == null) {

    p = new CvorListe();

    p.prvi = new CvorJSListe(pod, null); } else {

    while (p.sledeci != null && p.prvi.podatak

  • 44

    return Integer.MAX_VALUE;

    while (cvor.prethodni != null) { cvor = cvor.prethodni;

    }

    CvorDSListe min = minElement(cvor);

    if (min.prethodni != null) min.prethodni.sledeci = min.sledeci;

    if (min.sledeci != null)

    min.sledeci.prethodni = min.prethodni;

    return min.podatak;

    }

    29. Dat je pokazivač na prvi element DS liste. Napisati metodu koja vraća pokazivač na element sa najmanjom vrednošću u listi.

    private CvorDSListe minElement(CvorDSListe cvor) { CvorDSListe min = cvor;

    while (cvor != null) {

    if (cvor.podatak < min.podatak) min = cvor;

    cvor = cvor.sledeci;

    }

    return min;

    }

    30. Dat je pokazivac na pocetni cvor DS liste sortirane u rastucem redosledu koja sadrži pozitivne cele brojeve. Napisati funkciju koja ce izmedju svih onih elementa liste koji se po vrednosti razlikuju za više od 1 ubaciti u datu listu nove elemente tako da lista posle poziva operacije ima u sebi sukcesivne cele brojeve. Na primer ako lista sadrži 3, 5, 8 nakon poziva ove opercije sadržace 3, 4, 5, 6, 7, 8

    public void popuni(CvorDSListe prvi) { if (prvi == null || prvi.sledeci == null)

    return;

    if ((prvi.sledeci.podatak - prvi.podatak) > 1) {

    CvorDSListe novi = new CvorDSListe(prvi.podatak + 1, prvi, prvi.sledeci); prvi.sledeci.prethodni = novi;

    prvi.sledeci = novi;

    }

    popuni(prvi.sledeci);

    }

    31. Dat je pokazivac na neki cvor DS liste celih brojeva koja sigurno sadrži najmanje 4 elementa. Napisati funkciju ubaciNti(int A, int N) koja ce ubaciti novi element sa sadržajem A i to tako da on bude na N-toj poziciji od pocetka.

    public void ubaciN(CvorDSListe cvor, int a, int n) { if (cvor == null)

  • 45

    return;

    while (cvor.prethodni != null) cvor = cvor.prethodni;

    CvorDSListe pom = new CvorDSListe(a, null, null); if (n < 0) {

    return;

    }

    if (n == 0) { pom.prethodni = null; pom.sledeci = cvor;

    if (pom.sledeci != null) pom.sledeci.prethodni = pom;

    }

    int i = 0; while (i++ < n - 1) {

    if (cvor.sledeci == null) return;

    cvor = cvor.sledeci;

    }

    pom.prethodni = cvor;

    pom.sledeci = cvor.sledeci; if (cvor.sledeci != null)

    cvor.sledeci.prethodni = pom; cvor.sledeci =

    pom;

    }

    32. Metoda koja invertuje dvostruko-spregnutu listu.

    public CvorDSListe invertujLIstu(CvorDSListe cvor) { CvorDSListe c = null;

    while (cvor != null) {

    c = new CvorDSListe(cvor.podatak, null, c);

    if (c.sledeci != null)

    c.sledeci.prethodni = c;

    cvor = cvor.sledeci;

    }

    return c; }

    33. Metoda koja vraća DSListu koja predstavlja razliku (skupova) dve DSListe

    public CvorDSListe razlika(CvorDSListe c1, CvorDSListe c2) {

    if (c1 == null || c2 == null) return c1;

    CvorDSListe novi = null; CvorDSListe pom = c1; while (pom != null) {

    if (!pronadji(pom.podatak, c2)) {

  • 46

    novi = new CvorDSListe(pom.podatak, null, novi);

    if (novi.sledeci != null) { novi.sledeci.prethodni = novi;

    }

    }

    pom = pom.sledeci;

    }

    return novi;

    }

    34. Dati su pokazivači na početak dve dvostruko spregnute liste. Napisati program koji pravi treću listu koja predstavlja (skupovnu) razliku prve i druge liste. U prvom redu datoteke zad2.in je zadat broj n1 koji predstavlja dužinu prve liste. U narednih n1 redova je zadato n1 celih brojeva koji predstavljaju članove prve liste. Nakon toga je zadat broj n2 – broj članova druge liste, a nakon toga u n2 redova n2 celih brojeva koji predstavljaju članove druge liste. Rezultat zapisati u datoteku zad2.out i to tako što će u prvom redu biti zapisan broj n koji prestavalja broj elemenata rezultujuće liste, dok će se u narednih n redova nalaziti elementi rezultujuće liste.

    public void prebaciPoslednjiNaPocetak() { if (prvi == null) {

    return;

    }

    if (prvi.sledeci == null) {

    return;

    }

    CvorDSListe pom = poslednji;

    poslednji = pom.prethodni; pom.sledeci =

    prvi; prvi.prethodni = pom;

    pom.prethodni.sledeci = null; pom.prethodni = null;

    prvi = pom;

    }

    35. Dat je pokazivač na prvi element DS liste. Napisati metodu koja računa zbir elemenata koji se ponavljaju. Primer: Ulaz 5 7 2 2 5 2 8 2 5 6. Rezultat je 5+2=7. U prvom redu datoteke zad2.in je zadat broj n koji označava broj elemenata liste. Članovi liste su zadati u narednih n redova ulazne datoteke. Traženi zbir zapisati u datoteku zad2.out.

    public int ZbirDuplih(CvorDSListe p1) { if (p1 == null)

    return 0; CvorDSListe tek = p1;

    CvorDSListe tek1 = p1.sledeci;

    CvorDSListe tek2 = tek.prethodni; int ima = 0;

    int suma = 0;

    for (; tek != null; tek = tek.sledeci) {

  • 47

    for (; tek2 != null; tek2 = tek2.prethodni) {

    if (tek.podatak == tek2.podatak) {

    ima = 1;

    break;

    }

    }

    tek2 = tek;

    if (ima == 0) {

    for (; tek1.sledeci != null; tek1 = tek1.sledeci) {

    if (tek.podatak == tek1.podatak) { suma = suma + tek.podatak;

    break;

    }

    }

    }

    if (tek1.sledeci != null) {

    tek1 = tek1.sledeci;

    }

    }

    return suma; }

    36. Metoda koja vraća pokazivač na prvi element ciklične DSListe sortirane u rastućem redosledu. Dat je pokazivač na neki element u listi.

    public CvorDSListe vratiPokNaPrviEl(CvorDSListe p) {

    if (p == null || (p.sledeci == p && p.prethodni == p))

    return p; CvorDSListe pom = p;

    while (pom.sledeci.podatak > pom.podatak

    && pom.prethodni.podatak < pom.podatak)

    pom = pom.sledeci;

    return pom.sledeci;

    }

  • 48

    RETKO POSEDNUTE MATRICE

    Realizuje se preko spregnutih listi i ima za cilj smanjenje broja izračunavanja, kao i smanjenje potrebne

    memorije za čuvanje sturkture.

    Jedna moguća reprezentacija dvodimenzionalne retko posednute matrice bi bila preko jedne spregnute

    liste za svaki red i svaku kolonu matrice. Svaka od ovih listi ima zaglavlje, tj. glavu. Svakom nenultom mestu

    u matrici odgovara jedan čvor oblika:

    struct cvor {

    int red;

    int kolona;

    int vrednost;

    struct cvor *nar_u_kol;

    struct cvor *nar_u_vrsti;

    }

    Trebalo bi dati adekvatni zadatak!

    2.3. BSTEK

    2.3.1. 6BDEFINICIJE I STUKTURA

    Stek (stack) ili magacin je jedna od najznačajnijih linearnih i dinamičkih struktura podataka. Stavljanje

    (upis) ili brisanje (čitanje) elemenata se vrši samo na jednom kraju. Operacija stavljanja se naziva PUSH, a

    brisanja POP. Stek se prazni i puni po tzv. LIFO strategiji.

    #define MAXSTACKLEN 100 /* maksimalna dubina steka */

    int stack[MAXSTACKLEN];/*vrednost steka */

    int stackPointer;/*naredna slobodna pozicija na steku */

    /* push: gurni na stek */

  • 49

    void push( int arg ){

    if( stackPointer < MAXSTACKLEN )

    stack[stackPointer++] = arg;

    else

    printf("greska: stek je pun, nemoguce je smestiti %g\n", arg);

    }

    /* pop: skini sa steka*/

    int pop( void ){

    if( stackPointer > 0 )

    return stack[--stackPointer];

    else{

    printf("greska: stek je prazan\n" );

    return 0;

    }

    }

    int top(void){

    if(stackPointer > 0)

    return stack[stackPointer-1];

    else{

    printf("greska: stek je prazan\n");

    return 0;

    }

    }

    10BOpis zadatka:

    Za aritmetičke izraze kao što su T2+3T, T2+3*4T, T(2+3)*4T, itd. sa kojima se tipično susrećemo kako u

    matematici tako i u programiranju, kažemo da su zapisani u Tinfiksnoj formiT, s obzirom da se operator nalazi

    TizmeđuT operanada. Najveća mana ovakvog zapisa leži u činjenici da je neophodno uspostaviti konvencije o

    TprioritetuT pojedinih operatora (npr. konvenciju da množenje ima veći prioritet u odnosu na sabiranje), i

    eventualno koristiti zagrade za promenu prioriteta.

    U računarstvu je od velikog značaja jedan posve drugačiji zapis aritmetičkih izraza, poznat pod imenom

    TpostfiksnaT ili Tobrnuta poljska notacijaT, u kojem se operatori navode TnakonT operanada (naziv obrnuta

    poljska notacija dat je u čast poljskog matematičara Jana Lukasiewitza, koji je predložio upravo obrnuti

    princip - da se operatori zapisuju TispredT operanada). Na primer, prethodna tri izraza zapisana u infiksnoj

    notaciji, u obrnutoj poljskoj notaciji zapisuju se ovako:

    2 3 +

    2 3 4 * + 4 * 3 + 2

    2 3 + 4 * (2 + 3) * 4

    Izračunavanje izraza u obrnutoj poljskoj notaciji izvodi se tako da se svaki operand na koji se

    naiđe dodaje na kraj liste (koja je na početku prazna), dok se prilikom nailaska na binarni operator

    poslednja dva elementa iz liste brišu i zamenjuju rezultatom operacije (sličan princip može se

    primeniti i na n-arne operatore). Broj koji na kraju izračunavanja ostane u listi predstavlja rezultat

    izračunavanja (taj broj mora biti jedinstven ako je izraz bio ispravan). Uzmimo na primer, sledeći izraz

    zapisan u obrnutoj poljskoj notaciji:

    3 5 6 4 - * 6 + * 2 /

  • 50

    Izračunavanje ovog izraza teklo bi ovako:

    3

    3 5

    3 5 6

    3 5 6 4

    3 5 2 T6 i 4 su zamijenjeni sa 6-4=2

    3 10 T5 i 2 su zamijenjeni sa 5*2=10

    3 10 6

    3 16 T10 i 6 su zamijenjeni sa 10+6=16

    48 T3 i 16 su zamijenjeni sa 3*16=48

    48 2

    24 T48 i 2 su zamijenjeni sa 48/2=24

    Dakle, rezultat izračunavanja je 24. Jedna od glavnih prednosti obrnute poljske notacije leži u činjenici

    da nije potrebno voditi računa o prioritetu operacija, kao i da je Tsvaki T izraz moguće zapisati Tbez upotrebe

    zagradaT. Na primer, izraz koji bi se u infiksnom obliku zapisao kao

    ((3 + 5) / (7 - 2) + 4 / (8 - 5)) / (3 + 5 * (4 / (7 - 2)))

    u obrnutoj poljskoj notaciji zapisuje se kao

    3 5 + 7 2 - / 4 8 5 - / + 3 5 4 7 2 - / * + /

    Stoga, kompajleri većine programskih jezika interno prevode sve aritmetičke izraze u obrnutu poljsku

    notaciju pre bilo kakve dalje obrade. Vaš zadatak je da napravite program koji aritmetičke izraze u infiksnom

    obliku koji se sastoje od jednoslovnih promjenljivih (a-z), četiri računske operacije ( T+ T, T-T, T*T i T/T), i eventualno

    zagrada, pretvori u obrnutu poljsku notaciju.

    11BUlazna datoteka:

    U prvom i jedinom redu ulazne tekstualne datoteke TRPN.INT nalazi se niz znakova koji predstavlja

    aritmetički izraz u infiksnoj notaciji koji treba pretvoriti u postfiksnu odnosno obrnutu poljsku notaciju. Ispravan

    aritmetički izraz sme sadržavati samo jednoslovne promenljive pisane malim slovima (od "a" do "z"), binarne

    operatore "T+T", "T-T", "T*T" i "T/T" kao i male zagrade "(" i ")" za promenu prioriteta operacija. Ispravan aritmetički

    izraz neće sadržati nikakve razmake.

    12BIzlazna datoteka:

    Ukoliko ulazna datoteka sadrži ispravan aritmetički izraz u infiksnoj notaciji, tada u prvi i jedini red izlazne

    tekstualne datoteke TRPN.OUT T treba upisati niz znakova koji predstavlja aritmetički izraz u obrnutoj poljskoj

    notaciji. Ovaj izraz sastoji se od niza znakova koji smeju sadržavati samo mala slova (od "a" do "z") i binarne

    operatore "T+T", "T-T", "T*T" i " T/T". Nikakvi razmaci u izrazu nisu dozvoljeni. Ukoliko ulazna datoteka ne sadrži

    ispravan aritmetički izraz, u izlaznu datoteku treba samo ispisati tekst.

    NEISPRAVAN IZRAZ

    13BPrimeri:

    TRPN.IN

    x+y+z

    TRPN.OUT

    xy+z+

    TRPN.IN

    x+(y+z)

    TRPN.OUT

    xyz++

  • 51

    TRPN.IN

    x+y*z

    TRPN.OUT

    xyz*+

    TRPN.IN

    (x+y)*z

    TRPN.OUT

    xy+z*

    TRPN.IN

    x*(y+z

    TRPN.OUT

    NEISPRAVAN IZRAZ

    T

    RPN.IN

    a+b/c+d

    TRPN.OUT

    abc/+d+

    TRPN.IN

    (a+b)/(c+d)

    TRPN.OUT

    ab+cd+/

    TRPN.IN

    x*(y+z*(a+b*(c-d))/e)

    TRPN.OUT

    xyzabcd-*+*e/+*

    /******************************************

    * IZRACUNAVANJE IZRAZA KOJI JE ZADAT U *

    * INVERZNOJ POLJSKOJ NOTACIJI *

    *******************************************/

    int computePolish(char izraz[]){

    char symbol;

    int sum,n,i;

    n=(int)strlen(izraz);

    i=0;

    while (i=0 && (symbol - '0')

  • 52

    /* PREVODJENJE IZRAZA IZ INFIKS U POSTFIKS FORMU */

    #include

    #include

    #include

    #include

    int Priority(char Operator) {

    if(Operator=='*'||Operator=='/') return 2;

    else if(Operator=='+'||Operator=='-') return 1;

    else return 0;}

    char *Compile(char *Expr) {

    static char *Error="NEISPRAVAN IZRAZ";

    static char Comp[256]="";

    char Last=0,Ch,Ch1,Stack[256]="";

    int FindFlag,VarFlag=0,SSPtr=0,CompLen=0,SynError;

    int I,Parenths=0,Balance=0;

    for(I=0;I < (int)strlen(Expr);I++) {

    Ch=Expr[I]; SynError=1;

    if(Ch>='a' && ChPriority(Ch1)) {

    Stack[SSPtr++]=Ch; break;

    }

    Comp[CompLen++]=Ch1; SSPtr--;

    Balance-=(Ch1=='+'||Ch1=='-'||Ch1=='*'||Ch1=='/');

    }

    }

    if(Ch=='(') {

    Stack[SSPtr++]='('; SynError=0; Parenths++;

    }

    if(Ch==')'&&!(SynError=--Parenths=0;I--) {

    Ch=Comp[CompLen++]=Stack[I];

    Balance-=(Ch=='+'||Ch=='-'||Ch=='*'||Ch=='/');

    }

    if(Balance!=1) return Error;

    Comp[CompLen]=0;

    return Comp;

    }

    int main(void) {

    char Str[256];

    //ifstream InFile("RPN.IN"); ofstream OutFile("RPN.OUT");

    //InFile>>Str; OutFile

  • 53

    2.3.2. 7BPrimena steka – rekurzija

    Prilikom rekurzije moraju se poštovati dva osnovna principa:

    1) Svaki sledeći poziv mora voditi ka konačnom rešenju problema

    2) Mora postojati uslov za završetak procesa

    #define DIM 1000

    int faktorijelRekurzivno(int n){

    int retv,pom;

    if(n==1)

    retv=1;

    else{

    pom=faktorijelRekurzivno(n-1);

    retv=n*pom;

    }

    return retv;

    }

    int faktorijelNerekurzivno(int n){

    int top=-1, stn[DIM],stretv[DIM],stadr[DIM],stpom[DIM];

    int retv,adr,pom;

    step1:

    if(n==1){

    retv=1;

    stretv[top]=retv;

    }

    else{

    step2:

    //prevodjenje poziva faktorijelRekurzivno(n-1)

    top++;

    stn[top] = n;

    stretv[top] = retv;

    stpom[top] = pom;

    stadr[top] = 3;

    //postavi paramertre na nove vrednosti

    n--;

    goto step1;

    step3:

    pom = retv;

    retv = n*pom;

    stretv[top]=retv;

    }

    //prevodjenje return

    if(top == -1)

    return retv;

    else{

    n = stn[top];

    retv = stretv[top];

    pom = stpom[top];

    adr = stadr[top];

    top--;

    if(adr == 3)

    goto step3;

    //posto je samo jedan rekurzivan poziv

    //jedno je i mesto odakle se posle pozivna nastavlja funkcija

    //goto step3

  • 54

    }

    }

    void move(int d, char f, char t)

    {

    /* move disk d from peg f to peg t */;

    printf("moving disk %d : %c --> %c\n", d, f, t);

    }

    void hanoi(int h, char f, char t, char r)

    {

    if (h > 0)

    {

    hanoi(h-1, f, r, t);

    move (h, f, t);

    hanoi(h-1, r, t, f);

    }

    }

    void hanoiNerekurzivno(int n, char poc, char pom, char kraj){

    int stn[DIM], stpoc[DIM], stpom[DIM], stkraj[DIM], stadr[DIM];

    int top=-1, adr, tmp;

    step1:

    if(n==1){

    printf("\n %c -> %c ", poc, kraj);

    goto step5;

    }

    //prevodjenje poziva hanoi(n-1,poc,kraj,pom);

    top++;

    stn[top] = n;

    stpoc[top] = poc;

    stpom[top] = pom;

    stkraj[top] = kraj;

    stadr[top] = 3;

    //setuj parametre na nove vrednosti

    n--;

    poc = poc;

    tmp = pom;

    pom = kraj;

    kraj = tmp;

    goto step1;

    step3:

    printf("\n %c -> %c ", poc, kraj);

    //prevodjenje poziva hanoi(n-1,pom,poc,kraj)

    top++;

    stn[top] = n;

    stpoc[top] = poc;

    stpom[top] = pom;

    stkraj[top] = kraj;

    stadr[top] = 5;

    //setuj parametre na nove vrednosti

    n--;

    tmp = poc;

    poc = pom;

    pom = tmp;

    kraj = kraj;

    goto step1;

    step5:

    if(top == -1)

    return;

    else{

  • 55

    n = stn[top];

    poc = stpoc[top];

    pom = stpom[top];

    kraj = stkraj[top];

    adr = stadr[top];

    top--;

    if(adr == 3)

    goto step3;

    if(adr == 5)

    goto step5;

    }

    }

    2.4. 3BRED

    Kod steka se sva umetanja i brisanja izvršavaju na kraju koji se naziva vrh (TOP), dok se kod reda sva

    umetanja izvršavaju na kraju – KRAJ, a sva brisanja na drugom kraju reda, tj. početku – Čelo.

    Redovi su poznati kao FIFO memorije. Red S možemo implementirati kao konačan niz S[0..n-1] i pri

    tome se koriste dva podatka, CELO i KRAJ da bi se oznčile granice reda. Ako je CELO < KRAJ tada se red

    sastoji od S[CELO] ... S[KRAJ-1]. U suprotnom, ako je CELO > KRAJ, tada se red sastoji od S[CELO],...,S[n-

    1],S[0],...,S[KRAJ-1], i ako je CELO = KRAJ, tada je red prazan.

  • 56

  • 57

    /* Implementacija reda uz pomoc niza */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #define MAX 10 /* maksimalna duzina reda */ void insert(int queue[], int *rear, int value) { if (*rear < MAX - 1) { *rear = *rear + 1; queue[*rear] = value; } else { printf("Red je pun i ne moze se dodati nova vrednost\n"); exit(0); } } void delete(int queue[], int *front, int rear, int *value) { if (*front == rear) { printf("Red je prazan i ne mozemo brisati vrednost\n"); exit(0); } *front = *front + 1; *value = queue[*front]; } void print(int queue[], int front, int rear) { int i; printf("\n"); for (i = front + 1; i

  • 58

    printf("%d -> ", queue[i]); printf("KRAJ"); } void main() { int queue[MAX]; int front, rear; int value, kraj = 0, izbor; front = rear = -1; while (!kraj) { printf("\n1. Dodavanje elementa u red\n" "2. Brisanje elementa iz reda\n" "3. Stampanje reda\n" "0. Zavrsetak rada\n\n" "Vas izbor? " ); scanf("%d", &izbor); switch (izbor) { case 1: printf("\nBroj? "); scanf("%d", &value); insert(queue, &rear, value); break; case 2: delete(queue, &front, rear, &value); printf("\nPreuzeti element sa reda je %d\n", value); break; case 3: print(queue, front, rear); break; case 0: kraj = 1; break; } } } /* Implementacija reda uz pomoc linearnih listi */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include struct node { int data; struct node *link; }; void insert(struct node **front, struct node **rear, int value) { struct node *temp; temp = (struct node*) malloc(sizeof(struct node)); if (temp == NULL) { printf("No Memory available Error\n"); exit(0); } temp->data = value; temp->link = NULL; if (*rear == NULL) { *rear = temp; *front = *rear;

  • 59

    } else { (*rear)->link = temp; *rear = temp; } } void delete(struct node **front, struct node **rear, int *value) { struct node *temp; if ((*front == *rear) && (*rear == NULL)) { printf("Red je prazan nema brisanja!\n"); exit(0); } *value = (*front)->data; temp = *front; *front = (*front)->link; if (*rear == temp) *rear = (*rear)->link; free(temp); } void print(struct node *front, struct node *rear) { struct node *temp = front; printf("\n"); while (temp) { printf("%d -> ", temp->data); temp = temp->link; } printf("KRAJ"); } void main() { struct node *front = NULL, *rear = NULL; int value, kraj = 0, izbor; while (!kraj) { printf("\n1. Dodavanje elementa u red\n" "2. Brisanje elementa iz reda\n" "3. Stampanje reda\n" "0. Zavrsetak rada\n\n" "Vas izbor? " ); scanf("%d", &izbor); switch (izbor) { case 1: printf("\nBroj? "); scanf("%d", &value); insert(&front, &rear, value); break; case 2: delete(&front, &rear, &value); printf("\nPreuzeti element sa reda je %d\n", value); break; case 3: print(front, rear); break; case 0: kraj = 1; break; } } }

  • 60

    2.5. NELINEARNE STRUKTURE PODATAKA

    Najznačajnije nelinearne strukture podataka su stabla i grafovi.

    2.6. STABLA

    2.6.1. DEFINICIJE I KONCEPTI

    Graf G=(V,E) se sastoji od nepraznog skupa čvorova G i skupa E koji je skup grana grafa.

    Stablo je acikličan, orijentisan graf koji ima jedan čvor koji se zove koren (root) sa ulaznim stepenom 0

    dok svi drugi čvorovi imaju ulazni stepen 1. Ako izbrišemo koren i njegove grane dobijamo skup disjunktnih

    stabala. Svaki čvor koji ima izlazni stepen 0 naziva se terminalni čvor ili list, dok se svi drugi čvorovi nazivaju

    čvorovi grananja (brunch nodes).

    • Nivo čvora je dužina puta od korena, d.

    • Dubina (visina) stabla je maksimalna vrednost nivoa nekog čvora u stablu.

    • Za stablo se kaže da je n-arno (reda n) ako svaki čvor ima najviše n podčvorova.

    • Za stablo se kaže da je puno ako se svi listovi nalaze na istom rastojanju od korena, tj. ako od

    korena do svakog lista odgovara put dužine h-1.

    • Za stablo se kaže da je kompletno ako svi njegovi čvorovi koji ne predstavljaju listove imaju

    svih n odlaznih potega.

    • Broj čvorova kompletnog punog stabla iznosi

    C = n0 + n1 + n3 + ... + nh = ∑ 𝑛𝑗ℎ𝑗=0 =(𝑛ℎ+1−1)

    (𝑛−1)

    • Kapacitet čvora k predstavlja broj elemenata koji se može smestiti u čvor.

    • Za stablo se kaže da je balansirano ako za svaki čvor važi da se broj čvorova u svakom

    njegovom podstablu ne razlikuje za više od 1.

    • Za stablo reda n čiji su svi čvorovi na nivoima od 1 do h-1 kompletni, kaže se da je optimalno

    balansirano.

    2.6.2. OPERACIJE NA BINARNIM STABLIMA

    Neke od operacija nad binarnim stablom su: prolaz, umetanje, brisanje, pretraživanje i kopiranje.

  • 61

    /* rad sa binarnim stablom - implementacija funkcija koje vrse specificnu obradu nad

    cvorovima

    binarnog stabla */

    #include

    #include

    typedef struct cvor { int broj; struct cvor *levo, *desno; } Cvor;

    typedef Cvor *Stablo;

    Stablo stvori (void); /* Stavaranje praznog stabla. */

    int vel (Stablo koren); /* Broj cvorova u stablu. */

    int zbir (Stablo koren); /* Zbir brojeva u stablu. */

    void pisi_kld (Stablo koren); /* Prefiksno ispisivanje. */

    void pisi_lkd (Stablo koren); /* Infiksno ispisivanje. */

    void pisi_ldk (Stablo koren); /* Postfiksno ispisivanje. */

    void crtaj (Stablo koren, int nivo); /* Graficki prikaz stabla. */

    int pojav (Stablo koren, int b); /* Broj pojavljivanja u stablu. */

    int min_u (Stablo koren); /* Najmanji u uredjenom stablu. */

    int max_u (Stablo koren); /* Najveci u uredjenom stablu. */

    int min_n (Stablo koren); /* Najmanji u neuredjenom stablu. */

    int max_n (Stablo koren); /* Najveci u neuredjenom stablu. */

    int uredjeno (Stablo koren); /* Da li je stablo uredjeno? */

    Cvor *nadji_u (Stablo koren, int b); /* Trazenje u uredjenom stablu. */

    Cvor *nadji_n (Stablo koren, int b); /* Trazenje u neuredjenom stablu. */

    Stablo dodaj_u (Stablo koren, int b); /* Dodavanje u uredjeno stablo. */

    Stablo dodaj_n (Stablo koren, int b); /* Dodavanje u neuredjeno stablo. */

    Stablo citaj_u (int n); /* Citanje uredjenog stabla. */

    Stablo citaj_n (int n); /* Citanje neuredjenog stabla. */

    Stablo brisi (Stablo koren); /* Brisanje celog stabla. */

    Stablo izost_u (Stablo koren, int b); /* Izost. iz uredjenog stabla. */

    Stablo izost_n (Stablo koren, int b); /* Izost. iz neuredjenog stabla. */

    Stablo balans_u (Stablo koren); /* Balansiranje uredjenog stabla. */

    Stablo balans_n (Stablo koren); /* Balansiranje neuredjenog satbla.*/

    int moze (Stablo koren); /* Da li moze uredjena radnja? */

    Stablo radi (Stablo (*f)(Stablo,int), Stablo koren); /* Primena operacije na stablo za

    svaki procitani broj */

    int main () {

    Stablo koren = stvori (); //stablo

    int kraj = 0, broj, n; //indikator kraja rada, element u cvoru stabla, duzina

    char izbor[2]; //izbor korisnika sa menija opcija

    //obrada menija opcija koje se prikazuju korisniku

    while (!kraj) {

    printf ("\nDodavanje brojeva: a) uredjeno b) neuredjeno\n"

    "Izostavljanje brojeva: c) uredjeno d) neuredjeno\n"

    "Citanje stabla: e) uredjeno f) neuredjeno\n"

    "Najmanji element: g) uredjeno h) neuredjeno\n"

    "Najveci element: i) uredjeno j) neuredjeno\n"

    "Pretrazivanje: k) uredjeno l) neuredjeno\n"

    "Balansiranje: m) uredjeno n) neuredjeno\n"

    "Pisanje stabla: p) koren-levo-desno\n"

    " q) levo-koren-desno (uredjeno)\n"

    " r) levo-desno-kren\n"

    " s) crtanje\n"

    "1. Velicina stabla 2. Zbir elemenata\n"

    "3. Broj pojavljivanja 4. Praznjenje stabla\n"

    " 0. Zavrsetak rada\n\n"

    "Vas izbor? "

    );

    scanf ("%s", &izbor);

  • 62

    switch (izbor[0]) {

    case 'a': case 'A': /* Dodavanje brojeva u uredjeno stablo: */

    if (moze (koren)) koren = radi (dodaj_u, koren); break;

    case 'b': case 'B': /* Dodavanje brojeva u neuredjeno stablo: */

    koren = radi (dodaj_n, koren); break;

    case 'c': case 'C': /* Izostavljanje brojeva iz uredjenog stabla: */

    if (moze (koren)) koren = radi (izost_u, koren); break;

    case 'd': case 'D': /* Izostavljanje brojeva iz neuredjenog stabla: */

    koren = radi (izost_n, koren); break;

    case 'e': case 'E': /* Citanje uredjenog stabla: */

    printf ("Duzina? "); scanf ("%d", &n);

    printf ("Brojevi? "); koren = brisi (koren); koren = citaj_u (n);

    break;

    case 'f': case 'F': /* Citanje neuredjenog stabla: */

    printf ("Duzina? "); scanf ("%d", &n);

    printf ("Brojevi? "); koren = brisi (koren); koren = citaj_n (n);

    break;

    case 'g': case 'G': case 'h': case 'H':

    case 'i': case 'I': case 'j': case 'J':

    if (koren) switch (izbor[0]) {

    case 'g': case 'G': /* Najmanji element uredjenog stabla: */

    if (moze (koren)) printf ("min= %d\n", min_u (koren)); break;

    case 'h': case 'H': /* Najmanji element neuredjenog stabla: */

    printf ("min= %d\n", min_n (koren)); break;

    case 'i': case 'I': /* Najveci element uredjenog stabla: */

    if (moze (koren)) printf ("max= %d\n", max_u (koren)); break;

    case 'j': case 'J': /* Najveci element neuredjenog stabla: */

    printf ("max= %d\n", max_n (koren)); break;

    } else printf ("*** Stablo je parzno! ***\a\n");

    break;

    case 'k': case 'K': /* Broj pojavljivanja u uredjenom stablu: */

    if (moze (koren)) {

    printf ("Broj? "); scanf ("%d", &broj);

    printf ("Broj se%s nalazi u stablu.\n",

    (nadji_u (koren, broj) != NULL ? "" : " NE"));

    } break;

    case 'l': case 'L': /* Broj pojavljivanja u neuredjenom stablu: */

    printf ("Broj? "); scanf ("%d", &broj);

    printf ("Broj se%s nalazi u stablu.\n",

    (nadji_n (koren, broj) != NULL ? "" : " NE"));

    break;

    case 'm': case 'M': /* Balansiranje uredjenog stabla: */

    if (moze (koren)) koren = balans_u (koren); break;

    case 'n': case 'N': /* Balansiranje neuredjenog stabla: */

    koren = balans_n (koren); break;

    case 'p': case 'P': /* Pisanje stabla koren-levo-desno: */

    printf ("Stablo= "); pisi_kld (koren); putchar ('\n'); break;

    case 'q': case 'Q': /* Pisanje stabla levo-koren-desno: */

    printf ("Stablo= "); pisi_lkd (koren); putchar ('\n'); break;

    case 'r': case 'R': /* Pisanje stabla levo-desno-koren: */

    printf ("Stablo= "); pisi_ldk (koren); putchar ('\n'); break;

    case 's': case 'S': /* Crtanje stabla: */

    crtaj (koren, 0); break;

    case '1': /* Velicina stabla: */

    printf ("Vel= %d\n", vel (koren)); break;

    case '2': /* Zbir elemenata stabla: */

    printf ("Zbir= %d\n", zbir (koren)); break;

    case '3': /* Broj pojavljivanja datog broja: */

    printf ("Broj? "); scanf ("%d", &broj);

    printf ("Broj se pojavljuje %d puta.\n", pojav (koren, broj));

    break;

    case '4': /* Praznjenje stabla: */

  • 63

    koren = brisi (koren); break;

    case '0': /* Zavrsetak rada: */

    kraj = 1; break;

    default: /* Pogresan izbor: */

    printf ("*** Nedozvoljeni izbor! ***\a\n"); break;

    }

    }

    }

    Stablo stvori (void) { return NULL; } /* Stvaranje praznog stabla. */

    int vel (Stablo koren) /* Broj cvorova u stablu. */

    { return koren ? 1 + vel (koren->levo) + vel (koren->desno) : 0; }

    int zbir (Stablo koren) /* Zbir brojeva u stablu. */

    { return koren ? koren->broj + zbir (koren->levo) + zbir (koren->desno) : 0; }

    void pisi_kld (Stablo koren) { /* Prefiksno ispisivanje. */

    if (koren) {

    printf ("%d ", koren->broj); pisi_kld (koren->levo); pisi_kld (koren->desno);

    }

    }

    void pisi_lkd (Stablo koren) { /* Infiksno ispisivanje. */

    if (koren) {

    pisi_lkd (koren->levo); printf ("%d ", koren->broj); pisi_lkd (koren->desno);

    }

    }

    void pisi_ldk (Stablo koren) { /* Postfiksno ispisivanje. */

    if (koren) {

    pisi_ldk (koren->levo); pisi_ldk (koren->desno); printf ("%d ", koren->broj);

    }

    }

    void crtaj (Stablo koren, int nivo) { /* Graficki prikaz stabla. */

    if (koren) {

    crtaj (koren->desno, nivo+1);

    printf ("%*s%d\n", 4*nivo, "", koren->broj);

    crtaj (koren->levo, nivo+1);

    }

    }

    int pojav (Stablo koren, int b) /* Broj pojavljivanja broja b u stablu. */

    { return koren ? (koren->broj==b)+pojav(koren->levo,b)+pojav(koren->desno,b) : 0;}

    int min_u (Stablo koren) /* Najmanji u uredjenom stablu. */

    { return koren->levo ? min_u (koren->levo ) : koren->broj; }

    int max_u (Stablo koren) /* Najveci u uredjenom stablu. */

    { return koren->desno ? max_u (koren->desno) : koren->broj; }

    int min_n (Stablo koren) { /* Najmanji u neuredjenom stablu. */

    int m = koren->broj, k;

    if (koren->levo ) { k = min_n (koren->levo ); if (k < m) m = k; }

    if (koren->desno) { k = min_n (koren->desno); if (k < m) m = k; }

    return m;

    }

    int max_n (Stablo koren) { /* Najveci u neuredjenom stablu. */

    int m = koren->broj, k;

    if (koren->levo ) { k = max_n (koren->levo ); if (k > m) m = k; }

  • 64

    if (koren->desno) { k = max_n (koren->desno); if (k > m) m = k; }

    return m;

    }

    int uredjeno (Stablo koren) { /* Da li je stablo uredjeno? */

    if (! koren) return 1;

    if (koren->levo && (! uredjeno (koren->levo ) ||

    max_u (koren->levo) > koren->broj)) return 0;

    if (koren->desno && (! uredjeno (koren->desno) ||

    min_u (koren->desno) < koren->broj)) return 0;

    return 1;

    }

    Cvor *nadji_u (Stablo koren, int b) { /* Trazenje u uredjenom stablu. */

    if (! koren) return NULL;

    if (koren->broj == b) return koren;

    if (koren->broj > b) return nadji_u (koren->levo, b);

    return nadji_u (koren->desno, b);

    }

    Cvor *nadji_n (Stablo koren, int b) { /* Trazenje u neuredjenom stablu. */