/*

datoteke_txt_i_bin_-_lista_sa_string_string_int_float_v1.c

    Datoteke i liste:

Kreira listu od nizova stringova, integer-a i float-a.

Cvorovi liste sadrze: string, string, int, float.

Upis liste u bin datoteku.

Citanje liste iz bin datoteke.

Upis liste u txt datoteku.

Citanje liste iz txt datoteke.

Sortiranje liste.

*/

#include <stdio.h>
#include<stdlib.h>
#include <string.h>                         // zbog strcpy()

#define MAX_SIZE 100                        // niz moze imati najvise MAX_SIZE elemenata
#define TEKST_SIZE 30                       // string moze imati najvise TEKST_SIZE karaktera


struct cvor{                                // struktura cvor, to je jedan element liste,
    char ime[TEKST_SIZE];                   // ima svoj sadrzaj i
    char prezime[TEKST_SIZE];
    int brojInt;
    float brojFloat;
    struct cvor *sledeci;                   // pointer na sledeceg clana
};
typedef struct cvor CVOR;                   // jedan cvor liste CVOR
typedef CVOR* PCVOR;                        // pointer na listu CVOR


// Prikazuje opis liste i sadrzaj cvorova liste glava.
// Sa pomocnim cvorom tekuci (koji je ovde nepotreban, videti v1).
void prikazi_listu (char tekst[],PCVOR glava) {

    PCVOR tekuci = glava;                   // pomocni cvor u kojem cuvamo glava da ne bi bila promenjena
// glava nije predata funkciji sa adresom, tako da nece biti promenjena, tekuci je nepotreban
    printf("\n\n %s \n",tekst);             // prikazuje opis liste

    if(tekuci == NULL) {                    // ako nema cvorova u listi
        printf("\n prazna. \n");
    } else {                                // ako ima cvorova u listi
         while(tekuci != NULL) {            // od pocetka do kraja liste
            printf("\n | %-6s %-8s %5d %6.2f \t adresa sledeceg %p | \n",
                   tekuci->ime,
                   tekuci->prezime,
                   tekuci->brojInt,
                   tekuci->brojFloat,
                   tekuci->sledeci );
            tekuci = tekuci->sledeci;       // idemo na sledeci cvor liste
        }
    }
}


// Prikazuje opis liste i sadrzaj cvorova liste glava.
// Bez pomocnog cvora tekuci.
// Glava nece biti promenjena jer nije predata sa adresom (PCVOR *glava).
// Pojednostavljena verzija koja nece ispisati listu ako je prazna.
void prikazi_listu_v1 (char tekst[],PCVOR glava) {

    printf("\n\n %s \n",tekst);             // prikazuje opis liste

     while(glava != NULL) {             // od pocetka do kraja liste
        printf("\n | %-6s %-8s %5d %6.2f \t adresa sledeceg %p | \n",
               glava->ime,
               glava->prezime,
               glava->brojInt,
               glava->brojFloat,
               glava->sledeci );
        glava = glava->sledeci;           // idemo na sledeci cvor liste
    }
}


// Prikazuje jedan cvor KojiCvor (sadrzaj cvora i pointer na sledeci)
void prikazi_jedan_cvor (PCVOR KojiCvor) {

    printf("\n");

    if(KojiCvor == NULL) {                  // ako je cvor prazan
        printf("\n Cvor je prazan. \n");
    } else {                                // ako cvor nije prazan
            printf("\n | %-6s %-8s %5d %6.2f \t adresa sledeceg %p | \n",
                   KojiCvor->ime,
                   KojiCvor->prezime,
                   KojiCvor->brojInt,
                   KojiCvor->brojFloat,
                   KojiCvor->sledeci );
    }
}


// Vraca broj cvorova liste glava.
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
int prebroj_cvorove_liste (PCVOR glava)
{
    int BrojCvorova=0;                      // brojac cvorova

     while(glava != NULL) {                 // od prvog do poslednjeg cvora liste glava
        BrojCvorova++;                      // brojimo cvorove (uvecavamo brojac)
        glava = glava->sledeci;             // prelazimo na sledeci cvor
    }
    return BrojCvorova;                     // vraca broj cvorova liste glava
}


