`while` döngüsü kullanmadan fonksiyon ile `while True:` döngüsüne benzeyen yaptım

def döngü():
    # istenilen bir işlem eklenebilir buraya

    döngü() # eğer bunun doğru çalışmasını istiyorsanız bu kısmı silmeyin(önemli)

döngü()

tehlikeli yöntemler(önemli nokta, sakın çalıştırmayın CPU’nun tavuk dürüm olmasını yani dolmasını istemiyorsanız):

import random

def döngü():
    print("x" ** random.randint(1,500))
    
    döngü()

döngü()

bu kod neden çalıştırılmamalı?:

  1. CPU’yu doldurabilir(CPU’nun dayanıklılık seviyesine göre değişir)
2 Beğeni

for komutunu kullanmadan for döngüsü fonksiyonu yaptım bir de

def for_döngüsü(sayaç):
    if sayaç == 0:
        return
    # bir işlem ekleyin...

    for_döngüsü(sayaç-1)

for_döngüsü(10)
1 Beğeni

tebrikler fatih baba. daha en başta recursive fonksiyonları kendi kendine keşfetmişsin. iyi ilerliyorsun tebrik ederim.

1 Beğeni

Merhaba;

Recursive (yinelemeli) metotlar programlamada yaygın kullanılan konseptlerden biridir. Bunu kendi başınıza keşfetmiş olmanız ne kadar analitik düşünebildiğinizin güzel bir kanıtıdır.

def fib(n): return n if n <= 1 else fib(n - 1) + fib(n - 2)
print(fib(10))  # 55

Recursive Fonksiyonların Avantajları

  • Algoritmik olarak daha doğal ifade edilebilir: Özellikle Fibonacci, faktöriyel, ağaç yapıları veya grafik dolaşımı (DFS) gibi problemler matematiksel tanımı gereği recursive düşünülür.
  • Kod okunabilirliği yüksek olabilir: Bazı algoritmalar döngü yerine recursive yazıldığında çok daha kısa ve anlaşılır olur.
  • Bazı veri yapıları için doğaldır: Örneğin, Binary Tree gibi (worst case O(log n)) “ağacın sol ve sağ alt düğümlerini dolaş” gibi hiyerarşik yapılarda recursive yaklaşım mantıklı olur.

Dezavantajları ve Dikkat Edilmesi Gerekenler

  • Python tail recursion optimizasyonu yapmaz → performansı düşüktür.

    • Recursive fonksiyonlarda her çağrıda stack’e yeni bir fonksiyon hafıza bloğu eklenir. Önceki çağrı tamamlanmadan bu bloklar hafızadan silinmez, bu yüzden derin recursion performans ve stack taşması açısından risklidir.**
    • Döngülere göre çok daha yavaş çalışır.
  • RecursionError riski vardır (varsayılan limit ~1000 çağrı).

    import sys
    sys.getrecursionlimit()
    
  • Exponential zaman karmaşıklığı (özellikle Fibonacci gibi tekrar hesaplanan problemlerde).

  • Her çağrı fonksiyon çağrısı overhead içerdiğinden performans açısından dezavantajlıdır.


Ne Zaman Recursive Kullanılmalı?

Kullanım Durumu Recursive Uygun mu?
Matematiksel tanım (Fibonacci, Faktöriyel) :check_mark:
Ağaç / Grafik dolaşımı (DFS, Post-order traversal) :check_mark:
Basit tekrarlı işlemler (Sayaç, toplam, döngü) X (döngü kullan)
Performans kritikse X
Derinlik küçükse (≤ 50) :check_mark:

Performans için Alternatif

Eğer Fibonacci gibi hesaplamaların daha hızlı yapılması gerekiyorsa, memoization veya iterative yöntem kullanılmalıdır:

from functools import lru_cache

@lru_cache(maxsize=None)
def fib_fast(n):
    return n if n <= 1 else fib_fast(n - 1) + fib_fast(n - 2)

2 Beğeni

Merhaba,

Daha önce karşılaştınız mı bilmiyorum ama önce aşağıdaki bağlantılara bir göz atmanızı tavsiye ederim:

Fibonacci serisinin karakteristik polinomu: \phi^2 - \phi - 1 .
Bu polinomu açtığımızda şöyle bir indüksiyon elde ederiz: \phi^n = F_{n}\phi + F_{n-1} .
F_n , n . sıradaki fibonacci sayısını veren fonksiyondur.
Bu sonuca nasıl ulaştığımız yukarıdaki linklerde yer alıyor. Ama tekrar hatırlayıp polinomu modüler aritmetiğe göre temsil edelim.


