ADT של מבני נתונים ADT גנריים בחירת מבני נתונים שאלה לדוגמה

Slides:



Advertisements
Similar presentations
ממיבחניםC שאלות ++.
Advertisements

תוכנה 1 סמסטר א ' תשע " ב תרגול מס ' 7 * מנשקים, דיאגרמות וביטים * לא בהכרח בסדר הזה.
מבוא למדעי המחשב לתעשייה וניהול
1 Formal Specifications for Complex Systems (236368) Tutorial #4 Refinement in Z: data refinement; operations refinement; their combinations.
טבלאות סמלים נכתב ע"י אלכס קוגן סמסטר חורף, תשס"ח.
 ADT של מבני נתונים  ADT גנריים  בחירת מבני נתונים  שאלה לדוגמה.
תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים.
רקורסיות נושאי השיעור פתרון משוואות רקורסיביות שיטת ההצבה
תכנות תרגול 11 שבוע : מבנים מטרת המבנים היא לאפשר למתכנת להגדיר טיפוסי משתנים חדשים אשר מתאימים ספציפית לבעיה שאותה התוכנית פותרת. מטרת המבנים.
תכנות תרגול 6 שבוע : חישוב e זוהי הנוסחא לחישוב e נראה כיצד לתרגם אותה לפונקציה n n.
תרגול 5 רקורסיות. רקורסיה קריאה של פונקציה לעצמה –באופן ישיר או באופן עקיף היתרון : תכנות של דברים מסובכים נעשה ברור ונוח יותר, מכיוון שזו למעשה צורת.
שאלות חזרה לבחינה. שאלה דיסקים אופטיים מסוג WORM (write-once-read-many) משמשים חברות לצורך איחסון כמויות גדולות של מידע באופן קבוע ומבלי שניתן לשנותו.
מבוא לשפת C חידות ונקודות חשובות נכתב על-ידי יורי פקלני. © כל הזכויות שמורות לטכניון – מכון טכנולוגי לישראל.
מבוא למדעי המחשב תרגול 8 - מחרוזות שעת קבלה : יום שני 11:00-12:00 דוא " ל :
תרגול 5 דוגמא של ADT: מחסנית מצביעים לפונקציות תכנות גנרי דוגמא של ADT גנרי : מחסנית גנרית.
חורף - תשס " ג DBMS, צורות נורמליות 1 צורה נורמלית שלישית - 3NF הגדרה : תהי R סכמה רלציונית ותהי F קבוצת תלויות פונקציונליות מעל R. R היא ב -3NF.
1 Formal Specifications for Complex Systems (236368) Tutorial #5 Refinement in Z: data refinement; operations refinement; their combinations.
11 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
חלון הפקודות מיועד לבצע פעולה אחת בכל פעם. כיצד אפשר לבצע רשימת פקודות או אפליקציות מורכבות ?
תכנות תרגול 6 שבוע : תרגיל שורש של מספר מחושב לפי הסדרה הבאה : root 0 = 1 root n = root n-1 + a / root n-1 2 כאשר האיבר ה n של הסדרה הוא קירוב.
מנפה שגיאות - DEBUGGER מבוא למדעי המחשב (234114) רועי מלמד
ערמות ; מבני נתונים 09 מבוסס על מצגות של ליאור שפירא, חיים קפלן, דני פלדמן וחברים.
תכנות תרגול 6 שבוע : הגדרת פונקציות return-value-type function-name(parameter1, parameter2, …) הגדרת סוג הערכים שהפונקציה מחזירה שם הפונקציהרשימת.
תכנות תרגול 14 שבוע:
מבוא כללי למדעי המחשב תרגול 3. לולאות while לולאות while while (condition) { loop body } במקרה של קיום התנאי מתבצע גוף הלולאה ברגע שהתנאי לא מתקיים נצא.
תרגול 5 דוגמא של ADT: מחסנית מצביעים לפונקציות תכנות גנרי דוגמא של ADT גנרי : מחסנית גנרית.
קורס תכנות – סימסטר ב ' תשס " ח שיעור שישי: מערכים
מבוא כללי למדעי המחשב רשימות מקושרות
מבוא למדעי המחשב תרגול 6 - מערכים שעת קבלה : יום שני 11:00-12:00 דוא " ל :
Stacks and Queues. Stack ADT סוג של מערך מוגבל מהר מאוד ולוקחים מעט זכרון שימוש ב LIFO – LIFO (Last In, First Out) lists. –אפשר להוסיף רק בסוף הרשימה.
מערכים עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר int grade1, grade2, …, grade20; int grade1, grade2, …, grade20;
עקרון ההכלה וההדחה.
יחס סדר חלקי.
1 ADT Abstract Data Types The Stack Example. 2 ADT יוצגו שלושה פתרונות לבעיה זו : פתרון ישיר ופשוט - נועד להמחשת הבעיה. פתרון אשר נעזר ב ADT של מחסנית.
תכנות מונחה עצמים Object Oriented Programming (OOP) אתגר מחזור ב' Templates תבניות.
מבוא למדעי המחשב תרגול 3 שעת קבלה : יום שני 11:00-12:00 דוא " ל :
1 מבוא למדעי המחשב סיבוכיות. 2 סיבוכיות - מוטיבציה סידרת פיבונאצ'י: long fibonacci (int n) { if (n == 1 || n == 2) return 1; else return (fibonacci(n-1)
תכנות תרגול 12 שבוע : מבנים מטרת המבנים היא לאפשר למתכנת להגדיר טיפוסי משתנים חדשים אשר מתאימים ספציפית לבעיה שאותה התוכנית פותרת. מטרת המבנים.
11 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
הגדרת משתנים יום שישי 18 ספטמבר 2015 יום שישי 18 ספטמבר 2015 יום שישי 18 ספטמבר 2015 יום שישי 18 ספטמבר 2015 יום שישי 18 ספטמבר 2015 יום שישי 18 ספטמבר.
1 מבוא למדעי המחשב הרצאה 21: Queue, Iterator & Iterable.
מבוא למדעי המחשב לתעשייה וניהול הרצאה 7. סברוטינות subroutines.
תרגול 12: Iterator מחסנית תור 1. מחסנית (stack) מחסנית (stack) היא מבנה נתונים שמזכיר מחסנית של רובה : האיבר שנכנס ראשון למחסנית יוצא ממנה אחרון (LIFO.
מחסנית ותור Stacks and Queues. מחסנית Stack מחסנית - Stack ADT סוג של מערך מוגבל מהיר מאוד ותופס מעט זיכרון שימוש ב LIFO – LIFO (Last In, First Out)
שיאון שחוריMilOSS-il מוטיבציה  python זה קל ו C זה מהיר. למה לא לשלב?  יש כבר קוד קיים ב C. אנחנו רוצים להשתמש בו, ולבסס מעליו קוד חדש ב python.
תכנות מכוון עצמים ושפת ++C וויסאם חלילי. TODAY TOPICS: 1. Function Overloading & Default Parameters 2. Arguments By Reference 3. Multiple #include’s 4.
מבוא למדעי המחשב לתעשייה וניהול הרצאה 12. ספריות.
מחסנית ותור Stacks and Queues. מחסנית Stack מחסנית - Stack ADT סוג של מערך מוגבל מהיר מאוד ותופס מעט זיכרון שימוש ב LIFO – LIFO (Last In, First Out)
מבוא למדעי המחשב לתעשייה וניהול הרצאה 6. מפעל השעווה – לולאות  עד עכשיו  טיפלנו בייצור נרות מסוג אחד, במחיר אחיד  למדנו להתמודד עם טיפול במקרים שונים.
מבנה נתונים ואלגוריתמים ) לשעבר - עיבוד מידע( ד"ר אבי רוזנפלד ד"ר אריאלה ריכרדסון.
1 נתבונן בפונקציה הבאה public static int min(int[] a,int n) { int min = a[0]; for (int i = 1; (i < n ) && (i < a.length) ; i++) if (min > a[i]) min = a[i];
1 Formal Specifications for Complex Systems (236368) Tutorial #1 Course site:
מספרים אקראיים ניתן לייצר מספרים אקראיים ע"י הפונקציה int rand(void);
Programming Arrays.
מבני נתונים רשימה מקושרת, מחסנית ותור
Object Oriented Programming
Object Oriented Programming
Formal Specifications for Complex Systems (236368) Tutorial #1
מחלקות classes.
מבוא למדעי המחשב סיבוכיות.
מבנה נתונים ואלגוריתמים
שיעור חמישי: מערכים ומחרוזות
תירגול 14: מבני נתונים דינאמיים
הרצאה 06 רשימות מקושרות קרן כליף.
עבודה עם נתונים באמצעות ADO.NET
הרצאה 21: Queue, Iterator & Iterable
בניית מחסנית סטטית Static Stack Implementation מורים מובילים תשע"ה
תוכנה 1 תרגול 13 – סיכום.
ADT גנריים הידור של מספר קבצים Makefile שאלה לדוגמה
מחסנית ותור Stacks and Queues.
Presentation transcript:

ADT של מבני נתונים ADT גנריים בחירת מבני נתונים שאלה לדוגמה תרגול מס' 5 ADT של מבני נתונים ADT גנריים בחירת מבני נתונים שאלה לדוגמה

פתרון בעיה ישירות מבני נתונים מחסנית פתרון הבעיה בעזרת מחסנית ADT של מבני נתונים פתרון בעיה ישירות מבני נתונים מחסנית פתרון הבעיה בעזרת מחסנית מבוא לתכנות מערכות - 234122

בעיה לדוגמה נרצה לקלוט 100 מספרים אי שליליים מהקלט ולהדפיס אותם בסדר הפוך בזמן הכנסת הקלט המשתמש יכול להתחרט ולבטל את הכנסת המספר האחרון לצורך כך הוא צריך להכניס 1- פעולת הביטול דומה לפעולת “undo” בעורכי טקסטים המשתמש יכול לבצע “undo” כמה פעמים ולבטל כמה מספרים נפתור תחילה את הבעיה הזו ישירות מבוא לתכנות מערכות - 234122

פתרון ישיר #include <stdio.h> #include <assert.h> #define MAX_SIZE 100 #define UNDO_LAST_COMMAND -1 int main() { int input, size = 0, numbers[MAX_SIZE]; while (size < MAX_SIZE && scanf("%d", &input) == 1) { if (input != UNDO_LAST_COMMAND) { assert(size >= 0 && size < MAX_SIZE); numbers[size++] = input; continue; } if (size < 1) { printf("No numbers were entered until now\n"); continue; } size--; printf("undo\n"); } while (size > 0) { printf("%d\n", numbers[--size]); assert(size >= 0 && size < MAX_SIZE); } return 0; } מבוא לתכנות מערכות - 234122

חסרונות הפתרון הישיר לא ניתן לעשות שימוש חוזר בקוד עבור בעיות דומות קל להכניס באגים currentIndex-- או --currentIndex? currentIndex++ או ++currentIndex? currentIndex > 0או currentIndex >= 0? currentIndex < 1 או currentIndex < 0? הפתרון אינו מתעד את עצמו מוסיפים רק לסוף המערך מורידים מספרים רק מסוף המערך ההדפסה מתבצעת רק בסדר הפוך עבור בעיה גדולה יותר, כבר לא ניתן לשמור על הקוד פשוט כמו במקרה זה חשוב לציין שבחרנו בעיה פשוטה במיוחד ולכן הכלים שנשתמש בהם בקרוב ייראו קצת כ-overkill לבעיה. עם זאת, עבור בעיות גדולות הפתרון הישיר סובל בצורה בולטת מחסרונות אלו ופתרונות באמצעות ADT מוכיחים את עצמם כקלים יותר לכתיבה ולתחזוקה. מבוא לתכנות מערכות - 234122

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

מחסנית - Stack מבנה הנתונים מחסנית מוגדר לפי המנשק הבא: push - הוסף איבר למחסנית pop - הוצא את האיבר האחרון שהוכנס למחסנית (מבלי להחזיר את ערכו) top - החזר את ערכו של האיבר האחרון שהוכנס למחסנית (מבלי להוציאו) מחסנית מאפשרת גישה רק לאיבר האחרון שהוכנס ורק אותו ניתן להוציא ברגע נתון (LIFO - Last In First Out) המחשת מחסנית: http://www.cosc.canterbury.ac.nz/people/mukundan/dsal/StackAppl.html מבוא לתכנות מערכות - 234122

ADT מחסנית - stack.h לא לשכוח הגנה נגד include כפול איפה המבנה עצמו? #ifndef _STACK_H #define _STACK_H /** ADT of Stack of integers */ typedef struct Stack_t* Stack; /** possible return values */ typedef enum { STACK_BAD_ARGUMENT, STACK_SUCCESS, STACK_EMPTY, STACK_FULL } StackResult; /** creates a Stack with maximal capacity of 'maxSize'. if fails, returns NULL */ Stack stackCreate(int maxSize); /** releases the memory allocated for the stack */ void stackDestroy(Stack stack); איפה המבנה עצמו? מדוע? ערכי שגיאות מוסכמים כדי לאפשר למשתמש להתמודד עם שגיאות מבוא לתכנות מערכות - 234122

ADT מחסנית - stack.h /** insert a number to the top of the stack. Error Codes: STACK_BAD_ARGUMENT if stack is NULL STACK_FULL if the stack is full. */ StackResult stackPush(Stack stack, int number); /** removes the element at the top of the stack. Error codes: STACK_BAD_ARGUMENT if stack is NULL STACK_EMPTY if the stack is empty */ StackResult stackPop(Stack stack) /** returns in 'number' the last element that was pushed. Error codes: STACK_BAD_ARGUMENT if stack or number are NULL STACK_EMPTY if the stack is empty */ StackResult stackTop(Stack stack, int* number) /** returns the number of elements in the stack. stack must not be NULL */ int stackSize(Stack stack) #endif מבוא לתכנות מערכות - 234122

מימוש המחסנית 5 2 17 3 נבחר לממש את המחסנית בעזרת מערך נשמור שלושה שדות במבנה מערך בו יישמרו המספרים גודל המחסינת המקסימלי אינדקס המקום הפנוי הבא במערך זהו גם מספר האיברים במבנה איזו דרך נוספת קיימת למימוש מחסנית? nextIndex 5 דרך נוחה אחרת למימוש מחסנית היא בעזרת רשימה מקושרת. כך גם ניתן לממש בקלות מחסנית שאין לה חסם מקסמילי לגודלה. 2 17 3 מבוא לתכנות מערכות - 234122

ADT מחסנית - stack.c #include <stdlib.h> #include <assert.h> #include "stack.h" /** The Stack is implemented as an array of integers. * With nextIndex as an index to the next available position and * the maximal size is stored in maxSize. */ struct Stack_t { int* array; int nextIndex; int maxSize; }; מבוא לתכנות מערכות - 234122

שימו לב, בשלב זה כבר יש הקצאה שהצליחה ADT מחסנית - stack.c Stack stackCreate(int maxSize) { if (maxSize <= 0) { return NULL; } Stack stack = malloc(sizeof(*stack)); if (stack == NULL) { stack->array = malloc(sizeof(int)*maxSize); if (stack->array == NULL) { free(stack); stack->nextIndex = 0; stack->maxSize = maxSize; return stack; שימו לב, בשלב זה כבר יש הקצאה שהצליחה מבוא לתכנות מערכות - 234122

ADT מחסנית - stack.c StackResult stackPush(Stack stack, int number) { if (stack == NULL) { return STACK_BAD_ARGUMENT; } if (stack->nextIndex >= stack->maxSize) { return STACK_FULL; } assert(stack->nextIndex >= 0 && stack->nextIndex < stack->maxSize); stack->array[stack->nextIndex++] = number; return STACK_SUCCESS; } StackResult stackPop(Stack stack) { return STACK_BAD_ARGUMENT; } if (stack->nextIndex < 1) { return STACK_EMPTY; } stack->nextIndex--; return STACK_SUCCESS; } מבוא לתכנות מערכות - 234122

ADT מחסנית - stack.c כיצד ניתן לכתוב בצורה שונה כך שתחזיר ערכי שגיאה? StackResult stackTop(Stack stack, int* number) { if (stack == NULL || number == NULL) { return STACK_BAD_ARGUMENT; } if (stack->nextIndex < 1) { return STACK_EMPTY; } assert(stack->nextIndex > 0 && stack->nextIndex <= stack->maxSize); *number = stack->array[stack->nextIndex - 1]; return STACK_SUCCESS; } int stackSize(Stack stack) { assert(stack); return stack->nextIndex; } void stackDestroy(Stack stack) { if (stack != NULL) { free(stack->array); free(stack); } } את stackSize ניתן לתכוב גם כך: StackResult stackSize(Stack stack, int* size) { if (stack == NULL || size == NULL) { return STACK_BAD_ARGUMENT; } *size = stack->nextIndex; return STACK_SUCCESS; יתרונות החזרת ערכי שגיאה: הקוד אינו מתרסק במקרה של טעות - מסוכן מאוד לתוכנה גדולה המשתמש יכול להתמודד עם דיבוג ביתר קלות ע"י מציאת הבעיה שבגללה הפונקציה נכשלה חסרונות: הקריאה לקוד עם ערכי השגיאה הרבה פחות קריאה ונוחה, צריך משתנה שהוגדר לפני כן ולוודא את ערך החזרה של הפונקציה. בשיטה הרגילה הקוד פשוט מתרסק ונוכל להניח בד"כ שאין באגים אם זה לא קורה בפועל (בהנחה שבדקנו בצורה סבירה את הקוד) כיצד ניתן לכתוב בצורה שונה כך שתחזיר ערכי שגיאה? מה היתרונות והחסרונות של כל שיטה? מבוא לתכנות מערכות - 234122

פתרון הבעיה בעזרת מחסנית #include <stdio.h> #include <assert.h> #include <stdlib.h> #include "stack.h" #define MAX_INPUT_SIZE 100 #define UNDO_LAST_COMMAND -1 int main() { Stack stack = stackCreate(MAX_INPUT_SIZE); if (stack == NULL) { fprintf(stderr, "failed to create stack\n"); exit(1); } int input; while (stackSize(stack) < MAX_INPUT_SIZE && scanf("%d", &input) == 1) { if (input != UNDO_LAST_COMMAND) { StackResult result = stackPush(stack, input); assert(result == STACK_SUCCESS); continue; } StackResult result = stackPop(stack); if (result == STACK_EMPTY) { printf("No numbers were entered until now\n"); } else { assert(result == STACK_SUCCESS); printf("undo\n"); } } מבוא לתכנות מערכות - 234122

פתרון הבעיה בעזרת מחסנית while (stackSize(stack) > 0) { int number; StackResult result = stackTop(stack, &number); StackResult result2 = stackPop(stack); assert (result == STACK_SUCCESS && result2 == STACK_SUCCESS); printf("%d\n", number); } stackDestroy(stack); return 0; מבוא לתכנות מערכות - 234122

ADT של מבני נתונים - סיכום ע"י פתרון הבעיה עם מבנה המחסנית מתקבל פתרון עם סיכוי קטן יותר לבאגים הפתרון עם המחסנית מתעד את עצמו שימוש במבני נתונים מונע שכפול קוד שימוש במבני נתונים מבטיח את אופן העבודה עם הנתונים שימוש במבני הנתונים מקל על המתכנת בכתיבת קוד מבוא לתכנות מערכות - 234122

מבני נתונים גנריים מחסנית גנרית שימוש במחסנית הגנרית ADT גנריים מבני נתונים גנריים מחסנית גנרית שימוש במחסנית הגנרית מבוא לתכנות מערכות - 234122

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

מחסנית גנרית - stack.h typedef כדי להקל על המשתמש במבנה #ifndef _STACK_H #define _STACK_H /** generic ADT of Stack of integers */ typedef struct Stack_t* Stack; typedef void* Element; typedef Element (*CopyFunction)(Element); typedef void (*FreeFunction)(Element); /** possible return values */ typedef enum { STACK_BAD_ARGUMENT, STACK_SUCCESS, STACK_FAIL, STACK_EMPTY, STACK_FULL } StackResult; typedef כדי להקל על המשתמש במבנה קוד שגיאה להתמודדות עם שגיאות בפונקציות הנשלחות ע"י המשתמש מבוא לתכנות מערכות - 234122

מחסנית גנרית - stack.h /** creates a Stack with maximal capacity of 'maxSize'. if fails, returns NULL */ Stack stackCreate(int maxSize, CopyFunction copyFunction, FreeFunction freeFunction); /** releases the memory allocated for the stack */ void stackDestroy(Stack stack); /** inserts a number to the top of the stack. Error Codes: STACK_BAD_ARGUMENT if stack is NULL STACK_FULL if the stack is full and STACK_FAIL if the supplied copy function fails. */ StackResult stackPush(Stack stack, Element element); מבוא לתכנות מערכות - 234122

מחסנית גנרית - stack.h /** removes the element at the top of the stack. Error codes: STACK_BAD_ARGUMENT if stack is NULL STACK_EMPTY if the stack is empty */ StackResult stackPop(Stack stack); /** returns in 'number' the last element that was pushed. Error codes: STACK_BAD_ARGUMENT if stack or number are NULL STACK_EMPTY if the stack is empty and STACK_FAIL if the supplied copy function fails */ StackResult stackTop(Stack stack, Element* element); /** returns the number of elements in the stack. stack must not be NULL */ int stackSize(Stack stack); #endif מבוא לתכנות מערכות - 234122

מחסנית גנרית - stack.c #include <stdlib.h> #include <assert.h> #include "stack.h" /** The Stack is implemented as an array of Elements. * With nextIndex as an index to the next available position and * maximal size stored in maxsize. */ struct Stack_t { Element* array; int nextIndex; int maxSize; CopyFunction copyElement; FreeFunction freeElement; }; מבוא לתכנות מערכות - 234122

מחסנית גנרית - stack.c Stack stackCreate(int maxSize, CopyFunction copyFunction, FreeFunction freeFunction) { if (maxSize <= 0 || !copyFunction || !freeFunction) { return NULL; } Stack stack = (Stack) malloc(sizeof(*stack)); if (stack == NULL) { return NULL; } stack->array = (Element*) malloc(sizeof(Element) * maxSize); if (stack->array == NULL) { free(stack); return NULL; } stack->nextIndex = 0; stack->maxSize = maxSize; stack->copyElement = copyFunction; stack->freeElement = freeFunction; return stack; } מבוא לתכנות מערכות - 234122

מחסנית גנרית - stack.c StackResult stackPush(Stack stack, Element element) { if (stack == NULL) { return STACK_BAD_ARGUMENT; } if (stack->nextIndex >= stack->maxSize) { return STACK_FULL; Element newElement = stack->copyElement(element); if (newElement == NULL) { return STACK_FAIL; assert(stack->nextIndex >= 0 && stack->nextIndex < stack->maxSize); stack->array[stack->nextIndex++] = newElement; return STACK_SUCCESS; מבוא לתכנות מערכות - 234122

מחסנית גנרית - stack.c StackResult stackPop(Stack stack) { if (stack == NULL) { return STACK_BAD_ARGUMENT; } if (stack->nextIndex < 1) { return STACK_EMPTY; assert(stack->nextIndex > 0 && stack->nextIndex <= stack->maxSize); stack->freeElement(stack->array[stack->nextIndex - 1]); stack->nextIndex--; return STACK_SUCCESS; מבוא לתכנות מערכות - 234122

למה יוצרים העתק של העצם המוחזר? מחסנית גנרית - stack.c StackResult stackTop(Stack stack, Element* element) { if ((stack == NULL) || (element == NULL)) { return STACK_BAD_ARGUMENT; } if (stack->nextIndex < 1) { return STACK_EMPTY; assert(stack->nextIndex > 0 && stack->nextIndex <= stack->maxSize); Element newElement = stack->copyElement(stack->array[stack->nextIndex - 1]); if (newElement == NULL) { return STACK_FAIL; *element = newElement; return STACK_SUCCESS; כדי לשמור על נכונות ה-ADT חשוב לה להחזיר מצביעים לשדות פנימיים. מצביעים אלו יאפשרו למשתמש לשבור את המבנה מבפנים. לכן קיימות מספר אפשרויות: להחזיר מצביע לאיבר פנימי במקרים בהם זה הכרחי (למשל במקרה ורוצים לאפשר למשתמש לשנות איברים שכבר שומרים במבנה הנתונים) ולהקפיד בקוד שהמשתמש לא יוכל "לשבור" את שאר הקוד בטועת. להחזיר עותק להחזיר תוך שימוש במילה const, אך פתרון זה עובד בצורה טובה רק ב-C++, ולכן לא נהוג ב-C. למה יוצרים העתק של העצם המוחזר? מבוא לתכנות מערכות - 234122

מחסנית גנרית - stack.c int stackSize(Stack stack) { assert(stack); return stack->nextIndex; } void stackDestroy(Stack stack) { if (stack == NULL) { return; while (stackSize(stack) > 0) { StackResult result = stackPop(stack); assert(result == STACK_SUCCESS); free(stack->array); free(stack); מבוא לתכנות מערכות - 234122

פתרון הבעיה בעזרת מחסנית גנרית #include <stdio.h> #include <assert.h> #include <stdlib.h> #include "stack.h" #define MAX_INPUT_SIZE 10 #define UNDO_LAST_COMMAND -1 /* functions that will be used by the stack */ Element copyInt(Element element) { if (element == NULL) { return NULL; } int* newInt = malloc(sizeof(int)); if (newInt == NULL) { return NULL; } *newInt = *(int*)element; return newInt; } void freeInt(Element element) { free(element); } מבוא לתכנות מערכות - 234122

פתרון הבעיה בעזרת מחסנית גנרית int main() { Stack stack = stackCreate(MAX_INPUT_SIZE, copyInt, freeInt); if (stack == NULL) { fprintf(stderr, "failed to create stack\n"); exit(1); } int input; while (stackSize(stack) < MAX_INPUT_SIZE && scanf("%d", &input) == 1) { if (input != UNDO_LAST_COMMAND) { StackResult result = stackPush(stack, &input); assert(result == STACK_SUCCESS); continue; } StackResult result = stackPop(stack); if (result == STACK_EMPTY) { printf("No numbers were entered until now\n"); } else { assert(result == STACK_SUCCESS); printf("undo\n"); } } מבוא לתכנות מערכות - 234122

פתרון הבעיה בעזרת מחסנית גנרית while (stackSize(stack) > 0) { int* number = NULL; StackResult result = stackTop(stack, (Element*)&number); StackResult result2 = stackPop(stack); assert(result == STACK_SUCCESS && result2 == STACK_SUCCESS); printf("%d\n", *number); freeInt(number); } stackDestroy(stack); return 0; מבוא לתכנות מערכות - 234122

שימוש בגנריות נניח שהפעם אנחנו רוצים לקלוט מהקלט מחרוזות שמייצגות פקודות גודל מחרוזת מקסימלי הוא 80 בסוף קליטת הפקודות התוכנית תדפיס את הפקודות בסדר הפוך אחת הפקודות יכולה להיות “UNDO” - היא מבטלת קליטת פקודה קודמת פקודת UNDO אינה נקלטת ואינה מודפסת בסוף התוכנית מבוא לתכנות מערכות - 234122

שימוש במחסנית גנרית #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <string.h> #include "stack.h" #define MAX_INPUT_SIZE 100 #define UNDO_COMMAND "UNDO" #define MAX_COMMAND_SIZE 80 /* functions that will be used by the stack */ Element copyString(Element element) { if (element == NULL) { return NULL; } char* newString = malloc (strlen(element) + 1); if (newString == NULL) { return NULL; } return strcpy(newString, element); } void freeString(Element element) { free (element); } מבוא לתכנות מערכות - 234122

שימוש במחסנית גנרית int main() { Stack stack = stackCreate(MAX_INPUT_SIZE, copyString, freeString); if (stack == NULL) { fprintf(stderr, "failed to create stack\n"); exit(1); } char input[MAX_COMMAND_SIZE] = ""; while (stackSize(stack) < MAX_INPUT_SIZE && scanf("%s", input) == 1) { if (strcmp(input,UNDO_COMMAND) != 0) { StackResult result = stackPush(stack, input); assert(result == STACK_SUCCESS); continue; } StackResult result = stackPop(stack); if (result == STACK_EMPTY) { printf("No numbers were entered until now\n"); } else { assert(result == STACK_SUCCESS); printf("undo\n"); } } מבוא לתכנות מערכות - 234122

שימוש במחסנית גנרית while (stackSize(stack) > 0) { char* command = NULL; StackResult result = stackTop(stack, (Element*)&command); StackResult result2 = stackPop(stack); assert(result == STACK_SUCCESS && result2 == STACK_SUCCESS); printf("%s\n", command); freeString(command); } stackDestroy(stack); return 0; מבוא לתכנות מערכות - 234122

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

בחירת מבני נתונים מבני הנתונים הנלמדים בקורס מבוא לתכנות מערכות - 234122

מבני הנתונים הנלמדים בקורס בקורס זה אנו לומדים את מבני הנתונים הבסיסיים הבאים (כולם נלמדים כ-ADT): List - רשימה: שומרת אוסף איברים עם סדר ביניהם ומאפשרת הכנסת אותו איבר מספר פעמים Set - קבוצה: מאפשרת הכנסת איבר פעם אחת בלבד ואינה שומרת סדר בין איברי הקבוצה Stack - מחסנית: מאפשרת הכנסה, גישה והוצאה רק מסופה. שומרת על סדר ומאפשרת כפילויות Graph - גרף: שומר קבוצת צמתים וקבוצת קשתות המחברות ביניהם מתאים לבעיות הדורשות אבסטרקציה של רשתות כגון רשת כבישים, רשת מחשבים וכו'. לגבי סדר ב-set: כמו שבוודאי תשימו לב, חלק רק מהמימושים של set מגדירים סדר על האיברים בה ומאפשרים מעבר לפי סדר זה. דבר זה אינו שקול לשמירת סדר. שמירת סדר היא שמירה של סדר בין האיברים אשר יכול להשתנות ואינו קבוע מראש לכל קבוצה של איברים. למשל הרשימות הבאות שונות (1 2 3) ו-(3 2 1) ואילו הקבוצות הבאות שוות: {1 2 3} ו-{3 2 1}. שימו לב לחלק חשוב בהגדרת מבנה הנתונים - הפעולות אותן הוא מבצע על עצמים. פעולות אלו צריכות להישלח למ-ADT כמצביעים לפונקציה כדי שיוכל לעבוד. עבור list ו-stack הפעולות הללו הן העתקה של איבר (כדי להכניסו למבנה) ושחרורו (כדי שיהיה ניתן להוציא איברים מבמנה בבטחה) עבור set יש להוסיף פעולה נוספת - השוואה בין שני איברים במבנה. בלעדי פעולה זו set לא יכולה לדעת אם איבר כבר הוכנס למבנה. כאשר מתכננים מבנה נתונים חישבו אלו פעולות הוא צריך לבצע על האיברים והתאימו את המנשק כך שיקבל מצביעים מתאימים לפונקציות. מבוא לתכנות מערכות - 234122

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

בחירת מבני נתונים - סיכום מבני הנתונים הנלמדים בקורס הם List, Set, Stack ו-Graph יש לבחור מבנה נתונים מתאים לבעיה כדי להקל על העבודה מבוא לתכנות מערכות - 234122

שאלה לדוגמה - ADT מבוא לתכנות מערכות - 234122

שאלה לדוגמה מבנה הנתונים ערמה מאפשר הכנסת איברים והוצאה של האיבר "המקסימלי" לפי סדר שהוגדר. כלומר הפעולות הנדרשות מערמה הן: יצירת ערמה חדשה. שחרור ערמה קיימת. הכנסת איבר לערמה, ניתן להכניס מספר עותקים של אותו איבר. הוצאת האיבר המקסימלי מהערמה. במקרה והערמה ריקה תוחזר שגיאה. א. כתבו את קובץ המנשק עבור ADT של ערמה ב. באילו מה-ADT שנלמדו בקורס כדאי להשתמש למימוש בערמה? מדוע? ג. כתבו את הקוד הדרוש למימוש ה-struct עבור הערמה ד. ממשו את הפקונציה עבור יצירת ערמה חדשה מבוא לתכנות מערכות - 234122

ניתן להגדיר את המצביעים ישירות או להוסיף typedef מתאימים סעיף א' #ifndef _HEAP_H #define _HEAP_H #include <stdbool.h> typedef struct heap_t* Heap; typedef enum { HEAP_SUCCESS, HEAP_NULL_ARGUMENT, HEAP_OUT_OF_MEMORY, HEAP_EMPTY } HeapResult; Heap heapCreate(void* (*copy)(void*), void(*release)(void*), bool (*compare)(void*,void*)); HeapResult heapPush(Heap heap, void* element); HeapResult heapPop(Heap heap, void** element); void heapDestroy(Heap heap); #endif ניתן להגדיר את המצביעים ישירות או להוסיף typedef מתאימים מבוא לתכנות מערכות - 234122

איפה יישמרו המצביעים לשאר לפונקציות? סעיפים ב' ו-ג' נבחר להשתמש ב-List עבור מימוש הערמה: ייתכנו העתקים של אותו איבר בערמה יהיה לנו נוח יותר להוציא את האיבר ששמור בראש הרשימה מימוש המבנה בקובץ ה-C: struct heap_t { List items; bool (*compare)(void*,void*); }; איפה יישמרו המצביעים לשאר לפונקציות? מבוא לתכנות מערכות - 234122

סעיף ד' Heap heapCreate(void* (*copy)(void*), void (*release)(void*), bool (*compare)(void*,void*)) { Heap heap = malloc(*heap); if (!heap) { return NULL; } heap->items = listCreate(copy, release); if (!heap->items) { heapDestroy(heap); } heap->compare = compare; return heap; מבוא לתכנות מערכות - 234122