Tekrarlama ile yapılabilecek, döngü ile yapılamayan bir şey var mı?


126

Özyineleme kullanmanın bir döngü kullanmaktan daha iyi olduğu zamanlar vardır ve özgeçmiş kullanmak özyineleme kullanmaktan daha iyidir. "Doğru" olanı seçmek, kaynakları koruyabilir ve / veya daha az kod satırına neden olabilir.

Bir görevin döngü yerine özyinelemeyi kullanarak yapabileceği durumlar var mı?


13
Bundan cidden şüpheliyim. Özyineleme yüceltilmiş bir döngüdür.
Orbit

6
Cevapların gittiği farklı yönleri görerek (ve daha iyi bir cevap vermekte kendim başaramadım), eğer biraz daha arka plan ve ne tür bir cevap verdiğinizde, bir iyiliğe cevap vermeye çalışan birini yapabilirsiniz. Varsayım makineleri için teorik bir kanıt ister misiniz (sınırsız depolama ve çalışma süresi ile)? Veya pratik örnekler? (“Gülünç olarak karmaşık olurdu”, “yapılamaz” olarak nitelendirilebilir.) Veya farklı bir şey mi?
5gon12eder

8
@LightnessRacesinOrbit Anadili İngilizce olmayan kulağım için, "Özyineleme yüceltilmiş bir döngüdür", kastettiğin "Her yerde özyinelemeli arama yerine döngüsel bir yapı kullanabilirsin, ve kavram gerçekten kendi adını haketmiyor" demek istiyorsun. . Belki de "yüceltilmiş bir şey" deyimini yanlış yorumluyorum o zaman.
Hyde

13
Ackermann işlevi ne durumda? en.wikipedia.org/wiki/Ackermann_function , özellikle yararlı değil ama döngü üzerinden yapmak imkansız. (Bu videoyu ayrıca youtube.com/watch?v=i7sm9dzFtEI Computerphile tarafından da kontrol etmek isteyebilirsiniz )
WizardOfMenlo 22:15

8
@WizardOfMenlo befunge kodu ERRE çözümünün bir uygulamasıdır (aynı zamanda yığınla etkileşimli bir çözümdür ...). Bir yığın ile yinelemeli bir yaklaşım özyinelemeli bir çağrı taklit edebilir. Uygun şekilde güçlü olan herhangi bir programlamada, bir döngü yapısı diğerini taklit etmek için kullanılabilir. Talimatlara sahip kayıt makinesi INC (r), JZDEC (r, z)bir Turing makinesi uygulayabilir. 'Özyineleme' yok - Sıfır başka bir Düşüşse bu bir Atlama demektir. Ackermann işlevi hesaplanabilirse (bu), bu kayıt makinesi bunu yapabilir.

Yanıtlar:


164

Evet ve hayır. Sonuçta, özyinelemenin döngü yapamayacağını hesaplayabileceği hiçbir şey yoktur, ancak döngü daha fazla su tesisatı gerektirir. Bu nedenle, özyinelemelerin döngülerin yapamayacağı bir şey yapması bazı işleri süper kolaylaştırmaktır.

Bir ağaca yürü. Özyinelemeli bir ağaçta yürümek aptalca kolaydır. Dünyadaki en doğal şey bu. Döngü ile bir ağaçta yürümek çok daha az kolaydır. Yaptıklarınızı takip etmek için bir yığın ya da başka bir veri yapısını korumalısınız.

Genellikle, bir problemin özyinelemeli çözümü daha güzel olur. Bu teknik bir terimdir ve önemli.


120
Temel olarak, özyineleme yerine döngüler yapmak, yığını elle işlemek anlamına gelir.
Silviu Burcea,

15
... yığın (lar) . Aşağıdaki durum birden fazla yığının olmasını şiddetle tercih edebilir. AAğaçta bir şey bulan özyinelemeli bir işlevi düşünün . Her zaman Abu şeyle karşılaştığında B, alt ağaçta başlatıldığı konumda ilgili bir şey bulan başka bir özyinelemeli işlev başlatır A. Özyinleşmeyi Btamamladıktan sonra geri döner Ave ikincisi kendi özyinelemesine devam eder. Biri bir tanesini bir tanesine ilan edebilir veya Abir tanesini ilmeğin içine Bkoyabilir . Kişi tek bir yığın kullanmakta ısrar ederse, işler gerçekten karmaşıklaşır. BA
rwong

