it-swarm.dev

Açık İngilizce'de özyineleme nedir?

Özyineleme fikri gerçek dünyada çok yaygın değildir. Yani, acemi programcılar için biraz kafa karıştırıcı görünüyor. Yine de, sanırım, yavaş yavaş konsepte alışırlar. Peki, fikri kolayca kavramaları için güzel bir açıklama ne olabilir?

76
Gulshan

Bir fonksiyonun aynı fonksiyon içinden çağrılması.

59
ChaosPandion

Özyineleme, kendisini çağıran bir işlevdir.

Nasıl kullanılacağı, ne zaman kullanılacağı ve kötü tasarımın nasıl önleneceği bilmek önemlidir, bu da kendiniz denemenizi ve ne olduğunu anlamanızı gerektirir.

Bilmeniz gereken en önemli şey, hiç bitmeyen bir döngü elde etmemek için çok dikkatli olmaktır. pramodc84'ten gelen cevap sorunuzun şu hatası var: Asla bitmez ...
Özyinelemeli bir işlev, kendisini yeniden çağırıp çağırmayacağını belirlemek için her zaman bir koşulu kontrol etmelidir.

Özyinelemeyi kullanmanın en klasik örneği, derinliği statik olan bir ağaçla çalışmaktır. Bu özyinelemeyi kullanmanız gereken bir görevdir.

27
awe

Özyinelemeli programlama, kendi sürümlerini çözmeyi kolaylaştırmak için bir sorunu aşamalı olarak azaltma işlemidir.

Her özyinelemeli işlev:

  1. işlemek için bir liste veya başka bir yapı veya sorunlu etki alanı almak
  2. mevcut nokta/adım ile ilgilenmek
  3. geri kalanı/alan adlarını çağır
  4. alt alan çalışmasının sonuçlarını birleştirme veya kullanma

2. adım 3'ten önce olduğunda ve 4. adım önemsiz olduğunda (bir birleştirme, toplam veya hiçbir şey) bu kuyruk özyineleme sağlar. Mevcut adımın tamamlanması için sorunun alt alan (lar) ından elde edilen sonuçlara ihtiyaç duyulabileceğinden, 2. adım genellikle 3. adımdan sonra gelmelidir.

Düz bir ikili ağacın geçişini yapın. Geçiş, neye ihtiyaç duyulduğuna bağlı olarak ön sipariş, sipariş veya sipariş sırasında yapılabilir.

   B
A     C

Ön sipariş: B A C

traverse(tree):
    visit the node
    traverse(left)
    traverse(right)

Sırayla: A B C

traverse(tree):
    traverse(left)
    visit the node
    traverse(right)

Sonradan sipariş: A C B

traverse(tree):
    traverse(left)
    traverse(right)
    visit the node

Çok fazla özyinelemeli sorunlar, harita işleminin veya katla - yalnızca bu iki işlemin anlaşılması, özyineleme için iyi kullanım durumlarının önemli ölçüde anlaşılmasına yol açabilir.

21
Orbling

OP, özyinelemenin gerçek dünyada mevcut olmadığını söyledi, ancak farklı olmaya yalvarıyorum.

Bir pizza kesmenin gerçek dünyası 'operasyonunu' ele alalım. Pizzayı fırından çıkardınız ve servis etmek için ikiye kesmeniz, sonra bu yarıları ikiye kesmeniz, sonra tekrar ortaya çıkan yarıları ikiye kesmeniz gerekiyor.

İstediğiniz sonucu elde edene kadar dilimlediğiniz pizzayı tekrar tekrar kesme işlemi (dilim sayısı). Ve argümanlar için, diyelim ki kesilmemiş bir pizza bir dilimin kendisidir.

İşte Ruby'de bir örnek:

 def cut_pizza (mevcut_slices, wanted_slices) 
 mevcut_slices! = wanted_slices 
 # henüz herkesi beslemek için yeterli dilimimiz yok, bu yüzden 
 # pizza dilimlerini kesmek, böylece sayılarını iki katına çıkarmak 
 new_slices = mevcut_slices * 2 
 # ve işte burada özyinelemeli çağrı 
 cut_pizza (yeni_slices, wanted_slices) 
 
 # İstediğimiz sayıda dilim var, bu yüzden [..__.] mevcut_slices 
 son ​​
 son ​​
 
 pizza = 1 # bütün bir pizza, 'bir dilim' 
 cut_pizza (pizza, 8) # => 8 elde edeceğiz 

