CS62 - Spring 2021 - Class 8

Example code in this lecture

   Interfaces
   LinkedList

Lecture notes

  • admin
       - quiz today
       - Darwin due on Tuesday
       - Remote support

  • interfaces
       - There are two main ways we can indicate shared behavior. The first is through inheritance.
       - The second is through interfaces. Interfaces define methods that a class must define. E.g.,
          public interface InterfaceName{
             public void method1();
             public int method2(int number);
             public ArrayList<String> anotherMethod(String myString);
          }

          (see ExampleInterface in Interfaces code)

       - A class can then "implement" these methods by adding "implements" in the class definition:

          public class A implements InterfaceName{

          }

          - we must then implement ALL of the methods described in the interface, or our code will not compile

       - Why might this be useful?
          - interfaces define a type, i.e., we can declare variables and parameters of that type
          - allows us to group objects together with similar functionality
             - public void example(InterfaceName obj){...}
             - we know that we can call any methods defined in the interface from that object
          - we can say, the only thing that's important to me is that the class implement method x, y and z

  • look at the SimpleInterface in Interfaces code
       - two methods

  • look at the NegativeNumber and PositiveNumber classes in Interfaces code
       - Two classes that both implement the SimpleInterface interface
       - Notice that if I don't include one of the methods in the class, Java will complain
       - I can also have other methods

  • look at the NumberUser class in Interfaces code
       - Like a class, interfaces define a type
       - The methods that we can call on variables/parameters of that type are those defined by the interface
       - Any object that implements that interface can be put into a variable/parameter of the interface type
       - in the main method, we can call the useNumbers method with either a NegativeNumber object *or* a PositiveNumber object.

  • look at the BasicList interface in Interfaces code
       - defines a very basic interface for lists
          - get/set
          - add (add to the end)
          - size

       - like classes, we can also use generics on interfaces

  • look at the BasicArrayList class in Interfaces code
       - identical to the version we saw last class
       - implements the interface

  • look at SimpleSearch.integerSearch in Interfaces code
       - We can specify the generic type for the interface (in this case an integer).
       - Note that *any* class that implemented the BasicList interface could be used here
       - Allows us to abstract away the implementation!

  • look at SimpleSearch.search in Interfaces code
       - Uses generics!
       - If we have a static method and we want to use generics, we can define a type variable within the method header <E>
          - this ensures the that the type of thing in the BasicList is the same as the thing that we're searching for

  • Java has a List interface for data structures that store data sequentially:
          - https://docs.oracle.com/javase/8/docs/api/java/util/List.html
          - lots of methods, but key: get and set and particular indices

  • 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... amortized)
          - 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

       - 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