// U listi glava trazi cvor cije je prezime KojePrezime.
// Vraca 1 ako nadje takav cvor, inace vraca 0.
// strcmp(a,b) uporedjuje stringove a i b i vraca:  ( CoMPare )
//      -1 za a<b
//      0 za a=b
//      1 za a>b
int postoji_u_listi (PCVOR glava,char KojePrezime[])
{
    while(glava){                           // od pocetka do kraja liste

        if( strcmp(glava->prezime, KojePrezime ) == 0  )    // USLOV PRETRAGE
            return 1;                       // nadjen je takav cvor
/*
//  ako trazimo podatak koji je int (slicno je i za podatak float)
        if( glava->brojInt == KojiInt )     // USLOV PRETRAGE
            return 1;                       // nadjen je takav cvor
*/
        glava = glava->sledeci;             // prelazimo na sledeci cvor
    }
    return 0;                               // prosli smo sve cvorove i nije nadjen je takav cvor
}


// U listi glava broji cvorove cije je prezime KojePrezime.
// Vraca broj takvih cvorova.
// strcmp(a,b) uporedjuje stringove a i b i vraca:  ( CoMPare )
//      -1 za a<b
//      0 za a=b
//      1 za a>b
int broj_pojavljivanja_u_listi (PCVOR glava,char KojePrezime[])
{
    int BrojPojavljivanja=0;                // brojac pojavljivanja takvih cvorova

    while(glava){                           // od pocetka do kraja liste

        if( strcmp(glava->prezime, KojePrezime ) == 0  )    // USLOV PRETRAGE
            BrojPojavljivanja++;            // uvecavamo brojac
/*
//  ako trazimo podatak koji je int (slicno je i za podatak float)
        if( glava->brojInt == KojiInt )     // USLOV PRETRAGE
            BrojPojavljivanja++;            // uvecavamo brojac
*/
        glava = glava->sledeci;             // prelazimo na sledeci cvor
    }
    return BrojPojavljivanja;               // vraca broj pojavljivanja takvih cvorova
}


// Na pocetak liste glava dodaje vec napravljeni novi cvor
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
// Dobija se obrnuti redosled cvorova u odnosu na niz.
void dodaj_na_pocetak (PCVOR *glava, PCVOR *rep, PCVOR novi)
{
    if(*glava == NULL) {                    // ako je lista prazna
        *rep = novi;                        // i rep i glava su taj novi cvor
        *glava = novi;
    } else {                                // ako lista nije prazna
        novi->sledeci = *glava;             // sledeci od novog mora biti stara glava
        *glava = novi;                      // nova glava je taj novi
    }
}


// Na kraj liste glava dodaje vec napravljeni novi cvor
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
// Dobija se isti redosled cvorova u odnosu na niz.
void dodaj_na_kraj (PCVOR *glava, PCVOR *rep, PCVOR novi)
{
    if(*glava == NULL) {                    // ako je lista prazna
        *rep = novi;                        // i rep i glava su taj novi cvor
        *glava = novi;
    } else {                                // ako lista nije prazna
        (*rep)->sledeci = novi;             // sledeci od starog repa je taj novi
        *rep = novi;                        // novi rep je taj novi
    }
}


// Kreira cvor novi sa sadrzajem, sledeci mu je NULL
void napravi_novi_cvor( PCVOR *novi,
                        char ime[TEKST_SIZE],
                        char prezime[TEKST_SIZE],
                        int brojInt,
                        float brojFloat )
{
    *novi = (PCVOR)malloc(sizeof(CVOR));    // rezervisemo memoriju za cvor novi

    if(*novi == NULL) {                     // obrada eventualne greske pri rezervisanju memorije
        printf("\n Greska pri rezervisanju memorije! \n");
        exit(1);                            // prekidamo program
    }

    strcpy( (*novi)->ime, ime );            // sa stringovima mora strcpy()
    strcpy( (*novi)->prezime, prezime );    // sa stringovima mora strcpy()
    (*novi)->brojInt = brojInt;
    (*novi)->brojFloat = brojFloat;
    (*novi)->sledeci = NULL;                // za sada cvor novi ne pokazuje na sledeci cvor
}


// Kreira listu glava od nizova koji imaju brClanova
void kreiraj_listu_od_nizova ( PCVOR *glava, PCVOR *rep,
                               char ime[][TEKST_SIZE],
                               char prezime[][TEKST_SIZE],
                               int brojInt[],
                               float brojFloat[],
                               int brClanova )
{
    PCVOR novi; // samo je deklarisan, memorija za njega bice rezervisana u funkciji napravi_novi_cvor()
    int i;

    for(i=0;i<brClanova;i++){
        napravi_novi_cvor( &novi,
                           ime[i],
                           prezime[i],
                           brojInt[i],
                           brojFloat[i] );
        dodaj_na_kraj(glava,rep,novi);      // dodajemo na kraj da bi u listi bio isti redosled kao u nizu
    }
}


