从Java中的数组构建树结构(用于目录)

时间:2014-05-31 03:54:33

标签: java algorithm recursion

我有一个来自html标签的字符串数组....

String[] Headers = {"H1", "H1", "H2", "H3", "H3", "H2", "H2", "H3", "H4", "H2", "H2", "H2", "H1", "H2", "H2", "H3", "H4", "H4", "H2" };

我需要变成一个树形结构。哪个Hn是最近的Hn-1的孩子

ROOT
    H1
    H1
    ...H2
    ......H3
    ......H3
    ...H2
    ...H2
    ......H3
    .........H4
    ...H2
    ...H2
    ...H2
    H1
    ...H2
    ...H2
    ......H3
    .........H4
    .........H4
    ...H2

这感觉就像应该通过递归完成的事情,当我看到一个解决方案时,我会因为没有尽快考虑它而踢自己。有人为我找到了解决方案吗?

更新

所以我尝试了几种递归方式,绝对没有运气。事实证明,我让这个问题变得比以前更难。

由于出现了测试用例,

String [] Headers = {“H1”,“H1”,“H3”,“H3”,“H5”,“H4”,“H4”,“H4”};

我对bcorso的答案做了一个非常轻微的调整,这是我最终的结果:

private void addChildren(TocItem root, Elements headers) {
    if(headers == null || headers.size() == 0) return;

    Map<Integer, TocItem> mostRecent = new HashMap<Integer, TocItem>(headers.size());

    int startLevel = getTagLevel(headers.get(0)) - 1;
    mostRecent.put(startLevel, root);

    for(int i = 0; i < headers.size(); i++) {
        Element htag = headers.get(i);
        int level = getTagLevel(htag);
        TocItem next = new TocItem(htag, level);

        int offset = 1;
        TocItem parent =  mostRecent.get(level - offset);
        while(parent == null && offset < level) {
            offset++;
            parent = mostRecent.get(level - offset);
        }
        if(parent != null) {
            parent.addChild(next);
        }
        mostRecent.put(level, next);
    } 
}

2 个答案:

答案 0 :(得分:4)

这里你去:

class Example
{
    static class Node
    {
        final String name;
        final int indent;
        Collection<Node> children = new LinkedList<> ();

        Node (final String name)
        {
            this.name = name;
            this.indent = Integer.valueOf (name.substring (1));
        }
        Collection<Node> getChildren ()
        {
            return Collections.unmodifiableCollection (this.children);
        }
        void addChild (final Node child)
        {
            this.children.add (child);
        }
        @Override
        public String toString ()
        {
            final StringBuilder sb = new StringBuilder ();
            for (int i = 0; i < this.indent; i++)
                sb.append ("   ");
            sb.append (this.name).append ('\n');
            for (final Node node : this.children)
                sb.append (node.toString ());
            return sb.toString ();
        }
    }

    List<Node> contents = new LinkedList<> ();
    ArrayList<Node> stack = new ArrayList<> ();

    public void add (final String[] headers)
    {
        for (final String h : headers)
        {
            final int n = Integer.valueOf (h.substring (1));
            final Node node = new Node (h);

            while (this.stack.size () > n - 1)
                this.stack.remove (this.stack.size () - 1);

            if (n == 1)
            {
                this.contents.add (node);
                this.stack.add (node);
            }
            else
            {
                this.stack.get (n - 2).addChild (node);

                if (this.stack.size () < n)
                {
                    assert (this.stack.size () == n - 1);
                    this.stack.add (node);
                }
            }
        }
        this.stack.clear ();
    }

    @Override
    public String toString ()
    {
        final StringBuilder sb = new StringBuilder ();
        for (final Node node : this.contents)
            sb.append (node.toString ());
        return sb.toString ();
    }
}

使用:

    final Example ex = new Example ();
    ex.add (new String[] {"H1", "H1", "H2", "H3", "H3", "H2", "H2", "H3", "H4", "H2", "H2",
            "H2", "H1", "H2", "H2", "H3", "H4", "H4", "H2"});
    System.out.println (ex);

答案 1 :(得分:4)

Here is a working example on Ideone。代码如下:

public static class Node{
    int level;
    List<Node> children = new ArrayList<Node>();
    Node(int level){ this.level = level;}
}

public static void main (String[] args) throws java.lang.Exception{
    String[] h = {"H1", "H1", "H2", "H3", "H3", "H5", "H2", "H2", "H3", "H4",
                  "H2", "H2", "H2", "H1", "H2", "H2", "H3","H4", "H4", "H2"};

    Node[] mostRecent = new Node[6];                      // 5 headers + 1 root tag.
    mostRecent[0] = new Node(0);                          // root tag (level = 0)

    for(int i = 0; i < h.length; i++){
        int level = Integer.parseInt(""+h[i].charAt(1));  // get tag's "level"
        Node n = new Node(level);                         // create Node for tag
        mostRecent[level] = n;                            // update most recent tag

        int pLevel = level - 1;                          
        while(mostRecent[pLevel] == null) --pLevel;       // find nearest parent
        mostRecent[pLevel].children.add(n);               // append tag Node to parent

        for(int j = 1; j < level; j++)                    // print tag with indention
            System.out.print("\t");
        System.out.println(h[i]);
    } 
}

代码说明:

只需在for循环中遍历标题O(n)列表,并跟踪最新的hH1,即可在H2时间内运行,数组H3中的H4Node[]

该数组用于通过使用相应的整数引用它的级别来检索标记Hi的最新节点。例如,使用mostRecent[1]检索具有最新“H1”标记的节点(注意,元素0用作整个文档的根目录。)

注意:如果您需要专用功能来打印树see this Ideone