全排列的递归与非递归实现
问题:输入一个序列(元素无重复),输出其全排列
一般采用经典的递归解法,后来想将其改造为非递归代码,思考很久后觉得并不好写,手工模拟递归栈的行为容易出错。然后上网搜索了一下众网友的非递归代码,发现很多人的非递归代码是各种全新的求解算法,而不是相同算法的非递归实现,和我想要的不一样。
递归解法:
假设输入序列[0,1,2,3],将其分解为4个子问题
0+[1,2,3],
1+[0,2,3],
2+[0,1,3],
3+[0,1,2],这样每个子问题的规模减小了1,一直递归下去直到无法再分解。
1 //对a[idx]~a[n-1]的元素进行全排列,原地排列 2 //第一个参数为序列集合,第二个为序列长度,第三个为当前子问题(子序列)的起始位置 3 void recursivePermutation(int a[],int n,int idx) 4 { 5 if(idx == n-1) //递归结束条件 6 { 7 for(int i=0; i < n;++i) 8 { 9 printf("%d",a[i]); 10 } 11 printf("\n"); 12 return; 13 } 14 assert(idx < n-1); 15 for(int i=idx; i < n; ++i) 16 { 17 std::swap(a[idx],a[i]); 18 recursivePermutation(a,n,idx+1); 19 std::swap(a[idx],a[i]); 20 } 21 }
非递归:
需要一个数据结构来模拟调用栈,std::vector是一个不错的选择,其长度相当于递归深度,每个元素用来保存每次递归调用中的循环变量i。
代码流程来说,最外层需要一个无脑的循环,里面需要
1、判断某个排列是否结束,并输出排列值
2、判断当前子问题是否已经解决,如果结束则返回上一层子问题,如果未结束则进入下一个子问题
1 void permutation(int a[],int n) //假设无重复 2 { 3 vector<int> idx(1,0); //模拟递归算法中每个迭代的循环idx,其长度等于递归算法中的递归深度 4 while(1) 5 { 6 if(idx.size()==n) 7 { 8 for(int i=0; i < n;++i) 9 { 10 printf("%d",a[i]); 11 } 12 printf("\n"); 13 idx.back()++; //idx+1,与下面的if配合,回退到上一个迭代 14 } 15 16 if(idx.back() < n) //模拟递归算法中的循环判断条件 17 { 18 int i = idx.size()-1; 19 std::swap(a[i],a[idx.back()]); 20 idx.push_back(idx.size()); //idx size增加,模拟进入下一层递归 21 } 22 else 23 { 24 idx.pop_back(); //回退到上一层递归 25 if(idx.size()==0){break;} 26 int i =idx.size()-1; 27 std::swap( a[i],a[idx.back()]); 28 idx.back()++; //模拟递归算法中循环i的递增 29 } 30 }; 31 32 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步