35
Therefore, the one thing recursion can do that loops can't is make some tasks super easy. Döngülerin bu özyinelemeyi yapabileceği tek şey bazı işleri süper kolaylaştırmaktır. Çoğu doğal yinelemeli problemleri saf özyineleme aşamasından kuyruk özyineleme biçimine dönüştürmek için yapmanız gereken çirkin, sezgisel olmayan şeyleri gördünüz mü?
Mason Wheeler,

10
Gibilerin "şeyler" daha iyi bir özyineleme-operatör içine kapsüllü edilebilir zamanın @MasonWheeler% 99 mapveya fold(aslında bunları ilkelleri dikkate seçerseniz, size kullanabilirsiniz düşünmek fold/ unfolddöngüler için üçüncü bir alternatif olarak ya da tekrarlama). Kütüphane kodu yazmıyorsanız, yinelemenin uygulanması konusunda endişelenmeniz gereken pek çok durum yoktur, gerçekleştirmesi gereken görev yerine pratikte, bu açık döngüler ve açık yinelemenin aynı derecede zayıf olduğu anlamına gelir. en üst düzeyde kaçınılması gereken soyutlamalar.
Leushenko

7
Alt dizeleri yinelemeli olarak karşılaştırarak iki dizeyi karşılaştırabilir, ancak daha iyi performans göstermesi ve okuyucunun daha net olması için uygun olmayan bir eşleşme elde edinceye kadar her karakteri tek tek karşılaştırmanız yeterlidir.
Steven Burnap

78

Hayır.

Aşağı Ulaşım çok hesaplamak için gerekli minimum temelleri, sadece (tek başına bu yeterli değildir, daha ziyade gerekli bir bileşendir) döngüye gerekiyor. Önemli değil nasıl .

Bir Turing Makinesi uygulayabilen herhangi bir programlama diline Turing complete denir . Ve tamamlanan birçok dil var.

En sevdiğim dil, "gerçekten işe yarıyor mu?" Turing Bütünlük olmasıdır FRACTRAN olup, tam Turing . Bir döngü yapısına sahiptir ve içinde bir Turing makinesi kullanabilirsiniz. Böylece, hesaplanabilir her şey, özyinimi olmayan bir dilde uygulanabilir. Bu nedenle, özyinelemenin size basit döngülemenin yapamayacağı hesaplanabilirlik açısından verebileceği hiçbir şey yoktur.

Bu gerçekten birkaç noktaya kaynar:

  • Hesaplanabilir olan her şey bir Turing makinesinde hesaplanabilir
  • Turing makinesi uygulayabilen herhangi bir dil (Turing complete olarak adlandırılır), başka bir dilin yapabileceği her şeyi hesaplayabilir
  • Turing makineleri, öznitelikten yoksun olan dillerde (ve yalnızca diğer bazı esoguanlara girdiğinizde özyinelemeye sahip olan diğerleri olduğu için) olduğu için , özyinelemeyle yapamayacağınız hiçbir şey olmadığı kesindir. döngü (ve özyineleme ile yapamayacağınız bir döngü ile yapabileceğiniz hiçbir şey).

Bu, döngüden ziyade özyinelemeden, özyinelemeden çok döngüden daha kolay düşünülen bazı problem sınıfları olduğunu söylemek değildir. Ancak, bu araçlar da aynı derecede güçlü.

