Özyineleme anlayışınızı geliştirmek için kaynaklar? [kapalı]


13

Özyinelemenin ne olduğunu biliyorum (bir patten kendi içinde yeniden ortaya çıktığında, tipik olarak bir kopuk koşullu ... doğrudan sonra kendini çağıran bir işlev). Benim sorunum, yeni örnekler gördüğümde, her zaman başlangıçta kafam karıştı. Bir döngü veya bir eşleme, sıkıştırma, yuvalama, polimorfik çağrı vb. Görürsem, sadece ona bakarak neler olduğunu biliyorum. Özyinelemeli kod gördüğümde, düşünce sürecim genellikle 'wtf bu mu?' arkasından 'oh özyinelemeli' ve ardından 'Sanırım işe yarıyorsa, işe yaraması gerektiğini' takip eder.

Bu alanda becerilerin geliştirilmesi için herhangi bir ipucunuz / planınız / kaynağınız var mı? Özyineleme tuhaf bir kavramdır, bu yüzden bununla başa çıkmanın yolunun eşit derecede garip ve anlaşılmaz olabileceğini düşünüyorum.


28
Özyinelemeyi anlamak için önce özyinelemeyi anlamalısınız.
Andreas Johansson

1
Dr.Seuss tarafından 'Şapkadaki Kedi Geri Geliyor', bu tamamen yararlı olmayabilir, ancak kedinin özyinelemeli çağrısı bu sinir bozucu lekeden kurtulur. :-) Ayrıca çok hızlı bir okuma olma avantajına sahiptir!
DKnight

2
Uygulama, uygulama, uygulama.
David Thornley


3
@Graham Borland: Bu sonsuz tekrarlama örneğidir. Çoğu programda, temel durumun eksik olması genellikle yığın taşmasına veya yetersiz bellek hatasına yol açar. Web sitesi kullanıcıları için bu sadece karışıklığa neden olabilir. ;)
Hayal kırıklığına

Yanıtlar:


10

Basit bir şeyle başlayın ve kalem ve kağıtla izleyin. Seriosuly. Başlamak için iyi bir yer, ağaç geçiş algoritmalarıdır, çünkü özyineleme kullanarak düzenli yinelemeden çok daha kolay işlenirler. Karmaşık bir örnek olmak zorunda değil, basit ve çalışabileceğiniz bir şey.

Evet, garip ve bazen karşı sezgisel, ama bir kez tıkladığında, bir kez "Eureka!" Eğer merak edeceğiz vermedi önce bunu anlamak! ;) Ağaçları önerdim çünkü onlar (IMO) özyinelemede anlaşılması en kolay yapıdır ve kalem ve kağıt kullanarak çalışmak kolaydır. ;)


1
+ + Bu, kaçırma şeklim. Örneğin, OO kullanıyorsanız, üst alt öğe ilişkisi olan bazı sınıflar oluşturun ve bir nesnenin belirli bir ataya sahip olup olmadığını kontrol eden bir işlev / yöntem yapmaya çalışın.
Alb

5

Şunu tavsiye ederim, The Little Lisper kitabını kullanarak. Onunla tamamladıktan sonra sen olacaktır Özyinelemeyi, derin aşağı anlıyoruz. Neredeyse garantilidir.


1
+1 Bu kitap gerçekten benim için yaptı. Ama "Küçük Schemer" olarak yeniden adlandırıldı
mike30

4

Kesinlikle SICP öneririm. Ayrıca, yazarların tanıtım ders videolarına buradan göz atmalısınız ; inanılmaz derecede akıl almazlar.

Programlama ile çok ilgili olmayan bir başka yol da Gödel, Escher, Bach: Hofstadter'in Ebedi Altın Örgüsü . Bir kez çukurlaşırsanız, özyineleme aritmetik kadar doğal görünecektir. Ayrıca, P = nP olduğuna inanacaksınız ve düşünme makineleri inşa etmek isteyeceksiniz - ancak bu, faydalara kıyasla çok küçük bir yan etki.


GEB zaten okumaya değer; bahsettiği bazı şeyler biraz tarihlendirilmiş olsa bile (son 40 yılda temel CS araştırmalarında bazı ilerlemeler kaydedilmiş olsa da) temel anlayış değildir.
Donal Fellows

2

Temelde pratik yapmak için geliyor ... Genel problemleri (sıralama, arama, matematik problemleri, vb.) Alın ve birkaç kez tek bir fonksiyon uygularsanız bu problemlerin çözülebileceği bir yol görüp göremeyeceğinizi görün.

