PROGRAMMAZIONE I A A 20192020 LINKED LISTS LINKED

  • Slides: 29
Download presentation
PROGRAMMAZIONE I A. A. 2019/2020

PROGRAMMAZIONE I A. A. 2019/2020

LINKED LISTS

LINKED LISTS

LINKED LIST What are the problems with arrays? üSize is fixed üArray items are

LINKED LIST What are the problems with arrays? üSize is fixed üArray items are stored contiguously üInsertions and deletions at particular positions is complex Why linked lists? üSize is not fixed üData can be stored at any place üInsertions and deletions are simpler and faster

WHAT IS A LINKED LIST A linked list is a collection of nodes with

WHAT IS A LINKED LIST A linked list is a collection of nodes with various field It contains üData fields üLink fields Data fields Link fields

REPRESENTATION AND OPERATIONS OF SINGLY LINKED LISTS

REPRESENTATION AND OPERATIONS OF SINGLY LINKED LISTS

REPRESENTATION OF A NODE struct Node { int info; struct Node* p. Next; int

REPRESENTATION OF A NODE struct Node { int info; struct Node* p. Next; int info 1; char info 2; struct data info 3; } struct Node* p. Next; } info 1 p. Next info 2 info 3 typedef struct Node p. Next

ALLOCATION IN THE HEAP int main() { Node *p = (Node*) malloc(sizeof(Node)); … heap

ALLOCATION IN THE HEAP int main() { Node *p = (Node*) malloc(sizeof(Node)); … heap } 1000 info stack … p= 1000 … p. Next

INITIALIZATION int main() { Node *p = (Node*) malloc(sizeof(Node)); p->info = 3; p->p. Next=

INITIALIZATION int main() { Node *p = (Node*) malloc(sizeof(Node)); p->info = 3; p->p. Next= NULL; … } heap 1000 info = 3 stack … p= 1000 … p. Next= NULL

SIDE STRUCTURES One pointer to the first element of the list One pointer to

SIDE STRUCTURES One pointer to the first element of the list One pointer to the last element of the list (optional) 7000 Node* p. First 4000 Node* p. Last 10 1000 30 4000 5 NULL

MOST COMMON OPERATIONS Print all the elements Insertion üHead üTail üAt a given position

MOST COMMON OPERATIONS Print all the elements Insertion üHead üTail üAt a given position Deletion üHead üTail üAt a given position

PRINT (LIST SCAN) // As a parameter, it takes the pointer to the first

PRINT (LIST SCAN) // As a parameter, it takes the pointer to the first node of a list void print_list(Node* p. First) { if(p. First == NULL) // No node in the list { printf(”No node in the list!"); } else { // New pointer used to scan the list. Node* p. Scan = p. First; do { printf(”Info: %dn", p. Scan->id); // ptr. Scan is updated to point to the next node in the // list p. Scan = p. Scan->p. Next; }while(p. Scan!= NULL); //NULL when this was the last node } return; }

HOW IT RUNS p. First == NULL? No p. Scan = p. First 7000

HOW IT RUNS p. First == NULL? No p. Scan = p. First 7000 printf p. Scan->info 10 p. Scan = p. Scan ->p. Next 1000 p. Scan != NULL? Yes printf p. Scan->info 30 p. Scan = p. Scan ->p. Next 4000 p. Scan != NULL? Yes printf p. Scan->info 5 p. Scan = p. Scan ->p. Next NULL p. Scan != NULL? No return Info: 10 Info: 30 Info: 5 7000 10 7000 Node* p. First 30 1000 4000 5 4000 NULL

HEAD INSERTION // Node* p. First is a pointer to the first node of

HEAD INSERTION // Node* p. First is a pointer to the first node of a list (global) void head_insertion(void) { // Creation of a new node in the heap Node *p. New = (Node*) malloc(sizeof(Node)); scanf(“%d”, &(p. New->info)); p. New->p. Next= NULL; if(p. First == NULL) // No node in the list p. First = p. New; // The first node is the newly created one else { // Else, there is already at least one node in the list p. New-> p. Next= p. First; // the first node becomes the second one p. First= p. New; // The first node is the newly created one } return; }

HOW IT RUNS Node *p. New = (Node*) malloc(sizeof(Node)); scanf(“%d”, p. New->info); p. New->p.

HOW IT RUNS Node *p. New = (Node*) malloc(sizeof(Node)); scanf(“%d”, p. New->info); p. New->p. Next= NULL; 3500 3 NULL 3500 7000 Node* p. First NULL p. First == NULL? Yes p. First = p. New 3500

HOW IT RUNS Node *p. New = (Node*) malloc(sizeof(Node)); scanf(“%d”, p. New->info); p. New->p.

HOW IT RUNS Node *p. New = (Node*) malloc(sizeof(Node)); scanf(“%d”, p. New->info); p. New->p. Next= NULL; 3500 3 p. First == NULL? No p. New -> p. Next= p. First 7000 p. First = p. New 3500 7000 Node* p. First 10 1000 7000 NULL 30 4000 5 NULL

HEAD INSERTION (ALTERNATIVE) // Node** pp. First is a pointer to the first node

HEAD INSERTION (ALTERNATIVE) // Node** pp. First is a pointer to the first node of a list void head_insertion(Node** pp. First) { // Creation of a new node in the heap Node *p. New = (Node*) malloc(sizeof(Node)); scanf(“%d”, &(p. New->info)); p. New->p. Next= NULL; if(*pp. First == NULL) // No node in the list *pp. First = p. New; // The first node is the newly created one else { // Else, there is already at least one node in the list p. New-> p. Next= *pp. First; // the first node becomes the second one *p. First= p. New; // The first node is the newly created one } return; }

HEAD DELETION // Node* p. First is a pointer to the first node of

HEAD DELETION // Node* p. First is a pointer to the first node of a list (global) void head_deletion(void) { if(p. First == NULL) // No node in the list { printf(”No node in the list!"); } else { // Else, there is at least a node in the list // Remember the pointer to the second node, which will become // the first one Node* temp= p. First-> p. Next; // Memory is deallocated (node canceled from memory) free(p. First); // The first node becomes the former second node p. First= temp; } return; }

HOW IT WORKS p. First == NULL? No temp= p. First -> p. Next

HOW IT WORKS p. First == NULL? No temp= p. First -> p. Next 1000 free(p. First) 7000 p. First = temp 1000 7000 10 Node* p. First 1000 30 4000 5 NULL

ADDING AND REMOVING FROM TAIL When we need to add or remove a node

ADDING AND REMOVING FROM TAIL When we need to add or remove a node from the tail, it is useful to also have a pointer to the last node of a list üIt simplifies writing these two functions This pointer (p. Last) needs to be updated at the end of these operations Of course if we need to have add-or-remove from head and add-or-remove from tail, p. Last needs to be updated also in add-or-remove from head (as p. First in previous examples)

TAIL INSERTION // Node* p. First is a pointer to the first node and

TAIL INSERTION // Node* p. First is a pointer to the first node and Node* p. Last to the last node of // a list (both global) void tail_insertion(void) { // Creation of a new node in the heap Node *p. New = (Node*) malloc(sizeof(Node)); scanf(“%d”, &(p. New->info)); p. New->p. Next= NULL; if(p. First == NULL) // No node in the list p. First = p. New; // The first node is the newly created one p. Last = p. New; // The last node is the newly created one else { // Else, there is already at least one node in the list p. Last-> p. Next= p. New; // the last node becomes the second one p. Last= p. New; // The last node is the newly created one } return; }

HOW IT WORKS 7000 500 4000 10 p. First == NULL? No p. Last->

HOW IT WORKS 7000 500 4000 10 p. First == NULL? No p. Last-> p. Next= p. New 500 p. Last= p. New 500 Node* p. First Node* p. Last 1000 30 4000 15 NULL 500 5 500 NULL

TAIL DELETION void tail_deletion() { if(p. First == NULL) printf(”No node in the list!n");

TAIL DELETION void tail_deletion() { if(p. First == NULL) printf(”No node in the list!n"); else { Node* p. Prev = NULL; Node* p. Scan = p. First; if(p. Scan->p. Next == NULL) {// It means we only have one node in the list free(p. Scan); // Free memory p. First= NULL; // Now the list is empty } else {// Otherwise, I need to scan the list until I find the last node (p. Last) do{ if((p. Scan-> p. Next) == p. Last) {// Reached the node before the end p. Prev = p. Scan; break; } else p. Scan= p. Scan-> p. Next; // Otherwise, I need to iterate }while((p. Scan-> p. Next) != NULL); free(p. Prev-> p. Next); // Free memory allocated to the last node p. Prev-> p. Next = NULL; // p. Prev becomes the last node (no node after it) p. Last = p. Prev; // p. Prev becomes the last node } } }

HOW IT RUNS p. First == NULL? No p. Scan= p. First 7000 p.

HOW IT RUNS p. First == NULL? No p. Scan= p. First 7000 p. Scan-> p. Next== NULL? No p. Scan = p. Scan -> p. Next 1000 Node* p. First 7000 4000 10 Node* p. Last 1000 30 NULL 4000 (p. Scan-> p. Next) == p. Last Yes p. Prev= p. Scan 1000 free(p. Prev-> p. Next) 4000 p. Prev -> p. Next= NULL p. Last = p. Prev 1000 5 NULL

DELETE NODE IN SOME POSITION 7000 4000 10 Node* p. First 1. 2. 3.

DELETE NODE IN SOME POSITION 7000 4000 10 Node* p. First 1. 2. 3. 4. Iterate until (p. Scan -> p. Next) -> info == key temp= (p. Scan-> p. Next) -> next free(p. Scan->next) p. Scan-> p. Next = temp Node* p. Last 1000 4000 temp = 4000 30 4000 5 NULL void delete_if_equal(Node* p. First, Node* p. Last, int key){…} e. g. , 30 Update p. First or p. Last if instead you remove either the first or last node

ADD NODE IN SOME POSITION Node* p. First 7000 Node* p. Last 4000 10

ADD NODE IN SOME POSITION Node* p. First 7000 Node* p. Last 4000 10 5000 1000 30 4000 35 5000 15 1000 NULL Homework! NULL

DIFFERENT KINDS OF LISTS Singly linked lists Circular singly linked list Doubly linked lists

DIFFERENT KINDS OF LISTS Singly linked lists Circular singly linked list Doubly linked lists Circular doubly linked list

SINGLY LINKED LIST Pointer to the first element 7000 10 1000 Stored at memory

SINGLY LINKED LIST Pointer to the first element 7000 10 1000 Stored at memory address 7000 30 4000 Stored at memory address 1000 5 NULL Stored at memory address 4000

CIRCULAR SINGLY LINKED LIST Pointer to the first element 7000 10 1000 30 4000

CIRCULAR SINGLY LINKED LIST Pointer to the first element 7000 10 1000 30 4000 5 7000

DOUBLY LINKED LIST 7000 Stored at memory address 7000 NULL 10 1000 Stored at

DOUBLY LINKED LIST 7000 Stored at memory address 7000 NULL 10 1000 Stored at memory address 1000 7000 50 5000 Stored at memory address 5000 1000 30 NULL