Ve bunu 'esolang' uç noktasına götürürken (çoğunlukla Turing'i oldukça garip şekillerde uygulayan ve bulabileceğiniz şeyler bulabileceğiniz için), bu, eşanlamlıların herhangi bir şekilde isteğe bağlı olduğu anlamına gelmez. Yanlışlıkla Toplanan Magic, Sendmail, MediaWiki şablonları ve Scala tipi sistem dahil olmak üzere tamamen Turing'in tamamlandığı bir şeyler listesi var . Bunların birçoğu, pratik bir şeyler yapmak konusunda en iyisi olmaktan uzak, sadece bu araçları kullanarak hesaplanabilir bir şeyi hesaplayabilirsiniz.


Bu eşdeğerlik, kuyruk çağrısı olarak bilinen belirli bir özyineleme türüne girdiğinizde özellikle ilginç olabilir .

Söyleyelim, şöyle yazılmış bir faktörleme yönteminiz varsa:

int fact(int n) {
    return fact(n, 1);
}

int fact(int n, int accum) {
    if(n == 0) { return 1; }
    if(n == 1) { return accum; }
    return fact(n-1, n * accum);
}

Bu tür özyinelemeler döngü olarak yeniden yazılır - yığın kullanılmaz. Bu tür yaklaşımlar genellikle yazılan eşdeğer döngüden daha zarif ve anlaşılması daha kolaydır, ancak yine de, her özyinelemeli çağrı için yazılan bir eşdeğer döngü olabilir ve her döngü için bir özyinelemeli çağrı olabilir.

Basit döngüyü kuyruk aramasına dönüştürmenin özyinelemeli aramanın kıvrılabildiği ve anlaşılması daha zor olduğu zamanlar da vardır.


Bunun teori tarafına girmek istiyorsanız, Church Turing tezi konusuna bakın . Ayrıca kilise türetme tezini CS.SE'de yararlı bulabilirsin.


29
Turing bütünlüğü, olduğu gibi etrafa çok fazla fırlatılır. Turing Complete'in çoğu ( Toplantının Büyüsü gibi ), ancak bu Turing Complete'in olduğu gibi bir şey olduğu anlamına gelmez. En azından önemli olan bir seviyede değil. Magic the Gathering ile bir ağaca yürümek istemiyorum.
Roger

7
Bir problemi “bunun bir Turing makinesine eşit güce sahip” olduğu için bir kere azaltabileceğiniz zaman, onu oraya götürmeniz yeterlidir. Turing makineleri oldukça düşük bir engeldir, ancak gereken tek şey budur. Bir döngü, özyineleme yapamaz, tersi yapamaz hiçbir şey yapamaz.

4
Bu cevapta yapılan açıklama elbette doğru, ancak tartışmanın gerçekten ikna edici olmadığını söylemeye cüret ediyorum. Turing makinelerinin doğrudan bir tekrarlama kavramı yoktur, bu nedenle “tekrarlama olmadan bir Turing makinesini simüle edebilirsiniz” demek gerçekten bir şey kanıtlamaz. İfadeyi kanıtlamak için göstermeniz gereken, Turing makinelerinin özyinelemeyi simüle edebileceğidir. Bunu göstermezseniz, Kilise-Turing hipotezinin de (yinelemede) yineleme için geçerli olduğunu varsaymak zorundasınız, ancak OP bunu sorguladı.
5gon12eder

10
OP'nin sorusu “olabilir”, “en iyi” değil, “en verimli” veya başka bir niteleyicidir. "Turing Complete", tekrarlama ile yapılabilecek her şeyin bir döngü ile de yapılabileceği anlamına gelir. Herhangi bir dil uygulamasında bunu yapmanın en iyi yolu olup olmadığı tamamen farklı bir sorudur.
Steven Burnap

7
"Can", "en iyi" ile aynı şey DEĞİLDİR. Yapamazsın diye "en iyisi değil" hata yaptığında felç olursun, çünkü ne tür bir şey yaparsan yap, neredeyse her zaman daha iyi bir yol var.
Steven Burnap

31

Bir görevin döngü yerine özyinelemeyi kullanarak yapabileceği durumlar var mı?

Özyinelemeli algoritmayı her zaman geçici durumu depolamak için bir Son Giren İlk Veri yapısı (AKA yığını) kullanan bir döngüye dönüştürebilirsiniz, çünkü özyinelemeli çağrı tam olarak şu anki durumu bir yığında depolayarak algoritmaya devam eder, daha sonra devleti geri yükler. Kısa cevap: Hayır, böyle bir durum yok .

Ancak, "evet" için bir tartışma yapılabilir. Somut, kolay bir örnek alalım: birleştirme sırası. Verileri iki parçaya bölmeniz, birleştirme parçalarını sıralamanız ve sonra bunları birleştirmeniz gerekir. Parçalar üzerinde birleştirme işlemi yapmak için sıralama yapmak için gerçek bir programlama dili işlevi çağrısı yapmasanız bile, aslında bir işlev çağrısı yapmakla aynı işlevi (işlevselliği kendi yığınıza itin) uygulayın. farklı başlangıç ​​parametreleriyle döngünün başlangıcı, daha sonra durumu yığınızdan açın).

Özyineleme, özyinelemeyi uygularsanız, kendinize "ayrı durum" ve "başlangıca atlama" ve "pop durum" adımları şeklinde çağrı yapın mı? Ve bunun cevabı şudur: Hayır, hala özyineleme denmez, açık yığma ile yineleme denir (eğer yerleşik terminoloji kullanmak istiyorsanız).


Not, bu aynı zamanda "görev" tanımına da bağlıdır. Görev sıralamaksa, çoğu yinelemeye gerek duymayan birçok algoritma ile yapabilirsiniz. Görev, birleştirme sıralama gibi belirli bir algoritma uygulamaksa, o zaman yukarıdaki belirsizlik uygulanır.

Öyleyse soruyu düşünelim, bunun için sadece özyinelemeye benzer algoritmalar olan genel görevler var mı? Sorunun altındaki @WizardOfMenlo yorumundan, Ackermann işlevi bunun basit bir örneğidir. Dolayısıyla, tekrarlama kavramı, farklı bir bilgisayar program yapısıyla (açık yığınla yineleme) uygulanabilse bile, kendi başına durur.


2
Yığınsız bir işlemci için bir montaj ile uğraşırken, bu iki teknik aniden bir olur.
Joshua

@Joshua Gerçekten! Bu bir soyutlama seviyesi meselesidir. Eğer bir ya da iki seviyeye inersen, sadece mantık kapıları.
Hyde

2
Bu tam olarak doğru değil. Yinelemeyle özyinelemeyi taklit etmek için, rasgele erişimin mümkün olduğu bir yığına ihtiyacınız vardır. Rastgele erişimi olmayan sınırlı bir doğrudan erişilebilir belleğe sahip tek bir yığın, Turing tamamlanmayan bir PDA olacaktır.
Gilles

@Gilles Eski gönderi, ancak neden rasgele erişim yığını gerekli? Ayrıca, tüm gerçek bilgisayarlar, yalnızca sınırlı miktarda doğrudan erişilebilir belleğe sahip olduklarından ve hiç yığın olmadıklarından (bu belleği kullanmak hariç) olduğundan, PDA'lardan daha az değil mi? Bu, "gerçeklikte özyineleme yapamayız" yazıyorsa, çok pratik bir soyutlama gibi görünmüyor.
hyde

20

Bu özyinelemeyi ne kadar kesin tanımladığınıza bağlıdır.

Çağrı yığınını (veya program durumunu sürdürmek için hangi mekanizmaları kullanıyorsanız) dahil etmeyi kesinlikle istiyorsak, onu her zaman yerine geçmeyen bir şeyle değiştirebiliriz. Gerçekten de, doğal olarak özyinelemenin yoğun kullanımına neden olan diller, kuyruk çağrısı optimizasyonunu yoğun şekilde kullanan derleyicilere sahip olma eğilimindedir, bu nedenle yazdıklarınız özyinelemelidir ancak çalıştırdığınız şey yinelemelidir.

Ancak, özyinelemeli bir çağrı yaptığımız ve bir özyinelemeli çağrı için özyinelemeli çağrı sonucunu kullandığımız bir durumu düşünelim.

public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
  if (m == 0)
    return  n+1;
  if (n == 0)
    return Ackermann(m - 1, 1);
  else
    return Ackermann(m - 1, Ackermann(m, n - 1));
}

İlk özyinelemeli aramayı yinelemeli yapmak kolaydır:

