生成列表的所有可能排列的算法?

时间:2010-04-26 01:52:19

标签: algorithm list permutation

说我有一个n个元素的列表,我知道有n个!订购这些元素的可能方式。生成此列表的所有可能排序的算法是什么?例如,我有列表[a,b,c]。该算法将返回[[a,b,c],[a,c,b,],[b,a,c],[b,c,a],[c,a,b],[c,b ,a]]。

我在这里读到这个 http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations

但维基百科从未擅长解释。我对此并不了解。

35 个答案:

答案 0 :(得分:92)

基本上,对于从左到右的每个项目,生成剩余项目的所有排列(并且每个项目都添加了当前元素)。这可以递归地进行(或者如果你喜欢疼痛则迭代地进行),直到达到最后一个项目,此时只有一个可能的顺序。

因此,使用列表[1,2,3,4]生成所有以1开头的排列,然后是以2开始的所有排列,然后是3,然后是4。

这有效地减少了从找到四个项目列表的排列到三个项目的列表之一的问题。在减少到2个然后是1个项目列表后,将找到所有这些项目 示例显示使用3个彩色球的过程排列:
Red, green and blue coloured balls ordered permutations image(来自https://en.wikipedia.org/wiki/Permutation#/media/File:Permutations_RGB.svg - https://commons.wikimedia.org/wiki/File:Permutations_RGB.svg

答案 1 :(得分:24)

这是Python中的一种算法,它在数组上就位:

def permute(xs, low=0):
    if low + 1 >= len(xs):
        yield xs
    else:
        for p in permute(xs, low + 1):
            yield p        
        for i in range(low + 1, len(xs)):        
            xs[low], xs[i] = xs[i], xs[low]
            for p in permute(xs, low + 1):
                yield p        
            xs[low], xs[i] = xs[i], xs[low]

for p in permute([1, 2, 3, 4]):
    print p

您可以在此处亲自试用代码:http://repl.it/J9v

答案 2 :(得分:13)

维基百科对“词典顺序”的回答在食谱风格中对我来说似乎是完全明确的。它引用了该算法的14世纪起源!

我刚刚用Java编写了维基百科算法的快速实现作为检查,这没有问题。但是你在Q中的例子不是“列出所有排列”,而是“所有排列的列表”,所以维基百科对你没什么帮助。您需要一种可行地构建排列列表的语言。并且相信我,列出数十亿长的通常不会用命令式语言处理。你真的想要一种非严格的函数式编程语言,其中列表是一流的对象,以便在不使机器接近宇宙热死的情况下获取东西。

这很容易。在标准的Haskell或任何现代FP语言中:

-- perms of a list
perms :: [a] -> [ [a] ]
perms (a:as) = [bs ++ a:cs | perm <- perms as, (bs,cs) <- splits perm]
perms []     = [ [] ]

-- ways of splitting a list into two parts
splits :: [a] -> [ ([a],[a]) ]
splits []     = [ ([],[]) ]
splits (a:as) = ([],a:as) : [(a:bs,cs) | (bs,cs) <- splits as]

答案 3 :(得分:13)

这里已经有很多好的解决方案了,但我想分享一下我自己如何解决这个问题,并希望这对那些想要得出自己解决方案的人有所帮助。

在对这个问题进行一些思考之后,我得出了以下两个结论:

  1. 对于大小为L的列表n,将有相同数量的解决方案,以L 1 开头,L 2 ...... L列表的 n 元素。由于大小n!的列表总共有n个排列,因此我们会在每个组中获得n! / n = (n-1)!个排列。
  2. 2个元素的列表只有2个排列=&gt; [a,b][b,a]
  3. 使用这两个简单的想法,我得出了以下算法:

    permute array
        if array is of size 2
           return first and second element as new array
           return second and first element as new array
        else
            for each element in array
                new subarray = array with excluded element
                return element + permute subarray
    

    以下是我在C#中实现的方法:

    public IEnumerable<List<T>> Permutate<T>(List<T> input)
    {
        if (input.Count == 2) // this are permutations of array of size 2
        {
            yield return new List<T>(input);
            yield return new List<T> {input[1], input[0]}; 
        }
        else
        {
            foreach(T elem in input) // going through array
            {
                var rlist = new List<T>(input); // creating subarray = array
                rlist.Remove(elem); // removing element
                foreach(List<T> retlist in Permutate(rlist))
                {
                    retlist.Insert(0,elem); // inserting the element at pos 0
                    yield return retlist;
                }
    
            }
        }
    }
    

答案 4 :(得分:9)

正如WhirlWind所说,你从一开始就开始。

您将光标与每个剩余值交换,包括光标本身,这些都是新实例(我在示例中使用了int[]array.clone()。)

然后在所有这些不同的列表上执行排列,确保光标位于右侧。

当没有剩余值(光标在末尾)时,打印列表。这是停止条件。

public void permutate(int[] list, int pointer) {
    if (pointer == list.length) {
        //stop-condition: print or process number
        return;
    }
    for (int i = pointer; i < list.length; i++) {
        int[] permutation = (int[])list.clone();.
        permutation[pointer] = list[i];
        permutation[i] = list[pointer];
        permutate(permutation, pointer + 1);
    }
}

答案 5 :(得分:8)

递归总是需要一些心理上的努力才能维持。对于大数字,阶乘很容易,而且堆栈溢出很容易成为问题。

对于较小的数字(3或4,主要遇到),多个循环非常简单直接。这是一个不幸的答案,循环没有被投票。

让我们从枚举(而不是排列)开始。只需将代码读作伪perl代码即可。

$foreach $i1 in @list
    $foreach $i2 in @list 
        $foreach $i3 in @list
            print "$i1, $i2, $i3\n"

枚举比排列更常见,但如果需要排列,只需添加条件:

$foreach $i1 in @list
    $foreach $i2 in @list 
        $if $i2==$i1
            next
        $foreach $i3 in @list
            $if $i3==$i1 or $i3==$i2
                next
            print "$i1, $i2, $i3\n"

现在,如果您确实需要可能用于大型列表的通用方法,我们可以使用radix方法。首先,考虑枚举问题:

$n=@list
my @radix
$for $i=0:$n
    $radix[$i]=0
$while 1
    my @temp
    $for $i=0:$n
        push @temp, $list[$radix[$i]]
    print join(", ", @temp), "\n"
    $call radix_increment

subcode: radix_increment
    $i=0
    $while 1
        $radix[$i]++
        $if $radix[$i]==$n
            $radix[$i]=0
            $i++
        $else
            last
    $if $i>=$n
        last

基数增量基本上是数字计数(以列表元素数量为基础)。

现在,如果你需要permutaion,只需在循环中添加检查:

subcode: check_permutation
    my @check
    my $flag_dup=0
    $for $i=0:$n
        $check[$radix[$i]]++
        $if $check[$radix[$i]]>1
            $flag_dup=1
            last
    $if $flag_dup
        next

编辑:上面的代码应该可以工作,但是对于置换,radix_increment可能会浪费。因此,如果时间是实际问题,我们必须将radix_increment更改为permute_inc:

subcode: permute_init
    $for $i=0:$n
        $radix[$i]=$i

subcode: permute_inc                                       
    $max=-1                                                
    $for $i=$n:0                                           
        $if $max<$radix[$i]                                
            $max=$radix[$i]                                
        $else                                              
            $for $j=$n:0                                   
                $if $radix[$j]>$radix[$i]                  
                    $call swap, $radix[$i], $radix[$j]     
                    break                                  
            $j=$i+1                                        
            $k=$n-1                                        
            $while $j<$k                                   
                $call swap, $radix[$j], $radix[$k]         
                $j++                                       
                $k--                                       
            break                                          
    $if $i<0                                               
        break                                              

当然,现在这段代码在逻辑上更加复杂,我将留给读者练习。

答案 6 :(得分:5)

如果有人想知道如何在javascript中进行排列。

<强>思想/伪代码

  1. 一次挑选一个元素
  2. 置换元素的其余部分,然后将拾取的元素添加到所有排列
  3. 例如,

    。 'a'+ permute(bc)。 bc的变换将是bc&amp; CB。现在加上这两个会给abc,acb。同样,选择b + permute(ac)将使用bac,bca ...并继续前进。

    现在查看代码

    function permutations(arr){
    
       var len = arr.length, 
           perms = [],
           rest,
           picked,
           restPerms,
           next;
    
        //for one or less item there is only one permutation 
        if (len <= 1)
            return [arr];
    
        for (var i=0; i<len; i++)
        {
            //copy original array to avoid changing it while picking elements
            rest = Object.create(arr);
    
            //splice removed element change array original array(copied array)
            //[1,2,3,4].splice(2,1) will return [3] and remaining array = [1,2,4]
            picked = rest.splice(i, 1);
    
            //get the permutation of the rest of the elements
            restPerms = permutations(rest);
    
           // Now concat like a+permute(bc) for each
           for (var j=0; j<restPerms.length; j++)
           {
               next = picked.concat(restPerms[j]);
               perms.push(next);
           }
        }
    
       return perms;
    }
    

    花点时间了解这一点。我从(pertumation in JavaScript

    获得了这段代码

答案 7 :(得分:3)

enter image description here

// C program to print all permutations with duplicates allowed
#include <stdio.h>
#include <string.h>

/* Function to swap values at two pointers */
void swap(char *x, char *y)
{
    char temp;
    temp = *x;
    *x = *y;
    *y = temp;
}

/* Function to print permutations of string
   This function takes three parameters:
   1. String
   2. Starting index of the string
   3. Ending index of the string. */

void permute(char *a, int l, int r)
{
   int i;
   if (l == r)
     printf("%s\n", a);
   else
   {
       for (i = l; i <= r; i++)
       {
          swap((a+l), (a+i));
          permute(a, l+1, r);
          swap((a+l), (a+i)); //backtrack
       }
   }
}

/* Driver program to test above functions */
int main()
{
    char str[] = "ABC";
    int n = strlen(str);
    permute(str, 0, n-1);
    return 0;
}

参考:Geeksforgeeks.org

答案 8 :(得分:3)

public class PermutationGenerator
{
    private LinkedList<List<int>> _permutationsList;
    public void FindPermutations(List<int> list, int permutationLength)
    {
        _permutationsList = new LinkedList<List<int>>();
        foreach(var value in list)
        {
            CreatePermutations(value, permutationLength);
        }
    }

    private void CreatePermutations(int value, int permutationLength)
    {
        var node = _permutationsList.First;
        var last = _permutationsList.Last;
        while (node != null)
        {
            if (node.Value.Count < permutationLength)
            {
                GeneratePermutations(node.Value, value, permutationLength);
            }
            if (node == last)
            {
                break;
            }
            node = node.Next;
        }

        List<int> permutation = new List<int>();
        permutation.Add(value);
        _permutationsList.AddLast(permutation);
    }

    private void GeneratePermutations(List<int> permutation, int value, int permutationLength)
    {
       if (permutation.Count < permutationLength)
        {
            List<int> copyOfInitialPermutation = new List<int>(permutation);
            copyOfInitialPermutation.Add(value);
            _permutationsList.AddLast(copyOfInitialPermutation);
            List<int> copyOfPermutation = new List<int>();
            copyOfPermutation.AddRange(copyOfInitialPermutation);
            int lastIndex = copyOfInitialPermutation.Count - 1;
            for (int i = lastIndex;i > 0;i--)
            {
                int temp = copyOfPermutation[i - 1];
                copyOfPermutation[i - 1] = copyOfPermutation[i];
                copyOfPermutation[i] = temp;

                List<int> perm = new List<int>();
                perm.AddRange(copyOfPermutation);
                _permutationsList.AddLast(perm);
            }
        }
    }

    public void PrintPermutations(int permutationLength)
    {
        int count = _permutationsList.Where(perm => perm.Count() == permutationLength).Count();
        Console.WriteLine("The number of permutations is " + count);
    }
}

答案 9 :(得分:3)

PHP中的

$set=array('A','B','C','D');

function permutate($set) {
    $b=array();
    foreach($set as $key=>$value) {
        if(count($set)==1) {
            $b[]=$set[$key];
        }
        else {
            $subset=$set;
            unset($subset[$key]);
            $x=permutate($subset);
            foreach($x as $key1=>$value1) {
                $b[]=$value.' '.$value1;
            }
        }
    }
    return $b;
}

$x=permutate($set);
var_export($x);

答案 10 :(得分:3)

Java版

public static void main(String[] args) throws Exception { 
    my_permutationOf(new ArrayList<Integer>() {
        {
            add(1);
            add(2);
            add(3);

        }
    }, 3, null, true);
}

E.g。

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

输出:

{{1}}

答案 11 :(得分:3)

以下是Python中用于打印列表的所有可能排列的代码:

def next_perm(arr):
    # Find non-increasing suffix
    i = len(arr) - 1
    while i > 0 and arr[i - 1] >= arr[i]:
        i -= 1
    if i <= 0:
        return False

    # Find successor to pivot
    j = len(arr) - 1
    while arr[j] <= arr[i - 1]:
        j -= 1
    arr[i - 1], arr[j] = arr[j], arr[i - 1]

    # Reverse suffix
    arr[i : ] = arr[len(arr) - 1 : i - 1 : -1]
    print arr
    return True

def all_perm(arr):
    a = next_perm(arr)
    while a:
        a = next_perm(arr)
    arr = raw_input()
    arr.split(' ')
    arr = map(int, arr)
    arr.sort()
    print arr
    all_perm(arr)

我使用了词典顺序算法来获得所有可能的排列,但递归算法更有效。你可以在这里找到递归算法的代码: Python recursion permutations

答案 12 :(得分:3)

我已经在ANSI C中编写了这个递归解决方案。每次执行Permutate函数都会提供一个不同的排列,直到完成所有这些排列。全局变量也可用于变量事实和计数。

#include <stdio.h>
#define SIZE 4

void Rotate(int vec[], int size)
{
    int i, j, first;

    first = vec[0];
    for(j = 0, i = 1; i < size; i++, j++)
    {
        vec[j] = vec[i];
    }
    vec[j] = first;
}

int Permutate(int *start, int size, int *count)
{
    static int fact;

    if(size > 1)
    {
        if(Permutate(start + 1, size - 1, count))
        {
            Rotate(start, size);
        }
        fact *= size;
    }
    else
    {
        (*count)++;
        fact = 1;
    }

    return !(*count % fact);
}

void Show(int vec[], int size)
{
    int i;

    printf("%d", vec[0]);
    for(i = 1; i < size; i++)
    {
        printf(" %d", vec[i]);
    }
    putchar('\n');
}

int main()
{
    int vec[] = { 1, 2, 3, 4, 5, 6 }; /* Only the first SIZE items will be permutated */
    int count = 0;

    do
    {
        Show(vec, SIZE);
    } while(!Permutate(vec, SIZE, &count));

    putchar('\n');
    Show(vec, SIZE);
    printf("\nCount: %d\n\n", count);

    return 0;
}

答案 13 :(得分:3)

这是一个类似于#permutation.to_a的玩具Ruby方法,对于疯狂的人来说可能更容易辨认。这是hella慢,但也是5行。

def permute(ary)
  return [ary] if ary.size <= 1
  ary.collect_concat.with_index do |e, i|
    rest = ary.dup.tap {|a| a.delete_at(i) }
    permute(rest).collect {|a| a.unshift(e) }
  end
end

答案 14 :(得分:3)

void permutate(char[] x, int i, int n){
    x=x.clone();
    if (i==n){
        System.out.print(x);
        System.out.print(" ");
        counter++;}
    else
    {
        for (int j=i; j<=n;j++){
     //   System.out.print(temp); System.out.print(" ");    //Debugger
        swap (x,i,j);
      //  System.out.print(temp); System.out.print(" "+"i="+i+" j="+j+"\n");// Debugger
        permutate(x,i+1,n);
    //    swap (temp,i,j);
    }
    }
}

void swap (char[] x, int a, int b){
char temp = x[a];
x[a]=x[b];
x[b]=temp;
}

我创造了这个。也基于研究 permutate(qwe,0,qwe.length-1); 你知道,无论有没有回溯,都可以做到这一点

答案 15 :(得分:3)

我正在考虑编写一个代码来获取任何大小的任何给定整数的排列,即提供一个数字4567,我们得到所有可能的排列直到7654 ...所以我研究了它并找到了算法并最终实现了它,这是用“c”编写的代码。 您可以简单地复制它并在任何开源编译器上运行。但是有些缺陷正在等待调试。请欣赏。

代码:

#include <stdio.h>
#include <conio.h>
#include <malloc.h>

                //PROTOTYPES

int fact(int);                  //For finding the factorial
void swap(int*,int*);           //Swapping 2 given numbers
void sort(int*,int);            //Sorting the list from the specified path
int imax(int*,int,int);         //Finding the value of imax
int jsmall(int*,int);           //Gives position of element greater than ith but smaller than rest (ahead of imax)
void perm();                    //All the important tasks are done in this function


int n;                         //Global variable for input OR number of digits

void main()
{
int c=0;

printf("Enter the number : ");
scanf("%d",&c);
perm(c);
getch();
}

void perm(int c){
int *p;                     //Pointer for allocating separate memory to every single entered digit like arrays
int i, d;               
int sum=0;
int j, k;
long f;

n = 0;

while(c != 0)               //this one is for calculating the number of digits in the entered number
{
    sum = (sum * 10) + (c % 10);
    n++;                            //as i told at the start of loop
    c = c / 10;
}

f = fact(n);                        //It gives the factorial value of any number

p = (int*) malloc(n*sizeof(int));                //Dynamically allocation of array of n elements

for(i=0; sum != 0 ; i++)
{
    *(p+i) = sum % 10;                               //Giving values in dynamic array like 1234....n separately
    sum = sum / 10;
}

sort(p,-1);                                         //For sorting the dynamic array "p"

for(c=0 ; c<f/2 ; c++) {                        //Most important loop which prints 2 numbers per loop, so it goes upto 1/2 of fact(n)

    for(k=0 ; k<n ; k++)
        printf("%d",p[k]);                       //Loop for printing one of permutations
    printf("\n");

    i = d = 0;
    i = imax(p,i,d);                            //provides the max i as per algo (i am restricted to this only)
    j = i;
    j = jsmall(p,j);                            //provides smallest i val as per algo
    swap(&p[i],&p[j]);

    for(k=0 ; k<n ; k++)
        printf("%d",p[k]);
    printf("\n");

    i = d = 0;
    i = imax(p,i,d);
    j = i;
    j = jsmall(p,j);
    swap(&p[i],&p[j]);

    sort(p,i);
}
free(p);                                        //Deallocating memory
}

int fact (int a)
{
long f=1;
while(a!=0)
{
    f = f*a;
    a--;
}
return f;
}


void swap(int *p1,int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
return;
}


void sort(int*p,int t)
{
int i,temp,j;
for(i=t+1 ; i<n-1 ; i++)
{
    for(j=i+1 ; j<n ; j++)
    {
        if(*(p+i) > *(p+j))
        {
            temp = *(p+i);
            *(p+i) = *(p+j);
            *(p+j) = temp;
        }
    }
}
}


int imax(int *p, int i , int d)
{
    while(i<n-1 && d<n-1)
{
    if(*(p+d) < *(p+d+1))
    {   
        i = d;
        d++;
    }
    else
        d++;
}
return i;
}


int jsmall(int *p, int j)
{
int i,small = 32767,k = j;
for (i=j+1 ; i<n ; i++)
{
    if (p[i]<small && p[i]>p[k])
    {     
       small = p[i];
       j = i;
    }
}
return j;
}

答案 16 :(得分:3)

Python中的另一个,它不像@ cdiggins那样,但我认为它更容易理解

def permute(num):
    if len(num) == 2:
        # get the permutations of the last 2 numbers by swapping them
        yield num
        num[0], num[1] = num[1], num[0]
        yield num
    else:
        for i in range(0, len(num)):
            # fix the first number and get the permutations of the rest of numbers
            for perm in permute(num[0:i] + num[i+1:len(num)]):
                yield [num[i]] + perm

for p in permute([1, 2, 3, 4]):
    print p

答案 17 :(得分:2)

在Scala中

    def permutazione(n: List[Int]): List[List[Int]] = permutationeAcc(n, Nil)



def permutationeAcc(n: List[Int], acc: List[Int]): List[List[Int]] = {

    var result: List[List[Int]] = Nil
    for (i ← n if (!(acc contains (i))))
        if (acc.size == n.size-1)
            result = (i :: acc) :: result
        else
            result = result ::: permutationeAcc(n, i :: acc)
    result
}

答案 18 :(得分:2)

这是一个用于置换的java版本

public class Permutation {

    static void permute(String str) {
        permute(str.toCharArray(), 0, str.length());
    }

    static void permute(char [] str, int low, int high) {
        if (low == high) {
            System.out.println(str);
            return;
        }

        for (int i=low; i<high; i++) {
            swap(str, i, low);
            permute(str, low+1, high);
            swap(str, low, i);
        }

    }

    static void swap(char [] array, int i, int j) {
        char t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
}

答案 19 :(得分:2)

这是ColdFusion的一个实现(因为ArrayAppend()的merge参数需要CF10):

public array function permutateArray(arr){

    if (not isArray(arguments.arr) ) {
        return ['The ARR argument passed to the permutateArray function is not of type array.'];    
    }

    var len = arrayLen(arguments.arr);
    var perms = [];
    var rest = [];
    var restPerms = [];
    var rpLen = 0;
    var next = [];

    //for one or less item there is only one permutation 
    if (len <= 1) {
        return arguments.arr;
    }

    for (var i=1; i <= len; i++) {
        // copy the original array so as not to change it and then remove the picked (current) element
        rest = arraySlice(arguments.arr, 1);
        arrayDeleteAt(rest, i);

         // recursively get the permutation of the rest of the elements
         restPerms = permutateArray(rest);
         rpLen = arrayLen(restPerms);

        // Now concat each permutation to the current (picked) array, and append the concatenated array to the end result
        for (var j=1; j <= rpLen; j++) {
            // for each array returned, we need to make a fresh copy of the picked(current) element array so as to not change the original array
            next = arraySlice(arguments.arr, i, 1);
            arrayAppend(next, restPerms[j], true);
            arrayAppend(perms, next);
        }
     }

    return perms;
}

基于上面的KhanSharp的js解决方案。

答案 20 :(得分:1)

你不能真正谈论在递归中解决permultation问题而不用pioneered the idea的(方言)语言发布实现。因此,为了完整起见,这是在Scheme中可以实现的方法之一。

(define (permof wd)
  (cond ((null? wd) '())
        ((null? (cdr wd)) (list wd))
        (else
         (let splice ([l '()] [m (car wd)] [r (cdr wd)])
           (append
            (map (lambda (x) (cons m x)) (permof (append l r)))
            (if (null? r)
                '()
                (splice (cons m l) (car r) (cdr r))))))))

致电(permof (list "foo" "bar" "baz"))我们会得到:

'(("foo" "bar" "baz")
  ("foo" "baz" "bar")
  ("bar" "foo" "baz")
  ("bar" "baz" "foo")
  ("baz" "bar" "foo")
  ("baz" "foo" "bar"))

我不会进入算法细节,因为在其他帖子中已经对它进行了充分的解释。这个想法是一样的。

然而,递归问题往往更难以在Python,C和Java等破坏性媒介中进行建模和思考,而在Lisp或ML中则可以简明扼要地表达。

答案 21 :(得分:1)

在下面的Java解决方案中,我们利用了Strings不可变的事实,以避免在每次迭代时克隆结果集。

输入将是一个字符串,比如“abc”,输出将是所有可能的排列:

abc
acb
bac
bca
cba
cab

代码:

public static void permute(String s) {
    permute(s, 0);
}

private static void permute(String str, int left){
    if(left == str.length()-1) {
        System.out.println(str);
    } else {
        for(int i = left; i < str.length(); i++) {
            String s = swap(str, left, i);
            permute(s, left+1);
        }
    }
}

private static String swap(String s, int left, int right) {
    if (left == right)
        return s;

    String result = s.substring(0, left);
    result += s.substring(right, right+1);
    result += s.substring(left+1, right);
    result += s.substring(left, left+1);
    result += s.substring(right+1);
    return result;
}

可以对数组(而不是字符串)应用相同的方法:

public static void main(String[] args) {
    int[] abc = {1,2,3};
    permute(abc, 0);
}
public static void permute(int[] arr, int index) {
    if (index == arr.length) {
        System.out.println(Arrays.toString(arr));
    } else {
        for (int i = index; i < arr.length; i++) {
            int[] permutation = arr.clone();
            permutation[index] = arr[i];
            permutation[i] = arr[index];
            permute(permutation, index + 1);
        }
    }
}

答案 22 :(得分:1)

这是我在Java上的解决方案:

public class CombinatorialUtils {

    public static void main(String[] args) {
        List<String> alphabet = new ArrayList<>();
        alphabet.add("1");
        alphabet.add("2");
        alphabet.add("3");
        alphabet.add("4");

        for (List<String> strings : permutations(alphabet)) {
            System.out.println(strings);
        }
        System.out.println("-----------");
        for (List<String> strings : combinations(alphabet)) {
            System.out.println(strings);
        }
    }

    public static List<List<String>> combinations(List<String> alphabet) {
        List<List<String>> permutations = permutations(alphabet);
        List<List<String>> combinations = new ArrayList<>(permutations);

        for (int i = alphabet.size(); i > 0; i--) {
            final int n = i;
            combinations.addAll(permutations.stream().map(strings -> strings.subList(0, n)).distinct().collect(Collectors.toList()));
        }
        return combinations;
    }

    public static <T> List<List<T>> permutations(List<T> alphabet) {
        ArrayList<List<T>> permutations = new ArrayList<>();
        if (alphabet.size() == 1) {
            permutations.add(alphabet);
            return permutations;
        } else {
            List<List<T>> subPerm = permutations(alphabet.subList(1, alphabet.size()));
            T addedElem = alphabet.get(0);
            for (int i = 0; i < alphabet.size(); i++) {
                for (List<T> permutation : subPerm) {
                    int index = i;
                    permutations.add(new ArrayList<T>(permutation) {{
                        add(index, addedElem);
                    }});
                }
            }
        }
        return permutations;
    }
}

答案 23 :(得分:1)

我知道这是今天的stackoverflow中一个非常古老甚至偏离主题但我仍然想提供一个友好的javascript答案,原因很简单,它在浏览器中运行。

我还添加了debugger指令断点,以便您可以单步执行代码(需要chrome)以查看此算法的工作原理。用chrome打开您的开发控制台(在Windows中为F12或在Mac上为CMD + OPTION + I),然后点击“运行代码段”。这实现了@WhirlWind在他的回答中提出的相同的算法。

您的浏览器应暂停执行debugger指令。使用F8继续执行代码。

逐步执行代码,看看它是如何工作的!

function permute(rest, prefix = []) {
  if (rest.length === 0) {
    return [prefix];
  }
  return (rest
    .map((x, index) => {
      const oldRest = rest;
      const oldPrefix = prefix;
      // the `...` destructures the array into single values flattening it
      const newRest = [...rest.slice(0, index), ...rest.slice(index + 1)];
      const newPrefix = [...prefix, x];
      debugger;

      const result = permute(newRest, newPrefix);
      return result;
    })
    // this step flattens the array of arrays returned by calling permute
    .reduce((flattened, arr) => [...flattened, ...arr], [])
  );
}
console.log(permute([1, 2, 3]));

答案 24 :(得分:0)

这是C ++中的非递归解决方案,它以升序提供下一个排列,类似于std :: next_permutation提供的功能:

app.post('/clicked', (req, res) => {
  const click = {
    clickTime: new Date(),
    _id: // TODO: Find _id property from database, insert here!
  };
  ...
});

答案 25 :(得分:0)

这一次不生成列表就生成它们-最终结果与Marios Choudary的答案相同(或者就像Anders回答的那样,仅调用C ++的nextPermute)。但这是重新排列的Heap的算法(非递归版本)和一个用于保存上下文的类。用作:

P5=new genPermutes_t(5); // P5.P is now [0,1,2,3,4]
while(!P5.isDone()) {
  // use P5.P here
  P5.next();
}

代码使用C#表示未经认可。变量按原样来自Heap的伪代码,注释也指向该伪代码:

public class genPermutes_t {
  public int[] P; // the current permuation

  private int n, i; // vars from the original algorithm
  private int[] c; // ditto

  public genPermutes_t(int count) {
    // init algorithm:
    n=count;
    i=0;
    c=new int[n];
    for(int j=0;j<n;j++) c[j]=0;

    // start current permutation as 0,1 ... n-1:
    P=new int[n];
    for(int j=0;j<n;j++) P[j]=j;
  }

  public bool isDone() {
    return i>=n; // condition on the original while loop
  }

  public void next() {
    // the part of the loop that spins until done or ready for next permute:
    while(i<n && c[i]>=i) {
      c[i]=0;
      i++;
    }
    // pulled from inside loop -- the part that makes next permute:
    if(i<n) { // if not done
      if(i%2==0) swap(0,i);
      else swap(c[i], i);
      // "print P" removed. User will simply examine it
      c[i]+=1;
      i=0;
    }
  }

  private void swap(int i1, int i2) {int tmp=P[i1]; P[i1]=P[i2]; P[i2]=tmp;}
}

答案 26 :(得分:0)

在C语言中,创建一个矩阵(无符号字符)以快速轻松地访问从1到6的所有排列。基于https://www.geeksforgeeks.org/heaps-algorithm-for-generating-permutations/中的代码。

void swap(unsigned char* a, unsigned char* b)
{
    unsigned char t;

    t = *b;
    *b = *a;
    *a = t;
}

void print_permutations(unsigned char a[], unsigned char n)
{
    // can't rely on sizeof(a[6]) == 6, such as with MSVC 2019
    for (int i = 0; i < n; i++)
    {
        assert(a[i] < n);
        printf("%d ", a[i]);
    }
    printf("\n");
}

// Generating permutation using Heap Algorithm 
void generate_permutations(unsigned char (**permutations)[6], unsigned char a[], int size, int n)
{
    // can't rely on sizeof(a[6]) == 6, such as with MSVC 2019
    // if size becomes 1 then prints the obtained permutation 
    if (size == 1)
    {
        memcpy(*permutations, a, n);
        *permutations += 1;
    }
    else
    {
        for (int i = 0; i < size; i++)
        {
            generate_permutations(permutations, a, size - 1, n);

            // if size is odd, swap first and last element
            if (size & 1)
                swap(a, a + size - 1);

            // If size is even, swap ith and last element
            else
                swap(a + i, a + size - 1);
        }
    }
}

int main()
{
    unsigned char permutations[720][6]; // easily access all permutations from 1 to 6
    unsigned char suit_length_indexes[] = { 0, 1, 2, 3, 4, 5 };
    assert(sizeof(suit_length_indexes) == sizeof(permutations[0]));
    unsigned char(*p)[sizeof(suit_length_indexes)] = permutations;
    generate_permutations(&p, suit_length_indexes, sizeof(suit_length_indexes), sizeof(suit_length_indexes));
    for (int i = 0; i < sizeof(permutations) / sizeof(permutations[0]); i++)
        print_permutations(permutations[i], sizeof(suit_length_indexes));
    return 0;
}

答案 27 :(得分:0)

以下是递归和非递归 Heap algorithm 实现的两个经典 kotlin 实现:

非递归:

fun <T> permutationsHeapNonRecursive(list: List<T>): List<List<T>> {
    val result = mutableListOf<List<T>>()
    val c = Array(list.size) {0}
    result.add(list.toList())

    val tempList = list.toMutableList()
    var i = 1
    while (i < list.size) {
        if (c[i] < i) {
            if (i % 2 == 0)
                tempList[0] = tempList[i].also { tempList[i] = tempList[0] }
            else
                tempList[c[i]] = tempList[i].also { tempList[i] = tempList[c[i]] }
            result.add(tempList.toList())
            c[i] += 1
            i = 1
        }
        else {
            c[i] = 0
            i += 1
        }
    }
    return result
}

和,递归:

private fun <T> permutationsHeapRecursiveInternal(k: Int, list: MutableList<T>, outList: MutableList<List<T>>) {
    if (k == 1) {
        outList.add(List<T>(list.size) {list[it]})
    }
    else {
        permutationsHeapRecursiveInternal(k - 1, list, outList)
        for (i in 0 until k-1) {
            if (k % 2 == 0)
                list[i] = list[k-1].also{ list[k-1] = list[i] }
            else
                list[0] = list[k-1].also{ list[k-1] = list[0] }
            permutationsHeapRecursiveInternal(k - 1, list, outList)
        }
    }
}

fun <T> permutationsHeapRecursive(list: List<T>): List<List<T>> {
    val result = mutableListOf<List<T>>()
    if (list.isNotEmpty()) {
        val tempList = MutableList<T>(list.size) { i -> list[i] }
        permutationsHeapRecursiveInternal(tempList.size, tempList, result)
    }
    return result
}

我已经分析了非递归版本,经过一些限制内存分配的调整后,它比递归版本更快。

答案 28 :(得分:0)

要完成,C ++

#include <iostream>
#include <algorithm>
#include <string>

std::string theSeq = "abc";
do
{
  std::cout << theSeq << endl;
} 
while (std::next_permutation(theSeq.begin(), theSeq.end()));

...

abc
acb
bac
bca
cab
cba

答案 29 :(得分:0)

这是java的递归代码,其思路是添加其余字符的前缀:

public static void permutation(String str) { 
    permutation("", str); 
}

private static void permutation(String prefix, String str) {
    int n = str.length();
    if (n == 0) System.out.println(prefix);
    else {
        for (int i = 0; i < n; i++)
            permutation(prefix + str.charAt(i), str);
    }
}

示例:

输入=&#34; ABC&#34 ;; 输出:

ABC ACB BAC BCA 出租车 CBA

答案 30 :(得分:0)

Bourne shell解决方案 - 总共四行(没有测试没有param情况):

test $# -eq 1 && echo "$1" && exit
for i in $*; do
  $0 `echo "$*" | sed -e "s/$i//"` | sed -e "s/^/$i /"
done

答案 31 :(得分:0)

#!/usr/bin/env python
import time

def permutations(sequence):
  # print sequence
  unit = [1, 2, 1, 2, 1]

  if len(sequence) >= 4:
    for i in range(4, (len(sequence) + 1)):
      unit = ((unit + [i - 1]) * i)[:-1]
      # print unit
    for j in unit:
      temp = sequence[j]
      sequence[j] = sequence[0]
      sequence[0] = temp
      yield sequence
  else:
    print 'You can use PEN and PAPER'


# s = [1,2,3,4,5,6,7,8,9,10]
s = [x for x in 'PYTHON']

print s

z = permutations(s)
try:
  while True:
    # time.sleep(0.0001)
    print next(z)
except StopIteration:
    print 'Done'

['P', 'Y', 'T', 'H', 'O', 'N']
['Y', 'P', 'T', 'H', 'O', 'N']
['T', 'P', 'Y', 'H', 'O', 'N']
['P', 'T', 'Y', 'H', 'O', 'N']
['Y', 'T', 'P', 'H', 'O', 'N']
['T', 'Y', 'P', 'H', 'O', 'N']
['H', 'Y', 'P', 'T', 'O', 'N']
['Y', 'H', 'P', 'T', 'O', 'N']
['P', 'H', 'Y', 'T', 'O', 'N']
['H', 'P', 'Y', 'T', 'O', 'N']
['Y', 'P', 'H', 'T', 'O', 'N']
['P', 'Y', 'H', 'T', 'O', 'N']
['T', 'Y', 'H', 'P', 'O', 'N']
['Y', 'T', 'H', 'P', 'O', 'N']
['H', 'T', 'Y', 'P', 'O', 'N']
['T', 'H', 'Y', 'P', 'O', 'N']
['Y', 'H', 'T', 'P', 'O', 'N']
['H', 'Y', 'T', 'P', 'O', 'N']
['P', 'Y', 'T', 'H', 'O', 'N']
.
.
.
['Y', 'T', 'N', 'H', 'O', 'P']
['N', 'T', 'Y', 'H', 'O', 'P']
['T', 'N', 'Y', 'H', 'O', 'P']
['Y', 'N', 'T', 'H', 'O', 'P']
['N', 'Y', 'T', 'H', 'O', 'P']

答案 32 :(得分:0)

这是R中的算法,以防任何人需要避免像我一样需要加载其他库。

permutations <- function(n){
    if(n==1){
        return(matrix(1))
    } else {
        sp <- permutations(n-1)
        p <- nrow(sp)
        A <- matrix(nrow=n*p,ncol=n)
        for(i in 1:n){
            A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i))
        }
        return(A)
    }
}

使用示例:

> matrix(letters[permutations(3)],ncol=3)
     [,1] [,2] [,3]
[1,] "a"  "b"  "c" 
[2,] "a"  "c"  "b" 
[3,] "b"  "a"  "c" 
[4,] "b"  "c"  "a" 
[5,] "c"  "a"  "b" 
[6,] "c"  "b"  "a" 

答案 33 :(得分:0)

这是PHP中的递归解决方案。 WhirlWind的帖子准确地描述了逻辑。值得一提的是,生成所有排列都是在阶乘时间内运行的,因此使用迭代方法可能是个好主意。

public function permute($sofar, $input){
  for($i=0; $i < strlen($input); $i++){
    $diff = strDiff($input,$input[$i]);
    $next = $sofar.$input[$i]; //next contains a permutation, save it
    $this->permute($next, $diff);
  }
}

strDiff函数接受两个字符串s1s2,并返回一个新字符串,其中s1中的所有内容都没有s2中的元素(重复事项)。所以,strDiff('finish','i') =&gt; 'fnish'(第二个'我'已删除)。

答案 34 :(得分:-6)

我能想到解释这个问题的最简单方法是使用一些伪代码

所以

list of 1, 2 ,3
for each item in list
    templist.Add(item)
    for each item2 in list
        if item2 is Not item
            templist.add(item)
               for each item3 in list
                   if item2 is Not item
                      templist.add(item)

                   end if
               Next
            end if

    Next
    permanentListofPermutaitons,add(templist)
    tempList.Clear()
Next

现在很明显,这不是最灵活的方法,而且通过我疲惫的星期天晚上大脑不想考虑这一点,递归地做它会更加实用。如果没有人在早上提出递归版本,我会做一个。