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

56
ללללל5 ללללל ללADT : לללללל ללללללל ללללללללל ללללל לללל ללללל ללADT לללל: לללללל ללללל

Post on 20-Dec-2015

237 views

Category:

Documents


9 download

TRANSCRIPT

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

5תרגול

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

תכנות גנרי גנרי: מחסנית גנריתADTדוגמא של

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

הבעיה שנפתור

מספרים אי שליליים מהקלט 100 לקלוטלקלוטנרצה •בסדר הפוךבסדר הפוך אותם להדפיסלהדפיסו

להתחרט להתחרט בזמן הכנסת הקלט המשתמש יכול –המספר האחרוןהמספר האחרוןאת הכנסת ולבטל ולבטל

1-לצורך כך הוא צריך להכניס

בעורכי ””undoundo““פעולת הביטול דומה לפעולת –טקסטים

ולבטל כמה פעמים כמה פעמים ”undo“המשתמש יכול לבצע –כמה מספרים

2

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

שלושה פתרונות

- נועד להמחשת הבעיה.פתרון ישיר פתרון ישיר 1.1.

מחסניתמחסניתשל ADTADTפתרון אשר משתמש ב-2.

מחסניתמחסניתשל גנריגנרי ADTADTפתרון אשר משתמש ב-3.

3

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

הפתרון הישיר#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

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

הבעיות בפתרון הישיר

באגיםבאגיםסכנה של • ולהתבלבל:1ב-קל לטעות קל לטעות –

currentIndex-- או --currentIndexcurrentIndex++ או ++currentIndex currentIndex > 0 אוcurrentIndex >= 0currentIndex < 1 או currentIndex < 0

את העובדות הבאות מתעדמתעד לאלאהפתרון •המערךרק לסוף רק לסוף מספר מוסיפיםמוסיפים–המערךרק מסוף רק מסוף מספר מורידיםמורידים–רק בסדר הפוךרק בסדר הפוך את המספרים מדפיסיםמדפיסים–

5

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

Stackמחסנית -

במדעי המחשב קיימות הרבה בעיות שבהן• כלשהםשמירת פריטיםשמירת פריטיםיש צורך ב–מהסדר שבו הם בסדר הפוך בסדר הפוך פריטים מוציאיםמוציאים–

הוכנסוהוכנסושהוכנסרק לפרט האחרון רק לפרט האחרון ניגשיםניגשים

לדוגמא:•undoלצורך שמירת פעולות שמירת פעולות –שמירת סדר קריאות לפונקציות–

את הבעיות האלה נהוג לפתור על ידי שימוש •מחסניתמחסניתב

6

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

Stackמחסנית - , כאשרשמירת איבריםשמירת איבריםהמאפשר מבנה נתונים מבנה נתונים •

להוציא רק את איבר האחרון להוציא רק את איבר האחרון בכל רגע נתון ניתן –(Last In First Outשהוכנס )

לגשת רק לאיבר האחרוןלגשת רק לאיבר האחרוןניתן –

הדגמת העבודה עם המחסנית:•http://www.cosc.canterbury.ac.nz/people/mukundan/dsal/StackAppl.html

המבנה תומך בפעולות הבאות:•

– pushpush -איבר למחסנית. הוסףהוסף

– poppop - את האיבר האחרון שהוכנס למחסנית הוצאהוצא)מבלי להחזיר את ערכו(.

– toptop - של האיבר האחרון שהוכנס החזר את ערכו החזר את ערכולמחסנית )מבלי להוציא אותו מהמחסנית(

7

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

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

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

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

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

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

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

מימוש אפשרי של המחסנית: בעזרת מערך

:שלושה שדותשלושה שדותשבו מבנהמבנהנגדיר •בו יישמרו המספרים מערךמערך•גודל גודל שדה אשר ישמור את •

)שיהיה זהה למספר המערךהמערךהאיברים המכסימלי שיכולים

להישמר(האינדקס האינדקס שדה שישמור את •

אליו יוכנס האיבר הבא במערך במערך )יהיה שווה למספר האיברים

במבנה(

11

5

nextIndexnextIndex

3

17

2

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

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

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

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ב-להגדיר

משתנים לא רק בתחילת

בלוק

עדיף להגדיר משתנים כמה שיותר קרוב

לשימוש הראשון שלהם

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

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

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

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

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

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

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

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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית

#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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית

/* 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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית

/* 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

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

מחסנית ADTיתרונות השימוש ב-בדוגמא שראינו

באגיםבאגיםל סיכויהקטנת הקטנת •אין סכנה להתבלבל בין האינדקסים של המערך–

(self-documentingself-documenting)מתעד את עצמו מתעד את עצמו הקוד • מחסניתמחסניתמבין מה זה מדעי המחשב מדעי המחשב כל מי שלמד –

ויבין מה הקוד מבצע יותר בקלות

21

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

יתרונות נוספים לשימוש במבני נתונים אבסטרקטיים בתוכנה

שיכפול קודשיכפול קודמניעת •בכמה בכמה אם בתוכנה עובדים עם נתונים בצורה מסוימת –

כמה פעמיםכמה פעמיםאותו קוד לכתובלכתוב- אין צורך מקומות מקומות למשל אם בכמה מקומות בתוכנה יש צורך לעבד נתונים בסדר

הפוך מסדר קליטתם, בכל המקומות האלה נשתמש במחסנית

עם הנתוניםאופן העבודה אופן העבודה של הבטחה אוטומטיתהבטחה אוטומטית •באגיםבאגיםפחות –

מחסנית מבטיחה שלא ניתן לגשת לאמצע שלהSet מבטיח שלא יימצאו בו שני איברים זהים

22

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

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

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

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

, בצורה דומה מצביע לפונקציהמצביע לפונקציה ניתן להגדיר Cב-•מצביע למשתנהמצביע למשתנהכמו שניתן להגדיר

למצביע כתובת של פונקציה כתובת של פונקציה של השמההשמהניתן לבצע –לפונקציה

כפרמטריםכפרמטרים מצביעים לפונקציות להעבירלהעבירניתן –לפונקציות אחרות

int foo(char c, int i);int (*p) (char, int);p = &foo;(*p) (‘a’, 7);

24

מה הבדל עם int *p(char, int);?

פה יתבצע foo(‘a’,7);

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

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

& וגם * בהתייחסות למצביעים לפונקציותניתן להשמיטניתן להשמיט•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);

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

דוגמא בין מספריםפונקציות השוואהפונקציות השוואהנתונות שתי

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

מה ההבדל בין הפונקציות?

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

דוגמא פשוטה למצביעים לפונקציות

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;}

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

דוגמא מתקדמת – מיון מערכים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

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

דוגמא מתקדמת – מיון מערכים

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

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

פונקצית מיון גנרית

עצמים מכל טיפוס עצמים מכל טיפוס את פונקצית המיון למיין נרחיבנרחיב•שהוא

עצמים מטיפוסים שונים עצמים מטיפוסים שונים פונקציה שיכולה לעבד •פונקציה גנריתפונקציה גנריתנקראת

למנוע שיכפול קודלמנוע שיכפול קודהמטרה של פונקציות גנריות היא •טיפוסים שוניםטיפוסים שוניםעבור אותו קוד אותו קוד להימנע מכתיבת –

פונקציות גנריות מבצעות את העבודה שלהם בעזרת: •שהפונקציה עובדת עצמים כללים עצמים כללים לייצוג voidvoid מצביעים ל-מצביעים ל-–

איתםעל העצמים פעולותפעולותלייצוג מצביעים לפונקציות מצביעים לפונקציות –

30

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

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; } } }}

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

פונקצית השוואה בשביל פונקצית מיון גנרית

לשלמים•

לתאריכים•

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(;}

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

מיון תאריכים ושלמים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

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

( גנריADTמבנה נתונים )ממומש כ-

The stack examplegeneric version

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

מבנה נתונים גנרי

טיפוסי טיפוסי לא משנה איזה מבנה נתוניםמבנה נתוניםלרוב ל•יכיל, בין אם הם מחרוזות, מבנים, שלמים נתונים נתונים

” של המבנה תהיה לוגיקהלוגיקהאו תווים. בכל מקרה ה-“. זההזהה

למשל, מחסנית תמיד תוציא את האיברים שהוכנסו אליה –( - ללא קשר לטיפוס LIFOבסדר הפוך לסדר ההכנסה )

האיבריםשמסוגל להכיל מבנה נתונים גנרי מבנה נתונים גנרי נרצה לכתוב •

מכל טיפוס שהואמכל טיפוס שהואאיברים בשביל פעם אחת פעם אחת את מבנה הנתונים רק לכתובלכתובמספיק –

כל הטיפוסיםכל הטיפוסים שיכפול קודשיכפול קודמניעת

פונקציות גנריותפונקציות גנריותשל הרעיון של הכללההכללה–35

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

מבנה נתונים גנרי

כיצד לבצע פעולות כיצד לבצע פעולות מבנה הנתונים לא יידע :הבעיההבעיה•פשוטות הקשורות לאיברים שבו:

להעתיקלהעתיק–למחוקלמחוק–להשוותלהשוות–

של של הטיפוס של הטיפוס ידיעהידיעהביצוע פעולות אלו דורש •האיברים.

מצביעים לפונקציותמצביעים לפונקציותשימוש ב הפתרון:• המבנההמבנה מעביר בעת יצירתמעביר בעת יצירתהמשתמש במבנה הנתונים –

הספציפיות פעולותפעולותשמבצעות את המצביעים לפונקציות מצביעים לפונקציות לטיפוס

בדומה לפונקצית השוואה שפונקצית המיון מקבלת–

36

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית גנרית

#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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית גנרית

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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית

/* 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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית

/* 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

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

דוגמא נוספת לשימוש במחסנית גנרית

נניח שהפעם אנחנו רוצים לקלוט מהקלט •פקודותפקודות שמייצגות מחרוזותמחרוזות

80גודל מחרוזת מקסימלי הוא –

את תדפיסתדפיסבסוף קליטת הפקודות התוכנית •בסדר הפוךבסדר הפוךהפקודות

- היא UNDOUNDOאחת הפקודות יכולה להיות •פקודה קודמתפקודה קודמת קליטת מבטלתמבטלת

לא נקלטת ולא מודפסת בסוף UNDOפקודת –התוכנית

50

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

הפתרון של הבעיה הקודמת בעזרת מחסנית גנרית

#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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית

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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית

/* 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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית

/* 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

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

ADTsבסיסיים שנלמדים בקורס

הבאים )כולם מבני הנתונים הבסיסיים מבני הנתונים הבסיסיים בקורס אנחנו לומדים את •( :ADTבצורת

.1.1ListList )רשימה(בין האיבריםקיים סדר קיים סדר –כמה פעמים כמה פעמים במבנה יכול להופיע יכול להופיע כל איבר –

.2.2SetSet )קבוצה(לא מוגדרלא מוגדרבין האיברים הסדרהסדר–פעם אחת בלבד פעם אחת בלבד במבנה יכול להופיע יכול להופיע כל איבר –

.3.3StackStack )מחסנית(LIFOLIFOבין האיברים והוא קיים הסדר קיים הסדר –כמה פעמים כמה פעמים במבנה יכול להופיע יכול להופיע כל איבר –

• GraphGraphקשתותקשתותו צמתיםצמתיםשל אבסטרקציהאבסטרקציהמתאים לבעיות שדורשות 1.

למשל, תיאור ערים וכבישים ביניהם1.

55

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

התאמת מבנה נתונים בסיסי לבעיה

. בפרט, מתאים ביותרמתאים ביותרמבנה נתונים החשוב למצוא את חשוב למצוא את לכל בעיה •יש לשים לב:

בין האבריםסדרסדרל– בין האיבריםכפילויותכפילויותל–

בבחירת מבנה נתונים: המטרותהמטרות•לבעיהייצוג טבעי וברור ייצוג טבעי וברור –

מתעד את עצמומתעד את עצמוקוד קריא המניעת שיכפול קודמניעת שיכפול קוד–

קצר וברורקצר וברורשעובד מול המבנה צריך להיות כמה שיותר הקודהקודמניעת באגיםמניעת באגים–

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

הערה: מטרה נוספת היא סיבוכיות הפעולות עם המבנה. במטרה •במת''מ, אלא בקורס "מבני נתונים"לא מתחשבים לא מתחשבים הזאת

56