تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
الاستدعاء الذاتي (Recursion )
#1
كاتب الموضوع : جهاد العريقي

هذا الموضوع منقول

صاحب الموضوع الاخ رغيد الطيب


السلام عليكم ورحمة الله وبركاته ...

لقد فكرت في عمل سلسة من المواضيع ذات الاهمية للمبرمجين بحيث نناقش فيها بعض المواضيع التي نغفل عنها دائماً او لاتكون هناك معلومات بمتناول الجميع عنها وسوف اسعى فيها لفائدة المبرميجن الذين لهم خبرة لابأس بها في الفيجوال بيسك وكما اني لن انسى التركيز على المبتدئين الذين انا منهم ... كي نتشارك جميعاً في خلق روح للنقاش الجماعي البناء بعيداً عن مناقشة موضوع معين او برنامج بحد ذاته اذ اني لاحظت كون المنتدى اصبح مستودعاً لنسخ حلول المشاكل البرمجية ولم يعد مقراً للناقش حول هذة المشاكل ومحاولة كل فرد منا لطرح مالديه لفائدة الغير ... طبعاً هذا لاينفي روح التعاون التي نلمسها جميعاً بين المشاركات وما يتليها من ردود سريعة لاتدل إلا على وجود هذة الروح فينا ... ولكن ما يؤسفني هنا هو عدم محاولة فهم الحل بالقدر الذي يهتم فيه الجميع بالحصول على الحل ...

لهذا اتمنى من الجميع ان يساعدني في جعل هذه السلسة خالية من المشاركات التي لا تنتمي الى الموضوع الذي نناقشه بحيث نجعل حلقات هذة السلسة مرجع غني لكل فرد فينا في حال نسيانه بعض الطرق او التقنيات او المهارات المهمة ...

-------------------------------------------------------------------------------------------

في هذا الموضوع الجديد من مواضيع [ السلسة الذهبية في المواضيع العلمية ] .. سوف نتطرق بإذن الله تعالى الى موضوع تقنية الإستدعاء الذاتي ويطلق عليه في الانجليزية Recursion وهو موضوع مهم جداً في بناء البرامج واللوغارتيمات التي تكون درجة من التعقيد ...

طبعاً الموضوع يعتبر موضوع خارج نطاق اهتمام المبتدئ في البرمجة لذا فمن الافضل ان تكون ملماً بجميع الاساسيات ولك خبرة لا بأس بها في تصميم دوال خاصة بك حتى تستطيع إستيعاب الفكرة من الاستدعاء الذاتي ... ولكي لا يصاب من لم يفهم ما سوف يأتي معنا بعد قليل بالاحباط وجب التنبيه الى ان الامر يحتاج الى توضيح دقيق وضرب اكبر كمية ممكنة من الامثلة مع شرح لخطوات العمل بالتفصيل الممل ومع ذلك كله فأن نسبة ان تصل الفكرة للجميع هي نسبة صغيرة جداً ولا اظنها تتجاوز 30% كثيراً ... وذلك ان الدور الرئيسي في عدم فهم المعلومة هو سوء نقلها وهذا ما اظنني اعاني منه خاصة مع موضوع معقد بهذا الشكل ... لهذا كله ... همسة في أذن القارئ إن لم تفهم ما سوف يأتي معنا فقم بإلقاء اللوم اولاً على ناقل المعلومة (واضعاً في بالك طبعاً سلامة نيته ومحاولته للإفادة وإن كان الاخفاق نصيبه ) .. وثانياً ضع لومك على قلة الامثلة وعدم وضوحها وبساطتها ثم اخيراً على مدى إللمامك باللغة ( كما أن إهمالك للموضوع في هذة الفترة وعودتك اليه بعد فترة او بحثك عن مصدر آخر للمعلومات سوف يجعل الامر اكثر وضوحاً خاصة وان الامر يستحق ان تبذل مجهوداً فيه وذلك لمن يريد تعزيز فكره البرمجي بهذا السلاح خاصة و أن الاستدعاء الذاتي هو سلاح لايستهان به ابداً - في عالم البرمجة طبعاً ! - ) ....

ملاحظة اخيرة :
معظم الامثلة هي امثلة إرتجالية وليدة اللحظة لهذا فهي تحتمل ورود الخطأ فيها بشكل كبير .. كما ان معظم الامثلة التي سوف اذكرها يمكنك فيها الاستغناء عن الاستدعاء الذاتي وسوف تحقق نفس النتائج اي ان تضمين الاستدعاء الذاتي لن يزيد كفائة الكود في معظم هذة الامثلة وذلك لاني حاولت فقط تضمين اكبر قدر ممكن من الامثلة لتسهيل فهم الموضوع ... ولكن كن ذا ثقة بأنه يوجد حالات كثيرة سوف تختصر فيها عشرات الاسطر البرمجية باستخدامك الاستدعاء الذاتي ...

والان دعنا نبدء بإسم الله الرحمن الرحيم

---------------------------
مفهوم الاستدعاء الذاتي :
---------------------------
هو عبارة عن إستدعاء الاجراء او الدالة لنفسها فمثلاً نحن قد اعتدنا كثيراً ان نرى كود كالتالي :

كود :
[COLOR=#000000][COLOR=#0000bb]
Sub PrintOnForm[/COLOR][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]Dim I [/color][color=#007700]As [/color][COLOR=#0000bb]Integer
    
   [/COLOR][color=#007700]For [/color][color=#0000bb]I [/color][color=#007700]= [/color][COLOR=#0000bb]1 To N
       [/COLOR][color=#007700]Print [/color][COLOR=#0000bb]I
   Next
End Sub  
[/COLOR][/COLOR]


حيث ان الاجراء PrintOnForm يقوم بطباعة الارقام من 1 الى N على الفورم وهو إجراء بسيط ولكن ماذا اذا كتبنا نفس الاجراء بالصيغة التالية :


كود :
[color=#000000][COLOR=#0000bb]Sub PrintOnForm[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][COLOR=#007700])
   If [/COLOR][color=#0000bb]N [/color][color=#007700]> [/color][COLOR=#0000bb]0 Then
      PrintOnForm N [/COLOR][color=#007700]- [/color][COLOR=#0000bb]1
      [/COLOR][color=#007700]Print [/color][COLOR=#0000bb]N
   End [/COLOR][COLOR=#007700]If
[/COLOR][COLOR=#0000bb]End Sub  
[/COLOR][/COLOR]


اذا جربت الكود السابق بالشكل التالي :


كود :
[COLOR=#000000][COLOR=#0000bb]   PrintOnForm 5  
[/COLOR][/COLOR]

سوف تلاحظ ان كلا الاجرائين قد قاما بطباعة الارقام من واحد الى خمسة والاجراء الاول كان مفهوماً اما الثاني ففيه بعض الغموض حيث لا نرى اننا قد قمنا باستخدام اوامر الدوارن فيه ( For او Until او While ) كما ان الاجراء يستدعي نفسه اي انه داخل شفرة الاجراء نجد إستدعاء لنفسه ولكن بتغير المدخلات :

كود :
[color=#000000][COLOR=#0000bb]PrintOnForm N [/color][color=#007700]- [/color][COLOR=#0000bb]1  
[/COLOR][/COLOR]

لا تشغل بالك عند هذة اللحظة بكيفية عمل هذا الاجراء وكيف قام بطباعة الارقام ! وذلك لاننا سوف نتطرق لذلك لاحقاً ... المهم هنا التركيز على عملية جعل الاجراء او الدالة تستدعي نفسها ...

انظر الى المثال التالي :


كود :
[color=#000000][COLOR=#0000bb][/color][color=#007700]Function [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700]) As [/color][COLOR=#0000bb]Long
   [/COLOR][color=#007700]If [/color][color=#0000bb]N [/color][color=#007700]< [/color][COLOR=#0000bb]2 Then
      Sum [/COLOR][color=#007700]= [/color][COLOR=#0000bb]1
   [/COLOR][COLOR=#007700]Else
      [/COLOR][color=#0000bb]Sum [/color][color=#007700]= [/color][color=#0000bb]N [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]- [/color][color=#0000bb]1[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]End [/color][COLOR=#007700]If
[/COLOR][color=#0000bb]End [/color][COLOR=#007700]Function  
[/COLOR][color=#0000bb][/color][/COLOR]

تقوم هذة الدالة بإستدعاء نفسها مرة اخرى في السطر


كود :
[color=#000000][COLOR=#0000bb]   Sum [/color][color=#007700]= [/color][color=#0000bb]N [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]- [/color][color=#0000bb]1[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

ما نريد ان نخرج به هنا ان الاستدعاء الذاتي هو ان تقوم الدالة بإستدعاء نفسها داخل الكود الخاص بها ...

--------------------------------------
لماذا نحتاج تقنية الاستدعاء الذاتي :
--------------------------------------
نحتاج الى هذة التقنية بشكل كبير عند الحاجة الى القيام بعدد متكرر من العمليات خذ مثلاً البحث عن جميع الملفات داخل القسم C: مثلاً كيف يتم ؟
يتم اولاً بالبحث عن جميع الملفات داخل الـ C: يلي ذلك البحث عن جميع الملفات داخل اول مجلد في السي لنقل مثلاً C:\Windows ثم بعد ذلك البحث عن الملفات داخل جميع المجلدات التي بداخل C:\Windows ثم العودة الى السي مرة اخرى والبحث في المجلد الثاني لنقل مثلاً C:\Program Files وفي جميع المجلدات الفرعية التي بداخله وهكذا ... والان اذا فكرت قليلاً سوف ترى ان جميع العمليات تتم بصورة مكررة فعندما ينتقل الى مجلد معين نقوم اولاً بمعرفة جمع الملفات التي فيه ثم جميع المجلدات التي فيه بحيث نكرر نفس العملية على جميع المجلدات التي بداخله والان اذا كان لدينا دالة بسيطة وضيفتها البحث عن جميع الملفات في المجلد الحالي ثم تستدعي نفسها بعدد المجلدات الفرعية التي في المجلد وفي كل استدعاء تكرر نفس العلمية ..

قد يبدو الامر مربكاً عند هذة اللحظة ولكن جرب ان تقوم بتصميم دالة تبحث في جميع المجلدات عن الملفات الموجودة سوف تلاحظ انك سوف تقوم ببعض التكرار مع شيء من التعقيد في الكود ... والان انتظر قليلاً حتى نتعرف على اساسيات الاستدعاء الذاتي وسوف ترى كم من السهل ان تقوم بالبحث عن جميع الملفات باستخدام الاستدعاء الذاتي ...

المهم في هذة اللحظة فهم ضرورة اللجوء الى الاستدعاء الذاتي لتسهيل العمليات المعقدة ...

----------------------------------------
اساسيات بناء دوال الاستدعاء الذاتي :
----------------------------------------
ان اهم شيء ينبغي التفكير فيه عند تطوير دالة إستدعاء ذاتي هو معرفة الشرط الذي سوف يتوقف عنده الاستدعاء فمن غير المنطقي ابداً ان يتم الاستدعاء الى ما لا نهاية ولهذا سوف تجد ان معظم دوال الاستدعاء الذاتي تتأكد من شرط النهاية الذي سيتوقف عنده الاستدعاء خذ مثلاً اذا كان لدينا الدالة Sum ووجدنا فيه السطر التالي :

كود :
[color=#000000][COLOR=#0000bb]Sum [/color][color=#007700]= [/color][COLOR=#0000bb]5  
[/COLOR][/COLOR]

فهذا معناه نهاية الدالة وإعطائها قيمة ولكن اذا وجدنا هذا السطر داخل الدالة Sum :

كود :
[COLOR=#000000][COLOR=#0000bb]
Sum [/COLOR][color=#007700]= [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]12[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

فأن هذا يدل على ان الدالة Sum سوف تستدعي نفسها مع تمرير القيمة 12 في هذا المثال ...

والان كيف يمكن ان نعرف ان هذا الاستدعاء هو الاستدعاء الاخير ؟

الاجابة على هذا السؤال تكمن في فحص المدخلات الى الدالة اي اننا سوف نفحص المدخلات في كل مرة الى ان نجد الشرط الذي ينبغي عنده التوقف ...

----------------------------------
امثلة و دوال بسيطة مع الشرح :
----------------------------------
دعنا نأخد الدالة Sum التي قمنا بها في المرة الاولى وكودها كان كالتالي :


كود :
[color=#000000][COLOR=#0000bb][/color][color=#007700]Function [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700]) As [/color][COLOR=#0000bb]Long
   [/COLOR][color=#007700]If [/color][color=#0000bb]N [/color][color=#007700]< [/color][COLOR=#0000bb]2 Then
      Sum [/COLOR][color=#007700]= [/color][COLOR=#0000bb]1
   [/COLOR][COLOR=#007700]Else
      [/COLOR][color=#0000bb]Sum [/color][color=#007700]= [/color][color=#0000bb]N [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]- [/color][color=#0000bb]1[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]End [/color][COLOR=#007700]If
[/COLOR][color=#0000bb]End [/color][COLOR=#007700]Function  
[/COLOR][color=#0000bb][/color][/COLOR]


الان اذا ركزت قليلاً سوف تجد ان اول شرط تقوم به الدالة هو فحص هل المدخل (البارميتر) N يحمل قيمة اصغر من 2 فان الناتج حينها هو :


كود :
[color=#000000][COLOR=#0000bb]Sum [/color][color=#007700]= [/color][COLOR=#0000bb]1  
[/COLOR][/COLOR]

و الواحد هنا هو قيمة صحيحة لايوجد فيها اي استدعاء ولكن اذا لم يتحقق هذا الشرط فان الناتج هو


كود :
[color=#000000][COLOR=#0000bb]   Sum [/color][color=#007700]= [/color][color=#0000bb]N [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]- [/color][color=#0000bb]1[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

نلاحظ هنا ان الناتج في هذة الحالة سوف يكون المتغير N مضاف اليه ناتج الدالة نفسها ولكن مع تمرير N-1 في هذة المرة فاذا كانت قيمة N=4 فان السطر سوف يكون كالتالي :

كود :
[COLOR=#000000][COLOR=#0000bb]
   Sum [/COLOR][color=#007700]= [/color][color=#0000bb]4 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]3[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

ما سوف تلاحظه انه طالما الـ N اكبر من اثنين فانه سوف يتم استدعاء الدالة بتقليل قيمة الـ N وبالتالي فان في الاخير لابد وان يصل الى اقل من اثنين وينتهي عندها الاستدعاء الذاتي ..


والان دعنا نفهم ماذا سيحصل بالضبط عند استدعاء الدالة Sum طبعاً هذة الدالة وظيفتها ان تجمع القيم من الواحد والى القيمة N فاذا كانت القيمة N=4 فان الناتج هو :

كود :
[COLOR=#000000][COLOR=#0000bb]
N [/COLOR][color=#007700]= [/color][COLOR=#0000bb]4
1 [/COLOR][color=#007700]+ [/color][color=#0000bb]2 [/color][color=#007700]+ [/color][color=#0000bb]3 [/color][color=#007700]+ [/color][color=#0000bb]4 [/color][color=#007700]= [/color][COLOR=#0000bb]10  
[/COLOR][/COLOR]

اي ان الناتج هو 10 وكذلك الحال اذا كان N=6 فان الناتج ينبغي ان يكون :

كود :
[COLOR=#000000][COLOR=#0000bb]
N [/COLOR][color=#007700]= [/color][COLOR=#0000bb]6
1 [/COLOR][color=#007700]+ [/color][color=#0000bb]2 [/color][color=#007700]+ [/color][color=#0000bb]3 [/color][color=#007700]+ [/color][color=#0000bb]4 [/color][color=#007700]+ [/color][color=#0000bb]5 [/color][color=#007700]+ [/color][color=#0000bb]6 [/color][color=#007700]= [/color][COLOR=#0000bb]21  
[/COLOR][/COLOR]

طبعاً يمكن كتابة الدالة بدون الاستدعاء الذاتي بالشكل التالي:

كود :
[COLOR=#000000][COLOR=#0000bb]
[/COLOR][color=#007700]Function [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700]) As [/color][COLOR=#0000bb]Long
   Dim I [/COLOR][color=#007700]As [/color][COLOR=#0000bb]Integer
   Dim R [/COLOR][color=#007700]As [/color][COLOR=#0000bb]Long
    
   [/COLOR][color=#007700]For [/color][color=#0000bb]I [/color][color=#007700]= [/color][COLOR=#0000bb]1 To N
       R [/COLOR][color=#007700]= [/color][color=#0000bb]R [/color][color=#007700]+ [/color][COLOR=#0000bb]I
   Next I
    
   Sum [/COLOR][color=#007700]= [/color][COLOR=#0000bb]R
End [/COLOR][COLOR=#007700]Function  
[/COLOR][color=#0000bb][/color][/COLOR]


وهي دالة بسيطة وواضحة ولكننا سوف نستغل بساطتها في توضيح مفهوم الاستدعاء الذاتي و تتبع خطواته ...

والان سوف نكتب الدالة بشكل الاستدعاء الذاتي ثم نتبع الخطوات التي سوف تحصل اذا كانت قيمة N=5 :

كود :
[COLOR=#000000][COLOR=#0000bb]
[/COLOR][color=#007700]Function [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700]) As [/color][COLOR=#0000bb]Long
   [/COLOR][color=#007700]If [/color][color=#0000bb]N [/color][color=#007700]< [/color][COLOR=#0000bb]2 Then
      Sum [/COLOR][color=#007700]= [/color][COLOR=#0000bb]1
   [/COLOR][COLOR=#007700]Else
      [/COLOR][color=#0000bb]Sum [/color][color=#007700]= [/color][color=#0000bb]N [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]- [/color][color=#0000bb]1[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]End [/color][COLOR=#007700]If
[/COLOR][color=#0000bb]End [/color][COLOR=#007700]Function  
[/COLOR][color=#0000bb][/color][/COLOR]

والان عند الاستدعاء الاول للدالة بواسطتة كتابة السطر التالي مثلاً :



كود :
[color=#000000][COLOR=#0000bb][/color][color=#007700]Print [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]5[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

الان سوف تكون قمية N=5 وعندها فان اول خطوة سوف يفحص قيمة N هل اصغر من 2 وإلا فان الناتج هو :


كود :
[COLOR=#000000][COLOR=#0000bb]
  Sum [/COLOR][color=#007700]= [/color][color=#0000bb]N [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]N[/color][color=#007700]-[/color][color=#0000bb]1[/color][COLOR=#007700])
  [/COLOR][COLOR=#0000bb]وهذا يعني  
  Sum [/COLOR][color=#007700]= [/color][color=#0000bb]5 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]5[/color][color=#007700]-[/color][color=#0000bb]1[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

وبالتالي فاننا يمكن ان نستخدم الجدول التالي :

كود :
[COLOR=#000000][COLOR=#0000bb]

   1[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]5[/color][color=#007700]) = [/color][color=#0000bb]5 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]4[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]2[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]4[/color][color=#007700]) = [/color][color=#0000bb]4 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]3[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]3[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]3[/color][color=#007700]) = [/color][color=#0000bb]3 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]2[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]4[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]2[/color][color=#007700]) = [/color][color=#0000bb]2 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]1[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]5[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]1[/color][color=#007700]) = [/color][COLOR=#0000bb]1  
[/COLOR][/COLOR]

ما نلاحظه من الجدول السابق انه في الاستدعاء الاول كانت قيمة الدالة هي 5 مضاف اليها الدالة نفسها ولكن بتمرير 4 اي ان ناتج Sum(5) هو 5 مضاف الى Sum(4) ولاننا لانعرف كم ناتجSum(4) تقوم باستدعاء نفسها مرة اخرى الى ان نصل الى الخطوة الخامسة وهي الخطوة الحاسمة حيث تتنج قيمة عن الدالة لان المتغير N يساوي واحد اي اصغر من اثنين وبهذا فان ناتج الدالة Sum(1)=1 وعندئذ يتم تعويضه في الخطوة الرابعة فيتنج Sum(2)=2 +1 ومنها فان ناتج Sum(2)=3 وبالتالي يمكن تعويضه في الخطوة الثالثة حيث ان Sum(3)= 3+ 3 .... وهكذا حتى نحصل على قيمة للمعادلة Sum(5)=15 وذلك بالشكل التالي :


كود :
[COLOR=#000000][COLOR=#0000bb]
   1[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]5[/color][color=#007700]) = [/color][color=#0000bb]5 [/color][color=#007700]+ [/color][color=#0000bb]10 [/color][color=#007700]= [/color][COLOR=#0000bb]15
   2[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]4[/color][color=#007700]) = [/color][color=#0000bb]4 [/color][color=#007700]+ [/color][color=#0000bb]6 [/color][color=#007700]= [/color][COLOR=#0000bb]10
   3[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]3[/color][color=#007700]) = [/color][color=#0000bb]3 [/color][color=#007700]+ [/color][color=#0000bb]3 [/color][color=#007700]= [/color][COLOR=#0000bb]6
   4[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]2[/color][color=#007700]) = [/color][color=#0000bb]2 [/color][color=#007700]+ [/color][color=#0000bb]1 [/color][color=#007700]= [/color][COLOR=#0000bb]3
   5[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]1[/color][color=#007700]) = [/color][COLOR=#0000bb]1  
[/COLOR][/COLOR]

حيث ان كل خطوة تنتج بجمع N الى الناتج من الخطوة السابقة وهكذا ...

لنفترض الان ان قيمة N=9 فان الخطوات ستكون كالتالي :

كود :
[COLOR=#000000][COLOR=#0000bb]
   1[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]9[/color][color=#007700]) = [/color][color=#0000bb]9 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]8[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]2[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]8[/color][color=#007700]) = [/color][color=#0000bb]8 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]7[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]3[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]7[/color][color=#007700]) = [/color][color=#0000bb]7 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]6[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]4[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]6[/color][color=#007700]) = [/color][color=#0000bb]6 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]5[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]5[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]5[/color][color=#007700]) = [/color][color=#0000bb]5 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]4[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]6[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]4[/color][color=#007700]) = [/color][color=#0000bb]4 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]3[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]7[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]3[/color][color=#007700]) = [/color][color=#0000bb]3 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]2[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]8[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]2[/color][color=#007700]) = [/color][color=#0000bb]2 [/color][color=#007700]+ [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]1[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]9[/color][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]1[/color][color=#007700]) = [/color][COLOR=#0000bb]1  
[/COLOR][/COLOR]

وبالتالي فان الحل سيبدء من الخطوة التاسعة لانها لاتحتوي على استدعاء وفيها قيمة الدالة تساوي واحد وسيتدرج الحل من الخطوة التاسعة حتى الخطوة الاولى بحيث كل خطوة تأخد القيمة من التي سبقتها وهكذا .... بالشكل التالي :


كود :
[COLOR=#000000][COLOR=#0000bb]
   1[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]9[/color][color=#007700]) = [/color][color=#0000bb]9 [/color][color=#007700]+ [/color][color=#0000bb]36 [/color][color=#007700]= [/color][COLOR=#0000bb]45
   2[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]8[/color][color=#007700]) = [/color][color=#0000bb]8 [/color][color=#007700]+ [/color][color=#0000bb]28 [/color][color=#007700]= [/color][COLOR=#0000bb]36
   3[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]7[/color][color=#007700]) = [/color][color=#0000bb]7 [/color][color=#007700]+ [/color][color=#0000bb]21 [/color][color=#007700]= [/color][COLOR=#0000bb]28
   4[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]6[/color][color=#007700]) = [/color][color=#0000bb]6 [/color][color=#007700]+ [/color][color=#0000bb]15 [/color][color=#007700]= [/color][COLOR=#0000bb]21
   5[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]5[/color][color=#007700]) = [/color][color=#0000bb]5 [/color][color=#007700]+ [/color][color=#0000bb]10 [/color][color=#007700]= [/color][COLOR=#0000bb]15
   6[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]4[/color][color=#007700]) = [/color][color=#0000bb]4 [/color][color=#007700]+ [/color][color=#0000bb]6  [/color][color=#007700]= [/color][COLOR=#0000bb]10
   7[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]3[/color][color=#007700]) = [/color][color=#0000bb]3 [/color][color=#007700]+ [/color][color=#0000bb]3  [/color][color=#007700]= [/color][COLOR=#0000bb]6
   8[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]2[/color][color=#007700]) = [/color][color=#0000bb]2 [/color][color=#007700]+ [/color][color=#0000bb]1  [/color][color=#007700]= [/color][COLOR=#0000bb]3
   9[/COLOR][color=#007700]) [/color][color=#0000bb]Sum[/color][color=#007700]([/color][color=#0000bb]1[/color][color=#007700]) = [/color][COLOR=#0000bb]1  
[/COLOR][/COLOR]

وسنحصل في الاخير على 45 وهو بالطبع ناتج :


كود :
[color=#000000][COLOR=#0000bb]N[/color][color=#007700]=[/color][COLOR=#0000bb]9
1 [/COLOR][color=#007700]+ [/color][color=#0000bb]2 [/color][color=#007700]+ [/color][color=#0000bb]3 [/color][color=#007700]+ [/color][color=#0000bb]4 [/color][color=#007700]+ [/color][color=#0000bb]5 [/color][color=#007700]+ [/color][color=#0000bb]6 [/color][color=#007700]+ [/color][color=#0000bb]7 [/color][color=#007700]+ [/color][color=#0000bb]8 [/color][color=#007700]+ [/color][color=#0000bb]9 [/color][color=#007700]= [/color][COLOR=#0000bb]45  
[/COLOR][/COLOR]

وللدرس بقية انشا الله
}}}}
تم الشكر بواسطة:
#2
تكملة للدرس الاول:

المثال السابق كان لايجاد المجموع للعدد N وسوف اترك ايجاد المضروب لاي عدد N كاتمرين
وبالطبع هو مشابه تماماً لفكرة المجموع باختلاف انه مضروب اي يستخدم الضرب وليس الجمع والدالة بصيغتها العادية هي :


كود :
[COLOR=#000000][COLOR=#0000bb]
[/COLOR][color=#007700]Function [/color][color=#0000bb]Fact[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700]) As [/color][COLOR=#0000bb]Long
   Dim I [/COLOR][color=#007700]As [/color][COLOR=#0000bb]Integer
   Dim R [/COLOR][color=#007700]As [/color][COLOR=#0000bb]Long
    
   R [/COLOR][color=#007700]= [/color][COLOR=#0000bb]1
   [/COLOR][color=#007700]For [/color][color=#0000bb]I [/color][color=#007700]= [/color][COLOR=#0000bb]1 To N
       R [/COLOR][color=#007700]= [/color][color=#0000bb]R [/color][color=#007700]* [/color][COLOR=#0000bb]I
   Next I
    
   Fact [/COLOR][color=#007700]= [/color][COLOR=#0000bb]R
End [/COLOR][COLOR=#007700]Function  
[/COLOR][color=#0000bb][/color][/COLOR]

ويبقى على القارئ تحويلها الى صيغة الاستدعاء الذاتي ( وهي ابسط من تعتبر تمرين ذلك لشبهها الكبير إن لم يكن لتماثلها مع الدالة Sum ) ...


-------------
مثال آخر :
-------------
والان دعنا نأخد مثال آخر نفرض ان لدينا نص معين ونريد تصميم دالة تقوم بعكس هذا النص من النقطة التي نريدها ولنسميها Rev بحيث يكون لها مدخلان الاول هو النص والثاني هو الموقع الذي سوف نعكس من عنده خذ مثلاً :


كود :
[COLOR=#000000][COLOR=#0000bb]
   [/COLOR][color=#007700]Print [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700], [/color][color=#0000bb]1[/color][COLOR=#007700])
   Print [/COLOR][color=#0000bb]Rev[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700], [/color][color=#0000bb]3[/color][COLOR=#007700])
   Print [/COLOR][color=#0000bb]Rev[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700], [/color][color=#0000bb]5[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

بحيث يكون الناتج من السطر الاول هو "deehgR" .
ومن الثاني هو : "deeh"
ومن الثالث هو : "de"

لاحظ ان العكس في السطر الثاني من الموقع الثالث اي من الحرف h في كلمة Rgheed وبالتالي ينتج deeh وهكذا بالنسبة للثالث ...

والان لكي نعكس النص يجب ان نستخرج حرف بعد حرف ويمكن ذلك عن طريق الدالة Mid مثلاً لكي استخرج الحرف الثالث من كلمة Rgheed اكتب :

كود :
[COLOR=#000000][COLOR=#0000bb]
Mid[/COLOR][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700],[/color][color=#0000bb]3[/color][color=#007700],[/color][color=#0000bb]1[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

وتعني من الكلمة Rgheed استخرج من الموقع الثالث حرف واحد وبالتالي فهو الـ h ...
وهكذا اذا اردنا ان نستخرج الحرف d من الموقع السادس:


كود :
[color=#000000][COLOR=#0000bb]Mid[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700],[/color][color=#0000bb]6[/color][color=#007700],[/color][color=#0000bb]1[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

والان دعنا نكتب الدالة بصيغتها العادية كالتالي :

كود :
[COLOR=#000000][COLOR=#0000bb]
[/COLOR][color=#007700]Function [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#0000bb]S [/color][color=#007700]As [/color][color=#0000bb]String[/color][color=#007700], [/color][color=#0000bb]Pos [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700]) As [/color][COLOR=#0000bb]String
   Dim T [/COLOR][color=#007700]As [/color][COLOR=#0000bb]String
   Dim I [/COLOR][color=#007700]As [/color][COLOR=#0000bb]Integer
    
   [/COLOR][color=#007700]For [/color][color=#0000bb]I [/color][color=#007700]= [/color][color=#0000bb]Len[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700]) [/color][color=#0000bb]To Pos Step [/color][color=#007700]-[/color][COLOR=#0000bb]1
       T [/COLOR][color=#007700]= [/color][color=#0000bb]T [/color][color=#007700]+ [/color][color=#0000bb]Mid[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700], [/color][color=#0000bb]I[/color][color=#007700], [/color][color=#0000bb]1[/color][COLOR=#007700])
   [/COLOR][COLOR=#0000bb]Next
    
   Rev [/COLOR][color=#007700]= [/color][COLOR=#0000bb]T
End [/COLOR][COLOR=#007700]Function  
[/COLOR][color=#0000bb][/color][/COLOR]


ومن تركيب الدالة يتضح انها تبدء من آخر عنصر Len(S) الى الموقع الذي نريد العكس من عنده وهو Pos ثم نستخرج حرف بحرف وبحيث نستخرج الحرف الاخير ثم الذي قبله وهكذا وينتج في الاخير النص معكوس ...

والان دعنا نفكر كيف سنحولها الى صيغة الاستدعاء الذاتي ... اولاً وكما اسلفنا يجب التفكير في الشرط الذي سوف ننتهي عنده وذلك اعتماداً على المتغير المدخل وسوف نستخدم هنا المدخل Pos للفحص (كما استخدمنا المدخل N في المثال السابق ) ...

والفكرة التي سوف نستخدمها هنا هي اننا سوف نقوم بالعكس طالما الموقع Pos اصغر من موقع آخر عنصر بالشكل التالي :

كود :
[COLOR=#000000][COLOR=#0000bb]
[/COLOR][color=#007700]Function [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#0000bb]S [/color][color=#007700]As [/color][color=#0000bb]String[/color][color=#007700], [/color][color=#0000bb]Pos [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700]) As [/color][COLOR=#0000bb]String
   [/COLOR][color=#007700]If [/color][color=#0000bb]Pos [/color][color=#007700]<= [/color][color=#0000bb]Len[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700]) [/color][COLOR=#0000bb]Then
      Rev [/COLOR][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700], [/color][color=#0000bb]Pos [/color][color=#007700]+ [/color][color=#0000bb]1[/color][color=#007700]) + [/color][color=#0000bb]Mid[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700], [/color][color=#0000bb]Pos[/color][color=#007700], [/color][color=#0000bb]1[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]End [/color][COLOR=#007700]If
[/COLOR][color=#0000bb]End [/color][COLOR=#007700]Function  
[/COLOR][color=#0000bb][/color][/COLOR]

حيث اننا فحصنا هنا انه اذا كان Pos اصغر من موقع آخر عنصر Len(S) بالتالي نستمر بالعكس .... ولكي نفهم الامر دعنا نتتبع المثال لنفرض ان الكلمة هي Rgheed ونريد عكسها من الحرف الاول فاننا سوف نكتب التالي :

كود :
[COLOR=#000000][COLOR=#0000bb]
[/COLOR][color=#007700]Print [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700],[/color][color=#0000bb]1[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

من الواضح ان طول النص هو ستة حروف Len(S)=6 .... لاحظ ان الدالة كلها تعتمد على السطر :


كود :
[color=#000000][COLOR=#0000bb]Rev [/color][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700], [/color][color=#0000bb]Pos [/color][color=#007700]+ [/color][color=#0000bb]1[/color][color=#007700]) + [/color][color=#0000bb]Mid[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700], [/color][color=#0000bb]Pos[/color][color=#007700], [/color][color=#0000bb]1[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

اي انه اذا كانت قيمة الـ Pos هي واحد فان السطر السابق سوف يبدو كالتالي :

كود :
[COLOR=#000000][COLOR=#0000bb]
Rev [/COLOR][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700], [/color][color=#0000bb]1 [/color][color=#007700]+ [/color][color=#0000bb]1[/color][color=#007700]) + [/color][color=#0000bb]Mid[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700], [/color][color=#0000bb]1[/color][color=#007700],[/color][color=#0000bb]1[/color][COLOR=#007700])
[/COLOR][COLOR=#0000bb]وهذا يعني
Rev [/COLOR][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700],[/color][color=#0000bb]2[/color][color=#007700]) + [/color][COLOR=#dd0000]"R"  
[/COLOR][color=#0000bb][/color][/COLOR]

لاحظ ان الحرف R جاء كناتج من الامر Mid(S,1,1)ويعني استخرج الحرف الاول ...
اما اذا كان الـ Pos=2 فان السطر سوف يبدو :


كود :
[COLOR=#000000][COLOR=#0000bb]
Rev [/COLOR][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700], [/color][color=#0000bb]2 [/color][color=#007700]+ [/color][color=#0000bb]1[/color][color=#007700]) + [/color][color=#0000bb]Mid[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700], [/color][color=#0000bb]2[/color][color=#007700],[/color][color=#0000bb]1[/color][COLOR=#007700])
[/COLOR][COLOR=#0000bb]وهذا يعني
Rev [/COLOR][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#0000bb]S[/color][color=#007700],[/color][color=#0000bb]3[/color][color=#007700]) + [/color][COLOR=#dd0000]"g"  
[/COLOR][color=#0000bb][/color][/COLOR]

وهكذا الى ان يكون الـ pos اكبر من الستة عندها يكون الراجع من الدالة هو فراغ اي ان Rev="" وذلك لان الشرط If Pos <= Len(S) Then لن يتحقق وبالتالي سوف نخرج من الدالة مباشرة عند الخطوة السابعة ...


والخطوات كاملة سوف تكون كالتالي


كود :
[COLOR=#000000][COLOR=#0000bb]
  1[/COLOR][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700],[/color][color=#0000bb]2[/color][color=#007700]) + [/color][COLOR=#dd0000]"R"
  [/COLOR][color=#0000bb]2[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700],[/color][color=#0000bb]3[/color][color=#007700]) + [/color][COLOR=#dd0000]"g"
  [/COLOR][color=#0000bb]3[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700],[/color][color=#0000bb]4[/color][color=#007700]) + [/color][COLOR=#dd0000]"h"
  [/COLOR][color=#0000bb]4[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700],[/color][color=#0000bb]5[/color][color=#007700]) + [/color][COLOR=#dd0000]"e"
  [/COLOR][color=#0000bb]5[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700],[/color][color=#0000bb]6[/color][color=#007700]) + [/color][COLOR=#dd0000]"e"
  [/COLOR][color=#0000bb]6[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#0000bb]Rev[/color][color=#007700]([/color][color=#dd0000]"Rgheed"[/color][color=#007700],[/color][color=#0000bb]7[/color][color=#007700]) + [/color][COLOR=#dd0000]"d"
  [/COLOR][color=#0000bb]7[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][COLOR=#dd0000]""  
[/COLOR][color=#0000bb][/color][/COLOR]

بعد الوصول الى الخطوة الاخيرة ( الخطوة السابعة) فان قيمة الدالة عندها هي فراغ "" ويمكن هنا ان نأخذ هذة القيمة صعوداً ونعوض فيها بالخطوة السادسة ثم الناتج نعوضه في الخامسة وهكذا .. وسوف يكون الحل كالتالي :

كود :
[COLOR=#000000][COLOR=#0000bb]

  1[/COLOR][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#dd0000]"deehg" [/color][color=#007700]+ [/color][color=#dd0000]"R"  [/color][color=#007700]= [/color][COLOR=#dd0000]"deehgR"
  [/COLOR][color=#0000bb]2[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#dd0000]"deeh" [/color][color=#007700]+ [/color][color=#dd0000]"g"    [/color][color=#007700]= [/color][COLOR=#dd0000]"deehg"
  [/COLOR][color=#0000bb]3[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#dd0000]"dee" [/color][color=#007700]+ [/color][color=#dd0000]"h"      [/color][color=#007700]= [/color][COLOR=#dd0000]"deeh"
  [/COLOR][color=#0000bb]4[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#dd0000]"de" [/color][color=#007700]+ [/color][color=#dd0000]"e"        [/color][color=#007700]= [/color][COLOR=#dd0000]"dee"
  [/COLOR][color=#0000bb]5[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#dd0000]"d" [/color][color=#007700]+ [/color][color=#dd0000]"e"         [/color][color=#007700]= [/color][COLOR=#dd0000]"de"
  [/COLOR][color=#0000bb]6[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][color=#dd0000]"" [/color][color=#007700]+ [/color][color=#dd0000]"d"           [/color][color=#007700]= [/color][COLOR=#dd0000]"d"
  [/COLOR][color=#0000bb]7[/color][color=#007700]) [/color][color=#0000bb]Rev [/color][color=#007700]= [/color][COLOR=#dd0000]""  
[/COLOR][color=#0000bb][/color][/COLOR]

وبالتالي فأن الناتج الذي يهمنا هو عند الخطوة الاولى اي النص المعكوس "deehgR" ... ويمكنك ان تجرب نصوص اخرى او تبدء من اي مكان في النص ...


------------
مثال آخر :
------------
لنفرض الان اننا نريد ان نقوم بالبحث في مصفوفة خطية اسمها A(8) مكونة من ثمانية عناصر ومحتوياتها كالتالي :


كود :
[COLOR=#000000][COLOR=#0000bb]
   A[/COLOR][color=#007700]([/color][color=#0000bb]1[/color][color=#007700]) = [/color][COLOR=#0000bb]10
   A[/COLOR][color=#007700]([/color][color=#0000bb]2[/color][color=#007700]) = [/color][COLOR=#0000bb]20
   A[/COLOR][color=#007700]([/color][color=#0000bb]3[/color][color=#007700]) = [/color][COLOR=#0000bb]30
   A[/COLOR][color=#007700]([/color][color=#0000bb]4[/color][color=#007700]) = [/color][COLOR=#0000bb]40
   A[/COLOR][color=#007700]([/color][color=#0000bb]5[/color][color=#007700]) = [/color][COLOR=#0000bb]50
   A[/COLOR][color=#007700]([/color][color=#0000bb]6[/color][color=#007700]) = [/color][COLOR=#0000bb]60
   A[/COLOR][color=#007700]([/color][color=#0000bb]7[/color][color=#007700]) = [/color][COLOR=#0000bb]70
   A[/COLOR][color=#007700]([/color][color=#0000bb]8[/color][color=#007700]) = [/color][COLOR=#0000bb]80  
[/COLOR][/COLOR]

والان لكي نقوم بعمل بحث عن اي عنصر في المصفوفة ابتداءً من موقع معين بحيث نرجع رقم الموقع الذي فيه العنصر او نرجع صفر في حال عدم وجود العنصر يمكن عندها كتابة دالة مثل هذة :


كود :
[COLOR=#000000][COLOR=#0000bb]
[/COLOR][color=#007700]Function [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700]() As [/color][color=#0000bb]Integer[/color][color=#007700], [/color][color=#0000bb]Item [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700], [/color][color=#0000bb]Pos [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700]) As [/color][COLOR=#0000bb]Integer

   Dim Max [/COLOR][color=#007700]As [/color][COLOR=#0000bb]Integer
   Dim I [/COLOR][color=#007700]As [/color][COLOR=#0000bb]Integer
    
   Max [/COLOR][color=#007700]= [/color][color=#0000bb]UBound[/color][color=#007700]([/color][color=#0000bb]A[/color][COLOR=#007700])
    
   For [/COLOR][color=#0000bb]I [/color][color=#007700]= [/color][COLOR=#0000bb]Pos To Max
       [/COLOR][color=#007700]If [/color][color=#0000bb]A[/color][color=#007700]([/color][color=#0000bb]I[/color][color=#007700]) = [/color][COLOR=#0000bb]Item Then
          Find [/COLOR][color=#007700]= [/color][COLOR=#0000bb]I
          [/COLOR][COLOR=#007700]Exit Function
       [/COLOR][color=#0000bb]End [/color][COLOR=#007700]If
   [/COLOR][COLOR=#0000bb]Next I
    
End [/COLOR][COLOR=#007700]Function  
[/COLOR][color=#0000bb][/color][/COLOR]

في الدالة السابقة نقوم بتمرير المصفوفة والعنصر المراد البحث عنه Item وموقع البداية Pos ... خذ مثلاً :

كود :
[COLOR=#000000][COLOR=#0000bb]

[/COLOR][color=#007700]Print [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](),[/color][color=#0000bb]60[/color][color=#007700],[/color][color=#0000bb]1[/color][COLOR=#007700])
Print [/COLOR][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](),[/color][color=#0000bb]20[/color][color=#007700],[/color][color=#0000bb]5[/color][COLOR=#007700])
Print [/COLOR][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](),[/color][color=#0000bb]45[/color][color=#007700],[/color][color=#0000bb]1[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

الناتج من السطر الاول هو 6 لان الموقع السادس في المصفوفة يساوي 60 اي ان A(6)=60 ولكن الناتج من السطر الثاني هو صفر فعلى الرغم من المصفوفة تحتوي على الرقم 20 في الموقع الثاني إلا اننا اخبرنا الدالة بان تبدء البحث من الموقع الخامس لهذا فأن الناتج هو 0 .... واما السطر الثالث فان الناتج فيه فهو صفر ايضاً وذلك لان العنصر 45 غير موجود بين عناصر المصفوفة A() .....


والان لكي نكتب المصفوفة بالشكل الذي نستخدم فيه الاستدعاء الذاتي يجب علينا اولاً ان نفكر بالشرط الذي يجب عنده الخروج .... وهو في هذة الحالة ان يتجاوز الموقع الذي نريد البحث فيه موقع آخر عنصر (Max=UBound(A) وفي هذة الحالة يكون الناتج من الدالة صفراً .... والشرط التالي ان يتم العثور على العنصر وفي هذة الحالة يخرج ايضاً ولكن مع ارجاع الموقع الذي عثر على العنصر فيه .. واما الشرط الثالث وهو في حالة ان العنصر غير موجود في الموقع الحالي ويوجد مواقع لم تتم زيارتها بعد فأن الدالة تستدعي نفسها ولكن مع زيادة الموقع Pos الى الموقع الذي يليه Pos+1 وبالتالي فأن الدالة قد تبدو بالشكل التالي :

كود :
[COLOR=#000000][COLOR=#0000bb]

[/COLOR][color=#007700]Function [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700]() As [/color][color=#0000bb]Integer[/color][color=#007700], [/color][color=#0000bb]Item [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700], [/color][color=#0000bb]Pos [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700]) As [/color][COLOR=#0000bb]Integer
   Dim Max [/COLOR][color=#007700]As [/color][COLOR=#0000bb]Integer
   Dim I [/COLOR][color=#007700]As [/color][COLOR=#0000bb]Integer
    
   Max [/COLOR][color=#007700]= [/color][color=#0000bb]UBound[/color][color=#007700]([/color][color=#0000bb]A[/color][COLOR=#007700])
    
   If [/COLOR][color=#0000bb]Pos [/color][color=#007700]> [/color][COLOR=#0000bb]Max Then
      Find [/COLOR][color=#007700]= [/color][COLOR=#0000bb]0
   [/COLOR][color=#007700]ElseIf [/color][color=#0000bb]A[/color][color=#007700]([/color][color=#0000bb]Pos[/color][color=#007700]) = [/color][COLOR=#0000bb]Item Then
      Find [/COLOR][color=#007700]= [/color][COLOR=#0000bb]Pos
   [/COLOR][COLOR=#007700]Else
      [/COLOR][color=#0000bb]Find [/color][color=#007700]= [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]Item[/color][color=#007700], [/color][color=#0000bb]Pos [/color][color=#007700]+ [/color][color=#0000bb]1[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]End [/color][COLOR=#007700]If
[/COLOR][color=#0000bb]End [/color][COLOR=#007700]Function  
[/COLOR][color=#0000bb][/color][/COLOR]

لنفترض الان اننا نبحث عن الرقم 60 من الموقع 1 فان الخطوات سوف تكون كالتالي :

كود :
[COLOR=#000000][COLOR=#0000bb]


   1[/COLOR][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]1[/color][color=#007700]) = [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]2[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]2[/color][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]2[/color][color=#007700]) = [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]3[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]3[/color][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]3[/color][color=#007700]) = [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]4[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]4[/color][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]4[/color][color=#007700]) = [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]5[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]5[/color][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]5[/color][color=#007700]) = [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]6[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]6[/color][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]6[/color][color=#007700]) = [/color][COLOR=#0000bb]6  
[/COLOR][/COLOR]

في المرة الاولى سوف يكون الموقع اصغر من الـ Max وكذلك لن يعتر على العنصر 60 في الموقع الاول لهذا سوف يتنقل الى الموقع التالي وهكذا الى ان يصل الى الموقع السادس وفيه سوف يجد العنصر 60 لهذا سوف يكون الراجع هي قيمة الـ Pos اي 6 في هذة الحالة ثم سوف يتم التعويض بالقيمة 6 في الخطوة الخامسة ثم الرابعة ثم الثالثة وهكذا حتى الاولى وبهذا يكون الناتج هو 6 ... اي ان الحل سوف يكون كالتالي :

كود :
[COLOR=#000000][COLOR=#0000bb]

   1[/COLOR][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]1[/color][color=#007700]) = [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]2[/color][color=#007700]) = [/color][COLOR=#0000bb]6
   2[/COLOR][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]2[/color][color=#007700]) = [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]3[/color][color=#007700]) = [/color][COLOR=#0000bb]6
   3[/COLOR][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]3[/color][color=#007700]) = [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]4[/color][color=#007700]) = [/color][COLOR=#0000bb]6
   4[/COLOR][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]4[/color][color=#007700]) = [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]5[/color][color=#007700]) = [/color][COLOR=#0000bb]6
   5[/COLOR][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]5[/color][color=#007700]) = [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]6[/color][color=#007700]) = [/color][COLOR=#0000bb]6
   6[/COLOR][color=#007700]) [/color][color=#0000bb]Find[/color][color=#007700]([/color][color=#0000bb]A[/color][color=#007700](), [/color][color=#0000bb]60[/color][color=#007700], [/color][color=#0000bb]6[/color][color=#007700]) = [/color][COLOR=#0000bb]6  
[/COLOR][/COLOR]

وبنفس الطريقة يمكن التجربة عندما يكون العدد غير موجود في المصفوفة فانه سوف يصل الى الحالة الاخيرة التي يكون فيها Pos اكبر من Max وبهذا يتم ارجاع القيمة صفر ويتم التعويض بالقيمة صفر في الخطوات الى الخطوة الاولى ويكون عندها الراجع هو صفر ويعني ان العنصر غير موجود ...

لاحظ ان استخدام الدالة Find السابقة بدون الاستدعاء الذاتي كان اكثر كفائة من الحالة التي استخدمنا فيها الاستدعاء الذاتي لعدة اسباب منها اننا في حالة الاستدعاء الذاتي قمنا بعمليات فحص اكثر ... اي شرطان بدل الشرط الواحد بدون الاستدعاء الذاتي :
1-هل Pos اكبر من Max
2-هل A(Pos)=Item
كما ان العبارة Max=Ubound(A) يتم تنفيذها مرة واحدة (بدون الاستدعاء الذاتي) واما في حالة الاستدعاء الذاتي فانه يتم تنفيذها بعدد المرات التي يتم استدعاء الدالة فيها ... (طبعاً يمكن تلافي ذلك بتمرير القيمة العظمى للمصفوفة بدلاً من حسابها يدوياً ) ....

على الرغم العيوب السابقة فانه يمكن تحسين البحث ولكني هنا اعتمد التبسيط لهذا فأن تركيزنا هو كيف يعمل الاستدعاء الذاتي وكيف تتمكن من تتبع الدوال التي كتبت بصيغة الاستدعاء الذاتي ....

--------------------
حالات اكثر تعقيداً :
--------------------
لاحظنا في الامثلة السابقة ان جميع الحالات تم فيها استدعاء الدالة مرة واحدة فقط اي انه في كل استدعاء للدالة فانها تستدعي نفسها مرة واحدة ولكن يوجد حالات تقوم الدالة فيها باستدعاء نفسها اكثر من مرة وهنا تكمن قوة الاستدعاء الذاتي وسوف اضرب اكثر الامثلة شهرة في هذا المجال وهي حساب سلسلة Fibonacci و هذة السلسلة لها معادلة
خاصة حيث ان كل عنصر فيها هو عبارة عن مجموع العنصرين اللذان يسبقانه في هذة السلسلة وهي كالتالي :


كود :
[COLOR=#000000][COLOR=#0000bb]
0 [/COLOR][color=#007700]= [/color][COLOR=#0000bb]1
1 [/COLOR][color=#007700]= [/color][COLOR=#0000bb]1
2 [/COLOR][color=#007700]= [/color][COLOR=#0000bb]2
3 [/COLOR][color=#007700]= [/color][COLOR=#0000bb]3
4 [/COLOR][color=#007700]= [/color][COLOR=#0000bb]5
5 [/COLOR][color=#007700]= [/color][COLOR=#0000bb]8
6 [/COLOR][color=#007700]= [/color][COLOR=#0000bb]13
7 [/COLOR][color=#007700]= [/color][COLOR=#0000bb]21
8 [/COLOR][color=#007700]= [/color][COLOR=#0000bb]34
9 [/COLOR][color=#007700]= [/color][COLOR=#0000bb]55
[/COLOR][color=#007700]: [/color][COLOR=#0000bb]وهكذا
[/COLOR][COLOR=#007700]:  
[/COLOR][color=#0000bb][/color][/COLOR]

فاذا نظرت الى العنصر رقم 6 مثلاً فانه عبارة عن جمع العنصر رقم 5 (الذي يساوي 8) والعنصر رقم 4 (الذي يساوي 5) وبالتالي فان العنصر رقم 6 يساوي 13 ....


كود :
[COLOR=#000000][COLOR=#0000bb]
Fib[/COLOR][color=#007700]([/color][color=#0000bb]6[/color][color=#007700])=[/color][color=#0000bb]Fib[/color][color=#007700]([/color][color=#0000bb]5[/color][color=#007700])+[/color][color=#0000bb]Fib[/color][color=#007700]([/color][color=#0000bb]4[/color][COLOR=#007700])  
[/COLOR][color=#0000bb][/color][/COLOR]

وينطبق هذا الوضع على جميع العناصر ماعدا العنصرين رقم صفر ورقم واحد فكلاهما يحملان القيمة 1 ...

يتضح مما سبق انه اذا كانت اسم الدالة مثلاً Fib فان Fib(N) تساوي 1 اذا كان N =0 او N=1 وغير ذلك فان Fib(N)= Fib(N-1)+Fib(N-2) .... بالشكل التالي :


كود :
[COLOR=#000000][COLOR=#0000bb]
        [/COLOR][color=#007700]|= [/color][color=#0000bb]1             N[/color][color=#007700]<=[/color][COLOR=#0000bb]1
Fib[/COLOR][color=#007700]([/color][color=#0000bb]N[/color][color=#007700]) |= [/color][color=#0000bb]Fib[/color][color=#007700]([/color][color=#0000bb]N[/color][color=#007700]-[/color][color=#0000bb]1[/color][color=#007700])+[/color][color=#0000bb]Fib[/color][color=#007700]([/color][color=#0000bb]N[/color][color=#007700]-[/color][color=#0000bb]2[/color][color=#007700])    [/color][color=#0000bb]N[/color][color=#007700]>[/color][COLOR=#0000bb]1  
[/COLOR][/COLOR]

لهذا فأن كتابة دالة الاستدعاء الذاتي سيكون بسيطاً جداً بينما اذا فكرت في بنائه بدون استدعاء ذاتي فان هذا سيكون مرهقاً ....

والدالة هي كالتالي :

كود :
[COLOR=#000000][COLOR=#0000bb]  

[/COLOR][color=#007700]Function [/color][color=#0000bb]Fib[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]As [/color][color=#0000bb]Integer[/color][color=#007700]) As [/color][COLOR=#0000bb]Integer
   [/COLOR][color=#007700]If [/color][color=#0000bb]N [/color][color=#007700]<= [/color][COLOR=#0000bb]1 Then
      Fib [/COLOR][color=#007700]= [/color][COLOR=#0000bb]1
   [/COLOR][COLOR=#007700]Else
      [/COLOR][color=#0000bb]Fib [/color][color=#007700]= [/color][color=#0000bb]Fib[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]- [/color][color=#0000bb]1[/color][color=#007700]) + [/color][color=#0000bb]Fib[/color][color=#007700]([/color][color=#0000bb]N [/color][color=#007700]- [/color][color=#0000bb]2[/color][COLOR=#007700])
   [/COLOR][color=#0000bb]End [/color][COLOR=#007700]If
[/COLOR][color=#0000bb]End [/color][COLOR=#007700]Function  
[/COLOR][color=#0000bb][/color][/COLOR]


---------
خاتمة :
---------
مما سبق يمكن رؤية ان استخدام الاستدعاء الذاتي بالشكل الصحيح سوف يمكنك من تبسيط المسائل البرمجية المعقدة خاصة وان معظم الخوارزميات او اللوغارتيمات القوية تستخدم تقنية الاستدعاء الذاتي بشكل اساسي فيها مثل لوغارتيمات الفرز السريع ومن اشهرها QuickSort الذي يستخدم تقنية الاستدعاء الذاتي لتنفيذ مبدأ فرق تسد (Divide And Conquer) وهو من المبادئ المهمة في تصميم اللوغارتيمات كما ان معظم لوغارتيمات ضغط الملفات و البحث في القرص الصلب تستفيد كثيراً من هذة التقنية في عملها ...



اتمنى للجميع حظاً موفقاً و السلام عليكم ورحمة الله وبركاته ...
}}}}
تم الشكر بواسطة:


التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم