Presentation is loading. Please wait.

Presentation is loading. Please wait.

תרגול 5 דוגמא של ADT: מחסנית מצביעים לפונקציות תכנות גנרי דוגמא של ADT גנרי : מחסנית גנרית.

Similar presentations


Presentation on theme: "תרגול 5 דוגמא של ADT: מחסנית מצביעים לפונקציות תכנות גנרי דוגמא של ADT גנרי : מחסנית גנרית."— Presentation transcript:

1 תרגול 5 דוגמא של ADT: מחסנית מצביעים לפונקציות תכנות גנרי דוגמא של ADT גנרי : מחסנית גנרית

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

3 שלושה פתרונות 1. פתרון ישיר 1. פתרון ישיר - נועד להמחשת הבעיה. ADT מחסנית 2. פתרון אשר משתמש ב -ADT של מחסנית ADT גנרי מחסנית 3. פתרון אשר משתמש ב -ADT גנרי של מחסנית 3

4 הפתרון הישיר #include #define MAX_INPUT_SIZE 100 #define UNDO_LAST_COMMAND -1 int main(){ int lastNumber, currentIndex = 0; int numbers[MAX_INPUT_SIZE]; while (currentIndex < MAX_INPUT_SIZE && scanf("%d",&lastNumber) == 1){ if (lastNumber == UNDO_LAST_COMMAND){ if (currentIndex < 1){ printf("No numbers were entered until now\n"); } else{ currentIndex--; printf("undo\n"); } } else { assert(currentIndex >= 0 && currentIndex < MAX_INPUT_SIZE); numbers[currentIndex++] = lastNumber; } while (currentIndex > 0){ printf("%d\n", numbers[--currentIndex]); assert(currentIndex >= 0 && currentIndex < MAX_INPUT_SIZE); } return 0; } 4

5 הבעיות בפתרון הישיר באגיםסכנה של באגים –קל לטעות –קל לטעות ב -1 ולהתבלבל :  currentIndex-- או --currentIndex  currentIndex++ או ++currentIndex  currentIndex > 0 או currentIndex >= 0  currentIndex < 1 או currentIndex < 0 לאמתעדהפתרון לא מתעד את העובדות הבאות –מוסיפים רק לסוף –מוסיפים מספר רק לסוף המערך –מורידיםרק מסוף –מורידים מספר רק מסוף המערך –מדפיסיםרק בסדר הפוך –מדפיסים את המספרים רק בסדר הפוך 5

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

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

8 ADT מחסנית - הממשק ב -stack.h #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 ; 8

9 ADT מחסנית - הממשק ב -stack.h /* 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); /* insert a number to the top of the stack. Error Codes: StackBadArgument if stack is NULL StackFull if the stack is full. */ StackResult stackPush(Stack stack, int number); 9

10 ADT מחסנית - הממשק ב -stack.h /* removes the element at the top of the stack. Error codes: StackBadArgument if stack is NULL StackEmpty if the stack is empty */ StackResult stackPop(Stack stack); /* returns in 'number' the last element that was pushed. Error codes: StackBadArgument if stack or number are NULL StackEmpty if the stack is empty */ StackResult stackTop(Stack stack, int* number); /* returns the number of elements in the stack. Error codes: StackBadArgument if stack or size are NULL */ StackResult stackSize(Stack stack, int* size); #endif 10

11 מימוש אפשרי של המחסנית : בעזרת מערך מבנה שלושה שדותנגדיר מבנה שבו שלושה שדות : מערךמערך בו יישמרו המספרים גודל המערךשדה אשר ישמור את גודל המערך ( שיהיה זהה למספר האיברים המכסימלי שיכולים להישמר ) האינדקס במערךשדה שישמור את האינדקס במערך אליו יוכנס האיבר הבא ( יהיה שווה למספר האיברים במבנה ) 11 5 5 nextIndex 3 3 17 2 2

12 ADT מחסנית - המימוש ב -stack.c #include #include "stack.h" /* a structure that represents a Stack */ struct Stack_t { /* The Stack is implemented as an array of integers. With nextIndex as an index to the next available position and maximal size stored in maxCapacity. */ int* array; int nextIndex; int maxCapacity; }; 12

