平衡二叉搜索树 – 迭代方法

huangapple go评论73阅读模式
英文:

Balanced BST From a Sorted Array - Iterative Approach

问题

I want to create a balanced BST from a sorted array iteratively. I understand how to create this BST recursively, but how would you go about doing this iteratively? assuming a Node in the tree has left,right child and a parent.

我想以迭代方式从已排序的数组创建平衡二叉搜索树。我知道如何以递归方式创建这个BST,但你会如何以迭代方式执行呢?假设树中的节点具有左、右子节点和父节点。

I tried implementing the same key idea as in the recursive solution (take the median to be the root at each iteration). got stuck pretty fast when trying to write the for loop. saw some ideas about stack or queue but could not understand why you must create one of these (maybe you don't).Also in general why does iterative solution seem to be way more complicated than the recursive one? (and also not popular)
could use help. (jave please if you supply code)

我尝试实现与递归解决方案相同的关键思路(在每次迭代中将中值作为根节点)。但在尝试编写for循环时很快陷入困境。看到了一些关于堆栈或队列的想法,但无法理解为什么必须创建其中之一(也许不需要)。总的来说,为什么迭代解决方案似乎比递归解决方案更复杂?(而且也不流行)
需要帮助。(如果提供代码,请使用Java)

*I'm a beginner (don't be too harsh :))

英文:

I want to create a balanced BST from a sorted array iteratively. I understand how to create this BST recursively, but how would you go about doing this iteratively? assuming a Node in the tree has left,right child and a parent.

I tried implementing the same key idea as in the recursive solution (take the median to be the root at each iteration). got stuck pretty fast when trying to write the for loop. saw some ideas about stack or queue but could not understand why you must create one of these (maybe you don't).Also in general why does iterative solution seem to be way more complicated than the recursive one? (and also not popular)
could use help. (jave please if you supply code)

*I'm a beginner (don't be to harsh :))

答案1

得分: 0

要以迭代方式从已排序的数组创建平衡二叉搜索树(BST),您可以使用一种称为“自底向上”方法的技术。以下是如何实现它的方法:

  1. 初始化一个空栈。这个栈将存储表示每个子树元素范围的索引对。

  2. 将初始范围 [0, n-1] 推入栈中,其中 n 是已排序数组的大小。

  3. 当栈不为空时,执行以下操作:

    • 从栈中弹出顶部的索引对。我们将它们称为 start 和 end。

    • 计算中间索引 mid = (start + end) // 2。

    • 使用已排序数组中索引为 mid 的值创建一个新节点。

    • 将新节点的左子节点设置为下一次迭代的结果,范围为 [start, mid-1](即当前范围的左半部分)。

    • 将新节点的右子节点设置为下一次迭代的结果,范围为 [mid+1, end](即当前范围的右半部分)。

    • 根据需要设置新节点的父节点。

  4. 返回BST的根节点。

示例代码:

class Node {
    int value;
    Node left;
    Node right;
    Node parent;

    public Node(int value) {
        this.value = value;
        this.left = null;
        this.right = null;
        this.parent = null;
    }
}

public class BalancedBST {
    public static Node createBalancedBSTIterative(int[] sortedArray) {
        int n = sortedArray.length;
        if (n == 0) {
            return null;
        }

        Stack<int[]> stack = new Stack<>();
        Node root = null;

        int start = 0;
        int end = n - 1;

        int mid = (start + end) / 2;
        root = new Node(sortedArray[mid]);
        stack.push(new int[]{start, mid - 1});
        stack.push(new int[]{mid + 1, end});

        while (!stack.empty()) {
            int[] range = stack.pop();
            start = range[0];
            end = range[1];
            mid = (start + end) / 2;

            Node parent = new Node(sortedArray[mid]);
            parent.parent = root;

            if (start <= mid - 1) {
                stack.push(new int[]{start, mid - 1});
                parent.left = new Node(0);  // 现在是占位符节点
            }

            if (mid + 1 <= end) {
                stack.push(new int[]{mid + 1, end});
                parent.right = new Node(0); // 现在是占位符节点
            }

            if (parent.parent != null) {
                if (parent == parent.parent.left) {
                    parent.parent.left = parent;
                } else {
                    parent.parent.right = parent;
                }
            } else {
                root = parent;
            }
        }

        return root;
    }

    public static void main(String[] args) {
        int[] sortedArray = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        Node root = createBalancedBSTIterative(sortedArray);
        // 您可以遍历和打印生成的树来验证正确性
    }
}

希望这对您有帮助!

英文:

To create a balanced binary search tree (BST) from a sorted array iteratively, you can use a technique called the "Bottom-Up" approach. Here's how you can do it:

  1. Initialize an empty stack. This stack will store pairs of indices
    representing the range of elements for each subtree.

  2. Push the initial range [0, n-1] onto the stack, where n is the size
    of the sorted array.

  3. While the stack is not empty, do the following:

    • Pop the top pair of indices from the stack. Let's call them start and
      end.

    • Calculate the middle index as mid = (start + end) // 2.

    • Create a new node with the value at index mid in the sorted array.

    • Set the left child of the new node to the result of the next
      iteration
      with the range [start, mid-1] (i.e., the left half of the current range).

    • Set the right child of the new node to the result of the next
      iteration
      with the range [mid+1, end] (i.e., the right half of the current range).

    • Set the parent of the new node as needed.

  4. Return the root of the BST.

example code:

class Node {
int value;
Node left;
Node right;
Node parent;
public Node(int value) {
this.value = value;
this.left = null;
this.right = null;
this.parent = null;
}
}
public class BalancedBST {
public static Node createBalancedBSTIterative(int[] sortedArray) {
int n = sortedArray.length;
if (n == 0) {
return null;
}
Stack&lt;int[]&gt; stack = new Stack&lt;&gt;();
Node root = null;
int start = 0;
int end = n - 1;
int mid = (start + end) / 2;
root = new Node(sortedArray[mid]);
stack.push(new int[]{start, mid - 1});
stack.push(new int[]{mid + 1, end});
while (!stack.empty()) {
int[] range = stack.pop();
start = range[0];
end = range[1];
mid = (start + end) / 2;
Node parent = new Node(sortedArray[mid]);
parent.parent = root;
if (start &lt;= mid - 1) {
stack.push(new int[]{start, mid - 1});
parent.left = new Node(0);  // Placeholder node for now
}
if (mid + 1 &lt;= end) {
stack.push(new int[]{mid + 1, end});
parent.right = new Node(0); // Placeholder node for now
}
if (parent.parent != null) {
if (parent == parent.parent.left) {
parent.parent.left = parent;
} else {
parent.parent.right = parent;
}
} else {
root = parent;
}
}
return root;
}
public static void main(String[] args) {
int[] sortedArray = {1, 2, 3, 4, 5, 6, 7, 8, 9};
Node root = createBalancedBSTIterative(sortedArray);
// You can traverse and print the resulting tree to verify the correctness
}
}

答案2

得分: 0

以下是您要翻译的内容:

您可以使用迭代方法,其中目标是构建一棵完全的树,即叶子节点都在底部两层,并且底部一层的所有节点都在该层的左侧。

从输入数组的大小可以计算出要构建的树的高度以及底层将有多少节点。

然后,您可以使用一个数组,其中每个索引对应一个级别,每个条目表示该级别中最右边的节点(如果相关)。此数组将开始具有所有null条目,并且获得Node实例的第一个条目将是其最后一个条目(在数组末尾),因为它将是一个叶子节点。通过一些逻辑,您可以知道下一个节点将在哪个级别结束,将其引用存储在数组中的该索引处,并将其与其子节点(如果有)链接起来。

以下是一些详细说明的实现:

Node

class Node {
    int value;
    Node left = null;
    Node right = null;
    
    public Node(int value) {
        this.value = value;
    }
}

BinarySearchTree

import java.util.*;

class BinarySearchTree {
    Node root = null;
    
