【问题标题】:BST intersection, NullPointerExceptionBST 交点,NullPointerException
【发布时间】:2011-04-20 19:49:15
【问题描述】:

我正在尝试从 2 个已知 BST 的交集创建一个新的 BST。在第二种情况下,我在 intersect2 方法中得到 NullPointerException,在“cur3.item.set_account_id(cur1.item.get_accountid()+ cur2.item.get_accountid());”行。我知道当您尝试取消引用变量而不初始化它时会出现错误,但我认为我正在初始化它?我不太确定。我将不胜感激。

public static Bst<Customer> intersect(Bst<Customer> a, Bst<Customer> b){
     return( intersect2(a.root, b.root));
 }

  public static Bst<Customer> intersect2(BTNode<Customer> cur1, BTNode<Customer> cur2){
  Bst<Customer> result = new Bst<Customer>();

// 1. both empty -> true
  if (cur1==null && cur2==null){
  result=null;
 }
// 2. both non-empty -> compare them
 else if (cur1!=null && cur2!=null) {
  BTNode<Customer> cur3 = new BTNode<Customer>();
  cur3.item.set_account_id(cur1.item.get_accountid()+ cur2.item.get_accountid());
  result.insert(cur3.item);
  intersect2(cur1.left, cur2.left);
  intersect2(cur1.right, cur2.right);
 }

// 3. one empty, one not -> false
else if (cur1==null ||cur2==null){
  BTNode<Customer> cur3 = new BTNode<Customer>();
  cur3.item=null;
  intersect2(cur1.left, cur2.left);
  intersect2(cur1.right, cur2.right);
}
 return result;
}

这是问题的图片:

【问题讨论】:

  • 为什么不直接做Bst&lt;Customer&gt; intersection = new Bst&lt;Customer&gt;(); for(Customer c : a) if(b.contains(c)) intersection.add(c);
  • 对不起,但我没有听懂你想说的话。我的目标是通过在两个给定树都有子节点的级别添加节点来创建第三棵树。新树的元素是通过添加 Customer 对象的属性之一来决定的。
  • 那么,如果两棵树有相同的客户,但它位于三个 a 的第三个“级别”和树 b 的第四个“级别”,它不会包含在您的交集中?
  • 如果树 a 只有 3 层,那么结果树将只有 3 层。只有在树 a 也至少有 4 层时,才会将树 b 的第四层的客户纳入计算。现在是不是更有意义了?
  • 不,它没有。为什么树中元素的内部位置对交叉点很重要?树的用户不应该知道(或关心)元素在树中的位置,只是它们存在并且可以在合理的时间内(在本例中为 lg n)检索到。

标签: java binary-search-tree


【解决方案1】:

NullPointerException 可能由多种原因引起。在您给定的示例中,cur1 和 cur2 不为空,但不能保证 cur1.item、cur1.item.accountId(cur2 也是如此)不为空。

由于您没有对底层实现的描述,因此我无法提供进一步的帮助。 我可以建议你做一些事情:
1.) 检查对象的实现(如果每次都发生这种情况,可能存在某种初始化问题。
2.) 每当您创建项目实例时,是否确保指定 accountId 字段?尝试为此字段提供默认值,使其不能为空。 (尝试某种非法值 [例如 -1、false 等] 并对其进行测试。

如果您愿意发布更多实施细节,我(或某人)或许能够直接找出问题所在。

问候。

编辑:4/20@17:11 这是你应该做的一个例子。

public class Customer {  
    private int accountId;  

    public Customer() {  
        this.accountId = 0;  
    }  

    public Customer(int account_identification) {  
        this.accountId = account_identification);  
    }  

    //As a side note, general practice implies fields be private  
    //Use a method (hence the term 'getter' and the reciprocal, 'setter')  
    public int getId() {  
        return this.accountId;  
    }  

    public void setId(int replacement_account_identification) {  
        this.accountId = replacement_account_identification;  
    }
}

【讨论】:

  • 嗨,迈克,客户类有一个默认构造函数,它不设置任何值。它只是一个空的构造函数。 BTNode 构造函数将项目及其左右节点的值设置为 NULL。这些信息有帮助吗?
  • 是的,因为您没有初始化 accountId 字段(由空构造函数暗示),您正在尝试连接/添加一个潜在的空值。这是一个禁忌。左/右节点为空是可以的(它实际上是“正确的”),所以那里没有问题。看来您应该(至少)为 accountId 生成/定义一个默认值。
  • 我在默认构造函数中将accountId初始化为0,但错误依旧存在。
  • 大声笑我不敢相信我没有看到它...... cur3.item.set_account_id.... 这里 cur3 没有项目。为它制作一个项目(客户),问题(应该)消失。在问题行之前,将项目从其他节点之一中取出,将其放在 cur3 中,然后更新帐户。
  • 是的,我设法弄明白了。谢谢你的帮助,迈克尔。
【解决方案2】:

这是因为Customer对象中的item变量没有初始化。

【讨论】:

  • 您能详细说明一下吗?
  • 即。 cur3 的 item 成员可能为空。即 cur3.item = null。
【解决方案3】:

创建BTNode会自动分配其成员item吗?

你这样做:

cur3.item.set_account_id(.. )

要成功,cur3cur3.item 都必须不为空。

同样适用于cur1cur2,您稍后会在该行中引用。

而第三种情况的例子表明BTNode.item在某些场景下可以为null:

cur3.item=null;

【讨论】:

  • 创建一个 BTNode 会将成员项初始化为 null。我在第三个示例中这样做是因为我不希望结果树中该节点的任何值(它将是任何空节点,也就是不存在)。这样做有错吗?
  • 是的。 item==null 将创建 NPE,因为 cur3.item.set_account() 执行 dererference (cur3.item),它为 null,因此以 null.set_account() 结束。其他 BTNode 也一样。
  • 您能告诉我如何解决这个问题吗?据我所知,这一步是必要的,因为需要为新树节点的项目分配值。我应该将 cur3 分配给结果的根节点吗?我真的不知道这是否是理想的解决方案,因为根本身是通过该方法决定的。对不起,我只是困惑并停留在这一点上。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
  • 2021-04-06
  • 1970-01-01
  • 1970-01-01
  • 2021-10-17
  • 2017-06-14
相关资源
最近更新 更多