@@ -39,7 +39,6 @@ target/
|
||||
spring-openid/src/main/resources/application.properties
|
||||
.recommenders/
|
||||
/spring-hibernate4/nbproject/
|
||||
spring-security-openid/src/main/resources/application.properties
|
||||
|
||||
spring-all/*.log
|
||||
|
||||
|
||||
@@ -15,5 +15,4 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
|
||||
- [Creating a Triangle with for Loops in Java](https://www.baeldung.com/java-print-triangle)
|
||||
- [Efficient Word Frequency Calculator in Java](https://www.baeldung.com/java-word-frequency)
|
||||
- [The K-Means Clustering Algorithm in Java](https://www.baeldung.com/java-k-means-clustering-algorithm)
|
||||
- [Creating a Custom Annotation in Java](https://www.baeldung.com/java-custom-annotation)
|
||||
- More articles: [[<-- prev]](/algorithms-miscellaneous-2) [[next -->]](/algorithms-miscellaneous-4)
|
||||
|
||||
@@ -10,4 +10,6 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
|
||||
- [Find If Two Numbers Are Relatively Prime in Java](https://www.baeldung.com/java-two-relatively-prime-numbers)
|
||||
- [Knapsack Problem Implementation in Java](https://www.baeldung.com/java-knapsack)
|
||||
- [How to Determine if a Binary Tree is Balanced](https://www.baeldung.com/java-balanced-binary-tree)
|
||||
- [The Caesar Cipher in Java](https://www.baeldung.com/java-caesar-cipher)
|
||||
- [Overview of Combinatorial Problems in Java](https://www.baeldung.com/java-combinatorial-algorithms)
|
||||
- More articles: [[<-- prev]](/../algorithms-miscellaneous-4)
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
<artifactId>tradukisto</artifactId>
|
||||
<version>${tradukisto.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>28.1-jre</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.baeldung.algorithms.greedy;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public class Follower {
|
||||
|
||||
@Getter String username;
|
||||
@Getter long count;
|
||||
|
||||
public Follower(String username, long count) {
|
||||
super();
|
||||
this.username = username;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User: " + username + ", Followers: " + count + "\n\r" ;
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.baeldung.algorithms.greedy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FollowersPath {
|
||||
|
||||
private List<Follower> accounts;
|
||||
private long count;
|
||||
|
||||
public FollowersPath() {
|
||||
super();
|
||||
this.accounts = new ArrayList<>();
|
||||
}
|
||||
|
||||
public List<Follower> getAccounts() {
|
||||
return accounts;
|
||||
}
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void addFollower(String username, long count) {
|
||||
accounts.add(new Follower(username, count));
|
||||
}
|
||||
|
||||
public void addCount(long count) {
|
||||
this.count += count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String details = "";
|
||||
for(Follower a : accounts) {
|
||||
details+=a.toString() + ", ";
|
||||
}
|
||||
|
||||
return "Total: " + count + ", \n\r" +
|
||||
" Details: { " + "\n\r" +
|
||||
details + "\n\r" +
|
||||
" }";
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.baeldung.algorithms.greedy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GreedyAlgorithm {
|
||||
|
||||
int currentLevel = 0;
|
||||
final int maxLevel = 3;
|
||||
SocialConnector sc;
|
||||
FollowersPath fp;
|
||||
|
||||
public GreedyAlgorithm(SocialConnector sc) {
|
||||
super();
|
||||
this.sc = sc;
|
||||
this.fp = new FollowersPath();
|
||||
}
|
||||
|
||||
public long findMostFollowersPath(String account) throws Exception {
|
||||
long max = 0;
|
||||
SocialUser toFollow = null;
|
||||
|
||||
List<SocialUser> followers = sc.getFollowers(account);
|
||||
for (SocialUser el : followers) {
|
||||
long followersCount = el.getFollowersCount();
|
||||
if (followersCount > max) {
|
||||
toFollow = el;
|
||||
max = followersCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLevel < maxLevel - 1) {
|
||||
currentLevel++;
|
||||
max += findMostFollowersPath(toFollow.getUsername());
|
||||
//fp.addFollower(toFollow.getUsername(), max);
|
||||
//fp.addCount(max);
|
||||
return max;
|
||||
} else {
|
||||
//fp.addFollower(toFollow.getUsername(), max);
|
||||
//fp.addCount(max);
|
||||
return max;
|
||||
}
|
||||
}
|
||||
|
||||
public FollowersPath getFollowers() {
|
||||
return fp;
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.baeldung.algorithms.greedy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NonGreedyAlgorithm {
|
||||
|
||||
int currentLevel = 0;
|
||||
final int maxLevel = 3;
|
||||
SocialConnector tc;
|
||||
|
||||
public NonGreedyAlgorithm(SocialConnector tc, int level) {
|
||||
super();
|
||||
this.tc = tc;
|
||||
this.currentLevel = level;
|
||||
}
|
||||
|
||||
|
||||
public long findMostFollowersPath(String account) throws Exception {
|
||||
List<SocialUser> followers = tc.getFollowers(account);
|
||||
long total = currentLevel > 0 ? followers.size() : 0;
|
||||
|
||||
if (currentLevel < maxLevel ) {
|
||||
currentLevel++;
|
||||
|
||||
long[] count = new long[followers.size()];
|
||||
int i = 0;
|
||||
for (SocialUser el : followers) {
|
||||
NonGreedyAlgorithm sub = new NonGreedyAlgorithm(tc, currentLevel);
|
||||
count[i] = sub.findMostFollowersPath(el.getUsername());
|
||||
i++;
|
||||
}
|
||||
|
||||
long max = 0;
|
||||
for (; i > 0; i--) {
|
||||
if (count[i-1] > max )
|
||||
max = count[i-1];
|
||||
}
|
||||
|
||||
return total + max;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.baeldung.algorithms.greedy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class SocialConnector {
|
||||
private boolean isCounterEnabled = true;
|
||||
private int counter = 4;
|
||||
@Getter @Setter List<SocialUser> users;
|
||||
|
||||
public SocialConnector() {
|
||||
users = new ArrayList<>();
|
||||
}
|
||||
|
||||
public boolean switchCounter() {
|
||||
this.isCounterEnabled = !this.isCounterEnabled;
|
||||
return this.isCounterEnabled;
|
||||
}
|
||||
|
||||
public List<SocialUser> getFollowers(String account) throws Exception {
|
||||
if (counter < 0)
|
||||
throw new Exception ("API limit reached");
|
||||
else {
|
||||
if(this.isCounterEnabled) counter--;
|
||||
for(SocialUser user : users) {
|
||||
if (user.getUsername().equals(account)) {
|
||||
return user.getFollowers();
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.baeldung.algorithms.greedy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public class SocialUser {
|
||||
|
||||
@Getter private String username;
|
||||
@Getter private List<SocialUser> followers;
|
||||
|
||||
public SocialUser(String username) {
|
||||
super();
|
||||
this.username = username;
|
||||
this.followers = new ArrayList<>();
|
||||
}
|
||||
|
||||
public SocialUser(String username, List<SocialUser> followers) {
|
||||
super();
|
||||
this.username = username;
|
||||
this.followers = followers;
|
||||
}
|
||||
|
||||
public long getFollowersCount() {
|
||||
return followers.size();
|
||||
}
|
||||
|
||||
public void addFollowers(List<SocialUser> followers) {
|
||||
this.followers.addAll(followers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return ((SocialUser) obj).getUsername().equals(username);
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.algorithms.integerstreammedian;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
|
||||
public class MedianOfIntegerStream {
|
||||
|
||||
private Queue<Integer> minHeap, maxHeap;
|
||||
|
||||
MedianOfIntegerStream() {
|
||||
minHeap = new PriorityQueue<>();
|
||||
maxHeap = new PriorityQueue<>(reverseOrder());
|
||||
}
|
||||
|
||||
void add(int num) {
|
||||
if (!minHeap.isEmpty() && num < minHeap.peek()) {
|
||||
maxHeap.offer(num);
|
||||
if (maxHeap.size() > minHeap.size() + 1) {
|
||||
minHeap.offer(maxHeap.poll());
|
||||
}
|
||||
} else {
|
||||
minHeap.offer(num);
|
||||
if (minHeap.size() > maxHeap.size() + 1) {
|
||||
maxHeap.offer(minHeap.poll());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double getMedian() {
|
||||
int median;
|
||||
if (minHeap.size() < maxHeap.size()) {
|
||||
median = maxHeap.peek();
|
||||
} else if (minHeap.size() > maxHeap.size()) {
|
||||
median = minHeap.peek();
|
||||
} else {
|
||||
median = (minHeap.peek() + maxHeap.peek()) / 2;
|
||||
}
|
||||
return median;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.baeldung.algorithms.integerstreammedian;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
|
||||
public class MedianOfIntegerStream2 {
|
||||
|
||||
private Queue<Integer> minHeap, maxHeap;
|
||||
|
||||
MedianOfIntegerStream2() {
|
||||
minHeap = new PriorityQueue<>();
|
||||
maxHeap = new PriorityQueue<>(reverseOrder());
|
||||
}
|
||||
|
||||
void add(int num) {
|
||||
if (minHeap.size() == maxHeap.size()) {
|
||||
maxHeap.offer(num);
|
||||
minHeap.offer(maxHeap.poll());
|
||||
} else {
|
||||
minHeap.offer(num);
|
||||
maxHeap.offer(minHeap.poll());
|
||||
}
|
||||
}
|
||||
|
||||
double getMedian() {
|
||||
int median;
|
||||
if (minHeap.size() > maxHeap.size()) {
|
||||
median = minHeap.peek();
|
||||
} else {
|
||||
median = (minHeap.peek() + maxHeap.peek()) / 2;
|
||||
}
|
||||
return median;
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package com.baeldung.algorithms.kruskal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CycleDetector {
|
||||
|
||||
List<DisjointSetInfo> nodes;
|
||||
|
||||
public CycleDetector(int totalNodes) {
|
||||
initDisjointSets(totalNodes);
|
||||
}
|
||||
|
||||
public boolean detectCycle(Integer u, Integer v) {
|
||||
Integer rootU = pathCompressionFind(u);
|
||||
Integer rootV = pathCompressionFind(v);
|
||||
if (rootU.equals(rootV)) {
|
||||
return true;
|
||||
}
|
||||
unionByRank(rootU, rootV);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void initDisjointSets(int totalNodes) {
|
||||
nodes = new ArrayList<>(totalNodes);
|
||||
for (int i = 0; i < totalNodes; i++) {
|
||||
nodes.add(new DisjointSetInfo(i));
|
||||
}
|
||||
}
|
||||
|
||||
private Integer find(Integer node) {
|
||||
Integer parent = nodes.get(node).getParentNode();
|
||||
if (parent.equals(node)) {
|
||||
return node;
|
||||
} else {
|
||||
return find(parent);
|
||||
}
|
||||
}
|
||||
|
||||
private Integer pathCompressionFind(Integer node) {
|
||||
DisjointSetInfo setInfo = nodes.get(node);
|
||||
Integer parent = setInfo.getParentNode();
|
||||
if (parent.equals(node)) {
|
||||
return node;
|
||||
} else {
|
||||
Integer parentNode = find(parent);
|
||||
setInfo.setParentNode(parentNode);
|
||||
return parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
private void union(Integer rootU, Integer rootV) {
|
||||
DisjointSetInfo setInfoU = nodes.get(rootU);
|
||||
setInfoU.setParentNode(rootV);
|
||||
}
|
||||
|
||||
private void unionByRank(int rootU, int rootV) {
|
||||
DisjointSetInfo setInfoU = nodes.get(rootU);
|
||||
DisjointSetInfo setInfoV = nodes.get(rootV);
|
||||
int rankU = setInfoU.getRank();
|
||||
int rankV = setInfoV.getRank();
|
||||
if (rankU < rankV) {
|
||||
setInfoU.setParentNode(rootV);
|
||||
} else {
|
||||
setInfoV.setParentNode(rootU);
|
||||
if (rankU == rankV) {
|
||||
setInfoU.setRank(rankU + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.baeldung.algorithms.kruskal;
|
||||
|
||||
public class DisjointSetInfo {
|
||||
|
||||
private Integer parentNode;
|
||||
private int rank;
|
||||
|
||||
DisjointSetInfo(Integer nodeNumber) {
|
||||
setParentNode(nodeNumber);
|
||||
setRank(1);
|
||||
}
|
||||
|
||||
public Integer getParentNode() {
|
||||
return parentNode;
|
||||
}
|
||||
|
||||
public void setParentNode(Integer parentNode) {
|
||||
this.parentNode = parentNode;
|
||||
}
|
||||
|
||||
public int getRank() {
|
||||
return rank;
|
||||
}
|
||||
|
||||
public void setRank(int rank) {
|
||||
this.rank = rank;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.baeldung.algorithms.kruskal;
|
||||
|
||||
import com.google.common.graph.EndpointPair;
|
||||
import com.google.common.graph.MutableValueGraph;
|
||||
import com.google.common.graph.ValueGraph;
|
||||
import com.google.common.graph.ValueGraphBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class Kruskal {
|
||||
|
||||
public ValueGraph<Integer, Double> minSpanningTree(ValueGraph<Integer, Double> graph) {
|
||||
|
||||
return spanningTree(graph, true);
|
||||
}
|
||||
|
||||
public ValueGraph<Integer, Double> maxSpanningTree(ValueGraph<Integer, Double> graph) {
|
||||
return spanningTree(graph, false);
|
||||
}
|
||||
|
||||
private ValueGraph<Integer, Double> spanningTree(ValueGraph<Integer, Double> graph, boolean minSpanningTree) {
|
||||
Set<EndpointPair<Integer>> edges = graph.edges();
|
||||
List<EndpointPair<Integer>> edgeList = new ArrayList<>(edges);
|
||||
|
||||
if (minSpanningTree) {
|
||||
edgeList.sort(Comparator.comparing(e -> graph.edgeValue(e).get()));
|
||||
} else {
|
||||
edgeList.sort(Collections.reverseOrder(Comparator.comparing(e -> graph.edgeValue(e).get())));
|
||||
}
|
||||
|
||||
int totalNodes = graph.nodes().size();
|
||||
CycleDetector cycleDetector = new CycleDetector(totalNodes);
|
||||
int edgeCount = 0;
|
||||
|
||||
MutableValueGraph<Integer, Double> spanningTree = ValueGraphBuilder.undirected().build();
|
||||
for (EndpointPair<Integer> edge : edgeList) {
|
||||
if (cycleDetector.detectCycle(edge.nodeU(), edge.nodeV())) {
|
||||
continue;
|
||||
}
|
||||
spanningTree.putEdgeValue(edge.nodeU(), edge.nodeV(), graph.edgeValue(edge).get());
|
||||
edgeCount++;
|
||||
if (edgeCount == totalNodes - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return spanningTree;
|
||||
}
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.baeldung.algorithms.greedy;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class GreedyAlgorithmUnitTest {
|
||||
|
||||
private SocialConnector prepareNetwork() {
|
||||
SocialConnector sc = new SocialConnector();
|
||||
SocialUser root = new SocialUser("root");
|
||||
SocialUser child1 = new SocialUser("child1");
|
||||
SocialUser child2 = new SocialUser("child2");
|
||||
SocialUser child3 = new SocialUser("child3");
|
||||
SocialUser child21 = new SocialUser("child21");
|
||||
SocialUser child211 = new SocialUser("child211");
|
||||
SocialUser child2111 = new SocialUser("child2111");
|
||||
SocialUser child31 = new SocialUser("child31");
|
||||
SocialUser child311 = new SocialUser("child311");
|
||||
SocialUser child3111 = new SocialUser("child3111");
|
||||
child211.addFollowers(Arrays.asList(new SocialUser[]{child2111}));
|
||||
child311.addFollowers(Arrays.asList(new SocialUser[]{child3111}));
|
||||
child21.addFollowers(Arrays.asList(new SocialUser[]{child211}));
|
||||
child31.addFollowers(Arrays.asList(new SocialUser[]{child311,
|
||||
new SocialUser("child312"), new SocialUser("child313"), new SocialUser("child314")}));
|
||||
child1.addFollowers(Arrays.asList(new SocialUser[]{new SocialUser("child11"), new SocialUser("child12")}));
|
||||
child2.addFollowers(Arrays.asList(new SocialUser[]{child21, new SocialUser("child22"), new SocialUser("child23")}));
|
||||
child3.addFollowers(Arrays.asList(new SocialUser[]{child31}));
|
||||
root.addFollowers(Arrays.asList(new SocialUser[]{child1, child2, child3}));
|
||||
sc.setUsers(Arrays.asList(new SocialUser[]{root, child1, child2, child3, child21, child31, child311, child211}));
|
||||
return sc;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void greedyAlgorithmTest() throws Exception {
|
||||
GreedyAlgorithm ga = new GreedyAlgorithm(prepareNetwork());
|
||||
assertEquals(ga.findMostFollowersPath("root"), 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nongreedyAlgorithmTest() throws Exception {
|
||||
NonGreedyAlgorithm nga = new NonGreedyAlgorithm(prepareNetwork(), 0);
|
||||
Assertions.assertThrows(Exception.class, () -> {
|
||||
nga.findMostFollowersPath("root");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nongreedyAlgorithmUnboundedTest() throws Exception {
|
||||
SocialConnector sc = prepareNetwork();
|
||||
sc.switchCounter();
|
||||
NonGreedyAlgorithm nga = new NonGreedyAlgorithm(sc, 0);
|
||||
assertEquals(nga.findMostFollowersPath("root"), 6);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.baeldung.algorithms.integerstreammedian;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class MedianOfIntegerStreamUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenStreamOfIntegers_whenAnElementIsRead_thenMedianChangesWithApproach1() {
|
||||
MedianOfIntegerStream mis = new MedianOfIntegerStream();
|
||||
for (Map.Entry<Integer, Double> e : testcaseFixture().entrySet()) {
|
||||
mis.add(e.getKey());
|
||||
assertEquals(e.getValue(), (Double) mis.getMedian());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStreamOfIntegers_whenAnElementIsRead_thenMedianChangesWithApproach2() {
|
||||
MedianOfIntegerStream2 mis = new MedianOfIntegerStream2();
|
||||
for (Map.Entry<Integer, Double> e : testcaseFixture().entrySet()) {
|
||||
mis.add(e.getKey());
|
||||
assertEquals(e.getValue(), (Double) mis.getMedian());
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Integer, Double> testcaseFixture() {
|
||||
return new LinkedHashMap<Integer, Double>() {{
|
||||
put(1, 1d);
|
||||
put(7, 4d);
|
||||
put(5, 5d);
|
||||
put(8, 6d);
|
||||
put(3, 5d);
|
||||
put(9, 6d);
|
||||
put(4, 5d);
|
||||
}};
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.baeldung.algorithms.kruskal;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import com.google.common.graph.MutableValueGraph;
|
||||
import com.google.common.graph.ValueGraph;
|
||||
import com.google.common.graph.ValueGraphBuilder;
|
||||
import com.baeldung.algorithms.kruskal.Kruskal;
|
||||
|
||||
public class KruskalUnitTest {
|
||||
|
||||
private MutableValueGraph<Integer, Double> graph;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
graph = ValueGraphBuilder.undirected().build();
|
||||
graph.putEdgeValue(0, 1, 8.0);
|
||||
graph.putEdgeValue(0, 2, 5.0);
|
||||
graph.putEdgeValue(1, 2, 9.0);
|
||||
graph.putEdgeValue(1, 3, 11.0);
|
||||
graph.putEdgeValue(2, 3, 15.0);
|
||||
graph.putEdgeValue(2, 4, 10.0);
|
||||
graph.putEdgeValue(3, 4, 7.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGraph_whenMinimumSpanningTree_thenOutputCorrectResult() {
|
||||
final Kruskal kruskal = new Kruskal();
|
||||
ValueGraph<Integer, Double> spanningTree = kruskal.minSpanningTree(graph);
|
||||
|
||||
assertTrue(spanningTree.hasEdgeConnecting(0, 1));
|
||||
assertTrue(spanningTree.hasEdgeConnecting(0, 2));
|
||||
assertTrue(spanningTree.hasEdgeConnecting(2, 4));
|
||||
assertTrue(spanningTree.hasEdgeConnecting(3, 4));
|
||||
assertEquals(graph.edgeValue(0, 1), spanningTree.edgeValue(0, 1));
|
||||
assertEquals(graph.edgeValue(0, 2), spanningTree.edgeValue(0, 2));
|
||||
assertEquals(graph.edgeValue(2, 4), spanningTree.edgeValue(2, 4));
|
||||
assertEquals(graph.edgeValue(3, 4), spanningTree.edgeValue(3, 4));
|
||||
|
||||
assertFalse(spanningTree.hasEdgeConnecting(1, 2));
|
||||
assertFalse(spanningTree.hasEdgeConnecting(1, 3));
|
||||
assertFalse(spanningTree.hasEdgeConnecting(2, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGraph_whenMaximumSpanningTree_thenOutputCorrectResult() {
|
||||
final Kruskal kruskal = new Kruskal();
|
||||
ValueGraph<Integer, Double> spanningTree = kruskal.maxSpanningTree(graph);
|
||||
|
||||
assertTrue(spanningTree.hasEdgeConnecting(0, 1));
|
||||
assertTrue(spanningTree.hasEdgeConnecting(1, 3));
|
||||
assertTrue(spanningTree.hasEdgeConnecting(2, 3));
|
||||
assertTrue(spanningTree.hasEdgeConnecting(2, 4));
|
||||
assertEquals(graph.edgeValue(0, 1), spanningTree.edgeValue(0, 1));
|
||||
assertEquals(graph.edgeValue(1, 3), spanningTree.edgeValue(1, 3));
|
||||
assertEquals(graph.edgeValue(2, 3), spanningTree.edgeValue(2, 3));
|
||||
assertEquals(graph.edgeValue(2, 4), spanningTree.edgeValue(2, 4));
|
||||
|
||||
assertFalse(spanningTree.hasEdgeConnecting(0, 2));
|
||||
assertFalse(spanningTree.hasEdgeConnecting(1, 2));
|
||||
assertFalse(spanningTree.hasEdgeConnecting(3, 4));
|
||||
}
|
||||
}
|
||||
@@ -9,3 +9,4 @@ This module contains articles about searching algorithms.
|
||||
- [Breadth-First Search Algorithm in Java](https://www.baeldung.com/java-breadth-first-search)
|
||||
- [String Search Algorithms for Large Texts](https://www.baeldung.com/java-full-text-search-algorithms)
|
||||
- [Monte Carlo Tree Search for Tic-Tac-Toe Game](https://www.baeldung.com/java-monte-carlo-tree-search)
|
||||
- [Range Search Algorithm in Java](https://www.baeldung.com/java-range-search)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
public class Point {
|
||||
private float x;
|
||||
private float y;
|
||||
|
||||
public Point(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + x + " , " + y + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class QuadTree {
|
||||
private static final int MAX_POINTS = 3;
|
||||
private Region area;
|
||||
private List<Point> points = new ArrayList<>();
|
||||
private List<QuadTree> quadTrees = new ArrayList<>();
|
||||
private StringBuilder searchTraversePath;
|
||||
|
||||
public QuadTree(Region area) {
|
||||
this.area = area;
|
||||
}
|
||||
|
||||
public boolean addPoint(Point point) {
|
||||
if (this.area.containsPoint(point)) {
|
||||
if (this.points.size() < MAX_POINTS) {
|
||||
this.points.add(point);
|
||||
return true;
|
||||
} else {
|
||||
if (this.quadTrees.size() == 0) {
|
||||
createQuadrants();
|
||||
}
|
||||
return addPointToOneQuadrant(point);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean addPointToOneQuadrant(Point point) {
|
||||
boolean isPointAdded;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
isPointAdded = this.quadTrees.get(i)
|
||||
.addPoint(point);
|
||||
if (isPointAdded)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void createQuadrants() {
|
||||
Region region;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
region = this.area.getQuadrant(i);
|
||||
quadTrees.add(new QuadTree(region));
|
||||
}
|
||||
}
|
||||
|
||||
public List<Point> search(Region searchRegion, List<Point> matches, String depthIndicator) {
|
||||
searchTraversePath = new StringBuilder();
|
||||
if (matches == null) {
|
||||
matches = new ArrayList<Point>();
|
||||
searchTraversePath.append(depthIndicator)
|
||||
.append("Search Boundary =")
|
||||
.append(searchRegion)
|
||||
.append("\n");
|
||||
}
|
||||
if (!this.area.doesOverlap(searchRegion)) {
|
||||
return matches;
|
||||
} else {
|
||||
for (Point point : points) {
|
||||
if (searchRegion.containsPoint(point)) {
|
||||
searchTraversePath.append(depthIndicator)
|
||||
.append("Found match " + point)
|
||||
.append("\n");
|
||||
matches.add(point);
|
||||
}
|
||||
}
|
||||
if (this.quadTrees.size() > 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
searchTraversePath.append(depthIndicator)
|
||||
.append("Q")
|
||||
.append(i)
|
||||
.append("-->")
|
||||
.append(quadTrees.get(i).area)
|
||||
.append("\n");
|
||||
quadTrees.get(i)
|
||||
.search(searchRegion, matches, depthIndicator + "\t");
|
||||
this.searchTraversePath.append(quadTrees.get(i)
|
||||
.printSearchTraversePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
public String printTree(String depthIndicator) {
|
||||
String str = "";
|
||||
if (depthIndicator == "") {
|
||||
str += "Root-->" + area.toString() + "\n";
|
||||
}
|
||||
|
||||
for (Point point : points) {
|
||||
str += depthIndicator + point.toString() + "\n";
|
||||
}
|
||||
for (int i = 0; i < quadTrees.size(); i++) {
|
||||
str += depthIndicator + "Q" + String.valueOf(i) + "-->" + quadTrees.get(i).area.toString() + "\n";
|
||||
str += quadTrees.get(i)
|
||||
.printTree(depthIndicator + "\t");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public String printSearchTraversePath() {
|
||||
return searchTraversePath.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
public class Region {
|
||||
private float x1;
|
||||
private float y1;
|
||||
private float x2;
|
||||
private float y2;
|
||||
|
||||
public Region(float x1, float y1, float x2, float y2) {
|
||||
if (x1 >= x2 || y1 >= y2)
|
||||
throw new IllegalArgumentException("(x1,y1) should be lesser than (x2,y2)");
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
}
|
||||
|
||||
public Region getQuadrant(int quadrantIndex) {
|
||||
float quadrantWidth = (this.x2 - this.x1) / 2;
|
||||
float quadrantHeight = (this.y2 - this.y1) / 2;
|
||||
|
||||
// 0=SW, 1=NW, 2=NE, 3=SE
|
||||
switch (quadrantIndex) {
|
||||
case 0:
|
||||
return new Region(x1, y1, x1 + quadrantWidth, y1 + quadrantHeight);
|
||||
case 1:
|
||||
return new Region(x1, y1 + quadrantHeight, x1 + quadrantWidth, y2);
|
||||
case 2:
|
||||
return new Region(x1 + quadrantWidth, y1 + quadrantHeight, x2, y2);
|
||||
case 3:
|
||||
return new Region(x1 + quadrantWidth, y1, x2, y1 + quadrantHeight);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean containsPoint(Point point) {
|
||||
// Consider left and top side to be inclusive for points on border
|
||||
return point.getX() >= this.x1
|
||||
&& point.getX() < this.x2
|
||||
&& point.getY() >= this.y1
|
||||
&& point.getY() < this.y2;
|
||||
}
|
||||
|
||||
public boolean doesOverlap(Region testRegion) {
|
||||
// Is test region completely to left of my region?
|
||||
if (testRegion.getX2() < this.getX1()) {
|
||||
return false;
|
||||
}
|
||||
// Is test region completely to right of my region?
|
||||
if (testRegion.getX1() > this.getX2()) {
|
||||
return false;
|
||||
}
|
||||
// Is test region completely above my region?
|
||||
if (testRegion.getY1() > this.getY2()) {
|
||||
return false;
|
||||
}
|
||||
// Is test region completely below my region?
|
||||
if (testRegion.getY2() < this.getY1()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[Region (x1=" + x1 + ", y1=" + y1 + "), (x2=" + x2 + ", y2=" + y2 + ")]";
|
||||
}
|
||||
|
||||
public float getX1() {
|
||||
return x1;
|
||||
}
|
||||
|
||||
public float getY1() {
|
||||
return y1;
|
||||
}
|
||||
|
||||
public float getX2() {
|
||||
return x2;
|
||||
}
|
||||
|
||||
public float getY2() {
|
||||
return y2;
|
||||
}
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class QuadTreeSearchUnitTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(QuadTreeSearchUnitTest.class);
|
||||
|
||||
private static QuadTree quadTree;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() {
|
||||
Region area = new Region(0, 0, 400, 400);
|
||||
quadTree = new QuadTree(area);
|
||||
|
||||
float[][] points = new float[][] { { 21, 25 }, { 55, 53 }, { 70, 318 }, { 98, 302 },
|
||||
{ 49, 229 }, { 135, 229 }, { 224, 292 }, { 206, 321 }, { 197, 258 }, { 245, 238 } };
|
||||
|
||||
for (int i = 0; i < points.length; i++) {
|
||||
Point point = new Point(points[i][0], points[i][1]);
|
||||
quadTree.addPoint(point);
|
||||
}
|
||||
LOGGER.info("\n" + quadTree.printTree(""));
|
||||
LOGGER.info("==============================================");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenQuadTree_whenSearchingForRange_thenReturn1MatchingItem() {
|
||||
Region searchArea = new Region(200, 200, 250, 250);
|
||||
List<Point> result = quadTree.search(searchArea, null, "");
|
||||
LOGGER.info(result.toString());
|
||||
LOGGER.info(quadTree.printSearchTraversePath());
|
||||
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertArrayEquals(new float[] { 245, 238 },
|
||||
new float[]{result.get(0).getX(), result.get(0).getY() }, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenQuadTree_whenSearchingForRange_thenReturn2MatchingItems() {
|
||||
Region searchArea = new Region(0, 0, 100, 100);
|
||||
List<Point> result = quadTree.search(searchArea, null, "");
|
||||
LOGGER.info(result.toString());
|
||||
LOGGER.info(quadTree.printSearchTraversePath());
|
||||
|
||||
Assert.assertEquals(2, result.size());
|
||||
Assert.assertArrayEquals(new float[] { 21, 25 },
|
||||
new float[]{result.get(0).getX(), result.get(0).getY() }, 0);
|
||||
Assert.assertArrayEquals(new float[] { 55, 53 },
|
||||
new float[]{result.get(1).getX(), result.get(1).getY() }, 0);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
</context-param>
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>org.baeldung.config</param-value>
|
||||
<param-value>com.baeldung.config</param-value>
|
||||
</context-param>
|
||||
|
||||
<listener>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.baeldung.java;
|
||||
package com.baeldung.java;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.baeldung.java;
|
||||
package com.baeldung.java;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.baeldung.examples.olingo2</groupId>
|
||||
<groupId>com.baeldung.examples.olingo2</groupId>
|
||||
<artifactId>olingo2</artifactId>
|
||||
<name>olingo2</name>
|
||||
<description>Sample Olingo 2 Project</description>
|
||||
|
||||
+2
-7
@@ -1,4 +1,4 @@
|
||||
package org.baeldung.examples.olingo2;
|
||||
package com.baeldung.examples.olingo2;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -9,10 +9,8 @@ import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import javax.persistence.FlushModeType;
|
||||
import javax.persistence.LockModeType;
|
||||
import javax.persistence.Persistence;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
import javax.persistence.SynchronizationType;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaDelete;
|
||||
@@ -25,11 +23,8 @@ import org.apache.olingo.odata2.api.processor.ODataContext;
|
||||
import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
|
||||
import org.apache.olingo.odata2.jpa.processor.api.ODataJPAServiceFactory;
|
||||
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
|
||||
import org.baeldung.examples.olingo2.JerseyConfig.EntityManagerFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -58,7 +53,7 @@ public class CarsODataJPAServiceFactory extends ODataJPAServiceFactory {
|
||||
ODataJPAContext ctx = getODataJPAContext();
|
||||
ODataContext octx = ctx.getODataContext();
|
||||
HttpServletRequest request = (HttpServletRequest)octx.getParameter(ODataContext.HTTP_SERVLET_REQUEST_OBJECT);
|
||||
EntityManager em = (EntityManager)request.getAttribute(EntityManagerFilter.EM_REQUEST_ATTRIBUTE);
|
||||
EntityManager em = (EntityManager)request.getAttribute(JerseyConfig.EntityManagerFilter.EM_REQUEST_ATTRIBUTE);
|
||||
|
||||
// Here we're passing the EM that was created by the EntityManagerFilter (see JerseyConfig)
|
||||
ctx.setEntityManager(new EntityManagerWrapper(em));
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
package org.baeldung.examples.olingo2;
|
||||
package com.baeldung.examples.olingo2;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.ApplicationPath;
|
||||
import javax.ws.rs.Path;
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
package org.baeldung.examples.olingo2;
|
||||
package com.baeldung.examples.olingo2;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
@SpringBootApplication
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user