// Brise celu listu glava.
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
void obrisi_celu_listu (PCVOR *glava)
{
    PCVOR pom;

    while( ( pom = *glava ) != NULL ){      // dok glava postoji, brisemo glavu

        pom = *glava;                       // pocetni cvor glava pamtimo u pom zbog oslobadjanja memorije
        *glava = (*glava)->sledeci;         // drugi cvor postaje prvi, tj. novi prvi cvor glava postaje njegov (bivsi) sledeci cvor
        free(pom);                          // oslobadjamo memoriju koja je bila rezervisana za pom
    }                                       // (tu smo bili zapamtili bivsi prvi cvor glava)
}


// Brise prvi cvor liste glava
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
void obrisi_prvi_cvor (PCVOR *glava){
    PCVOR pom;

    if( *glava == NULL ){                   // ako nema cvorova u listi tj. ako je lista prazna
        printf("\n\n Lista je prazna! Nema cvorova za brisanje ! \n\n");
        system("PAUSE");
    }
    else{                                   // ako ima cvorova u listi tj. ako lista nije prazna
        pom = *glava;                       // pocetni cvor glava pamtimo u pom zbog oslobadjanja memorije
        *glava = (*glava)->sledeci;         // drugi cvor postaje prvi, tj. novi prvi cvor glava postaje njegov (bivsi) sledeci cvor
        free(pom);                          // oslobadjamo memoriju koja je bila rezervisana za pom
    }                                       // (tu smo bili zapamtili bivsi prvi cvor glava)
}


// Brise poslednji cvor liste glava tj. brise rep.
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
void obrisi_poslednji_cvor (PCVOR *glava)
{
    PCVOR pom, poslednji;                   // pomocni cvorovi

    poslednji = (PCVOR)malloc(sizeof(CVOR));// rezervisemo memoriju za poslednji, njega na kraju brisemo
    if(poslednji == NULL){                  // obrada eventualne greske pri rezervisanju memorije
        printf("\n Neuspelo rezervisanje memorije. \n");
        exit(1);
    }

    pom = *glava;                           // glavu pamtimo u cvoru pom (cuvamo glavu da je ne bi promenili)

    while( pom->sledeci->sledeci )          // idemo do PRETPOSLEDNJEG cvora  !!! CAKA !!!
        pom = pom->sledeci;                 // krecemo se po listi

    poslednji = pom->sledeci;               // poslednji cvor je sada bivsi pretposlednji cvor
    pom->sledeci = NULL;                    // i on pokazuje na NULL (jer je sada postao poslednji cvor)
    free(poslednji);                        // brisemo bivsi poslednji cvor
}


// Brise sve cvorove ciji je brojInt jednak KojiBrojInt.
void obrisi_sve_cvorove_KojiBrojInt (PCVOR *glava, int KojiBrojInt)
{
    PCVOR prethodni=NULL, tekuci=*glava, pom;

    while (tekuci != NULL) {                // od pocetka do kraja liste
        if (tekuci->brojInt == KojiBrojInt) { // ako je to cvor koji ima KojiBrojInt
                                              // KRITERIJUM BRISANJA !
            pom = tekuci;                       // pamtimo tekuci u pom
            tekuci = tekuci->sledeci;           // prelazimo na na sledeci

            // Sta ako brisemo glavu? Kako znamo da je glava: GLAVA NEMA PRETHODNOG !!! CAKA !!!
            if( prethodni == NULL )             // ako je tekuci glava
                *glava = tekuci;                    // pamtimo tekuci u glava
            else                                // ako tekuci nije glava
                prethodni->sledeci = tekuci;        // prethodni pokazuje na tekuceg

            free(pom);                              // brisemo pomocni

        }else{                                // ako to nije cvor koji ima KojiBrojInt

            prethodni = tekuci;                 // pamtimo prethodni
            tekuci = tekuci->sledeci;           // prelazimo na na sledeci
        }
    }
}


