Click here to Skip to main content
15,884,176 members
Articles / Programming Languages / C#
Article

Binary Tree Expression Solver

Rate me:
Please Sign up or sign in to vote.
4.58/5 (16 votes)
8 May 20056 min read 182.3K   3.8K   49   12
A simple method for solving expressions using binary trees, as well as converting between notations.

Introduction

Recently, I came across the need to create binary trees based on a mathematical expression as its input. In my math class we were covering a lesson on graph theory, and as an assignment we were to take expressions, put them in trees and evaluate them. Also part of the lesson was to convert from several notations to several others- a daunting task, especially without the help of a tree.

It was because of this that I wrote this program. It is a very basic, short class that implements the functionality needed to solve expression trees, as well as output their structure in prefix, postfix, and infix format. Though there are many features that are left unimplemented, this example was based on algorithms I have learned (and am learning) as I go. If anyone has anything to add (or change) to this class, please let me know!

About notations

Let's quickly go over to the different notations used in this class. Three functions are provided to output expressions in postfix, prefix, and infix formats. Two of these are almost identical, and the third one everyone is familiar with, as it is how we write equations normally.

Infix

Of the three notations, infix is the one we are all most familiar with. In this notation, all binary operators appear between the two operands. This provides several advantages to the other two notations- mainly, it is easy to see which operators are bound to which operands. At a glance (at least in my opinion) it is also easier to solve these equations mentally. Infix does create a few problems, however. Because operators appear where they do, when they are stacked and equations become more complex, it's hard to distinguish one operand from another. The solution is to use parentheses to group operations. Infix appears as:

((1+2) * (3-4))

Note: The way this code was implemented, expressions represented in infix notation will always be fully parenthesized. I can't get around this, and though they aren't necessary, they obviously do not affect the outcome.

Expressions in infix are solved by starting from the innermost set of parentheses and working outwards. Rules of precedence must also be followed, due to the possible ambiguity in interpretation.

Graphing infix expressions in a tree is fairly complicated because of the order of operations. You must start with a fully parenthesized equation, as this will make it clear what the "main" operator is (this is the operator that adds the other two sides of the expression, which makes up the whole expression). In the example above, the multiplication sign is the main operator. This will make up the root node of the tree. Each node under it will be determined by the groups that are most tightly bound to the main operator.

Prefix

This type of notation is arguably the easiest to use. In prefix, all operators appear near the beginning of the equation, with the two operands appearing right after. When operations are stacked, it becomes difficult to see how these operands are grouped, but because of the nature of prefix notation, no parentheses are needed to group them. To stop nodes (the operands) from running together, spaces are added between each one of them. Prefix appears as:

* + 1 2 - 3 4

Expressions in prefix are solved by scanning the equation for an operator with two immediate values to the right of it. This is continued and repeated until there are no more operators left.

Graphing prefix expressions follow a simple algorithm, which is as follows:

  • Write operator.
  • Go left unless the node is an immediate value.
  • When going left is unavailable, go to the node above you and go right.

This algorithm is left-recursive.

Postfix

Quite simply, postfix is just a variant of prefix. Instead of appearing at the beginning of the expression, the operators will appear near the end. This type of notation is very common in programming languages and such, as it is easily solvable using stacks. Postfix appears as:

1 2 + 3 4 - *

Expressions in postfix are solved by traveling down the tree (to the left) until an immediate value is reached. The idea is that an operator can't be written until all the values under it are present. When moving left can't be done, move right. When both left and right values of a node are written down, the operator binding them can be written.

Using the code

The code itself is encapsulated in a simple class with methods for returning the expression in all three notations, as well as a function to solve a tree.

Node class methods:

C#
class Node
{
    // Solves a tree
    public int Solve()
    // Returns the prefix notation for the expression
    public string Prefix()
    // Returns the postfix notation for the expression
    public string Postfix()
    // Returns the (fully parenthesized) infix
    // notation for the expression
    public string Infix()
    // Constructor for subnodes
    public Node(char op, Node l, Node r)
    // Constructor for leaf nodes
    public Node(string value)
    // Node connected on the left
    private Node left;
    // Node connected on the right
    private Node right;
    // Value (operator or term)
    private string Value;
}

The Node class contains everything needed to set up and evaluate expressions. To create a tree, simply call the constructor for the class. Sorry, I haven't added a parser, so this must be done manually:

