演算法-把n個數的每一種排列情況都列出來(排列組合)-全排列-字典序演算法(一看就懂)
阿新 • • 發佈:2019-02-09
首先需要介紹字典序演算法
比如 236541想找到下一個比它大的數
他有3個步驟
1.從最右邊開始找到第一組 左小於右的數 41 54 65 36 23 這樣找,很顯然,我們找到36就找到了,後面的就不用找了。
2.找到之後立刻交換嗎?不是的。定位了這個3以後,再從右邊開始找。找第一個比3大的數。那就是4。這時候我們交換3,4
3.交換以後就算完了嗎?不是的。還要進行一次排序。交換後是這樣的。246531。我們對4(也就是剛才3那個位置)之後進行排序。得出結果為241356
就好了。
原理:其實很簡單。從右邊找過來,就是為了保證下一個數就真的是比這個數大的下一個數。當找到 左小於右這種情況,就是我們要交換的機會。為什麼交換的機會在這裡?因為假如說你要強行找一組 左大於右的並且把他換掉,那豈不是越來越小了? 再換個角度思考。236541,你後面都已經倒序了,你覺得23開頭還有更大的嗎?沒了。
可能又有一個問題。那我6541不倒序,比如236154,你怎麼解釋?那你還是一樣去看待。236以後的154,54又是倒序。所以他第一步的目的,就是略過那些倒序,也就是略過已經實現最大的東西。
接下來幾步相比也不難理解。
程式碼:(分為遞迴和非遞迴兩種方法。雖然是用java寫的,但是不影響其他語言的人閱讀)
//這裡是遞迴形式方法(傳進來的必須是增序的,不然怎麼求全序列?) private static void Lexi(List<Integer> list) { int size = list.size(); //從右往左,找出第一組 左小於右 的數 //現在 1 2 3 4 5int a = -1; for (int i = size - 1; i >= 1; i --) {//1.找到並記錄第一個左小於右的數 if (list.get(i - 1) < list.get(i)) { a = i - 1; break; } } if (a == -1) {//執行完了退出遞迴 return; } int b = 0; for (int i = size - 1; i > a; i --) {//2.重新開始找,第一個大於我們找到的那個數 if(list.get(a) < list.get(i)) { b = i; break; } } List<Integer> newList = new ArrayList<>(); newList.addAll(list); Collections.swap(newList, a, b);//進行交換 //排序,從a + 1到最後都排一次序 sort(newList, a + 1, size - 1);//最後進行排序 allList.add(newList); Lexi(newList); }
程式碼十分簡單,和我們說的步驟基本一致,但是遞迴在處理大資料的時候回stackoverflow。所以還是用非遞迴形式比較好
//這裡採用的是非遞迴形式,傳進來的必須是增序的 private static void Lexi2(List<Integer> list) { List<Integer> mList = new ArrayList<>(); mList.addAll(list); int size = mList .size(); //計算需要幾次迴圈:其實就是你將會得到幾個數 int num = 1; for (int i = 1; i <= size; i ++) { num *= i; } while ((-- num) != 0) { int a = 0; for (int i = size - 1; i >= 1; i --) {//最後一個數-第二個數 if (mList .get(i - 1) < mList .get(i)) { a = i - 1; break; } } int b = 0; for (int i = size - 1; i > a; i --) { if (mList .get(i) > mList .get(a)) { b = i; break; } } Collections.swap(mList, a, b); sort(mList, a + 1, size - 1); List<Integer> newList = new ArrayList<>(); newList.addAll(mList); allList.add(newList); } }
全部程式碼
public class LexicographicAlgorithm { //如果n = 5(即題中的MAX為5),那麼應該有60種情況 public static void main(String[] args) throws Exception { initData(); Lexi2(list); // System.out.println(allList.size() + ""); for (int i = 0; i < allList.size(); i ++) { for (int j = 0; j < list.size(); j ++) { System.out.print(allList.get(i).get(j) + " "); } System.out.println(""); } } private static final int MAX = 8; private static List<Integer> list = new ArrayList<>(); private static List<List<Integer>> allList = new ArrayList<>(); private static void initData() { for (int i = 1; i <= MAX; i ++) { list.add(i); } allList.add(list); } //這裡是遞迴形式,傳進來的必須是增序的 private static void Lexi(List<Integer> list) { int size = list.size(); //從右往左,找出第一組 左小於右 的數 //現在 1 2 3 4 5 int a = -1; for (int i = size - 1; i >= 1; i --) { if (list.get(i - 1) < list.get(i)) { a = i - 1; break; } } if (a == -1) {//執行完了退出遞迴 return; } int b = 0; for (int i = size - 1; i > a; i --) { if (list.get(a) < list.get(i)) { b = i; break; } } List<Integer> newList = new ArrayList<>(); newList.addAll(list); Collections.swap(newList, a, b); //排序,從a + 1到最後都排一次序 sort(newList, a + 1, size - 1); allList.add(newList); Lexi(newList); } //這裡採用的是非遞迴形式,傳進來的必須是增序的 private static void Lexi2(List<Integer> list) { List<Integer> mList = new ArrayList<>(); mList.addAll(list); int size = mList .size(); //計算需要幾次迴圈:其實就是你將會得到幾個數 int num = 1; for (int i = 1; i <= size; i ++) { num *= i; } while ((-- num) != 0) { int a = 0; for (int i = size - 1; i >= 1; i --) {//最後一個數-第二個數 if (mList .get(i - 1) < mList .get(i)) { a = i - 1; break; } } int b = 0; for (int i = size - 1; i > a; i --) { if (mList .get(i) > mList .get(a)) { b = i; break; } } Collections.swap(mList, a, b); sort(mList, a + 1, size - 1); List<Integer> newList = new ArrayList<>(); newList.addAll(mList); allList.add(newList); } } //升序排序 private static void sort(List<Integer> list, int start, int end) {//1 2 if (start == end) { return; } else { for (int i = start; i <= end; i ++) { int min = Integer.MAX_VALUE; int index = -1; for (int j = i; j <= end; j ++) { if (list.get(j) < min) { min = list.get(j); index = j; } } Collections.swap(list, i, index); } } } }