// Brise sve cvorove ciji je brojFloat jednak KojiBrojFloat.
void obrisi_sve_cvorove_KojiBrojFloat (PCVOR *glava, float KojiBrojFloat)
{
    PCVOR prethodni=NULL, tekuci=*glava, pom;

    while (tekuci != NULL) {                // od pocetka do kraja liste
        if (tekuci->brojFloat == KojiBrojFloat) {   // ako je to cvor koji ima KojiBrojFloat
                                                        // KRITERIJUM BRISANJA !
            pom = tekuci;                       // pamtimo tekuci u pom
            tekuci = tekuci->sledeci;           // prelazimo na na sledeci

            // Sta ako brisemo glavu? Kako znamo da je glava: GLAVA NEMA PRETHODNOG !!! CAKA !!!
            if( prethodni == NULL )             // ako je tekuci glava
                *glava = tekuci;                    // pamtimo tekuci u glava
            else                                // ako tekuci nije glava
                prethodni->sledeci = tekuci;        // prethodni pokazuje na tekuceg

            free(pom);                              // brisemo pomocni

        }else{                                // ako to nije cvor koji ima KojiBrojInt

            prethodni = tekuci;                 // pamtimo prethodni
            tekuci = tekuci->sledeci;           // prelazimo na na sledeci
        }
    }
}


// Brise sve cvorove ciji je prezime jednako KojePrezime.
void obrisi_sve_cvorove_KojePrezime (PCVOR *glava, char KojePrezime[] )
{
    PCVOR prethodni=NULL, tekuci=*glava, pom;

    while (tekuci != NULL) {                // od pocetka do kraja liste
        if ( strcmp(tekuci->prezime, KojePrezime) == 0 ) {  // ako je to cvor koji ima KojiBrojFloat
                                                                // KRITERIJUM BRISANJA !
            pom = tekuci;                       // pamtimo tekuci u pom
            tekuci = tekuci->sledeci;           // prelazimo na na sledeci

            // Sta ako brisemo glavu? Kako znamo da je glava: GLAVA NEMA PRETHODNOG !!! CAKA !!!
            if( prethodni == NULL )             // ako je tekuci glava
                *glava = tekuci;                    // pamtimo tekuci u glava
            else                                // ako tekuci nije glava
                prethodni->sledeci = tekuci;        // prethodni pokazuje na tekuceg

            free(pom);                              // brisemo pomocni

        }else{                                // ako to nije cvor koji ima KojiBrojInt

            prethodni = tekuci;                 // pamtimo prethodni
            tekuci = tekuci->sledeci;           // prelazimo na na sledeci
        }
    }
}


// U binarnu datoteku ImeDatoteke upisuje listu glava.
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
void upisi_listu_u_bin_datoteku (char ImeDatoteke[],PCVOR glava)
{
    FILE *p_fajl;
    PCVOR tek = glava;                      // da glava ne bi bila promenjena, cuvamo glavu

    p_fajl = fopen(ImeDatoteke, "wb");      // otvaramo izlaznu binarnu datoteku za pisanje

    if( p_fajl == NULL ) {                  // obrada eventualne greske pri otvaranju fajla
        printf("\n Greska pri otvaranju izlaznog bin fajla ! \n");
        exit(1);                            // napustamo program
    }

    while( tek ){                           // od pocetka do kraja liste

//        prikazi_jedan_cvor(tek);            // prikazuje samo jedan cvor, tek

        fwrite(tek, sizeof(CVOR), 1, p_fajl); // ceo jedan cvor tek odjednom upisujemo u datoteku
                                            // Ovde se menja tek (zato nismo radili sa glava) :
        tek = tek->sledeci;                 // idemo na sledeci cvor
    }
    fclose(p_fajl);                         // zatvaramo izlaznu bin datoteku
}


// Ucitava listu glava iz binarne datoteke ImeDatoteke.
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
void ucitaj_listu_iz_bin_datoteke (char ImeDatoteke[],PCVOR *glava,PCVOR *rep)
{
    FILE *p_fajl;
    PCVOR novi; // samo je deklarisan, memorija za njega bice rezervisana kasnije u ovoj funkciji

    p_fajl = fopen(ImeDatoteke, "rb");      // otvaramo ulaznu binarnu datoteku za citanje

    if( p_fajl == NULL ) {                  // obrada eventualne greske pri otvaranju fajla
        printf("\n Greska pri otvaranju ulaznog bin fajla ! \n");
        exit(1);                            // napustamo program
    }
                                            // ucitavamo jedan po jedan cvor liste iz bin datoteke
    while( 1 ) {                            // beskonacna petlja koja se prekida sa break

        novi = (PCVOR)malloc(sizeof(CVOR)); // rezervisemo memoriju za cvor novi

        if(novi == NULL) {                  // obrada eventualne greske pri rezervisanju memorije
            printf("\n Greska pri rezervisanju memorije! \n");
            exit(1);                        // prekidamo program
        }

        fread(novi,sizeof(CVOR),1,p_fajl);  // u cvor novi ucitavamo ceo jedan cvor iz bin datoteke
                                            // funkciju feof() pozivamo obavezno tek nakon pokusaja citanja sa fread() !
        if( feof(p_fajl) )                  // ako smo stigli do kraja bin datoteke
            break;                          // prekidamo while petlju

//        prikazi_jedan_cvor(novi);           // prikazuje samo jedan cvor, novi

        dodaj_na_kraj(glava,rep,novi);      // dodajemo cvor novi na kraj liste da bi se ocuvao redosled kao u nizovima
    }
    fclose(p_fajl);                         // zatvaramo ulaznu bin datoteku
}


