[轉載]遞歸解決全排列生成算法

排列:從n個元素中任取m個元素,並按照必定的順序進行排列,稱爲排列;
全排列:當n==m時,稱爲全排列;算法

好比:集合{ 1,2,3}的全排列爲:
{ 1 2 3}
{ 1 3 2 }
{ 2 1 3 }
{ 2 3 1 }
{ 3 2 1 }
{ 3 1 2 }數組

方法一:遞歸

咱們能夠將這個排列問題畫成圖形表示,即排列枚舉樹,好比下圖爲{1,2,3}的排列枚舉樹,此樹和咱們這裏介紹的算法徹底一致;spa


算法思路:
(1)n個元素的全排列=(n-1個元素的全排列)+(另外一個元素做爲前綴);
(2)出口:若是隻有一個元素的全排列,則說明已經排完,則輸出數組;
(3)不斷將每一個元素放做第一個元素,而後將這個元素做爲前綴,並將其他元素繼續全排列,等到出口,出口出去後還須要還原數組;.net

public class Test {
    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}
     *      
     * @param arr
     * @param begin 
     * @param end
     */
    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);      //換過去後再還原
            }
        }
    }
}

方法二:循環

public class Test2 {
    public static int arr[] = new int[]{0,0,0};
    public static void main(String[] args) {
        perm(3);
    }
    /**
     * 數組變化過程:
     * 3 0 0
     * 3 2 0
     * 3 2 1
     * 3 2 0
     * 3 0 0
     * 3 0 2
     * 3 1 2
     * 3 0 2
     * 3 0 0
     * 0 0 0
     * 0 3 0
     * 2 3 0
     * 2 3 1
     * 2 3 0
     * 0 3 0
     * 0 3 2
     * 1 3 2
     * 0 3 2
     * 0 3 0
     * 0 0 0
     * 0 0 3
     * 2 0 3
     * 2 1 3
     * 2 0 3
     * 0 0 3
     * 0 2 3
     * 1 2 3
     * 0 2 3
     * 0 0 3
     * 0 0 0
     * @param m
     */
    private static void perm(int m) {
        if(m==0){
            for(int i=0;i<arr.length;i++){
                System.out.print(arr[i]+" ");
            }
            System.out.println();
            return;
        }
        else{
            for(int i=0;i<arr.length;i++){
                if(arr[i]==0){
                    arr[i] = m;
                    perm(m-1);
                    arr[i] = 0;
                }
            }
        }
    }
}

參考文獻:
1.全排列的遞歸算法實現 李盤榮
2.全排列遞歸算法在算法教學中的重要性 吳素萍
3.排序算法與全排列生成算法研究 陳衛東, 鮑蘇蘇code

論文下載地址:http://yunpan.cn/lk/05qsom5mleblog

私覺得寫的很好,特轉收藏。
轉自 http://blog.csdn.net/xiazdong/article/details/7986015排序

相關文章
相關標籤/搜索