C#
Node tree = new Node('*', new Node('+', new Node("1"), new Node("2")),
                          new Node('-', new Node("3"), new Node("4"))
            );

Notice that the constructor takes the operator first, then the left and right values. Alternatively, the constructor will also take a single string value for leaves (immediate values).

Now, to solve the tree, simply call the Solve method:

C#
Console.WriteLine("The answer is: {0}", tree.Solve());

Similarly, to find the prefix, infix, or postfix notations for the expression, call the respective functions, which all return strings.

C#
Console.WriteLine("The prefix notation of the expression is\n{0}", 
                                                  tree.Prefix());

Simple, huh?

Improvements

The program as it stands could do with many improvements. Here are a few I have thought of, and might get around to adding (though if you would like to implement them, please share with us!):

  • Parser- The program lacks the major functionality of an expression parser, taking an expression and building a tree from it. This could be accomplished with regular expressions, or even stack manipulation.
  • Error checking- Presently, no validation is performed on the expression to test whether it is solvable. Non-numeric values will confuse the program, as will expressions with too many signs, wrong placement, etc.. The responsibility is currently placed on the user to provide a good expression.
  • General purpose- The application of these types of trees can be extended to a broader field of data manipulation. It would be interesting to see classes developed to handle any type of data, not just numeric.
  • Node data- The tree is currently only able to support whole numbers (integers). Though easily changed, this was done intentionally to keep the example plain and easy to understand.
  • Limited size- Because of the way the solving algorithm and the notation functions work, trees are limited in size. This is due to the fact that the functions recurs to find their results, and as such, the internal stack fills up quite quickly. Very large trees will cause an overflow and the program will stop.

Conclusion

Writing this class proved easier than I had originally thought, and it has definitely sped up my school work! Using simple recursion techniques, it is almost trivial to manipulate binary trees in any fashion.

Ideally, the class could use a few other functions (as listed above), but as it stands I thought it was quite helpful. The code is commented and very detailed, so you should have no problem understanding it- a rather simple class anyway.

If you should have any questions or comments, I always love feedback :) Post a thread and I'll be sure to check it out. Also remember, to make changes and add to the code presented here--if you post it, I'll add it in and re-upload the code as soon as possible.

History

  • 7th May, 05- Initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
James Brannan is a 16 year old programmer attending high school in Lake Saint Louis, Missouri. He enjoys writing code in Perl, C++, and .NET in his free time, but also enjoys the finer things in life -- sleeping and eating! His homepage is at http://www.binary-craft.com and http://www.domainjames.com

Comments and Discussions

 
GeneralJava Pin
borisbergman30-May-08 3:59
borisbergman30-May-08 3:59 
GeneralRe: Java Pin
Member 1126482225-Nov-14 20:52
Member 1126482225-Nov-14 20:52 
GeneralInfix notation Pin
TristanJ20-Jul-07 4:38
TristanJ20-Jul-07 4:38 
QuestionA problem about Prefix Notation Pin
atatruva2-Aug-06 23:32
atatruva2-Aug-06 23:32 
Generalparsing tips... Pin
Super Lloyd13-Jul-05 15:15
Super Lloyd13-Jul-05 15:15 
GeneralBig O Pin
DavidNohejl10-May-05 1:29
DavidNohejl10-May-05 1:29 
GeneralRe: Big O Pin
Anonymous10-May-05 16:25
Anonymous10-May-05 16:25 
GeneralRe: Big O Pin
AngryLlama18-Nov-06 20:37
AngryLlama18-Nov-06 20:37 
GeneralRe: Big O Pin
dimitar_kazakov1-Aug-06 9:49
dimitar_kazakov1-Aug-06 9:49 
Generalkeep working good at it:) Pin
Huisheng Chen9-May-05 18:54
Huisheng Chen9-May-05 18:54 
General2005 & string Pin
Huisheng Chen8-May-05 7:11
Huisheng Chen8-May-05 7:11 
well, u use vs2005, that is ok, since we can use (string)before each stack.pop.

the problem is, can it accept the whole expression string as the parameter to calc?D'Oh! | :doh:

Regards,
unruledboy@hotmail.com
GeneralRe: 2005 & string Pin
James Brannan8-May-05 7:29
James Brannan8-May-05 7:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.