Programming and Data Structures Programming and Data Structures
Lecture 9 Lecture 9
Dr Piotr Cybula <piotr.cybula@wmii.uni.lodz.pl>
Dr Piotr Cybula <piotr.cybula@wmii.uni.lodz.pl>
Advanced operations on lists Advanced operations on lists
●
operations on the elements of a linked list do not require memory reallocation (modifications of pointer fields changing the order of nodes):
●
inversion of the list (changing the relationship between nodes by changing the address of the first node and the addresses of the next node)
●
removing a fragment of the list (skipping a fragment by changing the address of the next node in the node preceding the fragment and freeing memory)
●
moving a fragment within a list or between lists (skipping a fragment by changing the address of the next node in the node preceding the
fragment and changing the addresses of the next node in the new
preceding node and in the last node of the fragment)
Reversing Reversing
A next
C head
B next
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
Reversing Reversing
pred succ
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
Reversing Reversing
A C
head
B next
pred succ
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
(2) set the after pointer on the node following the one pointed to by succ
Reversing Reversing
pred succ after
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
(2) set the after pointer on the node following the one pointed to by succ
Reversing Reversing
A C
head
B next
pred succ after
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
(2) set the after pointer on the node following the one pointed to by succ (3) change the next pointer in the node pointed to by succ to the address pred
Reversing Reversing
pred succ after
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
(2) set the after pointer on the node following the one pointed to by succ (3) change the next pointer in the node pointed to by succ to the address pred
Reversing Reversing
A C
head
B next
pred succ after
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
(2) set the after pointer on the node following the one pointed to by succ (3) change the next pointer in the node pointed to by succ to the address pred (4) set the head and pred pointers to the node pointed to by succ
Reversing Reversing
pred succ after
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
(2) set the after pointer on the node following the one pointed to by succ (3) change the next pointer in the node pointed to by succ to the address pred (4) set the head and pred pointers to the node pointed to by succ
Reversing Reversing
A C
head
B next
pred succ after
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
(2) set the after pointer on the node following the one pointed to by succ (3) change the next pointer in the node pointed to by succ to the address pred (4) set the head and pred pointers to the node pointed to by succ
(5) set the succ pointer to the node pointed to by after
Reversing Reversing
pred succ
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
(2) set the after pointer on the node following the one pointed to by succ (3) change the next pointer in the node pointed to by succ to the address pred (4) set the head and pred pointers to the node pointed to by succ
(5) set the succ pointer to the node pointed to by after (6) if succ is not empty, go back to step (2)
Reversing Reversing
A C
head
B next
pred succ
next
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
(2) set the after pointer on the node following the one pointed to by succ (3) change the next pointer in the node pointed to by succ to the address pred (4) set the head and pred pointers to the node pointed to by succ
(5) set the succ pointer to the node pointed to by after (6) if succ is not empty, go back to step (2)
Reversing Reversing
(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is non- empty otherwise we abort, pred may be empty in the first step, head points to the node preceding succ)
(2) set the after pointer on the node following the one pointed to by succ (3) change the next pointer in the node pointed to by succ to the address pred (4) set the head and pred pointers to the node pointed to by succ
(5) set the succ pointer to the node pointed to by after (6) if succ is not empty, go back to step (2)
Fragment removal Fragment removal
A next
B C
head
next
B next
...
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
Fragment removal Fragment removal
pred succ
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
Fragment removal Fragment removal
A next
B C
head
next
B next
...
pred succ
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
Fragment removal Fragment removal
pred succ end after
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
Fragment removal Fragment removal
A next
B C
head
next
B next
...
pred succ end after
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
(3) set a dedicated killer to the node pointed to by succ, and set succ to after
Fragment removal Fragment removal
pred killer end succ
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
(3) set a dedicated killer to the node pointed to by succ, and set succ to after
Fragment removal Fragment removal
A next
B C
head
next
B next
...
pred killer end succ
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
(3) set a dedicated killer to the node pointed to by succ, and set succ to after
(4) set the next pointer of the node pointed to by pred (or the head pointer when pred is empty) to the address stored in succ
Fragment removal Fragment removal
pred killer end succ
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
(3) set a dedicated killer to the node pointed to by succ, and set succ to after
(4) set the next pointer of the node pointed to by pred (or the head pointer when pred is empty) to the address stored in succ
Fragment removal Fragment removal
A next
B C
head
next
B next
...
pred killer end succ
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
(3) set a dedicated killer to the node pointed to by succ, and set succ to after
(4) set the next pointer of the node pointed to by pred (or the head pointer when pred is empty) to the address stored in succ
(5) set to the empty next pointer in the node pointed to by end
Fragment removal Fragment removal
pred killer end succ
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
(3) set a dedicated killer to the node pointed to by succ, and set succ to after
(4) set the next pointer of the node pointed to by pred (or the head pointer when pred is empty) to the address stored in succ
(5) set to the empty next pointer in the node pointed to by end
Fragment removal Fragment removal
A next
B C
head
next
... B
pred killer end succ
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
(3) set a dedicated killer to the node pointed to by succ, and set succ to after
(4) set the next pointer of the node pointed to by pred (or the head pointer when pred is empty) to the address stored in succ
(5) set to the empty next pointer in the node pointed to by end
Fragment removal Fragment removal
pred killer end succ
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
(3) set a dedicated killer to the node pointed to by succ, and set succ to after
(4) set the next pointer of the node pointed to by pred (or the head pointer when pred is empty) to the address stored in succ
(5) set to the empty next pointer in the node pointed to by end
(6) release all nodes starting from the one pointed to by the killer to end (an independent list)
Fragment removal Fragment removal
(1) invoke two auxiliary pointers: set pred to an empty address, and succ to the address of the first node (head) and pass them towards the end of the list so that the pred pointer stops at the node preceding the fragment, and succ at the first node in the fragment (otherwise we stop the operation)
(2) invoke two auxiliary pointers: set end to succ, and after to the address of the next node behind succ and pass them towards the end of the list so that the end pointer stops at the last node of the fragment, and after on the first node after the fragment (it can be empty)
(3) set a dedicated killer to the node pointed to by succ, and set succ to after
(4) set the next pointer of the node pointed to by pred (or the head pointer when pred is empty) to the address stored in succ
(5) set to the empty next pointer in the node pointed to by end
(6) release all nodes starting from the one pointed to by the killer to end (an independent list)
A next
C
head pred succ
Fragment moving Fragment moving
pred begin end succ
(1) perform the first 5 steps of the removal algorithm by invoking the begin pointer in place of the killer (moving the tail pointer to the address stored in pred, when tail points to the node
pointed to by end)
Fragment moving Fragment moving
A next
B
C
head next
... B pred
begin end
succ tail
(1) perform the first 5 steps of the removal algorithm by invoking the begin pointer in place of the killer (moving the tail pointer to the address stored in pred, when tail points to the node
pointed to by end)
(2) the begin-end list is independent and can be safely moved:
Fragment moving Fragment moving
B next
... B pred
begin end
succ
(1) perform the first 5 steps of the removal algorithm by invoking the begin pointer in place of the killer (moving the tail pointer to the address stored in pred, when tail points to the node
pointed to by end)
(2) the begin-end list is independent and can be safely moved:
a) between any pair of pred and succ nodes (the next pointer from pred is set to begin, and the pointer next from end is set to succ)
Fragment moving Fragment moving
A next
B
C
head next
... B pred
begin end
succ tail
next
(1) perform the first 5 steps of the removal algorithm by invoking the begin pointer in place of the killer (moving the tail pointer to the address stored in pred, when tail points to the node
pointed to by end)
(2) the begin-end list is independent and can be safely moved:
a) between any pair of pred and succ nodes (the next pointer from pred is set to begin, and the pointer next from end is set to succ)
Fragment moving Fragment moving
B next
... B
begin end
(1) perform the first 5 steps of the removal algorithm by invoking the begin pointer in place of the killer (moving the tail pointer to the address stored in pred, when tail points to the node
pointed to by end)
(2) the begin-end list is independent and can be safely moved:
a) between any pair of pred and succ nodes (the next pointer from pred is set to begin, and the pointer next from end is set to succ)
b) to the beginning of the list (the next pointer from the end node is set to head, and then the head pointer to begin)
Fragment moving Fragment moving
A next B
C head
next
... B
begin end
tail next
(1) perform the first 5 steps of the removal algorithm by invoking the begin pointer in place of the killer (moving the tail pointer to the address stored in pred, when tail points to the node
pointed to by end)
(2) the begin-end list is independent and can be safely moved:
a) between any pair of pred and succ nodes (the next pointer from pred is set to begin, and the pointer next from end is set to succ)
b) to the beginning of the list (the next pointer from the end node is set to head, and then the head pointer to begin)
Fragment moving Fragment moving
B next
... B
begin end
(1) perform the first 5 steps of the removal algorithm by invoking the begin pointer in place of the killer (moving the tail pointer to the address stored in pred, when tail points to the node
pointed to by end)
(2) the begin-end list is independent and can be safely moved:
a) between any pair of pred and succ nodes (the next pointer from pred is set to begin, and the pointer next from end is set to succ)
b) to the beginning of the list (the next pointer from the end node is set to head, and then the head pointer to begin)
c) to the end of the list (set the next pointer from the tail node to begin, and then the tail pointer to end)
Fragment moving Fragment moving
(1) perform the first 5 steps of the removal algorithm by invoking the begin pointer in place of the killer (moving the tail pointer to the address stored in pred, when tail points to the node
pointed to by end)
(2) the begin-end list is independent and can be safely moved:
a) between any pair of pred and succ nodes (the next pointer from pred is set to begin, and the pointer next from end is set to succ)
b) to the beginning of the list (the next pointer from the end node is set to head, and then the head pointer to begin)
c) to the end of the list (set the next pointer from the tail node to begin, and then the tail pointer to end)