Title: Problem Solving with Data Structures using Java: A Multimedia Approach
1Problem Solving with Data Structures using Java
A Multimedia Approach
- Chapter 11 Abstract Data Types Separating the
Meaning from the Implementation
2Chapter Objectives
3Separating Meaning from Implementation
- Powerful engineering idea in computer science.
- Meaning
- Identify the behavior of an object or data
structure. - Build other program components to interact with
that behavior. - Implementation
- Hide how that behavior is implemented, so that no
program components can be dependent on the
implementation.
4Abstract Data Type Stacks
- An example of an Abstract Data Type (ADT)
- We can define the methods and the behavior apart
from any implementation. - There are multiple implementations, some better
than others. - Can use a stack to reverse a list in less time,
but more space. - A classic tradeoff! Space for time.
Only put on top,Never pull from bottom.
5A Stack is a LIFO List
- Last-In-First-Out (LIFO) List
- First item in the list is the last one out.
- Last one in is first one out.
I got here second!
I got here third!
I got here first!
This is the top of the stack
6New items go at the top
I got here second!
I got here third!
I got here fourth!
I got here first!
This is the new top of the stack
7Items only get removed from the top
I got here fourth! And now Im outta here!
I got here second!
I got here third!
I got here first!
This is the new (er, old) top of the stack
8What can we do with stacks?
- push(anObject) Tack a new object onto the top of
the stack - pop() Pull the top (head) object off the stack.
- peek() Get the top of the stack, but dont
remove it from the stack. - size() Return the size of the stack
9Separation of Concerns
- Separation definition of behavior of data
structure from implementation. - Lets one change without changing the other.
- Java allows us to use an interface as a way
specify that behavior definition.
10Stack Interface
- /
- An abstract definition of a stack
- _at_author Barb Ericson
- /
- public interface StackltEgt
- /
- Method to add the element to the top of the
stack - _at_param element the element to add
- /
- public void push(E element)
- /
- Method to return the top element on the
- stack, but not remove it from the stack
- _at_return the top object from the stack
- /
- public E peek()
Just defining the operations here. E is the type
of the things in the Stack. StackltEgt represents
the generic stack for any time element
11- /
- Method to remove the top element from the
- stack and return it
- _at_return the top element from the stack
- /
- public E pop()
- /
- Method to return the number of elements in
- the stack
- _at_return the number of elements in the stack
- /
- public int size()
- /
- Method to check if the stack is empty
- _at_return true if empty, else false
- /
- public boolean isEmpty()
12Creating an implementation
- We declare a class as implementing that
interface. - We can continue to use the ltEgt generic, so that
we can later create a stack for any type object.
13Stack as a LinkedList
- import java.util.LinkedList // Need for
LinkedList - /
- Class that represents a stack using a linked
list - of objects
- _at_author Mark Guzdial
- _at_author Barb Ericson
- /
- public class LinkedListStackltEgt implements
StackltEgt - / Where we store the elements /
- private LinkedListltEgt elements
- /
- Constructor that takes no arguments
- /
- public LinkedListStack()
- elements new LinkedListltEgt()
-
14- //// Methods ///
- /
- Method to add an element to the stack
- _at_param element the element to add
- /
- public void push(E element)
- // New elements go at the front
- elements.addFirst(element)
-
- /
- Method to return the top element on the
stack - but leave the element on the stack
- _at_return the top element on the stack
- /
- public E peek()
- return elements.getFirst()
15- /
- Method to remove the top element from a
stack - and return it
- _at_return the top element from the stack and
remove it - /
- public E pop()
- E toReturn this.peek()
- elements.removeFirst()
- return toReturn
-
- /
- Method to get the number of elements in the
stack - _at_return the number of elements in the stack
- /
- public int size()return elements.size()
- /
- Method to test if the stack is empty
- _at_return true if the stack is empty, else
false - /
16Using the Stack with Strings
- gt StackltStringgt stack new LinkedListStackltString
gt() - gt stack.push("This")
- gt stack.push("is")
- gt stack.push("a")
- gt stack.push("test")
- gt stack.size()
- 4
- gt stack.peek()
- "test"
- gt stack.pop()
- "test"
- gt stack.pop()
- "a"
- gt stack.pop()
- "is"
- gt stack.pop()
- "This"
Notice the use of ltStringgt
17A Stack ofPictures
- gt StackltPicturegt stack new LinkedListStackltPictu
regt() - gt stack.push(new Picture(FileChooser.getMediaPath(
"beach.jpg"))) - gt stack.push(new Picture(FileChooser.getMediaPath(
"arch.jpg"))) - gt stack.push(new Picture(FileChooser.getMediaPath(
"bridge.jpg"))) - gt stack.size()
- 3
- gt stack.peek()
- Picture, filename C\dsBook\media-source/bridge.jp
g - height 640 width 480
- gt stack.pop()
- Picture, filename C\dsBook\media-source/bridge.jp
g - height 640 width 480
- gt stack.pop()
- Picture, filename C\dsBook\media-source/arch.jpg
- height 480 width 360
- gt stack.pop()
- Picture, filename C\dsBook\media-source/beach.jpg
- height 480 width 640
Note You cant create an object using an
interface name, e.g., new StackltStringgt()
18A stack is a stack, no matter what lies beneath.
- Our description of the stack minus the
implementation is an example of an abstract data
type (ADT). - An abstract type is a description of the methods
that a data structure knows and what the methods
do. - We can actually write programs that use the
abstract data type without specifying the
implementation. - There are actually many implementations that will
work for the given ADT. - Some are better than others.
19New implementation Stack as Array
- /
- Implementation of a stack as an array
- _at_author Mark Guzdial
- _at_author Barb Ericson
- /
- public class ArrayStackltEgt implements StackltEgt
- / default size of the array /
- private static final int ARRAY_SIZE 20
- / Where we'll store our elements /
- private Object elements
20Constructor
- / Index where the top of the stack is /
- private int top
- /
- No argument constructor
- /
- public ArrayStack()
- elements new ObjectARRAY_SIZE
- top 0
-
21Methods for Stack as Array
- /
- Method to add an element to the top of the
stack - _at_param element the element to add
- /
- public void push(E element)
- // New elements go at the top
- elementstopelement
- // then add to the top
- top
- if (topARRAY_SIZE)
- System.out.println("Stack overflow!")
-
-
22- /
- Method to return the top element on the
stack - but not remove it.
- _at_return the object at the top of the stack
- /
- public E peek()
- if (top0)
- System.out.println("Stack empty!")
- return null
- else
- // this will give a warning but it is
unavoidable - return (E) elementstop-1
-
-
23- /
- Method to remove and return the top element
on the stack - _at_return the element on the top of the stack
- /
- public E pop()
- E toReturn this.peek()
- top--
- return toReturn
-
- /
- Method to return the number of elements in
the stack - _at_return the number of elements in the stack
- /
- public int size()return top
- /
- Method to check if the stack is empty
- _at_return true if the stack is empty else
false - /
24Trying out Stack as Array
- gt StackltStringgt stack new ArrayStackltStringgt()
25Pushing one element
26Push two more, pop one
- gt stack.push("Katie")
- gt stack.push("Jenny")
- gt stack.size() // without the ending '' it
prints out the result - 3
- gt stack.peek() // without the ending '' it
prints out the result - "Jenny"
- gt stack.pop()
- "Jenny"
27Critique the array-based implementation
- What happens if the number of elements in the
stack is more than 20?
28What are stacks good for?
- The algorithm for converting an equation into a
tree uses a stack. - Often use stacks when describing card games, like
solitaire. - The list of Web pages you have visited in a
browser is stored in a stack, so that you can go
back. - The list of operations you have executed is
stored in a stack, so that you can undo.
29Stacks describe function calls
- As new functions get called, position in old
functions get pushed on a stack. - So you always return to the last function you
were in. - If an error occurs, you get a stack trace.
- If your recursion goes into an infinite loop,
what error do you get? Stack overflow!
30A Stack Example New Reverse
- Recall our original implementation of reverse().
- We go to the end of the original list to find the
last(). - We then remove() it (which involves walking the
list until we find the one before last()) - We then insert it at the end of the new list (via
add(), which does last().insertAfter()). - All told For each node, we walk the whole list
three times. - O(nn2)O(n3)
31Original Reverse
- /
- Reverse the list starting at this,
- and return the last element of the list.
- The last element becomes the FIRST element
- of the list, and THIS points to null.
- /
- public LayeredSceneElement reverse()
- LayeredSceneElement reversed, temp
- // Handle the first node outside the loop
- reversed this.last()
- this.remove(reversed)
- while (this.getNext() ! null)
- temp this.last()
- this.remove(temp)
- reversed.add(temp)
-
Highly inefficient.Touching each node requires
touching every other node O(n2)
32New Reverse Push all, pull off reversed
- /
- Reverse2 Push all the elements on
- the stack, then pop all the elements
- off the stack.
- /
- public LayeredSceneElement reverse2()
- LayeredSceneElement reversed, current,
popped - StackltLayeredSceneElementgt stack
- new LinkedListStackltLayeredSceneElementgt()
33- // Push all the elements on the list
- currentthis
- while (current ! null)
-
- stack.push(current)
- current current.getNext()
-
- // Make the last element (current top of
stack) into new first - reversed stack.pop()
- // Now, pop them all onto the list
- current reversed
- while (stack.size()gt0)
- popped stack.pop()
- current.insertAfter(popped)
- current popped
-
- return reversed
-
34Whats the diff? Time
- How often is each node touched in reverse2()?
- Twice Once going onto the stack, once coming
off. - O(2n) gt O(n)
- The stack-based reverse is faster than the
original reverse.
35Whats the diff? Space
- How much space does reverse2() take?
- Whatever space the stack takes.
- How much additional space does reverse() take?
None - Very common tradeoff Space for time.
- You can make an algorithm go faster, by using
more space. - If you need to fit into less memory, you have to
do more processing, which takes more time.
36Testing Reverse in SoundListTest()
- public void reverseTest()
- Sound s null // For copying in sounds
-
- s new Sound(FileChooser.getMediaPath("guzdia
l.wav")) - SoundNode root new SoundNode(s)
-
- s new Sound(FileChooser.getMediaPath("is.wav
")) - SoundNode one new SoundNode(s)
- root.last().insertAfter(one)
-
- s new Sound(FileChooser.getMediaPath("scritc
h-q.wav")) - SoundNode two new SoundNode(s)
- root.last().insertAfter(two)
-
- s new Sound(FileChooser.getMediaPath("clap-q
.wav")) - SoundNode three new SoundNode(s)
- two.insertAfter(three)
-
- //root.playFromMeOn()
37Second ADT Introducing a Queue
- First-In-First-Out List
- First person in line is first person served
I got here second!
I got here third!
I got here first!
This is the front or head of the queue
This is the tail of the queue
38First-in-First-out
- New items only get added to the tail.
- Never in the middle
- Items only get removed from the head.
I got here second!
I got here third!
I got here first!
This is the front or head of the queue
This is the tail of the queue
39As items leave, the head shifts
I got here second!
I got here third!
I got here first! AND NOW IM UP!
Now, this is the front or head of the queue
This is the tail of the queue
Served!
40As new items come in, the tail shifts
I got here second!
I got here third!
I got here fourth!
Now, this is the tail of the queue
Now, this is the front or head of the queue
41Queue Operations
- push(element) Tack a new element onto the tail
(end) of the queue. - pop() Pull the top (head) element off the queue.
- peek() Get the head of the queue, but dont
remove it from the queue. - size() Return the size of the queue.
- isEmpty() Return true or false, if the size of
the queue is zero.
42Queue Interface
/ Interface to define an abstract queue
_at_author Barb Ericson / public interface
QueueltEgt / Push an element onto the
tail of the Queue _at_param element the element
to add to the queue / public void push(E
element) / Peek at, but don't remove,
the head of the queue _at_return the head of
the queue (top) / public E peek()
43- /
- Pop an object from the Queue
- _at_return the head (top) of the queue and
- remove it from the queue
- /
- public E pop()
- /
- Return the size of a queue
- _at_return the number of elements in the queue
- /
- public int size()
- /
- Method to see if the queue is empty
- _at_return true if the queue is empty, else
false - /
- public boolean isEmpty()
-
44Implementing a Queue as a Linked List
- import java.util. // LinkedList representation
- /
- Implements a simple queue using a linked list
- _at_author Mark Guzdial
- _at_author Barb Ericson
- /
- public class LinkedListQueueltEgt extends
AbstractQueueltEgt - / Where we'll store our elements /
- private LinkedListltEgt elements
-
45- /
- No argument constructor
- /
- public LinkedListQueue()
- elements new LinkedListltEgt()
-
- /// Methods
- /
- Push an element onto the tail of the Queue
- _at_param element the element to add to the
queue - /
- public void push(E element)
- elements.addFirst(element)
-
- /
- Peek at, but don't remove, top (first) of
queue - _at_return the first object in the queue
- /
- public E peek()
46- //
- Pop an object from the Queue
- _at_return the top object from the queue (and
remove it) - /
- public E pop()
- E toReturn this.peek()
- elements.removeLast()
- return toReturn
-
- /
- Return the size of a queue
- _at_return the number of elements in the queue
- /
- public int size() return elements.size()
- /
- Method to see if the queue is empty
- _at_return true if the queue is empty, else
false - /
- public boolean isEmpty() return size() 0
47Testing our implementationBehaving as expected?
- gt QueueltStringgt line new LinkedListQueueltStringgt
() - gt line.push("Fred")
- gt line.push("Mary")
- gt line.push("Jose")
- gt line.size()
- 3
- gt line.peek() // without ending '' prints the
result - "Fred"
- gt line.pop()
- "Fred"
- gt line.peek()
- "Mary"
- gt line.pop()
- "Mary"
- gt line.peek()
- "Jose"
- gt line.pop()
- "Jose"
48Queue as Array
- /
- Implements a simple queue using an array
- _at_author Mark Guzdial
- _at_author Barb Ericson
- /
- public class ArrayQueueltEgt extends
AbstractQueueltEgt - / constant for the size of the queue /
- private static final int ARRAY_SIZE 20
- / Where we'll store our elements /
- private Object elements
- / The index of the head /
- private int head
- / The index of the tail /
- private int tail
49- / No argument constructor /
- public ArrayQueue()
- elements new ObjectARRAY_SIZE
- head 0 tail 0
-
- /// Methods
- /
- Push an element onto the tail of the Queue
- _at_param element the element to add to the
queue - /
- public void push(E element)
- if ((tail 1) gt ARRAY_SIZE)
- System.out.println("Queue underlying
implementation failed") - else
- // Store at the tail,
- // then increment to a new open position
- elementstail element
- tail
-
50- /
- Peek at, but don't remove, the head of the
queue - _at_return the head of the queue (top)
- /
- public E peek()
- // this will give a warning but there is no
way around it - return (E) elementshead
-
51- /
- Pop an object from the Queue
- _at_return the head (top) of the queue and
- remove it from the queue
- /
- public E pop()
- E toReturn this.peek()
- if (((head 1) gt ARRAY_SIZE)
- (head gt tail))
- System.out.println("Queue underlying
implementation failed.") - return toReturn
-
- else
- // Increment the head forward, too.
- head
- return toReturn
-
-
52- /
- Return the size of a queue
- _at_return the number of elements in the queue
- /
- public int size() return tail-head
- /
- Method to see if the queue is empty
- _at_return true if the queue is empty, else
false - /
- public boolean isEmpty() return size() 0
53Again, testing implementation
- gt QueueltStringgt line new ArrayQueueltStringgt()
- gt line.push("Fred")
- gt line.push("Mary")
- gt line.push("Jose")
- gt line.size()
- 3
- gt line.peek() // without ending '' prints the
result - "Fred"
- gt line.pop()
- "Fred"
- gt line.peek()
- "Mary"
- gt line.pop()
- "Mary"
- gt line.peek()
- "Jose"
- gt line.pop()
- "Jose"
54How the array implementation of queue works
55Pushing Matt
56Pushing Katie
57Popping (returns Matt)
Notice that weve now permanently lost the
first cell.Challenge Can you recover that
cell?
58Improving the implementation
- Our two implementations have duplicated code.
- Check out isEmpty() in each.
- Where could we put the code so that its not
duplicated? - Interfaces cant have method bodies.
- We can use an abstract class.
59Abstract Queue Class
- /
- Class to define an abstract queue
- _at_author Barb Ericson
- /
- public abstract class AbstractQueueltEgt implements
QueueltEgt - /
- Push an object onto the Queue
- _at_param element the element to add to the
queue - /
- public abstract void push(E element)
60- /
- Peek at, but don't remove, the head of the
queue - _at_return the head of the queue (top)
- /
- public abstract E peek()
- /
- Pop an object from the Queue
- _at_return the head (top) of the queue and
- remove it from the queue
- /
- public abstract E pop()
- /
- Return the size of a queue
- _at_return the number of elements in the queue
- /
- public abstract int size()
61Finally, the isEmpty method, factored out
- /
- Method to see if the queue is empty
- _at_return true if the queue is empty, else
false - /
- public boolean isEmpty()
- return (size() 0)
-
-
62Revised ArrayQueue
- /
- Implements a simple queue using an array
- _at_author Mark Guzdial
- _at_author Barb Ericson
- /
- public class ArrayQueue extends AbstractQueue
- /// ... fields and other methods as before
- /
- Method to see if the queue is empty
- _at_return true if the queue is empty, else
false - /
- // commented out since inherited from
AbstractQueue - // public boolean isEmpty() return size()
0
63Revised LinkedListQueue
- /
- Implements a simple queue using a linked list
- _at_author Mark Guzdial
- _at_author Barb Ericson
- /
- public class LinkedListQueue extends
AbstractQueue - // ... fields and other methods as before
- /
- Check if the queue is empty
- _at_return true if no elements in the queue,
else false - /
- // commented out since inherited from
AbstractQueue - // public boolean isEmpty() return
this.size() 0
64Can switch implementations easily
- If inserting/deleting a lot, use LinkedList
- gt import java.util.
- gt ListltStringgt nameList new ArrayListltStringgt()
- gt nameList.add("Shayna")
- gt nameList.add("Marcus")
- gt nameList.add("Jakita")
- gt nameList
- Shayna, Marcus, Jakita
- gt import java.util.
- gt ListltStringgt nameList new LinkedListltStringgt()
- gt nameList.add("Shayna")
- gt nameList.add("Marcus")
- gt nameList.add("Jakita")
- gt nameList
- Shayna, Marcus, Jakita
How the List is used (methods and behavior) is
the same in both cases.
65A Common Pattern
- We see this structure repeated throughout
java.util - Interface defines ADT
- Abstract class defines common parts
- Concrete classes differ in implementation
66Switching implementations
- Switching the underlying implementation can
provide advantages. - Of speed
- Of flexibility
- For example, our stack implemented as an Array
can go out of bounds if grows too large. - But not if we use ArrayList!
67Using an ArrayListArrayListStack
- import java.util.
- /
- Implementation of a stack as an ArrayList
- _at_author Mark Guzdial
- _at_author Barb Ericson
- /
- public class ArrayListStackltEgt implements
StackltEgt - / Where we'll store our elements /
- private ListltEgt list new ArrayListltEgt()
- /
- No argument constructor
- /
- public ArrayListStack()
-
68- //// Methods ///
- /
- Method to add an element to the top of the
stack - _at_param element the element to add
- /
- public void push(E element)
- list.add(element)
-
- /
- Method to return the top element on the
stack - but not remove it.
- _at_return the object at the top of the stack
- /
- public E peek()
- return list.get(list.size() - 1)
-
69- /
- Method to remove and return the top element
on the stack - _at_return the element on the top of the stack
- /
- public E pop()
- return list.remove(list.size() - 1)
-
- /
- Method to return the number of elements in
the stack - _at_return the number of elements in the stack
- /
- public int size()return list.size()
70Main() for testing
- public static void main(String args)
- StackltStringgt stack new ArrayListStackltStrin
ggt() - stack.push("Matt")
- stack.push("Katie")
- stack.push("Jenny")
- System.out.println(stack.size())
- System.out.println(stack.peek())
- System.out.println(stack.pop())
- System.out.println(stack.pop())
- System.out.println(stack.pop())
-
71New ADT A Map
- A Map associates a value with a key.
- The key can be any unique object.
- The value can be any single object.
- If you store two values under one key, the second
value will overwrite the first value as THE value
for THAT key.
72Using a Map to create oil paintings
- Oil paintings have only one color for region
(size of brush) - Using the Java implementation of Map
(java.util.Map) to track how often a color (the
key) appears in a region. - For each region,
- Store color counts in map.
- Get most common (highest count) color.
- Set all colors in region to the most common color.
73oilPaint method in Picture
- /
- Method to do an oil paint effect on a
picture - _at_param dist the distance from the current
pixel - to use in the range
- _at_return the new picture
- /
- public Picture oilPaint(int dist)
- // create the picture to return
- Picture retPict new Picture(this.getWidth(),
this.getHeight()) - // declare pixels
- Pixel currPixel null
- Pixel retPixel null
74- // loop through the pixels
- for (int x 0 x lt this.getWidth() x)
- for (int y 0 y lt this.getHeight() y)
- currPixel this.getPixel(x,y)
- retPixel retPict.getPixel(x,y)
- retPixel.setColor(currPixel.getMostCommonC
olorInRange(dist)) -
-
- return retPict
-
75getMostCommonColorInRange in class Pixel
- /
- Method to return the most common color in
the given - range from the current pixel in the picture
or just - return this color.
- _at_param dist the distance to use for the
range - _at_return the most common color in this range
- /
- public Color getMostCommonColorInRange(int
dist) - MapltColor,Integergt colorMap new
HashMapltColor,Integergt() - Pixel currPixel null
- Integer value null
- Color theKey null
The variable colorMap is of type Map. We
instantiate HashMap, but could switch to another
implementation
76- // loop through the pixels around this one
within the distance - for (int currY y - dist currY lt y dist
currY) - for (int currX x - dist currX lt x
dist currX) - if (currY gt 0 currY lt
picture.getHeight() - currX gt 0 currX lt
picture.getWidth()) - currPixel picture.getPixel(currX,currY
) - theKey currPixel.getColor()
- value colorMap.get(theKey)
- if (value null)
- colorMap.put(theKey,1)
- else
- colorMap.put(theKey, value 1)
-
-
-
77- // find the color that is most common
- int maxValue 1
- int currValue 0
- theKey this.getColor() // use current
color as default - SetltColorgt keySet colorMap.keySet()
- for (Color key keySet)
- currValue colorMap.get(key)
- if (currValue gt maxValue)
- theKey key
- maxValue currValue
-
-
- return theKey
-
78Example Use