320 likes | 504 Views
EXPRESSION TREES In this lecture we will discuss Expression trees as a method for storing & evaluating mathematical expressions. Resources: Barrons Chapter 10 p.341 plus M/C #s 9, 10, 11 AP Java Text Chapter 19 p.822-826 Handouts: 1. ExpressionTree.java. Expression tree:
E N D
EXPRESSION TREES In this lecture we will discuss Expression trees as a method for storing & evaluating mathematical expressions
Resources: • Barrons Chapter 10 p.341 plus M/C #s 9, 10, 11 • AP Java Text Chapter 19 p.822-826 • Handouts: • 1. ExpressionTree.java
Expression tree: • Algebraic Expression with parentheses and a defined precedence of operations • A nested structure that can be represented by a Binary (expression) Tree
Example: Operator + - * / / \ 1st 2nd operand operand • a + b can be represented as: + / \ a b
Each node of the Expression tree contains a “TOKEN” which is either an operator (+ - * /) or an operand ( some #) • The operand can be a variable or a number
Example: (a + 1) (bc + 5 – c) can be represented as:
Example: * / \ + - / \ / \ a 1 + c / \ * 5 / \ b c
Operators are represented by nodes with children • Operands are represented by leaves
Evaluating Expressions Represented by Trees: • The evaluation of an expression tree includes calculating the value of an expression when given values for the operands’ variables. • Recursion is the easiest way to implement an evaluation function for expression trees.
Here is the process: • If a node is an operand, we fetch its value • If a node is an operator, we apply that operator to the results of an evaluation of its left and right subtrees
* ---- operator / \ b c ----- operands • CODE EXAMPLE “ExpressionTree.java”: Walk thru the code’s evaluate function *** Assume operands & operators are represented by character strings in tree nodes ***
String value = (String) node.getValue (); double leftVal, rightVal; if (value.equals ("+")) { leftVal = evaluate (node.getLeft ()); rightVal = evaluate (node.getRight ()); return leftValue + rightValue; } else return Double.parseDouble (value);
// IN SPVM TreeNode exprTree; // Convert the expression into a tree. exprTree = (TreeNode) TreeUtil.createExpressionTree (expr); result = evaluate (exprTree); System.out.println ("Result = " + result);
(a + 1) (bc + 5 – c) * / \ + - / \ / \ a 1 + c / \ * 5 / \ b c
PREFIX , POSTFIX & INFIX Notations • INFIX Notation: • An inorder traversal of an expression tree printed out fully parenthesized • Conventional algebraic notation where an operator is placed BETWEEN the operands x + y • Requires recursive evaluation of subtrees
INFIX Notation: Infix Notation: ( a + 1 ) *((( b * c ) + 5 ) - c)
Prefix and Postfix: • Convenient for evaluating expressions: • they do not use parenthesis • do not need to take into account order of precedence • order of operations can be reconstructed from the expression
Prefix and Postfix: • These notations for an algebraic expression can be generated by traversing the expression in preorder (for prefix) and postorder (for postfix)
PREFIX Notation: (N L R) • Place the operator BEFORE the operands +xy • However, there is no need for parenthesis as there is only 1 way to correctly place them • Prefix notation is also called Polish Notation Prefix Notation: * + a 1 - + * b c 5 c
POSTFIX Notation: (L R N) • Place the operator AFTER the operands xy+ • Again, there is no need for parenthesis as there is only 1 way to correctly place them • Postfix notation is also called ReversePolish Notation Postfix Notation: a 1 + b c * 5 + c - *
Evaluation of an Expression using Prefix and Postfix • Prefix & Postfix allow us to evaluate an algebraic expression in a single, sequential swipe
POSTFIX Notation can be evaluated: • Proceed from LEFT to RIGHT using a temporary STACK for holding unused operands and intermediate results
POSTFIX Notation can be evaluated... • Algorithm: • going from LEFT to RIGHT consider the next token • if it is an operand (#) push its value on the stack • if it is an operator: • pop the second operand • pop the first operand • perform the operation • push the result on the stack • we will be left with one value on the stack ---- the result of the evaluation
POSTFIX Notation can be evaluated... • EXAMPLE: a 1 + b c * 5 + c - * Lets Draw the Stack’s evolution showing the state of the stack AFTER each token is encountered
PREFIX Notation can be evaluated... • Proceed from RIGHT to LEFT using a temporary STACK for holding unused operands and intermediate results
PREFIX Notation can be evaluated... • Algorithm: • going from RIGHT to LEFT consider the next token • if it is an operand (#) push its value on the stack • if it is an operator: • pop the first operand • pop the Second operand • perform the operation • push the result on the stack • we will be left with one value on the stack ---- the result of the evaluation
NOTE: the operands appear in the same order in infix, prefix and postfix notations. Only the position of the operators is different. Infix Notation: ( a + 1 ) * ((( b * c ) + 5 ) - c) Prefix Notation: * + a 1 - + * b c 5 c Postfix Notation: a 1 + b c * 5 + c - *
Build an expression tree from a postfix or prefix notation • Instead of numbers, we push references to nodes on the stack, instead of performing an operation, we link the operator node to the nodes of the operands.
Algorthim: • going from LEFT to RIGHT consider the next token • Create a new node for the token • If it is an operand: • Set the LEFT and RIGHT children to null • Push the reference to the new node on the stack • If it is an operator: • Pop a reference from a stack • Set the new node’s RIGHT child to it • Pop another reference from the stack • Set the new node’s LEFT child to it • Push the reference to the new node on the stack