Özyinelemeli bir fonksiyonun yinelemeleri / döngüleri olabilir mi?


12

Özyinelemeli işlevler üzerinde çalışıyorum ve görünüşe göre, kendilerini çağıran işlevler ve yinelemeleri / döngüleri kullanmıyorlar (aksi takdirde yinelemeli bir işlev olmaz).

Ancak, örnekler için internette gezinirken (8-queens özyinelemeli problem), bu işlevi buldum:

private boolean placeQueen(int rows, int queens, int n) {
    boolean result = false;
    if (row < n) {
        while ((queens[row] < n - 1) && !result) {
            queens[row]++;
            if (verify(row,queens,n)) {
                ok = placeQueen(row + 1,queens,n);
            }
        }
        if (!result) {
            queens[row] = -1;
        }
    }else{
        result = true;
    }
    return result;
}

Bir whiledöngü var.

... şimdi biraz kayboldum. Döngüler kullanabilir miyim?


5
Derliyor mu? Evet. Öyleyse neden soruyorsun?
Thomas Eding

6
Tüm yineleme tanımı bir noktada, fonksiyonu döner önce kendi yürütme bir parçası olarak adlandırılan yeniden olabilir (ister s yeniden adlandırılan tek başına ya da aramaları başka bir işlevi olarak). Bu tanım hakkında hiçbir şey döngü olasılığını dışlamaz.
cHao

CHao'nun yorumuna bir ek olarak, özyinelemeli bir işlev kendisinin daha kolay bir sürümünde yeniden çağrılacaktır (aksi takdirde sonsuza kadar döngü yapacaktır). Yörüngeyi alıntılamak için ( Düz İngilizce olarak, özyineleme nedir? ): "Özyinelemeli programlama, kendi sürümlerini daha kolay çözmek için bir sorunu aşamalı olarak azaltma sürecidir." Bu durumda, en zor sürümü placeQueen"yer 8 kraliçeler" ve daha kolay sürümü placeQueen"yer 7 kraliçeler" dir (daha sonra yer 6, vb.)
Brian

Omega çalıştıran her şeyi kullanabilirsiniz. Çok nadiren yazılım özellikleri, hangi programlama tarzını kullanacağınızı belirler - okulda değilseniz ve ödeviniz bunu söylemez.
Apoorv Khurasia

@ThomasEding: Evet, elbette derliyor ve çalışıyor. Ama şu anda sadece mühendislik eğitimi alıyorum - Benim için önemli olan bu noktada programcıların günümüzde kullanma şekli değil katı bir kavram / tanım. Bu yüzden sahip olduğum kavramın doğru olup olmadığını soruyorum (ki öyle değil).
Omega

Yanıtlar:


41

Özyinelemeyi yanlış anladınız: yinelemenin yerini almak için kullanılabilse de, yinelemeli işlevin yinelemelerin kendi içinde dahili olmamasına kesinlikle gerek yoktur.

Bir fonksiyonun özyinelemeli olarak kabul edilmesi için tek gereksinim, doğrudan veya dolaylı olarak kendisini çağırdığı bir kod yolunun varlığıdır. Tüm doğru özyinelemeli işlevler, bir tür koşulludur ve sonsuza dek "tekrar etmelerini" önler.

Yinelemeli işleviniz, geriye doğru izlemeli yinelemeli aramanın yapısını göstermek için idealdir. Çıkış koşulunun kontrolü ile başlar row < nve özyineleme seviyesi hakkında arama kararları vermeye devam eder (yani kraliçe numarası için olası bir pozisyon seçmek row). Her yinelemeden sonra, işlevin şimdiye kadar bulduğu yapılandırma üzerine bir özyinelemeli çağrı yapılır; nihayetinde, derin seviyedeki özyinelemeli çağrıya rowulaştığında " dibe vurur".nn


1
"Doğru" özyinelemeli işlevler için +1, şartlı, heh olmayan yanlış birçok şey var
Jimmy Hoffa

