עבור לתוכן

אלגוריתים לפיתרון בעיית "מגדלי האנוי"

Featured Replies

פורסם

א. מהו האלגוריתים לפיתרון בעיית מגדלי האנוי?

ב. יש דרך קצרה יותר ללא שימוש בריקורסיה?

פורסם

הרקורסיבית די פשוטה ומובנת.

האלגוריתם הוא:

בהינתן, למשל, מגדל בעל 5 קומות, הזז (ברקורסיה) את 4 הקומות העליונות מעמוד א' לעמוד ב'.

הזז את הקומה החמישית (התחתונה, שנשארה לבד) מעמוד א' לעמוד ג'.

הזז (שוב ברקורסיה) את 4 הקומות מעמוד ב' לעמוד ג' (על הגב של הקומה החמישית).

פשוט וקל, לא? כמה כיף שיש רקורסיה לפעמים :)

פורסם

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

פורסם

זה לא מה שהקומפיילר עושה, פשוט לא.

תהליך "הפוך לפתרון שהוא לא טכנית רקורסיה" נקרא פריסה ובמידה ולא משנים את האלגוריתם אין לו שום תועלת (מבחינת נוחות/יעילות)

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

קיצר... גלשנו..

מטי.

פורסם

פשוט כן.

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

את ה- CPU לא מעניין שאצלך בקוד יש רקורסיה, או אפילו פונקציה. הוא פשוט מבצע סדרה של קפיצות, ועדכון ה- stack.

פורסם

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

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

תודה.

מטי.

פורסם

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

פורסם

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

פורסם

ברוב המקרים ההבדל הוא לא משמעותי.

כמו שאמרו כאן קודם, פריסה של רקורסיה בדר"כ הופכת את הקוד לפחות "יפה".

המקרה היחיד שבו הייתי להפוך רקורסיה ללולאה היה בתנאים לא סטנדרטיים (Stack מאוד קטן, ורקורסיית-זנב פשוטה יחסית).

פורסם

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

מקרה קצה שבו זה לא בהכרח הפיתרון העדיף הוא באלגוריתמיים רקורסיביים "מסוכנים": קח, לדוגמא, quicksort נאיבי שבוחר את האבר השמאלי כ-pivot, תן לו מערך ענק (נאמר, n=10000) ממויין מראש. תקבל עומק רקורסיה של 9999, שבקלות יכול לגרום ל-stack overflow. אחת הדרכים (הפחות אלגנטיות, לטעמי) להתמודד עם הבעיה הזו היא לממש את הרקורסיה באמצעות בלוק זיכרון שמתפקד כמחסנית - רקורסיה ידנית, בהיעדר תאור יותר מתאים - ולהגביל את הרקורסיה ע"י תנאי. כמובן שאפשר לממש את אותו פיתרון ע"י שליחת עומק הרקורסיה כפרמטר לפונקציה, אבל אז זה בזבזני אפילו יותר.

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

דיונים חדשים