Örneğin, hızlı sıralama, bir listedeki öğeyi iki yarıya taşıması ve daha sonra kendini bu yarıların her birine tekrar uygulamasıyla çalışır. İlk sıralama gerçekleştiğinde, iki yarının o noktada sıralanması konusunda endişelenmez. Aksine, pivot elemanını alıp o elemandan daha küçük olan tüm elemanları bir tarafa ve tüm elemanlar diğer tarafa eşit veya daha büyük olanı koymaktır. Bu, iki yeni küçük listeyi sıralamak için kendini bu noktada özyinelemeli olarak nasıl çağırabileceğini anlamıyor mu? Onlar da listeler. Sadece daha küçük. Ama yine de tasnif edilmeleri gerekiyor.

Özyinelemenin arkasındaki güç, bölün ve fethetme nosyonudur. Bir problemi tekrar tekrar doğada özdeş olan fakat sadece daha küçük olan problemlere bölün. Eğer bunu yeterince yaparsanız, kalan tek parçanın zaten çözüldüğü bir noktaya ulaşırsınız, o zaman döngüden geri dönüp sorun çözülür. Bu örnekleri inceleyin sen kadar Bahsettiğiniz anlıyorum onları. Biraz zaman alabilir ama sonunda daha kolay olacaktır. Sonra diğer sorunları almaya çalışın ve bunları çözmek için özyinelemeli bir işlev yapın! İyi şanslar!

DÜZENLEME: Ayrıca özyineleme için bir anahtar öğe işlevi durdurmak için garantili yeteneği olduğunu eklemeliyim. Bu, orijinal sorunun parçalanmasının sürekli olarak küçülmesi ve nihayetinde garantili bir durma noktası (yeni alt sorunun çözülebilir veya zaten çözülmüş olduğu bir nokta) olması gerektiği anlamına gelir .


Evet, sanırım daha önce hızlı bir açıklama gördüm, yukarıdaki hatırlatıcınızdan nasıl çalıştığını hayal edebiliyorum. Özyineleme ne kadar etkileyici / esnektir - çoğu problem özyinelemeli bir yaklaşıma zorlanabilir mi (optimal olmasa bile)? İnsanların ağda kodlama bulmacalarına cevap verdiğini gördüm, çoğu insan prosedürel olarak mücadele ediyordu, sanki sadece cehennem için istedikleri zaman özyineleme kullanabilirlerdi. Ben de bir kez okudum, bence, bazı diller döngü yapısını değiştirmek için bağımlı veya özyineleme. Ve garantili durma noktasından bahsediyorsunuz. Bunlardan birinin anahtar olabileceğini hissediyorum.
Andrew M

Kendi başınıza oluşturmanız için iyi bir basit başlangıç ​​problemi, bir sayının faktöriyelini bulan özyinelemeli bir program yazmak olacaktır.
Kenneth

Herhangi bir ilmek yapısı, özyinelemeli bir yapıya yerleştirilebilir. Herhangi bir özyinelemeli yapı döngüsel bir yapıya yerleştirilebilir ... az çok. Özyinelemenin ne zaman ve ne zaman kullanılmayacağını öğrenmek zaman ve pratik gerektirir, çünkü özyineleme kullandığınızda donanım düzeyinde kullanılan kaynaklar açısından çok fazla yük olduğunu hatırlamanız gerekir.
Kenneth

Örneğin, hızlı sıralama yapan döngüsel bir yapı oluşturmanın mümkün olduğunu görebiliyordum ... AMA heck'in kraliyet ağrısı olacağından ve nasıl yapıldığına bağlı olarak, sonunda yinelemeli bir işlevden daha fazla sistem kaynağı kullanabileceğinden emin olabilirsiniz. büyük diziler için.
Kenneth

işte faktöriyelere girişme. Adil olmak gerekirse bunu daha önce gördüm ve hafızadan değil sıfırdan yazmama rağmen, muhtemelen olduğundan daha kolay. JS'de denedim ancak ayrıştırma hatası vardı, ancak Python'da çalışıyor def factorial(number): """return factorial of number""" if number == 0: return 0 elif number == 1: return 1 else: return number * factorial(number - 1)
Andrew M

2

Şahsen en iyi bahsin pratik yoluyla olduğunu düşünüyorum.

LOGO ile özyineleme öğrendim. LISP kullanabilirsiniz. Bu dillerde özyineleme doğaldır. Aksi takdirde, daha önce gelenlere dayanarak bir sonraki ifadeyi ifade ettiğiniz matematiksel süitler ve serilerin incelenmesine benzeyebilirsiniz, yani u (n + 1) = f (u (n)) veya birden çok değişkeninizin olduğu daha karmaşık seriler ve çoklu bağımlılıklar, örneğin u (n) = g (u (n-1), u (n-2), v (n), v (n-1)); v (n) = h (u (n-1), u (n-2), v (n), v (n-1)) ...

