【问题标题】:Max-Heapify A Binary Tree最大堆化二叉树
【发布时间】:2020-06-28 18:25:17
【问题描述】:

这是我最近遇到的面试问题之一。

给定一棵完全或几乎完全二叉树的根地址,我们必须编写一个函数将二叉树转换为最大堆。

这里不涉及数组。树已经构建好了。

例如,

              1   
         /         \
        2           5
      /   \       /   \ 
     3      4    6     7

可以有任何可能的最大堆作为输出--

              7   
         /         \
        3           6
      /   \       /   \ 
     2     1     4     5

              7   
         /         \
        4           6
      /   \       /   \ 
     2     3     1     5

等等……

我写了一个解决方案,但使用了前后顺序遍历的组合,但我猜它在 O(n^2) 中运行。我的代码给出了以下输出。

              7   
         /         \
        3           6
      /   \       /   \ 
     1     2     4     5

我一直在寻找更好的解决方案。有人可以帮忙吗?

编辑:

我的代码

void preorder(struct node* root)
{    
    if(root==NULL)return;
    max_heapify(root,NULL);
    preorder(root->left); 
    preorder(root->right);
}
void max_heapify(struct node* root,struct node* prev)
{
    if(root==NULL)
        return ;             
    max_heapify(root->left,root);
    max_heapify(root->right,root);
    if(prev!=NULL && root->data > prev->data)
    {
        swapper(root,prev);
    }     
}
void swapper(struct node* node1, struct node* node2)
{   
    int temp= node1->data;
    node1->data = node2->data;
    node2->data = temp;
}

【问题讨论】:

  • 您展示的“二叉树”是最小堆,而不是排序二叉树。这是你的意图吗?
  • @Sneftel 你好!它恰好是一个最小堆。它不是故意的,可以是任何随机完整或几乎完整的二叉树。
  • "不涉及数组" - 这是否意味着您不允许将树复制到数组然后堆化,或者这是否意味着您最初没有将树作为数组?如果是后者,复制到数组,堆化,重建树;这是 O(n)。
  • @G.Bach 是的,您不允许将树复制到数组然后堆化,是的,您最初没有将树作为数组。它是一个二叉树,而不是数组的二叉树可视化。

标签: algorithm data-structures heap binary-tree binary-heap


【解决方案1】:

我认为这可以通过以下过程在 O(NlogN) 时间内完成。 http://www.cs.rit.edu/~rpj/courses/bic2/studios/studio1/studio121.html

假设树中有一个元素,其左右子树都是堆。

          E
       H1   H2

这棵由 E、H1 和 H2 组成的树可以通过使元素 E 游到正确的位置在 logN 时间内堆化。

因此,我们开始自下而上构建堆。转到最左边的子树并通过简单的比较将其转换为堆。为它的兄弟姐妹也这样做。然后上去转成堆。

对每个元素都这样做。

编辑:正如 cmets 中所述,复杂度实际上是 O(N)。

【讨论】:

  • 转到最左边的子树??那么,我们是否需要为此使用额外的空间来存储非叶子节点的地址通过级别顺序遍历?
  • @ankitG 不,只需 log(N) 堆栈空间在左孩子和右孩子上递归。定义一个过程“heapify”,它首先在当前节点的左右子节点上递归调用自身,如果有的话,然后将当前节点冒泡到其适当的空间。这与您在数组上使用的线性时间算法相同。
  • 我认为这里的复杂性分析是关闭的。如果你考虑树的高度 H,你会得到 O(H) = 2*O(H-1) + H,来自 (1) 堆积两个子树,以及 (2) 将根冒泡到它的位置.这表明 O(H) = 2^H,因此 O(N) = N。
  • @SteveD 是正确的。如果你正确地实现这一点,复杂性将是 O(N) 的时间。您应该能够将额外空间(递归堆栈深度)限制为 O(log n)。
【解决方案2】:

我不知道如果你不能轻松访问父节点或没有数组表示,如果你可以遍历树将它记录在数组中(O(N)),那么它变得简单。

        1   
     /    \
    2       5
  /   \    / \ 
 3     4  6   7

