Question Details

No question body available.

Tags

java data-structures tree hashmap

Answers (1)

May 26, 2026 Score: 3 Rep: 26,390 Quality: Medium Completeness: 80%

Setup

The first step would be to populate your children field properly based on your parentIds. That way you can also move through your tree forwards instead of only backwards.

Since you identify your nodes based on (unique) IDs, you should also have a way to obtain a node by its ID, so do that as the very first thing.

I am going to assume you have a way to iterate all nodes you created so far, so lets go:

Map idToNode = new HashMap();
for (Node node : nodes) {
  idToNode.put(node.getId(), node);
}

// or

Map idToNode = nodes.stream().collect(Collectors.toMap( Node::getId, Function.identity() ));

Next we populate the children field based on the parentIds:

Node root = null;
for (Node node : nodes) {
  Long parentId = node.getParentId();
  if (parentId == null) {
    root = node;
    continue;
  }

Node parent = idToNode.get(parerntId); // Caution: This contains check is expensive. Use Set instead of List for large tree structures if (!parent.children.contains(node)) { parent.children.add(node); } }

Now children is properly set up and we know root. You can now start traversing the tree forward.

Forward iteration

The last part is the printing. For that, we need a normal DFS traversal. See this pic from the first page of google results:

BFS vs DFS

The general construct for this (recursive) would be:

public void printTree(Node root) {
  printTree(root, 0);
}

private void printTree(Node current, int level) { // TODO Do something with the node...

// Relax children for (Node child : current.getChildren()) { printTree(child, level + 1); } }

Printing

Lets now deal with the actual printing of the structure. The current level will be the source for the indentation, lets use two spaces per level:

private void printTree(Node current, int level) {
  String indent = " ".repeat(level  2);
  IO.println(indent + "├─");

// Relax children for (Node child : current.getChildren()) { printTree(child, level + 1); } }

This already gets us very close:

├─Assets
  ├─Current Assets
    ├─Cash
    ├─Foo
  ├─Bar
  ├─Baz

Some small tweaking to take care of now.

Root no ├─

Special handling for the root, no leading ├─ :

private void printTree(Node current, int level) {
  if (level != 0) {
    String indent = " ".repeat(level  2);
    IO.println(indent + "├─");
  }

// Relax children for (Node child : current.getChildren()) { printTree(child, level + 1); } }

End symbol └─

And the last part is the extra symbol for the last entry, so it is └─ instead of always ├─. For that you need to know when the iteration for // Relax children is on the last element. With an ArrayList as backing structure for children that is easy as we can use an index-based loop instead. Otherwise you need to get a bit more creative.

public void printTree(Node root) {
  printTree(root, 0, false);
}

private void printTree(Node current, int level, boolean isLast) { if (level != 0) { String indent = " ".repeat(level 2); String symbol = isLast ? "└─" : "├─"; IO.println(indent + symbol); }

// Relax all children but last List children = current.getChildren(); for (int i = 0; i < children.size() - 1; i++) { Node child = children.get(i); printTree(child, level + 1, false); }

// And now the last child Node lastChild = children.get(children.size() - 1); printTree(lastChild, level + 1, true); }

There we go:

Assets
  |─Current Assets
    ├─Cash
    └─Foo
  ├─Bar
  └─Baz

Connecting without interruption

If you also want to continue the line between for example Current Assets and Bar you have to modify the ident part to print a | on every indent-level:

private void printTree(Node current, int level, boolean isLast) {
  if (level != 0) {
    for (int i = 0; i < level - 1; i++) {
      String lead = "  │";
      IO.print(lead);
    }
    String symbol = isLast ? "└─" : "├─";
    IO.println("  " + symbol);
  }

// Relax all children but last List children = current.getChildren(); for (int i = 0; i < children.size() - 1; i++) { Node child = children.get(i); printTree(child, level + 1, false); }

// And now the last child Node lastChild = children.get(children.size() - 1); printTree(lastChild, level + 1, true); }

Final result:

Assets
  ├─Current Assets
  │ ├─Cash
  │ └─Foo
  ├─Bar
  └─Baz

Remarks

Iterative DFS

Worth mentioning that this is currently a recursive solution. So it will have trouble with large trees. If you need to support that consider switching to an iterative variant. The base setup for this would be:

Queue nodesToProcess = Collections.asLifoQueue(new ArrayDeque());
nodesToProcess.add(rootNode); // add all starting nodes

Set visitedNodes = new HashSet(); while (!nodesToProcess.isEmpty()) { // Settle node Node currentNode = nodesToProcess.poll(); if (!visitedNodes.add(currentNode)) { continue; // Already visited before }

// Do something with the node System.out.println(currentNode); // Replace by whatever you need

// Relax all outgoing edges for (Node neighbor : currentNode.getNeighbors()) { nodesToProcess.add(neighbor); } }

But you need to modify it a bit so it maintains the indentation level.

Node#equals

Be careful should you decide to add equals/hashCode to your Node class. Make it based on the unique id and not based on all properties. Otherwise, with that List children the calls would be very expensive.