1. 程式人生 > >通過分治思想遞迴實現陣列的全排列

通過分治思想遞迴實現陣列的全排列

        在高中數學學習排列與組合的時候,我們知道,要得到一組元素的所有排列情況例如【1,2,3,4,5】這五個數字,它所有的排列一共有5!種,也就是5x4x3x2x1=120種。         這是怎麼得來的呢?我們是將它看作一個長度為5的序列,將每個位置上的可選元素的數目相乘得到的。例如,第一個數可以從1~5中選擇,可選元素是5個,去掉第一位選中的元素,第二位可選元素有4個,以此類推,一共有120種排列方式。         我們在程式設計中借鑑這個過程:陣列第一個數和其他所有的數交換位置,可以得到陣列第一個數可能出現的所有排列情況;然後先忽略掉陣列第一位數字,將剩餘陣列視作一個新的陣列,新陣列的第一個數字再和其他所有數字交換位置,可以得到新陣列第一個數可能出現的所有排列情況,以此類推,將一個數組分治為越來越小的陣列,最後組合出來的排列,就是原陣列的全排列。
/**
 * 分治遞迴實現全排列
 *
 * @author liuxiaofeng
 * @date 2018/10/24 13:32
 */
public class PermutationTest {

    /**
     * 記錄排列數
     */
    private int count = 0;


    /**
     * 直接傳入陣列的過載方法
     *
     * @param arr 進行排列的陣列
     */
    private void permutation(char[] arr) {
        permutation(arr, 0, arr.length -
1); } /** * 進行全排列的方法 * * @param arr 字元陣列 * @param start 陣列開始索引(分治子陣列的起始索引) * @param end 陣列末尾索引(為減少呼叫length方法次數,將末尾索引值靜態化) */ private void permutation(char[] arr, int start, int end) { if (start == end) { //排列完成,列印陣列 System.
out.println("第 " + (++count) + " 個排列:" + Arrays.toString(arr)); } else { for (int i = start; i < arr.length; i++) { //如果當前字元之前未出現過(非重複字元),和其他字元位置進行交換 if (isUnique(arr, start, i)) { //將當前字元與其他字元交換位置 swap(arr, start, i); //將當前字元之後的部分視作新的陣列(分治),對其進行排列 permutation(arr, start + 1, end); //一次迴圈結束後還原字元位置,開始下一次迴圈 swap(arr, start, i); } } } } /** * 字元交換位置的方法 * * @param arr 字元陣列 * @param index1 索引1 * @param index2 索引2 */ private void swap(char[] arr, int index1, int index2) { char tmp = arr[index1]; arr[index1] = arr[index2]; arr[index2] = tmp; } /** * 判斷當前字元是否已經出現過,出現過就是已經交換過,不再進行交換 * * @param arr 字元陣列 * @param start 當前陣列第一個字元的索引 * @param curr 當前字元索引 * @return 當前字元是否需要進行交換 */ private boolean isUnique(char[] arr, int start, int curr) { for (int i = start; i < curr; i++) { if (arr[curr] == arr[i]) { //當前字元已經出現過,返回false return false; } } return true; } /** * 測試方法 */ @Test public void test() { char[] arr = "1268133".toCharArray(); permutation(arr); } }