public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
restart:
  if (m == 0)
    return  n+1;
  if (n == 0)
  {
    m--;
    n = 1;
    goto restart;
  }
  else
    return Ackermann(m - 1, Ackermann(m, n - 1));
}

Daha sonra temizlik yapabiliriz, velociraptors ve Dijkstra'nın gölgesini gotoönlemek için:

public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
  while(m != 0)
  {
    if (n == 0)
    {
      m--;
      n = 1;
    }
    else
      return Ackermann(m - 1, Ackermann(m, n - 1));
  }
  return  n+1;
}

Ancak diğer özyinelemeli aramaları kaldırmak için bazı aramaların değerlerini bir yığında depolamak zorunda kalacağız:

public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
  Stack<BigInteger> stack = new Stack<BigInteger>();
  stack.Push(m);
  while(stack.Count != 0)
  {
    m = stack.Pop();
    if(m == 0)
      n = n + 1;
    else if(n == 0)
    {
      stack.Push(m - 1);
      n = 1;
    }
    else
    {
      stack.Push(m - 1);
      stack.Push(m);
      --n;
    }
  }
  return n;
}

Şimdi, kaynak kodu göz önüne aldığımızda, özyinelemeli yöntemimizi kesinlikle yinelemeli bir yönteme dönüştürdük.

Bunun neye derlendiğini göz önüne alarak, çağrı kodunu özyinelemeyen koda dönüştürmek için çağrı yığınını kullanan kod haline getirdik (ve bunu yaparken, sadece küçük kodlar için bile bir yığın taşması istisnası atacak kod haline getirdik) geri dönmek için müthiş uzun bir zaman ayırın [bkz. Ackerman işlevimin yığından taşmasını nasıl önleyebilirim? Gerçekten daha birçok giriş için geri dönmesini sağlayan bazı daha fazla optimizasyon için].

Genel olarak nasıl özyinelemenin uygulandığı göz önüne alındığında, çağrı yığınını kullanan kodu bekleyen işlemleri tutmak için farklı bir yığın kullanan koduna dönüştürdük. Bu nedenle, bu düşük seviyede değerlendirildiğinde hala özyinelemeli olduğunu savunabiliriz.

Ve bu seviyede, gerçekten de onun etrafında başka yollar yok. Eğer bu yöntemi özyinelemeli olarak düşünürseniz, gerçekten onsuz yapamayacağımız şeyler var. Genelde böyle bir kodu özyinelemeli olmasak da. Terimi tekrarlama o yaklaşımların belli kümelerini kapsar ve bize onlar hakkında konuşmak için bir yol verir, biz de artık bunlardan biri kullanıyor çünkü yararlıdır.

Elbette, bunların hepsi bir seçeneğiniz olduğunu varsayar. Özyinelemeli çağrıları yasaklayan diller ve yineleme için gerekli olan döngüsel yapıları olmayan diller vardır.


Çağrı yığını sınırlıysa veya çağrı yığını dışındaki sınırsız bir belleğe erişebiliyorsa çağrı yığınını eşdeğer bir şeyle değiştirmek mümkündür. Sınırsız bir çağrı yığını olan, ancak sınırlı sayıda duruma sahip olabilen aşağı itme otomatları ile çözülebilen önemli bir problem sınıfı vardır.
supercat

Bu en iyi cevap, belki de tek doğru cevap. İkinci örnek bile hala özyinelemelidir ve bu seviyede, asıl sorunun cevabı hayırdır . Daha geniş bir özyinelemeyle, Ackermann işlevi için özyinelemeden kaçınmak imkansızdır.
gerrit

@gerrit ve daha dar bir, bunu önlüyor. Sonuç olarak, yaptığımız işin kenarlarına iner veya belirli kod için kullandığımız bu faydalı etiketi uygulamaz.
Jon Hanna

1
Bu oylama için siteye katıldı. Ackermann işlevi / doğası gereği / özyinelemelidir. Bir döngü ve bir yığın ile özyinelemeli bir yapı uygulamak onu yinelemeli bir çözüm yapmaz, özyinelemeyi kullanıcı alanına taşıdınız.
Aaron McMillin

