├── SortedList ├── .DS_Store ├── SortedListTest.java └── SortedList.java ├── README.md ├── SomeAlgorithmicProblems └── Problem1.java ├── DfsOnTrees └── DfsOnTrees.java └── MaximumFlow └── Dinics └── SimplifyDebts.java /SortedList/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithun-mohan/Algorithms-Java-Cookbook/HEAD/SortedList/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Library: Data Structure and Algorithm Implementations 2 | 3 | 1) Sorted List - An AVL Tree based implementation of Balanced Binary Search Tree(BST). 4 | 2) Dfs on Trees - Shows how to generate Adjacency List, given edges in a Tree and perform DFS on Trees. 5 | 3) Simplifying Debts using Dinic's Maxflow Algorithm. 6 | -------------------------------------------------------------------------------- /SortedList/SortedListTest.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.lang.*; 3 | import java.io.*; 4 | import java.math.*; 5 | 6 | class SortedListNatural> extends SortedList { 7 | public SortedListNatural(){ 8 | super(new Comparator(){ 9 | public int compare(T one, T two){ 10 | return one.compareTo(two); 11 | } 12 | }); 13 | } 14 | } 15 | 16 | public class SortedListTest { 17 | public static void main(String[] args) { 18 | BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 19 | SortedListNatural list = new SortedListNatural(); 20 | 21 | // Add some elements 22 | list.add(9); 23 | list.add(5); 24 | list.add(1); 25 | list.add(7); 26 | list.add(3); 27 | 28 | // Find positions of elements if the elements were to placed in ascending order in some array 29 | System.out.println("Position of 1 is :" + list.findInOrderPosition(1)); // Prints 0 30 | System.out.println("Position of 3 is :" + list.findInOrderPosition(3)); // Prints 1 31 | System.out.println("Position of 5 is :" + list.findInOrderPosition(5)); // Prints 2 32 | System.out.println("Position of 7 is :" + list.findInOrderPosition(7)); // Prints 3 33 | System.out.println("Position of 9 is :" + list.findInOrderPosition(9)); // Prints 4 34 | 35 | // Find largest element strictly less than each of these inserted elements 36 | System.out.println("Largest element strictly less than 1 is :" + list.lower(1)); // Throws NullPointerException as 1 itself is the minimum value 37 | System.out.println("Largest element strictly less than 3 is :" + list.lower(3)); // Prints 1 38 | System.out.println("Largest element strictly less than 5 is :" + list.lower(5)); // Prints 3 39 | System.out.println("Largest element strictly less than 7 is :" + list.lower(7)); // Prints 5 40 | System.out.println("Largest element strictly less than 9 is :" + list.lower(9)); // Prints 7 41 | 42 | } 43 | } -------------------------------------------------------------------------------- /SomeAlgorithmicProblems/Problem1.java: -------------------------------------------------------------------------------- 1 | /* 2 | Problem Statement: You are given a string of only binary characters(i.e. for example 1010) of length N. You have to perform following operations on the given string M times; 3 | i) Replace all 1's with 10, and 4 | ii) Replace all 0's with 01. 5 | 6 | Now you will be asked what is the character at any given position(say P) in the resultant string. 7 | 8 | Solution Complexity: max(log(P), M) where P = position to find and M = number or times to do the operation 9 | */ 10 | 11 | import java.util.*; 12 | import java.lang.*; 13 | import java.io.*; 14 | import java.math.*; 15 | 16 | import java.util.*; 17 | import java.lang.*; 18 | import java.io.*; 19 | 20 | @SuppressWarnings("unchecked") 21 | public class Problem1 implements Runnable { 22 | 23 | static BufferedReader in; 24 | static PrintWriter out; 25 | 26 | public static void main(String[] args) { 27 | new Thread(null, new Problem1(), "whatever", 1<<29).start(); 28 | } 29 | 30 | public void run() { 31 | in = new BufferedReader(new InputStreamReader(System.in)); 32 | out = new PrintWriter(System.out, false); 33 | 34 | try 35 | { 36 | // in = new BufferedReader(new FileReader("A-large (1).in")); 37 | // out = new PrintWriter("output.txt"); 38 | 39 | System.out.print("Enter a binary string : "); 40 | String text = in.readLine().trim(); 41 | int textLength = text.length(); 42 | 43 | System.out.print("Enter the number of times to do the operation(i.e. replace 1 with 10 and 0 with 01) : "); 44 | int times = Integer.parseInt(in.readLine().trim()); 45 | 46 | System.out.print("Enter the position in the resultant string you want to query : "); 47 | long positionInResultantString = Long.parseLong(in.readLine().trim()) - 1; 48 | 49 | List pathToResultantPosition = new ArrayList<>(); 50 | long curPosition = positionInResultantString; 51 | 52 | for(int i = 0; i <= times; i++) { 53 | pathToResultantPosition.add(curPosition); 54 | curPosition /= 2; 55 | } 56 | 57 | long position = pathToResultantPosition.get(pathToResultantPosition.size() - 1); 58 | int bit = text.charAt((int)position) - 48; 59 | for(int i = pathToResultantPosition.size() - 2; i >= 0; i--) { 60 | position = pathToResultantPosition.get(i); 61 | bit = (position%2 == 0L) ? bit : (1-bit); 62 | } 63 | 64 | System.out.println(String.format("Character at position %s in resultant string is : %s", positionInResultantString + 1, bit)); 65 | 66 | out.flush(); 67 | out.close(); 68 | } 69 | catch(Exception e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /DfsOnTrees/DfsOnTrees.java: -------------------------------------------------------------------------------- 1 | /* Kickstart Round C 2018 : Problem A. Planet Distance 2 | * @author : Mithun Mohan K 3 | * handle@codechef : umbreon 4 | */ 5 | 6 | import java.util.*; 7 | import java.lang.*; 8 | import java.io.*; 9 | import java.math.*; 10 | 11 | import java.util.*; 12 | import java.lang.*; 13 | import java.io.*; 14 | 15 | @SuppressWarnings("unchecked") 16 | public class DfsOnTrees implements Runnable { 17 | 18 | static int[] from, to; 19 | 20 | static int nodeInCycle, nodeInCycleParent, qSize; 21 | static int[] parent, depth, q; 22 | static boolean[] visited; 23 | static int[][] adj; 24 | 25 | public static int[][] generateAdjList(int n, int[] from, int[] to) 26 | { 27 | int[][] g = new int[n][]; 28 | int[] p = new int[n]; 29 | for (int f : from) 30 | p[f]++; 31 | for (int t : to) 32 | p[t]++; 33 | for (int i = 0; i < n; i++) 34 | g[i] = new int[p[i]]; 35 | for (int i = 0; i < from.length; i++) 36 | { 37 | g[from[i]][--p[from[i]]] = to[i]; 38 | g[to[i]][--p[to[i]]] = from[i]; 39 | } 40 | return g; 41 | } 42 | 43 | public static void dfs(int cur, int parentVal) 44 | { 45 | if(parent[cur] == -1) 46 | { 47 | parent[cur] = parentVal; 48 | } 49 | else 50 | { 51 | if(nodeInCycle == -1) 52 | { 53 | nodeInCycle = cur; 54 | nodeInCycleParent = parentVal; 55 | } 56 | return; 57 | } 58 | 59 | for (int next : adj[cur]) 60 | { 61 | if(parent[cur] != next) 62 | { 63 | dfs(next, cur); 64 | } 65 | } 66 | } 67 | 68 | public static void handleCycle(int n) 69 | { 70 | q = new int[n]; 71 | visited = new boolean[n]; 72 | int node = nodeInCycle; 73 | qSize = 0; 74 | while(parent[node] != nodeInCycle) 75 | { 76 | q[qSize++] = node; 77 | depth[node] = 0; 78 | visited[node] = true; 79 | node = parent[node]; 80 | } 81 | q[qSize++] = node; 82 | depth[node] = 0; 83 | visited[node] = true; 84 | } 85 | 86 | public static void computeDepths() 87 | { 88 | for (int p = 0; p < qSize; p++) { 89 | int cur = q[p]; 90 | for (int next : adj[cur]) { 91 | if (!visited[next]) 92 | { 93 | depth[next] = depth[cur] + 1; 94 | visited[next] = true; 95 | q[qSize++] = next; 96 | } 97 | } 98 | } 99 | } 100 | 101 | public static void printArr(int test, int[] arr, PrintWriter out) 102 | { 103 | int n = arr.length; 104 | 105 | out.print("Case #" + (test + 1) + ": "); 106 | 107 | out.print(arr[0]); 108 | for(int i = 1; i < n; i++) 109 | out.print(" " + arr[i]); 110 | out.println(); 111 | } 112 | 113 | public static void main(String[] args) { 114 | new Thread(null, new DfsOnTrees(), "whatever", 1<<26).start(); 115 | } 116 | 117 | public void run() { 118 | BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 119 | PrintWriter out = new PrintWriter(System.out); 120 | 121 | try 122 | { 123 | int t,x1,n,m,i,j,k,ans,best,cur,sum; 124 | String str; 125 | String[] token; 126 | 127 | t=Integer.parseInt(in.readLine().trim()); 128 | 129 | for(x1=0;x1Time Complexity: O(E²V²) 10 | * 11 | * @author Mithun Mohan K, mithunmk93@gmail.com 12 | */ 13 | public class SimplifyDebts { 14 | private static final long OFFSET = 1000000000L; 15 | private static Set visitedEdges; 16 | 17 | public static void main(String[] args) { 18 | createGraphForDebts(); 19 | } 20 | 21 | /** 22 | * This example graph is taken from my Medium blog post. 23 | * Here Alice, Bob, Charlie, David, Ema, Fred and Gabe are represented by vertices from 0 to 6 respectively. 24 | */ 25 | private static void createGraphForDebts() { 26 | // List of all people in the group 27 | String[] person = { "Alice", "Bob", "Charlie", "David", "Ema", "Fred", "Gabe"}; 28 | int n = person.length; 29 | // Creating a graph with n vertices 30 | Dinics solver = new Dinics(n, person); 31 | // Adding edges to the graph 32 | solver = addAllTransactions(solver); 33 | 34 | System.out.println(); 35 | System.out.println("Simplifying Debts..."); 36 | System.out.println("--------------------"); 37 | System.out.println(); 38 | 39 | // Map to keep track of visited edges 40 | visitedEdges = new HashSet<>(); 41 | Integer edgePos; 42 | 43 | while((edgePos = getNonVisitedEdge(solver.getEdges())) != null) { 44 | // Force recomputation of subsequent flows in the graph 45 | solver.recompute(); 46 | // Set source and sink in the flow graph 47 | Dinics.Edge firstEdge = solver.getEdges().get(edgePos); 48 | solver.setSource(firstEdge.from); 49 | solver.setSink(firstEdge.to); 50 | // Initialize the residual graph to be same as the given graph 51 | List[] residualGraph = solver.getGraph(); 52 | List newEdges = new ArrayList<>(); 53 | 54 | for(List allEdges : residualGraph) { 55 | for(Dinics.Edge edge : allEdges) { 56 | long remainingFlow = ((edge.flow < 0) ? edge.capacity : (edge.capacity - edge.flow)); 57 | // If there is capacity remaining in the graph, then add the remaining capacity as an edge 58 | // so that it can be used for optimizing other debts within the graph 59 | if(remainingFlow > 0) { 60 | newEdges.add(new Dinics.Edge(edge.from, edge.to, remainingFlow)); 61 | } 62 | } 63 | } 64 | 65 | // Get the maximum flow between the source and sink 66 | long maxFlow = solver.getMaxFlow(); 67 | // Mark the edge from source to sink as visited 68 | int source = solver.getSource(); 69 | int sink = solver.getSink(); 70 | visitedEdges.add(getHashKeyForEdge(source, sink)); 71 | // Create a new graph 72 | solver = new Dinics(n, person); 73 | // Add edges having remaining capacity 74 | solver.addEdges(newEdges); 75 | // Add an edge from source to sink in the new graph with obtained maximum flow as it's weight 76 | solver.addEdge(source, sink, maxFlow); 77 | } 78 | // Print the edges in the graph 79 | solver.printEdges(); 80 | System.out.println(); 81 | } 82 | 83 | private static Dinics addAllTransactions(Dinics solver) { 84 | // Transactions made by Bob 85 | solver.addEdge(1, 2, 40); 86 | // Transactions made by Charlie 87 | solver.addEdge(2, 3, 20); 88 | // Transactions made by David 89 | solver.addEdge(3, 4, 50); 90 | // Transactions made by Fred 91 | solver.addEdge(5, 1, 10); 92 | solver.addEdge(5, 2, 30); 93 | solver.addEdge(5, 3, 10); 94 | solver.addEdge(5, 4, 10); 95 | // Transactions made by Gabe 96 | solver.addEdge(6, 1, 30); 97 | solver.addEdge(6, 3, 10); 98 | return solver; 99 | } 100 | 101 | /** 102 | * Get any non visited edge in the graph 103 | * @param edges list of all edges in the graph 104 | * @return index of a non visited edge 105 | */ 106 | private static Integer getNonVisitedEdge(List edges) { 107 | Integer edgePos = null; 108 | int curEdge = 0; 109 | for(Dinics.Edge edge : edges) { 110 | if(!visitedEdges.contains(getHashKeyForEdge(edge.from, edge.to))) { 111 | edgePos = curEdge; 112 | } 113 | curEdge++; 114 | } 115 | return edgePos; 116 | } 117 | 118 | /** 119 | * Get a unique hash key for a given edge 120 | * @param u the starting vertex in the edge 121 | * @param v the ending vertex in the edge 122 | * @return a unique hash key 123 | */ 124 | private static Long getHashKeyForEdge(int u, int v) { 125 | return u * OFFSET + v; 126 | } 127 | } 128 | 129 | 130 | /** 131 | * Implementation of Dinic's network flow algorithm. The algorithm works by first constructing a 132 | * level graph using a BFS and then finding augmenting paths on the level graph using multiple DFSs. 133 | * 134 | *

