קורס תכנות שיעור 13: רשימות מקושרות.

Slides:



Advertisements
Similar presentations
Linked List Alternate approach to maintaining an array of elements Rather than allocating one large group of elements, allocate elements as needed Q: how.
Advertisements

Inserting a Node into a Specified Position of a Linked List To create a node for the new item newNode = new Node(item); To insert a node between two nodes.
Linked Lists.
Linked Lists CSE 2451 Matt Boggus. Dynamic memory reminder Allocate memory during run-time malloc() and calloc() – return a void pointer to memory or.
LIST PROCESSING.
Computer Programming for Engineering Applications ECE 175 Intro to Programming.
Linked List Variations
CSCI2100B Linked List Jeffrey
Data Structure Lecture-5
Doubly-linked list library.
Data Structures: Doubly Linked List1 Doubly linked list l The linear linked list is accessed from the first node each time we want to insert or delete.
David Weinberg presents Linked Lists: The Background  Linked Lists are similar to ArrayLists in their appearance and method of manipulation  They do.
C Intro.
Chapter 17 Linked List Saurav Karmakar Spring 2007.
Computer Programming Link List (Insertion, Printing and Deletion functions) Lecture 23.
C Programming : Elementary Data Structures 2009/04/22 Jaemin
Linked List Improvements & Memory. BigO's What is BigO for our basic linked list operations? InsertStart Insert at middle InsertEnd Retrieve First Value.
Introduction to C Programming CE Lecture 20 Insertion and Deletion with Linear Linked Lists.
Reference: Vinu V Das, Principles of Data Structures using C and C++
Lists 1. Introduction Data: A finite sequence of data items. Operations: Construction: Create an empty list Empty: Check if list is empty Insert: Add.
© M. Gross, ETH Zürich, 2014 Informatik I für D-MAVT (FS 2014) Exercise 11 – Data Structures.
1 Objectives of these slides: to describe linked lists in C 6 – Lists.
Computer Programming for Engineering Applications ECE 175 Intro to Programming.
Linked Lists. Array List Issues Painful insert/remove at start/middle.
LINKED LIST’S EXAMPLES Salim Malakouti. Linked List? 523 Pointer Node ValuePointer.
CS-2852 Data Structures LECTURE 5 Andrew J. Wozniewicz Image copyright © 2010 andyjphoto.com.
Programming Linked Lists. Collections Store collection of data  Online store - Items  University – Students  Library – books Until now we used arrays.
ENEE150 – 0102 ANDREW GOFFIN Dynamic Memory. Dynamic vs Static Allocation Dynamic  On the heap  Amount of memory chosen at runtime  Can change allocated.
Doubly Linked List Exercises Sometimes it is useful to have a linked list with pointers to both the next and previous nodes. This is called a doubly linked.
Linked Lists and Generics Written by J.J. Shepherd.
Node Declaration and Example typedef struct nodeT { int key; struct nodeT *left, *right; } nodeT, *treeT;
CSC 143 P 1 CSC 143 Recursion [Chapter 5]. CSC 143 P 2 Recursion  A recursive definition is one which is defined in terms of itself  Example:  Compound.
Binary trees יום ראשון 08 אוקטובר 2017
Dynamic Allocation Review Structure and list processing
Linked List :: Basic Concepts
UNIT – I Linked Lists.
Linked List.
Doubly Linked List Review - We are writing this code
UNIT-3 LINKED LIST.
Data Structures and Algorithms
Problems with dynamic arrays
Linked lists.
Data Structures 7th Week
Linked Lists.
Lists.
Linked List Sudeshna Sarkar.
Programmazione I a.a. 2017/2018.
Dynamic memory allocation in C and C++
Lists.
קורס תכנות שיעור עשירי: מיונים, חיפושים, קצת ניתוח זמני ריצה, קצת תיקון טעויות ועוד על רשימות.
קורס תכנות שיעור 14: הסוף.
Linked Lists Chris Wright Winter 2006.
Chapter 16-2 Linked Structures
Dummy Nodes, Doubly Linked Lists and Circular Linked Lists
Yung-Hsiang Lu Purdue University
Linked Lists (continued)
Programming Linked Lists.
Data Structures and Algorithms
LINKED LIST.
Linked Lists Adapted from Dr. Mary Eberlein, UT Austin.
ECE 103 Engineering Programming Chapter 63 Queue Implementation
프로그래밍2 및 실습 Sort Code 전명중.
Dynamic memory allocation in C and C++
General List.
Linked Lists.
Queues: Implemented using Linked Lists
Linked List Improvements
Linked lists.
Linked Lists.
Dynamic Data Structures
Presentation transcript:

