הרצאה 06 רשימות מקושרות קרן כליף.

Slides:



Advertisements
Similar presentations
ממיבחניםC שאלות ++.
Advertisements

מבוא למדעי המחשב לתעשייה וניהול
©Silberschatz, Korth and Sudarshan4.1Database System Concepts סכימה לדוגמא.
 ADT של מבני נתונים  ADT גנריים  בחירת מבני נתונים  שאלה לדוגמה.
1 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים.
רקורסיות נושאי השיעור פתרון משוואות רקורסיביות שיטת ההצבה
רשימה מקושרת Linked Lists. דוגמא STRING איך עושים Dim x as String בלי לדעת מראש את הגודל !
תכנות תרגול 11 שבוע : מבנים מטרת המבנים היא לאפשר למתכנת להגדיר טיפוסי משתנים חדשים אשר מתאימים ספציפית לבעיה שאותה התוכנית פותרת. מטרת המבנים.
תכנות תרגול 6 שבוע : חישוב e זוהי הנוסחא לחישוב e נראה כיצד לתרגם אותה לפונקציה n n.
מבוא לשפת C חידות ונקודות חשובות נכתב על-ידי יורי פקלני. © כל הזכויות שמורות לטכניון – מכון טכנולוגי לישראל.
מבוא למדעי המחשב תרגול 8 - מחרוזות שעת קבלה : יום שני 11:00-12:00 דוא " ל :
- אמיר רובינשטיין Union-Find 1. הגדרה: מבנה נתונים, אשר בהינתן אוסף איברים המחולקים לקבוצות זרות, מאפשר ביצוע הפעולות הבאות: Find(i) – החזר.
Map-Reduce Input: a collection of scientific articles on different topics, each marked with a field of science –Mathematics, Computer Science, Biology,
רשימות. רשימה משורשרת typedef struct link{ int data; struct link * next; }link;
תכנות תרגול 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 תרגול
שימוש במערך דינמי : ArrayList. מאפיינים חשובים בכל LIST יכולת להכניס מידע בלי תלות בטיפוס יכולת למחוק מידע יכולת להוסיף מידע פונקציות נוספות ( מיון, חיפוש.
תכנות תרגול 6 שבוע : הגדרת פונקציות return-value-type function-name(parameter1, parameter2, …) הגדרת סוג הערכים שהפונקציה מחזירה שם הפונקציהרשימת.
תכנות – שיעור 7. חזרה -מערכים נגדיר בעזרתו קבוצת משתנים כאשר יהיה לנו מספר רב של משתנים זהים נגדיר בעזרתו קבוצת משתנים כאשר יהיה לנו מספר רב של משתנים.
תכנות תרגול 14 שבוע:
תכנות תרגול 14 שבוע : רשימות מקושרות ישנו מבנה נתונים אשר מאפשר ישנו מבנה נתונים אשר מאפשר לנו לבצע את הוספת האיברים בצורה נוחה יותר. מבנה זה.
קורס תכנות – סימסטר ב ' תשס " ח שיעור שישי: מערכים
תכנות תרגול 12 שבוע : הקצאת זיכרון דינאמית הזיכרון המקסימאלי ששימש את התוכנית שלנו עד היום היה קבוע מראש. לפני הרצת התוכנית, לאחר שהתוכנית עברה.
מבוא כללי למדעי המחשב רשימות מקושרות
Data Structures, CS, TAU, Perfect Hashing 1 Perfect Hashing בעיה : נתונה קבוצה S של n מפתחות מתחום U השוואה ל - Hash : * טבלה קבועה (Hash רגיל - דינאמי.
תכנות תרגול 5 שבוע : הגדרת פונקציות return-value-type function-name(parameter1, parameter2, …) הגדרת סוג הערכים שהפונקציה מחזירה שם הפונקציהרשימת.
1 Data Structures, CS, TAU, Perfect Hashing בעיה: נתונה קבוצה S של n מפתחות מתחום U השוואה ל- Hash : * טבלה קבועה (Hash רגיל - דינאמי) * רוצים זמן קבוע.
מערכים עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר int grade1, grade2, …, grade20; int grade1, grade2, …, grade20;
עקרון ההכלה וההדחה.
תכנות מונחה עצמים Object Oriented Programming (OOP) אתגר מחזור ב' Templates תבניות.
1 מבוא למדעי המחשב סיבוכיות. 2 סיבוכיות - מוטיבציה סידרת פיבונאצ'י: long fibonacci (int n) { if (n == 1 || n == 2) return 1; else return (fibonacci(n-1)
תכנות תרגול 12 שבוע : מבנים מטרת המבנים היא לאפשר למתכנת להגדיר טיפוסי משתנים חדשים אשר מתאימים ספציפית לבעיה שאותה התוכנית פותרת. מטרת המבנים.
1 Formal Specifications for Complex Systems (236368) Tutorial #3 Z introduction and notation (contd.); Birthday book example (Chapter 1 in the book)
מבוא למדעי המחשב תרגול 12 – הקצאת זיכרון דינאמית שעת קבלה : יום שני 11:00-12:00 דוא " ל :
בתרגול הקודם כללי הרשאות (Visibility modifiers) בהורשה – Public – Protected – private חוקי גישה לשדות ושיטות בהורשה ב -Java מחלקות אבסטרקטיות –המילה השמורה.
1 מבוא למדעי המחשב הרצאה 21: Queue, Iterator & Iterable.
מחסנית ותור Stacks and Queues. מחסנית Stack מחסנית - Stack ADT סוג של מערך מוגבל מהיר מאוד ותופס מעט זיכרון שימוש ב LIFO – LIFO (Last In, First Out)
Void*, pointer to functions, variadic functions קרן כליף.
Practice session 6 Sequence Operations Partial Evaluation Lazy Lists.
סיביות קרן כליף. © Keren Kalif 2 ביחידה זו נלמד:  מוטיבציה  אופרטורים לעבודה עם סיביות:  &  |  ^  ~  >> 
מחסנית ותור Stacks and Queues. מחסנית Stack מחסנית - Stack ADT סוג של מערך מוגבל מהיר מאוד ותופס מעט זיכרון שימוש ב LIFO – LIFO (Last In, First Out)
מבנים קרן כליף. ביחידה זו נלמד :  מהו מבנה (struct)  איתחול מבנה  השמת מבנים  השוואת מבנים  העברת מבנה לפונקציה  מבנה בתוך מבנה  מערך של מבנים.
מבנה נתונים או טיפוס נתונים מופשט חלק ב – פעולות על רשימה הוכן ע " י ולרי פקר דצמבר 2015.
Combo Box שלושה סוגים של Combo Box: Style 0 (default) - drop-down combo box המשתמש יכול להוסיף אפשרויות לרשימה או ללחוץ על החץ לבחירה מרשימת האפשרויות.
1 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
מספרים אקראיים ניתן לייצר מספרים אקראיים ע"י הפונקציה int rand(void);
Programming Arrays.
מבני נתונים רשימה מקושרת, מחסנית ותור
מבוא למדעי המחשב לתעשייה וניהול
Computer Architecture and Assembly Language
הרצאה 10 פונקציות עם מספר משתנה של פרמטרים
מבוא למדעי המחשב סיבוכיות.
הקצאות דינאמיות בשילוב מבנים
מיונים וחיפושים קרן כליף.
מצביעים קרן כליף.
מערכים קרן כליף.
תירגול 14: מבני נתונים דינאמיים
תכנות מכוון עצמים ושפת JAVA
הרצאה 07 עצים קרן כליף.
הקצאות דינאמיות קרן כליף.
מבנים קרן כליף.
מצביעים קרן כליף.
ניתוח זמן ריצה (על קצה המזלג)
מערכים ומטריצות קרן כליף.
Engineering Programming A
שאלה 1.
מחסנית ותור Stacks and Queues.
שיעור עשירי: מיונים, חיפושים, וקצת סיבוכיות חישוב
מבוא לתכנות ב- Java תרגול 10 - רשימות מקושרות.
Presentation transcript:

הרצאה 06 רשימות מקושרות קרן כליף

ביחידה זו נלמד: מהי רשימה מקושרת פונקציות של רשימות מקושרות מימושים רקורסיביים לפונקציות של רשימות מקושרות ההבדל בין מערך לרשימה וריאציות של רשימות מקושרות © Keren Kalif

מבנה נתונים מבנה נתונים הוא אוסף המאפשר לנו להחזיק יותר מאיבר אחד למשל: מערך קיימים מבני נתונים נוספים שלכל אחד יש את היתרונות והחסרונות שלו, ואלו ישפיעו על בחירת שימוש המבנה נתונים אחד או אחר היתרונות של מערך: גישה ישירה לאיבר הוספה בקלות לסוף המערך החסרונות של מערך: הסרה/הוספה לאמצע מורכבת גודל מוגבל © Keren Kalif

רשימה מקושרת זהו מבנה נתונים המאפשר הוספה דינאמית של איברים לכל מקום באוסף בקלות אין צורך להחליט מראש כמה איברים יהיו ברשימה הרעיון הוא יצירת איבר וקישורו למקום המתאים ברשימה בכל רגע נתון כל איבר ברשימה מקושרת הוא מבנה המכיל נתון והצבעה לאיבר הבא האיבר האחרון ברשימה יצביע ל- NULL בניגוד למערך, האיברים אינם ברצף בזיכרון typedef int type; typedef struct LNode } type data; struct LNode* next; } LNode; 4 9 6 typedef struct List } struct LNode* head; } List; © Keren Kalif

דוגמאת הוספת ערכים לרשימה lst head 1 ??? 2 2 void main() { List lst; lst.head = (LNode*)calloc(1, sizeof(LNode)); lst.head->data = 1; lst.head->next = (LNode*)calloc(1, sizeof(LNode)); lst.head->next->data = 2; } © Keren Kalif

פונקציה המחשבת את כמות הצמתים ברשימה int getListLength(const List* lst) { int count = 0; LNode* temp = lst->head; while (temp != NULL) count++; temp = temp->next; } return count; count = 0 count = 1 count = 2 temp lst head 1 ??? 2 2 © Keren Kalif

פונקציה המדפיסה את איברי הרשימה void printList(const List* lst) { LNode* temp = lst->head; while (temp != NULL) printf("%d ", temp->data); temp = temp->next; } 1 2 1 temp lst head 1 ??? 2 2 © Keren Kalif

פונקציה המשחררת את איברי הרשימה void freeList(List* lst) { LNode* current = lst->head; LNode* next; while (current) next = current->next; free(current); current = next; } lst->head = NULL; current next lst head 1 ??? 2 2 © Keren Kalif

שדרוג הרשימה עד כה החזקנו בתוך המבנה List מצביע לראש הרשימה, והוספת איבריו הייתה באמצעותו: void main() { List lst; lst.head = (LNode*)calloc(1, sizeof(LNode)); lst.head->data = 1; lst.head->next = (LNode*)calloc(1, sizeof(LNode)); lst.head->next->data = 2; lst.head->next->next = (LNode*)calloc(1, sizeof(LNode)); lst.head->next->next->data = 3; freeList(&lst); } © Keren Kalif

