You are given a set of links, e.g.
a ---> b
b ---> c
b ---> d
a ---> e
Print the tree that would form when each pair of these links that has the same character as start and end point is joined together. You have to maintain fidelity w.r.t. the height of nodes, i.e. nodes at height n from root should be printed at same row or column. For set of links given above, tree printed should be –
-->a
|-->b
| |-->c
| |-->d
|-->e
Note that these links need not form a single tree; they could form, ahem, a forest. Consider the following links
a ---> b
a ---> g
b ---> c
c ---> d
d ---> e
c ---> f
z ---> y
y ---> x
x ---> w
The output would be following forest.
-->a
|-->b
| |-->c
| | |-->d
| | | |-->e
| | |-->f
|-->g
-->z
|-->y
| |-->x
| | |-->w
You can assume that given links can form a tree or forest of trees only, and there are no duplicates among links.
Solution: The idea is to maintain two arrays, one array for tree nodes and other for trees themselves (we call this array forest). An element of the node array contains the TreeNode object that corresponds to respective character. An element of the forest array contains Tree object that corresponds to respective root of tree. It should be obvious that the crucial part is creating the forest here, once it is created, printing it out in required format is straightforward. To create the forest, following procedure is used –
Do following for each input link,
1. If start of link is not present in node array
Create TreeNode objects for start character
Add entries of start in both arrays.
2. If end of link is not present in node array
Create TreeNode objects for start character
Add entry of end in node array.
3. If end of link is present in node array.
If end of link is present in forest array, then remove it
from there.
4. Add an edge (in tree) between start and end nodes of link.
It should be clear that this procedure runs in linear time in number of nodes as well as of links – it makes only one pass over the links. It also requires linear space in terms of alphabet size. Following is Java implementation of above algorithm. In the following implementation characters are assumed to be only lower case characters from ‘a’ to ‘z’.
Implementation:
Java
public class Tree {
private TreeNode root;
public Tree[] buildFromLinks(String [] links) {
TreeNode[] nodes = new TreeNode[ 26 ];
Tree[] forest = new Tree[ 26 ];
for (String link : links) {
String[] ends = link.split( " " );
int start = ( int ) (ends[ 0 ].charAt( 0 ) - 'a' );
int end = ( int ) (ends[ 1 ].charAt( 0 ) - 'a' );
if (nodes[start] == null )
{
nodes[start] = new TreeNode(( char ) (start + 'a' ));
forest[start] = new Tree(nodes[start]);
}
if (nodes[end] == null )
nodes[end] = new TreeNode(( char ) (end + 'a' ));
else forest[end] = null ;
nodes[start].addChild(nodes[end], end);
}
return forest;
}
public Tree(TreeNode root) { this .root = root; }
public static void printForest(String[] links)
{
Tree t = new Tree( new TreeNode( '\0' ));
for (Tree t1 : t.buildFromLinks(links)) {
if (t1 != null )
{
t1.root.printTreeIdented( "" );
System.out.println( "" );
}
}
}
public static void main(String[] args) {
String [] links1 = { "a b" , "b c" , "b d" , "a e" };
System.out.println( "------------ Forest 1 ----------------" );
printForest(links1);
String [] links2 = { "a b" , "a g" , "b c" , "c d" , "d e" , "c f" ,
"z y" , "y x" , "x w" };
System.out.println( "------------ Forest 2 ----------------" );
printForest(links2);
}
}
class TreeNode {
TreeNode []children;
char c;
public void addChild(TreeNode n, int index) { this .children[index] = n;}
public TreeNode( char c) { this .c = c; this .children = new TreeNode[ 26 ];}
public void printTreeIdented(String indent) {
System.out.println(indent + "-->" + c);
for (TreeNode child : children) {
if (child != null )
child.printTreeIdented(indent + " |" );
}
}
}
|
C#
using System;
class Tree
{
public TreeNode root;
public Tree[] buildFromLinks(String [] links)
{
TreeNode[] nodes = new TreeNode[26];
Tree[] forest = new Tree[26];
foreach (String link in links)
{
char []sep = { ' ' , ' ' };
String[] ends = link.Split(sep);
int start = ( int ) (ends[0][0] - 'a' );
int end = ( int ) (ends[1][0] - 'a' );
if (nodes[start] == null )
{
nodes[start] = new TreeNode(( char ) (start + 'a' ));
forest[start] = new Tree(nodes[start]);
}
if (nodes[end] == null )
nodes[end] = new TreeNode(( char ) (end + 'a' ));
else forest[end] = null ;
nodes[start].addChild(nodes[end], end);
}
return forest;
}
public Tree(TreeNode root) { this .root = root; }
public static void printForest(String[] links)
{
Tree t = new Tree( new TreeNode( '\0' ));
foreach (Tree t1 in t.buildFromLinks(links))
{
if (t1 != null )
{
t1.root.printTreeIdented( "" );
Console.WriteLine( "" );
}
}
}
public static void Main(String[] args) {
String [] links1 = { "a b" , "b c" , "b d" , "a e" };
Console.WriteLine( "------------ Forest 1 ----------------" );
printForest(links1);
String [] links2 = { "a b" , "a g" , "b c" , "c d" , "d e" ,
"c f" , "z y" , "y x" , "x w" };
Console.WriteLine( "------------ Forest 2 ----------------" );
printForest(links2);
}
}
public class TreeNode
{
TreeNode []children;
char c;
public void addChild(TreeNode n, int index)
{
this .children[index] = n;
}
public TreeNode( char c)
{
this .c = c; this .children = new TreeNode[26];
}
public void printTreeIdented(String indent)
{
Console.WriteLine(indent + "-->" + c);
foreach (TreeNode child in children)
{
if (child != null )
child.printTreeIdented(indent + " |" );
}
}
}
|
Python3
class TreeNode:
def __init__( self , c):
self .c = c
self .children = [ None ] * 26
def addChild( self , n, index):
self .children[index] = n
def printTreeIdented( self , indent):
print (indent + "-->" + self .c)
for child in self .children:
if child:
child.printTreeIdented(indent + " |" )
class Tree:
def __init__( self , root):
self .root = root
def buildFromLinks( self , links):
nodes = [ None ] * 26
forest = [ None ] * 26
for link in links:
start = ord (link[ 0 ]) - ord ( 'a' )
end = ord (link[ 2 ]) - ord ( 'a' )
if not nodes[start]:
nodes[start] = TreeNode( chr (start + ord ( 'a' )))
forest[start] = Tree(nodes[start])
if not nodes[end]:
nodes[end] = TreeNode( chr (end + ord ( 'a' )))
else :
forest[end] = None
nodes[start].addChild(nodes[end], end)
return forest
@staticmethod
def printForest(links):
t = Tree(TreeNode( '\0' ))
for t1 in t.buildFromLinks(links):
if t1:
t1.root.printTreeIdented("")
print ()
if __name__ = = "__main__" :
links1 = [ "a b" , "b c" , "b d" , "a e" ]
print ( "------------ Forest 1 ----------------" )
Tree.printForest(links1)
links2 = [ "a b" , "a g" , "b c" , "c d" , "d e" , "c f" , "z y" , "y x" , "x w" ]
print ( "------------ Forest 2 ----------------" )
Tree.printForest(links2)
|
Javascript
class TreeNode {
constructor(c) {
this .c = c;
this .children = new Array(26).fill( null );
}
addChild(n, index) {
this .children[index] = n;
}
printTreeIdented(indent) {
document.write(indent + "-->" + this .c);
for (const child of this .children) {
if (child) {
child.printTreeIdented(indent + " |" );
}
}
}
}
class Tree {
constructor(root) {
this .root = root;
}
buildFromLinks(links) {
let nodes = new Array(26).fill( null );
let forest = new Array(26).fill( null );
for (const link of links) {
let start = link.charCodeAt(0) - 'a' .charCodeAt(0);
let end = link.charCodeAt(2) - 'a' .charCodeAt(0);
if (!nodes[start]) {
nodes[start] = new TreeNode(String.fromCharCode(start + 'a' .charCodeAt(0)));
forest[start] = new Tree(nodes[start]);
}
if (!nodes[end]) {
nodes[end] = new TreeNode(String.fromCharCode(end + 'a' .charCodeAt(0)));
}
else {
forest[end] = null ;
}
nodes[start].addChild(nodes[end], end);
}
return forest;
}
static printForest(links) {
let t = new Tree( new TreeNode( '\0' ));
let forest = t.buildFromLinks(links);
for (const t1 of forest) {
if (t1) {
t1.root.printTreeIdented( "" );
document.write( "<br>" );
}
}
}
}
let links1 = [ "a b" , "b c" , "b d" , "a e" ];
document.write( "------------ Forest 1 ----------------" + "<br>" );
Tree.printForest(links1);
let links2 = [ "a b" , "a g" , "b c" , "c d" , "d e" , "c f" , "z y" , "y x" , "x w" ];
document.write( "------------ Forest 2 ----------------" + "<br>" );
Tree.printForest(links2);
|
C++
#include <iostream>
#include <vector>
using namespace std;
class TreeNode {
public :
vector<TreeNode*> children;
char c;
TreeNode( char c) { this ->c = c; }
void addChild(TreeNode* n)
{
this ->children.push_back(n);
}
void printTreeIndented(string indent)
{
cout << indent << "-->" << c << endl;
for ( auto child : children) {
if (child != nullptr) {
child->printTreeIndented(indent + " |" );
}
}
}
};
class Tree {
private :
TreeNode* root;
public :
Tree(TreeNode* root) { this ->root = root; }
TreeNode* getRoot() { return root; }
vector<Tree*> buildFromLinks(vector<string> links)
{
TreeNode* nodes[26]
= { nullptr };
vector<Tree*> forest(
26, nullptr);
for ( auto link : links) {
char start = link[0];
char end = link[2];
if (nodes[start - 'a' ] == nullptr) {
nodes[start - 'a' ] = new TreeNode(start);
forest[start - 'a' ]
= new Tree(nodes[start - 'a' ]);
}
if (nodes[end - 'a' ] == nullptr) {
nodes[end - 'a' ] = new TreeNode(end);
}
else {
forest[end - 'a' ] = nullptr;
}
nodes[start - 'a' ]->addChild(nodes[end - 'a' ]);
}
return forest;
}
};
void printForest(std::vector<std::string> links)
{
Tree t( new TreeNode( '\0' ));
for (Tree* t1 : t.buildFromLinks(links)) {
if (t1 != nullptr) {
t1->getRoot()->printTreeIndented( "" );
std::cout << std::endl;
}
}
}
int main()
{
vector<string> links1 = { "a b" , "b c" , "b d" , "a e" };
cout << "------------ Forest 1 ----------------"
<< endl;
printForest(links1);
vector<string> links2
= { "a b" , "a g" , "b c" , "c d" , "d e" ,
"c f" , "z y" , "y x" , "x w" };
cout << "------------ Forest 2 ----------------"
<< endl;
printForest(links2);
return 0;
}
|
Output
------------ Forest 1 ----------------
-->a
|-->b
| |-->c
| |-->d
|-->e
------------ Forest 2 ----------------
-->a
|-->b
| |-->c
| | |-->d
| | | |-->e
| | |-->f
|-->g
-->z
|-->y
| |-->x
| | |-->w
Time Complexity: O(n) where n is the number of links in the input array.
Auxiliary Space: O(n)
Exercise: In the above implementation, endpoints of input links are assumed to be from set of only 26 characters. Extend the implementation where endpoints are strings of any length.
Last Updated :
08 Mar, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...