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