我有一个来自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);
}
}
答案 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)
列表,并跟踪最新的h
,H1
,即可在H2
时间内运行,数组H3
中的H4
和Node[]
。
该数组用于通过使用相应的整数引用它的级别来检索标记Hi
的最新节点。例如,使用mostRecent[1]
检索具有最新“H1”标记的节点(注意,元素0
用作整个文档的根目录。)
注意:如果您需要专用功能来打印树see this Ideone。