13 ADT מחסנית - המימוש ב -stack.c Stack stackCreate(int maxSize) { if (maxSize <= 0){ return NULL; } Stack stack = (Stack) malloc(sizeof(struct Stack_t)) ; if (stack == NULL){ return NULL; } stack->array = (int*) malloc(sizeof(int) * maxSize); if (stack->array == NULL){ free(stack); return NULL; } stack->nextIndex = 0; stack->maxCapacity = maxSize; return stack; } 13 ב -C99 ניתן להגדיר משתנים לא רק בתחילת בלוק עדיף להגדיר משתנים כמה שיותר קרוב לשימוש הראשון שלהם

14 ADT מחסנית - המימוש ב -stack.c StackResult stackPush(Stack stack, int number) { if (stack == NULL){ return STACK_BAD_ARGUMENT; } if (stack->nextIndex >= stack->maxCapacity){ return STACK_FULL; } assert(stack->nextIndex >= 0 && stack->nextIndex maxCapacity); stack->array[stack->nextIndex++] = number; return STACK_SUCCESS; } 14

15 ADT מחסנית - המימוש ב -stack.c StackResult stackPop(Stack stack) { if (stack == NULL){ return STACK_BAD_ARGUMENT; } if (stack->nextIndex < 1){ return STACK_EMPTY; } stack->nextIndex--; return STACK_SUCCESS; } 15

16 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 maxCapacity); *number = stack->array[stack->nextIndex-1]; return STACK_SUCCESS; } 16

