عالم الجافا | عالم الانترنت | عالم الألوان | عالم الكومبيوتر | مقارنات | سكربتات جاهزة

الرئيسية
راسلني

الأقراص والأعمدة (Recursion)

الرئيسية > الدروس > عالم الجافا > الأقراص والأعمدة (Recursion)
السلام عليكم ورحمة الله وبركاته..

الأخ صوت الشباب الفاضل أحضر هذا الكود، وطلب منّي أن أشرحه، وهنا أقوم بذلك وأتمنى أن يستفيد منه وكذلك أنتم إن شاء الله :)

المقدمة

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

المطلوب هو نقل جميع الأقراص بنفس الترتيب إلى العمود الثالث، بشرط: ألا تضع أبداً قرصاً على قرص أصغر منه أثناء عملية النقل.

فكرة الحل

لنفترض أنه لدينا الشكل التالي:

عدد من الأقراص في العمود الأول على اليسار، ونرغب بنقلها للعمود الثالث مثلاً. في هذه الحالة، إذا تمكّنا بطريقة ما من نقل جميع الأقراص التي تعلو القرص الأصفر إلى العمود الثاني، فإننا سنستطيع بالتالي أن ننقل القرص الأصفر الكبير إلى الثالث هكذا:

الآن انتهينا من القرص الكبير الأصفر، ونريد بالتالي نقل القرص الوردي أعلاه مباشرة، فإننا إذا تمكّنا من نقل جميع الأقراص التي تعلو الوردي إلى العمود الأول، فإننا سنستطيع أن نضع الوردي  على الأصفر هكذا:

إننا إذاً في كل مرحلة من مراحل الحل نقوم باعتبار أحد الأعمدة هو الهدف، ونقوم باعتبار أحد العمودين الآخرين مؤقتاً، ننقل فيه الأقراص التي تعلو أكبر قرص، حتى نتمكن من نقل القرص الكبير إلى العمود المطلوب.

نجد هنا أننا نكرر العملية نفسها، فإننا نبدأ بالعكس، نفترض أننا قمنا فعلياً بنقل الأقراص التي تعلو الكبير، ونبدأ نقترب من القرص الأصغر حتى ننجح في النهاية من نقل جميع الأقراص إلى العمود المطلوب.

الكود

كيف يعمل البرنامج؟

يبدأ البرنامج في السطر العاشر بقراءة عدد الأقراص من المستخدم، ولنفترض أننا قمنا بإدخال القيمة 3 هكذا:

ثم يقوم بتشغيل الوظيفة doHanoi بتمرير أربعة قيم لها عدد الأقراص، والقيمة واحد والقيمة ثلاثة والقيمة اثنان.

لنلقِ نظرة على كود الدالة نفسها، وكيف تنتقل القيم إليها:

أي أنه عند تشغيل الوظيفة method في المرة الأولى، تكون القيم الممررة هي:

المرحلة البيضاء:

نلاحظ عند الدخول إلى الوظيفة أن أول سطر هو أداة (if) الشرطية، حيث يتأكّد من أن عدد الأقرص أكبر من أو يساوي الواحد، وفي حالتنا عدد الأقراص كان 3، سيقوم بالدخول وتنفيذ السطر 18 وهو نداء للوظيفة نفسها وهو ما يعرف بالـ Recursion في البرمجة، ولكن بقيم جديدة.

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

وتكونالقيم الممررة في المرحلة الزرقاءكالتالي:

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

وتكون القيم الممررة في المرحلة الوردية كالتالي:

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

الآن القيم الممرة في المرحلة الصفراء ستكون كالتالي:

الأداة الشرطية في المرحلة الصفراء لا تتحقق، لأن عدد الأقراص = صفراً، والصفر ليست أكبر من ولا تساوي الواحد، لذا سيعود إلى السطر التاسع عشر من المرحلة الوردية، وسيقوم بطباعة القيم الموجودة في (start) و(end) في المرحلة الوردية كما يلي:

ودعوني أذكركم بالقيم في المرحلة الوردية:

وهذا يعني أننا نقلنا القرص الموجود في أعلى العمود الأول إلى العمود الثالث، هكذا:

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

وستكون القيم في هذه المرحلة الخضراء هكذا:

ولكن كما ترون فإن الشرط لن يتحقق في هذه الحالة لأن عدد الأقراص = صفر، بالتالي ستكون المرحلة الوردية قد انتهت ولا أسطر جديدة، وهكذا سيعود إلى السطر التاسع عشر من المرحلة الزرقاء، وسيكون طباعة القيم في المرحلة الزرقاء، ودعوني أذكركم بها:

