Bir listenin tüm olası permütasyonlarını üreten algoritma?


119

Diyelim ki n öğeden oluşan bir listem var, n olduğunu biliyorum! bu öğeleri sipariş etmenin olası yolları. Bu listenin tüm olası sıralamalarını oluşturmak için bir algoritma nedir? Örnek, [a, b, c] listem var. Algoritma [[a, b, c], [a, c, b,], [b, a, c], [b, c, a], [c, a, b], [c, b , a]].

Bunu burada okuyorum http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations

Ancak Wikipedia açıklamada hiçbir zaman iyi olmamıştı. Ben pek anlamıyorum.


5
Bir keresinde permütasyon üretmekle ilgili başka bir soruya kapsamlı bir cevap yazmıştım. Sanırım ilginizi çekecek: stackoverflow.com/questions/1506078/…
Joren

2
Bu, sorununuzu çözebilir en.wikipedia.org/wiki/Heap's_algorithm
Felix

Yanıtlar:


96

Temel olarak, soldan sağa her bir öğe için, kalan öğelerin tüm permütasyonları oluşturulur (ve her biri mevcut öğelerle birlikte eklenir). Bu, son öğeye ulaşılana kadar yinelemeli olarak (veya ağrıyı seviyorsanız yinelemeli olarak) yapılabilir, bu noktada yalnızca bir olası sipariş vardır.

Yani [1,2,3,4] listesiyle 1 ile başlayan tüm permütasyonlar, sonra 2, ardından 3 ve 4 ile başlayan tüm permütasyonlar üretilir.

Bu, sorunu dört öğeden oluşan bir listenin permütasyonlarını bulmaktan üç öğeden oluşan bir listeye etkili bir şekilde azaltır. 2 ve 1 öğe listesine indirgendikten sonra hepsi bulunacaktır.
3 renkli top kullanan işlem permütasyonlarını gösteren örnek:
Kırmızı, yeşil ve mavi renkli toplar permütasyon görüntülerini sipariş etti( https://en.wikipedia.org/wiki/Permutation#/media/File:Permutations_RGB.svg - https://commons.wikimedia.org/wiki/File:Permutations_RGB adresinden. svg )


2
İlk başta bunu da düşündüm, ancak o zaman mevcut öğe aşağıdakilerin bazıları arasına giremezdi. Dolayısıyla tüm permütasyonlar üretilmeyecektir.
57'de

@LL üzgünüm, cevabımı açıklığa kavuşturmak için "takip" yerine "kaldı" olarak güncelledim. Yine de iyi çalışıyor. Kodu yazıp 4 aldığınızı doğrulayarak kontrol edin! farklı sonuçlar.
WhirlWind

2
int permütasyonlar (int n, vektör <int> a) {statik int num_permutations = 0; eğer (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 ++) {permütasyonlar (n + 1, a); eğer (i <a.size ()) int temp = a [n], a [n] = a [i], a [i] = temp; }} dönüş_permutasyonları; } int ana (void) {vektör <int> v; v.push_back (1); ... dönüş permütasyonları (0, v); }
Somesh

Hata - bir yorumda kodu nasıl biçimlendireceğinizden emin değilim ... Kodu 7 ile test etti ve 5040 aldım. Öneri için @ WhirlWind'e teşekkürler.
Somesh

Her renkten sadece 1 tane yerine 2 veya 3 kırmızı # 1 topunuz varsa bu algo değişmez mi?
Alexander Mills

26

İşte Python'da bir dizi üzerinde yerinde çalışan bir algoritma:

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

Kodu buradan kendiniz deneyebilirsiniz: http://repl.it/J9v


Getiri kısmını açıklar mısınız? Kodu çalıştırmadım. Şimdiden teşekkürler.
Agniswar Bakshi

Stackoverflow.com/questions/104420/… adresindeki Stack Overflow sorusu, 2.6 ve üstü sürümlerde standart bir kitaplık modülü olduğunu ve liste permütasyonlarını almak için bir işlevde 6 satırlık bir çözüm sağlayan bir cevaba sahip olduğunu belirtir.
Edward

@Agniswar Bir bakışta, verim ifadesi oluşturucuları tanımlamak için kullanılır ve yerel değişkenleri yok etmeden arayan kişiye bir sonuç sağlamak için bir işlevin dönüşünü değiştirir. Her çağrıda yeni değişkenler kümesiyle başladığı bir işlevden farklı olarak, bir üretici kaldığı yerden yürütmeye devam edecektir. pythoncentral.io/python-generators-and-yield-keyword
MSS

Bu çözüm, aynı girişlerin bir listesini işlerken işe yaramayacaktır.
KaiserKatze

Paylaşım için teşekkürler. Bu, sezgisel ve etkilidir, ancak çıktı sözlüksel sırada olmasa da.
Sam

16

Burada zaten pek çok iyi çözüm var, ancak bu sorunu kendi başıma nasıl çözdüğümü paylaşmak istiyorum ve bunun kendi çözümünü de bulmak isteyen biri için faydalı olacağını umuyorum.

Sorun hakkında biraz düşündükten sonra şu iki sonuca vardım:

  1. LBoyut listesi için listenin nL 1 , L 2 ... L n öğeleriyle başlayan eşit sayıda çözüm olacaktır . Toplamda n!boyut listesinin permütasyonları olduğundan, her grupta permütasyonlar nalırız n! / n = (n-1)!.
  2. 2 elementin listesi sadece 2 permütasyona sahiptir => [a,b]ve [b,a].

Bu iki basit fikri kullanarak aşağıdaki algoritmayı türettim:

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

Bunu C # 'da şu şekilde uyguladım:

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

Wikipedia'nın "sözlük düzeni" cevabı, yemek kitabı tarzında bana çok açık görünüyor. Algoritma için 14. yüzyıldan kalma bir kökeni gösteriyor!

Bir kontrol olarak Java'da Wikipedia'nın algoritmasının hızlı bir uygulamasını yazdım ve hiç sorun olmadı. Ama örnek olarak Q'nuzda sahip olduğunuz şey "tüm permütasyonların listesi" DEĞİL, "tüm permütasyonların bir LİSTESİ" dir, bu nedenle wikipedia size çok yardımcı olmayacaktır. Permütasyon listelerinin uygulanabilir bir şekilde oluşturulduğu bir dile ihtiyacınız var. Ve inan bana, birkaç milyar uzunluğundaki listeler genellikle zorunlu dillerde ele alınmaz. Makineyi Evrenin ölümüne yaklaştırmadan bir şeyler çıkarmak için listelerin birinci sınıf bir nesne olduğu katı olmayan işlevsel bir programlama dilini gerçekten istiyorsunuz.

Bu kolay. Standart Haskell veya herhangi bir modern FP dilinde:

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

ve

-- 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'in dediği gibi, en baştan başlıyorsunuz.

İmleci, imlecin kendisi de dahil olmak üzere kalan her değerle değiştirirsiniz, bunların hepsi yeni örneklerdir ( örnekte bir int[]ve kullandım array.clone()).

Sonra tüm bu farklı listelerde, imlecin sağda bir tane olduğundan emin olarak permütasyonlar gerçekleştirin.

Kalan değer kalmadığında (imleç sondadır), listeyi yazdırın. Bu durma koşulu.

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

Özyinelemeli her zaman sürdürmek için biraz zihinsel çaba gerektirir. Ve büyük sayılar için, faktöriyel kolayca büyüktür ve yığın taşması kolayca sorun olabilir.

Küçük sayılar için (çoğunlukla karşılaşılan 3 veya 4), çoklu döngüler oldukça basit ve doğrudandır. Döngülerle verilen talihsiz cevapların oylanmaması talihsizdir.

Numaralandırma ile başlayalım (permütasyon yerine). Kodu sözde perl kodu olarak okuyun.

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

Numaralandırmaya permütasyondan daha sık rastlanır, ancak permütasyon gerekiyorsa, sadece koşulları ekleyin:

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

Şimdi, potansiyel olarak büyük listeler için gerçekten genel bir yönteme ihtiyacınız varsa, radix yöntemini kullanabiliriz. İlk olarak, numaralandırma problemini düşünü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

Sayı tabanı artışı esasen sayı sayımıdır (liste elemanlarının sayısına göre).

Şimdi permütasyona ihtiyacınız varsa, kontrolleri döngünün içine ekleyin:

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

Düzenleme: Yukarıdaki kod çalışmalıdır, ancak permütasyon için radix_increment israf olabilir. Öyleyse, zaman pratik bir kaygı ise, radix_increment öğesini permute_inc olarak değiştirmeliyiz:

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                                              

