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

Slides:



Advertisements
Similar presentations
Senem Kumova Metin Spring2009 STACKS AND QUEUES Chapter 10 in A Book on C.
Advertisements

ממיבחניםC שאלות ++.
תוכנה 1 סמסטר א ' תשע " ב תרגול מס ' 7 * מנשקים, דיאגרמות וביטים * לא בהכרח בסדר הזה.
מבוא למדעי המחשב לתעשייה וניהול
מבוא למדעי המחשב לתעשייה וניהול דוגמאות ותרגול נוסף במערך חד ממדי הרצאה 12.
Exercise 6 : Stack 1.Stack is a data structure that supports LIFO (Last In First Out) operations. - In this exercise, you implement Stack data structures.
טבלאות סמלים נכתב ע"י אלכס קוגן סמסטר חורף, תשס"ח.
Pointers הרצאה קריטית. השאלות הפתוחות מה זה ה- & שמופיע ב scanf מדוע כשמעבירים מחרוזת ל scanf אין צורך ב & האם ניתן להכריז על מערך שגדלו אינו ידוע בתחילת.
 ADT של מבני נתונים  ADT גנריים  בחירת מבני נתונים  שאלה לדוגמה.
ADT של מבני נתונים ADT גנריים בחירת מבני נתונים שאלה לדוגמה
רקורסיות נושאי השיעור פתרון משוואות רקורסיביות שיטת ההצבה
תכנות תרגול 11 שבוע : מבנים מטרת המבנים היא לאפשר למתכנת להגדיר טיפוסי משתנים חדשים אשר מתאימים ספציפית לבעיה שאותה התוכנית פותרת. מטרת המבנים.
תרגול 5 רקורסיות. רקורסיה קריאה של פונקציה לעצמה –באופן ישיר או באופן עקיף היתרון : תכנות של דברים מסובכים נעשה ברור ונוח יותר, מכיוון שזו למעשה צורת.
רקורסיות נושאי השיעור מהן רקורסיות פתרון רקורסיות : שיטת ההצבה שיטת איטרציות שיטת המסטר 14 יוני יוני יוני 1514 יוני יוני יוני 1514.
מבוא לשפת C חידות ונקודות חשובות נכתב על-ידי יורי פקלני. © כל הזכויות שמורות לטכניון – מכון טכנולוגי לישראל.
11 Introduction to Programming in C תרגול
מבוא למדעי המחשב תרגול 8 - מחרוזות שעת קבלה : יום שני 11:00-12:00 דוא " ל :
11 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
תרגול חזרה. מבנה האובייקט תאר את מבנה האובייקט כולל מבנה טבלאות הפונקציות הוירטואליות עבור התכנית הבאה struct A { int x; virtual void a() {}; }; struct.
תכנות תרגול 6 שבוע : תרגיל שורש של מספר מחושב לפי הסדרה הבאה : root 0 = 1 root n = root n-1 + a / root n-1 2 כאשר האיבר ה n של הסדרה הוא קירוב.
11 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
תכנות תרגול 6 שבוע : הגדרת פונקציות return-value-type function-name(parameter1, parameter2, …) הגדרת סוג הערכים שהפונקציה מחזירה שם הפונקציהרשימת.
Backpatching 1. תזכורת מתרגול קודם קוד ביניים - שפת הרביעיות שיטות לייצור קוד ביניים –שימוש בתכונת code –כתיבה ישירה ל-buffer של פקודות שיטות לתרגום מבני.
תכנות תרגול 14 שבוע:
תכנות תרגול 10 שבוע : הקשר בין מערכים למצביעים נרצה לעמוד על הקשר בין מערך למצביע מאחר ומערכים הם הכללה של משתנים הרי שברור שלמערך ולכל אחד מאיבריו.
תכנות תרגול 14 שבוע : רשימות מקושרות ישנו מבנה נתונים אשר מאפשר ישנו מבנה נתונים אשר מאפשר לנו לבצע את הוספת האיברים בצורה נוחה יותר. מבנה זה.
מבוא כללי למדעי המחשב תרגול 3. לולאות while לולאות while while (condition) { loop body } במקרה של קיום התנאי מתבצע גוף הלולאה ברגע שהתנאי לא מתקיים נצא.
תרגול 5 דוגמא של ADT: מחסנית מצביעים לפונקציות תכנות גנרי דוגמא של ADT גנרי : מחסנית גנרית.
קורס תכנות – סימסטר ב ' תשס " ח שיעור שישי: מערכים
מבוא למדעי המחשב תרגול 6 - מערכים שעת קבלה : יום שני 11:00-12:00 דוא " ל :
תכנות תרגול 5 שבוע : הגדרת פונקציות return-value-type function-name(parameter1, parameter2, …) הגדרת סוג הערכים שהפונקציה מחזירה שם הפונקציהרשימת.
מערכים עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר int grade1, grade2, …, grade20; int grade1, grade2, …, grade20;
עקרון ההכלה וההדחה.
1 ADT Abstract Data Types The Stack Example. 2 ADT יוצגו שלושה פתרונות לבעיה זו : פתרון ישיר ופשוט - נועד להמחשת הבעיה. פתרון אשר נעזר ב ADT של מחסנית.
תכנות מונחה עצמים Object Oriented Programming (OOP) אתגר מחזור ב' Templates תבניות.
מבוא למדעי המחשב תרגול 3 שעת קבלה : יום שני 11:00-12:00 דוא " ל :
Last time on Clang משתנה: "פתק" המשמש את המחשב לשמירת מידע. לכל משתנה יש שם וטיפוס כללים לשמות משתנים –חייבים להכיל רק אותיות, מספרים ו '_' –חייבים להתחיל.
1 מבוא למדעי המחשב סיבוכיות. 2 סיבוכיות - מוטיבציה סידרת פיבונאצ'י: long fibonacci (int n) { if (n == 1 || n == 2) return 1; else return (fibonacci(n-1)
תכנות תרגול 12 שבוע : מבנים מטרת המבנים היא לאפשר למתכנת להגדיר טיפוסי משתנים חדשים אשר מתאימים ספציפית לבעיה שאותה התוכנית פותרת. מטרת המבנים.
1 מבוא למדעי המחשב backtracking. 2 מוטיבציה בעיית n המלכות: נתון: לוח שחמט בגודל. המטרה: לסדר על הלוח n מלכות כך שאף אחת לא תאיים על השנייה. דוגמא: עבור.
מבוא למדעי המחשב תרגול 5 שעת קבלה : יום שני 11:00-12:00 דוא " ל :
11 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
Structure. מה לומדים היום ? דרך לבנות מבנה נתונים בסיסי – Structure מייצר " טיפוס " חדש מתאים כאשר רוצים לאגד כמה משתנים יחד דוגמאות : עובד : שם, טלפון,
1 מבוא למדעי המחשב הרצאה 21: Queue, Iterator & Iterable.
מבוא למדעי המחשב לתעשייה וניהול הרצאה 7. סברוטינות subroutines.
מחסנית ותור Stacks and Queues. מחסנית Stack מחסנית - Stack ADT סוג של מערך מוגבל מהיר מאוד ותופס מעט זיכרון שימוש ב LIFO – LIFO (Last In, First Out)
מבנה נתונים ואלגוריתמים ) לשעבר - עיבוד מידע( ד"ר אבי רוזנפלד ד"ר אריאלה ריכרדסון.
מבוא למדעי המחשב הרצאה 7: מבנים מבוסס על השקפים שנערכו שי ארצי, גיתית רוקנשטיין, איתן אביאור, וסאהר אסמיר, מיכאל אלעד, רון קימל וניר אילון עדכון אחרון.
קורס תכנות שיעור עשירי: מיונים, חיפושים, וקצת סיבוכיות חישוב.
תכנות מכוון עצמים ושפת ++C וויסאם חלילי. TODAY TOPICS: 1. Function Overloading & Default Parameters 2. Arguments By Reference 3. Multiple #include’s 4.
מבוא למדעי המחשב לתעשייה וניהול הרצאה 12. ספריות.
מחסנית ותור Stacks and Queues. מחסנית Stack מחסנית - Stack ADT סוג של מערך מוגבל מהיר מאוד ותופס מעט זיכרון שימוש ב LIFO – LIFO (Last In, First Out)
מבנים קרן כליף. ביחידה זו נלמד :  מהו מבנה (struct)  איתחול מבנה  השמת מבנים  השוואת מבנים  העברת מבנה לפונקציה  מבנה בתוך מבנה  מערך של מבנים.
מבוא למדעי המחשב לתעשייה וניהול הרצאה 6. מפעל השעווה – לולאות  עד עכשיו  טיפלנו בייצור נרות מסוג אחד, במחיר אחיד  למדנו להתמודד עם טיפול במקרים שונים.
מבנה נתונים ואלגוריתמים ) לשעבר - עיבוד מידע( ד"ר אבי רוזנפלד ד"ר אריאלה ריכרדסון.
עקרונות תכנות מונחה עצמים תרגול 11: OOP in C++. Outline  Where do the objects live ?  Inheritance  Slicing  Overriding vs Shadowing.
Programming Arrays.
מבני נתונים רשימה מקושרת, מחסנית ותור
Computer Architecture and Assembly Language
מבוא למדעי המחשב סיבוכיות.
תירגול 14: מבני נתונים דינאמיים
הרצאה 06 רשימות מקושרות קרן כליף.
ממשקים - interfaces איך לאפשר "הורשה מרובה".
בניית מחסנית סטטית Static Stack Implementation מורים מובילים תשע"ה
תוכנה 1 תרגול 13 – סיכום.
ADT גנריים הידור של מספר קבצים Makefile שאלה לדוגמה
מחסנית ותור Stacks and Queues.
שיעור עשירי: מיונים, חיפושים, וקצת סיבוכיות חישוב
Computer Programming תרגול 3 Summer 2016
Engineering Programming A
Presentation transcript:

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

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

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

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

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

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

מחסנית - Stack מבנה נתונים שמירת איבריםמבנה נתונים המאפשר שמירת איברים, כאשר להוציא רק את איבר האחרון –בכל רגע נתון ניתן להוציא רק את איבר האחרון שהוכנס (Last In First Out) לגשת רק לאיבר האחרון –ניתן לגשת רק לאיבר האחרון הדגמת העבודה עם המחסנית : המבנה תומך בפעולות הבאות : push הוסף – push - הוסף איבר למחסנית. pop הוצא – pop - הוצא את האיבר האחרון שהוכנס למחסנית ( מבלי להחזיר את ערכו ). top החזר את ערכו – top - החזר את ערכו של האיבר האחרון שהוכנס למחסנית ( מבלי להוציא אותו מהמחסנית ) 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

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

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

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

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

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

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

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

הפתרון של הבעיה הקודמת בעזרת מחסנית #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

הפתרון של הבעיה הקודמת בעזרת מחסנית /* 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-documentingהקוד מתעד את עצמו (self-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); /* */ sort(arr, 5, bigger2); /* */ return 0; } int main(){ int arr[] = { 1, -3, 9, -10, -5 }; sort(arr, 5, bigger); /* */ sort(arr, 5, bigger2); /* */ return 0; } 29

