CSE 143 Lecture 10

47
CSE 143 Lecture 10 Generics, Stack, Queue Based on slides by Alyssa Harding

description

CSE 143 Lecture 10. Generics, Stack, Queue Based on slides by Alyssa Harding. Review: ArrayIntList client. Now that we’ve built ArrayIntList , we can be its client - PowerPoint PPT Presentation

Transcript of CSE 143 Lecture 10

Page 1: CSE 143 Lecture 10

CSE 143Lecture 10

Generics,Stack, Queue

Based on slides by Alyssa Harding

Page 2: CSE 143 Lecture 10

Review: ArrayIntList client

• Now that we’ve built ArrayIntList , we can be its client

ArrayIntList list1 = new ArrayIntList(); list1.add(42); list1.add(7); list1.add(-10);

for (int i = 0; i < list1.size(); i++) { System.out.println(list1.get(i)); }

Page 3: CSE 143 Lecture 10

Generics

• But what if we want to have a list of Strings?

• We could copy ArrayIntList and change it into ArrayStringList…

• Java to the rescue: Generics!

Redundant!

Page 4: CSE 143 Lecture 10

ArrayList<E> uses Generics

• <E> is a type parameter

Page 5: CSE 143 Lecture 10

ArrayList<E>

•ArrayList<E> has all the methods we want:

// adds given value to end of list

void add(E value)

// adds given value at the given index

void add(E value, int index)

// removes value at the given index

void remove(int index)

// returns value at given index

E get(int index)

// returns size of list

int size()

E is the Element type

Page 6: CSE 143 Lecture 10

ArrayList<E>

• Now we can create and use a list of any type of Object:

ArrayList<String> list = new ArrayList<String>();

list.add(“hello”);

String s = list.get(0);

• However, this only works for Objects, not primitive data types, such as ints or doubles

Page 7: CSE 143 Lecture 10

Wrapper classes

• Java has classes that wrap the primitive types in objects:

• Example of autoboxing:ArrayList<Integer> list = new ArrayList<Integer>();

list.add(42);

int x = list.get(0);

primitive type object type

int Integer

double Double

char Character

boolean Boolean

Page 8: CSE 143 Lecture 10

ArrayList<E> client

• Now we can get back to our client code

ArrayList<Integer> list1 = new ArrayList<Integer>(); list1.add(42); list1.add(7); list1.add(-10);

for (int i = 0; i < list1.size(); i++) { System.out.println(list1.get(i)); }

Page 9: CSE 143 Lecture 10

Stacks & Queues

Page 10: CSE 143 Lecture 10

Stacks and Queues

• Sometimes it is good to have a collection that is less powerful, but is optimized to perform certain operations very quickly.

• Today we will examine two specialty collections:– stack: Retrieves elements in the reverse of the order they were

added.– queue: Retrieves elements in the same order they were added.

stack

queue

Page 11: CSE 143 Lecture 10

Abstract data types (ADTs)

• abstract data type (ADT): A specification of a collection of data and the operations that can be performed on it.– Describes what a collection does, not how it does it

• We don't know exactly how a stack or queue is implemented, and we don't need to.– We just need to understand the idea of the collection and

what operations it can perform.

(Stacks are usually implemented with arrays; queues are often implemented with a linked list.)

Page 12: CSE 143 Lecture 10

Stacks

• stack: A collection based on the principle of adding elements and retrieving them in the opposite order.– Last-In, First-Out ("LIFO")– The elements are stored in order of insertion,

but we do not think of them as having indexes.– The client can only add/remove

the last element added (the "top").

• basic stack operations:– push: Add an element to the top.– pop: Remove the top element.

Page 13: CSE 143 Lecture 10

Stacks in computer science

• Programming languages and compilers:– method calls are placed onto a stack (call=push, return=pop)– compilers use stacks to evaluate expressions

• Matching up related pairs of things:– find out whether a string is a palindrome– examine a file to see if its braces { } and other operators

match– convert "infix" expressions to "postfix" or "prefix"

• Sophisticated algorithms:– searching through a maze with "backtracking"– many programs use an "undo stack" of previous operations

