Lecture 8:  the LinkedList Class

 

Announcements

 

·      Homework #2 is graded – pick up @ end of class

o     solutions posted  (367-3 home page)

o     grading guide posted – What's New

o     check your grade; ask if errors not clear

we want to make sure the grading is correct

important to understand errors

 

·      Homework #3 is posted, due Tuesday

o     swap() for LinkedList class

o     no header node

o     swap the nodes, not the data

 

·      exam on 2/24,  7:15pm – 9:15pm

o     one more homework, #4, Tuesday

o     bring one sheet of notes

o     practice tests are posted

Implementing the Linked List Class

 

Like ArrayList, LinkedList will implement the List ADT

 

i.e., provide the same operations and conceptual picture

        but a different implementation (internal view)

 

so, keep the same method signatures

        change:   fields

                       method bodies

        why?  -- because some operations are more efficient

 

class LinkedList {

    // fields

    private Listnode items;

    private int numItems;

 

 

Here’s how the list ant, bat, rat is stored, assuming a header node:

 

 

 

 

 

 

 

 

 


Note:  "ant" is the first item in the list, which is numbered 0 in the List ADT

        so, get(0) returns "ant", and get(1) returns "bat"

 

The constructor:

·      a method with the same name as the class

·      initializes the fields of the class, in this case to represent an empty list

 

Public List() {// create an empty list w/ header node

    items = new Listnode(null);   

    numItems = 0;

}

 

0

 

 

 

 

L.add(item) – add to the end of the list:

 

·      use tmp to find the last node

 

          Listnode tmp = items;

    while (tmp.getNext() != null)

         tmp = tmp.getNext();

 

·      add new node after the one pointed to by tmp

(need special case for empty list if there’s no header node)

 

    easy to write, but time is O(N) where N = size of the list

 

alternative:  add a “lastNode” field to the LinkedList class

         

private Listnode lastNode; //new field

 

 

 

 

 

 

 

 

 


initialize lastNode in the constructor:

   

items

 
lastNode = items;

 

 

 

 

 

 


Now add to the end of the list is O(1) – (write the code)

        

lastNode.setNext(new listNode(ob));

    lastNode = lastnode.getNext();

 

Note:

·      code for other methods is a little more complicated

                    add(pos,item) // sometimes updates lastNode

         remove(pos)   // sometimes updates lastNode

·      but a common operation, add(ob), is more efficient

 

·      no method has higher time complexity

You try:

        Give English descriptions of what to do for

                    add(item, pos)

         get(pos)

         remove(pos)

         contains(item)

 

          Is special case code needed for each if

               no header node:

               have lastNode?

 

          What is the time complexity of each operation?

 

solutions:

 

add(item, pos)

·      throw exception if bad position

·      use tmp ptr to find node at pos – 1:

Listnode tmp = items;

while (pos>0){

    tmp = tmp.getNext();

    pos --;

}

·      add new node after tmp

 

no header:  do need special case (for pos = 0)

lastNode:  do need special case (for pos = size()-1)

 

time:  O(N)  where N is the size of the list

               or O(pos)

 

 

public Object remove(int pos) {

·       throw exception if bad pos

·       use tmp to find node at pos-1

Listnode tmp = items;

while (pos>0){

             tmp = tmp.getNext();

             pos --;

}

·       remove the node after tmp

}

no header node:  need special case  (for pos=0)

lastNode:  need special case (for pos = size()-1)

 

time:  O(N)  where N is the size of the list

               or O(pos)

 

public Object get(int pos) {

·       throw exception if bad pos

·       use tmp to find node at pos

Listnode tmp = items.getNext();

while (pos>0){

             tmp = tmp.getNext();

             pos --;

}

·       return that node's data

return tmp.getData();

}

no header node:  don't need special case  (start at tmp=items)

lastNode:  don't need special case

 

time:  O(N)  where N is the size of the list

               or O(pos)

Time comparisons

 

 

ArrayList

LinkedList

constructor

O(1)

O(1)

Size()

O(1)

O(1)

isEmpty()

O(1)

O(1)

add(ob)

O(1)**

O(1)*

add(pos,ob)

O(N)

O(N)

remove(pos)

O(N)

O(N)

get(pos)

O(1)

O(N)

contains(ob)

O(N)

O(N)

**O(N) if array is full, but O(1) overall;  why?

* requires lastNode

 

 

 

space comparisons

        linked list requires space for one pointer/item

        linked list requires space proportional to number of items

        (can keep array always proportional to # items)

 

implementation comparisons

        similar effort for each representation

 

Summary:  when to use ArrayList, when to use LinkedList

    ArrayList:  faster get, add/remove near end

    LinkedList:  faster add(1), remove(1)