Click here to Skip to main content
Click here to Skip to main content

Graphical BinaryTrees

By , 1 Mar 2012
 

Introduction

This article is about binary trees. A Binary Tree contains unlimited number of nodes, the nodes can be removed, added, searched, etc. Here we will discuss on how to make a binary tree on c# code, and how to draw that on bitmap using GDI+.

Each node on the binary tree has a unique value. for example 776 on the top of the image is a unique value for the root node on the tree.

The rules of adding a new node to the tree are:
starting from the root node,
1. if the node's value is less than the root's value, it would be added to the left node of root node.
2. if the node's value is greater than the root's value, it would be added to the right node of root node.
Consider that adding a node to any node would have the same process as 1 and 2.

The rules of removing a node from the binary tree are:
1. the node has no child => simply remove that node
2. the node just has a left child => the left child of the removing node will take it's position on the tree
3. the node has right child, and the right child does not have any left child => the right child of the node will take the position of the removing node on the tree
4. the node has right child, and the right child also has left child => the most left child of the right child will be removed (removing this node will cause a recursive algorithm!) and take the position of the removing node.

Using the code

When the application starts, it randomly adds some nodes to the tree. By pressing the add button (or pressing the enter key on textbox) the value of the textbox wil be added as a node to the binary tree. By pressing the create button a new binary tree will be created. By pressing the remove button the node containing the value of textbox will be removed from the tree
By pressing the "Rnd Add" button a random value will be added to the three as a node. By pressing the save button the current image on the picturebox will be saved on the disk.

A complete description of how to use the code and it's methods is represented on the main source code as XML parts. to understand it completely we prefer you read the main source code attached to this article.

It is easy to understand.

to create the tree and panit it use these lines:

private BinaryTree tree;
tree = new BinaryTree();
PaintTree();

to add a node with the unique number of val :

tree.Add(val); 

the add() method :

public void Add(int val)
{
    if (val < Value)// add to left
    {
        if (Left == null)
            Left = new Node(val);
        else
            Left.Add(val);
        IsChanged = true;
    }
    else if (val > Value) // add to right
    {
        IsChanged = true;
        if (Right == null)
            Right = new Node(val);
        else
            Right.Add(val);
    }
}

 

to remove a node with the value of val

 tree.Remove(val); 

The remove() method works the way described before. Removes the node containing the inserted value, also removes it's childs.

public bool Remove(int val, out bool containedOnMe)
{
Node nodeToRemove;
containedOnMe = false;
var isLeft = val < Value;
if (val < Value)
    nodeToRemove = Left;
else if (val > Value)
    nodeToRemove = Right;
else
{
    if(Left!=null)
    Left.IsChanged = true;
    if (Right != null)
        Right.IsChanged = true;
    containedOnMe = true;
    return false;
}

if (nodeToRemove == null)
    return false;

bool containOnChild;
var result = nodeToRemove.Remove(val, out containOnChild);
if (containOnChild)
{
    IsChanged = true;
    if (nodeToRemove.Left == null && nodeToRemove.Right == null)// no child
    {
        if (isLeft) Left = null; else Right = null;
    }
    else if (nodeToRemove.Right == null)// left child
    {
        if (isLeft) Left = nodeToRemove.Left; else Right = nodeToRemove.Left;
    }
    else // left and right are not null
    {
        if (nodeToRemove.Right.Left == null)// no left child for right child of node
        {
            nodeToRemove.Right.Left = nodeToRemove.Left;
            if (isLeft)
                Left = nodeToRemove.Right;
            else
                Right = nodeToRemove.Right;
        }
        else // there is a left child for right child of node
        {
            Node nLeft = null;
            for (var n = nodeToRemove.Right; n != null; n = n.Left)
                if (n.Left == null)
                    nLeft = n;
            bool temp;
            var v = nLeft.Value;
            Remove(nLeft.Value, out temp);
            nodeToRemove.Value = v;
        }
    }
    return true;
}
return result;
}

The paint operation is really easy: each node will draw itself and it's child nodes, the method of drawing is recursive calling every child to draw itself then passing the result to the parent so the parent can draw itself and this process happens for all the nodes

/// <summary>
/// paints the node and it's childs
/// </summary>
public Image Draw(out int center)
{
    center = _lastCenter;
    if (!IsChanged)
        return _lastImage;

    var lCenter = 0;
    var rCenter = 0;

    Image lImg = null, rImg = null;
    if (Left != null)
        lImg = Left.Draw(out lCenter);
    if (Right != null)
        rImg = Right.Draw(out rCenter);

    var me = new Bitmap(40, 40);
    var g = Graphics.FromImage(me);
    g.SmoothingMode = SmoothingMode.HighQuality;
    var rcl = new Rectangle(0, 0, me.Width - 1, me.Height - 1);
    g.FillRectangle(Brushes.White, rcl);
    g.FillEllipse(new LinearGradientBrush(new Point(0, 0), new Point(me.Width, me.Height), Color.Gold, Color.Black), rcl);

    var lSize = new Size();
    var rSize = new Size();
    var under = (lImg != null) || (rImg != null);
    if (lImg != null)
        lSize = lImg.Size;
    if (rImg != null)
        rSize = rImg.Size;

    var maxHeight = lSize.Height;
    if (maxHeight < rSize.Height)
        maxHeight = rSize.Height;

    var resSize = new Size
    {
        Width = me.Size.Width + lSize.Width + rSize.Width,
        Height = me.Size.Height + (under ? maxHeight + me.Size.Height : 0)
    };

    var result = new Bitmap(resSize.Width, resSize.Height);
    g = Graphics.FromImage(result);
    g.SmoothingMode = SmoothingMode.HighQuality;
    g.FillRectangle(Brushes.White, new Rectangle(new Point(0, 0), resSize));
    g.DrawImage(me, lSize.Width, 0);
    g.DrawString(Value.ToString(), new Font("Tahoma", 14), Brushes.White, lSize.Width + 5, me.Height / 2f - 12);

    center = lSize.Width + me.Width / 2;
    var pen = new Pen(Brushes.Black, 2.5f)
    {
        EndCap = LineCap.ArrowAnchor,
        StartCap = LineCap.Round
    };

    float x1 = center;
    float y1 = me.Height;
    float y2 = me.Height * 2;
    float x2 = lCenter;
    var h = Math.Abs(y2 - y1);
    var w = Math.Abs(x2 - x1);
    if (lImg != null)
    {
        g.DrawImage(lImg, 0, me.Size.Height * 2);
        var points1 = new List<PointF>
        {
            new PointF(x1, y1),
            new PointF(x1 - w/6, y1 + h/3.5f),
            new PointF(x2 + w/6, y2 - h/3.5f),
            new PointF(x2, y2),
        };
        g.DrawCurve(pen, points1.ToArray(), 0.5f);
    }
    if (rImg != null)
    {
        g.DrawImage(rImg, lSize.Width + me.Size.Width, me.Size.Height * 2);
        x2 = rCenter + lSize.Width + me.Width;
        w = Math.Abs(x2 - x1);
        var points = new List<PointF>
        {
            new PointF(x1, y1),
            new PointF(x1 + w/6, y1 + h/3.5f),
            new PointF(x2 - w/6, y2 - h/3.5f),
            new PointF(x2, y2)
        };
        g.DrawCurve(pen, points.ToArray(), 0.5f);
    }
    IsChanged = false;
    _lastImage = result;
    _lastCenter = center;
    return result;
}

Finally the BinaryTree class uses the methods and creates an instance of the binary tree

class BinaryTree
{
    public Node RootNode { get; private set; }

    public BinaryTree()//int rootValue)
    {
        RootNode = new Node(-1);//rootValue);
    }

    public List<int> Items { get; private set; }

    /// <summary>
    /// adds an item to tree
    /// </summary>
    public void Add(int value)
    {
        RootNode.Add(value);
    }
    /// <summary>
    /// Removes the node containing the inserted value and also it's childs, 
    /// returns true if could find and remove the node.
    /// return false if the inserted value is on rootNode, or the value does not exist on any of nodes.
    /// </summary>
    public bool Remove(int value)
    {
        bool isRootNode;
        var res = RootNode.Remove(value, out isRootNode);
        return !isRootNode && res;// return false if the inserted value is on rootNode, or the value does not exist on any of nodes
    }
    // draw
    public Image Draw()
    {
        int temp;
        return RootNode.Right == null ? null : RootNode.Right.Draw(out temp);
    }
} 

History

You may find out many samples about binaryTrees! but the way of viewing them visuali and on c# code is what we wanted to show.

Find Us

hmojtaba@live.com

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mojtaba Hosseini
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
Member
Currently:
Working at GitiNegarSoft company.
The leader of pnuzRobot humanoid robotic team(www.pnuzrobot.com)
A member of AUT (Amirkabir University of Technology) humanoid robotic team.
Interested in :
humanoid robots, WPF, systematic software development, Image processing, Artificial intelligence, motor controlling, omnidirectional moving systems, motion controller and editor etc.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberlosvce13 Oct '12 - 8:16 
This article introduced me to GDI , which will help me with some of my data visualizing research. Thank you!
GeneralMy vote of 5mvpKanasz Robert30 Jul '12 - 3:28 
Great article. Well done
GeneralReference to drawing functionmemberMatthew YC So22 Apr '12 - 21:30 
Hi,
 
