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

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는 설명을 잘하지 못했습니다. 나는 그것을 많이 이해하지 못한다.



답변

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

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

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


답변

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


답변

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

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

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

        }
    }
}


답변

“사전 순서”에 대한 위키피디아의 대답은 나에게 요리 책 스타일에서 완벽하게 명백해 보인다. 그것은 알고리즘의 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]


답변

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


답변

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

작은 숫자 (대부분 발생하는 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

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


답변

여기에 이미지 설명 입력

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