Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

Reruzivno sabiranje listi, C kod.

[es] :: C/C++ programiranje :: Reruzivno sabiranje listi, C kod.

[ Pregleda: 1714 | Odgovora: 2 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

Hyperborejac
Kotor

Član broj: 9988
Poruke: 56
*.crnagora.net.



+1 Profil

icon Reruzivno sabiranje listi, C kod.18.12.2004. u 13:42 - pre 235 meseci
Code:


/* Uradite copy/paste, kompajlirajte gcc-om (trebao bi svaki drugi) i pomozite, ako znate. Pozdrav i hvala.*/

/* Problematican program za gubljenje zivaca. */
/* Sabiranje dvije liste. Problem je u tome kako da izvedem sabiranje tri liste. */

#include <stdio.h>

/* Kreiram klasicnu listu. */
typedef struct anenzi {
    int glava;
    struct anenzi *rep;
} lista;

/* Funkcija koja vraca duzinu liste. */
int Duzina (lista **l) {
    if (*l == NULL) return 0;
    else return(1 + (Duzina(& ((*l) -> rep)) ));
}

/* Ispis liste... lista se ispisuje obratno, da bi sabiranje bilo brze (tj. broj 192 se pamti kao 2 -> 9 -> 1) */
void IspisNaopako(lista **l) {
    int i, z;
    lista *pom;
    z = Duzina(l);
    while (z) {
        pom = *l;
        for (i=1;i<z;++i) pom = pom -> rep;
        printf("%d -> ", pom -> glava);
        z--;
    }
    printf("\n");
}

/* Funkcija koja unosi element na pocetak liste. */
void NaPocetak(lista **l, int i) {
    lista *pom;
    pom = (lista *) malloc(sizeof(lista));
    pom -> glava = i;
    pom -> rep = *l;
    *l = pom;
}

/* Funkcija koja rekurzivno sabira dvije liste l i k i njihov rezultat upisuje u zbir. */
void RekurzLakse(lista **l, lista **k, lista **zbir, int prenos) {
    if ((*l != 0) && (*k != 0)) {
        *zbir = (lista *) malloc(sizeof(lista));
        (*zbir) -> glava = ((*l) -> glava + (*k) -> glava + prenos)%10;
        (*zbir) -> rep = 0;
        prenos = ((*l) -> glava + (*k) -> glava + prenos)/10;
        RekurzLakse(& ((*l) -> rep), & ((*k) -> rep), & ((*zbir) -> rep), prenos);
    }
    else if (*l != 0) {
        *zbir = (lista *) malloc(sizeof(lista));
        (*zbir) -> glava = ((*l) -> glava + prenos)%10;
        (*zbir) -> rep = 0;
        prenos = ((*l) -> glava + prenos)/10;
        RekurzLakse(& ((*l) -> rep), k, & ((*zbir) -> rep), prenos);
    }
    else if (*k != 0) {
        *zbir = (lista *) malloc(sizeof(lista));
        (*zbir) -> glava = ((*k) -> glava + prenos)%10;
        (*zbir) -> rep = 0;
        prenos = ((*k) -> glava + prenos)/10;
        RekurzLakse(l, & ((*k) -> rep), & ((*zbir) -> rep), prenos);
    }
    else if (prenos) {
        *zbir = (lista *) malloc(sizeof(lista));
        (*zbir) -> glava = 1;
        (*zbir) -> rep = 0;
    }
}            

/* Ovakav izlaz mi treba, tj. treba mi funkcija Saberi2 koja ce imati oblik :
    **Saberi2(lista **l, lista **k) 
    Ovaj program je dio jednog veceg programa u kome mi je bas ovakav oblik funkcije neophodan.
*/
lista **Saberi2(lista **l, lista **k) {
    lista **pom;
    RekurzLakse(l,k,pom,0);
    return(pom);
}


/* PROBLEMATICAN DIO I UJEDNO GLAVNO PITANJE : */
/* Ovaj dio koda normalno sabira 3 liste, ali rezultat prepisuje preko liste k koja mu se zadaje kao argument.*/
/* Kako ga promijeniti tako da i dalje sabira sve 3 liste, ali da ne mijenja argumente? */

lista **Saberi3(lista **l, lista **k, lista **z) {
    return(Saberi2((*Saberi2)(l,k), z));
}

main() {
    lista *l, *k, *z, *pom, *pom2, *pom3;
    int i, b1, b2, b3, cif, n;
    pom=NULL;
    pom2=NULL;
    l = NULL;
    k = NULL;
    z = NULL;
    pom = NULL;
    printf("Unesite koliko prvi broj ima cifara :\n");
    scanf("%d", &b1);
    printf("Unesite cifre prvog broja (iza svake enter...)\n");
    for (i=0; i<b1; ++i) {
        printf("Cifra %d : ", i+1);
        scanf("%d", &cif);
        NaPocetak(&l, cif);
    }
    printf("Unesite koliko drugi broj ima cifara :\n");
    scanf("%d", &b2);
    printf("Unesite cifre drugog broja (iza svake enter...)\n");
    for (i=0; i<b2; ++i) {
        printf("Cifra %d : ", i+1);
        scanf("%d", &cif);
        NaPocetak(&k, cif);
    }
    printf("Unesite koliko treci broj ima cifara :\n");
    scanf("%d", &b3);
    printf("Unesite cifre treceg broja (iza svake enter...)\n");
    for (i=0; i<b3; ++i) {
        printf("Cifra %d : ", i+1);
        scanf("%d", &cif);
        NaPocetak(&z, cif);
    }
    printf("\n\n\n\n\nDakle, unijeli ste sledece liste : \n");
    IspisNaopako(&l);
    IspisNaopako(&k);
    IspisNaopako(&z);
    printf("Idemo da saberemo prve dvije liste :\n");
    pom = *Saberi2(&l, &k);
    IspisNaopako(&pom);
    printf("Cisto da vidimo da se liste nisu promijenile : \n");
    IspisNaopako(&l);
    IspisNaopako(&k);
    IspisNaopako(&z);
    printf("Idemo sad da saberemo ove 3 liste :\n");
    pom2 = *Saberi3(&l, &k, &z);
    printf("Rezultat je :\n");
    IspisNaopako(&pom2);
    printf("Cisto da se uvjerimo da se liste l, k i z nisu promijenile :\n");
    IspisNaopako(&l);
    IspisNaopako(&k);
    IspisNaopako(&z);
    printf("... I TO NE RADI JER SE LISTA k PROMIJENILA! ZASTO I KAKO DA OTKLONIM?\n");
    printf("A sad idem da saberem liste l, k i z opet :\n");
    
        pom3 = *Saberi2(     Saberi2(&l, &k))     ,&z);
    /* Segmentation fault. Zasto ovo ne moze? Pitanje dva i ujedno poslednje. */
    
    IspisNaopako(&pom3);
    printf("Cisto da se uvjerimo da se liste l, k i z nisu promijenile :\n");
    IspisNaopako(&l);
    IspisNaopako(&k);
    IspisNaopako(&z);
}

