תרגול 5 דוגמא של adt: מחסנית מצביעים לפונקציות תכנות גנרי...
Post on 20-Dec-2015
237 views
TRANSCRIPT
5תרגול
: מחסניתADTדוגמא של מצביעים לפונקציות
תכנות גנרי גנרי: מחסנית גנריתADTדוגמא של
הבעיה שנפתור
מספרים אי שליליים מהקלט 100 לקלוטלקלוטנרצה •בסדר הפוךבסדר הפוך אותם להדפיסלהדפיסו
להתחרט להתחרט בזמן הכנסת הקלט המשתמש יכול –המספר האחרוןהמספר האחרוןאת הכנסת ולבטל ולבטל
1-לצורך כך הוא צריך להכניס
בעורכי ””undoundo““פעולת הביטול דומה לפעולת –טקסטים
ולבטל כמה פעמים כמה פעמים ”undo“המשתמש יכול לבצע –כמה מספרים
2
שלושה פתרונות
- נועד להמחשת הבעיה.פתרון ישיר פתרון ישיר 1.1.
מחסניתמחסניתשל ADTADTפתרון אשר משתמש ב-2.
מחסניתמחסניתשל גנריגנרי ADTADTפתרון אשר משתמש ב-3.
3
הפתרון הישיר#include <stdio.h>#include <assert.h>#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
הבעיות בפתרון הישיר
באגיםבאגיםסכנה של • ולהתבלבל:1ב-קל לטעות קל לטעות –
currentIndex-- או --currentIndexcurrentIndex++ או ++currentIndex currentIndex > 0 אוcurrentIndex >= 0currentIndex < 1 או currentIndex < 0
את העובדות הבאות מתעדמתעד לאלאהפתרון •המערךרק לסוף רק לסוף מספר מוסיפיםמוסיפים–המערךרק מסוף רק מסוף מספר מורידיםמורידים–רק בסדר הפוךרק בסדר הפוך את המספרים מדפיסיםמדפיסים–
5
Stackמחסנית -
במדעי המחשב קיימות הרבה בעיות שבהן• כלשהםשמירת פריטיםשמירת פריטיםיש צורך ב–מהסדר שבו הם בסדר הפוך בסדר הפוך פריטים מוציאיםמוציאים–
הוכנסוהוכנסושהוכנסרק לפרט האחרון רק לפרט האחרון ניגשיםניגשים
לדוגמא:•undoלצורך שמירת פעולות שמירת פעולות –שמירת סדר קריאות לפונקציות–
את הבעיות האלה נהוג לפתור על ידי שימוש •מחסניתמחסניתב
6
Stackמחסנית - , כאשרשמירת איבריםשמירת איבריםהמאפשר מבנה נתונים מבנה נתונים •
להוציא רק את איבר האחרון להוציא רק את איבר האחרון בכל רגע נתון ניתן –(Last In First Outשהוכנס )
לגשת רק לאיבר האחרוןלגשת רק לאיבר האחרוןניתן –
הדגמת העבודה עם המחסנית:•http://www.cosc.canterbury.ac.nz/people/mukundan/dsal/StackAppl.html
המבנה תומך בפעולות הבאות:•
– pushpush -איבר למחסנית. הוסףהוסף
– poppop - את האיבר האחרון שהוכנס למחסנית הוצאהוצא)מבלי להחזיר את ערכו(.
– toptop - של האיבר האחרון שהוכנס החזר את ערכו החזר את ערכולמחסנית )מבלי להוציא אותו מהמחסנית(
7
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
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
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
5
nextIndexnextIndex
3
17
2
ADT-מחסנית - המימוש ב stack.c#include <stdlib.h>#include <assert.h>#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
ADT-מחסנית - המימוש ב stack.cStack 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ב-להגדיר
משתנים לא רק בתחילת
בלוק
עדיף להגדיר משתנים כמה שיותר קרוב
לשימוש הראשון שלהם
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 < stack->maxCapacity);
stack->array[stack->nextIndex++] = number; return STACK_SUCCESS; }14
ADT-מחסנית - המימוש ב stack.cStackResult stackPop(Stack stack) { if (stack == NULL){ return STACK_BAD_ARGUMENT;
} if (stack->nextIndex < 1){ return STACK_EMPTY;
} stack->nextIndex--; return STACK_SUCCESS;}
15
ADT-מחסנית - המימוש ב stack.cStackResult 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->maxCapacity); *number = stack->array[stack->nextIndex-1]; return STACK_SUCCESS;}16
ADT-מחסנית - המימוש ב stack.cStackResult 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
הפתרון של הבעיה הקודמת בעזרת מחסנית
#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, size = 0;
18
הפתרון של הבעיה הקודמת בעזרת מחסנית
/* 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
הפתרון של הבעיה הקודמת בעזרת מחסנית
/* 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
מחסנית ADTיתרונות השימוש ב-בדוגמא שראינו
באגיםבאגיםל סיכויהקטנת הקטנת •אין סכנה להתבלבל בין האינדקסים של המערך–
(self-documentingself-documenting)מתעד את עצמו מתעד את עצמו הקוד • מחסניתמחסניתמבין מה זה מדעי המחשב מדעי המחשב כל מי שלמד –
ויבין מה הקוד מבצע יותר בקלות
21
יתרונות נוספים לשימוש במבני נתונים אבסטרקטיים בתוכנה
שיכפול קודשיכפול קודמניעת •בכמה בכמה אם בתוכנה עובדים עם נתונים בצורה מסוימת –
כמה פעמיםכמה פעמיםאותו קוד לכתובלכתוב- אין צורך מקומות מקומות למשל אם בכמה מקומות בתוכנה יש צורך לעבד נתונים בסדר
הפוך מסדר קליטתם, בכל המקומות האלה נשתמש במחסנית
עם הנתוניםאופן העבודה אופן העבודה של הבטחה אוטומטיתהבטחה אוטומטית •באגיםבאגיםפחות –
מחסנית מבטיחה שלא ניתן לגשת לאמצע שלהSet מבטיח שלא יימצאו בו שני איברים זהים
22
מצביעים לפונקציתפונקציות גנריות
מצביעים לפונקציות
, בצורה דומה מצביע לפונקציהמצביע לפונקציה ניתן להגדיר Cב-•מצביע למשתנהמצביע למשתנהכמו שניתן להגדיר
למצביע כתובת של פונקציה כתובת של פונקציה של השמההשמהניתן לבצע –לפונקציה
כפרמטריםכפרמטרים מצביעים לפונקציות להעבירלהעבירניתן –לפונקציות אחרות
int foo(char c, int i);int (*p) (char, int);p = &foo;(*p) (‘a’, 7);
24
מה הבדל עם int *p(char, int);?
פה יתבצע foo(‘a’,7);
מצביעים לפונקציות
& וגם * בהתייחסות למצביעים לפונקציותניתן להשמיטניתן להשמיט•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);
דוגמא בין מספריםפונקציות השוואהפונקציות השוואהנתונות שתי
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
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;}
דוגמא מתקדמת – מיון מערכים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
דוגמא מתקדמת – מיון מערכים
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
פונקצית מיון גנרית
עצמים מכל טיפוס עצמים מכל טיפוס את פונקצית המיון למיין נרחיבנרחיב•שהוא
עצמים מטיפוסים שונים עצמים מטיפוסים שונים פונקציה שיכולה לעבד •פונקציה גנריתפונקציה גנריתנקראת
למנוע שיכפול קודלמנוע שיכפול קודהמטרה של פונקציות גנריות היא •טיפוסים שוניםטיפוסים שוניםעבור אותו קוד אותו קוד להימנע מכתיבת –
פונקציות גנריות מבצעות את העבודה שלהם בעזרת: •שהפונקציה עובדת עצמים כללים עצמים כללים לייצוג voidvoid מצביעים ל-מצביעים ל-–
איתםעל העצמים פעולותפעולותלייצוג מצביעים לפונקציות מצביעים לפונקציות –
30
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
typedef Relation )*CmpFunction()void*, void*void*, void*(;
void sort)void **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; } } }}
typedef Relation )*CmpFunction()void*, void*void*, void*(;
void sort)void **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
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(;}
מיון תאריכים ושלמים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 20002 FEB 200120 MAY 20101717
1 JAN 20002 FEB 200120 MAY 2010171733
( גנריADTמבנה נתונים )ממומש כ-
The stack examplegeneric version
מבנה נתונים גנרי
טיפוסי טיפוסי לא משנה איזה מבנה נתוניםמבנה נתוניםלרוב ל•יכיל, בין אם הם מחרוזות, מבנים, שלמים נתונים נתונים
” של המבנה תהיה לוגיקהלוגיקהאו תווים. בכל מקרה ה-“. זההזהה
למשל, מחסנית תמיד תוציא את האיברים שהוכנסו אליה –( - ללא קשר לטיפוס LIFOבסדר הפוך לסדר ההכנסה )
האיבריםשמסוגל להכיל מבנה נתונים גנרי מבנה נתונים גנרי נרצה לכתוב •
מכל טיפוס שהואמכל טיפוס שהואאיברים בשביל פעם אחת פעם אחת את מבנה הנתונים רק לכתובלכתובמספיק –
כל הטיפוסיםכל הטיפוסים שיכפול קודשיכפול קודמניעת
פונקציות גנריותפונקציות גנריותשל הרעיון של הכללההכללה–35
מבנה נתונים גנרי
כיצד לבצע פעולות כיצד לבצע פעולות מבנה הנתונים לא יידע :הבעיההבעיה•פשוטות הקשורות לאיברים שבו:
להעתיקלהעתיק–למחוקלמחוק–להשוותלהשוות–
של של הטיפוס של הטיפוס ידיעהידיעהביצוע פעולות אלו דורש •האיברים.
מצביעים לפונקציותמצביעים לפונקציותשימוש ב הפתרון:• המבנההמבנה מעביר בעת יצירתמעביר בעת יצירתהמשתמש במבנה הנתונים –
הספציפיות פעולותפעולותשמבצעות את המצביעים לפונקציות מצביעים לפונקציות לטיפוס
בדומה לפונקצית השוואה שפונקצית המיון מקבלת–
36
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
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
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
ADT מחסנית גנרית - המימוש stack.cב-
#include <stdlib.h>#include <assert.h>#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
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
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 < stack->maxCapacity); stack->array[stack->nextIndex++] = newElement ; return STACK_SUCCESS; }
42
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 <= stack->maxCapacity);
stack->freeElement(stack->array[stack->nextIndex-1]); stack->nextIndex--;
return STACK_SUCCESS;}43
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 <= stack->maxCapacity); Element newElement = stack->copyElement(stack->array[stack->nextIndex-1]);
if (newElement == NULL){ return STACK_FAIL; } *element = newElement;
return STACK_SUCCESS;}
44
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
הפתרון של הבעיה הקודמת בעזרת מחסנית גנרית
#include <stdio.h>#include <assert.h>#include <stdlib.h>#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
הפתרון של הבעיה הקודמת בעזרת מחסנית גנרית
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
הפתרון של הבעיה הקודמת בעזרת מחסנית
/* 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
הפתרון של הבעיה הקודמת בעזרת מחסנית
/* 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
דוגמא נוספת לשימוש במחסנית גנרית
נניח שהפעם אנחנו רוצים לקלוט מהקלט •פקודותפקודות שמייצגות מחרוזותמחרוזות
80גודל מחרוזת מקסימלי הוא –
את תדפיסתדפיסבסוף קליטת הפקודות התוכנית •בסדר הפוךבסדר הפוךהפקודות
- היא UNDOUNDOאחת הפקודות יכולה להיות •פקודה קודמתפקודה קודמת קליטת מבטלתמבטלת
לא נקלטת ולא מודפסת בסוף UNDOפקודת –התוכנית
50
הפתרון של הבעיה הקודמת בעזרת מחסנית גנרית
#include <stdio.h>#include <assert.h>#include <stdlib.h>#include <string.h>#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
הפתרון של הבעיה הקודמת בעזרת מחסנית
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
הפתרון של הבעיה הקודמת בעזרת מחסנית
/* 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
הפתרון של הבעיה הקודמת בעזרת מחסנית
/* 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
ADTsבסיסיים שנלמדים בקורס
הבאים )כולם מבני הנתונים הבסיסיים מבני הנתונים הבסיסיים בקורס אנחנו לומדים את •( :ADTבצורת
.1.1ListList )רשימה(בין האיבריםקיים סדר קיים סדר –כמה פעמים כמה פעמים במבנה יכול להופיע יכול להופיע כל איבר –
.2.2SetSet )קבוצה(לא מוגדרלא מוגדרבין האיברים הסדרהסדר–פעם אחת בלבד פעם אחת בלבד במבנה יכול להופיע יכול להופיע כל איבר –
.3.3StackStack )מחסנית(LIFOLIFOבין האיברים והוא קיים הסדר קיים הסדר –כמה פעמים כמה פעמים במבנה יכול להופיע יכול להופיע כל איבר –
• GraphGraphקשתותקשתותו צמתיםצמתיםשל אבסטרקציהאבסטרקציהמתאים לבעיות שדורשות 1.
למשל, תיאור ערים וכבישים ביניהם1.
55
התאמת מבנה נתונים בסיסי לבעיה
. בפרט, מתאים ביותרמתאים ביותרמבנה נתונים החשוב למצוא את חשוב למצוא את לכל בעיה •יש לשים לב:
בין האבריםסדרסדרל– בין האיבריםכפילויותכפילויותל–
בבחירת מבנה נתונים: המטרותהמטרות•לבעיהייצוג טבעי וברור ייצוג טבעי וברור –
מתעד את עצמומתעד את עצמוקוד קריא המניעת שיכפול קודמניעת שיכפול קוד–
קצר וברורקצר וברורשעובד מול המבנה צריך להיות כמה שיותר הקודהקודמניעת באגיםמניעת באגים–
של המשתמשלהגן נגד טעויות להגן נגד טעויות המבנה צריך ימנע הכנסת אותו איבר יותר מפעם אחתSetלמשל –
הערה: מטרה נוספת היא סיבוכיות הפעולות עם המבנה. במטרה •במת''מ, אלא בקורס "מבני נתונים"לא מתחשבים לא מתחשבים הזאת
56