متسلسلة فيبوناتشي: شرح شامل وتطبيقات عملية بخمس لغات برمجة (بايثون، جافاسكريبت، C++، جافا، وسويفت)
متسلسلة فيبوناتشي: شرح شامل وتطبيقات عملية بخمس لغات برمجة
تُعد متسلسلة فيبوناتشي (Fibonacci Sequence) واحدة من أكثر المفاهيم الرياضية سحراً وانتشاراً في الطبيعة وعلوم الحاسوب على حد سواء. من ترتيب أوراق النباتات إلى أنماط نمو الحلزونات، وصولاً إلى تطبيقاتها في التحليل المالي والخوارزميات، تظهر هذه المتسلسلة في أماكن غير متوقعة.
ببساطة، متسلسلة فيبوناتشي هي تسلسل من الأعداد الصحيحة يبدأ بالصفر والواحد، حيث يكون كل عدد لاحق هو مجموع العددين السابقين له مباشرة. إليك كيف تبدو:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …
على الرغم من تطبيقاتها الواسعة في الرياضيات وحتى في مجالات مثل التداول (نعم، قرأت ذلك بشكل صحيح: التداول)، فإن هدفنا اليوم ليس الخوض في هذه التطبيقات المعقدة. بدلاً من ذلك، سنركز على كيفية حساب أي حد في هذه المتسلسلة باستخدام الدوال التكرارية (Recursive Functions) في خمس لغات برمجة مختلفة: Python، JavaScript، C++، Java، و Swift.
فهم الدوال التكرارية (Recursive Functions): مفتاح الحل
الدوال التكرارية هي دوال تستدعي نفسها بنفسها لحل مشكلة معينة. في سياق متسلسلة فيبوناتشي، تعني الدالة التكرارية أننا سنقوم باستدعاء الدالة نفسها لحساب الحدود السابقة حتى نصل إلى حالات أساسية معروفة.
من المهم الإشارة إلى أن هذا الأسلوب، رغم بساطته ومساعدته في فهم مفهوم التكرار، قد لا يكون الطريقة الأكثر كفاءة لحساب أعداد فيبوناتشي الكبيرة. فالقوة الحاسوبية المطلوبة لحساب حدود كبيرة من المتسلسلة بهذه الطريقة تكون هائلة، وقد يؤدي العدد الكبير من استدعاءات الدالة إلى تجاوز سعة مكدس الاستدعاءات (Stack Overflow) في معظم اللغات. ومع ذلك، لأغراض هذا الشرح التعليمي، سنعتمد هذا النهج لفهم المبدأ.
تصميم دالة فيبوناتشي التكرارية: التفكير المنطقي
دعونا نفكر في الشكل الذي سيبدو عليه الكود. سيتضمن:
- دالة تكرارية باسم
F(اختصار لـFibonacci): لحساب قيمة الحد التالي في المتسلسلة. - لا شيء آخر: لقد حذرتك بأنها ستكون بسيطة جداً.
ستأخذ دالتنا متغيراً n كمدخل، والذي سيشير إلى الحد ذي الترتيب n الذي نرغب في حسابه. على سبيل المثال، استدعاء F(4) يجب أن يُعيد الحد الرابع من المتسلسلة.
التخطيط المنطقي للدالة
يجب أن يبدو الكود، بغض النظر عن لغة البرمجة، شيئاً كهذا في صورته المنطقية:
function F(n)
if n = 0
return 0
if n = 1
return 1
else
return F(n-1) + F(n-2)
ملاحظة: سيتم اعتبار الحد ذي الترتيب 0 في المتسلسلة هو 0، وبالتالي سيكون الحد الأول هو 1، والثاني 1، والثالث 2، وهكذا. الفكرة واضحة.
تحليل عمل الدالة خطوة بخطوة
دعونا نحلل الدالة للحظة. إذا تلقت 0 كمدخل، فإنها تُعيد 0. إذا تلقت 1، فإنها تُعيد 1. ماذا لو تلقت 2؟ حسناً، في هذه الحالة ستدخل في جملة else، والتي ستستدعي الدالة مرة أخرى للحدود 2-1 (أي 1) و 2-2 (أي 0). ستُعيد هذه الاستدعاءات 1 و 0 على التوالي، وسيتم جمع النتيجتين، ليُعاد الرقم 1. ممتاز!
الآن يمكنك أن ترى لماذا تُشكل الدوال التكرارية مشكلة في بعض الحالات. تخيل أنك أردت الحد المئة من المتسلسلة. ستستدعي الدالة نفسها للحدين 99 و 98، واللذان بدورهما سيستدعيان الدالة مرة أخرى للحدين 98 و 97، و 97 و 96… وهكذا. ستكون العملية بطيئة جداً وتتطلب استدعاءات متكررة لنفس القيم عدة مرات.
لكن الخبر السار هو أنها تعمل بالفعل! لذا دعنا نبدأ بتطبيقها في اللغات المختلفة. لن أقدم الكثير من التفاصيل (في الواقع، لن أقدم أي تفاصيل إضافية) لجعل تجربة القراءة أفضل. ليس هناك الكثير لتفصيله على أي حال. دعنا ننتقل مباشرة إلى الأكواد:
تطبيق متسلسلة فيبوناتشي بلغات برمجة متعددة
بايثون (Python)
def F(n):
if n == 0:
return 0
if n == 1:
return 1
else:
return F(n-1) + F(n-2)
سويفت (Swift)
func F(_ n: Int) -> Int {
if n == 0 {
return 0
}
if n == 1 {
return 1
}
else {
return F(n-1) + F(n-2)
}
}
جافاسكريبت (JavaScript)
function F(n) {
if(n == 0) {
return 0;
}
if(n == 1) {
return 1;
}
else {
return F(n-1) + F(n-2);
}
}
جافا (Java)
public static int F(int n) {
if(n == 0) {
return 0;
}
if(n == 1) {
return 1;
}
else {
return F(n-1) + F(n-2);
}
}
C++
int F(int n) {
if(n == 0) {
return 0;
}
if(n == 1) {
return 1;
}
else {
return F(n-1) + F(n-2);
}
}
هذا كل شيء. لقد اخترت هذه اللغات بناءً على شعبيتها – أو على الأقل لأن هذه اللغات الخمس هي الأكثر شيوعاً التي أستخدمها شخصياً. لم تُدرج بترتيب معين، ولكن يمكن تصنيفها حسب صعوبة بناء الجملة (syntax difficulty) من Python (الأسهل) إلى C++ (الأصعب)، وذلك في رأيي الشخصي. لكن هذا يعتمد بشكل كبير على رأيك وخبرتك مع كل لغة.
الخلاصة التقنية
لقد استعرضنا في هذا المقال كيفية تطبيق متسلسلة فيبوناتشي باستخدام الدوال التكرارية عبر خمس لغات برمجة شائعة. بينما تُظهر الدوال التكرارية أناقة ووضوحاً في التعبير عن المشكلات التي يمكن تقسيمها إلى نسخ أصغر من نفسها، فإنها في حالة فيبوناتشي البسيطة تعاني من مشكلة الأداء بسبب الحسابات المتكررة لنفس القيم. هذا النقص في الكفاءة يجعلها غير مناسبة لحساب حدود فيبوناتشي الكبيرة في بيئات الإنتاج.
لتحسين الأداء، يمكن استخدام تقنيات مثل البرمجة الديناميكية (Dynamic Programming) أو الحفظ المؤقت (Memoization) لتخزين نتائج الحسابات السابقة وتجنب إعادة حسابها. كما يمكن استخدام الحلول التكرارية (Iterative Solutions) التي غالباً ما تكون أكثر كفاءة من الناحية الزمنية والمكانية. ومع ذلك، يظل فهم المبدأ التكراري أساسياً لأي مبرمج، وهذا المقال يقدم نقطة انطلاق ممتازة لاستيعاب هذا المفهوم الجوهري.