[BAEL-18364] move spring-rest-*** articles - 1

This commit is contained in:
Sjmillington 2019-10-17 17:17:31 +01:00
parent db85c8f275
commit f1673ce653
20415 changed files with 1639515 additions and 0 deletions

87
.gitignore vendored Normal file
View File

@ -0,0 +1,87 @@
*/bin/*
bin/
*.class
# Package Files #
*.jar
*.war
*.ear
# Eclipse
.settings/
*.project
*.classpath
.prefs
*.prefs
.metadata/
# Intellij
.idea/
*.iml
*.iws
out/
# VSCode
.vscode/
# Mac
.DS_Store
# Maven
log/*
target/
# Gradle
.gradle/
spring-openid/src/main/resources/application.properties
.recommenders/
/spring-hibernate4/nbproject/
spring-security-openid/src/main/resources/application.properties
spring-all/*.log
SpringDataInjectionDemo/.mvn/wrapper/maven-wrapper.properties
spring-call-getters-using-reflection/.mvn/wrapper/maven-wrapper.properties
spring-check-if-a-property-is-null/.mvn/wrapper/maven-wrapper.properties
*.springBeans
20171220-JMeter.csv
.factorypath
dependency-reduced-pom.xml
*.so
*.dylib
*.dll
xml/src/test/resources/example_dom4j_new.xml
xml/src/test/resources/example_dom4j_updated.xml
xml/src/test/resources/example_jaxb_new.xml
core-java-io/hard_link.txt
core-java-io/target_link.txt
core-java/src/main/java/com/baeldung/manifest/MANIFEST.MF
ethereum/logs/
jmeter/src/main/resources/*-JMeter.csv
**/node_modules/
**/dist
**/tmp
**/out-tsc
**/nbproject/
**/nb-configuration.xml
core-scala/.cache-main
core-scala/.cache-tests
persistence-modules/hibernate5/transaction.log
apache-avro/src/main/java/com/baeldung/avro/model/
jta/transaction-logs/
software-security/sql-injection-samples/derby.log
spring-soap/src/main/java/com/baeldung/springsoap/gen/
/report-*.json
transaction.log
*-shell.log

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Eugen Paraschiv
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

54
README.md Normal file
View File

@ -0,0 +1,54 @@
The Courses
==============================
Here's the new "Learn Spring" course: <br/>
**[>> LEARN SPRING - THE MASTER CLASS](https://www.baeldung.com/learn-spring-course?utm_source=github&utm_medium=social&utm_content=tutorials&utm_campaign=ls#master-class)**
Here's the Master Class of "REST With Spring" (along with the new announced Boot 2 material): <br/>
**[>> THE REST WITH SPRING - MASTER CLASS](https://www.baeldung.com/rest-with-spring-course?utm_source=github&utm_medium=social&utm_content=tutorials&utm_campaign=rws#master-class)**
And here's the Master Class of "Learn Spring Security": <br/>
**[>> LEARN SPRING SECURITY - MASTER CLASS](https://www.baeldung.com/learn-spring-security-course?utm_source=github&utm_medium=social&utm_content=tutorials&utm_campaign=lss#master-class)**
Java and Spring Tutorials
================
This project is **a collection of small and focused tutorials** - each covering a single and well defined area of development in the Java ecosystem.
A strong focus of these is, of course, the Spring Framework - Spring, Spring Boot and Spring Security.
In additional to Spring, the modules here are covering a number of aspects in Java.
Building the project
====================
To do the full build, do: `mvn clean install`
Building a single module
====================
To build a specific module run the command: `mvn clean install` in the module directory
Running a Spring Boot module
====================
To run a Spring Boot module run the command: `mvn spring-boot:run` in the module directory
Working with the IDE
====================
This repo contains a large number of modules.
When you're working with an individual module, there's no need to import all of them (or build all of them) - you can simply import that particular module in either Eclipse or IntelliJ.
Running Tests
=============
The command `mvn clean install` will run the unit tests in a module.
To run the integration tests, use the command `mvn clean install -Pintegration-lite-first`

3
akka-http/README.md Normal file
View File

@ -0,0 +1,3 @@
## Relevant articles:
- [Introduction to Akka HTTP](https://www.baeldung.com/akka-http)

47
akka-http/pom.xml Normal file
View File

@ -0,0 +1,47 @@
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<artifactId>akka-http</artifactId>
<name>akka-http</name>
<parent>
<artifactId>parent-modules</artifactId>
<groupId>com.baeldung</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-http_2.12</artifactId>
<version>${akka.http.version}</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-stream_2.12</artifactId>
<version>${akka.stream.version}</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-http-jackson_2.12</artifactId>
<version>${akka.http.version}</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-http-testkit_2.12</artifactId>
<version>${akka.http.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<akka.http.version>10.0.11</akka.http.version>
<akka.stream.version>2.5.11</akka.stream.version>
</properties>
</project>

View File

@ -0,0 +1,26 @@
package com.baeldung.akkahttp;
public class User {
private final Long id;
private final String name;
public User() {
this.name = "";
this.id = null;
}
public User(Long id, String name) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public Long getId() {
return id;
}
}

View File

@ -0,0 +1,41 @@
package com.baeldung.akkahttp;
import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.japi.pf.FI;
import com.baeldung.akkahttp.UserMessages.ActionPerformed;
import com.baeldung.akkahttp.UserMessages.CreateUserMessage;
import com.baeldung.akkahttp.UserMessages.GetUserMessage;
class UserActor extends AbstractActor {
private UserService userService = new UserService();
static Props props() {
return Props.create(UserActor.class);
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(CreateUserMessage.class, handleCreateUser())
.match(GetUserMessage.class, handleGetUser())
.build();
}
private FI.UnitApply<CreateUserMessage> handleCreateUser() {
return createUserMessageMessage -> {
userService.createUser(createUserMessageMessage.getUser());
sender().tell(new ActionPerformed(String.format("User %s created.", createUserMessageMessage.getUser()
.getName())), getSelf());
};
}
private FI.UnitApply<GetUserMessage> handleGetUser() {
return getUserMessageMessage -> {
sender().tell(userService.getUser(getUserMessageMessage.getUserId()), getSelf());
};
}
}

View File

@ -0,0 +1,49 @@
package com.baeldung.akkahttp;
import java.io.Serializable;
public interface UserMessages {
class ActionPerformed implements Serializable {
private static final long serialVersionUID = 1L;
private final String description;
public ActionPerformed(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
class CreateUserMessage implements Serializable {
private static final long serialVersionUID = 1L;
private final User user;
public CreateUserMessage(User user) {
this.user = user;
}
public User getUser() {
return user;
}
}
class GetUserMessage implements Serializable {
private static final long serialVersionUID = 1L;
private final Long userId;
public GetUserMessage(Long userId) {
this.userId = userId;
}
public Long getUserId() {
return userId;
}
}
}

View File

@ -0,0 +1,70 @@
package com.baeldung.akkahttp;
import java.util.Optional;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.http.javadsl.marshallers.jackson.Jackson;
import akka.http.javadsl.model.StatusCodes;
import akka.http.javadsl.server.HttpApp;
import akka.http.javadsl.server.Route;
import akka.pattern.PatternsCS;
import akka.util.Timeout;
import com.baeldung.akkahttp.UserMessages.ActionPerformed;
import com.baeldung.akkahttp.UserMessages.CreateUserMessage;
import com.baeldung.akkahttp.UserMessages.GetUserMessage;
import scala.concurrent.duration.Duration;
import static akka.http.javadsl.server.PathMatchers.*;
class UserServer extends HttpApp {
private final ActorRef userActor;
Timeout timeout = new Timeout(Duration.create(5, TimeUnit.SECONDS));
UserServer(ActorRef userActor) {
this.userActor = userActor;
}
@Override
public Route routes() {
return path("users", this::postUser)
.orElse(path(segment("users").slash(longSegment()), id ->
route(getUser(id))));
}
private Route getUser(Long id) {
return get(() -> {
CompletionStage<Optional<User>> user = PatternsCS.ask(userActor, new GetUserMessage(id), timeout)
.thenApply(obj -> (Optional<User>) obj);
return onSuccess(() -> user, performed -> {
if (performed.isPresent())
return complete(StatusCodes.OK, performed.get(), Jackson.marshaller());
else
return complete(StatusCodes.NOT_FOUND);
});
});
}
private Route postUser() {
return route(post(() -> entity(Jackson.unmarshaller(User.class), user -> {
CompletionStage<ActionPerformed> userCreated = PatternsCS.ask(userActor, new CreateUserMessage(user), timeout)
.thenApply(obj -> (ActionPerformed) obj);
return onSuccess(() -> userCreated, performed -> {
return complete(StatusCodes.CREATED, performed, Jackson.marshaller());
});
})));
}
public static void main(String[] args) throws Exception {
ActorSystem system = ActorSystem.create("userServer");
ActorRef userActor = system.actorOf(UserActor.props(), "userActor");
UserServer server = new UserServer(userActor);
server.startServer("localhost", 8080, system);
}
}

View File

@ -0,0 +1,35 @@
package com.baeldung.akkahttp;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class UserService {
private final static List<User> users = new ArrayList<>();
static {
users.add(new User(1l, "Alice"));
users.add(new User(2l, "Bob"));
users.add(new User(3l, "Chris"));
users.add(new User(4l, "Dick"));
users.add(new User(5l, "Eve"));
users.add(new User(6l, "Finn"));
}
public Optional<User> getUser(Long id) {
return users.stream()
.filter(user -> user.getId()
.equals(id))
.findFirst();
}
public void createUser(User user) {
users.add(user);
}
public List<User> getUsers(){
return users;
}
}

View File

@ -0,0 +1,50 @@
package com.baeldung.akkahttp;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.http.javadsl.model.ContentTypes;
import akka.http.javadsl.model.HttpEntities;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.testkit.JUnitRouteTest;
import akka.http.javadsl.testkit.TestRoute;
import org.junit.Test;
public class UserServerUnitTest extends JUnitRouteTest {
ActorSystem system = ActorSystem.create("helloAkkaHttpServer");
ActorRef userActorRef = system.actorOf(UserActor.props(), "userActor");
TestRoute appRoute = testRoute(new UserServer(userActorRef).routes());
@Test
public void whenRequest_thenActorResponds() {
appRoute.run(HttpRequest.GET("/users/1"))
.assertEntity(alice())
.assertStatusCode(200);
appRoute.run(HttpRequest.GET("/users/42"))
.assertStatusCode(404);
appRoute.run(HttpRequest.DELETE("/users/1"))
.assertStatusCode(200);
appRoute.run(HttpRequest.DELETE("/users/42"))
.assertStatusCode(200);
appRoute.run(HttpRequest.POST("/users")
.withEntity(HttpEntities.create(ContentTypes.APPLICATION_JSON, zaphod())))
.assertStatusCode(201);
}
private String alice() {
return "{\"id\":1,\"name\":\"Alice\"}";
}
private String zaphod() {
return "{\"id\":42,\"name\":\"Zaphod\"}";
}
}

3
akka-streams/README.md Normal file
View File

@ -0,0 +1,3 @@
### Relevant articles
- [Guide to Akka Streams](https://www.baeldung.com/akka-streams)

32
akka-streams/pom.xml Normal file
View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 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>
<artifactId>akka-streams</artifactId>
<name>akka-streams</name>
<parent>
<artifactId>parent-modules</artifactId>
<groupId>com.baeldung</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-stream_${scala.version}</artifactId>
<version>${akkastreams.version}</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-stream-testkit_${scala.version}</artifactId>
<version>${akkastreams.version}</version>
</dependency>
</dependencies>
<properties>
<akkastreams.version>2.5.2</akkastreams.version>
<scala.version>2.11</scala.version>
</properties>
</project>

View File

@ -0,0 +1,14 @@
package com.baeldung.akkastreams;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
public class AverageRepository {
CompletionStage<Double> save(Double average) {
return CompletableFuture.supplyAsync(() -> {
System.out.println("saving average: " + average);
return average;
});
}
}

View File

@ -0,0 +1,74 @@
package com.baeldung.akkastreams;
import akka.Done;
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.stream.ActorMaterializer;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Keep;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;
public class DataImporter {
private final ActorSystem actorSystem;
private final AverageRepository averageRepository = new AverageRepository();
public DataImporter(ActorSystem actorSystem) {
this.actorSystem = actorSystem;
}
private List<Integer> parseLine(String line) {
String[] fields = line.split(";");
return Arrays.stream(fields)
.map(Integer::parseInt)
.collect(Collectors.toList());
}
private Flow<String, Integer, NotUsed> parseContent() {
return Flow.of(String.class).mapConcat(this::parseLine);
}
private Flow<Integer, Double, NotUsed> computeAverage() {
return Flow.of(Integer.class).grouped(2).mapAsyncUnordered(8, integers ->
CompletableFuture.supplyAsync(() -> integers
.stream()
.mapToDouble(v -> v)
.average()
.orElse(-1.0)));
}
Flow<String, Double, NotUsed> calculateAverage() {
return Flow.of(String.class)
.via(parseContent())
.via(computeAverage());
}
private Sink<Double, CompletionStage<Done>> storeAverages() {
return Flow.of(Double.class)
.mapAsyncUnordered(4, averageRepository::save)
.toMat(Sink.ignore(), Keep.right());
}
CompletionStage<Done> calculateAverageForContent(String content) {
return Source.single(content)
.via(calculateAverage())
.runWith(storeAverages(), ActorMaterializer.create(actorSystem))
.whenComplete((d, e) -> {
if (d != null) {
System.out.println("Import finished ");
} else {
e.printStackTrace();
}
});
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,43 @@
package com.baeldung.akkastreams;
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.stream.ActorMaterializer;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Source;
import akka.stream.testkit.javadsl.TestSink;
import org.junit.Test;
public class DataImporterUnitTest {
private final ActorSystem actorSystem = ActorSystem.create();
@Test
public void givenStreamOfIntegers_whenCalculateAverageOfPairs_thenShouldReturnProperResults() {
//given
Flow<String, Double, NotUsed> tested = new DataImporter(actorSystem).calculateAverage();
String input = "1;9;11;0";
//when
Source<Double, NotUsed> flow = Source.single(input).via(tested);
//then
flow
.runWith(TestSink.probe(actorSystem), ActorMaterializer.create(actorSystem))
.request(4)
.expectNextUnordered(5d, 5.5);
}
@Test
public void givenStreamOfIntegers_whenCalculateAverageAndSaveToSink_thenShouldFinishSuccessfully() {
//given
DataImporter dataImporter = new DataImporter(actorSystem);
String input = "10;90;110;10";
//when
dataImporter.calculateAverageForContent(input)
.thenAccept(d -> actorSystem.terminate());
}
}

4
algorithms-genetic/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/target/
.settings/
.classpath
.project

View File

@ -0,0 +1,6 @@
## Relevant articles:
- [Introduction to Jenetics Library](https://www.baeldung.com/jenetics)
- [Ant Colony Optimization](https://www.baeldung.com/java-ant-colony-optimization)
- [Design a Genetic Algorithm in Java](https://www.baeldung.com/java-genetic-algorithm)
- [The Traveling Salesman Problem in Java](https://www.baeldung.com/java-simulated-annealing-for-traveling-salesman)

View File

@ -0,0 +1,64 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" 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>
<artifactId>algorithms-genetic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>algorithms-genetic</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>${commons-math3.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.jenetics</groupId>
<artifactId>jenetics</artifactId>
<version>${io.jenetics.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${org.assertj.core.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec-maven-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<properties>
<commons-math3.version>3.6.1</commons-math3.version>
<io.jenetics.version>3.7.0</io.jenetics.version>
<org.assertj.core.version>3.9.0</org.assertj.core.version>
<commons-codec.version>1.11</commons-codec.version>
</properties>
</project>

View File

@ -0,0 +1,38 @@
package com.baeldung.algorithms;
import java.util.Scanner;
import com.baeldung.algorithms.ga.annealing.SimulatedAnnealing;
import com.baeldung.algorithms.ga.ant_colony.AntColonyOptimization;
import com.baeldung.algorithms.ga.binary.SimpleGeneticAlgorithm;
public class RunAlgorithm {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Scanner in = new Scanner(System.in);
System.out.println("Run algorithm:");
System.out.println("1 - Simulated Annealing");
System.out.println("2 - Simple Genetic Algorithm");
System.out.println("3 - Ant Colony");
int decision = in.nextInt();
switch (decision) {
case 1:
System.out.println(
"Optimized distance for travel: " + SimulatedAnnealing.simulateAnnealing(10, 10000, 0.9995));
break;
case 2:
SimpleGeneticAlgorithm ga = new SimpleGeneticAlgorithm();
ga.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111");
break;
case 3:
AntColonyOptimization antColony = new AntColonyOptimization(21);
antColony.startAntOptimization();
break;
default:
System.out.println("Unknown option");
break;
}
in.close();
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.algorithms.ga.annealing;
import lombok.Data;
@Data
public class City {
private int x;
private int y;
public City() {
this.x = (int) (Math.random() * 500);
this.y = (int) (Math.random() * 500);
}
public double distanceToCity(City city) {
int x = Math.abs(getX() - city.getX());
int y = Math.abs(getY() - city.getY());
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
}
}

View File

@ -0,0 +1,36 @@
package com.baeldung.algorithms.ga.annealing;
public class SimulatedAnnealing {
private static Travel travel = new Travel(10);
public static double simulateAnnealing(double startingTemperature, int numberOfIterations, double coolingRate) {
System.out.println("Starting SA with temperature: " + startingTemperature + ", # of iterations: " + numberOfIterations + " and colling rate: " + coolingRate);
double t = startingTemperature;
travel.generateInitialTravel();
double bestDistance = travel.getDistance();
System.out.println("Initial distance of travel: " + bestDistance);
Travel bestSolution = travel;
Travel currentSolution = bestSolution;
for (int i = 0; i < numberOfIterations; i++) {
if (t > 0.1) {
currentSolution.swapCities();
double currentDistance = currentSolution.getDistance();
if (currentDistance < bestDistance) {
bestDistance = currentDistance;
} else if (Math.exp((bestDistance - currentDistance) / t) < Math.random()) {
currentSolution.revertSwap();
}
t *= coolingRate;
} else {
continue;
}
if (i % 100 == 0) {
System.out.println("Iteration #" + i);
}
}
return bestDistance;
}
}

View File

@ -0,0 +1,63 @@
package com.baeldung.algorithms.ga.annealing;
import java.util.ArrayList;
import java.util.Collections;
import lombok.Data;
@Data
public class Travel {
private ArrayList<City> travel = new ArrayList<>();
private ArrayList<City> previousTravel = new ArrayList<>();
public Travel(int numberOfCities) {
for (int i = 0; i < numberOfCities; i++) {
travel.add(new City());
}
}
public void generateInitialTravel() {
if (travel.isEmpty())
new Travel(10);
Collections.shuffle(travel);
}
public void swapCities() {
int a = generateRandomIndex();
int b = generateRandomIndex();
previousTravel = travel;
City x = travel.get(a);
City y = travel.get(b);
travel.set(a, y);
travel.set(b, x);
}
public void revertSwap() {
travel = previousTravel;
}
private int generateRandomIndex() {
return (int) (Math.random() * travel.size());
}
public City getCity(int index) {
return travel.get(index);
}
public int getDistance() {
int distance = 0;
for (int index = 0; index < travel.size(); index++) {
City starting = getCity(index);
City destination;
if (index + 1 < travel.size()) {
destination = getCity(index + 1);
} else {
destination = getCity(0);
}
distance += starting.distanceToCity(destination);
}
return distance;
}
}

View File

@ -0,0 +1,37 @@
package com.baeldung.algorithms.ga.ant_colony;
public class Ant {
protected int trailSize;
protected int trail[];
protected boolean visited[];
public Ant(int tourSize) {
this.trailSize = tourSize;
this.trail = new int[tourSize];
this.visited = new boolean[tourSize];
}
protected void visitCity(int currentIndex, int city) {
trail[currentIndex + 1] = city;
visited[city] = true;
}
protected boolean visited(int i) {
return visited[i];
}
protected double trailLength(double graph[][]) {
double length = graph[trail[trailSize - 1]][trail[0]];
for (int i = 0; i < trailSize - 1; i++) {
length += graph[trail[i]][trail[i + 1]];
}
return length;
}
protected void clear() {
for (int i = 0; i < trailSize; i++)
visited[i] = false;
}
}

View File

@ -0,0 +1,203 @@
package com.baeldung.algorithms.ga.ant_colony;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.OptionalInt;
import java.util.Random;
import java.util.stream.IntStream;
public class AntColonyOptimization {
private double c = 1.0;
private double alpha = 1;
private double beta = 5;
private double evaporation = 0.5;
private double Q = 500;
private double antFactor = 0.8;
private double randomFactor = 0.01;
private int maxIterations = 1000;
private int numberOfCities;
private int numberOfAnts;
private double graph[][];
private double trails[][];
private List<Ant> ants = new ArrayList<>();
private Random random = new Random();
private double probabilities[];
private int currentIndex;
private int[] bestTourOrder;
private double bestTourLength;
public AntColonyOptimization(int noOfCities) {
graph = generateRandomMatrix(noOfCities);
numberOfCities = graph.length;
numberOfAnts = (int) (numberOfCities * antFactor);
trails = new double[numberOfCities][numberOfCities];
probabilities = new double[numberOfCities];
IntStream.range(0, numberOfAnts)
.forEach(i -> ants.add(new Ant(numberOfCities)));
}
/**
* Generate initial solution
*/
public double[][] generateRandomMatrix(int n) {
double[][] randomMatrix = new double[n][n];
IntStream.range(0, n)
.forEach(i -> IntStream.range(0, n)
.forEach(j -> randomMatrix[i][j] = Math.abs(random.nextInt(100) + 1)));
return randomMatrix;
}
/**
* Perform ant optimization
*/
public void startAntOptimization() {
IntStream.rangeClosed(1, 3)
.forEach(i -> {
System.out.println("Attempt #" + i);
solve();
});
}
/**
* Use this method to run the main logic
*/
public int[] solve() {
setupAnts();
clearTrails();
IntStream.range(0, maxIterations)
.forEach(i -> {
moveAnts();
updateTrails();
updateBest();
});
System.out.println("Best tour length: " + (bestTourLength - numberOfCities));
System.out.println("Best tour order: " + Arrays.toString(bestTourOrder));
return bestTourOrder.clone();
}
/**
* Prepare ants for the simulation
*/
private void setupAnts() {
IntStream.range(0, numberOfAnts)
.forEach(i -> {
ants.forEach(ant -> {
ant.clear();
ant.visitCity(-1, random.nextInt(numberOfCities));
});
});
currentIndex = 0;
}
/**
* At each iteration, move ants
*/
private void moveAnts() {
IntStream.range(currentIndex, numberOfCities - 1)
.forEach(i -> {
ants.forEach(ant -> ant.visitCity(currentIndex, selectNextCity(ant)));
currentIndex++;
});
}
/**
* Select next city for each ant
*/
private int selectNextCity(Ant ant) {
int t = random.nextInt(numberOfCities - currentIndex);
if (random.nextDouble() < randomFactor) {
OptionalInt cityIndex = IntStream.range(0, numberOfCities)
.filter(i -> i == t && !ant.visited(i))
.findFirst();
if (cityIndex.isPresent()) {
return cityIndex.getAsInt();
}
}
calculateProbabilities(ant);
double r = random.nextDouble();
double total = 0;
for (int i = 0; i < numberOfCities; i++) {
total += probabilities[i];
if (total >= r) {
return i;
}
}
throw new RuntimeException("There are no other cities");
}
/**
* Calculate the next city picks probabilites
*/
public void calculateProbabilities(Ant ant) {
int i = ant.trail[currentIndex];
double pheromone = 0.0;
for (int l = 0; l < numberOfCities; l++) {
if (!ant.visited(l)) {
pheromone += Math.pow(trails[i][l], alpha) * Math.pow(1.0 / graph[i][l], beta);
}
}
for (int j = 0; j < numberOfCities; j++) {
if (ant.visited(j)) {
probabilities[j] = 0.0;
} else {
double numerator = Math.pow(trails[i][j], alpha) * Math.pow(1.0 / graph[i][j], beta);
probabilities[j] = numerator / pheromone;
}
}
}
/**
* Update trails that ants used
*/
private void updateTrails() {
for (int i = 0; i < numberOfCities; i++) {
for (int j = 0; j < numberOfCities; j++) {
trails[i][j] *= evaporation;
}
}
for (Ant a : ants) {
double contribution = Q / a.trailLength(graph);
for (int i = 0; i < numberOfCities - 1; i++) {
trails[a.trail[i]][a.trail[i + 1]] += contribution;
}
trails[a.trail[numberOfCities - 1]][a.trail[0]] += contribution;
}
}
/**
* Update the best solution
*/
private void updateBest() {
if (bestTourOrder == null) {
bestTourOrder = ants.get(0).trail;
bestTourLength = ants.get(0)
.trailLength(graph);
}
for (Ant a : ants) {
if (a.trailLength(graph) < bestTourLength) {
bestTourLength = a.trailLength(graph);
bestTourOrder = a.trail.clone();
}
}
}
/**
* Clear trails after simulation
*/
private void clearTrails() {
IntStream.range(0, numberOfCities)
.forEach(i -> {
IntStream.range(0, numberOfCities)
.forEach(j -> trails[i][j] = c);
});
}
}

View File

@ -0,0 +1,44 @@
package com.baeldung.algorithms.ga.binary;
import lombok.Data;
@Data
public class Individual {
protected int defaultGeneLength = 64;
private byte[] genes = new byte[defaultGeneLength];
private int fitness = 0;
public Individual() {
for (int i = 0; i < genes.length; i++) {
byte gene = (byte) Math.round(Math.random());
genes[i] = gene;
}
}
protected byte getSingleGene(int index) {
return genes[index];
}
protected void setSingleGene(int index, byte value) {
genes[index] = value;
fitness = 0;
}
public int getFitness() {
if (fitness == 0) {
fitness = SimpleGeneticAlgorithm.getFitness(this);
}
return fitness;
}
@Override
public String toString() {
String geneString = "";
for (int i = 0; i < genes.length; i++) {
geneString += getSingleGene(i);
}
return geneString;
}
}

View File

@ -0,0 +1,40 @@
package com.baeldung.algorithms.ga.binary;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
@Data
public class Population {
private List<Individual> individuals;
public Population(int size, boolean createNew) {
individuals = new ArrayList<>();
if (createNew) {
createNewPopulation(size);
}
}
protected Individual getIndividual(int index) {
return individuals.get(index);
}
protected Individual getFittest() {
Individual fittest = individuals.get(0);
for (int i = 0; i < individuals.size(); i++) {
if (fittest.getFitness() <= getIndividual(i).getFitness()) {
fittest = getIndividual(i);
}
}
return fittest;
}
private void createNewPopulation(int size) {
for (int i = 0; i < size; i++) {
Individual newIndividual = new Individual();
individuals.add(i, newIndividual);
}
}
}

View File

@ -0,0 +1,117 @@
package com.baeldung.algorithms.ga.binary;
import lombok.Data;
@Data
public class SimpleGeneticAlgorithm {
private static final double uniformRate = 0.5;
private static final double mutationRate = 0.025;
private static final int tournamentSize = 5;
private static final boolean elitism = true;
private static byte[] solution = new byte[64];
public boolean runAlgorithm(int populationSize, String solution) {
if (solution.length() != SimpleGeneticAlgorithm.solution.length) {
throw new RuntimeException("The solution needs to have " + SimpleGeneticAlgorithm.solution.length + " bytes");
}
setSolution(solution);
Population myPop = new Population(populationSize, true);
int generationCount = 1;
while (myPop.getFittest().getFitness() < getMaxFitness()) {
System.out.println("Generation: " + generationCount + " Correct genes found: " + myPop.getFittest().getFitness());
myPop = evolvePopulation(myPop);
generationCount++;
}
System.out.println("Solution found!");
System.out.println("Generation: " + generationCount);
System.out.println("Genes: ");
System.out.println(myPop.getFittest());
return true;
}
public Population evolvePopulation(Population pop) {
int elitismOffset;
Population newPopulation = new Population(pop.getIndividuals().size(), false);
if (elitism) {
newPopulation.getIndividuals().add(0, pop.getFittest());
elitismOffset = 1;
} else {
elitismOffset = 0;
}
for (int i = elitismOffset; i < pop.getIndividuals().size(); i++) {
Individual indiv1 = tournamentSelection(pop);
Individual indiv2 = tournamentSelection(pop);
Individual newIndiv = crossover(indiv1, indiv2);
newPopulation.getIndividuals().add(i, newIndiv);
}
for (int i = elitismOffset; i < newPopulation.getIndividuals().size(); i++) {
mutate(newPopulation.getIndividual(i));
}
return newPopulation;
}
private Individual crossover(Individual indiv1, Individual indiv2) {
Individual newSol = new Individual();
for (int i = 0; i < newSol.getDefaultGeneLength(); i++) {
if (Math.random() <= uniformRate) {
newSol.setSingleGene(i, indiv1.getSingleGene(i));
} else {
newSol.setSingleGene(i, indiv2.getSingleGene(i));
}
}
return newSol;
}
private void mutate(Individual indiv) {
for (int i = 0; i < indiv.getDefaultGeneLength(); i++) {
if (Math.random() <= mutationRate) {
byte gene = (byte) Math.round(Math.random());
indiv.setSingleGene(i, gene);
}
}
}
private Individual tournamentSelection(Population pop) {
Population tournament = new Population(tournamentSize, false);
for (int i = 0; i < tournamentSize; i++) {
int randomId = (int) (Math.random() * pop.getIndividuals().size());
tournament.getIndividuals().add(i, pop.getIndividual(randomId));
}
Individual fittest = tournament.getFittest();
return fittest;
}
protected static int getFitness(Individual individual) {
int fitness = 0;
for (int i = 0; i < individual.getDefaultGeneLength() && i < solution.length; i++) {
if (individual.getSingleGene(i) == solution[i]) {
fitness++;
}
}
return fitness;
}
protected int getMaxFitness() {
int maxFitness = solution.length;
return maxFitness;
}
protected void setSolution(String newSolution) {
solution = new byte[newSolution.length()];
for (int i = 0; i < newSolution.length(); i++) {
String character = newSolution.substring(i, i + 1);
if (character.contains("0") || character.contains("1")) {
solution[i] = Byte.parseByte(character);
} else {
solution[i] = 0;
}
}
}
}

View File

@ -0,0 +1,47 @@
package com.baeldung.algorithms.ga.jenetics;
import static org.jenetics.engine.EvolutionResult.toBestPhenotype;
import static org.jenetics.engine.limit.bySteadyFitness;
import java.util.stream.Stream;
import org.jenetics.BitChromosome;
import org.jenetics.BitGene;
import org.jenetics.Mutator;
import org.jenetics.Phenotype;
import org.jenetics.RouletteWheelSelector;
import org.jenetics.SinglePointCrossover;
import org.jenetics.TournamentSelector;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionStatistics;
//The main class.
public class Knapsack {
public static void main(String[] args) {
int nItems = 15;
double ksSize = nItems * 100.0 / 3.0;
KnapsackFF ff = new KnapsackFF(Stream.generate(KnapsackItem::random)
.limit(nItems)
.toArray(KnapsackItem[]::new), ksSize);
Engine<BitGene, Double> engine = Engine.builder(ff, BitChromosome.of(nItems, 0.5))
.populationSize(500)
.survivorsSelector(new TournamentSelector<>(5))
.offspringSelector(new RouletteWheelSelector<>())
.alterers(new Mutator<>(0.115), new SinglePointCrossover<>(0.16))
.build();
EvolutionStatistics<Double, ?> statistics = EvolutionStatistics.ofNumber();
Phenotype<BitGene, Double> best = engine.stream()
.limit(bySteadyFitness(7))
.limit(100)
.peek(statistics)
.collect(toBestPhenotype());
System.out.println(statistics);
System.out.println(best);
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.algorithms.ga.jenetics;
import java.util.function.Function;
import org.jenetics.BitChromosome;
import org.jenetics.BitGene;
import org.jenetics.Genotype;
public class KnapsackFF implements Function<Genotype<BitGene>, Double> {
private KnapsackItem[] items;
private double size;
public KnapsackFF(KnapsackItem[] items, double size) {
this.items = items;
this.size = size;
}
@Override
public Double apply(Genotype<BitGene> gt) {
KnapsackItem sum = ((BitChromosome) gt.getChromosome()).ones()
.mapToObj(i -> items[i])
.collect(KnapsackItem.toSum());
return sum.size <= this.size ? sum.value : 0;
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.algorithms.ga.jenetics;
import java.util.Random;
import java.util.stream.Collector;
import org.jenetics.util.RandomRegistry;
public class KnapsackItem {
public double size;
public double value;
public KnapsackItem(double size, double value) {
this.size = size;
this.value = value;
}
protected static KnapsackItem random() {
Random r = RandomRegistry.getRandom();
return new KnapsackItem(r.nextDouble() * 100, r.nextDouble() * 100);
}
protected static Collector<KnapsackItem, ?, KnapsackItem> toSum() {
return Collector.of(() -> new double[2], (a, b) -> {
a[0] += b.size;
a[1] += b.value;
} , (a, b) -> {
a[0] += b[0];
a[1] += b[1];
return a;
} , r -> new KnapsackItem(r[0], r[1]));
}
}

View File

@ -0,0 +1,33 @@
package com.baeldung.algorithms.ga.jenetics;
import org.jenetics.BitChromosome;
import org.jenetics.BitGene;
import org.jenetics.Genotype;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionResult;
import org.jenetics.util.Factory;
public class SimpleGeneticAlgorithm {
private static Integer eval(Genotype<BitGene> gt) {
return gt.getChromosome()
.as(BitChromosome.class)
.bitCount();
}
public static void main(String[] args) {
Factory<Genotype<BitGene>> gtf = Genotype.of(BitChromosome.of(10, 0.5));
System.out.println("Before the evolution:\n" + gtf);
Engine<BitGene, Integer> engine = Engine.builder(SimpleGeneticAlgorithm::eval, gtf)
.build();
Genotype<BitGene> result = engine.stream()
.limit(500)
.collect(EvolutionResult.toBestGenotype());
System.out.println("After the evolution:\n" + result);
}
}

View File

@ -0,0 +1,86 @@
package com.baeldung.algorithms.ga.jenetics;
import static java.util.Objects.requireNonNull;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.jenetics.BitGene;
import org.jenetics.engine.Codec;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionResult;
import org.jenetics.engine.Problem;
import org.jenetics.engine.codecs;
import org.jenetics.util.ISeq;
public class SpringsteenProblem implements Problem<ISeq<SpringsteenRecord>, BitGene, Double> {
private ISeq<SpringsteenRecord> records;
private double maxPricePerUniqueSong;
public SpringsteenProblem(ISeq<SpringsteenRecord> records, double maxPricePerUniqueSong) {
this.records = requireNonNull(records);
this.maxPricePerUniqueSong = maxPricePerUniqueSong;
}
@Override
public Function<ISeq<SpringsteenRecord>, Double> fitness() {
return SpringsteenRecords -> {
double cost = SpringsteenRecords.stream()
.mapToDouble(r -> r.price)
.sum();
int uniqueSongCount = SpringsteenRecords.stream()
.flatMap(r -> r.songs.stream())
.collect(Collectors.toSet())
.size();
double pricePerUniqueSong = cost / uniqueSongCount;
return pricePerUniqueSong <= maxPricePerUniqueSong ? uniqueSongCount : 0.0;
};
}
@Override
public Codec<ISeq<SpringsteenRecord>, BitGene> codec() {
return codecs.ofSubSet(records);
}
public static void main(String[] args) {
double maxPricePerUniqueSong = 2.5;
SpringsteenProblem springsteen = new SpringsteenProblem(
ISeq.of(new SpringsteenRecord("SpringsteenRecord1", 25, ISeq.of("Song1", "Song2", "Song3", "Song4", "Song5", "Song6")), new SpringsteenRecord("SpringsteenRecord2", 15, ISeq.of("Song2", "Song3", "Song4", "Song5", "Song6", "Song7")),
new SpringsteenRecord("SpringsteenRecord3", 35, ISeq.of("Song5", "Song6", "Song7", "Song8", "Song9", "Song10")), new SpringsteenRecord("SpringsteenRecord4", 17, ISeq.of("Song9", "Song10", "Song12", "Song4", "Song13", "Song14")),
new SpringsteenRecord("SpringsteenRecord5", 29, ISeq.of("Song1", "Song2", "Song13", "Song14", "Song15", "Song16")), new SpringsteenRecord("SpringsteenRecord6", 5, ISeq.of("Song18", "Song20", "Song30", "Song40"))),
maxPricePerUniqueSong);
Engine<BitGene, Double> engine = Engine.builder(springsteen)
.build();
ISeq<SpringsteenRecord> result = springsteen.codec()
.decoder()
.apply(engine.stream()
.limit(10)
.collect(EvolutionResult.toBestGenotype()));
double cost = result.stream()
.mapToDouble(r -> r.price)
.sum();
int uniqueSongCount = result.stream()
.flatMap(r -> r.songs.stream())
.collect(Collectors.toSet())
.size();
double pricePerUniqueSong = cost / uniqueSongCount;
System.out.println("Overall cost: " + cost);
System.out.println("Unique songs: " + uniqueSongCount);
System.out.println("Cost per song: " + pricePerUniqueSong);
System.out.println("Records: " + result.map(r -> r.name)
.toString(", "));
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.algorithms.ga.jenetics;
import static java.util.Objects.requireNonNull;
import org.jenetics.util.ISeq;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class SpringsteenRecord {
String name;
double price;
ISeq<String> songs;
public SpringsteenRecord(String name, double price, ISeq<String> songs) {
this.name = requireNonNull(name);
this.price = price;
this.songs = requireNonNull(songs);
}
}

View File

@ -0,0 +1,66 @@
package com.baeldung.algorithms.ga.jenetics;
import static java.util.Objects.requireNonNull;
import java.util.Random;
import java.util.function.Function;
import org.jenetics.EnumGene;
import org.jenetics.Mutator;
import org.jenetics.PartiallyMatchedCrossover;
import org.jenetics.Phenotype;
import org.jenetics.engine.Codec;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionResult;
import org.jenetics.engine.Problem;
import org.jenetics.engine.codecs;
import org.jenetics.engine.limit;
import org.jenetics.util.ISeq;
import org.jenetics.util.LCG64ShiftRandom;
public class SubsetSum implements Problem<ISeq<Integer>, EnumGene<Integer>, Integer> {
private ISeq<Integer> basicSet;
private int size;
public SubsetSum(ISeq<Integer> basicSet, int size) {
this.basicSet = requireNonNull(basicSet);
this.size = size;
}
@Override
public Function<ISeq<Integer>, Integer> fitness() {
return subset -> Math.abs(subset.stream()
.mapToInt(Integer::intValue)
.sum());
}
@Override
public Codec<ISeq<Integer>, EnumGene<Integer>> codec() {
return codecs.ofSubSet(basicSet, size);
}
public static SubsetSum of(int n, int k, Random random) {
return new SubsetSum(random.doubles()
.limit(n)
.mapToObj(d -> (int) ((d - 0.5) * n))
.collect(ISeq.toISeq()), k);
}
public static void main(String[] args) {
SubsetSum problem = of(500, 15, new LCG64ShiftRandom(101010));
Engine<EnumGene<Integer>, Integer> engine = Engine.builder(problem)
.minimizing()
.maximalPhenotypeAge(5)
.alterers(new PartiallyMatchedCrossover<>(0.4), new Mutator<>(0.3))
.build();
Phenotype<EnumGene<Integer>, Integer> result = engine.stream()
.limit(limit.bySteadyFitness(55))
.collect(EvolutionResult.toBestPhenotype());
System.out.print(result);
}
}

View File

@ -0,0 +1,67 @@
package com.baeldung.algorithms.ga.jenetics;
import static java.lang.Math.PI;
import static java.lang.Math.abs;
import static java.lang.Math.sin;
import static org.jenetics.engine.EvolutionResult.toBestPhenotype;
import static org.jenetics.engine.limit.bySteadyFitness;
import java.util.stream.IntStream;
import org.jenetics.EnumGene;
import org.jenetics.Optimize;
import org.jenetics.PartiallyMatchedCrossover;
import org.jenetics.Phenotype;
import org.jenetics.SwapMutator;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionStatistics;
import org.jenetics.engine.codecs;
public class TravelingSalesman {
private static final int STOPS = 50;
private static final double[][] ADJACENCE = matrix(STOPS);
private static double[][] matrix(int stops) {
final double radius = 100.0;
double[][] matrix = new double[stops][stops];
for (int i = 0; i < stops; ++i) {
for (int j = 0; j < stops; ++j) {
matrix[i][j] = chord(stops, abs(i - j), radius);
}
}
return matrix;
}
private static double chord(int stops, int i, double r) {
return 2.0 * r * abs(sin(PI * i / stops));
}
private static double dist(final int[] path) {
return IntStream.range(0, STOPS)
.mapToDouble(i -> ADJACENCE[path[i]][path[(i + 1) % STOPS]])
.sum();
}
public static void main(String[] args) {
final Engine<EnumGene<Integer>, Double> engine = Engine.builder(TravelingSalesman::dist, codecs.ofPermutation(STOPS))
.optimize(Optimize.MINIMUM)
.maximalPhenotypeAge(11)
.populationSize(500)
.alterers(new SwapMutator<>(0.2), new PartiallyMatchedCrossover<>(0.35))
.build();
final EvolutionStatistics<Double, ?> statistics = EvolutionStatistics.ofNumber();
final Phenotype<EnumGene<Integer>, Double> best = engine.stream()
.limit(bySteadyFitness(15))
.limit(250)
.peek(statistics)
.collect(toBestPhenotype());
System.out.println(statistics);
System.out.println(best);
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,22 @@
package com.baeldung.algorithms;
import org.junit.Assert;
import org.junit.Test;
import com.baeldung.algorithms.ga.ant_colony.AntColonyOptimization;
public class AntColonyOptimizationLongRunningUnitTest {
@Test
public void testGenerateRandomMatrix() {
AntColonyOptimization antTSP = new AntColonyOptimization(5);
Assert.assertNotNull(antTSP.generateRandomMatrix(5));
}
@Test
public void testStartAntOptimization() {
AntColonyOptimization antTSP = new AntColonyOptimization(5);
Assert.assertNotNull(antTSP.solve());
}
}

View File

@ -0,0 +1,16 @@
package com.baeldung.algorithms;
import org.junit.Assert;
import org.junit.Test;
import com.baeldung.algorithms.ga.binary.SimpleGeneticAlgorithm;
public class BinaryGeneticAlgorithmLongRunningUnitTest {
@Test
public void testGA() {
SimpleGeneticAlgorithm ga = new SimpleGeneticAlgorithm();
Assert.assertTrue(ga.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111"));
}
}

View File

@ -0,0 +1,15 @@
package com.baeldung.algorithms;
import org.junit.Assert;
import org.junit.Test;
import com.baeldung.algorithms.ga.annealing.SimulatedAnnealing;
public class SimulatedAnnealingLongRunningUnitTest {
@Test
public void testSimulateAnnealing() {
Assert.assertTrue(SimulatedAnnealing.simulateAnnealing(10, 1000, 0.9) > 0);
}
}

View File

@ -0,0 +1,9 @@
## Relevant articles:
- [Validating Input With Finite Automata in Java](https://www.baeldung.com/java-finite-automata)
- [Example of Hill Climbing Algorithm](https://www.baeldung.com/java-hill-climbing-algorithm)
- [Monte Carlo Tree Search for Tic-Tac-Toe Game](https://www.baeldung.com/java-monte-carlo-tree-search)
- [Binary Search Algorithm in Java](https://www.baeldung.com/java-binary-search)
- [Introduction to Minimax Algorithm](https://www.baeldung.com/java-minimax-algorithm)
- [How to Calculate Levenshtein Distance in Java?](https://www.baeldung.com/java-levenshtein-distance)
- [How to Find the Kth Largest Element in Java](https://www.baeldung.com/java-kth-largest-element)

View File

@ -0,0 +1,89 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" 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>
<artifactId>algorithms-miscellaneous-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>algorithms-miscellaneous-1</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>${commons-math3.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${org.assertj.core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.dpaukov</groupId>
<artifactId>combinatoricslib3</artifactId>
<version>${combinatoricslib3.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec-maven-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.7</version>
<configuration>
<instrumentation>
<ignores>
<ignore>com/baeldung/algorithms/dijkstra/*</ignore>
</ignores>
<excludes>
<exclude>com/baeldung/algorithms/dijkstra/*</exclude>
</excludes>
</instrumentation>
</configuration>
</plugin>
</plugins>
</reporting>
<properties>
<commons-math3.version>3.6.1</commons-math3.version>
<org.assertj.core.version>3.9.0</org.assertj.core.version>
<commons-codec.version>1.11</commons-codec.version>
<guava.version>27.0.1-jre</guava.version>
<combinatoricslib3.version>3.3.0</combinatoricslib3.version>
</properties>
</project>

View File

@ -0,0 +1,20 @@
package com.baeldung.algorithms.automata;
/**
* Finite state machine.
*/
public interface FiniteStateMachine {
/**
* Follow a transition, switch the state of the machine.
* @param c Char.
* @return A new finite state machine with the new state.
*/
FiniteStateMachine switchState(final CharSequence c);
/**
* Is the current state a final one?
* @return true or false.
*/
boolean canStop();
}

View File

@ -0,0 +1,30 @@
package com.baeldung.algorithms.automata;
/**
* Default implementation of a finite state machine.
* This class is immutable and thread-safe.
*/
public final class RtFiniteStateMachine implements FiniteStateMachine {
/**
* Current state.
*/
private State current;
/**
* Ctor.
* @param initial Initial state of this machine.
*/
public RtFiniteStateMachine(final State initial) {
this.current = initial;
}
public FiniteStateMachine switchState(final CharSequence c) {
return new RtFiniteStateMachine(this.current.transit(c));
}
public boolean canStop() {
return this.current.isFinal();
}
}

View File

@ -0,0 +1,42 @@
package com.baeldung.algorithms.automata;
import java.util.ArrayList;
import java.util.List;
/**
* State in a finite state machine.
*/
public final class RtState implements State {
private List<Transition> transitions;
private boolean isFinal;
public RtState() {
this(false);
}
public RtState(final boolean isFinal) {
this.transitions = new ArrayList<>();
this.isFinal = isFinal;
}
public State transit(final CharSequence c) {
return transitions
.stream()
.filter(t -> t.isPossible(c))
.map(Transition::state)
.findAny()
.orElseThrow(() -> new IllegalArgumentException("Input not accepted: " + c));
}
public boolean isFinal() {
return this.isFinal;
}
@Override
public State with(Transition tr) {
this.transitions.add(tr);
return this;
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung.algorithms.automata;
/**
* Transition in finite state machine.
*/
public final class RtTransition implements Transition {
private String rule;
private State next;
/**
* Ctor.
* @param rule Rule that a character has to meet
* in order to get to the next state.
* @param next Next state.
*/
public RtTransition (String rule, State next) {
this.rule = rule;
this.next = next;
}
public State state() {
return this.next;
}
public boolean isPossible(CharSequence c) {
return this.rule.equalsIgnoreCase(String.valueOf(c));
}
}

View File

@ -0,0 +1,29 @@
package com.baeldung.algorithms.automata;
/**
* State. Part of a finite state machine.
*/
public interface State {
/**
* Add a Transition to this state.
* @param tr Given transition.
* @return Modified State.
*/
State with(final Transition tr);
/**
* Follow one of the transitions, to get
* to the next state.
* @param c Character.
* @return State.
* @throws IllegalStateException if the char is not accepted.
*/
State transit(final CharSequence c);
/**
* Can the automaton stop on this state?
* @return true or false
*/
boolean isFinal();
}

View File

@ -0,0 +1,20 @@
package com.baeldung.algorithms.automata;
/**
* Transition in a finite State machine.
*/
public interface Transition {
/**
* Is the transition possible with the given character?
* @param c char.
* @return true or false.
*/
boolean isPossible(final CharSequence c);
/**
* The state to which this transition leads.
* @return State.
*/
State state();
}

View File

@ -0,0 +1,55 @@
package com.baeldung.algorithms.binarysearch;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class BinarySearch {
public int runBinarySearchIteratively(int[] sortedArray, int key, int low, int high) {
int index = Integer.MAX_VALUE;
while (low <= high) {
int mid = (low + high) / 2;
if (sortedArray[mid] < key) {
low = mid + 1;
} else if (sortedArray[mid] > key) {
high = mid - 1;
} else if (sortedArray[mid] == key) {
index = mid;
break;
}
}
return index;
}
public int runBinarySearchRecursively(int[] sortedArray, int key, int low, int high) {
int middle = (low + high) / 2;
if (high < low) {
return -1;
}
if (key == sortedArray[middle]) {
return middle;
} else if (key < sortedArray[middle]) {
return runBinarySearchRecursively(sortedArray, key, low, middle - 1);
} else {
return runBinarySearchRecursively(sortedArray, key, middle + 1, high);
}
}
public int runBinarySearchUsingJavaArrays(int[] sortedArray, Integer key) {
int index = Arrays.binarySearch(sortedArray, key);
return index;
}
public int runBinarySearchUsingJavaCollections(List<Integer> sortedList, Integer key) {
int index = Collections.binarySearch(sortedList, key);
return index;
}
}

View File

@ -0,0 +1,189 @@
package com.baeldung.algorithms.hillclimbing;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Stack;
public class HillClimbing {
public static void main(String[] args) {
HillClimbing hillClimbing = new HillClimbing();
String blockArr[] = { "B", "C", "D", "A" };
Stack<String> startState = hillClimbing.getStackWithValues(blockArr);
String goalBlockArr[] = { "A", "B", "C", "D" };
Stack<String> goalState = hillClimbing.getStackWithValues(goalBlockArr);
try {
List<State> solutionSequence = hillClimbing.getRouteWithHillClimbing(startState, goalState);
solutionSequence.forEach(HillClimbing::printEachStep);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void printEachStep(State state) {
List<Stack<String>> stackList = state.getState();
System.out.println("----------------");
stackList.forEach(stack -> {
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
System.out.println(" ");
});
}
private Stack<String> getStackWithValues(String[] blocks) {
Stack<String> stack = new Stack<>();
for (String block : blocks)
stack.push(block);
return stack;
}
/**
* This method prepares path from init state to goal state
*/
public List<State> getRouteWithHillClimbing(Stack<String> initStateStack, Stack<String> goalStateStack) throws Exception {
List<Stack<String>> initStateStackList = new ArrayList<>();
initStateStackList.add(initStateStack);
int initStateHeuristics = getHeuristicsValue(initStateStackList, goalStateStack);
State initState = new State(initStateStackList, initStateHeuristics);
List<State> resultPath = new ArrayList<>();
resultPath.add(new State(initState));
State currentState = initState;
boolean noStateFound = false;
while (!currentState.getState()
.get(0)
.equals(goalStateStack) || noStateFound) {
noStateFound = true;
State nextState = findNextState(currentState, goalStateStack);
if (nextState != null) {
noStateFound = false;
currentState = nextState;
resultPath.add(new State(nextState));
}
}
return resultPath;
}
/**
* This method finds new state from current state based on goal and
* heuristics
*/
public State findNextState(State currentState, Stack<String> goalStateStack) {
List<Stack<String>> listOfStacks = currentState.getState();
int currentStateHeuristics = currentState.getHeuristics();
return listOfStacks.stream()
.map(stack -> {
return applyOperationsOnState(listOfStacks, stack, currentStateHeuristics, goalStateStack);
})
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
/**
* This method applies operations on the current state to get a new state
*/
public State applyOperationsOnState(List<Stack<String>> listOfStacks, Stack<String> stack, int currentStateHeuristics, Stack<String> goalStateStack) {
State tempState;
List<Stack<String>> tempStackList = new ArrayList<>(listOfStacks);
String block = stack.pop();
if (stack.size() == 0)
tempStackList.remove(stack);
tempState = pushElementToNewStack(tempStackList, block, currentStateHeuristics, goalStateStack);
if (tempState == null) {
tempState = pushElementToExistingStacks(stack, tempStackList, block, currentStateHeuristics, goalStateStack);
}
if (tempState == null)
stack.push(block);
return tempState;
}
/**
* Operation to be applied on a state in order to find new states. This
* operation pushes an element into a new stack
*/
private State pushElementToNewStack(List<Stack<String>> currentStackList, String block, int currentStateHeuristics, Stack<String> goalStateStack) {
State newState = null;
Stack<String> newStack = new Stack<>();
newStack.push(block);
currentStackList.add(newStack);
int newStateHeuristics = getHeuristicsValue(currentStackList, goalStateStack);
if (newStateHeuristics > currentStateHeuristics) {
newState = new State(currentStackList, newStateHeuristics);
} else {
currentStackList.remove(newStack);
}
return newState;
}
/**
* Operation to be applied on a state in order to find new states. This
* operation pushes an element into one of the other stacks to explore new
* states
*/
private State pushElementToExistingStacks(Stack currentStack, List<Stack<String>> currentStackList, String block, int currentStateHeuristics, Stack<String> goalStateStack) {
Optional<State> newState = currentStackList.stream()
.filter(stack -> stack != currentStack)
.map(stack -> {
return pushElementToStack(stack, block, currentStackList, currentStateHeuristics, goalStateStack);
})
.filter(Objects::nonNull)
.findFirst();
return newState.orElse(null);
}
/**
* This method pushes a block to the stack and returns new state if its closer to goal
*/
private State pushElementToStack(Stack stack, String block, List<Stack<String>> currentStackList, int currentStateHeuristics, Stack<String> goalStateStack) {
stack.push(block);
int newStateHeuristics = getHeuristicsValue(currentStackList, goalStateStack);
if (newStateHeuristics > currentStateHeuristics) {
return new State(currentStackList, newStateHeuristics);
}
stack.pop();
return null;
}
/**
* This method returns heuristics value for given state with respect to goal
* state
*/
public int getHeuristicsValue(List<Stack<String>> currentState, Stack<String> goalStateStack) {
Integer heuristicValue;
heuristicValue = currentState.stream()
.mapToInt(stack -> {
return getHeuristicsValueForStack(stack, currentState, goalStateStack);
})
.sum();
return heuristicValue;
}
/**
* This method returns heuristics value for a particular stack
*/
public int getHeuristicsValueForStack(Stack<String> stack, List<Stack<String>> currentState, Stack<String> goalStateStack) {
int stackHeuristics = 0;
boolean isPositioneCorrect = true;
int goalStartIndex = 0;
for (String currentBlock : stack) {
if (isPositioneCorrect && currentBlock.equals(goalStateStack.get(goalStartIndex))) {
stackHeuristics += goalStartIndex;
} else {
stackHeuristics -= goalStartIndex;
isPositioneCorrect = false;
}
goalStartIndex++;
}
return stackHeuristics;
}
}

View File

@ -0,0 +1,43 @@
package com.baeldung.algorithms.hillclimbing;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class State {
private List<Stack<String>> state;
private int heuristics;
public State(List<Stack<String>> state) {
this.state = state;
}
State(List<Stack<String>> state, int heuristics) {
this.state = state;
this.heuristics = heuristics;
}
State(State state) {
if (state != null) {
this.state = new ArrayList<>();
for (Stack s : state.getState()) {
Stack s1;
s1 = (Stack) s.clone();
this.state.add(s1);
}
this.heuristics = state.getHeuristics();
}
}
public List<Stack<String>> getState() {
return state;
}
public int getHeuristics() {
return heuristics;
}
public void setHeuristics(int heuristics) {
this.heuristics = heuristics;
}
}

View File

@ -0,0 +1,111 @@
package com.baeldung.algorithms.kthlargest;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.IntStream;
public class FindKthLargest {
public int findKthLargestBySorting(Integer[] arr, int k) {
Arrays.sort(arr);
int targetIndex = arr.length - k;
return arr[targetIndex];
}
public int findKthLargestBySortingDesc(Integer[] arr, int k) {
Arrays.sort(arr, Collections.reverseOrder());
return arr[k - 1];
}
public int findKthElementByQuickSelect(Integer[] arr, int left, int right, int k) {
if (k >= 0 && k <= right - left + 1) {
int pos = partition(arr, left, right);
if (pos - left == k) {
return arr[pos];
}
if (pos - left > k) {
return findKthElementByQuickSelect(arr, left, pos - 1, k);
}
return findKthElementByQuickSelect(arr, pos + 1, right, k - pos + left - 1);
}
return 0;
}
public int findKthElementByQuickSelectWithIterativePartition(Integer[] arr, int left, int right, int k) {
if (k >= 0 && k <= right - left + 1) {
int pos = partitionIterative(arr, left, right);
if (pos - left == k) {
return arr[pos];
}
if (pos - left > k) {
return findKthElementByQuickSelectWithIterativePartition(arr, left, pos - 1, k);
}
return findKthElementByQuickSelectWithIterativePartition(arr, pos + 1, right, k - pos + left - 1);
}
return 0;
}
private int partition(Integer[] arr, int left, int right) {
int pivot = arr[right];
Integer[] leftArr;
Integer[] rightArr;
leftArr = IntStream.range(left, right)
.filter(i -> arr[i] < pivot)
.map(i -> arr[i])
.boxed()
.toArray(Integer[]::new);
rightArr = IntStream.range(left, right)
.filter(i -> arr[i] > pivot)
.map(i -> arr[i])
.boxed()
.toArray(Integer[]::new);
int leftArraySize = leftArr.length;
System.arraycopy(leftArr, 0, arr, left, leftArraySize);
arr[leftArraySize + left] = pivot;
System.arraycopy(rightArr, 0, arr, left + leftArraySize + 1, rightArr.length);
return left + leftArraySize;
}
private int partitionIterative(Integer[] arr, int left, int right) {
int pivot = arr[right], i = left;
for (int j = left; j <= right - 1; j++) {
if (arr[j] <= pivot) {
swap(arr, i, j);
i++;
}
}
swap(arr, i, right);
return i;
}
public int findKthElementByRandomizedQuickSelect(Integer[] arr, int left, int right, int k) {
if (k >= 0 && k <= right - left + 1) {
int pos = randomPartition(arr, left, right);
if (pos - left == k) {
return arr[pos];
}
if (pos - left > k) {
return findKthElementByRandomizedQuickSelect(arr, left, pos - 1, k);
}
return findKthElementByRandomizedQuickSelect(arr, pos + 1, right, k - pos + left - 1);
}
return 0;
}
private int randomPartition(Integer arr[], int left, int right) {
int n = right - left + 1;
int pivot = (int) (Math.random() * n);
swap(arr, left + pivot, right);
return partition(arr, left, right);
}
private void swap(Integer[] arr, int n1, int n2) {
int temp = arr[n2];
arr[n2] = arr[n1];
arr[n1] = temp;
}
}

View File

@ -0,0 +1,109 @@
package com.baeldung.algorithms.mcts.montecarlo;
import java.util.List;
import com.baeldung.algorithms.mcts.tictactoe.Board;
import com.baeldung.algorithms.mcts.tree.Node;
import com.baeldung.algorithms.mcts.tree.Tree;
public class MonteCarloTreeSearch {
private static final int WIN_SCORE = 10;
private int level;
private int opponent;
public MonteCarloTreeSearch() {
this.level = 3;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
private int getMillisForCurrentLevel() {
return 2 * (this.level - 1) + 1;
}
public Board findNextMove(Board board, int playerNo) {
long start = System.currentTimeMillis();
long end = start + 60 * getMillisForCurrentLevel();
opponent = 3 - playerNo;
Tree tree = new Tree();
Node rootNode = tree.getRoot();
rootNode.getState().setBoard(board);
rootNode.getState().setPlayerNo(opponent);
while (System.currentTimeMillis() < end) {
// Phase 1 - Selection
Node promisingNode = selectPromisingNode(rootNode);
// Phase 2 - Expansion
if (promisingNode.getState().getBoard().checkStatus() == Board.IN_PROGRESS)
expandNode(promisingNode);
// Phase 3 - Simulation
Node nodeToExplore = promisingNode;
if (promisingNode.getChildArray().size() > 0) {
nodeToExplore = promisingNode.getRandomChildNode();
}
int playoutResult = simulateRandomPlayout(nodeToExplore);
// Phase 4 - Update
backPropogation(nodeToExplore, playoutResult);
}
Node winnerNode = rootNode.getChildWithMaxScore();
tree.setRoot(winnerNode);
return winnerNode.getState().getBoard();
}
private Node selectPromisingNode(Node rootNode) {
Node node = rootNode;
while (node.getChildArray().size() != 0) {
node = UCT.findBestNodeWithUCT(node);
}
return node;
}
private void expandNode(Node node) {
List<State> possibleStates = node.getState().getAllPossibleStates();
possibleStates.forEach(state -> {
Node newNode = new Node(state);
newNode.setParent(node);
newNode.getState().setPlayerNo(node.getState().getOpponent());
node.getChildArray().add(newNode);
});
}
private void backPropogation(Node nodeToExplore, int playerNo) {
Node tempNode = nodeToExplore;
while (tempNode != null) {
tempNode.getState().incrementVisit();
if (tempNode.getState().getPlayerNo() == playerNo)
tempNode.getState().addScore(WIN_SCORE);
tempNode = tempNode.getParent();
}
}
private int simulateRandomPlayout(Node node) {
Node tempNode = new Node(node);
State tempState = tempNode.getState();
int boardStatus = tempState.getBoard().checkStatus();
if (boardStatus == opponent) {
tempNode.getParent().getState().setWinScore(Integer.MIN_VALUE);
return boardStatus;
}
while (boardStatus == Board.IN_PROGRESS) {
tempState.togglePlayer();
tempState.randomPlay();
boardStatus = tempState.getBoard().checkStatus();
}
return boardStatus;
}
}

View File

@ -0,0 +1,97 @@
package com.baeldung.algorithms.mcts.montecarlo;
import java.util.ArrayList;
import java.util.List;
import com.baeldung.algorithms.mcts.tictactoe.Board;
import com.baeldung.algorithms.mcts.tictactoe.Position;
public class State {
private Board board;
private int playerNo;
private int visitCount;
private double winScore;
public State() {
board = new Board();
}
public State(State state) {
this.board = new Board(state.getBoard());
this.playerNo = state.getPlayerNo();
this.visitCount = state.getVisitCount();
this.winScore = state.getWinScore();
}
public State(Board board) {
this.board = new Board(board);
}
Board getBoard() {
return board;
}
void setBoard(Board board) {
this.board = board;
}
int getPlayerNo() {
return playerNo;
}
void setPlayerNo(int playerNo) {
this.playerNo = playerNo;
}
int getOpponent() {
return 3 - playerNo;
}
public int getVisitCount() {
return visitCount;
}
public void setVisitCount(int visitCount) {
this.visitCount = visitCount;
}
double getWinScore() {
return winScore;
}
void setWinScore(double winScore) {
this.winScore = winScore;
}
public List<State> getAllPossibleStates() {
List<State> possibleStates = new ArrayList<>();
List<Position> availablePositions = this.board.getEmptyPositions();
availablePositions.forEach(p -> {
State newState = new State(this.board);
newState.setPlayerNo(3 - this.playerNo);
newState.getBoard().performMove(newState.getPlayerNo(), p);
possibleStates.add(newState);
});
return possibleStates;
}
void incrementVisit() {
this.visitCount++;
}
void addScore(double score) {
if (this.winScore != Integer.MIN_VALUE)
this.winScore += score;
}
void randomPlay() {
List<Position> availablePositions = this.board.getEmptyPositions();
int totalPossibilities = availablePositions.size();
int selectRandom = (int) (Math.random() * totalPossibilities);
this.board.performMove(this.playerNo, availablePositions.get(selectRandom));
}
void togglePlayer() {
this.playerNo = 3 - this.playerNo;
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.algorithms.mcts.montecarlo;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.baeldung.algorithms.mcts.tree.Node;
public class UCT {
public static double uctValue(int totalVisit, double nodeWinScore, int nodeVisit) {
if (nodeVisit == 0) {
return Integer.MAX_VALUE;
}
return (nodeWinScore / (double) nodeVisit) + 1.41 * Math.sqrt(Math.log(totalVisit) / (double) nodeVisit);
}
static Node findBestNodeWithUCT(Node node) {
int parentVisit = node.getState().getVisitCount();
return Collections.max(
node.getChildArray(),
Comparator.comparing(c -> uctValue(parentVisit, c.getState().getWinScore(), c.getState().getVisitCount())));
}
}

View File

@ -0,0 +1,155 @@
package com.baeldung.algorithms.mcts.tictactoe;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Board {
int[][] boardValues;
int totalMoves;
public static final int DEFAULT_BOARD_SIZE = 3;
public static final int IN_PROGRESS = -1;
public static final int DRAW = 0;
public static final int P1 = 1;
public static final int P2 = 2;
public Board() {
boardValues = new int[DEFAULT_BOARD_SIZE][DEFAULT_BOARD_SIZE];
}
public Board(int boardSize) {
boardValues = new int[boardSize][boardSize];
}
public Board(int[][] boardValues) {
this.boardValues = boardValues;
}
public Board(int[][] boardValues, int totalMoves) {
this.boardValues = boardValues;
this.totalMoves = totalMoves;
}
public Board(Board board) {
int boardLength = board.getBoardValues().length;
this.boardValues = new int[boardLength][boardLength];
int[][] boardValues = board.getBoardValues();
int n = boardValues.length;
for (int i = 0; i < n; i++) {
int m = boardValues[i].length;
for (int j = 0; j < m; j++) {
this.boardValues[i][j] = boardValues[i][j];
}
}
}
public void performMove(int player, Position p) {
this.totalMoves++;
boardValues[p.getX()][p.getY()] = player;
}
public int[][] getBoardValues() {
return boardValues;
}
public void setBoardValues(int[][] boardValues) {
this.boardValues = boardValues;
}
public int checkStatus() {
int boardSize = boardValues.length;
int maxIndex = boardSize - 1;
int[] diag1 = new int[boardSize];
int[] diag2 = new int[boardSize];
for (int i = 0; i < boardSize; i++) {
int[] row = boardValues[i];
int[] col = new int[boardSize];
for (int j = 0; j < boardSize; j++) {
col[j] = boardValues[j][i];
}
int checkRowForWin = checkForWin(row);
if(checkRowForWin!=0)
return checkRowForWin;
int checkColForWin = checkForWin(col);
if(checkColForWin!=0)
return checkColForWin;
diag1[i] = boardValues[i][i];
diag2[i] = boardValues[maxIndex - i][i];
}
int checkDia1gForWin = checkForWin(diag1);
if(checkDia1gForWin!=0)
return checkDia1gForWin;
int checkDiag2ForWin = checkForWin(diag2);
if(checkDiag2ForWin!=0)
return checkDiag2ForWin;
if (getEmptyPositions().size() > 0)
return IN_PROGRESS;
else
return DRAW;
}
private int checkForWin(int[] row) {
boolean isEqual = true;
int size = row.length;
int previous = row[0];
for (int i = 0; i < size; i++) {
if (previous != row[i]) {
isEqual = false;
break;
}
previous = row[i];
}
if(isEqual)
return previous;
else
return 0;
}
public void printBoard() {
int size = this.boardValues.length;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
System.out.print(boardValues[i][j] + " ");
}
System.out.println();
}
}
public List<Position> getEmptyPositions() {
int size = this.boardValues.length;
List<Position> emptyPositions = new ArrayList<>();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (boardValues[i][j] == 0)
emptyPositions.add(new Position(i, j));
}
}
return emptyPositions;
}
public void printStatus() {
switch (this.checkStatus()) {
case P1:
System.out.println("Player 1 wins");
break;
case P2:
System.out.println("Player 2 wins");
break;
case DRAW:
System.out.println("Game Draw");
break;
case IN_PROGRESS:
System.out.println("Game In Progress");
break;
}
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung.algorithms.mcts.tictactoe;
public class Position {
int x;
int y;
public Position() {
}
public Position(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}

View File

@ -0,0 +1,78 @@
package com.baeldung.algorithms.mcts.tree;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.baeldung.algorithms.mcts.montecarlo.State;
public class Node {
State state;
Node parent;
List<Node> childArray;
public Node() {
this.state = new State();
childArray = new ArrayList<>();
}
public Node(State state) {
this.state = state;
childArray = new ArrayList<>();
}
public Node(State state, Node parent, List<Node> childArray) {
this.state = state;
this.parent = parent;
this.childArray = childArray;
}
public Node(Node node) {
this.childArray = new ArrayList<>();
this.state = new State(node.getState());
if (node.getParent() != null)
this.parent = node.getParent();
List<Node> childArray = node.getChildArray();
for (Node child : childArray) {
this.childArray.add(new Node(child));
}
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
public List<Node> getChildArray() {
return childArray;
}
public void setChildArray(List<Node> childArray) {
this.childArray = childArray;
}
public Node getRandomChildNode() {
int noOfPossibleMoves = this.childArray.size();
int selectRandom = (int) (Math.random() * noOfPossibleMoves);
return this.childArray.get(selectRandom);
}
public Node getChildWithMaxScore() {
return Collections.max(this.childArray, Comparator.comparing(c -> {
return c.getState().getVisitCount();
}));
}
}

View File

@ -0,0 +1,26 @@
package com.baeldung.algorithms.mcts.tree;
public class Tree {
Node root;
public Tree() {
root = new Node();
}
public Tree(Node root) {
this.root = root;
}
public Node getRoot() {
return root;
}
public void setRoot(Node root) {
this.root = root;
}
public void addChild(Node parent, Node child) {
parent.getChildArray().add(child);
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.algorithms.minimax;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class GameOfBones {
static List<Integer> getPossibleStates(int noOfBonesInHeap) {
return IntStream.rangeClosed(1, 3).boxed()
.map(i -> noOfBonesInHeap - i)
.filter(newHeapCount -> newHeapCount >= 0)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,60 @@
package com.baeldung.algorithms.minimax;
import java.util.Comparator;
import java.util.List;
import java.util.NoSuchElementException;
public class MiniMax {
private Tree tree;
public Tree getTree() {
return tree;
}
public void constructTree(int noOfBones) {
tree = new Tree();
Node root = new Node(noOfBones, true);
tree.setRoot(root);
constructTree(root);
}
private void constructTree(Node parentNode) {
List<Integer> listofPossibleHeaps = GameOfBones.getPossibleStates(parentNode.getNoOfBones());
boolean isChildMaxPlayer = !parentNode.isMaxPlayer();
listofPossibleHeaps.forEach(n -> {
Node newNode = new Node(n, isChildMaxPlayer);
parentNode.addChild(newNode);
if (newNode.getNoOfBones() > 0) {
constructTree(newNode);
}
});
}
public boolean checkWin() {
Node root = tree.getRoot();
checkWin(root);
return root.getScore() == 1;
}
private void checkWin(Node node) {
List<Node> children = node.getChildren();
boolean isMaxPlayer = node.isMaxPlayer();
children.forEach(child -> {
if (child.getNoOfBones() == 0) {
child.setScore(isMaxPlayer ? 1 : -1);
} else {
checkWin(child);
}
});
Node bestChild = findBestChild(isMaxPlayer, children);
node.setScore(bestChild.getScore());
}
private Node findBestChild(boolean isMaxPlayer, List<Node> children) {
Comparator<Node> byScoreComparator = Comparator.comparing(Node::getScore);
return children.stream()
.max(isMaxPlayer ? byScoreComparator : byScoreComparator.reversed())
.orElseThrow(NoSuchElementException::new);
}
}

View File

@ -0,0 +1,42 @@
package com.baeldung.algorithms.minimax;
import java.util.ArrayList;
import java.util.List;
public class Node {
private int noOfBones;
private boolean isMaxPlayer;
private int score;
private List<Node> children;
public Node(int noOfBones, boolean isMaxPlayer) {
this.noOfBones = noOfBones;
this.isMaxPlayer = isMaxPlayer;
children = new ArrayList<>();
}
int getNoOfBones() {
return noOfBones;
}
boolean isMaxPlayer() {
return isMaxPlayer;
}
int getScore() {
return score;
}
void setScore(int score) {
this.score = score;
}
List<Node> getChildren() {
return children;
}
void addChild(Node newNode) {
children.add(newNode);
}
}

View File

@ -0,0 +1,16 @@
package com.baeldung.algorithms.minimax;
public class Tree {
private Node root;
Tree() {
}
Node getRoot() {
return root;
}
void setRoot(Node root) {
this.root = root;
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,58 @@
package com.baeldung.algorithms;
import com.baeldung.algorithms.hillclimbing.HillClimbing;
import com.baeldung.algorithms.hillclimbing.State;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class HillClimbingAlgorithmUnitTest {
private Stack<String> initStack;
private Stack<String> goalStack;
@Before
public void initStacks() {
String blockArr[] = { "B", "C", "D", "A" };
String goalBlockArr[] = { "A", "B", "C", "D" };
initStack = new Stack<>();
for (String block : blockArr)
initStack.push(block);
goalStack = new Stack<>();
for (String block : goalBlockArr)
goalStack.push(block);
}
@Test
public void givenInitAndGoalState_whenGetPathWithHillClimbing_thenPathFound() {
HillClimbing hillClimbing = new HillClimbing();
List<State> path;
try {
path = hillClimbing.getRouteWithHillClimbing(initStack, goalStack);
assertNotNull(path);
assertEquals(path.get(path.size() - 1)
.getState()
.get(0), goalStack);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void givenCurrentState_whenFindNextState_thenBetterHeuristics() {
HillClimbing hillClimbing = new HillClimbing();
List<Stack<String>> initList = new ArrayList<>();
initList.add(initStack);
State currentState = new State(initList);
currentState.setHeuristics(hillClimbing.getHeuristicsValue(initList, goalStack));
State nextState = hillClimbing.findNextState(currentState, goalStack);
assertTrue(nextState.getHeuristics() > currentState.getHeuristics());
}
}

View File

@ -0,0 +1,73 @@
package com.baeldung.algorithms;
import com.baeldung.algorithms.automata.*;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public final class RtFiniteStateMachineLongRunningUnitTest {
@Test
public void acceptsSimplePair() {
String json = "{\"key\":\"value\"}";
FiniteStateMachine machine = this.buildJsonStateMachine();
for (int i = 0; i < json.length(); i++) {
machine = machine.switchState(String.valueOf(json.charAt(i)));
}
assertTrue(machine.canStop());
}
@Test
public void acceptsMorePairs() {
String json = "{\"key1\":\"value1\",\"key2\":\"value2\"}";
FiniteStateMachine machine = this.buildJsonStateMachine();
for (int i = 0; i < json.length(); i++) {
machine = machine.switchState(String.valueOf(json.charAt(i)));
}
assertTrue(machine.canStop());
}
@Test(expected = IllegalArgumentException.class)
public void missingColon() {
String json = "{\"key\"\"value\"}";
FiniteStateMachine machine = this.buildJsonStateMachine();
for (int i = 0; i < json.length(); i++) {
machine = machine.switchState(String.valueOf(json.charAt(i)));
}
}
/**
* Builds a finite state machine to validate a simple
* Json object.
* @return
*/
private FiniteStateMachine buildJsonStateMachine() {
State first = new RtState();
State second = new RtState();
State third = new RtState();
State fourth = new RtState();
State fifth = new RtState();
State sixth = new RtState();
State seventh = new RtState();
State eighth = new RtState(true);
first.with(new RtTransition("{", second));
second.with(new RtTransition("\"", third));
//Add transitions with chars 0-9 and a-z
for (int i = 0; i < 26; i++) {
if (i < 10) {
third = third.with(new RtTransition(String.valueOf(i), third));
sixth = sixth.with(new RtTransition(String.valueOf(i), sixth));
}
third = third.with(new RtTransition(String.valueOf((char) ('a' + i)), third));
sixth = sixth.with(new RtTransition(String.valueOf((char) ('a' + i)), sixth));
}
third.with(new RtTransition("\"", fourth));
fourth.with(new RtTransition(":", fifth));
fifth.with(new RtTransition("\"", sixth));
sixth.with(new RtTransition("\"", seventh));
seventh.with(new RtTransition(",", second));
seventh.with(new RtTransition("}", eighth));
return new RtFiniteStateMachine(first);
}
}

View File

@ -0,0 +1,43 @@
package com.baeldung.algorithms.binarysearch;
import java.util.Arrays;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import com.baeldung.algorithms.binarysearch.BinarySearch;
public class BinarySearchUnitTest {
int[] sortedArray = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 };
int key = 6;
int expectedIndexForSearchKey = 7;
int low = 0;
int high = sortedArray.length - 1;
List<Integer> sortedList = Arrays.asList(0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9);
@Test
public void givenASortedArrayOfIntegers_whenBinarySearchRunIterativelyForANumber_thenGetIndexOfTheNumber() {
BinarySearch binSearch = new BinarySearch();
Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchIteratively(sortedArray, key, low, high));
}
@Test
public void givenASortedArrayOfIntegers_whenBinarySearchRunRecursivelyForANumber_thenGetIndexOfTheNumber() {
BinarySearch binSearch = new BinarySearch();
Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchRecursively(sortedArray, key, low, high));
}
@Test
public void givenASortedArrayOfIntegers_whenBinarySearchRunUsingArraysClassStaticMethodForANumber_thenGetIndexOfTheNumber() {
BinarySearch binSearch = new BinarySearch();
Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaArrays(sortedArray, key));
}
@Test
public void givenASortedListOfIntegers_whenBinarySearchRunUsingCollectionsClassStaticMethodForANumber_thenGetIndexOfTheNumber() {
BinarySearch binSearch = new BinarySearch();
Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaCollections(sortedList, key));
}
}

View File

@ -0,0 +1,57 @@
package com.baeldung.algorithms.kthlargest;
import static org.assertj.core.api.Assertions.*;
import org.junit.Before;
import org.junit.Test;
public class FindKthLargestUnitTest {
private FindKthLargest findKthLargest;
private Integer[] arr = { 3, 7, 1, 2, 8, 10, 4, 5, 6, 9 };
@Before
public void setup() {
findKthLargest = new FindKthLargest();
}
@Test
public void givenIntArray_whenFindKthLargestBySorting_thenGetResult() {
int k = 3;
assertThat(findKthLargest.findKthLargestBySorting(arr, k)).isEqualTo(8);
}
@Test
public void givenIntArray_whenFindKthLargestBySortingDesc_thenGetResult() {
int k = 3;
assertThat(findKthLargest.findKthLargestBySortingDesc(arr, k)).isEqualTo(8);
}
@Test
public void givenIntArray_whenFindKthLargestByQuickSelect_thenGetResult() {
int k = 3;
int kthLargest = arr.length - k;
assertThat(findKthLargest.findKthElementByQuickSelect(arr, 0, arr.length - 1, kthLargest)).isEqualTo(8);
}
@Test
public void givenIntArray_whenFindKthElementByQuickSelectIterative_thenGetResult() {
int k = 3;
int kthLargest = arr.length - k;
assertThat(findKthLargest.findKthElementByQuickSelectWithIterativePartition(arr, 0, arr.length - 1, kthLargest)).isEqualTo(8);
}
@Test
public void givenIntArray_whenFindKthSmallestByQuickSelect_thenGetResult() {
int k = 3;
assertThat(findKthLargest.findKthElementByQuickSelect(arr, 0, arr.length - 1, k - 1)).isEqualTo(3);
}
@Test
public void givenIntArray_whenFindKthLargestByRandomizedQuickSelect_thenGetResult() {
int k = 3;
int kthLargest = arr.length - k;
assertThat(findKthLargest.findKthElementByRandomizedQuickSelect(arr, 0, arr.length - 1, kthLargest)).isEqualTo(8);
}
}

View File

@ -0,0 +1,92 @@
package com.baeldung.algorithms.mcts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.algorithms.mcts.montecarlo.MonteCarloTreeSearch;
import com.baeldung.algorithms.mcts.montecarlo.State;
import com.baeldung.algorithms.mcts.montecarlo.UCT;
import com.baeldung.algorithms.mcts.tictactoe.Board;
import com.baeldung.algorithms.mcts.tictactoe.Position;
import com.baeldung.algorithms.mcts.tree.Tree;
public class MCTSUnitTest {
private Tree gameTree;
private MonteCarloTreeSearch mcts;
@Before
public void initGameTree() {
gameTree = new Tree();
mcts = new MonteCarloTreeSearch();
}
@Test
public void givenStats_whenGetUCTForNode_thenUCTMatchesWithManualData() {
double uctValue = 15.79;
assertEquals(UCT.uctValue(600, 300, 20), uctValue, 0.01);
}
@Test
public void giveninitBoardState_whenGetAllPossibleStates_thenNonEmptyList() {
State initState = gameTree.getRoot().getState();
List<State> possibleStates = initState.getAllPossibleStates();
assertTrue(possibleStates.size() > 0);
}
@Test
public void givenEmptyBoard_whenPerformMove_thenLessAvailablePossitions() {
Board board = new Board();
int initAvailablePositions = board.getEmptyPositions().size();
board.performMove(Board.P1, new Position(1, 1));
int availablePositions = board.getEmptyPositions().size();
assertTrue(initAvailablePositions > availablePositions);
}
@Test
public void givenEmptyBoard_whenSimulateInterAIPlay_thenGameDraw() {
Board board = new Board();
int player = Board.P1;
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
for (int i = 0; i < totalMoves; i++) {
board = mcts.findNextMove(board, player);
if (board.checkStatus() != -1) {
break;
}
player = 3 - player;
}
int winStatus = board.checkStatus();
assertEquals(winStatus, Board.DRAW);
}
@Test
public void givenEmptyBoard_whenLevel1VsLevel3_thenLevel3WinsOrDraw() {
Board board = new Board();
MonteCarloTreeSearch mcts1 = new MonteCarloTreeSearch();
mcts1.setLevel(1);
MonteCarloTreeSearch mcts3 = new MonteCarloTreeSearch();
mcts3.setLevel(3);
int player = Board.P1;
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
for (int i = 0; i < totalMoves; i++) {
if (player == Board.P1)
board = mcts3.findNextMove(board, player);
else
board = mcts1.findNextMove(board, player);
if (board.checkStatus() != -1) {
break;
}
player = 3 - player;
}
int winStatus = board.checkStatus();
assertTrue(winStatus == Board.DRAW || winStatus == Board.P1);
}
}

View File

@ -0,0 +1,36 @@
package com.baeldung.algorithms.minimax;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import com.baeldung.algorithms.minimax.MiniMax;
import com.baeldung.algorithms.minimax.Tree;
public class MinimaxUnitTest {
private Tree gameTree;
private MiniMax miniMax;
@Before
public void initMiniMaxUtility() {
miniMax = new MiniMax();
}
@Test
public void givenMiniMax_whenConstructTree_thenNotNullTree() {
assertNull(gameTree);
miniMax.constructTree(6);
gameTree = miniMax.getTree();
assertNotNull(gameTree);
}
@Test
public void givenMiniMax_whenCheckWin_thenComputeOptimal() {
miniMax.constructTree(6);
boolean result = miniMax.checkWin();
assertTrue(result);
miniMax.constructTree(8);
result = miniMax.checkWin();
assertFalse(result);
}
}

View File

@ -0,0 +1,10 @@
## Relevant articles:
- [Dijkstra Shortest Path Algorithm in Java](https://www.baeldung.com/java-dijkstra)
- [Introduction to Cobertura](https://www.baeldung.com/cobertura)
- [Test a Linked List for Cyclicity](https://www.baeldung.com/java-linked-list-cyclicity)
- [Introduction to JGraphT](https://www.baeldung.com/jgrapht)
- [A Maze Solver in Java](https://www.baeldung.com/java-solve-maze)
- [Create a Sudoku Solver in Java](https://www.baeldung.com/java-sudoku)
- [Displaying Money Amounts in Words](https://www.baeldung.com/java-money-into-words)
- [A Collaborative Filtering Recommendation System in Java](https://www.baeldung.com/java-collaborative-filtering-recommendations)

View File

@ -0,0 +1,96 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" 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>
<artifactId>algorithms-miscellaneous-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>algorithms-miscellaneous-2</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>${commons-math3.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
<version>${org.jgrapht.core.version}</version>
</dependency>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-ext</artifactId>
<version>${org.jgrapht.ext.version}</version>
</dependency>
<dependency>
<groupId>pl.allegro.finance</groupId>
<artifactId>tradukisto</artifactId>
<version>${tradukisto.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${org.assertj.core.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec-maven-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura-maven-plugin.version}</version>
<configuration>
<instrumentation>
<ignores>
<ignore>com/baeldung/algorithms/dijkstra/*</ignore>
</ignores>
<excludes>
<exclude>com/baeldung/algorithms/dijkstra/*</exclude>
</excludes>
</instrumentation>
</configuration>
</plugin>
</plugins>
</reporting>
<properties>
<commons-math3.version>3.6.1</commons-math3.version>
<tradukisto.version>1.0.1</tradukisto.version>
<org.jgrapht.core.version>1.0.1</org.jgrapht.core.version>
<org.jgrapht.ext.version>1.0.1</org.jgrapht.ext.version>
<org.assertj.core.version>3.9.0</org.assertj.core.version>
<commons-codec.version>1.11</commons-codec.version>
<cobertura-maven-plugin.version>2.7</cobertura-maven-plugin.version>
</properties>
</project>

View File

@ -0,0 +1,28 @@
package com.baeldung.algorithms;
import java.util.Scanner;
import com.baeldung.algorithms.slope_one.SlopeOne;
public class RunAlgorithm {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Scanner in = new Scanner(System.in);
System.out.println("1 - Slope One");
System.out.println("2 - Dijkstra");
int decision = in.nextInt();
switch (decision) {
case 1:
SlopeOne.slopeOne(3);
break;
case 2:
System.out.println("Please run the DijkstraAlgorithmLongRunningUnitTest.");
break;
default:
System.out.println("Unknown option");
break;
}
in.close();
}
}

View File

@ -0,0 +1,15 @@
package com.baeldung.algorithms.editdistance;
import java.util.Arrays;
public class EditDistanceBase {
static int costOfSubstitution(char a, char b) {
return a == b ? 0 : 1;
}
static int min(int... numbers) {
return Arrays.stream(numbers)
.min().orElse(Integer.MAX_VALUE);
}
}

View File

@ -0,0 +1,26 @@
package com.baeldung.algorithms.editdistance;
public class EditDistanceDynamicProgramming extends EditDistanceBase {
static int calculate(String x, String y) {
int[][] dp = new int[x.length() + 1][y.length() + 1];
for (int i = 0; i <= x.length(); i++) {
for (int j = 0; j <= y.length(); j++) {
if (i == 0)
dp[i][j] = j;
else if (j == 0)
dp[i][j] = i;
else {
dp[i][j] = min(dp[i - 1][j - 1]
+ costOfSubstitution(x.charAt(i - 1), y.charAt(j - 1)),
dp[i - 1][j] + 1, dp[i][j - 1] + 1);
}
}
}
return dp[x.length()][y.length()];
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.algorithms.editdistance;
public class EditDistanceRecursive extends EditDistanceBase {
static int calculate(String x, String y) {
if (x.isEmpty()) {
return y.length();
}
if (y.isEmpty()) {
return x.length();
}
int substitution = calculate(x.substring(1), y.substring(1)) + costOfSubstitution(x.charAt(0), y.charAt(0));
int insertion = calculate(x, y.substring(1)) + 1;
int deletion = calculate(x.substring(1), y) + 1;
return min(substitution, insertion, deletion);
}
}

View File

@ -0,0 +1,57 @@
package com.baeldung.algorithms.ga.dijkstra;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Set;
public class Dijkstra {
public static Graph calculateShortestPathFromSource(Graph graph, Node source) {
source.setDistance(0);
Set<Node> settledNodes = new HashSet<>();
Set<Node> unsettledNodes = new HashSet<>();
unsettledNodes.add(source);
while (unsettledNodes.size() != 0) {
Node currentNode = getLowestDistanceNode(unsettledNodes);
unsettledNodes.remove(currentNode);
for (Entry<Node, Integer> adjacencyPair : currentNode.getAdjacentNodes().entrySet()) {
Node adjacentNode = adjacencyPair.getKey();
Integer edgeWeigh = adjacencyPair.getValue();
if (!settledNodes.contains(adjacentNode)) {
CalculateMinimumDistance(adjacentNode, edgeWeigh, currentNode);
unsettledNodes.add(adjacentNode);
}
}
settledNodes.add(currentNode);
}
return graph;
}
private static void CalculateMinimumDistance(Node evaluationNode, Integer edgeWeigh, Node sourceNode) {
Integer sourceDistance = sourceNode.getDistance();
if (sourceDistance + edgeWeigh < evaluationNode.getDistance()) {
evaluationNode.setDistance(sourceDistance + edgeWeigh);
LinkedList<Node> shortestPath = new LinkedList<>(sourceNode.getShortestPath());
shortestPath.add(sourceNode);
evaluationNode.setShortestPath(shortestPath);
}
}
private static Node getLowestDistanceNode(Set<Node> unsettledNodes) {
Node lowestDistanceNode = null;
int lowestDistance = Integer.MAX_VALUE;
for (Node node : unsettledNodes) {
int nodeDistance = node.getDistance();
if (nodeDistance < lowestDistance) {
lowestDistance = nodeDistance;
lowestDistanceNode = node;
}
}
return lowestDistanceNode;
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.algorithms.ga.dijkstra;
import java.util.HashSet;
import java.util.Set;
public class Graph {
private Set<Node> nodes = new HashSet<>();
public void addNode(Node nodeA) {
nodes.add(nodeA);
}
public Set<Node> getNodes() {
return nodes;
}
public void setNodes(Set<Node> nodes) {
this.nodes = nodes;
}
}

View File

@ -0,0 +1,58 @@
package com.baeldung.algorithms.ga.dijkstra;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class Node {
private String name;
private LinkedList<Node> shortestPath = new LinkedList<>();
private Integer distance = Integer.MAX_VALUE;
private Map<Node, Integer> adjacentNodes = new HashMap<>();
public Node(String name) {
this.name = name;
}
public void addDestination(Node destination, int distance) {
adjacentNodes.put(destination, distance);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<Node, Integer> getAdjacentNodes() {
return adjacentNodes;
}
public void setAdjacentNodes(Map<Node, Integer> adjacentNodes) {
this.adjacentNodes = adjacentNodes;
}
public Integer getDistance() {
return distance;
}
public void setDistance(Integer distance) {
this.distance = distance;
}
public List<Node> getShortestPath() {
return shortestPath;
}
public void setShortestPath(LinkedList<Node> shortestPath) {
this.shortestPath = shortestPath;
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung.algorithms.linkedlist;
public class CycleDetectionBruteForce {
public static <T> CycleDetectionResult<T> detectCycle(Node<T> head) {
if (head == null) {
return new CycleDetectionResult<>(false, null);
}
Node<T> it1 = head;
int nodesTraversedByOuter = 0;
while (it1 != null && it1.next != null) {
it1 = it1.next;
nodesTraversedByOuter++;
int x = nodesTraversedByOuter;
Node<T> it2 = head;
int noOfTimesCurrentNodeVisited = 0;
while (x > 0) {
it2 = it2.next;
if (it2 == it1) {
noOfTimesCurrentNodeVisited++;
}
if (noOfTimesCurrentNodeVisited == 2) {
return new CycleDetectionResult<>(true, it1);
}
x--;
}
}
return new CycleDetectionResult<>(false, null);
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.algorithms.linkedlist;
public class CycleDetectionByFastAndSlowIterators {
public static <T> CycleDetectionResult<T> detectCycle(Node<T> head) {
if (head == null) {
return new CycleDetectionResult<>(false, null);
}
Node<T> slow = head;
Node<T> fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return new CycleDetectionResult<>(true, fast);
}
}
return new CycleDetectionResult<>(false, null);
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.algorithms.linkedlist;
import java.util.HashSet;
import java.util.Set;
public class CycleDetectionByHashing {
public static <T> CycleDetectionResult<T> detectCycle(Node<T> head) {
if (head == null) {
return new CycleDetectionResult<>(false, null);
}
Set<Node<T>> set = new HashSet<>();
Node<T> node = head;
while (node != null) {
if (set.contains(node)) {
return new CycleDetectionResult<>(true, node);
}
set.add(node);
node = node.next;
}
return new CycleDetectionResult<>(false, null);
}
}

View File

@ -0,0 +1,12 @@
package com.baeldung.algorithms.linkedlist;
public class CycleDetectionResult<T> {
boolean cycleExists;
Node<T> node;
public CycleDetectionResult(boolean cycleExists, Node<T> node) {
super();
this.cycleExists = cycleExists;
this.node = node;
}
}

View File

@ -0,0 +1,56 @@
package com.baeldung.algorithms.linkedlist;
public class CycleRemovalBruteForce {
public static <T> boolean detectAndRemoveCycle(Node<T> head) {
CycleDetectionResult<T> result = CycleDetectionByFastAndSlowIterators.detectCycle(head);
if (result.cycleExists) {
removeCycle(result.node, head);
}
return result.cycleExists;
}
/**
* @param loopNodeParam - reference to the node where Flyods cycle
* finding algorithm ends, i.e. the fast and the slow iterators
* meet.
* @param head - reference to the head of the list
*/
private static <T> void removeCycle(Node<T> loopNodeParam, Node<T> head) {
Node<T> it = head;
while (it != null) {
if (isNodeReachableFromLoopNode(it, loopNodeParam)) {
Node<T> loopStart = it;
findEndNodeAndBreakCycle(loopStart);
break;
}
it = it.next;
}
}
private static <T> boolean isNodeReachableFromLoopNode(Node<T> it, Node<T> loopNodeParam) {
Node<T> loopNode = loopNodeParam;
do {
if (it == loopNode) {
return true;
}
loopNode = loopNode.next;
} while (loopNode.next != loopNodeParam);
return false;
}
private static <T> void findEndNodeAndBreakCycle(Node<T> loopStartParam) {
Node<T> loopStart = loopStartParam;
while (loopStart.next != loopStartParam) {
loopStart = loopStart.next;
}
loopStart.next = null;
}
}

View File

@ -0,0 +1,44 @@
package com.baeldung.algorithms.linkedlist;
public class CycleRemovalByCountingLoopNodes {
public static <T> boolean detectAndRemoveCycle(Node<T> head) {
CycleDetectionResult<T> result = CycleDetectionByFastAndSlowIterators.detectCycle(head);
if (result.cycleExists) {
removeCycle(result.node, head);
}
return result.cycleExists;
}
private static <T> void removeCycle(Node<T> loopNodeParam, Node<T> head) {
int cycleLength = calculateCycleLength(loopNodeParam);
Node<T> cycleLengthAdvancedIterator = head;
Node<T> it = head;
for (int i = 0; i < cycleLength; i++) {
cycleLengthAdvancedIterator = cycleLengthAdvancedIterator.next;
}
while (it.next != cycleLengthAdvancedIterator.next) {
it = it.next;
cycleLengthAdvancedIterator = cycleLengthAdvancedIterator.next;
}
cycleLengthAdvancedIterator.next = null;
}
private static <T> int calculateCycleLength(Node<T> loopNodeParam) {
Node<T> loopNode = loopNodeParam;
int length = 1;
while (loopNode.next != loopNodeParam) {
length++;
loopNode = loopNode.next;
}
return length;
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.algorithms.linkedlist;
public class CycleRemovalWithoutCountingLoopNodes {
public static <T> boolean detectAndRemoveCycle(Node<T> head) {
CycleDetectionResult<T> result = CycleDetectionByFastAndSlowIterators.detectCycle(head);
if (result.cycleExists) {
removeCycle(result.node, head);
}
return result.cycleExists;
}
private static <T> void removeCycle(Node<T> meetingPointParam, Node<T> head) {
Node<T> loopNode = meetingPointParam;
Node<T> it = head;
while (loopNode.next != it.next) {
it = it.next;
loopNode = loopNode.next;
}
loopNode.next = null;
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung.algorithms.linkedlist;
public class Node<T> {
T data;
Node<T> next;
public static <T> Node<T> createNewNode(T data, Node<T> next) {
Node<T> node = new Node<T>();
node.data = data;
node.next = next;
return node;
}
public static <T> void traverseList(Node<T> root) {
if (root == null) {
return;
}
Node<T> node = root;
while (node != null) {
System.out.println(node.data);
node = node.next;
}
}
public static <T> Node<T> getTail(Node<T> root) {
if (root == null) {
return null;
}
Node<T> node = root;
while (node.next != null) {
node = node.next;
}
return node;
}
}

View File

@ -0,0 +1,52 @@
package com.baeldung.algorithms.maze.solver;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class BFSMazeSolver {
private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
public List<Coordinate> solve(Maze maze) {
LinkedList<Coordinate> nextToVisit = new LinkedList<>();
Coordinate start = maze.getEntry();
nextToVisit.add(start);
while (!nextToVisit.isEmpty()) {
Coordinate cur = nextToVisit.remove();
if (!maze.isValidLocation(cur.getX(), cur.getY()) || maze.isExplored(cur.getX(), cur.getY())) {
continue;
}
if (maze.isWall(cur.getX(), cur.getY())) {
maze.setVisited(cur.getX(), cur.getY(), true);
continue;
}
if (maze.isExit(cur.getX(), cur.getY())) {
return backtrackPath(cur);
}
for (int[] direction : DIRECTIONS) {
Coordinate coordinate = new Coordinate(cur.getX() + direction[0], cur.getY() + direction[1], cur);
nextToVisit.add(coordinate);
maze.setVisited(cur.getX(), cur.getY(), true);
}
}
return Collections.emptyList();
}
private List<Coordinate> backtrackPath(Coordinate cur) {
List<Coordinate> path = new ArrayList<>();
Coordinate iter = cur;
while (iter != null) {
path.add(iter);
iter = iter.parent;
}
return path;
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung.algorithms.maze.solver;
public class Coordinate {
int x;
int y;
Coordinate parent;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
this.parent = null;
}
public Coordinate(int x, int y, Coordinate parent) {
this.x = x;
this.y = y;
this.parent = parent;
}
int getX() {
return x;
}
int getY() {
return y;
}
Coordinate getParent() {
return parent;
}
}

View File

@ -0,0 +1,48 @@
package com.baeldung.algorithms.maze.solver;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class DFSMazeSolver {
private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
public List<Coordinate> solve(Maze maze) {
List<Coordinate> path = new ArrayList<>();
if (explore(maze, maze.getEntry()
.getX(),
maze.getEntry()
.getY(),
path)) {
return path;
}
return Collections.emptyList();
}
private boolean explore(Maze maze, int row, int col, List<Coordinate> path) {
if (!maze.isValidLocation(row, col) || maze.isWall(row, col) || maze.isExplored(row, col)) {
return false;
}
path.add(new Coordinate(row, col));
maze.setVisited(row, col, true);
if (maze.isExit(row, col)) {
return true;
}
for (int[] direction : DIRECTIONS) {
Coordinate coordinate = getNextCoordinate(row, col, direction[0], direction[1]);
if (explore(maze, coordinate.getX(), coordinate.getY(), path)) {
return true;
}
}
path.remove(path.size() - 1);
return false;
}
private Coordinate getNextCoordinate(int row, int col, int i, int j) {
return new Coordinate(row + i, col + j);
}
}

View File

@ -0,0 +1,141 @@
package com.baeldung.algorithms.maze.solver;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class Maze {
private static final int ROAD = 0;
private static final int WALL = 1;
private static final int START = 2;
private static final int EXIT = 3;
private static final int PATH = 4;
private int[][] maze;
private boolean[][] visited;
private Coordinate start;
private Coordinate end;
public Maze(File maze) throws FileNotFoundException {
String fileText = "";
try (Scanner input = new Scanner(maze)) {
while (input.hasNextLine()) {
fileText += input.nextLine() + "\n";
}
}
initializeMaze(fileText);
}
private void initializeMaze(String text) {
if (text == null || (text = text.trim()).length() == 0) {
throw new IllegalArgumentException("empty lines data");
}
String[] lines = text.split("[\r]?\n");
maze = new int[lines.length][lines[0].length()];
visited = new boolean[lines.length][lines[0].length()];
for (int row = 0; row < getHeight(); row++) {
if (lines[row].length() != getWidth()) {
throw new IllegalArgumentException("line " + (row + 1) + " wrong length (was " + lines[row].length() + " but should be " + getWidth() + ")");
}
for (int col = 0; col < getWidth(); col++) {
if (lines[row].charAt(col) == '#')
maze[row][col] = WALL;
else if (lines[row].charAt(col) == 'S') {
maze[row][col] = START;
start = new Coordinate(row, col);
} else if (lines[row].charAt(col) == 'E') {
maze[row][col] = EXIT;
end = new Coordinate(row, col);
} else
maze[row][col] = ROAD;
}
}
}
public int getHeight() {
return maze.length;
}
public int getWidth() {
return maze[0].length;
}
public Coordinate getEntry() {
return start;
}
public Coordinate getExit() {
return end;
}
public boolean isExit(int x, int y) {
return x == end.getX() && y == end.getY();
}
public boolean isStart(int x, int y) {
return x == start.getX() && y == start.getY();
}
public boolean isExplored(int row, int col) {
return visited[row][col];
}
public boolean isWall(int row, int col) {
return maze[row][col] == WALL;
}
public void setVisited(int row, int col, boolean value) {
visited[row][col] = value;
}
public boolean isValidLocation(int row, int col) {
if (row < 0 || row >= getHeight() || col < 0 || col >= getWidth()) {
return false;
}
return true;
}
public void printPath(List<Coordinate> path) {
int[][] tempMaze = Arrays.stream(maze)
.map(int[]::clone)
.toArray(int[][]::new);
for (Coordinate coordinate : path) {
if (isStart(coordinate.getX(), coordinate.getY()) || isExit(coordinate.getX(), coordinate.getY())) {
continue;
}
tempMaze[coordinate.getX()][coordinate.getY()] = PATH;
}
System.out.println(toString(tempMaze));
}
public String toString(int[][] maze) {
StringBuilder result = new StringBuilder(getWidth() * (getHeight() + 1));
for (int row = 0; row < getHeight(); row++) {
for (int col = 0; col < getWidth(); col++) {
if (maze[row][col] == ROAD) {
result.append(' ');
} else if (maze[row][col] == WALL) {
result.append('#');
} else if (maze[row][col] == START) {
result.append('S');
} else if (maze[row][col] == EXIT) {
result.append('E');
} else {
result.append('.');
}
}
result.append('\n');
}
return result.toString();
}
public void reset() {
for (int i = 0; i < visited.length; i++)
Arrays.fill(visited[i], false);
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.algorithms.maze.solver;
import java.io.File;
import java.util.List;
public class MazeDriver {
public static void main(String[] args) throws Exception {
File maze1 = new File("src/main/resources/maze/maze1.txt");
File maze2 = new File("src/main/resources/maze/maze2.txt");
execute(maze1);
execute(maze2);
}
private static void execute(File file) throws Exception {
Maze maze = new Maze(file);
dfs(maze);
bfs(maze);
}
private static void bfs(Maze maze) {
BFSMazeSolver bfs = new BFSMazeSolver();
List<Coordinate> path = bfs.solve(maze);
maze.printPath(path);
maze.reset();
}
private static void dfs(Maze maze) {
DFSMazeSolver dfs = new DFSMazeSolver();
List<Coordinate> path = dfs.solve(maze);
maze.printPath(path);
maze.reset();
}
}

View File

@ -0,0 +1,75 @@
package com.baeldung.algorithms.numberwordconverter;
import java.math.BigDecimal;
import pl.allegro.finance.tradukisto.MoneyConverters;
public class NumberWordConverter {
public static final String INVALID_INPUT_GIVEN = "Invalid input given";
public static final String[] ones = { "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
public static final String[] tens = {
"", // 0
"", // 1
"twenty", // 2
"thirty", // 3
"forty", // 4
"fifty", // 5
"sixty", // 6
"seventy", // 7
"eighty", // 8
"ninety" // 9
};
public static String getMoneyIntoWords(String input) {
MoneyConverters converter = MoneyConverters.ENGLISH_BANKING_MONEY_VALUE;
return converter.asWords(new BigDecimal(input));
}
public static String getMoneyIntoWords(final double money) {
long dollar = (long) money;
long cents = Math.round((money - dollar) * 100);
if (money == 0D) {
return "";
}
if (money < 0) {
return INVALID_INPUT_GIVEN;
}
String dollarPart = "";
if (dollar > 0) {
dollarPart = convert(dollar) + " dollar" + (dollar == 1 ? "" : "s");
}
String centsPart = "";
if (cents > 0) {
if (dollarPart.length() > 0) {
centsPart = " and ";
}
centsPart += convert(cents) + " cent" + (cents == 1 ? "" : "s");
}
return dollarPart + centsPart;
}
private static String convert(final long n) {
if (n < 0) {
return INVALID_INPUT_GIVEN;
}
if (n < 20) {
return ones[(int) n];
}
if (n < 100) {
return tens[(int) n / 10] + ((n % 10 != 0) ? " " : "") + ones[(int) n % 10];
}
if (n < 1000) {
return ones[(int) n / 100] + " hundred" + ((n % 100 != 0) ? " " : "") + convert(n % 100);
}
if (n < 1_000_000) {
return convert(n / 1000) + " thousand" + ((n % 1000 != 0) ? " " : "") + convert(n % 1000);
}
if (n < 1_000_000_000) {
return convert(n / 1_000_000) + " million" + ((n % 1_000_000 != 0) ? " " : "") + convert(n % 1_000_000);
}
return convert(n / 1_000_000_000) + " billion" + ((n % 1_000_000_000 != 0) ? " " : "") + convert(n % 1_000_000_000);
}
}

View File

@ -0,0 +1,35 @@
package com.baeldung.algorithms.slope_one;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.Data;
@Data
public class InputData {
protected static List<Item> items = Arrays.asList(new Item("Candy"), new Item("Drink"), new Item("Soda"), new Item("Popcorn"), new Item("Snacks"));
public static Map<User, HashMap<Item, Double>> initializeData(int numberOfUsers) {
Map<User, HashMap<Item, Double>> data = new HashMap<>();
HashMap<Item, Double> newUser;
Set<Item> newRecommendationSet;
for (int i = 0; i < numberOfUsers; i++) {
newUser = new HashMap<Item, Double>();
newRecommendationSet = new HashSet<>();
for (int j = 0; j < 3; j++) {
newRecommendationSet.add(items.get((int) (Math.random() * 5)));
}
for (Item item : newRecommendationSet) {
newUser.put(item, Math.random());
}
data.put(new User("User " + i), newUser);
}
return data;
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.algorithms.slope_one;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Item {
private String itemName;
}

View File

@ -0,0 +1,124 @@
package com.baeldung.algorithms.slope_one;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* Slope One algorithm implementation
*/
public class SlopeOne {
private static Map<Item, Map<Item, Double>> diff = new HashMap<>();
private static Map<Item, Map<Item, Integer>> freq = new HashMap<>();
private static Map<User, HashMap<Item, Double>> inputData;
private static Map<User, HashMap<Item, Double>> outputData = new HashMap<>();
public static void slopeOne(int numberOfUsers) {
inputData = InputData.initializeData(numberOfUsers);
System.out.println("Slope One - Before the Prediction\n");
buildDifferencesMatrix(inputData);
System.out.println("\nSlope One - With Predictions\n");
predict(inputData);
}
/**
* Based on the available data, calculate the relationships between the
* items and number of occurences
*
* @param data
* existing user data and their items' ratings
*/
private static void buildDifferencesMatrix(Map<User, HashMap<Item, Double>> data) {
for (HashMap<Item, Double> user : data.values()) {
for (Entry<Item, Double> e : user.entrySet()) {
if (!diff.containsKey(e.getKey())) {
diff.put(e.getKey(), new HashMap<Item, Double>());
freq.put(e.getKey(), new HashMap<Item, Integer>());
}
for (Entry<Item, Double> e2 : user.entrySet()) {
int oldCount = 0;
if (freq.get(e.getKey()).containsKey(e2.getKey())) {
oldCount = freq.get(e.getKey()).get(e2.getKey()).intValue();
}
double oldDiff = 0.0;
if (diff.get(e.getKey()).containsKey(e2.getKey())) {
oldDiff = diff.get(e.getKey()).get(e2.getKey()).doubleValue();
}
double observedDiff = e.getValue() - e2.getValue();
freq.get(e.getKey()).put(e2.getKey(), oldCount + 1);
diff.get(e.getKey()).put(e2.getKey(), oldDiff + observedDiff);
}
}
}
for (Item j : diff.keySet()) {
for (Item i : diff.get(j).keySet()) {
double oldValue = diff.get(j).get(i).doubleValue();
int count = freq.get(j).get(i).intValue();
diff.get(j).put(i, oldValue / count);
}
}
printData(data);
}
/**
* Based on existing data predict all missing ratings. If prediction is not
* possible, the value will be equal to -1
*
* @param data
* existing user data and their items' ratings
*/
private static void predict(Map<User, HashMap<Item, Double>> data) {
HashMap<Item, Double> uPred = new HashMap<Item, Double>();
HashMap<Item, Integer> uFreq = new HashMap<Item, Integer>();
for (Item j : diff.keySet()) {
uFreq.put(j, 0);
uPred.put(j, 0.0);
}
for (Entry<User, HashMap<Item, Double>> e : data.entrySet()) {
for (Item j : e.getValue().keySet()) {
for (Item k : diff.keySet()) {
try {
double predictedValue = diff.get(k).get(j).doubleValue() + e.getValue().get(j).doubleValue();
double finalValue = predictedValue * freq.get(k).get(j).intValue();
uPred.put(k, uPred.get(k) + finalValue);
uFreq.put(k, uFreq.get(k) + freq.get(k).get(j).intValue());
} catch (NullPointerException e1) {
}
}
}
HashMap<Item, Double> clean = new HashMap<Item, Double>();
for (Item j : uPred.keySet()) {
if (uFreq.get(j) > 0) {
clean.put(j, uPred.get(j).doubleValue() / uFreq.get(j).intValue());
}
}
for (Item j : InputData.items) {
if (e.getValue().containsKey(j)) {
clean.put(j, e.getValue().get(j));
} else {
clean.put(j, -1.0);
}
}
outputData.put(e.getKey(), clean);
}
printData(outputData);
}
private static void printData(Map<User, HashMap<Item, Double>> data) {
for (User user : data.keySet()) {
System.out.println(user.getUsername() + ":");
print(data.get(user));
}
}
private static void print(HashMap<Item, Double> hashMap) {
NumberFormat formatter = new DecimalFormat("#0.000");
for (Item j : hashMap.keySet()) {
System.out.println(" " + j.getItemName() + " --> " + formatter.format(hashMap.get(j).doubleValue()));
}
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.algorithms.slope_one;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String username;
}

View File

@ -0,0 +1,104 @@
package com.baeldung.algorithms.sudoku;
import java.util.stream.IntStream;
public class BacktrackingAlgorithm {
private static final int BOARD_SIZE = 9;
private static final int SUBSECTION_SIZE = 3;
private static final int BOARD_START_INDEX = 0;
private static final int NO_VALUE = 0;
private static final int MIN_VALUE = 1;
private static final int MAX_VALUE = 9;
private static int[][] board = {
{8, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 3, 6, 0, 0, 0, 0, 0},
{0, 7, 0, 0, 9, 0, 2, 0, 0},
{0, 5, 0, 0, 0, 7, 0, 0, 0},
{0, 0, 0, 0, 4, 5, 7, 0, 0},
{0, 0, 0, 1, 0, 0, 0, 3, 0},
{0, 0, 1, 0, 0, 0, 0, 6, 8},
{0, 0, 8, 5, 0, 0, 0, 1, 0},
{0, 9, 0, 0, 0, 0, 4, 0, 0}
};
public static void main(String[] args) {
BacktrackingAlgorithm solver = new BacktrackingAlgorithm();
solver.solve(board);
solver.printBoard();
}
private void printBoard() {
for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) {
System.out.print(board[row][column] + " ");
}
System.out.println();
}
}
private boolean solve(int[][] board) {
for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) {
if (board[row][column] == NO_VALUE) {
for (int k = MIN_VALUE; k <= MAX_VALUE; k++) {
board[row][column] = k;
if (isValid(board, row, column) && solve(board)) {
return true;
}
board[row][column] = NO_VALUE;
}
return false;
}
}
}
return true;
}
private boolean isValid(int[][] board, int row, int column) {
return rowConstraint(board, row) &&
columnConstraint(board, column) &&
subsectionConstraint(board, row, column);
}
private boolean subsectionConstraint(int[][] board, int row, int column) {
boolean[] constraint = new boolean[BOARD_SIZE];
int subsectionRowStart = (row / SUBSECTION_SIZE) * SUBSECTION_SIZE;
int subsectionRowEnd = subsectionRowStart + SUBSECTION_SIZE;
int subsectionColumnStart = (column / SUBSECTION_SIZE) * SUBSECTION_SIZE;
int subsectionColumnEnd = subsectionColumnStart + SUBSECTION_SIZE;
for (int r = subsectionRowStart; r < subsectionRowEnd; r++) {
for (int c = subsectionColumnStart; c < subsectionColumnEnd; c++) {
if (!checkConstraint(board, r, constraint, c)) return false;
}
}
return true;
}
private boolean columnConstraint(int[][] board, int column) {
boolean[] constraint = new boolean[BOARD_SIZE];
return IntStream.range(BOARD_START_INDEX, BOARD_SIZE)
.allMatch(row -> checkConstraint(board, row, constraint, column));
}
private boolean rowConstraint(int[][] board, int row) {
boolean[] constraint = new boolean[BOARD_SIZE];
return IntStream.range(BOARD_START_INDEX, BOARD_SIZE)
.allMatch(column -> checkConstraint(board, row, constraint, column));
}
private boolean checkConstraint(int[][] board, int row, boolean[] constraint, int column) {
if (board[row][column] != NO_VALUE) {
if (!constraint[board[row][column] - 1]) {
constraint[board[row][column] - 1] = true;
} else {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,33 @@
package com.baeldung.algorithms.sudoku;
class ColumnNode extends DancingNode {
int size;
String name;
ColumnNode(String n) {
super();
size = 0;
name = n;
C = this;
}
void cover() {
unlinkLR();
for (DancingNode i = this.D; i != this; i = i.D) {
for (DancingNode j = i.R; j != i; j = j.R) {
j.unlinkUD();
j.C.size--;
}
}
}
void uncover() {
for (DancingNode i = this.U; i != this; i = i.U) {
for (DancingNode j = i.L; j != i; j = j.L) {
j.C.size++;
j.relinkUD();
}
}
relinkLR();
}
}

Some files were not shown because too many files have changed in this diff Show More