You are on page 1of 18

Özyinelemeli (Recursive)

fonksiyonlar ve uygulamaları
Özyineleme(Recursion)
• Bazı problemler kendi öz yapıları nedeniyle, kendi türleri
cinsinden tanımlanabilirler. Örneğin faktöriyel işlemi böyle bir
işlemdir. Mesela 𝑛! = 𝑛 𝑛 − 1 ! dir. Burada dikkat edilirse 𝑛! i
bulmak için 𝑛 − 1 için de faktöriyel almak gerekir. Dolayısıyla 𝑛!
işleminin tanımında yine faktöriyel işlemi yer almaktadır.
• Özyineleme kendi türlerinin en basit formu ile tanımlanabilecek
karmaşık problemler için kullanışlı bir çözüm tekniğidir.
• Programlama açısından özyineleme; bir fonksiyonun (veya
algoritmanın) işlevini yerine getirebilmesi için kendi içerisinde
yine kendisini çağırması şeklinde yapılır.
• Özyineleme özelikle algoritmanın daha basit bir şekilde ifade
edilmesi ve hatasız bir şekilde tasarlanması açısından faydalıdır.
• Özyineleme alternatifi olarak programlamada döngüler
kullanılabilir.
Örnek: Faktöriyel İşlemi
• Faktöriyel işlemi pozitif tamsayılar için aşağıdaki gibi
tanımlanır.
n! = n*(n-1)*(n-2)*…*1 ; 1!=1
• Faktörüyel fonksiyonunu C++ da aşağıdaki gibi yazabiliriz.

int faktoriyel(int N){


if(N<=1)
return 1;
else
return N *faktoriyel(N-1);
}
Örnek: Faktöriyel İşlemi
• Varsayalım ki N=3 olsun; 𝟔
faktoriyel(3) :
3 <= 1 ? Hayır
faktoriyel(3) = 3 * faktoriyel(2)
faktoriyel(2) :
2 <= 1 ? Hayır
faktoriyel(2) = 2 * faktoriyel(1)
faktoriyel(1) :
1 <= 1 ? Evet.
return 1
int faktoriyel(int N)
if(N<=1) return 1;
else
return N *faktoriyel(N-1);
}
Faktoriyel fonksiyonu için iki yaklaşım

Özyinelemeli fonksiyon ile döngü kullanan (iteratif) fonksiyonun


karşılaştırılmasına faktöriyel fonksiyonu üzerinden bakalım.

Özyinelemeli Çözüm İteratif Çözüm

int faktoriyel(int N){


int carpim=1;
int faktoriyel(int N){
while(N>1){
if(N<=1)
return 1; carpim *= N;
else N--;
return N*faktoriyel(N-1); }
} return carpim;
}
N-1 tane fonksiyon çağrısı N-1 tane döngü
Hafıza kullanımı ve hız açısından hangisi daha maliyetli ?
Özyineleme
Özyineleme algoritma oluşturma ve basitlik açısından
avantaj sağlar ancak;
• Fonksiyon çağrıları bir döngü kurmaktan çok daha fazla zaman ve
hafıza harcanmasına neden olur.
• Yüksek performanslı uygulamalar (grafik işlem gerektiren
uygulamalar gibi) genellikle zorunlu olmadıkça özyineleme
kullanmazlar.
Algoritmanın basitliği, doğru çalışması performansından
çok daha önemli ise bu durumda özyineleme faydalıdır.
Özyinelemeli fonksiyonlarda
dikkat edilecek noktalar
• Özyinelemeli fonksiyonlarda en çok dikkat edilmesi gereken
noktalar, fonksiyonun kendiği çağırdığı nokta ve fonksiyon
çağrılarının sonlandığı noktadır.
• Sonlanma kriteri: Özyinelemenin bittiği ve fonksiyonun
sonucunun ana programa döndürüldüğü noktadır. Bu nokta
tanımlanmazsa fonksiyon sonsuz döngüye girebilir.

int faktoriyel(int N)
if(N<=1) return 1; Sonlanma kriteri
else ve sonlanma noktası
return N *faktoriyel(N-1);
}
Fonksiyon çağrısının
yapıldığı nokta
Faktoriyel Gerçek Kod
#include <iostream>
using namespace std;
int faktoriyel (int N){
if(N<=1) return 1;
else
{ printf("Sayimiz %d : \n",N);
return N*faktoriyel(N-1);}
}
int main ()
{ int N, sonuc;
cout<<"\nFaktoriyeli Alinacak Sayiyi Giriniz : "; cin>>N;
sonuc=faktoriyel(N);
printf( "%d in Faktoriyeli %d dir", N,sonuc);
cout<<endl<<endl; return(0); system("pause");
}
Çeşitli Özyinelemeli algoritmalar
• Aşağıda genellikle özyinelemeli olarak çözülen bazı problemler
listelenmektedir.
• Dizi elemanlarını sıralama
• Ağaç veri modelinde dolaşma algoritmaları
• Graf veri modelinde dolaşma algoritmaları
• Fibonacci serisi
• Hanoi kulesi oyunu çözümü
• …vb
Örnek Uygulamalar
• Fibonacci sayıları:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
Her bir sayı kendisinden önceki iki sayının toplamından elde
edilir.
• Özyineleme tanımı:
• F(0) = 0;
• F(1) = 1;
• F(N) = F(N-1)+ F(N-2);
Örnek: Fibonacci sayıları
int fibonacci(int N)
{
if (N == 0) return 0;
if (N == 1) return 1;
return (fibonacci(N-1) + fibonacci(N-2));
}

