Özyineleme, anlaşılması zor bir konudur ve burada bunu tam olarak yapabileceğimi sanmıyorum. Bunun yerine, burada sahip olduğunuz belirli kod parçasına odaklanmaya çalışacağım ve hem çözümün neden çalıştığına dair sezgiyi hem de kodun sonucunu nasıl hesapladığına dair mekaniği açıklamaya çalışacağım.
Burada verdiğiniz kod şu sorunu çözer: a'dan b'ye kadar olan tüm tamsayıların toplamını bilmek istiyorsunuz. Örneğiniz için, 2'den 5'e kadar olan sayıların toplamını istiyorsunuz.
2 + 3 + 4 + 5
Bir sorunu özyinelemeli olarak çözmeye çalışırken, ilk adımlardan biri, sorunu aynı yapıya sahip daha küçük bir soruna nasıl böleceğini bulmak olmalıdır. Diyelim ki 2'den 5'e kadar olan sayıları toplamak istiyorsunuz. Bunu basitleştirmenin bir yolu, yukarıdaki toplamın şu şekilde yeniden yazılabileceğini fark etmektir:
2 + (3 + 4 + 5)
Burada (3 + 4 + 5), 3 ile 5 arasındaki tüm tam sayıların toplamıdır. Diğer bir deyişle, 2 ile 5 arasındaki tüm tam sayıların toplamını bilmek istiyorsanız, 3 ile 5 arasındaki tüm tam sayıların toplamını hesaplayarak başlayın, sonra 2 ekleyin.
Peki 3 ile 5 arasındaki tüm tam sayıların toplamını nasıl hesaplarsınız? Peki, bu toplam
3 + 4 + 5
bunun yerine şu şekilde düşünülebilir
3 + (4 + 5)
Burada (4 + 5), 4 ile 5 arasındaki tüm tam sayıların toplamıdır. Dolayısıyla, 3 ile 5 arasındaki tüm sayıların toplamını hesaplamak isterseniz, 4 ile 5 arasındaki tüm tam sayıların toplamını hesaplar ve ardından 3 eklersiniz.
Burada bir model var! A ve b arasındaki tamsayıların toplamını hesaplamak istiyorsanız, aşağıdakileri yapabilirsiniz. İlk olarak, a + 1 ve b arasındaki tam sayıların toplamını hesaplayın. Ardından, bu toplama bir ekleyin. "A + 1 ve b arasındaki tam sayıların toplamını hesaplayın" ifadesinin, halihazırda çözmeye çalıştığımızla hemen hemen aynı türden bir problem olduğunu fark edeceksiniz, ancak biraz farklı parametrelerle. A'dan b'ye, her şey dahil, hesaplamak yerine, a + 1'den b'ye kadar hesaplama yapıyoruz. Bu yinelemeli adımdır - daha büyük sorunu çözmek için ("a'dan b'ye toplama, kapsayıcı"), sorunu kendisinin daha küçük bir versiyonuna indirgiyoruz ("a + 1'den b'ye toplamı dahil.").
Yukarıdaki koda bakarsanız, içinde şu adım olduğunu fark edeceksiniz:
return a + sumInts(a + 1, b: b)
Bu kod basitçe yukarıdaki mantığın bir çevirisidir - eğer a'dan b'ye (dahil) toplamak istiyorsanız, a + 1'den b'ye ( sumInt
s'ye özyinelemeli çağrıdır ) toplayarak başlayın , sonra ekleyin a
.
Tabii ki, bu yaklaşım kendi başına gerçekten işe yaramayacak. Örneğin, 5 ile 5 arasındaki tüm tam sayıların toplamını nasıl hesaplarsınız? Şu anki mantığımızı kullanarak, 6 ile 5 arasındaki tüm tam sayıların toplamını hesaplayıp ardından 5 eklersiniz. Peki, 6 ile 5 arasındaki tüm tam sayıların toplamını nasıl hesaplarsınız? Şu anki mantığımızı kullanarak, 7 ile 5 arasındaki tüm tam sayıların toplamını hesaplayıp sonra 6'yı eklersiniz. Burada bir sorun olduğunu fark edeceksiniz - bu sadece devam ediyor!
Özyinelemeli problem çözmede, problemi basitleştirmeyi bırakmanın ve bunun yerine doğrudan çözmenin bir yolu olmalı. Tipik olarak, cevabın hemen belirlenebileceği basit bir vaka bulursunuz, ardından çözümünüzü basit vakaları ortaya çıktığında doğrudan çözecek şekilde yapılandırırsınız. Bu genellikle temel durum veya özyinelemeli temel olarak adlandırılır .
Öyleyse bu özel problemdeki temel durum nedir? A'dan b'ye kadar olan tam sayıları topladığınızda, a, b'den büyük olursa, o zaman cevap 0'dır - aralıkta hiç sayı yoktur! Bu nedenle, çözümümüzü şu şekilde yapılandıracağız:
- A> b ise cevap 0'dır.
- Aksi takdirde (a ≤ b), cevabı şu şekilde alın:
- A + 1 ve b arasındaki tam sayıların toplamını hesaplayın.
- Cevabı almak için bir ekleyin.
Şimdi bu sahte kodu gerçek kodunuzla karşılaştırın:
func sumInts(a: Int, b: Int) -> Int {
if (a > b) {
return 0
} else {
return a + sumInts(a + 1, b: b)
}
}
Sözde kodda ana hatları verilen çözüm ile bu gerçek kod arasında neredeyse tam olarak bire bir harita olduğuna dikkat edin. İlk adım temel durumdur - boş bir sayı aralığının toplamını sorduğunuzda 0 elde edersiniz. Aksi takdirde, a + 1 ve b arasındaki toplamı hesaplayın ve sonra a ekleyin.
Şimdiye kadar, kodun arkasında sadece üst düzey bir fikir verdim. Ama çok güzel iki sorunuz daha vardı. İlk olarak, fonksiyon a> b ise 0 döndürmeyi söylediği halde bu neden her zaman 0 döndürmüyor? İkincisi, 14 aslında nereden geliyor? Sırayla bunlara bakalım.
Çok çok basit bir vakayı deneyelim. Ararsan ne olur sumInts(6, 5)
? Bu durumda, kodun izini sürdüğünüzde, işlevin sadece 0 döndürdüğünü görürsünüz. Bu yapılacak doğru şeydir - aralıkta hiç sayı yoktur. Şimdi daha sert bir şey dene. Aradığınızda ne olur sumInts(5, 5)
? İşte ne olacak:
- Sen ara
sumInts(5, 5)
. Düşüyoruzelse
“A + sumInts (6, 5) değerini döndüren dalın .
- İçin için
sumInts(5, 5)
ne olduğunu belirlemek için sumInts(6, 5)
, biz ne yaptığımızı durup bir çağrı yapmak gerekirsumInts(6, 5)
.
sumInts(6, 5)
çağrılır. Şubeye girer if
ve geri döner 0
. Ancak, bu örneği sumInts
tarafından çağrıldı sumInts(5, 5)
, bu nedenle dönüş değeri geri iletildisumInts(5, 5)
üst düzey arayan kişiye değil, .
sumInts(5, 5)
şimdi 5 + sumInts(6, 5)
geri dönmek için hesaplayabilir 5
. Daha sonra üst düzey arayana geri gönderir.
Burada 5 değerinin nasıl oluştuğuna dikkat edin. Bir aktif çağrı ile başladık sumInts
. Bu, başka bir özyinelemeli aramayı başlattı ve bu aramanın döndürdüğü değer, bilgiyi geri iletti sumInts(5, 5)
. Daha sumInts(5, 5)
sonra yapılan çağrı, bir miktar hesaplama yaptı ve arayana bir değer geri verdi.
Bunu ile denerseniz sumInts(4, 5)
, olacaklar:
sumInts(4, 5)
geri dönmeye çalışır 4 + sumInts(5, 5)
. Bunu yapmak için çağırıyor sumInts(5, 5)
.
sumInts(5, 5)
geri dönmeye çalışır 5 + sumInts(6, 5)
. Bunu yapmak için çağırıyor sumInts(6, 5)
.
sumInts(6, 5)
0 döndürür sumInts(5, 5).</li>
<li>
sumInts (5, 5) now has a value for
sumInts (6, 5) , namely 0. It then returns
5 + 0 = 5`.
sumInts(4, 5)
şimdi sumInts(5, 5)
5 için bir değere sahiptir . Daha sonra geri döner 4 + 5 = 9
.
Başka bir deyişle, döndürülen değer, değerleri birer birer toplanarak oluşturulur, her seferinde belirli bir özyinelemeli çağrı tarafından döndürülen bir değer alınır sumInts
ve geçerli değeri eklenir a
. Özyineleme dibe vurduğunda, en derin çağrı 0 döndürür. Ancak, bu değer özyinelemeli çağrı zincirinden hemen çıkmaz; bunun yerine, değeri, üstündeki bir katman olan özyinelemeli çağrıya geri verir. Bu şekilde, her özyinelemeli çağrı yalnızca bir sayı daha ekler ve onu zincirin üst kısmına döndürerek genel toplamla sonuçlanır. Bir egzersiz olarak, bunun izini sürmeyi deneyin sumInts(2, 5)
, başlamak istediğiniz şey budur.
Bu yardımcı olur umarım!