您的位置:首页 > 其它

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

2013-07-30 20:34 309 查看
问题:输入一个序列(元素无重复),输出其全排列

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

递归解法:

假设输入序列[0,1,2,3],将其分解为4个子问题

0+[1,2,3],

1+[0,2,3],

2+[0,1,3],

3+[0,1,2],这样每个子问题的规模减小了1,一直递归下去直到无法再分解。

//对a[idx]~a[n-1]的元素进行全排列,原地排列
//第一个参数为序列集合,第二个为序列长度,第三个为当前子问题(子序列)的起始位置
void recursivePermutation(int a[],int n,int idx)
{
if(idx == n-1) //递归结束条件
{
for(int i=0; i < n;++i)
{
printf("%d",a[i]);
}
printf("\n");
return;
}
assert(idx < n-1);
for(int i=idx; i < n; ++i)
{
std::swap(a[idx],a[i]);
recursivePermutation(a,n,idx+1);
std::swap(a[idx],a[i]);
}
}


非递归:

需要一个数据结构来模拟调用栈,std::vector是一个不错的选择,其长度相当于递归深度,每个元素用来保存每次递归调用中的循环变量i。

代码流程来说,最外层需要一个无脑的循环,里面需要

1、判断某个排列是否结束,并输出排列值

2、判断当前子问题是否已经解决,如果结束则返回上一层子问题,如果未结束则进入下一个子问题

void permutation(int a[],int n) //假设无重复
{
vector<int> idx(1,0); //模拟递归算法中每个迭代的循环idx,其长度等于递归算法中的递归深度
while(1)
{
if(idx.size()==n)
{
for(int i=0; i < n;++i)
{
printf("%d",a[i]);
}
printf("\n");
idx.back()++; //idx+1,与下面的if配合,回退到上一个迭代
}

if(idx.back() < n) //模拟递归算法中的循环判断条件
{
int i = idx.size()-1;
std::swap(a[i],a[idx.back()]);
idx.push_back(idx.size()); //idx size增加,模拟进入下一层递归
}
else
{
idx.pop_back(); //回退到上一层递归
if(idx.size()==0){break;}
int i =idx.size()-1;
std::swap( a[i],a[idx.back()]);
idx.back()++; //模拟递归算法中循环i的递增
}
};

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: