參考於:【stl】next_permutation的原理和使用
給定乙個數列,如何得到它的全排列?
例如1 2 3
,它的全排列是
123,
132,
213,
231,
312,
321。
全排列的關鍵在於,給定某一數列,能從該數列推出「下乙個」數列。
那麼如何找「下乙個」數列呢?
1、從後往前找兩個相鄰元素,前乙個位置記為i先試著自己按照這個演算法思路去模擬一下演算法過程,看能不能悟出這個演算法為什麼是對的?如果還是不明白這個演算法為什麼是對的,再繼續往下看。,後乙個記為
j,並且滿足
s[i]
2、從後往前找另乙個位置
k,若滿足
s[i]
,則將s[i]
與s[k]
交換,並將
j之後(包括
j)的所有元素顛倒排序,即得「下乙個」數列。
舉個例子,6 2 5 4 3 1
,觀察一下,下乙個數列是
6 3 1 2 4 5
,回憶一下觀察的過程,你是先從後往前找的對不對?你在找什麼?
其實你在從後往前找,比較相鄰兩個數字,如果前乙個數字比後乙個數字大或相等,就繼續往前找,直到找到前乙個數字比後乙個數字小,我們將前乙個數字的位置記為i
,後乙個數字的位置記為
j,此時應該滿足
s[i]。這個例子中
i = 1
,j = 2
。可以看出從j
開始的數列都是非公升序排列的,因為剛剛在找的過程中,前乙個數字都是比下乙個數字大或相等。
要知道,非公升序排列的數列不可能有「下乙個」數列,即非公升序排列的數列是「最大的」。那麼從j
開始的數列必定不存在「下乙個」數列;另外一點,我們需要考慮i
之前(不包括
i)的數列嗎?比如例子中的
6,不需要!因為從i
開始的數列必定存在「下乙個」數列,因為它不是非公升序排列的,非公升序排列的數列必定存在「下乙個」數列。所以結論是,我們只考慮從從i
開始的數列找「下乙個」數列。
從j開始的數列不可能有「下乙個」數列,那麼「下乙個」數列的i位置放的值不能是原數,而應該從後面的數找,找比原數大的,然後這個數要盡量小。那麼如何找到這個最小的數呢?因為從j
開始的數列是非公升序,所以從後往前找,找到比原數大的就行了。這個位置,我們記為k
,例子中這個最小的數是3,即
k=4。
找到k之後,交換
i,k位置的值(一定可以找到這樣的
k,因為
j位置就滿足了)。交換之後,從j
開始的數列依然是非公升序排列。這個很明顯,就不多解釋了。
因為從j
開始的數列是非公升序排列,逆序一下,得到非降序排列,非降序排列是「最小的」。所以交換之後,從j
開始,逆序排序一下,即得到「下乙個」排列。
下面自己實現的源**(原理同stl中的next_permutation)
bool nextpermutation(int s, int first, int last) //view codelast最後乙個元素的下乙個位置
if (i == first) //
找到第乙個元素都找不到,說明該陣列是降序排列的,下乙個排列不存在
i--, j--;}}
ps.理解源**之後就可以知道為什麼降序排列的陣列,用stl中的next_permutation之後變成公升序排列
最後再補充乙個不規範的遞迴版本,所謂不規範,就是排列的順序與stl中的next_permutation不一樣。
void nextpermutationrecursive(int s, int n, int first, int last) //view codelast是最後乙個元素的下乙個位置
else
}
}
全排列的演算法思想
前幾天的一道面試題目,要求輸入4個數進行全排列並進行按行輸出,精髓在於運用遞迴的思想。1,2兩個數的全排列是 1,2,3三個數的全排列是 根據以上規律可以看出,假如有n個數則它的全排列是以n個數開頭的 n 1 的全排列,以此類推以下個人的 片段 include include using names...
全排列演算法的遞迴思想及實現
題意 給定1 n n個正整數,寫出它們的所有排列順序。思路 根據高中的知識,我們知道不重複的條件下結果是n 個排列順序,在程式中我們先看看如何用遞迴來實現。例如陣列 1,2,3 的全排列為123,132,213,231.312.321。可以看出一點規律來,我們依次交換了第乙個數字,分別從1到3,後面...
演算法 全排列
從n個不同元素中任取m m n 個元素,按照一定的順序排列起來,叫做從n個不同元素中取出m個元素的乙個排列。當m n時所有的排列情況叫全排列。用演算法分別實現全排列,其中n個元素儲存在乙個長度為n的陣列中。實現全排列之前,先看一下對進行全排列的一種方法 從圖中可以看出,我們首先從n個元素中取出乙個元...