排列问题的递归算法和非递归算法
2013-08-14 17:45 youxin 阅读(910) 评论(0) 编辑 收藏 举报参考:算法设计与分析 郑宗汉
原理:
简单地说:第一个数与后面的依次交换!
E.g:E = (a , b , c),则 prem(E)= a.perm(b,c)+ b.perm(a,c)+ c.perm(a,b)
然后a.perm(b,c)= ab.perm(c)+ ac.perm(b)= abc + acb.依次递归进行
排列生成的代码:
#include<iostream> using namespace std; /* 数组a[],元素个数n,后面需要排列的元素个数k */ void perm(int a[],int k,int n) { int i; if(k==1) { for(i=0;i<n;i++) //已构成一个排列,输出它 cout<<a[i]; cout<<endl; } else { for(i=n-k;i<n;i++) //生成后续k个元素的一系列排列 { swap(a[n-k],a[i]); //元素互换 perm(a,k-1,n); //生成后续k-1个元素的一系列排列 swap(a[n-k],a[i]); //恢复元素原来的位置 } } } int main() { int a[]={1,2,3,4,5}; perm(a,3,5); }
输出:
12345
12354
12435
12453
12543
12534
请按任意键继续. . .
如果不恢复原来的位置会输出什么?
12345
12354
12534
12543
12345
12354
算法复杂时间度
k=1. 输出n个元素
k=n;对perm(a,k-1,n)执行n次调研,
f(1)=n;
f(n)=nf(n-1);
f(n)=nn!.
c++ swap函数:
template <class T> void swap ( T& a, T& b )
{
T c(a); a=b; b=c;
}
上面的解法从后面开始,我们可以从前面开始,比较好理解:
#include<iostream> using namespace std;
//b表示开始的元素,e表示最后的元素 void perm_aux(int a[],int b,int e) { int i; if(b==e) { for(i=0;i<=e;i++) cout<<a[i]; cout<<endl; } else { for(i=b;i<=e;i++) { swap(a[b],a[i]); perm_aux(a,b+1,e); swap(a[i],a[b]); } } } void perm(int a[],int n) { perm_aux(a,0,n-1); } void perm(int a[],int b,int e) { perm_aux(a,b,e); } int main() { int a[]={1,2,3,4,5}; perm(a,2,4); //生成345的全排列 }
我们重载了perm函数,使其可以直接使用
perm(a,sizeof(a)/sizeof(int))或采用上面的形式。
上面的递归属于指数递归:
指数递归定义:
An exponential recursive function is one that, if you were to draw out a representation of all the function calls, would have an exponential number of calls in relation to the size of the data set (exponential meaning if there were n elements, there would be O(an) function calls where a is a positive number).
上面的代码存在的问题:两个相同的数也进行了交换如果是
{1,2,2}输出:
122 122 212 221 221 212 请按任意键继续. . .
明显不符合要求。
改进后代码:
bool isSwap(int a[],int b,int e) { for(int i=b;i<e;i++) { if(a[i]==a[e]) return false; } return true; } void perm_aux(int a[],int b,int e) { int i; if(b==e) { for(i=0;i<=e;i++) cout<<a[i]; cout<<endl; } else { for(i=b;i<=e;i++) { if(isSwap(a,b,i)) { swap(a[b],a[i]); perm_aux(a,b+1,e); swap(a[i],a[b]); } } } }
122。输出;
122
212
221
请按任意键继续. . .
i=0 isSwap(0,0) true,perm_aux(a,1,2). 返回false.
i=1 isSwap(a,0,1) 可以交换
i=2 isSwap(a,0,2)
for(int i=b;i<e;i++) { if(a[i]==a[e]) return false; } return true;
在2前面a[1]=a[2],返回false。不可以交换。
重要的是IsSwap函数。
更多算法:
http://www.cnblogs.com/bakari/archive/2012/08/02/2620826.html
http://www.cppblog.com/goal00001111/archive/2009/01/20/72378.html
http://hi.baidu.com/tjuer/item/4e2701cae435dc3c44941685
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2012-08-14 Dom children 属性及childNodes