Objectives and Overview: Stacks and queues are special linear data structures that restrict the way in which elements can be added and deleted. Yet, these simple data structures have surprisingly wide utility in computer science and modeling applications. You will explore the properties and some of the applications of stacks and queues in this lab.
A postfix expression is an alternative way of writing an ariithmetic expression that allows a simple left-right evaluation strategy, as well as the elimination of the need for parentheses and operator precedence. Postfix expressions can be simply defined as follows:
Note that this definition is recursive. That is,we can build arbitrarily long postfix expressions from simpler ones by repeatedly applying this definition. Here are some examples, along with their ordinary (infix) interpretations on the right:
|
|
|
|
A number of observations follow from these examples. First, each postfix expression has only one interpretation in terms of the above definition. The second example, for instance, is a postfix expression only if 3 is identified as P1 in the definition, 4 5 - is identified as P2, and - is identified as op. Since part A of the definition allows 3 to be a postfix expression (that's the "base case"), and Part B can be used (recursively) to assure that the subexpression 4 5 - is a postfix expression, the definition allows that the entire expression 3 4 5 - - is a postfix expression.
The second observation is that there is no need to consider operator precedence or use parentheses when writing a postfix expression. The Infix expressions for the third and fifth examples in this list illustrate this point. The third example uses the fact that equal-preedence operators (- and -) are evaluated from left to right, while the fifth uses the fact that adjacent operators with different precedence (+ and *) are evaluated in order of precedence (* before +).
The third and most important observation we can draw from these examples is that the evaluation of a postfix expression can take place in a single left-right scan, using the assistance of a stack to store operands and intermediate results. This is not possible for infix expressions, whose evaluation may require many scans forward and backward before it is fully evaluated.
The postfix evaluation works as shown in the program simplerp.cpp which is available on the CS210 -> Tucker folder. The program has a Stack S for holding numerical (float) operands and intermediate results, and a String nextWord for holding the next operand or operator in the input. A loop is repeated for each input operand or operator until the end of the expression is reached. The stack S contains the results of all intermediate calculations, including the final value of the expression when the input processing is complete.
Set up a project to run this program, using the following as a guide for retrieving classes and header files from the CS210 -> Tucker -> source folder.
Run this program several times, using different postfix expressions such as the one shown in the output below. Note that the program shows the intermediate contents of the stack (the top is on the left) after each input number or operand is processed.
Not all sequences of operators and operands are valid postfix expressions. For instance, if the number of operators is not exactly one less than the number of operands, or if the operators are misplaced, the expression is not valid. Moreover, if any string in the expression is not either an operator or an operand, the evaluation cannot proceed.
Stacks and queues are also useful as "memory devices," storing or "remembering" alternative courses of action that can be taken in a situation that involves a series of complex decisions. Maze running is one of those situations, in which a feasible path from the start to the finish of a maze is not necessarily the one that is first chosen. This part of the lab asks you to write a C++ program that, using a stack, finds a feasible path from the start to the finish of a maze.
Mdore concretely, below is a 10-row maze (a copy is available in the file mymaze in the CS210 -> Tucker folder), in which the starting and finishing positions are marked by the characters "s" and "f". The presence of a wall is marked by the character "#", and the presence of an available move is marked by the blank character.
#################### #s# #f # # # ####### #### # # # # # # ### # ##### ### # # # # # ####### ## # # # ### # # # # # # # # # ## # # # # # # ####################
After a series of moves (marked below by the character "."), the program should either find a path to the finishing position or discover that there is no path from s to f. For example, the following display shows a solution to the above maze as an unbroken series of moves (.) from the starting position to the finishing position.
#################### #s# #f...#...# #.####### ####.#.#.# #.........#..#.###.# ##### ###.#........# # # #...#######.## # # #.### #...#..# # # #.#...#.#.##.# # #...#...#....# ####################
An immediate problem in solving this problem is one of representation. That is, what sort of data structure (class) can we use to represent the positions in a maze, and what functions are needed to simulate a move from one position to an adjacent one? We can begin by representing each position of the maze by an integer pair (row, col), denoting its row and column number (beginning from (0,0) in the upper lefthand corner. In this example, the starting positon is (1,1) and the finishing position is (1,11), and the solution path visits positions (2,1), (3,1), (3,2), (3,3), and so forth.
Two auxiliary classes are provided to facilitate this programming project, the Maze class and the Position class (these are combined in the single header file Maze.h in the CS210 -> Tucker folder). The Maze class takes care of reading a maze from an ASCII text file, displaying a Maze on the screen, and identifying whether a position in the maze is clear or has already been visited. Its functions are summarized below, for some maze M.
The Position class is a simple class, having two public variables, row and col. These mark the row and column number of a particular position in the maze. (You may wish to add functions to this class to facilitate solving this problem.)
And, of course, there is a stack (call it todo) of positions that is needed to keep track of alternative "fallback" positions for backtracking, in events where the current sequence of moves has led to a dead end. Note that several dead ends were reached in the maze run shown above [e.g., at position (1,16)]. The stack can also be used to store all positions that have been already visited in the search for a solution. Here is a sketch of an algorithm that runs the maze, using the above ideas:
Now design and debug the C++ program that solves this problem.
Finally, answer the following questions about your program after you have it working.
Submit your C++ program for Part 2 of this lab by dragging it to the Drop Box folder. Also hand in a hard copy listing of your program, along with your answers to the questions in Parts 1 and 2.
You are encouraged towork on the programming part of this lab in teams of two, but all answers to the questions should be developed individually.