Özyineleme, bir problemin aynı yapıda daha küçük alt problemlere ayrılabildiği durumlarda anlamlı bir seçimdir. Ancak her zaman döngüden daha iyi değildir; çözümün durması için açık bir taban durum ve her çağrıda küçülen bir girdi gerekir.
Karar verirken problemin yapısını, durma koşulunu, çağrı yığınının bellek kullanımını ve kodun okunabilirliğini birlikte değerlendirmek gerekir.
Özyineleme ne zaman kullanılır? Önce iki soruyu yanıtla
Özyinelemeli fonksiyon, bir işlemi tamamlamak için kendisini daha küçük bir girdıyla yeniden çağıran fonksiyondur. Bu yaklaşım özellikle ağaçlarda gezinme, klasör yapısını inceleme veya matematiksel olarak kendini tekrar eden problemlerde anlaşılır bir çözüm sağlayabilir.
Bir özyinelemeli çözümde iki temel parça bulunur. Taban durum, fonksiyonun artık kendisini çağırmadan doğrudan sonuç döndürdüğü durumdur. Recursive case ise problemi küçülten ve fonksiyonu yeni girdıyla yeniden çağıran adımdır. Her çağrıda problem küçülmüyorsa veya taban duruma ulaşılmıyorsa çözüm durmayabilir.
"Özyineleme seçmeden önce iki soruyu yanıtla: Problem daha küçük aynı türden alt probleme ayrılıyor mu ve çağrıyı durduracak taban durum açık mı?"
Taban durum ve çağrı yığını adım adım nasıl çalışır?

Faktöriyel hesabı, çağrı zincirini görmek için uygun bir örnektir. Dört sayısının faktöriyeli hesaplanırken çağrılar şu sırayla küçülür:
faktoriyel(4) → 4 * faktoriyel(3) → 4 * 3 * faktoriyel(2) → 4 * 3 * 2 * faktoriyel(1)
faktoriyel(1) taban durumdur ve doğrudan 1 döndürür. Bundan sonra çağrı yığını, bekleyen işlemleri ters sırayla tamamlar. Önce 2 * 1, ardından 3 * 2 ve son olarak 4 * 6 hesaplanır.
def faktoriyel(n):
if n <= 1:
return 1
return n * faktoriyel(n - 1)
def faktoriyel_dongu(n):
sonuc = 1
for sayi in range(2, n + 1):
sonuc *= sayi
return sonuc
print(faktoriyel(4))
print(faktoriyel_dongu(4))
Beklenen çıktı şöyledir:
24
24
İlk fonksiyon özyinelemeyi, ikinci fonksiyon aynı işlemi döngüyü kullanarak gösterir. Özyinelemeli sürüm, problemin matematiksel yapısını daha doğrudan yansıtır; fakat her tamamlanmamış çağrı çağrı yığınında beklediği için derin çağrı zincirlerinde bellek kullanımı ayrıca düşünülmelidir. Taban durumun bulunmaması veya girdinin her adımda küçülmemesi hâlinde fonksiyon duramayabilir.
Özyineleme ile döngü arasında nasıl seçim yapılır?
Özyineleme, aynı yapıda daha küçük alt problemlere ayrılabilen durumlarda anlamlı olabilir; her zaman döngüden daha iyi değildir ve açık bir taban durum gerektirir. Seçimi, kodun kısa görünmesine göre değil, problemin yapısına ve çözümün güvenli biçimde durup durmadığına göre yapmak daha sağlıklıdır.
| Ölçüt | Özyinelemeyi düşündüren durum | Döngüyü düşündüren durum | Kontrol sorusu |
|---|---|---|---|
| Problem yapısı | Problem, aynı kuralın daha küçük bir sürümüne doğal biçimde indirgeniyorsa. | İşlem, sıralı adımlarla ve tekrarlanan güncellemelerle ilerliyorsa. | Alt problem, ana problemle gerçekten aynı yapıda mı? |
| Durma koşulu | Açık ve kolay denetlenebilir bir taban durum varsa. | Başlangıç, bitiş ve tekrar sayısı doğrudan belirlenebiliyorsa. | Çözüm hangi noktada kesin olarak bitecek? |
| Bellek maliyeti | Çağrı derinliği sınırlı ve problem yapısı bunu gerektiriyorsa. | Çok sayıda adım, yalnızca birkaç değişken güncellenerek yürütülebiliyorsa. | Her çağrının çağrı yığınında ek yer tutması uygun mu? |
| Okunabilirlik | Fonksiyonun kendini çağırması çözüm fikrini daha açık gösteriyorsa. | Sayaç, birikim değişkeni veya koşullu ilerleme daha kolay takip ediliyorsa. | Kodu daha sonra okuyan biri akışı kolayca izleyebilir mi? |
Özyinelemeli çözümde her fonksiyon çağrısı, çağrı yığınında yeni bir çalışma çerçevesi oluşturur. Problem derinleştikçe bu çerçeveler bellekte birikir, fonksiyonlar sonuç döndürdükçe sırayla kaldırılır. Döngüde ise aynı işlem çoğu zaman birkaç değişken güncellenerek sürdüğü için ek çağrı zinciri oluşmaz.
Bu fark, döngünün her durumda daha uygun olduğu anlamına gelmez. Taban durum kolayca tanımlanıyor, her çağrı problemi küçültüyor ve çözüm daha anlaşılır kalıyorsa özyineleme değerlendirilebilir. İki yöntemden biri her problem için tek doğru yöntem değildir.
Python'da aynı işlemi özyineleme ve döngüyle yazma

