Vous êtes sur la page 1sur 49

TCSS 342, Winter 2005

Lecture Notes
Linked List Implementation
Weiss Ch. 6, pp. 183-205
Weiss Ch. 17, pp. 537-548
1

Collections

collection: an object that stores data inside it;

a.k.a. a "data structure"


the objects stored are called elements
some maintain an ordering, some don't
some collections allow duplicates, some don't
an array is like a very crude "collection"
typical operations: add element, remove element,
clear all elements, contains or find element, get
size
most collections are built with particular kinds of
data, or particular operations on that data, in
mind

examples:

java.util.ArrayList, java.util.HashMap,
java.util.TreeSet

Java's Collection
interface
Java provides an interface java.util.Collection
to represent many kinds of collections. It has the
following methods:

public boolean add(Object o)


Appends the specified element to this collection.
public void clear()
Removes all of the elements of this collection.
public boolean contains(Object o)
Returns true if this collection contains the specified element.
public boolean containsAll(Collection coll)
Returns true if this collection contains all of the elements in
the specified collection.

Collection
interface,cont'd.
public boolean isEmpty()

Returns true if this list contains no elements.


public Iterator iterator()
Returns a special object for examining the elements of the
list in order (seen later).
public boolean remove(Object o)
Removes the first occurrence in this list of the specified
element.
public int size()
Returns the number of elements in this list.
public Object[] toArray()
Returns an array containing all of the elements from this list. 4

An example collection: List

list: an ordered sequence of elements,


each accessible by a 0-based index

one of the most basic collections

List features

ORDERING: maintains order elements were


added
(new elements are added to the end by default)
DUPLICATES: yes (allowed)
OPERATIONS: add element to end of list, insert
element at given index, clear all elements,
search for element, get element at given index,
remove element at given index, get size

some of these operations are inefficient! (seen later)

list manages its own size; user of the list does


not need to worry about overfilling it
6

Java's List interface

Java also has an interface java.util.List


to represent a list of objects. It adds the
following methods to those in Collection:
(a partial list)

public void add(int index, Object o)


Inserts the specified element at the specified position in
this list.
public Object get(int index)
Returns the element at the specified position in this list.
public int indexOf(Object o)
Returns the index in this list of the first occurrence of the
specified element, or -1 if the list does not contain it.

List interface, cont'd.


public int lastIndexOf(Object o)
Returns the index in this list of the last occurrence of the
specified element, or -1 if the list does not contain it.
public Object remove(int index)
Removes the object at the specified position in this list.
public Object set(int index, Object o)
Replaces the element at the specified position in this list
with the specified element.

Notice that the methods added to Collection


by List all deal with indexes; a list has indexes
while a general collection may not
8

Some list questions

all of the list operations on the previous slide


could be performed using an array instead!

open question: What are some reasons why


we might want to use a list class, rather than
an array, to store our data?

thought question: How might a List be


implemented, under the hood?

why do all the List methods use type Object?


9

Array list

array list: a list implemented using an


array to store the elements

encapsulates array and # of elements (size)


in Java: java.util.ArrayList
when you want to use ArrayList, remember
to import java.util.*;

10

ArrayList features

think of it as an auto-resizing array that can


hold any type of object, with many
convenient methods
maintains most of the benefits of arrays,
such as fast random access
frees us from some tedious operations on
arrays, such as sliding elements and
resizing
can call toString on an ArrayList to print
its elements

[1, 2.65, Marty Stepp, Hello]

11

Collections class

Class java.util.Collections has many utility


methods that do useful things to collections

public
public
public
public
public
public
public
public

static
static
static
static
static
static
static
static

void copy(List dest, List src)


void fill(List list, Object value)
Object max(Collection coll)
Object min(Collection coll)
void reverse(List list)
void shuffle(List list)
void sort(List list)
void swap(List list, int i, int j)

Example:

Collections.sort(myArrayList);

12

Analysis of ArrayList
runtime

OPERATION
add to start of list
add to end of list
add at given index
clear
get
find index of an object
remove first element
remove last element
remove at given index
set
size
toString

RUNTIME (Big-Oh)
O(n)
O(1)
O(n)
O(1)
O(1)
O(n)
O(n)
O(1)
O(n)
O(1)
O(1)
O(n)

13

Open questions

Based on the preceding analysis, when is


an ArrayList a good collection to use?
When is it a poor performer?

Is there a way that we could fix some of


the problems with the ArrayList?

Should we represent our list in a different


way?
14

some ArrayList problems

