Skip to Sidebar Skip to Content
اقرأ-تك اقرأ-تك
ضيفنا الكريم

  • تسجيل الدخول
  • الرئيسية
  • المقالات
  • خطط الاشتراك
  • - اصدارتنا
  • ورقة وقلم
  • مدونات فطين
  • شنطة مبرمج
  • النشرة الأسبوعية
  • كنوز
  • - تعرف علينا
  • من نحن
  • الشراكات
  • كتاب المحتوى
  • اكتب معنا
  • تواصل معنا
  • - بنود الخدمة
  • سياسة الخصوصية
  • الشروط والأحكام
الوسوم
  • Backend
  • Distributed Systems
  • System Design
  • Databases
  • LinkedIn
  • X
  • Facebook
  • Telegram
  • GitHub
جميع الحقوق محفوظة لمنصة اقرأ-تِك 2024©

The Power of Recursion

  • Ahmed Anwar by Ahmed Anwar
    Ahmed Anwar Ahmed Anwar
    Software Technical Writer
    • Website
  • •
  • ٨ يناير، ٢٠٢٤
  • •
  • 9 min read
  • Share on X
  • Share on Facebook
  • Share on LinkedIn
  • Share on Pinterest
  • Email
The Power of Recursion
The Power of Recursion
  • Data Structures and Algorithms
  • Python

مقدمة 

هذا المقال هو الجزء الثاني من مقال making sense of recursion، بعدما رأينا كيفية عمل الـ recursion وكيفية استخدامه، في هذا المقال سنبني على ما تعلمناه في المقال السابق لنتعلم مبادئ جديدة وسنرى نوعية المشاكل التي يساعدنا الـ recursion على حلها.  

أغلب الأسئلة التي قمنا بحلها في المقال السابق كان يمكن حلها ببساطة باستخدام Loop دون الحاجة إلى استخدام recursion فعلى سبيل المثال سؤال مجموع الأعداد الصحيحة من 1 إلى N يمكن حله باستخدام loop كالتالي:

def s(n):
  result = 0
  for i in range(n + 1):
    result += i
  return res

حتى إذا كنت تفهم الـ recursion جيداََ فعلى الأرجح هذا الحل هو ما ستفكر فيه عند قراءة السؤال. وهذه إحدى المشاكل التي قد تواجهك أثناء تعلم الـ recursion وهي أنك في البداية ترى استخدام الـ recursion لحل أسئلة يمكن حلها بسهولة باستخدام Loop وهذا ما قد يجعلك تتسائل عن أهمية الـ recursion أو الفائدة من تعلمه. 

في هذا المقال، سنرى أمثلة متنوعة تظهر أهمية الـ recursion كأداة قوية لحل المشاكل.


Divide and conquer

أبرز الحالات التي يكون فيها الـ recursion مفيداََ هي خوارزميات divide and conquer

divide and conquer هو أحد أشهر الطرق لتصميم الخوارزميات والذي يعتمد على الـ recursion، باستخدام divide and conquer يمكننا حل العديد من المشاكل الصعبة بسهولة، وكمية الكود التي تكتبها عادة ما تكون صغيرةََ ويمكنك فهم ما الذي يقوم به الكود بمجرد قراءته، والميزة الأهم هي أنه يمكننا فعل كل ذلك بكفاءة

divide and conquer يتضمن ثلاث خطوات:

  1. divide: 

تقسيم المشكلة الأصلية إلى مشاكل أصغر (subproblems)  

  1. conquer:

حل كل subproblem على حدة، هذه هي الخطوة التي نقوم فيها باستخدام الـ recursion

  1. combine:

استخدام حلول الـ subproblems للوصول إلى حل المشكلة الأصلية.

Divide - Conquer - Combine

قد تتسائل الآن:  ما هو الفرق بين divide and conquer والـ recursion ففي المقال السابق ذكرنا أن الـ recursion يقوم بتقسيم المشكلة الأصلية إلى subproblems ثم يقوم بحل الـ subproblems للوصول إلى حل المشكلة الأصلية؟ 

