هذا المقال يتطلب مستوى: مبتدئ. هتفهم بعده يعني إيه دالة بتنادي نفسها، ليه أحيانًا الكود بيموت بـ Stack Overflow، وإمتى Recursion بيكون أنضف من الـ loop العادي.
Recursion للمبتدئ: لما الدالة بتنادي نفسها
لو كتبت دالة بسيطة بتجمع أرقام من 1 لـ 100 ولقيت Node بيرمي RangeError: Maximum call stack size exceeded، المشكلة مش في الـ RAM ولا في السيرفر. المشكلة إن دالتك بتنادي نفسها بدون شرط توقّف. ركز على الجملة دي كويس، لأنها المفتاح لكل حاجة جاية في المقال.
المشكلة باختصار
كل مبتدئ بيتعلم البرمجة بيقابل لحظة واحدة بتلخبطه: شوية كود قصير جدًا بيعمل حاجة معقدة، ومش فاهم إزاي. الكود ده غالبًا بيستخدم Recursion. وبدون ما تفهمه، هتلاقي نفسك بتكتب 40 سطر بـ for و while في مكان كان ممكن يتحل في 5 سطور.
لكن نفس Recursion ده، لو ما عرفتش تحطله شرط توقف، بيوقع الـ runtime كله. الموضوع مش نظري، ده بيحصل في production فعلًا.
مثال البصلة: تخيّل قبل ما تشوف الكود
تخيّل إن قدامك بصلة كبيرة، وعايز توصل لقلبها. إنت بتعمل إيه بالظبط؟ بتقشّر طبقة واحدة، وتلاقي بصلة أصغر جوّه. تعمل بيها نفس الحاجة: تقشّر طبقة، تلاقي بصلة أصغر، وهكذا. الموضوع بيقف لما توصل لطبقة مفيش جواها حاجة. دي بالظبط فكرة Recursion:
- كل مرة بتعمل نفس الخطوة (تقشير).
- المشكلة بتصغر مع كل خطوة (البصلة بتقل طبقاتها).
- في حالة نهائية بتخلّيك تقف (مفيش طبقات تانية).
لو نسيت الحالة النهائية، هتفضل تقشّر للأبد. نفس الكلام في الكود.
التعريف العلمي بدون رغي
في كتاب Introduction to Algorithms (المعروف بـ CLRS - Cormen, Leiserson, Rivest, Stein - الفصل 4)، التعريف بسيط: Recursion هي تقنية بتحل المشكلة الكبيرة عن طريق تقسيمها لنسخة أصغر من نفس المشكلة، وحل النسخة الأصغر بنفس الطريقة، لحد ما توصل لحالة بسيطة بتعرف تحلها مباشرة.
التعريف ده عنده ركنين أساسيين، ولازم يكونوا في كل دالة recursive:
- Base Case (الحالة الأساسية): الشرط اللي بيخلّي الدالة تقف وترجع قيمة من غير ما تنادي نفسها تاني.
- Recursive Case (الحالة المتكررة): الدالة بتنادي نفسها بقيمة أصغر بتقرّبها للـ Base Case.
أول مثال شغّال: factorial بـ Python
factorial بتاع رقم n هو حاصل ضرب الأرقام من 1 لـ n. يعني 5! = 5 × 4 × 3 × 2 × 1 = 120. لاحظ إن 5! = 5 × 4!، و 4! = 4 × 3!، وهكذا. ده تعريف بيقول حرفيًا "المشكلة الكبيرة = خطوة + نسخة أصغر من نفس المشكلة". مثالي لـ Recursion: