تجاوز إلى المحتوى الرئيسي
تابعنا على تيليجرامانضم

الدالة الراجعة (Recursion Function)

الخوارزميات والبرمجة · المهارات الرقمية

آخر تحديث:

محتويات الموضوع (٧)

شرح الموضوع

الدالة الراجعة

هل يمكن لدالة أن تستدعي نفسها؟

سأتعرَّف في هذا الدرس الدالَّة الراجعة، وأتعلَّم كيف أستخدمها في إيجاد ناتج برنامج يتكوَّن من حلقات مُتكرِّرة من الاستدعاء نفسه. تعرَّفتُ سابقًا مضروب العدد، وكيف يُمكن إيجاده باستخدام الحلقات في لغة البرمجة بايثون. كذلك تعرَّفتُ طريقة تعريف الدوال، وكيفية استدعائها في البرنامج. والآن سأتعرَّف نوعًا جديدًا من أنواع الدوال، هو الدالة الراجعة.

نتاجات التعلُّم :

  • أُعرِّف الدالة الراجعة (الدالة التي تستدعي نفسها).
  • أُحلِّل المشكلات التي يحتاج تمثيلها إلى دالة راجعة.
  • أستخدم لغة البرمجة بايثون في إيجاد حلول تتناسب مع الدالة الراجعة.

```python def Rectangle_Area(height, width): Area = height * width return Area

print(Rectangle_Area(7, 9)) ```

ما وظيفة هذا البرنامج؟

ماذا نتج من تنفيذ البرنامج؟

ما التعديل الذي يجب عمله لتمكين المُستخدم من إدخال قِيَم للمُتغيِّر ⁦(width)⁩ والمُتغيِّر ⁦(height)⁩؟

الدالة الراجعة ⁦(Recursion)⁩:

كيف تحلّ الدالة مسألة باستدعاء نفسها؟

  • يشيع استخدام الاستدعاء الذاتي في حلِّ المشكلات التي يُمكن تقسيمها إلى مشكلات فرعية صغيرة ذات هيكل مُشابه لهيكل المشكلة الأصلية.
  • تُطبَّق العملية نفسها على جزء أصغر من البيانات والمعاملات.
  • يُستخدم الاستدعاء الذاتي بدلًا من الدوران والتكرار؛ نظرًا إلى سهولة كتابة البرنامج ووضوحه.
  • ومن أشهر الأمثلة: حساب المضروب، حيث إنَّ:

5! = 5 * 4!

4! = 4 * 3!

3! = 3 * 2!

2! = 2 * 1!

1! = 1

  • مضروب العدد 5 يساوي حاصل ضرب (5) في مضروب العدد (4)، وهكذا وصولًا إلى الحالة الأساسية.
  • الحالة الأساسية هي مضروب العدد (1)، وهي حالة لا تتطلَّب استدعاء آخر للدالة.

فكيف تبدو هذه الفكرة مكتوبة بلغة بايثون؟

كيف تُكتب الدالة الراجعة في بايثون؟

``python def recursive_call(N): if base_case: return base_case_value else: return recursive_call(N - 1) ``

  • def: كلمة محجوزة تُستخدم في تعريف دالة جديدة.
  • recusive_call: اسم الدالة التي يجب أن يكون لها مُدخلات موضوعة بين أقواس.
  • recursive_call\text{recursive\_call}
  • base_case: القيمة الأساسية التي تجعل الدالة تتوقَّف، ومن دونها يصبح الدوران لانهائيًا.
  • basecasevalue: القيمة التي تعود إلى البرنامج عند تحقق شرط الوصول إلى القيمة الأساسية.

هل يُمكن التبديل بين جزأي ⁦(If)⁩ بحيث تصبح القيمة الراجعة عند الوصول إلى القيمة الأساسية (⁦base⁩case⁦value⁩) في جزئية ⁦(else)⁩؟ ما التعديل الذي يجب إجراؤه على البرنامج إن كان ذلك مُمكنًا؟