פונקצית מיון גנרית נרחיב עצמים מכל טיפוסנרחיב את פונקצית המיון למיין עצמים מכל טיפוס שהוא עצמים מטיפוסים שונים פונקציה גנריתפונקציה שיכולה לעבד עצמים מטיפוסים שונים נקראת פונקציה גנרית למנוע שיכפול קודהמטרה של פונקציות גנריות היא למנוע שיכפול קוד אותו קוד טיפוסים שונים –להימנע מכתיבת אותו קוד עבור טיפוסים שונים פונקציות גנריות מבצעות את העבודה שלהם בעזרת : –מצביעים ל - void עצמים כללים –מצביעים ל - void לייצוג עצמים כללים שהפונקציה עובדת איתם –מצביעים לפונקציות פעולות –מצביעים לפונקציות לייצוג פעולות על העצמים 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 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 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 FEB MAY JAN FEB MAY

מבנה נתונים ( ממומש כ -ADT) גנרי The stack example generic 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 #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 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 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 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 #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 תדפיס בסדר הפוךבסוף קליטת הפקודות התוכנית תדפיס את הפקודות בסדר הפוך UNDO מבטלת פקודה קודמתאחת הפקודות יכולה להיות UNDO - היא מבטלת קליטת פקודה קודמת –פקודת UNDO לא נקלטת ולא מודפסת בסוף התוכנית 50

הפתרון של הבעיה הקודמת בעזרת מחסנית גנרית #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

הפתרון של הבעיה הקודמת בעזרת מחסנית 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.List 1.List ( רשימה ) –קיים סדר –קיים סדר בין האיברים יכול להופיע כמה פעמים –כל איבר יכול להופיע במבנה כמה פעמים 2.Set 2.Set ( קבוצה ) –הסדר לא מוגדר –הסדר בין האיברים לא מוגדר יכול להופיע פעם אחת בלבד –כל איבר יכול להופיע במבנה פעם אחת בלבד 3.Stack 3.Stack ( מחסנית ) –קיים הסדר LIFO –קיים הסדר בין האיברים והוא LIFO יכול להופיע כמה פעמים –כל איבר יכול להופיע במבנה כמה פעמים 4. Graph אבסטרקציה צמתים קשתות –מתאים לבעיות שדורשות אבסטרקציה של צמתים וקשתות  למשל, תיאור ערים וכבישים ביניהם 55

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