关于二叉搜索树的问题

时间:2013-08-04 18:12:13

标签: binary-search-tree

显示每个n节点二叉搜索树不太可能(假设项目以随机顺序插入),并且平衡树比直线树更可能。

它如何证明数学?

2 个答案:

答案 0 :(得分:4)

可能的树配置数量:请参阅With ' N ' no of nodes, how many different Binary and Binary Search Trees possible?

获得单行的方法数量,最不平衡,最深的树有n个节点:2 ^(n-1) 说明: 拾取第一个节点(最大或最小)的2种方法 X 2种方式来获取第二个节点(n-1个剩余节点中的最大或最小节点) ... X 2种方法来获取第(n-1)个节点 X 1获取最后一个节点的方法

以平衡的方式将n个项目添加到二叉树中的方法数量: 设g(n,m)表示合并两个有序列表的方法的数量,方法是一次从一个列表或另一个列表中选取元素,直到两个列表都为空。 g(n,m)= g(n-1,m)+ g(n,m-1)恰好对应于Pascal三角形中定义的数字。这会给n + m选择n或n + m选择m =(n + m)! / n! (N + M-N)! =(n + m)!/(n!m!) 例: 合并包含2个元素的两个有序列表的方法数量= 4!/(2!2!)= 24/4 = 6 假设两个列表如下:

1 A
2 B

六种合并组合是:

1 1 1 A A A
2 A A B 1 1
A 2 B 1 B 2
B B 2 2 2 B

现在,让f(n)表示可以将n个排序元素添加到空二叉树中以使二叉树平衡的组合数。实现这一目标的唯一方法是首先添加

    如果n是奇数,则
  • 中间元素。这将是元素上限(n / 2)。每一方都有n / 2-1个元素。
  • 如果n是偶数,则元素n / 2或元素n / 2 + 1。一边是n / 2-1元素,另一边是n / 2元素,反之亦然。

选择中间元素后,左侧的所有元素将始终位于左子树上,右侧的所有元素将始终位于右侧子树上。假设右边的元素以这样的方式排序,即左子树是平衡的,而右边的元素也是按照右子树平衡的方式排序的,以任何方式合并两个列表总是会导致两个子树平衡。这意味着对于分别落在左右子树上的n和m元素的每个列表,使得两个子树都是平衡的,有(n + m)!/(n!m!)将它们合并以便实现同样的结果。

那会给我们(n + m)!/(n!m!)x f(n)x f(m)

我们现在可以如下制定: 基本情况:

f(1) = 1
f(2) = 2

一般情况:

f(n) = (n-1)!/[((n-1)/2)!]^2 x [f((n-1)/2)]^2  | n odd
f(n) = (n-1)!/((n/2-1)! x (n/2)!) x 2 x f(n/2-1) x f(n/2) | n even

根据n,将其转换为非递归公式。也许从最简单的情况开始会更容易,其中n = 2 ^ m - 1(即删除节点并除以2将始终给出整数,并将产生完全平衡的树)。

注意:我在这里发布了一个相关的数学问题:https://math.stackexchange.com/questions/460767/recurrent-relation-for-number-of-ways-to-get-a-balanced-n-binary-tree

