【问题标题】:Creating a Binary Search Tree from a sorted array从排序数组创建二叉搜索树
【发布时间】:2017-12-05 05:49:59
【问题描述】:

我目前正在检查编码算法。如果我们有以下情况:

给定一个具有唯一整数元素的排序(递增顺序)数组,编写一个算法来创建具有最小高度的二叉搜索树。

建议使用以下代码作为解决方案:

TreeNode createMinimalBST(int arr[], int start, int end){
    if (end < start) {
        return null;
    }
    int mid = (start + end) / 2;
    TreeNode n = new TreeNode(arr[mid]);
    n.setLeftChild(createMinimalBST(arr, start, mid - 1));
    n.setRightChild(createMinimalBST(arr, mid + 1, end));
    return n;
}

TreeNode createMinimalBST(int array[]) {
    return createMinimalBST(array, 0, array.length - 1);
}

但如果我尝试使用以下数组输入代码:

[2,4,6,8,10,20]

我执行第一次迭代

createMinimalBST([2,4,6,8,10,20], 0, 5);

下面一行:

int mid = (start + end) / 2; // in Java (0 + 5) / 2  =  2;

将计算中间值作为二叉搜索树的根,位置编号为 2,即值为 6。

但是,此示例中的二叉搜索树应如下所示:

    8
   / \
  4   10
 / \    \
2   6   20 

代码来自信誉良好的来源,但我的直觉是实现不正确。

是我遗漏了什么还是实现不正确?

【问题讨论】:

  • end 应该是数组的长度。是吗?
  • 代码中end的值是正确的(根据提供的解决方案)array.length - 1
  • 可以修改公式计算mid。如果end-start+1 是奇数,则为mid = (start+end)/2,否则为mid = (start + end)/2 + 1。另外,能否分享一下出处的链接?
  • @GAURANGVYAS 来源是一本书,名为《Cracking the Coding Interview》(第 6 版)。解决方案在第 242 页。

标签: binary-search-tree


【解决方案1】:

参考GeeksForGeeks

算法 -

  1. 获取数组的中间并使其成为根。
  2. 递归地对左半边和右半边做同样的事情。
    • 获取左半部分的中间并使其成为根的左孩子 在步骤 1 中创建。
    • 获取右半部分的中间并使其成为右半部分的右孩子 在步骤 1 中创建的根。

Wikipedia Link

代码

 class Node {

    int data;
    Node left, right;

    Node(int d) {
        data = d;
        left = right = null;
    }
}

class BinaryTree {

    static Node root;

    /* A function that constructs Balanced Binary Search Tree 
    from a sorted array */
    Node sortedArrayToBST(int arr[], int start, int end) {

        /* Base Case */
        if (start > end) {
            return null;
        }

        /* Get the middle element and make it root */
        int mid = (start + end) / 2;
        Node node = new Node(arr[mid]);

        /* Recursively construct the left subtree and make it
        left child of root */
        node.left = sortedArrayToBST(arr, start, mid - 1);

        /* Recursively construct the right subtree and make it
        right child of root */
        node.right = sortedArrayToBST(arr, mid + 1, end);

        return node;
    }

    /* A utility function to print preorder traversal of BST */
    void preOrder(Node node) {
        if (node == null) {
            return;
        }
        System.out.print(node.data + " ");
        preOrder(node.left);
        preOrder(node.right);
    }

    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();
        int arr[] = new int[]{2, 4, 6, 8, 10, 12};
        int n = arr.length;
        root = tree.sortedArrayToBST(arr, 0, n - 1);
        System.out.println("Preorder traversal of constructed BST");
        tree.preOrder(root);
    }
}

【讨论】:

  • 感谢您的回复,但我相信代码仍然选择 6 作为树的根,而不是 8。如果根以 6 开头,则它不是 binary search tree
  • @Tk421 如果根以 6 开头,则它不是二叉搜索树——这是不正确的。这将是一个平衡二分搜索,无论根是 6 还是 8。
  • @GAURANGVYAS 我已经仔细检查过了,它可以工作。可以生成几种二叉搜索树。感谢您的帮助。
  • GeeksforGeeks 复制粘贴后,您似乎忘记删除预购遍历。 -1 未注明您的来源。
  • 把这个答案写回去了;那时我还没有意识到给别人学分的重要性,但现在我知道了;添加了参考并感谢您的提醒
【解决方案2】:

排序后的数组将为您提供平衡的二叉树。这可以在 O(n) 时间内轻松完成,因为我们可以在 O(1) 时间内获得中间元素。下面是一个简单的算法,

  1. 为数组中的中间元素构造一个节点并返回它(这将是基本情况下的根)。

    1. 在数组的左半部分从 1. 开始重复,将返回值分配给根的左孩子。

    2. 在数组的右半部分从 1. 开始重复,将返回值分配给根的右孩子。

Java 实现

 TreeNode sortedArrayToBST(int arr[], int start, int end) {  
           if (start > end)
              return null; // same as (start+end)/2, avoids overflow.    
           int mid = start + (end - start) / 2;      
           TreeNode node = new
           TreeNode(arr[mid]); 
           node.left = sortedArrayToBST(arr, start, mid-1); 
           node.right = sortedArrayToBST(arr, mid+1, end); 
            return node; 
    }

TreeNode sortedArrayToBST(int arr[]) { return sortedArrayToBST(arr, 0, arr.length-1); }

时间复杂度: ** O(n) ** 以下是 sortedArrayToBST() 的递归关系。

T(n) = 2T(n/2) + C

T(n) --> 大小为 n 的数组所花费的时间

C --> 常量(查找数组的中间并将根链接到左右 子树需要恒定的时间)

【讨论】:

  • 你给出了两个答案,两个都是一样的。
  • 无法删除。将删除。
  • @GAURANGVYAS 如果你能删除另外两个,请这样做。
【解决方案3】:
  • 获取数组的middle,使其为root
  • 递归地对左半边和右半边执行相同的操作
    • 获取左半部分的middle 并使其成为根的left child
    • 获取右半部分的middle,使其成为根的right child

    public TreeNode Convert(int[] array)
    {
        if (array == null || array.Length == 0)
        {
            return null;
        }

        return Convert(array, 0, array.Length - 1);
    }

    private static TreeNode Convert(int[] array, int lo, int hi)
    {
        if (lo > hi)
        {
            return null;
        }

        int mid = lo + (hi - lo) / 2;
        var root = new TreeNode(array[mid]);
        root.Left = Convert(array, lo, mid - 1);
        root.Right = Convert(array, mid + 1, hi);
        return root;
    }

时间复杂度O(n)

来自CodeStandard

【讨论】:

    猜你喜欢
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多