PHP bir ÖZYINELEMELI İşlevi Nedir?

9 Cevap php

Herkes meslekten olmayan dil ve örnekler kullanarak (Fibonacci'yi kullanmadan) PHP benim için bir özyinelemeli işlev açıklayabilir misiniz? i bir örnek bakıyordu ama Fibonacci tamamen beni kaybettin!

Thank you in advance ;-) Also how often do you use them in web development?

9 Cevap

Laymens terms:

Bir recursive fonksiyon itself çağıran bir fonksiyondur

A bit more in depth:

Fonksiyon kendisini çağıran tutarsa ​​ne zaman duracağını, nasıl biliyor? Bir baz davası olarak bilinen bir durum kurmak. Baz durumlarda, aksi takdirde döngü sonsuz olur, ne zaman durdurmak için bizim özyineli çağrı söyle.

Ne matematik güçlü bir altyapıya sahip olduğundan, benim için iyi bir öğrenme örnek oldu factorial. Aşağıda yorum tarafından, bu faktoriyel fonksiyonu biraz fazla olabilir gibi görünüyor, ben sadece bunu istedim durumda burada bırakacağım.

function fact($n) {
  if ($n === 0) { // our base case
     return 1;
  }
  else {
     return $n * fact($n-1); // <--calling itself.
  }
}

Web geliştirme özyinelemeli fonksiyonlar kullanarak getirmedi, ben şahsen özyinelemeli çağrıları kullanarak çare yoktur. Ben özyineleme güvenmek kötü bir uygulama düşünün, ama onlar ilk seçenek olmamalı değil. Doğru kullanılmadığı takdirde ölümcül olabilir.

Ben dizin örnek ile rekabet edemez rağmen, ben bu biraz yardımcı olur umarım.

(4/20/10) Update:

Ayrıca kabul edilen yanıt özyinelemeli bir işlev nasıl çalıştığını rahip olmayan kimse açısından gösteriyor bu soruyu, kontrol etmek yararlı olacaktır. OP'ın soru Java ele olsa bile, kavram, aynı

Bir örnek (bir şekilde işlevini bozabilir bu dizinlere içinde hiçbir sembolik varsa) belirli bir dizinin altdizinlere her dosyayı yazdırmak olacaktır. Tüm dosyaları baskı bir pseudo-kod şöyle görünür:

function printAllFiles($dir) {
    foreach (getAllDirectories($dir) as $f) {
        printAllFiles($f); // here is the recursive call
    }
    foreach (getAllFiles($dir) as $f) {
        echo $f;
    }
}

Fikri ilk tüm alt dizinleri yazdırmak ve sonra geçerli dizinin dosyaları olduğunu. Bu fikir tüm alt dizinlere uygulanan ve tüm alt dizinleri için recursively bu işlevini çağırarak nedenini şu olsun.

Bu örneği denemek istiyorsanız, aksi takdirde printAllFiles(".") her zaman çağıran takılıyorum, özel dizinlere . ve .. için kontrol etmelisiniz. Ayrıca ne yazdırmak ve ne geçerli çalışma dizini (..., getcwd(), opendir() bakınız) olduğunu kontrol etmelidir.

Kendisini çağıran Onun bir fonksiyonu. Onun ağaçlar gibi kendilerini tekrar belirli veri yapılarını, yürüyüş için yararlıdır. Bir HTML DOM klasik bir örneğidir.

Javascript bir ağaç yapısı ve 'yürüyüş' ağaç için bir özyinelemeli fonksiyonun bir örneğidir.

    1
   / \
  2   3
     / \
    4   5

-

var tree = {
  id: 1,
  left: {
    id: 2,
    left: null,
    right: null
  },
  right: {
    id: 3,
    left: {
      id: 4,
      left: null,
      right: null
    },
    right: {
      id: 5,
      left: null,
      right: null
    }
  }
};

Ağaç yürümek, biz aynı işlevi geçerli düğümün alt düğümlerin geçen, defalarca aynı işlevi çağırın. Biz ilk önce sol düğümde, yeniden işlevini çağırın ve sonra sağda.

Bu örnekte, ağacın maksimum derinliği alırsınız

var depth = 0;

function walkTree(node, i) {

  //Increment our depth counter and check
  i++;
  if (i > depth) depth = i;

  //call this function again for each of the branch nodes (recursion!)
  if (node.left != null) walkTree(node.left, i);
  if (node.right != null) walkTree(node.right, i);

  //Decrement our depth counter before going back up the call stack
  i-;
}

