دالة الاستدعاء الذاتي: العاملي
جزء من قسم Logic & Flow في رحلة Dart على Coddy — الدرس 49 من 65.
مضروب العدد هو عملية رياضية كلاسيكية مثالية لتوضيح مفهوم العودية (recursion). مضروب العدد الصحيح الموجب n (والذي يُكتب n!) هو حاصل ضرب جميع الأعداد الصحيحة الموجبة من 1 إلى n. على سبيل المثال، 5! = 5 × 4 × 3 × 2 × 1 = 120.
ما يجعل المضروب (factorial) مثالياً للعودية (recursion) هو أنه ينقسم بشكل طبيعي إلى مشكلات أصغر ومتطابقة. لحساب !5، يمكنك التفكير فيه على أنه !4 × 5. و !4 هو ببساطة !3 × 4، وهكذا. يستمر هذا النمط حتى تصل إلى !1، والذي يساوي 1.
int factorial(int n) {
if (n <= 1) {
return 1; // الحالة الأساسية
}
return n * factorial(n - 1); // الخطوة العودية
}تتوقف الحالة الأساسية عن الاستدعاء الذاتي عندما n <= 1، حيث تعيد 1. تقوم الخطوة الاستدعائية بضرب الرقم الحالي في مضروب الرقم الأصغر التالي. عندما تستدعي factorial(5)، فإنها تعيد 5 * factorial(4)، والتي تعيد 5 * 4 * factorial(3)، وهكذا حتى تصل إلى الحالة الأساسية.
يوضح هذا النهج كيف تحل العودية (recursion) المشكلات بأناقة من خلال اختزالها إلى نسخ أبسط من المشكلة نفسها، مما يجعل الحسابات المعقدة تبدو طبيعية وبديهية.
التحدي
سهلقم بإنشاء برنامج يحسب المضروب (factorials) لعدة أرقام باستخدام العودية (recursion). سيقوم برنامجك باستعراض دالة المضروب العودية من خلال معالجة قائمة من الأرقام وحساب مضروباتها.
- اقرأ مدخلاً نصياً يحتوي على أرقام مفصولة بفاصلة (على سبيل المثال،
"3,5,0,7") - قم بتقسيم النص المدخل إلى أرقام فردية وحوّل كل منها إلى عدد صحيح (integer)
- أنشئ دالة عودية تسمى
factorialتأخذ معاملًا صحيحًاn - يجب أن تنفذ دالة
factorialالمنطق التالي: - الحالة الأساسية (Base case): إذا كانت
nأقل من أو تساوي 1، فقم بإرجاع 1 - الخطوة العودية (Recursive step): قم بإرجاع
nمضروبة فيfactorial(n - 1) - لكل رقم في القائمة المدخلة، احسب المضروب الخاص به باستخدام دالتك العودية
- اعرض النتائج موضحاً كل رقم والمضروب المقابل له
- احسب واعرض مجموع جميع نتائج المضروب
على سبيل المثال، إذا كان المدخل هو "4,3,2"، يجب أن يخرج برنامجك:
Factorial Calculator
====================
Processing numbers: [4, 3, 2]
====================
Factorial Results:
4! = 24
3! = 6
2! = 2
====================
Sum of all factorials: 32
Calculation completed successfullyإذا كان المدخل هو "5,0,1"، يجب أن يخرج برنامجك:
Factorial Calculator
====================
Processing numbers: [5, 0, 1]
====================
Factorial Results:
5! = 120
0! = 1
1! = 1
====================
Sum of all factorials: 122
Calculation completed successfullyإذا كان المدخل هو "6"، يجب أن يخرج برنامجك:
Factorial Calculator
====================
Processing numbers: [6]
====================
Factorial Results:
6! = 720
====================
Sum of all factorials: 720
Calculation completed successfullyيجب أن يقوم برنامجك بتنفيذ دالة factorial العودية التي تستدعي نفسها بقيم متناقصة حتى تصل إلى الحالة الأساسية. يجب أن توضح الدالة كيف تقوم العودية بتفكيك حساب المضروب إلى مشكلات فرعية أصغر ومتطابقة. استخدم استكمال السلسلة النصية (string interpolation) لتنسيق نتائج المضروب كـ "$n! = $result". تذكر أن !0 يساوي 1 حسب التعريف الرياضي، وهو ما يجب أن تتعامل معه الحالة الأساسية بشكل صحيح.
ورقة مرجعية
مضروب العدد الصحيح الموجب n (الذي يُكتب n!) هو حاصل ضرب جميع الأعداد الصحيحة الموجبة من 1 إلى n. على سبيل المثال، 5! = 5 × 4 × 3 × 2 × 1 = 120.
يُعد المضروب مثالياً للعودية (recursion) لأنه ينقسم إلى مشكلات أصغر ومتطابقة: 5! = 5 × 4!، و 4! = 4 × 3!، ويستمر ذلك حتى الوصول إلى 1! = 1.
int factorial(int n) {
if (n <= 1) {
return 1; // الحالة الأساسية
}
return n * factorial(n - 1); // الخطوة العودية
}تتوقف الحالة الأساسية عن العودية عندما يكون n <= 1، حيث تُرجع القيمة 1. أما الخطوة العودية فتقوم بضرب الرقم الحالي في مضروب الرقم الأصغر التالي.
جرّب بنفسك
import 'dart:io';
// TODO: أنشئ دالة المضروب (factorial) العودية هنا
void main() {
// قراءة سلسلة الإدخال التي تحتوي على أرقام مفصولة بفاصلة
String? input = stdin.readLineSync();
// تقسيم الإدخال وتحويله إلى أعداد صحيحة
List<int> numbers = input!.split(',').map((str) => int.parse(str.trim())).toList();
// TODO: اكتب الكود الخاص بك أدناه من أجل:
// 1. معالجة كل رقم باستخدام دالة المضروب الخاصة بك
// 2. حساب مجموع كل قيم المضروب
// 3. عرض النتائج بالتنسيق المطلوب
print("Factorial Calculator");
print("====================");
print("Processing numbers: $numbers");
print("====================");
print("Factorial Results:");
// TODO: احسب واعرض نتائج المضروب هنا
print("====================");
// TODO: عرض مجموع كل قيم المضروب
print("Calculation completed successfully");
}يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Logic & Flow
1التعامل المتقدم مع القوائم
خصائص القائمة: first و lastحالة القائمة: isEmpty و isNotEmptyعكس القائمةالإضافة إلى القائمة: insertالحذف من القائمة: removeWhereالبحث في القائمة: indexOfفرز القائمةخلط القائمةملخص - منظم القوائم4معالجة الـ Map المتقدمة
التكرار عبر الـ Mapالتحقق من المفاتيح والقيمخصائص الـ Map: keys و valuesإضافة مشروطة: putIfAbsentإزالة العناصر من الـ Mapالـ Maps المتداخلةمراجعة - تحديث المخزون7الدوال المتقدمة
الدوال المجهولةتمرير الدوال كوسطاءفهم الـ Closuresمقدمة في الاستدعاء الذاتيدالة الاستدعاء الذاتي: العد التنازليدالة الاستدعاء الذاتي: العامليمراجعة - معالج القوائم2عمليات القوائم الوظيفية
التحويل باستخدام 'map'التصفية باستخدام 'where'استخدام '.toList()'التحقق من الشروط باستخدام 'any'الشروط باستخدام 'every'البحث باستخدام 'firstWhere'مراجعة - تصفية البيانات5مشروع: حاسبة عربة التسوق
إعداد المشروعإضافة العناصر إلى العربة3المجموعات
ما هي المجموعة؟إنشاء مجموعةالإضافة والحذف من المجموعاتالتحقق من وجود عناصر في المجموعةتحويل قائمة إلى مجموعةاتحاد المجموعاتتقاطع المجموعاتالفرق بين المجموعاتمراجعة - قائمة ضيوف فريدة