17 ADT מחסנית - המימוש ב -stack.c StackResult stackSize(Stack stack, int* size) { if (stack == NULL || size == NULL){ return STACK_BAD_ARGUMENT; } *size = stack->nextIndex; return STACK_SUCCESS; } void stackDestroy(Stack stack) { if (stack != NULL){ free(stack->array); free(stack); } 17

18 הפתרון של הבעיה הקודמת בעזרת מחסנית #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"); exit(1); } int input, size = 0; 18

19 הפתרון של הבעיה הקודמת בעזרת מחסנית /* read the input numbers */ while (size < MAX_INPUT_SIZE && scanf("%d",& input) == 1){ if (input == UNDO_LAST_COMMAND){ StackResult result = stackPop(stack); if (result == STACK_EMPTY){ printf("No numbers were entered until now\n"); } else{ assert(result == STACK_SUCCESS); printf("undo\n"); } } else { StackResult result = stackPush(stack, input); assert(result == STACK_SUCCESS); } StackResult result = stackSize(stack, &size); assert(result == STACK_SUCCESS); } 19

20 הפתרון של הבעיה הקודמת בעזרת מחסנית /* print the numbers in the reverse order */ while (size > 0) { int number; StackResult result = stackTop(stack,&number); StackResult result2 = stackPop(stack); assert (result == STACK_SUCCESS && result2 == STACK_SUCCESS); printf("%d\n", number); stackSize(stack, &size); } stackDestroy(stack); return 0; { 20

21 יתרונות השימוש ב -ADT מחסנית בדוגמא שראינו הקטנת באגיםהקטנת סיכוי לבאגים –אין סכנה להתבלבל בין האינדקסים של המערך מתעד את עצמו self-documentingהקוד מתעד את עצמו (self-documenting) מדעי המחשב מחסנית –כל מי שלמד מדעי המחשב מבין מה זה מחסנית ויבין מה הקוד מבצע יותר בקלות 21

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

23 מצביעים לפונקצית פונקציות גנריות

24 מצביעים לפונקציות מצביע לפונקציה מצביע למשתנהב -C ניתן להגדיר מצביע לפונקציה, בצורה דומה כמו שניתן להגדיר מצביע למשתנה השמה כתובת של פונקציה –ניתן לבצע השמה של כתובת של פונקציה למצביע לפונקציה להעבירכפרמטרים –ניתן להעביר מצביעים לפונקציות כפרמטרים לפונקציות אחרות int foo(char c, int i); int (*p) (char, int); p = &foo; (*p) (‘a’, 7); 24 מה הבדל עם int *p(char, int); ? פה יתבצע foo(‘a’,7);

25 מצביעים לפונקציות ניתן להשמיטניתן להשמיט & וגם * בהתייחסות למצביעים לפונקציות p = foo; p(‘a’, 7); ניתן לשנותניתן לשנות את הערך של p ולגרום לו להצביע לפונקציה אחרת int bar(char c, int i);... p = foo; p(‘a’, 7); p = bar; p(‘b’, 17); 25 פה יתבצע foo(‘a’,7); פה יתבצע bar(‘b’,17);

26 דוגמא פונקציות השוואה נתונות שתי פונקציות השוואה בין מספרים typedef enum { Left, Eq, Right } Relation ; Relation bigger(int a, int b){ if (a > b) return Left ; if (a==b) return Eq ; return Right ; } Relation bigger(int a, int b){ if (a > b) return Left ; if (a==b) return Eq ; return Right ; } Relation bigger2(int a, int b) { if (a<0) a = -a; if (b<0) b = -b; if (a > b) return Left ; if (a==b) return Eq; return Right; } Relation bigger2(int a, int b) { if (a<0) a = -a; if (b<0) b = -b; if (a > b) return Left ; if (a==b) return Eq; return Right; } 26 מה ההבדל בין הפונקציות ?

27 דוגמא פשוטה למצביעים לפונקציות 27 int main() { /* function is a pointer to a function with signature Relation f(int, int) */ Relation (*function)(int, int) ; if (getchar() == '1') { function = bigger; } else { function = bigger2; } int a = -5, b = 3 ; Relation relation = function(a,b); switch (relation) { case Left: printf ("%d\n",a); break; case Eq: printf ("%d\n",a); break; case Right: printf ("%d\n",b); break; default: assert(false); } return 0; } int main() { /* function is a pointer to a function with signature Relation f(int, int) */ Relation (*function)(int, int) ; if (getchar() == '1') { function = bigger; } else { function = bigger2; } int a = -5, b = 3 ; Relation relation = function(a,b); switch (relation) { case Left: printf ("%d\n",a); break; case Eq: printf ("%d\n",a); break; case Right: printf ("%d\n",b); break; default: assert(false); } return 0; }

28 דוגמא מתקדמת – מיון מערכים typedef Relation (*CmpFunction)(int, int); void sort(int *array, int n, CmpFunction compare){ assert(array != NULL && compare != NULL); for(int i=0; i<n; i++) { for(int j=i+1; j<n; j++) { if(compare(arr[i], arr[j])==Left) { int tmp = array[i]; array[i] = array[j]; array[j] = tmp; } typedef Relation (*CmpFunction)(int, int); void sort(int *array, int n, CmpFunction compare){ assert(array != NULL && compare != NULL); for(int i=0; i<n; i++) { for(int j=i+1; j<n; j++) { if(compare(arr[i], arr[j])==Left) { int tmp = array[i]; array[i] = array[j]; array[j] = tmp; } 28

29 דוגמא מתקדמת – מיון מערכים int main(){ int arr[] = { 1, -3, 9, -10, -5 }; sort(arr, 5, bigger); /* -10 -5 -3 1 9 */ sort(arr, 5, bigger2); /* 1 -3 -5 9 -10*/ return 0; } int main(){ int arr[] = { 1, -3, 9, -10, -5 }; sort(arr, 5, bigger); /* -10 -5 -3 1 9 */ sort(arr, 5, bigger2); /* 1 -3 -5 9 -10*/ return 0; } 29

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

31 typedef Relation (*CmpFunction)(int, int); void sort(int *array, int n, CmpFunction compare){ assert(array != NULL && compare != NULL); for(int i=0; i<n; i++) { for(int j=i+1; j<n; j++) { if(compare(arr[i], arr[j])==Left) { int tmp = array[i]; array[i] = array[j]; array[j] = tmp; } typedef Relation (*CmpFunction)(int, int); void sort(int *array, int n, CmpFunction compare){ assert(array != NULL && compare != NULL); for(int i=0; i<n; i++) { for(int j=i+1; j<n; j++) { if(compare(arr[i], arr[j])==Left) { int tmp = array[i]; array[i] = array[j]; array[j] = tmp; } פונקצית מיון גנרית 31 void*, void* typedef Relation (*CmpFunction)(void*, void*); void ** void sort(void **array, int n, CmpFunction compare){ assert(array !=NULL && compare != NULL); for(int i=0; i<n; i++) { for(int j=i+1; j<n; j++) { if(compare(array[i], array[j])==Left) { void* void* tmp = array[i]; array[i] = array[j]; array[j] = tmp; } void*, void* typedef Relation (*CmpFunction)(void*, void*); void ** void sort(void **array, int n, CmpFunction compare){ assert(array !=NULL && compare != NULL); for(int i=0; i<n; i++) { for(int j=i+1; j<n; j++) { if(compare(array[i], array[j])==Left) { void* void* tmp = array[i]; array[i] = array[j]; array[j] = tmp; }

32 פונקצית השוואה בשביל פונקצית מיון גנרית לשלמים לתאריכים 32 Relation dateCompare(void* date1, void* date2){ int difference; DateResult result = dateDifference((Date)date1,(Date)date2, &difference); assert(result == DateSuccess); return bigger(difference,0); } Relation dateCompare(void* date1, void* date2){ int difference; DateResult result = dateDifference((Date)date1,(Date)date2, &difference); assert(result == DateSuccess); return bigger(difference,0); } Relation intCompare(void* a, void* b) { return bigger (*(int*)a, *(int*)b); } Relation intCompare(void* a, void* b) { return bigger (*(int*)a, *(int*)b); }

33 מיון תאריכים ושלמים int main() { void *dates[3]; dates[0] = dateCreate(20, 5, 2010); dates[1] = dateCreate(1, 1, 2000); dates[2] = dateCreate(2, 2, 2001); void* numbers[3]; numbers[0] = malloc(sizeof(int)); *(int*)numbers[0] = 17; numbers[1] = malloc(sizeof(int)); *(int*)numbers[1] = 1; numbers[2] = malloc(sizeof(int)); *(int*)numbers[2] = 7; sort(dates,3,dateCompare); sort(numbers,3,intCompare); for (int i=0; i<3; i++){ dateWrite(stdout,dates[i]); printf(“\n”); } for (int i=0; i<3; i++){ printf(“%d\n”,*(int*)numbers[i]); } return 0; } int main() { void *dates[3]; dates[0] = dateCreate(20, 5, 2010); dates[1] = dateCreate(1, 1, 2000); dates[2] = dateCreate(2, 2, 2001); void* numbers[3]; numbers[0] = malloc(sizeof(int)); *(int*)numbers[0] = 17; numbers[1] = malloc(sizeof(int)); *(int*)numbers[1] = 1; numbers[2] = malloc(sizeof(int)); *(int*)numbers[2] = 7; sort(dates,3,dateCompare); sort(numbers,3,intCompare); for (int i=0; i<3; i++){ dateWrite(stdout,dates[i]); printf(“\n”); } for (int i=0; i<3; i++){ printf(“%d\n”,*(int*)numbers[i]); } return 0; } 1 JAN 2000 2 FEB 2001 20 MAY 2010 1 7 17 1 JAN 2000 2 FEB 2001 20 MAY 2010 1 7 17 33

34 מבנה נתונים ( ממומש כ -ADT) גנרי The stack example generic version

35 מבנה נתונים גנרי מבנה נתוניםטיפוסי נתונים לוגיקהזההלרוב למבנה נתונים לא משנה איזה טיפוסי נתונים יכיל, בין אם הם מחרוזות, מבנים, שלמים או תווים. בכל מקרה ה -“ לוגיקה ” של המבנה תהיה זהה. –למשל, מחסנית תמיד תוציא את האיברים שהוכנסו אליה בסדר הפוך לסדר ההכנסה (LIFO) - ללא קשר לטיפוס האיברים מבנה נתונים גנרי מכל טיפוס שהואנרצה לכתוב מבנה נתונים גנרי שמסוגל להכיל איברים מכל טיפוס שהוא לכתוב פעם אחת כל הטיפוסים –מספיק לכתוב את מבנה הנתונים רק פעם אחת בשביל כל הטיפוסים שיכפול קוד  מניעת שיכפול קוד –הכללה פונקציות גנריות –הכללה של הרעיון של פונקציות גנריות 35

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

37 ADT מחסנית גנרית - הממשק ב -stack.h #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 ; 37

38 ADT מחסנית גנרית - הממשק ב -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); /* insert an element to the top of the stack. Error Codes: StackBadArgument if stack is NULL StackFull if the stack is full. */ StackResult stackPush(Stack stack, Element element); 38

39 ADT מחסנית גנרית - הממשק ב -stack.h /* removes the element at the top of the stack. Error codes: StackBadArgument if stack is NULL StackEmpty if the stack is empty */ StackResult stackPop(Stack stack); /* returns in the ‘element’ the last element that was pushed. Error codes: StackBadArgument if stack or element are NULL StackEmpty if the stack is empty */ StackResult stackTop(Stack stack, Element* element); /* returns the number of elements in the stack. Error codes: StackBadArgument if stack or size are NULL */ StackResult stackSize(Stack stack, int* size); #endif 39

40 ADT מחסנית גנרית - המימוש ב -stack.c #include #include "stack.h" /* a structure that represents a generic Stack */ struct Stack_t { /* The Stack is implemented as an array of Elements. With nextIndex as an index to the next available position and maximal size stored in maxCapacity. */ Element* array; int nextIndex; int maxCapacity; CopyFunction copyElement; FreeFunction freeElement; }; 40

41 ADT מחסנית גנרית - המימוש ב -stack.c Stack stackCreate(int maxSize, CopyFunction copyFunction, FreeFunction freeFunction) { if (maxSize <= 0){ return NULL; } Stack stack = (Stack) malloc(sizeof(struct Stack_t)) ; if (stack == NULL){ return NULL; } stack->array = (Element*) malloc(sizeof(Element) * maxSize); if (stack->array == NULL){ free(stack); return NULL; } stack->nextIndex = 0; stack->maxCapacity = maxSize; stack->copyElement= copyFunction; stack->freeElement = freeFunction; return stack; } 41

42 ADT מחסנית גנרית - המימוש ב -stack.c StackResult stackPush(Stack stack, Element element) { if (stack == NULL){ return STACK_BAD_ARGUMENT; } if (stack->nextIndex >= stack->maxCapacity){ return STACK_FULL; } Element newElement = stack->copyElement(element); if (newElement == NULL) { return STACK_FAIL; } assert(stack->nextIndex >= 0 && stack->nextIndex maxCapacity); stack->array[stack->nextIndex++] = newElement ; return STACK_SUCCESS; } 42

43 ADT מחסנית גנרית - המימוש ב -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 maxCapacity); stack->freeElement(stack->array[stack->nextIndex-1]); stack->nextIndex--; return STACK_SUCCESS; } 43

44 ADT מחסנית גנרית - המימוש ב -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 maxCapacity); Element newElement = stack->copyElement(stack->array[stack->nextIndex-1]); if (newElement == NULL){ return STACK_FAIL; } *element = newElement; return STACK_SUCCESS; } 44

45 ADT מחסנית גנרית - המימוש ב -stack.c StackResult stackSize(Stack stack, int* size) { if (stack == NULL || size == NULL){ return STACK_BAD_ARGUMENT; } *size = stack->nextIndex; return STACK_SUCCESS; } void stackDestroy(Stack stack) { /* empty the stack - free all the elements */ while (stackPop(stack) == STACK_SUCCESS){ /* empty while body */ ; } if (stack != NULL){ free(stack->array); free(stack); } 45

46 הפתרון של הבעיה הקודמת בעזרת מחסנית גנרית #include #include "stack.h" #define MAX_INPUT_SIZE 100 #define UNDO_LAST_COMMAND -1 /* functions that will be used by the ADT */ Element copyInt(Element element) { if (element == NULL) return NULL; int* newInt = (int*) malloc (sizeof(int)); if (newInt == NULL) return NULL; *newInt = *(int*)element; return newInt; } void freeInt(Element element) { free (element); } 46

47 הפתרון של הבעיה הקודמת בעזרת מחסנית גנרית int main() { Stack stack = stackCreate(MAX_INPUT_SIZE, copyInt, freeInt); if (stack == NULL){ fprintf(stderr,"failed to create stack\n"); exit(1); } int lastNumber, size = 0; 47

48 הפתרון של הבעיה הקודמת בעזרת מחסנית /* read the input numbers */ while (size < MAX_INPUT_SIZE && scanf("%d",&lastNumber) == 1){ if (lastNumber == UNDO_LAST_COMMAND){ StackResult result = stackPop(stack); if (result == STACK_EMPTY){ printf("No numbers were entered until now\n"); } else{ assert(result == STACK_SUCCESS); printf("undo\n"); } } else{ StackResult result = stackPush(stack,&lastNumber); assert(result == STACK_SUCCESS); } StackResult result= stackSize(stack, &size); assert(result == STACK_SUCCESS); } 48

49 הפתרון של הבעיה הקודמת בעזרת מחסנית /* print the numbers in the reverse order */ while (size > 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); stackSize(stack, &size); } stackDestroy(stack); return 0; { 49

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

51 הפתרון של הבעיה הקודמת בעזרת מחסנית גנרית #include #include "stack.h" #define MAX_INPUT_SIZE 100 #define UNDO_LAST_COMMAND “UNDO” #define MAX_COMMAND_SIZE 80 /* functions that will be used by the ADT */ Element copyString(Element element) { char *oldString = (char*) element; if (element == NULL) return NULL; char *newString = (char*) malloc (strlen(oldString) + 1); if (newString == NULL) return NULL; return strcpy(newString, oldString); } void freeString(Element element) { free (element); } 51

52 הפתרון של הבעיה הקודמת בעזרת מחסנית int main(){ Stack stack = stackCreate(MAX_INPUT_SIZE, copyString, freeString); if (stack == NULL){ fprintf(stderr,"failed to create stack\n"); exit(1); } int size = 0; char lastCommand[MAX_COMMAND_SIZE]; 52

53 הפתרון של הבעיה הקודמת בעזרת מחסנית /* read the input commands */ while (size < MAX_INPUT_SIZE && scanf("%s", lastCommand) == 1){ if (strcmp(lastCommand,UNDO_LAST_COMMAND) == 0){ StackResult result = stackPop(stack); if (result == StackEmpty){ printf("No numbers were entered until now\n"); } else{ assert(result == STACK_SUCCESS); printf("undo\n"); } } else{ StackResult result = stackPush(stack,lastCommand); assert(stackResult == STACK_SUCCESS); } StackResult result= stackSize(stack, &size); assert(result == STACK_SUCCESS); } 53

54 הפתרון של הבעיה הקודמת בעזרת מחסנית /* print the numbers in the reverse order */ while (size > 0) { char *tmpCommand = NULL; StackResult result = stackTop(stack, (Element*)&tmpCommand); StackResult result2 = stackPop(stack); assert (result == STACK_SUCCESS && result2 == STACK_SUCCESS); printf("%s\n", tmpCommand); freeString(tmpCommand); stackSize(stack, &size); } stackDestroy(stack); return 0; { 54

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

56 התאמת מבנה נתונים בסיסי לבעיה חשוב למצוא את מתאים ביותרלכל בעיה חשוב למצוא את מבנה נתונים המתאים ביותר. בפרט, יש לשים לב : סדר –לסדר בין האברים כפילויות –לכפילויות בין האיברים המטרותהמטרות בבחירת מבנה נתונים : –ייצוג טבעי וברור –ייצוג טבעי וברור לבעיה מתעד את עצמו  קוד קריא המתעד את עצמו –מניעת שיכפול קוד  הקוד קצר וברור  הקוד שעובד מול המבנה צריך להיות כמה שיותר קצר וברור –מניעת באגים להגן נגד טעויות  המבנה צריך להגן נגד טעויות של המשתמש –למשל Set ימנע הכנסת אותו איבר יותר מפעם אחת לא מתחשביםהערה : מטרה נוספת היא סיבוכיות הפעולות עם המבנה. במטרה הזאת לא מתחשבים במת '' מ, אלא בקורס " מבני נתונים " 56


Download ppt "תרגול 5 דוגמא של ADT: מחסנית מצביעים לפונקציות תכנות גנרי דוגמא של ADT גנרי : מחסנית גנרית."

Similar presentations


Ads by Google