1'den n'e kadar sayıların toplamı, iki yaklaşımın aynı sonucu farklı bir akışla nasıl ürettiğini görmek için uygundur.
def toplam_ozyinelemeli(n):
if n == 0:
return 0
return n + toplam_ozyinelemeli(n - 1)
def toplam_dongulu(n):
toplam = 0
for sayi in range(1, n + 1):
toplam += sayi
return toplam
n = 5
print(toplam_ozyinelemeli(n))
print(toplam_dongulu(n))
# Beklenen çıktı:
# 15
# 15
Özyinelemeli fonksiyonda n == 0 taban durumudur. Bu koşul sağlandığında fonksiyon kendini yeniden çağırmayı bırakır. n - 1 ile kurulan özyinelemeli adım, yani recursive case, problemi her çağrıda daha küçük bir hâle getirir.
Döngülü sürümde toplam başlangıçta 0 değerindedir. range(1, n + 1) her turda yeni bir sayı üretir ve bu sayı toplam değişkenine eklenir. Aynı işlemi iki yöntemle yazmak, sonucu doğrulamak ve problem yapısına göre hangi akışın daha anlaşılır olduğunu karşılaştırmak için yararlıdır.
Bir problemde özyineleme kararını vermek için kontrol listesi
Özyineleme kullanmadan önce aşağıdaki soruları sırayla kontrol et. Her soruya olumlu yanıt vermek özyinelemeyi zorunlu kılmaz, ancak kararını daha bilinçli vermeni sağlar.
- Problem daha küçük alt problemlere ayrılıyor mu? Her adımda aynı türden, fakat daha küçük bir problem oluşuyorsa özyineleme anlamlı olabilir.
- En küçük girdiyi tanımlayabiliyor musun? Fonksiyonun artık daha fazla çağrı yapmadan sonuç üreteceği durumu açıkça belirle.
- Taban durumu kodda görünür mü? Taban durum yalnızca açıklamada değil, fonksiyonun içinde doğrudan yazılmalıdır.
- Her çağrı taban duruma yaklaşıyor mu? Girdi küçülüyor, düğüm sayısı azalıyor veya problem başka bir ölçüte göre sona yaklaşıyor olmalıdır.
- Çağrı yığını ve bellek maliyeti uygun mu? Her çağrı kendi durumunu sakladığı için çok derin özyineleme ek bellek kullanabilir.
- Döngülü karşılık daha anlaşılır mı? Basit ve doğrusal tekrarlar için döngü, aynı işlemi daha açık biçimde ifade edebilir.
- Sınır durumlarını denedin mi? Boş girdi, en küçük değer, tek elemanlı yapı ve beklenmedik girdilerle çözümü sınamalısın.
Bu sorular, yalnızca özyinelemeyi değil, problemi parçalara ayırma ve durma koşulunu belirleme becerini de ölçer. Algoritmik Düşünme Testi ile benzer kararları farklı problem türleri üzerinde uygulayabilirsin.
Özyineleme ve döngü farkını pekiştirmek için sonraki adım
Aynı problemi iki yöntemle çözmek, farkı görmenin etkili yollarından biridir. Aşağıdaki örnekte amaç, 1’den n değerine kadar olan sayıları toplamaktır. Özyinelemeli çözümde taban durum n <= 0, ilerleme adımı ise n - 1 değerine geçmektir.
def toplam(n):
if n <= 0:
return 0
return n + toplam(n - 1)
def toplam_dongu(n):
sonuc = 0
while n > 0:
sonuc += n
n -= 1
return sonuc
print(toplam(4))
print(toplam_dongu(4))
Beklenen çıktı:
10
10
İlk fonksiyonda her çağrı, bir önceki çağrının sonucunu bekler ve n değeri taban duruma yaklaşır. İkinci fonksiyonda aynı ilerleme, while döngüsü ve sonuc değişkeniyle açıkça yönetilir. Problem ağaç veya iç içe yapı içerdiğinde özyineleme daha okunabilir olabilir. Basit tekrar işlemlerinde ise döngülü çözümün adımlarını izlemek daha kolay olabilir.
Çözümlerini 0, 1, 4 ve sınır durumunu temsil eden başka girdilerle dene. Ardından hangi yöntemi neden seçtiğini bir veya iki cümleyle yaz. Bu gerekçe, yalnızca çalışan kod üretmeni değil, çözüm tasarımını açıklamanı da sağlar.
Özyineleme, döngü ve algoritmik düşünme konularını farklı sorularla pekiştirmek için ücretsiz bilgi testleri merkezi üzerinden uygun testleri çözebilirsin.
Sık Sorulan Sorular
Özyineleme her zaman döngüden daha mı iyi?
Hayır. Alt problemlerin aynı yapıda ilerlediği veya ağaçların gezildiği durumlarda okunabilirliği artırabilir. Basit tekrarlar için döngü daha doğrudan bir seçenek olabilir.
Taban durum yazılmazsa ne olur?
Fonksiyon durma koşuluna ulaşamaz ve kendisini çağırmaya devam eder. Sonuç olarak program bir hata ile sonlanabilir veya kullanılabilir kaynakları tüketebilir.
Özyineleme kullanırken çağrı yığını neden önemlidir?
Her fonksiyon çağrısı, kendi değişkenlerini ve devam edeceği noktayı çağrı yığınında tutar. Çağrı derinliği arttıkça bellek kullanımı da artabileceği için problem boyutunu dikkate almak gerekir.
Özyinelemeli çözümü döngüye dönüştürürken hangi adımlar izlenir?
Önce taban durumu ve her çağrıda değişen değer belirlenir. Ardından bu değerler döngü değişkenlerine aktarılır, dönüş sonucu gerekiyorsa bir biriktiriciyle tutulur ve sınır girdileriyle iki çözüm karşılaştırılır.
Özyineleme kararını problem yapısını, durma koşulunu, bellek kullanımını ve okunabilirliği birlikte değerlendirerek ver.