/// <summary> /// Builds the tree also has a stack that we'll use to /// keep track of the list's items. Shunting algorithm and precedence /// will now be applied right away before items are read/to tree. /// Observe the following algorithm. We use a regular expression to store the possible combinations (-,/,+,*,(,)) /// Symbols are partitoned out using the regular expression. Then we throw the entire list through shunting algorithm /// We then iterate through the list returned and use the stack to push,pop out items accordingly. /// </summary> /// <param name="expression"></param> /// <returns></returns> private Node BuildTree(string expression) { var nodeStack = new Stack <Node>(); string pattern = @"([-/\+\*\(\)])"; var tokens = Regex.Split(expression, pattern).Where(s => s != String.Empty).ToList <string>(); foreach (var tok in ShuntingAlgo(tokens)) { if (Char.IsLetter(tok[0])) { nodeStack.Push(new VariableNode(tok)); } else if (Char.IsDigit(tok[0])) { nodeStack.Push(new ValueNode(Double.Parse(tok))); } else { var on = new OperatorNode(tok[0]); on.right = nodeStack.Pop(); on.left = nodeStack.Pop(); nodeStack.Push(on); } } root = nodeStack.Pop(); return(root); }
// recursively evaluates tree private double RecursiveEvaluate(Node root) { OperatorNode operatorHolder = new OperatorNode(' '); ConstantNode constantHolder = new ConstantNode(0); VariableNode variableHolder = new VariableNode(string.Empty); double num = 0; if (root is OperatorNode) { // if node is operator, evaluate left and right subtrees operatorHolder = (OperatorNode)root; return(Operation(RecursiveEvaluate(root.Left), RecursiveEvaluate(root.Right), operatorHolder.Op)); } else if (root is VariableNode) { // if node is variable, return value stored in variable variableHolder = (VariableNode)root; num = Variables[variableHolder.Name]; return(num); } else { // if node is constant, return value of constant constantHolder = (ConstantNode)root; num = constantHolder.Value; return(num); } }
/// <summary> /// Builds the tree and has cases that it'll watch out for /// </summary> /// <param name="expression"></param> /// <returns></returns> Node BuildTree(string expression) { double val; for (int i = expression.Length - 1; i >= 0; i--) { switch (expression[i]) { case '+': case '-': case '*': case '/': OperatorNode newbie = new OperatorNode(expression[i]); if (root == null) { root = newbie; } newbie.left = BuildTree(expression.Substring(0, i)); newbie.right = BuildTree(expression.Substring(i + 1)); return(newbie); } } if (Double.TryParse(expression, out val)) { return(new ValueNode(val)); } else { return(new VariableNode(expression)); } }
private double Evaluate(Node node) { if (node != null) { if (node is OperatorNode) { OperatorNode opNode = node as OperatorNode; double evaluation = opNode.Evaluate(); return(evaluation); } if (node is ConstantNode) { ConstantNode constNode = node as ConstantNode; return(constNode.Value); } if (node is VariableNode) { VariableNode varNode = node as VariableNode; return(this.Variables[varNode.Name]); } } return(0); }
/// <summary> /// Places a new node into the expression tree from the currentNode in either the left or right branches. /// </summary> /// <param name="newNode"> The node being inserted. </param> /// <param name="currentNode"> The current position in the expression tree. </param> /// <returns> True of false depending on if the node could be inserted. Helps TraverseTree() with recursion. </returns> private bool InsertNode(Node newNode, Node currentNode) { OperatorNode positionNode = currentNode as OperatorNode; ConstantNode constNode = newNode as ConstantNode; OperatorNode opNode = newNode as OperatorNode; VariableNode varNode = newNode as VariableNode; // Right first to match the order of the expression stack. if (positionNode.Right == null) { if (opNode != null) { // Making sure nothing is in the new branches as the tree is being made. opNode.Left = null; opNode.Right = null; positionNode.Right = opNode; } else { if (varNode != null) { constNode = new ConstantNode() { Value = this.Variables[varNode.Name] }; } positionNode.Right = constNode; } return(true); } else if (positionNode.Left == null) { if (opNode != null) { // Making sure nothing is in the new branches as the tree is being made. opNode.Left = null; opNode.Right = null; positionNode.Left = opNode; } else { if (varNode != null) { constNode = new ConstantNode() { Value = this.Variables[varNode.Name] }; } positionNode.Left = constNode; } return(true); } return(false); }
/// <summary> /// Evaluate: /// This function is used to evaluate the expression tree. This logic is given to /// us in our Etree.c lecture notes. It takes in an ExpressionTreeBaseNode param. /// then tries to cast it as a ConstantNode, VariableNode, or OperatorNode. Based /// on what the node type is (see ExpressionTreeNodeFactory) it will return a value /// to be evaluated. (all root nodes should be operators) /// </summary> /// <param name="node"></param> /// <returns></returns> private double Evaluate(ExpressionTreeBaseNode node) { ConstantNode constantNode = node as ConstantNode; if (constantNode != null) { return(constantNode.Value); } // as a variable VariableNode variableNode = node as VariableNode; if (variableNode != null) { return(variableDictionary[variableNode.Name]); } // it is an operator node if we came here OperatorNode operatorNode = node as OperatorNode; if (operatorNode != null) { // but which one? switch (operatorNode.Operator) { case '+': return(Evaluate(operatorNode.Left) + Evaluate(operatorNode.Right)); case '-': return(Evaluate(operatorNode.Left) - Evaluate(operatorNode.Right)); case '*': return(Evaluate(operatorNode.Left) * Evaluate(operatorNode.Right)); case '/': try { return(Evaluate(operatorNode.Left) / Evaluate(operatorNode.Right)); } catch (DivideByZeroException e) { Console.Write(e.Message); Console.ReadLine(); } break; case '^': return(Math.Pow(Evaluate(operatorNode.Left), Evaluate(operatorNode.Right))); default: // if it is not any of the operators that we support, throw an exception: throw new NotSupportedException( "Operator " + operatorNode.Operator.ToString() + " not supported."); } } throw new NotSupportedException(); }
/// <summary> /// Finds where to insert a new node into the expression tree and calls InsertNode(). /// </summary> /// <param name="newNode"> The node being inserted. </param> /// <param name="currentNode"> The current position in the expression tree. </param> /// <returns> True or false depending on if the node could be inserted. Helps with recursion of the tree. </returns> private bool TraverseTree(Node newNode, Node currentNode) { OperatorNode positionNode = currentNode as OperatorNode; OperatorNode rightNode = positionNode.Right as OperatorNode; // Right first to match the order of the expression stack. if (positionNode.Right != null && rightNode != null) { if (!this.TraverseTree(newNode, rightNode)) { if (positionNode.Left is OperatorNode leftNode) { if (this.TraverseTree(newNode, leftNode)) { return(true); } else { return(false); } } else { return(this.InsertNode(newNode, currentNode)); } } } else if (positionNode.Left != null) { if (positionNode.Left is OperatorNode leftNode) { if (this.TraverseTree(newNode, leftNode)) { return(true); } else { return(false); } } else { return(this.InsertNode(newNode, currentNode)); } } return(this.InsertNode(newNode, currentNode)); }
/// <summary> /// Evaluates the expression tree's arithmetic. /// </summary> /// <returns>Returns the arithmetic calculation of the expression tree.</returns> public double Evaluate() { if (this.head == null) { if (this.singleNodeString != null) { return(this.variables[this.singleNodeString]); } else { return(this.singleNodeDouble); } } OperatorNode current = this.head; // A reference to the head of this expression tree. return(this.EvaluateHelper(current)); // Return the result of the helper method. }
private double Eval(BaseNode node) { //Evaluate based on the kind of node ConstantNode constnode = node as ConstantNode; if (constnode != null) { return(constnode.OpValue); } VariableNode varnode = node as VariableNode; if (varnode != null) { // used to be a try/catch, but now we set every new variable to 0 when the tree is made, so there will always be a value to obtain. return(variableDict[varnode.Name]); } OperatorNode opnode = node as OperatorNode; if (opnode != null) { switch (opnode.Op) { case '+': return(Eval(opnode.Left) + Eval(opnode.Right)); case '-': return(Eval(opnode.Left) - Eval(opnode.Right)); case '*': return(Eval(opnode.Left) * Eval(opnode.Right)); case '/': return(Eval(opnode.Left) / Eval(opnode.Right)); } } return(0); }
/// <summary> /// Builds an expression tree from expression string. /// Returns the root node of the expression tree. /// </summary> /// <param name="expression">Expression string.</param> /// <returns>Root of built expression tree.</returns> private ExpressionTreeNode BuildExpressionTree(string expression) { List <ExpressionTreeNode> postfixList = this.GetPostfixList(expression); Stack <ExpressionTreeNode> stack = new Stack <ExpressionTreeNode>(); foreach (ExpressionTreeNode currNode in postfixList) { if (this.IsConstantNode(currNode) || this.IsVariableNode(currNode)) { stack.Push(currNode); } else { OperatorNode currOpNode = currNode as OperatorNode; currOpNode.Right = stack.Pop(); currOpNode.Left = stack.Pop(); stack.Push(currOpNode); } } return(stack.Pop()); }
public override TreeNode FactoryMethod(string expression) { OpNodeFactory opNodeFactory = new ConcreteOpNodeFactory(); OperatorNode @operator = opNodeFactory.FactoryMethod(expression); if (@operator != null) { return(@operator); } else { bool int_success = Int32.TryParse(expression, out int int_result), double_success = Double.TryParse(expression, out double double_result); if (int_success) { return(new ValueNode(int_result)); } else { return(new ValueNode(double_result)); } } }
/// <summary> /// Prints the content of the expression tree to the console. /// </summary> /// <param name="node">The head of the expression tree.</param> /// <param name="result">The resultant string.</param> private void PrintTreeHelper(OperatorNode node, string result) { // In-order traversal algorithm. if (node.Left != null && node.Right != null) { // Check for OperatorNode or other node on left. if (!this.IsOperatorNode(node.Left)) { Console.Write(node.Left.Value); result += node.Left.Value; } else { this.PrintTreeHelper((OperatorNode)node.Left, result); } // Print current node value. Console.Write(node.Value); result += node.Value; // Check for OperatorNode or other node on right. if (!this.IsOperatorNode(node.Right)) { Console.Write(node.Right.Value); } else { this.PrintTreeHelper((OperatorNode)node.Right, result); } } else { // Print the leaf's value. Console.WriteLine(node.Value); } }
/// <summary> /// GetNode: /// returns a ExpressionTreeNode such based off of client specified parameters. Only supports /// Constant, Variable, and Operator Nodes. All of which inherit from ExpressionTreeBaseNode. /// </summary> /// <param name="nodeType"> /// nodeType string will specify which kind of ExpressionTree Node the client wishes to instantiate /// </param> /// <param name="operation"> /// operation char specifies the operation the client wishes to pass into OperationNode constructor. /// (Optional) If passed in with "C" or "V" it will not be used. /// </param> /// <returns> ExpressionTreeBaseNode </returns> public ExpressionTreeBaseNode GetNode(string nodeType, string operation = "\0") { ExpressionTreeBaseNode node; switch (nodeType) { case "C": /*constant*/ ConstantNode constantNode = new ConstantNode(); double result; if (double.TryParse(operation, out result)) { constantNode.Value = result; } node = constantNode; return(node); case "V": /*variable*/ VariableNode variableNode = new VariableNode(); variableNode.Name = operation; node = variableNode; return(node); case "O": /*operator*/ char op = operation[0]; node = new OperatorNode(op); return(node); default: return(null); } }
/// <summary> /// Better implementation that checks and evaluates off dict right away. /// Evaluate is self explained that returns the value (new or assigned) /// </summary> /// <returns></returns> private double Evaluate(Node node) { ValueNode constnode = node as ValueNode; if (constnode != null) { return(constnode.OpValue); } VariableNode varnode = node as VariableNode; if (varnode != null) { return(variableDict[varnode.Name]); } OperatorNode opnode = node as OperatorNode; if (opnode != null) { switch (opnode.Op) { case '+': return(Evaluate(opnode.Left) + Evaluate(opnode.Right)); case '-': return(Evaluate(opnode.Left) - Evaluate(opnode.Right)); case '*': return(Evaluate(opnode.Left) * Evaluate(opnode.Right)); case '/': return(Evaluate(opnode.Left) / Evaluate(opnode.Right)); } } return(0); }
/// <summary> /// Takes a valid string expression and returns a postfix ordered list of expression tree nodes. /// Uses Dijkstra's Shunting Yard algorithm. /// </summary> /// <param name="expression">Valid expression string.</param> /// <returns>Postfix ordered expression tree node list.</returns> private List <ExpressionTreeNode> GetPostfixList(string expression) { Stack <char> stack = new Stack <char>(); List <ExpressionTreeNode> postfixList = new List <ExpressionTreeNode>(); OperatorNodeFactory opFact = new OperatorNodeFactory(); char[] expressionArray = expression.ToArray <char>(); // loops over each char in expression string for (int i = 0; i < expressionArray.Length; i++) { char currChar = expressionArray[i]; // if the current char is a left parenthesis, push to stack if (currChar.Equals('(')) { stack.Push(currChar); } // if the current char is a right parenthesis else if (currChar.Equals(')')) { // while the top of the stack is not a left parenthesis, pop and add to list while (!stack.Peek().Equals('(')) { OperatorNode newOpNode = opFact.CreateOperatorNode(stack.Pop()); postfixList.Add(newOpNode); } stack.Pop(); // pop the left parenthesis from the top of the stack } // If the current char is a valid operator else if (opFact.IsValidOperator(currChar)) { // if the stack is empty or the next char is a left parenthesis if (stack.Count <= 0 || stack.Peek().Equals('(')) { stack.Push(currChar); } // otherwise the next char on the stack is an operator else { OperatorNode currOpNode = opFact.CreateOperatorNode(currChar); OperatorNode nextOpNode = opFact.CreateOperatorNode(stack.Peek()); // if curr operator has > precedence than the next operator, or equal precedence and right associativity if (currOpNode.Precedence > nextOpNode.Precedence || (currOpNode.Precedence == nextOpNode.Precedence && currOpNode.Associativity == OperatorNode.Associative.Right)) { stack.Push(currChar); // push the current operator on the stack } // if curr operator has < precedence than the next operator, or equal precedence and left associativity else { // add the next operator to the list stack.Pop(); postfixList.Add(nextOpNode); i--; } } } // if the current char is a digit (0-9) else if (char.IsDigit(currChar)) { string constantString = currChar.ToString(); for (int j = i + 1; j < expressionArray.Length; j++) { currChar = expressionArray[j]; // if the next char is a digit, append to constant string if (char.IsDigit(currChar)) { constantString += currChar.ToString(); i++; } // otherwise the next char is not part of this number else { break; } } postfixList.Add(new ConstantNode(double.Parse(constantString))); // add the complete number to the list } // if the current char is a variable else { string variable = currChar.ToString(); for (int j = i + 1; j < expressionArray.Length; j++) { currChar = expressionArray[j]; // if the next char is not an operator if (!opFact.IsValidOperator(currChar)) { variable += expressionArray[j].ToString(); i++; } // otherwise the next char is not part of this variable else { break; } } // add the complete variable to the list postfixList.Add(new VariableNode(variable, ref this.variables)); // Add the name to variabelNames list if it is not already in it. if (!this.variableNames.Contains(variable)) { this.variableNames.Add(variable); } } } // pop and add the rest of the stack to the list while (stack.Count > 0) { OperatorNode newOpNode = opFact.CreateOperatorNode(stack.Pop()); postfixList.Add(newOpNode); } return(postfixList); }
/// <summary> /// Initializes a new instance of the <see cref="ExpressionTree"/> class. /// </summary> /// <param name="expression">The arithmetic expression to be generated.</param> public ExpressionTree(string expression) { bool isSingleNodeTree = true; foreach (char op in this.Operators) { if (expression.Contains(op)) { isSingleNodeTree = false; break; } } if (isSingleNodeTree) { try { this.singleNodeDouble = Convert.ToDouble(expression); } catch (Exception) { this.singleNodeString = expression; } return; } // Generate the postfix notation for the expression. string[] postfixArray = this.ConvertToPostfix(expression); // Declare local variables. Node left, right; OperatorNode center; Stack <Node> nodeStack = new Stack <Node>(); ExpressionTreeFactory etf = new ExpressionTreeFactory(); // Iterate through each string in the postfix expression. for (int i = 0; i < postfixArray.Length; i++) { string s = postfixArray[i]; // Check for an empty string. if (s == string.Empty) { continue; } // Operator found! if (s.Length == 1 && this.Operators.Contains(s[0])) { // Create a new node with the top two nodes of the stack // as children and push it onto the top of the stack. center = (OperatorNode)etf.CreateNode(s); right = nodeStack.Pop(); left = nodeStack.Pop(); center.Left = left; center.Right = right; nodeStack.Push(center); } else { nodeStack.Push(etf.CreateNode(s)); // Push a non-operator node onto the stack. } } // Set the new head of the expression tree. this.head = (OperatorNode)nodeStack.Peek(); nodeStack.Pop(); }
/// <summary> /// Evaluates the arithmetic logic of an expression tree. /// </summary> /// <param name="current">The head of the tree to be evaluated.</param> /// <returns>Returns the evaluation of the expression tree.</returns> private double EvaluateHelper(OperatorNode current) { // Both children are leaves. if (!this.IsOperatorNode(current.Left) && !this.IsOperatorNode(current.Right)) { double leftVal, rightVal; if (this.IsVariableNode(current.Left)) { leftVal = this.variables[current.Left.Value]; // Get left value from dictionary. } else { leftVal = Convert.ToDouble(current.Left.Value); // Get left value from left node. } if (this.IsVariableNode(current.Right)) { rightVal = this.variables[current.Right.Value]; // Get right value from dictionary. } else { rightVal = Convert.ToDouble(current.Right.Value); // Get right value from right node. } return(current.Evaluate(leftVal, rightVal)); } else if (!this.IsOperatorNode(current.Left)) { // Only the right node is an operator node. double leftVal; if (this.IsVariableNode(current.Left)) { leftVal = this.variables[current.Left.Value]; // Get left value from dictionary. } else { leftVal = Convert.ToDouble(current.Left.Value); // Get left value from left node. } return(current.Evaluate(leftVal, this.EvaluateHelper((OperatorNode)current.Right))); } else if (!this.IsOperatorNode(current.Right)) { // Only the left node is an operator node. double rightVal; if (this.IsVariableNode(current.Right)) { rightVal = this.variables[current.Right.Value]; // Get right value from dictionary. } else { rightVal = Convert.ToDouble(current.Right.Value); // Get right value from right node. } return(current.Evaluate(this.EvaluateHelper((OperatorNode)current.Left), rightVal)); } else { // Both children are operator nodes. OperatorNode leftNode = (OperatorNode)current.Left, rightNode = (OperatorNode)current.Right; return(current.Evaluate(this.EvaluateHelper(leftNode), this.EvaluateHelper(rightNode))); } }
private ExpressionTreeBaseNode CreateExpressionTree(string expression) { Stack <ExpressionTreeBaseNode> operandStack = new Stack <ExpressionTreeBaseNode>(); int precidence = -1; /**********************************************************************/ // we will parse the expression string into the expression tree here! // /**********************************************************************/ int expressionIndex = 0; for (; expressionIndex < expression.Length; expressionIndex++) { char currentChar = expression[expressionIndex]; //not an operator if (!CheckOperatorPrecidence(currentChar, ref precidence)) { switch (currentChar) { //Constant (double) case ':': string constantValue = ""; expressionIndex++; //traverse expression to grab the entire constant (double), and store in constantValue while (expressionIndex < expression.Length && expression[expressionIndex] != ':') { constantValue += expression[expressionIndex]; expressionIndex++; } //create new ConstantNode and pass in the corresponding Value prop. ExpressionTreeBaseNode constantNode = nodeFactory.GetNode("C", constantValue); //convert type to constant node to print the value /* * ConstantNode node = (ConstantNode)constantNode; * Console.WriteLine("constantNode.Value = " + node.Value); */ operandStack.Push(constantNode); //push to operand stack break; //Variable (string) case '{': string variableName = ""; expressionIndex++; //traverse expression to grab the entire constant (double), and store in constantValue while (expressionIndex < expression.Length && expression[expressionIndex] != '}') { variableName += expression[expressionIndex]; expressionIndex++; } //create new VariableNode and pass in the corresponding Name prop. ExpressionTreeBaseNode variableNode = nodeFactory.GetNode("V", variableName); //convert type to constant node to set the default value VariableNode tempNode = (VariableNode)variableNode; SetVariable(tempNode.Name, 0.0); operandStack.Push(variableNode); //push to operand stack break; } } //currentChar is an operator else { //create new OperatorNode and pass in the corresponding operator prop. ExpressionTreeBaseNode operatorNode = nodeFactory.GetNode("O", currentChar.ToString()); //convert type to constant node to print the value OperatorNode tempNode = (OperatorNode)operatorNode; //pop two operands off of the stack ExpressionTreeBaseNode rightNode = operandStack.Pop(); ExpressionTreeBaseNode leftNode = operandStack.Pop(); //set operatornode left and right nodes. tempNode.Left = leftNode; tempNode.Right = rightNode; operandStack.Push(tempNode); //push operator node onto stack } } ExpressionTreeBaseNode expressionTreeRoot = operandStack.Peek(); //expression tree root is top of stack operandStack.Pop(); //pop top of stack (root) return(expressionTreeRoot); }
/// <summary> /// Edsger Dijkstra's Shunting Yard algorithm to convert an infix expression into postfix expression. /// </summary> /// <param name="infixExpression"> Infix expression. </param> /// <returns> Postfix expression. </returns> private Queue <Node> ShuntingYardAlgorithm(string infixExpression) { Queue <Node> postfixExpression = new Queue <Node>(); Stack <OperatorNode> operatorStack = new Stack <OperatorNode>(); for (int index = 0; index < infixExpression.Length;) { // Need to create substring until the first operator in the expression is reached. string substring = string.Empty; int substringIndex; for (substringIndex = index; substringIndex < infixExpression.Length && !ExpressionTreeFactory.MatchesCharacter(infixExpression[substringIndex]); substringIndex++) { substring += infixExpression[substringIndex]; } // If the substring is a number then turn that substring into one. if (double.TryParse(substring, out double numSubstring)) { postfixExpression.Enqueue(new ConstantNode() { Value = numSubstring }); index = substringIndex; } else { if (ExpressionTreeFactory.MatchesOperator(infixExpression[index])) { OperatorNode op = ExpressionTreeFactory.CreateOperatorNode(infixExpression[index]); try { // If there are operators on the operatorStack with higher precedence than op then they need to be removed from the stack and added to the postfixExpression first. while (operatorStack.Peek().Precedence >= op.Precedence && operatorStack.Peek().Operator != '(') { postfixExpression.Enqueue(operatorStack.Pop()); } } catch { // Possible for there to be an empty operatorStack. In that case, nothing happens. } operatorStack.Push(op); } else if (infixExpression[index] == '(') { operatorStack.Push(new OperatorNode('(') { Precedence = 4 }); } else if (infixExpression[index] == ')') { try { while (operatorStack.Peek().Operator != '(') { postfixExpression.Enqueue(operatorStack.Pop()); } } catch { throw new ArgumentException("Missing a left parenthesis"); } operatorStack.Pop(); } else { // If the substring cannot be parsed as a double (constant) or parentheses then it's a variable. postfixExpression.Enqueue(new VariableNode() { Name = substring }); if (!this.Variables.ContainsKey(substring)) { this.SetVariable(substring, 0); } index = substringIndex - 1; } index++; } } // End of the expression, popping all operators onto the queue while (operatorStack.Count != 0) { if (operatorStack.Peek().Operator != '(') { postfixExpression.Enqueue(operatorStack.Pop()); } else { throw new ArgumentException("Missing a right parenthesis"); } } return(postfixExpression); }
public ExpressionTree(string expression) { this.expression = expression; List <Node> postfixExpression = new List <Node>(); List <OperatorNode> operatorStack = new List <OperatorNode>(); string variable = string.Empty; string integer = string.Empty; string expressionString = string.Empty; OperatorNode opNode; // create postfix expression from given expression // begin by building postfixExpression and operatorStack lists for (int i = 0; i < expression.Length; i++) { if (variable != string.Empty && Char.IsLetterOrDigit(expression[i])) { variable += expression[i]; } else if (Char.IsLetter(expression[i])) { variable += expression[i]; } else if (variable == string.Empty && Char.IsDigit(expression[i])) { integer += expression[i]; } else if (integer != string.Empty && Char.IsDigit(expression[i])) { integer += expression[i]; } else if (!Char.IsLetterOrDigit(expression[i]) && (expression[i] != ')') && variable != string.Empty) { postfixExpression.Add(new VariableNode(variable)); // add variable to postfix expression opNode = new OperatorNode(expression[i]); // only do if operator stack is not empty if (operatorStack.Count > 0) { bool overPrecedence = true; // encountered operator or parenthesis, determine what happens next while (overPrecedence == true && operatorStack.Count != 0) { // pop operators from operator stack and push onto list expression if precedence is greater than or equal to operator being pushed onto operator stack if (operatorStack[operatorStack.Count - 1].Precedence <= opNode.Precedence) { postfixExpression.Add(operatorStack[operatorStack.Count - 1]); operatorStack.RemoveAt(operatorStack.Count - 1); } else { overPrecedence = false; } } } operatorStack.Add(opNode); // push operator onto operator stack variables.Add(variable, 0); // add variable to dictionary, initialize to 0 variable = string.Empty; // reset variable string to empty, prepare for new variable entry } else if (!Char.IsLetterOrDigit(expression[i]) && (expression[i] != ')') && integer != string.Empty) { postfixExpression.Add(new ConstantNode(double.Parse(integer))); // add integer to postfix expression opNode = new OperatorNode(expression[i]); if (operatorStack.Count > 0) { bool overPrecedence = true; // encountered operator or parenthesis, determine what happens next while (overPrecedence == true && operatorStack.Count != 0) { // pop operators from operator stack and push onto list expression if precedence is greater than or equal to operator being pushed onto operator stack if (operatorStack[operatorStack.Count - 1].Precedence <= opNode.Precedence) { postfixExpression.Add(operatorStack[operatorStack.Count - 1]); operatorStack.RemoveAt(operatorStack.Count - 1); } else { overPrecedence = false; } } } operatorStack.Add(opNode); // push operator onto operator stack integer = string.Empty; // reset integer string to empty, prepare for new integer entry } else if (expression[i] == '(') { operatorStack.Add(new OperatorNode('(')); } else if (expression[i] == ')' && variable != string.Empty) { postfixExpression.Add(new VariableNode(variable)); // add variable to postfix expression if (!variables.ContainsKey(variable)) { variables.Add(variable, 0); // add variable to dictionary, initialize to 0 } variable = string.Empty; // reset variable string to empty, prepare for new variable entry // while no left bracket found, pop operators from operator stack onto expression while (operatorStack[operatorStack.Count - 1].Op != '(') { postfixExpression.Add(operatorStack[operatorStack.Count - 1]); operatorStack.RemoveAt(operatorStack.Count - 1); } operatorStack.RemoveAt(operatorStack.Count - 1); // remove left bracket from operator stack } else if (expression[i] == ')' && integer != string.Empty) { postfixExpression.Add(new ConstantNode(double.Parse(integer))); // add integer to postfix expression integer = string.Empty; // reset integer string to empty, prepare for new integer entry // while no left bracket found, pop operators from operator stack onto expression while (operatorStack[operatorStack.Count - 1].Op != '(') { postfixExpression.Add(operatorStack[operatorStack.Count - 1]); operatorStack.RemoveAt(operatorStack.Count - 1); } operatorStack.RemoveAt(operatorStack.Count - 1); // remove left bracket from operator stack } else if (expression[i] == ')') { // while no left bracket found, pop operators from operator stack onto expression while (operatorStack[operatorStack.Count - 1].Op != '(') { postfixExpression.Add(operatorStack[operatorStack.Count - 1]); operatorStack.RemoveAt(operatorStack.Count - 1); } operatorStack.RemoveAt(operatorStack.Count - 1); // remove left bracket from operator stack } else if (expression[i] == '*' || expression[i] == '+' || expression[i] == '-' || expression[i] == '/') { operatorStack.Add(new OperatorNode(expression[i])); // adds operator to stack, only used when an operator appears after a ')' } // takes into account an expression of only one variable or one constant (ex. "x" or "12") if ((i + 1) == expression.Length && variable != string.Empty) { variables.Add(variable, 0); postfixExpression.Add(new VariableNode(variable)); } else if ((i + 1) == expression.Length && integer != string.Empty) { postfixExpression.Add(new ConstantNode(double.Parse(integer))); } } int operands = postfixExpression.Count; // keeps track of how many operands in expression // pop the rest of the operators off of the operator stack for (int j = 0; j < operatorStack.Count; j++) { int index = operatorStack.Count - 1; postfixExpression.Add(operatorStack[index - j]); } Node curr = null; // used to keep track of what node we are on int postIndex = postfixExpression.Count - 1; List <Node> markers = new List <Node>(); // build tree based on postfixExpression while (postIndex >= 0) { // setting first node if (root == null) { root = postfixExpression[postIndex]; // set root to first node encountered in list curr = root; // set tracker to root after it is created postIndex -= 1; } else { if (postIndex >= 0) { // determine where next node needs to go based on positional criteria if ((curr.Left != null) && (curr.Right != null) && markers.Count != 0 && postIndex == 0) { // Condition: if both left and right nodes are full, there are still markers in marker list, and we are now at the beginning of the postfixExpression // Do: then work back through markers until we've reached needed position and place last node while (curr.Left != null && curr.Right != null) { curr = markers[markers.Count - 1]; markers.RemoveAt(markers.Count - 1); } if (curr.Right == null) { curr.Right = postfixExpression[postIndex]; } else if (curr.Left == null) { curr.Left = postfixExpression[postIndex]; } postIndex -= 1; } else if (!(curr.Left is OperatorNode) && !(curr.Right is OperatorNode) && (curr.Left != null) && (curr.Right != null) && markers.Count != 0) { // Condition: if both left and right nodes are not operators, are not null, and there are markers still in marker list // Do: then move back to the last node that has an open left or right and place next node in open position while (curr.Left != null && curr.Right != null) { curr = markers[markers.Count - 1]; markers.RemoveAt(markers.Count - 1); } if (curr.Right == null) { curr.Right = postfixExpression[postIndex]; if (curr.Right is OperatorNode) { curr = curr.Right; } } else if (curr.Left == null) { curr.Left = postfixExpression[postIndex]; if (curr.Left is OperatorNode) { curr = curr.Left; } } postIndex -= 1; } else if (curr is OperatorNode && !(postfixExpression[postIndex] is OperatorNode) && !(postfixExpression[postIndex - 1] is OperatorNode)) { // Condition: if we are currently on an operator node, and the next two nodes on postfixExpression are not operators // Do: then add these two nodes to the right and left of our current node curr.Right = postfixExpression[postIndex]; curr.Left = postfixExpression[postIndex - 1]; postIndex -= 2; } else if (curr is OperatorNode && postfixExpression[postIndex] is OperatorNode && curr.Right == null) { // Condition: if we are currently on an operator node, and the next node in the expression is an operator, and the current node's right is empty // Do: then add a marker to marker list that tracks current node, add node from expression to right of current node, and move current to the node we just placed markers.Add(curr); // drop marker to come back to curr.Right = postfixExpression[postIndex]; curr = curr.Right; postIndex -= 1; } else if ((curr is OperatorNode) && (postfixExpression[postIndex] is OperatorNode) && (curr.Left == null)) { // Condition: if our current node is an operator, and the next node in expression is an operator, and the current node's left is empty // Do: then add a marker to marker list that tracks current node, add node from expression to left of current node, and move current to the node we just placed markers.Add(curr); curr.Left = postfixExpression[postIndex]; curr = curr.Left; postIndex -= 1; } else { // Condition: if none of the other conditional statements matched with conditions // Do: then place the next node in expression to the right of our current node curr.Right = postfixExpression[postIndex]; postIndex -= 1; } } else { curr.Right = postfixExpression[postIndex]; // add node to right postIndex -= 1; } } } }