数字的全排列常见的是递归的方法。
- #include "stdafx.h"
- #include <iostream>
- using namespace std;
- int n = 0;
- void output(int str[], int begin,int N)
- {
- 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,N);
- t = str[p];
- str[p] = str[begin];
- str[begin] = t;
- }
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- int a[5],i;
- for (i = 0; i < 5; i++)
- {
- a[i] = i+1;
- }
- cout<<"所有的排序:"<<endl;
- output(a, 0,5);
- cout<<endl<<"共有 "<<n<<"种"<<endl;
- system("pause");
- return 0;
- }
如果不用递归,可以有以下方法:
非递归全排列算法的基本思想是: 1.找到所有排列中最小的一个排列P.
2.找到刚刚好比P大比其它都小的排列Q,
3.循环执行第二步,直到找到一个最大的排列,算法结束.
下面用数学的方法描述:
给定已知序列 P = A1A2A3
An ( Ai!=Aj , (1<=i<=n , 1<=j<=n, i != j ) )
找到P的一个最小排列Pmin = P1P2P3
Pn 有 Pi > P(i-1) (1 < i <= n)
从Pmin开始,总是目前得到的最大的排列为输入,得到下一个排列.
方法为:
1.从低位到高位(从后向前),找出“不符合趋势”的数字。即找到一个Pi,使Pi < P(i+1)。
若找不到这样的pi,说明我们已经找到最后一个全排列,可以返回了。
2.在 P(i+1)P(i+2)
Pn 中,找到一个Pj,便得 Pj"刚刚好大于"Pi.
("刚刚好大于"的意思是:在 P(i+1)P(i+2)
Pn 中所有大于Pi的元素构成的集合中最小的元素.)其实从后向前找,第一个大于Pi的即是
3.交换 Pi , Pj 的位置.注意:此处不改变i和j的值,改变的是Pi和Pj.
4.交换后, P1P2P3
Pn 并不是准确的后一个排列。因为根据第1步的查找,我们有P(i+1) > P(i+2) >
. > Pn
即使进行了Pi和Pj的交换,这仍然是这一部分最大的一个排列。将此排列逆序倒置(变成最小的排列)即为所求的下一个排列.
5.重复步骤1-4,直到步骤1中找不到“不符合趋势”的数字.
这个所谓的大小可以这么理解:
1,2,3,4 3,2,1 ((3 * (3) + 2) * (2) + 1) * (1) = 23
1,2,4,3 3,2,0 ((3 * (3) + 2) * (2) + 0) * (1) = 22
1,3,2,4 3,1,1 ((3 * (3) + 1) * (2) + 1) * (1) = 21
1,3,4,2 3,1,0 ((3 * (3) + 1) * (2) + 0) * (1) = 20
1,4,3,2 3,0,1 ((3 * (3) + 0) * (2) + 1) * (1) = 19
.上面的中间转换指的是:每一个数字后面比当前位数字大的数字的个数。 . .
- #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);
- }
另外更简单的方法是可以用next_permutation函数,要包含头文件algorithm,但要求数组是排好序的
- #include "stdafx.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <iostream>
- #include <algorithm>
- using namespace std;
- int main()
- {
- int a[] = {1,2,3};
- do{
- cout << a[0] << " " << a[1] << " " << a[2] << endl;
- }
- while (next_permutation(a,a+3));
- return 0;
- }
转载于:https://blog.51cto.com/buptdtt/860969