Yani gerçek dünya operasyonu bir pizza kesiyor ve özyineleme, istediğiniz şeyi elde edene kadar aynı şeyi tekrar tekrar yapıyor.

Özyinelemeli işlevlerle uygulayabileceğiniz kırpmayı bulacağınız işlemler şunlardır:

  • Birkaç ay boyunca bileşik faizin hesaplanması.
  • Bir dosya sisteminde bir dosya aranıyor (çünkü dosya sistemleri dizinler nedeniyle ağaçlardır).
  • Genel olarak ağaçlarla çalışmayı içeren her şey, sanırım.

Dosya adına göre bir dosya aramak için bir program yazmanızı ve bulunana kadar kendisini çağıran bir işlev yazmaya çalışmanızı öneririm, imza şöyle görünür:

find_file_by_name(file_name_we_are_looking_for, path_to_look_in)

Yani şöyle diyebilirsiniz:

find_file_by_name('httpd.conf', '/etc') # damn it i can never find Apache's conf

Bence sadece mekaniği programlamak, kopyalamayı akıllıca kaldırmak için bir yol. Bunu değişkenleri kullanarak yeniden yazabilirsiniz, ancak bu 'daha hoş' bir çözümdür. Bu konuda gizemli ya da zor bir şey yok. Birkaç özyinelemeli işlev yazacaksınız, programlama aracı kutunuza tıklayıp huzzah başka bir mekanik hile yapacak.

Ekstra Kredicut_pizza Yukarıdaki örnek, 2 gücü olmayan bir dizi dilim (yani 2 veya 4 veya 8 veya 16) sorarsanız, yığın düzeyinde çok derin bir hata verir. Birisi 10 dilim sorarsa sonsuza kadar koşmayacak şekilde değiştirebilir misiniz?

20
Ryan Allen

Tamam, bunu basit ve özlü tutmaya çalışacağım.

Özyinelemeli işlev, kendilerini çağıran işlevlerdir. Özyinelemeli işlev üç şeyden oluşur:

  1. Mantık
  2. Kendi kendine bir çağrı
  3. Ne zaman feshedilir.

Özyinelemeli yöntemler yazmanın en iyi yolları, yinelemek istediğiniz işlemin yalnızca bir döngüsünü işleyerek basit bir örnek olarak yazmaya çalıştığınız yöntemi düşünmek, daha sonra çağrıyı yönteme eklemek ve istediğiniz zaman eklemektir. sonlandırabilir. Öğrenmenin en iyi yolu her şey gibi pratik yapmaktır.

Bu programcılar web sitesi olduğundan kod yazmaktan kaçınacağım ama işte iyi bir link

eğer bu şakaya sahipseniz, özyineleme anlamına gelir.

16
dustyprogrammer

Özyineleme, bir programcının kendi başına bir işlev çağrısını başlatmak için kullanabileceği bir araçtır. Fibonacci dizisi, özyinelemenin nasıl kullanıldığına dair ders kitabı örneğidir.

Hepsi değilse en yinelemeli kod, yinelemeli işlev olarak ifade edilebilir, ancak genellikle dağınıktır. Diğer özyinelemeli programlara iyi örnekler, ağaçlar, ikili arama ağacı ve hatta çabuk sıralama gibi Veri Yapılarıdır.

Özyineleme kodu daha az özensiz yapmak için kullanılır, genellikle daha yavaş olduğunu ve daha fazla bellek gerektirdiğini unutmayın.

6
Bryan Harrington

Bunu kullanmayı seviyorum:

Mağazaya nasıl yürürsün?

Mağazanın girişindeyseniz, sadece içinden geçin. Aksi takdirde, bir adım atın, ardından mağazanın geri kalanına yürüyün.

Üç yönü dahil etmek önemlidir:

  • Önemsiz bir temel dava
  • Sorunun küçük bir parçasını çözme
  • Sorunun geri kalanını yinelemeli olarak çözme

Aslında özyinelemeyi günlük hayatta çok kullanıyoruz; sadece bu şekilde düşünmüyoruz.

5
Barry Brown

Size işaret edeceğim en iyi örnek, K & R tarafından C Programlama Dili'dir. dizin sayfası da.

3
Kanini

Josh K Matroshka bebeklerden zaten bahsetti. Sadece en kısa bebeğin bildiği bir şey öğrenmek istediğinizi varsayalım. Sorun, onunla gerçekten doğrudan konuşamamanızdır, çünkü aslında ilk resimde sol tarafına yerleştirilen daha uzun bebek içinde yaşıyor . Bu yapı böyle gider (bir bebek daha uzun bebeğin içinde yaşar) sadece en uzun olana kadar bitene kadar.

