טכניקות אלגוריתמיותמתחילים6 דק׳ קריאה

רקורסיה ומחסנית הקריאות - כיצד פונקציה קוראת לעצמה

הסבר מעמיק על רקורסיה: מקרי בסיס, מחסנית הקריאות, עומק מקסימלי, ומתי רקורסיה עדיפה על לולאה.

רקורסיה היא כאשר פונקציה קוראת לעצמה כחלק מחישובה. זוהי כלי עוצמתי שמאפשר לפתור בעיות מורכבות בקוד קומפקטי - ועומד בבסיסם של מיון מיזוג, Quick Sort, DFS, ועצי BST.

שני מרכיבים הכרחיים

  • מקרה בסיס (Base Case) - התנאי שמפסיק את הרקורסיה. בלעדיו יש הצפת מחסנית (Stack Overflow)
  • מקרה רקורסיבי - קריאה לאותה פונקציה עם קלט קטן יותר שמתקרב למקרה הבסיס

דוגמה - עצרת (Factorial)

function factorial(n) {
  if (n <= 1) return 1;          // מקרה בסיס
  return n * factorial(n - 1);   // מקרה רקורסיבי
}

// factorial(4)
// = 4 * factorial(3)
// = 4 * 3 * factorial(2)
// = 4 * 3 * 2 * factorial(1)
// = 4 * 3 * 2 * 1 = 24

מחסנית הקריאות (Call Stack)

כל קריאה רקורסיבית דוחפת מסגרת (frame) למחסנית הקריאות - הכוללת את המשתנים המקומיים ונקודת החזרה. כשמגיעים למקרה הבסיס, המסגרות נפרקות בחזרה בסדר הפוך.

ל-JavaScript ול-Python יש גבול עומק מחסנית (כ-1,000–10,000 קריאות). רקורסיה עמוקה מדי גורמת ל-Stack Overflow. לכן יש מקרים שבהם עדיפה איטרציה עם מחסנית מפורשת.

Tail Recursion

אם הקריאה הרקורסיבית היא הפעולה האחרונה בפונקציה (ללא חישוב אחרי החזרה), המהדר יכול לבצע 'אופטימיזציית זנב' ולהמיר לולאה - חוסך זיכרון מחסנית. זה נפוץ ב-Haskell ו-Scala, ונתמך חלקית ב-JavaScript בסביבות מסוימות.

רקורסיה מול איטרציה

קריטריוןרקורסיהאיטרציה
קריאותקריאות מחסניתלולאה
קריאותO(עומק) זיכרון מחסניתO(1) זיכרון מחסנית
קריאותקומפקטי לבעיות עצים/גרפיםעדיף לחישובים פשוטים
קריאותסכנת Stack Overflowאין מגבלת עומק

חשבו על רקורסיה בכל פעם שהבעיה מגדירה את עצמה במונחי עצמה - עצים, גרפים, חלוקה לתת-בעיות. לבעיות לינאריות פשוטות, לולאה תמיד עדיפה.

שאלות נפוצות

מה זה מקרה בסיס ולמה הוא הכרחי?

מקרה הבסיס הוא התנאי שבו הפונקציה מחזירה תשובה ישירות בלי לקרוא לעצמה שוב. בלעדיו הרקורסיה לעולם לא תעצור, כל קריאה תוסיף מסגרת למחסנית הקריאות, והתוכנית תקרוס בגלישת מחסנית. כל פונקציה רקורסיבית חייבת גם להתקדם לעבר מקרה הבסיס בכל קריאה.

איך מחסנית הקריאות עובדת ברקורסיה?

כל קריאה לפונקציה יוצרת מסגרת על המחסנית שמחזיקה את המשתנים המקומיים, הפרמטרים וכתובת החזרה. ברקורסיה המסגרות נערמות עד שמגיעים למקרה הבסיס, ואז הן נפרקות בסדר הפוך כשכל קריאה מחזירה את ערכה לקודמתה. עומק המחסנית שווה לעומק הרקורסיה, ולכן סיבוכיות המקום היא O(depth).

מתי עדיף להשתמש בלולאה במקום ברקורסיה?

כשהעומק עלול להיות גדול ולסכן גלישת מחסנית, וכשהאלגוריתם לינארי וטבעי לניסוח איטרטיבי — למשל חישוב עצרת או סכום מערך. רקורסיה עדיפה כשהבעיה עצמה רקורסיבית במבנה, כמו מעבר על עץ, הפרד ומשול או נסיגה, שם ניסוח איטרטיבי היה מחייב לנהל מחסנית ידנית ולסבך את הקוד.

מאמרים קשורים

ויזואליזציה של אלגוריתמי מיוןלכל המאמרים