// U txt datoteku ImeDatoteke upisuje listu glava.
void upisi_listu_u_txt_datoteku (char ImeDatoteke[],PCVOR glava)
{
    FILE *p_fajl;

    p_fajl = fopen(ImeDatoteke, "w");       // otvaramo izlaznu txt datoteku za pisanje
    if( p_fajl == NULL ) {                  // obrada eventualne greske pri otvaranju fajla
        printf("\n Greska pri otvaranju izlaznog txt fajla ! \n");
        exit(1);
    }

    while(glava){                           // od pocetka do kraja liste glava

        // fprintf(u sta, format, sta)
        // fprintf() vraca broj upisanih elemenata. Ako je greska, vraca negativan broj.
        // Upis mora u ovom formatu, ne moze sa %-6s ili sa %6.2f   !!!
        fprintf(p_fajl, "%6s %8s %5d %f \n",
                glava->ime,
                glava->prezime,
                glava->brojInt,             // nema potrebe da upisujemo pokazivac na sledeci cvor
                glava->brojFloat );         // jer ce se on biti formiran pri dodavanju cvora u listu

        // ovde se glava menja, ali nije preneta kao pointer tako da ne treba da je cuvamo u cvoru pom
        glava = glava->sledeci;             // idemo na sledeci cvor
    }
    fclose(p_fajl);                         // zatvaramo izlaznu txt datoteku
}


// Iz txt datoteke ImeDatoteke ucitava listu glava.
void ucitaj_listu_iz_txt_datoteke(char ImeDatoteke[],PCVOR *glava,PCVOR *rep)
{
    FILE *p_fajl;                           // deklaracija pointera na fajl
    PCVOR novi; // samo je deklarisan, memorija za njega bice kasnije rezervisana u petlji while

    p_fajl = fopen(ImeDatoteke, "r");       // otvaramo ulaznu txt datoteku za citanje
    if( p_fajl == NULL ) {                  // obrada eventualne greske pri otvaranju fajla
        printf("\n Greska pri otvaranju ulaznog txt fajla %s ! \n", ImeDatoteke);
        exit(1);
    }

    // fscanf(odakle, format, adrese u sta),
    // fscanf() vraca broj ucitanih elemenata ili EOF na kraju fajla.
    // Ucitavamo jedan po jedan red iz txt fajla U ISTOM FORMATU u kojem smo je upisali u txt fajl:
    while ( 1 ) {                           // beskonacna petlja koja se prekida sa break

        novi = (PCVOR)malloc(sizeof(CVOR)); // rezervisemo memoriju za cvor novi
        if(novi == NULL) {                  // obrada eventualne greske pri rezervisanju memorije
            printf("\n Greska pri rezervisanju memorije! \n");
            exit(1);                        // izlazimo iz programa
        }

        // Ucitavamo jedan red iz ulaznog txt fajla U ISTOM FORMATU u kojem je upisan u txt fajl:
        fscanf(p_fajl, "%6s %8s %5d %f \n",
                    novi->ime,              // NE TREBA & (ADRESA)  !!!
                    novi->prezime,          // NE TREBA & (ADRESA)  !!!
                    &(novi->brojInt),
                    &(novi->brojFloat) );

        novi->sledeci = NULL;               // za sada, za svaki slucaj

//        prikazi_jedan_cvor(novi);           // prikazuje samo jedan cvor, novi

        dodaj_na_kraj(glava,rep,novi);      // dodajemo cvor novi na kraj liste da bi se ocuvao redosled kao u nizovima

        if (feof(p_fajl))                   // Ukoliko smo dosli do kraja datoteke, prekidamo while(1) petlju
            break;
    }
    fclose(p_fajl);                         // zatvaramo ulaznu txt datoteku
}