6
+1 "yinelenen" sonsuza kadar `Turtle () {Turtle ();}
Mr.Mindor

1
@ Mr.Mindor Ben "tüm yol aşağı kaplumbağalar" alıntı :)
seviyorum

Bu beni güldürdü :-)
Martijn Verburg

2
"Tüm doğru özyinelemeli işlevlerin de bir tür koşulu vardır, bu da onları" sonsuza kadar tekrar etmelerini "önler." katı olmayan değerlendirme ile doğru değildir.
Pubby

12

Özyinelemeli bir işlevin genel yapısı aşağıdaki gibidir:

myRecursiveFunction(inputValue)
begin
   if evaluateBaseCaseCondition(inputValue)=true then
       return baseCaseValue;
   else
       /*
       Recursive processing
       */
       recursiveResult = myRecursiveFunction(nextRecursiveValue); //nextRecursiveValue could be as simple as inputValue-1
       return recursiveResult;
   end if
end

İşaretlediğim metin /*recursive processing*/herhangi bir şey olabilir. Bu olabilir çözülürken sorun bunu gerektirir ve özyinelemeli aramaları da dahil olsaydı, bir döngü içerir myRecursiveFunction.


1
Bu yanıltıcıdır, çünkü sadece bir özyinelemeli çağrı olduğu anlamına gelir ve özyinelemeli çağrının kendisinin bir döngü içinde olduğu durumları (örneğin B-ağacı geçişi) hemen hemen hariç tutar.
Peter Taylor

@PeterTaylor: Evet, basit tutmaya çalışıyordum.
SinirliWithFormsDesigner

Ya da her bir düğümün 2 çocuğu olması nedeniyle 2 çağrının olacağı düz bir ikili ağacın içinden geçmek gibi bir döngü olmadan birden fazla çağrı bile.
Izkata

6

Döngüler, yinelemeli bir işlevde mutlaka kullanabilirsiniz. Bir işlevi özyinelemeli yapan şey, işlevin yürütme yolunun bir noktasında kendisini çağırmasıdır. Ancak, işlevinizin geri dönemeyeceği sonsuz özyineleme çağrılarını önlemek için bazı koşullarınız olmalıdır.


1

Yinelemeli çağrılar ve döngüler, yinelemeli bir hesaplamayı uygulamanın yalnızca iki yoludur.

Bir whiledöngü kuyruk yinelemeli çağrıya karşılık gelir (örneğin buraya bakınız ), yani iki yineleme arasında ara sonuçları kaydetmeniz gerekmeyen bir yineleme (bir sonraki döngüye girdiğinizde bir döngünün tüm sonuçları hazırdır). Daha sonra tekrar kullanabileceğiniz ara sonuçları saklamanız gerekiyorsa, bir whileyığıyla birlikte bir döngü ( buraya bakın ) veya kuyruk özyinelemesiz (yani rasgele) özyinelemeli çağrı kullanabilirsiniz.

Birçok dil, her iki mekanizmayı da kullanmanıza izin verir ve size daha uygun olanı seçebilir ve hatta kodunuzda karıştırabilirsiniz. C, C ++, Java, vb. Gibi zorunlu dillerde, bir yığına ihtiyacınız olmadığında normalde bir whileveya fordöngü kullanırsınız ve bir yığına ihtiyacınız olduğunda özyinelemeli çağrılar kullanırsınız (örtük olarak çalışma zamanı yığınını kullanırsınız). Haskell (işlevsel bir dil) yineleme kontrol yapısı sunmaz, böylece yinelemeyi gerçekleştirmek için yalnızca yinelemeli çağrıları kullanabilirsiniz.

Örneğinizde (yorumlarıma bakın):

// queens should have type int [] , not int.
private boolean placeQueen(int row, int [] queens, int n)
{
    boolean result = false;
    if (row < n)
    {
        // Iterate with queens[row] = 1 to n - 1.
        // After each iteration, you either have a result
        // in queens, or you have to try the next column for
        // the current row: no intermediate result.
        while ((queens[row] < n - 1) && !result)
        {
            queens[row]++;
            if (verify(row,queens,n))
            {
                // I think you have 'result' here, not 'ok'.
                // This is another loop (iterate on row).
                // The loop is implemented as a recursive call
                // and the previous values of row are stored on
                // the stack so that we can resume with the previous
                // value if the current attempt finds no solution.
                result = placeQueen(row + 1,queens,n);
            }
        }
        if (!result) {
            queens[row] = -1;
        }
    }else{
        result = true;
    }
    return result;
}

1

Özyineleme ile yineleme veya döngü arasında bir ilişki olduğunu düşünmeye hakkınız var. Yinelemeli algoritmalar genellikle manuel veya hatta otomatik olarak kuyruk çağrısı optimizasyonu kullanılarak yinelemeli çözümlere dönüştürülür.

Sekiz kraliçede, özyinelemeli bölüm, geri izleme için gereken verilerin depolanmasıyla ilgilidir. Özyinelemeyi düşündüğünüzde, yığına neyin itildiğini düşünmek değerlidir. Yığın, algoritmada önemli bir rol oynayan değer parametrelerini ve yerel değişkenleri veya bazen dönüş adresi veya görünüşte kullanılan kraliçe sayısı ile ancak algoritma tarafından değiştirilmez.

Sekiz kraliçede gerçekleşen eylem, esasen, ilk sütunda yer alan geçerli sütundaki yinelenen olarak değerlendirilmek üzere geçirdiğimiz şimdiye kadar seçimleri yinelemeli olarak belirlediğimiz birkaç kraliçe için kısmi bir çözümün verilmesidir. kalan sütunlar. Yerel olarak, sekiz kraliçe hangi satırı denediğini takip eder ve geri izleme gerçekleşirse, geri kalan satırlar arasında ilerlemeye veya çalışabilecek başka bir satır bulamazsa geri dönerek parçayı geriye doğru ilerlemeye hazırdır.


0

"Sorunun daha küçük bir sürümünü oluştur" bölümünde döngüler olabilir. Metod kendisini problemin daha küçük bir versiyonunu parametre olarak geçmeye çağırdığı sürece, metod özyinelemelidir. Elbette, bir sorun taşması koşulunu önlemek için sorunun mümkün olan en küçük sürümü çözüldüğünde ve yöntem bir değer döndürdüğünde bir çıkış koşulu sağlanmalıdır.

Sorunuzdaki yöntem yinelemelidir.


0

Özyineleme temelde işlevinizi yeniden çağırır ve özyinelemenin ana avantajı bellek tasarrufu sağlar. Özyinelemenin içinde döngüler olabilir, başka bir işlem gerçekleştirmek için kullanılırlar.


Farklı dilenmek. Birçok algoritma özyinelemeli veya yinelemeli olabilir ve yinelemeli çözüm, yığına aktarılması gereken dönüş adreslerini, parametreleri ve yerel değişkenleri sayarsanız, genellikle çok daha fazla bellek yoğundur. Bazı diller kuyruk özyineleme veya kuyruk çağrısı optimizasyonu için algılama ve optimizasyona yardımcı olur, ancak bu bazen dile veya koda özgüdür.
GeliştiriciDon
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.