diff --git a/DIRECTORY.md b/DIRECTORY.md
index 4fa1392a3c17..6ccaf0b38e7f 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -332,6 +332,7 @@
* [MidpointEllipse](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/MidpointEllipse.java)
* [Point](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/Point.java)
* graph
+ * [ConstrainedShortestPath](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/graph/ConstrainedShortestPath.java)
* [StronglyConnectedComponentOptimized](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/graph/StronglyConnectedComponentOptimized.java)
* greedyalgorithms
* [ActivitySelection](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java)
@@ -419,18 +420,13 @@
* [LeastCommonMultiple](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LeastCommonMultiple.java)
* [LeonardoNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LeonardoNumber.java)
* [LinearDiophantineEquationsSolver](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LinearDiophantineEquationsSolver.java)
- * [LiouvilleLambdaFunction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LiouvilleLambdaFunction.java)
* [LongDivision](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LongDivision.java)
* [LucasSeries](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LucasSeries.java)
* [MagicSquare](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MagicSquare.java)
- * [MatrixRank](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MatrixRank.java)
- * [MatrixUtil](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MatrixUtil.java)
* [MaxValue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MaxValue.java)
* [Means](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Means.java)
* [Median](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Median.java)
- * [MillerRabinPrimalityCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MillerRabinPrimalityCheck.java)
* [MinValue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MinValue.java)
- * [MobiusFunction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MobiusFunction.java)
* [Mode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Mode.java)
* [NonRepeatingElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/NonRepeatingElement.java)
* [NthUglyNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/NthUglyNumber.java)
@@ -447,8 +443,13 @@
* [Pow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Pow.java)
* [PowerOfTwoOrNot](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PowerOfTwoOrNot.java)
* [PowerUsingRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PowerUsingRecursion.java)
- * [PrimeCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PrimeCheck.java)
- * [PrimeFactorization](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PrimeFactorization.java)
+ * Prime
+ * [LiouvilleLambdaFunction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Prime/LiouvilleLambdaFunction.java)
+ * [MillerRabinPrimalityCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Prime/MillerRabinPrimalityCheck.java)
+ * [MobiusFunction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Prime/MobiusFunction.java)
+ * [PrimeCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Prime/PrimeCheck.java)
+ * [PrimeFactorization](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Prime/PrimeFactorization.java)
+ * [SquareFreeInteger](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Prime/SquareFreeInteger.java)
* [PronicNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PronicNumber.java)
* [PythagoreanTriple](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PythagoreanTriple.java)
* [QuadraticEquationSolver](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/QuadraticEquationSolver.java)
@@ -458,7 +459,6 @@
* [SieveOfEratosthenes](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java)
* [SimpsonIntegration](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SimpsonIntegration.java)
* [SolovayStrassenPrimalityTest](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java)
- * [SquareFreeInteger](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SquareFreeInteger.java)
* [SquareRootWithBabylonianMethod](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SquareRootWithBabylonianMethod.java)
* [SquareRootWithNewtonRaphsonMethod](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonMethod.java)
* [StandardDeviation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/StandardDeviation.java)
@@ -478,11 +478,14 @@
* [InverseOfMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrix/InverseOfMatrix.java)
* matrixexponentiation
* [Fibonacci](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrix/matrixexponentiation/Fibonacci.java)
+ * [MatrixRank](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrix/MatrixRank.java)
* [MatrixTranspose](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrix/MatrixTranspose.java)
* [MedianOfMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrix/MedianOfMatrix.java)
* [MirrorOfMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrix/MirrorOfMatrix.java)
* [PrintAMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrder.java)
* [RotateMatrixBy90Degrees](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java)
+ * utils
+ * [MatrixUtil](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrix/utils/MatrixUtil.java)
* misc
* [ColorContrastRatio](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/ColorContrastRatio.java)
* [MapReduce](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MapReduce.java)
@@ -499,7 +502,6 @@
* [Sparsity](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/Sparsity.java)
* [ThreeSumProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/ThreeSumProblem.java)
* [TwoSumProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/TwoSumProblem.java)
- * [WordBoggle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/WordBoggle.java)
* others
* [ArrayLeftRotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ArrayLeftRotation.java)
* [ArrayRightRotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ArrayRightRotation.java)
@@ -539,10 +541,12 @@
* [RemoveDuplicateFromString](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/RemoveDuplicateFromString.java)
* [ReverseStackUsingRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ReverseStackUsingRecursion.java)
* [SkylineProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/SkylineProblem.java)
- * [Sudoku](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Sudoku.java)
- * [TowerOfHanoi](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/TowerOfHanoi.java)
* [TwoPointers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/TwoPointers.java)
* [Verhoeff](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Verhoeff.java)
+ * puzzlesandgames
+ * [Sudoku](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java)
+ * [TowerOfHanoi](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java)
+ * [WordBoggle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/puzzlesandgames/WordBoggle.java)
* recursion
* [FibonacciSeries](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java)
* [GenerateSubsets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/recursion/GenerateSubsets.java)
@@ -623,6 +627,7 @@
* [CombSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CombSort.java)
* [CountingSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CountingSort.java)
* [CycleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CycleSort.java)
+ * [DarkSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DarkSort.java)
* [DualPivotQuickSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DualPivotQuickSort.java)
* [DutchNationalFlagSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DutchNationalFlagSort.java)
* [ExchangeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/ExchangeSort.java)
@@ -1008,6 +1013,7 @@
* [MidpointCircleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java)
* [MidpointEllipseTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/MidpointEllipseTest.java)
* graph
+ * [ConstrainedShortestPathTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/graph/ConstrainedShortestPathTest.java)
* [StronglyConnectedComponentOptimizedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/graph/StronglyConnectedComponentOptimizedTest.java)
* greedyalgorithms
* [ActivitySelectionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java)
@@ -1087,17 +1093,12 @@
* [KrishnamurthyNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/KrishnamurthyNumberTest.java)
* [LeastCommonMultipleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LeastCommonMultipleTest.java)
* [LeonardoNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LeonardoNumberTest.java)
- * [LiouvilleLambdaFunctionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LiouvilleLambdaFunctionTest.java)
* [LongDivisionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LongDivisionTest.java)
* [LucasSeriesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LucasSeriesTest.java)
- * [MatrixRankTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MatrixRankTest.java)
- * [MatrixUtilTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MatrixUtilTest.java)
* [MaxValueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MaxValueTest.java)
* [MeansTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MeansTest.java)
* [MedianTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MedianTest.java)
- * [MillerRabinPrimalityCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MillerRabinPrimalityCheckTest.java)
* [MinValueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MinValueTest.java)
- * [MobiusFunctionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MobiusFunctionTest.java)
* [ModeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ModeTest.java)
* [NonRepeatingElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java)
* [NthUglyNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java)
@@ -1113,8 +1114,12 @@
* [PowerOfTwoOrNotTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PowerOfTwoOrNotTest.java)
* [PowerUsingRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PowerUsingRecursionTest.java)
* [PowTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PowTest.java)
- * [PrimeCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PrimeCheckTest.java)
- * [PrimeFactorizationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PrimeFactorizationTest.java)
+ * prime
+ * [LiouvilleLambdaFunctionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/prime/LiouvilleLambdaFunctionTest.java)
+ * [MillerRabinPrimalityCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/prime/MillerRabinPrimalityCheckTest.java)
+ * [MobiusFunctionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/prime/MobiusFunctionTest.java)
+ * [PrimeCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/prime/PrimeCheckTest.java)
+ * [PrimeFactorizationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/prime/PrimeFactorizationTest.java)
* [PronicNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PronicNumberTest.java)
* [PythagoreanTripleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PythagoreanTripleTest.java)
* [QuadraticEquationSolverTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java)
@@ -1139,7 +1144,9 @@
* [VolumeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/VolumeTest.java)
* matrix
* [InverseOfMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/matrix/InverseOfMatrixTest.java)
+ * [MatrixRankTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/matrix/MatrixRankTest.java)
* [MatrixTransposeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/matrix/MatrixTransposeTest.java)
+ * [MatrixUtilTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/matrix/MatrixUtilTest.java)
* [MedianOfMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/matrix/MedianOfMatrixTest.java)
* [MirrorOfMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/matrix/MirrorOfMatrixTest.java)
* [TestPrintMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/matrix/TestPrintMatrixInSpiralOrder.java)
@@ -1154,7 +1161,6 @@
* [SparsityTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/SparsityTest.java)
* [ThreeSumProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/ThreeSumProblemTest.java)
* [TwoSumProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/TwoSumProblemTest.java)
- * [WordBoggleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/WordBoggleTest.java)
* others
* [ArrayLeftRotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ArrayLeftRotationTest.java)
* [ArrayRightRotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ArrayRightRotationTest.java)
@@ -1182,10 +1188,12 @@
* [RemoveDuplicateFromStringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/RemoveDuplicateFromStringTest.java)
* [ReverseStackUsingRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ReverseStackUsingRecursionTest.java)
* [SkylineProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/SkylineProblemTest.java)
- * [SudokuTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/SudokuTest.java)
- * [TowerOfHanoiTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TowerOfHanoiTest.java)
* [TwoPointersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TwoPointersTest.java)
* [WorstFitCPUTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/WorstFitCPUTest.java)
+ * puzzlesandgames
+ * [SudokuTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java)
+ * [TowerOfHanoiTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java)
+ * [WordBoggleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/puzzlesandgames/WordBoggleTest.java)
* recursion
* [FibonacciSeriesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/recursion/FibonacciSeriesTest.java)
* [GenerateSubsetsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/recursion/GenerateSubsetsTest.java)
@@ -1267,6 +1275,7 @@
* [CombSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CombSortTest.java)
* [CountingSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CountingSortTest.java)
* [CycleSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CycleSortTest.java)
+ * [DarkSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DarkSortTest.java)
* [DualPivotQuickSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DualPivotQuickSortTest.java)
* [DutchNationalFlagSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DutchNationalFlagSortTest.java)
* [ExchangeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/ExchangeSortTest.java)
diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java
index 2c6ce8a427d1..d33bd3ee84d9 100644
--- a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java
+++ b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java
@@ -1,53 +1,33 @@
package com.thealgorithms.datastructures.crdt;
+import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
/**
- * Last-Write-Wins Element Set (LWWElementSet) is a state-based CRDT (Conflict-free Replicated Data Type)
- * designed for managing sets in a distributed and concurrent environment. It supports the addition and removal
- * of elements, using timestamps to determine the order of operations. The set is split into two subsets:
- * the add set for elements to be added and the remove set for elements to be removed.
+ * Last-Write-Wins Element Set (LWWElementSet) is a state-based CRDT (Conflict-free Replicated Data
+ * Type) designed for managing sets in a distributed and concurrent environment. It supports the
+ * addition and removal of elements, using timestamps to determine the order of operations. The set
+ * is split into two subsets: the add set for elements to be added and the remove set for elements
+ * to be removed. The LWWElementSet ensures that the most recent operation (based on the timestamp)
+ * wins in the case of concurrent operations.
*
- * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
- * @see Conflict-free_replicated_data_type
- * @see itakurah (Niklas Hoefflin)
+ * @param The type of the elements in the LWWElementSet.
+ * @author itakurah (GitHub), Niklas Hoefflin (LinkedIn)
+ * @see Conflict free
+ * replicated data type (Wikipedia)
+ * @see A comprehensive study of
+ * Convergent and Commutative Replicated Data Types
*/
-
-class Element {
- String key;
- int timestamp;
- Bias bias;
+class LWWElementSet {
+ final Map> addSet;
+ final Map> removeSet;
/**
- * Constructs a new Element with the specified key, timestamp and bias.
- *
- * @param key The key of the element.
- * @param timestamp The timestamp associated with the element.
- * @param bias The bias of the element (ADDS or REMOVALS).
- */
- Element(String key, int timestamp, Bias bias) {
- this.key = key;
- this.timestamp = timestamp;
- this.bias = bias;
- }
-}
-
-enum Bias {
- /**
- * ADDS bias for the add set.
- * REMOVALS bias for the remove set.
- */
- ADDS,
- REMOVALS
-}
-
-class LWWElementSet {
- private final Map addSet;
- private final Map removeSet;
-
- /**
- * Constructs an empty LWWElementSet.
+ * Constructs an empty LWWElementSet. This constructor initializes the addSet and removeSet as
+ * empty HashMaps. The addSet stores elements that are added, and the removeSet stores elements
+ * that are removed.
*/
LWWElementSet() {
this.addSet = new HashMap<>();
@@ -55,84 +35,92 @@ class LWWElementSet {
}
/**
- * Adds an element to the addSet.
+ * Adds an element to the addSet with the current timestamp. This method stores the element in the
+ * addSet, ensuring that the element is added to the set with an associated timestamp that
+ * represents the time of the addition.
*
- * @param e The element to be added.
+ * @param key The key of the element to be added.
*/
- public void add(Element e) {
- addSet.put(e.key, e);
+ public void add(T key) {
+ addSet.put(key, new Element<>(key, Instant.now()));
}
/**
- * Removes an element from the removeSet.
+ * Removes an element by adding it to the removeSet with the current timestamp. This method adds
+ * the element to the removeSet, marking it as removed with the current timestamp.
*
- * @param e The element to be removed.
+ * @param key The key of the element to be removed.
*/
- public void remove(Element e) {
- if (lookup(e)) {
- removeSet.put(e.key, e);
- }
+ public void remove(T key) {
+ removeSet.put(key, new Element<>(key, Instant.now()));
}
/**
- * Checks if an element is in the LWWElementSet by comparing timestamps in the addSet and removeSet.
+ * Checks if an element is in the LWWElementSet. An element is considered present if it exists in
+ * the addSet and either does not exist in the removeSet, or its add timestamp is later than any
+ * corresponding remove timestamp.
*
- * @param e The element to be checked.
- * @return True if the element is present, false otherwise.
+ * @param key The key of the element to be checked.
+ * @return {@code true} if the element is present in the set (i.e., its add timestamp is later
+ * than its remove timestamp, or it is not in the remove set), {@code false} otherwise (i.e.,
+ * the element has been removed or its remove timestamp is later than its add timestamp).
*/
- public boolean lookup(Element e) {
- Element inAddSet = addSet.get(e.key);
- Element inRemoveSet = removeSet.get(e.key);
+ public boolean lookup(T key) {
+ Element inAddSet = addSet.get(key);
+ Element inRemoveSet = removeSet.get(key);
- return (inAddSet != null && (inRemoveSet == null || inAddSet.timestamp > inRemoveSet.timestamp));
+ return inAddSet != null && (inRemoveSet == null || inAddSet.timestamp.isAfter(inRemoveSet.timestamp));
}
/**
- * Compares the LWWElementSet with another LWWElementSet to check if addSet and removeSet are a subset.
+ * Merges another LWWElementSet into this set. This method takes the union of both the add-sets
+ * and remove-sets from the two sets, resolving conflicts by keeping the element with the latest
+ * timestamp. If an element appears in both the add-set and remove-set of both sets, the one with
+ * the later timestamp will be retained.
*
- * @param other The LWWElementSet to compare.
- * @return True if the set is subset, false otherwise.
+ * @param other The LWWElementSet to merge with the current set.
*/
- public boolean compare(LWWElementSet other) {
- return other.addSet.keySet().containsAll(addSet.keySet()) && other.removeSet.keySet().containsAll(removeSet.keySet());
+ public void merge(LWWElementSet other) {
+ for (Map.Entry> entry : other.addSet.entrySet()) {
+ addSet.merge(entry.getKey(), entry.getValue(), this::resolveConflict);
+ }
+ for (Map.Entry> entry : other.removeSet.entrySet()) {
+ removeSet.merge(entry.getKey(), entry.getValue(), this::resolveConflict);
+ }
}
/**
- * Merges another LWWElementSet into this set by resolving conflicts based on timestamps.
+ * Resolves conflicts between two elements by selecting the one with the later timestamp. This
+ * method is used when merging two LWWElementSets to ensure that the most recent operation (based
+ * on timestamps) is kept.
*
- * @param other The LWWElementSet to merge.
+ * @param e1 The first element.
+ * @param e2 The second element.
+ * @return The element with the later timestamp.
*/
- public void merge(LWWElementSet other) {
- for (Element e : other.addSet.values()) {
- if (!addSet.containsKey(e.key) || compareTimestamps(addSet.get(e.key), e)) {
- addSet.put(e.key, e);
- }
- }
-
- for (Element e : other.removeSet.values()) {
- if (!removeSet.containsKey(e.key) || compareTimestamps(removeSet.get(e.key), e)) {
- removeSet.put(e.key, e);
- }
- }
+ private Element resolveConflict(Element e1, Element e2) {
+ return e1.timestamp.isAfter(e2.timestamp) ? e1 : e2;
}
+}
+
+/**
+ * Represents an element in the LWWElementSet, consisting of a key and a timestamp. This class is
+ * used to store the elements in both the add and remove sets with their respective timestamps.
+ *
+ * @param The type of the key associated with the element.
+ */
+class Element {
+ T key;
+ Instant timestamp;
/**
- * Compares timestamps of two elements based on their bias (ADDS or REMOVALS).
+ * Constructs a new Element with the specified key and timestamp.
*
- * @param e The first element.
- * @param other The second element.
- * @return True if the first element's timestamp is greater or the bias is ADDS and timestamps are equal.
+ * @param key The key of the element.
+ * @param timestamp The timestamp associated with the element.
*/
- public boolean compareTimestamps(Element e, Element other) {
- if (e.bias != other.bias) {
- throw new IllegalArgumentException("Invalid bias value");
- }
- Bias bias = e.bias;
- int timestampComparison = Integer.compare(e.timestamp, other.timestamp);
-
- if (timestampComparison == 0) {
- return bias != Bias.ADDS;
- }
- return timestampComparison < 0;
+ Element(T key, Instant timestamp) {
+ this.key = key;
+ this.timestamp = timestamp;
}
}
diff --git a/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java b/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java
index 36593d6669f8..0356949a8f69 100644
--- a/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java
@@ -3,106 +3,96 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import org.junit.jupiter.api.BeforeEach;
+import java.time.Instant;
import org.junit.jupiter.api.Test;
class LWWElementSetTest {
- private LWWElementSet set;
- private final Bias bias = Bias.ADDS;
-
- @BeforeEach
- void setUp() {
- set = new LWWElementSet();
- }
-
@Test
- void testAdd() {
- Element element = new Element("key1", 1, bias);
- set.add(element);
-
- assertTrue(set.lookup(element));
+ void testAddElement() {
+ LWWElementSet set = new LWWElementSet<>();
+ set.add("A");
+ assertTrue(set.lookup("A"));
}
@Test
- void testRemove() {
- Element element = new Element("key1", 1, bias);
- set.add(element);
- set.remove(element);
-
- assertFalse(set.lookup(element));
+ void testRemoveElement() {
+ LWWElementSet set = new LWWElementSet<>();
+ set.add("A");
+ set.remove("A");
+ assertFalse(set.lookup("A"));
}
@Test
- void testRemoveNonexistentElement() {
- Element element = new Element("key1", 1, bias);
- set.remove(element);
-
- assertFalse(set.lookup(element));
+ void testLookupWithoutAdding() {
+ LWWElementSet set = new LWWElementSet<>();
+ assertFalse(set.lookup("A"));
}
@Test
- void testLookupNonexistentElement() {
- Element element = new Element("key1", 1, bias);
+ void testLookupLaterTimestampsFalse() {
+ LWWElementSet set = new LWWElementSet<>();
+
+ set.addSet.put("A", new Element<>("A", Instant.now()));
+ set.removeSet.put("A", new Element<>("A", Instant.now().plusSeconds(10)));
- assertFalse(set.lookup(element));
+ assertFalse(set.lookup("A"));
}
@Test
- void testCompareEqualSets() {
- LWWElementSet otherSet = new LWWElementSet();
+ void testLookupEarlierTimestampsTrue() {
+ LWWElementSet set = new LWWElementSet<>();
- Element element = new Element("key1", 1, bias);
- set.add(element);
- otherSet.add(element);
+ set.addSet.put("A", new Element<>("A", Instant.now()));
+ set.removeSet.put("A", new Element<>("A", Instant.now().minusSeconds(10)));
- assertTrue(set.compare(otherSet));
-
- otherSet.add(new Element("key2", 2, bias));
- assertTrue(set.compare(otherSet));
+ assertTrue(set.lookup("A"));
}
@Test
- void testCompareDifferentSets() {
- LWWElementSet otherSet = new LWWElementSet();
-
- Element element1 = new Element("key1", 1, bias);
- Element element2 = new Element("key2", 2, bias);
-
- set.add(element1);
- otherSet.add(element2);
-
- assertFalse(set.compare(otherSet));
+ void testLookupWithConcurrentTimestamps() {
+ LWWElementSet set = new LWWElementSet<>();
+ Instant now = Instant.now();
+ set.addSet.put("A", new Element<>("A", now));
+ set.removeSet.put("A", new Element<>("A", now));
+ assertFalse(set.lookup("A"));
}
@Test
- void testMerge() {
- LWWElementSet otherSet = new LWWElementSet();
+ void testMergeTwoSets() {
+ LWWElementSet set1 = new LWWElementSet<>();
+ LWWElementSet set2 = new LWWElementSet<>();
- Element element1 = new Element("key1", 1, bias);
- Element element2 = new Element("key2", 2, bias);
+ set1.add("A");
+ set2.add("B");
+ set2.remove("A");
- set.add(element1);
- otherSet.add(element2);
+ set1.merge(set2);
- set.merge(otherSet);
-
- assertTrue(set.lookup(element1));
- assertTrue(set.lookup(element2));
+ assertFalse(set1.lookup("A"));
+ assertTrue(set1.lookup("B"));
}
@Test
- void testCompareTimestampsEqualTimestamps() {
- LWWElementSet lwwElementSet = new LWWElementSet();
+ void testMergeWithConflictingTimestamps() {
+ LWWElementSet set1 = new LWWElementSet<>();
+ LWWElementSet set2 = new LWWElementSet<>();
- Element e1 = new Element("key1", 10, Bias.REMOVALS);
- Element e2 = new Element("key1", 10, Bias.REMOVALS);
+ Instant now = Instant.now();
+ set1.addSet.put("A", new Element<>("A", now.minusSeconds(10)));
+ set2.addSet.put("A", new Element<>("A", now));
- assertTrue(lwwElementSet.compareTimestamps(e1, e2));
+ set1.merge(set2);
- e1 = new Element("key1", 10, Bias.ADDS);
- e2 = new Element("key1", 10, Bias.ADDS);
+ assertTrue(set1.lookup("A"));
+ }
- assertFalse(lwwElementSet.compareTimestamps(e1, e2));
+ @Test
+ void testRemoveOlderThanAdd() {
+ LWWElementSet set = new LWWElementSet<>();
+ Instant now = Instant.now();
+ set.addSet.put("A", new Element<>("A", now));
+ set.removeSet.put("A", new Element<>("A", now.minusSeconds(10)));
+ assertTrue(set.lookup("A"));
}
}