\phi^2 = \phi + 1
x^2 \equiv x + 1 \pmod{x^2 - x - 1}
x^2 \pmod{x^2 - x - 1} = x + 1

Kanıt: x’in yerine herhangi bir sayı yazın ve karakteristik polinomu kullanarak modüler aritmetik işlemini sonuçlandırın.

x = 10
10^2 \pmod{10^2 - 10 - 1} = 10 + 1
100 \pmod{89} = 11


\phi^3 = 2\phi + 1
x^3 \equiv 2x + 1 \pmod{x^2 - x - 1}
x^3 \pmod{x^2 - x - 1} = 2x + 1

Kanıt: x’in yerine herhangi bir sayı yazın ve karakteristik polinomu kullanarak modüler aritmetik işlemini sonuçlandırın.

x = 5
5^3 \pmod{5^2 - 5 - 1} = 2 \times 5 + 1
125 \pmod{19} = 11


\phi^4 = 3\phi + 2
x^4 \equiv 3x + 2 \pmod{x^2 - x - 1}
x^4 \pmod{x^2 - x - 1} = 3x + 2

Kanıt: x’in yerine herhangi bir sayı yazın ve karakteristik polinomu kullanarak modüler aritmetik işlemini sonuçlandırın.

x = 4
4^4 \pmod{4^2 - 4 - 1} = 3 \times 4 + 2
256 \pmod{11} = 14
256 \pmod{11} = 3


\phi^5 = 5\phi + 3
x^5 \equiv 5x + 3 \pmod{x^2 - x - 1}
x^5 \pmod{x^2 - x - 1} = 5x + 3

Kanıt: x’in yerine herhangi bir sayı yazın ve karakteristik polinomu kullanarak modüler aritmetik işlemini sonuçlandırın.

x = 7
7^5 \pmod{7^2 - 7 - 1} = 5 \times 7 + 3
16807 \pmod{41} = 38


\phi^n = F_{n}\phi + F_{n-1}
x^n \equiv F_{n}x + F_{n-1} \pmod{x^2 - x - 1}
x^n \pmod{x^2 - x - 1} = F_{n}x + F_{n-1}


F_{n}x \pmod{x} = 0
F_{n-1} \pmod{x} = F_{n-1}
F_{n}x + F_{n-1} \pmod{x} = F_{n-1}
F_{n-1} = x^n \pmod{x^2 - x - 1} \pmod{x}
F_{n} = x^{n+1} \pmod{x^2 - x - 1} \pmod{x}


Büyük sayılarla çalışabilmek için formül şöyle olur:

\begin{align} x =& 2^{n+1} \\ F_{n} =& x^{n+1} \pmod{x^2 - x - 1} \pmod{x} \end{align}
from timeit import timeit
from typing import Callable
from functools import lru_cache


@lru_cache(maxsize=None)
def fib_fast(n: int) -> int:
    return n if n <= 1 else fib_fast(n - 1) + fib_fast(n - 2)

    
def poly_mod_pow(n: int, f: Callable[[int], int]) -> int:
    return pow(x := 2 << n, n + 1, f(x)) % x
    

f1 = lambda x: x ** 2 - x - 1                   # Fibonacci serisinin karakteristik polinomu
f2 = lambda x: x ** 3 - x ** 2 - x - 1          # Tribonacci serisinin karakteristik polinomu
f3 = lambda x: x ** 4 - x ** 3 - x ** 2 - x - 1 # Tetrabonacci serisinin karakteristik polinomu

t1 = timeit(lambda: fib_fast(500), number=1)
t2 = timeit(lambda: poly_mod_pow(500, f1), number=1)
print(t1, t2)

for i in range(10):
    print(fib_fast(i), *map(poly_mod_pow, [i] * 3, (f1, f2, f3)))

Çıktı:

0.0003714870035764761 1.52790016727522e-05
0 0 0 0
1 1 0 0
1 1 1 0
2 2 1 1
3 3 2 1
5 5 4 2
8 8 7 4
13 13 13 8
21 21 24 15
34 34 44 29
2 Beğeni

Merhaba;

Verdiğiniz bağlantıları en yakın boş zamanda özenle inceleyeceğim.

Aşağıdaki benchmark durumu çok güzel özetliyor zaten.

Saygılar;

1 Beğeni