목록의 가능한 모든 순열을 생성하는 알고리즘?


119

n 개의 요소 목록이 있다고 가정하면 n 개가 있다는 것을 압니다! 이러한 요소를 주문하는 가능한 방법. 이 목록의 가능한 모든 순서를 생성하는 알고리즘은 무엇입니까? 예를 들어, 목록 [a, b, c]가 있습니다. 알고리즘은 [[a, b, c], [a, c, b,], [b, a, c], [b, c, a], [c, a, b], [c, b , ㅏ]].

나는 여기 http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations를 읽고 있습니다

그러나 Wikipedia는 설명을 잘하지 못했습니다. 나는 그것을 많이 이해하지 못한다.


5
한 번 순열 생성에 대한 또 다른 질문에 대한 광범위한 답변을 썼습니다. 나는 당신에게 관심이 될 것 같아요 : stackoverflow.com/questions/1506078/...
Joren

2
이 문제를 해결할 수 있습니다 en.wikipedia.org/wiki/Heap's_algorithm
펠릭스

답변:


96

기본적으로 각 항목에 대해 왼쪽에서 오른쪽으로 나머지 항목의 모든 순열이 생성됩니다 (각 항목은 현재 요소와 함께 추가됨). 이 작업은 가능한 순서가 하나 뿐인 마지막 항목에 도달 할 때까지 반복적으로 (또는 고통이 마음에 들면 반복적으로) 수행 할 수 있습니다.

따라서 [1,2,3,4] 목록을 사용하면 1로 시작하는 모든 순열이 생성되고, 2, 3, 4로 시작하는 모든 순열이 생성됩니다.

이는 4 개 항목 목록의 순열을 찾는 것에서 3 개 항목 목록으로 문제를 효과적으로 줄입니다. 2 개로 줄인 다음 1 개 항목 목록으로 줄이면 모두 검색됩니다.
: 예 3 개 색 공을 사용하여 프로세스 순열 보여주는
빨강, 녹색 및 파랑 색 공 순서 순열 이미지(에서 https://en.wikipedia.org/wiki/Permutation#/media/File:Permutations_RGB.svg - https://commons.wikimedia.org/wiki/File:Permutations_RGB합니다. svg )


2
처음에는 이것에 대해 생각했지만 현재 요소가 다음 중 일부 사이에 들어 가지 않을 것입니다. 따라서 모든 순열이 생성되는 것은 아닙니다.
fent apr

@LLer 죄송합니다. 명확하게하기 위해 "folllowing"에서 "remaining"으로 내 대답을 업데이트했습니다. 그래도 잘 작동합니다. 코드를 작성하고 4를 얻었는지 확인하여 확인하십시오! 다른 결과.
WhirlWind

2
int 순열 (int n, vector <int> a) {static int num_permutations = 0; if (n == (a.size ()-1)) {for (int i = 0; i <a.size (); i ++) cout << a [i] << ""; cout << "\ n"; num_permutations ++; } else {for (int i = n + 1; i <= a.size (); i ++) {순열 (n + 1, a); if (i <a.size ()) int temp = a [n], a [n] = a [i], a [i] = temp; }} return num_permutations; } int main (void) {vector <int> v; v.push_back (1); ... return permutations (0, v); }
Somesh 2014

죄송합니다-주석에서 코드 형식을 지정하는 방법을 모르겠습니다 ... 코드를 7로 테스트하고 5040을 얻었습니다. 제안 해 주신 @WhirlWind에게 감사드립니다.
Somesh 2014.11.04

각 색상의 1 개가 아닌 2 개 또는 3 개의 빨간색 # 1 공을 가질 수 있다면이 알고리즘이 변하지 않습니까?
Alexander Mills

26

다음은 배열에서 작동하는 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 에서 직접 코드를 시도해 볼 수 있습니다.


수율 부분을 설명해 주시겠습니까? 코드를 드라 이런 할 수 없었습니다. 미리 감사드립니다.
Agniswar Bakshi 2016 년

스택 오버플로 질문 stackoverflow.com/questions/104420/… 은 버전 2.6 이상에 표준 라이브러리 모듈이 있으며 목록 순열을 가져 오는 함수에 6 줄 솔루션을 제공하는 답변이 있습니다.
에드워드

@Agniswar 한 눈에, yield 문은 생성기를 정의하는 데 사용되며 함수의 반환을 대체하여 지역 변수를 파괴하지 않고 호출자에게 결과를 제공합니다. 각 호출에서 새로운 변수 세트로 시작하는 함수와 달리 생성기는 중단 된 위치에서 실행을 재개합니다. pythoncentral.io/python-generators-and-yield-keyword
MSS

이 솔루션은 동일한 항목 목록을 처리 할 때 작동하지 않습니다.
KaiserKatze

공유해 주셔서 감사합니다. 이는 직관적이고 효율적이지만 출력이 사전 순으로되어 있지는 않습니다.
Sam

16

여기에는 이미 많은 좋은 해결책이 있지만이 문제를 어떻게 해결했는지 공유하고 자신의 해결책을 도출하고 싶은 사람에게 도움이되기를 바랍니다.

문제에 대해 숙고 한 후 다음 두 가지 결론을 내 렸습니다.

  1. L크기 목록 의 n경우 L 1 , L로 시작하는 동일한 수의 솔루션이 있습니다. 2 ... L n 요소로 . 전체적으로 n!size 목록의 순열이 있으므로 각 그룹에서 순열을 n얻습니다 n! / n = (n-1)!.
  2. 2 개의 요소 목록에는 순열 => [a,b][b,a].

이 두 가지 간단한 아이디어를 사용하여 다음 알고리즘을 도출했습니다.

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;
            }

        }
    }
}

