600.226 Data Structures -- Spring 2013
Homework #7

Part A) Problem Prep

For this assignment you need to understand and implement basic stack and binary tree operations. Lots of resources for these are posted in the lecture notes and the detailed schedule. Also, you will be expected to use exceptions to detect and handle invalid input. If you are not familiar with handling them in try/catch blocks, review the intro Java exceptions examples. As always, read and review before starting the assignment.

We are used to seeing arithmetic and boolean expressions in what is called infix notation where binary operators appear between their operands, and unary operators appear to the left of their operand, such as 4+5*(6-23)/-7. A fully parenthesized infix expression is one in which the order of operations is completely determined by explicit parentheses; (4+((5*(6-23))/(-7))) is a fully parenthesized version of the expression above. There are also two other notations, prefix and postfix notation, where the operators appear before (prefix) or after (postfix) their operands. The prefix version of our example is + 4 / * 5 - 6 23 - 7 and the postfix version is 4 5 6 23 - * 7 - / +.

A classic way to do expression evaluation is using stacks and trees. The stack is used when parsing either a prefix or postfix expression, to create an expression tree in which the internal nodes are the operators and the external nodes are the data values. Here is the tree corresponding to the arithmetic expression above (each operator and operand is enclosed in ' ' to differentiate them from the slashes that represent the tree edges):

                 '+'
              /       \
           '4'           '/'
                      /       \
                    '*'       '-'
                   /   \        \
                 '5'   '-'      '7'
                       /  \
                     '6'  '23'

You can see that each type of notation corresponds to a particular binary tree traversal: infix - inorder, prefix - preorder, and postfix - postorder. For this assignment you are going to write a program that works with all three types of notation, but for set operations instead of arithmetic ones.

There are many on-line resources explaining the process of using a stack to create an expression tree. I recommend starting with wikipedia as usual. Chapters 3 and 4 in the Weiss textbook also have a thorough discussion of arithmetic expression evaluation using stacks and trees.

Part B) Testing -- due 2:30pm on Monday 3/11 -- 15 points

Write a set of JUnit4 tests that will thoroughly test any implementation of this Stack.java interface. Name your file StackTest.java and submit on Blackboard. We also advise using it to test whatever Stack implementation you end up using for the application below.

Part C) Application -- due 2:30pm Friday 3/15 -- 60 points

Write a program that will evaluate Set expressions which use the operators 'U' for union and 'I' for intersection. For simplicity, we will only process sets of integers, but it should be pretty straightforward to adapt your solution to sets of other types. We will also assume that both operators have the same precedence. A set will be represented in standard format, such as {1, 2, 3}. Your program must read a plain text file containing set expressions, one per line, and then process each line writing the results to an output file. Get the names of the input and output files from the user when the program begins.

Your main program must be able to do three main things for each expression in the input file:

  1. read it in postfix notation and compute the result,
  2. output the expression in prefix notation,
  3. output the expression in fully parenthesized infix notation.

For each valid line of input you must generate several lines of output in this exact order: the prefix version, the infix version, the postfix version (ie, the input itself), the resulting set (after complete expression evaluation), and a blank line. Some examples of input expressions and corresponding results are given below. You must format your results with exactly the same spacing and labels.

Input #1: {3} {5} U
Output #1: 
prefix:  U {3} {5}
infix:   ({3} U {5})
postfix: {3} {5} U
result:  {3, 5}

Input #2: {3} {5} I
Output #2: 
prefix:  I {3} {5}
infix:   ({3} I {5})
postfix: {3} {5} I
result:  {}

Input #3: {3, 4, 5} {4, 5, 6} I {1, 2} U
Output #3:
prefix:  U I {3, 4, 5} {4, 5, 6} {1, 2}
infix:   (({3, 4, 5} I {4, 5, 6}) U {1, 2})
postfix: {3, 4, 5} {4, 5, 6} I {1, 2} U
result:  {1, 2, 4, 5}

Input #4: {1, 5, 9} {1, 2, 3, 4, 5} {3, 4, 5} {6, 7} U U I
Output #4:
prefix:  I {1, 5, 9} U {1, 2, 3, 4, 5} U {3, 4, 5} {6, 7}
infix:   ({1, 5, 9} I ({1, 2, 3, 4, 5} U ({3, 4, 5} U {6, 7})))
postfix: {1, 5, 9} {1, 2, 3, 4, 5} {3, 4, 5} {6, 7} U U I
result:  {1, 5}

Your program should be able to detect and handle when an input string is not a properly formed postfix integer Set expression using exceptions. The types of errors you must catch are invalid operators, invalid operands, and invalid operator/operand combinations. All your program has to do when something invalid is detected is output an error message and continue, skipping past the invalid input line. You are not expected to say exactly what is wrong with an invalid expression - the notations in parentheses below are just for your understanding benefit. (Hint: if you use the stack correctly, it will be pretty easy to recognize a variety of invalid expressions.)

Here are some examples of invalid postfix integer set expressions, and the reasons why. Remember that your program does not have to say what is wrong with them, just catch that they are invalid.

{3} U {5}  (ill-formed expression, not postfix)
U {3} {5}  (ill-formed expression, not postfix)
{a} {b} U  (invalid operand)
2 3 I      (invalid operand)
{1} {5} *  (invalid operator)
{2 3} {5} U  (invalid operand)
{3} {4} {5} I  (ill-formed expression)
{3} {4} I {5} {6} U  (ill-formed expression)

Implementation Requirements - a violation of the first three will result in a 0 grade for the assignment:

  1. If you reuse or adapt code from the text or lectures, you MUST cite the original source in a comment. You may NOT reuse or adapt code from other sources.
  2. You MUST use stacks and trees, with any implementation of each that you choose to adapt from course code or write from scratch. You may not use the Java API Collections classes for these data structures. Make your Stack and Tree implementations generic and yet as simple as needed for this assignment. (Hint: make a simple BinaryTree class.)
  3. You MUST organize your code into multiple classes, minimally: one for stacks, one for trees, and the driver program. You will also need an OrderedSet of some sort. Reuse your code from prior assignments, or adapt a Java Collection class for this purpose. Make sure that you include all files needed to compile and run your program in the zip you submit.
  4. You must use exceptions (truly handled) to take care of poorly formed expressions. (See http://www.cs.jhu.edu/~joanne/cs107/code/Exceptions for examples of exception handling.) If you write your own Exception classes, be sure to include them in your submission. However, you can also choose to throw and catch appropriate Java API exceptions instead (ie, RuntimeException, IllegalArgumentException, etc.)
  5. You must adhere strictly to the input and output formats specified above.
  6. All original source code for this assignment must conform to our checkstyle format.
  7. Compilation & Submission: You must not have any compiler warnings when compiling with the "-Xlint:all" option. That means no array-based generics. Remember not to put any package declarations in your files. Also, continute to zip all source code files for the assignment into one compressed file for submission on Blackboard. Do not submit separate java files. Make sure that you include everything we need to compile and run your assignment for grading, even files taken from the course website. You may submit a separate README plain text file if you feel anything about your solution needs explaining. You are not required to submit printouts of any code, but may submit them for any files that you think warrant detailed feedback.

Grading Breakdown: