Ukázka odstranění rekurze Přemysl Tišer Ackermannova funkce Ukázka odstranění rekurze Přemysl Tišer
Definice A(0,n)=n+1 A(m,0)=A(m-1,1) A(m,n)=A(m-1,A(m,n-1)) v ostatních případech
Návrh shora dolů Zdánlivě jednoduchá rekurzivní definice vede na jednoduchý rekurzivní algoritmus: public static int ackRek(int m, int n) { if (m==0) return n+1; // programátorská hrůza if (n==0) return ackRek(m-1,1); return ackRek(m-1, ackRek(m, n-1)); }
Problémy s rekurzí Každé volání funkce téměř vždy znamená další dvě volání Možnosti počítače se vyčerpají již při nízkých hodnotách m,n Počet volání roste zhruba jako 4n, což pro n=8 dává 2785999 Pozn.: Pro A(4,1) program skončil přetečením zásobníku
Odstranění rekurze I Na začátku funkce definujeme zásobník pro ukládání parametrů Použijeme jeden cyklus pro vkládání parametrů, druhý pro odebírání parametrů, pro které již byla Ackermannova funkce spočítána Oba cykly se budou podle potřeby střídat
Odstranění rekurze II Na vrchol zásobníku vždy uložíme hodnoty m, n, pro které budeme potřebovat provést výpočet Po zpracování vrcholu zásobníku, parametry na tomto vrcholu odebereme Jakmile se vrátíme na první vložený záznam, spočítáme výsledek funkce a skončíme
Odstranění rekurze III Hodnotu n, kterou bude teprve potřeba spočítat, budeme reprezentovat číslem -1, které bude po provedení výpočtu nahrazeno správnou hodnotou
Algoritmus I Konkrétní řešení lze nalézt v přiloženém kódu ackRek používá rekurzi ackermann využívá výše popsaný způsob Uvedený algoritmus je pouze polotovar, lze vylepšit tak, aby zbytečně neukládal na zásobník parametry m,n, pro které je již Ackermannova funkce spočítána. Takto je ponechá pro větší názornost.
Algoritmus II Jako zásobník používám z lenosti ;o) dvě pole mZas a nZas, pro ukládání výsledků dvourozměrné pole pomTab. Použitá literatura: Miroslav Virius: Základy algoritmizace, skriptum ČVUT