Nihayet biz işlevini çağırın

alert('Tree depth:' + walkTree(tree, 0));

Anlayış özyineleme harika bir yoldur zamanında kod boyunca adım olduğunu.

Özyineleme tekerrür şeydir. Kendi içinde kendini çağıran bir fonksiyon gibi. Bana biraz sahte örnekte açıklamaya çalışalım:

Eğer Arkadaşları bira içme ile bitti düşünün, ama karınız gece yarısından önce eve dönmezsen sana cehennemi verecek. Bu amaçla, en $ zaman gece yarısı eksi geçerli içki bitirmek ve eve götüren zamandır orderAndDrinkBeer ($ zaman) işlevini yapalım.

Yani, barda gelen, ilk bira sipariş ve içme başlar:

$timeToGoHome = '23';  // Let's give ourselves an hour for last call and getting home

function orderAndDrinkBeer($timeToGoHome) {  // Let's create the function that's going to call itself.
    $beer = New Beer();  // Let's grab ourselves a new beer
    $currentTime = date('G'); // Current hour in 24-hour format

    while ($beer->status != 'empty') {  // Time to commence the drinking loop
        $beer->drink();  // Take a sip or two of the beer(or chug if that's your preference)
    }

    // Now we're out of the drinking loop and ready for a new beer

    if ($currentTime < $timeToGoHome) { // BUT only if we got the time
        orderAndDrinkBeer($timeToGoHome);  // So we make the function call itself again!
    } else {  // Aw, snap!  It is time :S
        break; // Let's go home :(
    }
}

- Şimdi sadece bu nedenle eşi ne olursa olsun eve zamanında olmanın kanepede uyku yapmak için gidiyor sarhoş olacak kadar bira içmek mümkün değildi umalım. -

Ama evet, bu oldukça fazla özyineleme nasıl gidiyor bulunuyor.

Basitçe söylemek gerekirse: A recursive fonksiyon kendisini çağıran bir fonksiyondur.

Özyineleme "Onun bitene kadar tekrar bu şey yapın" demenin süslü bir yoludur.

Olması gereken iki önemli şey:

  1. A temel durum - Sen almak için bir hedef var.
  2. Bir test - sen nereye gidiyoruz için var olmadığını bilmek nasıl.

Basit bir görevi düşünün: alfabetik bir yığın kitap sıralayın. Basit bir işlem, ilk iki kitap almak, bunları sıralamak olacaktır. Şimdi, burada özyinelemeli kısım geliyor: Daha fazla kitap var mı? Eğer öyleyse, tekrar yap. "Tekrar yapmak" özyineleme olduğunu. "Herhangi bir kitap daha var" testidir. Ve "hayır, hayır daha fazla kitap" temel durumdur.

Bir fonksiyon zaman tanımsız ve sonlu sayıda bir görevi yerine getirmeye kendisini çağırdığında o, çok basit. Benim kendi kodundan bir örnek, çok düzeyli kategori ağacında bir yerleştirmek için işlev

function category_tree($parent=0,$sep='')
{
    $q="select id,name from categorye where parent_id=".$parent;
    $rs=mysql_query($q);
    while($rd=mysql_fetch_object($rs))
    {
        echo('id.'">'.$sep.$rd->name.'');
        category_tree($rd->id,$sep.'--');
    }
}

Temelde bu. Onun bitene kadar kendisini arayıp duruyor

void print_folder(string root
{
    Console.WriteLine(root);
    foreach(var folder in Directory.GetDirectories(root))
    {
        print_folder(folder);
    }
}

Ayrıca döngüler ile çalışır!

void pretend_loop(int c)
{
    if(c==0) return;
    print "hi";
    pretend_loop(c-);
}

Ayrıca bunu googling çalışıyor olabilir. Not "Did you mean" (... üzerine tıklayın). http://www.google.com/search?q=recursion&spell=1

Özyineleme oldukça nadiren onlar koduna daha fazla açıklık ya da şıklık getirmek o, döngüler için bir alternatiftir. Iyi bir örnek diye özyineleme kullanmak olmaz eğer o (onu yığınını kullanarak muhasebe yapmak için izin verir o özyinelemeli bağıntılar (bu devlet denir) şu anda hangi dizin takip etmek zorunda kalacak, Progman cevabı tarafından verildi alanı nerede değişkenleri ve bir yöntemin dönüş adresi) saklanır

Bir döngü ile değiştirmek kolay çünkü faktöryel ve Fibonacci standart örnekler kavramını anlamak için yararlı değildir.