Lecture 11 - UMass CS !EdLab
Download
Report
Transcript Lecture 11 - UMass CS !EdLab
CMPSCI 187
Introduction to Programming
with Data Structures
Computer Science 187
Lecture 11: Stacks and Mazes
Announcements
1. Midterm exam: October 29 in class
2. A new OWL assignment is up, due 10/20.
3. Help for studying for the midterm is available
on the WIKI.
1
CMPSCI 187
Implementing Stacks
Book shows four possibilities:
As
an extension to Vector
With a list component
Using an array
As a linked structure
Included in these notes but not covered in class
Book defines a stack interface on page 259;
Java has no stack interface
2
CMPSCI 187
Implementing Stack as
Extension of Vector
Collection hierarchy includes java.util.Stack
The Vector class offers a growable array of
objects
Elements of a Vector accessed by index
Size can grow or shrink as needed
That is: Vector is just like ArrayList
3
CMPSCI 187
Implementing Stack as
Extension of Vector (2)
Top element of
the Stack is at
the highest index
4
CMPSCI 187
Stack Code
public class Stack<E> extends Vector<E> {
public E push (E e) {
add(e);
return e;
}
public E pop () throws EmptyStackException {
try {
return remove(size()-1);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new EmptyStackException();
}
}
...
5
CMPSCI 187
Stack Code (2)
public class Stack<E> extends Vector<E> {
...
public E peek () throws EmptyStackException {
try {
return get(size()-1);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new EmptyStackException();
}
}
public boolean empty () {
return size() == 0;
}
}
6
CMPSCI 187
Implementing Stack with a List
Can use ArrayList, Vector, or LinkedList:
All
implement the List interface
Name of class illustrated in text is ListStack
ListStack is an adapter class
Adapts
methods of another class to ...
Gives different names to essentially the same
operations
7
CMPSCI 187
ListStack Code
public class ListStack<E>
implements StackInt<E> {
private List<E> list;
public ListStack () {
list = new ArrayList<E>();
// or new Vector<E> or new LinkedList<E>
}
public E push (E e) {
list.add(e);
return e;
}
...
8
CMPSCI 187
ListStack Code (2)
public E peek () {
if (empty())
throw new EmptyStackException();
return list.get(list.size()-1);
}
public E pop () {
if (empty())
throw new EmptyStackException();
return list.remove(list.size()-1);
}
public boolean empty () {
return list.size() == 0;
}
9
CMPSCI 187
Implementing Stack Using an Array
Must allocate array with some default
capacity
Need to keep track of the top of the stack
Have no size method, so must track size
Similar to growable PhoneDirectory
Why not just use vector?
10
CMPSCI 187
Implementing Stack Using an Array (2)
11
CMPSCI 187
ArrayStack Code
public class ArrayStack<E>
implements StackInt<E> {
private static final int INITIAL_CAPACITY = 10;
private E[] data =
(E[]) new Object[INITIAL_CAPACITY];
private int top = -1;
public ArrayStack () { }
public boolean empty () { return top < 0; }
...
}
12
CMPSCI 187
ArrayStack Code (2)
public E push (E e) {
if (++top == data.length) reallocate();
return data[top] = e;
}
public E pop () {
if (empty()) throw new EmptyStackException();
return data[top--];
}
public E peek () {
if (empty()) throw new EmptyStackException();
return data[top];
}
13
CMPSCI 187
ArrayStack Code (3)
private void reallocate () {
E[] newData = (E[]) new Object[data.length*2];
System.arraycopy(data, 0, newData, 0,
data.length);
data = newData;
}
14
CMPSCI 187
Implementing Stack as a Linked Structure
We can implement Stack using a
linked list:
15
CMPSCI 187
LinkedStack Code
public class LinkedStack<E>
implements StackInt<E> {
private Node<E> top = null;
public LinkedStack () { }
public boolean empty () { return top == null; }
public E push (E e) {
top = new Node<E>(e, top);
return e;
}
...
}
16
CMPSCI 187
LinkedStack Code (2)
public E pop () {
if (empty()) throw new EmptyStackException();
E result = top.data;
top = top.next;
return result;
}
public E peek () {
if (empty()) throw new EmptyStackException();
return top.data;
}
17
LinkedStack Code (3)
CMPSCI 187
private static class Node<E> {
private E data;
private Node<E> next;
Node (E data, Node<E> next) {
this.data = data;
this.next = next;
}
}
18
CMPSCI 187
Comparison of Stack Implementations
Vector is a poor choice: exposes Vector methods
Likewise, extending other List classes exposes
their methods
Using a List as a component avoids exposing
LinkedStack
operations are O(1)
But Node objects add space overhead
ArrayList component is perhaps easiest
Still some space overhead (Stack+ArrayList)
Array as a component best in space and time
But somewhat harder to implement
19
CMPSCI 187
20
CMPSCI 187
M. C. Escher: Relativity
21
CMPSCI 187
Isabelle de Beaufort's environmental maze in the village of reignac sur Indre in France.
http://cccw.adh.bton.ac.uk/schoolofdesign/MA.COURSE/LMaze.html
22
CMPSCI 187
An Application of Stacks:
Solving a Maze
Mazes and Labyrinths: what’s the difference?
Enter
Exit
http://www.astrolog.org/labyrnth
23
CMPSCI 187
The Palace at Knossos
Greek myth of Thesesus and the Minotaur.
http://www.unmuseum.org/maze.htm
24
CMPSCI 187
What’s a Plausible Approach
to Solving a Maze?
Exit
Enter
25
CMPSCI 187
Solving a Maze
Represent as an array with black and white spaces
Path
Important decision /
choice points: which
path to follow?
Wall
Dead-ends
North
West
East
South
No-brainers
Special
26
CMPSCI 187
The General Cases
What direction can we move in?
not walls
not back where we came from
West
NESW
1 01 1
0
(=choice)
U
U
NESW
0 10 1
0
East
South
U
‘allowed’ directions
North
(=no choice)
NESW
0 00 1
0
(=deadend)
27
CMPSCI 187
What to do in each of the cases?
No-Brainer Case:
only one direction that we can move in.
suppose I know my current location and the direction to move?
I want to ‘take a step’ ….what’s my next coordinates?
columns
Helper
Method
col
rows
row-1
col
U
row
Helper
Method
NESW
1 0 0 0
North
row
col-1
U
row
col+1
row+1
col
‘next’ position
28
CMPSCI 187
What to do in each of the
cases?
The ‘choice’ or ‘decision’ case
need to remember all possibilities
[push each onto a stack]
need to choose one
[pop top one off the stack]
need to take a step in that direction
Helper Method
location
direction
U
NESW
1 01 0
location
direction
location
direction
location
direction
‘choice’ stack
‘choice’ stack
location
direction
location
direction
POP
possible next steps
29
CMPSCI 187
What to do in each of the cases?
Dead-end case
need to go back to previous choice point and explore an alternative path
[BACKTRACKING]
if there are NO previous choice points, then there is no path through the maze!
Where’s the next alternative(s) from the
previous choice point?? ON THE TOP OF
THE STACK.
U
location
direction
location
direction
POP
U
NESW
0 00 0
Becomes new
location and
direction
‘choice’ stack
‘choice’ stack
30
CMPSCI 187
Putting it all together
Given current location (=start) and goal location
Move one step into maze
get current direction given starting location
step in that direction
Repeat forever
Helper
Methods
v Is current location the goal?
if yes, report it found and stop.
v Get the allowed directions from here.
v Handle the cases
Only one choice.
get direction to go in
step in that direction
More than one choice
push a decision point onto the stack for EACH possible direction
pop the top location and set current location and direction
accordingly
take a step in that direction
No choices (dead-end)
If the stack is not empty, get top element (pop), set current
location and direction, and step in that direction
If the stack IS empty, report failure and stop.
31
CMPSCI 187
The Maze Program: Classes Used
All the stack classes:
LinkedStack.java,
StackfullException.java, StackEmptyException.java,
Node.java, Stack.java
The interface defining compass directions
CardinalDirections.java:
int NORTH = 0; int EAST = 1; int SOUTH = 2; int WEST = 3;
The class defining a location:
Location.java: protected int row; protected int col;
The class defining the structure of the information pushed
onto the stack
decBlock.java: myLocation = currPos; myDir=myDirection;
The class defining the maze itself:
Maze.java
A test program
TestMaze.java: reads in maze, prints it, and solves it,
32
CMPSCI 187
A Maze in a File
5 5
2 0
3 4
# .
#####
#.#.#
..#.#
#....
#####
The size of the maze (rows, columns)
The starting square (row, col)
The goal square
The symbol used for wall and path
The maze itself
33
CMPSCI 187
Maze.java
public class Maze implements CardinalDirections
{ protected char [ ][ ] maze;
//the maze; upper left corner of maze is (0,0)
protected int nrows, ncols;
//size of maze
protected location start;
//(row,col) coordinates of starting point
protected location goal;
//(row,col) coordinates of goal (i.e. the exit from the maze)
protected char wallSym;
//symbol used in file to designate a wall;
protected char pathSym;
//symbol used in file to designate a path;
protected boolean debug;
//debug flag...if true, debugging statements are on;
private int currDir;
//my current direction : North=0, East=1, etc.
private location currLoc;
//my current location in the maze (location is a row and column)
private int[] allowed;
//array of four possible directions I can move in from my
//current location with 0 indicating I can't go that way, and 1 indicating
//I can in order NESW
private LinkedStack choices;
//the stack to be used in the method mazeSolve()
private BufferedReader B;
private String fname;
//reader for maze file
//file that the maze is on
34
CMPSCI 187
The public methods of Java.maze
public Maze(String fileName, boolean IsDebugOn) throws IOException
sets up a buffered reader for the maze file
reads the array size, start location, goal location, and symbols from file
creates the maze array
creates the ‘choices’ stack
public char[ ][ ] getMaze()
‘get’ method which returns the two dimensional maze array
public void readMaze() throws IOException
reads the maze array itself from the file and fills maze array
public void writeMaze ()
prints the maze
public boolean mazeSolve()
returns true if the maze has a path from start to goal and false otherwise
public void closeFile() throws IOException
closes the maze file and frees I/O resources
35
CMPSCI 187
The private methods of
Maze.Java
private char toChar(String s)
returns the character equivalent of the first element of s
private int getDirection()
returns the direction corresponding to location of first allowed direction in
the allowed direction vector
private void step ()
given a direction, moves us to the next maze square in that direction by
modifying the current location
private int getStartDir()
given the starting location, determine the direction to step into the maze
private boolean isGoal()
compares current location and goal location; returns true if they match
private void getAllowed()
returns the four element vector indicating whether or not (1 or 0) we can
move in the corresponding direction from the current location
private void updateStack()
for every allowed direction from the current location, pushes a location
block onto the stack. Each block contains the current location and a
direction to move in.
36
CMPSCI 187
The mazeSolve method
public boolean mazeSolve()
{ currDir = getStartDir();
step();
while (true)
{
if(isGoal()) return true;
getAllowed();
int sum=sumAllowed();
//get direction to go in to step into the maze
//step into it
//we’ve found a solution, so we’re done.
//where can I go from here?
//add up the elements of the ‘allowed’ vector
switch(sum)
{ case 0:
//We have nowhere to go from this square (deadend)
{
if( !choices.isEmpty()) //Go back to previous decision point- search from there.
{
decBlock old = (decBlock) choices.pop();
currLoc = old.decLocation;
//update our location and direction
currDir = old.myDir;
step();
}
else return false;
//if stack is empty, nowhere to go back to, and no solution
break;
}
37
CMPSCI 187
Maze.java, continued
case 1:
//We have only one direction I can go in, so do it.
{ currDir=getDirection();
step();
break;
}
default:
{
updateStack();
//We have more than one direction to go in.
//push a block for each alternative (save them)
decBlock old = (decBlock) choices.pop(); //get one of the ones just pushed
//and start exploring.
currLoc = old.decLocation;
currDir = old.myDir;
step();
break;
}
}//end switch
}// end while
}//end mazeSolve
38
CMPSCI 187
A Test Program
import java.io.*;
public class test_Maze
{ public static void main(String args[]) throws IOException
{
boolean debug;
String str=null;
String fileName = args[0];
try
{str = args[1];}
catch (ArrayIndexOutOfBoundsException e)
{str="false";}
if (str.equalsIgnoreCase("true"))
debug=true;
else debug=false;
39
CMPSCI 187
Test Program: The Important Part
Maze mazer = new Maze(fileName, debug);
mazer.readMaze();
// read the Maze
mazer.closeFile();
//close out the input file
mazer.writeMaze();
//write the maze to the console
if (mazer.mazeSolve())
//solve the maze
System.out.println("This maze HAS a solution");
else
System.out.println("This maze DOES NOT HAVE a solution");
}
}
40
CMPSCI 187
Results
-------------Reading Maze from file:maze12x12.txt-------Size: 12 rows by 12 columns.
Start location for maze: [2, 0]
Goal location for maze: [10, 11]
# is used to designate a wall
. is used to designate a path
---------------------Finished Reading--------------------------Printing maze of size 12 rows by 12 columns------############
#..........#
..##########
#.#.#......#
#.#.########
#..........#
######.#####
#......#...#
######.#.#.#
#........#.#
##########..
############
---------------------------Done-------------------------This maze HAS a solution
41
CMPSCI 187
No Results
--------Reading Maze from file:maze12x12_noexit.txt---------Size: 12 rows by 12 columns.
Start location for maze: [2, 0]
Goal location for maze: [10, 11]
# is used to designate a wall
. is used to designate a path
---------------------Finished Reading-------------------------------Printing maze of size 12 rows by 12 columns-------############
#..........#
..##########
#.#.#......#
#.#.########
#..........#
######.#####
#......#...#
######.#.#.#
#........###
##########..
############
Change from previous example.
---------------------------Done----------------------------This maze DOES NOT HAVE a solution
42