שדרוג הרשימה כדי להקל על הוספת איברים לסוף הרשימה נשדרג את המבנה List כך שיכיל גם מצביע לאיבר האחרון: void main() { List lst; lst.head = (LNode*)calloc(1, sizeof(LNode)); lst.head->data = 1; lst.tail = lst.head; lst.tail->next = (LNode*)calloc(1, sizeof(LNode)); lst.tail->next->data = 2; lst.tail = lst.tail->next; lst.tail->next->data = 3; freeList(&lst); } typedef struct List } struct LNode *head, *tail; } List; ניתן לראות שכעת הקוד של הוספת איבר לסוף הרשימה זהה, ובפרט חוסך לולאה המטיילת לאיבר האחרון, ולכן יעילות הפעולה היא (1)O lst 3 1 head 2 tail © Keren Kalif

פונקציה המאתחלת רשימה ריקה פונקציה זו מאתחלת בשדות ה- head וה- tail את הערך NULL List makeEmptyList() { List lst; lst.head = lst.tail = NULL; return lst; } © Keren Kalif

פונקציה הבודקת האם רשימה ריקה int isEmpty(const List* lst) { return lst->head == NULL; } © Keren Kalif

פונקציה שיוצרת איבר להכנסה לרשימה הפונקציה תקבל את הערך שיהיה באיבר, ומצביע לאיבר הבא: פונקציה זו תשמש אותנו בפונקציות הבאות LNode* createNewNode(type newData, LNode* next) { LNode* newNode = (Node*)calloc(1], sizeof(LNode)); newNode->data = newData; newNode->next = next; return newNode; } © Keren Kalif

הוספת ערך לראש הרשימה void insertValueToHead(List* lst, type newData) { LNode* newNode = createNewNode(newData, lst->head); if (isEmpty(lst)) lst->head = lst->tail = newNode; else lst->head = newNode; } newData = 4 3 2 lst head tail 4 newNode © Keren Kalif

הוספת ערך לראש הרשימה (שהפעם ריקה) void insertValueToHead(List* lst, type newData) { LNode* newNode = createNewNode(newData, lst->head); if (isEmpty(lst)) lst->head = lst->tail = newNode; else lst->head = newNode; } newData = 4 lst head tail 4 newNode © Keren Kalif

הוספת ערך לסוף הרשימה void insertValueToTail(List* lst, type newData) { LNode* newNode = createNewNode(newData, NULL); if (isEmpty(lst)) lst->head = lst->tail = newNode; else lst->tail->next = newNode; lst->tail = newNode; } 3 2 lst newData = 4 head tail 4 newNode © Keren Kalif

הוספת ערך לסוף הרשימה (שהפעם ריקה) void insertValueToTail(List* lst, type newData) { LNode* newNode = createNewNode(newData, NULL); if (isEmpty(lst)) lst->head = lst->tail = newNode; else lst->tail->next = newNode; lst->tail = newNode; } lst newData = 4 head tail 4 newNode © Keren Kalif

הוספת איבר לסוף הרשימה void insertNodeToTail(List* lst, LNode* newNode) { if (isEmpty(lst)) lst->head = lst->tail = newNode; else lst->tail->next = newNode; lst->tail = newNode; } © Keren Kalif

דוגמאת החברים © Keren Kalif

דוגמא: פיצול רשימה לזוגיים ואי-זוגיים void main() { List lst = makeEmptyList(); List lstEven, lstOdd; int i; for (i=1 ; i <= 10 ; i++) insertValueToTail(&lst, i); splitListToEvenAndOdd(&lst, &lstEven, &lstOdd); printf("There are %d even nodes: ", getListLength(&lstEven)); printList(&lstEven); printf("\n"); printf("There are %d odd nodes: ", getListLength(&lstOdd)); printList(&lstOdd); freeList(&lstEven); freeList(&lstOdd); } © Keren Kalif

דוגמא: פיצול רשימה לזוגיים ואי-זוגיים (2) דוגמא: פיצול רשימה לזוגיים ואי-זוגיים (2) 3 void splitListToEvenAndOdd(List* src, List* even, List* odd) { LNode* current = src->head; LNode* next; *even = makeEmptyList(); *odd = makeEmptyList(); while (current) next = current->next; if (current->data%2 == 0) insertNodeToTail(even, current); else insertNodeToTail(odd, current); current->next = NULL; current = next; } 1 2 src head tail even head tail current next odd head tail פונקציה זו הורסת את הרשימה המקורית. כדי לשמור עליה היה מריך להעתיק קודם את רשימת המקור. © Keren Kalif

העתקת רשימה List copyList(const List* lst) { List res = makeEmptyList(); LNode* temp = lst->head; while (temp) insertValueToTail(&res, temp->data); temp = temp->next; } return res; © Keren Kalif

הרעיון מאחורי הוספת ערך לאמצע רשימה דוגמא: הוספת הערך 8 אחרי הערך 9 ראשית נייצר איבר חדש נחבר את האיבר החדש לאיבר שאמור להיות אחריו נחבר לאיבר החדש את האיבר שלפניו 4 9 6 8 © Keren Kalif