    BinarySearchTree(int[] values) {
        if (values.length == 0) return;
        int height = (int)(Math.log(values.length) / Math.log(2));
        // 要放置在新树底层的节点数:
        int bottomCount = (values.length + 1) - (1 << height);
        Node path[] = new Node[height + 1];
        Arrays.fill(path, null);
        // 下一个节点将在新树中具有的深度
        int depth = height; 
        for (int value : values) {
            path[depth] = new Node(value);
            // 是否有左子节点要链接?
            if (depth + 1 < path.length && path[depth+1] != null) { 
                path[depth].left = path[depth+1];
                path[depth+1] = null;
            }
            if (depth < height) {
                depth = height; // 下一个节点将是叶子节点
            } else {
                // 底层是否已经被覆盖?
                //    那么剩余部分的层级少一层
                if (--bottomCount == 0) height--;
                while (depth-- > 0 && path[depth] != null) {
                    path[depth].right = path[depth+1];
                    path[depth+1] = null;
                }
            }
        }
        root = path[0];
    }

    void print() {
        print(root, "");
    }

    void print(Node node, String indent) {
        if (node == null) return;
        print(node.right, indent + "   ");
        System.out.println(indent + node.value);
        print(node.left, indent + "   ");
    }
}

驱动代码

    public static void main(String[] args) {
        int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
        BinarySearchTree tree = new BinarySearchTree(values);
        tree.print();
    }

这具有O(n)时间复杂度和O(logn)辅助空间复杂度(不包括输入——值数组——和输出——树)。

英文:

You can use an iterative approach where you target a tree that is complete, i.e. where the leaves are all on the bottom two levels, and the bottom level has all its nodes at the left side of that level.

From the size of the input array you can calculate what the height is of the tree to build and how many nodes will be in its bottom level.

Then you can use an array where each index corresponds to a level, and each entry represents the rightmost node in that level (if relevant). This array will start out will all null entries, and the first entry to get a Node instance will be its last entry (at the end of the array), because it will be a leaf. With some logic you can know at which level the next node will end up, store its reference at that index in the array, and link it up with its child (if any).

Here is an implementation with some comments explaining some details:

Node

class Node {
int value;
Node left = null;
Node right = null;
public Node(int value) {
this.value = value;
}
}

BinarySearchTree

import java.util.*;
class BinarySearchTree {
Node root = null;
BinarySearchTree(int[] values) {
if (values.length == 0) return;
int height = (int)(Math.log(values.length) / Math.log(2));
// Number of nodes to be placed in the bottom level of the new tree:
int bottomCount = (values.length + 1) - (1 &lt;&lt; height);
Node path[] = new Node[height + 1];
Arrays.fill(path, null);
// Depth that the next node will have in the new tree 
int depth = height; 
for (int value : values) {
path[depth] = new Node(value);
// Is there a left child to link?
if (depth + 1 &lt; path.length &amp;&amp; path[depth+1] != null) { 
path[depth].left = path[depth+1];
path[depth+1] = null;
}
if (depth &lt; height) {
depth = height; // Next node will be a leaf
} else {
// Has bottom level been covered? 
//    Then remaining part has one less level
if (--bottomCount == 0) height--;
while (depth-- &gt; 0 &amp;&amp; path[depth] != null) {
path[depth].right = path[depth+1];
path[depth+1] = null;
}
}
}
root = path[0];
}
void print() {
print(root, &quot;&quot;);
}
void print(Node node, String indent) {
if (node == null) return;
print(node.right, indent + &quot;   &quot;);
System.out.println(indent + node.value);
print(node.left, indent + &quot;   &quot;);
}
}

Driver code

    public static void main(String[] args) {
int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
BinarySearchTree tree = new BinarySearchTree(values);
tree.print();
}

This has O(n) time complexity, and O(logn) auxiliary space complexity (not counting input -- the array of values -- nor output -- the tree).

答案3

得分: 0

因为如果你按照排序顺序更新树中的节点,你会访问树中不同长度的路径上的节点,需要管理这些路径,所以你需要一个辅助数据结构。

例如,

          3
1       5
0   2   4   6

节点是通过连续的路径填充的

3 1 0
3 1
3 1 2
3
3 5 4
3 5
3 5 6
英文:

Why is it "complicated" ?

Because if you update the nodes to the tree in sorted order, you access the nodes following varying paths in the tree, of varying lengths. To manage these paths, you need an auxiliary data structure.

E.g.

          3
1       5
0   2   4   6

The nodes are filled using the successive paths

3 1 0
3 1
3 1 2
3
3 5 4
3 5
3 5 6

huangapple
  • 本文由 发表于 2023年6月12日 21:02:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76456940.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定