الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

الطريق الى Tail Recursion

بدأه apex في 25 سبتمبر 2009 · 5 رد · 1,340 مشاهدة · في لغة C و ++C
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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

جمبعنا نعرف ال Recursion وهى عملية نداء الدالة لنفسها

ولكن للاسف معظم الكتب تتحدث عن الbasic recursion متجاهلة الTail Recursion مع ان الاخر اسرع بكثير

لنبداء لاوضح الفرق بينهم

الrecursion العادى يكون القيمة العائدة من الدالة بهذا الشكل

return value * function(value)

اى على طريقة الفاكتوريال تكون على هذا الشكل

return n * fact(n - 1)

ولكن للاسف ان لتلك الطريقة عيوب من حيث السرعة وoverhead من حيث الstack لان الدالة تظل تنسخ نفسها فى المكدس stack الى ان تصل الى شرط معين بحيث تتوقف عن مناداة نفسها وتقوم بالعودة تدريجيا الى الدالة الاصلية لتعود الى الدالة الاصلية ثم الى مستدعى الدالة اساسا

ولكن هناك الTail Recursion وهى افضل من حيث السرعة وهى تكون بشكل اكثر ذكاء وهى على هذا الشكل

return function(some value)

لنعود لمثال الفاكتوريال

int facttail(int n, int a) {
if (n < 0)
   return 0;
else if (n == 0)
   return 1;
else if (n == 1)
   return a;
else
   return facttail(n - 1, n * a);
}

االذكاء هنا انك تركت مجال للمترجم ان يقوم بعمل تحسين للكود فالreturn عبارة عن نداء اخر ولا يشوبها قيمة تجبر المترجم على الحفاظ على الدالة السابقة لحين عودة الrecursion

وبهذا تسمح للمترجم ان لا يقوم بصناعة دالة جديدة فى المكدس وبدلا من ذلك يقوم باستخدام نفس الدالة فى المكدس ولكن بالقيم الاخيرة وهذا ما تفعلة معظم المترجمات الحديثة (ان لم يكن كلها ) وبهذا تخلصت من مشاكل وبطى المكدس ومن مشاكل حجز وحذف الدوال من المكدس

اعلم انى لست بارع فى الشرح ولذلك فمعلومات الموضوع من كتاب Mastering Algorithms with C فى الفصل الثالث

ما ارائكم حول الافكار المناسبة لتحويل الدوال من الrecursion العادى الى الtail recursion وما مدى نجاح وسهولة الوصول الى هذا الحل ؟

name : mohamedyosry

#2

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

امم .. حسب مافهمت , أنه في Tail Recursion لايوجد استدعاء عكسي للدوال , بمجرد أن نصل الى الحالة الخاصة الأخيرة ( n=1 ) نكون وصلنا للحل ونعيده . اذا كان فهمي صحيح فانّك :

اقتباس
بارع فى الشرح

:)

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

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#3
اقتباس
حسب مافهمت , أنه في Tail Recursion لايوجد استدعاء عكسي للدوال , بمجرد أن نصل الى الحالة الخاصة الأخيرة ( n=1 ) نكون وصلنا للحل ونعيده

بالضبط

بالاضافة الى انة لا يوجد حجز متكرر فى الstack (وهذة من الامور التى تكلف وقت و ذاكرة) لان المترجم يستخدم نفس الدالة عدة مرات لكن بالقيم الجديدة عوضا عن انشاء تكرار للدوال فى المكدس

لكن ما يزعجنى فى مثال الفاكتوريال انك يجب ان ترسل دائما قيمة المتغير a دائما ب 1 وحسب معرفتى ان السى لا تدعم الdefault parameter كالc++ ولكن يمكن تعويضها بmacro بهذة الشكل

#define fac(n) facttail(n,1)

مع انها لا تضاهى الdefault parameter كc++ ولكنها حل جزئى وهى افضل فى هذا الموقف خصوصا

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

انا ايضاء لا ادرى :lol: ولكنها طريقة تضاف الى الiteration العادى بالتكرار لنحاول ان نتخلص من مساوى الrecursion العادى

تحياتي

تم تعديل هذه المشاركة بواسطة apex في 26 سبتمبر 2009 في 08:02

name : mohamedyosry

#4

السلام عليكم ...

معلومة جميلة :)

#5

ممكن تحول أى recursion إلى loop و العكس ﻷنهم هم اﻹتنين تكرار, بس لنفس المشكلة ممكن تبقى طريقة أصعب من التانية بكتير و بالتالى بنختار الطريقة اﻷسهل و اﻷكثر طبيعية.

#6
اقتباس
السلام عليكم ...

معلومة جميلة :)

نورت الموضوع بمرورك اخى خالد

اقتباس
ممكن تحول أى recursion إلى loop و العكس ﻷنهم هم اﻹتنين تكرار, بس لنفس المشكلة ممكن تبقى طريقة أصعب من التانية بكتير و بالتالى بنختار الطريقة اﻷسهل و اﻷكثر طبيعية.

بالطبع وخاصة اذا لم تكن السرعة من اولوياتنا

name : mohamedyosry

مواضيع مشابهة