C++ STL 全排列函數詳解


一、概念

  從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;
}

 四、全排列遞歸思路

我們可以將這個排列問題畫成圖形表示,即排列枚舉樹,比如下圖為{1,2,3}的排列枚舉樹,此樹和我們這里介紹的算法完全一致;
 
 
算法思路:
(1)n個元素的全排列=(n-1個元素的全排列)+(另一個元素作為前綴);
(2)出口:如果只有一個元素的全排列,則說明已經排完,則輸出數組;
(3)不斷將每個元素放作第一個元素,然后將這個元素作為前綴,並將其余元素繼續全排列,等到出口,出口出去后還需要還原數組;
代碼:
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);        //換過去后再還原
            }
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM