Stacks and queues are simple, yet very useful data structures. In this assignment, you will:
Starting code is in the StacksAndQueues project in your pair's repository (see link from schedule page for your team number). Commit your working code to the repository as you go.
Recall from day 1 of this course that when dealing with arrays that must grow in size, it is most efficient to double the capacity when the array is full, so that the expensive resizing operation occurs infrequently.
Your GrowableCircularArrayQueue class will implement the following operations specified by the Collections API: isEmpty(), clear(), size(), and contains(). You will also implement a toString() method for testing and convenience.
The GrowableCircularArrayQueue will also implement the following operations specified by the Queue ADT: enqueue(), dequeue(), peek().
Implementation requirements and hints:
The growable circular queue is an interesting implementation of a queue, but it is certainly not the only one. Here are three others:
For this part of the assignment, state the Big-Theta runtime of enqueue() and dequeue() for each of the four implementations. Then explain how each operation works in enough detail to justify the stated runtime. Record your answers in the Analysis.docx file in your Eclipse project and commit your work.
Programming languages must evaluate expressions following the syntax of the language. In this assignment, you will write a tool that will evaluate simple mathematical expressions given in different forms like 8 + 7 * 5 (infix) and 8 7 5 * + (postfix).
You are used to evaluating mathematical expressions that are written using infix notation, that is, each operator appears between the operands (numbers), such as
4 * 5or
6 * ( 10 - 7 ).However, that is not the only way to write expressions. In postfix notation, the operator is written after the operands. The previous examples would be written as
4 5 *and
6 10 7 - *,respectively.
Postfix notation has two advantages over infix notation. First, the order of operations is unambiguous without requiring parentheses. As we will see, 3 + ( 4 * 5 ) can be written as 3 4 5 * + , while ( 3 + 4 ) * 5 can be written as 3 4 + 5 *. Second, computers can evaluate postfix expressions easily using a stack.
In the very first example above, you can save the operands (4 and 5) on a stack and when you finally read an operator, just pop two operands and apply the operator. The second example works similarly - push the three operands (6, 10, and 7). When you read the - sign, pop the top two operands (7 and 10), apply the -, then push the answer back. When you read the * sign, pop the top two (3 and 6) and apply the * and push the answer. When you reach the end of the input, pop the answer. Your stack should now be empty - if not, the expression was malformed (too many operands). You can also detect if there were too many operators - can you see how?
Of course, calculators and computers don't require you to enter your expressions in postfix - they do it for you. Surprisingly, there is an algorithm to convert infix expressions to postfix that also uses a stack. Hint: in this postfix to infix conversion algorithm, the stack holds operators, not operands. If you try a couple examples, you'll see that this makes sense, since the order of the operands doesn't change, but the operators must somehow be stored and moved later in the output string.
So to evaluate infix, just convert it to postfix, then apply the algorithm described above!
Your starting code includes an abstract class called Evaluator, that has an abstract method to evaluate strings and return an int.
You will write PostfixEvaluator
and InfixEvaluator
subclasses in which you will override this method.
This is not the only way to do this, but is good extensible, object-oriented design.
(Perhaps we might want to write a PrefixEvaluator later, who knows?)
We want you to use the infixToPostfix conversion algorithm as the first step of evaluating infix expressions, so the tests include specific tests to isolate that method. Note that this method takes a String argument and returns a String.
Hint: The starting code has errors. I tried to make it so that using Eclipse to fix
the errors in the Main class will give you stubs of the classes and methods.
It should even guess that InfixEvaluator
should extend Evaluator
and that the return type of
infixToPostfix
should be a String. If not, you can make these adjustments.
You'll also need to add your own comments.
StringBuilder
for examples of how to use it if you
haven't.Grading of the implementations will be based on unit tests and programming style.
I reserve the right to add unit tests and to change the point values of the given unit tests.
Part of your grade on the circular queue will be for writing additional, well-named test cases that check different conditions.
Grading of the analysis will be based on the runtimes and justification.
Rough point distribution: queue implementation and tests: 35 points, analysis: 15 points, evaluator: 50 points. This initial thought is subject to change.