Yapabileceğiniz tek şey, sorunuzu en uzun bebeğe sormaktır. En uzun bebek (cevabı bilmeyen) sorunuzu daha kısa bebeğe (ilk resimde sağında) geçmesi gerekecektir. Cevabı da olmadığı için bir sonraki kısa bebeğe sorması gerekiyor. Mesaj en kısa bebeğe ulaşana kadar bu böyle gidecek. En kısa bebek (gizli cevabı bilen tek kişi) cevabı bir sonraki uzun boylu bebeğe geçirecek olan bir sonraki uzun boylu bebeğe (solda bulunan) geçecektir ... ve bu cevapya kadar devam edecek en uzun bebek olan son varış noktasına ulaşır ve sonunda ... sen :)

Özyineleme gerçekten böyle yapar. Bir işlev/yöntem beklenen cevabı alana kadar kendisini çağırır. Bu nedenle, özyinelemeli kod yazarken, özyinelemenin ne zaman sona ereceğine karar vermek çok önemlidir.

En iyi açıklama değil ama umarım yardımcı olur.

2
sakisk

Özyineleme n. - Bir işlemin kendisi açısından tanımlandığı bir algoritma tasarımı modeli.

Klasik örnek bir sayının faktöriyelini bulmaktır, n !. 0! = 1'dir ve diğer herhangi bir doğal sayı N için N'nin faktöriyörü, N'den küçük veya N'ye eşit tüm doğal sayıların çarpımıdır. = 6 * 5 * 4 * 3 * 2 * 1 = 720. Bu temel tanım basit bir yinelemeli çözüm oluşturmanıza izin verir:

int Fact(int degree)
{
    int result = 1;
    for(int i=degree; i>1; i--)
       result *= i;

    return result;
}

Ancak, işlemi tekrar inceleyin. 6! = 6 * 5 * 4 * 3 * 2 * 1. Aynı tanımla, 5! = 5 * 4 * 3 * 2 * 1, yani 6 diyebiliriz! = 6 * (5!). Buna karşılık, 5! = 5 * (4!) Vb. Bunu yaparak, sorunu önceki tüm işlemlerin sonucunda gerçekleştirilen bir işleme indirgiyoruz. Bu, sonuçta tanımın bilindiği bir temel durum adı verilen bir noktaya düşer. Bizim durumumuzda, 0! = 1 (çoğu durumda 1! = 1 diyebiliriz). Hesaplamada, yöntemin kendisini çağırması ve daha küçük bir girdi geçirmesi sayesinde algoritmaları çok benzer bir şekilde tanımlamamıza izin verilir, böylece problemi birçok özyineleme yoluyla temel bir duruma düşürür:

int Fact(int degree)
{
    if(degree==0) return 1; //the base case; 0! = 1 by definition
    else return degree * Fact(degree -1); //the recursive case; N! = N*(N-1)!
}

Bu, birçok dilde üçlü operatör kullanılarak daha da basitleştirilebilir (bazen operatörü bu şekilde sağlamayan dillerde bir Iif işlevi olarak görülür):

int Fact(int degree)
{
    //reads equivalently to the above, but is concise and often optimizable
    return degree==0 ? 1: degree * Fact(degree -1);
}

Avantajları:

  • Doğal ifade - birçok algoritma türü için, bu işlevi ifade etmenin çok doğal bir yoludur.
  • Azaltılmış LOC - Bir işlevi özyinelemeli olarak tanımlamak genellikle çok daha özlüdür.
  • Hız - Belirli durumlarda, dile ve bilgisayar mimarisine bağlı olarak, bir algoritmanın özyinelemesi eşdeğer yinelemeli çözümden daha hızlıdır, çünkü genellikle bir işlev çağrısı yapmak donanım düzeyinde yinelemeli döngü için gereken işlemlerden ve bellek erişiminden daha hızlı bir işlemdir.
  • Bölünebilirlik - Birçok özyinelemeli algoritma "böl ve fethet" zihniyetindedir; işlemin sonucu, girişin iki yarısının her birinde gerçekleştirilen aynı işlemin sonucunun bir işlevidir. Bu, işi her seviyede ikiye bölmenizi sağlar ve varsa diğer yarıyı işlemek için başka bir "yürütme birimine" verebilirsiniz. Yinelemeli bir algoritma ile bu genellikle daha zor veya imkansızdır.