// Medjusobno zamenjuje sadrzaje dva cvora i,j.
// To je pomocna funkcija za sortiranje liste tehnikom medjusobnog premestanja
// putnika dva vagona, dok vagoni ostaju na svojim mestima (to se vidi po adresama sledeceg).
// Lista je kao kompozicija voza. Na pocetku (glava) je lokomotiva,
// a iza nje su vagoni i svi su povezani (pointer na sledeci).
// Elementi liste su kao putnici u vagonima voza.
// Kada sortiramo, odnosno premestamo radi sortiranja,
// ne moramo da premestamo vagone, neka oni ostanu na svojim mestima.
// Samo premestamo putnike iz jednog vagona u drugi.
// Na taj nacin nema potrebe da menjamo pokazivace na sledece vagone,
// jer raspored vagona ostaje isti, samo su se putnici (sadrzaj cvora) premestili.
void zameni_medjusobno_sadrzaje_cvorova( PCVOR *i, PCVOR *j)
{                                           // argumenti su pointeri jer funkcija menja cvorove i,j.
//    char* mem_s=(char*)malloc(sizeof(char)*TEKST_SIZE);   // moze i tako, sa malloc()
//    char* mem_int=(int*)malloc(sizeof(int));
//    char* mem_float=(float*)malloc(sizeof(float));

    char mem_s[TEKST_SIZE];                 // pomocna memorija za sortiranje string podataka
    int mem_int;                            // pomocna memorija za sortiranje int podataka
    float mem_float;                        // pomocna memorija za sortiranje float podataka

// Sledi deo funkcije zavisi od sadrzaja cvorova:
    strcpy( mem_s, (*i)->ime );                // za stringove mora strcpy()
    strcpy( (*i)->ime, (*j)->ime );
    strcpy( (*j)->ime, mem_s );

    strcpy( mem_s, (*i)->prezime );
    strcpy( (*i)->prezime, (*j)->prezime );
    strcpy( (*j)->prezime, mem_s );

    mem_int = (*i)->brojInt;
    (*i)->brojInt = (*j)->brojInt;
    (*j)->brojInt = mem_int;

    mem_float = (*i)->brojFloat;
    (*i)->brojFloat = (*j)->brojFloat;
    (*j)->brojFloat = mem_float;
}


// Sortira neopadajuce listu glava neopadajuce po imenima premestanjem sadrzaja cvorova.
// strcmp(a,b) uporedjuje stringove a i b i vraca:  ( CoMPare )
//      -1 za a<b
//      0 za a=b
//      1 za a>b
void sortiraj_listu_neopadajuce_po_ime(PCVOR *glava)
{
    PCVOR i,j;                              // pomocni cvorovi za sortiranje

    for(i=*glava;i;i=i->sledeci)            // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava;j;j=j->sledeci)        // od prvog do poslednjeg cvora (tada je j = NULL)
            if( strcmp(i->ime, j->ime) == -1 )      // KRITERIJUM SORTIRANJA !
                                    // ==  1 za nerastuci (obrnuti) redosled sortiranja
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j );
                                                // predajemo adrese jer funkcija menja cvorove
}


// Sortira neopadajuce listu glava po prezimenima
// strcmp(a,b) uporedjuje stringove a i b i vraca:  ( CoMPare )
//      -1 za a<b
//      0 za a=b
//      1 za a>b
void sortiraj_listu_neopadajuce_po_prezime(PCVOR *glava)
{
    PCVOR i,j;                              // pomocni cvorovi za sortiranje

    for(i=*glava;i;i=i->sledeci)            // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava;j;j=j->sledeci)        // od prvog do poslednjeg cvora (tada je j = NULL)
            if( strcmp(i->prezime, j->prezime) == -1 )      // KRITERIJUM SORTIRANJA !
                                            // ==  1 za nerastuci (obrnuti) redosled sortiranja
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j );
                                                // predajemo adrese jer funkcija menja cvorove
}


// Sortira neopadajuce listu glava po brojInt
void sortiraj_listu_neopadajuce_po_brojInt(PCVOR *glava)
{
    PCVOR i,j;                              // pomocni cvorovi za sortiranje

    for(i=*glava;i;i=i->sledeci)            // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava;j;j=j->sledeci)        // od prvog do poslednjeg cvora (tada je j = NULL)
            if( i->brojInt < j->brojInt )           // KRITERIJUM SORTIRANJA !
                        // > za nerastuci (obrnuti) redosled sortiranja
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j );
                                                // predajemo adrese jer funkcija menja cvorove
}


