关于阿克曼函数(akermann)非递归算法的一点见解 c++
關(guān)于阿克曼函數(shù)(akermann)非遞歸算法的一點(diǎn)見解
- 0
- 阿克曼函數(shù)的形式
- 分析
- 如何寫代碼
- 解決辦法
- 代碼
- 1
0
這個星期,數(shù)據(jù)結(jié)構(gòu)與算法的陳老師布置了一道題目,要求用非遞歸的算法計(jì)算阿克曼函數(shù)。在百度上找了很多個網(wǎng)址,都沒有找到我想要的答案。于是,在我做出來之后,打算與大家分享一下我自己的想法。不足之處,請多多指教!
阿克曼函數(shù)的形式
如下圖是我從《數(shù)據(jù)結(jié)構(gòu)與程序設(shè)計(jì)》翻譯版描述的阿克曼函數(shù)。
看到阿克曼函數(shù)的這個形式,毫無疑問第一個想到的肯定是用遞歸的算法。但是如果不用遞歸的算法,事情就變得麻煩起來了。
分析
說到用其它的算法代替遞歸算法,大部分第一個想到的肯定是使用循環(huán),我第一個想到的也是循環(huán),這是正確的。但是這個問題比較特殊,特殊之處就在于它的問題的出現(xiàn)是線性的。也就是說,你想要解決上一個問題,你只需要解決這一個問題;你想要解決這一個問題,你只需要解決下一個問題。注意我這里的用詞:只需要!!!遞歸的實(shí)現(xiàn)其實(shí)就是一個堆棧出棧的過程。
下面就以計(jì)算A(2,1)的例子分析。如下圖。
(注:這個圖上的元素應(yīng)該從下往上看,像堆棧一樣)
如圖,我們要解決A(2,1),就得解決A(1,A(2,0));要解決A(1,A(2,0)),就得解決A(2,0)… 以此類推,直到我們得到一個m=0的元素A(0,1),A(0,1)解決了之后,它的結(jié)果可以一直回到原來要解決的問題A(1,A(2,0)),也即是A(1,3)。往后同樣分析,要解決A(1,3),就得先解決A(0,A(1,2));要解決A(0,A(1,2)),就得先解決A(1,2)…直到我們最終推出A(2,1)的結(jié)果為止,最終的結(jié)果是5。
如何寫代碼
從上面的分析,我們可以發(fā)現(xiàn):
(1)每一個需要計(jì)算的元素是一個個向上地堆棧,直到遇到m=0的情況,此時A(0,n)可以計(jì)算出一個整數(shù),之后就是出棧的操作。
(2)A(m,A(m1,m2)),這種情況在棧中是比較特殊的情況,當(dāng)這里的m=0時,棧就能繼續(xù)出棧了;但是m≠0的時候,我們還得繼續(xù)向上堆棧。
解決辦法
(1)聲明兩個棧s1、s2。
s1存儲m
s2存儲n
(2)遇到A(m,A(m1,m2))這種情況的時候,將n存儲為-1,這是為了后面出棧的算法能夠識別特殊情況,并且做出相應(yīng)的處理。
(3)聲明m和n,用于動態(tài)存儲并操作m值和n值,這是因?yàn)樵?#xff08;2)的要求下,n可能在棧s2中存為-1,此時存儲的值是一個待定值。
代碼
#include<iostream> #include<stack> using namespace std; int asker(int m, int n) {stack<int> s1;stack<int> s2;s1.push(m);s2.push(n);while (!s1.empty()){while (m != 0){if (n == 0){m = m - 1;n = 1;s1.push(m);s2.push(n);}else{n = n - 1;s1.push(m - 1);s2.push(-1);}}n = n + 1;while ((!s1.empty())&& (s2.top() != -1)){s1.pop();s2.pop();}if(!s1.empty()){m = s1.top();s2.pop();s2.push(n);}}return n; } void main() {cout << asker(2, 1); }1
這是我第一次寫博客,有很多不足之處。代碼是趕出來的,所以會有很多地方使用不當(dāng),請大家?guī)臀抑赋鲥e誤!
總結(jié)
以上是生活随笔為你收集整理的关于阿克曼函数(akermann)非递归算法的一点见解 c++的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机号段199/198/166,横空出世
- 下一篇: 李宏毅机器学习 之 机器学习介绍(一)