CS62 - Spring 2020 - Class 8

Example code in this lecture

   LinkedList

Lecture notes

  • admin
       - quiz today
       - Darwin due on Tuesday

  • Readings: Chapter 1.3 (Page 142–146)

  • The general ArrayList class implements the List interface (http://docs.oracle.com/javase/7/docs/api/java/util/List.html)
       - Which of the following methods are performed quickly by the ArrayList class (quickly being sub-linear)? Slowly?
          - get
          - set the value of an existing element
          - add to the end
          - contains/indexOf
          - add at an index
          - remove an element
          - size
       - Quick:
          - get
          - set
          - add to the end (like we saw last time)
          - size
       - Slow:
          - adding an element at a particular index
             - have to shift everything after towards the end
          - removing an element
             - have to remove and shift everything after towards the front
          - contains
             - have to iterate over every item

  • No free lunch!
       - there's no one best data structure
          - to make certain operations fast we often have to compromise and make other operations slower
       - depending on what operations are important, one data structure may be more appropriate than another
       - we're going to start looking at different data structures that are good at different things

  • Linked lists
       - linked lists are a *recursive* data structure
          - the data structure is built out of nodes
          - a node stores both a data item as well as a reference to another node
          - draw a picture and compare and contrast a picture of an array

       - how could we do this using a class?

       - look at the Node class in LinkedList code
          - we'll use generics again to make the class general purpose
          - two things that we keep track of (with private instance variables)
             - private E data: the data that we're actually storing in the node
             - private Node next: a link to the next node in our linked list
          - we have methods that allow us to access and manipulate the data within the node
          - as well as methods that allow us to traverse and manipulate the links

       - how could you build a linked list with N data items?
          - start by creating node (node1) with some data
          - create a new node (node2) with some other data and point it's next element at node1
          - create a new node (nod3) with some more data and point it's next element at nod2
          - etc, up through nodeN
          - in the end, we'll have nodeN->nodeN-1->...->node3->node2->node1

       - We want to build a linked list data structure that supports similar operations to ArrayList (i.e., the List interface). How would we do it?
          - we'll just store a link the head of the linked list
          - all of our operations will start at the head and then modify/traverse the list appropriately

       - look at the LinkedList class in the LinkedList code
          - only keep track of a single node, the head of the list

       - Look at the two addFirst methods in LinkedList code
          - addFirst
             - create the new node
             - set the next value of that new node to head
             - set head to be the new node

          - addFirst2
             - does the same things, but utilizing the Node constructor
             - when we evaluate the right hand side head gets passed as the next parameter to the Node
             - we then just store this new node directory as the head

       - how would we remove the first element (assuming that there is at least one element)?
          - look at removeFirst in LinkedList code
          - save the value of head so we can return it
          - set head to be head.next()
          - return the value of the original head

  • iterating through linked lists
       - how can we iterate through all of the values in a linked list?
          - how do we know were the end of the list is?
             - it will be a node whose next value is null
          - make a variable (it's often called "finger" and then move it down the list until we fall off of the end)

          Node finger = head;

          while (finger != null ) {
             // do something with the current node, finger
             finger = finger.next();
          }

          - do it recursively:

          void iterate(Node current){
             if( current == null ){
                return null;
             } else {
                // do something with current
                iterate(current.next());
             }
          }

  • write a method contains(E value). Returns true if the linked list has that value (based on .equals) and false otherwise
       - look at contains in LinkedList code
          - start at the head and traverse through the nodes
          - key: check if we've seen the node
          - stop when we either find it or we run off the end
          - at the end, see if we either found it or if we fell off the end of the list


       - look at recursiveContains in LinkedList code
          - recursive data structures are often conducive to recursive method
          - start at the head
          - two base cases: we're either null or we've found it
          - if neither of this, look at the next eleement

  • Which of these methods are fast/slow for singly linked lists?
       - add to the end (slow)
       - add to the front (fast)
       - contains (slow)
       - get (slow)
       - insert at an index
       - remove an element
       - set the value of an existing element
       - size

  • What does the singly linked list buy us?
       - add and remove at the front of the list in constant time!
       - what is the downside (no free lunch!)?
          - get and set are now linear time operations