490 likes | 783 Views
Let’s first forget about ‘classes’, but only a dynamic list. We make lists with ‘classes’ afterwards. List, (dynamic) linked list. A simple list Example: using a dynamic array. concept of a list, e.g. a list of integers Print out info Empty test Search an element
E N D
Let’s first forget about ‘classes’, but only a dynamic list. We make lists with ‘classes’ afterwards. List, (dynamic) linked list
A simple list Example: using a dynamic array • concept of a list, e.g. a list of integers • 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; • by a dynamic array int list[size]; int size; • by a linked list and more …
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 = addEnd(A,n,5); print(A, n); A = addHead(A,n,5); print(A, n); A = deleteFirst(A,n); print(A, n); selectionSort(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* deleteFirst(int list[], int& size){ int* newList; newList = new int[size-1]; // make new array if(size){ // copy and delete old array for(int i=0; i<size-1; i++) newList[i] = list[i+1]; delete [] list; } size--; return newList; }
Remark: Instead of A = deleteFirst(A,n) we can also just deleteFirst(A,n) if we define as a void type function: void deleteFirst(int*& A, int& size) { … A = newList; } We can also B = deleteFirst(A,n) if we keep the original intact
Adding Elements // for adding a new element to end of array int* addEnd(int list[], int& size, int value){ int* newList; newList = new int [size+1]; // make new array if(size){ // copy and delete old array for(int i=0; i<size; i++) newList[i] = list[i]; delete [] list; } newList[size] = value; size++; return newList; }
Add at the beginning: // for adding a new element at the beginning of the array int* addHead(int list[], int& size, int value){ int* newList; newList = new int [size+1]; // make new array if(size){ // copy and delete old array for(int i=0; i<size; i++) newList[i+1] = list[i]; delete [] list; } newList[0] = value; size++; return newList; }
Motivation • list using static array int myArray[1000]; int n; We have to decide (to oversize) in advance the size of the array (list) • list using dynamic array int* myArray; int n; cin >> n; myArray = 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.
Link Data 20 45 75 85 Array naturally represents a (ordered) list, the link is implicit, consecutive and contiguous! Now the link is explicit, any places! Data 75 85 20 45 1 array 0 2 Link Link Data 45 linked list 85 20 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 • A link to the next element • The link is used to chain the data Example: A linked list of integers:
20 45 addEnd(75), addEnd(85) 20 45 75 85 deleteEnd(85), deleteHead(20), deleteHead(45) Linked Lists: Basic Ideas • The list can grow and shrink 75
Linked Lists: Operations • Original linked list of integers: • Insertion (in the middle): • Deletion (in the middle) 20 45 75 85 old value 20 45 75 85 60 20 45 75 85 deleted item
Definition of linked list type: struct Node{ int data; Node* next; }; We can also: typedef Node* NodePtr;
Linked List Structure • Node : Data + Link • Definition struct Node { int data; //contains useful information Node* next; //points to next element or NULL }; • Create a Node Node* p; p = new Node; //points to newly allocated memory • Delete a Node delete p;
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
Head 20 45 75 85 Representing and accessing linked lists • 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
Head 20 newPtr Start the first node from scratch head = NULL; Node* newPtr; newPtr = new Node; newPtr->data = 20; newPtr->next = NULL; head = newPtr; Head
Inserting a Node at the Beginning newPtr = new Node; newPtr->data = 13; newPtr->next = Head; head = newPtr; 20 Head 13 newPtr
Head 50 40 13 20 newPtr Keep going …
Adding an element to the head: NodePtr& void addHead(Node*& head, int newdata){ Node* newPtr = new Node; newPtr->data = newdata; newPtr->next = Head; head = newPtr; } Call by reference, scaring!!!
Also written (more functionally) as: Node* addHead(Node* head, int newdata){ Node* newPtr = new Node; newPtr->data = newdata; newPtr->next = Head; return newPtr; } Compare it with ‘addHead’ with a dynamic array implementation
Deleting the Head Node Node* p; p = head; head = head->next; delete p; head (to delete) 50 40 13 20 p
void deleteHead(Node*& head){ if(head != NULL){ NodePtr p = head; head = head->next; delete p; } } As a function: Node* deleteHead(Node* head){ if(head != NULL){ NodePtr p = head; head = head->next; delete p; } return head; }
Displaying a Linked List p = head; p = p->next; head 20 45 p 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 displayList(Node* head){ NodePtr p; p = head; while(p != NULL){ cout << p->data << endl; p = p->next; } } For an array: void displayArray(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* searchNode(Node* head, int item){ NodePtr p = head; NodePtr 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 linked lists • Sorted linked lists • Circular linked lists • Doubly linked lists • …
Further considerations for the unsorted lists: • Physical copy of list for operators like ‘deleteHead’ and ‘addHead’ • ‘deleteHead’ should be understood as a decomposition into a sub-list …
B = deleteHead(A); Node* deleteHead(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=addEnd(newhead,temp->data); temp=temp->next; } if(newhead != NULL){ Node* p = newhead; newhead = newhead->next; delete p; } return newhead; }
50 40 13 20 More operation: adding to the end • Original linked list of integers: • Add to the end (insert at the end): 60 50 40 13 20 Last element The key is how to locate the last element or node of the list!
Add to the end: void addEnd(NodePtr& head, int newdata){ NodePtr newPtr = new Node; newPtr->data = newdata; newPtr->next = NULL; NodePtr last = head; if(last != NULL){ // general non-empty list case while(last->next != NULL) last=last->next; last->next = newPtr; } else // deal with the case of empty list head = newPtr; } Link new object to last->next Link a new object to empty list
Add to the end as a function: NodePtr addEnd(NodePtr head, int newdata){ NodePtr newPtr = new Node; newPtr->data = newdata; newPtr->next = NULL; NodePtr last = head; if(last != NULL){ // general non-empty list case while(last->next != NULL) last=last->next; last->next = newPtr; } else // deal with the case of empty list head = newPtr; return head; }
Implementation of a Sorted Linked List
Head ... 20 45 75 prev cur 33 newPtr Inserting a Node 1. (a) Create a new node using: NodePtr newPtr = 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) newPtr->next = cur; (b) prev->next = newPtr;
Finding prev and cur Suppose that we want to insert or delete a node with data value newValue. Then the following code successfully finds prev and cur such that prev->data < newValue <= cur->data
It’s a kind of search algo, prev = NULL; cur = head; found=false; while( (cur!=NULL) && (!found) ) { if (newValue > 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) && (newValue>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* insertNode(Node* head, int item){ NodePtr 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; } return head; } If the position happens to be the head General case
// not recommended void type function void insertNode(NodePtr& head, int item){ NodePtr 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 85 prev cur
Delete an element in a sorted linked list: Get the location Node* deleteNode(Node* head, int item){ NodePtr prev=NULL, cur = head; while( (cur!=NULL) && (item > cur->data)){ prev = cur; cur = cur->next; } if ( cur!==NULL && cur->data==item) { if(cur==head) head = head->next; else prev->next = cur->next; delete cur; } return head; } We can delete only if the element is present! If (cur==NULL || cur->data!=item) Item is not in the list! If the element is at the head General case
// in a void function, not recommended Get the location void deleteNode(NodePtr& head, int item){ NodePtr prev=NULL, cur = head; while( (cur!=NULL) && (item > cur->data)){ prev = cur; cur = cur->next; } if ( cur!==NULL && cur->data==item) { if(cur==Head) Head = Head->next; else prev->next = cur->next; delete cur; } } We can delete only if the element is present! If (cur==NULL || cur->data!=item) Item is not in the list! If the element is at the head General case