9

Klasik cevap "hayır" dır, ama neden "evet" in daha iyi bir cevap olduğunu düşündüğümü geliştirmeme izin ver.


Devam etmeden önce, yoldan bir şeyler çıkaralım: hesaplanabilirlik ve karmaşıklık açısından:

  • Yanıt, döngü sırasında yardımcı bir yığın olmasına izin veriliyorsa, "hayır" dır.
  • Yanıt, döngüde herhangi bir ek verilere izin verilmiyorsa "evet" tir.

Tamam, şimdi bir ayağı pratik yapalım, diğer ayağı da teorik arsada tutalım.


Çağrı yığını bir kontrol yapısı iken manuel bir yığın veridir. yapısıdır. Kontrol ve verilerdir değil eşit kavramlar, ancak konum eşdeğer onlar edilebileceğini anlamda azalmış bir computability veya karmaşıklık açısından (birbirleriyle aracılığıyla "taklit" veya) birbirlerine.

Bu ayrım ne zaman önemli olabilir? Gerçek dünya araçlarıyla çalışırken. İşte bir örnek:

N yolunu uyguladığınızı söyleyin mergesort . forHer Nbölümden geçen, mergesortayrı ayrı çağrılan ve sonuçları birleştiren bir döngü olabilir .

Bunu OpenMP ile nasıl paralel hale getirebilirsiniz?

Özyinelemeli alemde, son derece basit: sadece #pragma omp parallel for1'den N'e kadar olan döngünün etrafına koyun ve bitirdiniz. İteratif alemde bunu yapamazsınız. İş parçacıklarını manuel olarak çoğaltmanız ve ne yapacağını bilmeleri için uygun verileri el ile iletmeniz gerekir.

Öte yandan, #pragma vectordöngülerle çalışan fakat özyinelemede tamamen yararsız olan başka araçlar (örneğin, otomatik vektörleştiriciler gibi ) vardır.

İki paradigmanın matematiksel olarak denk olduğunu kanıtlayabilmeniz, pratikte eşit oldukları anlamına gelmez. Bir paradigmada otomasyona geçmek için önemsiz olabilecek bir problemi (örneğin, döngü paralelleştirme) diğer paradigmada çözmesi çok daha zor olabilir.

Örneğin: Bir paradigmanın araçları otomatik olarak diğer paradigmalara çevrilmez.

Sonuç olarak, bir problemi çözmek için bir araca ihtiyaç duyuyorsanız, olasılık, aracın yalnızca belirli bir yaklaşımla çalışabileceği ve dolayısıyla problemi matematiksel olarak ispatlayabilseniz bile, sorunu farklı bir yaklaşımla çözme konusunda başarısız olacaksınız. Her iki şekilde de çözülebilir.


Bunun ötesinde, aşağı açılır bir otomat ile çözülebilen sorun kümesinin, sınırlı bir otomat ile çözülebilecek olan kümeden (deterministik olsun ya da olmasın), küme ile çözülebilen kümeden daha küçük olduğunu düşünün. Turing makinesi.
Süpermen

8

Teorik akıl yürütmeyi bir kenara koyarsak, özyinelemelerin ve döngülerin (donanım veya sanal) bir makine bakış açısından nasıl göründüğüne bir bakalım. Özyineleme, bazı kodların yürütülmesini başlatmaya ve tamamlanmasına (sinyaller ve istisnalar göz ardı edildiğinde basit bir görünümde) ve bu diğer koda (bağımsız değişkenler) iletilen ve bu verilerden geri döndürülen verilere geri dönmeyi sağlayan kontrol akışının bir birleşimidir. o (sonuç). Genellikle açık bir bellek yönetimi söz konusu değildir, ancak geri dönüş adreslerini, argümanları, sonuçları ve ara yerel verileri kaydetmek için yığın bellek ayırması vardır .

Döngü, kontrol akışı ve yerel verilerin birleşimidir. Bunu özyineleme ile karşılaştırarak, bu durumda veri miktarının sabit olduğunu görebiliriz. Bu sınırlamayı aşmanın tek yolu , gerektiğinde tahsis edilebilecek (ve serbest bırakılacak) dinamik bellek ( yığın olarak da bilinir ) kullanmaktır.

