You are on page 1of 121

‫קורס תכנות בשפת ‪C‬‬

‫פרק ‪18‬‬
‫מבני נתונים – מחסנית ‪Stack -‬‬

‫ד"ר שייקה בילו‬


‫יועץ ומרצה בכיר למדעי המחשב וטכנולוגית מידע‬
‫מומחה למערכות מידע חינוכיות‪ ,‬אקדמיות ומנהליות‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫חידה לחימום‬

‫‪ ‬שלושה חכמים החליטו לבדוק מי מבניהם הוא החכם ביותר‪,‬‬


‫וביקשו מחכם רביעי שיכריע בסוגיה‪ .‬המבחן שהציע החכם‬
‫הרביעי הוא כדלקמן‪:‬‬
‫‪ ‬יש ברשותו חמישה כובעים – שלושה שחורים ושני לבנים‪.‬‬
‫‪ ‬הוא הניח את שלושת הכובעים השחורים על ראשי שלוש‬
‫החכמים‪ ,‬מבלי שאמר להם איזה כובע הוא שם על ראשם‪ ,‬כך‬
‫שכל איש חכם יודע רק את צבעי הכובעים שעל ראש שני חבריו‬
‫(במקרה זה – כל אחד מהם רואה שני כובעים שחורים)‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫חידה לחימום‬

‫‪ ‬כמו כן‪ ,‬הם לא יודעים אילו שני כובעים מבין חמשת הכובעים‬
‫אינם בשימוש‪.‬‬
‫‪ ‬שלושת החכמים התבקשו לקבוע את צבע הכובע שעל ראשם‪.‬‬
‫‪ ‬לאחר זמן מה‪ ,‬אחד מבין השלושה קבע כי הצבע שעל ראשו הוא‬
‫שחור‪ .‬כיצד קבע זאת?‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית – הגדרה‬

‫‪ ‬מחסנית (‪ )Stack‬היא סוג של טיפוס נתונים (‪ )data type‬התומך‬


‫בפעולות הכנסה והוצאה‪ ,‬כך שמתקיימת התכונה הבאה‪:‬‬
‫‪ ‬הוצאת ערך ממחסנית אפשרית רק כאשר היא אינה ריקה‪ ,‬והיא‬
‫מחזירה תמיד את הערך שהוכנס אחרון‪ ,‬מבין הערכים הקיימים‬
‫במחסנית‪.‬‬
‫הכנס ‪9‬‬
‫‪ ‬לדוגמא‪:‬‬
‫ראש המחסנית‬ ‫►‬ ‫‪3‬‬ ‫הכנס ‪5‬‬
‫הכנס ‪3‬‬
‫ראש המחסנית‬ ‫►‬ ‫‪5‬‬ ‫הוצא‬
‫ראש המחסנית‬ ‫►‬ ‫‪9‬‬ ‫הוצא‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית ‪ -‬תפקוד‬
‫‪ ‬מחסנית הינה טיפוס נתונים המאפשר הוצאת והכנסת נתונים אך‬
‫ורק מצידה האחד‪ .‬לפתח זה נקרא בשם "ראש המחסנית"‪.‬‬
‫‪ ‬ניתן לגשת רק לאיבר הנמצא בראש המחסנית‪ ,‬והוא מסתיר את כל‬
‫האיברים שמתחתיו‪.‬‬
‫‪ ‬אם נדחוף למחסנית איבר ומיד נבצע שליפה‪ ,‬אז יתקיים‪:‬‬
‫‪ ‬האיבר שנשלוף יהיה אותו איבר שזה עתה דחפנו‪.‬‬
‫‪ ‬מצב המחסנית לאחר השליפה יהיה זהה למצבה לפני הדחיפה‪.‬‬
‫‪ ‬המבנה המיוחד של המחסנית גורם לכך שבמהלך הכנסה והוצאה‬
‫של איברים למחסנית מתקיימת בה התכונה הנקראת‪:‬‬
‫)‪ ,Last In First Out (LIFO‬כלומר – האיבר שנכנס אחרון הוא‬
‫היוצא ראשון‪.‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מחסנית – פעולות מותרות‬

‫‪ ‬אילו פעולות נגדיר על מחסנית?‬


‫‪ ‬כדי שאפשר יהיה להוסיף איברים למחסנית ולהוציא אותם‬
‫ממנה‪ ,‬נגדיר את הפעולות דחוף‪-‬למחסנית ו‪-‬שלוף‪-‬ממחסנית‪.‬‬
‫‪ ‬המחסנית עשויה להיות ריקה‪ ,‬אך אז אסור לבצע עליה פעולת‬
‫שליפה‪ .‬לכן‪ ,‬נגדיר פעולה בשם מחסנית‪-‬ריקה?‪ ,‬המחזירה‬
‫'אמת' אם המחסנית ריקה‪ ,‬ו‪'-‬שקר' אם יש במחסנית איברים‪.‬‬
‫‪ ‬בפעולה זו נשתמש לפני שנשלוף מהמחסנית‪ ,‬כדי למנוע מצב שבו‬
‫אנחנו מנסים לשלוף איבר ממחסנית שהיא ריקה‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית – פעולות מותרות‬

‫‪ ‬לעיתים נרצה להציץ לראש המחסנית‪ ,‬כדי לדעת את ערכו של‬


‫האיבר שנמצא שם‪ ,‬אך מבלי לשלוף אותו‪ .‬איך אפשר לעשות‬
‫זאת?‬
‫‪ ‬דרך אחת היא לבצע פעולת שליפה‪ ,‬ואז לדחוף בחזרה למחסנית את‬
‫האיבר ששלפנו‪.‬‬
‫‪ ‬אפשרות אחרת‪ ,‬היא להגדיר את הפעולה הצץ‪-‬למחסנית שמחזירה לנו‬
‫את האיבר שבראש המחסנית‪ ,‬אך מבלי לשלוף אותו (מבלי להוציא‬
‫אותו החוצה)‪.‬‬
‫‪ ‬לבסוף‪ ,‬נגדיר פעולה בשם אתחל‪-‬מחסנית‪ ,‬שיוצרת מחסנית‬
‫ריקה‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית – פעולות מותרות‬

‫‪ ‬הממשק של טיפוס הנתונים מחסנית‪:‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


?‫שאלות‬

SCE-Chapter-18-Stack Shayke Bilu PhD


‫מחסנית – תאור תכולת מחסנית‪1-‬‬
‫‪ ‬תארו את תכולת המחסניות ‪ S1‬ו‪ S2-‬במהלך סדרת הפעולות הבאה‪:‬‬
‫אתחל‪-‬מחסנית ‪S1 ‬‬
‫דחוף‪-‬למחסנית (‪)S1,7‬‬
‫דחוף‪-‬למחסנית ( ‪)S1,9‬‬
‫אתחל‪-‬מחסנית ‪S2 ‬‬
‫שלוף‪-‬ממחסנית (‪i  )S1‬‬
‫דחוף‪-‬למחסנית (‪)S2,i‬‬
‫דחוף‪-‬למחסנית (‪)S1,6‬‬
‫שלוף‪-‬ממחסנית (‪i  )S2‬‬
‫שלוף‪-‬ממחסנית (‪i  )S1‬‬
‫דחוף‪-‬למחסנית (‪)S1,8‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מחסנית – תאור תכולת מחסנית‪2-‬‬
‫‪ ‬תארו את תכולת המחסניות ‪ S1‬ו‪ S2-‬במהלך סדרת הפעולות הבאה‪:‬‬
‫אתחל‪-‬מחסנית ‪S2 ‬‬
‫אתחל‪-‬מחסנית ‪S1 ‬‬
‫דחוף‪-‬למחסנית (’‪)S1,’a‬‬
‫דחוף‪-‬למחסנית (’‪)S1,’b‬‬
‫דחוף‪-‬למחסנית (’‪)S2,’c‬‬
‫שלוף‪-‬ממחסנית (‪ch  )S1‬‬
‫דחוף‪-‬למחסנית (‪)S2,ch‬‬
‫שלוף‪-‬ממחסנית (‪ch  )S1‬‬
‫אם לא מחסנית‪-‬ריקה? (‪ )S1‬אזי‬
‫הצג כפלט הצץ‪-‬למחסנית (‪)S1‬‬
‫אם לא מחסנית‪-‬ריקה? (‪ )S2‬אזי‬
‫הצג כפלט הצץ‪-‬למחסנית (‪)S2‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מחסנית – פקודת הביטול ‪Undo -‬‬
‫דוגמא לשימוש במחסנית‪ ,‬ניתן למצוא בתוכנות עריכה גראפיות‪,‬‬ ‫‪‬‬
‫שמאפשרות למעצב לבטל את הפעולה האחרונה (‪.)Undo‬‬
‫פעולת ‪ Undo‬מבטלת את הפעולה האחרונה שבוצעה (פרט‬ ‫‪‬‬
‫לפעולת ‪ Undo‬עצמה)‪.‬‬
‫המשתמש יכול לחזור ולהפעיל פעולה זו ללא הגבלה עד לביטול‬ ‫‪‬‬
‫הפעולה הראשונה שעשה‪.‬‬
‫איך נממש פעולה זו?‬ ‫‪‬‬
‫‪ ‬בכל פעם שהמשתמש יבצע איזושהי פעולת עיצוב (למשל‪ ,‬ציור קו או‬
‫נקודה)‪ ,‬נשמור את פרטי הפעולה (למשל‪ :‬מהו צבע הנקודה‪ ,‬מאיפה‬
‫לאיפה מותחים את הקו‪ ,‬וכו')‪.‬‬
‫‪ ‬את התיאורים הללו יש לשמור כך שניתן יהיה לגשת אליהם בסדר הפוך‬
‫לסדר בו הפעולות התבצעו‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית – פקודת הביטול ‪Undo -‬‬

‫‪ ‬נשתמש במחסנית‪:‬‬
‫בכל פעם שמתבצעת פעולה (פרט לפעולת ‪ Undo‬עצמה)‪ ,‬נדחוף‬
‫למחסנית את תיאורה ואת הפרמטרים שלה‪.‬‬
‫כאשר המשתמש ירצה לבטל פעולה‪ ,‬נשלוף את הפעולה שבראש‬
‫המחסנית‪ ,‬ונבצע פעולה המבטלת אותה‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית – פקודת הביטול ‪Undo -‬‬

‫‪ ‬כיצד תיראה המחסנית במהלך ביצוע סדרת הפעולות הבאה‪:‬‬


‫‪ ‬צייר‪-‬קו (‪)...‬‬
‫‪ ‬צייר‪-‬נקודה (‪)...‬‬
‫‪ ‬צייר‪-‬קו (‪)...‬‬
‫‪Undo ‬‬
‫‪ ‬צייר‪-‬מצולע (‪)...‬‬
‫‪Undo ‬‬
‫‪Undo ‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית – פקודת הביטול ‪Undo -‬‬
‫נכתוב את האלגוריתם הפותר את הבעיה‪:‬‬
‫(‪ )1‬אתחל‪-‬מחסנית ‪S ‬‬
‫(‪ )2‬כל עוד המשתמש מבצע פעולות‪ ,‬בצע‪:‬‬
‫(‪ )2.1‬קרא פעולה ‪x‬‬
‫(‪ )2.2‬אם ‪ x‬איננה הפעולה ‪ ,Undo‬אזי‪:‬‬
‫(‪ )2.2.1‬דחוף‪-‬למחסנית (‪)S,x‬‬
‫(‪ )2.2.2‬בצע את הפעולה ‪x‬‬
‫(‪ )2.3‬אחרת‪:‬‬
‫(‪ )2.3.1‬אם מחסנית‪-‬ריקה? (‪ )S‬אזי‪:‬‬
‫(‪ )2.3.1.1‬הצג כפלט‪" :‬אין פעולות בזיכרון"‬
‫(‪ )2.3.2‬אחרת‪:‬‬
‫(‪ )2.3.2.1‬שלוף‪-‬ממחסנית (‪y  )S‬‬
‫(‪ )2.3.2.2‬בצע את הפעולה המבטלת את ‪y‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית זמן ריצה‬

‫‪ ‬דוגמא נוספת לשימוש במחסנית‪ ,‬זהו רכיב הקיים במערכת‬


‫ההפעלה‪ ,‬הנקרא מחסנית זמן הריצה (‪ ,)run time stack‬או‬
‫מחסנית הקריאות (‪.)call stack‬‬
‫‪ ‬בכל פעם שמזמנים פונקציה‪ ,‬במהלך ריצת התוכנית‪ ,‬מערכת‬
‫ההפעלה דוחפת לתוך מחסנית זמן הריצה נתונים שישמשו אותה‬
‫כדי לדעת לאיזו נקודה בתכנית עליה לחזור‪ ,‬לאחר שהפונקציה‬
‫תסיים את ריצתה‪.‬‬
‫‪ ‬נתונים אלו כוללים את הפרמטרים שאיתם זימנו את הפונקציה‪,‬‬
‫וכן את הכתובת אליה יש לחזור בסופה‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית זמן ריצה‬

‫‪ ‬לאחר סיום ביצוע הפונקציה‪ ,‬שולפים מהמחסנית את הרשומה‬


‫שבראש המחסנית‪ ,‬וביצוע התכנית ממשיך לפי הנתונים המופיעים‬
‫שם‪.‬‬
‫‪ ‬אם מחסנית הקריאות מתמלאת‪ ,‬בעקבות קינון עמוק מדי של פונקציה‪-‬‬
‫בתוך‪-‬פונקציה‪ ,‬מתרחשת שגיאה הנקראת 'גלישת מחסנית' ( ‪Stack‬‬
‫‪ ,)overflow‬המביאה בדרך כלל לשגיאת זמן ריצה‪ ,‬ולסיום התכנית‪.‬‬
‫‪ ‬שגיאה כזו מתרחשת‪ ,‬למשל‪ ,‬אם כותבים פונקציה רקורסיבית‪ ,‬המזמנת את‬
‫עצמה שוב ושוב‪ ,‬ללא תנאי עצירה‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫בדיקת תקינות סוגריים‬

‫‪ ‬נגדיר את המושג 'ביטוי חשבוני תקין מבחינת סוגריים'‪:‬‬


‫‪ ‬זהו ביטוי שיכול להכיל סוגריים במספר לא מוגבל‪ ,‬ובלבד שיהיו מאוזנים‪.‬‬
‫‪ ‬איזון הסוגריים מחייב שמספר הפותחים והסוגרים יהיה שווה בדיוק‪.‬‬
‫‪ ‬לדוגמא‪ ,‬הביטויים האלה תקינים‪:‬‬
‫‪((a))‬‬
‫‪( b + a – 2 * 7) ‬‬
‫‪( + 32 * ( 37 * ) / ( 5 + 1 ) ) – 4 ‬‬
‫‪ ‬נשים לב כי הביטוי האחרון תקין מבחינת הסוגריים‪ ,‬על אף שכביטוי חשבוני הוא‬
‫אינו תקין‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫בדיקת תקינות סוגריים‬

‫‪ ‬ואילו הביטויים האלה אינם תקינים‪:‬‬


‫‪a+((c‬‬
‫‪((x+y)‬‬
‫‪z+)t‬‬
‫‪ ‬פתחו אלגוריתם המקבל כקלט ביטוי חשבוני‪ ,‬ומחזיר "אמת" אם‬
‫הוא תקין מבחינת סוגריים‪ ,‬ו‪"-‬שקר" אם לא‪.‬‬
‫‪ ‬נסו לפתור את הבעיה ללא שימוש במחסנית‪...‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫בדיקת תקינות סוגריים‬
‫נכתוב את האלגוריתם הבא‪ ,‬הפותר את הבעיה‪ ,‬תוך שימוש במונה‪:‬‬
‫‪counter  0‬‬
‫כל עוד יש עדיין תווים בקלט‪ ,‬בצע‪:‬‬
‫קרא תו ‪ ch‬מהקלט‬
‫אם ‪ ch‬שווה לתו ’(‘ ‪ ,‬אזי‪:‬‬
‫הגדל ב‪ 1-‬את ‪counter‬‬
‫אם ‪ ch‬שווה לתו ’)‘ ‪ ,‬אזי‪:‬‬
‫הקטן ב‪ 1-‬את ‪counter‬‬
‫אם ‪ ,counter < 0‬אזי‪:‬‬
‫החזר "שקר"‬
‫אם ‪ ,counter > 0‬אזי‪:‬‬
‫החזר "שקר"‬
‫אחרת‪:‬‬
‫החזר "אמת"‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫בדיקת תקינות סוגריים‬

‫‪ ‬נגדיר מחדש את המושג "ביטוי חשבוני תקין מבחינת סוגריים"‪,‬‬


‫כך שיכלול גם ביטויים המכילים סוגריים מסוגים שונים‪:‬‬
‫‪ ‬כעת הביטוי יכול להכיל‪ ,‬בנוסף לסוגריים רגילים‪ ,‬גם סוגריים מסולסלים‪,‬‬
‫מרובעים‪ ,‬וכו'‪ ,‬במספר לא מוגבל‪ ,‬ובלבד שיהיו מאוזנים‪.‬‬
‫‪ ‬איזון הסוגריים מחייב שמספר הפותחים והסוגרים יהיה שווה בדיוק‪ ,‬וכן‬
‫שכנגד כל פותח יימצא הסוגר המתאים מאותו סוג במקום המתאים‪.‬‬
‫‪ ‬לדוגמא‪ ,‬הביטויים האלה תקינים‪:‬‬
‫‪((a))‬‬
‫‪[b+a–2*7]‬‬
‫‪{ + 32 * ( 37 * ) / [ 5 + 1 ] } – 4 ‬‬
‫‪ ‬נשים לב כי הביטוי האחרון תקין מבחינת הסוגריים‪ ,‬על אף‬
‫שכביטוי חשבוני הוא אינו תקין לחלוטין‪.‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫בדיקת תקינות סוגריים‬

‫‪ ‬ואילו הביטויים האלה אינם תקינים‪:‬‬


‫‪a+((c‬‬
‫‪([3+a)+4]‬‬
‫‪[ ) ( 5 – 3 ] * [ 2 – 3] ‬‬

‫• האם לדעתכם ניתן יהיה להשתמש באותו הרעיון‬


‫האלגוריתמי כמקודם?‬
‫• ואם נגדיר כמה מונים?‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫בדיקת תקינות סוגריים‬

‫כדי לפתור את הבעיה נשתמש במחסנית‪ ,‬ונסרוק את הביטוי‬ ‫‪‬‬


‫משמאל לימין‪.‬‬
‫כיוון שאנו בודקים את תקינות הביטוי רק מבחינת הסוגריים‪,‬‬ ‫‪‬‬
‫נתעלם מכל התווים שאינם סוגריים‪.‬‬
‫בזמן סריקת הביטוי‪ ,‬נדחוף למחסנית כל פותח שניתקל בו‪.‬‬ ‫‪‬‬
‫כשניתקל בסוגר‪ ,‬אז נשלוף מהמחסנית את הפותח הנמצא‬ ‫‪‬‬
‫בראשה‪ ,‬ונשווה ביניהם‪ .‬אם הם לא מאותו סוג – אז הביטוי אינו‬
‫תקין‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫בדיקת תקינות סוגריים‬

‫‪ ‬ניסיון לשלוף פותח ממחסנית ריקה מציין גם הוא שהביטוי‬


‫שאינו תקין‪ ,‬שכן אז קיימים יותר סוגרים מפותחים‪.‬‬
‫‪ ‬אם הגענו לסוף הקלט והמחסנית טרם התרוקנה‪ ,‬סימן שהיו‬
‫פותחים שאין להם סוגרים‪ ,‬ואז הביטוי אינו תקין‪.‬‬
‫‪ ‬אם לעומת זאת המחסנית ריקה בסוף הקלט‪ ,‬אז הביטוי תקין‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫בדיקת תקינות סוגריים ‪1 -‬‬
‫נכתוב את האלגוריתם‪:‬‬
‫אתחל‪-‬מחסנית ‪S ‬‬
‫כל עוד יש עדיין תווים בקלט‪ ,‬בצע‪:‬‬
‫קרא תו ‪ ch‬מהקלט‬
‫אם ‪ ch‬הוא פותח‪ ,‬אזי‪:‬‬
‫דחוף‪-‬למחסנית (‪)S,ch‬‬
‫אם ‪ ch‬הוא סוגר‪ ,‬בצע‪:‬‬
‫אם מחסנית‪-‬ריקה? (‪ , )S‬אזי‪:‬‬
‫החזר 'שקר'‬
‫אחרת‪:‬‬
‫שלוף‪-‬ממחסנית (‪old_ch  )S‬‬
‫אם ‪ ch‬ו‪ old_ch-‬אינם מתאימים‪ ,‬אזי‪:‬‬
‫החזר 'שקר'‬
‫אם לא מחסנית‪-‬ריקה? (‪ , )S‬אזי‪:‬‬
‫החזר 'שקר'‬
‫אחרת‪:‬‬
‫החזר 'אמת'‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
1 - ‫בדיקת תקינות סוגריים‬

5+([3+2]/{4-1})
5+([3+2]/{4-1}) (

5+([3+2]/{4-1}) ( [

5+([3+2]/{4-1}) ( [

SCE-Chapter-18-Stack Shayke Bilu PhD


1 - ‫בדיקת תקינות סוגריים‬

5+([3+2]/{4-1}) ( {

5+([3+2]/{4-1}) { (

5+([3+2]/{4-1}) (

5+([3+2]/{4-1})
!!! ‫הביטוי תקין‬
SCE-Chapter-18-Stack Shayke Bilu PhD
‫בדיקת תקינות סוגריים ‪2 -‬‬

‫)‪(2+{5*2))+(3/5‬‬
‫)‪(2+{5*2))+(3/5‬‬ ‫(‬

‫)‪(2+{5*2))+(3/5‬‬ ‫(‬ ‫{‬

‫)‪(2+{5*2))+(3/5‬‬ ‫{‬ ‫(‬


‫אין התאמה בין הסוגר הנוכחי‬
‫הביטוי אינו תקין !!!‬ ‫לבין הפותח שבראש המחסנית‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫בדיקת תקינות סוגריים ‪3 -‬‬

‫‪( ( 2 + 5) + 3‬‬
‫‪( ( 2 + 5) + 3‬‬ ‫(‬

‫‪( ( 2 + 5) + 3‬‬ ‫(‬ ‫(‬

‫‪( ( 2 + 5) + 3‬‬ ‫(‬ ‫(‬


‫המחסנית אינה ריקה בסיום‬
‫‪( ( 2 + 5) + 3‬‬ ‫המעבר על הביטוי‬ ‫(‬
‫ולכן הביטוי אינו נכון !!!‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
?‫שאלות‬

SCE-Chapter-18-Stack Shayke Bilu PhD


‫מחסנית כטיפוס נתונים‬

‫‪ ‬במהלך לימודינו הכרנו כל מיני טיפוסי נתונים (‪:)data types‬‬


‫מספר שלם (‪ ,)int‬מספר ממשי (‪ ,)float‬תו (‪ ,)char‬וכו'‪.‬‬
‫‪ ‬גם מחסנית (‪ ,)stack‬כפי שהגדרנו אותה‪ ,‬היא סוג של טיפוס‬
‫נתונים‪ ,‬אם כי להבדיל מטיפוסי נתונים מוחשיים‪ ,‬הקיימים‬
‫בשפת ‪ C‬ואנו יודעים כיצד הם ממומשים בזיכרון המחשב‪ ,‬כגון‬
‫‪ ,int, double, long‬וכו'‪ ,‬הרי שהמחסנית היא‬
‫‪ ‬טיפוס נתונים מופשט (טנ"מ)‪ ,‬או באנגלית ‪Abstract Data Type -‬‬
‫)‪.(ADT‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית כטיפוס נתונים‬

‫‪ ‬מה הכוונה?‬
‫‪ ‬מחסנית היא טיפוס נתונים לכל דבר‪ :‬אפשר להגדיר משתנה מטיפוס‬
‫מחסנית‪ ,‬לכתוב פונקציה שמקבלת מחסנית כפרמטר‪ ,‬להגדיר מערך של‬
‫מחסניות‪ ,‬לכתוב פונקציה שמחזירה מחסנית‪ ,‬להגדיר משתנה שהוא‬
‫מצביע למחסנית‪ ,‬וכו'‪.‬‬
‫‪ ‬מצד שני‪ ,‬מחסנית היא טיפוס נתונים מופשט‪ ,‬במובן זה שאנחנו יכולים‬
‫לעשות את כל הדברים המפורטים מעלה‪ ,‬מבלי לדעת כיצד היא ממומשת‬
‫בזיכרון המחשב‪.‬‬
‫‪ ‬כל העבודה שלנו עם משתנה מטיפוס מחסנית נעשתה דרך פעולות ממשק‬
‫(‪ ,)interface‬מבלי שהתעניינו כלל בשאלה כיצד נעשה בפועל המימוש‬
‫(‪ .)implementation‬הפרדה זו בין ממשק למימוש‪ ,‬וההסתרה של פרטי‬
‫המימוש מהמתכנת‪ ,‬היא מהמאפיינים של טנ"מ (‪.)ADT‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מחסנית כטיפוס נתונים‬

‫איך תיעשה ההפרדה בין ממשק למימוש בסביבת העבודה של ‪?C‬‬ ‫‪‬‬
‫נבנה בעצמנו יחידת ספרייה ‪ ,stack.h‬שתכלול את הכותרות של‬ ‫‪‬‬
‫כל הפונקציות הפועלות על מחסנית (דחיפה‪ ,‬שליפה‪ ,‬בדיקה האם‬
‫ריק‪ ,‬איתחול‪ ,‬הצצה)‪.‬‬
‫נכתוב בקובץ ‪ stack.c‬מימוש לכל הפעולות השונות על מחסנית‪.‬‬ ‫‪‬‬
‫כשמתכנת אחר ירצה להשתמש במחסנית‪ ,‬הוא יצרף את יחידת‬ ‫‪‬‬
‫הספרייה שלנו באמצעות ההוראה ”‪ ,#include “stack.h‬ויזמן‬
‫את הפונקציות הכלולות בה‪ ,‬מבלי לדעת כיצד הן מומשו‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית כטיפוס נתונים‬

‫‪ ‬במהלך הקורס‪ ,‬נממש את טיפוס הנתונים המופשט 'מחסנית'‬


‫בצורות שונות‪:‬‬
‫‪ ‬באמצעות מערך סטטי‬
‫‪ ‬באמצעות מערך דינאמי‬
‫‪ ‬באמצעות רשימה מקושרת‬
‫‪ ‬וכו'‬
‫‪ ‬האם המתכנת שישתמש ביחידת הספרייה ‪ stack.h‬יהיה מודע‬
‫למבנה הנתונים בו אנחנו משתמשים מאחורי הקלעים?‬
‫‪ ‬לא‪ ,‬ובכך תישמר ההפרדה בין ממשק למימוש‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מחסנית – אלגוריתם חיפוש‬
‫‪ ‬פתחו אלגוריתם אשר מקבל כקלט מחסנית ‪ S‬לא ריקה‪ ,‬ומחזיר את הערך‬
‫הגדול ביותר הנמצא בה‪ .‬הניחו ש‪ S-‬מועבר כפרמטר לפי ערך‪.‬‬
‫מצא‪-‬מקסימום (‪)S‬‬
‫אתחל‪-‬מחסנית ‪S1 ‬‬
‫שלוף‪-‬ממחסנית (‪max  )S‬‬
‫דחוף‪-‬למחסנית (‪)S1,max‬‬
‫כל עוד לא מחסנית‪-‬ריקה? (‪ ,)S‬בצע‪:‬‬
‫שלוף‪-‬ממחסנית (‪x  )S‬‬
‫דחוף‪-‬למחסנית (‪)S1,x‬‬
‫אם ‪ ,x > max‬אזי‪:‬‬
‫‪max  x‬‬
‫החזר ‪max‬‬
‫‪ ‬האם הכרחי היה להשתמש במחסנית עזר?‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מחסנית – אלגוריתם חיפוש‬
‫‪ ‬פתחו אלגוריתם אשר מקבל כקלט מחסנית ‪ S‬לא ריקה‪ ,‬אשר אין בה איבר‬
‫המופיע יותר מפעם אחת‪ .‬האלגוריתם יחזיר מחסנית חדשה‪ ,‬שזהה למחסנית‬
‫‪ ,S‬פרט לכך שהערך הגדול ביותר מבין איברי המחסנית ‪ S‬נמצא בראש‬
‫המחסנית החדשה‪.‬‬
‫הגדול‪-‬בראש (‪)S‬‬
‫אתחל‪-‬מחסנית ‪S1 ‬‬
‫מצא‪-‬מקסימום (‪max  )S‬‬
‫כל עוד לא מחסנית‪-‬ריקה? (‪ ,)S‬בצע‪:‬‬
‫שלוף‪-‬ממחסנית (‪x  )S‬‬
‫אם ‪ ,x < max‬אזי‪:‬‬
‫דחוף‪-‬למחסנית (‪)S1,x‬‬
‫הפוך‪-‬מחסנית (‪S1  )S1‬‬
‫דחוף‪-‬למחסנית (‪)S1,max‬‬
‫החזר ‪S1‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מחסנית – אלגוריתם חיפוש‬
‫‪ ‬פתחו אלגוריתם אשר מקבל כקלט מחסנית ‪ S‬לא ריקה‪ .‬האלגוריתם יחזיר מחסנית חדשה‪,‬‬
‫שזהה למחסנית ‪ ,S‬פרט לכך שהערך הגדול ביותר מבין איברי המחסנית ‪ S‬נמצא בראש‬
‫המחסנית החדשה‪ .‬במידה והוא מופיע יותר מפעם אחת‪ ,‬יש להעביר לראש המחסנית את כל‬
‫הערכים האלה‪.‬‬
‫הגדולים‪-‬בראש (‪)S‬‬
‫אתחל‪-‬מחסנית ‪S1 ‬‬
‫אתחל‪-‬מחסנית ‪S2 ‬‬
‫מצא‪-‬מקסימום (‪max  )S‬‬
‫כל עוד לא מחסנית‪-‬ריקה? (‪ ,)S‬בצע‪:‬‬
‫שלוף‪-‬ממחסנית (‪x  )S‬‬
‫אם ‪ ,x < max‬אזי‪:‬‬
‫דחוף‪-‬למחסנית (‪)S1,x‬‬
‫האם היה הכרחי‬ ‫אחרת‪:‬‬
‫להשתמש בשתי‬ ‫דחוף‪-‬למחסנית (‪)S2,x‬‬
‫מחסניות לצורך‬ ‫הפוך‪-‬מחסנית (‪S1  )S1‬‬
‫כל עוד לא מחסנית‪-‬ריקה? (‪ ,)S2‬בצע‪:‬‬
‫פתרון הבעיה?‬ ‫דחוף‪-‬למחסנית (שלוף‪-‬ממחסנית (‪)S1,)S2‬‬
‫החזר ‪S1‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מחסנית – אלגוריתם חיפוש‬
‫‪ ‬פתחו אלגוריתם אשר מקבל כקלט מחסנית ‪ S‬לא ריקה‪ .‬האלגוריתם יחזיר מחסנית חדשה‪,‬‬
‫שזהה למחסנית ‪ ,S‬פרט לכך שהערך הגדול ביותר מבין איברי המחסנית ‪ S‬נמצא בראש‬
‫המחסנית החדשה‪ .‬במידה והוא מופיע יותר מפעם אחת‪ ,‬יש להעביר לראש המחסנית את כל‬
‫הערכים האלה‪.‬‬
‫הגדולים‪-‬בראש (‪)S‬‬
‫אתחל‪-‬מחסנית ‪S1 ‬‬
‫‪count_max  0‬‬
‫מצא‪-‬מקסימום (‪max  )S‬‬
‫כל עוד לא מחסנית‪-‬ריקה? (‪ ,)S‬בצע‪:‬‬
‫שלוף‪-‬ממחסנית (‪x  )S‬‬
‫אם ‪ ,x < max‬אזי‪:‬‬
‫דחוף‪-‬למחסנית (‪)S1,x‬‬
‫אחרת‪:‬‬
‫הגדל ב‪ 1-‬את ‪count_max‬‬
‫הפוך‪-‬מחסנית (‪S1  )S1‬‬
‫בצע ‪ count_max‬פעמים‪:‬‬
‫דחוף‪-‬למחסנית (‪)S1,max‬‬
‫החזר ‪S1‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מחסנית – אלגוריתם חיפוש במחרוזת‬
‫‪ ‬לפניכם אלגוריתם המקבל כקלט מחרוזת תווים‪:‬‬
‫אתחל‪-‬מחסנית ‪stk ‬‬
‫קלוט תו ‪ch ‬‬
‫כל עוד ’‪ ,ch = ‘a‬בצע‪:‬‬
‫דחוף‪-‬למחסנית (‪)stk,ch‬‬
‫קלוט תו ‪ch ‬‬
‫כל עוד ’‪ ch = ‘b‬וגם לא מחסנית‪-‬ריקה? (‪ ,)stk‬בצע‪:‬‬
‫שלוף‪-‬ממחסנית (‪ch  )stk‬‬
‫קלוט תו ‪ch ‬‬
‫אם לא נותרו עוד תווים בקלט וגם מחסנית‪-‬ריקה? (‪ , )stk‬אזי‪:‬‬
‫החזר "אמת"‬
‫אחרת‪:‬‬
‫החזר "שקר"‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מחסנית – אלגוריתם חיפוש במחרוזת‬
‫‪ ‬נתון אלגוריתם רקורסיבי המקבל מחסנית ‪ S‬לא ריקה‪ ,‬המכילה מספרים‪:‬‬
‫סוד‪-‬כמוס (‪)S‬‬
‫שלוף‪-‬ממחסנית (‪num  )S‬‬
‫אם מחסנית‪-‬ריקה? (‪ , )S‬אזי‪:‬‬
‫החזר "אמת"‬
‫אחרת‪:‬‬
‫אם הצץ‪-‬למחסנית (‪ ,num > )S‬בצע‪:‬‬
‫החזר סוד‪-‬כמוס (‪)S‬‬
‫אחרת‪:‬‬
‫החזר "שקר"‬
‫‪ ‬תנו דוגמא למחסנית בת חמישה איברים לפחות שעבורה האלגוריתם‬
‫יחזיר "אמת"‪ ,‬ודוגמא שעבורה הוא יחזיר "שקר"‪.‬‬
‫‪ ‬איזו משימה מבצע האלגוריתם?‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מחסנית – אלגוריתם חיפוש לעומק‬

‫כתבו אלגוריתם בשם איבר‪-‬בעומק‪-‬מחסנית (‪ ,)S,k‬המחזיר את‬ ‫•‬


‫האיבר הנמצא בעומק ‪ k‬במחסנית ‪ S‬המכילה תווים‪ .‬הפונקציה‬
‫אינה משנה את מצבה הסופי של המחסנית ‪.S‬‬
‫לדוגמא‪ ,‬אם המחסנית ‪ S‬נראית כך‪:‬‬ ‫•‬
‫אז איבר‪-‬בעומק‪-‬מחסנית (‪ )S,4‬יחזיר את התו ' ‪.' $‬‬ ‫•‬
‫שני סטודנטים מתווכחים לגבי הפונקציה‪:‬‬ ‫•‬
‫האחד טוען כי הפונקציה איבר‪-‬בעומק‪-‬מחסנית שימושית‬ ‫•‬
‫ביותר‪ ,‬ועל כן כדאי להוסיפה לממשק המחסנית‪.‬‬
‫הסטודנט השני טוען כי פונקציה זו אינה "טבעית" לטיפוס‬ ‫•‬
‫הנתונים מחסנית‪ ,‬ועדיף להימנע מהשימוש בה‪.‬‬
‫מי לדעתכם צודק?‬ ‫•‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


?‫שאלות‬

SCE-Chapter-18-Stack Shayke Bilu PhD


‫קורס תכנות בשפת ‪C‬‬
‫מבני נתונים – מימוש מחסנית‬
‫‪STACK‬‬

‫שייקה בילו‬
‫יועץ ומרצה בכיר למדעי המחשב וטכנולוגית מידע‬
‫מומחה למערכות מידע חינוכיות‪ ,‬אקדמיות ומנהליות‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מבני נתונים ויעילות אלגוריתמים‬

‫‪ ‬מימוש מחסנית בעזרת מערך‬


‫‪ ‬מיון‪-‬מיזוג (‪)Merge Sort‬‬
‫‪ ‬צירופים ומשולש פסקל‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית‬

‫עד כה הגדרנו ממשק לטיפוס הנתונים מחסנית‪ ,‬ופתרנו בעזרתו‬ ‫‪‬‬


‫בעיות אלגוריתמיות‪.‬‬
‫נשים לב כי פתרון בעיות אלו לא דרש החלטה באשר לדרך‬ ‫‪‬‬
‫הייצוג של המחסנית במחשב‪.‬‬
‫כדי לממש בסביבת העבודה את האלגוריתמים שפיתחנו‬ ‫‪‬‬
‫בשיעורים שעברו‪ ,‬יש להחליט על דרך ייצוג‪.‬‬
‫אפשר לייצג מחסנית באמצעות מערך של איברים‪ ,‬שבו ישוכנו‬ ‫‪‬‬
‫איברי המחסנית‪ .‬משתנה ‪ top‬מטיפוס ‪ int‬יכיל את מספר התא‬
‫שבו נמצא האיבר העליון במחסנית‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית‬

‫‪ ‬כאשר המחסנית ריקה‪ ,‬נגדיר את ערכו של ‪ top‬להיות ‪.-1‬‬


‫‪ ‬בעת דחיפת איבר למחסנית‪ ,‬נגדיל את ערכו של ‪ top‬באחד‪,‬‬
‫ובתא שמספרו ‪ top‬נשכן את האיבר החדש‪.‬‬
‫‪ ‬כאשר נרצה לשלוף איבר מן המחסנית‪ ,‬נקרא את האיבר‬
‫במקום ‪ ,top‬נחזיר איבר זה ונקטין את ערכו של ‪ top‬באחד‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית‬
‫‪ ‬נתונה מחסנית של תווים‪ ,‬הממומשת באמצעות מערך‪ .‬כיצד יראה‬
‫המערך ומה יהיה ערכו של המשתנה ‪ ,top‬במהלך סדרת הפעולות‬
‫הבאה?‬
‫הכנס‪-‬למחסנית (’!’‪)S,‬‬ ‫אתחל‪-‬מחסנית ‪,S ‬‬
‫שלוף‪-‬ממחסנית (‪)S‬‬ ‫הכנס‪-‬למחסנית (’‪,)S,’A‬‬
‫מחסנית‪-‬ריקה? (‪)S‬‬ ‫שלוף‪-‬ממחסנית (‪,)S‬‬
‫‪ ‬מדוע אין צורך לאפס את תאי המערך בעת ביצוע שליפה או‬
‫איתחול של המחסנית?‬

‫‪Top = 5-1‬‬
‫‪10‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית‬

‫‪ ‬נשים לב כי לעיתים בחירת דרך ייצוג מסוימת כופה מגבלות‬


‫שאינן קיימות בטיפוס הנתונים המופשט‪.‬‬
‫‪ ‬מחסנית‪ ,‬מעצם הגדרתה‪ ,‬אינה מוגבלת לגודל כלשהו‪ ,‬ואפשר‬
‫לדחוף לתוכה כל מספר של איברים‪.‬‬
‫‪ ‬כשאנו מייצגים מחסנית בעזרת מערך‪ ,‬גודלה של המחסנית מוגבל‬
‫לגודלו של המערך‪.‬‬
‫‪ ‬בשל הגבלה זו‪ ,‬עלולה להתעורר שגיאה בעת ניסיון לדחוף איבר‬
‫למחסנית מלאה‪.‬‬
‫‪ ‬שגיאה זו נקראת גלישה (‪.)overflow‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מימוש מחסנית‬

‫‪ ‬כדי למנוע גלישה‪ ,‬נוסיף לממשק של טיפוס הנתונים מחסנית‪,‬‬


‫פונקציה המחזירה "אמת" אם המחסנית מלאה‪ ,‬ו‪"-‬שקר" אחרת‪.‬‬
‫‪ ‬כשאנו מספקים למשתמש יחידת ספרייה המממשת את המחסנית‪,‬‬
‫עלינו להודיע לו על המגבלה ולציין מהו המספר המקסימלי של‬
‫איברים שהמחסנית יכולה להכיל‪.‬‬
‫‪ ‬נזכור גם שכשם שאסור לדחוף איבר למחסנית מלאה‪ ,‬כך גם אסור‬
‫לנסות לשלוף איבר ממחסנית ריקה‪.‬‬
‫‪ ‬טעות כזו נקראת חמיקה (‪.)underflow‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


?‫שאלות‬

SCE-Chapter-18-Stack Shayke Bilu PhD


‫מימוש מחסנית ע"י מערך‬

:stack.h ‫ נכתוב את הקובץ‬


#define STACK_MAX_SIZE 100

typedef int stack_item;

typedef struct
}
int top;
stack_item data[STACK_MAX_SIZE[;
} stack;

SCE-Chapter-18-Stack Shayke Bilu PhD


‫מימוש מחסנית ע"י מערך‬

‫‪ ‬מה כתבנו בינתיים?‬


‫‪ ‬הגדרנו את הקבוע ‪ STACK_MAX_SIZE‬להיות ‪100‬‬
‫(יכולנו לבחור גם מספר אחר)‪ ,‬ואז המחסנית לא תוכל להכיל‬
‫יותר מ‪ 100-‬איברים‪.‬‬

‫‪ ‬אם אנו מעוניינים במחסנית של שלמים‪ ,‬אז ניתן לטיפוס‬


‫הנתונים ‪ int‬את השם הנרדף ‪( stack_item‬איבר במחסנית)‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית ע"י מערך‬

‫‪ ‬מה כתבנו בינתיים?‬


‫‪ ‬אם נרצה לשנות את יחידת הספרייה כך שתייצג מחסנית של‬
‫תווים או מחסנית של ממשיים‪ ,‬אז נחליף את המילה ‪ int‬בשורה‬
‫זו‪ ,‬במילה ‪ ,float ,char‬או בכל טיפוס שנרצה‪.‬‬

‫‪ ‬נגדיר ‪ stack‬להיות מבנה המכיל את המס' השלם ‪ top‬ואת‬


‫המערך ‪ ,data‬שגודלו ‪ STACK_MAX_SIZE‬איברים‪ ,‬וכל‬
‫אחד מהם הוא מטיפוס ‪.stack_item‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית ע"י מערך‬
:‫ נכתוב את ההצהרות על הפונקציות‬,stack.h ‫ בהמשך הקובץ‬
void stack_init(stack *s);

int stack_empty (stack s);

int stack_full (stack s);

void stack_push (stack *s, stack_item x);

stack_item stack_pop (stack *s);

stack_item stack_top (stack s);

SCE-Chapter-18-Stack Shayke Bilu PhD


‫מימוש מחסנית ע"י מערך‬

‫‪ ‬מדוע הפונקציות ‪ stack_empty ,stack_top‬ו‪stack_full-‬‬


‫מקבלות פרמטר מטיפוס מחסנית‪ ,‬ואילו ‪stack_pop‬‬
‫‪ ,stack_push ,stack_init‬מקבלות פרמטר מטיפוס מצביע‬
‫למחסנית?‬
‫‪ ‬מדוע שלא נגדיר את ‪ stack_pop‬ו‪ stack_top-‬להחזיר ‪int‬‬
‫במקום ‪?stack_item‬‬
‫‪ ‬אז ניתן לקבל את ‪ stack_push‬לקבל פרמטר שני מטיפוס ‪int‬‬
‫במקום ‪?stack_item‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית ע"י מערך‬
:‫ ובו מימוש לפעולות הממשק‬,stack.c ‫ כעת נכתוב את הקובץ‬
#include “stack.h”
void stack_init (stack *s)
{
s->top = -1;
}
int stack_empty (stack s)
{
return (s.top == -1);
}
int stack_full (stack s)
{
return (s.top == STACK_MAX_SIZE-1);
}
‫ ולא‬,int ‫ הוא‬stack_full-‫ ו‬stack_empty ‫ מדוע הערך המוחזר של‬
?stack_item
SCE-Chapter-18-Stack Shayke Bilu PhD
‫מימוש מחסנית ע"י מערך‬
:stack.c ‫ המשך קובץ המימוש‬
void stack_push (stack *s, stack_item x)
{ stack_item stack_top
if (!stack_full(*s)) (stack s)
{ {
s->data[++s->top] = x; if
(!stack_empty(s))
} return
} s.data[s.top];
}
stack_item stack_pop (stack *s)
{
if (!stack_empty(*s))
return s->data[s->top--];
}

SCE-Chapter-18-Stack Shayke Bilu PhD


?‫שאלות‬

SCE-Chapter-18-Stack Shayke Bilu PhD


1 ‫מימוש מחסנית ע"י מערך – תרגול‬
:‫ לפניכם הפונקציה הבאה‬
int ok (stack s1)
{
stack s2,s3;
int flag = 1;
stack_init(&s2);
stack_init(&s3);
while (!stack_empty(s1))
{
stack_push(&s2,stack_top(s1));
stack_push(&s3,stack_pop(&s1));
}
SCE-Chapter-18-Stack Shayke Bilu PhD
1 ‫מימוש מחסנית ע"י מערך – תרגול‬

while (!stack_empty(s3))
stack_push(&s1,stack_pop(&s3));
while (!stack_empty(s1) && !stack_empty(s2) && flag)
if (stack_pop(&s1) != stack_pop(&s2))
flag = 0;
return stack_empty(s1) && stack_empty(s2) && flag;
}

.5,4,4,5 ‫ עבור המחסנית המכילה את האיברים‬,‫ עקבו אחר הפונקציה‬


?‫ מהי מטרת הפונקציה‬

SCE-Chapter-18-Stack Shayke Bilu PhD


2 ‫מימוש מחסנית ע"י מערך – תרגול‬
:‫לפניכם הפונקציה הבאה‬
void print (stack *s)
{
stack_item num; stack_init(s);
scanf (“%d”, &num);
while (num != -99)
{
if (num >= 0)
stack_push(s,num);
else
while ((num++ < 0) && !stack_empty(*s))
printf (“%d“, stack_pop(s));
scanf (“%d”, &num);
}}
SCE-Chapter-18-Stack Shayke Bilu PhD
‫מימוש מחסנית ע"י מערך – תרגול ‪2‬‬

‫‪ ‬עקבו אחר הפונקציה‪ ,‬ותארו מה יהיה הפלט עבור הקלט הבא‬


‫(משמאל לימין)‪. 4,2,5,-2,6,-3,8,1,-99 :‬‬
‫‪ ‬תנו דוגמא לקלט המכיל לפחות ‪ 3‬מספרים‪ ,‬שבסופו המחסנית‬
‫ריקה‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית ע"י מערך – מיזוג‬

‫‪ ‬נתונים לנו שני מערכים‪ arr1 ,‬ו‪ ,arr2-‬אשר שניהם ממוינים‬


‫בסדר עולה‪.‬‬
‫‪ ‬מעוניינים ליצור מערך שלישי ‪ ,arr3‬שיכיל את כל האיברים‬
‫שבשני המערכים הראשונים‪ ,‬כשהם ממוינים בסדר עולה‪.‬‬
‫‪ ‬נציג אלגוריתם מיזוג הפותר את הבעיה‪:‬‬
‫‪ ‬נציב שני מצביעים על תחילתו של כל אחד מהמערכים‬
‫‪ arr1‬ו‪.arr2-‬‬
‫‪ ‬נשווה את ערכיהם של האיברים בתאים שעליהם מורים‬
‫המצביעים (התאים הראשונים בכל אחד מהמערכים)‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית ע"י מערך – מיזוג‬

‫במקום הראשון במערך ‪ arr3‬נשמור את האיבר שערכו הוא‬ ‫‪‬‬


‫הנמוך מבין השניים‪ ,‬ונקדם את המצביע שהצביע על איבר‬
‫זה אל התא הבא במערך‪.‬‬
‫נחזור על הצעד לגבי הערכים החדשים של המצביעים‪.‬‬ ‫‪‬‬

‫נמשיך באותו האופן עד שאחד המצביעים יגיע לסוף‬ ‫‪‬‬


‫המערך‪.‬‬
‫אז‪ ,‬כמובן‪ ,‬לא נקדם אותו יותר‪ ,‬ונעתיק ל‪ arr3-‬לפי הסדר‬ ‫‪‬‬
‫את האיברים הנותרים במערך השני‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית ע"י מערך – מיזוג‬

‫‪ ‬מהי סיבוכיות זמן הריצה של האלגוריתם?‬


‫הצעד הבסיסי באלגוריתם המיזוג כולל‪ ,‬במקרה הגרוע‬ ‫‪‬‬
‫ביותר (‪ ,)W.C‬השוואה בין שני ערכים במערך‪ ,‬העתקת‬
‫איבר למערך שלישי‪ ,‬ועדכון הערכים של אחד המצביעים‪.‬‬
‫מספר הצעדים המבוצע הוא כאורכו של המערך הממוזג‪,‬‬ ‫‪‬‬
‫ואם נסמן גודל זה ב‪ ,n-‬נקבל כי סיבוכיות זמן הריצה היא‬
‫)‪.Θ(n‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫מימוש מחסנית ע"י מערך – דוגמה למיזוג‬

SCE-Chapter-18-Stack Shayke Bilu PhD


‫מימוש מחסנית ע"י מערך –מיון‬

‫כיצד אפשר להשתמש באלגוריתם המיזוג שתיארנו‪ ,‬כדי למיין‬ ‫‪‬‬


‫מערך ‪ A‬באורך ‪?n‬‬
‫אם נחלק את ‪ A‬לשני תת‪-‬מערכים שווים פחות או יותר בגודלם‪,‬‬ ‫‪‬‬
‫ונמיין כל אחד מהם‪ ,‬נוכל לאחר מכן להשתמש באלגוריתם המיזוג‬
‫שפיתחנו על מנת למזג שני חלקים אלה למערך ממוין‪.‬‬
‫נשאלת השאלה‪ ,‬מהי דרך המיון שנשתמש בה כדי למיין את שני‬ ‫‪‬‬
‫חלקי המערך ‪ ?A‬אולי נשתמש‪ ,‬למשל‪ ,‬באחד האלגוריתמים למיון‬
‫שהכרנו (כמו מיון בחירה‪ ,‬מיון בועות או מיון הכנסה)?‬
‫ניתן לעשות זאת‪ ,‬אולם בכך לא נשיג שיפור ביעילות האלגוריתם‪,‬‬ ‫‪‬‬
‫אשר תישאר ריבועית‪.‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מימוש מחסנית ע"י מערך –מיון מיזוג‬

‫‪ ‬המפתח לשיפור במקרה הזה הוא שימוש ברקורסיה‪.‬‬


‫‪ ‬את המערך המקורי חילקנו לשני תת‪-‬מערכים שווים‪ ,‬פחות או‬
‫יותר‪ ,‬בגודלם‪ ,‬ואנחנו מעוניינים למיין כל אחד מהם‪.‬‬
‫‪ ‬את שני החצאים האלה של המערך המקורי‪ ,‬נוכל למיין‬
‫רקורסיבית‪:‬‬
‫נחלק כל אחד מחצאים אלה לשני חלקים (שגודל כל אחד מהם רבע‬ ‫‪‬‬
‫מגודלו של המערך המקורי)‪.‬‬
‫נמיין שוב כל חלק בצורה רקורסיבית‪.‬‬ ‫‪‬‬
‫נמזג את הרבעים הממוינים‪ ,‬ונקבל שני תת‪-‬מערכים ממוינים‪.‬‬ ‫‪‬‬
‫‪ ‬בשלב כלשהו נגיע לתת‪-‬מערך בגודל ‪ .1‬תת‪-‬מערך זה כבר ממוין‪,‬‬
‫ולכן הרקורסיה תיעצר‪ .‬שיטת מיון זו מכונה מיון מיזוג‪:‬‬
‫(‪.)Merge Sort‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫מימוש מחסנית ע"י מערך –מיון מיזוג‬

‫‪ ‬נכתוב את האלגוריתם‪:‬‬

‫מיון‪-‬מיזוג(‪)a,n‬‬ ‫‪‬‬
‫אם ‪ n = 1‬אזי החזר ‪a‬‬ ‫‪‬‬
‫אחרת‪:‬‬ ‫‪‬‬
‫הכנס את ‪ n/2‬האיברים הראשונים של ‪ a‬לתוך מערך ‪b‬‬ ‫‪‬‬
‫הכנס את ‪ n/2‬האיברים האחרונים של ‪ a‬לתוך מערך ‪c‬‬ ‫‪‬‬
‫מיון‪-‬מיזוג(‪)b,n/2‬‬ ‫‪‬‬
‫מיון‪-‬מיזוג(‪)c,n/2‬‬ ‫‪‬‬
‫מזג את שני המערכים ‪ b‬ו‪ c-‬למערך ‪ ,a‬והחזר אותו‬ ‫‪‬‬

‫‪ ‬איזו נוסחת נסיגה מבטאת את זמן הריצה של האלגוריתם?‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


?‫שאלות‬

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

4 8 3 0 1 2 7 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

4 8 3 0 1 2 7 5

4 8 3 0

SCE-Chapter-18-Stack
SCE-Sami Shamoon College of Shayke
ShaykeBilu - 2012
Bilu PhD
Merge Sort - ‫מיון ומיזוג מחסנית‬

4 8 3 0 1 2 7 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬
74

33 00 11 22 7 5

44 88

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬
75

1 2 7 5

4 8 3 0

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

1 2 7 5

8 3 0

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

1 2 7 5

3 0

4 8

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

1 2 7 5

4 30 03

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

1 2 7 5

4 8 30 03

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

1 2 7 5

4 8 0 03

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

1 2 7 5

4 8 0 3

3 0

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

1 2 7 5

4 8 0

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

1 2 7 5

4 8 0 3

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 0 3 1 2 7 5

4 8 3

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 0 3 1 2 7 5

4 8

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 04 3 1 2 7 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83 1 2 7 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83 7 5

1 2

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83

1 2 7 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 04 83

2 7 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83

7 5

1 2

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83

1 7 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3

0 3 40 83

1 2 7 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83

1 2 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83

1 2

7 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83

1 2 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83

1 2 5 7

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83 1

2 5 7

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83 1 2

5 7

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83 1 2 5

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 3 40 83 1 2 5 7

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 0 3

3 40 83 1 2 5 7

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 1 0 3

3 40 83 2 5 7

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 1 20 3

3 40 83 5 7

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 1 20 3

40 83 5 7

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 1 20 3 4

0 83 5 7

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 1 20 3 4 5

0 83 7

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 1 20 3 4 5 7

0 83

SCE-Chapter-18-Stack Shayke Bilu PhD


Merge Sort - ‫מיון ומיזוג מחסנית‬

0 1 20 3 4 5 7 8

0 3

SCE-Chapter-18-Stack Shayke Bilu PhD


?‫שאלות‬

SCE-Chapter-18-Stack Shayke Bilu PhD


‫מחסנית ‪ -‬מיון מיזוג‬
‫‪ ‬נבדוק מהו מספר הצעדים הבסיסיים שמבצע האלגוריתם מיון‪-‬מיזוג‪ ,‬הפועל‬
‫על מערך שבו ‪ n‬איברים‪.‬‬
‫‪ ‬ראינו כי נוסחת הנסיגה המתאימה היא )‪. T(n) = 2T(n/2) + Θ(n‬‬
‫‪ ‬ניתן לפתור אותה על‪-‬ידי שימוש בשיטת האיטרציה‪:‬‬
‫‪T(n) = 2T(n/2) + n = ‬‬
‫= ‪= 2(2T(n/4) + n/2) + n‬‬
‫= ‪= 4T(n/4) + n + n‬‬
‫= ‪= 4(2T(n/8) + n/4) + 2n‬‬
‫= ‪= 8T(n/8) + n + 2n‬‬
‫= ‪= 8T(n/8) + 3n‬‬
‫…‬ ‫סיימו את החישוב כתרגיל‪ ,‬וקבלו‬
‫שהפתרון הוא )‪T(n) = Θ(nlogn‬‬
‫‪= 2kT(n/2k) + kn‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫תזכורת ‪ -‬צירופים‬
‫• ניתן להשתמש בזהות‬

‫על מנת לפתח פונקציה בשפת ‪ C‬המחשבת את ערכו של ‪-n‬בחר‪:k-‬‬


‫)‪unsigned long choose (int n, int k‬‬
‫{‬
‫;))‪return factorial(n) / (factorial(k) * factorial(n-k‬‬
‫}‬
‫• מכיוון שהגדרנו ‪ ,0! = 1‬נקבל כי‪:‬‬

‫• קל לראות גם כי מתקיימת הזהות הבאה‪:‬‬

‫• בנוסף‪ ,‬נקבע ש‪ C(n,k) = 0-‬עבור ‪:k > n‬‬


‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫צירופים‬

‫?‬ ‫• האם ישנה דרך נוספת לחשב את‬


‫ביטוי זה מציין את מספר הדרכים לבחור ‪ k‬איברים מתוך ‪.n‬‬ ‫•‬
‫נסמן אחד מ‪ n-‬האיברים שמתוכם עלינו לבחור‪ ,‬ונכנה אותו "האיבר‬ ‫•‬
‫המיוחד"‪.‬‬
‫כשאנחנו בוחרים ‪ k‬איברים מתוך ‪ ,n‬יש שתי אפשרויות‪ :‬או שאנחנו‬ ‫•‬
‫מכלילים את ה'איבר המיוחד' בין ‪ k‬האיברים שאנחנו בוחרים‪ ,‬או שלא‬
‫מכלילים אותו‪.‬‬
‫אם אנחנו לא מכלילים את ה'איבר המיוחד'‪ ,‬אז עלינו לבחור ‪ k‬איברים‬ ‫•‬
‫מתוך ‪ n-1‬איברים (כל איברי הקבוצה שאינם ה"איבר המיוחד")‪ .‬מס'‬
‫הצירופים לבחירת ‪ k‬איברים מתוך ‪ n-1‬הוא‪:‬‬

‫•‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫צירופים‬

‫• אם אנחנו כן מכלילים את ה'איבר המיוחד'‪ ,‬אז נותר לנו לבחור‬


‫‪ k-1‬איברים מתוך ‪ n-1‬איברים (כל איברי הקבוצה שאינם‬
‫ה'איבר המיוחד')‪ .‬מס' הצירופים לבחירת ‪ k-1‬איברים מתוך‬
‫‪ n-1‬הוא‪:‬‬

‫• מכיוון שאלו שתי האפשרויות היחידות‪ ,‬נקבל את הזהות‪:‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫צירופים‬

‫• ניתן להשתמש בזהות‬

:‫• על מנת לפתח את הפונקציה הרקורסיבית הבאה‬


unsigned long choose (int n, int k)
{
if (k > n)
return 0;
if (k == 0 || k == n)
return 1;
return (choose(n-1,k) + choose(n-1,k-1));
}
SCE-Chapter-18-Stack Shayke Bilu PhD
‫משולש פסקל‬

‫נסדר את )‪ C(n,k‬בצורת משולש‪.‬‬ ‫•‬


‫ברור שכל הביטויים שעל שתי הצלעות‬ ‫•‬

‫הצדדיות של המשולש שווים כולם ל‪.1-‬‬


‫כמו כן‪ ,‬מתקיים ‪ C(n,1) = n‬לכל ‪.n‬‬ ‫•‬

‫לפי הזהות‪:‬‬ ‫•‬

‫נובע שכל איבר במשולש שווה לסכום‬ ‫•‬

‫שני האיברים שמעליו‪.‬‬ ‫•‬

‫המשולש שהתקבל נקרא "משולש‬ ‫•‬


‫פסקל"‪ ,‬על שם המתמטיקאי‬
‫הצרפתי מהמאה ה‪ ,17-‬בלייז פסקל (‪.)Blaise Pascal‬‬
‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬
‫משולש פסקל‬

‫פסקל גילה את "משולש פסקל" כשעסק בחישובים‬ ‫•‬


‫הסתברותיים שונים‪ ,‬והוכיח כי למשולש ישנן תכונות‬
‫מתמטיות מעניינות רבות‪.‬‬
‫נצבע בשחור את המספרים האי‪-‬זוגיים שבמשולש פסקל‪.‬‬ ‫•‬

‫קיבלנו את משולש סרפינסקי (‪)Sierpinski’s Triangle‬‬ ‫•‬

‫נסתכל על ערכי המשולש כעל ספרות‬ ‫•‬

‫בינאריות (שחור = ‪ ,1‬לבן = ‪.)0‬‬


‫נעיין במספרים הבינאריים שהתקבלו‪.‬‬ ‫•‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫הדגמת משולש פסקל‬

SCE-Chapter-18-Stack Shayke Bilu PhD


‫הדגמת משולש פסקל‬

‫אם נסתכל על כל שורה כעל מספר בינארי‪ ,‬נקבל את סדרת‬ ‫•‬


‫המספרים‪:‬‬
‫… ‪1, 3, 5, 15, 17, 51, 85, 255, 257, 771, 1285, 3855, 4369,‬‬
‫מספרים אלו מציינים אילו מצולעים‬ ‫•‬

‫משוכללים בעלי מס' אי‪-‬זוגי של צלעות‬


‫ניתן לבנות בעזרת סרגל ומחוגה‪.‬‬
‫בנייה גיאומטרית בסרגל ובמחוגה נחקרה‬ ‫•‬

‫כבר בידי אוקלידס (‪ )Euclid‬ושאר‬


‫המתמטיקאים ביוון העתיקה‪.‬‬

‫‪SCE-Chapter-18-Stack‬‬ ‫‪Shayke Bilu PhD‬‬


‫הדגמת משולש פסקל‬

SCE-Chapter-18-Stack Shayke Bilu PhD


?‫שאלות‬

SCE-Chapter-18-Stack Shayke Bilu PhD

You might also like