16

"사전 순서"에 대한 위키피디아의 대답은 나에게 요리 책 스타일에서 완벽하게 명백해 보인다. 그것은 알고리즘의 14 세기 기원을 인용합니다!

나는 방금 Wikipedia의 알고리즘의 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]

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);
    }
}

8

재귀는 항상 유지하기 위해 약간의 정신적 노력이 필요합니다. 그리고 큰 숫자의 경우 팩토리얼은 쉽게 거대하고 스택 오버플로가 쉽게 문제가됩니다.

작은 숫자 (대부분 발생하는 3 또는 4)의 경우 다중 루프는 매우 간단하고 간단합니다. 루프가있는 불행한 답변이 투표되지 않았습니다.

(순열이 아닌) 열거부터 시작하겠습니다. 코드를 의사 펄 코드로 읽으십시오.

$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"

이제 큰 목록에 대해 잠재적으로 일반적인 방법이 필요한 경우 기수 방법을 사용할 수 있습니다. 먼저 열거 문제를 고려하십시오.

$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

기수 증분은 기본적으로 숫자 계산입니다 (목록 요소 수의 기준).

이제 순열이 필요하면 루프 내부에 검사를 추가하십시오.

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                                              

물론 이제이 코드는 논리적으로 더 복잡하므로 독자의 연습을 위해 떠날 것입니다.


7

여기에 이미지 설명 입력

// 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


5

누구든지 자바 스크립트에서 순열을 수행하는 방법을 궁금해한다면.

아이디어 / 의사 코드

  1. 한 번에 하나의 요소를 선택
  2. 나머지 요소를 순열 한 다음 선택한 요소를 모든 순열에 추가합니다.

예를 들면. 'a'+ permute (bc). bc의 permute는 bc & cb가 될 것입니다. 이제이 두 개를 추가하면 abc, acb가 제공됩니다. 유사하게, pick 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를 )


나는 비슷한 것을 생각하고 있었지만 선택한 요소를 restParams의 앞면과 끝에 모두 추가해서는 안됩니까? 이 경우 'abc'의 경우 a를 선택하면 'bc'순열은 'bc'와 'cb'입니다. 'a'를 목록에 다시 추가 할 때 앞에 'a + bc'+ 'a + cb'로 추가하지 말고 끝에 'bc + a'+ 'cb + a'로 추가하면 안됩니다. 목록?
Artimus

각각 'b'와 'c'로 시작하는 순열을하면 이러한 순열을 얻을 수 있습니다. (즉, 외부 'for'루프의 두 번째 및 세 번째 실행)
Ryan O'Neill

3

파이썬의 다른 하나, @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

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;
}

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); 아시다시피 백 트랙을 사용하거나 사용하지 않고 할 수 있습니다.


3

#permutation.to_a미친 사람들에게 더 읽기 쉬운 것처럼 작동하는 장난감 Ruby 메서드 가 있습니다. 느리지 만 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

3

이 재귀 솔루션을 ANSI C로 작성했습니다. Permutate 함수의 각 실행은 모두 완료 될 때까지 하나의 다른 순열을 제공합니다. 변수 fact 및 count에 전역 변수를 사용할 수도 있습니다.

#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;
}

3

자바 버전

/**
 * @param uniqueList
 * @param permutationSize
 * @param permutation
 * @param only            Only show the permutation of permutationSize,
 *                        else show all permutation of less than or equal to permutationSize.
 */
public static void my_permutationOf(List<Integer> uniqueList, int permutationSize, List<Integer> permutation, boolean only) {
    if (permutation == null) {
        assert 0 < permutationSize && permutationSize <= uniqueList.size();
        permutation = new ArrayList<>(permutationSize);
        if (!only) {
            System.out.println(Arrays.toString(permutation.toArray()));
        }
    }
    for (int i : uniqueList) {
        if (permutation.contains(i)) {
            continue;
        }
        permutation.add(i);
        if (!only) {
            System.out.println(Arrays.toString(permutation.toArray()));
        } else if (permutation.size() == permutationSize) {
            System.out.println(Arrays.toString(permutation.toArray()));
        }
        if (permutation.size() < permutationSize) {
            my_permutationOf(uniqueList, permutationSize, permutation, only);
        }
        permutation.remove(permutation.size() - 1);
    }
}

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

        }
    }, 3, null, true);
}

