YINELEYEN (RECURSIVE) FONKSIYONLAR

Sık sık duyarız, recursive (yineleyen) fonksiyon terimini. "Şunu yazmam gerek, nasıl yazarım?" sorusuna sıklıkla "recursive fonksiyon kullan" yanıtını alırız... Nedir bu recursive fonksiyon? Her haltı bununla mı yazacağız?

 

Hayır elbette... Aslında recursive fonksiyonları mümkün olduğunca az kullanmak belki de en iyisi ama bazı işlevleri başka türlü yazmak mümkün olmayabiliyor. İşte yalnızca böyle durumlarda ve büyük dikkatle kullanmamız gerekir recursive fonksiyonları. Tehlikelidir, daha n'oluyoruz demeden bilgisayarı kilitleyiverirsiniz...

 

Recursion

Recursive fonksiyon tanımı, kökenini "recursion" kelimesinden alır. Recursion kelimesinin Türkçe anlamı "özyineleme" dir. Google'da bir aratın:

Recursion

Sanırım bir fikir vermiştir. Evet, recursive fonksiyon demek kendine referans veren fonksiyon demektir.

 

Recursive Fonksiyon türleri

Temelde iki çeşit recursive fonksiyon vardır: Direkt ve endirekt recursive fonksiyonlar...

 

Direkt Özyineleme

Eğer bir fonksiyon, direkt olarak kendine referans veriyorsa buna "direkt recursive fonksiyon" diyoruz.

function direkt() {
  document.body.innerHTML = (document.body.innerHTML + '<br>Direkt');
  direkt();
  return;
}

Hayırlı olsun, kullanıcının makinasını sonsuz döngüye sokarak kilitledik... Aman, recursive fonksiyon yazarken kontrol parametreleri kullanarak sonsuz döngüyü engellemeye özen gösterelim. Çok küfür yeriz...

 

Endirekt Özyineleme

Eğer bir fonksiyonun referans verdiği fonksiyon ya da onun referans verdiği bir diğer fonksiyon (bu zincir uzar gider) ilk fonksiyona tekrar referans veriyorsa buna "endirekt recursive fonksiyon" diyoruz.

function fonkA(gelen) {
  if(!gelen) gelen = 1;
  document.body.innerHTML = (document.body.innerHTML + '<br>' + gelen);
  fonkB(gelen);
  return;
}

function fonkB(gelen) {
  gelen++;
  if(gelen <= 10) fonkA(gelen);
  return;
}

İstediğimiz sayıdan 10'a kadar alt alta yazan bir fonksiyon grubu yazdık. Hem bu defa kullanıcının bilgisayarını da kilitlemedik.

 

Hangi durumlarda recursion kullanmalıyız?

Recursive fonksiyonlarla ilgili örnekleme yapmak gerektiğinde herkesin aklına ilk olarak (nedense) faktoriyel hesabı geliyor. Yine bir JavaScript kodu ile inceleyelim:

function faktoriyel(gelen, sonuc) {
  if(!gelen) gelen = 1;
  if(!sonuc) sonuc = 1;

  if(gelen > 1) {
    sonuc *= gelen;
    gelen--;
    return faktoriyel(gelen, sonuc);
  }

  return sonuc;
}

document.body.innerHTML = (document.body.innerHTML + '<br>Sonuc: ' + faktoriyel(5));

İstediğimiz (örneğimizde 5) sayının faktoriyelini hesaplayan bir recursive fonksiyon yazdık. Peki anlamlı bir iş mi yaptık?

 

function faktoriyel(gelen) {
  if(!gelen) gelen = 1;
  var sonuc = 1;

  for(var i = 1; i <= gelen; i++) sonuc *= i;

  return sonuc;
}

document.body.innerHTML = (document.body.innerHTML + '<br>Sonuc: ' + faktoriyel(5));

Çok daha basit, değil mi?

 

İşte bu nedenle, recursive fonksiyonlara faktoriyel hesaplama örneğini "aman böyle saçma işler yapmayın, bir işi döngü kurarak yaptırabiliyorsanız recursive yazmayın" alt başlığı ile vermeyi tercih ederim. Peki ne zaman kullanacağız bu recursive fonksiyonları?

 

Basit, işi döngü kurarak kıvıramıyorsak recursive yazacağız...

 

Evet böyle durumlar ortaya çıkabiliyor. PHP ile böyle bir örnek oluşturalım.

 

Örnek

Sıkça karşılaşabileceğimiz bir senaryo düşünelim: Bir veri tabanımız olsun. Bu veri tabanında kategorilerimizi tutuyor olalım. Tablomuz "id", "(üst) kategori id" ve "kategori adı" kolonlarını içersin. Kullanıcıya bu kategori listesini tree-view sistemi ile sunmak istiyoruz. Ne yapacağız? Bunu basit bir döngü ile kurgulamak maalesef mümkün değil. Hangi kategorinin kaç alt kategorisi var bilmiyoruz, alt kategorilerin kaç tanesinin kaçar tane alt kategorisi var bilmiyoruz. İşte bu senaryo recursive fonksiyonu gerekli kılıyor...

 

Tablo yapısı

Tablomuzun ismi kategoriler olsun. İşlevi ise web sitemizin çok seviyeli menüsünü tutmak olsun... Veri tabanı örneğini buradan indirebilirsiniz.

 

Fonksiyon

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Yineleyen (recursive) fonksiyonlar</title>
  </head>
  <body>
    <?php
      kategoriYaz();
    ?>
  </body>
</html>
<?php
  function kategoriYaz($kid) {
    /* $kid hangi kategorinin çocuk kategorilerini
    ** listeleyeceğimizi belirlemek için gerekli.
    ** Eğer bir değer belirtilmemişse babası olmayan
    ** (en üst düzey) kategorileri listeleyeceğiz. */

    $db = new mysqli('sunucu', 'kullanici', 'sifre', 'vt_adi');

    $rs = $db->query("
      SELECT *
      FROM kategori
      WHERE ".($kid ? "kid = ".$kid : "ISNULL(kid)")."
      ORDER BY id
    ");

    if($rs->num_rows) {
      echo '<ul>';
      while($row = $rs->fetch_assoc()) {
        echo '<li>'.$row['isim'];
        kategoriYaz($row['id']); // Burası sayesinde
                                 // fonksiyon recursive
        echo '</li>';
      }
      echo '</ul>';
    }
  }
?>

Sonuç:

 

Kategori : Algoritmalar