Time Complexity: O(EV²) 135 | * 136 | * @link https://github.com/williamfiset/Algorithms 137 | */ 138 | class Dinics extends NetworkFlowSolverBase { 139 | 140 | private int[] level; 141 | 142 | /** 143 | * Creates an instance of a flow network solver. Use the {@link #addEdge} method to add edges to 144 | * the graph. 145 | * 146 | * @param n - The number of nodes in the graph including source and sink nodes. 147 | */ 148 | public Dinics(int n, String[] vertexLabels) { 149 | super(n, vertexLabels); 150 | level = new int[n]; 151 | } 152 | 153 | @Override 154 | public void solve() { 155 | // next[i] indicates the next unused edge index in the adjacency list for node i. This is part 156 | // of the Shimon Even and Alon Itai optimization of pruning deads ends as part of the DFS phase. 157 | int[] next = new int[n]; 158 | 159 | while (bfs()) { 160 | Arrays.fill(next, 0); 161 | // Find max flow by adding all augmenting path flows. 162 | for (long f = dfs(s, next, INF); f != 0; f = dfs(s, next, INF)) { 163 | maxFlow += f; 164 | } 165 | } 166 | 167 | for (int i = 0; i < n; i++) if (level[i] != -1) minCut[i] = true; 168 | } 169 | 170 | // Do a BFS from source to sink and compute the depth/level of each node 171 | // which is the minimum number of edges from that node to the source. 172 | private boolean bfs() { 173 | Arrays.fill(level, -1); 174 | level[s] = 0; 175 | Deque q = new ArrayDeque<>(n); 176 | q.offer(s); 177 | while (!q.isEmpty()) { 178 | int node = q.poll(); 179 | for (Edge edge : graph[node]) { 180 | long cap = edge.remainingCapacity(); 181 | if (cap > 0 && level[edge.to] == -1) { 182 | level[edge.to] = level[node] + 1; 183 | q.offer(edge.to); 184 | } 185 | } 186 | } 187 | return level[t] != -1; 188 | } 189 | 190 | private long dfs(int at, int[] next, long flow) { 191 | if (at == t) return flow; 192 | final int numEdges = graph[at].size(); 193 | 194 | for (; next[at] < numEdges; next[at]++) { 195 | Edge edge = graph[at].get(next[at]); 196 | long cap = edge.remainingCapacity(); 197 | if (cap > 0 && level[edge.to] == level[at] + 1) { 198 | 199 | long bottleNeck = dfs(edge.to, next, min(flow, cap)); 200 | if (bottleNeck > 0) { 201 | edge.augment(bottleNeck); 202 | return bottleNeck; 203 | } 204 | } 205 | } 206 | return 0; 207 | } 208 | } 209 | 210 | 211 | abstract class NetworkFlowSolverBase { 212 | 213 | // To avoid overflow, set infinity to a value less than Long.MAX_VALUE; 214 | protected static final long INF = Long.MAX_VALUE / 2; 215 | 216 | public static class Edge { 217 | public int from, to; 218 | public String fromLabel, toLabel; 219 | public Edge residual; 220 | public long flow, cost; 221 | public final long capacity, originalCost; 222 | 223 | public Edge(int from, int to, long capacity) { 224 | this(from, to, capacity, 0 /* unused */); 225 | } 226 | 227 | public Edge(int from, int to, long capacity, long cost) { 228 | this.from = from; 229 | this.to = to; 230 | this.capacity = capacity; 231 | this.originalCost = this.cost = cost; 232 | } 233 | 234 | public boolean isResidual() { 235 | return capacity == 0; 236 | } 237 | 238 | public long remainingCapacity() { 239 | return capacity - flow; 240 | } 241 | 242 | public void augment(long bottleNeck) { 243 | flow += bottleNeck; 244 | residual.flow -= bottleNeck; 245 | } 246 | 247 | public String toString(int s, int t) { 248 | String u = (from == s) ? "s" : ((from == t) ? "t" : String.valueOf(from)); 249 | String v = (to == s) ? "s" : ((to == t) ? "t" : String.valueOf(to)); 250 | return String.format( 251 | "Edge %s -> %s | flow = %d | capacity = %d | is residual: %s", 252 | u, v, flow, capacity, isResidual()); 253 | } 254 | } 255 | 256 | // Inputs: n = number of nodes, s = source, t = sink 257 | protected int n, s, t; 258 | 259 | protected long maxFlow; 260 | protected long minCost; 261 | 262 | protected boolean[] minCut; 263 | protected List[] graph; 264 | protected String[] vertexLabels; 265 | protected List edges; 266 | 267 | // 'visited' and 'visitedToken' are variables used for graph sub-routines to 268 | // track whether a node has been visited or not. In particular, node 'i' was 269 | // recently visited if visited[i] == visitedToken is true. This is handy 270 | // because to mark all nodes as unvisited simply increment the visitedToken. 271 | private int visitedToken = 1; 272 | private int[] visited; 273 | 274 | // Indicates whether the network flow algorithm has ran. We should not need to 275 | // run the solver multiple times, because it always yields the same result. 276 | protected boolean solved; 277 | 278 | /** 279 | * Creates an instance of a flow network solver. Use the {@link #addEdge} method to add edges to 280 | * the graph. 281 | * 282 | * @param n - The number of nodes in the graph including source and sink nodes. 283 | */ 284 | public NetworkFlowSolverBase(int n, String[] vertexLabels) { 285 | this.n = n; 286 | initializeGraph(); 287 | assignLabelsToVertices(vertexLabels); 288 | minCut = new boolean[n]; 289 | visited = new int[n]; 290 | edges = new ArrayList<>(); 291 | } 292 | 293 | // Construct an empty graph with n nodes including the source and sink nodes. 294 | private void initializeGraph() { 295 | graph = new List[n]; 296 | for (int i = 0; i < n; i++) graph[i] = new ArrayList(); 297 | } 298 | 299 | // Add labels to vertices in the graph. 300 | private void assignLabelsToVertices(String[] vertexLabels) { 301 | if(vertexLabels.length != n) 302 | throw new IllegalArgumentException(String.format("You must pass %s number of labels", n)); 303 | this.vertexLabels = vertexLabels; 304 | } 305 | 306 | /** 307 | * Adds a list of directed edges (and residual edges) to the flow graph. 308 | * 309 | * @param edges - A list of all edges to be added to the flow graph. 310 | */ 311 | public void addEdges(List edges) { 312 | if (edges == null) throw new IllegalArgumentException("Edges cannot be null"); 313 | for(Edge edge : edges) { 314 | addEdge(edge.from, edge.to, edge.capacity); 315 | } 316 | } 317 | 318 | /** 319 | * Adds a directed edge (and residual edge) to the flow graph. 320 | * 321 | * @param from - The index of the node the directed edge starts at. 322 | * @param to - The index of the node the directed edge ends at. 323 | * @param capacity - The capacity of the edge. 324 | */ 325 | public void addEdge(int from, int to, long capacity) { 326 | if (capacity < 0) throw new IllegalArgumentException("Capacity < 0"); 327 | Edge e1 = new Edge(from, to, capacity); 328 | Edge e2 = new Edge(to, from, 0); 329 | e1.residual = e2; 330 | e2.residual = e1; 331 | graph[from].add(e1); 332 | graph[to].add(e2); 333 | edges.add(e1); 334 | } 335 | 336 | /** Cost variant of {@link #addEdge(int, int, int)} for min-cost max-flow */ 337 | public void addEdge(int from, int to, long capacity, long cost) { 338 | Edge e1 = new Edge(from, to, capacity, cost); 339 | Edge e2 = new Edge(to, from, 0, -cost); 340 | e1.residual = e2; 341 | e2.residual = e1; 342 | graph[from].add(e1); 343 | graph[to].add(e2); 344 | edges.add(e1); 345 | } 346 | 347 | // Marks node 'i' as visited. 348 | public void visit(int i) { 349 | visited[i] = visitedToken; 350 | } 351 | 352 | // Returns whether or not node 'i' has been visited. 353 | public boolean visited(int i) { 354 | return visited[i] == visitedToken; 355 | } 356 | 357 | // Resets all nodes as unvisited. This is especially useful to do 358 | // between iterations of finding augmenting paths, O(1) 359 | public void markAllNodesAsUnvisited() { 360 | visitedToken++; 361 | } 362 | 363 | /** 364 | * Returns the graph after the solver has been executed. This allow you to inspect the {@link 365 | * Edge#flow} compared to the {@link Edge#capacity} in each edge. This is useful if you want to 366 | * figure out which edges were used during the max flow. 367 | */ 368 | public List[] getGraph() { 369 | execute(); 370 | return graph; 371 | } 372 | 373 | /** 374 | * Returns all edges in this flow network 375 | */ 376 | public List getEdges() { 377 | return edges; 378 | } 379 | 380 | // Returns the maximum flow from the source to the sink. 381 | public long getMaxFlow() { 382 | execute(); 383 | return maxFlow; 384 | } 385 | 386 | // Returns the min cost from the source to the sink. 387 | // NOTE: This method only applies to min-cost max-flow algorithms. 388 | public long getMinCost() { 389 | execute(); 390 | return minCost; 391 | } 392 | 393 | // Returns the min-cut of this flow network in which the nodes on the "left side" 394 | // of the cut with the source are marked as true and those on the "right side" 395 | // of the cut with the sink are marked as false. 396 | public boolean[] getMinCut() { 397 | execute(); 398 | return minCut; 399 | } 400 | 401 | /** 402 | * Used to set the source for this flow network 403 | */ 404 | public void setSource(int s) { 405 | this.s = s; 406 | } 407 | 408 | /** 409 | * Used to set the sink for this flow network 410 | */ 411 | public void setSink(int t) { 412 | this.t = t; 413 | } 414 | 415 | /** 416 | * Get source for this flow network 417 | */ 418 | public int getSource() { 419 | return s; 420 | } 421 | 422 | /** 423 | * Get sink for this flow network 424 | */ 425 | public int getSink() { 426 | return t; 427 | } 428 | 429 | /** 430 | * Set 'solved' flag to false to force recomputation of subsequent flows. 431 | */ 432 | public void recompute() { 433 | solved = false; 434 | } 435 | 436 | /** 437 | * Print all edges. 438 | */ 439 | public void printEdges() { 440 | for(Edge edge : edges) { 441 | System.out.println(String.format("%s ----%s----> %s", vertexLabels[edge.from], edge.capacity, vertexLabels[edge.to])); 442 | } 443 | } 444 | 445 | // Wrapper method that ensures we only call solve() once 446 | private void execute() { 447 | if (solved) return; 448 | solved = true; 449 | solve(); 450 | } 451 | 452 | // Method to implement which solves the network flow problem. 453 | public abstract void solve(); 454 | } 455 | -------------------------------------------------------------------------------- /SortedList/SortedList.java: -------------------------------------------------------------------------------- 1 | // Base code taken from http://blog.scottlogic.com/2010/12/22/sorted_lists_in_java.html 2 | // Supporting two additional operations that may be common on Balanced BSTs, 3 | // 1) lower - Finding the largest element strictly less than given element. 4 | // 2) findInOrderPosition - Finding the position of the element if all elements 5 | // were to be arranged in increasing order in an array. 6 | 7 | // SortedList based on AVL Tree 8 | import java.io.Serializable; 9 | import java.lang.reflect.Array; 10 | import java.util.AbstractList; 11 | import java.util.Collection; 12 | import java.util.Collections; 13 | import java.util.Comparator; 14 | import java.util.ConcurrentModificationException; 15 | import java.util.Iterator; 16 | import java.util.List; 17 | import java.util.NoSuchElementException; 18 | 19 | public class SortedList extends AbstractList implements Serializable { 20 | 21 | private Node root; 22 | private final Comparator comparator; 23 | 24 | /** 25 | * Constructs a new, empty SortedList which sorts the elements 26 | * according to the given {@code Comparator}. 27 | * 28 | * @param comparator the {@code Comparator} to sort the elements by. 29 | */ 30 | public SortedList(Comparator comparator){ 31 | this.comparator = comparator; 32 | } 33 | 34 | /** 35 | * Inserts the given object into this {code SortedList} at the appropriate 36 | * location, so as to ensure that the elements in the list are kept in 37 | * the order specified by the given {@code Comparator}. 38 | *

39 | * This method only allows non-null values to be added, if the given 40 | * object is null, the list remains unaltered and false returned. 41 | * 42 | * @param object the object to add. 43 | * @return false when the given object is null and true otherwise. 44 | */ 45 | @Override 46 | public boolean add(T object){ 47 | boolean treeAltered = false; 48 | if(object != null){ 49 | //wrap the value in a node and add it.. 50 | add(new Node(object)); //will ensure the modcount is increased.. 51 | treeAltered = true; 52 | } 53 | return treeAltered; 54 | } 55 | 56 | /** 57 | * Add the given Node to this {@code SortedList}. 58 | *

59 | * This method can be overridden by a subclass in order to change the definition of the {@code Node}s 60 | * that this List will store. 61 | *

62 | * This implementation uses the {@code Node#compareTo(Node)} method in order to ascertain where the 63 | * given {@code Node} should be stored. It also increments the modCount for this list. 64 | * 65 | * @param toAdd the {@code Node} to add. 66 | */ 67 | protected void add(Node toAdd){ 68 | if(root == null){ //simple case first.. 69 | root = toAdd; 70 | 71 | } else { //non-null root case.. 72 | Node current = root; 73 | while(current != null) { //should always break! 74 | int comparison = toAdd.compareTo(current); 75 | 76 | if(comparison < 0){ //toAdd < node 77 | if(current.leftChild == null){ 78 | current.setLeftChild(toAdd); 79 | break; 80 | } else { 81 | current = current.leftChild; 82 | } 83 | } else { //toAdd > node (equal should not be possible) 84 | if(current.rightChild == null){ 85 | current.setRightChild(toAdd); 86 | break; 87 | } else { 88 | current = current.rightChild; 89 | } 90 | } 91 | } 92 | } 93 | modCount++; //see AbstractList#modCount, incrementing this allows for iterators to be fail-fast.. 94 | } 95 | 96 | /** 97 | * Returns the number of elements in this {@code SortedList}. 98 | * 99 | * @return the number of elements stored in this {@code SortedList}. 100 | */ 101 | @Override 102 | public int size(){ 103 | return (root == null) ? 0 : 1 + root.numChildren; 104 | } 105 | 106 | /** 107 | * Returns the root node of this {@code SortedList}, which is 108 | * null in the case that this list is empty. 109 | * 110 | * @return the root node of this {@code SortedList}, which is 111 | * null in the case that this list is empty. 112 | */ 113 | protected Node getRoot(){ 114 | return root; 115 | } 116 | 117 | /** 118 | * Returns whether or not the given object is present in this {@code SortedList}. 119 | * The comparison check uses the {@code Object#equals(Object)} method and work 120 | * under the assumption that the given obj must have type T 121 | * to be equal to the elements in this {@code SortedList}. Works in time 122 | * O(log(n)), where n is the number of elements in the list. 123 | * 124 | * @param obj the object to check for. 125 | * @return true if the given object is present in this {code SortedList}. 126 | */ 127 | @SuppressWarnings("unchecked") 128 | @Override 129 | public boolean contains(Object obj){ 130 | return obj != null 131 | && !isEmpty() 132 | && findFirstNodeWithValue((T) obj) != null; 133 | } 134 | 135 | /** 136 | * Returns the node representing the given value in the tree, which can be null if 137 | * no such node exists. 138 | *

139 | * This method performs a binary search using the given comparator, and hence works in time 140 | * O(log(n)). 141 | * 142 | * @param value the value to search for. 143 | * @return the first node in this list with the given value. 144 | */ 145 | protected Node findFirstNodeWithValue(T value){ 146 | Node current = root; 147 | while(current != null){ 148 | //use the comparator on the values, rather than nodes.. 149 | int comparison = comparator.compare(current.value, value); 150 | if(comparison == 0){ 151 | //find the first such node.. 152 | while(current.leftChild != null 153 | && comparator.compare(current.leftChild.value, value) == 0){ 154 | current = current.leftChild; 155 | } 156 | break; 157 | } else if(comparison < 0){ //need to go right.. 158 | current = current.rightChild; 159 | } else { 160 | current = current.leftChild; 161 | } 162 | } 163 | return current; 164 | } 165 | 166 | /** 167 | * Removes the first element in the list with the given value, if such 168 | * a node exists, otherwise does nothing. Comparisons 169 | * on elements are done using the given comparator. 170 | *

171 | * Returns whether or not a matching element was found and removed or not. 172 | * 173 | * @param value the object to remove from this {@code SortedList}. 174 | * @return true if the given object was found in this 175 | * {@code SortedList} and removed, false otherwise. 176 | */ 177 | @Override 178 | public boolean remove(Object value){ 179 | boolean treeAltered = false; 180 | try { 181 | if(value != null && root != null){ 182 | @SuppressWarnings("unchecked") 183 | Node toRemove = findFirstNodeWithValue((T) value); 184 | if(toRemove != null){ 185 | remove(toRemove); 186 | treeAltered = true; 187 | } 188 | } 189 | } catch(ClassCastException e){ 190 | //comparator may throw this error, don't need to do anything.. 191 | } 192 | return treeAltered; 193 | } 194 | 195 | /** 196 | * Removes the given {@code Node} from this {@code SortedList}, re-balancing if required, 197 | * adds to modCount too. 198 | *

199 | * Operates in time O(log(n)), where n is the number of elements in the list. 200 | * 201 | * @param toRemove the {@code Node}, which must be a {@code Node} in this {@code SortedList}. 202 | */ 203 | protected void remove(Node toRemove){ 204 | if(toRemove.isLeaf()){ 205 | Node parent = toRemove.parent; 206 | if(parent == null){ //case where there is only one element in the list.. 207 | root = null; 208 | } else { 209 | toRemove.detachFromParentIfLeaf(); 210 | } 211 | } else if(toRemove.hasTwoChildren()){ //interesting case.. 212 | Node successor = toRemove.successor(); //will not be a non-null leaf or has one child!! 213 | 214 | //switch the values of the nodes over, then delete the switched node.. 215 | toRemove.switchValuesForThoseIn(successor); 216 | remove(successor); //will be one of the simpler cases. 217 | 218 | } else if(toRemove.leftChild != null){ 219 | toRemove.leftChild.contractParent(); 220 | } else { //leftChild is null but right isn't.. 221 | toRemove.rightChild.contractParent(); 222 | } 223 | modCount++; //see AbstractList#modCount, incrementing this allows for iterators to be fail-fast.. 224 | } 225 | 226 | /** 227 | * Returns the element at the given index in this {@code SortedList}. Since the list is sorted, 228 | * this is the "index"th smallest element, counting from 0-n-1. 229 | *

230 | * For example, calling {@code get(0)} will return the smallest element in the list. 231 | * 232 | * @param index the index of the element to get. 233 | * @return the element at the given index in this {@code SortedList}. 234 | * @throws IllegalArgumentException in the case that the index is not a valid index. 235 | */ 236 | @Override 237 | public T get(int index){ 238 | return findNodeAtIndex(index).value; 239 | } 240 | 241 | /** 242 | * Returns the {@code Node} at the given index. 243 | * 244 | * @param index the index to search for. 245 | * @return the {@code Node} object at the specified index. 246 | * 247 | * @throws IllegalArgumentException in the case that the the index is not valid. 248 | */ 249 | protected Node findNodeAtIndex(int index){ 250 | if(index < 0 || index >= size()){ 251 | throw new IllegalArgumentException(index + " is not valid index."); 252 | } 253 | Node current = root; 254 | //the the number of smaller elements of the current node as we traverse the tree.. 255 | int totalSmallerElements = (current.leftChild == null) ? 0 : current.leftChild.sizeOfSubTree(); 256 | while(current!= null){ //should always break, due to constraint above.. 257 | if(totalSmallerElements == index){ 258 | break; 259 | } 260 | if(totalSmallerElements > index){ //go left.. 261 | current = current.leftChild; 262 | totalSmallerElements--; 263 | totalSmallerElements -= (current.rightChild == null) ? 0 : current.rightChild.sizeOfSubTree(); 264 | } else { //go right.. 265 | totalSmallerElements++; 266 | current = current.rightChild; 267 | totalSmallerElements += (current.leftChild == null) ? 0 : current.leftChild.sizeOfSubTree(); 268 | } 269 | } 270 | return current; 271 | } 272 | 273 | /** 274 | * Returns the largest element strictly less than given element. 275 | * 276 | * @param element to search for. 277 | * @return largest element strictly less than given element. 278 | * 279 | * @throws NullPointerException in the case there is no element less than given element. 280 | */ 281 | public T lower(T value) { 282 | Node p = root; 283 | while (p != null) { 284 | int cmp = comparator.compare(value, p.value); 285 | if (cmp > 0) { 286 | if (p.rightChild != null) 287 | p = p.rightChild; 288 | else 289 | return p.value; 290 | } else { 291 | if (p.leftChild != null) { 292 | p = p.leftChild; 293 | } else { 294 | Node parent = p.parent; 295 | Node ch = p; 296 | while (parent != null && ch == parent.leftChild) { 297 | ch = parent; 298 | parent = parent.parent; 299 | } 300 | return parent.value; 301 | } 302 | } 303 | } 304 | return null; 305 | } 306 | 307 | /** 308 | * Returns the position of the element in Inorder traversal(i.e. ascending order) of the Balanced BST. 309 | * 310 | * @param element to search for. 311 | * @return position of the element in Inorder traversal. 312 | */ 313 | public int findInOrderPosition(T value){ 314 | Node current = root; 315 | int pos = 0; 316 | 317 | while(current != null){ 318 | //use the comparator on the values, rather than nodes.. 319 | int comparison = comparator.compare(current.value, value); 320 | if(comparison == 0){ 321 | pos += 1; 322 | if(current.leftChild != null) 323 | pos += current.leftChild.sizeOfSubTree(); 324 | //find the first such node.. 325 | while(current.leftChild != null 326 | && comparator.compare(current.leftChild.value, value) == 0){ 327 | current = current.leftChild; 328 | } 329 | break; 330 | } else if(comparison < 0){ //need to go right.. 331 | pos += 1; 332 | if(current.leftChild != null) 333 | pos += current.leftChild.sizeOfSubTree(); 334 | current = current.rightChild; 335 | } else { 336 | current = current.leftChild; 337 | } 338 | } 339 | return pos - 1; 340 | } 341 | 342 | /** 343 | * Returns whether or not the list contains any elements. 344 | * 345 | * @return {@code true} if the list has no element in it 346 | * and {@code false} otherwise. 347 | */ 348 | @Override 349 | public boolean isEmpty(){ 350 | return root == null; 351 | } 352 | 353 | /** 354 | * Removes all elements from the list, leaving it empty. 355 | */ 356 | @Override 357 | public void clear(){ 358 | root = null; //TF4GC. 359 | } 360 | 361 | /** 362 | * Returns the smallest balance factor across the entire list, this serves not other 363 | * purpose other than for testing. 364 | * 365 | * @return the minimum of all balance factors for nodes in this tree, or 0 if this tree is empty. 366 | */ 367 | int minBalanceFactor(){ 368 | int minBalanceFactor = 0; 369 | Node current = root; 370 | while(current != null){ 371 | minBalanceFactor = Math.min(current.getBalanceFactor(), minBalanceFactor); 372 | current = current.successor(); 373 | } 374 | return minBalanceFactor; 375 | } 376 | 377 | /** 378 | * Returns the largest balance factor across the entire list, this serves not other 379 | * purpose other than for testing. 380 | * 381 | * @return the maximum of all balance factors for nodes in this tree, or 0 if this tree is empty. 382 | */ 383 | int maxBalanceFactor(){ 384 | int maxBalanceFactor = 0; 385 | Node current = root; 386 | while(current != null){ 387 | maxBalanceFactor = Math.max(current.getBalanceFactor(), maxBalanceFactor); 388 | current = current.successor(); 389 | } 390 | return maxBalanceFactor; 391 | } 392 | 393 | //Implementation of the AVL tree rebalancing starting at the startNode and working up the tree... 394 | private void rebalanceTree(Node startNode){ 395 | Node current = startNode; 396 | while(current!= null){ 397 | //get the difference between the left and right subtrees at this point.. 398 | int balanceFactor = current.getBalanceFactor(); 399 | 400 | if(balanceFactor == -2){ //the right side is higher than the left. 401 | if(current.rightChild.getBalanceFactor() == 1){ //need to do a double rotation.. 402 | current.rightChild.leftChild.rightRotateAsPivot(); 403 | } 404 | current.rightChild.leftRotateAsPivot(); 405 | 406 | } else if(balanceFactor == 2){ //left side higher than the right. 407 | if(current.leftChild.getBalanceFactor() == -1){ //need to do a double rotation.. 408 | current.leftChild.rightChild.leftRotateAsPivot(); 409 | } 410 | current.leftChild.rightRotateAsPivot(); 411 | } 412 | 413 | if(current.parent == null){ //the root may have changed so this needs to be updated.. 414 | root = current; 415 | break; 416 | } else { 417 | //make the request go up the tree.. 418 | current = current.parent; 419 | } 420 | } 421 | } 422 | 423 | /** 424 | * Inner class used to represent positions in the tree. Each node stores a list of equal values, 425 | * is aware of their children and parent nodes, the height of the subtree rooted at that point and 426 | * the total number of children elements they have. 427 | * 428 | * @param T the value the node will store. 429 | */ 430 | protected class Node implements Comparable { 431 | 432 | private T value; //the data value being stored at this node 433 | 434 | private Node leftChild; 435 | private Node rightChild; 436 | private Node parent; 437 | 438 | //The "cached" values used to speed up methods.. 439 | private int height; 440 | private int numChildren; 441 | 442 | /** 443 | * Constructs a new Node which initially just stores the given value. 444 | * 445 | * @param t the value which this node will store. 446 | */ 447 | protected Node(T t){ 448 | this.value = t; 449 | } 450 | 451 | /** 452 | * Returns whether or not this {@code Node} has two children. 453 | * 454 | * @return true if this node has two children and false otherwise. 455 | */ 456 | protected boolean hasTwoChildren(){ 457 | return leftChild != null && rightChild != null; 458 | } 459 | 460 | //Removes this node if it's a leaf node and updates the number of children and heights in the tree.. 461 | private void detachFromParentIfLeaf(){ 462 | if(!isLeaf() || parent == null){ 463 | throw new RuntimeException("Call made to detachFromParentIfLeaf, but this is not a leaf node with a parent!"); 464 | } 465 | if(isLeftChildOfParent()){ 466 | parent.setLeftChild(null); 467 | } else { 468 | parent.setRightChild(null); 469 | } 470 | } 471 | 472 | /** 473 | * Returns the grand parent {@code Node} of this {@code Node}, which may be null. 474 | * 475 | * @return the grand parent of this node if there is one and null otherwise. 476 | */ 477 | protected Node getGrandParent(){ 478 | return (parent != null && parent.parent != null) ? parent.parent : null; 479 | } 480 | 481 | //Moves this node up the tree one notch, updates values and rebalancing the tree.. 482 | private void contractParent(){ 483 | if(parent == null || parent.hasTwoChildren()){ 484 | throw new RuntimeException("Can not call contractParent on root node or when the parent has two children!"); 485 | } 486 | Node grandParent = getGrandParent(); 487 | if(grandParent != null){ 488 | if(isLeftChildOfParent()){ 489 | if(parent.isLeftChildOfParent()){ 490 | grandParent.leftChild = this; 491 | } else { 492 | grandParent.rightChild = this; 493 | } 494 | parent = grandParent; 495 | } else { 496 | if(parent.isLeftChildOfParent()){ 497 | grandParent.leftChild = this; 498 | } else { 499 | grandParent.rightChild = this; 500 | } 501 | parent = grandParent; 502 | } 503 | } else { //no grandparent.. 504 | parent = null; 505 | root = this; //update root in case it's not done elsewhere.. 506 | } 507 | 508 | //finally clean up by updating values and rebalancing.. 509 | updateCachedValues(); 510 | rebalanceTree(this); 511 | } 512 | 513 | /** 514 | * Returns whether or not this not is the left child of its parent node; if this is the 515 | * root node, then false is returned. 516 | * 517 | * @return true if this is the left child of its parent node 518 | * and false otherwise. 519 | */ 520 | public boolean isLeftChildOfParent(){ 521 | return parent != null && parent.leftChild == this; 522 | } 523 | 524 | /** 525 | * Returns whether or not this not is the right child of its parent node; if this is the 526 | * root node, then false is returned. 527 | * 528 | * @return true if this is the right child of its parent node 529 | * and false otherwise. 530 | */ 531 | public boolean isRightChildOfParent(){ 532 | return parent != null && parent.rightChild == this; 533 | } 534 | 535 | /** 536 | * Returns the left child of this {@code Node}, which may be null. 537 | * 538 | * @return the left child of this {@code Node}, which may be null. 539 | */ 540 | protected Node getLeftChild(){ 541 | return leftChild; 542 | } 543 | 544 | /** 545 | * Returns the right child of this {@code Node}, which may be be null. 546 | * 547 | * @return the right child of this node, which may be null. 548 | */ 549 | protected Node getRightChild(){ 550 | return rightChild; 551 | } 552 | 553 | /** 554 | * Returns the parent {@code Node} of this node, which will be null 555 | * in the case that this is the root {@code Node}. 556 | * 557 | * @return the parent node of this one. 558 | */ 559 | protected Node getParent(){ 560 | return parent; 561 | } 562 | 563 | /** 564 | * Compares the value stored at this node with the value at the given node using 565 | * the comparator, if these values are equal it compares the nodes on their IDs; 566 | * older nodes considered to be smaller. 567 | * 568 | * @return if the comparator returns a non-zero number when comparing the values stored at 569 | * this node and the given node, this number is returned, otherwise this node's id minus 570 | * the given node's id is returned. 571 | */ 572 | public int compareTo(Node other){ 573 | int comparison = comparator.compare(value, other.value); 574 | return comparison; 575 | } 576 | 577 | /** 578 | * Finds and returns the smallest node in the tree rooted at this node. 579 | * 580 | * @return the smallest valued node in the tree rooted at this node, which maybe this node. 581 | */ 582 | protected final Node smallestNodeInSubTree(){ 583 | Node current = this; 584 | while(current != null){ 585 | if(current.leftChild == null){ 586 | break; 587 | } else { 588 | current = current.leftChild; 589 | } 590 | } 591 | return current; 592 | } 593 | 594 | /** 595 | * Finds the largest node in the tree rooted at this node. 596 | * 597 | * @return the largest valued node in the tree rooted at this node which may be this node. 598 | */ 599 | protected final Node largestNodeInSubTree(){ 600 | Node current = this; 601 | while(current != null){ 602 | if(current.rightChild == null){ 603 | break; 604 | } else { 605 | current = current.rightChild; 606 | } 607 | } 608 | return current; 609 | } 610 | 611 | /** 612 | * Gets the next biggest node in the tree, which is null if this is 613 | * the largest valued node. 614 | * 615 | * @return the next biggest node in the tree, which is null if this 616 | * is the largest valued node. 617 | */ 618 | protected final Node successor(){ 619 | Node successor = null; 620 | if(rightChild != null){ 621 | successor = rightChild.smallestNodeInSubTree(); 622 | } else if(parent != null){ 623 | Node current = this; 624 | while(current != null && current.isRightChildOfParent()){ 625 | current = current.parent; 626 | } 627 | successor = current.parent; 628 | } 629 | return successor; 630 | } 631 | 632 | //Sets the child node to the left/right, should only be used if the given node 633 | //is null or a leaf, and the current child is the same.. 634 | private void setChild(boolean isLeft, Node leaf){ 635 | //perform the update.. 636 | if(leaf != null){ 637 | leaf.parent = this; 638 | } 639 | if(isLeft){ 640 | leftChild = leaf; 641 | } else { 642 | rightChild = leaf; 643 | } 644 | 645 | //make sure any change to the height of the tree is dealt with.. 646 | updateCachedValues(); 647 | rebalanceTree(this); 648 | } 649 | 650 | /** 651 | * Returns whether or not this {@code Node} is a leaf; this is true in the case that 652 | * both its left and right children are set to null. 653 | * 654 | * @return true if this node is leaf and false otherwise. 655 | */ 656 | public boolean isLeaf(){ 657 | return (leftChild == null && rightChild == null); 658 | } 659 | 660 | //performs a left rotation using this node as a pivot.. 661 | private void leftRotateAsPivot(){ 662 | if(parent == null || parent.rightChild != this){ 663 | throw new RuntimeException("Can't left rotate as pivot has no valid parent node."); 664 | } 665 | 666 | //first move this node up the tree, detaching parent... 667 | Node oldParent = parent; 668 | Node grandParent = getGrandParent(); 669 | if(grandParent != null){ 670 | if(parent.isLeftChildOfParent()){ 671 | grandParent.leftChild = this; 672 | } else { 673 | grandParent.rightChild = this; 674 | } 675 | } 676 | this.parent = grandParent; //could be null. 677 | 678 | //now make old parent left child and put old left child as right child of parent.. 679 | Node oldLeftChild = leftChild; 680 | oldParent.parent = this; 681 | leftChild = oldParent; 682 | if(oldLeftChild != null){ 683 | oldLeftChild.parent = oldParent; 684 | } 685 | oldParent.rightChild = oldLeftChild; 686 | 687 | //now we need to update the values for height and number of children.. 688 | oldParent.updateCachedValues(); 689 | } 690 | 691 | /** 692 | * Returns, the number of children of this {@code Node} plus one. This method uses 693 | * a cached variable ensuring it runs in constant time. 694 | * 695 | * @return the number of children of this {@code Node} plus one. 696 | */ 697 | public int sizeOfSubTree(){ 698 | return 1 + numChildren; 699 | } 700 | 701 | /** 702 | * Returns the value stored at this {@code Node}. 703 | * 704 | * @return the value that this {@code Node} stores. 705 | */ 706 | public T getValue(){ 707 | return value; 708 | } 709 | 710 | //performs a left rotation using this node as a pivot.. 711 | private void rightRotateAsPivot(){ 712 | if(parent == null || parent.leftChild != this){ 713 | throw new RuntimeException("Can't right rotate as pivot has no valid parent node."); 714 | } 715 | //first move this node up the tree, detaching parent... 716 | Node oldParent = parent; 717 | Node grandParent = getGrandParent(); 718 | if(grandParent != null){ 719 | if(parent.isLeftChildOfParent()){ 720 | grandParent.leftChild = this; 721 | } else { 722 | grandParent.rightChild = this; 723 | } 724 | } 725 | this.parent = grandParent; //could be null. 726 | 727 | //now switch right child to left child of old parent.. 728 | oldParent.parent = this; 729 | Node oldRightChild = rightChild; 730 | rightChild = oldParent; 731 | if(oldRightChild != null){ 732 | oldRightChild.parent = oldParent; 733 | } 734 | oldParent.leftChild = oldRightChild; 735 | 736 | //now we need to update the values for height and number of children.. 737 | oldParent.updateCachedValues(); 738 | } 739 | 740 | /** 741 | * Updates the height and the number of children for nodes on the path to this. 742 | * Also calls {@code #updateAdditionalCachedValues()}, for every node on the path to 743 | * this, including this one. 744 | */ 745 | protected final void updateCachedValues(){ 746 | Node current = this; 747 | while(current != null){ 748 | if(current.isLeaf()){ 749 | current.height = 0; 750 | current.numChildren = 0; 751 | 752 | } else { 753 | //deal with the height.. 754 | int leftTreeHeight = (current.leftChild == null) ? 0 : current.leftChild.height; 755 | int rightTreeHeight = (current.rightChild == null) ? 0 : current.rightChild.height; 756 | current.height = 1 + Math.max(leftTreeHeight, rightTreeHeight); 757 | 758 | //deal with the number of children.. 759 | int leftTreeSize = (current.leftChild == null) ? 0 : current.leftChild.sizeOfSubTree(); 760 | int rightTreeSize = (current.rightChild == null) ? 0 : current.rightChild.sizeOfSubTree(); 761 | current.numChildren = leftTreeSize + rightTreeSize; 762 | } 763 | 764 | //update any additional cached values set if required.. 765 | current.updateAdditionalCachedValues(); 766 | 767 | //propagate up the tree.. 768 | current = current.parent; 769 | } 770 | } 771 | 772 | /** 773 | * Called when a node is inserted or removed from the tree and provides a hook for 774 | * sub-classes to get their cached values updated. 775 | *

776 | * This method is called every time the list is altered. It is first called on the deepest node 777 | * which is affected by a given change and is then subsequently called on ancestors of this node until 778 | * it is called on the root node. 779 | *

780 | * It is therefore only suitable for updating cached values in the case that they are non-global 781 | * and do not rely on the parent node having the correct value when being calculated. 782 | *

783 | * This implementation is empty, and hence does nothing. 784 | */ 785 | protected void updateAdditionalCachedValues(){ 786 | //do nothing - this is a hook to allow subclasses to provide additional behaviour.. 787 | } 788 | 789 | //Just replaces the values this this node with those in other.. 790 | //should only be called when this is doing to be removed and has just one value.. 791 | private void switchValuesForThoseIn(Node other){ 792 | this.value = other.value; //switch the values over, nothing else need change.. 793 | } 794 | 795 | //returns (height of the left subtree - the right of the right subtree).. 796 | private int getBalanceFactor(){ 797 | return ((leftChild == null) ? 0 : leftChild.height + 1) - 798 | ((rightChild == null) ? 0 : rightChild.height + 1); 799 | } 800 | 801 | //Sets the left child node. 802 | private void setLeftChild(Node leaf){ 803 | if((leaf != null && !leaf.isLeaf()) || (leftChild != null && !leftChild.isLeaf())){ 804 | throw new RuntimeException("setLeftChild should only be called with null or a leaf node, to replace a likewise child node."); 805 | } 806 | setChild(true, leaf); 807 | } 808 | 809 | //Sets the right child node. 810 | private void setRightChild(Node leaf){ 811 | if((leaf != null && !leaf.isLeaf()) || (rightChild != null && !rightChild.isLeaf())){ 812 | throw new RuntimeException("setRightChild should only be called with null or a leaf node, to replace a likewise child node."); 813 | } 814 | setChild(false, leaf); 815 | } 816 | } //End of inner class: Node. 817 | 818 | } --------------------------------------------------------------------------------