an insertion into a full list causes a large


reallocation
an insertion to the front "slides" down the
subsequent items (slow!)
a removal also "slides" down subsequent
items
still need to use indexes/subscripts a lot
somewhat ugly syntax to use it
15

The underlying issue

the elements of an ArrayList are too


tightly attached; can't easily rearrange
them
can we break the element storage apart
into a more dynamic and flexible
structure?

16

Nodes: objects to store


elements

let's make a special "node" type of object


that represents a storage slot to hold one
element of a list
each node will keep a reference to the
node after it (the "next" node)
the last node will have next == null
(drawn as / ), signifying the end of the list

17

Node implementation
/* Stores one element of a linked list. */
public class Node {
public Object element;
public Node next;
public Node(Object element) {
this(element, null);
}

public Node(Object element, Node next) {


this.element = element;
this.next = next;
}
18

Linked node problems (a)

Let's examine sample chains of nodes


together, and try to write the correct
code for each

each Node stores an Integer object

1.
before:

after:
19

Linked node problems (b)


2.
before:

after:

3.
before:

after:

20

Linked node problems (c)


4.
before:

after:

5.
before:

after:

21

Linked node problems (d)


6.
before:

after:

7.
before:

after:

22

Linked list

linked list: a list implemented using a


linked sequence of nodes

the list only needs to keep a reference to the


first node (we might name it myFront)
in Java: java.util.LinkedList
(but we'll write our own)

23

Linked list implementation


/* Models an entire linked list. */
public class MyLinkedList {
private Node myFront;
public MyLinkedList() {
myFront = null;
}
/* Methods go here */
}
24

Some list states of interest

empty list
(myFront == null)

list with one element

list with many


elements
25

Let's draw them together...

an add operation

at the front, back, and middle

a remove operation
a get operation
a set operation
an index of (searching) operation

26

Analysis of LinkedList
runtime

OPERATION
add to start of list
add to end of list
add at given index
clear
get
find index of an object
remove first element
remove last element
remove at given index
set
size
toString

RUNTIME (Big-Oh)
O(1)
O(n)
O(n)
O(1)
O(n)
O(n)
O(1)
O(n)
O(n)
O(n)
O(n)
O(n)

27

An optimization: mySize

problem: array list has a O(1) size


method, but the linked list needs O(n)
time
solution: add a mySize field to our linked
list

what changes must be made to the


implementation of the methods of the linked
list?

28

A variation: dummy
header

dummy header: a front node


intentionally left blank

myFront always refers to dummy header


(myFront will never be null)
requires minor modification to many methods
surprisingly, makes implementation much
easier

29

An optimization: myBack

problem: array list has O(1) get/remove of


last element, but the linked list needs
O(n)
solution: add a myBack pointer to the last
node

which methods' Big-Oh runtime improve to


O(1)?
what complications does this add to the
implementation of the methods of the list?
30

Doubly-linked lists

add a prev pointer to our Node class


allows backward iteration (for
ListIterator)
some methods need to be modified

when adding or removing a node, we must fix


the prev and next pointers to have the
correct value!
can make it easier to implement some
methods such as remove
31

Combining the approaches

Most actual linked list implementations


are doubly-linked and use a dummy
header and dummy tail
this actually makes a very clean
implementation for all linked list methods
and provides good efficiency for as many
operations as possible

32

Improved LinkedList
runtime

OPERATION
add to start of list
add to end of list
add at given index
clear
get
find index of an object
remove first element
remove last element
remove at given index
set
size
toString

RUNTIME (Big-Oh)
O(1)
O(1)
O(n)
O(1)
O(n)
O(n)
O(1)
O(1)
O(n)
O(n)
O(1)
O(n)

33

A particularly slow idiom


// print every element of linked list
for (int i = 0; i < list.size(); i++) {
Object element = list.get(i);
System.out.println(i + ": " + element);
}

This code executes an O(n) operation (get)


every time through a loop that runs n times!

Its runtime is O(n2), which is much worse than


O(n)
this code will take prohibitively long to run for
large data sizes

34

The problem of position

The code on the previous slide is wasteful


because it throws away the position each time

every call to get has to re-traverse the list!

it would be much better if we could somehow


keep the list in place at each index as we
looped through it

Java uses special objects to represent a


position of a collection as it's being
examined...

these objects are called "iterators"

35

Iterators in Java

interface java.util.Iterator

public boolean hasNext()


Returns true if there are more elements to
see

public Object next()


Returns the next object
in this collection, then
advances the iterator;
throws an exception
if no more elements
remain

public void remove()


Deletes the element that was
last returned by next (not always supported)36

Iterators on array lists

An iterator on an array list is simple; it


maintains an index of its current node

iterators are not as useful on array lists

Why?
What is the Big-Oh of get and set?
What is the Big-Oh of add and remove?
Does the array list iterator improve this?

37

Iterators on linked lists

an iterator on a linked list maintains (at


least) its current index and a reference to
that node
when iterator() is called on a linked list,
the iterator initially refers to the first
node (index 0)

38

Linked list iterator


iteration
when next() is called, the iterator:

grabs the current myNode's element value (32)


follows the next pointer on its node and increments
its index
returns the element it grabbed (32)

hasNext is determined by whether myNode is


null

(Why?)

39

How does remove work?

remove is supposed to remove the last


value that was returned by next
to do this, we need to delete the node
before myNode, which may require
modification

40

Fixing the slow LL idiom


// print every element of the list
for (int i = 0; i < list.size(); i++) {
Object element = list.get(i);
System.out.println(i + ": " + element);
}
Iterator itr = list.iterator();
for (int i = 0; itr.hasNext(); i++) {
Object element = itr.next();
System.out.println(i + ": " + element);
}

41

Iterator usage example


MyLinkedList names = new MyLinkedList();
// ... fill the list with some data ...
// print every name in the list, in upper case
Iterator itr = myList.iterator();
while (itr.hasNext()) {
String element = (String)itr.next();
System.out.println(element.toUpperCase());
}
// remove strings from list that start with "m"
itr = myList.iterator();
while (itr.hasNext()) {
String element = (String)itr.next();
if (element.startsWith("m"))
itr.remove(); // remove element we just saw
}
42

Benefits of iterators

speed up loops over linked lists' elements

What is the Big-Oh of each iterator method?

provide a unified way to examine all


elements of a collection

every collection in Java has an iterator method

in fact, that's the only guaranteed way to examine


the elements of any Collection (see Slide 4)

don't need to look up different collections'


method names to see how to examine their
elements

don't have to use indexes as much on lists

43

Iterator is still not perfect


// print odd-valued elements, with their indexes
Iterator itr = list.iterator();
for (int i = 0; itr.hasNext(); i++) {
int element = ((Integer)itr.next()).intValue();
if (element % 2 == 1)
System.out.println(i + ": " + element);
i++;
}

We still had to maintain the index variable i so


that we could print the index of each element
Wouldn't it be nice if the iterator could just tell
us the index?
44

More iterator problems


// add a 0 after any odd element
Iterator itr = list.iterator();
int i = 0;
while (itr.hasNext()) {
int element = ((Integer)itr.next()).intValue();
if (element % 2 == 1)
list.add(i, new Integer(0));
// fails
}

can't use the iterator to add, set element values


(iterator is programmed to crash if list is modified)
the iterator speeds up get and remove loops only
the iterator really should be able to help us speed
up loops that add elements or set elements' values!
45

ListIterator interface

Java interface java.util.ListIterator extends


Iterator to add these methods:

public
public
public
public

void add(Object o)
int nextIndex()
int previousIndex()
void set(Object o)

ListIterator is also able to iterate in reverse:


public boolean hasPrevious()
public Object previous()

get a ListIterator by calling these methods on the


List: (both ArrayList and LinkedList have them)

public ListIterator listIterator()


public ListIterator listIterator(int index)

46

ListIterator usage
// print odd-valued elements, with their indexes
for (ListIterator itr = list.listIterator();
itr.hasNext(); ) {
int element = ((Integer)itr.next()).intValue();
if (element % 2 == 1)
System.out.println(itr.previousIndex() + ": " +
element);
}
// add a 0 after any odd element
for (ListIterator itr = list.listIterator();
itr.hasNext(); ) {
int element = ((Integer)itr.next()).intValue();
if (element % 2 == 1)
itr.add(0);
}

47

ListIterator benefits

using the ListIterator internally to


implement the methods of the linked list
can make the code cleaner and simpler:

public Object get(int index) {


ListIterator itr = listIterator(index);
return itr.next();
}

should the code check the index for


validity?

48

Summary

lists are ordered, integer-indexed


collections that allow duplicates
lists are good for storing elements in order
of insertion and traversing them in that
order
linked lists are faster for add / remove
operations at the front and back, but slower
than array lists for arbitrary get / set
operations
lists are bad for searching for elements and
for lots of arbitrary add / remove operations
49

Vous aimerez peut-être aussi