【问题标题】:Strategy to find duplicate entries in a binary search tree在二叉搜索树中查找重复条目的策略
【发布时间】:2011-12-04 04:09:05
【问题描述】:

我有一个包含重复条目的 BST。我正在尝试查找重复的条目。现在显然我可以编写一个遍历整个树的愚蠢算法,这很容易。

但是,我想写一个更有效的。到目前为止,这是我所做/想到的:

假设以下树。

      10
     /   \
    5    15
   /\    / \
  2  8   10 16
      \    \
       8   12

如果我想找到所有的8,我会先在10的左子树上找到8。要找到一个重复的,如果它没有右孩子,它会不会是右边最左边的节点- 大于该节点 (8) 的第一个父节点的子树?如果它确实有一个右孩子,那么它可以在其右子树的最左边的节点中,也可以在其左子树的最右边的节点中?

是不是所有情况都可以通过一堆循环和 if 语句来实现?

如果没有,有什么更好的方法?有人可以帮忙吗?

谢谢

编辑: 实际上我刚刚意识到它不能是“最左边的节点”或“最右边的节点”。这将找到下一个最高值或前一个最低值的节点。之前会是一个节点吗?

编辑 2:

修复了我的 BST 示例。它遵循以下插入方法:

if (node == null) 
    return new NodeBST<Value>(name, value);

if (node.key().compareTo(name) > 0)
    node.setLeft(insert(node.left(), name, value));     
else
    node.setRight(insert(node.right(), name, value));

这意味着重复项将被添加到其重复项的右侧.. 对吗?

【问题讨论】:

  • 你事先知道你要找什么号码吗?
  • 这不是违背了 BST 的目的吗?
  • 这不是正确的 BST。根 10 的右分支上不能有 8。
  • @lynks 是的 - 你得到了你想要删除的号码。
  • @John Kugelman 哦,没错!让我解决这个问题。对不起

标签: java algorithm binary-tree


【解决方案1】:

此实现使用递归方法并返回重复条目数组

public class TreeNode<E> {
    public int data;
    public TreeNode left;
    public TreeNode right;
}

public Integer[] findDuplicate(TreeNode tree) {
    Map<Integer, Integer> entries = new HashMap<>();
    List<Integer> duplicates = new LinkedList<>();

    return (Integer[]) findDuplicate(tree, entries, duplicates);
}

private Integer[] findDuplicate(TreeNode tree, Map entries, List duplicates) {
    if (tree == null) 
        return (Integer[]) duplicates.toArray(new Integer[] {});

    if (entries.containsKey(tree.data))
        duplicates.add(tree.data);
    else 
        entries.put((int) tree.data, 1);

    findDuplicate(tree.left, entries, duplicates);
    findDuplicate(tree.right, entries, duplicates);

    return (Integer[]) duplicates.toArray(new Integer[] {});
}

【讨论】:

    【解决方案2】:
    1. 查找使用通常的二叉树搜索算法与您的键匹配的元素。如果找不到,请停止。
    2. 检查 LH 子分支。如果其键匹配,则将其设为当前节点并重复此步骤。
    3. 您现在位于具有该键的树中的第一个元素。现在,在键相等的情况下从该节点开始进行树遍历,即访问该节点、右子树、父节点、父节点的右子树等,留给读者作为练习。

    【讨论】:

    • 我相信在步骤 2 中它应该是 RH 子分支,因为根据我的插入(如上面的编辑 2 所示),重复项被插入到节点的右子节点。对吗?
    • @Nayefc 第一次到(2)可能不知道所有的重复都只在右边。这取决于您如何编写搜索代码。
    • 哦,是的,我知道。我只是说我的插入方法将重复项放在节点的右侧。 (请参见上面的代码+图表)。所以这不会使第 2 步成为:Examine the RH sub-brance 而不是 LH 子分支?
    • @Nayefc 这不会改变任何事情。 当你搜索时,你要么在键相等时继续向左走,要么在第一个匹配时停止。如果是后者,则副本可能在两侧。
    • 哦,你给出了整个搜索算法。明白了...谢谢
    【解决方案3】:

    您展示的树假设(好吧,至少我假设... ;-))小于在左边,大于在右边,对吗?

    所以你应该考虑两件事:

    1. 你的树错了! “10”头部右侧的第二个“8”不可能存在,因为它小于 10。正确的插入和正确的平衡,如果不是在“下一次”迭代中正确的话,都会非常接近从“左 8”开始。

    2. 通过将树定义为左侧的“小于或等于”和右侧的“大于”,您会得到想要的结果:所有“8”都将链接到在一个简单的插入树上彼此的左边。

    【讨论】:

    • 是的,我为我的错误道歉。请参阅编辑 2。我的插入将它们链接到彼此的右侧。因此,当我找到重复项时,只需通过其正确的子项/子项查看所有重复项?
    • 绝对。此外,为了简洁和性能,如果您期望大量重复,则从第一个扩展所有相似值对象的链表可能是一个好主意。如果确实有大量重复项,您可以为包含重复项的叶子创建一个哈希表……这一切都取决于您要解决的特定问题!
    【解决方案4】:

    递归算法可以快速解决这个问题。您不必递归整个树,因为您可以使用 BST 的结构来寻找您需要的值。

    你画的并不是严格意义上的 BST,我可能是错的,但我相信它已经很糟糕了 - 左边树中的所有数字都应该小于 10,反之亦然。

    【讨论】:

    • 对不起,我知道。我做错了,请参阅修改后的编辑 2。谢谢
    猜你喜欢
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 2014-06-11
    • 1970-01-01
    • 1970-01-01
    • 2011-02-05
    • 2021-10-20
    • 1970-01-01
    相关资源
    最近更新 更多