如何求1到N的数的全排列

// 求N个数的全排列 #include "stdafx.h" #include <iostream> #include <Windows.h> #include <string> using namespace std; #define N 5 int n = 0; void output(int str[N], int begin) { if (begin == N - 1) { for (int i = 0; i < N; i++) { cout<<str[i]<<"\t"; } cout<<endl; n++; return; } for (int p = begin; p < N; p++) { int t = str[p]; str[p] = str[begin]; str[begin] = t; output(str, begin+1); t = str[p]; str[p] = str[begin]; str[begin] = t; } } int _tmain(int argc, _TCHAR* argv[]) { int a[N],i; for (i = 0; i < N; i++) { a[i] = i+1; } cout<<"所有的排序:"<<endl; output(a, 0); cout<<endl<<"共有 "<<n<<"种"<<endl; system("pause"); return 0; }

这是递归算法,相应的时间复杂度和空间复杂度会很大,下面是非递归算法:

要考虑全排列的非递归实现,先来考虑如何计算字符串的下一个排列。如"1234"的下一个排列就是"1243"。只要对字符串反复求出下一个排列,全排列的也就迎刃而解了。

如何计算字符串的下一个排列了?来考虑"926520"这个字符串,我们从后向前找第一双相邻的递增数字,"20"、"52"都是非递增的,"26 "即满足要求,称前一个数字2为替换

数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到"956220",然后再将替换点后的字符"6220"颠

倒即得到"950226"。对于像"4321"这种已经是最“大”的排列,采用STL中的处理方法,将字符串整个颠倒得到最“小”的排列"1234"并返回false。这样,只要一个循环再加上计算

字符串下一个排列的函数就可以轻松的实现非递归的全排列算法。按上面思路并参考STL中的实现源码,不难写成一份质量较高的代码。值得注意的是在循环前要对字符串排序

下!

#include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> using namespace std; //交换数组a中下标为i和j的两个元素的值 void swap(int* a,int i,int j) { a[i]^=a[j]; a[j]^=a[i]; a[i]^=a[j]; } //将数组a中的下标i到下标j之间的所有元素逆序倒置 void reverse(int a[],int i,int j) { while (i < j) swap(a,i++,j--); } void print(int a[],int length) { for(int i=0;i<length;++i) cout<<a[i]<<" "; cout<<endl; } //求取全排列,打印结果 void combination(int a[],int length) { if(length<2) return; while(true) { print(a,length); int i,j; for(i=length-2;i>=0;--i) //找升序的相邻2数,前一个数即替换数 { if(a[i]<a[i+1]) break; else if(i==0) return; } for(j=length-1;j>i;--j) //从后往前找到替换点后第一个比替换数大的数 if(a[j]>a[i]) break; swap(a,i,j); reverse(a,i+1,length-1); //将替换点以后的序列反转 } } int QsortCmp(const void *pa, const void *pb) { return *(char*)pa - *(char*)pb; } int main() { int arr[5] = {1,2,3,4,5}; qsort(arr, 5, sizeof(arr[0]), QsortCmp); //排序之前先将数组递增排序 combination(arr, 5); }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值