zoukankan      html  css  js  c++  java
  • 全排列生成算法

    方法一:最经典的递归算法

    a = list(range(4))
    
    
    def go(beg):
        if beg >= len(a):
            print(a)
        for i in range(beg, len(a)):
            a[beg], a[i] = a[i], a[beg]
            go(beg + 1)
            a[beg], a[i] = a[i], a[beg]
    
    
    go(0)
    

    它生成的排列是非字典序的。

    方法二:字典序生成全排列

    这种方法复杂度较高,非常直观。
    1,2,3,4
    1,2,4,3
    1,3,2,4
    1,3,4,2
    1,4,3,2
    .......
    4,3,2,1

    从最后一个元素往前走,我们想让它是递增的,如果碰见了不递增的,那就让右面中略大于该数字的数字出头顶替这个违背了递增规律的数字。然后翻转右面。

    方法三:全排列散列

    给定一个int值,这个数字可以映射到一个排列
    这种方法生成排列的顺序满足字典序。

    方法四:类似方法一,但每次只交换1次

    方法1每生成一个排列交换过去之后还要再交换回来,本方法只需要交换一次
    这种方法很抽象。

    """
    当n为偶数,每调用一次go(n-1)后,各个数字位置不变
    当n为奇数,每调用一次go(n-1)后,各个数字循环左移一个
    所以当n为偶数,让a[n]与a[i]交换,当n为奇数,让a[n]与a[0]交换
    这样主要是为了让a[n]发生变化,让a中每个元素都从第n个位置过一下
    """
    a = [i for i in range(4)]
    
    
    def go(n):
        if n == 1:
            print(a)
            return
        # 如果n为偶数,那么n-1为奇数,执行偶数次heap(奇数),而heap(奇数)只是简单的首尾互换,所以偶数次heap(奇数)不改变数组
        for i in range(n):
            go(n - 1)
            if n & 1:
                a[0], a[n - 1] = a[n - 1], a[0]
            else:
                a[i], a[n - 1] = a[n - 1], a[i]
    
    
    go(len(a))
    
    

    奇数偶数的判断放在for循环里面不太好,可以这么整:

    a = [i for i in range(4)]
    
    
    def odd(n):
        if n == 1:
            print(a)
            return
        for i in range(n):
            even(n - 1)
            a[0], a[n - 1] = a[n - 1], a[0]
    
    
    def even(n):
        for i in range(n):
            odd(n - 1)
            a[i], a[n - 1] = a[n - 1], a[i]
    
    
    def go(n):
        if n & 1:
            odd(n)
        else:
            even(n)
    
    
    go(len(a))
    

    方法五:Steinhaus-Johnson-Trotter算法

    Steinhaus-Johnson-Trotter算法是一种基于最小变换的全排列生成算法。也就是说,相邻的两个排列只有两个位置的数字不一样(交换了位置),这非常像格雷码!

    a = list(range(4))
    di = [-1] * len(a)
    cnt = 0
    while 1:
        print(a)
        ma = None
        for i in range(len(a)):
            if 0 <= i + di[i] < len(a) and a[i + di[i]] < a[i]:
                if ma is None or a[ma] < a[i]:
                    ma = i
        if ma is None: break
        target = ma + di[ma]
        a[ma], a[target] = a[target], a[ma]
        di[ma], di[target] = di[target], di[ma]
        for i in range(len(a)):
            if a[i] > a[target]:
                di[i] *= -1
    

    这种算法复杂度为O(n*n!),生成的序列如下:

    [0, 1, 2, 3]
    [0, 1, 3, 2]
    [0, 3, 1, 2]
    [3, 0, 1, 2]
    [3, 0, 2, 1]
    [0, 3, 2, 1]
    [0, 2, 3, 1]
    [0, 2, 1, 3]
    [2, 0, 1, 3]
    [2, 0, 3, 1]
    [2, 3, 0, 1]
    [3, 2, 0, 1]
    [3, 2, 1, 0]
    [2, 3, 1, 0]
    [2, 1, 3, 0]
    [2, 1, 0, 3]
    [1, 2, 0, 3]
    [1, 2, 3, 0]
    [1, 3, 2, 0]
    [3, 1, 2, 0]
    [3, 1, 0, 2]
    [1, 3, 0, 2]
    [1, 0, 3, 2]
    [1, 0, 2, 3]
    

    参考资料

    Steinhaus-Johnson-Trotter算法

  • 相关阅读:
    restful风格 webapi 发送put delete请求 405 错误
    mysql 连接数据库间接性连接异常
    .net core 发布到centos The configuration file 'appsettings.json' was not found and is not optional. 找不到文件
    .net list<int>、int[]参数类型 前端调用传参方法
    long? long 可空类型转换
    EF 多对多循环引用序列化失败 解决办法
    HTML5学习之HTML标记类型
    电脑高手常用的5个按钮!(太有用了!留下了!)
    final关键字用法总结
    Java程序员面试失败的5大原因 //转自:极客网
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/7682031.html
Copyright © 2011-2022 走看看