الدّالّة (6) - Recursion 1
Recursion هي تقنية برمجة حيث تستدعي الدالة نفسها بشكل مباشر أو غير مباشر. يمكن استخدام هذا لحل المشكلات التي يمكن تقسيمها إلى مشكلات أصغر وأبسط من نفس النوع.
قد يكون من الصعب فهم الـ Recursion في البداية، ولكنها أداة قوية يمكن استخدامها لحل مجموعة واسعة من المشكلات.
فيما يلي مثال لدالّة Recursion بسيطة في لغة C++:
#include <iostream> using namespace std; void f(int n) { if (n < 1) return; else cout << "round:" << n << endl; f(n - 1); } int main() { f(5); return 0; }
الدالة f(int n)
هي دالة recursive تقوم بطباعة السلسلة "round:" متبوعة بالعدد الصحيح n
إلى شاشة المخرجات n
من المرات.
تعمل الدالة عن طريق استدعاء نفسها بشكل متكرر لطباعة السلسلة "round:" متبوعة بالعدد الصحيح n - 1
إلى شاشة المخرجات. تستمر هذه العملية حتى تصبح قيمة n
مساوية للعدد 1، وعند هذه النقطة ترجع الدالة.
المخرجات:
round: 5 round: 4 round: 3 round: 2 round: 1
يمكن أن يكون من الصعب قليلًا فهم دوال الـ Recursive في البداية، ولكنها أداة قوية يمكن استخدامها لحل مجموعة واسعة من المشكلات.
يجب عليك الانتباه إلى هذه المحتويات الثلاثة لدالة الـ recursive (الحالة الأساسية، والمنطق، والمشكلة الفرعية)، والتي تم وضع علامة عليها في الدالة التالية:
void f(int n) { if (n < 1) return; //base case else cout << "round:" << n << endl; //logic f(n - 1); //subproblem }
المحتويات الثلاثة لدالة الـrecursive هي:
- الحالة الأساسية: الحالة الأساسية هي حالة خاصة يتم التعامل معها مباشرة في الدالة دون إجراء أي استدعاءات متكررة. عادةً ما تكون الحالة الأساسية حالة بسيطة يمكن حلها مباشرةً.
- المنطق: منطق دالة الـ recursive هو الكود الذي يتم تنفيذه لتقسيم المشكلة إلى مشاكل أصغر وأبسط من نفس النوع. يتضمن المنطق عادةً إجراء استدعاءات متكررة للدالة ذات قيم إدخال أصغر.
- المشكلة الفرعية: المشكلة الفرعية هي مشكلة أصغر وأبسط من نفس نوع المشكلة الأصلية. تعمل دوال الـ recursive عن طريق تقسيم المشكلة الأصلية إلى مشكلات فرعية ثم حل المشكلات الفرعية باستخدام نفس دالة الـ recursive.
فيما يلي مثال على دالة recursive في لغة C++ تحسب مضروب الرقم:
#include <iostream> using namespace std; int fact(int n) { if (n == 0 || n == 1) return 1; else return n*fact(n - 1); } int main() { cout << fact(5) << endl; return 0; }
الدالة fact(int n)
هي دالة recursive تحسب مضروب العدد. مضروب العدد هو حاصل ضرب جميع الأعداد الصحيحة الموجبة الأصغر من أو تساوي هذا العدد. على سبيل المثال، مضروب 5 هو 120، لأن 120 هو حاصل ضرب 1، 2، 3، 4، و5. لذلك، سيكون ناتج برنامجنا 120.
الدالة fact(int n)
تعمل عن طريق استدعاء نفسها بشكل متكرر لحساب مضروب الرقم واحد أقل من رقم الإدخال. على سبيل المثال، لحساب مضروب 5، ستستدعي الدالة نفسها أولاً لحساب مضروب 4. ومن ثم ستستدعي نفسها لحساب مضروب 3، وهكذا. في النهاية، ستصل الدالة إلى الحالة الأساسية، حيث يكون رقم الإدخال هو 0 أو 1. الحالة الأساسية هي حالة خاصة يتم التعامل معها مباشرة في الدالة دون إجراء أي استدعاءات متكررة. مضروب 0 هو 1 ومضروب 1 هو أيضًا 1، لذا تقوم الدالة ببساطة بإرجاع 1 في هذه الحالات.
سلسلة فيبوناتشي
متسلسة فيبوناتشي هي سلسلة من الأعداد بحيث يمثل كل عدد في السلسة مجموع العددين السابقين له في السلسلة. أول عددين في السلسة هما 0 و 1، وكل عدد لاحق هو مجموع العددين السابقين.
إليك تسلسل فيبوناتشي حتى أول 10 أرقام:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
يمكن إنشاء تسلسل فيبوناتشي باستخدام علاقة التكرار التالية:
F(n) = F(n - 1) + F(n - 2)
بينما F(n)
هو الرقم n في تسلسل فيبوناتشي.
يحتوي تسلسل فيبوناتشي على عدد من الخصائص المثيرة للاهتمام. على سبيل المثال، نسبة أرقام فيبوناتشي المتعاقبة تقترب من النسبة الذهبية عندما تصبح الأرقام أكبر. النسبة الذهبية هي رقم غير منطقي يساوي تقريبًا 1.618.
يظهر تسلسل فيبوناتشي في العديد من مجالات مختلفة في الرياضيات والطبيعة. على سبيل المثال، يمكن استخدامه لنمذجة نمو مجموعة من الأرانب، النمط الحلزوني للصدفة، والنمط المتفرع للشجرة.
فيما يلي بعض الأمثلة على كيفية استخدام تسلسل فيبوناتشي في العالم الحقيقي:
- الموارد المالية: يمكن استخدام تسلسل فيبوناتشي لتحديد مستويات الدعم والمقاومة المحتملة لأسعار الأسهم.
- الموسيقى: يمكن استخدام تسلسل فيبوناتشي لإنشاء مقطوعات موسيقية ذات إيقاع وبنية ممتعة.
- الفن: يمكن استخدام تسلسل فيبوناتشي لإنشاء أعمال فنية ذات تركيبة متوازنة ومتناغمة.
- الهندسة المعمارية: يمكن استخدام تسلسل فيبوناتشي لتصميم المباني والهياكل الأخرى التي تكون مبهجة من الناحية الجمالية وسليمة من الناحية الهيكلية.
تسلسل فيبوناتشي هو تسلسل رياضي رائع ومتعدد الاستخدامات وله العديد من التطبيقات في العالم الحقيقي.
مثال:
#include <iostream> using namespace std; int fib(int n) { if (n == 0 || n == 1) return n; else return fib(n - 1) + fib(n - 2); } int main() { cout << fib(3) << endl; return 0; }
الدالة fib(int n)
يعمل عن طريق استدعاء نفسه بشكل متكرر لحساب أرقام فيبوناتشي للرقمين السابقين. إذا كان رقم الإدخال n
0 أو 1، فإن الدالة تقوم ببساطة بإرجاع الرقم، لأن أول رقمين فيبوناتشي هما 0 و1. وبخلاف ذلك، تقوم الدالة بإرجاع مجموع أرقام فيبوناتشي للرقمين السابقين.
المخرجات:
2