Lecture 5 Notes

Download Report

Transcript Lecture 5 Notes

CS203 LECTURE 4
John Hurley
Cal State LA
Data Structures
Memorize This!
A data structure is a systematic way to organize information in
order to improve the efficiency of algorithms that will use the data
3
The Stack Class
java.util.Vector<E>
java.util.Stack<E>
The Stack class represents a last-infirst-out stack of objects. The elements
are accessed only from the top of the
stack. You can retrieve, insert, or
remove an element from the top of the
stack.
+Stack()
Creates an empty stack.
+empty(): boolean
Returns true if this stack is empty.
+peek(): E
Returns the top element in this stack.
+pop(): E
Returns and removes the top element in this stack.
+push(o: E) : E
Adds a new element to the top of this stack.
+search(o: Object) : int
Returns the position of the specified element in this stack.
4
Stacks
Stack<String> myStack = new Stack<String>();
myStack.push("Mary");
myStack.push("Bob");
myStack.push("Jack");
System.out.println(myStack.peek());
System.out.println(myStack.pop());
System.out.println(myStack.pop());
myStack.push("Sue");
myStack.push("Bill");
do {
System.out.println(myStack.pop());
} while (!myStack.isEmpty());
5
StackOperations
The next example uses two of the standard
stack operations:
Push: put an object at the top of the stack
Pop: take the object from the top of the stack
(remove and retrieve)
package demos;
//http://cs.fit.edu/~ryan/java/programs/generic/GenericStack-java.html
import java.util.*;
public class GenericStack<T> {
private ArrayList<T> stack = new ArrayList<T>();
private int top = 0;
public int size() {
return top;
}
public void push(T item) {
stack.add(top++, item);
}
public T pop() {
return stack.remove(--top);
}
public static void main(String[] args) {
GenericStack<Integer> s = new GenericStack<Integer>();
s.push(17);
int i = s.pop();
System.out.format("%4d%n", i);
}
}
package demos;
public class GenericStackDriver {
public static void main(String[] args) {
GenericStack<String> jenny = new GenericStack<String>();
jenny.push("Moe");
jenny.push("Curly");
jenny.push("Larry");
System.out.println(jenny.pop());
System.out.println(jenny.pop());
System.out.println(jenny.pop());
GenericStack<Integer> eric = new GenericStack<Integer>();
eric.push(1);
eric.push(2);
System.out.println(eric.pop());
System.out.println(eric.pop());
}
}
More Data Structures
So far we have studied arrays and lists, specifically ArrayLists, in detail, and also
discussed stacks.
As you know, this class is called "Programming With Data Structures," and
obviously, data structures are the main topic of the course. Over the next few
weeks, we will introduce a wide array (ha!) of new data structures.
Most of these data structures can be used as collections of wide ranges of
parameterized types
We will first learn to use some of the data structure types included with the JDK, then
implement one or two on our own, then return to using the built-in ones.
9
Java Collection Framework
A collection is a container object that holds a group
of objects, often referred to as elements.
The Java Collections Framework supports three
types of collections, named sets, lists, and maps.
10
Java Collection Framework hierarchy,
cont.
Set and List are subinterfaces of Collection.
11
The Collection Interface
The Collection interface is the root interface for manipulatin
a collection of objects.
12
ArrayList and LinkedList
Like an array, a list stores elements in a sequential order, and allows the
user to specify where the element is stored. The user can access the
elements by index.
Recall that an array is fixed once it is created. An array is suitable if your
application does not require insertion or deletion of elements.
A list can grow or shrink dynamically. ArrayList and LinkedList are the
most common concrete implementations of the List interface.
If you need to support random access through an index without inserting
or removing elements from any place other than the end, ArrayList offers
the most efficient collection. ArrayList is implemented using an
underlying array that begins with a default size. If the list outgrows the
array, a new array must be created and the contents of the old one
copied. Inserting values at arbitrary spots in the list involves moving all
the subsequent elements.
If your application requires the insertion or deletion of elements from
arbitrary locations in the list, use a LinkedList.
13
The List Interface, cont.
14
java.util.ArrayList
«interface»
java.util.Collection<E>
«interface»
java.util.List<E>
java.util.ArrayList<E>
+ArrayList()
Creates an empty list with the default initial capacity.
+ArrayList(c: Collection<? extends E>)
Creates an array list from an existing collection.
+ArrayList(initialCapacity: int)
Creates an empty list with the specified initial capacity.
+trimToSize(): void
Trims the capacity of this ArrayList instance to be the
list's current size.
15
Linked Lists
A linked list is a data structure consisting of a group of nodes which represent a
sequence.
In the simplest form of linked list, each node is composed of a datum and a reference
(in other words, a link) to the next node in the sequence. This is called a singly
linked list.
We will learn more about how linked lists are implemented in a few weeks;
this week we will use the Java Collections Framework LinkedList<E> class.
16
Linked Lists
In a doubly linked list, each node contains a reference to the next node and
a reference to the previous node.
Either a singly or double linked list may be circular; that is, last node
points to the first, and, in a circular doubly-linked list, the first node has a reference
to the last
Diagrams from Wikipedia: http://en.wikipedia.org/wiki/Linked_list
17
Linked Lists
Adding and removing elements from any spot in a linked list involves changing,
at most, one reference in each of two existing elements and setting, at most, two
references in a new element. Compare this to the expense of periodically creating
a new array and copying all the elements from an old one.
Add a node to a singly-linked list:
Inserting a node into a doubly linked list just involves also changing the reference
from the subsequent element and adding one from the new element back to the
previous one
18
Linked Lists
Delete a node from a singly-linked list:
19
java.util.LinkedList
LinkedList implements a doubly-linked list. It is a subclass of a hierarchy of
List classes, but more importantly it implements the List interface.
«interface»
java.util.Collection<E>
«interface»
java.util.List<E>
java.util.LinkedList<E>
+LinkedList()
Creates a default empty linked list.
+LinkedList(c: Collection<? extends E>) Creates a linked list from an existing collection.
+addFirst(o: E): void
Adds the object to the head of this list.
+addLast(o: E): void
Adds the object to the tail of this list.
+getFirst(): E
Returns the first element from this list.
+getLast(): E
Returns the last element from this list.
+removeFirst(): E
Returns and removes the first element from this list.
+removeLast(): E
Returns and removes the last element from this list.
20
package demos;
import java.util.*;
public class TestArrayAndLinkedList {
public static void main(String[] args) {
List<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(1); // 1 is autoboxed to new Integer(1)
arrayList.add(2);
arrayList.add(3);
arrayList.add(1);
arrayList.add(4);
arrayList.add(0, 10);
arrayList.add(3, 30);
System.out.println("A list of integers in the array list:");
System.out.println(arrayList);
LinkedList<Object> linkedList = new LinkedList<Object>(arrayList);
linkedList.add(1, "red");
linkedList.removeLast();
linkedList.addFirst("green");
System.out.println("Display the linked list backward:");
for (int i = linkedList.size() - 1; i >= 0; i--) {
System.out.print(linkedList.get(i) + " ");
}
}
}
21
Linked Lists
Based on the info above, you might expect linked lists to be much more
efficient than array lists. However, data in a linked list is accessed sequentially;
we start at the head of the list and follow the references. This is called
traversing the list.
node = list.firstNode
while node not null
(do something with node.data)
node = node.next
Source for pseudocode: Wikipedia
This may make a linked list less efficient than an array list for operations that
require a great deal of traversal, because accessing an array element by index
is very efficiently implemented.
Also, memory is allocated on the fly when a node is added. This makes it more
likely that different nodes will be far apart in memory, which makes it more
expensive to traverse the list.
22
package listcompare;
public class StopWatch {
private long elapsedTime;
private long startTime;
private boolean isRunning;
public StopWatch() {
reset();
}
public void start() {
if (isRunning) {
return;
}
isRunning = true;
startTime = System.currentTimeMillis();
}
public void stop() {
if (!isRunning) {
return;
}
isRunning = false;
long endTime = System.currentTimeMillis();
elapsedTime = elapsedTime + endTime - startTime;
}
23
public long getElapsedTime() {
if (isRunning) {
long endTime = System.currentTimeMillis();
return elapsedTime + endTime - startTime;
} else {
return elapsedTime;
}
}
public void reset() {
elapsedTime = 0;
isRunning = false;
}
}
package listcompare;
24
import java.util.List;
import java.util.Random;
public class ListComparer {
Random r = new Random();
public void sequentialAddsAtEnd(List<Integer> list) {
for (int counter = 0; counter < 100000; counter++) {
list.add(list.size(), counter);
//System.out.println(counter);
}
}
public void sequentialAddsAtBeginning(List<Integer> list) {
for (int counter = 0; counter < 100000; counter++) {
list.add(0, counter);
//System.out.println(counter);
}
}
public void randomAdds(List<Integer> list) {
for (int counter = 0; counter < 100000; counter++) {
list.add(r.nextInt(list.size()+1), counter);
//System.out.println(counter);
}
}
}
25
package listcompare;
import java.util.ArrayList;
import java.util.LinkedList;
public class ListDriver {
public static void main(String[] args) {
StopWatch s = new StopWatch();
ListComparer l = new ListComparer();
ArrayList <Integer> al;
LinkedList<Integer> ll;
al = new ArrayList<Integer>();
s.reset();
s.start();
l.sequentialAddsAtEnd(al);
s.stop();
System.out.println("Array List add at end exercise took " + s.getElapsedTime() + " ms");
ll = new LinkedList<Integer>();
s.reset();
s.start();
l.sequentialAddsAtEnd(ll);
s.stop();
System.out.println("Linked List add at end exercise took " + s.getElapsedTime() + " ms");
26
al.clear();
s.reset();
s.start();
l.sequentialAddsAtBeginning(al);
s.stop();
System.out.println("Array List add at beginning exercise took " + s.getElapsedTime() + " ms");
ll.clear();
s.reset();
s.start();
l.sequentialAddsAtBeginning(ll);
s.stop();
System.out.println("Linked List add at beginning exercise took " + s.getElapsedTime() + " ms");
al.clear();
s.reset();
s.start();
l.randomAdds(al);
s.stop();
System.out.println("Array List random exercise took " + s.getElapsedTime() + " ms");
ll.clear();
s.reset();
s.start();
l.randomAdds(ll);
s.stop();
System.out.println("Linked List random exercise took " + s.getElapsedTime() + " ms");
}
}
27
I/O Expense
This is a good time to point out that I/O is very
expensive. Rerun the code above with the
System.out.println statements uncommented.
28
Expense of traversing lists
Traversing an array list involves accessing the elements by array subscript
and is very efficient.
29
More on ArrayLists and Linked Lists
package listcompare;
public class StopWatch {
private long elapsedTime;
private long startTime;
private boolean isRunning;
public StopWatch() {
reset();
}
public void start() {
if (isRunning) {
return;
}
isRunning = true;
startTime = System.currentTimeMillis();
}
public void stop() {
if (!isRunning) {
return;
}
isRunning = false;
long endTime = System.currentTimeMillis();
elapsedTime = elapsedTime + endTime - startTime;
}
public long getElapsedTime() {
if (isRunning) {
long endTime = System.currentTimeMillis();
return elapsedTime + endTime - startTime;
} else {
return elapsedTime;
}
}
}
public void reset() {
elapsedTime = 0;
isRunning = false;
}
30
More on ArrayLists and Linked Lists
package listcompare;
import java.util.List;
public class ListComparer {
public void integerListSequentialAdds(List<Integer> list, int
count) {
}
for (int counter = 0; counter < count; counter++) {
list.add(0, counter);
}
public void integerListGets(List<Integer> list, List<Integer>
indices) {
for (int i: indices) {
list.get(i);
}
}
}
31
More on ArrayLists and Linked Lists
package listcompare;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
public class ListDriver {
public static void main(String[] args) {
Random r = new Random();
StopWatch s = new StopWatch();
ListComparer l = new ListComparer();
List<Integer> al = new ArrayList<Integer>();
List<Integer> ll = new LinkedList<Integer>();
int count = 100000;
int indexCount = 100000;
List<Integer> indices = new ArrayList<Integer> (indexCount);
for(int counter = 0; counter< indexCount; counter++)
indices.add(r.nextInt(count));
l.integerListSequentialAdds(ll, count);
l.integerListSequentialAdds(al, count);
s.reset();
s.start();
l.integerListGets(ll, indices);
s.stop();
System.out.println("Linked List exercise took " + s.getElapsedTime() + " ms");
}
}
s.reset();
s.start();
l.integerListGets(al, indices);
s.stop();
System.out.println("Array List exercise took " + s.getElapsedTime() + " ms");
32
Iterators
An iterator is an object that provides methods for
traversing the elements of a collection.
Even with Lists, which are not hard to manipulate
using loops, iterators sometimes provide easier
ways to traverse data structures
In many cases, the enhanced for loop is just as
convenient as an iterator.
33
The List Iterator
34
Iterator
public static void main(String[] args) {
List<String> names = new LinkedList<String>();
names.add("John");
names.add("Paul");
names.add("George");
names.add("Ringo");
String currName;
ListIterator<String> namesIterator = names.listIterator();
while(namesIterator.hasNext()){
currName = namesIterator.next();
System.out.println(currName + " " +
(currName.compareTo("Mick") < 0? "earlier than Mick": "not earlier than Mick"));
}
}
35
Queues and Priority Queues
A queue is a first-in/first-out data structure. Elements are
appended to the end of the queue
• In a standard queue, elements are removed from the
beginning of the queue.
• In a priority queue, elements are assigned priorities. When
accessing elements, the element with the highest priority is
removed first.
36
The Queue Interface
37
Using LinkedList for Queue
LinkedList implements the Queue interface, so you can
use the queue methods with an LL
38
Using LinkedList for Queue
public static void main(String[] args) throws
InterruptedException {
int time = 30;
Queue<Integer> queue = new LinkedList<Integer>();
for (int i = time; i >= 0; i--)
queue.add(i);
while (!queue.isEmpty()) {
System.out.println(queue.remove());
Thread.sleep(500);
}
}
39
Using LinkedList for Queue
Suppose eight children will take turns on two swings. At each round,
the next child in the queue gets swing # (round % 2).
public static void main(String[] args) throws InterruptedException {
int[] swings = {1,2};
Queue<String> queue = new LinkedList<String>();
queue.offer("Brian");
queue.offer("Diana");
queue.offer("Al");
queue.offer("Mary");
queue.offer("Mike");
queue.offer("Florence");
queue.offer("Carl");
queue.offer("Dennis");
int round = 0;
while (!queue.isEmpty()) {
System.out.println(queue.remove() + " uses swing # " + round %
swings.length);
Thread.sleep(1000);
round++;
}
}
40
The PriorityQueue Class
PriorityQueueDemo
Run
41
PriorityQueue
A PriorityQueue removes items in sorted order from lowest to highest
value, following a convention that the most important item gets the
lowest value, as in "First in Command, Second in Command," etc.
Change the Queue in the swingset example to a PriorityQueue; the
children will take turns in alphabetical order
To control the priority order, use a PriorityQueue with objects of a class
in which compareTo() is implemented to sort in the order you need, or
use a Comparator
Run the sample code that follows, then comment out the line that
creates the PriorityQueue and uncomment the two following lines that
create a Comparator and a PriorityQueue using it. Compare the
output.
42
Comparator
The Comparator interface specifies method compare(obj1, obj2). In
other words, instead of comparing this object to another one as
Comparable does, it compares two objects.
Here are some common scenarios for Comparator:
• Suppose we have a set of objects of a class that we didn't write and
can’t change. It may implement Comparable, but we want to sort using
a different order than the one that will be produced by Comparable.
• We need to be able to compare two objects of different classes without
changing the class code
• We need to sort the same kinds of objects in different ways at different
times
43
Priority Queue
package priorityqueue;
public class Product implements Comparable <Product>{
String name;
double priceInDollars;
public String getName() {
return name;
}
public double getPriceInDollars() {
return priceInDollars;
}
public Product(String nameIn, double priceInDollarsIn) {
name = nameIn;
priceInDollars = priceInDollarsIn;
}
public String toString(){
return name + ": $ " + priceInDollars;
}
@Override
public int compareTo(Product otherProduct){
return name.compareTo(otherProduct.getName());
}
44
Priority Queue
package priorityqueue;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
public class PriorityQueueDemo {
public static void main(String[] args) throws InterruptedException {
Queue<Product> queue = new PriorityQueue<Product>();
//
Comparator<Product> comp = new ProductComparatorUsingPrice();
//
Queue<Product> queue = new PriorityQueue<Product>(5, comp);
queue.offer(new Product("Socks", 7.99));
queue.offer(new Product("Shoes", 59.99));
queue.offer(new Product("Laces", 1.99));
queue.offer(new Product("Hat", 23.99));
queue.offer(new Product("Shirt", 41.99));
while (!queue.isEmpty()) {
System.out.println(queue.remove());
}
}
}
45
Priority Queue
package priorityqueue;
import java.util.Comparator;
public class ProductComparatorUsingPrice implements Comparator<Product>{
@Override
public int compare(Product p1, Product p2) {
double diff = p1.getPriceInDollars() - p2.getPriceInDollars();
if(diff > 0) return -1;
else if (diff < 0) return 1;
else return 0;
}
}