from the last parent node to the root node(in your case 5,2,1:
  for each node make it compare to their children:
    if children is larger than parent, swap parent and children:
      if swapped: then check the new children's childrens utill no swap

        1   
     /    \
    2       7
  /   \    / \ 
 3     4  6   5    check [7]   5<-->7

        1   
     /    \
    4       7
  /   \    / \ 
 3     2  6   5    check [2]   4<-->2

        7   
     /    \
    4       1
  /   \    / \ 
 3     2  6   5    check [1]   7<-->1

        7   
     /    \
    4       6
  /   \    / \ 
 3     2  1   5    check [1]   6<-->1

就是这样! 复杂度应该是 O(N*LogN)。

【讨论】:

  • 谢谢!是的!我也对在这种情况下访问父节点表示怀疑,但看起来我们必须使用额外的空间来通过级别顺序遍历来存储非叶节点的地址。
  • 但是如果我们必须使用数组(O(N)),为什么不将二叉树存储在一个数组中,然后在O(n)中进行堆放。我的解决方案可能在 O(n^2) 中有效,并且不使用额外空间。
  • @ankitG heapify cost 在我的记忆中应该是 O(NlogN),因为你应该检查所有有子节点的节点。
【解决方案3】:

我认为您只需修改 postOrderTraverse 即可完成一项工作。这是 O(n)

void Heapify_Min(TreeNode* node)
{
  if(! = node) return;
   Heapify_Min(node->left);
   Heapify_Min(node->right);
   TreeNode* largest = node;
   if(node->left && node->left->val > node->val)
      largest = node->left;
   if(node->right && node->right->val > node->val)
      largest = node->right;

  if(largest != node)
  {
    swap(node, largest)
  }
}

void swap(TreeNode* n1, TreeNode* n2)
{
    TreeNode* temp = n1->left;
    n1->left = n2->left;
    n2->left =temp;

    temp = n1->right;
    n1->right = n2->right;
    n2->right = temp;
}

}

【讨论】:

  • 进行交换后,您需要再次检查子树是否仍然是堆
【解决方案4】:

这是解决此问题的有效代码。

package Test;


import static Test.BinaryTreeNode.swap;

public class TestImplementations {
    public static void main(String args[]){
        BinaryTreeNode root = new BinaryTreeNode(2,
                new BinaryTreeNode(7,
                        new BinaryTreeNode(5,
                                new BinaryTreeNode(1),new BinaryTreeNode(6)),
                        new BinaryTreeNode(9,
                                new BinaryTreeNode(17))),
                new BinaryTreeNode(3,
                        new BinaryTreeNode(11),new BinaryTreeNode(4))
                );
        System.out.println(root);
        CustomHeap h = new CustomHeap();
        h.minHeapify(root);
        System.out.println(root);
    }
}

class BinaryTreeNode {
    private  Integer value;
    private  BinaryTreeNode left;
    private  BinaryTreeNode right;

    public BinaryTreeNode(Integer value){
        this.value = value;
        this.left = null;
        this.right = null;
    }

    public BinaryTreeNode(Integer value, BinaryTreeNode left){
        this.value = value;
        this.left = left;
        this.right = null;
    }

    public BinaryTreeNode(Integer value, BinaryTreeNode left, BinaryTreeNode right){
        this.value = value;
        this.left = left;
        this.right = right;
    }

    public Integer getValue() {
        return value;
    }

    public BinaryTreeNode getLeft() {
        return left;
    }

    public BinaryTreeNode getRight() {
        return right;
    }

    public static void swap(BinaryTreeNode r, BinaryTreeNode c){
        Integer val = r.getValue();
        r.value = c.getValue();
        c.value = val;
    }
}

class CustomHeap {
    public void minHeapify(Test.BinaryTreeNode r){
        if( r == null || (r.getLeft() == null && r.getRight() == null)){
            return;
        }
        minHeapify(r.getLeft());
        minHeapify(r.getRight());
        if(isMin(r,r.getLeft())){
            swap(r,r.getLeft());
            minHeapify(r.getLeft());
        }
        if(r.getRight() !=null && isMin(r,r.getRight())){
            swap(r,r.getRight());
            minHeapify(r.getRight());
        }
    }

    private Boolean isMin(Test.BinaryTreeNode r, Test.BinaryTreeNode c){
        return c.getValue() < r.getValue() ? Boolean.TRUE : Boolean.FALSE;
    }
}

【讨论】:

    猜你喜欢
    • 2011-03-08
    • 2019-04-07
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 2013-11-15
    • 2021-09-07
    • 2023-03-16
    • 2018-10-22
    相关资源
    最近更新 更多