List dynamic linked list Lets first forget about
List, (dynamic) linked list Let’s first forget about ‘classes’, but only a dynamic list. We make lists with ‘classes’ afterwards.
A simple list Example: using a dynamic array * concept of a list, e. g. a list of integers n n n * Print out info Empty test Search an element Insertion (at head, at end, any position) Deletion … implemented by a static array (over-sized if necessary) int list[1000]; int size; n by a dynamic array int list[size]; int size; n by a linked list and more … n
How to use a list? int main() { cout << "Enter list size: "; int n; cin >> n; int* A = new int[n]; initialize(A, n, 0); print(A, n); A = add. End(A, n, 5); print(A, n); A = add. Head(A, n, 5); print(A, n); A = delete. First(A, n); print(A, n); selection. Sort(A, n); print(A, n); delete [] A; } int A[10000]; int n; Nothing compulsory in programming, only style matters!
Initialize void initialize(int list[], int size, int value){ for(int i=0; i<size; i++) list[i] = value; }
Print out a list void print(int list[], int size) { cout << "[ "; for(int i=0; i<size; i++) cout << list[i] << " "; cout << "]" << endl; }
Delete the first element // for deleting the first element of the array int* delete. First(int list[], int& size){ int* new. List; new. List = new int[size-1]; // make new array if(size){ // copy and delete old array for(int i=0; i<size-1; i++) new. List[i] = list[i+1]; delete [] list; } size--; return new. List; }
Remark: Instead of A = delete. First(A, n) we can also just delete. First(A, n) if we define as a void type function: void delete. First(int*& A, int& size) { … A = new. List; } We can also B = delete. First(A, n) if we keep the original intact
Adding Elements // for adding a new element to end of array int* add. End(int list[], int& size, int value){ int* new. List; new. List = new int [size+1]; // make new array if(size){ // copy and delete old array for(int i=0; i<size; i++) new. List[i] = list[i]; delete [] list; } new. List[size] = value; size++; return new. List; }
Add at the beginning: // for adding a new element at the beginning of the array int* add. Head(int list[], int& size, int value){ int* new. List; new. List = new int [size+1]; // make new array if(size){ // copy and delete old array for(int i=0; i<size; i++) new. List[i+1] = list[i]; delete [] list; } new. List[0] = value; size++; return new. List; }
Linked list: a dynamic list
Motivation * list using static array int my. Array[1000]; int n; We have to decide (to oversize) in advance the size of the array (list) * list using dynamic array int* my. Array; int n; cin >> n; my. Array = new int[n]; We allocate an array (list) of any specified size while the program is running * linked-list (dynamic size) size = ? ? The list is dynamic. It can grow and shrink to any size.
Array naturally represents a (ordered) list, the link is implicit, consecutive and contiguous! Now the link is explicit, any places! Data Link 20 0 45 1 75 array 2 Link Data 85 45 20 85 linked list 75 Link Data 20 45 75 85
Linked Lists: Basic Idea * * A linked list is an ordered collection of data Each element of the linked list has Some data n A link to the next element n * The link is used to chain the data Example: A linked list of integers: Link Data 20 45 75 85
Linked Lists: Basic Ideas * The 20 list can grow and shrink 45 add. End(75), add. End(85) 20 45 75 85 delete. End(85), delete. Head(20), delete. Head(45) 75
Linked Lists: Operations * Original linked list of integers: 20 * Insertion 20 45 20 85 (in the middle): old value 45 * Deletion 75 75 85 60 (in the middle) 45 deleted item 75 85
Definition of linked list type: struct Node{ int data; Node* next; }; We can also: typedef Node* Node. Ptr;
Linked List Structure * Node n : Data + Link Definition struct Node { int data; Node* next; }; n Create a Node* p; p = new Node; n //contains useful information //points to next element or NULL Delete a Node delete p; //points to newly allocated memory
n Access fields in a node (*p). data; //access the data field (*p). next; //access the pointer field Or it can be accessed this way p->data //access the data field p->next //access the pointer field
Representing and accessing linked lists Head 20 * 45 75 85 We define a pointer Node* head; that points to the first node of the linked list. When the linked list is empty then head is NULL.
Passing a Linked List to a Function It is roughly the same as for an array!!! * When passing a linked list to a function it should suffice to pass the value of head. Using the value of head the function can access the entire list. * Problem: If a function changes the beginning of a list by inserting or deleting a node, then head will no longer point to the beginning of the list. * Solution: When passing head always pass it by reference (not good!) or using a function to return a new pointer value
Implementation of an (Unsorted) Linked List
Start the first node from scratch head = NULL; Head Node* new. Ptr; new. Ptr = new Node; new. Ptr->data = 20; new. Ptr->next = NULL; head = new. Ptr; 20 Head new. Ptr
Inserting a Node at the Beginning new. Ptr = new Node; new. Ptr->data = 13; new. Ptr->next = Head; head = new. Ptr; 20 Head 13 new. Ptr
Keep going … Head 50 new. Ptr 40 13 20
Adding an element to the head: Node. Ptr& void add. Head(Node*& head, int newdata){ Node* new. Ptr = new Node; new. Ptr->data = newdata; new. Ptr->next = Head; head = new. Ptr; } Call by reference, scaring!!!
Also written (more functionally) as: Node* add. Head(Node* head, int newdata){ Node* new. Ptr = new Node; new. Ptr->data = newdata; new. Ptr->next = Head; return new. Ptr; } Compare it with ‘add. Head’ with a dynamic array implementation
Deleting the Head Node* p; p = head; head = head->next; delete p; head (to delete) 50 p 40 13 20
void delete. Head(Node*& head){ if(head != NULL){ Node. Ptr p = head; head = head->next; delete p; } } As a function: Node* delete. Head(Node* head){ if(head != NULL){ Node. Ptr p = head; head = head->next; delete p; } return head; }
Displaying a Linked List p = head; head 20 45 p p = p->next; head 20 45 p
A linked list is displayed by walking through its nodes one by one, and displaying their data fields (similar to an array!). void display. List(Node* head){ Node. Ptr p; p = head; while(p != NULL){ cout << p->data << endl; p = p->next; } } For an array: void display. Array(int data[], int size) int n=0; while ( n<size ) { cout << data[i] << endl; n++; } } {
Searching for a node (look at array searching first!) //return the pointer of the node that has data=item //return NULL if item does not exist Node* search. Node(Node* head, int item){ Node. Ptr p = head; Node. Ptr result = NULL; bool found=false; while((p != NULL) && (!found)){ if(p->data == item) { found = true; result = p; } p = p->next; } return result; }
Remember array searching algorithm: void main() { const int size=8; int data[size] = { 10, 7, 9, 1, 17, 30, 5, 6 }; int value; cout << "Enter search element: "; cin >> value; int n=0; int position=-1; bool found=false; while ( (n<size) && (!found) ) { if(data[n] == value) { found=true; position=n; } n++; } if(position==-1) cout << "Not found!!n"; else cout << "Found at: " << position << endl; } It is essentially the same!
Variations of linked lists * Unsorted * Sorted linked lists * Circular linked lists * Doubly linked lists *…
Further considerations for the unsorted lists: * Physical copy of list for operators like ‘delete. Head’ and ‘add. Head’ * ‘delete. Head’ should be understood as a decomposition into a sub-list …
B = delete. Head(A); Node* delete. Head(Node* head){ // physically copy head into a new one, newhead // so to keep the original list intact! Node* newhead=NULL; Node* temp=head; while(temp!=NULL) { newhead=add. End(newhead, temp->data); temp=temp->next; } if(newhead != NULL){ Node* p = newhead; newhead = newhead->next; delete p; } return newhead; }
More operation: adding to the end * Original linked list of integers: 50 * 40 13 20 Add to the end (insert at the end): 50 40 13 20 60 Last element The key is how to locate the last element or node of the list!
Add to the end: void add. End(Node. Ptr& head, int newdata){ Node. Ptr new. Ptr = new Node; new. Ptr->data = newdata; new. Ptr->next = NULL; Node. Ptr last = head; if(last != NULL){ // general non-empty list case while(last->next != NULL) last=last->next; last->next = new. Ptr; } else // deal with the case of empty list head = new. Ptr; } Link a new object to empty list Link new object to last->next
Add to the end as a function: Node. Ptr add. End(Node. Ptr head, int newdata){ Node. Ptr new. Ptr = new Node; new. Ptr->data = newdata; new. Ptr->next = NULL; Node. Ptr last = head; if(last != NULL){ // general non-empty list case while(last->next != NULL) last=last->next; last->next = new. Ptr; } else // deal with the case of empty list head = new. Ptr; return head; }
Implementation of a Sorted Linked List
Inserting a Node 1. (a) Create a new node using: Node. Ptr new. Ptr = new node; (b) Fill in the data field correctly. 2. Find “prev” and “cur” such that the new node should be inserted between *prev and *cur. 3. Connect the new node to the list by using: (a) new. Ptr->next = cur; (b) prev->next = new. Ptr; Head 20 prev 45 33 new. Ptr cur 75 . . .
Finding prev and cur Suppose that we want to insert or delete a node with data value new. Value. Then the following code successfully finds prev and cur such that prev->data < new. Value <= cur->data
It’s a kind of search algo, prev = NULL; cur = head; found=false; while( (cur!=NULL) && (!found) ) { if (new. Value > cur->data) { prev=cur; cur=cur->next; } else found = true; } Prev is necessary as we can’t go back!
Finally, it is equivalent to: prev = NULL; cur = head; while( (cur!=NULL) && (new. Value>cur->data) ) { prev=cur; cur=cur->next; } Logical AND (&&) is short-circuited, sequential, i. e. if the first part is false, the second part will not be executed.
//insert item into linked list according to ascending order Node* insert. Node(Node* head, int item){ Node. Ptr newp, cur, pre; newp = new Node; newp->data = item; pre = NULL; cur = head; while( (cur != NULL) && (item>cur->data)){ pre = cur; cur = cur->next; } if(pre == NULL){ //insert to head of linked list newp->next = head; head = newp; If the position happens to be the head } else { pre->next = newp; new->next = cur; General case } return head; }
// not recommended void type function void insert. Node(Node. Ptr& head, int item){ Node. Ptr newp, cur, pre; newp = new Node; newp->data = item; pre = NULL; cur = head; while( (cur != NULL) && (item>cur->data)){ pre = cur; cur = cur->next; } if(pre == NULL){ //insert to head of linked list newp->next = head; head = newp; } else { pre->next = newp; new->next = cur; } }
Deleting a Node * To delete a node from the list 1. Locate the node to be deleted (a) cur points to the node. (b) prev points to its predecessor 2. Disconnect node from list using: prev->next = cur->next; 3. Return deleted node to system: delete cur; (to delete) Head 20 45 75 prev cur 85 . . .
Delete an element in a sorted linked list: Node* delete. Node(Node* head, int item){ Node. Ptr prev=NULL, cur = head; while( (cur!=NULL) && (item > cur->data)){ prev = cur; cur = cur->next; } if ( cur!==NULL && cur->data==item) Get the location { We can delete only if the element is present! If (cur==NULL || cur->data!=item) Item is not in the list! if(cur==head) head = head->next; else prev->next = cur->next; delete cur; } return head; } If the element is at the head General case
// in a void function, not recommended void delete. Node(Node. Ptr& head, int item){ Node. Ptr prev=NULL, cur = head; while( (cur!=NULL) && (item > cur->data)){ prev = cur; cur = cur->next; } if ( cur!==NULL && cur->data==item) Get the location { We can delete only if the element is present! If (cur==NULL || cur->data!=item) Item is not in the list! if(cur==Head) Head = Head->next; else If the element is at the head prev->next = cur->next; delete cur; } } General case
- Slides: 48