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

    Use LinkedList:  when {add, remove, get} are most frequently

                                    near the front of the list

    otherwise, use ArrayList