yinelemeye karşı yineleme


109

Özyinelemenin kullanıldığı her yerde fordöngü kullanılabilir demek doğru mu? Ve eğer özyineleme genellikle daha yavaşsa, onu fordöngü üzerinden yinelemeyi kullanmanın teknik nedeni nedir?

Ve eğer bir özyinelemeyi bir fordöngüye dönüştürmek her zaman mümkünse , bunu yapmanın pratik bir yolu var mı?


3
recursionvs iteration? iteration = for loopBence.
gongzhitaao

4
: Tom Moertel blogu iteratif koduna özyinelemeli kod dönüştürme dört mükemmel mesajları vardır blog.moertel.com/tags/recursion.html
cjohnson318

Yanıtlar:


148

Özyineleme genellikle çok daha yavaştır, çünkü tüm işlev çağrılarının, arayan işlevlerine geri dönülmesini sağlamak için bir yığın halinde depolanması gerekir. Çoğu durumda, kapsam izolasyonunu uygulamak için belleğin tahsis edilmesi ve kopyalanması gerekir.

Kuyruk arama optimizasyonu gibi bazı optimizasyonlar, özyinelemeleri daha hızlı hale getirir ancak her zaman mümkün değildir ve tüm dillerde uygulanmaz.

Özyinelemeyi kullanmanın ana nedenleri şunlardır:

  • soruna yaklaşımımızı taklit ettiğinde birçok durumda daha sezgisel olduğunu
  • Ağaçlar gibi bazı veri yapılarının özyineleme kullanarak keşfedilmesinin daha kolay olduğunu (veya her durumda yığınlara ihtiyaç duyacağını)

Tabii ki her tekrarlama olabilir işlemci sonuçta ne yapacağı: döngü bir tür olarak modellenebilir. Ve özyinelemenin kendisi, daha doğrudan, işlev çağrılarını ve kapsamlarını bir yığına koymak anlamına gelir. Ancak yinelemeli algoritmanızı döngüsel bir algoritmaya dönüştürmek çok fazla çalışma gerektirebilir ve kodunuzu daha az bakım yapılabilir hale getirebilir: her optimizasyonda olduğu gibi, yalnızca bazı profiller veya kanıtlar gerekli olduğunu gösterdiğinde denenmelidir.


10
Eklemek gerekirse - özyineleme, birçok algoritmada ve genel olarak CS'de merkezi bir rol oynayan indirgeme terimi ile yakından ilgilidir.
SomeWittyUsername

3
Özyinelemenin kodu daha sürdürülebilir kıldığı bir örnek verebilir misiniz? Benim deneyimlerime göre, her zaman tam tersi. Teşekkürler
Yeikel

@Yeikel f(n)n'inci Fibonacci sayısını döndüren bir fonksiyon yazın .
Matt

54

Özyinelemenin kullanıldığı her yerde bir for döngüsü kullanılabilir demek doğru mu?

Evet, çünkü çoğu CPU'daki özyineleme, döngüler ve bir yığın veri yapısı ile modellenmiştir.

Ve eğer özyineleme genellikle daha yavaşsa, onu kullanmanın teknik nedeni nedir?

"Genellikle daha yavaş" değildir: yanlış uygulanan özyinelemedir ve daha yavaştır. Üstelik, modern derleyiciler bazı özyinelemeleri sormadan döngülere dönüştürmede iyidirler.

Ve bir özyinelemeyi bir for döngüsüne dönüştürmek her zaman mümkünse, bunu yapmanın pratik bir yolu var mı?

Yinelemeli açıklandığında en iyi anlaşılan algoritmalar için yinelemeli programlar yazın; En iyi özyinelemeli olarak açıklanan algoritmalar için özyinelemeli programlar yazın.

Örneğin, birçok programlama dilinde ikili ağaçların aranması, hızlı sıralama çalıştırılması ve ifadelerin ayrıştırılması genellikle yinelemeli olarak açıklanır. Bunlar en iyi özyinelemeli olarak kodlanır. Öte yandan, faktörleri hesaplamak ve Fibonacci sayılarını hesaplamak, yinelemeler açısından açıklamak çok daha kolaydır. Onlar için özyineleme kullanmak, bir balyozla sinekleri dövmek gibidir: Balyoz bunda gerçekten iyi bir iş çıkarsa bile, bu iyi bir fikir değildir + .


+ Balyoz benzetmesini Dijkstra'nın "Programlama Disiplini" nden ödünç aldım.