Dezavantajları:

  • Anlama gerektirir - Neler olup bittiğini anlamak ve böylece etkili özyinelemeli algoritmalar yazmak ve sürdürmek için özyineleme kavramını "kavramanız" yeterlidir. Aksi takdirde sadece kara büyü gibi görünür.
  • Bağlama bağlı - Özyinelemenin iyi bir fikir olup olmadığı algoritmanın kendisi açısından ne kadar zarif bir şekilde tanımlanabileceğine bağlıdır. Örneğin, bir özyinelemeli SelectionSort oluşturmak mümkün olmakla birlikte, yinelemeli algoritma tipik olarak daha anlaşılırdır.
  • Trades RAM çağrı yığını için erişim - Genellikle, işlev çağrıları önbelleğe erişimden daha ucuzdur, bu da özyinelemeyi yinelemeden daha hızlı hale getirir. yinelemeli algoritmanın çalışacağı yerde hataya özyineleme.
  • Sonsuz özyineleme - Ne zaman duracağınızı bilmelisiniz. Sonsuz yineleme de mümkündür, ancak ilgili döngü yapılarını anlamak ve böylece hata ayıklamak genellikle daha kolaydır.
2
KeithS

Kullandığım örnek gerçek hayatta karşılaştığım bir problem. Bir konteyneriniz var (bir seyahate çıkmayı planladığınız büyük bir sırt çantası gibi) ve toplam ağırlığı bilmek istiyorsunuz. Kapta iki veya üç gevşek eşya ve diğer bazı kaplar var (örneğin, çuvallar). Toplam kabın ağırlığı açık bir şekilde boş kabın ağırlığı artı içindeki her şeyin ağırlığıdır. Gevşek ürünler için, sadece onları tartabilirsiniz ve malzeme çuvalları için onları sadece tartabilirsiniz ya da "her bir malzemenin ağırlığının boş kabın ağırlığı artı içindeki her şeyin ağırlığıdır" diyebilirsiniz. Ve sonra konteynırlarda konteynırların içine girmeye devam edersiniz ve bir konteynırda sadece gevşek eşyaların olduğu bir noktaya gelene kadar devam edersiniz. Bu özyineleme.

Bunun gerçek hayatta asla gerçekleşmediğini düşünebilirsiniz, ancak belirli bir şirketteki veya bölümdeki kişilerin, sadece şirket için çalışan insanların, bölümlerdeki insanların, daha sonra bölümler bölümler vb. vardır. Veya bir kısmı alt bölgeleri vb. Olan bölgeleri olan bir ülkede satış yapmak. Bu tür sorunlar iş hayatında her zaman olur.

1
Kate Gregory

Özyineleme birçok sayım sorununu çözmek için kullanılabilir. Örneğin, bir partide (n> 1) bir grup n grubunuz olduğunu ve herkesin herkesin elini tam olarak bir kez salladığını varsayalım. Kaç el sıkışma gerçekleşir? Çözeltinin C (n, 2) = n (n-1)/2 olduğunu biliyor olabilirsiniz, ancak aşağıdaki gibi özyinelemeli olarak çözebilirsiniz:

Diyelim ki sadece iki kişi var. Sonra (muayene ile) cevap açıktır 1.

Diyelim ki üç kişiniz var. Bir kişiyi seçip diğer iki kişiyle el sıkıştığına dikkat edin. Bundan sonra sadece diğer iki kişi arasındaki el sıkışmalarını saymanız gerekir. Bunu şimdiden yaptık ve bu 1. Yani cevap 2 + 1 = 3.

Diyelim ki n kişiniz var. Öncekiyle aynı mantığa göre, (n-1) + (n-1 kişi arasındaki el sıkışma sayısı). Genişlerken, (n-1) + (n-2) + ... + 1 elde ederiz.

Özyinelemeli işlev olarak ifade edilir,

f (2) = 1
f (n) = n-1 + f (n-1), n> 2

0
Mitch Schwartz

İşte özyineleme için gerçek bir dünya örneği.

Komik bir koleksiyonları olduğunu hayal edin ve hepsini büyük bir yığın haline getireceksiniz. Dikkatli - gerçekten bir koleksiyonları varsa, sadece bunu yapma fikrinden bahsettiğinizde sizi anında öldürebilirler.

Şimdi bu büyük sıralanmamış çizgi roman yığınını bu kılavuzun yardımıyla sıralamasına izin verin:

Manual: How to sort a pile of comics

Check the pile if it is already sorted. If it is, then done.

