【问题标题】:Why Is My Binary Search Tree Delete Recursion Not Ending?为什么我的二叉搜索树删除递归没有结束?
【发布时间】:2021-06-02 15:49:39
【问题描述】:

我正在尝试使用 Java 实现二叉搜索树。我要创建的功能之一是删除功能。这将包含两种方法,一种称为 delete,另一种称为 getNodeToDeletegetNodeToDelete 方法是 delete 方法的辅助函数。

getNodeToDelete 方法是递归的,基本上返回用户想要从树中删除的节点。使用从这个 getNodeToDelete 方法返回的节点,非递归 delete 方法基本上会根据不同的情况(例如,它是叶节点,是否是根节点等)。

这是非递归的删除方法:

 /**
     * Deletes the relevant node (according to the key inputted by the user), using two helper functions:
     * getNodeToDelete(int deleteKey, Node root) and getMinRight(Node nodeToDelete).
     * @param key
     */
    public void delete(int key) {
        if (root.left == null && root.right == null) {
            if (root.key == key) {
                root = null;
                System.out.println("It reached the first if-statement of the delete() method.");
            }
        }
        Node nodeToDelete = getNodeToDelete(key, root); //The node that is returned from its helper function.
        System.out.println("This is the node to delete: " + nodeToDelete.key);
        if (nodeToDelete.right == null && nodeToDelete.left == null) {  //If the nodeToDelete is a leaf.
            nodeToDelete = null;
//            System.out.println("This is the key of the deleted node: " + nodeToDelete.key);
            return;
        } else if (nodeToDelete.right == null) {  //If the nodeToDelete has an empty right tree.
            Node immediateLeftNode = nodeToDelete.left;
            nodeToDelete.key = immediateLeftNode.key;
            nodeToDelete.left = immediateLeftNode.left;
            nodeToDelete.right = immediateLeftNode.right;
        } else if (nodeToDelete.right != null) {  //If the nodeToDelete has a non-empty right tree
            if (nodeToDelete.right.left == null) {  //If the left branch of the right branch of nodeToDelete is empty.
                nodeToDelete.key = nodeToDelete.right.key;
                nodeToDelete.right = nodeToDelete.right.right;
            } else {
                Node replacementNode = getMinRight(nodeToDelete);
                nodeToDelete.key = replacementNode.key;
            }
        }
    }

这是递归的getNodeToDelete方法:

/**
     * Assumption: the key does exist in the tree.
     * Returns the node that the user wants to delete, based on the key that the user inputs.
     * @param deleteKey
     * @param startingRoot
     * @return
     */
    public Node getNodeToDelete(int deleteKey, Node startingRoot) {
        if (startingRoot == null) {
            return null;
        }

        if (startingRoot.key == deleteKey) {
            return startingRoot;
        }

        if (deleteKey < startingRoot.key) {
            getNodeToDelete(deleteKey, startingRoot.left);
        }

        getNodeToDelete(deleteKey, startingRoot.right);
        return startingRoot;
    }

问题是,辅助函数 getNodeToDelete 向下遍历树到其节点之一,例如值为 -12 的叶节点。然后它返回该节点,但递归方法 getNodeToDelete 似乎没有结束。然后它再次遍历回到根节点,始终导致返回的值是根节点。

我知道在 Java 中实现二叉搜索树有很多不同的方法,但是这个递归问题困扰着我,我真的很想知道失败背后的原因。

如果您需要更多说明,请告诉我。谢谢

【问题讨论】:

  • 删除一个节点是什么意思?是否要删除该节点下的整个子树?或者只是那个节点,然后“重新连接”子树?
  • 我只想删除该节点并重新连接子树。顺便说一句,你是在删除之前写答案的人吗?

标签: java recursion binary-search-tree


【解决方案1】:

有人在删除之前回答了我的问题,但他们的回答确实帮助我找到了解决方案。所以,谢谢你。

基本上,我的递归(在递归方法中,getNodeToDelete)总是返回我的根节点,因为我没有返回递归的结果。因此,丢弃我想要的数据而不是让它再次出现在我身上。这很难解释,但基本上,这是修复后的 getNodeToDelete 方法:

/**
     * Assumption: the key does exist in the tree.
     * Returns the node that the user wants to delete, based on the key that the user inputs.
     * @param deleteKey
     * @param startingRoot
     * @return
     */
    public List<List> getNodeToDelete(int deleteKey, Node startingRoot, Node parentNode, String directionFlag) {
        List<Node> nodes = new ArrayList<>();
        nodes.add(startingRoot);
        nodes.add(parentNode);

        List<List> nodeData = new ArrayList<>();
        nodeData.add(nodes);
        List<String> direction = new ArrayList<>();
        direction.add(directionFlag);

        nodeData.add(direction);

        if (startingRoot == null) {
            return null;
        }

        if (startingRoot.key == deleteKey) {
            System.out.println("This is node that is FINALLY RETURNED " + startingRoot.key);
            return nodeData;
        }

        if (deleteKey < startingRoot.key) {
            System.out.println("This is node that is returned " + startingRoot.key);
            return getNodeToDelete(deleteKey, startingRoot.left, startingRoot, "left"); //Added return statement here.
        }

        System.out.println("This is node that is returned " + startingRoot.key);
        return getNodeToDelete(deleteKey, startingRoot.right, startingRoot, "right");  //Added return statement here.
    }

除了我更改的其他几件事,这是由于我的 delete 函数中的一些错误,允许我的 getNodeToDelete 方法返回节点的事情用户想要删除,是通过在上面的代码sn-p中用Added return statement here注释的地方添加return语句。

对于为什么我忽略了递归背后的这一重要步骤,这仍然让我感到非常震惊,所以我需要更多地思考它。但是,基本上,这个故事的寓意是,确保真正从递归中返回结果,而不是简单地递归调用函数!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-08
    • 1970-01-01
    • 2018-03-19
    • 2014-01-02
    • 1970-01-01
    相关资源
    最近更新 更多