קורס תכנות שיעור 13: רשימות מקושרות

היום מהי רשימה חלופות מימוש: יתרונות וחסרונות רשימה מקושרת מימוש רשימה מקושרת

מהי רשימה רשימה היא אוסף סדור של ערכים פעולות: הוספה של ערך מחיקה של ערך גישה לערך במקום ה-i ...

מערך הוא רשימה? לא! מערך הוא מימוש אפשרי אחד של רשימה יתרונות: גישה נוחה לערך במקום ה-i הוספה/מחיקה של ערך בסוף הרשימה חסרונות: גודל קבוע הוספה/מחיקה של ערך שלא בסוף הרשימה ייתכן בזבוז זיכרון בזבוז זיכרון אם מחזיקים מערך גדול יותר ממספר הערכים שמשתמשים בפועל

מערך דינאמי גם מערך דינאמי הוא מימוש אפשרי של רשימה פותר את בעיית הגודל הקבוע הוספת/מחיקת ערך עדיין לא יעיל. עדיין ייתכן בזבוז זיכרון

רשימה מקושרת מימוש אפשרי נוסף יתרונות חסרונות צריכת זיכרון פרופורציונאלית למספר האברים ברשימה הוספה/מחיקה נוחה של אברים משני קצוות הרשימה הוספה/מחיקה נוחה לאחר אבר ספציפי ברשימה חסרונות אין גישה ישירה לאבר ה-i

אילוסטרציה רשימה מקושרת מערך 3 7 5 9 3 5 7 9

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

דוגמה: רשימה של מספרים שלמים כל חוליה בשרשרת תמומש בעזרת מבנה המכיל את המידע (מספר שלם) מצביע לחוליה הבאה בשרשרת נשתמש במבנה לצורך הגדרת חוליה ברשימה typedef struct node { int data; struct node *next; } node_t;

החזקת רשימה נחזיק רשימה על ידי שמירת מצביע לחוליה הראשונה int main() { node_t *head = ...; ... } מצביע ל"ראש" הרשימה (המבנה הראשון)

פעולות על רשימות מעבר על הרשימה הוספת איבר מחיקת איבר מחיקת רשימה שלמה מספר איברים, חיפוש, ... הוספת איבר בתחילת הרשימה, בסופה, במקום כלשהו מחיקת איבר מחיקת רשימה שלמה

רשימה של מספרים נקלוט מהמשתמש רשימה של מספרים אי-שליליים נאחסן את הערכים ברשימה מקושרת בכל שלב נקלוט ערך מהמשתמש ונוסיף אבר לרשימה המכיל ערך זה בתחילה הרשימה ריקה

הוספת איבר בהתחלה* ניצור איבר חדש נדאג לכך ש האיבר החדש יצביע לראש הרשימה המקורית ראש הרשימה יהיה האיבר החדש *הוספה באמצע ובסוף בהמשך 7 3 5 9

הוספת איבר לרשימה יצירת אבר חדש החוליה החדשה תצביע לראש הרשימה int main() { int value = 0; node_t *list = NULL, *new_node = NULL; printf("enter values (negative to stop)\n"); scanf("%d", &value); while (value >= 0) { new_node = (node_t*) malloc(sizeof(node_t)); if (new_node == NULL) { printf("Fatal error: memory allocation failed!\n"); return EXIT_FAILURE; } new_node->data = value; new_node->next = list; list = new_node; scanf("%d", &value); } /* print the number of input values */ /* free list */ return EXIT_SUCCESS; } יצירת אבר חדש החוליה החדשה תצביע לראש הרשימה ראש הרשימה הוא החוליה החדשה

