Transcript lst head 2

‫הרצאה ‪06‬‬
‫רשימות מקושרות‬
‫קרן כליף‬
‫ביחידה זו נלמד‪:‬‬
‫‪ ‬מהי רשימה מקושרת‬
‫‪ ‬ההבדל בין מערך לרשימה‬
‫‪2‬‬
‫‪© Keren Kalif‬‬
‫מבנה נתונים‬
‫‪ ‬מבנה נתונים הוא אוסף המאפשר לנו להחזיק יותר מאיבר אחד‬
‫‪ ‬למשל‪ :‬מערך‬
‫‪ ‬קיימים מבני נתונים נוספים שלכל אחד יש את היתרונות‬
‫והחסרונות שלו‪ ,‬ואלו ישפיעו על בחירת שימוש המבנה נתונים‬
‫אחד או אחר‬
‫‪ ‬היתרונות של מערך‪:‬‬
‫‪ ‬גישה ישירה לאיבר‬
‫‪ ‬הוספה בקלות לסוף המערך‬
‫‪ ‬החסרונות של מערך‪:‬‬
‫‪ ‬הסרה‪/‬הוספה לאמצע מורכבת‬
‫‪ ‬גודל מוגבל‬
‫‪3‬‬
‫‪© Keren Kalif‬‬
‫רשימה מקושרת‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫זהו מבנה נתונים המאפשר הוספה דינאמית של איברים לכל מקום‬
‫באוסף בקלות‬
‫אין צורך להחליט מראש כמה איברים יהיו ברשימה‬
‫הרעיון הוא יצירת איבר וקישורו למקום המתאים ברשימה בכל רגע‬
‫נתון‬
‫כל איבר ברשימה מקושרת הוא מבנה המכיל נתון והצבעה לאיבר‬
‫הבא‬
‫‪typedef struct LNode‬‬
‫}‬
‫האיבר האחרון ברשימה יצביע ל‪NULL -‬‬
‫;‪int data‬‬
‫;‪struct LNode* next‬‬
‫בניגוד למערך‪ ,‬האיברים אינם ברצף בזיכרון‬
‫;‪} LNode‬‬
‫‪6‬‬
‫‪4‬‬
‫‪© Keren Kalif‬‬
‫‪9‬‬
‫‪4‬‬
‫‪typedef struct List‬‬
‫}‬
‫;‪struct LNode* head‬‬
‫;‪} List‬‬
‫דוגמאת הוספת ערכים לרשימה‬
lst
head
10
???
2
0
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
5
‫פונקציה המחשבת את כמות הצמתים ברשימה‬
int getListLength(const List* lst)
{
int count = 0;
LNode* temp = lst->head;
while (temp != NULL)
{
count++;
temp = temp->next;
}
return count;
}
1
count = 2
0
temp
lst
head
10
???
2
0
© Keren Kalif
6
‫פונקציה המדפיסה את איברי הרשימה‬
void printList(const List* lst)
{
LNode* temp = lst->head;
while (temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
}
1 2
temp
lst
head
10
???
2
0
© Keren Kalif
7
‫פונקציה המשחררת את איברי הרשימה‬
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
10
???
2
0
© Keren Kalif
8
‫שדרוג הרשימה‬
‫ והוספת‬,‫ מצביע לראש הרשימה‬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
9
‫שדרוג הרשימה‬
‫ כדי להקל על הוספת איברים לסוף הרשימה נשדרג את המבנה‬
:‫ כך שיכיל גם מצביע לאיבר האחרון‬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 = (LNode*)calloc(1, sizeof(LNode));
lst.tail->next->data = 3;
lst.tail = lst.tail->next;
lst
freeList(&lst); head
tail
1
typedef struct List
}
struct LNode *head, *tail;
} List;
‫ניתן לראות שכעת הקוד של‬
‫הוספת איבר לסוף הרשימה‬
‫ ובפרט חוסך לולאה‬,‫זהה‬
‫ ולכן‬,‫המטיילת לאיבר האחרון‬
O)1( ‫יעילות הפעולה היא‬
2
3
© Keren Kalif
10
‫פונקציה המאתחלת רשימה ריקה‬
NULL ‫ את הערך‬tail -‫ וה‬head -‫ פונקציה זו מאתחלת בשדות ה‬
List makeEmptyList()
{
List lst;
lst.head = lst.tail = NULL;
return lst;
}
© Keren Kalif
11
‫פונקציה הבודקת האם רשימה ריקה‬
int isEmpty(const List* lst)
{
return lst->head == NULL;
}
© Keren Kalif
12
‫פונקציה שיוצרת איבר להכנסה לרשימה‬
:‫ ומצביע לאיבר הבא‬,‫ הפונקציה תקבל את הערך שיהיה באיבר‬
LNode* createNewNode(int newData, LNode* next)
{
LNode* newNode = (Node*)calloc(1], sizeof(LNode));
newNode->data = newData;
newNode->next = next;
return newNode;
}
‫ פונקציה זו תשמש אותנו בפונקציות הבאות‬
© Keren Kalif
13
‫הוספת ערך לראש הרשימה‬
void insertValueToHead(List* lst, int newData)
{
LNode* newNode = createNewNode(newData, lst->head);
if (isEmpty(lst))
lst->head = lst->tail = newNode;
else
lst->head = newNode;
}
newData = 4
2
lst
head
tail
3
4
newNode
© Keren Kalif
14
)‫(שהפעם ריקה‬
‫הוספת ערך לראש הרשימה‬
void insertValueToHead(List* lst, int 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
15
‫הוספת ערך לסוף הרשימה‬
void insertValueToTail(List* lst, int newData)
{
LNode* newNode = createNewNode(newData, NULL);
if (isEmpty(lst))
lst->head = lst->tail = newNode;
else
{
lst->tail->next = newNode;
lst->tail = newNode;
}
}
2
lst
head
tail
3
newData = 4
4
newNode
© Keren Kalif
16
)‫(שהפעם ריקה‬
‫הוספת ערך לסוף הרשימה‬
void insertValueToTail(List* lst, int newData)
{
LNode* newNode = createNewNode(newData, NULL);
if (isEmpty(lst))
lst->head = lst->tail = newNode;
else
{
lst->tail->next = newNode;
lst->tail = newNode;
}
}
lst
head
tail
newData = 4
4
newNode
© Keren Kalif
17
‫הוספת איבר לסוף הרשימה‬
void insertNodeToTail(List* lst, LNode* newNode)
{
if (isEmpty(lst))
lst->head = lst->tail = newNode;
else
{
lst->tail->next = newNode;
lst->tail = newNode;
}
}
© Keren Kalif
18
‫זוגיים‬-‫ פיצול רשימה לזוגיים ואי‬:‫דוגמא‬
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);
printf("\n");
freeList(&lstEven);
freeList(&lstOdd);
}
© Keren Kalif
19
)2(
‫זוגיים‬-‫ פיצול רשימה לזוגיים ואי‬:‫דוגמא‬
void splitListToEvenAndOdd(List* src, List* even, List* odd)
{
LNode* current = src->head;
src
LNode* next;
head
tail
*even = makeEmptyList();
*odd = makeEmptyList();
1
even
while (current)
head
{
tail
next = current->next;
if (current->data%2 == 0)
insertNodeToTail(even, current);
else
insertNodeToTail(odd, current);
current->next = NULL;
current = next;
3
2
current next
odd
head
tail
}
}
© Keren Kalif
20