当前位置: 首页 > 知识库问答 >
问题:

为什么我的二叉搜索树删除递归没有结束?

訾凯歌
2023-03-14

我试图实现一个二叉查找树使用Java。我想创建的函数之一是删除函数。这将由两个方法组成,一个称为删除,另一个称为getNodeToDelete。getNodeToDelete方法是删除方法的辅助函数。

getNodeToDelete方法是递归的,基本上返回用户希望从树中删除的节点。使用此getNodeToDelete方法返回的节点,非递归删除方法基本上会根据不同情况(例如,它是叶节点还是根节点等)对如何删除此节点做出重要决定。

这是非递归删除方法:

 /**
     * 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;
    }

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

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

如果你需要更多的澄清,请告诉我。谢啦

共有1个答案

关冠宇
2023-03-14

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

基本上,我的递归(在递归方法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.
    }

除了我改变的其他几件事情,这是因为我的删除函数中的一些错误,让我的getNodeToDelete方法返回用户想要删除的节点,是通过在添加返回注释的地方添加返回语句以上代码片段中的语句。

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

 类似资料:
  • 首先,这是家庭作业,所以把它放在外面。 我应该用特定的方法实现二叉查找树: void insert(字符串)、boolean remove(字符串)和boolean find(字符串)。 我已经能够成功地编程和测试插入,并找到方法,但我有困难与删除。 我的程序中发生的事情是,删除实际上并没有从树中删除任何东西,我相信这是因为它只引用当前节点的本地创建,但我可能错了。我认为我可以实现我需要测试的不同

  • 在二元搜索树的情况下,为什么我们不能简单地在一个节点有两个子节点的情况下,将一个节点的前一个节点替换为后一个节点?

  • 我试图为我的BST做一个递归加法。public add方法接受一个int参数,private方法接受相同的int和一个节点。这是我目前掌握的代码 我经常得到空指针,也尝试过调试,但我的逻辑中有一些我看不到的缺陷。

  • 我正在尝试为我一直在研究的BST结构实现一个移除方法。以下是包含查找、插入和删除方法的代码: 我被告知可以使用insert方法来帮助我使用remove方法,但我只是不知道如何获取最小/最大的元素,然后用该值替换我正在删除的元素,然后递归地删除我获取替换值的节点,同时仍然保持O(logn)的复杂性。有人有什么想法或明显的漏洞我错过了,或任何其他有帮助的,因为我撞我的头在这个问题上? 编辑:我用答案的

  • 从二叉查找树中删除节点时,您可以将节点替换为左侧的最大子节点或右侧的最小子节点。 我很难理解以下实现执行删除操作的方式。 上面的代码包括以下步骤: < li >查找替换节点。 < li >让替换节点引用已删除节点的左右子节点。 < li >让已删除节点的左右子节点将替换节点作为父节点。 < li >让替换节点引用已删除节点的父节点作为自己的父节点。 < li >清理。 我有困难的部分特别是递归。据

  • 对于我用私有字段实现的二叉树对象 我有一个方法,它需要返回一个树,包括具有的节点和具有的节点之间的所有键及其相应值。这个方法也需要使用递归来执行。 我遇到的问题是,我无法找到一种方法来获得一个以结尾的树(可能看起来像一个LinkedList),而不包括和。我想我应该首先在根的左树或右树上递归调用方法,这取决于startKey是大于还是小于根键,所以: 这将一直在树中导航,直到到达包含键的节点。当我