الشكل (٤-٢): مُخطَّط سَيْر العمليات للدالة الراجعة (Recursive_call).
الشكل (٤-٢): مُخطَّط سَيْر العمليات للدالة الراجعة ⁦(Recursive_call)⁩.
الشكل (٤-٣): مثال على آلية عمل الدوال الراجعة (Recursive Functions)، واستخدام (Stack Frame) في عملية التنفيذ.
الشكل (٤-٣): مثال على آلية عمل الدوال الراجعة ⁦(Recursive Functions)⁩، واستخدام ⁦(Stack Frame)⁩ في عملية التنفيذ.

استخدام المكدس في تتبُّع حالة كل استدعاء للدالة الراجعة:

كيف يتذكّر البرنامج أين يعود؟

  • المكدس نوع من هياكل البيانات، يعتمد في عمله على مبدأ أنَّ آخر قيمة تدخل هي أوَّل قيمة تخرج.
  • يُستخدم المكدس في تتبُّع حالة كل استدعاء للدالة الراجعة، بحيث يتمكَّن البرنامج من العودة إلى النقطة الصحيحة.
  • عند استدعاء البرنامج لنفسه يتمُّ إنشاء إطار جديد يحتوي على المعطيات وقِيَم المُتغيِّرات المحلية والموضع الذي تُتابع منه عملية التنفيذ.
  • عند الحالة الأساسية أو انتهاء التنفيذ يُزال الإطار من المكدس، وتُعاد مهمة التحكم إلى الإطار السابق في المكدس.
  • عدد كبير من الاستدعاءات: يُفضي إلى وضع عدد كبير من الإطارات في المكدس؛ ما يزيد من استخدام حجم الذاكرة.
  • قد يتسبَّب ذلك في تجاوز حجم الذاكرة المُتوافرة؛ ما يؤدِّي إلى توقف البرنامج عن العمل.

فلنطبّق الفكرة على مثال كامل نتتبّعه خطوة خطوة.

مثال:

كيف تجمع الدالة الأعداد من البداية إلى ⁦N⁩؟

الخطوةالعملية الحاليةالقيمة الراجعة من الدالةالنتيجة النهائية ⁦(result)⁩
1sum_recursion (0) + 1 = result01
2sum_recursion (1) + 2 = result13
3sum_recursion (2) + 3 = result36
4sum_recursion (3) + 4 = result610
5sum_recursion (5) + 5 = result1015
6sum_recursion (5) + 6 = result1521
7sum_recursion (6) + 7 = result2128
  • تعود الدالة الراجعة بعد إنهاء إيجاد المجموع إلى البرنامج الأصلي لتبدأ عملية التنفيذ، وتعود تحديدًا إلى جملة:

print("The summation of the first", N, "numbers =", sum_recursion(N))

الشكل (٤-٥): ناتج تنفيذ ()sum_recursion.
الشكل (٤-٥): ناتج تنفيذ ⁦()sum_recursion⁩.

هل أتتبّع دالة راجعة بنفسي؟

```python def fib(n): if n 0: return 0 elif n 1: return 1 return fib(n - 1) + fib(n - 2)

for i in range(10): print(fib(i)) ```

أُتتبَّع البرنامج الآتي، وأتوقَّع ناتج تنفيذه. ما وظيفة هذا البرنامج؟

أُنفِّذ البرنامج باستخدام مُفسِّر لغة البرمجة بايثون. أُقارن ناتج التنفيذ بما توقعته.

``python import math print(math.factorial(8)) ``

المواطنة الرقمية:

كيف أستخدم الدوال الراجعة بمسؤولية؟

  • المسؤولية الرقمية ⁦(Digital Responsibility)⁩: أحرص على عدم استخدام الدوال الراجعة في الحالات التي قد تُسبِّب استهلاكًا مُفرطًا للذاكرة أو الوقت.
  • وبخاصة في الأنظمة المُشتركة أو الأنظمة الحسَّاسة.
  • محو الأمية الرقمية ⁦(Digital Literacy)⁩: أُوضِّح أهمية الدوال الراجعة وكيفية استخدامها بطرائق صحيحة وفاعلة، وأُشجِّع تعلُّم مبادئ البرمجة المسؤولة لتطوير مهارات البرمجة المستدامة.

أُقيِّم تعلُّمي

هل فهمتُ الدالة الراجعة؟

ما المقصود بالدالة الراجعة؟ وما الحالة الأساسية في الدوال الراجعة؟

أستخلص إيجابيات استخدام الدالة الراجعة وسلبياتها.

أكتب الصيغة العامة للدوال الراجعة في لغة البرمجة بايثون.

ما الفَرق بين الدالة الراجعة وجملة الدوران، مثل: ⁦(for)⁩، و⁦(while)⁩؟

```python def reversestring(s): if len(s) == 0: return s return s[-1] + reversestring(s[:-1])

Word = input("Enter a word: ")

print(reverse_string(Word)) ```

أجد ناتج تنفيذ البرنامج الآتي عند إدخال كلمة ⁦(Hello)⁩:

أكتب دالة راجعة جديدة لإيجاد مجموع الأرقام الفردية فقط بين 1 و ⁦N⁩.

أُتتبَّع يدويًا الخطوات التي يَمُرُّ بها المكدس عند تنفيذ الدالة الراجعة لحساب مضروب العدد (2).

أكتب برنامجًا لإيجاد أقل عدد في قائمة ما باستخدام الدوال الراجعة، وأُوضِّح كيف يُمكن معالجة كل خطوة يدويًا.

أكتب برنامجًا لإيجاد ناتج ضرب الأرقام في قائمة ما باستخدام دالة راجعة، وأُوضِّح كيف يُمكن معالجة كل خطوة يدويًا.

أجد الخطأ في المقاطع البرمجية الآتية، ثمَّ أُصحِّحه، علمًا بأنَّ هذه المقاطع تحتوي على دالة راجعة:

```python def factorial(n): if n == 0: return 1 return n * factorial(n - 1)

print(factorial(-5)) `` ``python def linearsearch(lst, target, index=0): if index len(lst): return -1 if lst[index] target: return index return linearsearch(lst, target)

print(linearsearch([1, 2, 3, 4, 5], 3)) `` ``python def sumlist(lst): if len(lst) == 0: return 0 return lst[0] + sum_list(lst)

print(sum_list([1, 2, 3, 4, 5])) ```

تعريفات أساسية

الدالة الراجعة ⁦(Recursion)⁩

دالة قادرة على حلِّ مسألة مُعيَّنة عن طريق استدعاء نفسها مرَّات عديدة، وأداء المهمة نفسها كل مرَّة باستخدام عناصر ⁦(Parameters)⁩ مختلفة

def

كلمة محجوزة تُستخدم في تعريف دالة جديدة

base_case

القيمة الأساسية التي تجعل الدالة تتوقَّف، ومن دونها يصبح الدوران لانهائيًا

basecasevalue

القيمة التي تعود إلى البرنامج عند تحقق شرط الوصول إلى القيمة الأساسية

Factorial ()

دالة جاهزة ضمن مكتبة ⁦(math)⁩، وهي تُستخدم في إيجاد مضروب العدد، لكنَّها ليست دالة راجعة

المكدس

نوع من هياكل البيانات، يعتمد في عمله على مبدأ مفاده أنَّ آخر قيمة تدخل هي أوَّل قيمة تخرج

بطاقات مهمة

الحالة الأساسية

حالة أساسية يتوقَّف عندها الاستدعاء الذاتي؛ لكيلا يدخل هذا الاستدعاء في سلسلة لانهائية من الاستدعاءات

معاينة موضوع «الدالة الراجعة (Recursion Function)» من وحدة «الخوارزميات والبرمجة» في مادة المهارات الرقمية. أقسام الشرح: ٧، التعريفات: ٦.

المصدر: المركز الوطني لتطوير المناهج، الدالة الراجعة (Recursion Function) (ص ٦٠–٧٠)

موضوعات أخرى في الوحدة

تابع الدراسة