산출:

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

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);

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 재귀 순열


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);
    }
}

그것은 유용한 답변입니다
AYAZ Alifov

2

스칼라에서

    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
}

2

이것은 순열을위한 자바 버전입니다

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;
    }
}

2

다음은 ColdFusion에 대한 구현입니다 (ArrayAppend ()에 대한 병합 인수 때문에 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 솔루션을 기반으로합니다.


알고리즘의 전반적인 전략에 대한 설명이이 답변을 개선하는 좋은 방법이 될 것입니다.
Richard

그렇다면 왜 반대표를 던졌습니까? 이것은 작동하는 구현입니다.
earachefl

@Richard, 전반적인 전략은 Whirlwind와 다른 사람들이 위에서 설명했습니다. 설명없이 구현으로 게시 된 다른 모든 답변에 대한 귀하의 의견을 보지 못했습니다.
earachefl

1

나는 이것이 오늘날의 stackoverflow에서 매우 오래되고 주제에서 벗어난 것을 알고 있지만 브라우저에서 실행된다는 간단한 이유 때문에 친숙한 자바 스크립트 답변을 제공하고 싶었습니다.

또한 debugger이 알고리즘이 어떻게 작동하는지 확인하기 위해 코드 (크롬 필요)를 단계별로 실행할 수 있도록 지시문 중단 점을 추가했습니다 . 크롬에서 개발 콘솔을 엽니 다 ( F12Windows 또는CMD + OPTION + I Mac) 다음 "Run code snippet"을 클릭합니다. 이것은 @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]));


1

다음 Java 솔루션에서는 반복 할 때마다 결과 집합이 복제되는 것을 방지하기 위해 문자열이 불변이라는 사실을 활용합니다.

입력은 "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);
        }
    }
}

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;
    }
}

1

아이디어개척 한 (방언) 언어로 구현을 게시하지 않고는 재귀에서 퍼멀 테이션 문제를 해결하는 것에 대해 말할 수 없습니다 . 따라서 완전성을 위해 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에서는 간결하게 표현할 수 있습니다.


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 함수는 두 문자열을 소요 s1하고 s2, 그리고 모든 것을 가진 새로운 문자열을 반환 s1요소없이 s2(중복 문제). 따라서 strDiff('finish','i')=> 'fnish'(두 번째 'i'는 제거 되지 않습니다 ).


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" 

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']

솔루션은 요구 사항에 따라 문자열을 변경하지 않았 음을 보여줍니다. 두 번째 순열 PYTHNO 했어야
라훌 Kadukar

0

이것은 자바에 대한 재귀 코드이며, 아이디어는 나머지 문자를 추가하는 접두사를 갖는 것입니다.

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);
    }
}

예:

입력 = "ABC"; 산출:

ABC ACB BAC BCA CAB CBA


1
좋은 생각이지만 str재귀 적으로 호출 할 때 charAt (i)도 제거해야한다고 생각합니다 . 그렇지 않으면 종료되지 않습니다.
크리스탈

1
복사하여 붙여 넣으려면 (1) 속성을 부여하고 (2) 편집 내용이 올바른지 확인해야합니다. 어트 리뷰 션의 경우 introcs.cs.princeton.edu/java/23recursion/…의 perm1 입니다. 또한 편집이 잘못되었습니다. str.substring (0, i) + str.substring (i + 1, n)은 str과 동일하지 않습니다. 전자가 i 위치의 문자를 생략하기 때문입니다.
케빈

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

0

다음은 std :: next_permutation에서 제공하는 기능과 유사하게 다음 순열을 오름차순으로 제공하는 C ++의 비 재귀 솔루션입니다.

void permute_next(vector<int>& v)
{
  if (v.size() < 2)
    return;

  if (v.size() == 2)
  { 
    int tmp = v[0];
    v[0] = v[1];
    v[1] = tmp;
    return;
  }

  // Step 1: find first ascending-ordered pair from right to left
  int i = v.size()-2;
  while(i>=0)
  { 
    if (v[i] < v[i+1])
      break;
    i--;
  }
  if (i<0) // vector fully sorted in descending order (last permutation)
  {
    //resort in ascending order and return
    sort(v.begin(), v.end());
    return;
  }

  // Step 2: swap v[i] with next higher element of remaining elements
  int pos = i+1;
  int val = v[pos];
  for(int k=i+2; k<v.size(); k++)
    if(v[k] < val && v[k] > v[i])
    {
      pos = k;
      val = v[k];
    }
  v[pos] = v[i];
  v[i] = val;

  // Step 3: sort remaining elements from i+1 ... end
  sort(v.begin()+i+1, v.end());
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.