Yani benim önerim basit (kendi ifadelerinde) standart özyineleme "problemlerini" bulup bunları kendi dilinizde uygulamaya çalışmanızdır. Pratik yapmak, bu "problemleri" nasıl düşüneceğinizi, okuduğunuzu ve ifade edeceğinizi öğrenmenize yardımcı olacaktır. Bu sorunların bir kısmının yinelemeyle ifade edilebileceğini, ancak yinelemenin bunları çözmek için daha zarif bir yol olabileceğini unutmayın. Bunlardan biri faktöriyel sayıların hesaplanmasıdır.

Grafiksel "problemler" bulmayı daha kolay görüyorum. Bu yüzden Koch'un pullarına, Fibonacci'ye, ejderha eğrisine ve genel olarak fraktallara bakın. Ancak hızlı sıralama algoritmasına da bakın ...

Başınıza her şey gelmeden önce birkaç programı (sonsuz döngüler, sonsuz kaynakların geçici kullanımı) ve yanlış koşulları (beklenmedik sonuçlar elde etmek için) çökertmeniz gerekir. Ve bunu elde ettiğinizde bile, bu hataları yine de daha az sıklıkta yapacaksınız.



0

SICP ve Gödel, Escher, Bach gibi sevdiğim kadarıyla : Sonsuz Altın Örgü , Touretzky'nin LISP: Sembolik Hesaplamaya Nazik Giriş de özyineleme konusunda iyi bir iş çıkarıyor.

Temel kavram şudur: İlk olarak, özyinelemeli işlevinizin ne zaman bittiğini bilmelisiniz, böylece bir sonuç döndürebilir. Ardından, bitmemiş vakayı nasıl alacağınızı ve tekrarlayabileceğiniz bir şeye indirgemeniz gerekir. Geleneksel faktöriyel (N) örnek için, N <= 1 olduğunda işiniz bitti ve bitmemiş durum N * faktöriyeli (N-1).

Çok daha çirkin bir örnek için Ackermann'ın A (m, n) fonksiyonu var .

A(0,n) = n+1.                                   This is the terminal case.
A(m,0) = A(m-1,1) if m > 0.                     This is a simple recursion.
A(m,n) = A(m-1, A(m, n-1)) if m > 0 and n > 0.  This one is ugly.

0

OCaml veya Haskell gibi ML tarzı fonksiyonel dillerle oynamanızı öneririm. Örüntü eşleme sözdiziminin gerçekten karmaşık olan özyinelemeli işlevleri bile anlamama yardımcı olduğunu buldum , kesinlikle Şema ifve condifadelerden çok daha iyi . (Haskell ve Scheme'yi aynı anda öğrendim.)

İşte kontrast için önemsiz bir örnek:

(define (fib n)
   (cond [(= n 0) 0]
         [(= n 1) 1]
         [else (+ (fib (- n 1)) (fib (- n 2)))]))

ve desen eşleşmesi ile:

fib 0 = 0
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)

Bu örnek gerçekten fark adaletini yapmaz - fonksiyonun her iki versiyonuyla da hiç problem yaşamadım. Sadece iki seçeneğin nasıl olduğunu göstermek. Listeler ve ağaçlar gibi şeyleri kullanarak çok daha karmaşık işlevlere ulaştığınızda, fark çok daha belirgin hale gelir.

Özellikle Haskell'i öneriyorum çünkü çok güzel bir sözdizimine sahip basit bir dil. Ayrıca, koreksuryon gibi daha gelişmiş fikirlerle çalışmayı çok daha kolay hale getirir :

fibs = 0 : 1 : zipWith (+) fibs (drop 1 fibs)
fib n = fibs !! n

(Haskell ile biraz oynayana kadar yukarıdaki kodu anlamayacaksınız, ancak temelde büyülü olduğundan emin olabilirsiniz: S.) Şemadaki akışlarla da aynısını yapabilirsiniz, ancak Haskell'de çok daha doğal.


0

Baskısı tükenmiş, ancak bulabilirseniz, Richard Lorentz'in "Özyinelemeli Algoritmalar" özyinelemeden başka bir şey değildir. Özyinelemenin temellerini ve belirli özyinelemeli algoritmaları kapsar.

Örnekler Pascal'dadır, ancak dil seçimi rahatsız edici değildir.

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.