Programarea Calculatoarelor: Laborator 4

Vom trata același tip de probleme cu prelucrări repetitive, făcând trecerea de la rezolvarea recursivă la cea iterativă. E important să învățăm de asemenea descompunerea unei probleme în subprobleme mai mici, folosind decizia și secventierea. Exemple:

Discutăm în continuare scrierea recursivă și iterativă a problemei prezentate la curs, de citire a unui întreg. Scriem întâi ambele funcții cu doi parametri: caracterul curent și valoarea parțial calculată:

#include <ctype.h>
#include <stdio.h>
int readint_r(int c, int val)
{
  return isdigit(c) ? readint_r(getchar(), 10*val + (c - '0'))
                    : val;
}

int readint_it(int c, int val)
{
  while (isdigit(c)) {
    val = 10 * val + (c - '0');
    c = getchar();
  }
  return val;
}
int main(void)
{
  printf("%d\n", readint_r(getchar(), 0));
  printf("%d\n", readint_it(getchar(), 0));
  return 0;
}
Prelucrarea se efectuează la fel în ambele funcții, cu aceeasi secvență la fiecare pas:
-- se testează valoarea caracterului curent
-- dacă acesta nu e cifră, prelucrarea se încheie și se returnează valoarea curentă calculată
-- dacă acesta e cifră, se actualizează valoarea curentă calculată, și se citește următorul caracter
Diferă modul în care se exprimă repetiția acestui pas. În varianta recursivă, valorile actualizate (pentru caracterul nou citit și numărul calculat) sunt transmise ca argumente la un nou apel al aceleiași funcții -- care va efectua deci aceeași prelucrare ca și apelul curent, însă lucrând cu noile valori transmise ca argumente. Remarcăm faptul că funcția nu conține atribuiri, nici pentru c, nici pentru val, fiind suficientă transmiterea de parametri. Varianta nerecursiva exprimă repetiția prin intermediul instructiunii while, care revine la test după ce a executat corpul său. Următorul pas de prelucrare se execută cu noi valori pentru val si c, întrucât aceastea au fost atribuite în corpul instrucțiunii.
Valorile inițiale pentru caracter (primul caracter citit), și numărul calculat (0) se transmit la fel în ambele cazuri. Valoarea finală e returnată direct în cazul iterativ; în cazul recursiv, ea returnată pe ramura de "fals" din ultimul apel făcut, si transmisă mai departe până la primul apel, deoarece pe ramura de "adevărat" funcția e scrisă să returneze valoarea calculată în următorul apel recursiv pe care l-a generat.

Putem rescrie funcțiile transformând caracterul din parametru în variabilă locală, iar pentru varianta nerecursivă, și valoarea calculată. Structura codului se modifică minimal, reflectând faptul că trebuie acum citită în funcție valoarea caracterului, înainte de a fi testată, și funcțiile au mai puțini parametri. În varianta iterativă, val trebuie inițializată cu aceeași valoare (0) pe care o primea anterior la primul apel.

#include <ctype.h>
#include <stdio.h>
int readint_r(int val)
{
  int c;
  c = getchar();
  return isdigit(c) ? readint_r(10*val + (c - '0')) : val;
}

int readint_it()
{
  int c, val = 0;
  c = getchar();
  while (isdigit(c)) {
    val = 10 * val + (c - '0');
    c = getchar();
  }
  return val;
}

int main(void)
{
  printf("%d\n", readint_r(0));
  printf("%d\n", readint_it());
  return 0;
}

Marius Minea
Last modified: Sun Mar 54 17:38:25 EET 2006