method3

return varlocal varsparameters

method2

return varlocal varsparameters

method1

return varlocal varsparameters

Page 14: CSE 143 Lecture 10

Queues

• queue: Retrieves elements in the order they were added.– First-In, First-Out ("FIFO")– Elements are stored in order of

insertion but don't have indexes.– Client can only add to the end of the

queue, and can only removethe front of the queue.

• basic queue operations:– enqueue: Add an element to the back.– dequeue: Remove the front element.

queue

Page 15: CSE 143 Lecture 10

Queues in computer science

• Operating systems:– queue of print jobs to send to the printer– queue of programs / processes to be run– queue of network data packets to send

• Programming:– modeling a line of customers or clients– storing a queue of computations to be performed in order

• Real world examples:– people on an escalator or waiting in a line– cars at a gas station (or on an assembly line)

Page 16: CSE 143 Lecture 10

16

Stacks

• Stacks are a Last In First Out (LIFO) structure

// add value to the top of the stack

void push(E value)

// remove and return the value at the top

E pop()

// return the size

int size()

// return whether the stack is empty

boolean isEmpty()

Page 17: CSE 143 Lecture 10

17

Queues

• Queues are a First In First Out (FIFO) structure

// add value to the back of the queue

void enqueue(E value)

// remove and return the value at the front

E dequeue()

// return the size

int size()

// return whether the queue is empty

boolean isEmpty()

Page 18: CSE 143 Lecture 10

18

Interfaces & Implementations

Important!!• We’re using our own Stack<E> and Queue<E> interfaces

• We’re using our own ArrayStack<E> and LinkedQueue<E> implementations (classes)

• We are using generics with both the interfaces and the implementations, so we can store any type of Object in them

• Note: There are other implementations (and interfaces) of stacks and queues in the Java collections. They have more method and use different names for the methods. We are NOT using these!

Page 19: CSE 143 Lecture 10

19

Our Stack Interface

public interface Stack<E> {

public void push(E value);

public E pop();

public int size();

public boolean isEmpty();

}

Page 20: CSE 143 Lecture 10

20

Our Queue Interface

public interface Queue<E> {

public void enqueue(E value);

public E dequeue(); public int size();

public boolean isEmpty(); }

Page 21: CSE 143 Lecture 10

21

Stack and Queue client

Stack<Integer> s = new ArrayStack<Integer>();

Queue<Integer> q = new LinkedQueue<Integer>();

for (int i = 0; i < 3; i++) {

s.push(i);

q.enqueue(i);

}

System.out.println("stack = " + s); System.out.println("queue = " + q);

Page 22: CSE 143 Lecture 10

22

What does this do?Stack<Integer> s = new ArrayStack<Integer>();

Queue<Integer> q = new LinkedQueue<Integer>();

for (int i = 0; i < 3; i++) {

s.push(i);

q.enqueue(i);

}

System.out.println(s.pop());

System.out.println("stack = " + s);

System.out.println(q.dequeue());

System.out.println("queue = " + q);

Page 23: CSE 143 Lecture 10

23

Stack and Queue client methods: fillQueue

• We might want to fill a Queue with values:

public static Queue<Integer> fillQueue(int n) { Queue<Integer> q = new LinkedQueue<Integer>();

return q;

}

Note that the variable declaration and return value use the interface type

Page 24: CSE 143 Lecture 10

24

Stack and Queue client methods: fillQueue

• We might want to fill a Queue with values:

public static Queue<Integer> fillQueue(int n) { Queue<Integer> q = new LinkedQueue<Integer>(); for (int i = 0; i < n; i++) { q.enqueue(i);

} return q;

}

Note that the variable declaration and return value use the interface type

Page 25: CSE 143 Lecture 10

25

Stack and Queue client methods: queueToStack

• We might want to move values from a Queue to a Stack:

public static void queueToStack(

Queue<Integer> q, Stack<Integer> s) {

while ( ) {

}

}

Page 26: CSE 143 Lecture 10

26

Stack and Queue client methods: queueToStack

• We might want to move values from a Queue to a Stack:

