Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


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

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

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

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

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

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

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

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

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

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

10 #include #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"); return -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"); } } מבוא לתכנות מערכות - 23412210

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

12 22 1717 33  נבחר לממש את המחסנית בעזרת מערך  נשמור שלושה שדות במבנה – מערך בו יישמרו המספרים – גודל המחסינת המקסימלי – אינדקס המקום הפנוי הבא במערך זהו גם מספר האיברים במבנה  איזו דרך נוספת קיימת למימוש מחסנית ? מבוא לתכנות מערכות - 23412212 nextIndex 55

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

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

15 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 maxSize); stack->array[stack->nextIndex++] = number; return STACK_SUCCESS; } StackResult stackPop(Stack stack) { if (stack == NULL) { return STACK_BAD_ARGUMENT; } if (stack->nextIndex < 1) { return STACK_EMPTY; } stack->nextIndex--; return STACK_SUCCESS; } מבוא לתכנות מערכות - 23412215

16 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 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); } } מבוא לתכנות מערכות - 23412216 כיצד ניתן לכתוב את פונקציה זו בצורה שונה כך שתחזיר ערכי שגיאה ? מה היתרונות והחסרונות של כל שיטה ? כיצד ניתן לכתוב את פונקציה זו בצורה שונה כך שתחזיר ערכי שגיאה ? מה היתרונות והחסרונות של כל שיטה ?

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

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

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

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

21 /** 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 an element 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); מבוא לתכנות מערכות - 23412221

22 /** 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 'element' 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 מבוא לתכנות מערכות - 23412222

23 #include #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); } מבוא לתכנות מערכות - 23412223

24 int main() { Stack stack = stackCreate(MAX_INPUT_SIZE, copyInt, freeInt); if (stack == NULL) { fprintf(stderr, "failed to create stack\n"); return -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"); } } מבוא לתכנות מערכות - 23412224

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

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

27 #include #include #include #include #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); } מבוא לתכנות מערכות - 23412227

28 int main() { Stack stack = stackCreate(MAX_INPUT_SIZE, copyString, freeString); if (stack == NULL) { fprintf(stderr, "failed to create stack\n"); return -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"); } } מבוא לתכנות מערכות - 23412228

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

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

31 Stack stackCreate(int maxSize, CopyFunction copyFunction, FreeFunction freeFunction) { if (maxSize <= 0 || !copyFunction || !freeFunction) { return NULL; } Stack stack = malloc(sizeof(*stack)); if (stack == NULL) { return NULL; } stack->array = 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; } מבוא לתכנות מערכות - 23412231

32 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 maxSize); stack->array[stack->nextIndex++] = newElement; return STACK_SUCCESS; } מבוא לתכנות מערכות - 23412232

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

34 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 maxSize); Element newElement = stack->copyElement(stack->array[stack->nextIndex - 1]); if (newElement == NULL) { return STACK_FAIL; } *element = newElement; return STACK_SUCCESS; } מבוא לתכנות מערכות - 23412234 למה יוצרים העתק של העצם המוחזר ?

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

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

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

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

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

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

41 מבוא לתכנות מערכות - 23412241

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

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

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

45 Heap heapCreate(void* (*copy)(void*), void (*release)(void*), bool (*compare)(void*,void*)) { if (!copy || !release || !compare) { return NULL; } Heap heap = malloc(sizeof(*heap)); if (!heap) { return NULL; } heap->items = listCreate(copy, release); if (!heap->items) { heapDestroy(heap); return NULL; } heap->compare = compare; return heap; } מבוא לתכנות מערכות - 23412245


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

Similar presentations


Ads by Google