高效遍历单向树

发布于 2024-07-08 11:24:21 字数 347 浏览 8 评论 0原文

我有一个单向对象树,其中每个对象都指向其父对象。 给定一个对象,我需要获取其整个后代子树,作为对象的集合。 这些对象实际上并不在任何数据结构中,但我可以轻松获取所有对象的集合。

最简单的方法是检查批处理中的每个对象,查看给定的对象是否是祖先,然后将其放在一边。 这不会太高效...它会带来 O(N*N) 的开销,其中 N 是对象的数量。

另一种方法是递归方法,即搜索对象的直接子对象并在下一个级别重复该过程。 不幸的是,这棵树是单向的……没有直接到达子节点的方法,而且这只会比以前的方法稍微便宜一点。

我的问题:我在这里忽略了一种有效的算法吗?

谢谢,

尤瓦尔=8-)

I've got a unidirectional tree of objects, in which each objects points to its parent. Given an object, I need to obtain its entire subtree of descendants, as a collection of objects. The objects are not actually in any data structure, but I can easily get a collection of all the objects.

The naive approach is to examine each object in the batch, see if the given object is an ancestor, and keep it aside. This would not be too efficient... It carries an overhead of O(N*N), where N is the number of objects.

Another approach is the recursive one, meaning search for the object's direct children and repeat the process for the next level. Unfortunately the tree is unidirectional... there's no direct approach to the children, and this would be only slightly less costly than the previous approach.

My question: Is there an efficient algorithm I'm overlooking here?

Thanks,

Yuval =8-)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

奈何桥上唱咆哮 2024-07-15 11:24:21

正如其他人提到的,构建对象的哈希表/映射到其(直接)子对象的列表。

从那里您可以轻松查找“目标对象”的直接子对象列表,然后对于列表中的每个对象重复该过程。

下面是我在 Java 中使用泛型的方法,使用队列而不是任何递归:

public static Set<Node> findDescendants(List<Node> allNodes, Node thisNode) {

    // keep a map of Nodes to a List of that Node's direct children
    Map<Node, List<Node>> map = new HashMap<Node, List<Node>>();

    // populate the map - this is O(n) since we examine each and every node
    // in the list
    for (Node n : allNodes) {

        Node parent = n.getParent();
        if (parent != null) {

            List<Node> children = map.get(parent);
            if (children == null) {
                // instantiate list
                children = new ArrayList<Node>();
                map.put(parent, children);
            }
            children.add(n);
        }
    }


    // now, create a collection of thisNode's children (of all levels)
    Set<Node> allChildren = new HashSet<Node>();

    // keep a "queue" of nodes to look at
    List<Node> nodesToExamine = new ArrayList<Node>();
    nodesToExamine.add(thisNode);

    while (nodesToExamine.isEmpty() == false) {
        // pop a node off the queue
        Node node = nodesToExamine.remove(0);

        List<Node> children = map.get(node);
        if (children != null) {
            for (Node c : children) {
                allChildren.add(c);
                nodesToExamine.add(c);
            }
        }
    }

    return allChildren;
}

如果我记得如何计算的话,预期执行时间介于 O(n) 和 O(2n) 之间。 您一定会查看列表中的每个节点,再加上一些操作来查找节点的所有后代 - 在最坏的情况下(如果您在根节点上运行算法),您将查看列表中的每个节点列表两次。

As others have mentioned, build a hashtable/map of objects to a list of their (direct) children.

From there you can easily lookup a list of direct children of your "target object", and then for each object in the list, repeat the process.

Here's how I did it in Java and using generics, with a queue instead of any recursion:

public static Set<Node> findDescendants(List<Node> allNodes, Node thisNode) {

    // keep a map of Nodes to a List of that Node's direct children
    Map<Node, List<Node>> map = new HashMap<Node, List<Node>>();

    // populate the map - this is O(n) since we examine each and every node
    // in the list
    for (Node n : allNodes) {

        Node parent = n.getParent();
        if (parent != null) {

            List<Node> children = map.get(parent);
            if (children == null) {
                // instantiate list
                children = new ArrayList<Node>();
                map.put(parent, children);
            }
            children.add(n);
        }
    }


    // now, create a collection of thisNode's children (of all levels)
    Set<Node> allChildren = new HashSet<Node>();

    // keep a "queue" of nodes to look at
    List<Node> nodesToExamine = new ArrayList<Node>();
    nodesToExamine.add(thisNode);

    while (nodesToExamine.isEmpty() == false) {
        // pop a node off the queue
        Node node = nodesToExamine.remove(0);

        List<Node> children = map.get(node);
        if (children != null) {
            for (Node c : children) {
                allChildren.add(c);
                nodesToExamine.add(c);
            }
        }
    }

    return allChildren;
}

The expected execution time is something between O(n) and O(2n), if I remember how to calculate that right. You're guaranteed to look at every node in the list, plus a few more operations to find all of the descendants of your node - in the worst case (if you run the algorithm on the root node) you are looking at every node in the list twice.

软糯酥胸 2024-07-15 11:24:21

数据库的工作方式相同,所以做数据库的事情。 建立一个从父级映射到子级列表的哈希表。 这需要 O(n)。 然后使用该哈希表将使查找和查询可能更加高效。

Databases work the same way, so do what databases do. Build up a hashtable which maps from parent to list-of-children. That takes O(n). Then using that hashtable would make lookups and queries potentially be a lot more efficient.

伏妖词 2024-07-15 11:24:21

您的问题有点抽象,但是 嵌套集 (向下滚动,可能有点太特定于 mysql)可能是您的一个选择。 尽管任何修改都非常复杂(并且平均必须修改一半的树),但读取操作的速度非常快。

但这需要能够修改数据结构。 我想如果您可以修改结构,您也可以添加对子对象的引用。 如果你不能修改结构,我怀疑还有什么比你的想法更快的了。

Your question is a little abstract, but nested sets (scroll down, might be a little too mysql-specific) might be an option for you. It's extremely fast for read operations, though any modifications are quite complex (and have to modify half the tree on average).

That requires the ability to modify your data structure, though. And I guess if you can modify the structure, you could just as well add references to child objects. If you can't modify the structure, I doubt there's anything faster than your ideas.

等风也等你 2024-07-15 11:24:21

构建一棵树,其中的对象指向其直接子对象可能是最好的方法,特别是如果您需要进行未来的查找。 建造树很大程度上取决于原始树的高度。 最多需要 O(n^2)。

在构建树时,构建一个哈希表。 哈希表将使未来搜索特定对象的速度更快(O(1) 与 O(n))。

Building a tree where the objects point to their immediate children would probably be the best approach, especially if you need to do future look-ups. Building the tree largely depends on the height of the original tree. At maximum, it would take O(n^2).

While you're building the tree, build a hashtable. The hashtable will make future searches for a particular object faster (O(1) vs. O(n)).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文