public static void queueToStack(

Queue<Integer> q, Stack<Integer> s) {

while ( !q.isEmpty() ) { int n = q.dequeue(); s.push(n); }

}

Boolean zen!

Page 27: CSE 143 Lecture 10

27

Stack and Queue client methods: sum (first

attempt)• We might want to sum the values in a Queue:

public static int sum(Queue<Integer> q) { int sum = 0; while ( !q.isEmpty() ) { sum += q.dequeue(); }

return sum;

}

Page 28: CSE 143 Lecture 10

28

Stack and Queue client methods: sum (first

attempt)• We might want to sum the values in a Queue:

public static int sum(Queue<Integer> q) { int sum = 0; while ( !q.isEmpty() ) { sum += q.dequeue(); }

return sum;

}

But this destroys the Queue and leaves it empty!

Page 29: CSE 143 Lecture 10

29

Stack and Queue client methods: sum (2nd

attempt)• We might want to sum the values in a Queue:

public static int sum(Queue<Integer> q) { int sum = 0; for ( ) {

} return sum;

}

Page 30: CSE 143 Lecture 10

30

Stack and Queue client methods: sum

• We might want to sum the values in a Queue:

public static int sum(Queue<Integer> q) { int sum = 0; for (int i = 0; i < q.size(); i++) { int n = q.dequeue(); sum += n; q.enqueue(n); } return sum;

}

So we store values back in the Queue and loop the correct number of times.

Page 31: CSE 143 Lecture 10

31

Stack and Queue client methods: fillStack

• We might also want to fill a Stack:

public static Stack<Integer> fillStack(int n) { Stack<Integer> s = new ArrayStack<Integer>(); for (int i = 0; i < n; i++)

return s;

}

We can copy the Queue code and change it to use a Stack.

Page 32: CSE 143 Lecture 10

32

Stack and Queue client methods: fillStack

• We might also want to fill a Stack:

public static Stack<Integer> fillStack(int n) { Stack<Integer> s = new ArrayStack<Integer>(); for (int i = 0; i < n; i++) s.push(i); return s;

}

We can copy the Queue code and change it to use a Stack.

Page 33: CSE 143 Lecture 10

33

Stack and Queue client methods: stackToQueue

• We might also want to move values from a Stack to a Queue:

public static void stackToQueue(

Stack<Integer> s, Queue<Integer> q) {

while ( !s.isEmpty() ) { int n = s.pop(); q.enqueue(n); }

}

We can copy the Queue code and change it to use a Stack.

Page 34: CSE 143 Lecture 10

34

Stack and Queue client methods: sum (first

attempt)• We might want to sum the values in a Stack:

public static int sum(Stack<Integer> s) { int sum = 0; for (int i = 0; i < s.size(); i++) { int n = s.pop(); sum += n; s.push(n); } return sum;

}

What is wrong with this code?

Page 35: CSE 143 Lecture 10

35

Stack and Queue client methods: sum (first

attempt)• We might want to sum the values in a Stack:

public static int sum(Stack<Integer> s) { int sum = 0; for (int i = 0; i < s.size(); i++) { int n = s.pop(); sum += n; s.push(n); } return sum;

}

But if we copy the Queue code, we push and pop the same value over and over.

Page 36: CSE 143 Lecture 10

36

Stack and Queue client methods: sum (2nd

attempt)• We might want to sum the values in a Stack:

public static int sum(Stack<Integer> s) { int sum = 0; Queue<Integer> q = new LinkedQueue<Integer>(); for (int i = 0; i < s.size(); i++) { int n = s.pop(); sum += n; q.enqueue(n); }

queueToStack(q,s); return sum;

} Does this work?

Page 37: CSE 143 Lecture 10

37

Stack and Queue client methods: sum (2nd

attempt)• We might want to sum the values in a Stack:

public static int sum(Stack<Integer> s) { int sum = 0; Queue<Integer> q = new LinkedQueue<Integer>(); for (int i = 0; i < s.size(); i++) { int n = s.pop(); sum += n; q.enqueue(n); }

queueToStack(q,s); return sum;

}

Even though we store values in a Queue, i

increases and s.size() decreases, so we only

examine half the values

Page 38: CSE 143 Lecture 10

38

Stack and Queue client methods: sum (3rd attempt)

• We might want to sum the values in a Stack:

public static int sum(Stack<Integer> s) { int sum = 0; Queue<Integer> q = new LinkedQueue<Integer>(); while ( !s.isEmpty() ) { int n = s.pop(); sum += n; q.enqueue(n); } queueToStack(q,s); return sum;

}Does this work?

Page 39: CSE 143 Lecture 10

39

Stack and Queue client methods: sum (3rd attempt)

• We might want to sum the values in a Stack:

public static int sum(Stack<Integer> s) { int sum = 0; Queue<Integer> q = new LinkedQueue<Integer>(); while ( !s.isEmpty() ) { int n = s.pop(); sum += n; q.enqueue(n); } queueToStack(q,s); return sum;

}

Now the sum is correct, but our

resulting Stack is reversed! This

happens when we transfer from a Stack

to Queue and back.

Page 40: CSE 143 Lecture 10

40

Stack and Queue client methods: sum (final

version)• We might want to sum the values in a Stack:

public static int sum(Stack<Integer> s) { int sum = 0; Queue<Integer> q = new LinkedQueue<Integer>(); while ( !s.isEmpty() ) { int n = s.pop(); sum += n; q.enqueue(n); }

queueToStack(q,s);

stackToQueue(s,q);

queueToStack(q,s); return sum;

}

Now both the sum and the Stack are

correct.

Page 41: CSE 143 Lecture 10

41

Stack and Queue client methods: findMin

• We might want to find the minimum value in a Stack:

public static int findMin(Stack<Integer> s) { int min = 0; Queue<Integer> q = new LinkedQueue<Integer>(); while ( !s.isEmpty() ) { int n = s.pop(); if ( n < min ) min = n; q.enqueue(n); } queueToStack(q,s); stackToQueue(s,q); queueToStack(q,s); return min;

}

Does this work?

Page 42: CSE 143 Lecture 10

42

Stack and Queue client methods: findMin

• We might want to find the minimum value in a Stack:

public static int findMin(Stack<Integer> s) { int min = 0; Queue<Integer> q = new LinkedQueue<Integer>(); while ( !s.isEmpty() ) { int n = s.pop(); if ( n < min ) min = n; q.enqueue(n); } queueToStack(q,s); stackToQueue(s,q); queueToStack(q,s); return min;

}

What if the values in the Stack are all greater than 0? This would still return

0 as the minimum.

Page 43: CSE 143 Lecture 10

43

Stack and Queue client methods: findMin(final

version)• We might want to find the minimum value in a Stack:

public static int findMin(Stack<Integer> s) { Queue<Integer> q = new LinkedQueue<Integer>();

int min = s.pop();

s.push(min); while ( !s.isEmpty() ) { int n = s.pop(); if ( n < min ) min = n; q.enqueue(n); } queueToStack(q,s); stackToQueue(s,q); queueToStack(q,s); return min; }

Instead, we start our minimum at a value that

is in the Stack.

Page 44: CSE 143 Lecture 10

44

Preconditions

• Remember the precondition of Stack’s pop method?

• The Stack cannot be empty when we call pop

• Since we call pop in our method without checking that the Stack isn’t empty, our method has this precondition too

Page 45: CSE 143 Lecture 10

45

Preconditions

• How are we going to deal with this?

• We need to return a value, but what would we return if we were passed an empty Stack?

• We can comment this precondition, but that doesn’t stop clients from using our method incorrectly

Page 46: CSE 143 Lecture 10

46

Exceptions

• Java lets us throw exceptions in our methods:throw new <exception type here>();

• In this case, we want to throw an exception if the method was given an illegal argument, so we throw an IllegalArgumentException:

if ( s.isEmpty() ) throw new IllegalArgumentException();

Page 47: CSE 143 Lecture 10

47

Exceptions

• Always comment the type and cause of any exceptions you throw:

// throws IllegalArgumentException if the

// stack is empty