Libreria personale C funzione ricorsiva

di il
11 risposte

Libreria personale C funzione ricorsiva

Buonasera a tutti,
in una libreria personale in ANSI C è presente la seguente funzione iterativa, dove nella posizione 0 dell'array è presente il numero di double presenti nell'array e nelle posizioni successive i rispettivi valori. I parametri d'ingresso ed uscita non sono modificabili.
Com'è possibile renderla una funzione ricorsiva?
int function(double number, double *set)
{
  int i, incl=0;
  
  for (i=1; i<=set[0]; i++)
  {
    if(number==set[i])
    {
      incl=1;
    }  
  }
  return(incl);
}
ho provato con questa strada ma non sta in piedi
int function(double number, double *set)
{
  int i=set[0], incl=0;      
  if(number==set[i])
  {
    incl=1;    
  }
  else
  {  
    incl=function(number, &set[0]);
  }
  return(incl);
}
Grazie

11 Risposte

  • Re: Libreria personale C funzione ricorsiva

    Idea giusta, implementazione sbagliata.

    Riparti dal concetto di funzione ricorsiva e da come si fa una dimostrazione mediante il principio di induzione
  • Re: Libreria personale C funzione ricorsiva

    Il problema del tuo codice è che ricominci ogni volta da
    i=set[0]
    il che rende la ricorsione non-convergente: la funzione terminerà solo nel caso number==set[0].
    Devi aggiungere una funzione supplementare che abbia tra i parametri anche il valore corrente di i.
    Come alternativa puoi passare una versione diversa (ad esempio con un elemento in meno, cioè l'ultimo confrontato) di set ad ogni chiamata ricorsiva (il che comporta riscrivere l'array set in un array temporaneo ad ogni chiamata ricorsiva).
    Secondo me la funzione aggiuntiva è l'unica soluzione a costo decente (e con meno rischi di sfondare l'heap).
  • Re: Libreria personale C funzione ricorsiva

    Un paio di considerazioni:
    - nella versione iterativa non sempre c'è bisogno di scorrere interamente l'array;
    - confrontare due valori in virgola mobile con un'uguaglianza non è quasi mai una buona idea.
  • Re: Libreria personale C funzione ricorsiva

    Dopo 4 ore non riesco ancora ad implementarla...
    Grazie comunque per tutti i consigli
  • Re: Libreria personale C funzione ricorsiva

    La soluzione più semplice è quella prospettata da @Andrea Quaglia relativamente ad una funzione supplementare, oppure equivalentemente potresti usare una variabile globale o statica.

    In ogni caso ragionando un po' sul problema sono arrivato alla seguente soluzione che non fa uso di altre funzioni o variabili e che non rischia di "sfondare l'heap":
    bool fun(int *v, int n)
    {
        if(!v[0] || v[v[0]] == n)
        {
            return v[0];
        }
        return fun(&(--v[0]), n) * ++v[0];
    }
    Il trucco è quello di decrementare v[0] nella fase di "andata" della ricorsione e di incrementarlo in quella di "ritorno".
  • Re: Libreria personale C funzione ricorsiva

    Scusami ma ancora non comprendo ciò che hai fatto ed in una funzione posso usare solo 1 return.

    Questo ragionamento potrebbe funzionare?
    Grazie
    Funzione(numero, insieme)
    appartiene=0
    {
      se(numero==insieme [ultpos])
      {
        appartiene=1;    
      }
      altrimenti
      {  
        se([ultpos]==0)
        {
          appartiene=0;    
        }
        altrimenti
        {
          Funzione(numero, [ultpos]-1) 
        }
      }
      return(Appartiene);
    }
  • Re: Libreria personale C funzione ricorsiva

    Nippolo ha scritto:


    La soluzione più semplice è quella prospettata da @Andrea Quaglia relativamente ad una funzione supplementare, oppure equivalentemente potresti usare una variabile globale o statica.

    In ogni caso ragionando un po' sul problema sono arrivato alla seguente soluzione che non fa uso di altre funzioni o variabili e che non rischia di "sfondare l'heap":
    bool fun(int *v, int n)
    {
        if(!v[0] || v[v[0]] == n)
        {
            return v[0];
        }
        return fun(&(--v[0]), n) * ++v[0];
    }
    Il trucco è quello di decrementare v[0] nella fase di "andata" della ricorsione e di incrementarlo in quella di "ritorno".
    Ciao, ho provato di nuovo a capire la tua funzione, mi ritrovo in difficoltà in quanto su ANSI C non è presente il tipo bool e nella seconda return
    return fun(&(--v[0]), n) * ++v[0];
    il compilatore mi riporta l'errore:
    error: lvalue required as unary â&â operand
         return fun(&(--v[0]), n) * ++v[0];
    non posso utilizzare variabili globali e più di una funzione return nella stessa funzione.

    Comunque grazie per il supporto, provo a seguire la strada della funzione supplementare consigliata da Andrea
  • Re: Libreria personale C funzione ricorsiva

    Scusami ma ancora non comprendo ciò che hai fatto
    Innanzitutto per semplificare il tutto ho utilizzato un array di interi, visto che, come già detto nell'altro post, non ha quasi mai senso fare
    double1 == double2.
    Infatti per valutare l'uguaglianza tra due valori in virgola mobile si ricorre di solito a qualcosa del genere
    |double1-double2|<€
    dove € è l'errore relativo ritenuto accettabile.

    bool è un tipo che può assumere solo due valori: true (corrispondente a 1) e false (corrispondente a 0). Nel casting da int a bool, tutti i valori diversi da 0 vengono convertiti in true, mentre 0 viene convertito in false.

    Per quanto riguarda la condizione dell'if (ti faccio notare che !v[0] coincide con v[0]==0):
    - se risulta falsa si verifica un'ulteriore chiamata ricorsiva (ossia fun(&(--v[0]), n));
    - se risulta vera il processo ricorsivo si interrompe e viene ritornato (return v[0]) la conversione in bool (essendo bool il tipo di ritorno della funzione) dell'intero costituito da v[0]. In particolare:
    * v[0]==0 (ossia l'array non contiene alcun elemento uguale ad n) ==> return 0;
    * v[v[0]]==n (ossia l'array contiene almeno un elemento uguale ad n) ==> return 1.

    Concentriamoci ora sulla chiamata ricorsiva fun(&(--v[0]), n). In pratica gli passo sempre lo stesso array, infatti l'identificatore dell'array v coincide con l'indirizzo di memoria (che prelevo con l'operatore &) del primo elemento (ossia v[0]), ma ad ogni chiamata ricorsiva diminuisco di 1 (--v[0]) il valore del primo elemento, in modo che vado a considerare tutti gli elementi dell'array a partire dall'ultimo fino al secondo (ossia v[1]).

    Consideriamo infine l'espressione return fun(&(--v[0]), n) * ++v[0]. Essa ritornerà lo stesso valore ritornato dal return all'interno dell'if, infatti considerando che ++v[0] assumerà valori che vanno da 1 fino al valore originale di v[0] (pari al numero di elementi dell'array -1) avremo che:
    - se l'if ritorna 0 allora return fun(&(--v[0]), n) * ++v[0] ritornerà sempre 0, in quanto il prodotto tra 0 e un numero positivo è uguale a 0;
    - se l'if ritorna 1 allora return fun(&(--v[0]), n) * ++v[0] ritornerà sempre 1, in quanto il prodotto tra 1 e un numero positivo è uguale ad un numero positivo che convertito in bool restituisce 1.
    Lo scopo di moltiplicare per ++v[0] è quello di incrementare nella fase di "ritorno" della ricorsione il valore di v[0] decrementato nella fase di "andata".
    ed in una funzione posso usare solo 1 return.
    E come mai?!
    In ogni caso non sarebbe difficile aggiustare il tiro:
    bool fun(int *v, int n)
    {
        bool flag = v[0];
        if(flag && v[v[0]] != n)
        {
            flag = fun(&(--v[0]), n) * ++v[0];
        }
        return flag;
    }
    Questo ragionamento potrebbe funzionare?
    Prova a tradurlo in codice e ti faccio sapere, anche se ho qualche dubbio al riguardo... il problema è che ti serve cmq un altro argomento o variabile statica/globale che tenga conto di quella che tu chiami ultpos!
    Ciao, ho provato di nuovo a capire la tua funzione, mi ritrovo in difficoltà in quanto su ANSI C non è presente il tipo bool
    Premesso che non so di preciso cosa si intenda con ANSI C, non è comunque difficile simulare il tipo bool con un int, ti faccio inoltre presente che esiste la libreria stdbool.h per utilizzare i valori booleani anche nel C.
    il compilatore mi riporta l'errore:
    ...
    Non saprei, devo pensarci!
    Magari qualcun altro ti saprà rispondere.
    non posso utilizzare variabili globali e più di una funzione return nella stessa funzione.

    Comunque grazie per il supporto, provo a seguire la strada della funzione supplementare consigliata da Andrea
    Ok, nel caso dopo ci penso e ti posto qualche "input".
  • Re: Libreria personale C funzione ricorsiva

    Nippolo ha scritto:


    Premesso che non so di preciso cosa si intenda con ANSI C
    Questo link lo spiega sicuramente meglio di me
    https://en.wikipedia.org/wiki/ANSI_

    comunque per mettermi nella modalità ansi compilo in questo modo il sorgente:
    gcc -ansi -Wall -O programma.c -o programma
  • Re: Libreria personale C funzione ricorsiva

    Devo dire la verità... con tutte le cose che ho scritto mi sarei aspettato un commento un po' più "tecnico" e che entrasse maggiormente nel merito della questione!

    In realtà mi ero già imbattuto in quel link cercando "ANSI C" su google, ma ho lasciato perdere perché l'argomento non mi appassionava per nulla!

    Per quanto riguarda la questione della funzione ausiliaria, qualcosa del genere andrebbe bene?
    int fun(int *v, int n, unsigned int last)
    {
        ...
    }
    
    int Fun(int *v, int n)
    {
        return fun(v, n, v[0]);
    }
    
    int main()
    {
        ...
        cout << Fun(v, n);
        ...
    }
  • Re: Libreria personale C funzione ricorsiva

    Sì scusami, ti ho scritto velocemente appena ho visto la tua risposta quando in realtà non avevo tempo per farlo in maniera più approfondita.
    ANSI C è il linguaggio che normalmente viene insegnato in alcune università in quanto viene considerato il primo standard riconosciuto di questo linguaggio ed è noto per insegnare un approccio razionale allo sviluppo di programmi per un primo corso di programmazione.
    Questo consente di avere delle basi per poi approcciare tutti gli altri linguaggi, da esso derivati, partendo sempre dal presupposto che con i comandi base e le sue librerie standard, presenti nell'ANSI C si riesce comunque a sviluppare tutta la parte fondamentale in maniera completa.

    Ora provo ad implementare la funzione ausiliaria come da te indicato, poi ti faccio sapere l'esito.
    Grazie
Devi accedere o registrarti per scrivere nel forum
11 risposte