Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are large binary trees built?

Tags:

tree

This is a question that has been bothering me for years. I want to know how large binary trees are built, the only method I know is to create a function to push one element onto a tree(a function called insert();). If I have a 3 element tree and want to add 5 elements, I am going to have to call the insert function 5 times. This seems a pretty poor method, what if I want to add 50 elements? There has to be a better way than just calling the insert() function fifty times.

like image 951
user2202911 Avatar asked Dec 20 '22 23:12

user2202911


1 Answers

If the data is pre-sorted you can build it recursively.

Basically to build the tree for some input:

  1. Create a new node
  2. If the input is one entry only, the value of the node is that entry
  3. Otherwise:
    1. In the left sub-tree of the node, place the tree built from the first half of the input
    2. In the right sub-tree of the node, place the tree built from the second half of the input

The third step will recursively apply itself to portions of the input.

Here's some pseudo-code:

FUNCTION TREE (input -> node)
    IF input IS 1 ENTRY
        VALUE OF node IS entry OF input
    ELSE
        SPLIT input IN 2
        LEFT SUB-TREE OF node IS TREE(FIRST HALF OF input)
        RIGHT SUB-TREE OF node IS TREE(SECOND HALF OF input)

Here's some LINQPad C# code you can experiment with:

// Add the following two using-directives to LINQPad:
// System.Drawing
// System.Drawing.Imaging

static Bitmap _Dummy = new Bitmap(16, 16, PixelFormat.Format24bppRgb);
static Font _Font = new Font("Arial", 12);

void Main()
{
    var sorted = Enumerable.Range(1, 16).ToArray();
    var tree = BuildTree(sorted);
    Visualize(tree);
}

public Node<T> BuildTree<T>(T[] input)
{
    return BuildTree<T>(input, 0, input.Length);
}

public Node<T> BuildTree<T>(T[] input, int left, int right)
{
    if (right <= left)
        return null;

    if (right == left + 1)
        return new Node<T> { Value = input[left] };

    int middle = (left + right) / 2;
    return new Node<T>
    {
        Left = BuildTree<T>(input, left, middle),
        Right = BuildTree<T>(input, middle, right)
    };
}

public class Node<T>
{
    public T Value;
    public Node<T> Left;
    public Node<T> Right;

    public Bitmap ToBitmap()
    {
        Size valueSize;
        using (Graphics g = Graphics.FromImage(_Dummy))
        {
            var tempSize = g.MeasureString(Value.ToString(), _Font);
            valueSize = new Size((int)tempSize.Width + 4, (int)tempSize.Height + 4);
        }

        Bitmap bitmap;
        Color valueColor = Color.LightPink;
        if (Left == null && Right == null)
        {
            bitmap = new Bitmap(valueSize.Width, valueSize.Height);
            using (var g = Graphics.FromImage(bitmap))
                g.Clear(Color.White);
            valueColor = Color.LightGreen;
        }
        else
        {
            using (var leftBitmap = Left.ToBitmap())
            using (var rightBitmap = Right.ToBitmap())
            {
                int subNodeHeight = Math.Max(leftBitmap.Height, rightBitmap.Height);
                bitmap = new Bitmap(
                    leftBitmap.Width + rightBitmap.Width + valueSize.Width,
                    valueSize.Height + 32 + subNodeHeight);

                using (var g = Graphics.FromImage(bitmap))
                {
                    g.Clear(Color.White);
                    int baseY  = valueSize.Height + 32;

                    int leftTop = baseY; // + (subNodeHeight - leftBitmap.Height) / 2;
                    g.DrawImage(leftBitmap, 0, leftTop);

                    int rightTop = baseY; // + (subNodeHeight - rightBitmap.Height) / 2;
                    g.DrawImage(rightBitmap, bitmap.Width - rightBitmap.Width, rightTop);

                    g.DrawLine(Pens.Black, bitmap.Width / 2 - 4, valueSize.Height, leftBitmap.Width / 2, leftTop);
                    g.DrawLine(Pens.Black, bitmap.Width / 2 + 4, valueSize.Height, bitmap.Width - rightBitmap.Width / 2, rightTop);
                }
            }
        }

        using (var g = Graphics.FromImage(bitmap))
        {
            float x = (bitmap.Width - valueSize.Width) / 2;
            using (var b = new SolidBrush(valueColor))
                g.FillRectangle(b, x, 0, valueSize.Width - 1, valueSize.Height - 1);
            g.DrawRectangle(Pens.Black, x, 0, valueSize.Width - 1, valueSize.Height - 1);
            if (Left == null && Right == null)
                g.DrawString(Value.ToString(), _Font, Brushes.Black, x + 1, 2);
        }

        return bitmap;
    }
}

void Visualize<T>(Node<T> node)
{
    node.ToBitmap().Dump();
}

Here's the output:

LINQPad output

like image 125
Lasse V. Karlsen Avatar answered Dec 22 '22 14:12

Lasse V. Karlsen