נעשה סדר בעזרת פונקציות node_t* create_node(int data) { node_t *new_node = (node_t*) malloc(sizeof(node_t)); if (new_node != NULL) { new_node->data = data; new_node->next = NULL; } return new_node; node_t* add_first(node_t *head, int data) { node_t *new_node = create_node(data); if (new_node == NULL) return NULL; new_node->next = head; return new_node; } ראש הרשימה הערך שנרצה להוסיף ניצור חוליה חדשה נצביע לראש הנוכחי הראש החדש הוא הערך המוחזר

הוספת איבר לרשימה שימו לב: הערכים יישמרו ברשימה בסדר הפוך לסדר הכנסתם int main() { int value = 0; node_t *list = NULL; printf("enter values (negative to stop)\n"); scanf("%d", &value); while (value >= 0) { if ( (list = add_first(list, value)) == NULL) { printf("Fatal error: memory allocation failed!\n"); return EXIT_FAILURE; } scanf("%d", &value); } /* print the number of input values */ /* free list */ return EXIT_SUCCESS; } שימו לב: הערכים יישמרו ברשימה בסדר הפוך לסדר הכנסתם

שימוש ב add_first ליצירת רשימה עבור הקלט (משמאל לימין): 10 20 5 7 list 01 list 20 01 list 5 20 10 list 7 5 20 10 list

מעבר על רשימה מתחילים בהתחלה (head) נתקדם לאיבר הבא (iter→next) עד שנגיע לסוף (iter == NULL) head iter iter iter iter iter Data Next Data Next Data Next Data Next NULL

חישוב אורך רשימה (מספר האיברים) נספור את מספר האיברים ברשימה רקורסיבי int length(const node_t *head) { int count = 0; node_t *iter; for (iter = head; iter != NULL; iter = iter->next) { count++; } return count; } int length(const node_t *head) { if (head == NULL) return 0; return 1 + length(head->next); }

מעבר על רשימה - תבנית מצביע לראש הרשימה כל זמן שלא הגענו לסופה בצע פעולה בעזרת האיבר הנוכחי התקדם לאיבר הבא for (iter = head; iter != NULL; iter = iter->next) { // do something }

חישוב אורך רשימה (מספר האיברים) נשתמש בפונקציה length int main() { int len; node_t *list = create_list(); ... len = length(list); return 0; }

הוספת איבר לרשימה int main() { int value = 0; node_t *list = NULL; printf("enter values (negative to stop)\n"); scanf("%d", &value); while (value >= 0) { if ( (list = add_first(list, value)) == NULL) { printf("Fatal error: memory allocation failed!\n"); return EXIT_FAILURE; } scanf("%d", &value); } printf("read %d values", length(list)); /* free list */ return EXIT_SUCCESS; }

דוגמה נוספת: חיפוש חיפוש ערך ברשימה רקורסיבי node_t* find(node_t *head, int val) { while (head != NULL && head->data != val) head = head->next; return head; } node_t* find(node_t *head, int val) { if (head == NULL) return NULL; return (head->data == val) ? head : find(head->next, val); }

הוספת אברים שלא בהתחלה בהינתן החוליה שאחריה נרצה להוסיף, הוספת איבר היא קלה 7 new after 3 2 1 list

מימוש הוספת איבר בסוף הרשימה שתי אפשרויות הרשימה ריקה הרשימה לא ריקה בכל מקרה צריך ליצור איבר חדש אם הרשימה ריקה, איבר זה יהיה הרשימה החדשה אחרת צריך להצביע על איבר זה מסוף הרשימה

מימוש הפונקציה add_last node_t* add_last(node_t *head, int data) { node_t *tail = head; node_t *new_node = create_node(data); if (new_node == NULL) return NULL; if (head == NULL) return new_node; while (tail->next != NULL) tail = tail->next; tail->next = new_node; return head; } הקצאת איבר חדש הרשימה המקורית ריקה נרוץ לסוף הרשימה ונוסיף את האיבר החדש ניתן להשתמש באותה פונקציה ליצירת אבר חדש מכיוון שלא ציינו היכן מופיע ברשימה ראש הרשימה לא השתנה

הוספת איבר לרשימה שימו לב: הערכים יישמרו ברשימה לפי סדר הכנסתם int main() { int value = 0; node_t *list = NULL; printf("enter values (negative to stop)\n"); scanf("%d", &value); while (value >= 0) { if ( (list = add_last(list, value)) == NULL) { printf("Fatal error: memory allocation failed!\n"); return EXIT_FAILURE; } scanf("%d", &value); } printf("Read %d values\n", length(list)); /* free list */ return EXIT_SUCCESS; } שימו לב: הערכים יישמרו ברשימה לפי סדר הכנסתם

שימוש ב add_last ליצירת רשימה עבור הקלט (משמאל לימין): 10 20 5 7 list 01 list 10 02 list 10 20 5 list 10 20 5 7 list

רשימה ממוינת רשימה שבה האברים מסודרים לפי סדר כלשהו שתי אפשרויות: מספרים – סדר עולה / יורד סטודנטים – לפי שם (סדר לקסיקוגרפי), לפי מספר מזהה נקודות במרחב – לפי מרחק מראשית הצירים שתי אפשרויות: נקלוט את כל הערכים ואז נמיין נשמור את הרשימה ממוינת על ידי הוספת ערך חדש במקום המתאים (אחרי האיבר שקטן ממנו ולפני זה שגדול ממנו)

הוספת איבר ברשימה ממוינת node_t* add(node_t *head, int data) { node_t* iter, *prev = NULL; node_t* new_node = create_node(data); /* incomplete, must check for failure */ if (head == NULL) return new_node; if (new_node->data < head->data) { new_node->next = head; } iter = head; while (iter != NULL && new_node->data > iter->data) { prev = iter; iter = iter->next; prev->next = new_node; new_node->next = iter; return head; רשימה ריקה מינימלי – ראש הרשימה נמצא את המקום המתאים הוספה במקום המתאים

הוספת איבר לרשימה int main() { int value = 0; node_t *list = NULL; printf("enter values (negative to stop)\n"); scanf("%d", &value); while (value >= 0) { if ( (list = add(list, value)) == NULL) { printf("Fatal error: memory allocation failed!\n"); return EXIT_FAILURE; } scanf("%d", &value); } printf("Read %d values\n", length(list)); /* free list */ return EXIT_SUCCESS; }

שימוש ב add ליצירת רשימה עבור הקלט (משמאל לימין): 10 20 5 7 list 01 list 10 02 list 5 10 20 list 5 7 10 20 list

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

מימוש מחיקת איבר מרשימה (1) node_t *delete(node_t *head, int value) { node_t *iter = head, prev = NULL; if (head == NULL) return head; if (head->data == value) iter = head->next; free(head); return iter; } ... רשימה ריקה האיבר הראשון ברשימה

מימוש מחיקת איבר מרשימה (המשך) ... while (iter->next != NULL) { if (iter->data == value) prev->next = iter->next; free(iter); break; } prev = iter; iter = iter->next; return head; לא הגענו לסוף נמחק את האבר prev iter

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

שחרור רשימה מקושרת - מימוש רקורסיבי void free_list(node_t* head) { node_t* temp; while (head != NULL) temp = head; head = head->next; free(temp); } כל עוד לא הגענו לסוף נשמור מצביע לאיבר נשחרר את האיבר ונתקדם הלאה void free_list(node_t* head) { if (head == NULL) return; free_list(head->next); free(head); } רשימה ריקה שחרר את שאר הרשימה שחרר את האיבר הנוכחי

גישה לאבר ה-i אין גישה ישירה נצטרך לספור i אברים מההתחלה /* assumes index >= 0 */ node_t* get(node_t* head, int index) { while (index > 0 && head != NULL) { head = head->next; index--; } return head; }

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