全排列的递归与非递归实现

问题:输入一个序列(元素无重复),输出其全排列

一般采用经典的递归解法,后来想将其改造为非递归代码,思考很久后觉得并不好写,手工模拟递归栈的行为容易出错。然后上网搜索了一下众网友的非递归代码,发现很多人的非递归代码是各种全新的求解算法,而不是相同算法的非递归实现,和我想要的不一样。

递归解法:

假设输入序列[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 }

 

posted @ 2013-07-30 20:34  _pop  阅读(911)  评论(0编辑  收藏  举报