7
Yineleme, yığın çerçeveleri ve benzerlerinin oluşturulması nedeniyle genellikle daha pahalıdır (daha yavaş / daha fazla bellek). Yeterince karmaşık bir problem için doğru uygulandığında fark küçük olabilir, ancak yine de daha pahalıdır. Kuyruk özyineleme optimizasyonu gibi olası istisnalar vardır.
Bernhard Barker

Her durumda tek bir for döngüsünden emin değilim . Daha karmaşık bir özyineleme veya birden fazla değişken içeren bir özyineleme düşünün
SomeWittyUsername

@dasblinkenlight Birden fazla döngüyü tek bir döngüye indirgemek teorik olarak mümkün olabilir, ancak bundan emin değilim.
SomeWittyUsername

@icepack Evet, mümkün. Güzel olmayabilir ama mümkün.
Bernhard Barker

İlk ifadenize katılıyorum emin değilim. CPU'ların kendileri gerçekten özyinelemeyi modellemezler, özyinelemeyi modelleyen CPU üzerinde çalıştırılan talimatlardır. ikinci olarak, bir döngü yapısı dinamik olarak büyüyen ve küçülen bir veri kümesine sahip değildir (zorunlu olarak), burada özyinelemeli bir algoritma genellikle her düzey için özyinelemenin derinliklerinde adım atmalıdır.
trumpetlicks

29

Soru:

Ve eğer özyineleme genellikle daha yavaşsa, onu döngü yinelemesi için kullanmanın teknik nedeni nedir?

Cevap :

Çünkü bazı algoritmalarda bunu yinelemeli olarak çözmek zordur. Derinlik aramasını hem özyinelemeli hem de yinelemeli olarak çözmeye çalışın. DFS'yi yinelemeyle çözmenin çok zor olduğu fikrine kapılacaksınız.

Denenecek başka bir iyi şey: Yinelemeli olarak Birleştirme sıralaması yazmaya çalışın. Biraz zaman alacak.

Soru:

Özyinelemenin kullanıldığı her yerde bir for döngüsü kullanılabilir demek doğru mu?

Cevap :

Evet. Bu konu bunun için çok güzel bir cevaba sahip.

Soru:

Ve bir özyinelemeyi bir for döngüsüne dönüştürmek her zaman mümkünse, bunu yapmanın pratik bir yolu var mı?

Cevap :

Güven Bana. Derinlik aramasını yinelemeli olarak çözmek için kendi sürümünüzü yazmaya çalışın. Bazı problemlerin tekrar tekrar çözülmesinin daha kolay olduğunu fark edeceksiniz.

İpucu: Böl ve ele geçir tekniği ile çözülebilecek bir problemi çözerken yineleme iyidir .


3
Yetkili bir cevap verme girişimini takdir ediyorum ve yazarın zeki olduğundan eminim ama "bana güven" cevabı hemen belli olmayan anlamlı bir soruya yardımcı bir cevap değil. Yinelemeli derinlik arama yapmak için çok basit algoritmalar vardır. Sözde koddaki
jdelman

3

Özyineleme, daha yavaş olmasının yanı sıra, ne kadar derin olduğuna bağlı olarak yığın taşması hatalarına da neden olabilir.


3

Yineleme kullanarak eşdeğer bir yöntem yazmak için açıkça bir yığın kullanmalıyız. Yinelemeli sürümün çözümü için bir yığın gerektirmesi, sorunun özyinelemeden yararlanabilecek kadar zor olduğunu gösterir. Genel bir kural olarak, özyineleme, sabit miktarda bellekle çözülemeyen ve dolayısıyla yinelemeli olarak çözüldüğünde bir yığın gerektiren sorunlar için en uygun olanıdır. Bunu söyledikten sonra, özyineleme ve yineleme, farklı kalıpları takip ederken aynı sonucu gösterebilir. Hangi yöntemin daha iyi çalıştığına karar vermek duruma göre yapılır ve en iyi uygulama, sorunun izlediği kalıba göre seçim yapmaktır.

Örneğin, Üçgen dizinin n'inci üçgen sayısını bulmak için: 1 3 6 10 15… n'inci üçgen sayısını bulmak için yinelemeli bir algoritma kullanan bir program:

Yinelemeli bir algoritma kullanma:

//Triangular.java
import java.util.*;
class Triangular {
   public static int iterativeTriangular(int n) {
      int sum = 0;
      for (int i = 1; i <= n; i ++)
         sum += i;
      return sum;
   }
   public static void main(String args[]) {
      Scanner stdin = new Scanner(System.in);
      System.out.print("Please enter a number: ");
      int n = stdin.nextInt();
      System.out.println("The " + n + "-th triangular number is: " + 
                            iterativeTriangular(n));
   }
}//enter code here