Özetlemek:

  • Özyineleme durumu = Kontrol akışı + Yığın (+ Yığın)
  • Döngü durumu = Kontrol akışı + Yığın

Kontrol akışı bölümünün oldukça güçlü olduğu varsayılarak , tek fark mevcut bellek türlerindedir. Yani, 4 vakada kaldıkız (ifade gücü parantez içinde verilmiştir):

  1. Yığın yok, yığın yok: özyineleme ve dinamik yapılar imkansız. (özyineleme = döngü)
  2. Yığın, yığın yok: özyineleme tamam, dinamik yapılar imkansız. (özyineleme> döngü)
  3. Yığın yok, yığın: özyineleme imkansız, dinamik yapılar tamam. (özyineleme = döngü)
  4. Yığın, yığın: özyineleme ve dinamik yapılar tamam. (özyineleme = döngü)

Oyunun kuralları biraz daha katıysa ve yinelemeli uygulamanın döngüler kullanmasına izin verilmezse bunun yerine şunu alırız:

  1. Yığın yok, yığın yok: özyineleme ve dinamik yapılar imkansız. (özyineleme <döngü)
  2. Yığın, yığın yok: özyineleme tamam, dinamik yapılar imkansız. (özyineleme> döngü)
  3. Yığın yok, yığın: özyineleme imkansız, dinamik yapılar tamam. (özyineleme <döngü)
  4. Yığın, yığın: özyineleme ve dinamik yapılar tamam. (özyineleme = döngü)

Önceki senaryodaki en önemli fark, yığın belleği eksikliğinin, döngüler olmadan özyinelemenin yürütme sırasında kod satırlarından daha fazla adım atmasına izin vermemesidir.


2

Evet. Özyinelemeyi kullanarak başarması kolay olan ancak sadece döngülerle imkansız olan birkaç ortak görev vardır:

  • Yığın taşmalarına neden olur.
  • Tamamen kafa karıştırıcı başlangıç ​​programcıları.
  • Gerçekten O (n ^ n) olan hızlı görünen fonksiyonlar yaratmak.

3
Lütfen, bunlar döngülerle gerçekten çok kolay, her zaman onları görüyorum. Heck, biraz çaba ile döngülere bile ihtiyacınız yok. Özyineleme daha kolay olsa bile.
AviD

1
gerçekten, A (0, n) = n + 1; A (m, 0) = A (m-1,1) m> 0 ise; A (m, n) = A (m-1, A (m, n-1)) m> 0, n> 0, O (n ^ n) 'den biraz daha hızlı büyürse (m = n) :)
John Donn

1
@JohnDonn Biraz daha fazla, süper üstel. n = 3 için n ^ n ^ n, n = 4 n ^ n ^ n ^ n ^ n vd. n gücü n kere n.
Aaron McMillin

1

Özyinelemeli fonksiyonlar ve ilkel özyinelemeli fonksiyonlar arasında bir fark var. İlkel özyinelemeli fonksiyonlar, her döngü için maksimum yineleme sayısının döngü yürütme başlamadan önce hesaplandığı, döngü kullanılarak hesaplanan işlevlerdir. (Ve burada "özyinelemeli" özyinelemenin kullanımı ile ilgisi yoktur).

İlkel özyinelemeli fonksiyonlar özyinelemeli fonksiyonlardan kesinlikle daha az güçlüdür. Özyinelemenin maksimum derinliğinin önceden hesaplanması gereken özyinelemeyi kullanan işlevleri aldıysanız aynı sonucu elde edersiniz.


3
Bunun yukarıdaki soru için nasıl geçerli olduğundan emin değilim? Lütfen bu bağlantıyı daha net yapabilir misiniz?
Yakk

1
"Sınırsız yineleme sayısı olan döngü" ile "sınırsız yineleme sayısı olan döngü" arasındaki kesin olmayan "döngü" yi değiştirmek, herkesin CS
101'den

