Overview

In this project, you will be working with expression trees represented in First-Child-Next-Sibling format. Basic features of the tree include:

  • As an expression tree, every node represents either an operator or an operand. We restrict our operands to be integers only. For operators, we only consider the ones included in the table below. Refer Weiss 11.2.4 (pp. 468) for more details.
  • As a First-Child-Next-Sibling tree, each node keeps two links, one to its left child (if it is not a leaf) and one to its right sibling (if it is not the rightmost sibling) in the normal binary expression tree. Refer Weiss 18.1.2 (pp. 653) for more details.

Operator Definition Example Example Evaluation
+ Addition 5 + 3 8
- Subtraction 5 - 3 2
* Multiplication 5 * 3 15
/ (integer) Division 5 / 3 1
% Remainder 5 % 3 2
~ Negation ~5 -5

Examples: Representations of the expression (5+3)*((5*10)/2) is shown below.

Figure 1: Binary Tree Representation see image.

Figure 2: First-Child-Next-Sibling Tree Representation see image.

A tree node in both representations, maintain three fields: value and links to its two children. A binary tree maintains left and right children while a FCNS tree maintain firstChild and nextSibling children. Thus, in a binary tree representation +.left is 5 and +.right is 3 while in the FCNS representation +.firstChild is 5 and +.nextSibling is /. Note that the root nodes in both representations are the same.

Classes Overview

ExpressionBinaryTree and BinaryTreeNode (ExpressionBinaryTree.java): These two classes are used to represent expressions as binary trees. They are already implemented and provided to you. Do not make any modification to them.

Stack (Stack.java) and Queue (Queue.java): These two are generic implementation of stack and queue data structures respectively. You will find them useful in multiple tasks you need to implement in this project.

ExpressionFCNSTree and FCNSTreeNode (ExpressionFCNSTree.java): These two classes are used to represent expressions as FCNS-format trees. FCNSTreeNode is already implemented and provided to you. You should use it without making any modification. ExpressionFCNSTree is the main class that you will need to implement. We have provided the signature and description of all required methods in the template Java file. Below is the list of main tasks.

Figure 3: FCNS Tree reorganized see image.

Task 1: Reporting tree properties, including the size, height, and the number of tree nodes with certain features.

Task 2: Generating string representation of the tree. You will need to generate a string representing pre-order, post-order, and level-order (breadth-first) tree traversal of the FCNS tree respectively. Check the template file for format requirements and examples. For example, based on the FCNS tree in Figure 4, we should have the following string representations:

  • Prefix: "+ % 5 3 10 "
  • Postfix: "3 5 10 % + "
  • Level-order: "+ % 5 10 3 "

Task 3: Construct a FCNS tree from an expression in prefix notation using method buildTree(). This method should accept a String parameter filename, open the file and construct a FCNS expression tree based on the file contents. Each input file contains a numeric expression in prefix notation. For example, * + 5 3 / * 5 10 2 represents (5+3)*((5*10)/2) and corresponds to a FCNS tree shown in Figure 2. You can assume that the input file is error-free and that operators/operands are separated by a space. More examples are included in Figure 3 and 4.

Figure 3: FCNS for * ~ 5 10 see image.

Figure 4: FCNS for + % 5 3 10 see image.

Allowed Operators: add(+), subtract(-), multiply(*), divide(/), mod(%), negate(~). See the previous table for definitions and examples. Note that the tree supports unary operator ~ which can complicate your code.

Allowed Operands: integers (positive, negative, zero).

Task 4: Construct a binary tree from the FCNS tree using buildBinaryTree(). You will need to create the corresponding binary tree from the FCNS tree. For example, given the FCNS tree in Figure 2, a binary tree as in Figure 1 should be constructed and the root should be returned.

Task 5: Simulate in-order binary tree traversal with the FCNS tree using toStringPrettyInFix(). You will need to generate an infix notation of the expression. This is essentially simulating the in-order traversal of the corresponding binary expression tree. Note that you are NOT allowed to first construct the binary tree and then perform an in-order traversal to generate the string. The infix notation must be generated from the FCNS tree directly without building a binary tree. Parentheses need to be inserted to make the expression correct and human-readable. For example, the string generated from Figure 2 should be (5+3)*((5*10)/2).

Task 6: Evaluate the expression to an integer from FCNS tree, both recursively and iteratively. In this task, you will compute the result of the expression using the FCNS tree.

Task 6.1: Recursive Implementation. Implement method evaluate() for this task. The method walks through the tree and update two attributes for individual nodes: an integer value and a boolean flag nan to indicate whether the expression is not-a-number. Normally, the value of an operand node is the integer value of that operand; the value of an operator is the integer value associated with sub-expression rooted at that node. For example, the value of each tree node in Figure 4 after we perform evaluate() is given in the following table:

Node symbol 5 3 % 10 +
Node.value 5 3 2 10 12
Reason operand operand 5%3 operand (5%3)+10 = 2+ 10

The special situation not-a-number is triggered when a division has a zero divisor. Then the not-a- number flag needs to be propagated following this rule: any operation applying on a not-a-number yields a not-a-number result. When a node is marked as not-a-number, its value should be null.

Task 6.2: Iterative Implementation. Implement method evaluateNonRec() for this task. This method returns an integer value without changing any tree node attributes. For this task, you can assume all expressions are valid and there is no division-by-zero.

Sample inputs and results:

Input (prefix notation) Pretty-Infix notation (or Binary Tree Infix Traversal with parenthesis) FCNS Infix Notation (implementation not required)
* + 5 3 / * 5 10 2 ((5+3)*((5*10)/2)) 5 3 + 5 10 * 2 / *
* ~ 5 10 ((-5) * 10) 5 ~ 10 *
+ % 5 3 10 ((5 % 3) + 10) 5 3 % 10 +
/ 10 ~ * 5 2 (10 / -(5 * 2)) 10 5 2 * ~ /
3 5 10 5 2 * / + * * + 5 / 3 * 5 2 10 200
5 10 ~ * * ~ 5 10 -50
3 5 10 % + + % 5 10 3 12
2 5 * ~ 10 / / 10 ~ * 5 2 -1

Big-O

Template given to you in the starter package contains instructions on the REQUIRED Big-O runtime for a subset of methods. For those methods, your implementation should not have a higher Big-O.

Testing

Test cases will not be provided for this project. However, feel free to create test cases by yourselves. In addition, the main methods provided along with the template classes contain useful code to test your code. You can use command like " java ExpressionFCNSTree " to run the testing defined in main( ). You could also edit main( ) to perform additional testing. As always, a part of your grade will be based on automatic grading using test cases that are not provided to you. A set of expression files are provided to you for testing purpose.

Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.