SORU
9 Aralık 2008, Salı


Üreten tembel permütasyon

Bir algoritma için Clojure onları tembel bir listesini yapabilirim böyle bir şekilde bir dizi permütasyon oluşturmak için arıyorum. yani her permütasyon yalvarıyorum kadar hesaplanmaz nerede permütasyon bir liste üzerinde yineleme yapmak istiyorum, ve permütasyon tüm bellekte aynı anda saklı olmak zorunda değil.

Alternatif olarak benim aradığım bir algoritma nerede verilen belli bir set olacak dönüş "ileri" permütasyon bir dizi, böyle bir şekilde sürekli arama işlevi kendi başına çıkış döngüsü boyunca permütasyon orijinal set, biraz düzen (ne sırası önemli değil).

Böyle bir algoritma var mı? Gördüğüm permütasyon üreten algoritmalar en çok büyük kümeleri ölçekli görünmüyor ki, hepsini bir kerede (genellikle yinelemeli olarak), üretmek eğilimindedir. Clojure bir uygulama (veya başka bir fonksiyonel dil) yararlı olurdu ama kesinliği tespit edebilirim.

CEVAP
9 Aralık 2008, Salı


Evet, orada"bir sonraki permütasyon" algoritma ve oldukça basit. C standart şablon kitaplığı (STL) işlevi next_permutation çağırdı.

Algoritma aslında bulurgelecekpermütasyon -- lexicographically sonraki. Fikir şu: bir dizi verilir, "32541". sanırım Bir sonraki permütasyon nedir?

Eğer düşünürseniz, görürsünüz "34125". Ve düşüncelerinizi bu muhtemelen bir şey vardı: "32541",

  • yok yola devam "32" sabit ve bir sonraki permütasyon "541" parçası, çünkü permütasyon zaten son 5,4 ve 1 -- sıralanmış bir miktar sipariş.
  • Değişim" en küçük sayı daha büyük aslında, daha büyük bir şey için "541" bölümü, 4 yani. "2 Zorundasınız
  • Şimdi, bir kez permütasyon olarak başlayacak karar verdik "", geri kalanı cevabı bu artan içinde olmalıdır, "34125". 34

Algoritma tam olarak akıl bu hattı uygulamak için:

  1. En uzun "kuyruk" azalan sırası. emretti bul ("541" bölümü.)
  2. Sadece kuyruk önce numarasını değiştirmek ("2") kuyruk en küçük numara daha büyük (4).
  3. Artan sıralama kuyruğu gibi.

(1.) verimli sonundan başlayarak ve geriye doğru bir önceki öğenin geçerli öğe daha küçük olduğu sürece giderek. (2.) sadece takas "4" '2 olacak", "34521". Bunu yaptığınızda, bir sıralama algoritması (3.), kullanarak önleyebilirsiniz kuyruk vardı, ve hala (bunu düşün) çünkü, azalan sıralı, sadece geri alınması gerekiyor.

C kodu mu tam olarak bu (bak kaynağı /usr/include/c /4.0.0/bits/stl_algo.h sistemi veya this article); olmalı basit tercüme etmek için dilinizi: [Okuma "Bidirectionalİterator" "işaretçi", eğer bilginiz C yineleyicisi. Kod dönerse bir sonraki permütasyon ise yok false, yani zaten azalan.]

template <class BidirectionalIterator>
bool next_permutation(BidirectionalIterator first,
                      BidirectionalIterator last) {
    if (first == last) return false;
    BidirectionalIterator i = first;
      i;
    if (i == last) return false;
    i = last;
    --i;
    for(;;) {
        BidirectionalIterator ii = i--;
        if (*i <*ii) {
            BidirectionalIterator j = last;
            while (!(*i <*--j));
            iter_swap(i, j);
            reverse(ii, last);
            return true;
        }
        if (i == first) {
            reverse(first, last);
            return false;
        }
    }
}

Permütasyon başına(n) O zaman alabilir, ama eğer bu konuda daha dikkatli düşünürsen, O(n!) gereken kanıtlayabilirim gelebilir her zaman(1) -- sürekli zaman permütasyon başına O kadar da toplam permütasyon,.

İyi bir şey olduğunu algoritma çalışır hatta bir sıra ile tekrarlanan elemanları ile, diyelim ki, "232254421", o-cekti bulmak kuyruk "olarak 54421" takas "2" ve "4" (yani "232454221"), geriye kalanını veren "232412245", hangi bir sonraki permütasyon.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Missouri Star Quilt Company

    Missouri Sta

    18 ŞUBAT 2009
  • MotoManTV

    MotoManTV

    10 Aralık 2009
  • Tire Rack

    Tire Rack

    31 Mayıs 2007