Tree 大型二叉树是如何建立的?

Tree 大型二叉树是如何建立的?,tree,Tree,这是一个困扰我多年的问题。我想知道二叉树有多大,我知道的唯一方法是创建一个函数,将一个元素推送到树上(一个名为insert();)的函数)。如果我有一个3元素的树,并且想要添加5个元素,那么我必须调用insert函数5次。这似乎是一个非常糟糕的方法,如果我想添加50个元素呢?必须有更好的方法,而不仅仅是调用insert()函数50次 有。Knuth在ACP第三卷中给出了一个从排序输入构建合理平衡的二进制的算法。如果数据是预排序的,你可以递归地构建它 基本上是为一些输入构建树: 创建一个新节点 如

这是一个困扰我多年的问题。我想知道二叉树有多大,我知道的唯一方法是创建一个函数,将一个元素推送到树上(一个名为insert();)的函数)。如果我有一个3元素的树,并且想要添加5个元素,那么我必须调用insert函数5次。这似乎是一个非常糟糕的方法,如果我想添加50个元素呢?必须有更好的方法,而不仅仅是调用insert()函数50次

有。Knuth在ACP第三卷中给出了一个从排序输入构建合理平衡的二进制的算法。如果数据是预排序的,你可以递归地构建它

基本上是为一些输入构建树:

  • 创建一个新节点
  • 如果输入仅为一个条目,则节点的值就是该条目
  • 否则:
  • 在节点的左子树中,放置从输入的前半部分构建的树
  • 在节点的右侧子树中,放置从输入的后半部分构建的树
  • 第三步将递归地应用于部分输入

    下面是一些伪代码:

    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)
    
    下面是一些你可以尝试的C代码:

    // 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();
    }
    
    //将以下两个using指令添加到LINQPad:
    //系统图
    //系统、绘图、成像
    静态位图_Dummy=新位图(16,16,PixelFormat.Format24bppRgb);
    静态字体_Font=新字体(“Arial”,12);
    void Main()
    {
    var sorted=Enumerable.Range(1,16).ToArray();
    var-tree=BuildTree(已排序);
    形象化(树);
    }
    公共节点构建树(T[]输入)
    {
    返回BuildTree(input,0,input.Length);
    }
    公共节点构建树(T[]输入,左整数,右整数)
    {
    
    如果(对,在谷歌上快速搜索平衡二叉树,找到类似的东西。我想现在我甚至有更多的领域可以选择那本书。谢谢你的回答。我给了你+1,但我想在我授予赏金之前完全相信如何做到这一点-我不是。我有点同意你提供的步骤,但你的伪代码不匹配。“创建一个新节点”,如何递归地创建不同的节点,特别是使用C/C++这样的语言,其中必须使用指针?在伪代码中,您也没有指定任何树的实际构建方式,这正是我要寻找的。在您的步骤中,您会说:“放置从前半部分构建的树”,但是这是怎么发生的呢?同样-在您提供的C代码中,特别是在构建中(T[]输入,int left,int right)函数,“left”和“right”的参数从何而来?看起来它们仍然需要手动指定。如果是这样,那么我仍然需要手动而不是递归地建立树-这完全违背了目的。“input”是一个输入的排序数组。左侧从0开始,右侧总是从数组的长度开始。我不理解你对C/C++的评论,你当然会根据需要从堆中分配新的节点对象/结构。