日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【经典算法实现 15】阿克曼函数(非递归实现)

發(fā)布時(shí)間:2023/12/14 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【经典算法实现 15】阿克曼函数(非递归实现) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

【經(jīng)典算法實(shí)現(xiàn) 15】阿克曼函數(shù) -- 非遞歸實(shí)現(xiàn)

    • 一、阿克曼函數(shù) -- 非遞歸實(shí)現(xiàn)

在前面《【經(jīng)典算法實(shí)現(xiàn) 14】阿克曼函數(shù)(手動(dòng)推導(dǎo)求解、遞歸實(shí)現(xiàn)、非遞歸實(shí)現(xiàn))》 中,
我們實(shí)現(xiàn)了阿克曼函數(shù)的手動(dòng)推導(dǎo)及遞歸實(shí)現(xiàn)代碼,
在本文中,我們來研究下它的非遞歸實(shí)現(xiàn)。


其遞歸代碼為:

long ack(int m,int n) {if(m == 0){return n+1;}else if(n == 0){return ack(m - 1, 1);}else{return ack(m - 1, ack(m, n - 1));} }

一、阿克曼函數(shù) – 非遞歸實(shí)現(xiàn)

由于阿克曼函數(shù)中,每計(jì)算一個(gè)數(shù),其都高度依賴前一個(gè)數(shù)計(jì)算的結(jié)果,
因此在本非遞歸實(shí)現(xiàn)的思路,其實(shí)和遞歸差不多,利用棧來實(shí)現(xiàn)。

由于在C 語言中,操作棧比較麻煩,我們此處,就用單向循環(huán)鏈表來模擬棧。
以鏈表的頭指針作為棧頂, 每次入棧就是向鏈表頭部插入一個(gè)元素,出棧就是從鏈表頭部刪除一個(gè)元素

具體實(shí)現(xiàn)如下:

#include <stdio.h>// 單向循環(huán)鏈表定義 typedef struct ListNode{long long value;struct ListNode *next; }ListNode, *LinkList;// 定義兩個(gè)List 分別存儲(chǔ) m 和 n 的值. LinkList m_ListHead; LinkList n_ListHead; int is_Empty(LinkList ListHead){/*int count=0;LinkList List_tmp=ListHead->next;while(List_tmp != ListHead){count++;List_tmp = List_tmp->next; } printf("當(dāng)前鏈表元素個(gè)數(shù) %d\n",count);*/// 單向循環(huán)鏈表next 等于自身時(shí),為空 if(ListHead->next == ListHead){return 1;}return 0; }// 入棧,使用頭插法插入元素 void push(LinkList ListHead, long long num){LinkList List_tmp;List_tmp = (LinkList)malloc(sizeof(struct ListNode));List_tmp->value = num;List_tmp->next = ListHead->next;ListHead->next = List_tmp; }// 出棧, 從頭部刪除元素 void pop(LinkList ListHead){LinkList List_tmp;if( !is_Empty(ListHead) ){List_tmp = ListHead->next;ListHead->next = List_tmp->next;free(List_tmp); // 釋放元素} }void clear_List(LinkList ListHead){int count=0;LinkList List_tmp=ListHead->next;while(List_tmp != ListHead){ListHead->next = List_tmp->next;free(List_tmp);List_tmp = ListHead->next;count++;} printf("\n釋放了%d個(gè)鏈表元素!!!\n", count); }// 阿克曼函數(shù)實(shí)現(xiàn) long long ack(long long m, long long n) {push(m_ListHead, m); // 將 m 入棧push(n_ListHead, n); // 將 n 入棧while( !is_Empty(m_ListHead) ) // 判斷 m 鏈表是否為空{// m != 0時(shí),入棧 while(m != 0){if(n == 0){printf("[%s][%4d] 當(dāng)前m=%lld, n=%lld, 即將入棧m-1=%lld, n=1 \n", __func__, __LINE__, m, n, m-1); m = m-1;n = 1;push(m_ListHead, m); // 將 m 入棧push(n_ListHead, n); // 將 n 入棧}else{// 使用 -1 代表 ack(m - 1, ack(m, n - 1)); 的情況 printf("[%s][%4d] 當(dāng)前m=%lld, n=%lld, 即將入棧m-1=%lld, n=-1 \n", __func__, __LINE__, m, n, m-1); n = n-1;push(m_ListHead, m-1); // 將 m 入棧push(n_ListHead, -1); // 將 n 入棧} }// 當(dāng) m==0 時(shí) 出棧 printf("[%s][%4d] 當(dāng)前m=%lld, n=%lld, 計(jì)算 n=n+1 = %lld\n", __func__, __LINE__, m, n, n+1); n = n+1;while( (!is_Empty(m_ListHead)) && (n_ListHead->next->value != -1)){printf("[%s][%4d] 當(dāng)前m=%lld, n=%lld, 即將出棧 m =%lld, n=%lld \n", __func__, __LINE__, m, n, m_ListHead->next->value, n_ListHead->next->value); pop(m_ListHead);pop(n_ListHead);} // 處理 ack(m - 1, ack(m, n - 1));的情況,此時(shí),獲取m-1 的值,彈出-1, 將當(dāng)前n push 入棧 if((!is_Empty(m_ListHead))){m = m_ListHead->next->value;pop(n_ListHead); push(n_ListHead, n);}}return n; }int main(void) {long long m=0;long long n=0;// 分配 List 頭結(jié)點(diǎn) m_ListHead = (LinkList)malloc(sizeof(struct ListNode));n_ListHead = (LinkList)malloc(sizeof(struct ListNode));m_ListHead->next = m_ListHead;n_ListHead->next = n_ListHead;while(m != -1){scanf("%d %d", &m, &n);printf("\n\n計(jì)算結(jié)果===> m=%lld,n=%lld 時(shí), ack=%lld \n\n", m, n, ack(m, n));}// 釋放鏈表頭節(jié)點(diǎn)內(nèi)存 free(m_ListHead);free(n_ListHead);return 0; }

實(shí)測(cè)結(jié)果為:

2 2 [ack][ 118] 當(dāng)前m=2, n=2, 即將入棧m-1=1, n=-1 [ack][ 118] 當(dāng)前m=2, n=1, 即將入棧m-1=1, n=-1 [ack][ 110] 當(dāng)前m=2, n=0, 即將入棧m-1=1, n=1 [ack][ 118] 當(dāng)前m=1, n=1, 即將入棧m-1=0, n=-1 [ack][ 110] 當(dāng)前m=1, n=0, 即將入棧m-1=0, n=1[ack][ 125] 當(dāng)前m=0, n=1, 計(jì)算 n=n+1 = 2 [ack][ 129] 當(dāng)前m=0, n=2, 即將出棧 m =0, n=1[ack][ 125] 當(dāng)前m=0, n=2, 計(jì)算 n=n+1 = 3 [ack][ 129] 當(dāng)前m=0, n=3, 即將出棧 m =0, n=2 [ack][ 129] 當(dāng)前m=0, n=3, 即將出棧 m =1, n=1 [ack][ 118] 當(dāng)前m=1, n=3, 即將入棧m-1=0, n=-1 [ack][ 118] 當(dāng)前m=1, n=2, 即將入棧m-1=0, n=-1 [ack][ 118] 當(dāng)前m=1, n=1, 即將入棧m-1=0, n=-1 [ack][ 110] 當(dāng)前m=1, n=0, 即將入棧m-1=0, n=1[ack][ 125] 當(dāng)前m=0, n=1, 計(jì)算 n=n+1 = 2 [ack][ 129] 當(dāng)前m=0, n=2, 即將出棧 m =0, n=1[ack][ 125] 當(dāng)前m=0, n=2, 計(jì)算 n=n+1 = 3 [ack][ 129] 當(dāng)前m=0, n=3, 即將出棧 m =0, n=2[ack][ 125] 當(dāng)前m=0, n=3, 計(jì)算 n=n+1 = 4 [ack][ 129] 當(dāng)前m=0, n=4, 即將出棧 m =0, n=3[ack][ 125] 當(dāng)前m=0, n=4, 計(jì)算 n=n+1 = 5 [ack][ 129] 當(dāng)前m=0, n=5, 即將出棧 m =0, n=4 [ack][ 129] 當(dāng)前m=0, n=5, 即將出棧 m =1, n=3 [ack][ 118] 當(dāng)前m=1, n=5, 即將入棧m-1=0, n=-1 [ack][ 118] 當(dāng)前m=1, n=4, 即將入棧m-1=0, n=-1 [ack][ 118] 當(dāng)前m=1, n=3, 即將入棧m-1=0, n=-1 [ack][ 118] 當(dāng)前m=1, n=2, 即將入棧m-1=0, n=-1 [ack][ 118] 當(dāng)前m=1, n=1, 即將入棧m-1=0, n=-1 [ack][ 110] 當(dāng)前m=1, n=0, 即將入棧m-1=0, n=1[ack][ 125] 當(dāng)前m=0, n=1, 計(jì)算 n=n+1 = 2 [ack][ 129] 當(dāng)前m=0, n=2, 即將出棧 m =0, n=1[ack][ 125] 當(dāng)前m=0, n=2, 計(jì)算 n=n+1 = 3 [ack][ 129] 當(dāng)前m=0, n=3, 即將出棧 m =0, n=2[ack][ 125] 當(dāng)前m=0, n=3, 計(jì)算 n=n+1 = 4 [ack][ 129] 當(dāng)前m=0, n=4, 即將出棧 m =0, n=3[ack][ 125] 當(dāng)前m=0, n=4, 計(jì)算 n=n+1 = 5 [ack][ 129] 當(dāng)前m=0, n=5, 即將出棧 m =0, n=4[ack][ 125] 當(dāng)前m=0, n=5, 計(jì)算 n=n+1 = 6 [ack][ 129] 當(dāng)前m=0, n=6, 即將出棧 m =0, n=5[ack][ 125] 當(dāng)前m=0, n=6, 計(jì)算 n=n+1 = 7 [ack][ 129] 當(dāng)前m=0, n=7, 即將出棧 m =0, n=6 [ack][ 129] 當(dāng)前m=0, n=7, 即將出棧 m =1, n=5 [ack][ 129] 當(dāng)前m=0, n=7, 即將出棧 m =2, n=2計(jì)算結(jié)果===> m=2,n=2 時(shí), ack=7-1 2 請(qǐng)按任意鍵繼續(xù). . .

總結(jié)

以上是生活随笔為你收集整理的【经典算法实现 15】阿克曼函数(非递归实现)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。