רקורסיה.

demultiplexer

New member
רקורסיה.

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

danielcs

New member
נראה לי שהזוגמה שהבאתי די טריוויאלי

זו הדוגמה הכי פשוטה. אם אתה לא מבין. תשאל.
 

demultiplexer

New member
אני מבין ולא מבין

כלומר, אני חושב שאני מבין מה עושה האלגוריתם הזה. הוא בודק אם אני מנסה לחשב עצרת של 0 אם כן הוא נותן את התשובה 1. אם לא הוא מדפיס
y!=(y*y-1)​
אבל הוא לא מחשב את העצרת נכון ? או שכן ? ואיך הוא מחשב ? הוא כל הזמן מפחית 1 מY ? בסוף הוא יגיע ל0 וידפיס 1 לא ? אפשר לקבל דוגמא בJAVA SCRIPT ?
 

selalerer

New member
JS:

function func(num) { if(num<=1) { return 1; } else { return num * func(num-1); } }​
הסבר כללי על רקורסיה: רקורסיה זו דרך לשמור כמות דינמית של משתנים בזכרון בצורה מסובכת יותר, במקום להשתמש במערך למשל, אתה משתמש במחסנית הקריאות (שם נשמרים הפרמטרים שנשלחים לפונקציות) וכל פעם שאתה קורא לפונקציה נוספת מבלי שסיימת את הנוכחית, הפרמטרים של הפונקציה הנוכחית נקברים עמוק יותר בתוך המחסנית ע"י הפרמטרים של הפונקציה החדשה שקראת לה. הסבר על הרקורסיה הזאת: אז ככה, כשאתה קורא לfunc ושולח לה X, אז num שווה לX הזה, במידה והפונקציה מגיעה לelse אז נעשית קריאה נוספת לפונקציה הזאת עם X-1, ואז הפונקציה הנוכחית "קופאת בזמן", כלומר כלום לא קורה בה עד שהקריאה שהיא עשתה תחזור, והnum שלה נשאר שווה לX, ואז מתחילה לרוץ כאילו פונקציה נוספת (זה שזאת למעשה אותה הפונקציה לא משנה לחלוטין למחשב) שהnum שלה שווה לX-1, ושוב אם היא מגיעה לelse אז תקראה כמה שורות למעלה (כי קורה שוב אותו הדבר רק עם X-2). עד כאן תהליך הכניסה לרקורסיה, למעשה מה שיש לנו עד שnum הגיע ל1 זה הרבה פונקציות "קפואות בזמן" שמחכות לפונקציה שהן קראו לה (שהיא עצמן למעשה רק עם פרמטר אחר), ועכשיו לתהליך היציאה מהרקורסיה. num עכשיו שווה 1 הif מתבצע, כלומר מוחזר 1. הפונקציה שקראה לזאת, עכשיו קיבלה ממנה תשובה (1) ולכן יכול להמשיך את הביצוע, היא כופלת את ה1 הזה בnum שלה שהוא שווה ל2 ומחזירה את התוצאה (2). ושוב עוד שלב אחד החוצה, הפונקציה שהמתינה לסיומה קיבלה תשובה (2) אז היא ממשיכה בביצוע, וכופלת את ה2 בnum שלה שהוא 3 ומחזירה את התוצאה וכן הלאה, עד שמגיעים לשכבה החיצונית ביותר וזאת בעצם התוצאה של העצרת. אני מקווה שהבנת, אם לא תשאל ונמשיך.
 

demultiplexer

New member
הבנתי.ההסבר שלך מצויין. עוד שאלה

1. עכשיו יש עוד בעיה שזה תופס יותר זיכרון לא ?
 

demultiplexer

New member
SELALERER - אתה יודע JS צד שרת ?

אם אתה מבין בזה אולי תוכל לעזור לי עם השאלה שהייתה לי בנוגע לכתיבת קבצים על השרת.
 

selalerer

New member
אני יודע JS ואני יודע ASP, אני יכול

לשלב ביניהם. ב ASP אתה משתמש בFileSystemObject בכדי לטפל בקבצים, בין אם אתה משתמש בשפת VBScrip או JScript (שזה לא בדיוק JavaScript) השימוש הוא כמעט אותו דבר, יש שינויים קטנים של איך אתה קורא לפונקציות ואיך אתה יוצר אובייקטים על השרת (new ActiveXObject או Server.CreateObject) אבל אלה הם שינויים מינוריים. תסתכל על התיעוד של ASP בMSDN, אני חושב שיש שם דוגמאות לכל מה שאתה צריך (בכל הסבר יש גם קוד VBScripta וגם קוד JScript).
 

selalerer

New member
בשפות אחרות כדאי לחשב, לא תמיד

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

Nsof

New member
זה אכן תופס יותר זיכרון

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

demultiplexer

New member
אז תפרט אל תזרוק מושגים באויר

מה זה רקורסיות זנב, איך עושים אותן, למה הן משמשות ?
 

the another one

New member
בסדר !

רקורסיית זנב : רקורסייה שהפעולה האחרונה שאתה עושה בה הוא הקריאה הבאה לפונקציה עצמה. זה הכל. למה הן משמשות : הן פשוט יעילות יותר. תחשוב על זה, בקריאה לפונקציה, היא מקצה משתנים חדשים. עכשיו, במקום שבקריאה הבאה לפנוקציה היא תצטרך להקצאות משתנים חדשים שוב, היא יכולה למחוק את הערכים במשתנים הישנים! לא צריכים אותם יותר, נכון? הרי אחרי הקריאה לפונקציה - יוצאים גם מהפונקציה שקראה לה ולכן לא נשתמש בהם יותר. וחוץ מזה, ברקורסיית זנב יש הקצאת משתנים רק בקריאה הראשונה לפונקציה ולכן לא תצטרך לדאוג ל stack overflow (הקצאת יותר מדי משתנים - המחסנית לא תעמוד בזה והתוכנית תעוף) לכן לרקורסיית זנב יש (לפחות) שני יתרונות : 1. הקצאת משתנים יחידה. 2. יותר אמינה (לדעתי) 3. יותר מהירה ( כי את התוצאה אתה מקבל "בדרך לשם" ואתה לא צריך לחכות למנגנון של יציאה מהפונקצייה - בעצם, יכול להיות שזו תוצאה של 1 ) בסדר?
 

DadleFish

New member
כל רקורסיה יכולה לעוף גם אם אין

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

the another one

New member
על מה אתה מדבר ???

1. אתה אומר שרקורסיית זנב לא יעילה יותר? 2. רקורסיה רגילה תכניס למחסנית את כל המשתנים שהיא צריכה בכל קריאה לפונקציה. רקורסיית זנב לא! לכן המחסנית תתמלא יותר מהר ברקורסיה רגילה ולכן התוכנית תעוף מהר יותר בגלל stack overflow.
 

vinney

Well-known member
אתם מדברים על שני דברים שונים

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

the another one

New member
בתיאוריה הוא צודק אבל

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

vinney

Well-known member
אתה לא צודק

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