C++

Рекурсията в C++6

Рекурсията в C++
(0 от 0 гласували)

 

 

Рекурсията

Непряка рекурсия.
    Ако една функция
f1 вика друга функция f2, а втората функция f2 вика първата f1, казваме, че има непряка рекурсия.
     Пример. Хилбертови криви.
    Хилбертова крива от 1-ви ред H1 се получава като се чертае наляво - надолу - надясно единичната отсечка. H2 се състои от 4 криви H1 намалени наполовина, първата завъряна на +90, втората отместена на 1/2 наляво,  третата отместена на 1/2 надясно и четвъртата завъртяна на -90 градуса и отместена 1/2 надясно. По същия начин е получена и кривата от 3-ти ред H3 от H2. Процесът може да продължи с получаване на H4, H5 и т. н. Има 4 елемента A, B, C и D, от които се състои всяка крива. За да напишем рекурсията, нека предположим, че можем да чертаем тези елементи и отсечки като "костенурка-графика":
- left - наляво;
- down - надолу;
- right - надясно;
- up - нагоре
с дължини 1/n за кривата Hn.

Получаваме следната схема на рекурсията:
A: left,  down, right -> D left  A down  A right B
B: up,    right,down  -> C up    B right B down  A
C: right, up,   left  -> B right C up    C left  D
D: down, left,  up    -> A down  D left  D up    C
Остава да се реализира "костенурка-графика", което може да се направи с познатата графична библиотека.
    Програма за чертаене на Хилбертови криви.
// hilbert.cpp
#include "ccc_win.cpp"

int h = 512;    /* дължината на "единичната" отсечка   */
int xold, yold; /* текущи координати на "костенурката" */
int x, y;       /* нови координати на "костенурката"   */

void Hilbert();
void A(int i);
void B(int i);
void C(int i);
void D(int i);

void plot()
/* ЦЕЛ: реализира "костенурка-графика" -
   чертае отсечка, свързваща точките (xold, yold) и (x,y)в
*/
{ Line l(Point(x,y), Point(xold, yold));
  cwin << l;
  xold = x;  yold = y;
}

void Hilbert()
{ int i = 0;
  int x0 = h/2, y0 = h/2;
  do
  { i++; h /= 2;
    x0 += h/2; y0 += h/2;
    xold = x = x0; yold = y = y0;
    A(i);
  }
  while (i < 5);
}

void A(int i)
{ if (i == 0) return;
  D(i-1); x -= h; plot();
  A(i-1); y -= h; plot();
  A(i-1); x += h; plot();
  B(i-1);
}
void B(int i)
{ if (i == 0) return;
  C(i-1); y += h; plot();
  B(i-1); x += h; plot();
  B(i-1); y -= h; plot();
  A(i-1);
}
void C(int i)
{ if (i == 0) return;
  B(i-1); x += h; plot();
  C(i-1); y += h; plot();
  C(i-1); x -= h; plot();
  D(i-1);
}
void D(int i)
{ if (i == 0) return;
  A(i-1); y -= h; plot();
  D(i-1); x -= h; plot();
  D(i-1); y += h; plot();
  C(i-1);
}

int main()
{ cwin.coord(0, h, h, 0);
  Hilbert();
  return 0;
} 
 

Ефективност на рекурсията.
* Числа на Фибоначи.
    Рекурсията е мощен инструмент за реализиране на ефективни алгоритми. В някои случаи обаче, тя може да доведе до лошо работещи алгоритми. Такъв е случаят с алгоритъма за пресмятане на числата на Фибоначи  fi, които се дефинират рекурентно така:

f1 f2 = 1 и  fi fi - 1 fi - 2 за  i = 3, 4, ... .

Рекурсивна функция за пресмятане на n-тото число на Фибоначи се пише лесно точно по рекурентната формула. Ще измерваме и времето за работа на тази функция.
// fibtime.cpp
#include <iostream>
using namespace std;
#include "ccc_time.cpp"

long fib(int n)
{ if (n <= 2) return 1;
  else return fib(n - 1) + fib(n - 2);
}

int main()
{ cout << "Enter n: ";
  int n;
  cin >> n;
  Time before;
  long f = fib(n);
  Time after;
  cout << "fib(" << n << ") = " << f << "\n";
  cout << "Elapsed time = " << after.seconds_from(before)
       << " seconds\n";
  return 0;
}

Enter n: 30
fib(30) = 832040
Elapsed time = 2 seconds

    Поставяме трасиращи печати във функцията, за да видим колко пъти се извиква функцията.
// fibtrace.cpp
#include <iostream>
using namespace std;

long fib(int n)
{ cout << "Entering fib: n = " << n << "\n";
  long f;
  if (n <= 2) f = 1;
  else f = fib(n - 1) + fib(n - 2);
  cout << "Exiting fib: n = " << n
       << " return value = " << f << "\n";
  return f;
}

Рекурсията в C++

Коментари