繁体   English   中英

从展平DFS结构创建递归结构

[英]Create recursive structure from flatten DFS structure

问题

我有以下树:

      2
     / \
    3   5
   /   / \ 
  6   4   1

以下列方式和顺序表示

id    parent
------------
2     null
3     2
6     3
5     2
4     5
1     5

目的:

将这个扁平树存储在O(n)的递归结构中(O(n * log(n))是可以接受的,但不是很好)(我知道如何在O(n ^ 2)中解决它,但我存储了数据在该DFS命令中能够以更有效的方式“解析”它。 例如:

class R {
    int id;
    List<R> children;
}

看起来像这样的JSON形式:

{
    id: 2,
    children: [
            {
                id: 3,
                children: { ... }             
            },
            {
                id: 5,
                children: { ... }
            }
    ]
}

我怎么能这样做? 编程语言并不重要,因为我可以用Java翻译它。


Java代码:

R r = new R();
Map<Long, Line> map = createMap2();
List<Line> vals = new ArrayList<Line>(map.values());
r.id = vals.get(0).id;
vals.remove(0);
r.children = createResource(vals, r.id);
...
private static List<R> createResource(List<Line> l, Long pid) {
    List<R> lr = new ArrayList<R>();
    if ( l.size() > 0 ) {           
        Long id = l.get(0).id;
        Long p = l.get(0).pid;
        l.remove(0);
        if ( pid.equals(p) ) {
            R r = new R();
            r.id = id;
            r.children = createResource(l, id);
            lr.add(r);
        }
        else {
            return createResource(l, pid);   // of course, this is not ok
        }
    }
    return lr;
}

在上面的代码中的问题是,只有236存储在递归结构(类R)。 我想在整个 递归结构 (R对象)中存储整个展平树结构 (许多Line对象),而不仅仅是一些节点。

PS:问题被简化了。 我对特定解决方案不感兴趣,因为涉及许多领域和数千个条目。 我也对能够在最坏情况下(不同种类的树)工作正常的解决方案感兴趣,因为这是用户的保证。

这样的事情怎么样? 在第一遍中,将父项哈希为子项的数组并标识根; 在第二个中,从根开始,对于每个子节点,插入一个具有自己子节点的新对象,依此类推:

举个例子,第一遍就会产生

parent_hash = {2:[3,5], 3:[6], 5:[4,1]}
root = 2

第二遍将是这样的:

object 2 -> object 3 -> object 6
         -> object 5 -> object 4
                     -> object 1
done

您的代码的问题是,一旦条目不满足p == pid条件,它将永远丢失。 您应该打破循环并立即返回,而不是丢失条目。 违规入口也应由R上游的适当实例返回和处理。

您可以轻松地在数组中表示整个树,因为树的每个节点都可以由数组中的索引表示。 对于二叉树,索引i的子节点将在索引2 * i + 1和索引2 * i + 2处。 然后将数组转换为任何其他表示将很简单。 阵列本身对于平衡树来说是一个节省空间的表示,但是会为非常不平衡的树浪费大量空间。 (除非您处理大量数据,否则这无关紧要。)

如果对于大型不平衡树需要一种节省内存的方法,那么使用树的标准节点表示是有意义的。 要从列表转换,您可以使用HashMap作为建议的גלעדברקן。 但是,如果节点的id大部分是连续的(例如它们从1到6的示例),你也可以使用一个数组,其中数组i的每个索引用于存储id为i的Node。 。 这将使您可以轻松找到父节点,并在创建子节点时为其分配节点。

(参见我的Trees教程 ,将树存储为数组。)

我找到了一个基于“DFS”顺序的简单解决方案。

即使我使用“线”对象列表或地图,此方法也可以使用。

private static List<R> createResource(List<Line> l, Long pid) {
    List<R> lr = new ArrayList<R>();
    for ( Line line : l ) { 
        if ( line is a children ) {
            R r = new R();
            r.id = id;
            l.remove(0);
            r.children = createResource(l, line.id);                
            lr.add(r);
        }
    }
    return lr;
}

它似乎在O(n ^ 2)中,因为所有元素都有一个for循环+递归,但它在O(n)中 由于DFS顺序, createResource的下一个元素位于第一个位置(0 - > O(1) )。 因为递归占用每个元素=>复杂度是O(n)

但是如果订单不是DFS订单(可能涉及不是LinkedHashMapMap ),我推荐包含父类数组的解决方案。 (根据גלעדברקן)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM