11/**
2- * Often when working with trees we are given them as a graph with undirected edges, however
3- * sometimes a better representation is a rooted tree.
2+ * Rooting an Undirected Tree
43 *
5- * <p>Time Complexity: O(V+E)
4+ * Given an undirected tree as an adjacency list, this algorithm converts it
5+ * into a rooted tree by performing a DFS from a chosen root node. Each node
6+ * in the resulting tree stores its parent and children.
7+ *
8+ * Time: O(V + E)
9+ * Space: O(V)
610 *
711 * @author William Fiset, william.alexandre.fiset@gmail.com
812 */
913package com .williamfiset .algorithms .graphtheory .treealgorithms ;
1014
11- import java .util .*;
15+ import java .util .ArrayList ;
16+ import java .util .List ;
1217
1318public class RootingTree {
1419
1520 public static class TreeNode {
16- private int id ;
17- private TreeNode parent ;
18- private List <TreeNode > children ;
21+ private final int id ;
22+ private final TreeNode parent ;
23+ private final List <TreeNode > children ;
1924
2025 // Useful constructor for root node.
2126 public TreeNode (int id ) {
@@ -25,7 +30,7 @@ public TreeNode(int id) {
2530 public TreeNode (int id , TreeNode parent ) {
2631 this .id = id ;
2732 this .parent = parent ;
28- children = new LinkedList <>();
33+ this . children = new ArrayList <>();
2934 }
3035
3136 public void addChildren (TreeNode ... nodes ) {
@@ -66,43 +71,63 @@ public int hashCode() {
6671 }
6772 }
6873
74+ /**
75+ * Roots the undirected tree at the given node and returns the root TreeNode.
76+ */
6977 public static TreeNode rootTree (List <List <Integer >> graph , int rootId ) {
7078 TreeNode root = new TreeNode (rootId );
7179 return buildTree (graph , root );
7280 }
7381
74- // Do dfs to construct rooted tree.
82+ /**
83+ * Recursively builds the rooted tree via DFS. Skips the edge back to the
84+ * parent to avoid cycles.
85+ */
7586 private static TreeNode buildTree (List <List <Integer >> graph , TreeNode node ) {
7687 for (int childId : graph .get (node .id ())) {
77- // Ignore adding an edge pointing back to parent.
88+ // Ignore the edge pointing back to parent.
7889 if (node .parent () != null && childId == node .parent ().id ()) {
7990 continue ;
8091 }
81-
8292 TreeNode child = new TreeNode (childId , node );
8393 node .addChildren (child );
84-
8594 buildTree (graph , child );
8695 }
8796 return node ;
8897 }
8998
90- /** ********** TESTING ********* */
99+ /* Graph helpers */
91100
92- // Create a graph as a adjacency list
93- private static List <List <Integer >> createGraph (int n ) {
101+ public static List <List <Integer >> createGraph (int n ) {
94102 List <List <Integer >> graph = new ArrayList <>(n );
95- for (int i = 0 ; i < n ; i ++) graph .add (new LinkedList <>());
103+ for (int i = 0 ; i < n ; i ++) graph .add (new ArrayList <>());
96104 return graph ;
97105 }
98106
99- private static void addUndirectedEdge (List <List <Integer >> graph , int from , int to ) {
107+ public static void addUndirectedEdge (List <List <Integer >> graph , int from , int to ) {
100108 graph .get (from ).add (to );
101109 graph .get (to ).add (from );
102110 }
103111
112+ // ==================== Main ====================
113+
104114 public static void main (String [] args ) {
105115
116+ // Undirected tree:
117+ //
118+ // 0 - 1 - 2 - 3 - 4
119+ // | |
120+ // 6 5
121+ // / \
122+ // 7 8
123+ //
124+ // Rooted at 6:
125+ //
126+ // 6
127+ // 2 7 8
128+ // 1 3
129+ // 0 4 5
130+
106131 List <List <Integer >> graph = createGraph (9 );
107132 addUndirectedEdge (graph , 0 , 1 );
108133 addUndirectedEdge (graph , 2 , 1 );
@@ -113,12 +138,6 @@ public static void main(String[] args) {
113138 addUndirectedEdge (graph , 6 , 7 );
114139 addUndirectedEdge (graph , 6 , 8 );
115140
116- // Rooted at 6 the tree should look like:
117- // 6
118- // 2 7 8
119- // 1 3
120- // 0 4 5
121-
122141 TreeNode root = rootTree (graph , 6 );
123142
124143 // Layer 0: [6]
@@ -136,7 +155,8 @@ public static void main(String[] args) {
136155 + ", "
137156 + root .children .get (0 ).children .get (1 ).children );
138157
139- // Rooted at 3 the tree should look like:
158+ // Rooted at 3:
159+ //
140160 // 3
141161 // 2 4 5
142162 // 6 1
0 commit comments