Ricorsione in C

di il
43 risposte

Ricorsione in C

Buongiorno, devo scrivere una funzione ricorsiva che mi ritorni 1 se una stringa è in ordine alfabetico, 0 altrimenti. Ho analizzato il problema in questo modo, considerando il confronto tra i codici ascii dei caratteri. Il programma mi restituisce pero sempre 0. Quale potrebbe essere il problema?
#include <stdio.h>
#include <string.h>
int fun(int a, int b)
{
if(a<b)return 1;
else return 0;
}
int fun2(char *s)
{
int l;
l=strlen(s);
if (l==1)return 1;
return fun(s[0], fun2(s+1));
}

43 Risposte

  • Re: Ricorsione in C

  • Re: Ricorsione in C

    In generale tutte le 'ricorsioni' verrebbero meglio come 'iterazioni'

    Ci sono comunque casi nei quali il programma risulta più 'elegante' in forma ricorsiva che in forma iterativa

    Questo non è uno di quei casi

    Qui sarebbe meglio farlo iterativo
    Ma se la prescrizione è cogente si può fare anche ricorsivo, con una sola funzione, oltre naturalmente alla main ()

    Basta ragionare 'easy' è ricordarsi che avanzare di 1 un puntatore sembra 'accorciare' la stringa
  • Re: Ricorsione in C

    StandardOil ha scritto:


    In generale tutte le 'ricorsioni' verrebbero meglio come 'iterazioni'
    Affermazione MOOOOOLTO tirata per i cappelli.

    ""meglio"" non direi proprio!!!!

    E' VERO che un'implementazione ricorsiva PUO' essere fatta ANCHE in modo iterativo E VICEVERSA,

    MA ...

    c'e' un bel MA di mezzo !!!!

    Ed il MA consiste nel gestirti A MANO lo stack!

    @ProgrammaGat, LASCIA PERDERE i puntatori, RAGIONA SOLO in termini di

    1) VETTORE, di cui hai il puntatore MA di questo non ne puoi fare a meno
    2) LUNGHEZZA del vettore
    3) INDICE all'interno del vettore

    RICORDA come si definisce una funzione ricorsiva:

    1) serve la BASE della ricorsione
    2) serve un passo che combini un'operazione sul vettrore corrente ed una su un vettore che e' UN ELEMENTO PU' PICCOLO di quello corrente!
  • Re: Ricorsione in C

    Non le metto, le due soluzioni
    Una iterativa e una ricorsiva
    Per non dare la pappa fatta

    Ma le mie non sono ipotesi,
    Sono affermazioni comprovate

    Ho ancora da vedere una soluzione ricorsiva più veloce e meno esosa di memoria della corrispondente iterativa

    Di contro fare iterativamente la torre di Hanoi non è una passeggiata

    Ricorsivamente è una banalità
  • Re: Ricorsione in C

    @StandardOil se non hai ancora visto

    una soluzione ricorsiva piu' veloce e meno esostadella corrispondente iterativa

    non e' certo colpa mia

    In ogni caso, se fatte con COGNIZIONE DI CAUSA, le due soluzioni SONO PERFETTAMENTE EQUIVALENTI in termini di TUTTO!!!
    E questa NON E' un'ipotesi, MA

    1) UN TEOREMA (ad esempio )
    2) buon senso (se lo stack serve, SERVE ANCHE nell'implementazione iterativa, SE NON SERVE, non serve NEMMENO in quella ricorsiva)
    3) 50 anni di linguaggi di programmazione funzionali (tail recursion, ad esempio)
  • Re: Ricorsione in C

    Lo prendo per buono, grazie


    Rimane il fatto che la soluzione iterativa al problema dello OP è più semplice di quella ricorsiva
  • Re: Ricorsione in C

    A me viene in mente

    ricorsiva
    
    int is_ordered(char * s){
        static int p = 0;
        if(s[p] == '\0'){
            p = 0;
            return 1;
        }else if (p < 1 || s[p] >= s[p - 1]){
            p++;
            return is_ordered(s);
        }else{
            p = 0;
            return 0;
        }
    }
    
    iterativa
    
    int is_ordered(char * s){
        int p = 0;
        while(s[p++] != '\0')
            if(p > 1 && s[p - 1] < s[p - 2])
                return 0;
        return 1;
    }
    
    Per me la prima andrebbe in stack overflow laddove la seconda continuerebbe, probabilmente non è così come dice migliorabile, ma a questo punto dipenderà dal compilatore
  • Re: Ricorsione in C

    @Weierstrass l'implementazione ricorsiva e' concettualmente SBAGLIATA.

    Una funzione ricorsiva NON DEVE AVERE side effects, cosa che invece ottieni con quel orrendo staticone del 'p'

    SUPPONENDO un ordine crescente
    
    	bool is_ordered(char* s, int p){ 
    		if (s[p] == 0 || s[p+1] == 0)
    			return true;
    		else if (s[p] > s[p+1])
    			return false;
    		else
    			return is_ordered(s,p+1);
    	}
    
    un buon compilatore la convertirebbe in un ciclo
  • Re: Ricorsione in C

    Stasera da casa metto qualcosa anch'io

    Ho idee....
  • Re: Ricorsione in C

    @ProgrammaGat in effetti non è semplicissimo ragionare in termini ricorsivi!

    In ogni caso ti faccio notare che per individuare la fine della stringa, sarebbe più efficiente sfruttare il carattere terminatore di stringa, piuttosto che richiamare la funzione strlen() ad ogni chiamata ricorsiva.

    Entrando nel merito del codice che hai postato:
    - innanzitutto una domanda: la stringa abbc è da ritenersi ordinata? Se sì, allora la condizione nella funzione fun() va aggiustata;
    - risulta evidente che la ricorsione si ferma soltanto quando viene raggiunto l'ultimo elemento della stringa, ma se ci pensi non avrebbe senso farlo per una stringa del tipo bacccccccccccccccccc, visto che già dopo il primo confronto saremo in grado di dire che non è ordinata. Questo ci porta a concludere che sono due i casi in cui la ricorsione deve arrestarsi:
    1) è stata raggiunta la fine della stringa;
    2) sono stati trovati due caratteri consecutivi non ordinati.
    - consideriamo poi la seguente chiamata ricorsiva presente in fun2():
    fun(s[0], fun2(s+1))
    se ci rifletti stai confrontando un carattere (ossia s[0]) con un valore logico (ossia fun2() che può ritornare soltanto 0 o 1)... è per questo motivo che il programma ti restituisce sempre 0.

    E dopo aver fornito degli spunti di riflessione per lo OP, posto anche io la mia versione
    int fun(char *s)
    {
        return s[0] && s[1] ? s[0] <= s[1] && fun(s + 1) : 1;
    }
  • Re: Ricorsione in C

    Sampei ci ha fatto il mazzo anche stavolta
  • Re: Ricorsione in C

    @nippolo, al contrario di weierstrass, non concordo sulla compattezza del codice.

    Ti stai rivolgendo a qualcuno che sa poco o niente di programmazione.
    Fare I giochi di prestigio con puntatori e caratteristice 'oscure' del linguaggio (oscure nel senso di NON ASSOLUTAMENTE CHIARE) se da una parte permette di scrivere del codice compatto, dall'altra parte non serve a nulla perche il compilatore e' in grado di fare di meglio, e rende oscuro al'autore il funzionamento dell'algoritmo.
  • Re: Ricorsione in C

    Come promesso metto qui una mia versione

    cominciamo con la versione iterativa:
    
    _Bool ordinatai(char * s)
    {
       // versione iterativa
       if(!s)
          return 0;
    
       while(*s <= *(s + 1))
          s++;
    
       return !(*(s + 1));
    }
    
    se si escludono le prime due righe, che sono per pura sicurezza, servono per il caso che venga passato un puntatore nullo, caso che non dovrebbe accadere se si usa un array di caratteri

    dicevo, se si escludono le prime due righe, si vede che rimane molto poco nel corpo della funzione

    il funzionamento?

    semplicissimo,
    essendo la stringa terminata da uno zero
    e dovendo determinare se è crescente oppure no

    ho unito i due concetti:

    appena de-cresce
    delle due l'una
    o è uno zero, stringa finita, ovvero era tutta crescente
    oppure non è uno zero, stringa non finita non era tutta crescente
    basta negare l'ultimo carattere esaminato.......

    non credo, qualunque cosa dica il teorema citato in precedenza, che una soluzione ricorsiva possa essere più breve di questa, usando un linguaggio come il C

    non conosco altri, e non mi esprimo



    PS
    Nippolo è tra i miei ignorati

    Non so cosa abbia scritto ne mi interessa saperlo

    Ignorati certamente

    Maledetto correttore
  • Re: Ricorsione in C

    @StandardOil: una versione ricorsiva NON E' piu' compatta di una iterativa o piu' veloce, E' COMPATTA COME ed E' VELOCE COME!!!!

    Il teorema di cui sopra dice che OGNI funzione ricorsiva SI PUO' SEMPRE convertire in una iterativa, ed OVVIAMENTE e' vero ANCHE il viceversa (la coversione da iterativo a ricorsivo E' BANALE).

    (Certo che una letta c'e' la potevi anche dare )

    Nota: NON E' "ignoraNti" ma "ignorati" Almeno spero
Devi accedere o registrarti per scrivere nel forum
43 risposte