python
algorithm
全排列(Permutation)
排列(英語:Permutation)是將相異物件或符號根據確定的順序重排。每個順序都稱作一個排列。例如,從一到六的數字有720種排列,對應於由這些數字組成的所有不重復亦不闕漏的序列,例如4, 5, 6, 1, 2, 3 與1, 3, 5, 2, 4, 6。【From Wikipedia】
從n個相異元素中取出 k個元素,k個元素的排列數量為:
其中P意為Permutation(排列),!表示階乘運算。全排列而取k為n,則結果為n!。
全排列生成算法
-
字典序法
字典序,就是將元素按照字典的順序(a-z, 1-9)進行排列。以字典的順序作為比較的依據,可以比較出兩個串的大小。比如 "1" < "13"<"14"<"153", 就是按每個數字位逐個比較的結果。對於一個串“123456789”, 可以知道最小的串是“123456789”,而最大的串“987654321”。這樣針對這個串以字典序法生成全排列生成全排列,就是依次生成“123456789”->“123456798”->......->"987654312"->"987654321"這樣的串。字典序法要求這一個與下一個有盡可能長的共同前綴,也即變化限制在盡可能短的后綴上。
-
鄰位對換法
該算法由Johnson-Trotter首先提出,是一個能快速生成全排列的算法。它的下一個全排列總是上一個全排列對換某相鄰兩位得到的。如果已知n-1個元素的排列,將n插入到排列的不同位置,就得到了n個元素的排列。用這種方法可以產生出任意n個元素的排列。這個方法有一個缺點:為了產生n個元素的排列,我們必須知道並存儲所有n-1個元素的排列,然后才能產生出所有n階排列。
-
遞增進位制法
這個算法是基於序列的遞增進位制數[3]。遞增進位制數是指數字的進制隨着位數的遞增而遞增。一般情況下,數字最右邊的進制是2,次右邊的進制是3,以此類推。n位遞增進位制數一共包含n!個數字,所以它可以與全排列生成算法結合在一起。
-
遞減進位制法
該方法與遞增進位制法的原理相似,不同的是它定義的“遞減進位制數”是數字的進制隨着位數的遞增而遞減。這種進制一般最左邊的進制是2,次左邊的進制是3。其余原理與遞增進位制法基本相同。
Python實現
字典序法
非遞歸算法
設P是集合{1,2,……n-1,n}的一個全排列:P=P1P2……Pj-1PjPj+1……Pn(1≤P1,P2,……,Pn≤n-1)
1.從排列的右端開始,找出第一個比右邊數字小的數字的序號j,即j=max{i|Pi<Pi+1,i>j}在Pj的右邊的數字中,
找出所有比Pj大的數字中最小的數字Pk,即k=min{i|Pi>Pj,i>j}
2.交換Pi,Pk
3.再將排列右端的遞減部分Pj+1Pj+2……Pn倒轉,因為j右端的數字是降序,所以只需要其左邊和右邊的交換,直到中間,因此可以得到一個新的排列P'=P1P2……Pj-1PkPn……Pj+2Pj+1
代碼
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
@author: gsharp
"""
def Swap(n,a,b):
n[a],n[b] = n[b],n[a]
return None
def Reverse(n,begin):
if len(n) > begin:
i = begin
j = len(n)-1
while i < j:
Swap(n,i,j)
i += 1
j -= 1
return n
def FindMin(n,i):
j = len(n)-1
k = i + 1
while j > i:
if n[j] > n[i] and n[j] < n[k]:
k = j
j -= 1
return k
def Permut(n):
count = 0
j = len(n) -1
if j < 1:
return n
else :
print n
count += 1
while j >= 1:
i = j - 1
if n[i] < n [j] :
k = FindMin(n,i)
Swap (n,i,k)
Reverse (n,j)
j = len(n) - 1
count += 1
print n
else :
j -= 1
print count
n =[1,2,3,4,5,6]
Permut(n)
注意:
- 這里只能對於具有可比較值的列表排序,對於如【'~','!','@','#'】無法直接排序。
- 初始序列必須為最小序列,否則無法列出全部排列。可先使用快速排序來排序后作為輸入。