diff --git a/algorithms/.gitignore b/algorithms/.gitignore
new file mode 100644
index 0000000000..b83d22266a
--- /dev/null
+++ b/algorithms/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/algorithms/pom.xml b/algorithms/pom.xml
index 529af19686..884c804d13 100644
--- a/algorithms/pom.xml
+++ b/algorithms/pom.xml
@@ -31,6 +31,11 @@
             <version>${lombok.version}</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+   	 		<groupId>io.jenetics</groupId>
+    		<artifactId>jenetics</artifactId>
+    		<version>3.7.0</version>
+		</dependency>
 	</dependencies>
 
 	<build>
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/Knapsack.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/Knapsack.java
new file mode 100644
index 0000000000..cc99ccf204
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/Knapsack.java
@@ -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);
+    }
+}
\ No newline at end of file
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackFF.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackFF.java
new file mode 100644
index 0000000000..e3e06d301a
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackFF.java
@@ -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;
+    }
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackItem.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackItem.java
new file mode 100644
index 0000000000..876df0ba25
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackItem.java
@@ -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]));
+    }
+
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SimpleGeneticAlgorithm.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SimpleGeneticAlgorithm.java
new file mode 100644
index 0000000000..845e11b349
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SimpleGeneticAlgorithm.java
@@ -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);
+
+    }
+
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenProblem.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenProblem.java
new file mode 100644
index 0000000000..55f2f7af0a
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenProblem.java
@@ -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(", "));
+
+    }
+
+}
\ No newline at end of file
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenRecord.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenRecord.java
new file mode 100644
index 0000000000..b49709e7f5
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenRecord.java
@@ -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);
+    }
+
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SubsetSum.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SubsetSum.java
new file mode 100644
index 0000000000..db1e11239f
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SubsetSum.java
@@ -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);
+    }
+
+}
\ No newline at end of file
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/TravelingSalesman.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/TravelingSalesman.java
new file mode 100644
index 0000000000..80ede0f8c5
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/TravelingSalesman.java
@@ -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);
+    }
+
+}