Your drawing function for binary tree is great. I have followed your original idea and create AST drawing with mutiple child nodes. Please refer to link at [Visual AST for ANTLR Generated Parser Output].
 
Matthew
GeneralRe: Reference to drawing functionmemberMojtaba Hosseini23 Apr '12 - 17:09 
Hi,
 
I saw your project, and it is GREAT. Voted it to 5.
GeneralRe: Reference to drawing functionmemberMatthew YC So23 Apr '12 - 18:21 
Thanks! It is your original design fuels up my idea to create visual AST. Smile | :)
Questiongraphical bstmembersumkhan16 Apr '12 - 21:36 
hello ;
how we can run ur file is visual studio 2008
AnswerRe: graphical bstmemberMojtaba Hosseini23 Apr '12 - 10:19 
hi,
the project is reusable on vs2008, you may need just to run the project with vs2008,
if did not opened well, you can create your own project and paste the codes and classes from the main source code to your own project.
QuestionTree traversal (Inorder Preorder Postorder).memberfyfy_ictm31 Mar '12 - 16:52 
Please help me.
I want to do, Binary Tree traversal (Inorder Preorder Postorder).
Thank you.
GeneralMy vote of 5memberRC_Sebastien_C19 Mar '12 - 16:13 
Thanks
GeneralMy vote of 5memberAnirudha_baba15 Mar '12 - 3:39 
wow...amazing
GeneralMy vote of 5memberMihai MOGA11 Mar '12 - 15:46 
Great article. Please keep it up!
GeneralRe: My vote of 5memberMojtaba Hosseini13 Mar '12 - 4:36 
thanks, and, what do u mean by keeping it up? sorry i did not get you. Smile | :)
QuestionLook Great!memberchenandczh5 Mar '12 - 13:54 
Very good teaching materials!
GeneralMy vote of 5memberSledgeHammer012 Mar '12 - 10:44 
Cool stuff. Just had to write something like this.
QuestionBinary Search TreememberSunarya29 Feb '12 - 12:37 
Excellent work, salam from Jakarta
Five stars for you
QuestionType-omemberDavidCrow27 Feb '12 - 10:49 
The text right below the image states, "for example 510 on the top image is a unique value for the root node on the tree" yet there is no such node in the tree. Did you mean 776 instead?

"One man's wage rise is another man's price increase." - Harold Wilson

"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

"Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous


AnswerRe: Type-omemberMojtaba Hosseini1 Mar '12 - 6:29 
yes! you are right, it is 776. thanks for your fix.
GeneralMy vote of 5memberT_uRRiCA_N27 Feb '12 - 1:09 
Interesting thing!
5 from me.
But: Do you test the readers? Who will find the 510 in the picture first?
GeneralRe: My vote of 5members.kleinschmidt27 Feb '12 - 4:46 
T_uRRiCA_N wrote:
But: Do you test the readers? Who will find the 510 in the picture first?

 
Where is the 510? I'm getting totally crazy here! 1000$ for the first person hitting line 5! Come on! 555 0900 123456789 is the number! *sirens* Time is running! 5 ... 4 ... 3 ... 2 ... 1 *honk* No one is calling? I can't believe it! *beep* Extratime!!! Yeah! Come on, where is 510? It's that easy! Just call 555 0900 123456789, hit line 5 and answer the big question: Where is 510? *zap*...
GeneralRe: My vote of 5members.kleinschmidt27 Feb '12 - 4:49 
BTW, i also think that this is a great article, but the 510 challenge just made me think of that late night tv quiz shows and i couldn't resist...
GeneralRe: My vote of 5memberT_uRRiCA_N27 Feb '12 - 8:52 
I called this number 3 times, but they told me, that all lines are busy at the moment! Big Grin | :-D
With the things I don't know, I could fill libraries

GeneralRe: My vote of 5memberMojtaba Hosseini1 Mar '12 - 6:31 
think i have to modify the article and fix this HUGE mistake Smile | :)
GeneralMy vote of 5membermanoj kumar choubey23 Feb '12 - 19:41 
Nice
GeneralRe: My vote of 5memberMojtaba Hosseini1 Mar '12 - 6:32 
thanks Smile | :)

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 1 Mar 2012
Article Copyright 2012 by Mojtaba Hosseini
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid