تخطَّ إلى المحتوى

🧮 شرح هياكل البيانات والخوارزميات

الاستدعاء الذاتي (Recursion) — تصوّر وتطبيق

الدرس 27 من 32· ⏱ 3 دقائق قراءة

ما هو الاستدعاء الذاتي؟

دالة تستدعي نفسها — كأن تنظر في مرآة أمام مرآة أخرى.

     factorial(5)
         │
    ┌────┴────┐
    │ 5 * factorial(4) │
    │         │        │
    │    ┌────┴────┐   │
    │    │ 4 * factorial(3) │
    │    │         │        │
    │    │    ┌────┴────┐   │
    │    │    │ 3 * factorial(2) │
    │    │    │         │        │
    │    │    │    ┌────┴────┐   │
    │    │    │    │ 2 * factorial(1) │
    │    │    │    │         │        │
    │    │    │    │    ┌────┴────┐   │
    │    │    │    │    │    1    │   │
    │    │    │    │    └─────────┘   │
    │    │    │    └─────────────────┘   │
    │    │    └─────────────────────────┘   │
    │    └─────────────────────────────────┘   │
    └─────────────────────────────────────────┘

Base Case vs Recursive Case

كل دالة استدعاء ذاتي تحتاج ركنين:

  1. Base Case: متى تتوقف؟ (الخروج من المرآة)
  2. Recursive Case: كيف تستدعي نفسها بمدخل أصغر؟
def countdown(n):
    # Base case
    if n <= 0:
        print("🚀 إقلاع!")
        return
    # Recursive case
    print(n)
    countdown(n - 1)

تصوّر مكدس الاستدعاءات (Call Stack)

الاستدعاء countdown(3):

الخطوة 1:          الخطوة 2:          الخطوة 3:
┌─────────┐        ┌─────────┐        ┌─────────┐
│count(3) │        │count(3) │        │count(3) │
├─────────┤        ├─────────┤        ├─────────┤
│         │        │count(2) │        │count(2) │
└─────────┘        ├─────────┤        ├─────────┤
                   │         │        │count(1) │
                   └─────────┘        ├─────────┤
                                       │         │
                                       └─────────┘

الخطوة 4 (تبدأ العودة):
┌─────────┐        ┌─────────┐        ┌─────────┐
│count(3) │        │count(3) │        │         │
├─────────┤        ├─────────┤        └─────────┘
│count(2) │        │         │
├─────────┤        └─────────┘
│count(1) │
├─────────┤
│🚀 إقلاع│
└─────────┘

⚠️ كل استدعاء يستهلك ذاكرة على المكدس. نسيان base case = Stack Overflow.

Factorial مع إطارات المكدس

def fact(n):
    if n <= 1:
        return 1
    return n * fact(n - 1)
fact(4) يستدعي fact(3) ويحتاج نتيجته
  └─ fact(3) يستدعي fact(2) ويحتاج نتيجته
       └─ fact(2) يستدعي fact(1) ويحتاج نتيجته
            └─ fact(1) → يرجع 1 (BASE CASE!)

ثم تبدأ العودة عكسياً:
    fact(1) = 1
    fact(2) = 2 × 1 = 2
    fact(3) = 3 × 2 = 6
    fact(4) = 4 × 6 = 24 ✅

Recursion vs Iteration

المقارنةالاستدعاء الذاتيالحلقات (Iteration)
حجم الكودأقل وأوضحأطول أحيانًا
الذاكرةيستهلك مكدسًالا يستهلك إضافي
الأداءأبطأ قليلاًأسرع
الاستخدامأشجار، رسوم بيانية، Divide & Conquerمسائل بسيطة متكررة
سهولة الفهمطبيعي للمسائل الهرميةطبيعي للتكرار الخطي

مشاكل شائعة

1. نسيان base case — يستمر الاستدعاء إلى مالا نهاية:

def forever():
    return forever()  # Stack Overflow بعد microseconds

2. عدم تقليل حجم المسألة — نفس القيمة تدخل مرارًا:

def infinite(n):
    if n == 0:
        return 0
    return n + infinite(n)  # n لم يتغير!

3. استهلاك ذاكرة كبير — recursion depth يتجاوز الحد:

import sys
print(sys.getrecursionlimit())  # عادة 1000

تطبيقات واقعية

  • File System: تجدير المجلدات — كل مجلد يحتوي مجلدات فرعية
  • DOM Tree: تصفح شجرة HTML
  • JSON Parsing: بيانات متداخلة
  • Fractals: أشكال رياضية متكررة مثل مثلث Sierpinski
الطبيعة تحب الاستدعاء الذاتي:
🌳 شجرة → فروع ← فروع أصغر ← فروع أصغر ...
🥦 Broccoli → زهيرات ← زهيرات أصغر ...
🫧 فقاعات في الرغوة ← فقاعات أصغر ...

🎯 التالي: البرمجة الديناميكية — أمثلة من الحياة الواقعية.

شرح الاستدعاء الذاتي (Recursion) — تصوّر وتطبيق — هياكل البيانات والخوارزميات بالعربي
الاستدعاء الذاتي (Recursion) — تصوّر وتطبيقهياكل البيانات والخوارزميات بالعربي · The Code Fix

📚 لمزيد من التعمّق في هياكل البيانات والخوارزميات، راجِع هياكل البيانات على ويكيبيديا.

هل كان هذا الدرس مفيدًا؟