Algorithm 生成go中的所有排列

Algorithm 生成go中的所有排列,algorithm,go,Algorithm,Go,我正在寻找一种方法来生成元素列表中所有可能的排列。类似于itertools.permutations(arr) 不同的是,我不关心是按需生成置换(如python中的生成器)还是全部一起生成置换。我也不在乎它们是否会按字典排序。我所需要的就是以某种方式得到这些n排列。有很多算法可以生成。我发现最简单的方法之一是: 它通过选择一对,从上一个置换生成每个置换 要交换的元素的集合 在上面的链接中概述了一个想法和一个伪代码,它一个接一个地打印排列。这是我的算法实现,它返回所有置换 func permuta

我正在寻找一种方法来生成元素列表中所有可能的排列。类似于
itertools.permutations(arr)


不同的是,我不关心是按需生成置换(如python中的生成器)还是全部一起生成置换。我也不在乎它们是否会按字典排序。我所需要的就是以某种方式得到这些
n排列。

有很多算法可以生成。我发现最简单的方法之一是:

它通过选择一对,从上一个置换生成每个置换 要交换的元素的集合

在上面的链接中概述了一个想法和一个伪代码,它一个接一个地打印排列。这是我的算法实现,它返回所有置换

func permutations(arr []int)[][]int{
    var helper func([]int, int)
    res := [][]int{}

    helper = func(arr []int, n int){
        if n == 1{
            tmp := make([]int, len(arr))
            copy(tmp, arr)
            res = append(res, tmp)
        } else {
            for i := 0; i < n; i++{
                helper(arr, n - 1)
                if n % 2 == 1{
                    tmp := arr[i]
                    arr[i] = arr[n - 1]
                    arr[n - 1] = tmp
                } else {
                    tmp := arr[0]
                    arr[0] = arr[n - 1]
                    arr[n - 1] = tmp
                }
            }
        }
    }
    helper(arr, len(arr))
    return res
}
需要注意的一点是,排列不是按字典顺序排序的(正如您在
itertools.permutations
中看到的)。如果出于某种原因需要对其进行排序,我发现的一种方法是从a生成它们(在
排列部分中有描述,允许快速查找第n个词典排列)


p.S.您还可以查看其他人的代码,这里的代码可以迭代所有排列,而不首先生成所有排列。切片
p
在Fisher-Yates洗牌算法中将中间状态保留为偏移量。这有一个很好的特性,
p
的零值描述了身份置换

package main

import "fmt"

func nextPerm(p []int) {
    for i := len(p) - 1; i >= 0; i-- {
        if i == 0 || p[i] < len(p)-i-1 {
            p[i]++
            return
        }
        p[i] = 0
    }
}

func getPerm(orig, p []int) []int {
    result := append([]int{}, orig...)
    for i, v := range p {
        result[i], result[i+v] = result[i+v], result[i]
    }
    return result
}

func main() {
    orig := []int{11, 22, 33}
    for p := make([]int, len(orig)); p[0] < len(p); nextPerm(p) {
        fmt.Println(getPerm(orig, p))
    }
}
主程序包
输入“fmt”
func下一个术语(p[]int){
对于i:=len(p)-1;i>=0;i--{
如果i==0 | | p[i]
在我的例子中,我引用了一个数组,然后在您的示例中做了一些更改:

func generateIntPermutations(array []int, n int, result *[][]int) {
    if n == 1 {
        dst := make([]int, len(array))
        copy(dst, array[:])
        *result = append(*result, dst)
    } else {
        for i := 0; i < n; i++ {
            generateIntPermutations(array, n-1, result)
            if n%2 == 0 {
                // Golang allow us to do multiple assignments
                array[0], array[n-1] = array[n-1], array[0]
            } else {
                array[i], array[n-1] = array[n-1], array[i]
            }
        }
    }
}
numbers := []int{0, 1, 2}
var result [][]int
generateIntPermutations(numbers, len(numbers), &result)

// result -> [[0 1 2] [1 0 2] [2 1 0] [1 2 0] [2 0 1] [0 2 1]]
func生成置换(数组[]int,n int,结果*[]int){
如果n==1{
dst:=make([]整数,len(数组))
拷贝(dst,数组[:])
*结果=追加(*结果,dst)
}否则{
对于i:=0;i[0112][1022][2110][1201][021][021]
另一个工作代码

package permutations

import "fmt"

func AllPermutation(a []int) {
    var res [][]int
    calPermutation(a, &res, 0)
    fmt.Println(res)
}
func calPermutation(arr []int, res *[][]int, k int) {
    for i := k; i < len(arr); i++ {
        swap(arr, i, k)
        calPermutation(arr, res, k+1)
        swap(arr, k, i)
    }
    if k == len(arr)-1 {
        r := make([]int, len(arr))
        copy(r, arr)
        *res = append(*res, r)
        return
    }
}
func swap(arr []int, i, k int) {
    arr[i], arr[k] = arr[k], arr[i]
}
//result [[1 2 3] [1 3 2] [2 1 3] [2 3 1] [3 2 1] [3 1 2]]
包置换
输入“fmt”
func-AllPermutation(a[]int){
var res[][]int
计算置换(a,&res,0)
fmt.Println(res)
}
func计算置换(arr[]int,res*[]int,k int){
对于i:=k;i
出色的实施(+1来自我)。谢谢你的另一个算法。只有一个小错误:它在空片上恐慌。你还可以补充一点,排列是按字典顺序排列的。我把它变成了一个个人项目的库。我将函数转换为方法,修复了空切片的处理,并添加了从通道读取的选项。你介意我发布这个开源吗?+1最快的字典顺序排列算法afaik!如果getPerm()第1行更改为结果:=make([]int,len(orig)),则速度可能会提高约10%;复印件(结果、原件);(go1.10.3 darwin/amd64)原因是append正在重复调用以根据append源的漏洞重新分配额外内存(append是时间关键型的)。调用者应提供getPerm的结果变量以防止更多cpu使用。感谢@derricw,我忘了在函数中插入那个副本。我的原始函数使用了一段字符串,因此我不需要在该点复制数组。我将来会努力找到更好的方法。
func generateIntPermutations(array []int, n int, result *[][]int) {
    if n == 1 {
        dst := make([]int, len(array))
        copy(dst, array[:])
        *result = append(*result, dst)
    } else {
        for i := 0; i < n; i++ {
            generateIntPermutations(array, n-1, result)
            if n%2 == 0 {
                // Golang allow us to do multiple assignments
                array[0], array[n-1] = array[n-1], array[0]
            } else {
                array[i], array[n-1] = array[n-1], array[i]
            }
        }
    }
}
numbers := []int{0, 1, 2}
var result [][]int
generateIntPermutations(numbers, len(numbers), &result)

// result -> [[0 1 2] [1 0 2] [2 1 0] [1 2 0] [2 0 1] [0 2 1]]
package permutations

import "fmt"

func AllPermutation(a []int) {
    var res [][]int
    calPermutation(a, &res, 0)
    fmt.Println(res)
}
func calPermutation(arr []int, res *[][]int, k int) {
    for i := k; i < len(arr); i++ {
        swap(arr, i, k)
        calPermutation(arr, res, k+1)
        swap(arr, k, i)
    }
    if k == len(arr)-1 {
        r := make([]int, len(arr))
        copy(r, arr)
        *res = append(*res, r)
        return
    }
}
func swap(arr []int, i, k int) {
    arr[i], arr[k] = arr[k], arr[i]
}
//result [[1 2 3] [1 3 2] [2 1 3] [2 3 1] [3 2 1] [3 1 2]]