Milivojev pas je siledžija. Siledžija!
 
Odgovor na temu

tomkeus

Član broj: 40478
Poruke: 503
*.vdial.verat.net.



+6 Profil

icon Re: Reruzivno sabiranje listi, C kod.18.12.2004. u 14:08 - pre 235 meseci
Bacio sam letimičan pogled i mislim da je problem u sledećem. U funkciji za sabiranje liste prenosiš kao pokazivače, i time svaki put kada izvršiš operaciju na derefernciranom pokazivalču ti menjaš sadržaj adrese na koju on pokazuje. Rešenje je ili da parametre prenosiš kopiranjem (znači ne kao pokazivače) ili da unutar funkcije napraviš kopije liste i na njima obavljaš sve operacije. Ovo ume da bude škakljivo, zato što kada kao rezultat funkcije vraćaš kao pokazivač moraš da vodiš računa da ono na šta taj pokazivač pokazuje ne nestane posle poziva te funkcije.
 
Odgovor na temu

Hyperborejac
Kotor

Član broj: 9988
Poruke: 56
*.crnagora.net.



+1 Profil

icon ReKuRzivno sabiranje listi, C kod.19.12.2004. u 21:40 - pre 235 meseci
Evo da odgovorim samom sebi, mozda nekome bude i korisno.

Umjesto funkcija RekurzLakse i Saberi 2, treba ubaciti sledece dvije :

Code:


void NaKraj(lista **l, int i) {
    if (*l == 0) {
        *l = (lista *) malloc(sizeof(lista));
        (*l) -> glava = i;
        (*l) -> rep = NULL;
    }
    else NaKraj(&((*l) -> rep), i);
}


lista **Saberi2(lista **l, lista **k) {
    lista **zbir, *nal, *nak;
    int prenos;
    zbir = (lista **) malloc(sizeof(lista));
    *zbir = 0; 
    if ((*l == 0) && (*k == 0)) return(zbir);
    else {
        nal = *l;
        nak = *k;
        prenos = 0;
        do {
            if ((nal != 0) && (nak != 0)) {
                NaKraj(zbir,(nal->glava + nak-> glava + prenos)%10);
                prenos = (nal->glava + nak->glava + prenos)/10;
                nak = nak -> rep;
                nal = nal -> rep;
            }
            else if (nal != 0) {
                NaKraj(zbir,(nal->glava + prenos)%10);
                prenos = (nal->glava + prenos)/10;
                nal = nal -> rep;
            }
            else if (nak != 0) {
                NaKraj(zbir,(nak->glava + prenos)%10);
                prenos = (nak->glava + prenos)/10;
                nak = nak -> rep;
            }
        } while ((nal != 0) || (nak != 0));
        if (prenos) NaKraj(zbir, 1);
    }
    return(zbir);
}


U cemu je ukratko poenta (koga nije volja da cita)? U sledecem :
Zamislimo da u nekom (bilo kom) programu imam definisanu strukturu lista i sledecu promjenjivu :

Code:

lista *k;


a uz to imam funkciju oblika
Code:

lista **Saberi(..., ...) {
   lista **i;
    ...
    return(i)
}


pitanje je kako dodijeliti listi k listu koja se javila kao rezultat saberi? Ovako :

Code:

k = *Saberi(...,...);


Tu nisam napravio gresku. Aki evo gdje jesam : kako da vratim NULL kao rezultat Saberi? Jasno je da mi onda ono na sta pokazuje Saberi mora biti null, ali ovdje je kljucna fraza 'ono na sta pokazuje saberi A NE I SAMO SABERI!!!'. Ja sam pravio gresku za greskom. Idemo na prvu :

Code:

lista **Saberi(..., ...) {
    lista **i;
    i = NULL;
   return(i);
}


Ovo je bas uzasna greska. Sta sam ja ovim uradio? Ja sam pokazivac na pokazivac na listu anulirao, a to je pogresno, jer treba da anuliram samo drugi pokazivac. Onda sam napravio drugu gresku :

Code:

lista **Saberi(...,...) {
   lista **i;
   *i = NULL;
   return(i);
}


Sta je ovdje greska? Ovo "*i = NULL" nije, iz prostog razloga sto ja i treba da anuliram drugi pokazivac. Pravi problem je u tome sto ja nisam PRVI pokazivac uopste alocirao u memoriji. Zato je jedino resenje sledece :

Code:

lista **Saberi(...,...) {
   lista **i;
    i = (lista **) malloc(sizeof(lista));
   *i = NULL;
   return(i);
}


Sve je jasno. Imam pokazivac na pokazivac na listu. Prvo alociram 'indirektni' pokazivac (onaj koji pokazuje na pokazivac na listu), a onda onaj preostali pokazivac (koji direktno pokazuje na listu) stavim na NULL. Ako to uradim, dodjela

Code:

k = *Saberi(...,...);


moze k-u da dodijeli NULL kao vrijednost. Zanimljivo je da funkcija u kojoj sam ja mislio da je problem, tj.

Code:

lista **Saberi3(lista **l, lista **k, lista **z) {
    return(Saberi2((*Saberi2)(l,k), z));


je bila od samog starta OK, iako izgleda ovako rogobatno. Hvala svima. Pozdrav.
Milivojev pas je siledžija. Siledžija!
 
Odgovor na temu

[es] :: C/C++ programiranje :: Reruzivno sabiranje listi, C kod.

[ Pregleda: 1714 | Odgovora: 2 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.