二叉树最大总和水平 - 更好的设计?

时间:2012-08-13 06:55:32

标签: java algorithm optimization tree binary-tree

我编写了一个代码,用于在二叉树中查找具有最大元素总和的级别。我有几个问题。

  1. 这是一个好的设计吗? - 我使用了2个队列,但两个队列存储的元素总数将小于n。所以我认为应该没问题。
  2. 可以有更好的设计吗?

    public class MaxSumLevel {  
    public static int findLevel(BinaryTreeNode root) {      
        Queue mainQ = new Queue();
        Queue tempQ = new Queue();
        int maxlevel = 0;
        int maxVal = 0;
        int tempSum = 0;
        int tempLevel = 0;
        if (root != null) {
            mainQ.enqueue(root);
            maxlevel = 1;
            tempLevel = 1;
            maxVal = root.getData();
        }           
        while ( !mainQ.isEmpty()) {         
            BinaryTreeNode head = (BinaryTreeNode) mainQ.dequeue();
            BinaryTreeNode left = head.getLeft();
            BinaryTreeNode right = head.getRight();
            if (left != null) {
                tempQ.enqueue(left);
                tempSum = tempSum + left.getData();
            }
            if (right != null) {
                tempQ.enqueue(right);
                tempSum = tempSum + right.getData();
            }           
            if (mainQ.isEmpty()) {
                mainQ = tempQ;
                tempQ = new Queue();
                tempLevel ++;
                if (tempSum > maxVal) {
                    maxVal = tempSum;
                    maxlevel = tempLevel;
                    tempSum = 0;
                }               
            }           
        }
        return maxlevel;
    }
    

    }

5 个答案:

答案 0 :(得分:1)

这取决于您的树木有多少节点以及它们有多深。由于您正在执行breadth first search,因此您的队列将占用 O(n)内存空间,这对大多数应用程序都是可以的。

以下解决方案具有 O(l)空间复杂度和 O(n)时间复杂度( l 是树的深度和 n 其顶点数量):

public List<Integer> levelsSum(BinaryTreeNode tree) {
    List<Integer> sums = new ArrayList<Integer>()
    levelsSum(tree, sums, 0);
    return sums;
}
protected void levelsSum(BinaryTreeNode tree, List<Integer> levelSums, int level) {
    if (tree == null)
        return;
    // add new element into the list if needed
    if (level.size() <= level)
        levelSums.add(Integer.valueOf(0));
    // add this node's value to the appropriate level
    levelSums.set(level, levelSums.get(level) + tree.getData());
    // process subtrees
    levelSum(tree.getLeft(),  levelSums, level + 1);
    levelSum(tree.getRight(), levelSums, level + 1);
}

现在只需在树上调用levelsSum并扫描返回的列表以找到最大值。

答案 1 :(得分:1)

我喜欢递归(注意,未经测试的代码):

public static int maxLevel(BinaryTreeNode tree) {    
    ArrayList<Integer> levels = new ArrayList<Integer>();
    findLevels(tree, 0, levels);
    // now just return the index in levels with the maximal value.
    // bearing in mind that levels could be empty.
}
private static void findLevels(BinaryTreeNode tree, int level,
                                  ArrayList<Integer> levels) {
    if (tree == null) {
        return;
    }
    if (levels.length <= level) {
        levels.add(0);
    }
    levels.set(level, levels.get(level) + tree.getData());
    findLevels(tree.getLeft(), level+1, levels);
    findLevels(tree.getRight(), level+1, levels);
}

如果我对垃圾收集器真的很有意义,我会让findLevels返回一个(级别,值)对的列表并对它们求和。这在共同规范的语言中更有意义,但在Java中它会很奇怪。

显然,您可以在递归函数中使用策略,并使用要处理的显式堆栈节点来执行此操作。我和你的方式之间的关键区别在于我的记忆与树的高度成正比;你的内存与其宽度成正比。

查看您的代码,这种方法似乎很合理。我将tempLevel重命名为currentLevel,我倾向于将内循环拉入函数sumLevel,该函数接受队列并返回一个int和一个队列(实际上除外)队列是一个参数,因为你只能返回一个值,grrr)。但它似乎没问题。

答案 2 :(得分:0)

你确定元素都是非负面的吗?

我会像new MaxSumLevel(root).getLevel()一样调用它。否则,当你有时必须返回maxSum时,你会怎么做?

我会将其构造为2个嵌套循环:

while(!mainQ.isEmpty()){
     while(!mainQ.isEmpty()){
        BinaryTreeNode head = (BinaryTreeNode) mainQ.dequeue();
        BinaryTreeNode left = head.getLeft();
        BinaryTreeNode right = head.getRight();
        if (left != null) {
            tempQ.enqueue(left);
            tempSum = tempSum + left.getData();
        }
        if (right != null) {
            tempQ.enqueue(right);
            tempSum = tempSum + right.getData();
        }
     }
     mainQ = tempQ;
     tempQ = new Queue();
     tempLevel ++;
     if (tempSum > maxVal) {
         maxVal = tempSum;
         maxlevel = tempLevel;
         tempSum = 0;
     }               

}

答案 3 :(得分:0)

这种递归方法对我有用:

public int findMaxSumRootLeaf(TreeNode node,int currSum) {
    if(node == null)
        return 0;
    return Math.max(findMaxSumRootLeaf(node.leftChild,currSum)+node.data, findMaxSumRootLeaf(node.rightChild,currSum)+node.data);
}

答案 4 :(得分:0)

您可以使用队列中的null来表示级别的结束,并计算每个级别的最大总和。

public int maxLevelSum(BinaryTreeNode root) {
    if (root == null)                 //if empty tree
        return 0;
    else {
        int current_sum = 0;          
        int max_sum = 0;
        Queue<BinaryTreeNode> queue = new LinkedList<BinaryTreeNode>();       //initialize a queue
        queue.offer(root);  //add root in queue
        queue.offer(null);  // null in queue represent end of a level
        while (!queue.isEmpty()) {
            BinaryTreeNode temp = queue.poll();         
            if (temp != null) {
                if (temp.getLeft() != null)                  //if left is not null
                    queue.offer(temp.getLeft());
                if (temp.getRight() != null)
                    queue.offer(temp.getRight());            //if right is not null
                current_sum = current_sum + temp.getData();  //add to level current level sum
            } else {                                         // we reached end of a level
                if (current_sum > max_sum)                   //check if cuurent level sum is greater than max
                    max_sum = current_sum;
                current_sum = 0;                            //make current_sum=0 for new level
                if (!queue.isEmpty())                                  
                    queue.offer(null);                      //completion of a level
            }
        }
        return max_sum;                                     //return the max sum
    }
}