הוספת איבר לאמצע הרשימה (אחרי ערך מסוים) void insertAfterValue(List* lst, type insertAfter, type newValue) { LNode* temp = lst->head; while (temp && temp->data != insertAfter) temp = temp->next; if (temp) LNode* newNode = (LNode*)malloc(sizeof(LNode)); newNode->data = newValue; newNode->next = temp->next; temp->next = newNode; הוספה לאחר איבר שלא קיים - לא תבוצע 2 9 6 insertAfter = 9 newValue = 8 head temp temp 8 newNode © Keren Kalif

5 2 9 מחיקת איבר void removeFirstValueOf(List* lst, type toRemove) { LNode* prev = lst->head; LNode* temp = lst->head; while (temp && temp->data != toRemove) prev = temp; temp = temp->next; prev->next = temp->next; free(temp); 5 toRemove = 9 prev 2 9 head temp temp © Keren Kalif

2 9 6 חיפוש ערך LNode* findValue(List* lst, type lookFor) { LNode* temp = lst->head; while (temp) if (temp->data == lookFor) return temp; temp = temp->next; return NULL; } lookFor = 9 2 9 6 head temp temp © Keren Kalif

2 4 1 7 2 דוגמא true false true void main() { List list = makeEmptyList(); LNode* found; printf("Is Empty? %s\n", isEmpty(&list) ? "true" : "false"); insertValueToHead(&list, 4); insertValueToHead(&list, 7); insertValueToTail(&list, 1); insertAfterValue(&list, 4, 2); insertAfterValue(&list, 8, 9); // doesn't add.. insertAfterValue(&list, 1, 2); removeFirstValueOf(&list, 2); found = findValue(&list, 4); found = findValue(&list, 10); printList(&list); printf(“\nIs Empty? %s\n", isEmpty(&list) ? "true" : "false"); freeList(&list); דוגמא 2 true 4 head 1 7 2 false true © Keren Kalif

מימושים רקורסיביים – שחרור רשימה void freeListRec(List* lst) { freeListHelper(lst->head); lst->head = NULL; lst->tail = NULL; } void freeListHelper(LNode* head) { if (head == NULL) return; freeListHelper(head->next); free(head); } © Keren Kalif

מימושים רקורסיביים – הדפסת רשימה void printListRec(List* lst) { printListHelper(lst->head); } void printListHelper(LNode* head) { if (head == NULL) printf("\n"); return; } printf("%d ", head->data); printListHelper(head->next); © Keren Kalif

מימושים רקורסיביים – חיפוש איבר LNode* findValueRec(List* lst, type lookFor) { return findValueRec(lst->head, lookFor); } LNode* findValueHelper(LNode* head, type lookFor) { if (head == NULL) return NULL; if (head->data == lookFor) return head; return findValueRec(head->next, lookFor); } © Keren Kalif

מימושים רקורסיביים – אורך רשימה int getListLengthRec(List* lst) { return getListLengthHelper(lst->head); } int getListLengthHelper(LNode* head) { if (head == NULL) return 0; return 1 + getListLengthHelper(head->next); } © Keren Kalif

דוגמאת ניהול הזכרון © Keren Kalif

וריאציות של רשימה מקושרת עבודה עם dummy head: בעת הוספה/הסרה וכד' חוסך בדיקה האם האיבר הוא הראשון רשימה דו-כיוונית: יעיל עבור טיול דו כיווני, מאפשר לא לשמור את המשתנה prev בכל מקום בו צריך לשמור הפניה לאיבר הקודם (למשל במחיקה) מאפשר גישה מיידית לאיבר קודם מקל על פעולת החלפה של 2 איברים רשימה מעגלית האיבר האחרון מצביע לראשון © Keren Kalif

יתרונות/חסרונות לשימוש ברשימה מקושרת יתרונות: ניתן להוסיף בקלות איברים לכל מקום באוסף ניתן להסיר איברים בקלות חסרונות: אין גישה ישירה לאיבר שימוש בהקצאה דינאמית עבור כל איבר חדש נשתמש כאשר הפעולות העיקריות על האוסף יהיו הוספה להתחלה, לאמצע, הסרה © Keren Kalif

ביחידה זו למדנו: מהי רשימה מקושרת פונקציות של רשימות מקושרות מימושים רקורסיביים לפונקציות של רשימות מקושרות ההבדל בין מערך לרשימה וריאציות של רשימות מקושרות © Keren Kalif