非遞歸全排列 python實現


python algorithm

全排列(Permutation)


排列(英語:Permutation)是將相異物件或符號根據確定的順序重排。每個順序都稱作一個排列。例如,從一到六的數字有720種排列,對應於由這些數字組成的所有不重復亦不闕漏的序列,例如4, 5, 6, 1, 2, 3 與1, 3, 5, 2, 4, 6。【From Wikipedia】
從n個相異元素中取出 k個元素,k個元素的排列數量為:

\[ {P_{k}^{n}={\frac {n!}{(n-k)!}}} \]

其中P意為Permutation(排列),!表示階乘運算。全排列而取k為n,則結果為n!。

全排列生成算法

  1. 字典序法

    字典序,就是將元素按照字典的順序(a-z, 1-9)進行排列。以字典的順序作為比較的依據,可以比較出兩個串的大小。比如 "1" < "13"<"14"<"153", 就是按每個數字位逐個比較的結果。對於一個串“123456789”, 可以知道最小的串是“123456789”,而最大的串“987654321”。這樣針對這個串以字典序法生成全排列生成全排列,就是依次生成“123456789”->“123456798”->......->"987654312"->"987654321"這樣的串。字典序法要求這一個與下一個有盡可能長的共同前綴,也即變化限制在盡可能短的后綴上。

  2. 鄰位對換法

    該算法由Johnson-Trotter首先提出,是一個能快速生成全排列的算法。它的下一個全排列總是上一個全排列對換某相鄰兩位得到的。如果已知n-1個元素的排列,將n插入到排列的不同位置,就得到了n個元素的排列。用這種方法可以產生出任意n個元素的排列。這個方法有一個缺點:為了產生n個元素的排列,我們必須知道並存儲所有n-1個元素的排列,然后才能產生出所有n階排列。

  3. 遞增進位制法

    這個算法是基於序列的遞增進位制數[3]。遞增進位制數是指數字的進制隨着位數的遞增而遞增。一般情況下,數字最右邊的進制是2,次右邊的進制是3,以此類推。n位遞增進位制數一共包含n!個數字,所以它可以與全排列生成算法結合在一起。

  4. 遞減進位制法

該方法與遞增進位制法的原理相似,不同的是它定義的“遞減進位制數”是數字的進制隨着位數的遞增而遞減。這種進制一般最左邊的進制是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&lt;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)

注意:

  1. 這里只能對於具有可比較值的列表排序,對於如【'~','!','@','#'】無法直接排序。
  2. 初始序列必須為最小序列,否則無法列出全部排列。可先使用快速排序來排序后作為輸入。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM