[php] نظرة علي الاستدعاء الذاتي (Recusion)

مدرج تحت قسم: دروس
17 نوفمبر 2007

أثناء سفري للمدرسة كنت ادردش مع أحد اصدقائي عن أمور برمجية في لغة C++ فسالني عن معرفتي بالRecursion فكان اول مرة لى اسمع عن هذا المصطلح فطلبت منه ان يشرح ما يعرفه عنه فافادني بانها طريقة تقوم من خلالها باستدعاء الدالة من داخلها العديد من المرات حتي شرط معين لاستخدامها في شيء متكرر

وسنري الان امثلة على الاستخدام لهذا الاسلوب الرائع وخصوصا بال PHP :

اول مثال كان قاله لي صديقي وهو مثال عن المضروب factorial
والمضروب هو ناتج ضرب عدد معين فى الاعداد التي تسبقه الاكبر من الصفر
اى كمثال مضروب العدد 4 هو 4*3*2*1 = 24

وهذا المثال بلغة السي++ يكون بالشكل الاتي

#include<iostream.h>
int factorial(int n){
  if(n<=1) return 1;
    return n*factorial(n-1);
}
main (){
cout<<factorial(4);
return 0;
}

وهذا المثال بال PHP سيكون كالاتي

function factorial($n) {
  if($n<=1) return 1;
  return $n*factorial($n-1);
}
print factorial(3); //print (3*2*1) = 6

وشرح استخدام هذا الاسلوب كالاتي
عملنا دالة باسم وليكن factorial تاخذ متغير واحد
بداخل الدالة شرط اذا كان المتغير اصغر من او يساوي 1 تقوم بارجاع القيمة 1
وبعدها نقوم بارجاع العدد المراد معرفة المضروب له * الدالة مرة اخري ولكن نقوم بانقاص قيمة المتغير الداخل لها بقيمة 1
لنفترض ان العدد المراد معرفة المضروب له هو 3 اى 3*2*1 = 6
فى اول استدعاء الدالة لن يتحقق الشرط للرقم المراد معرفة المضروب له وهو 3 (الشرط = ان يكون مساوي للواحد او اصغر منه )
فستقوم بارجاع حاصل ضرب العدد 3 * ( factorial(3-1) = factorial(2) )
فتقوم بارجاع حاصل ضرب العدد 2 * ( factorial(2-1) = factorial(1) )
فى هذه الحالة سيتحقق الشرط وتقوم الدالة بارجاع القيمة 1 ليتم ضربها فى القيم السابقة

اي سيتم الاتي بداخل الدالة

factorial(3) => 3* (factorial(2) => 2* (factorial(1) => 1) ) => (3*2*1) = 6

وهكذا فى ادخال اى رقم

ومثال اخر على استخدام الRecursion هو الحصول على ناتج رفع عدد معين لاس معين
توجد دالة جاهزة فى الPHP لعمل هذا وهي دالة pow التي تقوم باخذ متغيرين وترجع قيمة رفع العدد الاول للاس ( العدد الثاني )
ولكن هنا سنستخدم ال Recursion للحصول على نفس اداء هذه الدالة

function mypow($x,$y)
{
if( $y == 0 )  return 1;
elseif( $y >0 )  return $x*mypow($x,$y-1);
}
print mypow(2,3); // print 2^3 = 2*2*2 = 16

قمنا بتعريف دالة ولتكن Mypow تاخذ متغيرين وهم الأساس والأس
فى بداية الدالة شرط اذا كان الاس = 0 تقوم بارجاع القيمة 1 لان اى رقم مرفوع للأس 0 يساوي 1
واذا كان الاس اكبر من الصفر اى عددا موجبا يقوم بارجاع قيمة الاساس * الدالة بنفس الاساس ولكن بتقليل الاس بقيمة 1
ولنفترض اننا نريد معرفة ناتج رفع العدد2 للاس 4
فتقوم الدالة بالتحقق من الشرط الاول ولن يتحقق لان الاس 4 وليس 0 فتنتقل للشرط الاخر الذي سيتحقق لان الاس 4 اكبر
من الصفر فتقوم بارجاع قيمة الاساس * الدالة مرة اخري بنفس الاساس ولكن الاس سيكون (الاس -1) وستظل على هذا
حتي يصل الاس الى القيمة 0 فيتحقق الشرط الاول و تعيد حينها القيمة 1 لتضرب فى القيم السابقة وهكذا
اى ستقوم الدالة بعمل الاتي

mypow(2,3) => 2* (mypow(2,2) => 2* (mypow(2,1) => 2* (mypow(2,0) =>  1) ) )

أى ان

mypow(2,3) = 2*(2*(2*1))  = 2*2*2 = 8

وهو ناتج رفع ال2 للاس 3 اي ضرب ال2 فى نفسها 3 مرات
اتمني ان اكون قدرت اوصل فكرة الاستدعاء الذاتي باستخدام الPHP

لي عودة مع المزيد عن الاستدعاء الذاتي ان شاء الله

مراجع

عن الكاتب

Hawy_PHP مبرمج ومطور مواقع ، طالب بمدرسة تكنولوجيا المعلومات ، مدمن برمجة :)

  • Share/Bookmark

التعليقات (8) على ”[php] نظرة علي الاستدعاء الذاتي (Recusion)“

  1. hax

    موضوع رائع ، إلى الأمام :)

  2. عمار

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

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

  4. عبدالله خالد

    بارك الله فيك أخي على هذا الدرس

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

    أخوك

  5. Libyano

    السلام عليكم …
    كنت راح أرد رد شبيه بالاخ عبد الله خالد قبل ما أشوف التعليقات وكلامه ينطبق على جميع لغات البرمجة . Recusion بطيئة كثير !!
    غريب فيه مثال أخر معروف عن Recusion (سلسلة فيبوناتشى) لو لقيت المثال عندى راح أكتبه .
    فى امان الله

  6. اسف على التاخير فى الرد لكن ظروف الدراسة القاهرة

    @ Hax :
    شكرا لمرورك ويارب تكون استفدت

    @عمار :
    اكيد طبعا وحشتك برمجة السي الممتعة والمملة في بعض الاحيان :D
    بالنسبة لمثال فى استخدامها فى السكربتات وهكذا لا انصح به لانها بطيئة وستجد ذلك فى الردود السابقة لهذا الرد من الاخ عبد الله خالد والاخ Libyano
    الغرض من الدرس -> التعريف بالتقنية

    @ مراد علوان :
    جزاك الله كل خير على الافادة وشكرا لمرورك

    @ عبد الله خالد :
    بارك الله فيك ، فعلا الاستدعاء الذاتي بطئ جدا على الذاكرة وكما ذكرت فى ردي على الاخ عمار الدرس الغرض منه التعريف بالتقنية وكيفية استخدامها فى ال PHP ولكن لا ينصح بها فعلا وايضا اردت افادة اخواني بالمعلومة لما عرفتها
    جزاك الله كل خير

    @ Libyano :
    وعليكم السلام
    جزاك الله كل خير و قد اسلفت الحديث عن سرعة الاستدعاء الذاتي والغرض من الدرس
    وبالنسبة لامثلة الاستدعاء الذاتي فهي كثيرة وان شاء الله اضع مثال اخر بال PHP

    جزاكم الله كل خير اجمعين

    اخوكم محمد ،،

  7. شكراً لك أخي Hawy_PHP
    ذكرتني بأيام الريكرجن..في كورس الجافا..

    الريكرجن رائعة.. وحالياً نتعلمها في التعامل مع الـ SQL
    وأظنها مفيدة في الإستدعاء المتتابع كـ الآباء والأجداد
    ففي الـ SQL لايمكن ان تصل إلى الأب البعيد بالطرق العادية..
    إلا باستخدام الـ With..

    نعود للريكرجن في لغات البرمجة..
    ما أذكره فيها انه هناك شرط توقف.. أو base case..
    وهو الذي تبني عليه التكرار.. فمتى ما وصلت القيمة لهذا الشرط تتوقف..
    وهو في مثالك : if( $y == 0 ) return 1;

    ربما تفيدك هذه الروابط -حصلت عليها خلال بحثي عند دراستي للريكرجن-

    -شرح مبسط لها على لغة سي++
    http://www.cprogramming.com/tutorial/lesson16.html

    رابط آخر
    http://www-static.cc.gatech.edu/classes/AY2006/cs1322_fall/LA/files/recursion_gallis.htm

    أتمنى أكون أفدتك..
    موفق أخوي..:)

  8. @ ربان :
    جزاك الله كل خير اخي
    فعلا كما قلت فلابد من وجود شرط توقف حتي تبدا عملية ارجاع القيم والعودة الى البداية

    والرابط الاول كنت اعرفه بالفعل وقرات منه
    ان شاء الله اقرا ما فى الثاني جزاك الله كل خير

أضف تعليقك




يمكنك استخدام الوسوم التالية في التعليق: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


* حقول مطلوبة