一、概念
從n個不同元素中任取m(m≤n)個元素,按照一定的順序排列起來,叫做從n個不同元素中取出m個元素的一個排列。當m=n時所有的排列情況叫全排列。如果這組數有n個,那么全排列數為n!個。
比如a,b,c的全排列一共有3!= 6 種 分別是{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a}。
二、常用操作
1.頭文件
#include <algorithm>
2.使用方法
這里先說兩個概念:“下一個排列組合”和“上一個排列組合”,對序列 {a, b, c},每一個元素都比后面的小,按照字典序列,固定a之后,a比bc都小,c比b大,它的下一個序列即為{a, c, b},而{a, c, b}的上一個序列即為{a, b, c},同理可以推出所有的六個序列為:{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a},其中{a, b, c}沒有上一個元素,{c, b, a}沒有下一個元素。
1)next_permutation:求下一個排列組合
a.函數模板:next_permutation(arr, arr+size);
b.參數說明:
arr: 數組名
size:數組元素個數
c.函數功能: 返回值為bool類型,當當前序列不存在下一個排列時,函數返回false,否則返回true,排列好的數在數組中存儲
d.注意:在使用前需要對欲排列數組按升序排序,否則只能找出該序列之后的全排列數。
比如,如果數組num初始化為2,3,1,那么輸出就變為了:{2 3 1} {3 1 2} {3 2 1}
2)prev_permutation:求上一個排列組合
a.函數模板:prev_permutation(arr, arr+size);
b.參數說明:
arr: 數組名
size:數組元素個數
c.函數功能: 返回值為bool類型,當當前序列不存在上一個排列時,函數返回false,否則返回true
d.注意:在使用前需要對欲排列數組按降序排序,否則只能找出該序列之后的全排列數。
三、代碼
#include <iostream>
#include <algorithm>
using namespace std;
int main ()
{
int arr[] = {3,2,1};
cout<<"用prev_permutation對3 2 1的全排列"<<endl;
do
{
cout << arr[0] << ' ' << arr[1] << ' ' << arr[2]<<'\n';
}
while ( prev_permutation(arr,arr+3) ); ///獲取上一個較大字典序排列,如果3改為2,只對前兩個數全排列
int arr1[] = {1,2,3};
cout<<"用next_permutation對1 2 3的全排列"<<endl;
do
{
cout << arr1[0] << ' ' << arr1[1] << ' ' << arr1[2] <<'\n';
}
while ( next_permutation(arr1,arr1+3) ); ///獲取下一個較大字典序排列,如果3改為2,只對前兩個數全排列
///注意數組順序,必要時要對數組先進行排序
return 0;
}
四、全排列遞歸思路
public class hello {
public static int arr[] = new int[]{1,2,3};
public static void main(String[] args) {
perm(arr,0,arr.length-1);
}
private static void swap(int i1, int i2) {
int temp = arr[i2];
arr[i2] = arr[i1];
arr[i1] = temp;
}
/**
* 對arr數組中的begin~end進行全排列
*
* 比如:
* arr = {1,2,3}
* 第一步:執行 perm({1,2,3},0,2),begin=0,end=2;
* j=0,因此執行perm({1,2,3},1,2),begin=1,end=2;
* j=1,swap(arr,0,0)-->arr={1,2,3}, perm({1,2,3},2,2),begin=2,end=2;
* 因為begin==end,因此輸出數組{1,2,3}
* swap(arr,1,1) --> arr={1,2,3};
* j=2,swap(arr,1,2)-->arr={1,3,2}, perm({1,3,2},2,2),begin=2,end=2;
* 因為begin==end,因此輸出數組{1,3,2}
* swap(arr,2,1) --> arr={1,2,3};
* j=1,swap(arr,0,1) --> arr={2,1,3}, perm({2,1,3},1,2),begin=1,end=2;
* j=1,swap(arr,1,1)-->arr={2,1,3} perm({2,1,3},2,2),begin=2,end=2;
* 因為begin==end,因此輸出數組{2,1,3}
* swap(arr,1,1)--> arr={2,1,3};
* j=2,swap(arr,1,2)后 arr={2,3,1},並執行perm({2,3,1},2,2),begin=2,end=2;
* 因為begin==end,因此輸出數組{2,3,1}
* swap(arr,2,1) --> arr={2,1,3};
* swap(arr,1,0) --> arr={1,2,3}
* j=2,swap(arr,2,0) --> arr={3,2,1},執行perm({3,2,1},1,2),begin=1,end=2;
* j=1,swap(arr,1,1) --> arr={3,2,1} , perm({3,2,1},2,2),begin=2,end=2;
* 因為begin==end,因此輸出數組{3,2,1}
* swap(arr,1,1) --> arr={3,2,1};
* j=2,swap(arr,2,1) --> arr={3,1,2},並執行perm({2,3,1},2,2),begin=2,end=2;
* 因為begin==end,因此輸出數組{3,1,2}
* swap(arr,2,1) --> arr={3,2,1};
* swap(arr,0,2) --> arr={1,2,3}
*
*/
public static void perm(int arr[], int begin,int end) {
if(end==begin){ //一到遞歸的出口就輸出數組,此數組為全排列
for(int i=0;i<=end;i++){
System.out.print(arr[i]+" ");
}
System.out.println();
return;
}
else{
for(int j=begin;j<=end;j++){
swap(begin,j); //for循環將begin~end中的每個數放到begin位置中去
perm(arr,begin+1,end); //假設begin位置確定,那么對begin+1~end中的數繼續遞歸
swap(begin,j); //換過去后再還原
}
}
}
}