Özyinelemeli bir algoritma kullanma:

//Triangular.java
import java.util.*;
class Triangular {
   public static int recursiveTriangular(int n) {
      if (n == 1)
     return 1;  
      return recursiveTriangular(n-1) + n; 
   }

   public static void main(String args[]) {
      Scanner stdin = new Scanner(System.in);
      System.out.print("Please enter a number: ");
      int n = stdin.nextInt();
      System.out.println("The " + n + "-th triangular number is: " + 
                             recursiveTriangular(n)); 
   }
}

1

Yanıtların çoğu, iterative= olduğunu varsayıyor gibi görünüyor for loop. Eğer for döngüsünüz kısıtlanmamışsa ( a la C, döngü sayacınızla istediğinizi yapabilirsiniz), o zaman bu doğrudur. Bir buysa gerçek for döngü sonra ise, (el döngü sayacını değiştiremezsiniz nerede Python ya da en işlevsel dilde olduğu gibi söylemek) değil doğru.

Tüm (hesaplanabilir) işlevler hem özyinelemeli olarak hem de whiledöngüler (veya temelde aynı şey olan koşullu sıçramalar) kullanılarak uygulanabilir. Kendinizi gerçekten sınırlarsanız for loops, bu işlevlerin yalnızca bir alt kümesini elde edersiniz (ilkel özyinelemeli olanlar, temel işlemleriniz makul ise). Kabul edilirse, pratikte kodlayacağınız her bir işlevi içeren oldukça büyük bir alt kümedir.

Çok daha önemli olan şey, birçok işlevin yinelemeli olarak uygulanması çok kolay ve yinelemeli olarak uygulanması çok zor olmasıdır (çağrı yığınınızı manuel olarak yönetmek sayılmaz).


1

Evet, hem adı geçen tarafından Thanakron Tandavas ,

Böl ve fethet tekniği ile çözülebilecek bir problemi çözerken yineleme iyidir.

Örneğin: Hanoi Kuleleri

  1. Artan boyutta N yüzük
  2. 3 kutuplu
  3. Halkalar kutup 1'e istiflenmeye başlar. Amaç, halkaları kutup 3'e istiflenecek şekilde hareket ettirmektir ... Ama
    • Bir seferde yalnızca bir yüzük hareket ettirilebilir.
    • Küçük yüzüğün üstüne daha büyük bir yüzük koyamazsınız.
  4. Yinelemeli çözüm "güçlü ama çirkin" dir; özyinelemeli çözüm “zariftir”.

İlginç bir örnek. Sanırım MC Er "The Towers of Hanoi and Binary Numerals" adlı makaleyi biliyorsunuz. Ayrıca 3brown1blue tarafından harika bir videoda işlendi.
Andrestand

0

Bilgisayar bilimi profesörümün, yinelemeli çözümleri olan tüm sorunların da yinelemeli çözümleri olduğunu söylediğini hatırlıyorum. Özyinelemeli bir çözümün genellikle daha yavaş olduğunu, ancak yinelemeli çözümlere göre akıl yürütmesi ve kodlaması daha kolay olduğunda sıklıkla kullanıldığını söylüyor.

Ancak, daha gelişmiş özyinelemeli çözümler söz konusu olduğunda, her zaman basit bir fordöngü kullanarak bunları uygulayabileceğine inanmıyorum .


Yinelemeli bir algoritmayı yinelemeli bir algoritmaya dönüştürmek her zaman mümkündür (yığınlar kullanarak). Özellikle basit bir döngü ile sonuçlanmayabilirsiniz, ancak bu mümkündür.
Bernhard Barker

-4

özyineleme + ezberleme, saf yinelemeli bir yaklaşımla karşılaştırıldığında daha etkili bir çözüme yol açabilir, örneğin şunu kontrol edin: http://jsperf.com/fibonacci-memoized-vs-iterative-for-large-n


3
Herhangi bir özyinelemeli kod, yığınlar kullanılarak işlevsel olarak özdeş yinelemeli koda dönüştürülebilir. Gösterdiğiniz fark, özyineleme ve yineleme arasındaki fark değil, aynı sorunu çözmek için iki yaklaşım arasındaki farktır.
Bernhard Barker

-6

Kısa cevap: Takas, özyinelemenin daha hızlı olması ve döngülerin neredeyse tüm durumlarda daha az bellek almasıdır. Bununla birlikte, genellikle daha hızlı çalışmasını sağlamak için for döngüsünü veya özyinelemeyi değiştirmenin yolları vardır.

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.