As long as there are comics in the pile, put each one on another pile, 
ordered from left to right in ascending order:

    If your current pile contains different comics, pile them by comic.
    If not and your current pile contains different years, pile them by year.
    If not and your current pile contains different tenth digits, pile them 
    by this digit: Issue 1 to 9, 10 to 19, and so on.
    If not then "pile" them by issue number.

Refer to the "Manual: How to sort a pile of comics" to separately sort each
of the new piles.

Collect the piles back to a big pile from left to right.

Done.

Burada güzel olan şey: Tek sayıya düştüklerinde, yerlerinde önlerinde görünen yerel yığınlarla tam bir “yığın çerçevesi” var. Onlara el kitabının birden fazla çıktısını verin ve şu anda bu seviyede olduğunuz bir işaretle (yani, yerel değişkenlerin durumu) her kazık seviyesini bir kenara koyun, böylece her Bitti'de devam edebilirsiniz.

Özyineleme temelde budur: Aynı işlemi yapmak, daha ince bir ayrıntı düzeyinde, daha fazla girdiğinizde.

0
Secure

Hayatta (bir bilgisayar programında aksine) özyineleme nadiren doğrudan kontrolümüz altında gerçekleşir, çünkü gerçekleşmesi kafa karıştırıcı olabilir. Ayrıca, algı işlevsel olarak saf olmaktan ziyade yan etkilerle ilgili olma eğilimindedir, bu nedenle özyineleme oluyorsa bunu fark etmeyebilirsiniz.

Yine de dünyada tekrarlama olur. Çok.

Bunun iyi bir örneği su döngüsünün (basitleştirilmiş bir versiyonu):

  • Güneş gölü ısıtır
  • Su gökyüzüne yükselir ve bulutlar oluşturur
  • Bulutlar bir dağa kayıyor
  • Dağda hava, nemin tutulması için çok soğuk olur
  • Yağmur yağıyor
  • Bir nehir oluşur
  • Nehirdeki su göle akıyor

Bu, kendisinin tekrar olmasına neden olan bir döngüdür. Özyinelemeli.

Özyineleme alabileceğiniz başka bir yer İngilizce'dir (ve genel olarak insan dilidir). İlk başta tanımayabilirsiniz, ancak bir cümle üretme şeklimiz yinelemelidir, çünkü kurallar bir sembolün bir örneğini aynı sembolün başka bir örneğine gömmemize izin verir.

Steven Pinker'in Dil İçgüdüsü'nden:

kız dondurma yerse veya kız şeker yerse o zaman sosisli sandviç yer

Bu diğer tüm cümleleri içeren bütün bir cümledir:

kız dondurma yiyor

kız şeker yiyor

oğlan sosisli sandviç yiyor

Tam cümleyi anlama eylemi, tam cümle olarak anlaşılması için aynı zihinsel hile kümesini kullanan daha küçük cümlelerin anlaşılmasını içerir.

Özyinelemeyi bir programlama perspektifinden anlamak için özyineleme ile çözülebilecek bir soruna bakmak ve bunun neden olması gerektiğini ve bunun ne yapmanız gerektiğini anlamak en kolay yoldur.

Örnek için en büyük ortak bölme işlevini veya kısaca gcd'yi kullanacağım.

İki numaranız a ve b. Gcd'lerini bulmak için (ikisinin de 0 olmadığı varsayılarak) a'ın b içine eşit bölünebilir olup olmadığını kontrol etmeniz gerekir. Eğer o zaman b ise gcd ise, aksi takdirde b 'nin gcd'sini ve a/b.

Gcd işlevini çağıran gcd işlevine sahip olduğunuz için, bunun yinelemeli bir işlev olduğunu görebilmeniz gerekir. Sadece eve çekiçlemek için, burada c # (yine 0'ın parametre olarak hiç geçmediğini varsayarsak):

int gcd(int a, int b)
{   
    if (a % b == 0) //this is a stopping condition
    {
        return b;
    }

    return (gcd(b, a % b)); //the call to gcd here makes this function recursive
}

Bir programda, bir durdurma koşulu olması önemlidir, aksi takdirde işlev sonsuza kadar tekrarlanır ve bu da sonunda bir yığın taşmasına neden olur!

Burada, bir while döngüsü veya başka bir yinelemeli yapı yerine özyineleme kullanmanın nedeni, kodu okudukça size ne yaptığını ve bir sonraki adımda ne olacağını söylemesi, bu yüzden doğru çalışıp çalışmadığını anlamak daha kolay .

0
Matt Ellen