Skip to content

Commit 3474d60

Browse files
author
lennart
committed
add findCentroid recursive method, add tests for building CTree
1 parent 563ef68 commit 3474d60

2 files changed

Lines changed: 108 additions & 19 deletions

File tree

src/main/java/com/thealgorithms/tree/CentroidDecomposition.java

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,65 +3,109 @@
33
import java.util.ArrayList;
44
import java.util.Arrays;
55
import java.util.List;
6-
import java.util.HashMap;
76

87
public class CentroidDecomposition {
98
private List<Integer>[] tree;
109
private List<Integer>[] centroidTree;
11-
private boolean[] removedCentroids;
10+
private boolean[] centroidMarked;
11+
private int[] centroidParent;
12+
private int startingNode;
13+
private int N;
1214

15+
public CentroidDecomposition(int n, int startingNode){
16+
tree = new ArrayList[n];
17+
centroidTree = new ArrayList[n];
18+
N = n;
19+
for (int i = 0; i < centroidTree.length; i++) centroidTree[i] = new ArrayList<>();
20+
for (int i = 0; i < tree.length; i++) tree[i] = new ArrayList<>();
21+
centroidMarked = new boolean[n];
22+
centroidParent = new int[n];
23+
startingNode = (int)(Math.random() * n+1);
24+
for(int i = 0; i<n; i++){
25+
tree[i] = new ArrayList<>();
26+
}
27+
}
1328
public CentroidDecomposition(int n){
1429
tree = new ArrayList[n];
1530
centroidTree = new ArrayList[n];
16-
removedCentroids = new boolean[n];
31+
centroidMarked = new boolean[n];
32+
centroidParent = new int[n];
33+
startingNode = (this.startingNode == -1) ? (int)(Math.random() * n+1) : this.startingNode;
34+
N = n;
35+
for (int i = 0; i < centroidTree.length; i++) centroidTree[i] = new ArrayList<>();
36+
for (int i = 0; i < tree.length; i++) tree[i] = new ArrayList<>();
1737
for(int i = 0; i<n; i++){
1838
tree[i] = new ArrayList<>();
1939
}
2040
}
2141

42+
public List<Integer>[] getCentroidTree(){
43+
return centroidTree;
44+
}
45+
2246
public void addEdge(int u, int v){
2347
tree[u].add(v);
2448
tree[v].add(u);
2549
}
2650

51+
private void addEdgeCTree(int u, int v){
52+
centroidTree[u].add(v);
53+
centroidTree[v].add(u);
54+
centroidParent[v] = u;
55+
}
56+
57+
2758
public void findSubtreeSizes(int src, boolean[] visited, int[] subtreeSizes){
2859
// dfs traversal to find size of subtree rooted at src
2960
visited[src] = true;
3061
subtreeSizes[src] = 1;
3162
for (int node : tree[src]){
32-
if(!visited[node]){
63+
if(!visited[node] && !centroidMarked[node]){
3364
visited[node] = true;
3465
findSubtreeSizes(node, visited, subtreeSizes); // recurse down to last child node
3566
subtreeSizes[src] += subtreeSizes[node]; // add size of full recursive path to subtree Size of src
3667
}
3768
}
3869
}
3970

40-
private void findCentroid(int src){
41-
int treeSize = tree[src].size();
42-
int[] subtreeSizes = new int[treeSize];
43-
boolean[] visited = new boolean[treeSize];
71+
public void findCentroid(int src, int previousCentroid){
72+
int[] subtreeSizes = new int[N];
73+
boolean[] visited = new boolean[N];
4474
Arrays.fill(visited, false);
45-
75+
4676
findSubtreeSizes(src, visited, subtreeSizes);
77+
int treeSize = Arrays.stream(subtreeSizes).max().getAsInt();
78+
79+
centroidMarked[src] = true;
4780

48-
boolean isCentroid = true;
4981
for (int node : tree[src]){
50-
isCentroid = (subtreeSizes[node] <= (subtreeSizes[src]/2)) ? true : false;
82+
if (subtreeSizes[node] > (treeSize/2)){
83+
centroidMarked[src] = false;
84+
break;
85+
}
5186
}
52-
53-
if (isCentroid){
87+
88+
if (centroidMarked[src]){
89+
if (src != startingNode && src != previousCentroid) addEdgeCTree(previousCentroid, src);
90+
// centroidTree[previousCentroid].add(src);
5491
for (int node : tree[src]){
55-
92+
if (!centroidMarked[node])
93+
findCentroid(node, src);
5694
}
5795
}
5896
else{
59-
// pick one of the children of the node for next check
97+
// pick one of the children of the root for next check
98+
int nextLargestSubtree = tree[src].getFirst();
99+
for (int node : tree[src]){
100+
if (subtreeSizes[node] >= subtreeSizes[nextLargestSubtree])
101+
nextLargestSubtree = node;
102+
}
103+
findCentroid(nextLargestSubtree, previousCentroid);
60104
}
61105
}
62106

63107
public static void main(String[] args) {
64-
CentroidDecomposition cd = new CentroidDecomposition(16);
108+
CentroidDecomposition cd = new CentroidDecomposition(16, -1);
65109
cd.addEdge(0, 1);
66110
cd.addEdge(0, 2);
67111
cd.addEdge(0, 3);
@@ -81,7 +125,22 @@ public static void main(String[] args) {
81125
boolean[] visited = new boolean[16];
82126
int[] subtreeSizes = new int[16];
83127

84-
cd.findSubtreeSizes(3, visited, subtreeSizes);
128+
// int start = cd.startingNode;
129+
int src = (int) ((Math.random() * (15)) + 0);
130+
System.out.println("src= " + src);
131+
132+
cd.findCentroid(src, src);
133+
134+
// System.out.println((int)(Math.random() * 16));
135+
136+
for (int i = 0; i < cd.centroidTree.length; i++) {
137+
System.out.println(String.format("%s %s", i, cd.centroidTree[i]));
138+
}
139+
140+
// cd.findSubtreeSizes(8, visited, subtreeSizes);
141+
// for (int i = 0; i < subtreeSizes.length; i++) {
142+
// System.out.println(String.format("%s %s", i, subtreeSizes[i]));
143+
// }
85144
}
86145

87146
}

src/test/java/com/thealgorithms/tree/CentroidDecompositionTest.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
package com.thealgorithms.tree;
22

3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
34
import static org.junit.jupiter.api.Assertions.assertEquals;
45
import static org.junit.jupiter.api.Assertions.assertTrue;
56
import static org.mockito.Answers.values;
67

8+
import java.util.ArrayList;
79
import java.util.Arrays;
10+
import java.util.List;
811

912
import org.junit.jupiter.api.BeforeEach;
13+
import org.junit.jupiter.api.RepeatedTest;
1014
import org.junit.jupiter.api.Test;
1115

1216
class CentroidDecompositionTest {
1317
private CentroidDecomposition cd;
18+
private int n = 16;
1419

1520
@BeforeEach
1621
void setUp(){
@@ -45,20 +50,45 @@ void setUp(){
4550
14
4651
\
4752
15
53+
54+
55+
56+
0
57+
/ | \
58+
1 11 8
59+
/ \ / | \ / | \
60+
4 5 2 12 14 3 9 10
61+
/ \ / \
62+
7 6 15 13
4863
4964
*/
5065
}
5166

5267
@Test
5368
void testFindSubtreeSizes(){
54-
boolean[] visited = new boolean[16];
55-
int[] subtreeSizes = new int[16];
69+
boolean[] visited = new boolean[n];
70+
int[] subtreeSizes = new int[n];
5671

5772
cd.findSubtreeSizes(3, visited, subtreeSizes);
5873
assertEquals(subtreeSizes[8], 3);
5974
assertEquals(subtreeSizes[0], 12);
6075
}
6176

77+
@RepeatedTest(100)
78+
void testBuildCentroidTree(){
79+
int src = (int) ((Math.random() * (15)) + 0);
80+
cd.findCentroid(src, src);
81+
List<Integer>[] centroidTree = cd.getCentroidTree();
82+
83+
List<Integer> correct = new ArrayList<Integer>();
84+
correct.add(0);
85+
correct.add(3);
86+
correct.add(9);
87+
correct.add(10);
6288

89+
for (int j = 0; j < centroidTree[8].size(); j++) {
90+
assertEquals(correct.get(j), centroidTree[8].get(j));
91+
}
6392

93+
}
6494
}

0 commit comments

Comments
 (0)