以下是一个C#控制台应用程序,它列出了可以将节点添加到二叉树中的所有序列,以使其平衡(运行它here):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AllBalancedTrees
{
    class Program
    {
        static void Main(string[] args)
        {
            char[] nodes = { 'A', 'B', 'C', 'D', 'E' };

            AllBalancedTrees<char> AllBalancedTrees = new AllBalancedTrees<char>(); 

            foreach (char[] a in AllBalancedTrees.allBalancedTreeCombinations(nodes))
            {
                foreach (char c in a)
                {
                    Console.Write(c + " ");
                }
                Console.WriteLine();
            }

            Console.ReadKey();
        }
    }

    class AllBalancedTrees<T>
    {
        public IEnumerable<T[]> allBalancedTreeCombinations(T[] nodes)
        {
            T[] result;
            if (nodes.Length == 1)
            {
                yield return nodes;
            }
            else if (nodes.Length == 2)
            {
                yield return nodes;
                T[] nodes2 = new T[2];
                nodes2[0] = nodes[1];
                nodes2[1] = nodes[0];
                yield return nodes2;
            }
            else if (nodes.Length % 2 == 1)
            {
                int mid = (nodes.Length - 1) / 2;
                T[] left = new T[mid];
                T[] right = new T[mid];
                Array.Copy(nodes, 0, left, 0, mid);
                Array.Copy(nodes, mid + 1, right, 0, mid);
                foreach (T[] l in allBalancedTreeCombinations(left))
                {
                    foreach (T[] r in allBalancedTreeCombinations(right))
                    {
                        result = new T[nodes.Length];
                        result[0] = nodes[mid];
                        foreach (T[] a in allMergeCombinations(l, r))
                        {
                            Array.Copy(a, 0, result, 1, a.Length);
                            yield return result;
                        }
                    }
                }
            }
            else
            {
                int mid = (nodes.Length) / 2;
                T[] left = new T[mid];
                T[] right = new T[mid - 1];
                Array.Copy(nodes, 0, left, 0, mid);
                Array.Copy(nodes, mid + 1, right, 0, mid - 1);
                foreach (T[] l in allBalancedTreeCombinations(left))
                {
                    foreach (T[] r in allBalancedTreeCombinations(right))
                    {
                        result = new T[nodes.Length];
                        result[0] = nodes[mid];
                        foreach (T[] a in allMergeCombinations(l, r))
                        {
                            Array.Copy(a, 0, result, 1, a.Length);
                            yield return result;
                        }
                    }
                }

                mid = nodes.Length / 2 - 1;
                left = new T[mid];
                right = new T[mid + 1];
                Array.Copy(nodes, 0, left, 0, mid);
                Array.Copy(nodes, mid + 1, right, 0, mid+1);
                foreach (T[] l in allBalancedTreeCombinations(left))
                {
                    foreach (T[] r in allBalancedTreeCombinations(right))
                    {
                        result = new T[nodes.Length];
                        result[0] = nodes[mid];
                        foreach (T[] a in allMergeCombinations(l, r))
                        {
                            Array.Copy(a, 0, result, 1, a.Length);
                            yield return result;
                        }
                    }
                }


            }
        }

        public IEnumerable<T[]> allMergeCombinations(T[] firstArray, T[] secondArray)
        {
            if (firstArray.Length == 0)
            {
                yield return secondArray;
            }
            else if (secondArray.Length == 0)
            {
                yield return firstArray;
            }
            else
            {
                T[] result;

                T[] firstMinusOne;
                firstMinusOne = new T[firstArray.Length - 1];
                Array.Copy(firstArray, 1, firstMinusOne, 0, firstMinusOne.Length);
                foreach (T[] a in allMergeCombinations(firstMinusOne, secondArray))
                {
                    result = new T[firstArray.Length + secondArray.Length];
                    result[0] = firstArray[0];
                    Array.Copy(a, 0, result, 1, a.Length);
                    yield return result;
                }

                T[] secondMinusOne;
                secondMinusOne = new T[secondArray.Length - 1];
                Array.Copy(secondArray, 1, secondMinusOne, 0, secondMinusOne.Length);
                foreach (T[] a in allMergeCombinations(firstArray, secondMinusOne))
                {
                    result = new T[firstArray.Length + secondArray.Length];
                    result[0] = secondArray[0];
                    Array.Copy(a, 0, result, 1, a.Length);
                    yield return result;
                }

            }
        }
    }
}

答案 1 :(得分:0)

每个n节点二分搜索树的可能性不大,因为如果以随机顺序插入项目,则输入不会严格增加或减少顺序的概率要大得多。只要项目不是按升序或降序排列,直线树就是不可能的。 例如,在具有键1,2,3和4的四个记录的树中,有4个!或24种方式将这些物品作为输入订购。这些方法中只有两种可以产生直线树(4,3,2,1和1,2,3,4)。在这种情况下,直线树的概率约为8.3%,而(某种程度上)平衡树的概率为91.6%。显然,可能性与获得结果的直线树的机会相反。