Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


Presentation on theme: "ADT של מבני נתונים ADT גנריים בחירת מבני נתונים שאלה לדוגמה"— Presentation transcript:

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

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

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

4 פתרון ישיר #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; } מבוא לתכנות מערכות

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

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

7 מחסנית - Stack מבנה הנתונים מחסנית מוגדר לפי המנשק הבא:
push - הוסף איבר למחסנית pop - הוצא את האיבר האחרון שהוכנס למחסנית (מבלי להחזיר את ערכו) top - החזר את ערכו של האיבר האחרון שהוכנס למחסנית (מבלי להוציאו) מחסנית מאפשרת גישה רק לאיבר האחרון שהוכנס ורק אותו ניתן להוציא ברגע נתון (LIFO - Last In First Out) המחשת מחסנית: מבוא לתכנות מערכות

8 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); איפה המבנה עצמו? מדוע? ערכי שגיאות מוסכמים כדי לאפשר למשתמש להתמודד עם שגיאות מבוא לתכנות מערכות

9 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 מבוא לתכנות מערכות

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

11 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; }; מבוא לתכנות מערכות

12 שימו לב, בשלב זה כבר יש הקצאה שהצליחה
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; שימו לב, בשלב זה כבר יש הקצאה שהצליחה מבוא לתכנות מערכות

13 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; } מבוא לתכנות מערכות

14 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; יתרונות החזרת ערכי שגיאה: הקוד אינו מתרסק במקרה של טעות - מסוכן מאוד לתוכנה גדולה המשתמש יכול להתמודד עם דיבוג ביתר קלות ע"י מציאת הבעיה שבגללה הפונקציה נכשלה חסרונות: הקריאה לקוד עם ערכי השגיאה הרבה פחות קריאה ונוחה, צריך משתנה שהוגדר לפני כן ולוודא את ערך החזרה של הפונקציה. בשיטה הרגילה הקוד פשוט מתרסק ונוכל להניח בד"כ שאין באגים אם זה לא קורה בפועל (בהנחה שבדקנו בצורה סבירה את הקוד) כיצד ניתן לכתוב בצורה שונה כך שתחזיר ערכי שגיאה? מה היתרונות והחסרונות של כל שיטה? מבוא לתכנות מערכות

15 פתרון הבעיה בעזרת מחסנית
#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"); } } מבוא לתכנות מערכות

16 פתרון הבעיה בעזרת מחסנית
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; מבוא לתכנות מערכות

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

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

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

20 מחסנית גנרית - 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 כדי להקל על המשתמש במבנה קוד שגיאה להתמודדות עם שגיאות בפונקציות הנשלחות ע"י המשתמש מבוא לתכנות מערכות

21 מחסנית גנרית - 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); מבוא לתכנות מערכות

22 מחסנית גנרית - 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 מבוא לתכנות מערכות

23 מחסנית גנרית - 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; }; מבוא לתכנות מערכות

24 מחסנית גנרית - 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; } מבוא לתכנות מערכות

25 מחסנית גנרית - 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; מבוא לתכנות מערכות

26 מחסנית גנרית - 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; מבוא לתכנות מערכות

27 למה יוצרים העתק של העצם המוחזר?
מחסנית גנרית - 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. למה יוצרים העתק של העצם המוחזר? מבוא לתכנות מערכות

28 מחסנית גנרית - 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); מבוא לתכנות מערכות

29 פתרון הבעיה בעזרת מחסנית גנרית
#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); } מבוא לתכנות מערכות

30 פתרון הבעיה בעזרת מחסנית גנרית
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"); } } מבוא לתכנות מערכות

31 פתרון הבעיה בעזרת מחסנית גנרית
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; מבוא לתכנות מערכות

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

33 שימוש במחסנית גנרית #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); } מבוא לתכנות מערכות

34 שימוש במחסנית גנרית 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"); } } מבוא לתכנות מערכות

35 שימוש במחסנית גנרית 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; מבוא לתכנות מערכות

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

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

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

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

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

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

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

43 ניתן להגדיר את המצביעים ישירות או להוסיף 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 מתאימים מבוא לתכנות מערכות

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

45 סעיף ד' 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; מבוא לתכנות מערכות


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

Similar presentations


Ads by Google