在不使用if条件的情况下计算二叉树中的叶子

时间:2016-08-22 05:51:51

标签: java algorithm recursion tree polymorphism

我知道有一种通用算法可以通过检查节点是否没有左右子来计算递归的叶数。但是我想用多态代码编写相同的代码并检查它是否可能,现在我不能检查叶子条件,但是这些信息并不完全取决于当前节点,下面是我的代码实现直到现在:

import java.util.*;
import java.lang.*;
import java.io.*;


abstract class Tree {
  abstract int count();
}

class Empty extends Tree {
  public int count() {
    return 0;   
  }
}

class NonEmpty extends Tree {

  private final int val;
  private final Tree left;
  private final Tree right;

  public NonEmpty(int val, Tree left, Tree right) {
    this.val   = val;
    this.left  = left;
    this.right = right;
  }

  public int count() {
    return left.count() + right.count();
  }
}

public class Main {
  public static void main(String[] args) throws java.lang.Exception {
    Tree t = new NonEmpty(5, new Empty(), new Empty());
    System.out.println(t.count()); // 0 but should be 1
  }
}

更新1

我和几位同事讨论过这个想法,我受到了很多批评,所以这是一个坏主意吗?我认为这对我来说很干净,我想听听别人的意见。

5 个答案:

答案 0 :(得分:4)

最终修复解决方案:

interface Tree {
    Tree NULL_TREE = new NullTree();

    int countLeafs();
    Tree left();
    Tree right();
}

class NullTree implements Tree {
    @Override
    public int countLeafs() {
        return 0;
    }

    @Override
    public Tree left() {
        return this;
    }

    @Override
    public Tree right() {
        return this;
    }
}

class Leaf implements Tree {
    private int val;

    public Leaf(int val) {
        this.val = val;
    }

    public int countLeafs() {
        return 1;
    }

    @Override
    public Tree left() {
        return NULL_TREE;
    }

    @Override
    public Tree right() {
        return NULL_TREE;
    }
}

class Node implements Tree {

    private final int val;
    private final Tree left;
    private final Tree right;

    public Node(int val, Tree left, Tree right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }

    @Override
    public int countLeafs() {
        return left.countLeafs() + right.countLeafs();
    }

    @Override
    public Tree left() {
        return left;
    }

    @Override
    public Tree right() {
        return right;
    }
}

public class Main {
    public static void main(String[] args) throws java.lang.Exception {
        Tree t = new Node(5, new Leaf(10), new Leaf(20));
        System.out.println(t.countLeafs());
    }
}

答案 1 :(得分:3)

更改

public int count() {
    return left.count() + right.count();
}

public int count() {
    return Math.max(1, left.count() + right.count());
}

这与涉及条件表达式的Konstantin's original answer类似:如果left.count() + right.count()为0,则它​​是一个叶子,其计数应为1.

(编辑:我删除了其余部分,因为它有太多警告并且消除它们会比它更复杂。)

答案 2 :(得分:2)

好吧,让我们有另一个名为Branch的类,建议@ friendlydog

abstract class Tree {
  abstract int count();
}

class Empty extends Tree {
  public int count() {
    return 0;   
  }
}

class NonEmpty extends Tree{
    private final int val;

    public NonEmpty(int val){
        this.val=val;
    }

    public int count(){
        return 1;
    }
}

class Branch extends Tree {

  private final int val;
  private final Tree left;
  private final Tree right;

  public Branch(int val, Tree left, Tree right) {
    this.val   = val;
    this.left  = left;
    this.right = right;
  }


  public int count() {
    return 1+left.count() + right.count(); // to count all non-empty nodes
    //return left.count()+right.count(); //to count only leaves;
  }
}

public class Main {
  public static void main(String[] args) throws java.lang.Exception {
    Tree t = new Branch(5, new Empty(), new Empty());
    System.out.println(t.count()); // now it's 1 :)
  }
}

对于更好的解决方案,您可以在Branch上再增加2个构造函数:一个只有val,用leftright填充Empty },以及val和非Empty left的另一个,仅填充right

答案 3 :(得分:2)

我到目前为止所看到的答案假设您有一个叶子或一个两个一个左右孩子的节点。这是一种可以处理任何失踪儿童的方法:

class Tree {
    final Optional<Tree> left;
    final Optional<Tree> right;

    Tree(Optional<Tree> left, Optional<Tree> right) {
        this.left = left;
        this.right = right;
    }

    int leafCount() {
        return left.map(Tree::leafCount)
                .map(l -> right.map(Tree::leafCount).map(r -> l + r).orElse(l))
                .orElse(right.map(Tree:leafCount).orElse(1));

    }
}

Optional.orElse()看起来很像伪装的if ......

答案 4 :(得分:0)

添加额外函数和额外变量以确定节点类型。

这假设一个NonEmpty节点有两个空节点作为子节点是叶子,其他条件被认为不是叶子。

abstract class Tree {
    abstract int count();
    abstract int type();
}

class Empty extends Tree {
    public int type() {
        return 1;   
    }

    public int count() {
        return 0;   
    }
}

class NonEmpty extends Tree {

    private final int val;
    private final Tree left;
    private final Tree right;
    private final int type;

    public NonEmpty(int val, Tree left, Tree right) {
        this.val   = val;
        this.left  = left;
        this.right = right;
        this.type  = left.type() * right.type();
    }

    public int type() {
        return 0;   
    }

    public int count() {
        return (1-this.type) * (left.count() + right.count()) + this.type;
    }

}