11package com .ctci .treesandgraphs ;
22
3+ import java .util .ArrayList ;
4+ import java .util .HashMap ;
5+ import java .util .HashSet ;
6+ import java .util .LinkedHashMap ;
7+ import java .util .List ;
8+ import java .util .Map ;
9+ import java .util .Set ;
10+ import java .util .stream .Stream ;
11+
312/**
413 * @author rampatra
514 * @since 2019-02-21
615 */
716public class BuildOrder {
817
9- // todo
10-
18+ private class Project {
19+ String name ;
20+ Set <Project > dependencies = new HashSet <>();
21+
22+ Project (String name ) {
23+ this .name = name ;
24+ }
25+
26+ @ Override
27+ public String toString () {
28+ return name ;
29+ }
30+ }
31+
32+ private final Map <String , Project > projects = new HashMap <>();
33+
34+ private void addProjects (Stream <String > projectNames ) {
35+ projectNames .forEach (name -> projects .put (name , new Project (name )));
36+ }
37+
38+ /**
39+ * Adds a directed edge from {@code projectName2} to {@code ProjectName1}. This means {@code projectName2} is
40+ * dependent on {@code projectName1}, i.e, {@code projectName1} has to be built before {@code projectName2}.
41+ *
42+ * @param projectName1 name of project 1
43+ * @param projectName2 name of project 2
44+ */
45+ private void addDependency (String projectName1 , String projectName2 ) {
46+ Project p1 = projects .get (projectName1 );
47+ Project p2 = projects .get (projectName2 );
48+
49+ if (p1 == null ) {
50+ p1 = new Project (projectName1 );
51+ projects .put (projectName1 , p1 );
52+ }
53+ if (p2 == null ) {
54+ p2 = new Project (projectName2 );
55+ projects .put (projectName2 , p2 );
56+ }
57+
58+ p2 .dependencies .add (p1 );
59+ }
60+
61+ /**
62+ * Determines the order in which the projects need to be built.
63+ * Time complexity: TODO
64+ *
65+ * @return a list of projects in the order they should be built, the first project should be built first and so on.
66+ */
67+ private List <Project > getBuildOrder () {
68+ Map <String , Project > projectsBuilt = new LinkedHashMap <>(); // linked hashmap is needed to maintain the insertion order
69+
70+ while (projectsBuilt .size () != projects .size ()) {
71+ // find the projects which are not dependent on any project
72+ Set <Project > nextProjectsToBuild = getProjectsWithNoDependencies (projectsBuilt );
73+
74+ // if there are no further independent projects to build, then we can't proceed further
75+ if (nextProjectsToBuild .size () == 0 ) {
76+ throw new IllegalStateException ("Error: Projects can't be built." );
77+ }
78+ nextProjectsToBuild .forEach (p -> projectsBuilt .put (p .name , p ));
79+
80+ // once a project is built, remove the dependencies from all other projects dependent on this
81+ removeDependency (nextProjectsToBuild );
82+ }
83+
84+ return new ArrayList <>(projectsBuilt .values ());
85+ }
86+
87+ private Set <Project > getProjectsWithNoDependencies (Map <String , Project > alreadyBuildProjects ) {
88+ Set <Project > unBuiltProjectsWithZeroDependencies = new HashSet <>();
89+
90+ for (Map .Entry <String , Project > entry : projects .entrySet ()) {
91+ if (entry .getValue ().dependencies .size () == 0 && alreadyBuildProjects .get (entry .getKey ()) == null ) {
92+ unBuiltProjectsWithZeroDependencies .add (entry .getValue ());
93+ }
94+ }
95+
96+ return unBuiltProjectsWithZeroDependencies ;
97+ }
98+
99+ private void removeDependency (Set <Project > newlyBuiltProjects ) {
100+ projects .forEach ((n , p ) -> p .dependencies .removeAll (newlyBuiltProjects ));
101+ }
102+
103+
11104 public static void main (String [] args ) {
105+ /* test case 1
12106
107+ ––––––––––– b
108+ | ↑
109+ ↓ |
110+ f <–– a <–– d <–– c
111+
112+
113+ */
114+ BuildOrder buildOrder = new BuildOrder ();
115+ buildOrder .addProjects (Stream .of ("a" , "b" , "c" , "d" , "e" , "f" ));
116+ buildOrder .addDependency ("a" , "d" );
117+ buildOrder .addDependency ("f" , "b" );
118+ buildOrder .addDependency ("b" , "d" );
119+ buildOrder .addDependency ("f" , "a" );
120+ buildOrder .addDependency ("d" , "c" );
121+ System .out .println (buildOrder .getBuildOrder ());
122+
123+ // test case 2
124+ buildOrder = new BuildOrder ();
125+ buildOrder .addProjects (Stream .of ("a" , "b" , "c" , "d" , "e" , "f" , "g" ));
126+ buildOrder .addDependency ("d" , "g" );
127+ buildOrder .addDependency ("f" , "b" );
128+ buildOrder .addDependency ("f" , "c" );
129+ buildOrder .addDependency ("f" , "a" );
130+ buildOrder .addDependency ("c" , "a" );
131+ buildOrder .addDependency ("b" , "a" );
132+ buildOrder .addDependency ("b" , "e" );
133+ buildOrder .addDependency ("a" , "e" );
134+ System .out .println (buildOrder .getBuildOrder ());
13135 }
14- }
136+ }
0 commit comments