【问题标题】:How to handle null check when searching for a node in Binary Search Tree在二叉搜索树中搜索节点时如何处理空检查
【发布时间】:2014-12-31 10:12:29
【问题描述】:

我有以下代码在 BST 中搜索节点:

private Node<AnyType> searchAndGetNode(AnyType value) {
        Node<AnyType> currentNode = root; 
        while(currentNode != null && currentNode.getData() != null) {
            if (value.compareTo(currentNode.getData()) == 0) {
                return currentNode;
            } else if (value.compareTo(currentNode.getData()) < 0) {
                currentNode = currentNode.getLeft();
            } else {
                currentNode = currentNode.getRight();
            }
        }
        return null;
    }

我知道 Optional.ofNullable() 来获取一个 Optional 对象,然后使用 isPresent() 来避免空检查。但是我想不出任何巧妙的方法来避免在上述方法的while循环中进行空检查比较。我正在使用 Java 8。请提出建议。

【问题讨论】:

    标签: java data-structures binary-search-tree optional


    【解决方案1】:

    您应该删除条件的 &amp;&amp; currentNode.getData() != null 部分,因为在二叉树中存在空值是没有意义的(您不能在 null 上调用 compareTo,那么您将它插入到树的哪个位置?)。除此之外,您的空检查没有任何问题。

    但是,为了提高性能,您不应为每个值调用两次compareTo,而应调用一次并检查结果:

    int cmp = value.compareTo(currentNode.getData());
    if (cmp == 0) {
        return currentNode;
    } else if (cmp < 0) {
        currentNode = currentNode.getLeft();
    } else { // cmp > 0
        currentNode = currentNode.getRight();
    }
    

    【讨论】:

      【解决方案2】:

      但我想不出任何巧妙的方法来避免空检查比较 在while循环中

      !=null 没有任何问题。


      但是您可以改用 Leafs 和 Nodes 的接口(并使用 Java 8 的默认方法)。
      interface Tree<T> {
      
          boolean isEmpty();
      
          default T getData() {
              throw new UnsupportedOperationException();
          }
      
          default Tree<T> getLeft() {
              throw new UnsupportedOperationException();
          }
      
          default Tree<T> getRight() {
              throw new UnsupportedOperationException();
          }
      
      }
      
      class Leaf<T> implements Tree<T> {
      
          @Override
          public boolean isEmpty() {
              return true;
          }
      
      }
      
      class Node<T> implements Tree<T> {
      
          public Node(Tree<T> left, Tree<T> right, T data) {...}
          //implement getLeft, getRight etc.
          @Override
          public boolean isEmpty() {
              return false;
          }   
      
      }
      

      那么就不再需要在您的代码中进行空值检查(在这一点上遵循 @Boann,您将在 BST 中的哪里存储 null 引用?):

      class BST<T extends Comparable<? super T>> {
      
          ...
      
          private Tree<T> searchAndGetNode(T value) {
              Tree<T> currentNode = root; 
              while(!currentNode.isEmpty()) {
                  int cmp = value.compareTo(currentNode.getData());
                  if (cmp == 0) {
                      return currentNode;
                  } else if (cmp < 0) {
                      currentNode = currentNode.getLeft();
                  } else {
                      currentNode = currentNode.getRight();
                  }
              }
              return currentNode; //it will be a Leaf at this point
          }
      
      }
      

      然后您可以调用isEmpty() 来检查是否从searchAndGetNode 方法返回了节点或叶子。

      有些人可能会争辩说isEmpty() 也可以在Tree 接口中实现。

      【讨论】:

        【解决方案3】:

        你必须在某个地方检查它,如果不是在while 条件中而不是在getLeft()getRight() 中(无论是当你调用它还是在它里面)。您选择的选项更好恕我直言,因为您只检查一次,而其他选项需要多次检查。

        【讨论】:

          【解决方案4】:

          你无法避免空值检查。您必须有一些条件来确定何时完成对树的搜索而没有找到请求的节点。这个检查是比较一些对 null 的引用还是询问一些 Optional 是否为空都没有区别。

          【讨论】:

            【解决方案5】:

            我认为您的代码可以正常工作。当您输入不存在或具有空值的右/左孩子时,您将简单地退出您的 while 循环。你的循环需要一个结束条件,而 null 就是这个地方。

            我只建议更换

            currentNode.getData() != null
            

            使用此节点的方法,例如currentNode.hasData()。这将隐藏您的逻辑并且更具可读性:)

                 private Node<AnyType> searchAndGetNode(AnyType value) {
                    Node<AnyType> currentNode = root; 
                    while(currentNode != null && currentNode.getData() != null) {
                        int comparedValue = value.compareTo(currentNode.getData());//compare once. Because this is a int
                        if (comparedValue  == 0) {
                            return currentNode;
                        } else if (comparedValue  < 0) {
                            currentNode = currentNode.getLeft();
                        } else {
                            currentNode = currentNode.getRight();
                        }
                    }
                    return null;
                }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多