وهكذا سيقوم بطباعة التالي:

وهذا يعني أننا نقلنا القرص الموجود في أعلى العمود الأول إلى العمود الثاني هكذا:

الآن سيقوم بالانتقال للسطر العشرون من المرحلة الزرقاء، وسيكون كما يلي:

عدد الأقراص في هذه الحالة يحقق الشرط، وبالتالي سيقوم بالدخول إلى محتوى أداة الشرط (إذا) (وهذه هي المرحلة البنفسجية) وهنا سيحاول أن ينادي الوظيفة بعدد الأقراص 1-1=0 ولا حاجة لإعادة ما ذكرناه في السابق من أن هذا لن يحقق الشرط، وبالتالي سيقوم بتنفيذ السطر التالي وهو علامة الطباعة على القيم التي ستكون في هذه المرحلة البنفسجية كالتالي:

سيقوم بطباعتها كالتالي:

وهذا يعني أننا قمنا بنقل القرص الموجود في أعلى العمود الثالث إلى العمود الثاني، هكذا:

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

وهكذا سيتم طباعة التالي:

وهذا يعني أننا نقلنا القرص من أعلى العمود الأول إلى العمود الثالث:

ثم ننتقل إلى السطر العشرون في المرحلة البيضاء وهو يقوم بنداء نفس الوظيفة بالقيم التالية وهكذا نكون قد انتقلنا إلى مرحلة جديدة، وستكون مرحلة اللون البرتقالي:

وهكذا ستكون القيم الجديدة للمرحلة البرتقالية كالتالي:

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

ونكون قد انتقلنا إلى المرحلة الرمادية، وتكون المتغيرات في هذه المرحلة كما يلي:

في السطر الثامن عشر من المرحلة الرمادية لن يتم تشغيل الوظيفة لأن القيمة 1-1=0 وبالتالي لن يتم تحقق الشرط، وهكذا سنعود للسطر التاسع عشر من المرحلة الرمادية، والتي سيتم فيها طباعة القيم في المرحلة الرمادية هكذا:

وهذا يعني أنه سيتم نقل قرص من أعلى العمود الثاني إلى العمود الأول هكذا:

الآن سنتابع إلى السطر العشرون من المرحلة الرمادية، وهو أيضاً لن يفعل شيئاً لأن الشرط لن يتحقق، وهكذا سنعود إلى السطر التاسع عشر من المرحلة البرتقالية وسنطبع القيم الموجودة في المرحلة البرتقالية كما يلي:

وتكون الطباعة هكذا:

وهذا يعني أننا قمنا بنقل قرص من العمود الثاني إلى العمود الثالث هكذا:

الآن وصلنا للسطر الأخير من المرحلة البرتقالية، التي بنهايتها تنتهي المرحلة البيضاء والبرنامج، وتشغيل هذه المرحلة سأتركه لكم :)

تذكر أن عدد الأقراص يمكن أن يكون أكثر من ثلاثة، حاول أن تقوم بتتبع البرنامج في حالة عدد الأقراص كان اثنين أو أربعة أو أكثر.

قد يساعدك على فهم الـ Recursion الشكل التالي:

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

أرجو أن يكون المثال واضحاً، وشكراً لصوت الشباب الذي أحضره لي لأشرحه :)

وفوق كل ذي علم عليم

أوشال

مواضيع أخرى من نفس النوعية

سلسلة دروس الجافا

  1. مقدمة على البرمجة بشكل عام
  2. لغات الجيل الرابع
  3. البرمجة بالكائنات الشيئية
  4. البرمجة بالكائنات الشيئية - يتبع
  5. إعداد بيئة التشغيل
  6. البرنامج الأوّل بلغة الجافا
  7. شرح البرنامج الأوّل
  8. الآلة التخيلية للجافا-JVM
  9. المتغيرات
  10. التعليقات
  1. استخدام المتغيرات
  2. تعريف فئة
  3. استخراج عضو من فئة
  4. استخدام عضو من فئة
  5. صفة في فئة، عضو من فئة أخرى
  6. الـ Constructors
  7. التحكّم - الأدوات الشرطية
  8. التحكّم - جمل التكرار
  9. الوظائف
  10. try and catch

أمثلة ومقارنات

أخرى

جميع الحقوق محفوظة JavaGirl, 2006