字典序輸出全排列演算法
阿新 • • 發佈:2019-02-15
#include<stdio.h> #include<iostream> using namespace std; void pailie(int a[],int n); main() { int n; scanf("%d",&n); int a[n],i; for(i=1;i<=n;i++) //必須保證傳入到函式中的一組數一定要已經是按從小到大排列好的,否則整個演算法就會崩潰 a[i-1]=i; pailie(a,n); return 0; } void pailie(int a[],int n) { int i; int j, k; while (1) { for(i=0;i<n;i++) printf("%d",a[i]); //當第一次進入迴圈時,就會輸出一次從一開始就從小到大排列好的數 printf("\n"); /*這裡的j>=0要放在前面*/ for (j = n - 2; j >= 0 && a[j] > a[j + 1]; j--); //這一步是從這一組數中右邊(即從倒數第二個數判斷,因為倒數第一個數右邊沒有數字)開始判斷,找出第一個比自己右邊數字小的數,下標存到j中 if (j < 0) return; //當已經找不到還有比自己右邊數字大的時候,就說明所有的全排列已經全部輸出了。因為字典序全排列就是從一個最小的數,一直到最大的數1234----4321,當輸到最大時,全排列就全部輸出了 for (k = n - 1; k > j&&a[k] < a[j]; k--); // 這一步是從這一組數中最右邊開始判斷的,在上一步找出j那個位置的數的右邊的數字中,找出所有比j大的數中最小的數字,把他的下標存入k中,用來在下一步將j和k的值互換(右邊的數從右至左是遞增的,因此k是所有大於j的數字中序號最大者) swap(a[k], a[j]); //這是將上面找到第一個比左邊數字小的數字j和數字j右邊比j大的數字中最小的數字k互換一下,這是為了把還沒排在前面過的數字,排到前面去 for (int l = j + 1, r = n - 1; l < r; l++, r--) //因為此時j這個位置的數字後面的數是從大到小排序的,給對調一下就得出了下一次要輸出的全排列 swap(a[l], a[r]); } }