// Sortira neopadajuce listu glava po brojFloat
void sortiraj_listu_neopadajuce_po_brojFloat(PCVOR *glava)
{
    PCVOR i,j;                              // pomocni cvorovi za sortiranje

    for(i=*glava;i;i=i->sledeci)            // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava;j;j=j->sledeci)        // od prvog do poslednjeg cvora (tada je j = NULL)
            if( i->brojFloat < j->brojFloat )       // KRITERIJUM SORTIRANJA !
                          // > za nerastuci (obrnuti) redosled sortiranja
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j );
                                                // predajemo adrese jer funkcija menja cvorove
}


/*
Sortiranje liste premestanjem cvorova u neopadajuci redosled,
( od sadrzaja cvorova zavisi samo u KRITERIJUMU ZA SORTIRANJE ) :
Da bismo sortirali listu p, prvo prolazimo kroz nju kako bismo pronasli
element sa najvecom vrednoscu podatka.
Nakon toga uklanjamo taj element iz liste p
i dodajemo ga na pocetak druge liste nova_glava, koja je inicijalno bila prazna.
Ovaj proces ponavljamo sve dok pocetna lista p ne postane prazna.
Na kraju p postaje pokazivac na listu nova_glava u koju su prebaceni svi elementi.
*/
// Sortira listu premestanjem cvorova u neopadajuci redosled,
// ( od sadrzaja cvorova zavisi samo u KRITERIJUMU ZA SORTIRANJE )
void sortiraj_listu_premestanjem_cvorova_neopadajuce_po_prezime( PCVOR *glava )
{
    PCVOR tekuci, tek_sledeci, max, prethodni, nova_glava;

    nova_glava = NULL;

    while( *glava ){      // do kraja liste

        prethodni = NULL;
        max  =  *glava;     // pretpostavljamo da je najveci bas prvi element (glava)
        tekuci =  *glava;
        tek_sledeci = (*glava)->sledeci;

        while ( tek_sledeci ) {
// ---------------------------------------------------------------------------------------------
// KRITERIJUM SORTIRANJA, SAMO TU FUNKCIJA ZAVISI OD SADRZAJA CVOROVA

//                           ->ime              ->ime
//            if( strcmp( max->ime , tek_sledeci->ime ) == 1 )

//                         ->prezime              ->prezime
            if( strcmp( max->prezime , tek_sledeci->prezime ) == 1 )

//                   ->brojInt              ->brojInt
//            if( max->brojInt > tek_sledeci->brojInt )

//                   ->brojFloat              ->brojFloat
//            if( max->brojFloat > tek_sledeci->brojFloat )

// I SAMO TU JE TREBA PRILAGODITI SADRZAJU CVOROVA
// I REDOSLEDU SORTIRANJA ( == -1  odnosno  <  za nerastuci redosled )
// ---------------------------------------------------------------------------------------------
            {
                max = tek_sledeci;  // max postaje tek_sledeci
                prethodni = tekuci;
            }

            tekuci = tek_sledeci;
            tek_sledeci = tek_sledeci->sledeci;
        }

        if( prethodni == NULL )
            *glava = max->sledeci;
        else
            prethodni->sledeci = max->sledeci;

        max->sledeci = NULL;

        // dodaj max na kraj nova_glava (bez repa)
        if( nova_glava == NULL )
            nova_glava = max; // premesta element sa najvecom vrednoscu podatka iz liste glava na pocetak liste nova_glava
        else {
            tekuci = nova_glava;
                    // prolazi kroz listu nova_glava da bi pronasao njen poslednji element
            while( tekuci->sledeci )
                tekuci = tekuci->sledeci;
                    // premesta element sa najvecom vrednoscu podatka iz liste glava na kraj liste nova_glava
            tekuci->sledeci = max;
        }
    }
    // glava postaje nova_glava
    *glava = nova_glava; // Na kraju glava postaje pokazivac na listu nova_glava u koju su prebaceni svi elementi.
}




int main (void)
{
    char ime[MAX_SIZE][TEKST_SIZE] = {"Ivana","Pera","Mika","Laza"};            // niz imena
    char prezime[MAX_SIZE][TEKST_SIZE] = {"Milicev","Peric","Mikic","Lazic"};   // niz prezimena
    int nizInt[MAX_SIZE] = {1997, 1992, 1996, 1995};                            // niz integer-a
    float nizFloat[MAX_SIZE] = {9.78, 8.45, 7.56, 10.0};                        // niz float-a
    int brClanova = 4;                      // broj clanova nizova stringova, integer-a i float-a
    PCVOR Lista = NULL;                     // lista
    PCVOR rep = NULL;                       // rep liste

    printf("\n sizeof(CVOR)  = %2d \n",sizeof(CVOR));           // prikaz velicine memorije za CVOR
    printf("\n sizeof(PCVOR) = %2d \n",sizeof(PCVOR));          // prikaz velicine memorije za PCVOR

    // Kreiramo listu od nizova stringova, integer-a i float-a.
    // Dajemo adresu jer se vrsi promena liste.
    kreiraj_listu_od_nizova( &Lista, &rep,
                             ime,
                             prezime,
                             nizInt,
                             nizFloat,
                             brClanova );

    // prikazujemo listu kreiranu od nizova, ne treba adresa jer se lista samo cita
    prikazi_listu("Lista iz nizova je: ",Lista);


// Binarna datoteka:

    // Listu upisujemo u bin datoteku, ne treba adresa jer se lista samo cita
    printf("\n\n Listu upisujemo u bin datoteku. \n");
    upisi_listu_u_bin_datoteku("Lista.bin",Lista);

    // Brisemo celu listu, dajemo adresu jer se vrsi promena liste
    printf("\n\n Brisemo celu listu (upisana je u bin datoteku). \n");
    obrisi_celu_listu(&Lista);

    prikazi_listu("Lista nakon brisanja je: ",Lista);

    // Listu ucitavamo iz bin datoteke, dajemo adrese jer se vrsi promena liste
    printf("\n\n Listu ucitavamo iz bin datoteke. \n");
    ucitaj_listu_iz_bin_datoteke("Lista.bin",&Lista,&rep);

    // prikazujemo listu ucitanu iz bin datoteke, ne treba adresa jer se lista samo cita
    prikazi_listu("Lista iz bin datoteke je: ",Lista);


// Tekstualna datoteka:

    // Listu upisujemo u txt datoteku, ne treba adresa jer se lista samo cita
    printf("\n\n Listu upisujemo u txt datoteku. \n");
    upisi_listu_u_txt_datoteku("Lista.txt",Lista);

    // Brisemo celu listu, dajemo adresu jer se vrsi promena liste
    printf("\n\n Brisemo celu listu (upisana je u txt datoteku). \n");
    obrisi_celu_listu(&Lista);

    prikazi_listu("Lista nakon brisanja je: ",Lista);

    // Listu ucitavamo iz txt datoteke, dajemo adrese jer se vrsi promena liste
    printf("\n\n Listu ucitavamo iz txt datoteke. \n");
    ucitaj_listu_iz_txt_datoteke("Lista.txt",&Lista,&rep);

    // prikazujemo listu ucitanu iz txt datoteke, ne treba adresa jer se lista samo cita
    prikazi_listu("Lista iz txt datoteke je: ",Lista);


// Sortiranja liste
    printf("\n\n\n Sortiranja liste: \n");

    // Sortiramo listu neopadajuce po imenima
    sortiraj_listu_neopadajuce_po_ime(&Lista);
    prikazi_listu("Lista sortirana neopadajuce po imenima je: ",Lista);

    // Sortiramo listu neopadajuce po prezimenima
    sortiraj_listu_neopadajuce_po_prezime(&Lista);
    prikazi_listu("Lista sortirana neopadajuce po prezimenima je: ",Lista);

    // Sortiramo listu neopadajuce po brojInt
    sortiraj_listu_neopadajuce_po_brojInt(&Lista);
    prikazi_listu("Lista sortirana neopadajuce po brojInt je: ",Lista);

    // Sortiramo listu neopadajuce po brojFloat
    sortiraj_listu_neopadajuce_po_brojFloat(&Lista);
    prikazi_listu("Lista sortirana neopadajuce po brojFloat je: ",Lista);


    // Sortiramo listu premestanjem cvorova neopadajuce po prezimenima
    sortiraj_listu_premestanjem_cvorova_neopadajuce_po_prezime(&Lista);
    prikazi_listu("Lista sortirana premestanjem cvorova neopadajuce po prezimenima je: ",Lista);



/*
    // brisanje napravljenih datoteka
    remove("Lista.txt");
    remove("Lista.bin");
*/


    printf("\n\n\n");
    system("PAUSE");
    return 0;
}