Elbette şimdi bu kod mantıksal olarak daha karmaşık, okuyucunun alıştırması için bırakacağım.


7

görüntü açıklamasını buraya girin

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

Referans: Geeksforgeeks.org


5

Javascript'te permütasyonun nasıl yapılacağını merak eden varsa.

Fikir / pseudocode

  1. her seferinde bir öğe seçin
  2. öğenin geri kalanını permute ve sonra seçilen öğeyi tüm permütasyona ekle

Örneğin. 'a' + permüt (bc). permute bc, bc & cb olacaktır. Şimdi bu ikisini eklerseniz, abc, acb verir. benzer şekilde, b + permute (ac) 'yi seç, bac, bca ... ve devam eder.

şimdi koda bak

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

Bunu anlamak için zaman ayırın. Bu kodu ( JavaScript'te pertumation ) adresinden aldım


Benzer bir şey düşünüyordum ama seçilen öğeyi restParams'ın hem önüne hem de sonuna eklememeli misiniz? Bu durumda, 'abc' için, a seçerseniz, o zaman 'bc' permütasyonları 'bc' ve 'cb'dir. Listeye geri 'a' eklediğinizde, bunu öne 'a + bc' + 'a + cb' olarak eklememeli, aynı zamanda sonuna 'bc + a' + 'cb + a' liste?
Artimus

Sırasıyla 'b' ve 'c' ile başlayarak izin verdiğinizde bu permütasyonları alacaksınız. (yani dış 'for' döngüsünün ikinci ve üçüncü çalışmaları)
Ryan O'Neill

3

Python'da bir tane daha, @ cdiggins olarak yerinde değil, ama anlaşılması daha kolay olduğunu düşünüyorum

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

Herhangi bir büyüklükteki herhangi bir tamsayının permütasyonunu elde etmek için bir kod yazmayı düşünüyordum, yani 4567 sayısını sağlayarak 7654'e kadar tüm olası permütasyonları alıyoruz ... Bu yüzden üzerinde çalıştım ve bir algoritma buldum ve sonunda onu uyguladım, İşte "c" ile yazılmış koddur. Basitçe kopyalayabilir ve herhangi bir açık kaynak derleyicide çalıştırabilirsiniz. Ancak bazı kusurlar ayıklanmayı bekliyor. Lütfen takdir edin.

Kod:

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

Bunu ben yarattım. araştırmaya göre çok permütasyon (qwe, 0, qwe.length-1); Sadece şunu bilmelisin ki, bunu geri dönüşlü veya geri izlemesiz yapabilirsin


3

İşte böyle çalışan bir oyuncak Ruby yöntemi #permutation.to_açılgın insanlar için daha okunaklı olabilir. Çok yavaş, ama aynı zamanda 5 satır.

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

Bu özyinelemeli çözümü ANSI C'de yazdım. Permutate işlevinin her yürütülmesi, tümü tamamlanana kadar bir farklı permütasyon sağlar. Global değişkenler, olgu ve sayı değişkenleri için de kullanılabilir.

#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

Java sürümü

/**
 * @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);
    }
}

Örneğin

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

        }
    }, 3, null, true);
}

çıktı:

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

3

PHP'de

$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

Bir listenin tüm olası permütasyonlarını yazdırmak için Python'daki kod:

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)

Olası tüm permütasyonları elde etmek için bir sözlüksel sıralama algoritması kullandım, ancak yinelemeli bir algoritma daha verimli. Özyinelemeli algoritmanın kodunu burada bulabilirsiniz: Python özyineleme permütasyonları


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

faydalı bir cevap
Ayaz Alifov

2

Scala'da

    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

bu permütasyon için bir java sürümüdür

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

İşte ColdFusion için bir uygulama (ArrayAppend () için birleştirme bağımsız değişkeni nedeniyle CF10 gerektirir):

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'ın yukarıdaki js çözümüne dayanmaktadır.


Algoritmanızın genel stratejisine ilişkin bazı açıklamalar, bu yanıtı geliştirmenin iyi bir yolu olabilir.
Richard

Öyleyse neden olumsuz oy? Bu, çalışan bir uygulamadır.
earachefl

@Richard, genel strateji yukarıda Whirlwind ve diğerleri tarafından açıklanmıştır. Açıklama olmadan uygulama olarak gönderilen diğer tüm cevaplar hakkındaki yorumunuzu görmüyorum.
earachefl

1

Bunun günümüzün yığın akışında çok eski ve hatta konu dışı olduğunu biliyorum, ancak yine de tarayıcınızda çalışması için basit bir javascript cevabına katkıda bulunmak istedim.

debuggerYönerge kesme noktasını da ekledim, böylece bu algoritmanın nasıl çalıştığını görmek için kodda (krom gerekli) adım adım ilerleyebilirsiniz. Geliştirici konsolunuzu Chrome'da açın ( F12Windows veya CMD + OPTION + IMac'te) ve ardından "Kod parçacığını çalıştır" ı tıklayın. Bu, @ WhirlWind'in cevabında sunduğu aynı algoritmayı uygular.

Tarayıcınız debuggeryönergede yürütmeyi duraklatmalıdır . F8Kod yürütmeye devam etmek için kullanın .

Kodu inceleyin ve nasıl çalıştığını görün!

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

Aşağıdaki Java çözümünde, her yinelemede sonuç kümesini klonlamaktan kaçınmak için Dizelerin değişmez olduğu gerçeğinden yararlanıyoruz.

Girdi bir Dize olacaktır, örneğin "abc" ve çıktı tüm olası permütasyonlar olacaktır:

abc
acb
bac
bca
cba
cab

Kod:

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

Dizilere aynı yaklaşım uygulanabilir (bir dizge yerine):

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'daki çözümüm:

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

Fikre öncülük eden bir dilde (lehçesinde) bir uygulama yayınlamadan özyinelemede bir permülasyon problemini çözmekten gerçekten bahsedemezsiniz . Yani, bütünlük adına, Scheme'de yapılabilecek yollardan biri burada.

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

arayarak (permof (list "foo" "bar" "baz"))alacağız:

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

Diğer gönderilerde yeterince açıklandığı için algoritma detaylarına girmeyeceğim. Fikir aynı.

Bununla birlikte, özyinelemeli problemler, Python, C ve Java gibi yıkıcı ortamlarda modellenmesi ve üzerinde düşünülmesi daha zor olma eğilimindeyken, Lisp veya ML'de kısaca ifade edilebilir.


0

İşte PHP'de özyinelemeli bir çözüm. WhirlWind'in yazısı mantığı doğru bir şekilde tanımlıyor. Tüm permütasyonların üretilmesinin faktöryel zamanda çalıştığından bahsetmeye değer, bu yüzden bunun yerine yinelemeli bir yaklaşım kullanmak iyi bir fikir olabilir.

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 fonksiyonu iki dizeyi alır, s1ve s2, ve her şeyi ile yeni bir dize döndürür s1elemanların olmadan s2(suretler madde). Yani, strDiff('finish','i')=> 'fnish'(ikinci 'i' değil kaldırıldı).


0

Burada R'de bir algoritma var, birinin benim zorunda olduğum gibi ek kitaplıklar yüklemekten kaçınması gerekmesi durumunda.

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

Örnek kullanım:

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

Çözüm, diziyi gereksinime göre değiştirmediğinizi gösterir. İkinci permütasyon PYTHNO
Rahul Kadukar

0

Bu, java için yinelemeli bir koddur, fikir, karakterlerin geri kalanını ekleyen bir ön eke sahip olmaktır:

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

Misal:

Giriş = "ABC"; Çıktı:

ABC ACB BAC BCA CAB CBA


1
Güzel fikir, ancak stryinelemeli arama yaparken charAt (i) 'i de kaldırmanız gerektiğini düşünüyorum , aksi takdirde sona ermeyecektir.
Crystal

1
Kopyalayıp yapıştıracaksanız, (1) atıfta bulunmanız ve (2) tüm düzenlemelerin doğru olduğundan emin olmanız gerekir. Atıf için, bu introcs.cs.princeton.edu/java/23recursion/… 'dan perm1'dir . Ayrıca düzenlemeniz yanlıştır: str.substring (0, i) + str.substring (i + 1, n) str ile aynı değildir, çünkü ilki i konumundaki karakteri atlar.
Kevin

0

Tam olmak için, 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

Burada, std :: next_permutation tarafından sağlanan işlevselliğe benzer şekilde, bir sonraki permütasyonu artan sırada sağlayan C ++ 'da yinelemeli olmayan bir çözüm yer almaktadır:

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());
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.