Şekilden de görüldüğü gibi fibonacci fonksiyonu her bir sayı için 2 fonksiyon çağrısı yapmaktadır.
Sayı büyüdükçe bu durum oldukça verimsiz bir hafıza kullanımı ve çalışma süresi sunmaktadır.
Örnek: Fibonacci sayıları döngü ile
• Aşağıda fibonacci sayılarının bir döngü
yardımıyla hesaplandığı fonksiyon verilmiştir. Bu
fonksiyon özyinelemelki fonksiyona göre hafıza
kullanımı ve süre açısından çok daha verimlidir.

int fibonacci_dongu(int n)
// n. Fibonacci sayisini verir
{
int onceki=0, sonraki=1,sonuc;
for (int i=2; i<n; i++)
{sonuc = onceki + sonraki;
onceki=sonraki;
sonraki=sonuc;}
return sonuc;
}
Örnek: Fibonacci sayıları gerçek kod
#include <iostream>
using namespace std;
int fibonacci(int N) {
if (N == 0) return 0; if (N == 1) return 1;
return (fibonacci(N-1) + fibonacci(N-2));}
int fibonacci_dongu(int n){
if (n==0) return 0;if (n==1) return 1;
int onceki=0, sonraki=1,sonuc;
for (int i=2; i<=n; i++)
{sonuc = onceki + sonraki; onceki=sonraki; sonraki=sonuc;}return sonuc;}
int main (){
int N, sonuc;cout<<"\n N sayisini giriniz : "; cin>>N;cout<<endl;
for (int i=0;i<=N;i++) {
sonuc=fibonacci_dongu(i);//sonuc=fibonacci(i);
printf( "%d. Fibonacci Sayisi %d dir",i, sonuc);
cout<<endl<<endl;}
return(0);system("pause");}
Özyinelemeli Fonksiyon Genel Formatı

• Özyinelemeli fonksiyonların genel formatı aşağıdaki gibidir.

int recursive_function(giris parametreleri){


if(durma sarti)
return durma degeri;
// varsa diger durma kriterleri
return recursive_function(duzenlenmis parametreler)

}
Örnek: Hanoi Kuleleri Oyunu

• Amaç bir çubuktaki tüm diskleri başka bir çubuğa


aynı sıra ile aktarmaktır.
• Bir seferde sadece bir disk hareket ettirilebilir.
• Büyük bir disk asla kendisinden daha kucuk bir
diskin üstünde yer alamaz
• Bir ve yalnızca bir extra çubuk ara diskleri tutmak
amacıyla kullanılabilir.
Örnek: Hanoi Kuleleri Oyunu

• Algoritma:
• Varsayalım ki ilk çubuk A, ikincisi B üçüncüsü de C
olarak isimlendirilmiş olsun ve n tane diskimiz olsun.
Bu durumda çözüm için disk kaydırma şu şekildedir.
1. n-1 tane diski A dan B’ye kaydır
2. Son diski A’dan C’ye kaydır
3. n-1 diski B’den C’ye Kaydır.
Örnek: Hanoi Kuleleri Oyunu
void hanoi(int kaynak, int hedef, int sayi)
{
int temp = 6 - kaynak - hedef; //geçici saklama
//sutununu bul
if (sayi == 1){
cout << " Diski 1 hareketi : " << kaynak
<< " den " << hedef << " ‘ e " << endl;
}
else {
hanoi(kaynak, temp, sayi - 1);
cout << sayi <<". Disk hareketi " << kaynak<<
" tan " << hedef<< " ‘ e " << endl;
hanoi(temp, hedef, sayi - 1);
}
}
Örnek: Hanoi Kuleleri Oyunu
int main() {
int disk_sayisi;

cout << " lutfen bir sayi giriniz (0 cikis)";


cin >> disk_sayisi;

while (disk_sayisi > 0){


hanoi(1, 3, disk_sayisi);
cout << " lutfen pozitif bir sayi giriniz ";
cin >> disk_sayisi;
}
return 0;
}

You might also like