الـ recursion مفهوم أوسع يشير إلى طريقة للبرمجة حيث تستدعي الدالة نفسها على input أصغر وهو مفهوم عام ويمكن استخدامه بطرق مختلفة. بينما divide and conquer طريقة تصميم خوارزميات تستخدم الـ recursion بطريقة معينة ففي الخطوة الأولى ( divide ) التي نقوم فيها بتقسيم المشكلة إلى subproblems فإن حجم كل subproblem عادةََ ما يكون حجم المشكلة الأصلية مقسوم على رقم فمثلاََ نقوم بتقسيم المشكلة الأصلية إلى نصفين أو إلى أربعة أرباع أو شئ مشابه لذلك، هذا بالنسبة لـ divide and conquer أما بالنسبة للـ recursion فلا يوجد طريقة محددة لتقسيم المشكلة الأصلية إلى subproblems. باختصار فإن كل divide and conquer يستخدم الـ recursion بينما ليس كل الـ recursion عبارة عن divide and conquer.

 لنفهم divide and conquer أكثر والفرق بينه وبين الـ recursion من خلال مثال، في هذا المثال مطلوب أن نقوم بكتابة دالة تأخذ array وتقوم بإيجاد أكبر رقم فيه، أمثلة:

  • find_max([3, 8, 2, 5, 1, 7, 4, 6]) = 8
  • find_max([-10, -5, -8, -3, -12]) = -3

لنتذكر الخطوات التي كنا نتبعها حتى نصل إلى الحل، أولاََ كيف يمكن جعل الـ input أصغر؟ يمكننا إزالة الرقم الأول من الـ array، ثانياََ كيف يمكن استخدام نتيجة استدعاء الدالة find_max على ما تبقى من الـ array بعد إزالة الرقم الأول لإيجاد أكبر رقم في الـ array؟ لنفترض أن الـ array المعطى هو [3,8,2,5] بعد إزالة الرقم الأول يصبح [8,2,5] واستدعاء الدالة find_max على هذا الـ array سيقوم بإيجاد أكبر رقم فيه وهو 8، نقوم بمقارنة 8 مع الرقم الذي قمنا بإزالته (3)  فنجد أن 8 أكبر وبالتالي 8 هو أكبر رقم في الـ array كله، إذا كان الـ array المعطى [9,8,2,5] سنقوم بإزالة 9 ثم نجد أكبر رقم في الـ array بعد إزالة 9 وهو 8 ثم نقوم بالمقارنة بينهم فنجد 9 أكبر وفي هذه الحالة 9 هو أكبر رقم في الـ array كله، باختصار ما نقوم به هو التالي:

  1. إزالة أول رقم من الـ array. 
  2. إيجاد أكبر رقم في ما تبقى من الـ array بعد إزالة أول رقم. 
  3. نتيجة الدالة تكون العدد الأكبر بين أول رقم في الـ array المعطى و أكبر رقم في ما تبقى من الـ array بعد إزالة أول رقم.
💡
بالنسبة للـ base case فأبسط input لهذه الدالة قد يكون array فارغ في هذه الحالة أكبر رقم غير موجود لذلك النتيجة ستكون null، وقد يكون array به رقم وحيد وفي هذه الحالة هذا الرقم الوحيد هو أكبر رقم. 
def find_max(arr):
  # base case 1
  if len(arr) == 0:
    return None
  # base case 2
  if len(arr) == 1:
    return arr[0]

  # recursion
  max_from_1_to_end = find_max(arr[1:])
  return max(arr[0] , max_from_1_to_end)
0:00
/0:16

حتى الآن لا يوجد جديد، استخدمنا الـ recursion بنفس الطريقة التي استخدمناها في المقال السابق، لنرى كيف يمكن حل نفس السؤال باستخدام divide and conquer.  

الفكرة في divide and conquer هي: بدلاََ من جعل الـ array أصغر عن طريق إزالة أول رقم، يمكننا جعله أصغر عن طريق تقسيمه إلى نصفين ( divide ) ثم نقوم باستدعاء الدالة find_max على النصفين لإيجاد الرقم الأكبر في كل نصف ( conquer ) ثم نقارن بين هذه الرقمين والنتيجة ستكون الرقم الأكبر بينهما ( combine ) كالتالي:

0:00
/0:12

لتقسيم الـ array إلى نصفين نقوم بالتالي:

  1. حساب قيمة الـ index عند منتصف الـ array والتي تساوي طول الـ array على 2 ونخزن هذه القيمة في متغير اسمه mid 
  2. النصف الأول سيكون عبارة عن الأرقام من البداية ( index 0 ) وحتى المنتصف (index mid - 1 ) 
  3. النصف الثاني سيكون عبارة عن الأرقام من بعد نهاية النصف الأول ( index mid ) وحتى نهاية الـ array. 
💡
لا تنس أن divide and conquer يستخدم الـ recursion وبالتالي يجب أن نقوم بتحديد الـ base case في الكود وهي نفس الـ base case التي قمنا بتحديدها في الحل الأول. 

الكود لحل divide and conquer: 

هذا المقال مخصص للأعضاء فقط

اشترك الآن وتصفح كافة المقالات المميزة واستمتع بمحتوى حصري وابق على اطلاع دائم بالتحديثات المستمرة.

اشترك الآن 🚀

هل لديك حساب؟ تسجيل الدخول

في هذا المقال
اشترك الآن واكمل قراءة المقال
قناة اقرأ-تِك على التليجرام قناة اقرأ-تِك على التليجرام

اشترك الآن بنشرة اقرأ‑تِك الأسبوعية

لا تدع أي شيء يفوتك. واحصل على أحدث المقالات المميزة مباشرة إلى بريدك الإلكتروني وبشكل مجاني!

مقالات ذات صلة

  • Java Collections Cheatsheet 1 min read

    Java Collections Cheatsheet

    Mahmoud Youssef Mahmoud Youssef • ٢٥ أغسطس، ٢٠٢٤
    Mahmoud Youssef Mahmoud Youssef
    CEO & Founder
    • X
    • Facebook
    • Website
  • Making Sense of Recursion - Full Guide 5 min read

    Making Sense of Recursion - Full Guide

    Ahmed Anwar Ahmed Anwar • ٣ ديسمبر، ٢٠٢٣
    Ahmed Anwar Ahmed Anwar
    Software Technical Writer
    • Website
  • Data Structures Use Cases In a Nutshell 1 min read

    Data Structures Use Cases In a Nutshell

    Mahmoud Youssef Mahmoud Youssef • ٢٤ أكتوبر، ٢٠٢٣
    Mahmoud Youssef Mahmoud Youssef
    CEO & Founder
    • X
    • Facebook
    • Website
  • Grokking Algorithms Book Recommendation

    Grokking Algorithms Book Recommendation

    Mahmoud Youssef Mahmoud Youssef • ١٧ أكتوبر، ٢٠٢٣
    Mahmoud Youssef Mahmoud Youssef
    CEO & Founder
    • X
    • Facebook
    • Website
  • Analysis of Problem Solving Interviews 1 min read

    Analysis of Problem Solving Interviews

    Abanoub Asaad Abanoub Asaad • ٣٠ يونيو، ٢٠٢٣
    Abanoub Asaad Abanoub Asaad
    Software Engineer
    • Hands On How to Build a Dynamic Array 4 min read

      Hands On How to Build a Dynamic Array

      Ahmed Anwar Ahmed Anwar • ٢٢ يونيو، ٢٠٢٣
      Ahmed Anwar Ahmed Anwar
      Software Technical Writer
      • Website
    • Data Structures Use Cases Part 2 1 min read

      Data Structures Use Cases Part 2

      Alaa Elkzaz Alaa Elkzaz • ٧ مايو، ٢٠٢٣
      Alaa Elkzaz Alaa Elkzaz
      Co-Founder & Software Engineer
      • Website
    • Data Structures Use Cases Part 1 1 min read

      Data Structures Use Cases Part 1

      Alaa Elkzaz Alaa Elkzaz • ٢٧ أبريل، ٢٠٢٣
      Alaa Elkzaz Alaa Elkzaz
      Co-Founder & Software Engineer
      • Website
    • How Choosing The Right Data Structures Affects Performance 1 min read

      How Choosing The Right Data Structures Affects Performance

      Mahmoud Youssef Mahmoud Youssef • ٢٥ فبراير، ٢٠٢٣
      Mahmoud Youssef Mahmoud Youssef
      CEO & Founder
      • X
      • Facebook
      • Website
    اقرأ-تك اقرأ-تك
    • الرئيسية
    • المقالات
    • خطط الاشتراك
    • - اصدارتنا
    • ورقة وقلم
    • مدونات فطين
    • شنطة مبرمج
    • النشرة الأسبوعية
    • كنوز
    • - تعرف علينا
    • من نحن
    • الشراكات
    • كتاب المحتوى
    • اكتب معنا
    • تواصل معنا
    • - بنود الخدمة
    • سياسة الخصوصية
    • الشروط والأحكام
    الوسوم
    • Backend
    • Distributed Systems
    • System Design
    • Databases
    • LinkedIn
    • X
    • Facebook
    • Telegram
    • GitHub
    جميع الحقوق محفوظة لمنصة اقرأ-تِك 2024©