Rekurencyjne dodawanie elementów do listy
Mariusz:
Rekurencyjne dodawanie elementów do listy
typedef struct lista{
int wart;
struct lista *nast;
}lista;
void dodaj(lista *l,int nowy)
{
if(l!=NULL)
{
dodaj(l−>nast,nowy);
}
else
{
l=(lista*) malloc((sizeof(lista)));
l−>wart=nowy;
l−>nast=NULL;
}
}
void pokaz(lista *l)
{
if(l!=NULL)
{
printf("%i ",l−>wart);
pokaz(l−>nast);
}
}
Gdy wkleimy kod do naszej funkcji głównej to wprawdzie się skompiluje ale nie będzie efektów
Dlaczego tak się dzieje i jaki macie pomysł aby to poprawić
Problematyczna może być funkcja dodaj
1 sty 20:59
Dziadek Mróz:
Sychy kod tak jak powinno działać:
void dodaj(lista *elem, int nowy)
{
if (elem == NULL)
{
elem = (lista *)malloc(sizeof(lista));
elem = nowy;
elem−>next = NULL;
}
else
{
dodaj(elem−>next, nowy);
}
}
lista *first = NULL;
pokaz(first); → (NULL)
dodaj(NULL, 1);
NULL == NULL → tak
elem = (lista *)malloc(sizeof(lista));
elem = nowy;
elem−>next = NULL;
pokaz(first); → (1, NULL)
dodaj(1, 2);
1 == NULL → nie
dodaj(NULL, 2):
NULL == NULL → tak
elem = (lista *)malloc(sizeof(lista));
elem = nowy;
elem−>next = NULL;
pokaz(first); → (1, 2, NULL)
1 sty 21:43
Dziadek Mróz:
void pokaz(lista *elem)
{
if (elem == NULL)
{
printf("NULL");
}
else
{
printf("%d, ", (*elem).wart);
pokaz((*elem).next);
}
}
1 sty 21:45
Dziadek Mróz:
W rekurencji musisz pilnować warunku stopu bo inaczej będziesz krążył w nieskończonej
rekurencji
1 sty 21:46
Dziadek Mróz:
tam jest:
elem−>next = nowy; // (*elem).wart = nowy;
1 sty 21:52
Mariusz:
Ja podejrzałem kod innej funkcji rekurencyjnej i miałem pomysł aby funkcja zwracała
wskaźnik na głowę zmienionej listy bo
dodanie drugiego wskaźnika skompilkowałoby rekurencyjne wywołanie
a referencja wchodzi dopiero w C++
1 sty 22:01
Mariusz:
https://matematykaszkolna.pl/forum/340043.html
Kod funkcji na podstawie którego wpadłem na pomysł aby funkcja zwracała wskaźnik
na zmienioną głowę listy
Czy aby na pewno po wyjściu z funkcji zmieni nam listę ?
Dlaczego w podejściu iteracyjnym jest podwójny wskaźnik
1 sty 22:29
Dziadek Mróz:
Taka funkcja zwraca pojedynczy węzeł. A co będzie do niego podpięte to inna sprawa. Jak
napiszesz kod tak będzie wyglądała lista. Najprostszy sposób to kartka, ołówek i rozpisanie
każdego kroku
1 sty 22:39
Mariusz:
W iteracyjnym podejściu jest podwójny wskaźnik , po co on jest ?
Gdybyśmy chcieli dać w funkcji rekurencyjnej podwójny wskaźnik
to jak wyglądałoby rekurencyjne wywołanie
Gdy zmieniłem tę funkcję tak aby zwracała wskaźnik na głowę zmienionej listy to działa
ale napisałem to na wzór innej funkcji rekurencyjnej bez pewności że pomysł zadziała
W Pascalu jest słówko var po którym procedurę można przepisać słowo w słowo i działa
1 sty 22:51
Dziadek Mróz:
Pokaż mnie fragment kodu bo nie wiem jak chcesz użyć taki podwójny wskaźnik
int d = 10
int *ptr1 = &d;
int **pptr1 = &ptr1;
1 sty 22:54
Mariusz:
lista* dodaj(lista *l,int nowy)
{
lista* wynik=NULL;
if(l!=NULL)
{
wynik=l;
wynik−>nast=dodaj(l−>nast,nowy);
}
else
{
wynik=(lista*)malloc(sizeof(lista));
wynik−>wart=nowy;
wynik−>nast=NULL;
}
return wynik;
}
void pokaz(lista *l)
{
if(l!=NULL)
{
printf("%i ",l−>wart);
pokaz(l−>nast);
}
}
Pomysł który powinien zadziałać
1 sty 22:57
Mariusz:
void dodaj(lista** l,int nowy)
{
lista* p;
lista* e;
e=(lista*)malloc(sizeof(lista));
e−>wart=nowy;
e−>nast=NULL;
p=(*l);
if(p==NULL)
(*l)=e;
else
{
while(p−>nast!=NULL)
p=p−>nast;
p−>nast=e;
}
}
Dla wersji iteracyjnej pomysł z podwójnym wskaźnikiem działa
1 sty 23:01
Dziadek Mróz:
no dobrze, a gdzie jest ten podwójny wskaźnik?
1 sty 23:01
Mariusz:
Wersja rekurencyjna mogłaby chyba tak wyglądać
void dodaj(lista **l,int nowy)
{
if((*l)!=NULL)
{
dodaj(&((*l)−>nast),nowy);
}
else
{
(*l)=(lista*)malloc(sizeof(lista));
(*l)−>wart=nowy;
(*l)−>nast=NULL;
}
}
1 sty 23:13
Mariusz:
Funkcja pokaż ma tylko wskaźnik na głowę jako parametr
natomiast funkcja dodaj albo zwraca wskaźnik na głowę albo
jej parametr ma jeszcze dodatkowy wskaźnik , nie widzisz tego ?
Dlaczego jest ten podwójny wskaźnik
1 sty 23:25
Mariusz:
Do pary przydałaby się rekurencyjna funkcja usun
3 sty 04:16
Mariusz:
Napisałem taką funkcję usuń ale nie wiem czy dobrze działa
void usun1(lista **l)
{
if((*l)!=NULL)
{
if((*l)−>nast==NULL)
{
free((*l));
(*l)=NULL;
}
else
{
usun1(&((*l)−>nast));
}
}
}
lista* usun2(lista *l)
{
lista* wynik=NULL;
if(l!=NULL)
{
if(l−>nast==NULL)
{
free(l);
wynik=NULL;
}
else
{
wynik=l;
l−>nast=usun2(l−>nast);
}
}
return wynik;
}
3 sty 18:57