Elbette, ama hala soru için geçerli değil. Sorun, ilkel özyinelemenin ve özyinelemenin değil, döngüsel ve özyinelemeyle ilgili. Birinin C / C ++ farkları hakkında bir soru sorup sormadığını ve K&R C ile Ansi C arasındaki farkı cevapladığınızı düşünün. Elbette, işleri daha kesin yapan, ancak soruyu yanıtlamadığından emin olun.
Yakk

1

Eğer c ++ ile programlama yapıyorsanız ve c ++ 11 kullanıyorsanız, özyinelemeler kullanılarak yapılması gereken bir şey vardır: constexpr fonksiyonları. Ancak standart, bu cevapta açıklandığı gibi, bunu 512 ile sınırlandırmaktadır . Bu durumda döngüler kullanmak mümkün değildir, çünkü bu durumda işlev karmaşık olamaz, ancak bu c ++ 14'te değiştirilir.


0
  • Özyinelemeli çağrı özyinelemeli bir işlevin ilk veya en son ifadesiyse (koşul denetimi hariç), döngüsel bir yapıya çevrilmesi oldukça kolaydır.
  • Ancak fonksiyon özyinelemeli çağrıdan önce ve sonra başka şeyler yaparsa , onu döngülere dönüştürmek hantal olur.
  • Eğer fonksiyonun çoklu özyinelemeli çağrıları varsa, onu sadece döngüler kullanan koda dönüştürmek oldukça imkansız olacaktır. Verilere ayak uydurmak için bir miktar yığın gerekli olacak. Özyinelemede çağrı yığınının kendisi veri yığını olarak çalışacaktır.

Ağaç yürüyüşünde birden fazla özyinelemeli arama vardır (her çocuk için bir tane), ancak açık bir yığın kullanarak önemsiz bir şekilde bir döngüye dönüştürülür. Öte yandan, ayrıştırıcılar, dönüştürmek için can sıkıcıdır.
KodlarInChaos

@CodesInChaos Düzenlendi.
Gulshan

-6

Diğer sorulara katılıyorum. Özyineleme ile yapabileceğiniz hiçbir şey yoktur, bir döngü ile yapamazsınız.

AMA , bence özyineleme çok tehlikeli olabilir. İlk olarak, bazıları için kodda gerçekte ne olduğunu anlamak daha zor. İkincisi, en azından C ++ için (Java emin değilim) her yineleme adımının bellek üzerinde etkisi vardır, çünkü her yöntem çağrısı, bellek birikmesine ve yöntemler başlığının başlatılmasına neden olur. Bu şekilde yığınızı patlatabilirsiniz. Giriş değeri yüksek olan Fibonacci sayılarının özdeyişini deneyin.


2
Fibonacci sayılarının özyinelemeli saf özyinelemeli bir uygulaması, yığın alanı dolmadan önce "zaman aşımına uğrar". Sanırım bu örnek için daha iyi olan başka sorunlar var. Ayrıca, birçok sorun için, bir döngü sürümünün özyinelemeyle aynı bellek etkisi vardır, yığın yerine yalnızca yığın üzerinde (programlama diliniz bunları ayırt ediyorsa).
Paŭlo Ebermann 22:15

6
Döngü de "çok tehlikeli" olabilir, sadece döngü değişkenini arttırmayı unutursanız ...
h22

2
Bu yüzden, aslında, kasıtlı olarak bir yığın taşması üretmek, özyineleme kullanmadan çok zor hale gelen bir iştir.
5gon12eder

Bizi bize getiren @ 5gon12eder Bir özyinelemeli algoritmada yığın taşmasını önlemek için hangi yöntemler vardır? - TCO'yu meşgul etmek için yazmak ya da hatıra vermek faydalı olabilir. Yinelemeli ve özyinelemeli Yaklaşımlar da Fibonacci için iki farklı özyinelemeli yaklaşımla ilgilendiği için ilginçtir.

1
Özyinelemede yığın taşması olursa çoğu zaman yinelemeli sürümü askıya alırsınız. En azından eski yığın iziyle atıyor.
Jon Hanna
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.