PRESENTED BY MATTHEW GRAF AND LEE MIROWITZ Linked Lists
The Linked List Class Nodes Value – the data that the node contains Pointers – point to the next and/or previous node Head/tail pointers Indicates start and end of the list
Implementation - Nodes Node struct contained within a Linked List class Constructor – sets data to newData, next to NULL T is the data type according to the template Typically an int in the context of this course, but can be any data type or class struct Node { T data; Node * next; Node(T newData):data(newData),next(NULL){} };
What is a struct? Think of it as a public class An object that contains member variables and functions data and next are variables, the constructor is a function A node is just one piece of the entire list Just contains a value (our data) and a pointer to the next node Node(3) constructs the node to the right struct Node { T data; Node * next; Node(T newData):data(newData),next(NULL){} };
Implementation – the List class template class List{ public: List():size(0), head(NULL) {} ~List(); int size(); void insert(int loc, T data); void remove(int loc); T const & getItem(int loc) const; Private: Node* head; Node * find(int k, Node * curr); struct Node{... } };
Essential Linked List Methods Insert– create a node and put it somewhere in the list (public) Remove – get rid of a node, link the neighboring nodes to keep list intact (public) Get Item – return the value of a node at some arbitrary position in the list (public) Find – return a pointer to a node at some arbitrary position in the list (private) helper function for the other three methods
Essential Linked List Methods Now give it a try!
Find Method Node * find(int k, Node * curr) { }
Insert Method void insert(int k, T data) { }
Remove Method void remove(int k) { }
getItem Method T getItem(int k) { }
InterleaveWith Function For example, if interleaveWith is called on the list of integers List list1 = with parameter list List list2 = then the call to list1.interleaveWith(list2) should result in list1 == list2 ==
MixSplit Function For example, if we have a list, original, of integers List original = and call List returned = original.mixSplit(); The resulting list should be original == and the returned list should be returned ==
Implementation – the sort() Function In MP3, the sort() function was a member of the List class This means we dont need to pass a List as a parameter, but instead say myList.sort(), where myList is a List we created One of the requirements for sort() was that we could NOT allocate new listNodes We cannot create new nodes, but we can modify the way these nodes are connected Note: Before you start writing your own code, know that there are multiple ways to implement the same thing. We will be showing our implementation, but you can take a different path as long as it works and makes sense to you.
Sort() – base case For our base case, we must check if the list has length 0 or 1. We had a length member variable, so this is straightforward. void List ::sort() { }
Sort() – base case For our base case, we must check if the list has length 0 or 1. We had a length member variable, so this is straightforward. void List ::sort() { // Base case: we have a list of length 1 or 0 if(length==1 || length==0) return; // the rest of our code, yet to be written }
Sort() – Dividing the list in two parts Now we have to create two new lists. We will put half of the nodes in the first, and the other half in the second. void List ::sort() { // (we wont show code from the previous slides) List left; // to hold the left half List right; // to hold the right half }
Sort() – Dividing the list in two parts We have to actually make these lists have meaning. First, set the left lists head to point to the current lists head Our strategy was to create a pointer curr, originally pointing at the head of the current list curr will traverse the list, setting the left and right lists head and tail pointers at the appropriate nodes Finally, we will break the link between these two lists, making them independent
Sort() – Dividing the list in two parts How do we implement this in code? Lets set up a few things: Something to hold the midpoint The curr pointer used to traverse a list Something to keep track of our position in the list void List ::sort() { // (we wont be showing the code from previous slides) }
Sort() – Dividing the list in two parts How do we implement this in code? Lets set up a few things: Something to hold the midpoint The curr pointer used to traverse a list Something to keep track of our position in the list void List ::sort() { // (we wont be showing the code from previous slides) int mid = length/2; ListNode * curr = head; int pos = 1; // this is our position in the list }
Sort() – Dividing the list in two parts Now lets use curr to move down the list, and set up the left and right lists The key thing to remember is setting the head and tail pointers for the lists We dont need to change the next pointers very much, because the nodes are already linked together We have know the midpoint, and we keep track of the position in the list, so its easy to know where these heads/tails should be Dont forget to modify the length variable
Sort() – Dividing the list in two parts Write a loop to set up the left and right lists There are multiple ways to do this, but this was the setup we chose (feel free to do your own thing if it works) // loop until we reach the end of the list while(){ if(pos <= mid){ // do something } else { // do something else } curr = curr->next; pos++; }
Sort() – Dividing the list in two parts // loop until we reach the end of the list while(curr != NULL){ if(pos <= mid){ if(pos == 1) left.head = curr; if(pos == mid) left.tail = curr; left.length++; } else { if(pos == mid+1) right.head = curr; if(pos == length) right.tail = curr; right.length++; } curr = curr->next; pos++; }
Sort() – Dividing the list in two parts So what did we just do here? Lets draw it out
Sort() – Dividing the list in two parts No we just need to break the link between the two lists, figuratively speaking left.tail->next = NULL; right.head->prev = NULL; // good, now our left and right lists are separated
Sort – the Recursive Part We have successfully divided our list into two parts. Now we should sort them. left.sort(); right.sort(); // well that was easy
Sort – Merge Lets assume weve written a helper function called merge(list1, list2) which will merge two lists back together in the proper order. Our two lists are sorted, so now we call merge(list1, list2) on these lists merge(left, right); // cool
Sort – Merge We arent going to go into the details of merge(), but just the general ideas when it comes to merging on a linked list. We have the information about the left and right lists saved already, so lets just start with a blank slate. void List ::merge(List & left, List & right) { // our nodes still exist on the heap; we arent // going to delete them, but instead we will remove // all ties this list has with the nodes }
Sort – Merge We arent going to go into the details of merge(), but just the general ideas when it comes to merging on a linked list. We have the information about the left and right lists saved already, so lets just start with a blank slate. void List ::merge(List & left, List & right) { // our nodes still exist on the heap; we arent // going to delete them, but instead we will remove // all ties this list has with the nodes head=NULL; tail=NULL; length=0; }
Sort – Merge Now we should make some pointers to point to the heads of both the left and right lists. Lets call them currLeft, and currRight; these will be used to traverse the list and make comparisons between nodes void List ::merge(List & left, List & right) { ListNode * currLeft = left.head; listNode * currRight = right.head }
Sort – Merge We wont go into the rest of the merge implementation in too much detail You should compare the values of the nodes pointed at by currLeft and currRight. The node with the lesser value should become the new tail of the original list Whenever currLeft or currRight becomes the tail of the new list, you should have that pointer move down a node By doing this, the original list will become sorted Again, dont forget details like adjusting the length, and setting head, tail, next, and prev (if the list is doubly linked) pointers
Bonus Questions!
Summing two Reversed Linked Lists