From 98dfa3787730ee49b78f8bc4f808e0339db40ea3 Mon Sep 17 00:00:00 2001 From: Diego Delgado <105917468+dideldev@users.noreply.github.com> Date: Sat, 28 May 2022 19:22:44 +0200 Subject: [PATCH 001/138] Add Kosaraju Algorithm (#303) Co-authored-by: Diego Delgado Co-authored-by: diego --- Algorithms.Tests/Graph/KosarajuTests.cs | 103 +++++++++++++++++++ Algorithms/Graph/Kosaraju.cs | 127 ++++++++++++++++++++++++ README.md | 1 + 3 files changed, 231 insertions(+) create mode 100644 Algorithms.Tests/Graph/KosarajuTests.cs create mode 100644 Algorithms/Graph/Kosaraju.cs diff --git a/Algorithms.Tests/Graph/KosarajuTests.cs b/Algorithms.Tests/Graph/KosarajuTests.cs new file mode 100644 index 00000000..8e7e6582 --- /dev/null +++ b/Algorithms.Tests/Graph/KosarajuTests.cs @@ -0,0 +1,103 @@ +using Algorithms.Graph; +using DataStructures.Graph; +using NUnit.Framework; +using FluentAssertions; +using System.Collections.Generic; +using System.Linq; + +namespace Algorithms.Tests.Graph +{ + public class KosarajuTests + { + + [Test] + public void GetRepresentativesTest() + { + // Create a graph with some SCC. + var graph = new DirectedWeightedGraph(10); + + var vertex1 = graph.AddVertex(1); + var vertex2 = graph.AddVertex(2); + var vertex3 = graph.AddVertex(3); + var vertex4 = graph.AddVertex(4); + var vertex5 = graph.AddVertex(5); + var vertex6 = graph.AddVertex(6); + var vertex7 = graph.AddVertex(7); + + graph.AddEdge(vertex1, vertex2, 1); + graph.AddEdge(vertex2, vertex3, 1); + graph.AddEdge(vertex3, vertex1, 1); + graph.AddEdge(vertex3, vertex2, 1); + graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex4, vertex5, 1); + graph.AddEdge(vertex5, vertex4, 1); + graph.AddEdge(vertex5, vertex6, 1); + + // Run the agorithm and obtain the representative vertex of the SCC to which each vertex belongs. + Dictionary,Vertex> result = Kosaraju.GetRepresentatives(graph); + + // Check every Vertex belongs to a SCC + result.Should().ContainKey(vertex1); + result.Should().ContainKey(vertex2); + result.Should().ContainKey(vertex3); + result.Should().ContainKey(vertex4); + result.Should().ContainKey(vertex5); + result.Should().ContainKey(vertex6); + result.Should().ContainKey(vertex7); + + // There should be 4 SCC: {1,2,3}, {4,5}, {6} and {7} + // Vertices 1, 2 and 3 are a SCC + result[vertex1].Should().Be(result[vertex2]).And.Be(result[vertex3]); + + // Vertices 4 and 5 are another SCC + result[vertex4].Should().Be(result[vertex5]); + + // And the should have a different representative vertex + result[vertex1].Should().NotBe(result[vertex4]); + + // Vertices 6 and 7 are their own SCC + result[vertex6].Should().Be(vertex6); + result[vertex7].Should().Be(vertex7); + } + + [Test] + public void GetSccTest() + { + // Create a graph with some SCC. + var graph = new DirectedWeightedGraph(10); + + var vertex1 = graph.AddVertex(1); + var vertex2 = graph.AddVertex(2); + var vertex3 = graph.AddVertex(3); + var vertex4 = graph.AddVertex(4); + var vertex5 = graph.AddVertex(5); + var vertex6 = graph.AddVertex(6); + var vertex7 = graph.AddVertex(7); + + graph.AddEdge(vertex1, vertex2, 1); + graph.AddEdge(vertex2, vertex3, 1); + graph.AddEdge(vertex3, vertex1, 1); + graph.AddEdge(vertex3, vertex2, 1); + graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex4, vertex5, 1); + graph.AddEdge(vertex5, vertex4, 1); + graph.AddEdge(vertex5, vertex6, 1); + + // Run the algorithm and get SCC as lists of vertices. + var scc = Kosaraju.GetScc(graph); + + // There should be 4 SCC: {1,2,3}, {4,5}, {6} and {7} + scc.Should().HaveCount(4); + + // Vertices 1, 2 and 3 are a SCC + scc.First(c => c.Contains(vertex1)).Should().Contain(vertex2).And.Contain(vertex3); + + // Vertices 4 and 5 are another SCC + scc.First(c => c.Contains(vertex4)).Should().Contain(vertex5); + + // Vertices 6 and 7 are their own SCC + scc.First(c => c.Contains(vertex6)).Should().HaveCount(1); + scc.First(c => c.Contains(vertex7)).Should().HaveCount(1); + } + } +} diff --git a/Algorithms/Graph/Kosaraju.cs b/Algorithms/Graph/Kosaraju.cs new file mode 100644 index 00000000..d31fa7b5 --- /dev/null +++ b/Algorithms/Graph/Kosaraju.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System.Linq; +using DataStructures.Graph; + +namespace Algorithms.Graph +{ + /// + /// Implementation of Kosaraju-Sharir's algorithm (also known as Kosaraju's algorithm) to find the + /// strongly connected components (SCC) of a directed graph. + /// See https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm. + /// + /// Vertex data type. + public static class Kosaraju + { + /// + /// First DFS for Kosaraju algorithm: traverse the graph creating a reverse order explore list . + /// + /// Vertex to explore. + /// Graph instance. + /// List of already visited vertex. + /// Reversed list of vertex for the second DFS. + public static void Visit(Vertex v, IDirectedWeightedGraph graph, HashSet> visited, Stack> reversed) + { + if (visited.Contains(v)) + { + return; + } + + // Set v as visited + visited.Add(v); + + // Push v in the stack. + // This can also be done with a List, inserting v at the begining of the list + // after visit the neighbors. + reversed.Push(v); + + // Visit neighbors + foreach (var u in graph.GetNeighbors(v)) + { + Visit(u!, graph, visited, reversed); + } + } + + /// + /// Second DFS for Kosaraju algorithm. Traverse the graph in reversed order + /// assigning a root vertex for every vertex that belong to the same SCC. + /// + /// Vertex to assign. + /// Root vertext, representative of the SCC. + /// Graph with vertex and edges. + /// + /// Dictionary that assigns to each vertex the root of the SCC to which it corresponds. + /// + public static void Assign(Vertex v, Vertex root, IDirectedWeightedGraph graph, Dictionary, Vertex> roots) + { + // If v already has a representative vertex (root) already assigned, do nothing. + if (roots.ContainsKey(v)) + { + return; + } + + // Assign the root to the vertex. + roots.Add(v, root); + + // Assign the current root vertex to v neighbors. + foreach (var u in graph.GetNeighbors(v)) + { + Assign(u!, root, graph, roots); + } + } + + /// + /// Find the representative vertex of the SCC for each vertex on the graph. + /// + /// Graph to explore. + /// A dictionary that assigns to each vertex a root vertex of the SCC they belong. + public static Dictionary, Vertex> GetRepresentatives(IDirectedWeightedGraph graph) + { + HashSet> visited = new HashSet>(); + Stack> reversedL = new Stack>(); + Dictionary, Vertex> representatives = new Dictionary, Vertex>(); + + foreach (var v in graph.Vertices) + { + if (v != null) + { + Visit(v, graph, visited, reversedL); + } + } + + visited.Clear(); + + while (reversedL.Count > 0) + { + Vertex v = reversedL.Pop(); + Assign(v, v, graph, representatives); + } + + return representatives; + } + + /// + /// Get the Strongly Connected Components for the graph. + /// + /// Graph to explore. + /// An array of SCC. + public static IEnumerable>[] GetScc(IDirectedWeightedGraph graph) + { + var representatives = GetRepresentatives(graph); + Dictionary, List>> scc = new Dictionary, List>>(); + foreach (var kv in representatives) + { + // Assign all vertex (key) that have the seem root (value) to a single list. + if (scc.ContainsKey(kv.Value)) + { + scc[kv.Value].Add(kv.Key); + } + else + { + scc.Add(kv.Value, new List> { kv.Key }); + } + } + + return scc.Values.ToArray(); + } + } +} diff --git a/README.md b/README.md index 9a4aefc7..5b28e1ba 100755 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ This repository contains algorithms and data structures implemented in C# for ed * [BreadthFirstSearch](./Algorithms/Graph/BreadthFirstSearch.cs) * [DepthFirstSearch](./Algorithms/Graph/DepthFirstSearch.cs) * [Dijkstra Shortest Path](./Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs) + * [Kosaraju](./Algorithms/Graph/Kosaraju.cs) * [Knapsack problem](./Algorithms/Knapsack) * [Naive solver](./Algorithms/Knapsack/NaiveKnapsackSolver.cs) * [Dynamic Programming solver](./Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs) From c3a12721afd6fc8f15d1814919fd0415a4f88cea Mon Sep 17 00:00:00 2001 From: Diego Delgado <105917468+dideldev@users.noreply.github.com> Date: Sat, 11 Jun 2022 21:03:23 +0200 Subject: [PATCH 002/138] Add Manhattan distance and tests (#307) --- .../LinearAlgebra/Distances/ManhattanTests.cs | 40 +++++++++++++++++++ .../LinearAlgebra/Distances/Manhattan.cs | 35 ++++++++++++++++ README.md | 2 + 3 files changed, 77 insertions(+) create mode 100644 Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs create mode 100644 Algorithms/LinearAlgebra/Distances/Manhattan.cs diff --git a/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs b/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs new file mode 100644 index 00000000..29f106cb --- /dev/null +++ b/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs @@ -0,0 +1,40 @@ +using NUnit.Framework; +using Algorithms.LinearAlgebra.Distances; +using FluentAssertions; +using System; + +namespace Algorithms.Tests.LinearAlgebra.Distances +{ + public class ManhattanTests + { + /// + /// Test the result given by Manhattan distance function. + /// + /// Origin point. + /// Target point. + /// Expected result. + [Test] + [TestCase(new[] { 1.5 }, new[] { -1.0 }, 2.5)] + [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0, 5.0 }, 5)] + [TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 1.0, 2.0, 3.0 }, 0)] + [TestCase(new[] { 1.0, 2.0, 3.0, 4.0 }, new[] { 1.75, 2.25, -3.0, 0.5 }, 10.5)] + public void DistanceTest(double[] point1, double[] point2, double expectedDistance) + { + Manhattan.Distance(point1, point2).Should().BeApproximately(expectedDistance, 0.01); + } + + /// + /// Test that it throws ArgumentException if two different dimension arrays are given. + /// + /// First point of N dimensions. + /// Second point of M dimensions, M != N. + [Test] + [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0 })] + [TestCase(new[] { 1.0 }, new[] { 1.0, 2.0, 3.0 })] + public void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2) + { + Action action = () => Manhattan.Distance(point1, point2); + action.Should().Throw(); + } + } +} diff --git a/Algorithms/LinearAlgebra/Distances/Manhattan.cs b/Algorithms/LinearAlgebra/Distances/Manhattan.cs new file mode 100644 index 00000000..1b47563f --- /dev/null +++ b/Algorithms/LinearAlgebra/Distances/Manhattan.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.LinearAlgebra.Distances +{ + /// + /// Implementation fo Manhattan distance. + /// It is the sum of the lengths of the projections of the line segment between the points onto the coordinate axes. + /// In other words, it is the sum of absolute difference between the measures in all dimensions of two points. + /// + /// Its commonly used in regression analysis. + /// + public static class Manhattan + { + /// + /// Calculate Manhattan distance for two N-Dimensional points. + /// + /// First N-Dimensional point. + /// Second N-Dimensional point. + /// Calculated Manhattan distance. + public static double Distance(double[] point1, double[] point2) + { + if (point1.Length != point2.Length) + { + throw new ArgumentException("Both points should have the same dimensionality"); + } + + // distance = |x1-y1| + |x2-y2| + ... + |xn-yn| + return point1.Zip(point2, (x1, x2) => Math.Abs(x1 - x2)).Sum(); + } + } +} diff --git a/README.md b/README.md index 5b28e1ba..e1830c5f 100755 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ This repository contains algorithms and data structures implemented in C# for ed * [Dynamic Programming solver](./Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs) * [Branch and bound solver](./Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs) * [Linear Algebra](./Algorithms/LinearAlgebra) + * [Distances](./Algorithms/LinearAlgebra/Distances) + * [Manhattan](./Algorithms/LinearAlgebra/Distances/Manhattan.cs) * [Eigenvalue](./Algorithms/LinearAlgebra/Eigenvalue) * [Power Iteration](./Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs) * [Numeric](./Algorithms/Numeric) From 143e8a35aa0b017c2bca7dfe12bc2a0a4f8bb1e5 Mon Sep 17 00:00:00 2001 From: Diego Delgado <105917468+dideldev@users.noreply.github.com> Date: Sun, 12 Jun 2022 08:31:43 +0200 Subject: [PATCH 003/138] Add Euclidean distance (#309) Co-authored-by: diego Co-authored-by: Andrii Siriak --- .../LinearAlgebra/Distances/EuclideanTests.cs | 38 +++++++++++++++++++ .../LinearAlgebra/Distances/Euclidean.cs | 31 +++++++++++++++ README.md | 1 + 3 files changed, 70 insertions(+) create mode 100644 Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs create mode 100644 Algorithms/LinearAlgebra/Distances/Euclidean.cs diff --git a/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs b/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs new file mode 100644 index 00000000..72e9b7f8 --- /dev/null +++ b/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs @@ -0,0 +1,38 @@ +using NUnit.Framework; +using Algorithms.LinearAlgebra.Distances; +using FluentAssertions; +using System; + +namespace Algorithms.Tests.LinearAlgebra.Distances +{ + public static class EuclideanTests + { + /// + /// Test the result given by Euclidean distance function. + /// + /// Origin point. + /// Target point. + /// Expected result. + [Test] + [TestCase(new[] { 1.5 }, new[] { -1.0 }, 2.5)] + [TestCase(new[] { 7.0, 4.0, 3.0 }, new[] { 17.0, 6.0, 2.0 }, 10.247)] + public static void DistanceTest(double[] point1, double[] point2, double expectedResult) + { + Euclidean.Distance(point1, point2).Should().BeApproximately(expectedResult, 0.01); + } + + /// + /// Throws ArgumentException if two different dimension arrays are given. + /// + /// First point of N dimensions. + /// Second point of M dimensions, M != N. + [Test] + [TestCase(new[] { 7.0, 4.5 }, new[] { -3.0 })] + [TestCase(new[] { 12.0 }, new[] { 1.5, 7.0, 3.2 })] + public static void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2) + { + Action action = () => Euclidean.Distance(point1, point2); + action.Should().Throw(); + } + } +} diff --git a/Algorithms/LinearAlgebra/Distances/Euclidean.cs b/Algorithms/LinearAlgebra/Distances/Euclidean.cs new file mode 100644 index 00000000..fc893036 --- /dev/null +++ b/Algorithms/LinearAlgebra/Distances/Euclidean.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.LinearAlgebra.Distances +{ + /// + /// Implementation for Euclidean distance. + /// + public static class Euclidean + { + /// + /// Calculate Euclidean distance for two N-Dimensional points. + /// + /// First N-Dimensional point. + /// Second N-Dimensional point. + /// Calculated Euclidean distance. + public static double Distance(double[] point1, double[] point2) + { + if (point1.Length != point2.Length) + { + throw new ArgumentException("Both points should have the same dimensionality"); + } + + // distance = sqrt((x1-y1)^2 + (x2-y2)^2 + ... + (xn-yn)^2) + return Math.Sqrt(point1.Zip(point2, (x1, x2) => (x1 - x2) * (x1 - x2)).Sum()); + } + } +} diff --git a/README.md b/README.md index e1830c5f..2cbeffa0 100755 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ This repository contains algorithms and data structures implemented in C# for ed * [Branch and bound solver](./Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs) * [Linear Algebra](./Algorithms/LinearAlgebra) * [Distances](./Algorithms/LinearAlgebra/Distances) + * [Euclidean](./Algorithms/LinearAlgebra/Distances/Euclidean.cs) * [Manhattan](./Algorithms/LinearAlgebra/Distances/Manhattan.cs) * [Eigenvalue](./Algorithms/LinearAlgebra/Eigenvalue) * [Power Iteration](./Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs) From 1ffea4913e01e0e9efa24dc19e4b314f017eb2b5 Mon Sep 17 00:00:00 2001 From: Diego Delgado <105917468+dideldev@users.noreply.github.com> Date: Sun, 12 Jun 2022 08:51:22 +0200 Subject: [PATCH 004/138] Add optional seed for Fisher yates Shuffler (#310) Co-authored-by: diego Co-authored-by: Andrii Siriak --- .../Shufflers/FisherYatesShufflerTests.cs | 46 ++++++++++++++++++- Algorithms/Shufflers/FisherYatesShuffler.cs | 5 +- Algorithms/Shufflers/IShuffler.cs | 2 +- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs b/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs index c79137f1..b5a5ad44 100644 --- a/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs +++ b/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs @@ -35,11 +35,53 @@ public static void ArrayShuffled_NewArrayHasSameValues( // Act shuffler.Shuffle(testArray); - Array.Sort(testArray); - Array.Sort(correctArray); // Assert testArray.Should().BeEquivalentTo(correctArray); } + + [Test] + public static void ArrayShuffled_SameShuffle( + [Random(0, 1000, 2, Distinct = true)] int n, + [Random(1000, 10000, 5, Distinct = true)] int seed) + { + // Arrange + var shuffler = new FisherYatesShuffler(); + var (array1, array2) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(array1, seed); + shuffler.Shuffle(array2, seed); + + // Assert + array1.Should().BeEquivalentTo(array2, options => options.WithStrictOrdering()); + } + + [Test] + public static void ArrayShuffled_DifferentSeedDifferentShuffle( + [Random(0, 100, 2, Distinct = true)] int n, + [Random(1000, 10000, 5, Distinct = true)] int seed) + { + // Arrange + var shuffler = new FisherYatesShuffler(); + var (array1, array2) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(array1, seed); + shuffler.Shuffle(array2, seed + 13); + + // It seems the actual version of FluentAssertion has no options in NotBeEquivalentTo. + // With default options, it does not check for order, but for the same elements in the collection. + // So until the library is updated check that not all the items have the same order. + int hits = 0; + for (int i = 0; i < n; i++) + { + if (array1[i] == array2[i]) + { + hits++; + } + } + hits.Should().BeLessThan(array2.Length); + } } } diff --git a/Algorithms/Shufflers/FisherYatesShuffler.cs b/Algorithms/Shufflers/FisherYatesShuffler.cs index 03ea41d8..0682625c 100644 --- a/Algorithms/Shufflers/FisherYatesShuffler.cs +++ b/Algorithms/Shufflers/FisherYatesShuffler.cs @@ -16,9 +16,10 @@ public class FisherYatesShuffler : IShuffler /// choose element we use in swap operation. /// /// Array to shuffle. - public void Shuffle(T[] array) + /// Random generator seed. Used to repeat the shuffle. + public void Shuffle(T[] array, int? seed = null) { - var random = new Random(); + var random = seed is null ? new Random() : new Random(seed.Value); for (var i = array.Length - 1; i > 0; i--) { diff --git a/Algorithms/Shufflers/IShuffler.cs b/Algorithms/Shufflers/IShuffler.cs index 16cb3a7a..821f711a 100644 --- a/Algorithms/Shufflers/IShuffler.cs +++ b/Algorithms/Shufflers/IShuffler.cs @@ -10,6 +10,6 @@ public interface IShuffler /// Shuffles array. /// /// Array to Shuffle. - void Shuffle(T[] array); + void Shuffle(T[] array, int? seed = null); } } From 1013d9bffffc0343d0c046f67ab10441e13fad7f Mon Sep 17 00:00:00 2001 From: MatthiasHeinz <7958945+MatthiasHeinz@users.noreply.github.com> Date: Fri, 12 Aug 2022 18:36:47 +0200 Subject: [PATCH 005/138] Add algorithms for Modular Arithmetic (#313) --- .../ChineseRemainderTheoremTest.cs | 193 ++++++++++++++++++ .../ExtendedEuclideanAlgorithmTest.cs | 55 +++++ .../ModularMultiplicativeInverseTest.cs | 68 ++++++ .../ChineseRemainderTheorem.cs | 193 ++++++++++++++++++ .../ExtendedEuclideanAlgorithm.cs | 95 +++++++++ .../ModularMultiplicativeInverse.cs | 65 ++++++ README.md | 4 + 7 files changed, 673 insertions(+) create mode 100644 Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs create mode 100644 Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs create mode 100644 Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs create mode 100644 Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs create mode 100644 Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs create mode 100644 Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs diff --git a/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs b/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs new file mode 100644 index 00000000..06289e3a --- /dev/null +++ b/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs @@ -0,0 +1,193 @@ +using Algorithms.ModularArithmetic; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace Algorithms.Tests.ModularArithmetic +{ + public static class ChineseRemainderTheoremTest + { + [Test] + public static void TestCompute1() + { + var expected = 43L; + + // Act + var x = ChineseRemainderTheorem.Compute(new List { 1L, 1L, 3L, 1L }, new List { 2L, 3L, 5L, 7L }); + + // Assert + Assert.AreEqual(expected, x); + } + + [Test] + public static void TestCompute2() + { + var expected = 100L; + + // Act + var x = ChineseRemainderTheorem.Compute(new List { 0L, 0L, 2L, 1L, 1L }, new List { 2L, 5L, 7L, 9L, 11L }); + + // Assert + Assert.AreEqual(expected, x); + } + + [Test] + public static void TestCompute3() + { + var expected = 13L; + + // Act + var x = ChineseRemainderTheorem.Compute(new List { 1L, 4L, 13L }, new List { 4L, 9L, 25L }); + + // Assert + Assert.AreEqual(expected, x); + } + + [Test] + public static void TestCompute_RequirementsNotMet_ArgumentLengthDifferent() + { + // Act + void Act() => ChineseRemainderTheorem.Compute(new List(), new List { 5L }); + + // Assert + _ = Assert.Throws(Act); + } + + [Test] + public static void TestCompute_RequirementsNotMet_NTooSmall() + { + foreach (var n in new List { long.MinValue, -1L, 0L, 1L }) + { + // Act + void Act() => ChineseRemainderTheorem.Compute(new List { 1L }, new List { n }); + + // Assert + _ = Assert.Throws(Act); + } + } + + [Test] + public static void TestCompute_RequirementsNotMet_ATooSmall() + { + foreach (var a in new List { long.MinValue, -2L, -1L }) + { + // Act + void Act() => ChineseRemainderTheorem.Compute(new List { a }, new List { 3L }); + + // Assert + _ = Assert.Throws(Act); + } + } + + [Test] + public static void TestCompute_RequirementsNotMet_NNotCoprime() + { + foreach (var n in new List { 3L, 9L, 15L, 27L }) + { + // Act + void Act() => ChineseRemainderTheorem.Compute(new List { 1L, 1L, 1L, 1L, 1L }, new List { 2L, 3L, 5L, 7L, n }); + + // Assert + _ = Assert.Throws(Act); + } + } + + [Test] + public static void TestCompute_BigInteger_1() + { + var expected = new BigInteger(43); + + // Act + var x = ChineseRemainderTheorem.Compute( + new List { BigInteger.One, BigInteger.One, new BigInteger(3), BigInteger.One }, + new List { new BigInteger(2), new BigInteger(3), new BigInteger(5), new BigInteger(7) } + ); + + // Assert + Assert.AreEqual(expected, x); + } + + [Test] + public static void TestCompute_BigInteger_2() + { + var expected = new BigInteger(100); + + // Act + var x = ChineseRemainderTheorem.Compute( + new List { BigInteger.Zero, BigInteger.Zero, new BigInteger(2), BigInteger.One, BigInteger.One }, + new List { new BigInteger(2), new BigInteger(5), new BigInteger(7), new BigInteger(9), new BigInteger(11) } + ); + + // Assert + Assert.AreEqual(expected, x); + } + + [Test] + public static void TestCompute_BigInteger_3() + { + var expected = new BigInteger(13); + + // Act + var x = ChineseRemainderTheorem.Compute( + new List { BigInteger.One, new BigInteger(4), new BigInteger(13) }, + new List { new BigInteger(4), new BigInteger(9), new BigInteger(25) } + ); + + // Assert + Assert.AreEqual(expected, x); + } + + [Test] + public static void TestCompute_BigInteger_RequirementsNotMet_ArgumentLengthDifferent() + { + // Act + void Act() => ChineseRemainderTheorem.Compute(new List(), new List { new BigInteger(5) }); + + // Assert + _ = Assert.Throws(Act); + } + + [Test] + public static void TestCompute_BigInteger_RequirementsNotMet_NTooSmall() + { + foreach (var n in new List { new BigInteger(long.MinValue), BigInteger.MinusOne, BigInteger.Zero, BigInteger.One }) + { + // Act + void Act() => ChineseRemainderTheorem.Compute(new List { BigInteger.One }, new List { n }); + + // Assert + _ = Assert.Throws(Act); + } + } + + [Test] + public static void TestCompute_BigInteger_RequirementsNotMet_ATooSmall() + { + foreach (var a in new List { new BigInteger(long.MinValue), new BigInteger(-2), BigInteger.MinusOne }) + { + // Act + void Act() => ChineseRemainderTheorem.Compute(new List { a }, new List { new BigInteger(3) }); + + // Assert + _ = Assert.Throws(Act); + } + } + + [Test] + public static void TestCompute_BigInteger_RequirementsNotMet_NNotCoprime() + { + foreach (var n in new List { new BigInteger(3), new BigInteger(9), new BigInteger(15), new BigInteger(27) }) + { + // Act + void Act() => ChineseRemainderTheorem.Compute( + new List { BigInteger.One, BigInteger.One, BigInteger.One, BigInteger.One, BigInteger.One }, + new List { new BigInteger(2), new BigInteger(3), new BigInteger(5), new BigInteger(7), n } + ); + + // Assert + _ = Assert.Throws(Act); + } + } + } +} diff --git a/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs b/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs new file mode 100644 index 00000000..aa9eaa33 --- /dev/null +++ b/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs @@ -0,0 +1,55 @@ +using Algorithms.ModularArithmetic; +using NUnit.Framework; +using System.Numerics; + +namespace Algorithms.Tests.ModularArithmetic +{ + public static class ExtendedEuclideanAlgorithmTest + { + [Test] + [TestCase(240, 46, 2, -9, 47)] + [TestCase(46, 240, 2, 47, -9)] + [TestCase(2, 3, 1, -1, 1)] + [TestCase(1, 1, 1, 0, 1)] + [TestCase(13, 17, 1, 4, -3)] + [TestCase(0, 17, 17, 0, 1)] + [TestCase(17, 0, 17, 1, 0)] + [TestCase(17, 17, 17, 0, 1)] + [TestCase(2 * 17, 17, 17, 0, 1)] + [TestCase(0, 0, 0, 1, 0)] + [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13, -1, 1)] + public static void TestCompute(long a, long b, long expectedGCD, long expectedBezoutOfA, long expectedBezoutOfB) + { + // Act + var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, b); + + // Assert + Assert.AreEqual(expectedGCD, eeaResult.gcd); + Assert.AreEqual(expectedBezoutOfA, eeaResult.bezoutA); + Assert.AreEqual(expectedBezoutOfB, eeaResult.bezoutB); + } + + [Test] + [TestCase(240, 46, 2, -9, 47)] + [TestCase(46, 240, 2, 47, -9)] + [TestCase(2, 3, 1, -1, 1)] + [TestCase(1, 1, 1, 0, 1)] + [TestCase(13, 17, 1, 4, -3)] + [TestCase(0, 17, 17, 0, 1)] + [TestCase(17, 0, 17, 1, 0)] + [TestCase(17, 17, 17, 0, 1)] + [TestCase(2 * 17, 17, 17, 0, 1)] + [TestCase(0, 0, 0, 1, 0)] + [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13, -1, 1)] + public static void TestCompute_BigInteger(long a, long b, long expectedGCD, long expectedBezoutOfA, long expectedBezoutOfB) + { + // Act + var eeaResult = ExtendedEuclideanAlgorithm.Compute(new BigInteger(a), new BigInteger(b)); + + // Assert + Assert.AreEqual(new BigInteger(expectedGCD), eeaResult.gcd); + Assert.AreEqual(new BigInteger(expectedBezoutOfA), eeaResult.bezoutA); + Assert.AreEqual(new BigInteger(expectedBezoutOfB), eeaResult.bezoutB); + } + } +} diff --git a/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs b/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs new file mode 100644 index 00000000..37d2de0a --- /dev/null +++ b/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs @@ -0,0 +1,68 @@ +using Algorithms.ModularArithmetic; +using NUnit.Framework; +using System; +using System.Numerics; + +namespace Algorithms.Tests.ModularArithmetic +{ + public static class ModularMultiplicativeInverseTest + { + [Test] + [TestCase(2, 3, 2)] + [TestCase(1, 1, 0)] + [TestCase(13, 17, 4)] + public static void TestCompute(long a, long n, long expected) + { + // Act + var inverse = ModularMultiplicativeInverse.Compute(a, n); + + // Assert + Assert.AreEqual(expected, inverse); + } + + [Test] + [TestCase(46, 240)] + [TestCase(0, 17)] + [TestCase(17, 0)] + [TestCase(17, 17)] + [TestCase(0, 0)] + [TestCase(2 * 13 * 17, 4 * 9 * 13)] + public static void TestCompute_Irrevertible(long a, long n) + { + // Act + void Act() => ModularMultiplicativeInverse.Compute(a, n); + + // Assert + _ = Assert.Throws(Act); + } + + [Test] + [TestCase(2, 3, 2)] + [TestCase(1, 1, 0)] + [TestCase(13, 17, 4)] + public static void TestCompute_BigInteger(long a, long n, long expected) + { + // Act + var inverse = ModularMultiplicativeInverse.Compute(new BigInteger(a), new BigInteger(n)); + + // Assert + Assert.AreEqual(new BigInteger(expected), inverse); + } + + [Test] + [TestCase(46, 240)] + [TestCase(0, 17)] + [TestCase(17, 0)] + [TestCase(17, 17)] + [TestCase(0, 0)] + [TestCase(2 * 13 * 17, 4 * 9 * 13)] + public static void TestCompute_BigInteger_Irrevertible(long a, long n) + { + // Act + void Act() => ModularMultiplicativeInverse.Compute(new BigInteger(a), new BigInteger(n)); + + // Assert + _ = Assert.Throws(Act); + } + } +} diff --git a/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs b/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs new file mode 100644 index 00000000..a8b702a6 --- /dev/null +++ b/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +namespace Algorithms.ModularArithmetic +{ + /// + /// Chinese Remainder Theorem: https://en.wikipedia.org/wiki/Chinese_remainder_theorem. + /// + public static class ChineseRemainderTheorem + { + /// + /// The Chinese Remainder Theorem is used to compute x for given set of pairs of integers (a_i, n_i) with: + /// + /// x = a_0 mod n_0 + /// x = a_1 mod n_1 + /// ... + /// x = a_k mod n_k + /// + /// for 0 <= i < k, for some positive integer k. Additional requirements are: + /// + /// n_i > 1 for 0 <= i < k + /// n_i and n_j are coprime, for all 0 <= i < j < k + /// 0 <= a_i < n_i, for all 0 <= i < k + /// 0 <= x < n_0 * n_1 * ... * n_(k-1) + /// + /// + /// An ordered list of a_0, a_1, ..., a_k. + /// An ordered list of n_0, n_1, ..., n_k. + /// The value x. + /// If any of the requirements is not fulfilled. + public static long Compute(List listOfAs, List listOfNs) + { + // Check the requirements for this algorithm: + CheckRequirements(listOfAs, listOfNs); + + // For performance-reasons compute the product of all n_i as prodN, because we're going to need access to (prodN / n_i) for all i: + var prodN = 1L; + foreach (var n in listOfNs) + { + prodN *= n; + } + + var result = 0L; + for (var i = 0; i < listOfNs.Count; i++) + { + var a_i = listOfAs[i]; + var n_i = listOfNs[i]; + var modulus_i = prodN / n_i; + + var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).bezoutB; + result += a_i * bezout_modulus_i * modulus_i; + } + + // Make sure, result is in [0, prodN). + result %= prodN; + if (result < 0) + { + result += prodN; + } + + return result; + } + + /// + /// The Chinese Remainder Theorem is used to compute x for given set of pairs of integers (a_i, n_i) with: + /// + /// x = a_0 mod n_0 + /// x = a_1 mod n_1 + /// ... + /// x = a_k mod n_k + /// + /// for 0 <= i < k, for some positive integer k. Additional requirements are: + /// + /// n_i > 1 for 0 <= i < k + /// n_i and n_j are coprime, for all 0 <= i < j < k + /// 0 <= a_i < n_i, for all 0 <= i < k + /// 0 <= x < n_0 * n_1 * ... * n_(k-1) + /// + /// + /// An ordered list of a_0, a_1, ..., a_k. + /// An ordered list of n_0, n_1, ..., n_k. + /// The value x. + /// If any of the requirements is not fulfilled. + public static BigInteger Compute(List listOfAs, List listOfNs) + { + // Check the requirements for this algorithm: + CheckRequirements(listOfAs, listOfNs); + + // For performance-reasons compute the product of all n_i as prodN, because we're going to need access to (prodN / n_i) for all i: + var prodN = BigInteger.One; + foreach (var n in listOfNs) + { + prodN *= n; + } + + var result = BigInteger.Zero; + for (var i = 0; i < listOfNs.Count; i++) + { + var a_i = listOfAs[i]; + var n_i = listOfNs[i]; + var modulus_i = prodN / n_i; + + var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).bezoutB; + result += a_i * bezout_modulus_i * modulus_i; + } + + // Make sure, result is in [0, prodN). + result %= prodN; + if (result < 0) + { + result += prodN; + } + + return result; + } + + /// + /// Checks the requirements for the algorithm and throws an ArgumentException if they are not being met. + /// + /// An ordered list of a_0, a_1, ..., a_k. + /// An ordered list of n_0, n_1, ..., n_k. + /// If any of the requirements is not fulfilled. + private static void CheckRequirements(List listOfAs, List listOfNs) + { + if (listOfAs == null || listOfNs == null || listOfAs.Count != listOfNs.Count) + { + throw new ArgumentException("The parameters 'listOfAs' and 'listOfNs' must not be null and have to be of equal length!"); + } + + if (listOfNs.Any(x => x <= 1)) + { + throw new ArgumentException($"The value {listOfNs.First(x => x <= 1)} for some n_i is smaller than or equal to 1."); + } + + if (listOfAs.Any(x => x < 0)) + { + throw new ArgumentException($"The value {listOfAs.First(x => x < 0)} for some a_i is smaller than 0."); + } + + // Check if all pairs of (n_i, n_j) are coprime: + for (var i = 0; i < listOfNs.Count; i++) + { + for (var j = i + 1; j < listOfNs.Count; j++) + { + long gcd; + if ((gcd = ExtendedEuclideanAlgorithm.Compute(listOfNs[i], listOfNs[j]).gcd) != 1L) + { + throw new ArgumentException($"The GCD of n_{i} = {listOfNs[i]} and n_{j} = {listOfNs[j]} equals {gcd} and thus these values aren't coprime."); + } + } + } + } + + /// + /// Checks the requirements for the algorithm and throws an ArgumentException if they are not being met. + /// + /// An ordered list of a_0, a_1, ..., a_k. + /// An ordered list of n_0, n_1, ..., n_k. + /// If any of the requirements is not fulfilled. + private static void CheckRequirements(List listOfAs, List listOfNs) + { + if (listOfAs == null || listOfNs == null || listOfAs.Count != listOfNs.Count) + { + throw new ArgumentException("The parameters 'listOfAs' and 'listOfNs' must not be null and have to be of equal length!"); + } + + if (listOfNs.Any(x => x <= 1)) + { + throw new ArgumentException($"The value {listOfNs.First(x => x <= 1)} for some n_i is smaller than or equal to 1."); + } + + if (listOfAs.Any(x => x < 0)) + { + throw new ArgumentException($"The value {listOfAs.First(x => x < 0)} for some a_i is smaller than 0."); + } + + // Check if all pairs of (n_i, n_j) are coprime: + for (var i = 0; i < listOfNs.Count; i++) + { + for (var j = i + 1; j < listOfNs.Count; j++) + { + BigInteger gcd; + if ((gcd = ExtendedEuclideanAlgorithm.Compute(listOfNs[i], listOfNs[j]).gcd) != BigInteger.One) + { + throw new ArgumentException($"The GCD of n_{i} = {listOfNs[i]} and n_{j} = {listOfNs[j]} equals {gcd} and thus these values aren't coprime."); + } + } + } + } + } +} diff --git a/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs b/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs new file mode 100644 index 00000000..19481fcd --- /dev/null +++ b/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs @@ -0,0 +1,95 @@ +using System.Numerics; + +namespace Algorithms.ModularArithmetic +{ + /// + /// Extended Euclidean algorithm: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm. + /// + public static class ExtendedEuclideanAlgorithm + { + /// + /// Computes the greatest common divisor (gcd) of integers a and b, also the coefficients of Bézout's identity, + /// which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = gcd(a, b). + /// + /// Input number. + /// Second input number. + /// A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the gcd(a,b). + public static ExtendedEuclideanAlgorithmResult Compute(long a, long b) + { + long quotient; + long tmp; + var s = 0L; + var bezoutOfA = 1L; + var r = b; + var gcd = a; + var bezoutOfB = 0L; + + while (r != 0) + { + quotient = gcd / r; // integer division + + tmp = gcd; + gcd = r; + r = tmp - quotient * r; + + tmp = bezoutOfA; + bezoutOfA = s; + s = tmp - quotient * s; + } + + if (b != 0) + { + bezoutOfB = (gcd - bezoutOfA * a) / b; // integer division + } + + return new ExtendedEuclideanAlgorithmResult(bezoutOfA, bezoutOfB, gcd); + } + + /// + /// Computes the greatest common divisor (gcd) of integers a and b, also the coefficients of Bézout's identity, + /// which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = gcd(a, b). + /// + /// Input number. + /// Second input number. + /// A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the gcd(a,b). + public static ExtendedEuclideanAlgorithmResult Compute(BigInteger a, BigInteger b) + { + BigInteger quotient; + BigInteger tmp; + var s = BigInteger.Zero; + var bezoutOfA = BigInteger.One; + var r = b; + var gcd = a; + var bezoutOfB = BigInteger.Zero; + + while (r != 0) + { + quotient = gcd / r; // integer division + + tmp = gcd; + gcd = r; + r = tmp - quotient * r; + + tmp = bezoutOfA; + bezoutOfA = s; + s = tmp - quotient * s; + } + + if (b != 0) + { + bezoutOfB = (gcd - bezoutOfA * a) / b; // integer division + } + + return new ExtendedEuclideanAlgorithmResult(bezoutOfA, bezoutOfB, gcd); + } + + /// + /// The result type for the computation of the Extended Euclidean Algorithm. + /// + /// The data type of the computation (i.e. long or BigInteger). + /// The bezout coefficient of the parameter a to the computation. + /// The bezout coefficient of the parameter b to the computation. + /// The greatest common divisor of the parameters a and b to the computation. + public record ExtendedEuclideanAlgorithmResult(T bezoutA, T bezoutB, T gcd); + } +} diff --git a/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs b/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs new file mode 100644 index 00000000..e1ba724c --- /dev/null +++ b/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs @@ -0,0 +1,65 @@ +using System; +using System.Numerics; + +namespace Algorithms.ModularArithmetic +{ + /// + /// Modular multiplicative inverse: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse. + /// + public static class ModularMultiplicativeInverse + { + /// + /// Computes the modular multiplicative inverse of a in Z/nZ, if there is any (i.e. if a and n are coprime). + /// + /// The number a, of which to compute the multiplicative inverse. + /// The modulus n. + /// The multiplicative inverse of a in Z/nZ, a value in the interval [0, n). + /// If there exists no multiplicative inverse of a in Z/nZ. + public static long Compute(long a, long n) + { + var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, n); + + // Check if there is an inverse: + if (eeaResult.gcd != 1) + { + throw new ArithmeticException($"{a} is not invertible in Z/{n}Z."); + } + + // Make sure, inverseOfA (i.e. the bezout coefficient of a) is in the interval [0, n). + var inverseOfA = eeaResult.bezoutA; + if (inverseOfA < 0) + { + inverseOfA += n; + } + + return inverseOfA; + } + + /// + /// Computes the modular multiplicative inverse of a in Z/nZ, if there is any (i.e. if a and n are coprime). + /// + /// The number a, of which to compute the multiplicative inverse. + /// The modulus n. + /// The multiplicative inverse of a in Z/nZ, a value in the interval [0, n). + /// If there exists no multiplicative inverse of a in Z/nZ. + public static BigInteger Compute(BigInteger a, BigInteger n) + { + var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, n); + + // Check if there is an inverse: + if (eeaResult.gcd != 1) + { + throw new ArithmeticException($"{a} is not invertible in Z/{n}Z."); + } + + // Make sure, inverseOfA (i.e. the bezout coefficient of a) is in the interval [0, n). + var inverseOfA = eeaResult.bezoutA; + if (inverseOfA < 0) + { + inverseOfA += n; + } + + return inverseOfA; + } + } +} diff --git a/README.md b/README.md index 2cbeffa0..4a7f8cc9 100755 --- a/README.md +++ b/README.md @@ -38,6 +38,10 @@ This repository contains algorithms and data structures implemented in C# for ed * [Manhattan](./Algorithms/LinearAlgebra/Distances/Manhattan.cs) * [Eigenvalue](./Algorithms/LinearAlgebra/Eigenvalue) * [Power Iteration](./Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs) + * [Modular Arithmetic](./Algorithms/ModularArithmetic) + * [Chinese Remainder Theorem](./Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs) + * [Extended Euclidean Algorithm](./Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs) + * [Modular Multiplicative Inverse](./Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs) * [Numeric](./Algorithms/Numeric) * [Aliquot Sum Calculator](./Algorithms/Numeric/AliquotSumCalculator.cs) * [Decomposition](./Algorithms/Numeric/Decomposition) From 24a3bd3dd41dec6b6808d083780d3a31ad760a91 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Sun, 14 Aug 2022 10:52:02 +0300 Subject: [PATCH 006/138] Fix blinking test coverage (#321) --- Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs | 2 ++ Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs b/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs index 1bed1903..2f404ba9 100644 --- a/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs +++ b/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs @@ -15,6 +15,8 @@ public static class MillerRabinPrimalityTest [TestCase("2476099", ExpectedResult = false)] // false 19^5 // false 247894109041876714378152933343208766493*315757551269487563269454472438030700351 [TestCase("78274436845194327170519855212507883195883737501141260366253362532531612139043", ExpectedResult = false)] + [Repeat(5)] + [Retry(3)] public static bool MillerRabinPrimalityWork(String testcase) { // Arrange diff --git a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs index 0b97d814..18647458 100755 --- a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs @@ -12,7 +12,7 @@ public static class TimSorterTests [Test] public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] + [Random(0, 10_000, 200, Distinct = true)] int n) { // Arrange From 364bbc1112346ecfb0d35bdc202336c00f8edd94 Mon Sep 17 00:00:00 2001 From: Anton Minko Date: Sun, 14 Aug 2022 10:17:51 +0200 Subject: [PATCH 007/138] Add Skip List (#319) --- .../LinkedList/SkipListTests.cs | 123 ++++++++++ .../LinkedList/SkipList/SkipList.cs | 220 ++++++++++++++++++ .../LinkedList/SkipList/SkipListNode.cs | 25 ++ README.md | 1 + 4 files changed, 369 insertions(+) create mode 100644 DataStructures.Tests/LinkedList/SkipListTests.cs create mode 100644 DataStructures/LinkedList/SkipList/SkipList.cs create mode 100644 DataStructures/LinkedList/SkipList/SkipListNode.cs diff --git a/DataStructures.Tests/LinkedList/SkipListTests.cs b/DataStructures.Tests/LinkedList/SkipListTests.cs new file mode 100644 index 00000000..87e8bceb --- /dev/null +++ b/DataStructures.Tests/LinkedList/SkipListTests.cs @@ -0,0 +1,123 @@ +using System; +using DataStructures.LinkedList.SkipList; +using NUnit.Framework; +using FluentAssertions; +using System.Collections.Generic; + +namespace DataStructures.Tests.LinkedList +{ + public static class SkipListTests + { + [Test] + public static void TestAdd() + { + var list = new SkipList(); + list.AddOrUpdate(1, 1); + list[2] = 2; + list[3] = 3; + + list.Count.Should().Be(3); + list.GetValues().Should().ContainInOrder(1, 2, 3); + } + + [Test] + public static void TestUpdate() + { + var list = new SkipList(); + + // Add some elements. + list[1] = "v1"; + list[2] = "v2"; + list[5] = "v5"; + + // Update + list.AddOrUpdate(1, "v1-updated"); + list[2] = "v2-updated"; + + list.Count.Should().Be(3); + list.GetValues().Should().ContainInOrder("v1-updated", "v2-updated", "v5"); + } + + [Test] + public static void TestContains() + { + var list = new SkipList(); + list.AddOrUpdate(1, 1); + list.AddOrUpdate(3, 3); + list.AddOrUpdate(5, 5); + + list.Contains(1).Should().BeTrue(); + list.Contains(3).Should().BeTrue(); + list.Contains(5).Should().BeTrue(); + list.Contains(0).Should().BeFalse(); + list.Contains(2).Should().BeFalse(); + list.Contains(9).Should().BeFalse(); + } + + [Test] + public static void TestGetByKey_Success() + { + var list = new SkipList(); + list[1] = "value1"; + + list[1].Should().Be("value1"); + } + + [Test] + public static void TestGetByKey_KeyNotFoundException() + { + var list = new SkipList(); + list[1] = "value1"; + + String value; + Action act = () => value = list[2]; + act.Should().Throw(); + } + + [Test] + public static void TestRemove_ItemRemoved() + { + var list = new SkipList(); + list.AddOrUpdate(1, 1); + list.AddOrUpdate(2, 2); + list.AddOrUpdate(3, 3); + + list.Count.Should().Be(3); + list.Contains(2).Should().BeTrue(); + + var isRemoved = list.Remove(2); + + list.Count.Should().Be(2); + list.Contains(2).Should().BeFalse(); + isRemoved.Should().BeTrue(); + } + + [Test] + public static void TestRemove_ItemNotFound() + { + var list = new SkipList(); + list.AddOrUpdate(1, 1); + list.AddOrUpdate(2, 2); + list.AddOrUpdate(3, 3); + + var isRemoved = list.Remove(222); + + list.Count.Should().Be(3); + isRemoved.Should().BeFalse(); + } + + [Test] + public static void TestGetValues() + { + var list = new SkipList(); + list[4] = "four"; + list[2] = "two"; + list[3] = "three"; + list[1] = "one"; + + var valuesSortedByKey = list.GetValues(); + + valuesSortedByKey.Should().ContainInOrder("one", "two", "three", "four"); + } + } +} \ No newline at end of file diff --git a/DataStructures/LinkedList/SkipList/SkipList.cs b/DataStructures/LinkedList/SkipList/SkipList.cs new file mode 100644 index 00000000..926e53da --- /dev/null +++ b/DataStructures/LinkedList/SkipList/SkipList.cs @@ -0,0 +1,220 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace DataStructures.LinkedList.SkipList +{ + /// + /// Skip list implementation that is based on the singly linked list, + /// but offers O(log n) time complexity on most operations. + /// + /// The type of the values in the list. + /// + /// Skip list nodes sorted by key. + /// The "skip lanes" allow searching for a node in O(log n) time on average. + /// The worst case performence is O(n) when the height of all nodes is 1 (very + /// unluckily to happen on any decent list size). + /// These two properties make the skip list an excellent data structure for + /// implementing additional operations like finding min/max value in the list, + /// finding values with the key in a given range, etc. + /// + /// Sourses: + /// - "Skip Lists: A Probabilistic Alternative to Balanced Trees" by William Pugh. + /// - https://en.wikipedia.org/wiki/Skip_list + /// - https://iq.opengenus.org/skip-list/ + /// - https://medium.com/simple-computer-science/data-structures-basics-skip-list-8b8c69f9a044 + /// - https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java + /// + /// The key is hardcoded to be of type int to simplify the implementation, + /// but it can be easily an any generic type that implements IComparable. + /// + [DebuggerDisplay("Count = {Count}")] + public class SkipList + { + private const double Probability = 0.5; + private readonly int maxLevels; + private readonly SkipListNode head; + private readonly SkipListNode tail; + private readonly Random random = new Random(); + + /// + /// Initializes a new instance of the class. + /// + /// Expected number of elements the list might contain. + public SkipList(int capacity = 255) + { + maxLevels = (int)Math.Log2(capacity) + 1; + + head = new(int.MinValue, default(TValue), maxLevels); + tail = new(int.MaxValue, default(TValue), maxLevels); + + for(int i = 0; i < maxLevels; i++) + { + head.Next[i] = tail; + } + } + + /// + /// Gets the number of elements currently in the list. + /// + public int Count { get; private set; } + + /// + /// Gets or sets the element with the specified key. + /// + /// The key is not present in the list. + public TValue this[int key] + { + get + { + var previousNode = GetSkipNodes(key).First(); + if(previousNode.Next[0].Key == key) + { + return previousNode.Next[0].Value!; + } + else + { + throw new KeyNotFoundException(); + } + } + + set => AddOrUpdate(key, value); + } + + /// + /// Adds an element with the specified key and value to the list. + /// If an element with the same key already exists, updates its value. + /// + /// The key of the element to add. + /// The value of the element to add. + /// + /// Time complexity: O(log n) where n is the number of elements in the list. + /// + public void AddOrUpdate(int key, TValue value) + { + var skipNodes = GetSkipNodes(key); + + var previousNode = skipNodes.First(); + if (previousNode.Next[0].Key == key) + { + // Node with the given key already exists. + // Update its value. + previousNode.Next[0].Value = value; + return; + } + + // Node with the given key does not exist. + // Insert the new one and update the skip nodes. + var newNode = new SkipListNode(key, value, GetRandomHeight()); + for (var level = 0; level < newNode.Height; level++) + { + newNode.Next[level] = skipNodes[level].Next[level]; + skipNodes[level].Next[level] = newNode; + } + + Count++; + } + + /// + /// Returns whether a value with the given key exists in the list. + /// + /// + /// Time complexity: O(log n) where n is the number of elements in the list. + /// + public bool Contains(int key) + { + var previousNode = GetSkipNodes(key).First(); + return previousNode.Next[0].Key == key; + } + + /// + /// Removes the value with the given key from the list. + /// + /// + /// true if the value was removed; otherwise, false. + /// + /// + /// Time complexity: O(log n) where n is the number of elements in the list. + /// + public bool Remove(int key) + { + var skipNodes = GetSkipNodes(key); + var previousNode = skipNodes.First(); + if (previousNode.Next[0].Key != key) + { + return false; + } + + // Key exists in the list, remove it and update the skip nodes. + var nodeToRemove = previousNode.Next[0]; + for (var level = 0; level < nodeToRemove.Height; level++) + { + skipNodes[level].Next[level] = nodeToRemove.Next[level]; + } + + Count--; + + return true; + } + + /// + /// Returns an enumerator that iterates through the list. + /// + /// + /// Order of values is the ascending order of their keys. + /// Time complexity: O(n) where n is the number of elements in the list. + /// + public IEnumerable GetValues() + { + var current = head.Next[0]; + while (current.Key != tail.Key) + { + yield return current.Value!; + current = current.Next[0]; + } + } + + /// + /// Builds a list of skip nodes on each level that + /// are closest, but smaller than the given key. + /// + /// + /// The node on level 0 will point to the node with the given key, if it exists. + /// Time complexity: O(log n) where n is the number of elements in the list. + /// + private SkipListNode[] GetSkipNodes(int key) + { + var skipNodes = new SkipListNode[maxLevels]; + var current = head; + for (var level = head.Height - 1; level >= 0; level--) + { + while (current.Next[level].Key < key) + { + current = current.Next[level]; + } + + skipNodes[level] = current; + } + + return skipNodes; + } + + /// + /// Determines the height of skip levels for the new node. + /// + /// + /// Probability of the next level is 1/(2^level). + /// + private int GetRandomHeight() + { + int height = 1; + while (random.NextDouble() < Probability && height <= maxLevels) + { + height++; + } + + return height; + } + } +} diff --git a/DataStructures/LinkedList/SkipList/SkipListNode.cs b/DataStructures/LinkedList/SkipList/SkipListNode.cs new file mode 100644 index 00000000..38965ac2 --- /dev/null +++ b/DataStructures/LinkedList/SkipList/SkipListNode.cs @@ -0,0 +1,25 @@ +using System; +using System.Diagnostics; + +namespace DataStructures.LinkedList.SkipList +{ + [DebuggerDisplay("Key = {Key}, Height = {Height}, Value = {Value}")] + internal class SkipListNode + { + public SkipListNode(int key, TValue? value, int height) + { + Key = key; + Value = value; + Height = height; + Next = new SkipListNode[height]; + } + + public int Key { get; } + + public TValue? Value { get; set; } + + public SkipListNode[] Next { get; } + + public int Height { get; } + } +} diff --git a/README.md b/README.md index 4a7f8cc9..6fcff97c 100755 --- a/README.md +++ b/README.md @@ -188,6 +188,7 @@ This repository contains algorithms and data structures implemented in C# for ed * [Linked List](./DataStructures/LinkedList) * [Singly Linked List](./DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs) * [Doubly Linked List](./DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs) + * [Skip List](./DataStructures/LinkedList/SkipList/SkipList.cs) * [Graph](./DataStructures/Graph) * [Directed Weighted Graph Via Adjacency Matrix](./DataStructures/Graph/DirectedWeightedGraph.cs) * [Disjoint Set](./DataStructures/DisjointSet) From e8a5b3d947cc1bf6b61b6dbfaf7aacb4d55cfc13 Mon Sep 17 00:00:00 2001 From: MatthiasHeinz <7958945+MatthiasHeinz@users.noreply.github.com> Date: Mon, 15 Aug 2022 22:42:12 +0200 Subject: [PATCH 008/138] Add tests for TrialDivisionFactorizer (#320) --- .../TrialDivisionFactorizerTests.cs | 24 ++++++++++++++++++- .../Factorization/TrialDivisionFactorizer.cs | 4 ++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs b/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs index 048542c6..11c927b0 100755 --- a/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs +++ b/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs @@ -1,4 +1,4 @@ -using Algorithms.Numeric.Factorization; +using Algorithms.Numeric.Factorization; using NUnit.Framework; namespace Algorithms.Tests.Numeric.Factorization @@ -21,5 +21,27 @@ public static void PrimeNumberFactorizationFails(int p) // Assert Assert.IsFalse(success); } + + [Test] + [TestCase(4, 2)] + [TestCase(6, 2)] + [TestCase(8, 2)] + [TestCase(9, 3)] + [TestCase(15, 3)] + [TestCase(35, 5)] + [TestCase(49, 7)] + [TestCase(77, 7)] + public static void PrimeNumberFactorizationSucceeds(int n, int expected) + { + // Arrange + var factorizer = new TrialDivisionFactorizer(); + + // Act + var success = factorizer.TryFactor(n, out var factor); + + // Assert + Assert.IsTrue(success); + Assert.AreEqual(expected, factor); + } } } diff --git a/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs b/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs index 4b23b2cc..43820e24 100755 --- a/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs +++ b/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; namespace Algorithms.Numeric.Factorization @@ -9,7 +9,7 @@ namespace Algorithms.Numeric.Factorization public class TrialDivisionFactorizer : IFactorizer { /// - /// Finds a factor of a given number or returns false if it's prime. + /// Finds the smallest non trivial factor (i.e.: 1 < factor <= sqrt()) of a given number or returns false if it's prime. /// /// Integer to factor. /// Found factor. From 2362b6f8bcedfc995da1b8397f4f92939597fb29 Mon Sep 17 00:00:00 2001 From: alihut Date: Sat, 20 Aug 2022 23:30:49 +0300 Subject: [PATCH 009/138] Add Amicable Numbers Checker (#322) Co-authored-by: Ali Hut --- .../Numeric/AmicableNumbersTest.cs | 29 +++++++++++++ Algorithms/Numeric/AmicableNumbersChecker.cs | 41 +++++++++++++++++++ README.md | 1 + 3 files changed, 71 insertions(+) create mode 100644 Algorithms.Tests/Numeric/AmicableNumbersTest.cs create mode 100644 Algorithms/Numeric/AmicableNumbersChecker.cs diff --git a/Algorithms.Tests/Numeric/AmicableNumbersTest.cs b/Algorithms.Tests/Numeric/AmicableNumbersTest.cs new file mode 100644 index 00000000..1ece5f3d --- /dev/null +++ b/Algorithms.Tests/Numeric/AmicableNumbersTest.cs @@ -0,0 +1,29 @@ +using Algorithms.Numeric; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Tests.Numeric +{ + public static class AmicableNumbersTest + { + [Test] + [TestCase(220, 284)] + [TestCase(1184, 1210)] + [TestCase(2620, 2924)] + [TestCase(5020, 5564)] + public static void AmicableNumbersChecker_Test(int x, int y) + { + // Arrange + + // Act + var result = AmicableNumbersChecker.AreAmicableNumbers(x, y); + + // Assert + Assert.IsTrue(result); + } + } +} diff --git a/Algorithms/Numeric/AmicableNumbersChecker.cs b/Algorithms/Numeric/AmicableNumbersChecker.cs new file mode 100644 index 00000000..ad18cd8c --- /dev/null +++ b/Algorithms/Numeric/AmicableNumbersChecker.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Numeric +{ + /// + /// Amicable numbers are two different natural numbers related in such a way that the sum of the proper divisors of + /// each is equal to the other number. That is, σ(a)=b+a and σ(b)=a+b, where σ(n) is equal to the sum of positive divisors of n (see also divisor function). + /// See here for more info. + /// + public static class AmicableNumbersChecker + { + /// + /// Checks if two numbers are amicable or not. + /// + /// First number to check. + /// Second number to check. + /// True if they are amicable numbers. False if not. + public static bool AreAmicableNumbers(int x, int y) + { + return SumOfDivisors(x) == y && SumOfDivisors(y) == x; + } + + private static int SumOfDivisors(int number) + { + var sum = 0; /* sum of its positive divisors */ + for (var i = 1; i < number; ++i) + { + if (number % i == 0) + { + sum += i; + } + } + + return sum; + } + } +} diff --git a/README.md b/README.md index 6fcff97c..a7c58f2a 100755 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ This repository contains algorithms and data structures implemented in C# for ed * [Modular Multiplicative Inverse](./Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs) * [Numeric](./Algorithms/Numeric) * [Aliquot Sum Calculator](./Algorithms/Numeric/AliquotSumCalculator.cs) + * [Amicable Numbers Checker](./Algorithms/Numeric/AmicableNumbersChecker.cs) * [Decomposition](./Algorithms/Numeric/Decomposition) * [LU Decomposition](./Algorithms/Numeric/Decomposition/LU.cs) * [Thin Singular Vector Decomposition](./Algorithms/Numeric/Decomposition/ThinSVD.cs) From a297069ea2a28ab7d8f6077a07b35e3cc490242e Mon Sep 17 00:00:00 2001 From: Anton Minko Date: Thu, 1 Sep 2022 16:48:00 +0200 Subject: [PATCH 010/138] Add LRU and LFU Caches (#323) --- DataStructures.Tests/Cache/LfuCacheTests.cs | 78 ++++++++++ DataStructures.Tests/Cache/LruCacheTests.cs | 71 +++++++++ DataStructures/Cache/LfuCache.cs | 158 ++++++++++++++++++++ DataStructures/Cache/LruCache.cs | 112 ++++++++++++++ README.md | 3 + 5 files changed, 422 insertions(+) create mode 100644 DataStructures.Tests/Cache/LfuCacheTests.cs create mode 100644 DataStructures.Tests/Cache/LruCacheTests.cs create mode 100644 DataStructures/Cache/LfuCache.cs create mode 100644 DataStructures/Cache/LruCache.cs diff --git a/DataStructures.Tests/Cache/LfuCacheTests.cs b/DataStructures.Tests/Cache/LfuCacheTests.cs new file mode 100644 index 00000000..f349cead --- /dev/null +++ b/DataStructures.Tests/Cache/LfuCacheTests.cs @@ -0,0 +1,78 @@ +using System; +using DataStructures.Cache; +using NUnit.Framework; +using FluentAssertions; + +namespace DataStructures.Tests.Cache +{ + public static class LfuCacheTests + { + [Test] + public static void TestPutGet() + { + var cache = new LfuCache(); + cache.Put(1, "one"); + + cache.Contains(1).Should().BeTrue(); + cache.Get(1).Should().Be("one"); + } + + [Test] + public static void TestCacheMiss() + { + var cache = new LfuCache(); + cache.Put(1, "one"); + + cache.Contains(5).Should().BeFalse(); + cache.Get(5).Should().BeNull(); + } + + [Test] + public static void Evict_ItemWasNotUsed() + { + var cache = new LfuCache(capacity: 1); + cache.Put(1, "one"); + + // Add to the full cache, 1 will be removed + cache.Put(2, "two"); + + cache.Get(1).Should().BeNull(); + cache.Get(2).Should().Be("two"); + } + + [Test] + public static void Evict_OneItemWasUsed() + { + var cache = new LfuCache(capacity: 2); + cache.Put(1, "one"); + cache.Put(2, "two"); + + cache.Put(1, "ONE"); + + // Add to the full cache, 2 will be removed + cache.Put(3, "three"); + + cache.Get(1).Should().Be("ONE"); + cache.Get(2).Should().BeNull(); + cache.Get(3).Should().Be("three"); + } + + [Test] + public static void Evict_LruOrder() + { + var cache = new LfuCache(capacity: 2); + cache.Put(1, "one"); + cache.Put(2, "two"); + + cache.Put(1, "ONE"); + cache.Put(2, "TWO"); + + // Add to the full cache, 1 will be removed + cache.Put(3, "three"); + + cache.Get(1).Should().BeNull(); + cache.Get(2).Should().Be("TWO"); + cache.Get(3).Should().Be("three"); + } + } +} diff --git a/DataStructures.Tests/Cache/LruCacheTests.cs b/DataStructures.Tests/Cache/LruCacheTests.cs new file mode 100644 index 00000000..e39434d9 --- /dev/null +++ b/DataStructures.Tests/Cache/LruCacheTests.cs @@ -0,0 +1,71 @@ +using System; +using DataStructures.Cache; +using NUnit.Framework; +using FluentAssertions; + +namespace DataStructures.Tests.Cache +{ + public static class LruCacheTests + { + [Test] + public static void TestPutGet() + { + var cache = new LruCache(); + cache.Put(1, "one"); + + cache.Contains(1).Should().BeTrue(); + cache.Get(1).Should().Be("one"); + } + + [Test] + public static void TestCacheMiss() + { + var cache = new LruCache(); + cache.Put(1, "one"); + + cache.Contains(5).Should().BeFalse(); + cache.Get(5).Should().BeNull(); + } + + [Test] + public static void TestCacheUpdate() + { + var cache = new LruCache(); + cache.Put(1, "one"); + cache.Put(1, "ONE"); + + cache.Get(1).Should().Be("ONE"); + } + + [Test] + public static void RemoveOldestItem_ItemWasNotUsed() + { + var cache = new LruCache(capacity: 2); + cache.Put(1, "one"); + cache.Put(2, "two"); + + // Add to the full cache, 1 will be removed + cache.Put(3, "three"); + + cache.Get(1).Should().BeNull(); + cache.Get(2).Should().Be("two"); + cache.Get(3).Should().Be("three"); + } + + [Test] + public static void RemoveOldestItem_ItemWasRecentlyUsed() + { + var cache = new LruCache(capacity: 2); + cache.Put(1, "one"); + cache.Put(2, "two"); + cache.Get(1); + + // Add to the full cache, 1 was used, 2 should be removed + cache.Put(3, "three"); + + cache.Get(1).Should().Be("one"); + cache.Get(2).Should().BeNull(); + cache.Get(3).Should().Be("three"); + } + } +} \ No newline at end of file diff --git a/DataStructures/Cache/LfuCache.cs b/DataStructures/Cache/LfuCache.cs new file mode 100644 index 00000000..7c460ef2 --- /dev/null +++ b/DataStructures/Cache/LfuCache.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; + +namespace DataStructures.Cache +{ + /// + /// Least Frequently Used (LFU) cache implementation. + /// + /// The type of the key (must be not null). + /// The type of the value. + /// + /// Cache keeps up to capacity items. When new item is added and cache is full, + /// one of the least frequently used item is removed (e.g. it keeps N items that were the most + /// frequently requested using Get() or Put() methods). + /// When there are multiple items with the same frequency, the least recently used item is removed. + /// + /// Cache is built on top of two data structures: + /// - Dictionary. Allows items to be looked up by key in O(1) time. Another dictionary + /// is used to store the frequency of each key. + /// - LinkedList - Allows items with the same frequency to be ordered by the last + /// usage in O(1) time. + /// + /// Useful links: + /// https://en.wikipedia.org/wiki/Cache_replacement_policies + /// https://www.enjoyalgorithms.com/blog/least-frequently-used-cache + /// https://www.educative.io/answers/what-is-least-frequently-used-cache-replace-policy + /// https://leetcode.com/problems/lfu-cache/ . + /// + public class LfuCache where TKey : notnull + { + private class CachedItem + { + public TKey Key { get; set; } = default!; + + public TValue? Value { get; set; } + + public int Frequency { get; set; } + } + + private const int DefaultCapacity = 100; + + private readonly int capacity; + + // Note that Dictionary stores LinkedListNode as it allows + // removing the node from the LinkedList in O(1) time. + private readonly Dictionary> cache = new(); + + // Map frequency (number of times the item was requested or updated) + // to the LRU linked list. + private readonly Dictionary> frequencies = new(); + + // Track the minimum frequency with non-empty linked list in frequencies. + // When the last item with the minFrequency is promoted (after being requested or updated), + // the minFrequency is increased. + // When a new item is added, the minFrequency is set to 1. + private int minFrequency = -1; + + /// + /// Initializes a new instance of the class. + /// + /// The max number of items the cache can store. + public LfuCache(int capacity = DefaultCapacity) + { + this.capacity = capacity; + } + + public bool Contains(TKey key) => cache.ContainsKey(key); + + /// + /// Gets the cached item by key. + /// + /// The key of cached item. + /// The cached item or default if item is not found. + /// Time complexity: O(1). + public TValue? Get(TKey key) + { + if (!cache.ContainsKey(key)) + { + return default; + } + + var node = cache[key]; + UpdateFrequency(node, isNew: false); + return node.Value.Value; + } + + /// + /// Adds or updates the value in the cache. + /// + /// The key of item to cache. + /// The value to cache. + /// + /// Time complexity: O(1). + /// If the value is already cached, it is updated and the item is moved + /// to the end of the LRU list. + /// If the cache is full, one of the least frequently used items is removed. + /// + public void Put(TKey key, TValue value) + { + if (cache.ContainsKey(key)) + { + var existingNode = cache[key]; + existingNode.Value.Value = value; + UpdateFrequency(existingNode, isNew: false); + return; + } + + if (cache.Count >= capacity) + { + EvictOneItem(); + } + + var item = new CachedItem { Key = key, Value = value }; + var newNode = new LinkedListNode(item); + UpdateFrequency(newNode, isNew: true); + cache.Add(key, newNode); + } + + private void UpdateFrequency(LinkedListNode node, bool isNew) + { + var item = node.Value; + + if (isNew) + { + item.Frequency = 1; + minFrequency = 1; + } + else + { + // Remove the existing node from the LRU list with its previous frequency. + var lruList = frequencies[item.Frequency]; + lruList.Remove(node); + if (lruList.Count == 0 && minFrequency == item.Frequency) + { + minFrequency++; + } + + item.Frequency++; + } + + // Insert item to the end of the LRU list that corresponds to its new frequency. + if (!frequencies.ContainsKey(item.Frequency)) + { + frequencies[item.Frequency] = new LinkedList(); + } + + frequencies[item.Frequency].AddLast(node); + } + + private void EvictOneItem() + { + var lruList = frequencies[minFrequency]; + var itemToRemove = lruList.First!.Value; + lruList.RemoveFirst(); + cache.Remove(itemToRemove.Key); + } + } +} diff --git a/DataStructures/Cache/LruCache.cs b/DataStructures/Cache/LruCache.cs new file mode 100644 index 00000000..b82abe18 --- /dev/null +++ b/DataStructures/Cache/LruCache.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; + +namespace DataStructures.Cache +{ + /// + /// Least Recently Used (LRU) cache implementation. + /// + /// The type of the key (must be not null). + /// The type of the value. + /// + /// Cache keeps up to capacity items. When new item is added and cache is full, + /// the least recently used item is removed (e.g. it keeps N items that were recently requested + /// using Get() or Put() methods). + /// + /// Cache is built on top of two data structures: + /// - Dictionary - allows items to be looked up by key in O(1) time. + /// - LinkedList - allows items to be ordered by last usage time in O(1) time. + /// + /// Useful links: + /// https://en.wikipedia.org/wiki/Cache_replacement_policies + /// https://www.educative.io/m/implement-least-recently-used-cache + /// https://leetcode.com/problems/lru-cache/ + /// + /// In order to make the most recently used (MRU) cache, when the cache is full, + /// just remove the last node from the linked list in the method Put + /// (replace RemoveFirst with RemoveLast). + /// + public class LruCache where TKey : notnull + { + private class CachedItem + { + public TKey Key { get; set; } = default!; + + public TValue? Value { get; set; } + } + + private const int DefaultCapacity = 100; + + private readonly int capacity; + + // Note that Dictionary stores LinkedListNode as it allows + // removing the node from the LinkedList in O(1) time. + private readonly Dictionary> cache = new(); + private readonly LinkedList lruList = new(); + + /// + /// Initializes a new instance of the class. + /// + /// The max number of items the cache can store. + public LruCache(int capacity = DefaultCapacity) + { + this.capacity = capacity; + } + + public bool Contains(TKey key) => cache.ContainsKey(key); + + /// + /// Gets the cached item by key. + /// + /// The key of cached item. + /// The cached item or default if item is not found. + /// Time complexity: O(1). + public TValue? Get(TKey key) + { + if (!cache.ContainsKey(key)) + { + return default; + } + + var node = cache[key]; + lruList.Remove(node); + lruList.AddLast(node); + + return node.Value.Value; + } + + /// + /// Adds or updates the value in the cache. + /// + /// The key of item to cache. + /// The value to cache. + /// + /// Time complexity: O(1). + /// If the value is already cached, it is updated and the item is moved + /// to the end of the LRU list. + /// If the cache is full, the least recently used item is removed. + /// + public void Put(TKey key, TValue value) + { + if (cache.ContainsKey(key)) + { + var existingNode = cache[key]; + existingNode.Value.Value = value; + lruList.Remove(existingNode); + lruList.AddLast(existingNode); + return; + } + + if (cache.Count >= capacity) + { + var first = lruList.First!; + lruList.RemoveFirst(); + cache.Remove(first.Value.Key); + } + + var item = new CachedItem { Key = key, Value = value }; + var newNode = lruList.AddLast(item); + cache.Add(key, newNode); + } + } +} diff --git a/README.md b/README.md index a7c58f2a..ede6f6e4 100755 --- a/README.md +++ b/README.md @@ -197,6 +197,9 @@ This repository contains algorithms and data structures implemented in C# for ed * [Inverted index](./DataStructures/InvertedIndex.cs) * [Unrolled linked list](./DataStructures/UnrolledList/UnrolledLinkedList.cs) * [Tries](./DataStructures/Tries/Trie.cs) + * [Cache](./DataStructures/Cache) + * [Least Frequently Used (LFU) Cache](./DataStructures/Cache/LfuCache.cs) + * [Least Recently Used (LRU) Cache](./DataStructures/Cache/LruCache.cs) ## Contributing From 2e499237fef8307a32f18c1d8079f83e9916b397 Mon Sep 17 00:00:00 2001 From: David Leal Date: Sat, 10 Sep 2022 04:01:16 -0500 Subject: [PATCH 011/138] chore: add Discord and donate buttons (#324) --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index ede6f6e4..a85e9e29 100755 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ # The Algorithms - C# + +[![Discord chat](https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA)](https://discord.gg/c7MnfGFGa6) [![Build Status](https://travis-ci.com/TheAlgorithms/C-Sharp.svg?branch=master)](https://travis-ci.com/TheAlgorithms/C-Sharp) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/58895a2795bd48a8b3b7eb6ebe22d576)](https://www.codacy.com/gh/TheAlgorithms/C-Sharp/dashboard?utm_source=github.com&utm_medium=referral&utm_content=TheAlgorithms/C-Sharp&utm_campaign=Badge_Grade) [![codecov](https://codecov.io/gh/TheAlgorithms/C-Sharp/branch/master/graph/badge.svg)](https://codecov.io/gh/TheAlgorithms/C-Sharp) [![GuardRails badge](https://badges.guardrails.io/TheAlgorithms/C-Sharp.svg?token=84805208ba243f0931a74c5148883f894cbe9fd97fe54d64d6d0a89852067548)](https://dashboard.guardrails.io/default/gh/TheAlgorithms/C-Sharp) +[![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/TheAlgorithms/donate) This repository contains algorithms and data structures implemented in C# for educational purposes. From 6a8f7d232ff5dd5742f83c11db4074a920cb1555 Mon Sep 17 00:00:00 2001 From: MathewBeldon Date: Tue, 27 Sep 2022 17:51:18 +0100 Subject: [PATCH 012/138] Fix insertion sort (#326) --- Algorithms/Sorters/Comparison/InsertionSorter.cs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/Algorithms/Sorters/Comparison/InsertionSorter.cs b/Algorithms/Sorters/Comparison/InsertionSorter.cs index 3f1b20ad..367b7c1a 100644 --- a/Algorithms/Sorters/Comparison/InsertionSorter.cs +++ b/Algorithms/Sorters/Comparison/InsertionSorter.cs @@ -19,20 +19,14 @@ public class InsertionSorter : IComparisonSorter /// Compares elements. public void Sort(T[] array, IComparer comparer) { - for (var i = 0; i < array.Length - 1; i++) + for (var i = 1; i < array.Length; i++) { - var imin = i; - for (var j = i + 1; j < array.Length; j++) + for (var j = i; j > 0 && comparer.Compare(array[j], array[j - 1]) < 0; j--) { - if (comparer.Compare(array[j], array[imin]) < 0) - { - imin = j; - } + var temp = array[j - 1]; + array[j - 1] = array[j]; + array[j] = temp; } - - var t = array[imin]; - array[imin] = array[i]; - array[i] = t; } } } From 048d7b9bb5eae7d1126e1166de7bb2646b472e15 Mon Sep 17 00:00:00 2001 From: Daniel Alfonso <55640656+Dalfonso06@users.noreply.github.com> Date: Tue, 27 Sep 2022 13:12:03 -0400 Subject: [PATCH 013/138] Update xml documentation (#327) Co-authored-by: Dalfonso06 --- Algorithms/Numeric/GaussJordanElimination.cs | 2 +- Algorithms/Search/BinarySearcher.cs | 13 +++++++------ Algorithms/Strings/Palindrome.cs | 19 ++++++++++++++----- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Algorithms/Numeric/GaussJordanElimination.cs b/Algorithms/Numeric/GaussJordanElimination.cs index 546969fb..27a54dd8 100644 --- a/Algorithms/Numeric/GaussJordanElimination.cs +++ b/Algorithms/Numeric/GaussJordanElimination.cs @@ -3,7 +3,7 @@ namespace Algorithms.Numeric { /// - /// TODO. + /// Algorithm used to find the inverse of any matrix that can be inverted. /// public class GaussJordanElimination { diff --git a/Algorithms/Search/BinarySearcher.cs b/Algorithms/Search/BinarySearcher.cs index 65ab8fb5..4ff4234e 100644 --- a/Algorithms/Search/BinarySearcher.cs +++ b/Algorithms/Search/BinarySearcher.cs @@ -3,16 +3,17 @@ namespace Algorithms.Search { /// - /// TODO. + /// Binary Searcher checks an array for element specified by checking + /// if element is greater or less than the half being checked. + /// time complexity: O(log(n)), + /// space complexity: O(1). + /// Note: Array must be sorted beforehand. /// - /// TODO. 2. + /// Type of element stored inside array. 2. public class BinarySearcher where T : IComparable { /// - /// Finds index of item in array that equals to item searched for, - /// time complexity: O(log(n)), - /// space complexity: O(1), - /// where n - array size. + /// Finds index of an array by using binary search. /// /// Sorted array to search in. /// Item to search for. diff --git a/Algorithms/Strings/Palindrome.cs b/Algorithms/Strings/Palindrome.cs index ddb8632e..7d88f077 100644 --- a/Algorithms/Strings/Palindrome.cs +++ b/Algorithms/Strings/Palindrome.cs @@ -4,22 +4,31 @@ namespace Algorithms.Strings { /// - /// TODO. + /// Palindrome a series of characters or a string that when reversed, + /// equals the original string. /// public static class Palindrome { /// - /// TODO. + /// Function to check if a string is a palindrome. /// - /// TODO. 2. - /// TODO. 3. + /// String being checked. public static bool IsStringPalindrome(string word) => TypifyString(word).Equals(TypifyString(ReverseString(word))); - // Typify string to lower and remove white spaces. + /// + /// Typify string to lower and remove white spaces. + /// + /// String to remove spaces. + /// Returns original string without spaces. private static string TypifyString(string word) => Regex.Replace(word.ToLowerInvariant(), @"\s+", string.Empty); + /// + /// Helper function that returns a reversed string inputed. + /// + /// String to be reversed. + /// Returns s reversed. private static string ReverseString(string s) { var arr = s.ToCharArray(); From 11fd0c510c5ecc25eb9e67704a2a3c3f017013e8 Mon Sep 17 00:00:00 2001 From: pea-sys <49807271+pea-sys@users.noreply.github.com> Date: Sat, 1 Oct 2022 14:26:23 +0900 Subject: [PATCH 014/138] Update from .NET 5 to .NET 6 (#328) Co-authored-by: Andrii Siriak --- .travis.yml | 4 ++-- Algorithms.Tests/Algorithms.Tests.csproj | 2 +- Algorithms/Algorithms.csproj | 2 +- CONTRIBUTING.md | 2 +- DataStructures.Tests/DataStructures.Tests.csproj | 2 +- DataStructures/DataStructures.csproj | 2 +- Utilities.Tests/Utilities.Tests.csproj | 2 +- Utilities/Utilities.csproj | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index d95e61f9..711ab1dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: csharp solution: C-Sharp.sln mono: none -dist: xenial -dotnet: 5.0 +dist: focal +dotnet: 6.0 script: - sudo apt update - sudo apt install -y libgdiplus diff --git a/Algorithms.Tests/Algorithms.Tests.csproj b/Algorithms.Tests/Algorithms.Tests.csproj index eaf9c7bf..7d601849 100644 --- a/Algorithms.Tests/Algorithms.Tests.csproj +++ b/Algorithms.Tests/Algorithms.Tests.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 false ..\stylecop.ruleset true diff --git a/Algorithms/Algorithms.csproj b/Algorithms/Algorithms.csproj index 2293f466..9d3f6252 100644 --- a/Algorithms/Algorithms.csproj +++ b/Algorithms/Algorithms.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 ..\stylecop.ruleset true enable diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a52c426d..52ab3d89 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ this repository. We welcome adding new algorithms and data structures that were mentioned in books or other reputable sources. We also welcome fixing bugs in code, clarifying documentation and adding new test cases to check existing code. -The framework targeted by our code is **dotnet 5**. The corresponding SDK can be found [here](https://dotnet.microsoft.com/download/dotnet/5.0). +The framework targeted by our code is **dotnet 6**. The corresponding SDK can be found [here](https://dotnet.microsoft.com/download/dotnet/6.0). Please note that we have a code of conduct, please follow it in all your interactions with the project. diff --git a/DataStructures.Tests/DataStructures.Tests.csproj b/DataStructures.Tests/DataStructures.Tests.csproj index 79f2ff33..732a0089 100644 --- a/DataStructures.Tests/DataStructures.Tests.csproj +++ b/DataStructures.Tests/DataStructures.Tests.csproj @@ -1,7 +1,7 @@  - net5.0 + net6.0 false ..\stylecop.ruleset true diff --git a/DataStructures/DataStructures.csproj b/DataStructures/DataStructures.csproj index 0f4447e4..9803466f 100644 --- a/DataStructures/DataStructures.csproj +++ b/DataStructures/DataStructures.csproj @@ -1,7 +1,7 @@  - net5.0 + net6.0 ..\stylecop.ruleset true enable diff --git a/Utilities.Tests/Utilities.Tests.csproj b/Utilities.Tests/Utilities.Tests.csproj index 9771db6b..7b1fcf7b 100644 --- a/Utilities.Tests/Utilities.Tests.csproj +++ b/Utilities.Tests/Utilities.Tests.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 false ..\stylecop.ruleset true diff --git a/Utilities/Utilities.csproj b/Utilities/Utilities.csproj index 44114c47..6cb21c39 100644 --- a/Utilities/Utilities.csproj +++ b/Utilities/Utilities.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 ..\stylecop.ruleset true enable From f45715609c620e0efe37e9cfe17de7af8299493d Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Sun, 2 Oct 2022 11:21:12 +0300 Subject: [PATCH 015/138] Update build badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a85e9e29..ced7ec97 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # The Algorithms - C# [![Discord chat](https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA)](https://discord.gg/c7MnfGFGa6) -[![Build Status](https://travis-ci.com/TheAlgorithms/C-Sharp.svg?branch=master)](https://travis-ci.com/TheAlgorithms/C-Sharp) +[![Build Status](https://app.travis-ci.com/TheAlgorithms/C-Sharp.svg?branch=master)](https://app.travis-ci.com/TheAlgorithms/C-Sharp) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/58895a2795bd48a8b3b7eb6ebe22d576)](https://www.codacy.com/gh/TheAlgorithms/C-Sharp/dashboard?utm_source=github.com&utm_medium=referral&utm_content=TheAlgorithms/C-Sharp&utm_campaign=Badge_Grade) [![codecov](https://codecov.io/gh/TheAlgorithms/C-Sharp/branch/master/graph/badge.svg)](https://codecov.io/gh/TheAlgorithms/C-Sharp) [![GuardRails badge](https://badges.guardrails.io/TheAlgorithms/C-Sharp.svg?token=84805208ba243f0931a74c5148883f894cbe9fd97fe54d64d6d0a89852067548)](https://dashboard.guardrails.io/default/gh/TheAlgorithms/C-Sharp) From 9416dfb87b98741c33391db5570285037222b05b Mon Sep 17 00:00:00 2001 From: Richard Vasquez <1706965+RichardVasquez@users.noreply.github.com> Date: Sun, 2 Oct 2022 01:52:46 -0700 Subject: [PATCH 016/138] Add A000032 Lukas Numbers (#332) --- .../LucasNumbersBeginningAt2SequenceTests.cs | 109 ++++++++++++++++++ .../LucasNumbersBeginningAt2Sequence.cs | 65 +++++++++++ README.md | 1 + 3 files changed, 175 insertions(+) create mode 100644 Algorithms.Tests/Sequences/LucasNumbersBeginningAt2SequenceTests.cs create mode 100644 Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs diff --git a/Algorithms.Tests/Sequences/LucasNumbersBeginningAt2SequenceTests.cs b/Algorithms.Tests/Sequences/LucasNumbersBeginningAt2SequenceTests.cs new file mode 100644 index 00000000..7d79778e --- /dev/null +++ b/Algorithms.Tests/Sequences/LucasNumbersBeginningAt2SequenceTests.cs @@ -0,0 +1,109 @@ +using System.Linq; +using System.Numerics; +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Sequences; + +public class LucasNumbersBeginningAt2SequenceTests +{ + [Test] + public void FirstElementsCorrect() + { + // Initial test of 38 values from http://oeis.org/A000032/list which passed. + // Testing 200 Lucas numbers, with values from https://r-knott.surrey.ac.uk/Fibonacci/lucas200.html and + // compared to initial 38, which passed. + // Assigning numeric values to BigInteger types performed by string parsing dues to length of value. + var bigNumbers = new[] { + "2", "1", "3", "4", "7", "11", "18", "29", "47", "76", "123", "199", "322", + "521", "843", "1364", "2207", "3571", "5778", "9349", "15127", "24476", + "39603", "64079", "103682", "167761", "271443", "439204", "710647", "1149851", + "1860498", "3010349", "4870847", "7881196", "12752043", "20633239", "33385282", + "54018521", "87403803", "141422324", "228826127", "370248451", "599074578", + "969323029", "1568397607", "2537720636", "4106118243", "6643838879", + "10749957122", "17393796001", "28143753123", "45537549124", "73681302247", + "119218851371", "192900153618", "312119004989", "505019158607", "817138163596", + "1322157322203", "2139295485799", "3461452808002", "5600748293801", + "9062201101803", "14662949395604", "23725150497407", "38388099893011", + "62113250390418", "100501350283429", "162614600673847", "263115950957276", + "425730551631123", "688846502588399", "1114577054219522", "1803423556807921", + "2918000611027443", "4721424167835364", "7639424778862807", + "12360848946698171", "20000273725560978", "32361122672259149", + "52361396397820127", "84722519070079276", "137083915467899403", + "221806434537978679", "358890350005878082", "580696784543856761", + "939587134549734843", "1520283919093591604", "2459871053643326447", + "3980154972736918051", "6440026026380244498", "10420180999117162549", + "16860207025497407047", "27280388024614569596", "44140595050111976643", + "71420983074726546239", "115561578124838522882", "186982561199565069121", + "302544139324403592003", "489526700523968661124", "792070839848372253127", + "1281597540372340914251", "2073668380220713167378", "3355265920593054081629", + "5428934300813767249007", "8784200221406821330636", "14213134522220588579643", + "22997334743627409910279", "37210469265847998489922", + "60207804009475408400201", "97418273275323406890123", + "157626077284798815290324", "255044350560122222180447", + "412670427844921037470771", "667714778405043259651218", + "1080385206249964297121989", "1748099984655007556773207", + "2828485190904971853895196", "4576585175559979410668403", + "7405070366464951264563599", "11981655542024930675232002", + "19386725908489881939795601", "31368381450514812615027603", + "50755107359004694554823204", "82123488809519507169850807", + "132878596168524201724674011", "215002084978043708894524818" + , "347880681146567910619198829", "562882766124611619513723647", + "910763447271179530132922476", "1473646213395791149646646123", + "2384409660666970679779568599", "3858055874062761829426214722", + "6242465534729732509205783321", "10100521408792494338631998043", + "16342986943522226847837781364", "26443508352314721186469779407", + "42786495295836948034307560771", "69230003648151669220777340178", + "112016498943988617255084900949", "181246502592140286475862241127", + "293263001536128903730947142076", "474509504128269190206809383203", + "767772505664398093937756525279", "1242282009792667284144565908482", + "2010054515457065378082322433761", "3252336525249732662226888342243", + "5262391040706798040309210776004", "8514727565956530702536099118247", + "13777118606663328742845309894251", "22291846172619859445381409012498", + "36068964779283188188226718906749", "58360810951903047633608127919247", + "94429775731186235821834846825996", "152790586683089283455442974745243", + "247220362414275519277277821571239", "400010949097364802732720796316482", + "647231311511640322009998617887721", "1047242260609005124742719414204203", + "1694473572120645446752718032091924", "2741715832729650571495437446296127", + "4436189404850296018248155478388051", "7177905237579946589743592924684178", + "11614094642430242607991748403072229", "18791999880010189197735341327756407", + "30406094522440431805727089730828636", "49198094402450621003462431058585043", + "79604188924891052809189520789413679", "128802283327341673812651951847998722", + "208406472252232726621841472637412401", "337208755579574400434493424485411123", + "545615227831807127056334897122823524", "882823983411381527490828321608234647", + "1428439211243188654547163218731058171", + "2311263194654570182037991540339292818", + "3739702405897758836585154759070350989", + "6050965600552329018623146299409643807", + "9790668006450087855208301058479994796", + "15841633607002416873831447357889638603", + "25632301613452504729039748416369633399", + "41473935220454921602871195774259272002", + "67106236833907426331910944190628905401", + "108580172054362347934782139964888177403", + "175686408888269774266693084155517082804", + "284266580942632122201475224120405260207", + "459952989830901896468168308275922343011", + "744219570773534018669643532396327603218", + "1204172560604435915137811840672249946229", + "1948392131377969933807455373068577549447", + "3152564691982405848945267213740827495676", + "5100956823360375782752722586809405045123", + "8253521515342781631697989800550232540799", + "13354478338703157414450712387359637585922", + "21607999854045939046148702187909870126721", + "34962478192749096460599414575269507712643", + "56570478046795035506748116763179377839364", + "91532956239544131967347531338448885552007", + "148103434286339167474095648101628263391371", + "239636390525883299441443179440077148943378", + "387739824812222466915538827541705412334749", + "627376215338105766356982006981782561278127", + }; + + var check = bigNumbers.Select(BigInteger.Parse).ToArray(); + var sequence = new LucasNumbersBeginningAt2Sequence().Sequence.Take(check.Length); + sequence.SequenceEqual(check).Should().BeTrue(); + } +} diff --git a/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs b/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs new file mode 100644 index 00000000..d915d5fb --- /dev/null +++ b/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Algorithms.Sequences +{ + /// + /// + /// Sequence of Lucas number values. + /// + /// + /// Wikipedia: https://en.wikipedia.org/wiki/Lucas_number. + /// + /// + /// OEIS: http://oeis.org/A000032. + /// + /// + public class LucasNumbersBeginningAt2Sequence : ISequence + { + /// + /// + /// Gets Lucas number sequence. + /// + /// + /// Lucas numbers follow the same type of operation that the Fibonacci (A000045) + /// sequence performs with starting values of 2, 1 versus 0,1. As Fibonacci does, + /// the ratio between two consecutive Lucas numbers converges to phi. + /// + /// + /// This implementation is similar to A000204, but starts with the index of 0, thus having the + /// initial values being (2,1) instead of starting at index 1 with initial values of (1,3). + /// + /// + /// A simple relationship to Fibonacci can be shown with L(n) = F(n-1) + F(n+1), n>= 1. + /// + /// n | L(n) | F(n-1) | F(n+1) + /// --|-------|--------+--------+ + /// 0 | 2 | | | + /// 1 | 1 | 0 | 1 | + /// 2 | 3 | 1 | 2 | + /// 3 | 4 | 1 | 3 | + /// 4 | 7 | 2 | 5 | + /// 5 | 11 | 3 | 8 | + /// --|-------|--------+--------+. + /// + /// + public IEnumerable Sequence + { + get + { + yield return 2; + yield return 1; + BigInteger previous = 2; + BigInteger current = 1; + while (true) + { + var next = previous + current; + previous = current; + current = next; + + yield return next; + } + } + } + } +} diff --git a/README.md b/README.md index ced7ec97..4a374967 100755 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ This repository contains algorithms and data structures implemented in C# for ed * [A000008 Make Change](./Algorithms/Sequences/MakeChangeSequence.cs) * [A000010 Euler's Totient](./Algorithms/Sequences/EulerTotientSequence.cs) * [A000027 Natural](./Algorithms/Sequences/NaturalSequence.cs) + * [A000032 Lucas Numbers](./Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs) * [A000040 Primes](./Algorithms/Sequences/PrimesSequence.cs) * [A000045 Fibonacci](./Algorithms/Sequences/FibonacciSequence.cs) * [A000079 Powers of 2](./Algorithms/Sequences/PowersOf2Sequence.cs) From b0328087318ecdc299dc261231e70b7457ccdaf8 Mon Sep 17 00:00:00 2001 From: Poorva Diwan Date: Mon, 3 Oct 2022 10:19:31 +0530 Subject: [PATCH 017/138] Update README.md (#330) --- README.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) mode change 100755 => 100644 README.md diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 4a374967..c0ef5fa1 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +
+ # The Algorithms - C# [![Discord chat](https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA)](https://discord.gg/c7MnfGFGa6) @@ -7,9 +9,16 @@ [![GuardRails badge](https://badges.guardrails.io/TheAlgorithms/C-Sharp.svg?token=84805208ba243f0931a74c5148883f894cbe9fd97fe54d64d6d0a89852067548)](https://dashboard.guardrails.io/default/gh/TheAlgorithms/C-Sharp) [![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/TheAlgorithms/donate) -This repository contains algorithms and data structures implemented in C# for educational purposes. +## All Algorithms implemented in C# - for education purposes + +The repository is a collection of a variety of algorithms implemented in C#. The algorithms span over a variety of topics +from computer science, mathematics and statistics, data science, machine learning, engineering, etc. The implementations +and their associated documentations are meant to provide a learning resource for educators and students. Hence, one may +find more than one implementation for the same objective but using different algorithm strategies and optimizations. -## Overview +
+ +## List of Algorithms * [Algorithms](./Algorithms) * [Data Compression](./Algorithms/DataCompression) @@ -30,11 +39,13 @@ This repository contains algorithms and data structures implemented in C# for ed * [BreadthFirstSearch](./Algorithms/Graph/BreadthFirstSearch.cs) * [DepthFirstSearch](./Algorithms/Graph/DepthFirstSearch.cs) * [Dijkstra Shortest Path](./Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs) + * [FloydWarshall](./Algorithms/Graph/FloydWarshall.cs) * [Kosaraju](./Algorithms/Graph/Kosaraju.cs) * [Knapsack problem](./Algorithms/Knapsack) * [Naive solver](./Algorithms/Knapsack/NaiveKnapsackSolver.cs) * [Dynamic Programming solver](./Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs) * [Branch and bound solver](./Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs) + * [IHeuristicSolver](./Algorithms/Knapsack/IHeuristicSolver.cs) * [Linear Algebra](./Algorithms/LinearAlgebra) * [Distances](./Algorithms/LinearAlgebra/Distances) * [Euclidean](./Algorithms/LinearAlgebra/Distances/Euclidean.cs) @@ -60,6 +71,8 @@ This repository contains algorithms and data structures implemented in C# for ed * [Series](./Algorithms/Numeric/Series) * [Maclaurin Series](./Algorithms/Numeric/Series/Maclaurin.cs) * [Gauss-Jordan Elimination](./Algorithms/Numeric/GaussJordanElimination.cs) + * [BinomialCoefficient](./Algorithms/Numeric/BinomialCoefficient.cs) + * [Factorial](./Algorithms/Numeric/Factorial.cs) * [Keith Number Checker](./Algorithms/Numeric/KeithNumberChecker.cs) * [Pseudo-Inverse](./Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs) * [Narcissistic Number Checker](./Algorithms/Numeric/NarcissisticNumberChecker.cs) @@ -149,6 +162,8 @@ This repository contains algorithms and data structures implemented in C# for ed * [Fermat Prime Checker](./Algorithms/Other/FermatPrimeChecker.cs) * [Sieve of Eratosthenes](./Algorithms/Other/SieveOfEratosthenes.cs) * [Luhn](./Algorithms/Other/Luhn.cs) + * [Int2Binary](./Algorithms/Other/Int2Binary.cs) + * [GeoLocation](./Algorithms/Other/GeoLocation.cs) * [Mandelbrot](./Algorithms/Other/Mandelbrot.cs) * [Koch Snowflake](./Algorithms/Other/KochSnowflake.cs) * [RGB-HSV Conversion](./Algorithms/Other/RGBHSVConversion.cs) @@ -156,6 +171,8 @@ This repository contains algorithms and data structures implemented in C# for ed * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) * [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs) + * [Accepter](./Algorithms/Problems/StableMarriage/Accepter.cs) + * [Proposer](./Algorithms/Problems/StableMarriage/Proposer.cs) * [N-Queens](./Algorithms/Problems/NQueens) * [Backtracking](./Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs) * [Dynamic Coin Change](./Algorithms/Problems/CoinChange) @@ -205,9 +222,10 @@ This repository contains algorithms and data structures implemented in C# for ed * [Least Frequently Used (LFU) Cache](./DataStructures/Cache/LfuCache.cs) * [Least Recently Used (LRU) Cache](./DataStructures/Cache/LruCache.cs) + ## Contributing You can contribute with pleasure to this repository. Please orient on the directory structure and overall code style of this repository -and refer to [our contributing guidelines](./CONTRIBUTING.md) for more detail. +and refer to [our contributing guidelines](./CONTRIBUTING.md) for more details. If you want to ask a question or suggest something, please open an issue. From f337ab2a7e98681b52bc4305b7cf43e6e5f4caa1 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Mon, 3 Oct 2022 07:56:04 +0300 Subject: [PATCH 018/138] Fix blinking test --- Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs index 18647458..1e2b5e51 100755 --- a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs @@ -12,7 +12,7 @@ public static class TimSorterTests [Test] public static void ArraySorted( - [Random(0, 10_000, 200, Distinct = true)] + [Random(0, 100_000, 200, Distinct = true)] int n) { // Arrange From a66c960910a53a5125f27a6ce89c1c7fe8d63869 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Mon, 3 Oct 2022 10:10:40 +0300 Subject: [PATCH 019/138] Fix blinking tests & reduce testing time (#337) --- .../Numeric/MillerRabinPrimalityTest.cs | 13 ++++++------- .../NQueens/BacktrackingNQueensSolverTests.cs | 1 - Algorithms.Tests/Search/JumpSearcherTests.cs | 4 ++-- .../Shufflers/FisherYatesShufflerTests.cs | 8 ++++---- .../Sorters/Comparison/TimSorterTests.cs | 3 +-- Algorithms.Tests/Strings/PermutationTests.cs | 2 +- .../Numeric/MillerRabinPrimalityChecker.cs | 18 ++++++++++++------ .../LinkedList/SkipListTests.cs | 4 ++-- DataStructures/LinkedList/SkipList/SkipList.cs | 2 +- 9 files changed, 29 insertions(+), 26 deletions(-) diff --git a/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs b/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs index 2f404ba9..bd9f9a32 100644 --- a/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs +++ b/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs @@ -10,23 +10,22 @@ public static class MillerRabinPrimalityTest [TestCase("7", ExpectedResult = true)] // true [TestCase("47", ExpectedResult = true)] // true [TestCase("247894109041876714378152933343208766493", ExpectedResult = true)] // true + [TestCase("247894109041876714378152933343208766493", 1, ExpectedResult = true)] // true [TestCase("315757551269487563269454472438030700351", ExpectedResult = true)] // true - - [TestCase("2476099", ExpectedResult = false)] // false 19^5 + [TestCase("2476099", 12445, ExpectedResult = false)] // false 19^5 // false 247894109041876714378152933343208766493*315757551269487563269454472438030700351 [TestCase("78274436845194327170519855212507883195883737501141260366253362532531612139043", ExpectedResult = false)] - [Repeat(5)] [Retry(3)] - public static bool MillerRabinPrimalityWork(String testcase) + public static bool MillerRabinPrimalityWork(string testcase, int? seed = null) { // Arrange BigInteger number = BigInteger.Parse(testcase); - // Recommended number of checks' rounds = Log2(number) as Biginter has no Log2 function we need to convert Log10 + // Recommended number of checks' rounds = Log2(number) as BigInteger has no Log2 function we need to convert Log10 BigInteger rounds = (BigInteger)(BigInteger.Log10(number) / BigInteger.Log10(2)); // Act - var result = MillerRabinPrimalityChecker.IsProbablyPrimeNumber(number, rounds); + var result = MillerRabinPrimalityChecker.IsProbablyPrimeNumber(number, rounds, seed); // Assert return result; @@ -36,7 +35,7 @@ public static bool MillerRabinPrimalityWork(String testcase) [TestCase("0")] [TestCase("3")] // By the algorithm definition the number which is checked should be more than 3 - public static void MillerRabinPrimalityShouldThrowEx(String testcase) + public static void MillerRabinPrimalityShouldThrowEx(string testcase) { // Arrange BigInteger number = BigInteger.Parse(testcase); diff --git a/Algorithms.Tests/Problems/NQueens/BacktrackingNQueensSolverTests.cs b/Algorithms.Tests/Problems/NQueens/BacktrackingNQueensSolverTests.cs index 20876d24..bf95ecdb 100644 --- a/Algorithms.Tests/Problems/NQueens/BacktrackingNQueensSolverTests.cs +++ b/Algorithms.Tests/Problems/NQueens/BacktrackingNQueensSolverTests.cs @@ -21,7 +21,6 @@ public static class BacktrackingNQueensSolverTests [TestCase(9, 352)] [TestCase(10, 724)] [TestCase(11, 2680)] - [TestCase(12, 14200)] public static void SolvesCorrectly(int n, int expectedNumberOfSolutions) { // Arrange diff --git a/Algorithms.Tests/Search/JumpSearcherTests.cs b/Algorithms.Tests/Search/JumpSearcherTests.cs index 26a2efe8..34045060 100644 --- a/Algorithms.Tests/Search/JumpSearcherTests.cs +++ b/Algorithms.Tests/Search/JumpSearcherTests.cs @@ -56,10 +56,10 @@ public void FindIndex_ArrayEmpty_MinusOneReturned([Random(-100, 1100, 10)] int m [TestCase(null, "abc")] [TestCase(new[] { "abc", "def", "ghi" }, null)] [TestCase(null, null)] - public void FindIndex_ArrayNull_ItemNull_ArgumentNullExceptionThrown(String[] sortedArray, String searchItem) + public void FindIndex_ArrayNull_ItemNull_ArgumentNullExceptionThrown(string[] sortedArray, string searchItem) { // Arrange - var searcher = new JumpSearcher(); + var searcher = new JumpSearcher(); // Act, Assert _ = Assert.Throws(() => searcher.FindIndex(sortedArray, searchItem)); diff --git a/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs b/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs index b5a5ad44..95efaeea 100644 --- a/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs +++ b/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs @@ -10,7 +10,7 @@ public static class FisherYatesShufflerTests { [Test] public static void ArrayShuffled_NewArrayHasSameSize( - [Random(0, 1000, 100, Distinct = true)] + [Random(10, 1000, 100, Distinct = true)] int n) { // Arrange @@ -26,7 +26,7 @@ public static void ArrayShuffled_NewArrayHasSameSize( [Test] public static void ArrayShuffled_NewArrayHasSameValues( - [Random(0, 1000, 100, Distinct = true)] + [Random(0, 100, 10, Distinct = true)] int n) { // Arrange @@ -59,7 +59,7 @@ public static void ArrayShuffled_SameShuffle( [Test] public static void ArrayShuffled_DifferentSeedDifferentShuffle( - [Random(0, 100, 2, Distinct = true)] int n, + [Random(10, 100, 2, Distinct = true)] int n, [Random(1000, 10000, 5, Distinct = true)] int seed) { // Arrange @@ -72,7 +72,7 @@ public static void ArrayShuffled_DifferentSeedDifferentShuffle( // It seems the actual version of FluentAssertion has no options in NotBeEquivalentTo. // With default options, it does not check for order, but for the same elements in the collection. - // So until the library is updated check that not all the items have the same order. + // So until the library is updated check that not all the items have the same order. int hits = 0; for (int i = 0; i < n; i++) { diff --git a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs index 1e2b5e51..f611744a 100755 --- a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs @@ -12,8 +12,7 @@ public static class TimSorterTests [Test] public static void ArraySorted( - [Random(0, 100_000, 200, Distinct = true)] - int n) + [Random(0, 10_000, 1000)] int n) { // Arrange var sorter = new TimSorter(); diff --git a/Algorithms.Tests/Strings/PermutationTests.cs b/Algorithms.Tests/Strings/PermutationTests.cs index 1af7869d..8bfeae2b 100644 --- a/Algorithms.Tests/Strings/PermutationTests.cs +++ b/Algorithms.Tests/Strings/PermutationTests.cs @@ -15,7 +15,7 @@ public class PermutationTests [TestCase("abcd")] [TestCase("aabcd")] [TestCase("aabbbcd")] - [TestCase("aabbbccccd")] + [TestCase("aabbccccd")] public void Test_GetEveryUniquePermutation(string word) { var permutations = Permutation.GetEveryUniquePermutation(word); diff --git a/Algorithms/Numeric/MillerRabinPrimalityChecker.cs b/Algorithms/Numeric/MillerRabinPrimalityChecker.cs index 813eaff5..b458888a 100644 --- a/Algorithms/Numeric/MillerRabinPrimalityChecker.cs +++ b/Algorithms/Numeric/MillerRabinPrimalityChecker.cs @@ -18,9 +18,18 @@ public static class MillerRabinPrimalityChecker /// /// Number to check. /// Number of rounds, the parameter determines the accuracy of the test, recommended value is Log2(n). + /// Seed for random number generator. /// True if is a highly likely prime number; False otherwise. - /// Error: number should be morhe than 3. - public static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds) + /// Error: number should be more than 3. + public static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds, int? seed = null) + { + Random rand = seed is null + ? new() + : new(seed.Value); + return IsProbablyPrimeNumber(n, rounds, rand); + } + + private static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds, Random rand) { if (n <= 3) { @@ -41,9 +50,6 @@ public static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds) d /= 2; } - BigInteger x; - Random rand = new(); - // as there is no native random function for BigInteger we suppose a random int number is sufficient int nMaxValue = (n > int.MaxValue) ? int.MaxValue : (int)n; BigInteger a = rand.Next(2, nMaxValue - 2); // ; pick a random integer a in the range[2, n − 2] @@ -51,7 +57,7 @@ public static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds) while (rounds > 0) { rounds--; - x = BigInteger.ModPow(a, d, n); + var x = BigInteger.ModPow(a, d, n); if (x == 1 || x == (n - 1)) { continue; diff --git a/DataStructures.Tests/LinkedList/SkipListTests.cs b/DataStructures.Tests/LinkedList/SkipListTests.cs index 87e8bceb..1fe69d17 100644 --- a/DataStructures.Tests/LinkedList/SkipListTests.cs +++ b/DataStructures.Tests/LinkedList/SkipListTests.cs @@ -69,7 +69,7 @@ public static void TestGetByKey_KeyNotFoundException() var list = new SkipList(); list[1] = "value1"; - String value; + string value; Action act = () => value = list[2]; act.Should().Throw(); } @@ -120,4 +120,4 @@ public static void TestGetValues() valuesSortedByKey.Should().ContainInOrder("one", "two", "three", "four"); } } -} \ No newline at end of file +} diff --git a/DataStructures/LinkedList/SkipList/SkipList.cs b/DataStructures/LinkedList/SkipList/SkipList.cs index 926e53da..cb07af0e 100644 --- a/DataStructures/LinkedList/SkipList/SkipList.cs +++ b/DataStructures/LinkedList/SkipList/SkipList.cs @@ -209,7 +209,7 @@ private SkipListNode[] GetSkipNodes(int key) private int GetRandomHeight() { int height = 1; - while (random.NextDouble() < Probability && height <= maxLevels) + while (random.NextDouble() < Probability && height < maxLevels) { height++; } From 30928d20cc51a3fb05f015186417fb4e55c437b7 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Mon, 3 Oct 2022 10:32:30 +0300 Subject: [PATCH 020/138] Fix blinking test --- DataStructures.Tests/Probabilistic/BloomFilterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataStructures.Tests/Probabilistic/BloomFilterTests.cs b/DataStructures.Tests/Probabilistic/BloomFilterTests.cs index b8f11799..aaa4ded0 100644 --- a/DataStructures.Tests/Probabilistic/BloomFilterTests.cs +++ b/DataStructures.Tests/Probabilistic/BloomFilterTests.cs @@ -60,7 +60,7 @@ public void TestBloomFilterInsertOptimalSize() { var filter = new BloomFilter(1000); var set = new HashSet(); - var rand = new Random(); + var rand = new Random(124); var falsePositives = 0; for (var i = 0; i < 1000; i++) { From dad43c3f4358e8776f18faefe5cc2b5da84e8193 Mon Sep 17 00:00:00 2001 From: Matthias Reitinger Date: Mon, 3 Oct 2022 09:46:15 +0200 Subject: [PATCH 021/138] Remove uses of ApplicationException (#334) Co-authored-by: Andrii Siriak --- Algorithms/Search/AStar/PathfindingException.cs | 2 +- Utilities/Exceptions/ItemNotFoundException.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Algorithms/Search/AStar/PathfindingException.cs b/Algorithms/Search/AStar/PathfindingException.cs index 02e94a8e..2de9d1d6 100644 --- a/Algorithms/Search/AStar/PathfindingException.cs +++ b/Algorithms/Search/AStar/PathfindingException.cs @@ -5,7 +5,7 @@ namespace Algorithms.Search.AStar /// /// A pathfinding exception is thrown when the Pathfinder encounters a critical error and can not continue. /// - public class PathfindingException : ApplicationException + public class PathfindingException : Exception { public PathfindingException(string message) : base(message) diff --git a/Utilities/Exceptions/ItemNotFoundException.cs b/Utilities/Exceptions/ItemNotFoundException.cs index da05b373..6b35580b 100644 --- a/Utilities/Exceptions/ItemNotFoundException.cs +++ b/Utilities/Exceptions/ItemNotFoundException.cs @@ -5,7 +5,7 @@ namespace Utilities.Exceptions /// /// Signs that sequence doesn't contain any items that one was looking for. /// - public class ItemNotFoundException : ApplicationException + public class ItemNotFoundException : Exception { } } From a9fa9bfec14ba825464e48ea8b96d2f291c9a662 Mon Sep 17 00:00:00 2001 From: maxsIT <44552868+maxsIT@users.noreply.github.com> Date: Tue, 4 Oct 2022 13:26:07 +0300 Subject: [PATCH 022/138] Add Pareto optimization algorithm (#331) Co-authored-by: Maksym Sitaylo --- .../Other/ParetoOptimizationTests.cs | 46 ++++++++++++ Algorithms/Other/ParetoOptimization.cs | 75 +++++++++++++++++++ README.md | 1 + 3 files changed, 122 insertions(+) create mode 100644 Algorithms.Tests/Other/ParetoOptimizationTests.cs create mode 100644 Algorithms/Other/ParetoOptimization.cs diff --git a/Algorithms.Tests/Other/ParetoOptimizationTests.cs b/Algorithms.Tests/Other/ParetoOptimizationTests.cs new file mode 100644 index 00000000..51b581d5 --- /dev/null +++ b/Algorithms.Tests/Other/ParetoOptimizationTests.cs @@ -0,0 +1,46 @@ +using Algorithms.Other; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Tests.Other +{ + public static class ParetoOptimizationTests + { + [Test] + public static void Verify_Pareto_Optimization() + { + // Arrange + var paretoOptimization = new ParetoOptimization(); + + var matrix = new List> + { + new List { 7, 6, 5, 8, 5, 6 }, + new List { 4, 8, 4, 4, 5, 3 }, + new List { 3, 8, 1, 4, 5, 2 }, + new List { 5, 6, 3, 6, 4, 5 }, + new List { 1, 4, 8, 6, 3, 6 }, + new List { 5, 1, 8, 6, 5, 1 }, + new List { 6, 8, 3, 6, 3, 5 } + }; + + var expectedMatrix = new List> + { + new List { 7, 6, 5, 8, 5, 6 }, + new List { 4, 8, 4, 4, 5, 3 }, + new List { 1, 4, 8, 6, 3, 6 }, + new List { 5, 1, 8, 6, 5, 1 }, + new List { 6, 8, 3, 6, 3, 5 } + }; + + // Act + var optimizedMatrix = paretoOptimization.Optimize(matrix); + + // Assert + Assert.AreEqual(optimizedMatrix, expectedMatrix); + } + } +} diff --git a/Algorithms/Other/ParetoOptimization.cs b/Algorithms/Other/ParetoOptimization.cs new file mode 100644 index 00000000..8f6ec2a5 --- /dev/null +++ b/Algorithms/Other/ParetoOptimization.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Other +{ + /// + /// Almost all real complex decision-making task is described by more than one criterion. + /// Therefore, the methods of multicriteria optimization are important. For a wide range + /// of tasks multicriteria optimization, described by some axioms of "reasonable" + /// behavior in the process of choosing from a set of possible solutions X, each set of + /// selected solutions Sel X should be contained in a set optimal for Pareto. + /// + public class ParetoOptimization + { + /// + /// Performs decision optimizations by using Paretor's optimization algorithm. + /// + /// Contains a collection of the criterias sets. + /// An optimized collection of the criterias sets. + public List> Optimize(List> matrix) + { + var optimizedMatrix = new List>(matrix.Select(i => i)); + int i = 0; + while (i < optimizedMatrix.Count) + { + for (int j = i + 1; j < optimizedMatrix.Count; j++) + { + decimal directParwiseDifference = GetMinimalPairwiseDifference(optimizedMatrix[i], optimizedMatrix[j]); + decimal indirectParwiseDifference = GetMinimalPairwiseDifference(optimizedMatrix[j], optimizedMatrix[i]); + /* + * in case all criteria of one set are larger that the criteria of another, this + * decision is not optimal and it has to be removed + */ + if (directParwiseDifference >= 0 || indirectParwiseDifference >= 0) + { + optimizedMatrix.RemoveAt(directParwiseDifference >= 0 ? j : i); + i--; + break; + } + } + + i++; + } + + return optimizedMatrix; + } + + /// + /// Calculates the smallest difference between criteria of input decisions. + /// + /// Criterias of the first decision. + /// Criterias of the second decision. + /// Values that represent the smallest difference between criteria of input decisions. + private decimal GetMinimalPairwiseDifference(List arr1, List arr2) + { + decimal min = decimal.MaxValue; + if (arr1.Count == arr2.Count) + { + for (int i = 0; i < arr1.Count; i++) + { + decimal difference = arr1[i] - arr2[i]; + if (min > difference) + { + min = difference; + } + } + } + + return min; + } + } +} diff --git a/README.md b/README.md index c0ef5fa1..982a3563 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,7 @@ find more than one implementation for the same objective but using different alg * [Koch Snowflake](./Algorithms/Other/KochSnowflake.cs) * [RGB-HSV Conversion](./Algorithms/Other/RGBHSVConversion.cs) * [Flood Fill](./Algorithms/Other/FloodFill.cs) + * [Pareto Optimization](./Algorithms/Other/ParetoOptimization.cs) * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) * [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs) From 5831b7d51f0a29dcd9fedb18647d52d62e75593e Mon Sep 17 00:00:00 2001 From: Matthias Reitinger Date: Tue, 4 Oct 2022 13:03:24 +0200 Subject: [PATCH 023/138] Add missing tests and documentation in Utilities (#335) --- .../Extensions/DictionaryExtensionsTests.cs | 37 +++++ .../Extensions/MatrixExtensionsTests.cs | 28 ++++ .../Extensions/RandomExtensionsTests.cs | 21 +++ .../Extensions/VectorExtensionsTests.cs | 137 ++++++++++++++++++ Utilities/Extensions/DictionaryExtensions.cs | 13 +- Utilities/Extensions/RandomExtensions.cs | 6 + 6 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 Utilities.Tests/Extensions/DictionaryExtensionsTests.cs create mode 100644 Utilities.Tests/Extensions/RandomExtensionsTests.cs create mode 100644 Utilities.Tests/Extensions/VectorExtensionsTests.cs diff --git a/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs b/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs new file mode 100644 index 00000000..7d34d509 --- /dev/null +++ b/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using FluentAssertions; +using NUnit.Framework; +using Utilities.Extensions; + +namespace Utilities.Tests.Extensions +{ + public class DictionaryExtensionsTests + { + [Test] + public void AddMany_ShouldThrowArgumentException_WhenKeyAlreadyExists() + { + var dictionary = new Dictionary { ["one"] = 1 }; + var enumerable = new[] { ("one", 1), ("two", 2) }; + + var action = () => dictionary.AddMany(enumerable); + + action.Should().Throw(); + } + + [Test] + public void AddMany_ShouldAddAllKeyValuePairs() + { + var dictionary = new Dictionary { ["one"] = 1 }; + var enumerable = new[] { ("two", 2), ("three", 3) }; + + dictionary.AddMany(enumerable); + + dictionary.Should().HaveCount(3); + + dictionary.Should().ContainKey("one").WhichValue.Should().Be(1); + dictionary.Should().ContainKey("two").WhichValue.Should().Be(2); + dictionary.Should().ContainKey("three").WhichValue.Should().Be(3); + } + } +} diff --git a/Utilities.Tests/Extensions/MatrixExtensionsTests.cs b/Utilities.Tests/Extensions/MatrixExtensionsTests.cs index 4fff17b3..952dc257 100644 --- a/Utilities.Tests/Extensions/MatrixExtensionsTests.cs +++ b/Utilities.Tests/Extensions/MatrixExtensionsTests.cs @@ -179,5 +179,33 @@ public void Subtract_ShouldCalculateSubtractionResult( double[,] operand, double[,] result) => source.Subtract(operand).Should().BeEquivalentTo(result); + + [Test] + public void RoundToNextInt_ShouldReturnRoundedMatrix() + { + var source = new[,] + { + { -1.9, 1.9 }, + { -1.5, 1.5 }, + { -1.1, 1.1 }, + { -0.9, 0.9 }, + { -0.5, 0.5 }, + { -0.1, 0.1 }, + }; + + var result = new double[,] + { + { -2, 2 }, + { -2, 2 }, + { -1, 1 }, + { -1, 1 }, + { 0, 0 }, + { 0, 0 }, + }; + + var actualResult = source.RoundToNextInt(); + + actualResult.Should().BeEquivalentTo(result); + } } } diff --git a/Utilities.Tests/Extensions/RandomExtensionsTests.cs b/Utilities.Tests/Extensions/RandomExtensionsTests.cs new file mode 100644 index 00000000..c3c5abb0 --- /dev/null +++ b/Utilities.Tests/Extensions/RandomExtensionsTests.cs @@ -0,0 +1,21 @@ +using System; +using FluentAssertions; +using NUnit.Framework; +using Utilities.Extensions; + +namespace Utilities.Tests.Extensions +{ + public class RandomExtensionsTests + { + [Test] + public void NextVector_ShouldReturnNormalizedVector() + { + var random = new Random(0); + + var result = random.NextVector(10); + + result.Length.Should().Be(10); + result.Magnitude().Should().BeApproximately(1.0, 1e-6); + } + } +} diff --git a/Utilities.Tests/Extensions/VectorExtensionsTests.cs b/Utilities.Tests/Extensions/VectorExtensionsTests.cs new file mode 100644 index 00000000..3c24de8a --- /dev/null +++ b/Utilities.Tests/Extensions/VectorExtensionsTests.cs @@ -0,0 +1,137 @@ +using System; +using FluentAssertions; +using NUnit.Framework; +using Utilities.Extensions; + +namespace Utilities.Tests.Extensions +{ + public class VectorExtensionsTests + { + [Test] + public void Copy_ShouldReturnCopyOfVector() + { + var vector = new double[] { 0, 1, 2, 3 }; + + var vectorCopy = vector.Copy(); + + vectorCopy.Should().BeEquivalentTo(vector); + vectorCopy.Should().NotBeSameAs(vector); + } + + [Test] + public void OuterProduct_ShouldCalculateOuterProduct() + { + var lhs = new double[] { -2, -1, 0, 1, 2 }; + var rhs = new double[] { 1, 2, 3 }; + + var result = new double[,] + { + { -2, -4, -6 }, + { -1, -2, -3 }, + { 0, 0, 0 }, + { 1, 2, 3 }, + { 2, 4, 6 }, + }; + + var actualResult = lhs.OuterProduct(rhs); + + actualResult.Should().BeEquivalentTo(result); + } + + [Test] + public void Dot_ShouldThrowArgumentException_WhenDimensionsDoNotMatch() + { + var lhs = new double[] { 1, 2, 3 }; + var rhs = new double[] { 1, 2, 3, 4 }; + + var func = () => lhs.Dot(rhs); + + func.Should().Throw() + .WithMessage("Dot product arguments must have same dimension"); + } + + [Test] + public void Dot_ShouldCalculateDotProduct() + { + var lhs = new double[] { 1, 2, 3 }; + var rhs = new double[] { 4, 5, 6 }; + + var actualResult = lhs.Dot(rhs); + + actualResult.Should().Be(32); + } + + [Test] + public void Magnitude_ShouldCalculateMagnitude() + { + var vector = new double[] { -3, 4 }; + + var actualResult = vector.Magnitude(); + + actualResult.Should().BeApproximately(5.0, 0.0001); + } + + [Test] + public void Scale_ShouldCalculateScale() + { + var vector = new double[] { -1, 0, 1 }; + var factor = 2; + + var result = new double[] { -2, 0, 2 }; + + var actualResult = vector.Scale(factor); + + actualResult.Should().BeEquivalentTo(result); + } + + [Test] + public void ToColumnVector_ShouldReturnColumnVector() + { + var vector = new double[] { 1, 2, 3, 4 }; + var result = new double[,] { { 1 }, { 2 }, { 3 }, { 4 } }; + + var actualResult = vector.ToColumnVector(); + + actualResult.Should().BeEquivalentTo(result); + } + + [Test] + public void ToRowVector_ShouldThrowInvalidOperationException_WhenSourceIsNotAColumnVector() + { + var source = new double[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } }; + + var func = () => source.ToRowVector(); + + func.Should().Throw() + .WithMessage("The column vector should have only 1 element in width."); + } + + [Test] + public void ToRowVector_ShouldReturnRowVector() + { + var source = new double[,] { { 1 }, { 2 }, { 3 }, { 4 } }; + var result = new double[] { 1, 2, 3, 4 }; + + var actualResult = source.ToRowVector(); + + actualResult.Should().BeEquivalentTo(result); + } + + [Test] + public void ToDiagonalMatrix_ShouldReturnDiagonalMatrix() + { + var source = new double[] { 1, 2, 3, 4 }; + var result = new double[,] + { + { 1, 0, 0, 0 }, + { 0, 2, 0, 0 }, + { 0, 0, 3, 0 }, + { 0, 0, 0, 4 }, + }; + + var actualResult = source.ToDiagonalMatrix(); + + actualResult.Should().BeEquivalentTo(result); + } + } +} diff --git a/Utilities/Extensions/DictionaryExtensions.cs b/Utilities/Extensions/DictionaryExtensions.cs index 632796fa..714232a1 100644 --- a/Utilities/Extensions/DictionaryExtensions.cs +++ b/Utilities/Extensions/DictionaryExtensions.cs @@ -1,9 +1,20 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Utilities.Extensions { public static class DictionaryExtensions { + /// + /// Adds the specified key value tuples to the dictionary. + /// + /// The dictionary. + /// The collection of key value tuples to add. + /// The type of the keys in the dictionary. + /// The type of the values in the dictionary. + /// + /// A key from the already exists in . + /// public static void AddMany( this Dictionary keys, IEnumerable<(TKey, TValue)> enumerable) where TKey : notnull diff --git a/Utilities/Extensions/RandomExtensions.cs b/Utilities/Extensions/RandomExtensions.cs index df750703..87138957 100644 --- a/Utilities/Extensions/RandomExtensions.cs +++ b/Utilities/Extensions/RandomExtensions.cs @@ -5,6 +5,12 @@ namespace Utilities.Extensions { public static class RandomExtensions { + /// + /// Returns a random normalized vector of the specified size. + /// + /// The random number generator. + /// The size of the vector to return. + /// A random normalized vector. public static double[] NextVector(this Random rand, int size) { var vector = Enumerable.Range(0, size) From 4a0eca2aa8f597f8f4694f70cb669adf436a11ea Mon Sep 17 00:00:00 2001 From: Valdas Date: Wed, 5 Oct 2022 21:01:09 +0300 Subject: [PATCH 024/138] Add Levenshtein Distance (#336) Co-authored-by: Valdas --- .../Strings/LevenshteinDistanceTests.cs | 21 ++++++++ Algorithms/Strings/LevenshteinDistance.cs | 48 +++++++++++++++++++ README.md | 1 + 3 files changed, 70 insertions(+) create mode 100644 Algorithms.Tests/Strings/LevenshteinDistanceTests.cs create mode 100644 Algorithms/Strings/LevenshteinDistance.cs diff --git a/Algorithms.Tests/Strings/LevenshteinDistanceTests.cs b/Algorithms.Tests/Strings/LevenshteinDistanceTests.cs new file mode 100644 index 00000000..3822c566 --- /dev/null +++ b/Algorithms.Tests/Strings/LevenshteinDistanceTests.cs @@ -0,0 +1,21 @@ +using Algorithms.Strings; +using NUnit.Framework; + +namespace Algorithms.Tests.Strings +{ + public class LevenshteinDistanceTests + { + [Test] + [TestCase("kitten", "sitting", 3)] + [TestCase("bob", "bond", 2)] + [TestCase("algorithm", "logarithm", 3)] + [TestCase("star", "", 4)] + [TestCase("", "star", 4)] + [TestCase("abcde", "12345", 5)] + public void Calculate_ReturnsCorrectLevenshteinDistance(string source, string destination, int expectedDistance) + { + var result = LevenshteinDistance.Calculate(source, destination); + Assert.AreEqual(expectedDistance, result); + } + } +} diff --git a/Algorithms/Strings/LevenshteinDistance.cs b/Algorithms/Strings/LevenshteinDistance.cs new file mode 100644 index 00000000..e7af537e --- /dev/null +++ b/Algorithms/Strings/LevenshteinDistance.cs @@ -0,0 +1,48 @@ +using System; + +namespace Algorithms.Strings +{ + /// + /// + /// Levenshtein distance between two words is the minimum number of single-character edits (insertions, deletions or substitutions) required to change one word into the other. + /// + /// + /// Wikipedia: https://en.wikipedia.org/wiki/Levenshtein_distance. + /// + /// + public static class LevenshteinDistance + { + /// + /// Calculates Levenshtein distance. + /// Time and space complexity is O(ab) where a and b are the lengths of the source and target strings. + /// + /// Source string. + /// Target string. + /// Levenshtein distance between source and target strings. + public static int Calculate(string source, string target) + { + var distances = new int[source.Length + 1, target.Length + 1]; + + for(var i = 0; i <= source.Length; i++) + { + distances[i, 0] = i; + } + + for (var i = 0; i <= target.Length; i++) + { + distances[0, i] = i; + } + + for (var i = 1; i <= source.Length; i++) + { + for (var j = 1; j <= target.Length; j++) + { + var substitionCost = source[i - 1] == target[j - 1] ? 0 : 1; + distances[i, j] = Math.Min(distances[i - 1, j] + 1, Math.Min(distances[i, j - 1] + 1, distances[i - 1, j - 1] + substitionCost)); + } + } + + return distances[source.Length, target.Length]; + } + } +} diff --git a/README.md b/README.md index 982a3563..630a655d 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,7 @@ find more than one implementation for the same objective but using different alg * [Boyer Moore](./Algorithms/Strings/BoyerMoore.cs) * [Palindrome Checker](./Algorithms/Strings/Palindrome.cs) * [Get all permutations of a string](./Algorithms/Strings/Permutation.cs) + * [Levenshtein Distance](./Algorithms/Strings/LevenshteinDistance.cs) * [Other](./Algorithms/Other) * [Fermat Prime Checker](./Algorithms/Other/FermatPrimeChecker.cs) * [Sieve of Eratosthenes](./Algorithms/Other/SieveOfEratosthenes.cs) From 14bb73cf42a7b11ee4fe18e60fba22400c67bdeb Mon Sep 17 00:00:00 2001 From: Richard Vasquez <1706965+RichardVasquez@users.noreply.github.com> Date: Wed, 5 Oct 2022 11:23:49 -0700 Subject: [PATCH 025/138] Add A000120 (#340) --- .../Sequences/OnesCountingSequenceTest.cs | 108 ++++++++++++++++++ Algorithms/Sequences/OnesCountingSequence.cs | 89 +++++++++++++++ README.md | 1 + 3 files changed, 198 insertions(+) create mode 100644 Algorithms.Tests/Sequences/OnesCountingSequenceTest.cs create mode 100644 Algorithms/Sequences/OnesCountingSequence.cs diff --git a/Algorithms.Tests/Sequences/OnesCountingSequenceTest.cs b/Algorithms.Tests/Sequences/OnesCountingSequenceTest.cs new file mode 100644 index 00000000..49e34025 --- /dev/null +++ b/Algorithms.Tests/Sequences/OnesCountingSequenceTest.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Sequences; + +[TestFixture] +public class OnesCountingSequenceTest +{ + /// + /// + /// Values taken from http://oeis.org/A000120/b000120.txt. + /// + /// + /// While the file contains 10,000 values, this only tests 1000. + /// + /// + private readonly BigInteger[] oeisValues = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, + 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, + 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, + 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, + 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, + 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, + 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, + 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, + 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, + 6, 7, 6, 7, 7, 8, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, + 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, + 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, + 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, + 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, + 7, 5, 6, 6, 7, 6, 7, 7, 8, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, + 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 3, 4, + 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, + 7, 6, 7, 7, 8, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, + 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, + 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, + 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, + 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, + 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, + 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, + 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, + 6, 7, 7, 8, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, + 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, + 7, 8, 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9, 2, 3, 3, 4, 3, 4, 4, + 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, + 6, 6, 7, 6, 7, 7, 8, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, + 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, + 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9, 3, 4, 4, 5, + 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, + 7, 7, 8, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, + 7, 8, 6, 7, 7, 8, 7, 8, 8, 9, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, + 8, 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9, 5, 6, 6, 7, 6, 7, 7, 8, + }; + + /// + /// + /// Performs number of ones in the binary representation of a BigInteger. + /// + /// + /// This is used as a check to compare the provided values from OEIS. + /// + /// + /// BigInteger value to count 1s in + /// Number of 1s in binary representation of number. + private int CountOnes(BigInteger i) + { + var temp = i; + BigInteger remainder = 0; + var result = 0; + + while (temp != BigInteger.Zero) { + temp = BigInteger.DivRem(temp, 2, out remainder); + result += remainder.IsOne ? 1 : 0; + } + + return result; + } + + + [Test] + public void Count1000() + { + // Compare generated sequence against provided data + var sequence = new OnesCountingSequence().Sequence.Take(oeisValues.Length); + sequence.SequenceEqual(oeisValues).Should().BeTrue(); + } + + [Test] + public void CompareAgainstCalculated() + { + // Calculate 1s in binary value the old fashioned way. + var calculated = new List(); + for (var i = 0; i < oeisValues.Length; i++) { + calculated.Add(CountOnes(new BigInteger(i))); + } + + calculated.SequenceEqual(oeisValues).Should().BeTrue(); + } +} diff --git a/Algorithms/Sequences/OnesCountingSequence.cs b/Algorithms/Sequences/OnesCountingSequence.cs new file mode 100644 index 00000000..2836e7b4 --- /dev/null +++ b/Algorithms/Sequences/OnesCountingSequence.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Algorithms.Sequences; + +/// +/// +/// 1's-counting sequence: number of 1's in binary expression of n. +/// +/// +/// OEIS: https://oeis.org/A000120. +/// +/// +public class OnesCountingSequence : ISequence +{ + /// + /// + /// Gets the generated sequence of the 1's contained in the binary representation of n. + /// + /// + /// The sequence is generated as follows. + /// 1. The initial 0 value is provided. + /// 2. A recursively generated sequence is iterated, starting with a length of 1 (i.e., 2^0), + /// followed by increasing 2^x length values. + /// 3. Each sequence starts with the value 1, and a targeted value of depths that it will recurse + /// for the specific iteration. + /// 4. If the call depth to the recursive function is met, it returns the value argument received. + /// 5. If the call depth has not been met, it recurses to create 2 sequences, one starting with the + /// value argument, and the following with the value argument + 1. + /// 6. Using ':' as a visual separator for each sequence, this results in the following sequences + /// that are returned sequentially after the initial 0. + /// 1 : 1, 2 : 1, 2, 2, 3 : 1, 2, 2, 3, 2, 3, 3, 4. + /// + /// + /// + /// This one comes from thinking over information contained within the COMMENTS section of the OEIS page. + /// + /// + /// Using the comments provided by Benoit Cloitre, Robert G. Wilson v, and Daniel Forgues, the above + /// algorithm was coded. + /// + /// + /// + public IEnumerable Sequence + { + get + { + yield return 0; + var depth = 0; + while (true) + { + foreach (var count in GenerateFractalCount(BigInteger.One, depth)) + { + yield return count; + } + + depth++; + } + } + } + + /// + /// + /// Recursive function to generate sequences. + /// + /// + /// The value that will start off the current IEnumerable sequence. + /// The remaining depth of recursion. Value of 0 is the stop condition. + /// An IEnumerable sequence of BigInteger values that can be iterated over. + private static IEnumerable GenerateFractalCount(BigInteger i, int depth) + { + // Terminal condition + if (depth == 0) + { + yield return i; + yield break; + } + + foreach (var firstHalf in GenerateFractalCount(i, depth - 1)) + { + yield return firstHalf; + } + + foreach (var secondHalf in GenerateFractalCount(i + 1, depth - 1)) + { + yield return secondHalf; + } + } +} diff --git a/README.md b/README.md index 630a655d..030b05d9 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,7 @@ find more than one implementation for the same objective but using different alg * [A000045 Fibonacci](./Algorithms/Sequences/FibonacciSequence.cs) * [A000079 Powers of 2](./Algorithms/Sequences/PowersOf2Sequence.cs) * [A000108 Catalan](./Algorithms/Sequences/CatalanSequence.cs) + * [A000120 1's Counting](./Algorithms/Sequences/OnesCountingSequence.cs) * [A000142 Factorial](./Algorithms/Sequences/FactorialSequence.cs) * [A000215 Fermat Numbers](./Algorithms/Sequences/FermatNumbersSequence.cs) * [A000290 Squares](./Algorithms/Sequences/SquaresSequence.cs) From 12d72d500d6d711042c59a21c6091dd2477f1a20 Mon Sep 17 00:00:00 2001 From: Kalkwst Date: Thu, 6 Oct 2022 10:06:03 +0300 Subject: [PATCH 026/138] Add Krishnamurthy Number Checker (#333) --- .../KrishnamurthyNumberCheckerTests.cs | 36 ++++++++++++++++++ .../Numeric/KrishnamurthyNumberChecker.cs | 38 +++++++++++++++++++ README.md | 1 + 3 files changed, 75 insertions(+) create mode 100644 Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs create mode 100644 Algorithms/Numeric/KrishnamurthyNumberChecker.cs diff --git a/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs b/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs new file mode 100644 index 00000000..a2107668 --- /dev/null +++ b/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs @@ -0,0 +1,36 @@ +using Algorithms.Numeric; +using NUnit.Framework; + +namespace Algorithms.Tests.Numeric +{ + public class KrishnamurthyNumberCheckerTests + { + [TestCase(1)] + [TestCase(2)] + [TestCase(145)] + [TestCase(40585)] + public void KrishnamurthyNumberCheckerKnownNumbers(int number) + { + var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); + Assert.IsTrue(result); + } + + [TestCase(3)] + [TestCase(4)] + [TestCase(239847)] + [TestCase(12374)] + public void KrishnamurthyNumberCheckerNotKMNumber(int number) + { + var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); + Assert.IsFalse(result); + } + + [TestCase(0)] + [TestCase(-1)] + public void KrishnamurthyNumberCheckerNotPositiveNumber(int number) + { + var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); + Assert.IsFalse(result); + } + } +} diff --git a/Algorithms/Numeric/KrishnamurthyNumberChecker.cs b/Algorithms/Numeric/KrishnamurthyNumberChecker.cs new file mode 100644 index 00000000..95a199e0 --- /dev/null +++ b/Algorithms/Numeric/KrishnamurthyNumberChecker.cs @@ -0,0 +1,38 @@ +using System; + +namespace Algorithms.Numeric +{ + /// + /// A Krishnamurthy number is a number whose sum of the factorial of digits + /// is equal to the number itself. + /// + /// For example, 145 is a Krishnamurthy number since: 1! + 4! + 5! = 1 + 24 + 120 = 145. + /// + public static class KrishnamurthyNumberChecker + { + /// + /// Check if a number is Krishnamurthy number or not. + /// + /// The number to check. + /// True if the number is Krishnamurthy, false otherwise. + public static bool IsKMurthyNumber(int n) + { + int sumOfFactorials = 0; + int tmp = n; + + if (n <= 0) + { + return false; + } + + while (n != 0) + { + int factorial = (int)Factorial.Calculate(n % 10); + sumOfFactorials += factorial; + n = n / 10; + } + + return tmp == sumOfFactorials; + } + } +} diff --git a/README.md b/README.md index 030b05d9..4da484d7 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ find more than one implementation for the same objective but using different alg * [Perfect Square Checker](./Algorithms/Numeric/PerfectSquareChecker.cs) * [Euler Method](./Algorithms/Numeric/EulerMethod.cs) * [Miller-Rabin primality check](./Algorithms/Numeric/MillerRabinPrimalityChecker.cs) + * [KrishnamurthyNumberChecker](./Algorithms/Numeric/KrishnamurthyNumberChecker.cs) * [Searches](./Algorithms/Search) * [A-Star](./Algorithms/Search/AStar/) * [Binary Search](./Algorithms/Search/BinarySearcher.cs) From 8ac76fd9ea1a4f19014332b99711917fdfe08a48 Mon Sep 17 00:00:00 2001 From: Valdas Date: Thu, 6 Oct 2022 10:14:24 +0300 Subject: [PATCH 027/138] Add Hamming distance (#339) Co-authored-by: Valdas Co-authored-by: Andrii Siriak --- .../Strings/HammingDistanceTests.cs | 25 ++++++++++++ Algorithms/Strings/HammingDistance.cs | 38 +++++++++++++++++++ README.md | 1 + 3 files changed, 64 insertions(+) create mode 100644 Algorithms.Tests/Strings/HammingDistanceTests.cs create mode 100644 Algorithms/Strings/HammingDistance.cs diff --git a/Algorithms.Tests/Strings/HammingDistanceTests.cs b/Algorithms.Tests/Strings/HammingDistanceTests.cs new file mode 100644 index 00000000..1a2c7702 --- /dev/null +++ b/Algorithms.Tests/Strings/HammingDistanceTests.cs @@ -0,0 +1,25 @@ +using Algorithms.Strings; +using NUnit.Framework; +using System; + +namespace Algorithms.Tests.Strings +{ + public class HammingDistanceTests + { + [Test] + [TestCase("equal", "equal", 0)] + [TestCase("dog", "dig", 1)] + [TestCase("12345", "abcde", 5)] + public void Calculate_ReturnsCorrectHammingDistance(string s1, string s2, int expectedDistance) + { + var result = HammingDistance.Calculate(s1, s2); + Assert.AreEqual(expectedDistance, result); + } + + [Test] + public void Calculate_ThrowsArgumentExceptionWhenStringLengthsDiffer() + { + Assert.Throws(() => HammingDistance.Calculate("123", "12345")); + } + } +} diff --git a/Algorithms/Strings/HammingDistance.cs b/Algorithms/Strings/HammingDistance.cs new file mode 100644 index 00000000..2490bd67 --- /dev/null +++ b/Algorithms/Strings/HammingDistance.cs @@ -0,0 +1,38 @@ +using System; + +namespace Algorithms.Strings +{ + /// + /// + /// Hamming distance between two strings of equal length is the number of positions at which the corresponding symbols are different. + /// Time complexity is O(n) where n is the length of the string. + /// + /// + /// Wikipedia: https://en.wikipedia.org/wiki/Hamming_distance. + /// + /// + public static class HammingDistance + { + /// + /// Calculates Hamming distance between two strings of equal length. + /// + /// First string. + /// Second string. + /// Levenshtein distance between source and target strings. + public static int Calculate(string s1, string s2) + { + if(s1.Length != s2.Length) + { + throw new ArgumentException("Strings must be equal length."); + } + + var distance = 0; + for (var i = 0; i < s1.Length; i++) + { + distance += s1[i] != s2[i] ? 1 : 0; + } + + return distance; + } + } +} diff --git a/README.md b/README.md index 4da484d7..41510b7a 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,7 @@ find more than one implementation for the same objective but using different alg * [Palindrome Checker](./Algorithms/Strings/Palindrome.cs) * [Get all permutations of a string](./Algorithms/Strings/Permutation.cs) * [Levenshtein Distance](./Algorithms/Strings/LevenshteinDistance.cs) + * [Hamming Distance](./Algorithms/Strings/HammingDistance.cs) * [Other](./Algorithms/Other) * [Fermat Prime Checker](./Algorithms/Other/FermatPrimeChecker.cs) * [Sieve of Eratosthenes](./Algorithms/Other/SieveOfEratosthenes.cs) From 1fc8b2d73630480f1b104aa683a8af8c5b6b0e4c Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Thu, 6 Oct 2022 10:33:12 +0300 Subject: [PATCH 028/138] Update TimSorterTests.cs --- Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs index f611744a..0015149d 100755 --- a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs @@ -12,7 +12,7 @@ public static class TimSorterTests [Test] public static void ArraySorted( - [Random(0, 10_000, 1000)] int n) + [Random(0, 10_000, 2000)] int n) { // Arrange var sorter = new TimSorter(); From d53effb36b5825b9227e075edbf498d2f97556a8 Mon Sep 17 00:00:00 2001 From: maxsIT <44552868+maxsIT@users.noreply.github.com> Date: Thu, 6 Oct 2022 10:51:27 +0300 Subject: [PATCH 029/138] Add linear and maxmin decision selection methods (#341) Co-authored-by: Maksym Sitaylo --- .../Other/DecisionsConvolutionsTest.cs | 65 ++++++++++++++++ Algorithms/Other/DecisionsConvolutions.cs | 78 +++++++++++++++++++ README.md | 1 + 3 files changed, 144 insertions(+) create mode 100644 Algorithms.Tests/Other/DecisionsConvolutionsTest.cs create mode 100644 Algorithms/Other/DecisionsConvolutions.cs diff --git a/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs b/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs new file mode 100644 index 00000000..aa8c16c7 --- /dev/null +++ b/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs @@ -0,0 +1,65 @@ +using Algorithms.Other; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Tests.Other +{ + public static class DecisionsConvolutionsTest + { + [Test] + public static void Verify_Linear_Convolution() + { + // Arrange + var matrix = new List> + { + new List { 7, 6, 5, 8, 5, 6 }, + new List { 4, 8, 4, 4, 5, 3 }, + new List { 3, 8, 1, 4, 5, 2 }, + new List { 5, 6, 3, 6, 4, 5 }, + new List { 1, 4, 8, 6, 3, 6 }, + new List { 5, 1, 8, 6, 5, 1 }, + new List { 6, 8, 3, 6, 3, 5 } + }; + + var expectedMatrix = new List { 7, 6, 5, 8, 5, 6 }; + + var priorities = new List { 1, 1, 1, 1, 0.545m, 0.583m }; + + // Act + var optimizedMatrix = DecisionsConvolutions.Linear(matrix, priorities); + + // Assert + Assert.AreEqual(optimizedMatrix, expectedMatrix); + } + + [Test] + public static void Verify_MaxMin_Convolution() + { + // Arrange + var matrix = new List> + { + new List { 7, 6, 5, 8, 5, 6 }, + new List { 4, 8, 4, 4, 5, 3 }, + new List { 3, 8, 1, 4, 5, 2 }, + new List { 5, 6, 3, 6, 4, 5 }, + new List { 1, 4, 8, 6, 3, 6 }, + new List { 5, 1, 8, 6, 5, 1 }, + new List { 6, 8, 3, 6, 3, 5 } + }; + + var expectedMatrix = new List { 7, 6, 5, 8, 5, 6 }; + + var priorities = new List { 1, 1, 1, 1, 0.545m, 0.583m }; + + // Act + var optimizedMatrix = DecisionsConvolutions.MaxMin(matrix, priorities); + + // Assert + Assert.AreEqual(optimizedMatrix, expectedMatrix); + } + } +} diff --git a/Algorithms/Other/DecisionsConvolutions.cs b/Algorithms/Other/DecisionsConvolutions.cs new file mode 100644 index 00000000..fcb23342 --- /dev/null +++ b/Algorithms/Other/DecisionsConvolutions.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Other +{ + /// + /// Almost all real complex decision-making task is described by more than one criterion. + /// There are different methods to select the best decisions from the defined set of decisions. + /// This class contains implementations of the popular convolution methods: linear and maxmin. + /// + public static class DecisionsConvolutions + { + /// + /// This method implements the linear method of decision selection. It is based on + /// the calculation of the "value" for each decision and the selection of the most + /// valuable one. + /// + /// Contains a collection of the criteria sets. + /// Contains a set of priorities for each criterion. + /// The most effective decision that is represented by a set of criterias. + public static List Linear(List> matrix, List priorities) + { + var decisionValues = new List(); + + foreach (var decision in matrix) + { + decimal sum = 0; + for (int i = 0; i < decision.Count; i++) + { + sum += decision[i] * priorities[i]; + } + + decisionValues.Add(sum); + } + + decimal bestDecisionValue = decisionValues.Max(); + int bestDecisionIndex = decisionValues.IndexOf(bestDecisionValue); + + return matrix[bestDecisionIndex]; + } + + /// + /// This method implements maxmin method of the decision selection. It is based on + /// the calculation of the least criteria value and comparison of decisions based + /// on the calculated results. + /// + /// Contains a collection of the criteria sets. + /// Contains a set of priorities for each criterion. + /// The most effective decision that is represented by a set of criterias. + public static List MaxMin(List> matrix, List priorities) + { + var decisionValues = new List(); + + foreach (var decision in matrix) + { + decimal minValue = decimal.MaxValue; + for (int i = 0; i < decision.Count; i++) + { + decimal result = decision[i] * priorities[i]; + if (result < minValue) + { + minValue = result; + } + } + + decisionValues.Add(minValue); + } + + decimal bestDecisionValue = decisionValues.Max(); + int bestDecisionIndex = decisionValues.IndexOf(bestDecisionValue); + + return matrix[bestDecisionIndex]; + } + } +} diff --git a/README.md b/README.md index 41510b7a..4feba428 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ find more than one implementation for the same objective but using different alg * [RGB-HSV Conversion](./Algorithms/Other/RGBHSVConversion.cs) * [Flood Fill](./Algorithms/Other/FloodFill.cs) * [Pareto Optimization](./Algorithms/Other/ParetoOptimization.cs) + * [Decisions Convolutions](./Algorithms/Other/DecisionsConvolutions.cs) * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) * [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs) From dfae27502c7c12be93e65ea3c78b579f62ca0c83 Mon Sep 17 00:00:00 2001 From: maxsIT <44552868+maxsIT@users.noreply.github.com> Date: Fri, 7 Oct 2022 10:25:48 +0300 Subject: [PATCH 030/138] Add Gauss optimization algorithm (#342) Co-authored-by: Maksym Sitaylo --- .../Other/GaussOptimizationTest.cs | 101 ++++++++++++++++++ Algorithms/Other/GaussOptimization.cs | 80 ++++++++++++++ README.md | 1 + 3 files changed, 182 insertions(+) create mode 100644 Algorithms.Tests/Other/GaussOptimizationTest.cs create mode 100644 Algorithms/Other/GaussOptimization.cs diff --git a/Algorithms.Tests/Other/GaussOptimizationTest.cs b/Algorithms.Tests/Other/GaussOptimizationTest.cs new file mode 100644 index 00000000..338fafbd --- /dev/null +++ b/Algorithms.Tests/Other/GaussOptimizationTest.cs @@ -0,0 +1,101 @@ +using Algorithms.Other; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Tests.Other +{ + public static class GaussOptimizationTest + { + [Test] + public static void Verify_Gauss_Optimization_Positive() + { + // Arrange + var gaussOptimization = new GaussOptimization(); + + // Declaration of the constants that are used in the function + var coefficients = new List { 0.3, 0.6, 2.6, 0.3, 0.2, 1.4 }; + + // Description of the function + var func = (double x1, double x2) => + { + if (x1 > 1 || x1 < 0 || x2 > 1 || x2 < 0) + { + return 0; + } + + return coefficients[0] + coefficients[1] * x1 + coefficients[2] * x2 + coefficients[3] * x1 * x2 + + coefficients[4] * x1 * x1 + coefficients[5] * x2 * x2; + }; + + // The parameter that identifies how much step size will be decreased each iteration + double n = 2.4; + + // Default values of x1 and x2. These values will be used for the calculation of the next + // coordinates by Gauss optimization method + double x1 = 0.5; + double x2 = 0.5; + + // Default optimization step + double step = 0.5; + + // This value is used to control the accuracy of the optimization. In case if the error is less + // than eps, optimization will be stopped + double eps = Math.Pow(0.1, 10); + + // Act + (x1, x2) = gaussOptimization.Optimize(func, n, step, eps, x1, x2); + + // Assert + Assert.AreEqual(x1, 1, 0.3); + Assert.AreEqual(x2, 1, 0.3); + } + + [Test] + public static void Verify_Gauss_Optimization_Negative() + { + // Arrange + var gaussOptimization = new GaussOptimization(); + + // Declaration of the constants that are used in the function + var coefficients = new List { -0.3, -0.6, -2.6, -0.3, -0.2, -1.4 }; + + // Description of the function + var func = (double x1, double x2) => + { + if (x1 > 0 || x1 < -1 || x2 > 0 || x2 < -1) + { + return 0; + } + + return coefficients[0] + coefficients[1] * x1 + coefficients[2] * x2 + coefficients[3] * x1 * x2 + + coefficients[4] * x1 * x1 + coefficients[5] * x2 * x2; + }; + + // The parameter that identifies how much step size will be decreased each iteration + double n = 2.4; + + // Default values of x1 and x2. These values will be used for the calculation of the next + // coordinates by Gauss optimization method + double x1 = -0.5; + double x2 = -0.5; + + // Default optimization step + double step = 0.5; + + // This value is used to control the accuracy of the optimization. In case if the error is less + // than eps, optimization will be stopped + double eps = Math.Pow(0.1, 10); + + // Act + (x1, x2) = gaussOptimization.Optimize(func, n, step, eps, x1, x2); + + // Assert + Assert.AreEqual(x1, -1, 0.3); + Assert.AreEqual(x2, -1, 0.3); + } + } +} diff --git a/Algorithms/Other/GaussOptimization.cs b/Algorithms/Other/GaussOptimization.cs new file mode 100644 index 00000000..117ef910 --- /dev/null +++ b/Algorithms/Other/GaussOptimization.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Other +{ + /// + /// The Gaussian method (coordinate descent method) refers to zero-order methods in which only the value + /// of the function Q(X) at different points in the space of variables is used to organize the search + /// for the extremum. This reduces the overall computational cost of finding the extremum. Also in + /// the Gaussian method, the procedures for finding and moving the operating point are simplified as + /// much as possible. + /// + public class GaussOptimization + { + /// + /// Implementation of function extremum search by the Gauss optimization algorithm. + /// + /// Function for which extremum has to be found. + /// This parameter identifies how much step size will be decreased each iteration. + /// The initial shift step. + /// This value is used to control the accuracy of the optimization. In case if the error is less than eps, + /// optimization will be stopped. + /// The first function parameter. + /// The second function parameter. + /// A tuple of coordinates of function extremum. + public (double, double) Optimize( + Func func, + double n, + double step, + double eps, + double x1, + double x2) + { + // The initial value of the error + double error = 1; + + while (Math.Abs(error) > eps) + { + // Calculation of the function with coordinates that are calculated with shift + double bottom = func(x1, x2 - step); + double top = func(x1, x2 + step); + double left = func(x1 - step, x2); + double right = func(x1 + step, x2); + + // Determination of the best option. + var possibleFunctionValues = new List { bottom, top, left, right }; + double maxValue = possibleFunctionValues.Max(); + double maxValueIndex = possibleFunctionValues.IndexOf(maxValue); + + // Error evaluation + error = maxValue - func(x1, x2); + + // Coordinates update for the best option + switch (maxValueIndex) + { + case 0: + x2 -= step; + break; + case 1: + x2 += step; + break; + case 2: + x1 -= step; + break; + default: + x1 += step; + break; + } + + // Step reduction + step /= n; + } + + return (x1, x2); + } + } +} diff --git a/README.md b/README.md index 4feba428..996af18b 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ find more than one implementation for the same objective but using different alg * [RGB-HSV Conversion](./Algorithms/Other/RGBHSVConversion.cs) * [Flood Fill](./Algorithms/Other/FloodFill.cs) * [Pareto Optimization](./Algorithms/Other/ParetoOptimization.cs) + * [Gauss Optimization](./Algorithms/Other/GaussOptimization.cs) * [Decisions Convolutions](./Algorithms/Other/DecisionsConvolutions.cs) * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) From 670da9f8447219faaab01e5837e17a5d3518080c Mon Sep 17 00:00:00 2001 From: Valdas Date: Sat, 8 Oct 2022 13:36:36 +0300 Subject: [PATCH 031/138] Add Jaro Similarity (#345) Co-authored-by: Valdas --- .../Strings/JaroSimilarityTests.cs | 22 +++++ Algorithms/Strings/JaroSimilarity.cs | 97 +++++++++++++++++++ README.md | 1 + 3 files changed, 120 insertions(+) create mode 100644 Algorithms.Tests/Strings/JaroSimilarityTests.cs create mode 100644 Algorithms/Strings/JaroSimilarity.cs diff --git a/Algorithms.Tests/Strings/JaroSimilarityTests.cs b/Algorithms.Tests/Strings/JaroSimilarityTests.cs new file mode 100644 index 00000000..390e69d6 --- /dev/null +++ b/Algorithms.Tests/Strings/JaroSimilarityTests.cs @@ -0,0 +1,22 @@ +using Algorithms.Strings; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Strings +{ + public class JaroSimilarityTests + { + [Test] + [TestCase("equal", "equal", 1)] + [TestCase("abc", "123", 0)] + [TestCase("FAREMVIEL", "FARMVILLE", 0.88d)] + [TestCase("CRATE", "TRACE", 0.73d)] + [TestCase("CRATE11111", "CRTAE11111", 0.96d)] + [TestCase("a", "a", 1)] + [TestCase("", "", 1)] + public void Calculate_ReturnsCorrectJaroSimilarity(string s1, string s2, double expected) + { + JaroSimilarity.Calculate(s1, s2).Should().BeApproximately(expected, 0.01); + } + } +} diff --git a/Algorithms/Strings/JaroSimilarity.cs b/Algorithms/Strings/JaroSimilarity.cs new file mode 100644 index 00000000..82db856c --- /dev/null +++ b/Algorithms/Strings/JaroSimilarity.cs @@ -0,0 +1,97 @@ +using System; + +namespace Algorithms.Strings +{ + /// + /// + /// Jaro Similarity measures how similar two strings are. + /// Result is between 0 and 1 where 0 represnts that there is no similarity between strings and 1 represents equal strings. + /// Time complexity is O(a*b) where a is the length of the first string and b is the length of the second string. + /// + /// + /// Wikipedia: https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance#Jaro_similarity. + /// + /// + public static class JaroSimilarity + { + /// + /// Calculates Jaro Similarity between two strings. + /// + /// First string. + /// Second string. + public static double Calculate(string s1, string s2) + { + if (s1 == s2) + { + return 1; + } + + var longerString = s1.Length > s2.Length ? s1 : s2; + var shorterString = s1.Length < s2.Length ? s1 : s2; + + // will look for matching characters in this range + var matchingCharacterRange = Math.Max((longerString.Length / 2) - 1, 0); + var matches = 0d; + + // true if i-th index of s1 was matched in s2 + var s1MatchedIndeces = new bool[s1.Length]; + + // true if i-th index of s2 was matched in s1 + var s2MatchedIndeces = new bool[s2.Length]; + + for (var i = 0; i < longerString.Length; i++) + { + var startIndex = Math.Max(i - matchingCharacterRange, 0); + var endIndex = Math.Min(i + matchingCharacterRange, shorterString.Length - 1); + for (var j = startIndex; j <= endIndex; j++) + { + if (s1[i] == s2[j] && !s2MatchedIndeces[j]) + { + matches++; + s1MatchedIndeces[i] = true; + s2MatchedIndeces[j] = true; + break; + } + } + } + + if (matches == 0) + { + return 0; + } + + var transpositions = CalculateTranspositions(s1, s2, s1MatchedIndeces, s2MatchedIndeces); + + return ((matches / s1.Length) + (matches / s2.Length) + ((matches - transpositions) / matches)) / 3; + } + + /// + /// Calculates number of matched characters that are not in the right order. + /// + private static int CalculateTranspositions(string s1, string s2, bool[] s1MatchedIndeces, bool[] s2MatchedIndeces) + { + var transpositions = 0; + var s2Index = 0; + for (var s1Index = 0; s1Index < s1.Length; s1Index++) + { + if (s1MatchedIndeces[s1Index]) + { + while (!s2MatchedIndeces[s2Index]) + { + s2Index++; + } + + if (s1[s1Index] != s2[s2Index]) + { + transpositions++; + } + + s2Index++; + } + } + + transpositions /= 2; + return transpositions; + } + } +} diff --git a/README.md b/README.md index 996af18b..ee90505b 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,7 @@ find more than one implementation for the same objective but using different alg * [Get all permutations of a string](./Algorithms/Strings/Permutation.cs) * [Levenshtein Distance](./Algorithms/Strings/LevenshteinDistance.cs) * [Hamming Distance](./Algorithms/Strings/HammingDistance.cs) + * [Jaro Similarity](./Algorithms/Strings/JaroSimilarity.cs) * [Other](./Algorithms/Other) * [Fermat Prime Checker](./Algorithms/Other/FermatPrimeChecker.cs) * [Sieve of Eratosthenes](./Algorithms/Other/SieveOfEratosthenes.cs) From aaf5b37d279314057e329334d0ff0aedf8620c85 Mon Sep 17 00:00:00 2001 From: JJS <29949+JJS@users.noreply.github.com> Date: Sat, 8 Oct 2022 12:59:03 +0200 Subject: [PATCH 032/138] Improve Avl tree (#348) --- DataStructures.Tests/AVLTreeTests.cs | 256 +++++++++++++++++++++---- DataStructures/AVLTree/AVLTree.cs | 260 +++++++++++++------------- DataStructures/AVLTree/AVLTreeNode.cs | 24 +-- 3 files changed, 364 insertions(+), 176 deletions(-) diff --git a/DataStructures.Tests/AVLTreeTests.cs b/DataStructures.Tests/AVLTreeTests.cs index 9ea883a1..f02d5b78 100644 --- a/DataStructures.Tests/AVLTreeTests.cs +++ b/DataStructures.Tests/AVLTreeTests.cs @@ -4,19 +4,32 @@ using DataStructures.AVLTree; using FluentAssertions; using NUnit.Framework; +using static FluentAssertions.FluentActions; namespace DataStructures.Tests { internal class AvlTreeTests { + private static readonly int[] Data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + private static readonly int[] PreOrder = { 4, 2, 1, 3, 8, 6, 5, 7, 9, 10 }; + private static readonly int[] PostOrder = { 1, 3, 2, 5, 7, 6, 10, 9, 8, 4 }; + [Test] public void Constructor_UseCustomComparer_FormsCorrectTree() { var tree = new AvlTree(Comparer.Create((x, y) => y.CompareTo(x))); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + + tree.AddRange(Data); + tree.GetMin().Should().Be(10); + tree.GetMax().Should().Be(1); - tree.GetKeysInOrder().SequenceEqual(new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }).Should().BeTrue(); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + Data.Reverse(), + config => config.WithStrictOrdering()); } [Test] @@ -24,14 +37,29 @@ public void Add_MultipleKeys_FormsCorrectTree() { var tree = new AvlTree(); - foreach(var value in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + for (var i = 0; i < Data.Length; ++i) { - tree.Add(value); - tree.Count.Should().Be(value); + tree.Add(Data[i]); + tree.Count.Should().Be(i + 1); } - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 8, 6, 5, 7, 9, 10 }).Should().BeTrue(); + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + Data, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + PreOrder, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + PostOrder, + config => config.WithStrictOrdering()); } [Test] @@ -39,7 +67,8 @@ public void Add_KeyAlreadyInTree_ThrowsException() { var tree = new AvlTree(); tree.AddRange(new[] { 1, 2, 3, 4, 5 }); - Assert.Throws(() => tree.Add(1)); + + Invoking(() => tree.Add(1)).Should().ThrowExactly(); } [Test] @@ -47,38 +76,107 @@ public void AddRange_MultipleKeys_FormsCorrectTree() { var tree = new AvlTree(); tree.AddRange(new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }); + tree.Count.Should().Be(7); - tree.GetKeysInOrder().SequenceEqual(new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 'd', 'b', 'a', 'c', 'f', 'e', 'g' }).Should().BeTrue(); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + new[] { 'd', 'b', 'a', 'c', 'f', 'e', 'g' }, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + new[] { 'a', 'c', 'b', 'e', 'g', 'f', 'd' }, + config => config.WithStrictOrdering()); } [Test] public void Remove_MultipleKeys_TreeStillValid() { var tree = new AvlTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.AddRange(Data); tree.Remove(7); + tree.Count.Should().Be(9); tree.Contains(7).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 8, 9, 10 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 8, 6, 5, 9, 10 }).Should().BeTrue(); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + new[] { 1, 2, 3, 4, 5, 6, 8, 9, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + new[] { 4, 2, 1, 3, 8, 6, 5, 9, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + new[] { 1, 3, 2, 5, 6, 10, 9, 8, 4 }, + config => config.WithStrictOrdering()); tree.Remove(2); + tree.Count.Should().Be(8); tree.Contains(2).Should().BeFalse(); tree.Remove(1); + tree.Count.Should().Be(7); tree.Contains(1).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 3, 4, 5, 6, 8, 9, 10 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 8, 4, 3, 6, 5, 9, 10 }).Should().BeTrue(); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + new[] { 3, 4, 5, 6, 8, 9, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + new[] { 8, 4, 3, 6, 5, 9, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + new[] { 3, 5, 6, 4, 10, 9, 8 }, + config => config.WithStrictOrdering()); tree.Remove(9); + tree.Count.Should().Be(6); tree.Contains(9).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 3, 4, 5, 6, 8, 10 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 6, 4, 3, 5, 8, 10 }).Should().BeTrue(); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + new[] { 3, 4, 5, 6, 8, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + new[] { 6, 4, 3, 5, 8, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + new[] { 3, 5, 4, 10, 8, 6 }, + config => config.WithStrictOrdering()); tree.Remove(3); tree.Remove(4); @@ -88,29 +186,93 @@ public void Remove_MultipleKeys_TreeStillValid() tree.Remove(10); tree.Count.Should().Be(0); - tree.GetKeysInOrder().SequenceEqual(Array.Empty()).Should().BeTrue(); + tree.GetKeysInOrder().Should().BeEmpty(); + } + + [Test] + public void Remove_MultipleKeys_TreeStillValid_Variant2() + { + var tree = new AvlTree(); + tree.AddRange(Data); + + tree.Remove(10); + + tree.Count.Should().Be(9); + tree.Contains(10).Should().BeFalse(); + + tree.Remove(5); + + tree.Count.Should().Be(8); + tree.Contains(5).Should().BeFalse(); + + tree.Remove(7); + + tree.Count.Should().Be(7); + tree.Contains(7).Should().BeFalse(); + + tree.Remove(9); + + tree.Count.Should().Be(6); + tree.Contains(9).Should().BeFalse(); + + tree.Remove(1); + + tree.Count.Should().Be(5); + tree.Contains(1).Should().BeFalse(); + + tree.Remove(3); + + tree.Count.Should().Be(4); + tree.Contains(3).Should().BeFalse(); + + tree.Remove(2); + + tree.Count.Should().Be(3); + tree.Contains(2).Should().BeFalse(); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + new[] { 4,6,8 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + new[] { 6,4,8 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + new[] { 4,8,6 }, + config => config.WithStrictOrdering()); } [Test] public void Remove_EmptyTree_ThrowsException() { var tree = new AvlTree(); - Assert.Throws(() => tree.Remove(1)); + + Invoking(() => tree.Remove(1)).Should().ThrowExactly(); } [Test] public void Remove_KeyNotInTree_ThrowsException() { var tree = new AvlTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - Assert.Throws(() => tree.Remove(24)); + tree.AddRange(Data); + + Invoking(() => tree.Remove(24)).Should().ThrowExactly(); } [Test] public void Contains_CorrectReturn() { var tree = new AvlTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + + tree.AddRange(Data); + tree.Contains(3).Should().BeTrue(); tree.Contains(7).Should().BeTrue(); tree.Contains(24).Should().BeFalse(); @@ -121,6 +283,7 @@ public void Contains_CorrectReturn() public void Contains_EmptyTree_ReturnsFalse() { var tree = new AvlTree(); + tree.Contains(5).Should().BeFalse(); tree.Contains(-12).Should().BeFalse(); } @@ -129,7 +292,8 @@ public void Contains_EmptyTree_ReturnsFalse() public void GetMin_CorrectReturn() { var tree = new AvlTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.AddRange(Data); + tree.GetMin().Should().Be(1); } @@ -137,14 +301,16 @@ public void GetMin_CorrectReturn() public void GetMin_EmptyTree_ThrowsException() { var tree = new AvlTree(); - Assert.Throws(() => tree.GetMin()); + + Invoking(() => tree.GetMin()).Should().ThrowExactly(); } [Test] public void GetMax_CorrectReturn() { var tree = new AvlTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.AddRange(Data); + tree.GetMax().Should().Be(10); } @@ -152,52 +318,72 @@ public void GetMax_CorrectReturn() public void GetMax_EmptyTree_ThrowsException() { var tree = new AvlTree(); - Assert.Throws(() => tree.GetMax()); + + Invoking(() => tree.GetMax()).Should().ThrowExactly(); } [Test] public void GetKeysInOrder_CorrectReturn() { var tree = new AvlTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); + tree.AddRange(Data); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + Data, + config => config.WithStrictOrdering()); } [Test] public void GetKeysInOrder_EmptyTree_CorrectReturn() { var tree = new AvlTree(); - tree.GetKeysInOrder().SequenceEqual(Array.Empty()).Should().BeTrue(); + + tree.GetKeysInOrder().Should().BeEmpty(); } [Test] public void GetKeysPreOrder_CorrectReturn() { var tree = new AvlTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 8, 6, 5, 7, 9, 10 }).Should().BeTrue(); + + tree.AddRange(Data); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + PreOrder, + config => config.WithStrictOrdering()); } [Test] public void GetKeysPreOrder_EmptyTree_CorrectReturn() { var tree = new AvlTree(); - tree.GetKeysPreOrder().SequenceEqual(Array.Empty()).Should().BeTrue(); + + tree.GetKeysPreOrder().Should().BeEmpty(); } [Test] public void GetKeysPostOrder_CorrectReturn() { var tree = new AvlTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 6, 10, 9, 8, 4 }).Should().BeTrue(); + tree.AddRange(Data); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + PostOrder, + config => config.WithStrictOrdering()); } [Test] public void GetKeysPostOrder_EmptyTree_CorrectReturn() { var tree = new AvlTree(); - tree.GetKeysPostOrder().SequenceEqual(Array.Empty()).Should().BeTrue(); + + tree.GetKeysPostOrder().Should().BeEmpty(); } } } diff --git a/DataStructures/AVLTree/AVLTree.cs b/DataStructures/AVLTree/AVLTree.cs index 18fa5bd0..665aa055 100644 --- a/DataStructures/AVLTree/AVLTree.cs +++ b/DataStructures/AVLTree/AVLTree.cs @@ -12,9 +12,9 @@ namespace DataStructures.AVLTree /// balancing BST invented. The primary property of an AVL tree is that /// the height of both child subtrees for any node only differ by one. /// Due to the balanced nature of the tree, its time complexities for - /// insertion, deletion, and search all have a worst-case time complexity - /// of O(log n). Which is an improvement over the worst-case O(n) for a - /// regular BST. + /// insertion, deletion, and search all have a worst-case time + /// complexity of O(log n). Which is an improvement over the worst-case + /// O(n) for a regular BST. /// See https://en.wikipedia.org/wiki/AVL_tree for more information. /// Visualizer: https://visualgo.net/en/bst. /// @@ -37,7 +37,8 @@ public class AvlTree private AvlTreeNode? root; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the + /// class. /// public AvlTree() { @@ -45,10 +46,12 @@ public AvlTree() } /// - /// Initializes a new instance of the class - /// using the specified comparer. + /// Initializes a new instance of the + /// class using the specified comparer. /// - /// Comparer to use when comparing keys. + /// + /// Comparer to use when comparing keys. + /// public AvlTree(Comparer customComparer) { comparer = customComparer; @@ -78,7 +81,7 @@ public void Add(TKey key) /// Key values to add. public void AddRange(IEnumerable keys) { - foreach(var key in keys) + foreach (var key in keys) { Add(key); } @@ -90,19 +93,8 @@ public void AddRange(IEnumerable keys) /// Key value to remove. public void Remove(TKey key) { - if (root is null) - { - throw new InvalidOperationException("Tree is empty!"); - } - else if (!Contains(key)) - { - throw new KeyNotFoundException($"Key {key} is not in the tree"); - } - else - { - root = Remove(root, key); - Count--; - } + root = Remove(root, key); + Count--; } /// @@ -139,9 +131,9 @@ public bool Contains(TKey key) /// Minimum value in tree. public TKey GetMin() { - if(root is null) + if (root is null) { - throw new InvalidOperationException("Tree is empty!"); + throw new InvalidOperationException("AVL tree is empty."); } return GetMin(root).Key; @@ -153,16 +145,17 @@ public TKey GetMin() /// Maximum value in tree. public TKey GetMax() { - if(root is null) + if (root is null) { - throw new InvalidOperationException("Tree is empty!"); + throw new InvalidOperationException("AVL tree is empty."); } return GetMax(root).Key; } /// - /// Get keys in order from smallest to largest as defined by the comparer. + /// Get keys in order from smallest to largest as defined by the + /// comparer. /// /// Keys in tree in order from smallest to largest. public IEnumerable GetKeysInOrder() @@ -230,104 +223,13 @@ void PostOrderWalk(AvlTreeNode? node) } } - /// - /// Recursively function to add a node to the tree. - /// - /// Node to check for null leaf. - /// Key value to add. - /// New node with key inserted. - private AvlTreeNode Add(AvlTreeNode node, TKey key) - { - // Regular binary search tree insertion - int compareResult = comparer.Compare(key, node.Key); - if (compareResult < 0) - { - if (node.Left is null) - { - var newNode = new AvlTreeNode(key); - node.Left = newNode; - } - else - { - node.Left = Add(node.Left, key); - } - } - else if (compareResult > 0) - { - if (node.Right is null) - { - var newNode = new AvlTreeNode(key); - node.Right = newNode; - } - else - { - node.Right = Add(node.Right, key); - } - } - else - { - throw new ArgumentException($"Key \"{key}\" already exists in tree!"); - } - - // Check all of the new node's ancestors for inbalance and perform - // necessary rotations - node.UpdateBalanceFactor(); - - return Rebalance(node); - } - - /// - /// Recursive function to remove node from tree. - /// - /// Node to check for key. - /// Key value to remove. - /// New node with key removed. - private AvlTreeNode? Remove(AvlTreeNode node, TKey key) - { - // Normal binary search tree removal - var compareResult = comparer.Compare(key, node.Key); - if (compareResult < 0) - { - node.Left = Remove(node.Left!, key); - } - else if (compareResult > 0) - { - node.Right = Remove(node.Right!, key); - } - else - { - if (node.Left is null && node.Right is null) - { - return null; - } - else if (node.Left is null) - { - var successor = GetMin(node.Right!); - node.Right = Remove(node.Right!, successor.Key); - node.Key = successor.Key; - } - else - { - var predecessor = GetMax(node.Left!); - node.Left = Remove(node.Left!, predecessor.Key); - node.Key = predecessor.Key; - } - } - - // Check all of the removed node's ancestors for rebalance and - // perform necessary rotations. - node.UpdateBalanceFactor(); - - return Rebalance(node); - } - /// /// Helper function to rebalance the tree so that all nodes have a /// balance factor in the range [-1, 1]. /// /// Node to rebalance. /// New node that has been rebalanced. - private AvlTreeNode Rebalance(AvlTreeNode node) + private static AvlTreeNode Rebalance(AvlTreeNode node) { if (node.BalanceFactor > 1) { @@ -338,7 +240,8 @@ private AvlTreeNode Rebalance(AvlTreeNode node) return RotateLeft(node); } - else if (node.BalanceFactor < -1) + + if (node.BalanceFactor < -1) { if (node.Left!.BalanceFactor == 1) { @@ -347,10 +250,8 @@ private AvlTreeNode Rebalance(AvlTreeNode node) return RotateRight(node); } - else - { - return node; - } + + return node; } /// @@ -358,10 +259,10 @@ private AvlTreeNode Rebalance(AvlTreeNode node) /// /// Node to rotate about. /// New node with rotation applied. - private AvlTreeNode RotateLeft(AvlTreeNode node) + private static AvlTreeNode RotateLeft(AvlTreeNode node) { var temp1 = node; - var temp2 = node!.Right!.Left; + var temp2 = node.Right!.Left; node = node.Right; node.Left = temp1; node.Left.Right = temp2; @@ -377,10 +278,10 @@ private AvlTreeNode RotateLeft(AvlTreeNode node) /// /// Node to rotate about. /// New node with rotation applied. - private AvlTreeNode RotateRight(AvlTreeNode node) + private static AvlTreeNode RotateRight(AvlTreeNode node) { var temp1 = node; - var temp2 = node!.Left!.Right; + var temp2 = node.Left!.Right; node = node.Left; node.Right = temp1; node.Right.Left = temp2; @@ -397,7 +298,7 @@ private AvlTreeNode RotateRight(AvlTreeNode node) /// /// Node specifying root of subtree. /// Minimum value in node's subtree. - private AvlTreeNode GetMin(AvlTreeNode node) + private static AvlTreeNode GetMin(AvlTreeNode node) { while (node.Left is not null) { @@ -411,9 +312,9 @@ private AvlTreeNode GetMin(AvlTreeNode node) /// Helper function to get node instance with maximum key value /// in the specified subtree. /// - /// Node specifyng root of subtree. + /// Node specifying root of subtree. /// Maximum value in node's subtree. - private AvlTreeNode GetMax(AvlTreeNode node) + private static AvlTreeNode GetMax(AvlTreeNode node) { while (node.Right is not null) { @@ -422,5 +323,104 @@ private AvlTreeNode GetMax(AvlTreeNode node) return node; } + + /// + /// Recursively function to add a node to the tree. + /// + /// Node to check for null leaf. + /// Key value to add. + /// New node with key inserted. + private AvlTreeNode Add(AvlTreeNode node, TKey key) + { + // Regular binary search tree insertion + var compareResult = comparer.Compare(key, node.Key); + if (compareResult < 0) + { + if (node.Left is null) + { + var newNode = new AvlTreeNode(key); + node.Left = newNode; + } + else + { + node.Left = Add(node.Left, key); + } + } + else if (compareResult > 0) + { + if (node.Right is null) + { + var newNode = new AvlTreeNode(key); + node.Right = newNode; + } + else + { + node.Right = Add(node.Right, key); + } + } + else + { + throw new ArgumentException( + $"Key \"{key}\" already exists in AVL tree."); + } + + // Check all of the new node's ancestors for inbalance and perform + // necessary rotations + node.UpdateBalanceFactor(); + + return Rebalance(node); + } + + /// + /// Recursive function to remove node from tree. + /// + /// Node to check for key. + /// Key value to remove. + /// New node with key removed. + private AvlTreeNode? Remove(AvlTreeNode? node, TKey key) + { + if (node == null) + { + throw new KeyNotFoundException( + $"Key \"{key}\" is not in the AVL tree."); + } + + // Normal binary search tree removal + var compareResult = comparer.Compare(key, node.Key); + if (compareResult < 0) + { + node.Left = Remove(node.Left, key); + } + else if (compareResult > 0) + { + node.Right = Remove(node.Right, key); + } + else + { + if (node.Left is null && node.Right is null) + { + return null; + } + + if (node.Left is null) + { + var successor = GetMin(node.Right!); + node.Right = Remove(node.Right!, successor.Key); + node.Key = successor.Key; + } + else + { + var predecessor = GetMax(node.Left!); + node.Left = Remove(node.Left!, predecessor.Key); + node.Key = predecessor.Key; + } + } + + // Check all of the removed node's ancestors for rebalance and + // perform necessary rotations. + node.UpdateBalanceFactor(); + + return Rebalance(node); + } } } diff --git a/DataStructures/AVLTree/AVLTreeNode.cs b/DataStructures/AVLTree/AVLTreeNode.cs index 0857987d..49050f83 100644 --- a/DataStructures/AVLTree/AVLTreeNode.cs +++ b/DataStructures/AVLTree/AVLTreeNode.cs @@ -3,21 +3,17 @@ namespace DataStructures.AVLTree { /// - /// Generic class to represent nodes in an instance. + /// Generic class to represent nodes in an + /// instance. /// /// The type of key for the node. - public class AvlTreeNode + internal class AvlTreeNode { /// /// Gets or sets key value of node. /// public TKey Key { get; set; } - /// - /// Gets the height of the node. - /// - public int Height { get; private set; } - /// /// Gets the balance factor of the node. /// @@ -34,7 +30,13 @@ public class AvlTreeNode public AvlTreeNode? Right { get; set; } /// - /// Initializes a new instance of the class. + /// Gets or sets the height of the node. + /// + private int Height { get; set; } + + /// + /// Initializes a new instance of the + /// class. /// /// Key value for node. public AvlTreeNode(TKey key) @@ -47,17 +49,17 @@ public AvlTreeNode(TKey key) /// public void UpdateBalanceFactor() { - if(Left is null && Right is null) + if (Left is null && Right is null) { Height = 0; BalanceFactor = 0; } - else if(Left is null) + else if (Left is null) { Height = Right!.Height + 1; BalanceFactor = Height; } - else if(Right is null) + else if (Right is null) { Height = Left!.Height + 1; BalanceFactor = -Height; From bcf01ce40a54c31ea3a213b7455ec2e09071dca1 Mon Sep 17 00:00:00 2001 From: Wrrikk <86593125+Wrrikk@users.noreply.github.com> Date: Sun, 9 Oct 2022 16:38:40 +0530 Subject: [PATCH 033/138] Add BoyerMoore algorithm (#347) --- Algorithms.Tests/Search/BoyerMooreTests.cs | 36 ++++++++++++++ Algorithms/Search/BoyerMoore.cs | 58 ++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 Algorithms.Tests/Search/BoyerMooreTests.cs create mode 100644 Algorithms/Search/BoyerMoore.cs diff --git a/Algorithms.Tests/Search/BoyerMooreTests.cs b/Algorithms.Tests/Search/BoyerMooreTests.cs new file mode 100644 index 00000000..6e206c23 --- /dev/null +++ b/Algorithms.Tests/Search/BoyerMooreTests.cs @@ -0,0 +1,36 @@ +using Algorithms.Search; +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using NUnit.Framework.Internal; + +namespace Algorithms.Tests.Search +{ + public class BoyerMoore_Tests + { + [Test] + public void BoyerMoore_Majority_Finder_Test() + { + var elementCount = 1000; + + var rnd = new Random(); + var randomNumbers = new List(); + + while (randomNumbers.Count < elementCount / 2) + { + randomNumbers.Add(rnd.Next(0, elementCount)); + } + + var majorityElement = rnd.Next(0, elementCount); + + randomNumbers.AddRange(Enumerable.Repeat(majorityElement, elementCount / 2 + 1)); + randomNumbers = randomNumbers.OrderBy(x => rnd.Next()).ToList(); + + var expected = majorityElement; + var actual = BoyerMoore.FindMajority(randomNumbers); + + Assert.AreEqual(actual, expected); + } + } +} diff --git a/Algorithms/Search/BoyerMoore.cs b/Algorithms/Search/BoyerMoore.cs new file mode 100644 index 00000000..cb86d0ad --- /dev/null +++ b/Algorithms/Search/BoyerMoore.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Algorithms.Search +{ + /// + /// A Boyer-Moore majority finder algorithm implementation. + /// + /// Type of element stored inside array. + public static class BoyerMoore where T : IComparable + { + public static T? FindMajority(IEnumerable input) + { + var candidate = FindMajorityCandidate(input, input.Count()); + + if (VerifyMajority(input, input.Count(), candidate)) + { + return candidate; + } + + return default(T?); + } + + // Find majority candidate + private static T FindMajorityCandidate(IEnumerable input, int length) + { + int count = 1; + T candidate = input.First(); + + foreach (var element in input.Skip(1)) + { + if (candidate.Equals(element)) + { + count++; + } + else + { + count--; + } + + if (count == 0) + { + candidate = element; + count = 1; + } + } + + return candidate; + } + + // Verify that candidate is indeed the majority + private static bool VerifyMajority(IEnumerable input, int size, T candidate) + { + return input.Count(x => x.Equals(candidate)) > size / 2; + } + } +} From b8a1cfd96f51aebdd0e66ad6c5f56ac0da018fcf Mon Sep 17 00:00:00 2001 From: Kalkwst Date: Mon, 10 Oct 2022 20:10:45 +0300 Subject: [PATCH 034/138] Add Automorphic Number Calculator (#344) --- .../Numeric/AutomorphicNumberTests.cs | 114 ++++++++++++++++++ Algorithms/Numeric/AutomorphicNumber.cs | 74 ++++++++++++ README.md | 1 + 3 files changed, 189 insertions(+) create mode 100644 Algorithms.Tests/Numeric/AutomorphicNumberTests.cs create mode 100644 Algorithms/Numeric/AutomorphicNumber.cs diff --git a/Algorithms.Tests/Numeric/AutomorphicNumberTests.cs b/Algorithms.Tests/Numeric/AutomorphicNumberTests.cs new file mode 100644 index 00000000..e07274a2 --- /dev/null +++ b/Algorithms.Tests/Numeric/AutomorphicNumberTests.cs @@ -0,0 +1,114 @@ +using Algorithms.Numeric; +using NUnit.Framework; +using System; +using System.Collections.Generic; + +namespace Algorithms.Tests.Numeric +{ + public class AutomorphicNumberTests + { + [TestCase(1)] + [TestCase(5)] + [TestCase(6)] + [TestCase(25)] + [TestCase(76)] + [TestCase(376)] + [TestCase(625)] + [TestCase(9376)] + [TestCase(90625)] + [TestCase(109376)] + + public void TestAutomorphicNumbers(int number) + { + Assert.That(AutomorphicNumber.IsAutomorphic(number), Is.True); + } + + [TestCase(2)] + [TestCase(3)] + [TestCase(7)] + [TestCase(18)] + [TestCase(79)] + [TestCase(356)] + [TestCase(623)] + [TestCase(9876)] + [TestCase(90635)] + [TestCase(119376)] + [TestCase(891625)] + [TestCase(2990625)] + [TestCase(7209376)] + [TestCase(12891625)] + [TestCase(87129396)] + public void TestNonAutomorphicNumbers(int number) + { + Assert.That(AutomorphicNumber.IsAutomorphic(number), Is.False); + } + + [TestCase(0)] + [TestCase(-1)] + public void TestInvalidAutomorphicNumbers(int number) + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo($"An automorphic number must always be positive."), + delegate + { + AutomorphicNumber.IsAutomorphic(number); + }); + } + + [TestCase(1, 100)] + public void TestAutomorphicNumberSequence(int lower, int upper) + { + List automorphicList = new() { 1, 5, 6, 25, 76 }; + Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList)); + } + + [TestCase(8, 12)] + public void TestNoAutomorphicNumberInTheSequence(int lower, int upper) + { + List automorphicList = new(); + Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList)); + } + + [TestCase(25,25)] + public void TestAutomorphicNumberSequenceSameBounds(int lower, int upper) + { + List automorphicList = new() { 25 }; + Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList)); + } + + [TestCase(-1,1)] + [TestCase(0, 1)] + public void TestAutomorphicNumberSequenceInvalidLowerBound(int lower, int upper) + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo($"Lower bound must be greater than 0."), + delegate + { + AutomorphicNumber.GetAutomorphicNumbers(lower, upper); + }); + } + + [TestCase(1, -1)] + [TestCase(10, -1)] + public void TestAutomorphicNumberSequenceInvalidUpperBound(int lower, int upper) + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo($"Upper bound must be greater than 0."), + delegate + { + AutomorphicNumber.GetAutomorphicNumbers(lower, upper); + }); + } + + [TestCase(25, 2)] + public void TestAutomorphicNumberSequenceReversedBounds(int lower, int upper) + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo($"The lower bound must be less than or equal to the upper bound."), + delegate + { + AutomorphicNumber.GetAutomorphicNumbers(lower, upper); + }); + } + } +} diff --git a/Algorithms/Numeric/AutomorphicNumber.cs b/Algorithms/Numeric/AutomorphicNumber.cs new file mode 100644 index 00000000..c3bd9991 --- /dev/null +++ b/Algorithms/Numeric/AutomorphicNumber.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +namespace Algorithms.Numeric +{ + /// + /// Calculates Automorphic numbers. A number is said to be an Automorphic number + /// if the square of the number will contain the number itself at the end. + /// + public static class AutomorphicNumber + { + /// + /// Generates a list of automorphic numbers that are between and + /// inclusive. + /// + /// The lower bound of the list. + /// The upper bound of the list. + /// A list that contains all of the automorphic numbers between and inclusive. + /// If the + /// or is not greater than zero + /// or is lower than the . + public static IEnumerable GetAutomorphicNumbers(int lowerBound, int upperBound) + { + if (lowerBound < 1) + { + throw new ArgumentException($"Lower bound must be greater than 0."); + } + + if (upperBound < 1) + { + throw new ArgumentException($"Upper bound must be greater than 0."); + } + + if (lowerBound > upperBound) + { + throw new ArgumentException($"The lower bound must be less than or equal to the upper bound."); + } + + return Enumerable.Range(lowerBound, upperBound).Where(IsAutomorphic); + } + + /// + /// Checks if a given natural number is automorphic or not. + /// + /// The number to check. + /// True if the number is automorphic, false otherwise. + /// If the number is non-positive. + public static bool IsAutomorphic(int number) + { + if (number < 1) + { + throw new ArgumentException($"An automorphic number must always be positive."); + } + + BigInteger square = BigInteger.Pow(number, 2); + + // Extract the last digits of both numbers + while (number > 0) + { + if (number % 10 != square % 10) + { + return false; + } + + number /= 10; + square /= 10; + } + + return true; + } + } +} diff --git a/README.md b/README.md index ee90505b..c7605091 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ find more than one implementation for the same objective but using different alg * [Euler Method](./Algorithms/Numeric/EulerMethod.cs) * [Miller-Rabin primality check](./Algorithms/Numeric/MillerRabinPrimalityChecker.cs) * [KrishnamurthyNumberChecker](./Algorithms/Numeric/KrishnamurthyNumberChecker.cs) + * [Automorphic Number](./Algorithms/Numeric/AutomorphicNumber.cs) * [Searches](./Algorithms/Search) * [A-Star](./Algorithms/Search/AStar/) * [Binary Search](./Algorithms/Search/BinarySearcher.cs) From 96a34df42cbe69e3cc3f56c9aeb7726084ab52e4 Mon Sep 17 00:00:00 2001 From: VincentDawn Date: Mon, 10 Oct 2022 18:19:35 +0100 Subject: [PATCH 035/138] Add A000012 Sequence (#350) --- .../Sequences/AllOnesSequenceTests.cs | 18 ++++++++++++ Algorithms/Sequences/AllOnesSequence.cs | 29 +++++++++++++++++++ README.md | 1 + 3 files changed, 48 insertions(+) create mode 100644 Algorithms.Tests/Sequences/AllOnesSequenceTests.cs create mode 100644 Algorithms/Sequences/AllOnesSequence.cs diff --git a/Algorithms.Tests/Sequences/AllOnesSequenceTests.cs b/Algorithms.Tests/Sequences/AllOnesSequenceTests.cs new file mode 100644 index 00000000..710520dd --- /dev/null +++ b/Algorithms.Tests/Sequences/AllOnesSequenceTests.cs @@ -0,0 +1,18 @@ +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; +using System; +using System.Linq; +using System.Numerics; + +namespace Algorithms.Tests.Sequences; +public class AllOnesSequenceTests +{ + [Test] + public void First10ElementsCorrect() + { + var sequence = new AllOnesSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }) + .Should().BeTrue(); + } +} diff --git a/Algorithms/Sequences/AllOnesSequence.cs b/Algorithms/Sequences/AllOnesSequence.cs new file mode 100644 index 00000000..86645e65 --- /dev/null +++ b/Algorithms/Sequences/AllOnesSequence.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Algorithms.Sequences; + +/// +/// +/// The all ones sequence. +/// +/// +/// OEIS: https://oeis.org/A000012. +/// +/// +public class AllOnesSequence : ISequence +{ + /// + /// Gets all ones sequence. + /// + public IEnumerable Sequence + { + get + { + while (true) + { + yield return 1; + } + } + } +} diff --git a/README.md b/README.md index c7605091..6476924a 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ find more than one implementation for the same objective but using different alg * [A000005 Count of Divisors](./Algorithms/Sequences/DivisorsCountSequence.cs) * [A000008 Make Change](./Algorithms/Sequences/MakeChangeSequence.cs) * [A000010 Euler's Totient](./Algorithms/Sequences/EulerTotientSequence.cs) + * [A000012 All Ones](./Algorithms/Sequences/AllOnesSequence.cs) * [A000027 Natural](./Algorithms/Sequences/NaturalSequence.cs) * [A000032 Lucas Numbers](./Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs) * [A000040 Primes](./Algorithms/Sequences/PrimesSequence.cs) From a8366120fa4b5ec6393c6c37319f654c5f8d6c0c Mon Sep 17 00:00:00 2001 From: Valdas Date: Tue, 11 Oct 2022 11:17:37 +0300 Subject: [PATCH 036/138] Add Jaro-Winkler distance (#349) Co-authored-by: Valdas --- .../Strings/JaroWinklerDistanceTests.cs | 20 +++++++++++ Algorithms/Strings/JaroWinklerDistance.cs | 34 +++++++++++++++++++ README.md | 1 + 3 files changed, 55 insertions(+) create mode 100644 Algorithms.Tests/Strings/JaroWinklerDistanceTests.cs create mode 100644 Algorithms/Strings/JaroWinklerDistance.cs diff --git a/Algorithms.Tests/Strings/JaroWinklerDistanceTests.cs b/Algorithms.Tests/Strings/JaroWinklerDistanceTests.cs new file mode 100644 index 00000000..7f908c96 --- /dev/null +++ b/Algorithms.Tests/Strings/JaroWinklerDistanceTests.cs @@ -0,0 +1,20 @@ +using Algorithms.Strings; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Strings +{ + public class JaroWinklerDistanceTests + { + [Test] + [TestCase("equal", "equal", 0)] + [TestCase("abc", "123", 1)] + [TestCase("Winkler", "Welfare", 0.33)] + [TestCase("faremviel", "farmville", 0.08)] + [TestCase("", "", 0)] + public void Calculate_ReturnsCorrectJaroWinklerDistance(string s1, string s2, double expected) + { + JaroWinklerDistance.Calculate(s1, s2).Should().BeApproximately(expected, 0.01); + } + } +} diff --git a/Algorithms/Strings/JaroWinklerDistance.cs b/Algorithms/Strings/JaroWinklerDistance.cs new file mode 100644 index 00000000..cb2c5492 --- /dev/null +++ b/Algorithms/Strings/JaroWinklerDistance.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; + +namespace Algorithms.Strings +{ + /// + /// + /// Jaro–Winkler distance is a string metric measuring an edit distance between two sequences. + /// The score is normalized such that 1 means an exact match and 0 means there is no similarity. + /// Time complexity is O(a*b) where a is the length of the first string and b is the length of the second string. + /// + /// + /// Wikipedia: https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance. + /// + /// + public static class JaroWinklerDistance + { + /// + /// Calculates Jaro–Winkler distance. + /// + /// First string. + /// Second string. + /// Scaling factor for how much the score is adjusted upwards for having common prefixes. Default is 0.1. + /// Distance between two strings. + public static double Calculate(string s1, string s2, double scalingFactor = 0.1) + { + var jaroSimilarity = JaroSimilarity.Calculate(s1, s2); + var commonPrefixLength = s1.Zip(s2).Take(4).TakeWhile(x => x.First == x.Second).Count(); + var jaroWinklerSimilarity = jaroSimilarity + commonPrefixLength * scalingFactor * (1 - jaroSimilarity); + + return 1 - jaroWinklerSimilarity; + } + } +} diff --git a/README.md b/README.md index 6476924a..92d46987 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ find more than one implementation for the same objective but using different alg * [Levenshtein Distance](./Algorithms/Strings/LevenshteinDistance.cs) * [Hamming Distance](./Algorithms/Strings/HammingDistance.cs) * [Jaro Similarity](./Algorithms/Strings/JaroSimilarity.cs) + * [Jaro-Winkler Distance](./Algorithms/Strings/JaroWinklerDistance.cs) * [Other](./Algorithms/Other) * [Fermat Prime Checker](./Algorithms/Other/FermatPrimeChecker.cs) * [Sieve of Eratosthenes](./Algorithms/Other/SieveOfEratosthenes.cs) From b24963c2e3a4f470528661101339db493e2f05a2 Mon Sep 17 00:00:00 2001 From: VincentDawn Date: Wed, 12 Oct 2022 19:42:59 +0100 Subject: [PATCH 037/138] Add all twos sequence (#351) --- .../Sequences/AllTwosSequenceTests.cs | 18 +++++++++++++ Algorithms/Sequences/AllTwosSequence.cs | 26 +++++++++++++++++++ README.md | 1 + 3 files changed, 45 insertions(+) create mode 100644 Algorithms.Tests/Sequences/AllTwosSequenceTests.cs create mode 100644 Algorithms/Sequences/AllTwosSequence.cs diff --git a/Algorithms.Tests/Sequences/AllTwosSequenceTests.cs b/Algorithms.Tests/Sequences/AllTwosSequenceTests.cs new file mode 100644 index 00000000..3286e87d --- /dev/null +++ b/Algorithms.Tests/Sequences/AllTwosSequenceTests.cs @@ -0,0 +1,18 @@ +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; +using System; +using System.Linq; +using System.Numerics; + +namespace Algorithms.Tests.Sequences; +public class AllTwosSequenceTests +{ + [Test] + public void First10ElementsCorrect() + { + var sequence = new AllTwosSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }) + .Should().BeTrue(); + } +} diff --git a/Algorithms/Sequences/AllTwosSequence.cs b/Algorithms/Sequences/AllTwosSequence.cs new file mode 100644 index 00000000..2213c4a4 --- /dev/null +++ b/Algorithms/Sequences/AllTwosSequence.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Algorithms.Sequences; + +/// +/// +/// The all twos sequence. +/// +/// +/// OEIS: https://oeis.org/A007395. +/// +/// +public class AllTwosSequence : ISequence +{ + public IEnumerable Sequence + { + get + { + while (true) + { + yield return 2; + } + } + } +} diff --git a/README.md b/README.md index 92d46987..970ecc10 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,7 @@ find more than one implementation for the same objective but using different alg * [A006879 Number of Primes by Number of Digits](./Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs) * [A006880 Number of Primes by Powers of 10](./Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs) * [A007318 Binomial](./Algorithms/Sequences/BinomialSequence.cs) + * [A007395 All Twos](./Algorithms/Sequences/AllTwosSequence.cs) * [A010051 Binary Prime Constant](./Algorithms/Sequences/BinaryPrimeConstantSequence.cs) * [A011557 Powers of 10](./Algorithms/Sequences/PowersOf10Sequence.cs) * [A057588 Kummer Numbers](./Algorithms/Sequences/KummerNumbersSequence.cs) From 0c516ee9f4b0c98454ae01265a0743fb36017dc6 Mon Sep 17 00:00:00 2001 From: VincentDawn Date: Wed, 12 Oct 2022 19:53:42 +0100 Subject: [PATCH 038/138] Add all threes sequence (#352) --- .../Sequences/AllThreesSequenceTests.cs | 18 +++++++++++++ Algorithms/Sequences/AllThreesSequence.cs | 26 +++++++++++++++++++ README.md | 1 + 3 files changed, 45 insertions(+) create mode 100644 Algorithms.Tests/Sequences/AllThreesSequenceTests.cs create mode 100644 Algorithms/Sequences/AllThreesSequence.cs diff --git a/Algorithms.Tests/Sequences/AllThreesSequenceTests.cs b/Algorithms.Tests/Sequences/AllThreesSequenceTests.cs new file mode 100644 index 00000000..41efbe36 --- /dev/null +++ b/Algorithms.Tests/Sequences/AllThreesSequenceTests.cs @@ -0,0 +1,18 @@ +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; +using System; +using System.Linq; +using System.Numerics; + +namespace Algorithms.Tests.Sequences; +public class AllThreesSequenceTests +{ + [Test] + public void First10ElementsCorrect() + { + var sequence = new AllThreesSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }) + .Should().BeTrue(); + } +} diff --git a/Algorithms/Sequences/AllThreesSequence.cs b/Algorithms/Sequences/AllThreesSequence.cs new file mode 100644 index 00000000..956c0f0a --- /dev/null +++ b/Algorithms/Sequences/AllThreesSequence.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Algorithms.Sequences; + +/// +/// +/// The all threes sequence. +/// +/// +/// OEIS: https://oeis.org/A010701. +/// +/// +public class AllThreesSequence : ISequence +{ + public IEnumerable Sequence + { + get + { + while (true) + { + yield return 3; + } + } + } +} diff --git a/README.md b/README.md index 970ecc10..2021cb71 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,7 @@ find more than one implementation for the same objective but using different alg * [A007318 Binomial](./Algorithms/Sequences/BinomialSequence.cs) * [A007395 All Twos](./Algorithms/Sequences/AllTwosSequence.cs) * [A010051 Binary Prime Constant](./Algorithms/Sequences/BinaryPrimeConstantSequence.cs) + * [A010701 All Threes](./Algorithms/Sequences/BinaryPrimeConstantSequence.cs) * [A011557 Powers of 10](./Algorithms/Sequences/PowersOf10Sequence.cs) * [A057588 Kummer Numbers](./Algorithms/Sequences/KummerNumbersSequence.cs) * [A019434 Fermat Primes](./Algorithms/Sequences/FermatPrimesSequence.cs) From 43e1cafdf37f9419b6916a02625582139441341f Mon Sep 17 00:00:00 2001 From: Richard Vasquez <1706965+RichardVasquez@users.noreply.github.com> Date: Sat, 15 Oct 2022 22:34:01 -0700 Subject: [PATCH 039/138] Add Sequence A002717 (#354) --- .../MatchstickTriangleSequenceTests.cs | 28 ++++++++ .../Sequences/MatchstickTriangleSequence.cs | 71 +++++++++++++++++++ README.md | 1 + 3 files changed, 100 insertions(+) create mode 100644 Algorithms.Tests/Sequences/MatchstickTriangleSequenceTests.cs create mode 100644 Algorithms/Sequences/MatchstickTriangleSequence.cs diff --git a/Algorithms.Tests/Sequences/MatchstickTriangleSequenceTests.cs b/Algorithms.Tests/Sequences/MatchstickTriangleSequenceTests.cs new file mode 100644 index 00000000..bf838dff --- /dev/null +++ b/Algorithms.Tests/Sequences/MatchstickTriangleSequenceTests.cs @@ -0,0 +1,28 @@ +using System.Linq; +using System.Numerics; +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Sequences; + +[TestFixture] +public static class MatchstickTriangleSequenceTests +{ + private static BigInteger[] TestList = { + 0, 1, 5, 13, 27, 48, 78, 118, 170, 235, 315, 411, 525, 658, + 812, 988, 1188, 1413, 1665, 1945, 2255, 2596, 2970, 3378, + 3822, 4303, 4823, 5383, 5985, 6630, 7320, 8056, 8840, 9673, + 10557, 11493, 12483, 13528, 14630, 15790, 17010, 18291, + 19635, 21043, 22517, + }; + /// + /// This test uses the list values provided from http://oeis.org/A002717/list. + /// + [Test] + public static void TestOeisList() + { + var sequence = new MatchstickTriangleSequence().Sequence.Take(TestList.Length); + sequence.SequenceEqual(TestList).Should().BeTrue(); + } +} diff --git a/Algorithms/Sequences/MatchstickTriangleSequence.cs b/Algorithms/Sequences/MatchstickTriangleSequence.cs new file mode 100644 index 00000000..9033cab1 --- /dev/null +++ b/Algorithms/Sequences/MatchstickTriangleSequence.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of number of triangles in triangular matchstick arrangement of side n for n>=0. +/// +/// +/// M. E. Larsen, The eternal triangle – a history of a counting problem, College Math. J., 20 (1989), 370-392. +/// https://web.math.ku.dk/~mel/mel.pdf. +/// +/// +/// OEIS: http://oeis.org/A002717. +/// +/// +public class MatchstickTriangleSequence : ISequence +{ + /// + /// + /// Gets number of triangles contained in an triangular arrangement of matchsticks of side length n. + /// + /// + /// This also counts the subset of smaller triangles contained within the arrangement. + /// + /// + /// Based on the PDF referenced above, the sequence is derived from step 8, using the resulting equation + /// of f(n) = (n(n+2)(2n+1) -(delta)(n)) / 8. Using BigInteger values, we can effectively remove + /// (delta)(n) from the previous by using integer division instead. + /// + /// + /// Examples follow. + ///
+    ///   .
+    ///  / \   This contains 1 triangle of size 1.
+    /// .---.
+    ///
+    ///     .
+    ///    / \     This contains 4 triangles of size 1.
+    ///   .---.    This contains 1 triangle of size 2.
+    ///  / \ / \   This contains 5 triangles total.
+    /// .---.---.
+    ///
+    ///       .
+    ///      / \      This contains 9 triangles of size 1.
+    ///     .---.     This contains 3 triangles of size 2.
+    ///    / \ / \    This contains 1 triangles of size 3.
+    ///   .---.---.
+    ///  / \ / \ / \  This contains 13 triangles total.
+    /// .---.---.---.
+    /// 
+ ///
+ ///
+ public IEnumerable Sequence + { + get + { + var index = BigInteger.Zero; + var eight = new BigInteger(8); + while (true) + { + var temp = index * (index + 2) * (index * 2 + 1); + var result = BigInteger.Divide(temp, eight); + yield return result; + index++; + } + } + } +} diff --git a/README.md b/README.md index 2021cb71..64dc09d5 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ find more than one implementation for the same objective but using different alg * [A001462 Golomb's](./Algorithms/Sequences/GolombsSequence.cs) * [A001478 Negative Integers](./Algorithms/Sequences/NegativeIntegersSequence.cs) * [A002110 Primorial Numbers](./Algorithms/Sequences/PrimorialNumbersSequence.cs) + * [A002717 Matchstick Triangle Arrangement](./Algorithms/Sequences/MatchstickTriangleSequence.cs) * [A005132 Recaman's](./Algorithms/Sequences/RecamansSequence.cs) * [A006577 Number of '3n+1' steps to reach 1](./Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs) * [A006862 Euclid Numbers](./Algorithms/Sequences/EuclidNumbersSequence.cs) From 35a304b0ba2b990342d070ec17f9f4738f40fc36 Mon Sep 17 00:00:00 2001 From: Richard Vasquez <1706965+RichardVasquez@users.noreply.github.com> Date: Sat, 15 Oct 2022 22:41:17 -0700 Subject: [PATCH 040/138] Add Sequence A000292 (#355) --- .../Sequences/TetrahedralSequenceTests.cs | 30 +++++++++++++ Algorithms/Sequences/TetrahedralSequence.cs | 42 +++++++++++++++++++ README.md | 1 + 3 files changed, 73 insertions(+) create mode 100644 Algorithms.Tests/Sequences/TetrahedralSequenceTests.cs create mode 100644 Algorithms/Sequences/TetrahedralSequence.cs diff --git a/Algorithms.Tests/Sequences/TetrahedralSequenceTests.cs b/Algorithms.Tests/Sequences/TetrahedralSequenceTests.cs new file mode 100644 index 00000000..82ceb63e --- /dev/null +++ b/Algorithms.Tests/Sequences/TetrahedralSequenceTests.cs @@ -0,0 +1,30 @@ +using System.Linq; +using System.Numerics; +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Sequences; + +[TestFixture] +public class TetrahedralSequenceTests +{ + private static readonly BigInteger[] TestList = { + 0, 1, 4, 10, 20, 35, 56, 84, 120, 165, 220, 286, 364, 455, + 560, 680, 816, 969, 1140, 1330, 1540, 1771, 2024, 2300, + 2600, 2925, 3276, 3654, 4060, 4495, 4960, 5456, 5984, 6545, + 7140, 7770, 8436, 9139, 9880, 10660, 11480, 12341, 13244, + 14190, 15180, + }; + + /// + /// This test uses the list values provided from http://oeis.org/A000292/list. + /// + [Test] + public void TestOeisList() + { + var sequence = new TetrahedralSequence().Sequence.Take(TestList.Length); + sequence.SequenceEqual(TestList).Should().BeTrue(); + + } +} diff --git a/Algorithms/Sequences/TetrahedralSequence.cs b/Algorithms/Sequences/TetrahedralSequence.cs new file mode 100644 index 00000000..e0a298d2 --- /dev/null +++ b/Algorithms/Sequences/TetrahedralSequence.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of tetrahedral (triangular pyramids) counts for n >= 0. +/// +/// +/// OEIS: http://oeis.org/A000292. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Tetrahedral_number. +/// +/// +public class TetrahedralSequence : ISequence +{ + /// + /// + /// Gets the value of packing spheres in a regular tetrahedron + /// with increasing by 1 triangular numbers under each layer. + /// + /// + /// It can be reviewed by starting at the 4th row of Pascal's Triangle + /// following the diagonal values going into the triangle. + /// + /// + public IEnumerable Sequence + { + get + { + var index = BigInteger.Zero; + var six = new BigInteger(6); + while (true) + { + yield return BigInteger.Divide(index * (index + 1) * (index + 2), six); + index++; + } + } + } +} diff --git a/README.md b/README.md index 64dc09d5..7748bbe7 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ find more than one implementation for the same objective but using different alg * [A000142 Factorial](./Algorithms/Sequences/FactorialSequence.cs) * [A000215 Fermat Numbers](./Algorithms/Sequences/FermatNumbersSequence.cs) * [A000290 Squares](./Algorithms/Sequences/SquaresSequence.cs) + * [A000292 Tetrahedral numbers](./Algorithms/Sequences/TetrahedralSequence.cs) * [A000578 Cubes](./Algorithms/Sequences/CubesSequence.cs) * [A000720 PrimePi](./Algorithms/Sequences/PrimePiSequence.cs) * [A001146 Number of Boolean Functions](./Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs) From d381c4ec87aa782e958da34cdc8fc29d5dcb8ec9 Mon Sep 17 00:00:00 2001 From: Kalkwst Date: Sun, 16 Oct 2022 10:02:24 +0300 Subject: [PATCH 041/138] Add Newton's Square Root Calculation Method (#357) --- .../Numeric/NewtonSquareRootTests.cs | 44 +++++++++++++++++++ Algorithms/NewtonSquareRoot.cs | 37 ++++++++++++++++ README.md | 1 + 3 files changed, 82 insertions(+) create mode 100644 Algorithms.Tests/Numeric/NewtonSquareRootTests.cs create mode 100644 Algorithms/NewtonSquareRoot.cs diff --git a/Algorithms.Tests/Numeric/NewtonSquareRootTests.cs b/Algorithms.Tests/Numeric/NewtonSquareRootTests.cs new file mode 100644 index 00000000..d101f07d --- /dev/null +++ b/Algorithms.Tests/Numeric/NewtonSquareRootTests.cs @@ -0,0 +1,44 @@ +using System; +using System.Numerics; +using NUnit.Framework; + +namespace Algorithms.Tests.Numeric; + +public class NewtonSquareRootTests +{ + private static readonly object[] CalculateSquareRootInput = + { + new object[] {BigInteger.One, BigInteger.One}, + new object[] {new BigInteger(221295376), new BigInteger(14876)}, + new object[] {new BigInteger(2530995481), new BigInteger(50309)}, + new object[] {new BigInteger(3144293476), new BigInteger(56074)}, + new object[] {new BigInteger(3844992064), new BigInteger(62008)}, + new object[] {new BigInteger(5301150481), new BigInteger(72809)}, + new object[] {new BigInteger(5551442064), new BigInteger(74508)}, + new object[] {new BigInteger(6980435401), new BigInteger(83549)}, + new object[] {new BigInteger(8036226025), new BigInteger(89645)}, + }; + + [TestCaseSource(nameof(CalculateSquareRootInput))] + public void CalculateSquareRootTest(BigInteger number, BigInteger result) + { + Assert.That(NewtonSquareRoot.Calculate(number), Is.EqualTo(result)); + } + + [Test] + public void CalculateSquareRootOfZero() + { + Assert.That(NewtonSquareRoot.Calculate(0), Is.EqualTo(BigInteger.Zero)); + } + + [Test] + public void CalculateSquareRootNegativeNumber() + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo("Cannot calculate the square root of a negative number."), + delegate + { + NewtonSquareRoot.Calculate(BigInteger.MinusOne); + }); + } +} diff --git a/Algorithms/NewtonSquareRoot.cs b/Algorithms/NewtonSquareRoot.cs new file mode 100644 index 00000000..4e8935a8 --- /dev/null +++ b/Algorithms/NewtonSquareRoot.cs @@ -0,0 +1,37 @@ +using System; +using System.Numerics; + +namespace Algorithms; + +public static class NewtonSquareRoot +{ + public static BigInteger Calculate(BigInteger number) + { + if (number < 0) + { + throw new ArgumentException("Cannot calculate the square root of a negative number."); + } + + if (number == 0) + { + return BigInteger.Zero; + } + + var bitLength = Convert.ToInt32(Math.Ceiling(BigInteger.Log(number, 2))); + BigInteger root = BigInteger.One << (bitLength / 2); + + while (!IsSquareRoot(number, root)) + { + root += number / root; + root /= 2; + } + + return root; + } + + private static bool IsSquareRoot(BigInteger number, BigInteger root) + { + var lowerBound = root * root; + return number >= lowerBound && number <= lowerBound + root + root; + } +} diff --git a/README.md b/README.md index 7748bbe7..62258030 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ find more than one implementation for the same objective but using different alg * [Miller-Rabin primality check](./Algorithms/Numeric/MillerRabinPrimalityChecker.cs) * [KrishnamurthyNumberChecker](./Algorithms/Numeric/KrishnamurthyNumberChecker.cs) * [Automorphic Number](./Algorithms/Numeric/AutomorphicNumber.cs) + * [Newton's Square Root Calculation](./Algorithms/NewtonSquareRoot.cs) * [Searches](./Algorithms/Search) * [A-Star](./Algorithms/Search/AStar/) * [Binary Search](./Algorithms/Search/BinarySearcher.cs) From 8d0729bbf04948ea13effc04052522e45bf47fb2 Mon Sep 17 00:00:00 2001 From: Damian Sikora Date: Mon, 17 Oct 2022 16:19:56 +0200 Subject: [PATCH 042/138] Add Welford's Variance (#358) --- .../Other/WelfordsVarianceTest.cs | 163 ++++++++++++++++++ Algorithms/Other/WelfordsVariance.cs | 72 ++++++++ README.md | 1 + 3 files changed, 236 insertions(+) create mode 100644 Algorithms.Tests/Other/WelfordsVarianceTest.cs create mode 100644 Algorithms/Other/WelfordsVariance.cs diff --git a/Algorithms.Tests/Other/WelfordsVarianceTest.cs b/Algorithms.Tests/Other/WelfordsVarianceTest.cs new file mode 100644 index 00000000..502ac40c --- /dev/null +++ b/Algorithms.Tests/Other/WelfordsVarianceTest.cs @@ -0,0 +1,163 @@ +using Algorithms.Other; +using NUnit.Framework; + +namespace Algorithms.Tests.Other +{ + public class WelfordsVarianceTest + { + [Test] + public void WelfordVariance_Example1() + { + var welfordsVariance = new WelfordsVariance(); + welfordsVariance.AddValue(4); + welfordsVariance.AddValue(7); + welfordsVariance.AddValue(13); + welfordsVariance.AddValue(16); + + Assert.AreEqual(4, welfordsVariance.Count); + Assert.AreEqual(10, welfordsVariance.Mean, 0.0000001); + Assert.AreEqual(22.5, welfordsVariance.Variance, 0.0000001); + Assert.AreEqual(30, welfordsVariance.SampleVariance, 0.0000001); + } + + [Test] + public void WelfordVariance_Example2() + { + var stats = new WelfordsVariance(); + stats.AddValue(100000004); + stats.AddValue(100000007); + stats.AddValue(100000013); + stats.AddValue(100000016); + Assert.AreEqual(4, stats.Count); + Assert.AreEqual(100000010, stats.Mean, 0.0000001); + Assert.AreEqual(22.5, stats.Variance, 0.0000001); + Assert.AreEqual(30, stats.SampleVariance, 0.0000001); + } + + [Test] + public void WelfordVariance_Example3() + { + var stats = new WelfordsVariance(); + stats.AddValue(1000000004); + stats.AddValue(1000000007); + stats.AddValue(1000000013); + stats.AddValue(1000000016); + Assert.AreEqual(4, stats.Count); + Assert.AreEqual(1000000010, stats.Mean, 0.0000001); + Assert.AreEqual(22.5, stats.Variance, 0.0000001); + Assert.AreEqual(30, stats.SampleVariance, 0.0000001); + } + + [Test] + public void WelfordVariance_Example4() + { + var stats = new WelfordsVariance(); + stats.AddValue(6); + stats.AddValue(2); + stats.AddValue(3); + stats.AddValue(1); + Assert.AreEqual(4, stats.Count); + Assert.AreEqual(3, stats.Mean, 0.0000001); + Assert.AreEqual(3.5, stats.Variance, 0.0000001); + Assert.AreEqual(4.6666667, stats.SampleVariance, 0.0000001); + } + + [Test] + public void WelfordVariance_Example5() + { + var stats = new WelfordsVariance(new double[] { 2, 2, 5, 7 }); + Assert.AreEqual(4, stats.Count); + Assert.AreEqual(4, stats.Mean, 0.0000001); + Assert.AreEqual(4.5, stats.Variance, 0.0000001); + Assert.AreEqual(6, stats.SampleVariance, 0.0000001); + } + + [Test] + public void WelfordVariance_Example6() + { + var stats = new WelfordsVariance(); + stats.AddRange(new double[] { 2, 4, 4, 4, 5, 5, 7, 9 }); + Assert.AreEqual(8, stats.Count); + Assert.AreEqual(5, stats.Mean, 0.0000001); + Assert.AreEqual(4, stats.Variance, 0.0000001); + Assert.AreEqual(4.5714286, stats.SampleVariance, 0.0000001); + } + + [Test] + public void WelfordVariance_Example7() + { + var stats = new WelfordsVariance(); + stats.AddRange(new double[] { 9, 2, 5, 4, 12, 7, 8, 11, 9, 3, 7, 4, 12, 5, 4, 10, 9, 6, 9, 4 }); + Assert.AreEqual(20, stats.Count); + Assert.AreEqual(7, stats.Mean, 0.0000001); + Assert.AreEqual(8.9, stats.Variance, 0.0000001); + Assert.AreEqual(9.3684211, stats.SampleVariance, 0.0000001); + } + + [Test] + public void WelfordVariance_Example8() + { + var stats = new WelfordsVariance(); + stats.AddRange(new [] { 51.3, 55.6, 49.9, 52.0 }); + Assert.AreEqual(4, stats.Count); + Assert.AreEqual(52.2, stats.Mean, 0.0000001); + Assert.AreEqual(4.4250000, stats.Variance, 0.0000001); + Assert.AreEqual(5.9000000, stats.SampleVariance, 0.0000001); + } + + [Test] + public void WelfordVariance_Example9() + { + var stats = new WelfordsVariance(); + stats.AddRange(new double[] { -5, -3, -1, 1, 3 }); + Assert.AreEqual(5, stats.Count); + Assert.AreEqual(-1, stats.Mean, 0.0000001); + Assert.AreEqual(8, stats.Variance, 0.0000001); + Assert.AreEqual(10, stats.SampleVariance, 0.0000001); + } + + [Test] + public void WelfordVariance_Example10() + { + var stats = new WelfordsVariance(); + stats.AddRange(new double[] { -1, 0, 1 }); + Assert.AreEqual(3, stats.Count); + Assert.AreEqual(0, stats.Mean, 0.0000001); + Assert.AreEqual(0.6666667, stats.Variance, 0.0000001); + Assert.AreEqual(1, stats.SampleVariance, 0.0000001); + } + + [Test] + public void WelfordVariance_NoValue() + { + var stats = new WelfordsVariance(); + Assert.AreEqual(0, stats.Count); + Assert.AreEqual(double.NaN, stats.Mean); + Assert.AreEqual(double.NaN, stats.Variance); + Assert.AreEqual(double.NaN, stats.SampleVariance); + } + + [Test] + public void WelfordVariance_OneValue() + { + var stats = new WelfordsVariance(); + stats.AddValue(1); + Assert.AreEqual(1, stats.Count); + Assert.AreEqual(double.NaN, stats.Mean); + Assert.AreEqual(double.NaN, stats.Variance); + Assert.AreEqual(double.NaN, stats.SampleVariance); + } + + [Test] + public void WelfordVariance_TwoValues() + { + var stats = new WelfordsVariance(); + stats.AddValue(1); + stats.AddValue(2); + Assert.AreEqual(2, stats.Count); + Assert.AreEqual(1.5, stats.Mean, 0.0000001); + Assert.AreEqual(0.25, stats.Variance, 0.0000001); + Assert.AreEqual(0.5, stats.SampleVariance, 0.0000001); + } + } +} diff --git a/Algorithms/Other/WelfordsVariance.cs b/Algorithms/Other/WelfordsVariance.cs new file mode 100644 index 00000000..9ed51edf --- /dev/null +++ b/Algorithms/Other/WelfordsVariance.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Other +{ + /// Implementation of Welford's variance algorithm. + /// + public class WelfordsVariance + { + /// + /// Mean accumulates the mean of the entire dataset, + /// m2 aggregates the squared distance from the mean, + /// count aggregates the number of samples seen so far. + /// + private int count; + + public double Count => count; + + private double mean; + + public double Mean => count > 1 ? mean : double.NaN; + + private double m2; + + public double Variance => count > 1 ? m2 / count : double.NaN; + + public double SampleVariance => count > 1 ? m2 / (count - 1) : double.NaN; + + public WelfordsVariance() + { + count = 0; + mean = 0; + } + + public WelfordsVariance(double[] values) + { + count = 0; + mean = 0; + AddRange(values); + } + + public void AddValue(double newValue) + { + count++; + AddValueToDataset(newValue); + } + + public void AddRange(double[] values) + { + var length = values.Length; + for (var i = 1; i <= length; i++) + { + count++; + AddValueToDataset(values[i - 1]); + } + } + + private void AddValueToDataset(double newValue) + { + var delta1 = newValue - mean; + var newMean = mean + delta1 / count; + + var delta2 = newValue - newMean; + m2 += delta1 * delta2; + + mean = newMean; + } + } +} diff --git a/README.md b/README.md index 62258030..50c34296 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ find more than one implementation for the same objective but using different alg * [Pareto Optimization](./Algorithms/Other/ParetoOptimization.cs) * [Gauss Optimization](./Algorithms/Other/GaussOptimization.cs) * [Decisions Convolutions](./Algorithms/Other/DecisionsConvolutions.cs) + * [Welford's Variance](./Algorithms/Other/WelfordsVariance.cs) * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) * [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs) From bb5c243655ca2abf46fa5a6e06a87ad23a114947 Mon Sep 17 00:00:00 2001 From: Kalkwst Date: Tue, 18 Oct 2022 21:03:10 +0300 Subject: [PATCH 043/138] Add Josephus Problem solver (#356) --- .../Numeric/JosephusProblemTest.cs | 37 +++++++++++++++++++ Algorithms/Numeric/JosephusProblem.cs | 33 +++++++++++++++++ README.md | 1 + 3 files changed, 71 insertions(+) create mode 100644 Algorithms.Tests/Numeric/JosephusProblemTest.cs create mode 100644 Algorithms/Numeric/JosephusProblem.cs diff --git a/Algorithms.Tests/Numeric/JosephusProblemTest.cs b/Algorithms.Tests/Numeric/JosephusProblemTest.cs new file mode 100644 index 00000000..b4ba7dcc --- /dev/null +++ b/Algorithms.Tests/Numeric/JosephusProblemTest.cs @@ -0,0 +1,37 @@ +using System; +using Algorithms.Numeric; +using NUnit.Framework; + + +namespace Algorithms.Tests.Numeric; + +public class JosephusProblemTest +{ + + [TestCase(10, 0)] + [TestCase(10, -1)] + public void JosephusProblemInvalidStepSize(long groupSize, long step) + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo("The step cannot be smaller than 1"), + delegate { JosephusProblem.FindWinner(groupSize, step); }); + } + + [TestCase(10, 12)] + public void JosephusProblemStepSizeGreaterThanGroup(long groupSize, long step) + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo("The step cannot be greater than the size of the group"), + delegate { JosephusProblem.FindWinner(groupSize, step); }); + } + + [TestCase(10, 2, 5)] + [TestCase(10, 8, 1)] + [TestCase(254, 18, 92)] + [TestCase(3948, 614, 2160)] + [TestCase(86521, 65903, 29473)] + public void JosephusProblemWinnerCalculation(long groupSize, long step, long position) + { + Assert.That(JosephusProblem.FindWinner(groupSize, step), Is.EqualTo(position)); + } +} diff --git a/Algorithms/Numeric/JosephusProblem.cs b/Algorithms/Numeric/JosephusProblem.cs new file mode 100644 index 00000000..0aac5ace --- /dev/null +++ b/Algorithms/Numeric/JosephusProblem.cs @@ -0,0 +1,33 @@ +using System; + +namespace Algorithms.Numeric; + +public static class JosephusProblem +{ + /// + /// Calculates the winner in the Josephus problem. + /// + /// The number of people in the initial circle. + /// The count of each step. k-1 people are skipped and the k-th is executed. + /// The 1-indexed position where the player must choose in order to win the game. + public static long FindWinner(long n, long k) + { + if (k <= 0) + { + throw new ArgumentException("The step cannot be smaller than 1"); + } + + if (k > n) + { + throw new ArgumentException("The step cannot be greater than the size of the group"); + } + + long winner = 0; + for (long stepIndex = 1; stepIndex <= n; ++stepIndex) + { + winner = (winner + k) % stepIndex; + } + + return winner + 1; + } +} diff --git a/README.md b/README.md index 50c34296..1c770ca5 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ find more than one implementation for the same objective but using different alg * [Miller-Rabin primality check](./Algorithms/Numeric/MillerRabinPrimalityChecker.cs) * [KrishnamurthyNumberChecker](./Algorithms/Numeric/KrishnamurthyNumberChecker.cs) * [Automorphic Number](./Algorithms/Numeric/AutomorphicNumber.cs) + * [Josephus Problem](./Algorithms/Numeric/JosephusProblem.cs) * [Newton's Square Root Calculation](./Algorithms/NewtonSquareRoot.cs) * [Searches](./Algorithms/Search) * [A-Star](./Algorithms/Search/AStar/) From cd6ec8063af40db36f2eb6dab1b06f996a5b6ace Mon Sep 17 00:00:00 2001 From: Damian Sikora Date: Fri, 21 Oct 2022 20:55:53 +0200 Subject: [PATCH 044/138] Add z-block substring search algorithm (#360) Co-authored-by: Kalkwst --- .../Strings/ZblockSubstringSearchTest.cs | 23 +++++++ Algorithms/Strings/ZblockSubstringSearch.cs | 69 +++++++++++++++++++ README.md | 1 + 3 files changed, 93 insertions(+) create mode 100644 Algorithms.Tests/Strings/ZblockSubstringSearchTest.cs create mode 100644 Algorithms/Strings/ZblockSubstringSearch.cs diff --git a/Algorithms.Tests/Strings/ZblockSubstringSearchTest.cs b/Algorithms.Tests/Strings/ZblockSubstringSearchTest.cs new file mode 100644 index 00000000..262e8344 --- /dev/null +++ b/Algorithms.Tests/Strings/ZblockSubstringSearchTest.cs @@ -0,0 +1,23 @@ +using Algorithms.Strings; +using NUnit.Framework; + +namespace Algorithms.Tests.Strings +{ + public class ZblockSubstringSearchTest + { + [TestCase("abc", "abcdef", 1)] + [TestCase("xxx", "abxxxcdexxxf", 2)] + [TestCase("aa", "waapaaxcdaalaabb", 4)] + [TestCase("ABC", "ABAAABCDBBABCDDEBCABC", 3)] + [TestCase("xxx", "abcdefghij", 0)] + [TestCase("aab", "caabxaaaz", 1)] + [TestCase("abc", "xababaxbabcdabx", 1)] + [TestCase("GEEK", "GEEKS FOR GEEKS", 2)] + [TestCase("ground", "Hello, playground!", 1)] + public void Test(string pattern, string text, int expectedOccurences) + { + var occurencesFound = ZblockSubstringSearch.FindSubstring(pattern, text); + Assert.AreEqual(expectedOccurences, occurencesFound); + } + } +} diff --git a/Algorithms/Strings/ZblockSubstringSearch.cs b/Algorithms/Strings/ZblockSubstringSearch.cs new file mode 100644 index 00000000..dc96b537 --- /dev/null +++ b/Algorithms/Strings/ZblockSubstringSearch.cs @@ -0,0 +1,69 @@ +namespace Algorithms.Strings +{ + /// Implementation Z-block substring search. + /// + public static class ZblockSubstringSearch + { + /// + /// This algorithm finds all occurrences of a pattern in a text in linear time - O(m+n). + /// + public static int FindSubstring(string pattern, string text) + { + var concatStr = $"{pattern}${text}"; + var patternLength = pattern.Length; + var n = concatStr.Length; + var zArray = new int[n]; + + var left = 0; + var right = 0; + + for(var i = 1; i < n; i++) + { + if(i > right) + { + left = i; + right = ComputeNewRightValue(concatStr, n, left, i); + + zArray[i] = right - left; + right--; + } + else + { + var k = i - left; + if (zArray[k] < (right - i + 1)) + { + zArray[i] = zArray[k]; + } + else + { + left = i; + right = ComputeNewRightValue(concatStr, n, left, right); + zArray[i] = right - left; + right--; + } + } + } + + var found = 0; + foreach(var z_value in zArray) + { + if(z_value == patternLength) + { + found++; + } + } + + return found; + } + + private static int ComputeNewRightValue(string concatStr, int n, int left, int right) + { + while (right < n && concatStr[right - left].Equals(concatStr[right])) + { + right++; + } + + return right; + } + } +} diff --git a/README.md b/README.md index 1c770ca5..c57078f8 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,7 @@ find more than one implementation for the same objective but using different alg * [Hamming Distance](./Algorithms/Strings/HammingDistance.cs) * [Jaro Similarity](./Algorithms/Strings/JaroSimilarity.cs) * [Jaro-Winkler Distance](./Algorithms/Strings/JaroWinklerDistance.cs) + * [Z-block substring search](./Algorithms/Strings/ZblockSubstringSearch.cs) * [Other](./Algorithms/Other) * [Fermat Prime Checker](./Algorithms/Other/FermatPrimeChecker.cs) * [Sieve of Eratosthenes](./Algorithms/Other/SieveOfEratosthenes.cs) From f871b97766e0d80398444f0054fd2ce06f3451b7 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Fri, 21 Oct 2022 21:57:56 +0300 Subject: [PATCH 045/138] Update pull_request_template.md --- .github/pull_request_template.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 2d8aa100..744a8beb 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,6 +2,8 @@ Please include a summary of the change. Please also include relevant motivation and context (if applicable). Put 'x' in between square brackets to mark an item as complete. +[x] means checked checkbox +[ ] means unchecked checkbox --> - [ ] I have performed a self-review of my code From c0517a3ada940dae8b7b853bf169f4821159b0e9 Mon Sep 17 00:00:00 2001 From: Tim Riemann Date: Thu, 27 Oct 2022 20:46:10 +0200 Subject: [PATCH 046/138] Add new OEIS sequences: A000124, A000125, A000213, A000288 (#362) --- .../Sequences/CakeNumbersSequenceTests.cs | 25 ++++++++++++++ .../CentralPolygonalNumbersSequenceTests.cs | 23 +++++++++++++ .../TetranacciNumbersSequenceTests.cs | 23 +++++++++++++ .../TribonacciNumbersSequenceTests.cs | 23 +++++++++++++ Algorithms/Sequences/CakeNumbersSequence.cs | 30 +++++++++++++++++ .../CentralPolygonalNumbersSequence.cs | 30 +++++++++++++++++ .../Sequences/TetranacciNumbersSequence.cs | 33 +++++++++++++++++++ .../Sequences/TribonacciNumbersSequence.cs | 32 ++++++++++++++++++ README.md | 4 +++ 9 files changed, 223 insertions(+) create mode 100644 Algorithms.Tests/Sequences/CakeNumbersSequenceTests.cs create mode 100644 Algorithms.Tests/Sequences/CentralPolygonalNumbersSequenceTests.cs create mode 100644 Algorithms.Tests/Sequences/TetranacciNumbersSequenceTests.cs create mode 100644 Algorithms.Tests/Sequences/TribonacciNumbersSequenceTests.cs create mode 100644 Algorithms/Sequences/CakeNumbersSequence.cs create mode 100644 Algorithms/Sequences/CentralPolygonalNumbersSequence.cs create mode 100644 Algorithms/Sequences/TetranacciNumbersSequence.cs create mode 100644 Algorithms/Sequences/TribonacciNumbersSequence.cs diff --git a/Algorithms.Tests/Sequences/CakeNumbersSequenceTests.cs b/Algorithms.Tests/Sequences/CakeNumbersSequenceTests.cs new file mode 100644 index 00000000..bd3ab74c --- /dev/null +++ b/Algorithms.Tests/Sequences/CakeNumbersSequenceTests.cs @@ -0,0 +1,25 @@ +using System.Linq; +using System.Numerics; +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Sequences; + +public class CakeNumbersSequenceTests +{ + [Test] + public void First46ElementsCorrect() + { + var sequence = new CakeNumbersSequence().Sequence.Take(46); + sequence.SequenceEqual(new BigInteger[] + { + 1, 2, 4, 8, 15, 26, 42, 64, 93, 130, + 176, 232, 299, 378, 470, 576, 697, 834, 988, 1160, + 1351, 1562, 1794, 2048, 2325, 2626, 2952, 3304, 3683, 4090, + 4526, 4992, 5489, 6018, 6580, 7176, 7807, 8474, 9178, 9920, + 10701, 11522, 12384, 13288, 14235, 15226 + }) + .Should().BeTrue(); + } +} diff --git a/Algorithms.Tests/Sequences/CentralPolygonalNumbersSequenceTests.cs b/Algorithms.Tests/Sequences/CentralPolygonalNumbersSequenceTests.cs new file mode 100644 index 00000000..bfdb975c --- /dev/null +++ b/Algorithms.Tests/Sequences/CentralPolygonalNumbersSequenceTests.cs @@ -0,0 +1,23 @@ +using System.Linq; +using System.Numerics; +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Sequences; + +public class CentralPolygonalNumbersSequenceTests +{ + [Test] + public void First53ElementsCorrect() + { + var sequence = new CentralPolygonalNumbersSequence().Sequence.Take(53); + sequence.SequenceEqual(new BigInteger[] + { + 1, 2, 4, 7, 11, 16, 22, 29, 37, 46, 56, 67, 79, 92, 106, 121, 137, 154, 172, 191, 211, 232, 254, + 277, 301, 326, 352, 379, 407, 436, 466, 497, 529, 562, 596, 631, 667, 704, 742, 781, 821, 862, 904, + 947, 991, 1036, 1082, 1129, 1177, 1226, 1276, 1327, 1379, + }) + .Should().BeTrue(); + } +} diff --git a/Algorithms.Tests/Sequences/TetranacciNumbersSequenceTests.cs b/Algorithms.Tests/Sequences/TetranacciNumbersSequenceTests.cs new file mode 100644 index 00000000..84e0c5b9 --- /dev/null +++ b/Algorithms.Tests/Sequences/TetranacciNumbersSequenceTests.cs @@ -0,0 +1,23 @@ +using System.Linq; +using System.Numerics; +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Sequences; + +public class TetranacciNumbersSequenceTests +{ + [Test] + public void First35ElementsCorrect() + { + var sequence = new TetranacciNumbersSequence().Sequence.Take(35); + sequence.SequenceEqual(new BigInteger[] + { + 1, 1, 1, 1, 4, 7, 13, 25, 49, 94, 181, 349, 673, 1297, 2500, 4819, 9289, 17905, 34513, 66526, 128233, + 247177, 476449, 918385, 1770244, 3412255, 6577333, 12678217, 24438049, 47105854, 90799453, 175021573, + 337364929, 650291809, 1253477764, + }) + .Should().BeTrue(); + } +} diff --git a/Algorithms.Tests/Sequences/TribonacciNumbersSequenceTests.cs b/Algorithms.Tests/Sequences/TribonacciNumbersSequenceTests.cs new file mode 100644 index 00000000..8d2b4a7d --- /dev/null +++ b/Algorithms.Tests/Sequences/TribonacciNumbersSequenceTests.cs @@ -0,0 +1,23 @@ +using System.Linq; +using System.Numerics; +using Algorithms.Sequences; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Sequences; + +public class TribonacciNumbersSequenceTests +{ + [Test] + public void First37ElementsCorrect() + { + var sequence = new TribonacciNumbersSequence().Sequence.Take(37); + sequence.SequenceEqual(new BigInteger[] + { + 1, 1, 1, 3, 5, 9, 17, 31, 57, 105, 193, 355, 653, 1201, 2209, 4063, 7473, 13745, 25281, 46499, 85525, + 157305, 289329, 532159, 978793, 1800281, 3311233, 6090307, 11201821, 20603361, 37895489, 69700671, + 128199521, 235795681, 433695873, 797691075, 1467182629, + }) + .Should().BeTrue(); + } +} diff --git a/Algorithms/Sequences/CakeNumbersSequence.cs b/Algorithms/Sequences/CakeNumbersSequence.cs new file mode 100644 index 00000000..ac186107 --- /dev/null +++ b/Algorithms/Sequences/CakeNumbersSequence.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Algorithms.Sequences; + +/// +/// +/// Cake numbers: maximal number of pieces resulting from n planar cuts through a cube +/// (or cake): C(n+1,3) + n + 1. +/// +/// +/// OEIS: https://oeis.org/A000125. +/// +/// +public class CakeNumbersSequence : ISequence +{ + public IEnumerable Sequence + { + get + { + var n = new BigInteger(0); + while (true) + { + var next = (BigInteger.Pow(n, 3) + 5 * n + 6) / 6; + n++; + yield return next; + } + } + } +} diff --git a/Algorithms/Sequences/CentralPolygonalNumbersSequence.cs b/Algorithms/Sequences/CentralPolygonalNumbersSequence.cs new file mode 100644 index 00000000..1f84aaa1 --- /dev/null +++ b/Algorithms/Sequences/CentralPolygonalNumbersSequence.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Algorithms.Sequences; + +/// +/// +/// Central polygonal numbers (the Lazy Caterer's sequence): n(n+1)/2 + 1; or, maximal number of pieces +/// formed when slicing a pancake with n cuts. +/// +/// +/// OEIS: https://oeis.org/A000124. +/// +/// +public class CentralPolygonalNumbersSequence : ISequence +{ + public IEnumerable Sequence + { + get + { + var n = new BigInteger(0); + while (true) + { + var next = n * (n + 1) / 2 + 1; + n++; + yield return next; + } + } + } +} diff --git a/Algorithms/Sequences/TetranacciNumbersSequence.cs b/Algorithms/Sequences/TetranacciNumbersSequence.cs new file mode 100644 index 00000000..34220808 --- /dev/null +++ b/Algorithms/Sequences/TetranacciNumbersSequence.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +namespace Algorithms.Sequences; + +/// +/// +/// Tetranacci numbers: a(n) = a(n-1) + a(n-2) + a(n-3) + a(n-4) with a(0) = a(1) = a(2) = a(3) = 1. +/// +/// +/// OEIS: https://oeis.org/A000288. +/// +/// +public class TetranacciNumbersSequence : ISequence +{ + public IEnumerable Sequence + { + get + { + var buffer = Enumerable.Repeat(BigInteger.One, 4).ToArray(); + while (true) + { + yield return buffer[0]; + var next = buffer[0] + buffer[1] + buffer[2] + buffer[3]; + buffer[0] = buffer[1]; + buffer[1] = buffer[2]; + buffer[2] = buffer[3]; + buffer[3] = next; + } + } + } +} diff --git a/Algorithms/Sequences/TribonacciNumbersSequence.cs b/Algorithms/Sequences/TribonacciNumbersSequence.cs new file mode 100644 index 00000000..bf8bdcdd --- /dev/null +++ b/Algorithms/Sequences/TribonacciNumbersSequence.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +namespace Algorithms.Sequences; + +/// +/// +/// Tribonacci numbers: a(n) = a(n-1) + a(n-2) + a(n-3) with a(0)=a(1)=a(2)=1. +/// +/// +/// OEIS: https://oeis.org/A000213. +/// +/// +public class TribonacciNumbersSequence : ISequence +{ + public IEnumerable Sequence + { + get + { + var buffer = Enumerable.Repeat(BigInteger.One, 4).ToArray(); + while (true) + { + yield return buffer[0]; + var next = buffer[0] + buffer[1] + buffer[2]; + buffer[0] = buffer[1]; + buffer[1] = buffer[2]; + buffer[2] = next; + } + } + } +} diff --git a/README.md b/README.md index c57078f8..cd6706fe 100644 --- a/README.md +++ b/README.md @@ -137,8 +137,12 @@ find more than one implementation for the same objective but using different alg * [A000079 Powers of 2](./Algorithms/Sequences/PowersOf2Sequence.cs) * [A000108 Catalan](./Algorithms/Sequences/CatalanSequence.cs) * [A000120 1's Counting](./Algorithms/Sequences/OnesCountingSequence.cs) + * [A000124 Central Polygonal Numbers](./Algorithms/Sequences/CentralPolygonalNumbersSequence.cs) + * [A000125 Cake Numbers](./Algorithms/Sequences/CakeNumbersSequence.cs) * [A000142 Factorial](./Algorithms/Sequences/FactorialSequence.cs) + * [A000213 Tribonacci Numbers](./Algorithms/Sequences/TribonacciNumbersSequence.cs) * [A000215 Fermat Numbers](./Algorithms/Sequences/FermatNumbersSequence.cs) + * [A000288 Tetranacci Numbers](./Algorithms/Sequences/TetranacciNumbersSequence.cs) * [A000290 Squares](./Algorithms/Sequences/SquaresSequence.cs) * [A000292 Tetrahedral numbers](./Algorithms/Sequences/TetrahedralSequence.cs) * [A000578 Cubes](./Algorithms/Sequences/CubesSequence.cs) From 650ee475e0534ed7dbadb2810db3d2fb80321e23 Mon Sep 17 00:00:00 2001 From: Kerry M-R Date: Fri, 28 Oct 2022 05:24:23 +1030 Subject: [PATCH 047/138] Add Meeus' Julian Easter algorithm (#363) Co-authored-by: Kerry Russell --- Algorithms.Tests/Other/JulianEasterTests.cs | 32 +++++++++++++++++++++ Algorithms/Other/JulianEaster.cs | 32 +++++++++++++++++++++ README.md | 1 + 3 files changed, 65 insertions(+) create mode 100644 Algorithms.Tests/Other/JulianEasterTests.cs create mode 100644 Algorithms/Other/JulianEaster.cs diff --git a/Algorithms.Tests/Other/JulianEasterTests.cs b/Algorithms.Tests/Other/JulianEasterTests.cs new file mode 100644 index 00000000..ba103832 --- /dev/null +++ b/Algorithms.Tests/Other/JulianEasterTests.cs @@ -0,0 +1,32 @@ +using System; +using System.Globalization; +using Algorithms.Other; +using NUnit.Framework; + +namespace Algorithms.Tests.Other +{ + /// + /// A class for testing the Meeus's Julian Easter algorithm. + /// + public static class JulianEasterTest + { + private static readonly JulianCalendar Calendar = new(); + + [TestCaseSource(nameof(CalculateCases))] + public static void CalculateTest(int year, DateTime expected) + { + var result = JulianEaster.Calculate(year); + + Assert.AreEqual(expected, result); + } + + private static readonly object[] CalculateCases = + { + new object[] { 1800, new DateTime(1800, 04, 08, Calendar) }, + new object[] { 1950, new DateTime(1950, 03, 27, Calendar) }, + new object[] { 1991, new DateTime(1991, 03, 25, Calendar) }, + new object[] { 2000, new DateTime(2000, 04, 17, Calendar) }, + new object[] { 2199, new DateTime(2199, 04, 07, Calendar) } + }; + } +} diff --git a/Algorithms/Other/JulianEaster.cs b/Algorithms/Other/JulianEaster.cs new file mode 100644 index 00000000..6224f72c --- /dev/null +++ b/Algorithms/Other/JulianEaster.cs @@ -0,0 +1,32 @@ +using System; +using System.Globalization; + +namespace Algorithms.Other +{ + /// + /// Date of Easter calculated with Meeus's Julian algorithm. + /// The algorithm is described in Jean Meeus' Astronomical Algorithms (1991, p. 69). + /// + public static class JulianEaster + { + /// + /// Calculates the date of Easter. + /// + /// Year to calculate the date of Easter. + /// Date of Easter as a DateTime. + public static DateTime Calculate(int year) + { + var a = year % 4; + var b = year % 7; + var c = year % 19; + var d = (19 * c + 15) % 30; + var e = (2 * a + 4 * b - d + 34) % 7; + var month = (int)Math.Floor((d + e + 114) / 31M); + var day = ((d + e + 114) % 31) + 1; + + DateTime easter = new(year, month, day, new JulianCalendar()); + + return easter; + } + } +} diff --git a/README.md b/README.md index cd6706fe..dcb2d04a 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,7 @@ find more than one implementation for the same objective but using different alg * [Gauss Optimization](./Algorithms/Other/GaussOptimization.cs) * [Decisions Convolutions](./Algorithms/Other/DecisionsConvolutions.cs) * [Welford's Variance](./Algorithms/Other/WelfordsVariance.cs) + * [Julian Easter](./Algorithms/Other/JulianEaster.cs) * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) * [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs) From 8b49dcefe20d8c1daa7a415692b722731e019b38 Mon Sep 17 00:00:00 2001 From: Damian Sikora Date: Fri, 28 Oct 2022 21:51:47 +0200 Subject: [PATCH 048/138] Adde Pollards Rho algorithm (#365) --- .../Other/PollardsRhoFactorizingTests.cs | 19 ++++++++++ Algorithms/Other/PollardsRhoFactorizing.cs | 37 +++++++++++++++++++ README.md | 1 + 3 files changed, 57 insertions(+) create mode 100644 Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs create mode 100644 Algorithms/Other/PollardsRhoFactorizing.cs diff --git a/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs b/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs new file mode 100644 index 00000000..9375118f --- /dev/null +++ b/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs @@ -0,0 +1,19 @@ +using Algorithms.Other; +using NUnit.Framework; + +namespace Algorithms.Tests.Other +{ + public class PollardsRhoFactorizingTests + { + [TestCase(8051, 97)] + [TestCase(105, 21)] + [TestCase(253, 11)] + [TestCase(10403, 101)] + [TestCase(187, 11)] + public void SimpleTest(int number, int expectedResult) + { + var result = PollardsRhoFactorizing.Calculate(number); + Assert.AreEqual(expectedResult, result); + } + } +} diff --git a/Algorithms/Other/PollardsRhoFactorizing.cs b/Algorithms/Other/PollardsRhoFactorizing.cs new file mode 100644 index 00000000..b9c95a85 --- /dev/null +++ b/Algorithms/Other/PollardsRhoFactorizing.cs @@ -0,0 +1,37 @@ +using System; +using Algorithms.Numeric.GreatestCommonDivisor; + +namespace Algorithms.Other +{ + /// Implementation of the Pollard's rho algorithm. + /// Algorithm for integer factorization. + /// Wiki: https://en.wikipedia.org/wiki/Pollard's_rho_algorithm. + /// + public static class PollardsRhoFactorizing + { + public static int Calculate(int number) + { + var x = 2; + var y = 2; + var d = 1; + var p = number; + var i = 0; + var gcd = new BinaryGreatestCommonDivisorFinder(); + + while (d == 1) + { + x = Fun_g(x, p); + y = Fun_g(Fun_g(y, p), p); + d = gcd.FindGcd(Math.Abs(x - y), p); + i++; + } + + return d; + } + + private static int Fun_g(int x, int p) + { + return (x * x + 1) % p; + } + } +} diff --git a/README.md b/README.md index dcb2d04a..df003852 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,7 @@ find more than one implementation for the same objective but using different alg * [Decisions Convolutions](./Algorithms/Other/DecisionsConvolutions.cs) * [Welford's Variance](./Algorithms/Other/WelfordsVariance.cs) * [Julian Easter](./Algorithms/Other/JulianEaster.cs) + * [Pollard's Rho](./Algorithms/Other/PollardsRhoFactorizing.cs) * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) * [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs) From a27d4cfa0170a9aa533dfbc55a177ad363975443 Mon Sep 17 00:00:00 2001 From: Daniel Alfonso <55640656+Dalfonso06@users.noreply.github.com> Date: Sat, 29 Oct 2022 01:37:35 -0400 Subject: [PATCH 049/138] Add Breadth First Tree Traversal (#364) Co-authored-by: Dalfonso06 Co-authored-by: Andrii Siriak --- .../Graph/BreadthFirstTreeTraversalTests.cs | 93 +++++++++++++++++++ Algorithms/Graph/BreadthFirstTreeTraversal.cs | 90 ++++++++++++++++++ .../BinarySearchTree/BinarySearchTree.cs | 42 ++++----- README.md | 1 + 4 files changed, 205 insertions(+), 21 deletions(-) create mode 100644 Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs create mode 100644 Algorithms/Graph/BreadthFirstTreeTraversal.cs diff --git a/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs b/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs new file mode 100644 index 00000000..657e0df1 --- /dev/null +++ b/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs @@ -0,0 +1,93 @@ +using Algorithms.Graph; +using NUnit.Framework; +using DataStructures.BinarySearchTree; +using System; + +namespace Algorithms.Tests.Graph +{ + public static class BreadthFirstTreeTraversalTests + { + [Test] + public static void CorrectLevelOrderTraversal() + { + // Arrange + int[] correctPath = { 7, 4, 13, 2, 5, 11, 15, 14, 16 }; + int[] insertionOrder = { 7, 13, 11, 15, 14, 4, 5, 16, 2 }; + BinarySearchTree testTree = new BinarySearchTree(); + foreach (int data in insertionOrder) + { + testTree.Add(data); + } + + // Act + int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); + + // Assert + Assert.AreEqual(levelOrder, correctPath); + } + + [Test] + public static void EmptyArrayForNullRoot() + { + // Arrange + BinarySearchTree testTree = new BinarySearchTree(); + + // Act + int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); + + // Assert + Assert.IsEmpty(levelOrder); + } + + [Test] + [TestCase(new [] {7, 9, 5})] + [TestCase(new [] { 7, 13, 11, 15, 14, 4, 5, 16, 2 })] + public static void IncorrectLevelOrderTraversal(int[] insertion) + { + // Arrange + BinarySearchTree testTree = new BinarySearchTree(); + foreach (int data in insertion) + { + testTree.Add(data); + } + + // Act + int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); + + // Assert + Assert.AreNotEqual(levelOrder, insertion); + } + + [Test] + public static void DeepestNodeInTree() + { + // Arrange + BinarySearchTree testTree = new BinarySearchTree(); + int[] insertion = { 7, 13, 11, 15, 4, 5, 12, 2, 9 }; + foreach (int data in insertion) + { + testTree.Add(data); + } + + // Act + int deepest = BreadthFirstTreeTraversal.DeepestNode(testTree); + + // Assert + Assert.AreEqual(12, deepest); + } + + [Test] + public static void DeepestNodeOfEmptyTree() + { + // Arrange + BinarySearchTree testTree = new BinarySearchTree(); + + // Act + int? deepest = BreadthFirstTreeTraversal.DeepestNode(testTree); + + // Assert + Assert.IsNull(deepest); + } + } +} + diff --git a/Algorithms/Graph/BreadthFirstTreeTraversal.cs b/Algorithms/Graph/BreadthFirstTreeTraversal.cs new file mode 100644 index 00000000..04b5ef0b --- /dev/null +++ b/Algorithms/Graph/BreadthFirstTreeTraversal.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using DataStructures.BinarySearchTree; + +namespace Algorithms.Graph +{ + /// + /// Breadth first tree traversal traverses through a binary tree + /// by iterating through each level first. + /// time complexity: O(n). + /// space complexity: O(w) where w is the max width of a binary tree. + /// + /// Type of key held in binary search tree. + public static class BreadthFirstTreeTraversal + { + /// + /// Level Order Traversal returns an array of integers in order + /// of each level of a binary tree. It uses a queue to iterate + /// through each node following breadth first search traversal. + /// + /// Passes the binary tree to traverse. + /// Returns level order traversal. + public static TKey[] LevelOrderTraversal(BinarySearchTree tree) + { + BinarySearchTreeNode? root = tree.Root; + TKey[] levelOrder = new TKey[tree.Count]; + if (root is null) + { + return Array.Empty(); + } + + Queue> breadthTraversal = new Queue>(); + breadthTraversal.Enqueue(root); + for (int i = 0; i < levelOrder.Length; i++) + { + BinarySearchTreeNode current = breadthTraversal.Dequeue(); + levelOrder[i] = current.Key; + if (current.Left is not null) + { + breadthTraversal.Enqueue(current.Left); + } + + if (current.Right is not null) + { + breadthTraversal.Enqueue(current.Right); + } + } + + return levelOrder; + } + + /// + /// Deepest Node return the deepest node in a binary tree. If more + /// than one node is on the deepest level, it is defined as the + /// right-most node of a binary tree. Deepest node uses breadth + /// first traversal to reach the end. + /// + /// Tree passed to find deepest node. + /// Returns the deepest node in the tree. + public static TKey? DeepestNode(BinarySearchTree tree) + { + BinarySearchTreeNode? root = tree.Root; + if (root is null) + { + return default(TKey); + } + + Queue> breadthTraversal = new Queue>(); + breadthTraversal.Enqueue(root); + TKey deepest = root.Key; + while (breadthTraversal.Count > 0) + { + BinarySearchTreeNode current = breadthTraversal.Dequeue(); + if (current.Left is not null) + { + breadthTraversal.Enqueue(current.Left); + } + + if (current.Right is not null) + { + breadthTraversal.Enqueue(current.Right); + } + + deepest = current.Key; + } + + return deepest; + } + } +} diff --git a/DataStructures/BinarySearchTree/BinarySearchTree.cs b/DataStructures/BinarySearchTree/BinarySearchTree.cs index b5138966..70a416a9 100644 --- a/DataStructures/BinarySearchTree/BinarySearchTree.cs +++ b/DataStructures/BinarySearchTree/BinarySearchTree.cs @@ -24,20 +24,20 @@ public class BinarySearchTree private readonly Comparer comparer; /// - /// The root of the BST. + /// Gets the root of the BST. /// - private BinarySearchTreeNode? root; + public BinarySearchTreeNode? Root { get; private set; } public BinarySearchTree() { - root = null; + Root = null; Count = 0; comparer = Comparer.Default; } public BinarySearchTree(Comparer customComparer) { - root = null; + Root = null; Count = 0; comparer = customComparer; } @@ -56,13 +56,13 @@ public BinarySearchTree(Comparer customComparer) /// public void Add(TKey key) { - if (root is null) + if (Root is null) { - root = new BinarySearchTreeNode(key); + Root = new BinarySearchTreeNode(key); } else { - Add(root, key); + Add(Root, key); } Count++; @@ -86,14 +86,14 @@ public void AddRange(IEnumerable keys) /// /// The key to search for. /// The node with the specified key if it exists, otherwise a default value is returned. - public BinarySearchTreeNode? Search(TKey key) => Search(root, key); + public BinarySearchTreeNode? Search(TKey key) => Search(Root, key); /// /// Checks if the specified key is in the BST. /// /// The key to search for. /// true if the key is in the BST, false otherwise. - public bool Contains(TKey key) => Search(root, key) is not null; + public bool Contains(TKey key) => Search(Root, key) is not null; /// /// Removes a node with a key that matches . @@ -102,12 +102,12 @@ public void AddRange(IEnumerable keys) /// true if the removal was successful, false otherwise. public bool Remove(TKey key) { - if (root is null) + if (Root is null) { return false; } - var result = Remove(root, root, key); + var result = Remove(Root, Root, key); if (result) { Count--; @@ -122,12 +122,12 @@ public bool Remove(TKey key) /// The node if possible, a default value otherwise. public BinarySearchTreeNode? GetMin() { - if (root is null) + if (Root is null) { return default; } - return GetMin(root); + return GetMin(Root); } /// @@ -136,31 +136,31 @@ public bool Remove(TKey key) /// The node if possible, a default value otherwise. public BinarySearchTreeNode? GetMax() { - if (root is null) + if (Root is null) { return default; } - return GetMax(root); + return GetMax(Root); } /// /// Returns all the keys in the BST, sorted In-Order. /// /// A list of keys in the BST. - public ICollection GetKeysInOrder() => GetKeysInOrder(root); + public ICollection GetKeysInOrder() => GetKeysInOrder(Root); /// /// Returns all the keys in the BST, sorted Pre-Order. /// /// A list of keys in the BST. - public ICollection GetKeysPreOrder() => GetKeysPreOrder(root); + public ICollection GetKeysPreOrder() => GetKeysPreOrder(Root); /// /// Returns all the keys in the BST, sorted Post-Order. /// /// A list of keys in the BST. - public ICollection GetKeysPostOrder() => GetKeysPostOrder(root); + public ICollection GetKeysPostOrder() => GetKeysPostOrder(Root); /// /// Recursive method to add a key to the BST. @@ -261,7 +261,7 @@ private bool Remove(BinarySearchTreeNode? parent, BinarySearchTreeNode(predecessorNode.Key) { Left = node.Left, @@ -271,9 +271,9 @@ private bool Remove(BinarySearchTreeNode? parent, BinarySearchTreeNode Date: Sat, 29 Oct 2022 13:46:35 +0800 Subject: [PATCH 050/138] Fix reverse link when adding node to DoublyLinkedList. (#366) --- DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs | 4 ++++ .../LinkedList/DoublyLinkedList/DoublyLinkedList.cs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs b/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs index 440f7160..ba80c407 100644 --- a/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs +++ b/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs @@ -46,9 +46,11 @@ public static void TestAddtion() dll.Add(4); var arr = dll.GetData().ToArray(); + var reversedArr = dll.GetDataReversed().ToArray(); Assert.AreEqual(dll.Count, 5); Assert.AreEqual(new[] { 0, 1, 2, 3, 4 }, arr); + Assert.AreEqual(new[] { 4, 3, 2, 1, 0 }, reversedArr); } [Test] @@ -61,9 +63,11 @@ public static void TestRemove() dll.Remove(); var arr = dll.GetData().ToArray(); + var reversedArr = dll.GetDataReversed().ToArray(); Assert.AreEqual(dll.Count, 2); Assert.AreEqual(new[] { 1, 3 }, arr); + Assert.AreEqual(new[] { 3, 1 }, reversedArr); } [Test] diff --git a/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs b/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs index e4a72e62..72a8bb1e 100644 --- a/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs +++ b/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs @@ -113,9 +113,9 @@ public DoublyLinkedListNode AddAfter(T data, DoublyLinkedListNode existing node.Previous = existingNode; existingNode.Next = node; - if (existingNode.Next is not null) + if (node.Next is not null) { - existingNode.Next.Previous = node; + node.Next.Previous = node; } Count++; From 59c7a7b2ab9d2d8f97268b38f812528d45150ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Victor?= <68869379+JoaoVictor6@users.noreply.github.com> Date: Tue, 24 Jan 2023 03:54:17 -0300 Subject: [PATCH 051/138] Remove unnecessary array loop (#373) --- DataStructures/Stack/ArrayBasedStack.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/DataStructures/Stack/ArrayBasedStack.cs b/DataStructures/Stack/ArrayBasedStack.cs index 31cb9832..41654fa7 100644 --- a/DataStructures/Stack/ArrayBasedStack.cs +++ b/DataStructures/Stack/ArrayBasedStack.cs @@ -42,13 +42,10 @@ public ArrayBasedStack(T item) /// Initializes a new instance of the class. /// /// Items to push onto the . - public ArrayBasedStack(IEnumerable items) - : this() + public ArrayBasedStack(T[] items) { - foreach (var item in items) - { - Push(item); - } + stack = items; + top = items.Length - 1; } /// From 8a5db71e580f864dee4a0eb0a68dbb17d7796362 Mon Sep 17 00:00:00 2001 From: deljohnson1 <123424256+deljohnson1@users.noreply.github.com> Date: Mon, 30 Jan 2023 11:54:15 -0600 Subject: [PATCH 052/138] Fix Sieve of Eratosthenes (#377) --- .../Other/SieveOfEratosthenesTests.cs | 19 ++++-- Algorithms/Other/SieveOfEratosthenes.cs | 62 +++++++++++++++---- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs b/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs index dd964173..21102bf2 100644 --- a/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs +++ b/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs @@ -1,12 +1,13 @@ -using System.Numerics; +using System.Numerics; using Algorithms.Other; +using FluentAssertions; using NUnit.Framework; namespace Algorithms.Tests.Other { public static class SieveOfEratosthenesTests { - private static readonly BigInteger[] First10000PrimeNumbers = + private static readonly long[] First10000PrimeNumbers = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, @@ -667,7 +668,17 @@ public static class SieveOfEratosthenesTests }; [Test] - public static void First10_000PrimesCorrect() => - Assert.AreEqual(First10000PrimeNumbers, SieveOfEratosthenes.GetPrimeNumbers(10_000)); + public static void First10_000PrimesCorrect() => + Assert.AreEqual(First10000PrimeNumbers, new SieveOfEratosthenes(104729).GetPrimes()); + + [Test] + public static void TestMaxNumber() => Assert.AreEqual(new SieveOfEratosthenes(69).MaximumNumber, 69); + + [TestCase(13, true)] + [TestCase(10, false)] + public static void TestIsPrime(int input, bool expected) + { + Assert.AreEqual(new SieveOfEratosthenes(100).IsPrime(input), expected); + } } } diff --git a/Algorithms/Other/SieveOfEratosthenes.cs b/Algorithms/Other/SieveOfEratosthenes.cs index 34746c31..a118a5c7 100644 --- a/Algorithms/Other/SieveOfEratosthenes.cs +++ b/Algorithms/Other/SieveOfEratosthenes.cs @@ -1,31 +1,71 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Numerics; +using System.Runtime.CompilerServices; namespace Algorithms.Other { /// - /// TODO. + /// Implements the Sieve of Eratosthenes. /// - public static class SieveOfEratosthenes + public class SieveOfEratosthenes { + private readonly bool[] primes; + /// - /// TODO. + /// Initializes a new instance of the class. + /// Uses the Sieve of Eratosthenes to precalculate the primes from 0 up to maximumNumberToCheck. + /// Requires enough memory to allocate maximumNumberToCheck bytes. + /// https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes . /// - /// TODO. 2. - /// TODO. 3. - public static List GetPrimeNumbers(int count) + /// long which specifies the largest number you wish to know if it is prime. + public SieveOfEratosthenes(long maximumNumberToCheck) { - var output = new List(); - for (BigInteger n = 2; output.Count < count; n++) + primes = new bool[maximumNumberToCheck + 1]; + + // initialize primes array + Array.Fill(this.primes, true, 2, primes.Length - 2); + + for(long i = 2; i * i <= maximumNumberToCheck; i++) { - if (output.All(x => n % x != 0)) + if (!primes[i]) + { + continue; + } + + for(long composite = i * i; composite <= maximumNumberToCheck; composite += i) { - output.Add(n); + primes[composite] = false; } } + } + + /// + /// Gets the maximumNumberToCheck the class was instantiated with. + /// + public long MaximumNumber => primes.Length - 1; - return output; + /// + /// Returns a boolean indicating whether the number is prime. + /// + /// The number you desire to know if it is prime or not. + /// A boolean indicating whether the number is prime or not. + public bool IsPrime(long numberToCheck) => primes[numberToCheck]; + + /// + /// Returns an IEnumerable of long primes in asending order. + /// + /// Primes in ascending order. + public IEnumerable GetPrimes() + { + for(long i = 2; i < primes.Length; i++) + { + if (primes[i]) + { + yield return i; + } + } } } } From 5d54eb7917cd4bee06a7400637fc8bee8eb8ea1b Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Sat, 18 Mar 2023 10:08:23 +0200 Subject: [PATCH 053/138] Remove outdated GuardRails badge --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 80d971b3..3032c6c7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ [![Build Status](https://app.travis-ci.com/TheAlgorithms/C-Sharp.svg?branch=master)](https://app.travis-ci.com/TheAlgorithms/C-Sharp) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/58895a2795bd48a8b3b7eb6ebe22d576)](https://www.codacy.com/gh/TheAlgorithms/C-Sharp/dashboard?utm_source=github.com&utm_medium=referral&utm_content=TheAlgorithms/C-Sharp&utm_campaign=Badge_Grade) [![codecov](https://codecov.io/gh/TheAlgorithms/C-Sharp/branch/master/graph/badge.svg)](https://codecov.io/gh/TheAlgorithms/C-Sharp) -[![GuardRails badge](https://badges.guardrails.io/TheAlgorithms/C-Sharp.svg?token=84805208ba243f0931a74c5148883f894cbe9fd97fe54d64d6d0a89852067548)](https://dashboard.guardrails.io/default/gh/TheAlgorithms/C-Sharp) [![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/TheAlgorithms/donate) ## All Algorithms implemented in C# - for education purposes From 41bbea318e612f475001a2113c530dd23467898e Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Fri, 31 Mar 2023 10:33:15 +0300 Subject: [PATCH 054/138] Move CI from Travis to GitHub Actions (#388) --- .github/workflows/ci.yml | 21 +++++++++++++++++++++ .travis.yml | 11 ----------- README.md | 1 - 3 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..4765da54 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: CI + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup .NET SDK + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 6.x + - name: Restore + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --no-restore --collect "XPlat Code Coverage" + - name: Upload code coverage to Codecov + run: bash <(curl -s https://codecov.io/bash) diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 711ab1dd..00000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: csharp -solution: C-Sharp.sln -mono: none -dist: focal -dotnet: 6.0 -script: - - sudo apt update - - sudo apt install -y libgdiplus - - dotnet build - - travis_wait 60 dotnet test --collect:"XPlat Code Coverage" - - bash <(curl -s https://codecov.io/bash) diff --git a/README.md b/README.md index 3032c6c7..1ce96994 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ # The Algorithms - C# [![Discord chat](https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA)](https://discord.gg/c7MnfGFGa6) -[![Build Status](https://app.travis-ci.com/TheAlgorithms/C-Sharp.svg?branch=master)](https://app.travis-ci.com/TheAlgorithms/C-Sharp) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/58895a2795bd48a8b3b7eb6ebe22d576)](https://www.codacy.com/gh/TheAlgorithms/C-Sharp/dashboard?utm_source=github.com&utm_medium=referral&utm_content=TheAlgorithms/C-Sharp&utm_campaign=Badge_Grade) [![codecov](https://codecov.io/gh/TheAlgorithms/C-Sharp/branch/master/graph/badge.svg)](https://codecov.io/gh/TheAlgorithms/C-Sharp) [![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/TheAlgorithms/donate) From 52bf864adb2e121d1ba23d4989aca1845e47c788 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Apr 2023 13:57:35 +0300 Subject: [PATCH 055/138] Bump System.Drawing.Common from 5.0.2 to 5.0.3 in /Algorithms (#389) Bumps [System.Drawing.Common](https://github.com/dotnet/runtime) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v5.0.2...v5.0.3) --- updated-dependencies: - dependency-name: System.Drawing.Common dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Algorithms/Algorithms.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Algorithms/Algorithms.csproj b/Algorithms/Algorithms.csproj index 9d3f6252..dc8491dc 100644 --- a/Algorithms/Algorithms.csproj +++ b/Algorithms/Algorithms.csproj @@ -20,7 +20,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + From 97bdcbd73f4afcbacc1a76080b1a73a55730ea8d Mon Sep 17 00:00:00 2001 From: MatthiasHeinz <7958945+MatthiasHeinz@users.noreply.github.com> Date: Sun, 16 Apr 2023 21:35:29 +0200 Subject: [PATCH 056/138] Switch to BigInteger in Binomial Coefficient (fixes #381) (#392) --- .../Numeric/BinomialCoefficientTests.cs | 11 +++---- Algorithms/Numeric/BinomialCoefficient.cs | 30 ++++++++++++++++--- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs b/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs index a8149e1f..01614dd5 100644 --- a/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs +++ b/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs @@ -1,4 +1,5 @@ -using System; +using System; +using System.Numerics; using Algorithms.Numeric; using NUnit.Framework; @@ -8,15 +9,15 @@ public static class BinomialCoefficientTests { [TestCase(4, 2, 6)] [TestCase(7, 3, 35)] - public static void CalculateFromPairs(int n, int k, long expected) + public static void CalculateFromPairs(int n, int k, int expected) { // Arrange // Act - var result = BinomialCoefficient.Calculate(n, k); + var result = BinomialCoefficient.Calculate(new BigInteger(n), new BigInteger(k)); // Assert - Assert.AreEqual(expected, result); + Assert.AreEqual(new BigInteger(expected), result); } [Test] @@ -28,7 +29,7 @@ public static void TeoremCalculateThrowsException(int n, int k) // Act // Assert - _ = Assert.Throws(() => BinomialCoefficient.Calculate(n, k)); + _ = Assert.Throws(() => BinomialCoefficient.Calculate(new BigInteger(n), new BigInteger(k))); } } } diff --git a/Algorithms/Numeric/BinomialCoefficient.cs b/Algorithms/Numeric/BinomialCoefficient.cs index 054bbba2..cb61239c 100644 --- a/Algorithms/Numeric/BinomialCoefficient.cs +++ b/Algorithms/Numeric/BinomialCoefficient.cs @@ -1,4 +1,5 @@ -using System; +using System; +using System.Numerics; namespace Algorithms.Numeric { @@ -14,14 +15,35 @@ public static class BinomialCoefficient /// First number. /// Second number. /// Binimial Coefficients. - public static long Calculate(int num, int k) + public static BigInteger Calculate(BigInteger num, BigInteger k) { if (num < k || k < 0) { - throw new ArgumentException("n ≥ k ≥ 0"); + throw new ArgumentException("num ≥ k ≥ 0"); } - return Factorial.Calculate(num) / (Factorial.Calculate(k) * Factorial.Calculate(num - k)); + // Tricks to gain performance: + // 1. Because (num over k) equals (num over (num-k)), we can save multiplications and divisions + // by replacing k with the minimum of k and (num - k). + k = BigInteger.Min(k, num - k); + + // 2. We can simplify the computation of (num! / (k! * (num - k)!)) to ((num * (num - 1) * ... * (num - k + 1) / (k!)) + // and thus save some multiplications and divisions. + var numerator = BigInteger.One; + for (var val = num - k + 1; val <= num; val++) + { + numerator *= val; + } + + // 3. Typically multiplication is a lot faster than division, therefore compute the value of k! first (i.e. k - 1 multiplications) + // and then divide the numerator by the denominator (i.e. 1 division); instead of performing k - 1 divisions (1 for each factor in k!). + var denominator = BigInteger.One; + for (var val = k; val > BigInteger.One; val--) + { + denominator *= val; + } + + return numerator / denominator; } } } From 9104ebca75cc25b9512df01eccf913768af08faf Mon Sep 17 00:00:00 2001 From: Sid Chalke <22353899+bladeassault45@users.noreply.github.com> Date: Tue, 25 Apr 2023 07:02:36 -0400 Subject: [PATCH 057/138] Switch factorial calculation to big integer (#393) --- Algorithms.Tests/Numeric/FactorialTests.cs | 28 +++++++++----------- Algorithms.Tests/Strings/PermutationTests.cs | 4 +-- Algorithms/Numeric/Factorial.cs | 25 ++++++++++++----- Algorithms/Numeric/Series/Maclaurin.cs | 6 ++--- 4 files changed, 37 insertions(+), 26 deletions(-) diff --git a/Algorithms.Tests/Numeric/FactorialTests.cs b/Algorithms.Tests/Numeric/FactorialTests.cs index 88a9302e..1f03613f 100644 --- a/Algorithms.Tests/Numeric/FactorialTests.cs +++ b/Algorithms.Tests/Numeric/FactorialTests.cs @@ -1,4 +1,5 @@ using System; +using System.Numerics; using Algorithms.Numeric; using NUnit.Framework; @@ -6,36 +7,33 @@ namespace Algorithms.Tests.Numeric { public static class FactorialTests { - [Test] - [TestCase(5, 120)] - [TestCase(1, 1)] - [TestCase(0, 1)] - [TestCase(4, 24)] - [TestCase(18, 6402373705728000)] - [TestCase(10, 3628800)] - public static void GetsFactorial(int input, long expected) + [TestCase(0, "1")] + [TestCase(1, "1")] + [TestCase(4, "24")] + [TestCase(10, "3628800")] + [TestCase(18, "6402373705728000")] + public static void GetsFactorial(int input, string expected) { // Arrange + BigInteger expectedBigInt = BigInteger.Parse(expected); // Act var result = Factorial.Calculate(input); // Assert - Assert.AreEqual(expected, result); + Assert.AreEqual(expectedBigInt, result); } - [Test] - public static void GetsFactorialExceptionForNonPositiveNumbers( - [Random(-1000, -1, 10, Distinct = true)] - int input) + [TestCase(-5)] + [TestCase(-10)] + public static void GetsFactorialExceptionForNegativeNumbers(int num) { // Arrange // Act - void Act() => Factorial.Calculate(input); + void Act() => Factorial.Calculate(num); // Assert - _ = Assert.Throws(Act); } } diff --git a/Algorithms.Tests/Strings/PermutationTests.cs b/Algorithms.Tests/Strings/PermutationTests.cs index 8bfeae2b..189d602f 100644 --- a/Algorithms.Tests/Strings/PermutationTests.cs +++ b/Algorithms.Tests/Strings/PermutationTests.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Numerics; using Algorithms.Numeric; using Algorithms.Strings; -using FluentAssertions; using NUnit.Framework; namespace Algorithms.Tests.Strings @@ -48,7 +48,7 @@ public void Test_GetEveryUniquePermutation(string word) { return current / Factorial.Calculate(keyValuePair.Value); }); - Assert.AreEqual(expectedNumberOfAnagrams, permutations.Count); + Assert.AreEqual(expectedNumberOfAnagrams, new BigInteger(permutations.Count)); // End 1. // Start 2 diff --git a/Algorithms/Numeric/Factorial.cs b/Algorithms/Numeric/Factorial.cs index 1f8b28ac..845a92ea 100644 --- a/Algorithms/Numeric/Factorial.cs +++ b/Algorithms/Numeric/Factorial.cs @@ -1,4 +1,5 @@ using System; +using System.Numerics; namespace Algorithms.Numeric { @@ -9,18 +10,30 @@ namespace Algorithms.Numeric public static class Factorial { /// - /// Calculates factorial of a number. + /// Calculates factorial of a integer number. /// - /// Input number. - /// Factorial of input number. - public static long Calculate(int num) + /// Integer Input number. + /// Factorial of integer input number. + public static BigInteger Calculate(int inputNum) { - if (num < 0) + // Convert integer input to BigInteger + BigInteger num = new BigInteger(inputNum); + + // Don't calculate factorial if input is a negative number. + if (BigInteger.Compare(num, BigInteger.Zero) < 0) { throw new ArgumentException("Only for num >= 0"); } - return num == 0 ? 1 : num * Calculate(num - 1); + // Factorial of numbers greater than 0. + BigInteger result = BigInteger.One; + + for (BigInteger i = BigInteger.One; BigInteger.Compare(i, num) <= 0; i = BigInteger.Add(i, BigInteger.One)) + { + result = BigInteger.Multiply(result, i); + } + + return result; } } } diff --git a/Algorithms/Numeric/Series/Maclaurin.cs b/Algorithms/Numeric/Series/Maclaurin.cs index 9d45acf8..cfae31a3 100644 --- a/Algorithms/Numeric/Series/Maclaurin.cs +++ b/Algorithms/Numeric/Series/Maclaurin.cs @@ -117,7 +117,7 @@ private static double ErrorTermWrapper(double x, double error, FuncGiven point. /// Term index from 0 to n. /// Single term value. - private static double ExpTerm(double x, int i) => Math.Pow(x, i) / Factorial.Calculate(i); + private static double ExpTerm(double x, int i) => Math.Pow(x, i) / (long)Factorial.Calculate(i); /// /// Single term for sin(x) function approximation: (-1)^i * x^(2*i + 1) / (2*i + 1)!. @@ -126,7 +126,7 @@ private static double ErrorTermWrapper(double x, double error, FuncTerm index from 0 to n. /// Single term value. private static double SinTerm(double x, int i) => - Math.Pow(-1, i) / Factorial.Calculate(2 * i + 1) * Math.Pow(x, 2 * i + 1); + Math.Pow(-1, i) / ((long)Factorial.Calculate(2 * i + 1)) * Math.Pow(x, 2 * i + 1); /// /// Single term for cos(x) function approximation: (-1)^i * x^(2*i) / (2*i)!. @@ -135,6 +135,6 @@ private static double SinTerm(double x, int i) => /// Term index from 0 to n. /// Single term value. private static double CosTerm(double x, int i) => - Math.Pow(-1, i) / Factorial.Calculate(2 * i) * Math.Pow(x, 2 * i); + Math.Pow(-1, i) / ((long)Factorial.Calculate(2 * i)) * Math.Pow(x, 2 * i); } } From 83b544396c3d39a684a2dcd0ce2056ad4f996c40 Mon Sep 17 00:00:00 2001 From: BSzmolke <40246238+BSzmolke@users.noreply.github.com> Date: Sat, 20 May 2023 11:42:31 +0200 Subject: [PATCH 058/138] Add Runge-Kutta method (#394) --- .../Numeric/RungeKuttaMethodTest.cs | 43 ++++++++++++ Algorithms/Numeric/RungeKuttaMethod.cs | 69 +++++++++++++++++++ README.md | 1 + 3 files changed, 113 insertions(+) create mode 100644 Algorithms.Tests/Numeric/RungeKuttaMethodTest.cs create mode 100644 Algorithms/Numeric/RungeKuttaMethod.cs diff --git a/Algorithms.Tests/Numeric/RungeKuttaMethodTest.cs b/Algorithms.Tests/Numeric/RungeKuttaMethodTest.cs new file mode 100644 index 00000000..d85d8abe --- /dev/null +++ b/Algorithms.Tests/Numeric/RungeKuttaMethodTest.cs @@ -0,0 +1,43 @@ +using Algorithms.Numeric; +using FluentAssertions; +using NUnit.Framework; +using System; +using System.Collections.Generic; + +namespace Algorithms.Tests.Numeric +{ + public static class RungeKuttaTest + { + [Test] + public static void TestLinearEquation() + { + Func exampleEquation = (x, _) => x; + List points = RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0.001, 0, exampleEquation); + var yEnd = points[^1][1]; + yEnd.Should().BeApproximately(8, 0.01); + } + + [Test] + public static void TestExampleFunciton() + { + Func exampleEquation = (_, y) => y; + List points = RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0.0125, 1, exampleEquation); + var yEnd = points[^1][1]; + yEnd.Should().BeApproximately(54.598, 0.0005); + } + + [Test] + public static void StepsizeIsZeroOrNegative_ThrowsArgumentOutOfRangeException() + { + Func exampleEquation = (x, _) => x; + Assert.Throws(() => RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0, 0, exampleEquation)); + } + + [Test] + public static void StartIsLargerThanEnd_ThrowsArgumentOutOfRangeException() + { + Func exampleEquation = (x, _) => x; + Assert.Throws(() => RungeKuttaMethod.ClassicRungeKuttaMethod(0, -4, 0.1, 0, exampleEquation)); + } + } +} diff --git a/Algorithms/Numeric/RungeKuttaMethod.cs b/Algorithms/Numeric/RungeKuttaMethod.cs new file mode 100644 index 00000000..6f694e6e --- /dev/null +++ b/Algorithms/Numeric/RungeKuttaMethod.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; + +namespace Algorithms.Numeric +{ + /// + /// In numerical analysis, the Runge–Kutta methods are a family of implicit and explicit iterative methods, + /// used in temporal discretization for the approximate solutions of simultaneous nonlinear equations. + /// The most widely known member of the Runge–Kutta family is generally referred to as + /// "RK4", the "classic Runge–Kutta method" or simply as "the Runge–Kutta method". + /// + public static class RungeKuttaMethod + { + /// + /// Loops through all the steps until xEnd is reached, adds a point for each step and then + /// returns all the points. + /// + /// Initial conditions x-value. + /// Last x-value. + /// Step-size on the x-axis. + /// Initial conditions y-value. + /// The right hand side of the differential equation. + /// The solution of the Cauchy problem. + public static List ClassicRungeKuttaMethod( + double xStart, + double xEnd, + double stepSize, + double yStart, + Func function) + { + if (xStart >= xEnd) + { + throw new ArgumentOutOfRangeException( + nameof(xEnd), + $"{nameof(xEnd)} should be greater than {nameof(xStart)}"); + } + + if (stepSize <= 0) + { + throw new ArgumentOutOfRangeException( + nameof(stepSize), + $"{nameof(stepSize)} should be greater than zero"); + } + + List points = new(); + double[] firstPoint = { xStart, yStart }; + points.Add(firstPoint); + + var yCurrent = yStart; + var xCurrent = xStart; + + while (xCurrent < xEnd) + { + var k1 = function(xCurrent, yCurrent); + var k2 = function(xCurrent + 0.5 * stepSize, yCurrent + 0.5 * stepSize * k1); + var k3 = function(xCurrent + 0.5 * stepSize, yCurrent + 0.5 * stepSize * k2); + var k4 = function(xCurrent + stepSize, yCurrent + stepSize * k3); + + yCurrent += (1.0 / 6.0) * stepSize * (k1 + 2 * k2 + 2 * k3 + k4); + xCurrent += stepSize; + + double[] newPoint = { xCurrent, yCurrent }; + points.Add(newPoint); + } + + return points; + } + } +} diff --git a/README.md b/README.md index 1ce96994..74fa834b 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ find more than one implementation for the same objective but using different alg * [Perfect Number Checker](./Algorithms/Numeric/PerfectNumberChecker.cs) * [Perfect Square Checker](./Algorithms/Numeric/PerfectSquareChecker.cs) * [Euler Method](./Algorithms/Numeric/EulerMethod.cs) + * [Classic Runge-Kutta Method](./Algorithms/Numeric/RungeKuttaMethod.cs) * [Miller-Rabin primality check](./Algorithms/Numeric/MillerRabinPrimalityChecker.cs) * [KrishnamurthyNumberChecker](./Algorithms/Numeric/KrishnamurthyNumberChecker.cs) * [Automorphic Number](./Algorithms/Numeric/AutomorphicNumber.cs) From c13608a85fab58049db0f2fc607c5ca7e2cbb8dd Mon Sep 17 00:00:00 2001 From: BSzmolke <40246238+BSzmolke@users.noreply.github.com> Date: Thu, 25 May 2023 12:54:57 +0200 Subject: [PATCH 059/138] Add interpolation search (#395) --- .../Search/InterpolationSearchTests.cs | 58 +++++++++++++++++++ Algorithms/Search/InterpolationSearch.cs | 52 +++++++++++++++++ README.md | 6 +- 3 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 Algorithms.Tests/Search/InterpolationSearchTests.cs create mode 100644 Algorithms/Search/InterpolationSearch.cs diff --git a/Algorithms.Tests/Search/InterpolationSearchTests.cs b/Algorithms.Tests/Search/InterpolationSearchTests.cs new file mode 100644 index 00000000..f32e7104 --- /dev/null +++ b/Algorithms.Tests/Search/InterpolationSearchTests.cs @@ -0,0 +1,58 @@ +using Algorithms.Search; +using NUnit.Framework.Internal; +using NUnit.Framework; +using System; +using System.Linq; + +namespace Algorithms.Tests.Search +{ + public static class InterpolationSearchTests + { + [Test] + public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int n) + { + // Arrange + var random = Randomizer.CreateRandomizer(); + var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).OrderBy(x => x).ToArray(); + var selectedIndex = random.Next(0, n); + + // Act + var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, arrayToSearch[selectedIndex]); + + // Assert + Assert.AreEqual(arrayToSearch[selectedIndex], arrayToSearch[actualIndex]); + } + + [Test] + public static void FindIndex_ItemMissing_MinusOneReturned( + [Random(0, 1000, 10)] int n, + [Random(-100, 1100, 10)] int missingItem) + { + // Arrange + var random = Randomizer.CreateRandomizer(); + var arrayToSearch = Enumerable.Range(0, n) + .Select(_ => random.Next(0, 1000)) + .Where(x => x != missingItem) + .OrderBy(x => x).ToArray(); + + // Act + var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, missingItem); + + // Assert + Assert.AreEqual(-1, actualIndex); + } + + [Test] + public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemToSearch) + { + // Arrange + var arrayToSearch = new int[0]; + + // Act + var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, itemToSearch); + + // Assert + Assert.AreEqual(-1, actualIndex); + } + } +} diff --git a/Algorithms/Search/InterpolationSearch.cs b/Algorithms/Search/InterpolationSearch.cs new file mode 100644 index 00000000..baad76ef --- /dev/null +++ b/Algorithms/Search/InterpolationSearch.cs @@ -0,0 +1,52 @@ +namespace Algorithms.Search +{ + /// + /// Class that implements interpolation search algorithm. + /// + public static class InterpolationSearch + { + /// + /// Finds the index of the item searched for in the array. + /// Algorithm performance: + /// worst-case: O(n), + /// average-case: O(log(log(n))), + /// best-case: O(1). + /// + /// Array with sorted elements to be searched in. Cannot be null. + /// Value to be searched for. Cannot be null. + /// If an item is found, return index, else return -1. + public static int FindIndex(int[] sortedArray, int val) + { + var start = 0; + var end = sortedArray.Length - 1; + + while (start <= end && val >= sortedArray[start] && val <= sortedArray[end]) + { + var denominator = (sortedArray[end] - sortedArray[start]) * (val - sortedArray[start]); + + if (denominator == 0) + { + denominator = 1; + } + + var pos = start + (end - start) / denominator; + + if (sortedArray[pos] == val) + { + return pos; + } + + if (sortedArray[pos] < val) + { + start = pos + 1; + } + else + { + end = pos - 1; + } + } + + return -1; + } + } +} diff --git a/README.md b/README.md index 74fa834b..cfc2e8b8 100644 --- a/README.md +++ b/README.md @@ -87,11 +87,13 @@ find more than one implementation for the same objective but using different alg * [Searches](./Algorithms/Search) * [A-Star](./Algorithms/Search/AStar/) * [Binary Search](./Algorithms/Search/BinarySearcher.cs) - * [Recursive Binary Search](./Algorithms/Search/RecursiveBinarySearcher.cs) - * [Linear Search](./Algorithms/Search/LinearSearcher.cs) + * [BoyerMoore Search](./Algorithms/Search/BoyerMoore.cs) * [Fast Search](./Algorithms/Search/FastSearcher.cs) * [Fibonacci Search](./Algorithms/Search/FibonacciSearcher.cs) + * [Interpolation Search](./Algorithms/Search/InterpolationSearch.cs) * [Jump Search](./Algorithms/Search/JumpSearcher.cs) + * [Linear Search](./Algorithms/Search/LinearSearcher.cs) + * [Recursive Binary Search](./Algorithms/Search/RecursiveBinarySearcher.cs) * [Sorts](./Algorithms/Sorters) * [Comparison](./Algorithms/Sorters/Comparison) * [Binary Insertion Sort](./Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs) From 61d7716d156508ec7b42afe53e7083c5a3cddc3d Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Fri, 23 Jun 2023 13:59:51 +0300 Subject: [PATCH 060/138] Fix commit history detection in ci.yml --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4765da54..ee961f95 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Setup .NET SDK uses: actions/setup-dotnet@v3 with: From 2d6a3eed631d4f0134360a01fd5e5c5b30c17518 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Sun, 1 Oct 2023 15:16:12 +0300 Subject: [PATCH 061/138] Replaced Todo's with useful information in Translator.cs (#404) --- Algorithms/DataCompression/Translator.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Algorithms/DataCompression/Translator.cs b/Algorithms/DataCompression/Translator.cs index 480c757c..8372a52b 100644 --- a/Algorithms/DataCompression/Translator.cs +++ b/Algorithms/DataCompression/Translator.cs @@ -4,16 +4,16 @@ namespace Algorithms.DataCompression { /// - /// TODO. + /// Provides method for text conversion by key mapping. /// public class Translator { /// - /// TODO. + /// Converts the input text according to the translation keys. /// - /// TODO. 2. - /// TODO. 3. - /// TODO. 4. + /// Input text. + /// Translation keys used for text matching. + /// Converted text according to the translation keys. public string Translate(string text, Dictionary translationKeys) { var sb = new StringBuilder(); From 5d9c5fe37e97f60aa453edfc828f23b7d926cf0c Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Wed, 4 Oct 2023 22:17:18 +0300 Subject: [PATCH 062/138] Add blowfish algorithm (#405) --- .../Encoders/BlowfishEncoderTests.cs | 44 ++ Algorithms/Encoders/BlowfishEncoder.cs | 393 ++++++++++++++++++ README.md | 1 + 3 files changed, 438 insertions(+) create mode 100644 Algorithms.Tests/Encoders/BlowfishEncoderTests.cs create mode 100644 Algorithms/Encoders/BlowfishEncoder.cs diff --git a/Algorithms.Tests/Encoders/BlowfishEncoderTests.cs b/Algorithms.Tests/Encoders/BlowfishEncoderTests.cs new file mode 100644 index 00000000..3f2087b8 --- /dev/null +++ b/Algorithms.Tests/Encoders/BlowfishEncoderTests.cs @@ -0,0 +1,44 @@ +using Algorithms.Encoders; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Encoders; + +// Tests ported from the Java Algorithms repository + +public class BlowfishEncoderTests +{ + private BlowfishEncoder _encoder = new(); + const string key = "aabb09182736ccdd"; + + [SetUp] + public void Setup() + { + _encoder = new BlowfishEncoder(); + _encoder.GenerateKey(key); + } + + [Test] + public void BlowfishEncoder_Encryption_ShouldWorkCorrectly() + { + const string plainText = "123456abcd132536"; + + const string cipherText = "d748ec383d3405f7"; + + var result = _encoder.Encrypt(plainText); + + result.Should().Be(cipherText); + } + + [Test] + public void BlowfishEncoder_Decryption_ShouldWorkCorrectly() + { + const string cipherText = "d748ec383d3405f7"; + + const string plainText = "123456abcd132536"; + + var result = _encoder.Decrypt(cipherText); + + result.Should().Be(plainText); + } +} diff --git a/Algorithms/Encoders/BlowfishEncoder.cs b/Algorithms/Encoders/BlowfishEncoder.cs new file mode 100644 index 00000000..558542c5 --- /dev/null +++ b/Algorithms/Encoders/BlowfishEncoder.cs @@ -0,0 +1,393 @@ +using System; +using System.Linq; +using System.Text; + +namespace Algorithms.Encoders; + +/// +/// +/// The Blowfish algorithm is a symmetric-key block cipher, which means it uses the same secret key to encrypt and +/// decrypt data. It was designed by Bruce Schneier in 1993. +/// +/// +/// The blowfish algorithm works on 64-bit blocks of data, which are divided into two 32-bit halves: left and right. +/// It uses a variable-length key, from 32 bits to 448 bits, to generate 18 subkeys and four S-boxes, which are arrays +/// of 256 32-bit words. The subkeys and the S-boxes are key-dependent, meaning that they change according to the secret key. +/// +/// +/// The blowfish algorithm performs 16 rounds of encryption or decryption on each block of data, using a Feistel network +/// structure. In each round, the left half is XORed with a subkey, then passed through a function F that applies four +/// S-box lookups and two XOR operations. The output of F is then XORed with the right half. The left and right halves +/// are swapped at the end of each round, except for the last one. The final output is XORed with two more subkeys to +/// produce the encrypted or decrypted block. +/// +/// Blowfish on Wikipedia. +/// +public class BlowfishEncoder +{ + // Initialize modVal to 2^32 + private const ulong ModVal = 4294967296L; + + // Initialize the substitution boxes + private readonly string[][] s = + { + new[] + { + "d1310ba6", "98dfb5ac", "2ffd72db", "d01adfb7", "b8e1afed", "6a267e96", "ba7c9045", "f12c7f99", + "24a19947", "b3916cf7", "0801f2e2", "858efc16", "636920d8", "71574e69", "a458fea3", "f4933d7e", + "0d95748f", "728eb658", "718bcd58", "82154aee", "7b54a41d", "c25a59b5", "9c30d539", "2af26013", + "c5d1b023", "286085f0", "ca417918", "b8db38ef", "8e79dcb0", "603a180e", "6c9e0e8b", "b01e8a3e", + "d71577c1", "bd314b27", "78af2fda", "55605c60", "e65525f3", "aa55ab94", "57489862", "63e81440", + "55ca396a", "2aab10b6", "b4cc5c34", "1141e8ce", "a15486af", "7c72e993", "b3ee1411", "636fbc2a", + "2ba9c55d", "741831f6", "ce5c3e16", "9b87931e", "afd6ba33", "6c24cf5c", "7a325381", "28958677", + "3b8f4898", "6b4bb9af", "c4bfe81b", "66282193", "61d809cc", "fb21a991", "487cac60", "5dec8032", + "ef845d5d", "e98575b1", "dc262302", "eb651b88", "23893e81", "d396acc5", "0f6d6ff3", "83f44239", + "2e0b4482", "a4842004", "69c8f04a", "9e1f9b5e", "21c66842", "f6e96c9a", "670c9c61", "abd388f0", + "6a51a0d2", "d8542f68", "960fa728", "ab5133a3", "6eef0b6c", "137a3be4", "ba3bf050", "7efb2a98", + "a1f1651d", "39af0176", "66ca593e", "82430e88", "8cee8619", "456f9fb4", "7d84a5c3", "3b8b5ebe", + "e06f75d8", "85c12073", "401a449f", "56c16aa6", "4ed3aa62", "363f7706", "1bfedf72", "429b023d", + "37d0d724", "d00a1248", "db0fead3", "49f1c09b", "075372c9", "80991b7b", "25d479d8", "f6e8def7", + "e3fe501a", "b6794c3b", "976ce0bd", "04c006ba", "c1a94fb6", "409f60c4", "5e5c9ec2", "196a2463", + "68fb6faf", "3e6c53b5", "1339b2eb", "3b52ec6f", "6dfc511f", "9b30952c", "cc814544", "af5ebd09", + "bee3d004", "de334afd", "660f2807", "192e4bb3", "c0cba857", "45c8740f", "d20b5f39", "b9d3fbdb", + "5579c0bd", "1a60320a", "d6a100c6", "402c7279", "679f25fe", "fb1fa3cc", "8ea5e9f8", "db3222f8", + "3c7516df", "fd616b15", "2f501ec8", "ad0552ab", "323db5fa", "fd238760", "53317b48", "3e00df82", + "9e5c57bb", "ca6f8ca0", "1a87562e", "df1769db", "d542a8f6", "287effc3", "ac6732c6", "8c4f5573", + "695b27b0", "bbca58c8", "e1ffa35d", "b8f011a0", "10fa3d98", "fd2183b8", "4afcb56c", "2dd1d35b", + "9a53e479", "b6f84565", "d28e49bc", "4bfb9790", "e1ddf2da", "a4cb7e33", "62fb1341", "cee4c6e8", + "ef20cada", "36774c01", "d07e9efe", "2bf11fb4", "95dbda4d", "ae909198", "eaad8e71", "6b93d5a0", + "d08ed1d0", "afc725e0", "8e3c5b2f", "8e7594b7", "8ff6e2fb", "f2122b64", "8888b812", "900df01c", + "4fad5ea0", "688fc31c", "d1cff191", "b3a8c1ad", "2f2f2218", "be0e1777", "ea752dfe", "8b021fa1", + "e5a0cc0f", "b56f74e8", "18acf3d6", "ce89e299", "b4a84fe0", "fd13e0b7", "7cc43b81", "d2ada8d9", + "165fa266", "80957705", "93cc7314", "211a1477", "e6ad2065", "77b5fa86", "c75442f5", "fb9d35cf", + "ebcdaf0c", "7b3e89a0", "d6411bd3", "ae1e7e49", "00250e2d", "2071b35e", "226800bb", "57b8e0af", + "2464369b", "f009b91e", "5563911d", "59dfa6aa", "78c14389", "d95a537f", "207d5ba2", "02e5b9c5", + "83260376", "6295cfa9", "11c81968", "4e734a41", "b3472dca", "7b14a94a", "1b510052", "9a532915", + "d60f573f", "bc9bc6e4", "2b60a476", "81e67400", "08ba6fb5", "571be91f", "f296ec6b", "2a0dd915", + "b6636521", "e7b9f9b6", "ff34052e", "c5855664", "53b02d5d", "a99f8fa1", "08ba4799", "6e85076a", + }, + new[] + { + "4b7a70e9", "b5b32944", "db75092e", "c4192623", "ad6ea6b0", "49a7df7d", "9cee60b8", "8fedb266", + "ecaa8c71", "699a17ff", "5664526c", "c2b19ee1", "193602a5", "75094c29", "a0591340", "e4183a3e", + "3f54989a", "5b429d65", "6b8fe4d6", "99f73fd6", "a1d29c07", "efe830f5", "4d2d38e6", "f0255dc1", + "4cdd2086", "8470eb26", "6382e9c6", "021ecc5e", "09686b3f", "3ebaefc9", "3c971814", "6b6a70a1", + "687f3584", "52a0e286", "b79c5305", "aa500737", "3e07841c", "7fdeae5c", "8e7d44ec", "5716f2b8", + "b03ada37", "f0500c0d", "f01c1f04", "0200b3ff", "ae0cf51a", "3cb574b2", "25837a58", "dc0921bd", + "d19113f9", "7ca92ff6", "94324773", "22f54701", "3ae5e581", "37c2dadc", "c8b57634", "9af3dda7", + "a9446146", "0fd0030e", "ecc8c73e", "a4751e41", "e238cd99", "3bea0e2f", "3280bba1", "183eb331", + "4e548b38", "4f6db908", "6f420d03", "f60a04bf", "2cb81290", "24977c79", "5679b072", "bcaf89af", + "de9a771f", "d9930810", "b38bae12", "dccf3f2e", "5512721f", "2e6b7124", "501adde6", "9f84cd87", + "7a584718", "7408da17", "bc9f9abc", "e94b7d8c", "ec7aec3a", "db851dfa", "63094366", "c464c3d2", + "ef1c1847", "3215d908", "dd433b37", "24c2ba16", "12a14d43", "2a65c451", "50940002", "133ae4dd", + "71dff89e", "10314e55", "81ac77d6", "5f11199b", "043556f1", "d7a3c76b", "3c11183b", "5924a509", + "f28fe6ed", "97f1fbfa", "9ebabf2c", "1e153c6e", "86e34570", "eae96fb1", "860e5e0a", "5a3e2ab3", + "771fe71c", "4e3d06fa", "2965dcb9", "99e71d0f", "803e89d6", "5266c825", "2e4cc978", "9c10b36a", + "c6150eba", "94e2ea78", "a5fc3c53", "1e0a2df4", "f2f74ea7", "361d2b3d", "1939260f", "19c27960", + "5223a708", "f71312b6", "ebadfe6e", "eac31f66", "e3bc4595", "a67bc883", "b17f37d1", "018cff28", + "c332ddef", "be6c5aa5", "65582185", "68ab9802", "eecea50f", "db2f953b", "2aef7dad", "5b6e2f84", + "1521b628", "29076170", "ecdd4775", "619f1510", "13cca830", "eb61bd96", "0334fe1e", "aa0363cf", + "b5735c90", "4c70a239", "d59e9e0b", "cbaade14", "eecc86bc", "60622ca7", "9cab5cab", "b2f3846e", + "648b1eaf", "19bdf0ca", "a02369b9", "655abb50", "40685a32", "3c2ab4b3", "319ee9d5", "c021b8f7", + "9b540b19", "875fa099", "95f7997e", "623d7da8", "f837889a", "97e32d77", "11ed935f", "16681281", + "0e358829", "c7e61fd6", "96dedfa1", "7858ba99", "57f584a5", "1b227263", "9b83c3ff", "1ac24696", + "cdb30aeb", "532e3054", "8fd948e4", "6dbc3128", "58ebf2ef", "34c6ffea", "fe28ed61", "ee7c3c73", + "5d4a14d9", "e864b7e3", "42105d14", "203e13e0", "45eee2b6", "a3aaabea", "db6c4f15", "facb4fd0", + "c742f442", "ef6abbb5", "654f3b1d", "41cd2105", "d81e799e", "86854dc7", "e44b476a", "3d816250", + "cf62a1f2", "5b8d2646", "fc8883a0", "c1c7b6a3", "7f1524c3", "69cb7492", "47848a0b", "5692b285", + "095bbf00", "ad19489d", "1462b174", "23820e00", "58428d2a", "0c55f5ea", "1dadf43e", "233f7061", + "3372f092", "8d937e41", "d65fecf1", "6c223bdb", "7cde3759", "cbee7460", "4085f2a7", "ce77326e", + "a6078084", "19f8509e", "e8efd855", "61d99735", "a969a7aa", "c50c06c2", "5a04abfc", "800bcadc", + "9e447a2e", "c3453484", "fdd56705", "0e1e9ec9", "db73dbd3", "105588cd", "675fda79", "e3674340", + "c5c43465", "713e38d8", "3d28f89e", "f16dff20", "153e21e7", "8fb03d4a", "e6e39f2b", "db83adf7", + }, + new[] + { + "e93d5a68", "948140f7", "f64c261c", "94692934", "411520f7", "7602d4f7", "bcf46b2e", "d4a20068", + "d4082471", "3320f46a", "43b7d4b7", "500061af", "1e39f62e", "97244546", "14214f74", "bf8b8840", + "4d95fc1d", "96b591af", "70f4ddd3", "66a02f45", "bfbc09ec", "03bd9785", "7fac6dd0", "31cb8504", + "96eb27b3", "55fd3941", "da2547e6", "abca0a9a", "28507825", "530429f4", "0a2c86da", "e9b66dfb", + "68dc1462", "d7486900", "680ec0a4", "27a18dee", "4f3ffea2", "e887ad8c", "b58ce006", "7af4d6b6", + "aace1e7c", "d3375fec", "ce78a399", "406b2a42", "20fe9e35", "d9f385b9", "ee39d7ab", "3b124e8b", + "1dc9faf7", "4b6d1856", "26a36631", "eae397b2", "3a6efa74", "dd5b4332", "6841e7f7", "ca7820fb", + "fb0af54e", "d8feb397", "454056ac", "ba489527", "55533a3a", "20838d87", "fe6ba9b7", "d096954b", + "55a867bc", "a1159a58", "cca92963", "99e1db33", "a62a4a56", "3f3125f9", "5ef47e1c", "9029317c", + "fdf8e802", "04272f70", "80bb155c", "05282ce3", "95c11548", "e4c66d22", "48c1133f", "c70f86dc", + "07f9c9ee", "41041f0f", "404779a4", "5d886e17", "325f51eb", "d59bc0d1", "f2bcc18f", "41113564", + "257b7834", "602a9c60", "dff8e8a3", "1f636c1b", "0e12b4c2", "02e1329e", "af664fd1", "cad18115", + "6b2395e0", "333e92e1", "3b240b62", "eebeb922", "85b2a20e", "e6ba0d99", "de720c8c", "2da2f728", + "d0127845", "95b794fd", "647d0862", "e7ccf5f0", "5449a36f", "877d48fa", "c39dfd27", "f33e8d1e", + "0a476341", "992eff74", "3a6f6eab", "f4f8fd37", "a812dc60", "a1ebddf8", "991be14c", "db6e6b0d", + "c67b5510", "6d672c37", "2765d43b", "dcd0e804", "f1290dc7", "cc00ffa3", "b5390f92", "690fed0b", + "667b9ffb", "cedb7d9c", "a091cf0b", "d9155ea3", "bb132f88", "515bad24", "7b9479bf", "763bd6eb", + "37392eb3", "cc115979", "8026e297", "f42e312d", "6842ada7", "c66a2b3b", "12754ccc", "782ef11c", + "6a124237", "b79251e7", "06a1bbe6", "4bfb6350", "1a6b1018", "11caedfa", "3d25bdd8", "e2e1c3c9", + "44421659", "0a121386", "d90cec6e", "d5abea2a", "64af674e", "da86a85f", "bebfe988", "64e4c3fe", + "9dbc8057", "f0f7c086", "60787bf8", "6003604d", "d1fd8346", "f6381fb0", "7745ae04", "d736fccc", + "83426b33", "f01eab71", "b0804187", "3c005e5f", "77a057be", "bde8ae24", "55464299", "bf582e61", + "4e58f48f", "f2ddfda2", "f474ef38", "8789bdc2", "5366f9c3", "c8b38e74", "b475f255", "46fcd9b9", + "7aeb2661", "8b1ddf84", "846a0e79", "915f95e2", "466e598e", "20b45770", "8cd55591", "c902de4c", + "b90bace1", "bb8205d0", "11a86248", "7574a99e", "b77f19b6", "e0a9dc09", "662d09a1", "c4324633", + "e85a1f02", "09f0be8c", "4a99a025", "1d6efe10", "1ab93d1d", "0ba5a4df", "a186f20f", "2868f169", + "dcb7da83", "573906fe", "a1e2ce9b", "4fcd7f52", "50115e01", "a70683fa", "a002b5c4", "0de6d027", + "9af88c27", "773f8641", "c3604c06", "61a806b5", "f0177a28", "c0f586e0", "006058aa", "30dc7d62", + "11e69ed7", "2338ea63", "53c2dd94", "c2c21634", "bbcbee56", "90bcb6de", "ebfc7da1", "ce591d76", + "6f05e409", "4b7c0188", "39720a3d", "7c927c24", "86e3725f", "724d9db9", "1ac15bb4", "d39eb8fc", + "ed545578", "08fca5b5", "d83d7cd3", "4dad0fc4", "1e50ef5e", "b161e6f8", "a28514d9", "6c51133c", + "6fd5c7e7", "56e14ec4", "362abfce", "ddc6c837", "d79a3234", "92638212", "670efa8e", "406000e0", + }, + new[] + { + "3a39ce37", "d3faf5cf", "abc27737", "5ac52d1b", "5cb0679e", "4fa33742", "d3822740", "99bc9bbe", + "d5118e9d", "bf0f7315", "d62d1c7e", "c700c47b", "b78c1b6b", "21a19045", "b26eb1be", "6a366eb4", + "5748ab2f", "bc946e79", "c6a376d2", "6549c2c8", "530ff8ee", "468dde7d", "d5730a1d", "4cd04dc6", + "2939bbdb", "a9ba4650", "ac9526e8", "be5ee304", "a1fad5f0", "6a2d519a", "63ef8ce2", "9a86ee22", + "c089c2b8", "43242ef6", "a51e03aa", "9cf2d0a4", "83c061ba", "9be96a4d", "8fe51550", "ba645bd6", + "2826a2f9", "a73a3ae1", "4ba99586", "ef5562e9", "c72fefd3", "f752f7da", "3f046f69", "77fa0a59", + "80e4a915", "87b08601", "9b09e6ad", "3b3ee593", "e990fd5a", "9e34d797", "2cf0b7d9", "022b8b51", + "96d5ac3a", "017da67d", "d1cf3ed6", "7c7d2d28", "1f9f25cf", "adf2b89b", "5ad6b472", "5a88f54c", + "e029ac71", "e019a5e6", "47b0acfd", "ed93fa9b", "e8d3c48d", "283b57cc", "f8d56629", "79132e28", + "785f0191", "ed756055", "f7960e44", "e3d35e8c", "15056dd4", "88f46dba", "03a16125", "0564f0bd", + "c3eb9e15", "3c9057a2", "97271aec", "a93a072a", "1b3f6d9b", "1e6321f5", "f59c66fb", "26dcf319", + "7533d928", "b155fdf5", "03563482", "8aba3cbb", "28517711", "c20ad9f8", "abcc5167", "ccad925f", + "4de81751", "3830dc8e", "379d5862", "9320f991", "ea7a90c2", "fb3e7bce", "5121ce64", "774fbe32", + "a8b6e37e", "c3293d46", "48de5369", "6413e680", "a2ae0810", "dd6db224", "69852dfd", "09072166", + "b39a460a", "6445c0dd", "586cdecf", "1c20c8ae", "5bbef7dd", "1b588d40", "ccd2017f", "6bb4e3bb", + "dda26a7e", "3a59ff45", "3e350a44", "bcb4cdd5", "72eacea8", "fa6484bb", "8d6612ae", "bf3c6f47", + "d29be463", "542f5d9e", "aec2771b", "f64e6370", "740e0d8d", "e75b1357", "f8721671", "af537d5d", + "4040cb08", "4eb4e2cc", "34d2466a", "0115af84", "e1b00428", "95983a1d", "06b89fb4", "ce6ea048", + "6f3f3b82", "3520ab82", "011a1d4b", "277227f8", "611560b1", "e7933fdc", "bb3a792b", "344525bd", + "a08839e1", "51ce794b", "2f32c9b7", "a01fbac9", "e01cc87e", "bcc7d1f6", "cf0111c3", "a1e8aac7", + "1a908749", "d44fbd9a", "d0dadecb", "d50ada38", "0339c32a", "c6913667", "8df9317c", "e0b12b4f", + "f79e59b7", "43f5bb3a", "f2d519ff", "27d9459c", "bf97222c", "15e6fc2a", "0f91fc71", "9b941525", + "fae59361", "ceb69ceb", "c2a86459", "12baa8d1", "b6c1075e", "e3056a0c", "10d25065", "cb03a442", + "e0ec6e0e", "1698db3b", "4c98a0be", "3278e964", "9f1f9532", "e0d392df", "d3a0342b", "8971f21e", + "1b0a7441", "4ba3348c", "c5be7120", "c37632d8", "df359f8d", "9b992f2e", "e60b6f47", "0fe3f11d", + "e54cda54", "1edad891", "ce6279cf", "cd3e7e6f", "1618b166", "fd2c1d05", "848fd2c5", "f6fb2299", + "f523f357", "a6327623", "93a83531", "56cccd02", "acf08162", "5a75ebb5", "6e163697", "88d273cc", + "de966292", "81b949d0", "4c50901b", "71c65614", "e6c6c7bd", "327a140a", "45e1d006", "c3f27b9a", + "c9aa53fd", "62a80f00", "bb25bfe2", "35bdd2f6", "71126905", "b2040222", "b6cbcf7c", "cd769c2b", + "53113ec0", "1640e3d3", "38abbd60", "2547adf0", "ba38209c", "f746ce76", "77afa1c5", "20756060", + "85cbfe4e", "8ae88dd8", "7aaaf9b0", "4cf9aa7e", "1948c25c", "02fb8a8c", "01c36ae4", "d6ebe1f9", + "90d4f869", "a65cdea0", "3f09252d", "c208e69f", "b74e6132", "ce77e25b", "578fdfe3", "3ac372e6", + }, + }; + + // Initialize the P-array sub-keys + private readonly string[] p = + { + "243f6a88", "85a308d3", "13198a2e", "03707344", "a4093822", "299f31d0", "082efa98", "ec4e6c89", "452821e6", + "38d01377", "be5466cf", "34e90c6c", "c0ac29b7", "c97c50dd", "3f84d5b5", "b5470917", "9216d5d9", "8979fb1b", + }; + + /// + /// Generate a key for the encryption algorithm based on the given string parameter. + /// + /// The key to generate the subkey from. + public void GenerateKey(string key) + { + var j = 0; + for (var i = 0; i < p.Length; i++) + { + // Perform the key expansion + var subKey = key.Substring(j % key.Length, 8); + p[i] = Xor(p[i], subKey); + + j += 8; + } + } + + /// + /// Encrypts a string using the blowfish algorithm. + /// + /// The string to be encrypted, represented as a hexadecimal string. + /// The encrypted string, represented as a hexadecimal string. + public string Encrypt(string plainText) + { + // Perform the 16 rounds of the blowfish algorithm on the plainText. + for (var i = 0; i < 16; i++) + { + plainText = Round(i, plainText); + } + + // Swap the left and right parts of the plainText. + var left = plainText.Substring(8, 8); + var right = plainText[..8]; + + // XOR the left half with the last subkey of the P-array. + left = Xor(left, p[17]); + + // XOR the right half with the second to last subkey from the P-array. + right = Xor(right, p[16]); + + // Return the encrypted string as a concatenated string. + return left + right; + } + + /// + /// Decrypts a string using the blowfish algorithm. + /// + /// The string to be decrypted, represented as a hexadecimal string. + /// The decrypted string, represented as a hexadecimal string. + public string Decrypt(string cipherText) + { + // Perform 16 rounds of the blowfish algorithm on the cipherText in reverse order. + for (var i = 17; i > 1; i--) + { + cipherText = Round(i, cipherText); + } + + // Swap the left and right halves of the cipherText. + var left = cipherText.Substring(8, 8); + var right = cipherText.Substring(0, 8); + + // XOR the left half with the first subkey from the P-array. + left = Xor(left, p[0]); + + // XOR the right half with the second subkey from the P-array. + right = Xor(right, p[1]); + + // Return the decrypted string as a concatenated string. + return left + right; + } + + /// + /// Converts a hexadecimal string to a binary string. + /// + /// The hexadecimal string to convert. + /// A multiple of 4 binary string representing the hexadecimal input. + private string HexadecimalToBinary(string hex) + { + return hex.Select(t => + + // Convert each character to an integer using base 16 + Convert.ToString(Convert.ToInt32(t.ToString(), 16), 2)) + + // Pad each binary string with leading zeros to make it 4 bits long + .Select(fourBitBinary => fourBitBinary.PadLeft(4, '0')) + + // Concatenate all the binary strings into one + .Aggregate(string.Empty, (current, fourBitBinary) => current + fourBitBinary); + } + + /// + /// Converts a binary string to a hexadecimal string. + /// + /// The multiple of 4 binary string to convert. + /// A hexadecimal string representing the binary input. + private string BinaryToHexadecimal(string binaryInput) + { + return string.Concat( + Enumerable.Range(0, binaryInput.Length / 4) + + // Select each group of 4 bits + .Select(index => binaryInput.Substring(index * 4, 4)) + + // Convert each group to an integer using base 2 + .Select(fourBitBinary => Convert.ToInt32(fourBitBinary, 2) + + // Convert each integer to a hexadecimal character using base 16 + .ToString("x"))); + } + + /// + /// Performs a bitwise XOR operation on two hexadecimal strings and returns the result. + /// + /// The first hexadecimal string to XOR. + /// The second hexadecimal string to XOR. + /// A hexadecimal string representing the XOR of the inputs. + private string Xor(string left, string right) + { + // Convert the hexadecimal strings to binary strings using a helper method + left = HexadecimalToBinary(left); + right = HexadecimalToBinary(right); + + var xor = new StringBuilder(); + + // Loop through each bit in the binary strings + for (var i = 0; i < left.Length; i++) + { + // Perform a bitwise XOR operation on the corresponding bits and append the result to xor + xor.Append((char)(((left[i] - '0') ^ (right[i] - '0')) + '0')); + } + + // Convert the binary string to a hexadecimal string + var result = BinaryToHexadecimal(xor.ToString()); + return result; + } + + /// + /// Adds two hexadecimal strings and returns the result modulo _modVal. + /// + /// The first hexadecimal string to add. + /// The second hexadecimal string to add. + /// A hexadecimal string representing the sum of the inputs modulo _modVal. + private string AddAndMod(string left, string right) + { + // Convert the hexadecimal strings to unsigned 64-bit integers using base 16 + var leftNumber = Convert.ToUInt64(left, 16); + var rightNumber = Convert.ToUInt64(right, 16); + + // Add the two integers and calculate the remainder after dividing by _modVal + var total = (leftNumber + rightNumber) % ModVal; + + // Convert the result to a hexadecimal string using base 16 + var result = total.ToString("x"); + + // Pad the result with leading zeros to make it 8 characters long + result = "00000000" + result; + + // Return the last 8 characters of the result + return result[^8..]; + } + + /// + /// Performs the F function on a 32-bit input and returns a 32-bit output. + /// + /// The 32-bit hexadecimal input to the F function. + /// The 32-bit hexadecimal output of the F function. + /// + /// The F function is a non-linear function that operates on a 32-bit input and produces a 32-bit output. It is used + /// to generate the sub-keys and to perform the encryption and decryption of the data blocks. + /// + private string F(string plainText) + { + var a = new string[4]; + + for (var i = 0; i < 8; i += 2) + { + var col = Convert.ToUInt64(HexadecimalToBinary(plainText.Substring(i, 2)), 2); + a[i / 2] = s[i / 2][col]; + } + + var answer = AddAndMod(a[0], a[1]); + answer = Xor(answer, a[2]); + answer = AddAndMod(answer, a[3]); + return answer; + } + + /// + /// Performs one round of the blowfish encryption on a 64-bit block of data. + /// + /// The round number, from 0 to 15, indicating which subkey from the P-array to use. + /// The 64-bit block of data to be encrypted or decrypted, represented as a hexadecimal string. + /// The encrypted or decrypted block of data, represented as a hexadecimal string. + private string Round(int feistelRound, string plainText) + { + // Split the plainText into two 32-bit halves. + var left = plainText[..8]; + var right = plainText.Substring(8, 8); + + // XOR the left half with the subkey from the P-array. + left = Xor(left, p[feistelRound]); + + // Apply the F function to the left half. + var fOutput = F(left); + + // XOR the output of the F function with the right half. + right = Xor(fOutput, right); + + // Swap the left and right halves and return them as a concatenated string. + return right + left; + } +} diff --git a/README.md b/README.md index cfc2e8b8..81f73366 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ find more than one implementation for the same objective but using different alg * [NYSIIS](./Algorithms/Encoders/NysiisEncoder.cs) * [Soundex](./Algorithms/Encoders/SoundexEncoder.cs) * [Feistel](./Algorithms/Encoders/FeistelCipher.cs) + * [Blowfish](./Algorithms/Encoders/BlowfishEncoder.cs) * [Graph](./Algorithms/Graph) * [Minimum Spanning Tree](./Algorithms/Graph/MinimumSpanningTree) * [Prim's Algorithm (Adjacency Matrix)](./Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs) From 38a092212e10df7866f29acf44643645852d0a10 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Fri, 6 Oct 2023 20:01:39 +0300 Subject: [PATCH 063/138] Add pkcs7 padding (#406) --- .../Crypto/Padding/PKCS7PaddingTests.cs | 177 ++++++++++++++++++ Algorithms/Crypto/Paddings/PKCS7Padding.cs | 177 ++++++++++++++++++ README.md | 3 + 3 files changed, 357 insertions(+) create mode 100644 Algorithms.Tests/Crypto/Padding/PKCS7PaddingTests.cs create mode 100644 Algorithms/Crypto/Paddings/PKCS7Padding.cs diff --git a/Algorithms.Tests/Crypto/Padding/PKCS7PaddingTests.cs b/Algorithms.Tests/Crypto/Padding/PKCS7PaddingTests.cs new file mode 100644 index 00000000..46769c60 --- /dev/null +++ b/Algorithms.Tests/Crypto/Padding/PKCS7PaddingTests.cs @@ -0,0 +1,177 @@ +using System; +using Algorithms.Crypto.Paddings; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Crypto.Padding; + +public class PKCS7PaddingTests +{ + private const int defaultBlockSize = 16; + + [Test] + public void Constructor_WhenBlockSizeIsLessThanOne_ShouldThrowArgumentOutOfRangeException() + { + const int blockSize = 0; + + Action act = () => new Pkcs7Padding(blockSize); + + act.Should().Throw() + .WithMessage("Invalid block size: 0 (Parameter 'blockSize')"); + } + + [Test] + public void Constructor_WhenBlockSizeIsMoreThan255_ShouldThrowArgumentOutOfRangeException() + { + const int blockSize = 256; + + Action act = () => new Pkcs7Padding(blockSize); + + act.Should().Throw() + .WithMessage("Invalid block size: 256 (Parameter 'blockSize')"); + } + + [Test] + public void Constructor_WhenBlockSizeIsWithinValidRange_ShouldNotThrowAFit() + { + const int blockSize = 128; + + Action act = () => new Pkcs7Padding(blockSize); + + act.Should().NotThrow(); + } + + [Test] + public void AddPadding_WhenNotEnoughSpaceInInputArrayForPadding_ShouldThrowArgumentException() + { + var padding = new Pkcs7Padding(defaultBlockSize); + const int inputOffset = 1; + + var size16Input = new byte[16]; + + Action act = () => padding.AddPadding(size16Input, inputOffset); + + act.Should().Throw() + .WithMessage("Not enough space in input array for padding"); + } + + [Test] + public void AddPadding_WhenInputArrayHasEnoughSpace_ShouldReturnCorrectPaddingSize() + { + var padding = new Pkcs7Padding(defaultBlockSize); + const int inputOffset = defaultBlockSize; + + var size32Input = new byte[32]; + + var result = padding.AddPadding(size32Input, inputOffset); + + result.Should().Be(defaultBlockSize); + } + + [Test] + public void AddPadding_WhenAppliedToAnInputArray_ShouldAddCorrectPKCS7Padding() + { + var padding = new Pkcs7Padding(defaultBlockSize); + const int inputOffset = defaultBlockSize; + + var size32Input = new byte[32]; + + padding.AddPadding(size32Input, inputOffset); + + for (var i = 0; i < defaultBlockSize - 1; i++) + { + size32Input[inputOffset + i].Should().Be(defaultBlockSize); + } + } + + [Test] + public void RemovePadding_WhenAppliedToAValidInputArray_ShouldRemovePKCS7PaddingCorrectly() + { + var paddingSize = 5; + var size32Input = new byte[32]; + for (var i = 0; i < paddingSize; i++) + { + size32Input[size32Input.Length - 1 - i] = (byte)paddingSize; + } + + var padding = new Pkcs7Padding(defaultBlockSize); + + var output = padding.RemovePadding(size32Input); + + output.Length.Should().Be(size32Input.Length - paddingSize); + } + + [Test] + public void RemovePadding_WhenInputLengthNotMultipleOfBlockSize_ShouldThrowArgumentException() + { + var input = new byte[defaultBlockSize + 1]; // Length is not a multiple of blockSize + var padding = new Pkcs7Padding(defaultBlockSize); + + Action act = () => padding.RemovePadding(input); + + act.Should().Throw() + .WithMessage("Input length must be a multiple of block size"); + } + + [Test] + public void RemovePadding_WhenInvalidPaddingLength_ShouldThrowArgumentException() + { + var size32Input = new byte[32]; + + size32Input[^1] = (byte)(defaultBlockSize + 1); // Set invalid padding length + var padding = new Pkcs7Padding(defaultBlockSize); + + Action act = () => padding.RemovePadding(size32Input); + + act.Should().Throw().WithMessage("Invalid padding length"); + } + + [Test] + public void RemovePadding_WhenInvalidPadding_ShouldThrowArgumentException() + { + var size32Input = new byte[32]; + + size32Input[^1] = (byte)(defaultBlockSize); // Set valid padding length + size32Input[^2] = (byte)(defaultBlockSize - 1); // Set invalid padding byte + var padding = new Pkcs7Padding(defaultBlockSize); + + Action act = () => padding.RemovePadding(size32Input); + + act.Should().Throw() + .WithMessage("Invalid padding"); + } + + [Test] + public void GetPaddingCount_WhenInputArrayIsValid_ShouldReturnCorrectPaddingCount() + { + var paddingSize = 5; + var size32Input = new byte[32]; + + for (var i = 0; i < paddingSize; i++) + { + size32Input[size32Input.Length - 1 - i] = (byte)paddingSize; // Add padding bytes at the end of the array + } + + var padding = new Pkcs7Padding(defaultBlockSize); + + var output = padding.GetPaddingCount(size32Input); + + output.Should().Be(paddingSize); + } + + [Test] + public void GetPaddingCount_WhenInvalidPadding_ShouldThrowArgumentException() + { + var size32Input = new byte[32]; + + size32Input[^1] = defaultBlockSize; + size32Input[^2] = defaultBlockSize - 1; + + var padding = new Pkcs7Padding(defaultBlockSize); + + Action act = () => padding.GetPaddingCount(size32Input); + + act.Should().Throw() + .WithMessage("Padding block is corrupted"); + } +} diff --git a/Algorithms/Crypto/Paddings/PKCS7Padding.cs b/Algorithms/Crypto/Paddings/PKCS7Padding.cs new file mode 100644 index 00000000..114cdd4d --- /dev/null +++ b/Algorithms/Crypto/Paddings/PKCS7Padding.cs @@ -0,0 +1,177 @@ +using System; + +namespace Algorithms.Crypto.Paddings; + +/// +/// +/// This class implements the PKCS7 padding scheme, which is a standard way of padding data to fit a certain block size. +/// +/// +/// PKCS7 padding adds N bytes of value N to the end of the data, where N is the number of bytes needed to reach the block size. +/// For example, if the block size is 16 bytes, and the data is 11 bytes long, then 5 bytes of value 5 will be added to the +/// end of the data. This way, the padded data will be 16 bytes long and can be encrypted or decrypted by a block cipher algorithm. +/// +/// +/// The padding can be easily removed after decryption by looking at the last byte and subtracting that many bytes from the +/// end of the data. +/// +/// +/// This class supports any block size from 1 to 255 bytes, and can be used with any encryption algorithm that requires +/// padding, such as AES. +/// +/// +public class Pkcs7Padding +{ + private readonly int blockSize; + + public Pkcs7Padding(int blockSize) + { + if (blockSize is < 1 or > 255) + { + throw new ArgumentOutOfRangeException(nameof(blockSize), $"Invalid block size: {blockSize}"); + } + + this.blockSize = blockSize; + } + + /// + /// Adds padding to the end of a byte array according to the PKCS#7 standard. + /// + /// The byte array to be padded. + /// The offset from which to start padding. + /// The padding value that was added to each byte. + /// + /// If the input array does not have enough space to add blockSize bytes as padding. + /// + /// + /// The padding value is equal to the number of of bytes that are added to the array. + /// For example, if the input array has a length of 16 and the input offset is 10, + /// then 6 bytes with the value 6 will be added to the end of the array. + /// + public int AddPadding(byte[] input, int inputOffset) + { + // Calculate how many bytes need to be added to reach the next multiple of block size. + var code = (byte)((blockSize - (input.Length % blockSize)) % blockSize); + + // If no padding is needed, add a full block of padding. + if (code == 0) + { + code = (byte)blockSize; + } + + if (inputOffset + code > input.Length) + { + throw new ArgumentException("Not enough space in input array for padding"); + } + + // Add the padding + for (var i = 0; i < code; i++) + { + input[inputOffset + i] = code; + } + + return code; + } + + /// + /// Removes the PKCS7 padding from the given input data. + /// + /// The input data with PKCS7 padding. Must not be null and must have a vaild length and padding. + /// The input data without the padding as a new byte array. + /// + /// Thrown if the input data is null, has an invalid length, or has an invalid padding. + /// + public byte[] RemovePadding(byte[] input) + { + // Check if input length is a multiple of blockSize + if (input.Length % blockSize != 0) + { + throw new ArgumentException("Input length must be a multiple of block size"); + } + + // Get the padding length from the last byte of input + var paddingLength = input[^1]; + + // Check if padding length is valid + if (paddingLength < 1 || paddingLength > blockSize) + { + throw new ArgumentException("Invalid padding length"); + } + + // Check if all padding bytes have the correct value + for (var i = 0; i < paddingLength; i++) + { + if (input[input.Length - 1 - i] != paddingLength) + { + throw new ArgumentException("Invalid padding"); + } + } + + // Create a new array with the size of input minus the padding length + var output = new byte[input.Length - paddingLength]; + + // Copy the data without the padding into the output array + Array.Copy(input, output, output.Length); + + return output; + } + + /// + /// Gets the number of padding bytes in the given input data according to the PKCS7 padding scheme. + /// + /// The input data with PKCS7 padding. Must not be null and must have a valid padding. + /// The number of padding bytes in the input data. + /// + /// Thrown if the input data is null or has an invalid padding. + /// + /// + /// This method uses bitwise operations to avoid branching. + /// + public int GetPaddingCount(byte[] input) + { + if (input == null) + { + throw new ArgumentNullException(nameof(input), "Input cannot be null"); + } + + // Get the last byte of the input data as the padding value. + var lastByte = input[^1]; + var paddingCount = lastByte & 0xFF; + + // Calculate the index where the padding starts + var paddingStartIndex = input.Length - paddingCount; + var paddingCheckFailed = 0; + + // Check if the padding start index is negative or greater than the input length. + // This is done by using bitwise operations to avoid branching. + // If the padding start index is negative, then its most significant bit will be 1. + // If the padding count is greater than the block size, then its most significant bit will be 1. + // By ORing these two cases, we can get a non-zero value rif either of them is true. + // By shifting this value right by 31 bits, we can get either 0 or -1 as the result. + paddingCheckFailed = (paddingStartIndex | (paddingCount - 1)) >> 31; + + for (var i = 0; i < input.Length; i++) + { + // Check if each byte matches the padding value. + // This is done by using bitwise operations to avoid branching. + // If a byte does not match the padding value, then XORing them will give a non-zero value. + // If a byte is before the padding start index, then we want to ignore it. + // This is done by using bitwise operations to create a mask that is either all zeros or all ones. + // If i is less than the padding start index, then subtracting them will give a negative value. + // By shifting this value right by 31 bits, we can get either -1 or 0 as the mask. + // By negating this mask, we can get either 0 or -1 as the mask. + // By ANDing this mask with the XOR result, we can get either 0 or the XOR result as the final result. + // By ORing this final result with the previous padding check result, we can accumulate any non-zero values. + paddingCheckFailed |= (input[i] ^ lastByte) & ~((i - paddingStartIndex) >> 31); + } + + // Check if the padding check failed. + if (paddingCheckFailed != 0) + { + throw new ArgumentException("Padding block is corrupted"); + } + + // Return the number of padding bytes. + return paddingCount; + } +} diff --git a/README.md b/README.md index 81f73366..4fc577ba 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ find more than one implementation for the same objective but using different alg ## List of Algorithms * [Algorithms](./Algorithms) + * [Crypto](./Algorithms/Crypto/) + * [Paddings](./Algorithms/Crypto/Paddings/) + * [PKC7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) * [Data Compression](./Algorithms/DataCompression) * [Burrows-Wheeler transform](./Algorithms/DataCompression/BurrowsWheelerTransform.cs) * [Huffman Compressor](./Algorithms/DataCompression/HuffmanCompressor.cs) From e5cd1f5435807c025b03e034c9332d1a6e82dc5b Mon Sep 17 00:00:00 2001 From: Sid Chalke Date: Sat, 7 Oct 2023 13:26:21 -0400 Subject: [PATCH 064/138] Reorganize Dynamic Programming Problems (fixes #398) (#403) --- .../CoinChange}/GenerateChangesDictionaryTests.cs | 4 ++-- .../CoinChange}/GenerateSingleCoinChangesTests.cs | 4 ++-- .../CoinChange}/GetMinimalNextCoinTests.cs | 4 ++-- .../CoinChange}/MakeCoinChangeDynamicTests.cs | 4 ++-- .../LevenshteinDistance}/LevenshteinDistanceTests.cs | 4 ++-- .../CoinChange/DynamicCoinChangeSolver.cs | 2 +- .../LevenshteinDistance}/LevenshteinDistance.cs | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) rename Algorithms.Tests/Problems/{CoinChange/Dynamic => DynamicProgramming/CoinChange}/GenerateChangesDictionaryTests.cs (88%) rename Algorithms.Tests/Problems/{CoinChange/Dynamic => DynamicProgramming/CoinChange}/GenerateSingleCoinChangesTests.cs (96%) rename Algorithms.Tests/Problems/{CoinChange/Dynamic => DynamicProgramming/CoinChange}/GetMinimalNextCoinTests.cs (79%) rename Algorithms.Tests/Problems/{CoinChange/Dynamic => DynamicProgramming/CoinChange}/MakeCoinChangeDynamicTests.cs (88%) rename Algorithms.Tests/{Strings => Problems/DynamicProgramming/LevenshteinDistance}/LevenshteinDistanceTests.cs (86%) rename Algorithms/Problems/{ => DynamicProgramming}/CoinChange/DynamicCoinChangeSolver.cs (98%) rename Algorithms/{Strings => Problems/DynamicProgramming/LevenshteinDistance}/LevenshteinDistance.cs (97%) diff --git a/Algorithms.Tests/Problems/CoinChange/Dynamic/GenerateChangesDictionaryTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateChangesDictionaryTests.cs similarity index 88% rename from Algorithms.Tests/Problems/CoinChange/Dynamic/GenerateChangesDictionaryTests.cs rename to Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateChangesDictionaryTests.cs index 1bc19f70..78ff100c 100644 --- a/Algorithms.Tests/Problems/CoinChange/Dynamic/GenerateChangesDictionaryTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateChangesDictionaryTests.cs @@ -1,9 +1,9 @@ using System.Linq; -using Algorithms.Problems.CoinChange; +using Algorithms.Problems.DynamicProgramming.CoinChange; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Problems.CoinChange.Dynamic +namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange { [TestFixture] public class GenerateChangesDictionaryTests diff --git a/Algorithms.Tests/Problems/CoinChange/Dynamic/GenerateSingleCoinChangesTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateSingleCoinChangesTests.cs similarity index 96% rename from Algorithms.Tests/Problems/CoinChange/Dynamic/GenerateSingleCoinChangesTests.cs rename to Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateSingleCoinChangesTests.cs index c49838cc..e530e520 100644 --- a/Algorithms.Tests/Problems/CoinChange/Dynamic/GenerateSingleCoinChangesTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateSingleCoinChangesTests.cs @@ -1,10 +1,10 @@ using System; using System.Linq; -using Algorithms.Problems.CoinChange; +using Algorithms.Problems.DynamicProgramming.CoinChange; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Problems.CoinChange.Dynamic +namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange { [TestFixture] public class GenerateSingleCoinChangesTests diff --git a/Algorithms.Tests/Problems/CoinChange/Dynamic/GetMinimalNextCoinTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GetMinimalNextCoinTests.cs similarity index 79% rename from Algorithms.Tests/Problems/CoinChange/Dynamic/GetMinimalNextCoinTests.cs rename to Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GetMinimalNextCoinTests.cs index 26e37e98..ac4b5fb6 100644 --- a/Algorithms.Tests/Problems/CoinChange/Dynamic/GetMinimalNextCoinTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GetMinimalNextCoinTests.cs @@ -1,8 +1,8 @@ -using Algorithms.Problems.CoinChange; +using Algorithms.Problems.DynamicProgramming.CoinChange; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Problems.CoinChange.Dynamic +namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange { public class GetMinimalNextCoinTests { diff --git a/Algorithms.Tests/Problems/CoinChange/Dynamic/MakeCoinChangeDynamicTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/MakeCoinChangeDynamicTests.cs similarity index 88% rename from Algorithms.Tests/Problems/CoinChange/Dynamic/MakeCoinChangeDynamicTests.cs rename to Algorithms.Tests/Problems/DynamicProgramming/CoinChange/MakeCoinChangeDynamicTests.cs index 7ee5b6b1..11520867 100644 --- a/Algorithms.Tests/Problems/CoinChange/Dynamic/MakeCoinChangeDynamicTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/MakeCoinChangeDynamicTests.cs @@ -1,9 +1,9 @@ using System.Linq; -using Algorithms.Problems.CoinChange; +using Algorithms.Problems.DynamicProgramming.CoinChange; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Problems.CoinChange.Dynamic +namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange { [TestFixture] public class MakeCoinChangeDynamicTests diff --git a/Algorithms.Tests/Strings/LevenshteinDistanceTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs similarity index 86% rename from Algorithms.Tests/Strings/LevenshteinDistanceTests.cs rename to Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs index 3822c566..b2ad0298 100644 --- a/Algorithms.Tests/Strings/LevenshteinDistanceTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs @@ -1,7 +1,7 @@ -using Algorithms.Strings; using NUnit.Framework; +using Algorithms.Problems.DynamicProgramming; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.DynamicProgramming { public class LevenshteinDistanceTests { diff --git a/Algorithms/Problems/CoinChange/DynamicCoinChangeSolver.cs b/Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs similarity index 98% rename from Algorithms/Problems/CoinChange/DynamicCoinChangeSolver.cs rename to Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs index 8a81f119..e05f4593 100644 --- a/Algorithms/Problems/CoinChange/DynamicCoinChangeSolver.cs +++ b/Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; -namespace Algorithms.Problems.CoinChange +namespace Algorithms.Problems.DynamicProgramming.CoinChange { public static class DynamicCoinChangeSolver { diff --git a/Algorithms/Strings/LevenshteinDistance.cs b/Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs similarity index 97% rename from Algorithms/Strings/LevenshteinDistance.cs rename to Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs index e7af537e..30a33846 100644 --- a/Algorithms/Strings/LevenshteinDistance.cs +++ b/Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs @@ -1,6 +1,6 @@ using System; -namespace Algorithms.Strings +namespace Algorithms.Problems.DynamicProgramming { /// /// From daee450fe8f2bdf980509c15c36326ddf2017754 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Sun, 8 Oct 2023 11:07:46 +0300 Subject: [PATCH 065/138] Add iso7816d4 padding (#409) --- .../Crypto/Paddings/Iso7816D4PaddingTests.cs | 169 ++++++++++++++++++ .../Crypto/Paddings/Iso7816D4Padding.cs | 154 ++++++++++++++++ README.md | 1 + 3 files changed, 324 insertions(+) create mode 100644 Algorithms.Tests/Crypto/Paddings/Iso7816D4PaddingTests.cs create mode 100644 Algorithms/Crypto/Paddings/Iso7816D4Padding.cs diff --git a/Algorithms.Tests/Crypto/Paddings/Iso7816D4PaddingTests.cs b/Algorithms.Tests/Crypto/Paddings/Iso7816D4PaddingTests.cs new file mode 100644 index 00000000..9e0e99ac --- /dev/null +++ b/Algorithms.Tests/Crypto/Paddings/Iso7816D4PaddingTests.cs @@ -0,0 +1,169 @@ +using System; +using System.Linq; +using Algorithms.Crypto.Paddings; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Crypto.Paddings; + +public class Iso7816D4PaddingTests +{ + private readonly Iso7816D4Padding padding = new Iso7816D4Padding(); + + [Test] + public void AddPadding_WhenCalledWithValidInput_ShouldReturnCorrectPadding() + { + var inputData = new byte[10]; + var inputOffset = 5; + + var result = padding.AddPadding(inputData, inputOffset); + + result.Should().Be(5); + inputData[5].Should().Be(80); + inputData.Skip(6).Should().AllBeEquivalentTo(0); + } + + [Test] + public void AddPadding_WhenCalledWithInvalidInput_ShouldThrowArgumentException() + { + var inputData = new byte[10]; + var inputOffset = 11; + + Action act = () => padding.AddPadding(inputData, inputOffset); + + act.Should().Throw() + .WithMessage("not enough space in input array for padding"); + } + + [Test] + public void AddPadding_WhenCalledWithZeroOffset_ShouldReturnCorrectPadding() + { + var inputData = new byte[10]; + var inputOffset = 0; + + var result = padding.AddPadding(inputData, inputOffset); + + result.Should().Be(10); + inputData[0].Should().Be(80); + inputData.Skip(1).Should().AllBeEquivalentTo(0); + } + + [Test] + public void AddPadding_WhenCalledWithOffsetEqualToLength_ShouldThrowArgumentException() + { + var inputData = new byte[10]; + var inputOffset = 10; + + Action act = () => padding.AddPadding(inputData, inputOffset); + + act.Should().Throw() + .WithMessage("Not enough space in input array for padding"); + } + + [Test] + public void AddPadding_WhenCalledWithEmptyArray_ShouldThrowArgumentException() + { + var inputData = new byte[0]; + var inputOffset = 0; + + Action act = () => padding.AddPadding(inputData, inputOffset); + + act.Should().Throw() + .WithMessage("Not enough space in input array for padding"); + } + + [Test] + public void RemovePadding_WhenCalledWithValidInput_shouldReturnCorrectData() + { + var inputData = new byte[] { 1, 2, 3, 4, 5, 0x80, 0, 0, 0 }; + + var result = padding.RemovePadding(inputData); + + result.Should().Equal(new byte[] { 1, 2, 3, 4, 5 }); + } + + [Test] + public void RemovePadding_WhenCalledWithInvalidInput_ShouldThrowArgumentException() + { + var inputData = new byte[] { 1, 2, 3, 4, 5 }; + + Action act = () => padding.RemovePadding(inputData); + + act.Should().Throw() + .WithMessage("Invalid padding"); + } + + [Test] + public void RemovePadding_WhenCalledWithArrayContainingOnlyPadding_ShouldReturnEmptyArray() + { + var inputData = new byte[] { 0x80, 0, 0, 0, 0 }; + + var result = padding.RemovePadding(inputData); + + result.Should().BeEmpty(); + } + + [Test] + public void RemovePadding_WhenCalledWithArrayNotContainingStartOfPadding_ShouldThrowArgumentException() + { + var input = new byte[] { 1, 2, 3, 4, 5, 0, 0, 0, 0 }; + + Action act = () => padding.RemovePadding(input); + + act.Should().Throw() + .WithMessage("Invalid padding"); + } + + [Test] + public void GetPaddingCount_WhenCalledWithValidInput_ShouldReturnCorrectCount() + { + var inputData = new byte[] { 1, 2, 3, 4, 5, 0x80, 0, 0, 0 }; + + var result = padding.GetPaddingCount(inputData); + + result.Should().Be(4); + } + + [Test] + public void GetPaddingCount_WhenCalledWithInvalidInput_ShouldThrowArgumentException() + { + var inputData = new byte[] { 1, 2, 3, 4, 5 }; + + Action act = () => padding.GetPaddingCount(inputData); + + act.Should().Throw() + .WithMessage("Pad block corrupted"); + } + + [Test] + public void GetPaddingCount_WhenCalledWithEmptyArray_ShouldThrowArgumentException() + { + var inputData = Array.Empty(); + + Action act = () => padding.GetPaddingCount(inputData); + + act.Should().Throw() + .WithMessage("Pad block corrupted"); + } + + [Test] + public void GetPaddingCount_WhenCalledWithArrayContainingOnlyPadding_ShouldReturnCorrectCount() + { + var inputData = new byte[] { 0x80, 0x00, 0x00 }; + + var result = padding.GetPaddingCount(inputData); + + result.Should().Be(3); + } + + [Test] + public void GetPaddingCount_WhenCalledWithArrayNotContainingStartOfPadding_ShouldThrowAnException() + { + var inputData = new byte[] { 1, 2, 3, 4, 5, 0, 0, 0, 0 }; + + Action act = () => padding.GetPaddingCount(inputData); + + act.Should().Throw() + .WithMessage("Pad block corrupted"); + } +} diff --git a/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs b/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs new file mode 100644 index 00000000..be794ac1 --- /dev/null +++ b/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs @@ -0,0 +1,154 @@ +using System; + +namespace Algorithms.Crypto.Paddings; + +/// +/// +/// ISO 7816-4 padding is a padding scheme that is defined in the ISO/IEC 7816-4 documentation. +/// +/// +/// It is used for adding data to the end of a message that needs to be encrypted or decrypted by a block cipher. +/// +/// ISO 7816-4 padding works as follows: +/// +/// The first byte of the padding is 0x80, which is the hexadecimal representation of the binary value 10000000. This +/// byte indicates the start of the padding. +/// +/// +/// All other bytes of the padding are 0x00, which is the hexadecimal representation of the binary value 00000000. These +/// bytes fill up the remaining space in the last block. +/// +/// +/// The padding can be of any size, from 1 byte to the block size. For example, if the block size is 8 bytes and the +/// message has 5 bytes, then 3 bytes of padding are needed. The padding would be 0x80 0x00 0x00. +/// +/// +/// ISO 7816-4 padding is also known as bit padding,because it simply places a single 1 bit after the plaintext, followed +/// by 0 valued bits up to the block size. It works for both byte-oriented and bit-oriented protocols, as it does not +/// depend on any specific character encoding or representation. +/// +/// +public class Iso7816D4Padding +{ + /// + /// Adds padding to the input data according to the ISO 7816-4 standard. + /// + /// The input data array that needs padding. + /// The offset in the input data array where the padding should start. + /// The number of bytes added as padding. + /// + /// Thrown when there is not enough space in the input array for padding or when the input offset is invalid. + /// + public int AddPadding(byte[] inputData, int inputOffset) + { + // Calculate the number of padding bytes based on the input data length and offset. + var code = (byte)(inputData.Length - inputOffset); + + // Check if the padding bytes are valid and fit in the input array. + if (code == 0 || inputOffset + code > inputData.Length) + { + throw new ArgumentException("Not enough space in input array for padding"); + } + + // Set the first padding byte to 80. This marks the start of padding in the ISO 7816-4 standard. + inputData[inputOffset] = 80; + inputOffset++; + + // Set the remaining padding bytes to 0. + while (inputOffset < inputData.Length) + { + inputData[inputOffset] = 0; + inputOffset++; + } + + // Return the number of padding bytes. + return code; + } + + /// + /// Removes the padding from the input data array and returns the original data. + /// + /// + /// The input data with ISO 7816-4 padding. Must not be null and must have a valid length and padding. + /// + /// The input data without the padding as a new byte array. + /// + /// Thrown when the input data has invalid padding. + /// + public byte[] RemovePadding(byte[] inputData) + { + // Find the index of the first padding byte by scanning from the end of the input. + var paddingIndex = inputData.Length - 1; + + // Skip all the padding bytes that are 0. + while (paddingIndex >= 0 && inputData[paddingIndex] == 0) + { + paddingIndex--; + } + + // Check if the first padding byte is 0x80. + if (paddingIndex < 0 || inputData[paddingIndex] != 0x80) + { + throw new ArgumentException("Invalid padding"); + } + + // Create a new array to store the unpadded data. + var unpaddedData = new byte[paddingIndex]; + + // Copy the unpadded data from the input data to the new array. + Array.Copy(inputData, 0, unpaddedData, 0, paddingIndex); + + // Return the unpadded data array. + return unpaddedData; + } + + /// + /// Gets the number of padding bytes in the input data according to the ISO 7816-4 standard. + /// + /// The input data array that has padding. + /// The number of padding bytes in the input data. + /// Thrown when the input data has invalid padding. + public int GetPaddingCount(byte[] input) + { + // Initialize the index of the first padding byte to -1. + var paddingStartIndex = -1; + + // Initialize a mask to indicate if the current byte is still part of the padding. + var stillPaddingMask = -1; + + // Initialize the current index to the end of the input data. + var currentIndex = input.Length; + + // Loop backwards through the input data. + while (--currentIndex >= 0) + { + // Get the current byte as an unsigned integer. + var currentByte = input[currentIndex] & 0xFF; + + // Compute a mask to indicate if the current byte is 0x00. + var isZeroMask = (currentByte - 1) >> 31; + + // Compute a mask to indicate if the current byte is 0x80. + var isPaddingStartMask = ((currentByte ^ 0x80) - 1) >> 31; + + // Update the index of the first padding byte using bitwise operations. + // If the current byte is 0x80 and still part of the padding, set the index to the current index. + // Otherwise, keep the previous index. + paddingStartIndex ^= (currentIndex ^ paddingStartIndex) & (stillPaddingMask & isPaddingStartMask); + + // Update the mask to indicate if the current byte is still part of the padding using bitwise operations. + // If the current byte is 0x00, keep the previous mask. + // Otherwise, set the mask to 0. + stillPaddingMask &= isZeroMask; + } + + // Check if the index of the first padding byte is valid. + if (paddingStartIndex < 0) + { + throw new ArgumentException("Pad block corrupted"); + } + + // Return the number of padding bytes. + return input.Length - paddingStartIndex; + } +} diff --git a/README.md b/README.md index 4fc577ba..06ff3d22 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ find more than one implementation for the same objective but using different alg * [Algorithms](./Algorithms) * [Crypto](./Algorithms/Crypto/) * [Paddings](./Algorithms/Crypto/Paddings/) + * [ISO 7816-4 Padding](./Algorithms/Crypto/Paddings/ISO7816d4Padding.cs) * [PKC7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) * [Data Compression](./Algorithms/DataCompression) * [Burrows-Wheeler transform](./Algorithms/DataCompression/BurrowsWheelerTransform.cs) From ccf464746579a3be2bc052ed8193a3eb80779ba2 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Sun, 8 Oct 2023 14:38:30 +0300 Subject: [PATCH 066/138] Add iso10125d2 padding (#407) --- .../Crypto/Paddings/Iso10126D2PaddingTests.cs | 122 +++++++++++++++++ .../Pkcs7PaddingTests.cs} | 46 +++---- .../Crypto/Paddings/Iso10126D2Padding.cs | 127 ++++++++++++++++++ .../{PKCS7Padding.cs => Pkcs7Padding.cs} | 0 README.md | 1 + 5 files changed, 273 insertions(+), 23 deletions(-) create mode 100644 Algorithms.Tests/Crypto/Paddings/Iso10126D2PaddingTests.cs rename Algorithms.Tests/Crypto/{Padding/PKCS7PaddingTests.cs => Paddings/Pkcs7PaddingTests.cs} (76%) create mode 100644 Algorithms/Crypto/Paddings/Iso10126D2Padding.cs rename Algorithms/Crypto/Paddings/{PKCS7Padding.cs => Pkcs7Padding.cs} (100%) diff --git a/Algorithms.Tests/Crypto/Paddings/Iso10126D2PaddingTests.cs b/Algorithms.Tests/Crypto/Paddings/Iso10126D2PaddingTests.cs new file mode 100644 index 00000000..e5aae6d4 --- /dev/null +++ b/Algorithms.Tests/Crypto/Paddings/Iso10126D2PaddingTests.cs @@ -0,0 +1,122 @@ +using System; +using Algorithms.Crypto.Paddings; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Crypto.Paddings; + +public class Iso10126D2PaddingTests +{ + private readonly Iso10126D2Padding padding = new Iso10126D2Padding(); + + [Test] + public void AddPadding_WhenInputOffsetIsLessThanInputDataLength_ShouldNotThrowException() + { + var inputData = new byte[10]; + const int inputOffset = 5; + + Action act = () => padding.AddPadding(inputData, inputOffset); + + act.Should().NotThrow(); + } + + [Test] + public void AddPadding_WhenInputOffsetIsEqualToInputDataLength_ShouldThrowException() + { + var inputData = new byte[10]; + const int inputOffset = 10; + + Action act = () => padding.AddPadding(inputData, inputOffset); + + act.Should().Throw() + .WithMessage("Not enough space in input array for padding"); + } + + [Test] + public void AddPadding_WhenInputOffsetIsGreaterThanInputDataLength_ShouldThrowException() + { + var inputData = new byte[10]; + const int inputOffset = 128; + + Action act = () => padding.AddPadding(inputData, inputOffset); + + act.Should().Throw() + .WithMessage("Not enough space in input array for padding"); + } + + [Test] + public void AddPadding_WhenInputArrayIsValid_ShouldReturnCorrectPaddingSize() + { + var inputData = new byte[10]; + const int inputOffset = 5; + + var result = padding.AddPadding(inputData, inputOffset); + + result.Should().Be(5); + } + + [Test] + public void RemovePadding_WhenLengthIsLessThanOne_ShouldThrowATantrum() + { + var inputData = new byte[] { 0 }; + + Action act = () => padding.RemovePadding(inputData); + + act.Should().Throw() + .WithMessage("Invalid padding length"); + } + + [Test] + public void RemovePadding_WhenPaddingLengthIsGreaterThanInputDataLength_ShouldThrowAnException() + { + var inputData = new byte[] { 2 }; + + Action act = () => padding.RemovePadding(inputData); + + act.Should().Throw() + .WithMessage("Invalid padding length"); + } + + [Test] + public void RemovePadding_WhenInputDataIsValid_ShouldReturnCorrectData() + { + var inputData = new byte[] { 1, 2, 3, 1 }; + var expected = new byte[] { 1, 2, 3 }; + + var result = padding.RemovePadding(inputData); + + result.Should().Equal(expected); + } + + [Test] + public void GetPaddingCount_WhenInputIsNull_ShouldThrowAnException() + { + byte[]? input = null; + + Action act = () => padding.GetPaddingCount(input!); + + act.Should().Throw() + .WithMessage("Input cannot be null (Parameter 'input')"); + } + + [Test] + public void GetPaddingCount_WhenPaddingBlockIsCorrupted_ShouldThrowAnException() + { + var input = new byte[] { 1, 2, 3, 4, 5, 7 }; + + Action act = () => padding.GetPaddingCount(input); + + act.Should().Throw() + .WithMessage("Padding block is corrupted"); + } + + [Test] + public void GetPaddingCount_WhenInputDataIsValid_ShouldReturnCorrectPaddingCount() + { + var input = new byte[] { 1, 2, 3, 4, 1 }; + + var result = padding.GetPaddingCount(input); + + result.Should().Be(1); + } +} diff --git a/Algorithms.Tests/Crypto/Padding/PKCS7PaddingTests.cs b/Algorithms.Tests/Crypto/Paddings/Pkcs7PaddingTests.cs similarity index 76% rename from Algorithms.Tests/Crypto/Padding/PKCS7PaddingTests.cs rename to Algorithms.Tests/Crypto/Paddings/Pkcs7PaddingTests.cs index 46769c60..1c159183 100644 --- a/Algorithms.Tests/Crypto/Padding/PKCS7PaddingTests.cs +++ b/Algorithms.Tests/Crypto/Paddings/Pkcs7PaddingTests.cs @@ -3,11 +3,11 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Crypto.Padding; +namespace Algorithms.Tests.Crypto.Paddings; -public class PKCS7PaddingTests +public class Pkcs7PaddingTests { - private const int defaultBlockSize = 16; + private const int DefaultBlockSize = 16; [Test] public void Constructor_WhenBlockSizeIsLessThanOne_ShouldThrowArgumentOutOfRangeException() @@ -44,7 +44,7 @@ public void Constructor_WhenBlockSizeIsWithinValidRange_ShouldNotThrowAFit() [Test] public void AddPadding_WhenNotEnoughSpaceInInputArrayForPadding_ShouldThrowArgumentException() { - var padding = new Pkcs7Padding(defaultBlockSize); + var padding = new Pkcs7Padding(DefaultBlockSize); const int inputOffset = 1; var size16Input = new byte[16]; @@ -58,29 +58,29 @@ public void AddPadding_WhenNotEnoughSpaceInInputArrayForPadding_ShouldThrowArgum [Test] public void AddPadding_WhenInputArrayHasEnoughSpace_ShouldReturnCorrectPaddingSize() { - var padding = new Pkcs7Padding(defaultBlockSize); - const int inputOffset = defaultBlockSize; + var padding = new Pkcs7Padding(DefaultBlockSize); + const int inputOffset = DefaultBlockSize; var size32Input = new byte[32]; var result = padding.AddPadding(size32Input, inputOffset); - result.Should().Be(defaultBlockSize); + result.Should().Be(DefaultBlockSize); } [Test] public void AddPadding_WhenAppliedToAnInputArray_ShouldAddCorrectPKCS7Padding() { - var padding = new Pkcs7Padding(defaultBlockSize); - const int inputOffset = defaultBlockSize; + var padding = new Pkcs7Padding(DefaultBlockSize); + const int inputOffset = DefaultBlockSize; var size32Input = new byte[32]; padding.AddPadding(size32Input, inputOffset); - for (var i = 0; i < defaultBlockSize - 1; i++) + for (var i = 0; i < DefaultBlockSize - 1; i++) { - size32Input[inputOffset + i].Should().Be(defaultBlockSize); + size32Input[inputOffset + i].Should().Be(DefaultBlockSize); } } @@ -94,7 +94,7 @@ public void RemovePadding_WhenAppliedToAValidInputArray_ShouldRemovePKCS7Padding size32Input[size32Input.Length - 1 - i] = (byte)paddingSize; } - var padding = new Pkcs7Padding(defaultBlockSize); + var padding = new Pkcs7Padding(DefaultBlockSize); var output = padding.RemovePadding(size32Input); @@ -104,8 +104,8 @@ public void RemovePadding_WhenAppliedToAValidInputArray_ShouldRemovePKCS7Padding [Test] public void RemovePadding_WhenInputLengthNotMultipleOfBlockSize_ShouldThrowArgumentException() { - var input = new byte[defaultBlockSize + 1]; // Length is not a multiple of blockSize - var padding = new Pkcs7Padding(defaultBlockSize); + var input = new byte[DefaultBlockSize + 1]; // Length is not a multiple of blockSize + var padding = new Pkcs7Padding(DefaultBlockSize); Action act = () => padding.RemovePadding(input); @@ -118,8 +118,8 @@ public void RemovePadding_WhenInvalidPaddingLength_ShouldThrowArgumentException( { var size32Input = new byte[32]; - size32Input[^1] = (byte)(defaultBlockSize + 1); // Set invalid padding length - var padding = new Pkcs7Padding(defaultBlockSize); + size32Input[^1] = (byte)(DefaultBlockSize + 1); // Set invalid padding length + var padding = new Pkcs7Padding(DefaultBlockSize); Action act = () => padding.RemovePadding(size32Input); @@ -131,9 +131,9 @@ public void RemovePadding_WhenInvalidPadding_ShouldThrowArgumentException() { var size32Input = new byte[32]; - size32Input[^1] = (byte)(defaultBlockSize); // Set valid padding length - size32Input[^2] = (byte)(defaultBlockSize - 1); // Set invalid padding byte - var padding = new Pkcs7Padding(defaultBlockSize); + size32Input[^1] = (byte)(DefaultBlockSize); // Set valid padding length + size32Input[^2] = (byte)(DefaultBlockSize - 1); // Set invalid padding byte + var padding = new Pkcs7Padding(DefaultBlockSize); Action act = () => padding.RemovePadding(size32Input); @@ -152,7 +152,7 @@ public void GetPaddingCount_WhenInputArrayIsValid_ShouldReturnCorrectPaddingCoun size32Input[size32Input.Length - 1 - i] = (byte)paddingSize; // Add padding bytes at the end of the array } - var padding = new Pkcs7Padding(defaultBlockSize); + var padding = new Pkcs7Padding(DefaultBlockSize); var output = padding.GetPaddingCount(size32Input); @@ -164,10 +164,10 @@ public void GetPaddingCount_WhenInvalidPadding_ShouldThrowArgumentException() { var size32Input = new byte[32]; - size32Input[^1] = defaultBlockSize; - size32Input[^2] = defaultBlockSize - 1; + size32Input[^1] = DefaultBlockSize; + size32Input[^2] = DefaultBlockSize - 1; - var padding = new Pkcs7Padding(defaultBlockSize); + var padding = new Pkcs7Padding(DefaultBlockSize); Action act = () => padding.GetPaddingCount(size32Input); diff --git a/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs b/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs new file mode 100644 index 00000000..26c4385a --- /dev/null +++ b/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs @@ -0,0 +1,127 @@ +using System; +using System.Security.Cryptography; + +namespace Algorithms.Crypto.Paddings; + +/// +/// +/// This class implements the ISO10126d2 padding scheme, which is a standard way of padding data to fit a certain block +/// size. +/// +/// +/// ISO10126d2 padding adds N-1 random bytes and one byte of value N to the end of the data, where N is the number of +/// bytes needed to reach the block size. For example, if the block size is 16 bytes, and the data is 10 bytes long, then +/// 5 random bytes and a byte with value 6 will be added to the end of data. This way the padded data will be 16 bytes +/// long and can be encrypted or decrypted by a block cipher algorithm. +/// +/// +/// The padding can easily be removed after decryption by looking at the last byte and discarding that many bytes from +/// the end of the data. +/// +/// +public class Iso10126D2Padding +{ + /// + /// Adds random padding to the input data array to make it a multiple of the block size according to the + /// ISO10126d2 standard. + /// + /// The input data array that needs to be padded. + /// The offset in the input data array where the padding should start. + /// The number of bytes added as padding. + /// + /// Thrown when there is not enough space in the input array for padding. + /// + public int AddPadding(byte[] inputData, int inputOffset) + { + // Calculate how many bytes need to be added to reach the next multiple of block size. + var code = (byte)(inputData.Length - inputOffset); + + if (code == 0 || inputOffset + code > inputData.Length) + { + throw new ArgumentException("Not enough space in input array for padding"); + } + + // Add the padding. + while (inputOffset < (inputData.Length - 1)) + { + inputData[inputOffset] = (byte)RandomNumberGenerator.GetInt32(255); + inputOffset++; + } + + // Set the last byte of the array to the size of the padding added. + inputData[inputOffset] = code; + + return code; + } + + /// + /// Removes the padding from the input data array and returns the original data. + /// + /// + /// The input data with ISO10126d2 padding. Must not be null and must have a valid length and padding. + /// + /// + /// The input data without the padding as a new byte array. + /// + /// + /// Thrown when the padding length is invalid. + /// + public byte[] RemovePadding(byte[] inputData) + { + // Get the size of the padding from the last byte of the input data. + var paddingLength = inputData[^1]; + + // Check if the padding size is valid. + if (paddingLength < 1 || paddingLength > inputData.Length) + { + throw new ArgumentException("Invalid padding length"); + } + + // Create a new array to hold the original data. + var output = new byte[inputData.Length - paddingLength]; + + // Copy the original data into the new array. + Array.Copy(inputData, 0, output, 0, output.Length); + + return output; + } + + /// + /// Gets the number of padding bytes from the input data array. + /// + /// The input data array that has been padded. + /// The number of padding bytes. + /// Thrown when the input is null. + /// Thrown when the padding block is corrupted. + public int GetPaddingCount(byte[] input) + { + if (input == null) + { + throw new ArgumentNullException(nameof(input), "Input cannot be null"); + } + + // Get the last byte of the input data as the padding value. + var lastByte = input[^1]; + var paddingCount = lastByte & 0xFF; + + // Calculate the index where the padding starts. + var paddingStartIndex = input.Length - paddingCount; + var paddingCheckFailed = 0; + + // The paddingCheckFailed will be non-zero under the following circumstances: + // 1. When paddingStartIndex is negative: This happens when paddingCount (the last byte of the input array) is + // greater than the length of the input array. In other words, the padding count is claiming that there are more + // padding bytes than there are bytes in the array, which is not a valid scenario. + // 2. When paddingCount - 1 is negative: This happens when paddingCount is zero or less. Since paddingCount + // represents the number of padding bytes and is derived from the last byte of the input array, it should always + // be a positive number. If it's zero or less, it means that either there's no padding, or an invalid negative + // padding count has shomehow encoded into the last byte of the input array. + paddingCheckFailed = (paddingStartIndex | (paddingCount - 1)) >> 31; + if (paddingCheckFailed != 0) + { + throw new ArgumentException("Padding block is corrupted"); + } + + return paddingCount; + } +} diff --git a/Algorithms/Crypto/Paddings/PKCS7Padding.cs b/Algorithms/Crypto/Paddings/Pkcs7Padding.cs similarity index 100% rename from Algorithms/Crypto/Paddings/PKCS7Padding.cs rename to Algorithms/Crypto/Paddings/Pkcs7Padding.cs diff --git a/README.md b/README.md index 06ff3d22..49b80576 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ find more than one implementation for the same objective but using different alg * [Algorithms](./Algorithms) * [Crypto](./Algorithms/Crypto/) * [Paddings](./Algorithms/Crypto/Paddings/) + * [ISO-10125d2 Padding](./Algorithms/Crypto/Paddings/ISO10126d2Padding.cs) * [ISO 7816-4 Padding](./Algorithms/Crypto/Paddings/ISO7816d4Padding.cs) * [PKC7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) * [Data Compression](./Algorithms/DataCompression) From d65c7d1c9d0a1d652c2eb2a00a839a056e3d9f39 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Mon, 9 Oct 2023 12:40:12 +0300 Subject: [PATCH 067/138] Correct spelling for PKCS7 and ISO 1012-2 (#411) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 49b80576..c4d228c3 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ find more than one implementation for the same objective but using different alg * [Algorithms](./Algorithms) * [Crypto](./Algorithms/Crypto/) * [Paddings](./Algorithms/Crypto/Paddings/) - * [ISO-10125d2 Padding](./Algorithms/Crypto/Paddings/ISO10126d2Padding.cs) + * [ISO 10125-2 Padding](./Algorithms/Crypto/Paddings/ISO10126d2Padding.cs) * [ISO 7816-4 Padding](./Algorithms/Crypto/Paddings/ISO7816d4Padding.cs) - * [PKC7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) + * [PKCS7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) * [Data Compression](./Algorithms/DataCompression) * [Burrows-Wheeler transform](./Algorithms/DataCompression/BurrowsWheelerTransform.cs) * [Huffman Compressor](./Algorithms/DataCompression/HuffmanCompressor.cs) From b6d7385942ee82f4d60cf420bc8c8bdc80fc3f05 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Mon, 9 Oct 2023 18:09:58 +0300 Subject: [PATCH 068/138] Add TBC Padding (#413) --- .../Crypto/Paddings/TbcPaddingTests.cs | 157 +++++++++++++++++ Algorithms/Crypto/Paddings/TbcPadding.cs | 161 ++++++++++++++++++ README.md | 1 + 3 files changed, 319 insertions(+) create mode 100644 Algorithms.Tests/Crypto/Paddings/TbcPaddingTests.cs create mode 100644 Algorithms/Crypto/Paddings/TbcPadding.cs diff --git a/Algorithms.Tests/Crypto/Paddings/TbcPaddingTests.cs b/Algorithms.Tests/Crypto/Paddings/TbcPaddingTests.cs new file mode 100644 index 00000000..1bf131d4 --- /dev/null +++ b/Algorithms.Tests/Crypto/Paddings/TbcPaddingTests.cs @@ -0,0 +1,157 @@ +using System; +using Algorithms.Crypto.Paddings; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Crypto.Paddings; + +public class TbcPaddingTests +{ + private readonly TbcPadding padding = new TbcPadding(); + + [Test] + public void AddPadding_WhenInputOffsetIsZero_ShouldPadWithLastBit() + { + var input = new byte[] { 0x01, 0x02, 0x03, 0x04 }; + var inputOffset = 0; + + var result = padding.AddPadding(input, inputOffset); + + result.Should().Be(4); + input.Should().BeEquivalentTo(new byte[]{0xff, 0xff, 0xff, 0xff}); + } + + [Test] + public void AddPadding_WhenInputOffsetIsPositive_ShouldPadWithPreviousBit() + { + var input = new byte[] { 0x01, 0x02, 0x03, 0x04 }; + var inputOffset = 2; + + var result = padding.AddPadding(input, inputOffset); + + result.Should().Be(2); + input.Should().BeEquivalentTo(new byte[] { 0x01, 0x02, 0xff, 0xff }); + } + + [Test] + public void AddPadding_WhenInputOffsetIsGreaterThanLength_ShouldThrowArgumentException() + { + var input = new byte[] { 0x01, 0x02, 0x03, 0x04 }; + var inputOffset = 5; + + Action act = () => padding.AddPadding(input, inputOffset); + + act.Should().Throw() + .WithMessage("Not enough space in input array for padding"); + } + + [Test] + public void AddPadding_WhenLastBitIsZero_ShouldPadWith0xFF() + { + var input = new byte[] { 0x02 }; + const int inputOffset = 0; + + var result = padding.AddPadding(input, inputOffset); + + result.Should().Be(1); + input.Should().BeEquivalentTo(new byte[] { 0xFF }); + } + + [Test] + public void AddPadding_WhenLastBitIsOne_ShouldPadWith0x00() + { + var input = new byte[] { 0x03 }; + const int inputOffset = 0; + + var result = padding.AddPadding(input, inputOffset); + + result.Should().Be(1); + input.Should().BeEquivalentTo(new byte[] { 0x00 }); + } + + [Test] + public void RemovePadding_WhenCalledWithPaddedData_ShouldReturnUnpaddedData() + { + var paddedData = new byte[] { 0x01, 0x02, 0x03, 0xff, 0xff }; + var expectedData = new byte[] { 0x01, 0x02, 0x03 }; + + var result = padding.RemovePadding(paddedData); + + result.Should().BeEquivalentTo(expectedData); + } + + [Test] + public void RemovePadding_WhenCalledWithUnpaddedData_ShouldReturnsSameData() + { + var unpaddedData = new byte[] { 0x01, 0x02, 0x03 }; + + var result = padding.RemovePadding(unpaddedData); + + result.Should().BeEquivalentTo(unpaddedData); + } + + [Test] + public void RemovePadding_WhenCalledWithEmptyArray_ShouldReturnEmptyArray() + { + var emptyData = Array.Empty(); + + var result = padding.RemovePadding(emptyData); + + result.Should().BeEquivalentTo(emptyData); + } + + [Test] + public void RemovePadding_WhenCalledWithSingleBytePaddedData_ShouldReturnEmptyArray() + { + var singleBytePaddedData = new byte[] { 0xff }; + + var result = padding.RemovePadding(singleBytePaddedData); + + result.Should().BeEmpty(); + } + + [Test] + public void RemovePadding_WhenCalledWitAllBytesPadded_ShouldReturnEmptyArray() + { + var allBytesPaddedData = new byte[] { 0xff, 0xff, 0xff }; + var emptyData = Array.Empty(); + + var result = padding.RemovePadding(allBytesPaddedData); + + result.Should().BeEquivalentTo(emptyData); + } + + [Test] + public void GetPaddingBytes_WhenCalledWithPaddedData_ShouldReturnCorrectPaddingCount() + { + + var paddedData = new byte[] { 0x01, 0x02, 0x03, 0xff, 0xff }; + const int expectedPaddingCount = 2; + + var result = padding.GetPaddingBytes(paddedData); + + result.Should().Be(expectedPaddingCount); + } + + [Test] + public void GetPaddingBytes_WhenCalledWithUnpaddedData_ShouldReturnZero() + { + var unpaddedData = new byte[] { 0x01, 0x02, 0x03 }; + + Action action = () => padding.GetPaddingBytes(unpaddedData); + + action.Should().Throw() + .WithMessage("No padding found"); + } + + [Test] + public void GetPaddingBytes_WhenCalledWithEmptyArray_ShouldReturnZero() + { + var emptyData = Array.Empty(); + + Action action = () => padding.GetPaddingBytes(emptyData); + + action.Should().Throw() + .WithMessage("No padding found."); + } +} diff --git a/Algorithms/Crypto/Paddings/TbcPadding.cs b/Algorithms/Crypto/Paddings/TbcPadding.cs new file mode 100644 index 00000000..97b7a4b8 --- /dev/null +++ b/Algorithms/Crypto/Paddings/TbcPadding.cs @@ -0,0 +1,161 @@ +using System; + +namespace Algorithms.Crypto.Paddings; + +/// +/// +/// Trailing-Bit-Complement padding is a padding scheme that is defined in the ISO/IEC 9797-1 standard. +/// +/// +/// It is used for adding data to the end of a message that needs to be encrypted or decrypted by a block cipher. +/// +/// +/// The padding bytes are either 0x00 or 0xFF, depending on the last bit of the original data. For example, if the last +/// bit of the original data is 0, then the padding bytes are 0xFF; if the last bit is 1, then the padding bytes are 0x00. +/// The padding bytes are added at the end of the data block until the desired length is reached. +/// +/// +public class TbcPadding +{ + /// + /// Adds padding to the input array according to the TBC standard. + /// + /// The input array to be padded. + /// The offset in the input array where the padding starts. + /// The number of bytes that were added. + /// Thrown when the input array does not have enough space for padding. + public int AddPadding(byte[] input, int inputOffset) + { + // Calculate the number of bytes to be padded. + var count = input.Length - inputOffset; + byte code; + + // Check if the input array has enough space for padding. + if (count < 0) + { + throw new ArgumentException("Not enough space in input array for padding"); + } + + if (inputOffset > 0) + { + // Get the last bit of the previous byte. + var lastBit = input[inputOffset - 1] & 0x01; + + // Set the padding code to 0xFF if the last bit is 0, or 0x00 if the last bit is 1. + code = (byte)(lastBit == 0 ? 0xff : 0x00); + } + else + { + // Get the last bit of the last byte in the input array. + var lastBit = input[^1] & 0x01; + + // Set the padding code to 0xff if the last bit is 0, or 0x00 if the last bit is 1. + code = (byte)(lastBit == 0 ? 0xff : 0x00); + } + + while (inputOffset < input.Length) + { + // Set each byte to the padding code. + input[inputOffset] = code; + inputOffset++; + } + + // Return the number of bytes that were padded. + return count; + } + + /// + /// Removes the padding from a byte array according to the Trailing-Bit-Complement padding algorithm. + /// + /// The byte array to remove the padding from. + /// A new byte array without the padding. + /// + /// This method assumes that the input array has padded with either 0x00 or 0xFF bytes, depending on the last bit of + /// the original data. The method works by finding the last byte that does not match the padding code and copying all + /// the bytes up to that point into a new array. If the input array is not padded or has an invalid padding, the + /// method may return incorrect results. + /// + public byte[] RemovePadding(byte[] input) + { + if (input.Length == 0) + { + return Array.Empty(); + } + + // Get the last byte of the input array. + var lastByte = input[^1]; + + // Determine the byte code + var code = (byte)((lastByte & 0x01) == 0 ? 0x00 : 0xff); + + // Start from the end of the array and move towards the front. + int i; + for (i = input.Length - 1; i >= 0; i--) + { + // If the current byte does not match the padding code, stop. + if (input[i] != code) + { + break; + } + } + + // Create a new array of the appropriate length. + var unpadded = new byte[i + 1]; + + // Copy the unpadded data into the new array. + Array.Copy(input, unpadded, i + 1); + + // Return the new array. + return unpadded; + } + + /// + /// Returns the number of padding bytes in a byte array according to the Trailing-Bit-Complement padding algorithm. + /// + /// The byte array to check for padding. + /// The number of padding bytes in the input array. + /// + /// This method assumes that the input array has been padded with either 0x00 or 0xFF bytes, depending on the last + /// bit of the original data. The method works by iterating backwards from the end of the array and counting the + /// number of bytes that match the padding code. The method uses bitwise operations to optimize the performance and + /// avoid branching. If the input array is not padded or has an invalid padding, the method may return incorrect + /// results. + /// + public int GetPaddingBytes(byte[] input) + { + var length = input.Length; + + if (length == 0) + { + throw new ArgumentException("No padding found."); + } + + // Get the value of the last byte as the padding value + var paddingValue = input[--length] & 0xFF; + var paddingCount = 1; // Start count at 1 for the last byte + var countingMask = -1; // Initialize counting mask + + // Check if there is no padding + if (paddingValue != 0 && paddingValue != 0xFF) + { + throw new ArgumentException("No padding found"); + } + + // Loop backwards through the array + for (var i = length - 1; i >= 0; i--) + { + var currentByte = input[i] & 0xFF; + + // Calculate matchMask. If currentByte equals paddingValue, matchMask will be 0, otherwise -1 + var matchMask = ((currentByte ^ paddingValue) - 1) >> 31; + + // Update countingMask. Once a non-matching byte is found, countingMask will remain -1 + countingMask &= matchMask; + + // Increment count only if countingMask is 0 (i.e., currentByte matches paddingValue) + paddingCount -= countingMask; + } + + return paddingCount; + } +} diff --git a/README.md b/README.md index c4d228c3..9377089a 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ find more than one implementation for the same objective but using different alg * [Paddings](./Algorithms/Crypto/Paddings/) * [ISO 10125-2 Padding](./Algorithms/Crypto/Paddings/ISO10126d2Padding.cs) * [ISO 7816-4 Padding](./Algorithms/Crypto/Paddings/ISO7816d4Padding.cs) + * [TBC Padding](./Algorithms/Crypto/Paddings/TbcPadding.cs) * [PKCS7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) * [Data Compression](./Algorithms/DataCompression) * [Burrows-Wheeler transform](./Algorithms/DataCompression/BurrowsWheelerTransform.cs) From 30e750ec2a280d1f3523125743ab5773e3550fc4 Mon Sep 17 00:00:00 2001 From: manish0x0f <140893931+manish0x0f@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:47:29 +0530 Subject: [PATCH 069/138] Add Queue-based Stack (#412) --- .../Stack/QueueBasedStackTests.cs | 127 ++++++++++++++++++ DataStructures/Stack/QueueBasedStack.cs | 76 +++++++++++ README.md | 1 + 3 files changed, 204 insertions(+) create mode 100644 DataStructures.Tests/Stack/QueueBasedStackTests.cs create mode 100644 DataStructures/Stack/QueueBasedStack.cs diff --git a/DataStructures.Tests/Stack/QueueBasedStackTests.cs b/DataStructures.Tests/Stack/QueueBasedStackTests.cs new file mode 100644 index 00000000..69f67621 --- /dev/null +++ b/DataStructures.Tests/Stack/QueueBasedStackTests.cs @@ -0,0 +1,127 @@ +using DataStructures.Stack; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DataStructures.Tests.Stack +{ + public static class QueueBasedStackTests + { + [Test] + public static void PopWorksCorrectly() + { + //Arrange + QueueBasedStack s = new QueueBasedStack(); + s.Push('A'); + s.Push('B'); + s.Push('C'); + var result = new StringBuilder(); + + //Act + for (int i = 0; i < 3; i++) + { + result.Append(s.Pop()); + } + + + //Assert + Assert.That("CBA", Is.EqualTo(result.ToString())); + Assert.IsTrue(s.IsEmpty(), "Stack is Empty"); + } + [Test] + public static void PeekWorksCorrectly() + { + //Arrange + QueueBasedStack s = new QueueBasedStack(); + s.Push(1); + s.Push(2); + s.Push(3); + var peeked = 0; + + //Act + for (int i = 0; i < 3; i++) + { + peeked = s.Peek(); + } + + + //Assert + Assert.That(3, Is.EqualTo(peeked)); + Assert.IsFalse(s.IsEmpty(), "Stack is Empty"); + } + [Test] + public static void PopEmptyStackThrowsInvalidOperationException() + { + //Arrange + var s = new QueueBasedStack(); + Exception? exception = null; + + //Act + try + { + s.Pop(); + } + catch (Exception ex) + { + exception = ex; + } + + //Assert + Assert.That(exception?.GetType(), Is.EqualTo(typeof(InvalidOperationException))); + } + [Test] + public static void PeekEmptyStackThrowsInvalidOperationException() + { + //Arrange + var s = new QueueBasedStack(); + Exception? exception = null; + + //Act + try + { + s.Peek(); + } + catch (Exception ex) + { + exception = ex; + } + + //Assert + Assert.That(exception?.GetType(), Is.EqualTo(typeof(InvalidOperationException))); + } + [Test] + public static void ClearWorksCorrectly() + { + // Arrange + var s = new QueueBasedStack(); + s.Push(1); + s.Push(2); + + // Act + s.Clear(); + + // Assert + Assert.IsTrue(s.IsEmpty(), "Queue is empty"); + + } + [Test] + public static void LengthWorksCorrectly() + { + // Arrange + var s = new QueueBasedStack(); + s.Push(1); + s.Push(2); + var length = 0; + + // Act + length = s.Length(); + + // Assert + Assert.That(2, Is.EqualTo(length)); + + } + } +} diff --git a/DataStructures/Stack/QueueBasedStack.cs b/DataStructures/Stack/QueueBasedStack.cs new file mode 100644 index 00000000..ea5af6b4 --- /dev/null +++ b/DataStructures/Stack/QueueBasedStack.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DataStructures.Stack +{ + public class QueueBasedStack + { + private readonly Queue queue; + + public QueueBasedStack() => queue = new Queue(); + + /// + /// Clears the stack. + /// + public void Clear() => queue.Clear(); + + public bool IsEmpty() => queue.Count == 0; + + /// + /// Adds an item on top of the stack. + /// + /// Item to be added on top of stack. + public void Push(T item) => queue.Enqueue(item); + + /// + /// Removes an item from top of the stack and returns it. + /// + /// item on top of stack. + /// Throw if stack is empty. + public T Pop() + { + if (IsEmpty()) + { + throw new InvalidOperationException("The stack contains no items."); + } + + for (int i = 0; i < queue.Count - 1; i++) + { + queue.Enqueue(queue.Dequeue()); + } + + return queue.Dequeue(); + } + + /// + /// return an item from the top of the stack without removing it. + /// + /// item on top of the stack. + /// Throw if stack is empty. + public T Peek() + { + if (IsEmpty()) + { + throw new InvalidOperationException("The stack contains no items."); + } + + for (int i = 0; i < queue.Count - 1; i++) + { + queue.Enqueue(queue.Dequeue()); + } + + var item = queue.Peek(); + queue.Enqueue(queue.Dequeue()); + return item; + } + + /// + /// returns the count of items on the stack. + /// + /// number of items on the stack. + public int Length() => queue.Count; + } +} diff --git a/README.md b/README.md index 9377089a..e42a864c 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,7 @@ find more than one implementation for the same objective but using different alg * [Stack](./DataStructures/Stack) * [Array-based Stack](./DataStructures/Stack/ArrayBasedStack.cs) * [List-based Stack](./DataStructures/Stack/ListBasedStack.cs) + * [Queue-based Stack](./DataStructures/Stack/QueueBasedStack.cs) * [Heap](./DataStructures/Heap) * [Min-Max Heap](./DataStructures/Heap/MinMaxHeap.cs) * [Binary Heap](./DataStructures/Heap/BinaryHeap.cs) From 15748ead91e84272d5f7241fa7c899604cdb9d83 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Tue, 10 Oct 2023 17:56:53 +0300 Subject: [PATCH 070/138] Add X9.32 padding (#414) --- .../Crypto/Paddings/X932PaddingTests.cs | 172 ++++++++++++++++++ Algorithms/Crypto/Paddings/X932Padding.cs | 140 ++++++++++++++ README.md | 1 + 3 files changed, 313 insertions(+) create mode 100644 Algorithms.Tests/Crypto/Paddings/X932PaddingTests.cs create mode 100644 Algorithms/Crypto/Paddings/X932Padding.cs diff --git a/Algorithms.Tests/Crypto/Paddings/X932PaddingTests.cs b/Algorithms.Tests/Crypto/Paddings/X932PaddingTests.cs new file mode 100644 index 00000000..22e7daf4 --- /dev/null +++ b/Algorithms.Tests/Crypto/Paddings/X932PaddingTests.cs @@ -0,0 +1,172 @@ +using System; +using Algorithms.Crypto.Paddings; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Crypto.Paddings; + +public class X932PaddingTests +{ + private readonly X932Padding zeroPadding = new X932Padding(false); + private readonly X932Padding randomPadding = new X932Padding(true); + + [Test] + public void AddPadding_WhenCalledWithZeroPadding_ShouldReturnCorrectCode() + { + var inputData = new byte[10]; + const int inputOffset = 5; + + var result = zeroPadding.AddPadding(inputData, inputOffset); + + result.Should().Be(5); + } + + [Test] + public void AddPadding_WhenCalledWithZeroPaddingAndOffsetIsEqualToDataLength_ShouldThrowArgumentException() + { + var inputData = new byte[10]; + const int inputOffset = 10; + + Action action = () => zeroPadding.AddPadding(inputData, inputOffset); + + action.Should().Throw() + .WithMessage("Not enough space in input array for padding"); + } + + [Test] + public void AddPadding_WhenCalledWithZeroPaddingAndOffsetIsGreaterThanDataLength_ShouldThrowArgumentException() + { + var inputData = new byte[10]; + const int inputOffset = 11; + + Action action = () => zeroPadding.AddPadding(inputData, inputOffset); + + action.Should().Throw() + .WithMessage("Not enough space in input array for padding"); + } + + + [Test] + public void AddPadding_WhenCalledWithRandomPadding_ShouldReturnCorrectCode() + { + var inputData = new byte[10]; + const int inputOffset = 5; + + var result = randomPadding.AddPadding(inputData, inputOffset); + + result.Should().Be(5); + } + + [Test] + public void AddPadding_WhenCalledWithRandomPaddingAndOffsetIsEqualToDataLength_ShouldThrowArgumentException() + { + var inputData = new byte[10]; + const int inputOffset = 10; + + Action action = () => randomPadding.AddPadding(inputData, inputOffset); + + action.Should().Throw() + .WithMessage("Not enough space in input array for padding"); + } + + [Test] + public void AddPadding_WhenCalledWithRandomPaddingAndOffsetIsGreaterThanDataLength_ShouldThrowArgumentException() + { + var inputData = new byte[10]; + const int inputOffset = 11; + + Action action = () => randomPadding.AddPadding(inputData, inputOffset); + + action.Should().Throw() + .WithMessage("Not enough space in input array for padding"); + } + + [Test] + public void AddPadding_WhenCalledWithZeroPaddingAndOffsetIsZero_ShouldReturnLengthOfInputData() + { + var inputData = new byte[10]; + const int inputOffset = 0; + + var result = zeroPadding.AddPadding(inputData, inputOffset); + + result.Should().Be(10); + } + + [Test] + public void AddPadding_WhenCalledWithRandomPaddingAndOffsetIsZero_ShouldReturnLengthOfInputData() + { + var inputData = new byte[10]; + const int inputOffset = 0; + + var result = randomPadding.AddPadding(inputData, inputOffset); + + result.Should().Be(10); + } + + [Test] + public void AddPadding_WhenCalledWithRandomPadding_ShouldFillThePaddingWithRandomValues() + { + var inputData = new byte[10]; + const int inputOffset = 5; + + var result = randomPadding.AddPadding(inputData, inputOffset); + + for (var i = inputOffset; i < inputData.Length - 1; i++) + { + inputData[i].Should().BeInRange(0, 255); + } + + inputData[^1].Should().Be((byte)result); + } + + [Test] + public void RemovePadding_WhenCalledInEmptyArray_ShouldReturnAnEmptyArray() + { + var result = zeroPadding.RemovePadding(Array.Empty()); + + result.Should().AllBeEquivalentTo(Array.Empty()); + } + + [Test] + public void RemovePadding_WhenCalledOnArrayWithValidPadding_ShouldRemovePadding() + { + var inputData = new byte[] { 1, 2, 3, 2 }; + var expectedOutput = new byte[] { 1, 2 }; + + var result = zeroPadding.RemovePadding(inputData); + + result.Should().BeEquivalentTo(expectedOutput); + } + + [Test] + public void RemovePadding_WithInvalidPadding_ThrowsArgumentException() + { + var inputData = new byte[] { 1, 2, 3, 5 }; + + Action act = () => zeroPadding.RemovePadding(inputData); + + act.Should().Throw() + .WithMessage("Invalid padding length"); + } + + [Test] + public void GetPaddingCount_WithValidPadding_ReturnsCorrectCount() + { + var inputData = new byte[] { 1, 2, 3, 2 }; + + var result = zeroPadding.GetPaddingCount(inputData); + + result.Should().Be(2); + } + + [Test] + public void GetPaddingCount_WithInvalidPadding_ThrowsArgumentException() + { + var inputData = new byte[] { 1, 2, 3, 5 }; + + Action action = () => zeroPadding.GetPaddingCount(inputData); + + action.Should().Throw() + .WithMessage("Pad block corrupted"); + } +} diff --git a/Algorithms/Crypto/Paddings/X932Padding.cs b/Algorithms/Crypto/Paddings/X932Padding.cs new file mode 100644 index 00000000..ea03fa32 --- /dev/null +++ b/Algorithms/Crypto/Paddings/X932Padding.cs @@ -0,0 +1,140 @@ +using System; +using System.Security.Cryptography; + +namespace Algorithms.Crypto.Paddings; + +/// +/// +/// X9.32 padding is a padding scheme for symmetric encryption algorithms that is based on the ANSI X9.32 standard. +/// +/// +/// It adds bytes with value equal to 0 up to the end of the plaintext. For example if the plaintext is 13 bytes long +/// and the block size is 16 bytes, then 2 bytes with value 0 will be added as padding. The last byte indicates the +/// number of padding bytes. +/// +/// +/// If random padding mode is selected then random bytes are added before the padding bytes. For example, if the plaintext +/// is 13 bytes long, then 2 random bytes will be added as padding. Again the last byte indicates the number of padding +/// bytes. +/// +/// +public class X932Padding +{ + private readonly bool useRandomPadding; + + /// + /// Initializes a new instance of the class with the specified padding mode. + /// + /// A boolean value that indicates whether to use random bytes as padding or not. + public X932Padding(bool useRandomPadding) => + this.useRandomPadding = useRandomPadding; + + /// + /// Adds padding to the input data according to the X9.23 padding scheme. + /// + /// The input data array to be padded. + /// The offset in the input data array where the padding should start. + /// The number of padding bytes added. + /// + /// Thrown when the input offset is greater than or equal to the input data length. + /// + public int AddPadding(byte[] inputData, int inputOffset) + { + // Check if the input offset is valid. + if (inputOffset >= inputData.Length) + { + throw new ArgumentException("Not enough space in input array for padding"); + } + + // Calculate the number of padding bytes needed. + var code = (byte)(inputData.Length - inputOffset); + + // Fill the remaining bytes with random or zero bytes + while (inputOffset < inputData.Length - 1) + { + if (!useRandomPadding) + { + // Use zero bytes if random padding is disabled. + inputData[inputOffset] = 0; + } + else + { + // Use random bytes if random padding is enabled. + inputData[inputOffset] = (byte)RandomNumberGenerator.GetInt32(255); + } + + inputOffset++; + } + + // Set the last byte to the number of padding bytes. + inputData[inputOffset] = code; + + // Return the number of padding bytes. + return code; + } + + /// + /// Removes padding from the input data according to the X9.23 padding scheme. + /// + /// The input data array to be unpadded. + /// The unpadded data array. + /// + /// Thrown when the input data is empty or has an invalid padding length. + /// + public byte[] RemovePadding(byte[] inputData) + { + // Check if the array is empty. + if (inputData.Length == 0) + { + return Array.Empty(); + } + + // Get the padding length from the last byte of the input data. + var paddingLength = inputData[^1]; + + // Check if the padding length is valid. + if (paddingLength < 1 || paddingLength > inputData.Length) + { + throw new ArgumentException("Invalid padding length"); + } + + // Create a new array for the output data. + var output = new byte[inputData.Length - paddingLength]; + + // Copy the input data without the padding bytes to the output array. + Array.Copy(inputData, output, output.Length); + + // Return the output array. + return output; + } + + /// + /// Gets the number of padding bytes in the input data according to the X9.23 padding scheme. + /// + /// The input data array to be checked. + /// The number of padding bytes in the input data. + /// + /// Thrown when the input data has a corrupted padding block. + /// + public int GetPaddingCount(byte[] input) + { + // Get the last byte of the input data, which is the padding length. + var count = input[^1] & 0xFF; + + // Calculate the position of the first padding byte. + var position = input.Length - count; + + // Check if the position and count are valid using bitwise operations. + // If either of them is negative or zero, the result will be negative. + var failed = (position | (count - 1)) >> 31; + + // Throw an exception if the result is negative. + if (failed != 0) + { + throw new ArgumentException("Pad block corrupted"); + } + + // Return the padding length. + return count; + } +} diff --git a/README.md b/README.md index e42a864c..717aeaa6 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ find more than one implementation for the same objective but using different alg * [Paddings](./Algorithms/Crypto/Paddings/) * [ISO 10125-2 Padding](./Algorithms/Crypto/Paddings/ISO10126d2Padding.cs) * [ISO 7816-4 Padding](./Algorithms/Crypto/Paddings/ISO7816d4Padding.cs) + * [X9.32 Padding](./Algorithms/Crypto/Paddings/X932Padding.cs) * [TBC Padding](./Algorithms/Crypto/Paddings/TbcPadding.cs) * [PKCS7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) * [Data Compression](./Algorithms/DataCompression) From 0677638e785ac2c3e13bde91b49981b92170ffeb Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Thu, 12 Oct 2023 12:51:18 +0300 Subject: [PATCH 071/138] Add MD2 Hashing (#415) --- .../Crypto/Digests/Md2DigestTests.cs | 32 +++ Algorithms/Crypto/Digests/Md2Digest.cs | 224 ++++++++++++++++++ README.md | 4 +- 3 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 Algorithms.Tests/Crypto/Digests/Md2DigestTests.cs create mode 100644 Algorithms/Crypto/Digests/Md2Digest.cs diff --git a/Algorithms.Tests/Crypto/Digests/Md2DigestTests.cs b/Algorithms.Tests/Crypto/Digests/Md2DigestTests.cs new file mode 100644 index 00000000..818ebe10 --- /dev/null +++ b/Algorithms.Tests/Crypto/Digests/Md2DigestTests.cs @@ -0,0 +1,32 @@ +using System; +using System.Text; +using Algorithms.Crypto.Digests; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Crypto.Digesters; + +[NonParallelizable] +public class Md2DigestTests +{ + private readonly Md2Digest digest = new Md2Digest(); + + [TestCase("", "8350E5A3E24C153DF2275C9F80692773")] + [TestCase("a", "32EC01EC4A6DAC72C0AB96FB34C0B5D1")] + [TestCase("abc", "DA853B0D3F88D99B30283A69E6DED6BB")] + [TestCase("message digest", "AB4F496BFB2A530B219FF33031FE06B0")] + [TestCase("abcdefghijklmnopqrstuvwxyz", "4E8DDFF3650292AB5A4108C3AA47940B")] + [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "DA33DEF2A42DF13975352846C30338CD")] + [TestCase("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "D5976F79D83D3A0DC9806C3C66F3EFD8")] + [TestCase("123456789012345678901234567890123456789012345678901234567890123456789012345678901", "6FAD0685C4A3D03E3D352D12BBAD6BE3")] + public void Digest_ReturnsCorrectValue(string input, string expected) + { + var inputBytes = Encoding.ASCII.GetBytes(input); + + var result = digest.Digest(inputBytes); + + var output = Convert.ToHexString(result); + + output.Should().Be(expected); + } +} diff --git a/Algorithms/Crypto/Digests/Md2Digest.cs b/Algorithms/Crypto/Digests/Md2Digest.cs new file mode 100644 index 00000000..e29e976a --- /dev/null +++ b/Algorithms/Crypto/Digests/Md2Digest.cs @@ -0,0 +1,224 @@ +using System; + +namespace Algorithms.Crypto.Digests; + +/// +/// MD2 is a cryptographic hash function that takes an input message and produces a 128-bit output, also called a message +/// digest or a hash. +/// +/// A hash function has two main properties: it is easy to compute the hash from the input, but it is hard to find the +/// input from the hash or to find two different inputs that produce the same hash. +/// +/// +/// MD2 works by first padding the input message to a multiple of 16 bytes and adding a 16-byte checksum to it. Then, it +/// uses a 48-byte auxiliary block and a 256-byte S-table (a fixed permutation of the numbers 0 to 255) to process the +/// message in 16-byte blocks. +/// +/// +/// For each block, it updates the auxiliary block by XORing it with the message block and then applying the S-table 18 +/// times. After all blocks are processed, the first 16 bytes of the auxiliary block become the hash value. +/// +/// +public class Md2Digest +{ + // The S-table is a set of constants generated by shuffling the integers 0 through 255 using a variant of + // Durstenfeld's algorithm with a pseudorandom number generator based on decimal digits of pi. + private static readonly byte[] STable = + { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, + 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202, + 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18, + 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, + 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, + 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3, + 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, + 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, + 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, + 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, + 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, + 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, + 120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, + 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10, + 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20, + }; + + // The X buffer is a 48-byte auxiliary block used to compute the message digest. + private readonly byte[] xBuffer = new byte[48]; + + // The M buffer is a 16-byte auxiliary block that keeps 16 byte blocks from the input data. + private readonly byte[] mBuffer = new byte[16]; + + // The checksum buffer + private readonly byte[] checkSum = new byte[16]; + + private int xBufferOffset; + private int mBufferOffset; + + /// + /// Computes the MD2 hash of the input byte array. + /// + /// The input byte array to be hashed. + /// The MD2 hash as a byte array. + public byte[] Digest(byte[] input) + { + Update(input, 0, input.Length); + + // Pad the input to a multiple of 16 bytes. + var paddingByte = (byte)(mBuffer.Length - mBufferOffset); + + for (var i = mBufferOffset; i < mBuffer.Length; i++) + { + mBuffer[i] = paddingByte; + } + + // Process the checksum of the padded input. + ProcessCheckSum(mBuffer); + + // Process the first block of the padded input. + ProcessBlock(mBuffer); + + // Process the second block of the padded input, which is the checksum. + ProcessBlock(checkSum); + + // Copy the first 16 bytes of the auxiliary block to the output. + var digest = new byte[16]; + + xBuffer.AsSpan(xBufferOffset, 16).CopyTo(digest); + + // Reset the internal state for reuse. + Reset(); + return digest; + } + + /// + /// Resets the engine to its initial state. + /// + private void Reset() + { + xBufferOffset = 0; + for (var i = 0; i != xBuffer.Length; i++) + { + xBuffer[i] = 0; + } + + mBufferOffset = 0; + for (var i = 0; i != mBuffer.Length; i++) + { + mBuffer[i] = 0; + } + + for (var i = 0; i != checkSum.Length; i++) + { + checkSum[i] = 0; + } + } + + /// + /// Performs the compression step of MD2 hash algorithm. + /// + /// The 16 bytes block to be compressed. + /// + /// the compression step is designed to achieve diffusion and confusion, two properties that make it hard to reverse + /// or analyze the hash function. Diffusion means that changing one bit of the input affects many bits of the output, + /// and confusion means that there is no apparent relation between the input and the output. + /// + private void ProcessBlock(byte[] block) + { + // Copying and XORing: The input block is copied to the second and third parts of the internal state, while XORing + // the input block with the first part of the internal state. + // By copying the input block to the second and third parts of the internal state, the compression step ensures + // that each input block contributes to the final output digest. + // By XORing the input block with the first part of the internal state, the compression step introduces a non-linear + // transformation that depends on both the input and the previous state. This makes it difficult to deduce the input + // or the state from the output, or vice versa. + for (var i = 0; i < 16; i++) + { + xBuffer[i + 16] = block[i]; + xBuffer[i + 32] = (byte)(block[i] ^ xBuffer[i]); + } + + var tmp = 0; + + // Mixing: The internal state is mixed using the substitution table for 18 rounds. Each round consists of looping + // over the 48 bytes of the internal state and updating each byte by XORing it with a value from the substitution table. + // The mixing process ensures that each byte of the internal state is affected by every byte of the input block and + // every byte of the substitution table. This creates a high degree of diffusion and confusion, which makes it hard + // to find collisions or preimages for the hash function. + for (var j = 0; j < 18; j++) + { + for (var k = 0; k < 48; k++) + { + tmp = xBuffer[k] ^= STable[tmp]; + tmp &= 0xff; + } + + tmp = (tmp + j) % 256; + } + } + + /// + /// Performs the checksum step of MD2 hash algorithm. + /// + /// The 16 bytes block to calculate the checksum. + /// + /// The checksum step ensures that changing any bit of the input message will change about half of the bits of the + /// checksum, making it harder to find collisions or preimages. + /// + private void ProcessCheckSum(byte[] block) + { + // Assign the last element of checksum to the variable last. This is the initial value of the checksum. + var last = checkSum[15]; + for (var i = 0; i < 16; i++) + { + // Compute the XOR of the current element of the mBuffer array and the last value, and uses it as an index + // to access an element of STable. This is a substitution operation that maps each byte to another byte using + // the STable. + var map = STable[(mBuffer[i] ^ last) & 0xff]; + + // Compute the XOR of the current element of checkSum and the substituted byte, and stores it back to the + // checksum. This is a mixing operation that updates the checksum value with the input data. + checkSum[i] ^= map; + + // Assign the updated element of checksum to last. This is to keep track of the last checksum value for the + // next iteration. + last = checkSum[i]; + } + } + + /// + /// Update the message digest with a single byte. + /// + /// The input byte to digest. + private void Update(byte input) + { + mBuffer[mBufferOffset++] = input; + } + + /// + /// Update the message digest with a block of bytes. + /// + /// The byte array containing the data. + /// The offset into the byte array where the data starts. + /// The length of the data. + private void Update(byte[] input, int inputOffset, int length) + { + // process whole words + while (length >= 16) + { + Array.Copy(input, inputOffset, mBuffer, 0, 16); + ProcessCheckSum(mBuffer); + ProcessBlock(mBuffer); + + length -= 16; + inputOffset += 16; + } + + while (length > 0) + { + Update(input[inputOffset]); + inputOffset++; + length--; + } + } +} diff --git a/README.md b/README.md index 717aeaa6..33497bc5 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,9 @@ find more than one implementation for the same objective but using different alg * [ISO 7816-4 Padding](./Algorithms/Crypto/Paddings/ISO7816d4Padding.cs) * [X9.32 Padding](./Algorithms/Crypto/Paddings/X932Padding.cs) * [TBC Padding](./Algorithms/Crypto/Paddings/TbcPadding.cs) - * [PKCS7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) + * [PKCS7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) + * [Digests](./Algorithms/Crypto/Digests/) + * [MD2 Digest](./Algorithms/Crypto/Digests/Md2Digest.cs) * [Data Compression](./Algorithms/DataCompression) * [Burrows-Wheeler transform](./Algorithms/DataCompression/BurrowsWheelerTransform.cs) * [Huffman Compressor](./Algorithms/DataCompression/HuffmanCompressor.cs) From fe4b357f9145b110bca342b2a733f745932b179c Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Sat, 14 Oct 2023 15:16:43 +0300 Subject: [PATCH 072/138] Add Jaccard Similarity (#419) --- .../Similarity/JaccardDistanceTests.cs | 36 +++++++ .../Similarity/JaccardSimilarityTests.cs | 35 +++++++ .../Strings/Similarity/JaccardDistance.cs | 48 +++++++++ .../Strings/Similarity/JaccardSimilarity.cs | 98 +++++++++++++++++++ README.md | 3 + 5 files changed, 220 insertions(+) create mode 100644 Algorithms.Tests/Strings/Similarity/JaccardDistanceTests.cs create mode 100644 Algorithms.Tests/Strings/Similarity/JaccardSimilarityTests.cs create mode 100644 Algorithms/Strings/Similarity/JaccardDistance.cs create mode 100644 Algorithms/Strings/Similarity/JaccardSimilarity.cs diff --git a/Algorithms.Tests/Strings/Similarity/JaccardDistanceTests.cs b/Algorithms.Tests/Strings/Similarity/JaccardDistanceTests.cs new file mode 100644 index 00000000..bfa04f35 --- /dev/null +++ b/Algorithms.Tests/Strings/Similarity/JaccardDistanceTests.cs @@ -0,0 +1,36 @@ +using System; +using Algorithms.Strings.Similarity; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Strings.Similarity; + +public class JaccardDistanceTests +{ + private readonly JaccardDistance jaccard = new JaccardDistance(); + private readonly double precision = 0.0001; + + [TestCase("left", null)] + [TestCase(null, "right")] + [TestCase(null, null)] + public void Calculate_WhenStringsAreNull_ThrowsArgumentNullException(string left, string right) + { + Action action = () => jaccard.Calculate(left, right); + action.Should().Throw(); + } + + + [TestCase("", "", 0.0d)] + [TestCase("left", "", 1.0d)] + [TestCase("", "right", 1.0d)] + [TestCase("frog", "fog", 0.25d)] + [TestCase("fly", "ant", 1.0d)] + [TestCase("elephant", "hippo", 0.777777d)] + [TestCase("ABC Corporation", "ABC Corp", 0.36363d)] + public void Calculate_WhenProvidedWithStrings_CalculatesCorrectDistance(string left, string right, double expected) + { + var distance = jaccard.Calculate(left, right); + + distance.Should().BeApproximately(expected, precision); + } +} diff --git a/Algorithms.Tests/Strings/Similarity/JaccardSimilarityTests.cs b/Algorithms.Tests/Strings/Similarity/JaccardSimilarityTests.cs new file mode 100644 index 00000000..eb33c6b7 --- /dev/null +++ b/Algorithms.Tests/Strings/Similarity/JaccardSimilarityTests.cs @@ -0,0 +1,35 @@ +using System; +using Algorithms.Strings.Similarity; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Strings.Similarity; + +public class JaccardSimilarityTests +{ + private readonly JaccardSimilarity jaccard = new JaccardSimilarity(); + private readonly double precision = 0.0001; + + [TestCase("left", null)] + [TestCase(null, "right")] + [TestCase(null, null)] + public void Calculate_WhenStringsAreNull_ThrowsArgumentNullException(string left, string right) + { + Action action = () => jaccard.Calculate(left, right); + action.Should().Throw(); + } + + [TestCase("", "", 1.0d)] + [TestCase("left", "", 0.0d)] + [TestCase("", "right", 0.0d)] + [TestCase("frog", "fog", 0.75d)] + [TestCase("fly", "ant", 0.0d)] + [TestCase("elephant", "hippo", 0.22222d)] + [TestCase("ABC Corporation", "ABC Corp", 0.636363d)] + public void Calculate_WhenProvidedWithStrings_CalculatesTheCorrectDistance(string left, string right, double expected) + { + var similarity = jaccard.Calculate(left, right); + + similarity.Should().BeApproximately(expected, precision); + } +} diff --git a/Algorithms/Strings/Similarity/JaccardDistance.cs b/Algorithms/Strings/Similarity/JaccardDistance.cs new file mode 100644 index 00000000..2765fcb1 --- /dev/null +++ b/Algorithms/Strings/Similarity/JaccardDistance.cs @@ -0,0 +1,48 @@ +namespace Algorithms.Strings.Similarity; + +/// +/// +/// Jaccard distance is a measure of two sets of data are. It is calculated by subtracting the Jaccard similarity +/// coefficient from 1, or, equivalently by dividing the difference of the sizes of the union and intersection of two sets +/// by the size of the union. +/// +/// +/// For example, suppose we have two sets of words: +/// +/// +/// A = {apple, banana, cherry, date} +/// +/// +/// B = {banana, cherry, elderberry, fig} +/// +/// +/// +/// +/// The number of common elements in both sets is 2 (banana and cherry). The number of elements in either set is 6 +/// (apple, banana, cherry, date, elderberry, fig). +/// +/// +/// The Jaccard similarity coefficient is 2 / 6 = 0.333333 or 33.333% similarity. +/// +/// +/// The Jaccard distance is 1 - 0.33333 = 0.66667. This means that the two sets are about 67% different. +/// +/// +/// Jaccard distance is commonly used to calculate a matrix of clustering and multidimensional scaling of sample tests. +/// +/// +public class JaccardDistance +{ + private readonly JaccardSimilarity jaccardSimilarity = new(); + + /// + /// Calculate the Jaccard distance between to strings. + /// + /// The first string. + /// The second string. + /// The Jaccard distance. + public double Calculate(string left, string right) + { + return 1.0 - jaccardSimilarity.Calculate(left, right); + } +} diff --git a/Algorithms/Strings/Similarity/JaccardSimilarity.cs b/Algorithms/Strings/Similarity/JaccardSimilarity.cs new file mode 100644 index 00000000..63fe23cc --- /dev/null +++ b/Algorithms/Strings/Similarity/JaccardSimilarity.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; + +namespace Algorithms.Strings.Similarity; + +/// +/// +/// Jaccard similarity is a statistic that measures how similar two sets of data are. It is calculated by dividing +/// the number of common elements in both sets by the number of elements in either set. More formally, it is the +/// quotient of the division of the size of the size of the intersection divided by the size of the union of two sets. +/// +/// +/// The result is a value between 0 and 1, where 0 means no similarity and 1 means perfect similarity. +/// +/// +/// For example, suppose we have two sets of words: +/// +/// +/// A = {apple, banana, cherry, date} +/// +/// +/// B = {banana, cherry, elderberry, fig} +/// +/// +/// +/// +/// The number of common elements in both sets is 2 (banana and cherry). The number of elements in either set is 6 +/// (apple, banana, cherry, date, elderberry, fig). +/// +/// +/// The Jaccard similarity coefficient is 2 / 6 = 0.333333 or 33.333% similarity. +/// +/// +public class JaccardSimilarity +{ + /// + /// Calculates the Jaccard similarity coefficient between two strings. + /// + /// The first string to compare. + /// The second string to compare. + /// A double value between 0 and 1 that represents the similarity of the two strings. + /// Thrown when either the input is null. + /// + /// This method uses a HashSet to represent the sets of characters in the input strings. + /// + public double Calculate(string left, string right) + { + // Validate the input strings before proceeding. + ValidateInput(left, right); + + // Get the lengths of the input strings. + var leftLength = left.Length; + var rightLength = right.Length; + + // If both strings are empty, return 1.0 as the similarity coefficient. + if (leftLength == 0 && rightLength == 0) + { + return 1.0d; + } + + // If either string is empty, return 0.0 as the similarity coefficient. + if (leftLength == 0 || rightLength == 0) + { + return 0.0d; + } + + // Get the unique characters in each string. + var leftSet = new HashSet(left); + var rightSet = new HashSet(right); + + // Get the union of the two strings. + var unionSet = new HashSet(leftSet); + foreach (var c in rightSet) + { + unionSet.Add(c); + } + + // Calculate the intersection size of the two strings. + var intersectionSize = leftSet.Count + rightSet.Count - unionSet.Count; + + // Return the Jaccard similarity coefficient as the ratio of intersection to union. + return 1.0d * intersectionSize / unionSet.Count; + } + + /// + /// Validates the input strings and throws an exception if either is null. + /// + /// The first string to validate. + /// The second string to validate. + private void ValidateInput(string left, string right) + { + if (left == null || right == null) + { + var paramName = left == null ? nameof(left) : nameof(right); + throw new ArgumentNullException(paramName, "Input cannot be null"); + } + } +} diff --git a/README.md b/README.md index 33497bc5..fde4001d 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,9 @@ find more than one implementation for the same objective but using different alg * [A019434 Fermat Primes](./Algorithms/Sequences/FermatPrimesSequence.cs) * [A181391 Van Eck's](./Algorithms/Sequences/VanEcksSequence.cs) * [String](./Algorithms/Strings) + * [Similarity](./Algorithms/Strings/Similarity/) + * [Jaccard Similarity](./Algorithms/Strings/Similarity/JaccardSimilarity.cs) + * [Jaccard Distance](./Algorithms/Strings/Similarity/JaccardDistance.cs) * [Longest Consecutive Character](./Algorithms/Strings/GeneralStringAlgorithms.cs) * [Naive String Search](./Algorithms/Strings/NaiveStringSearch.cs) * [Rabin Karp](./Algorithms/Strings/RabinKarp.cs) From 102f8c6ad240d5d0fe56bb0523429db76786404d Mon Sep 17 00:00:00 2001 From: Praful Katare <47990928+Kpraful@users.noreply.github.com> Date: Sat, 14 Oct 2023 18:03:37 +0530 Subject: [PATCH 073/138] Add Bellman ford algorithm (#416) --- Algorithms.Tests/Graph/BellmanFordTests.cs | 75 +++++++++++++ Algorithms/Graph/BellmanFord.cs | 120 +++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 Algorithms.Tests/Graph/BellmanFordTests.cs create mode 100644 Algorithms/Graph/BellmanFord.cs diff --git a/Algorithms.Tests/Graph/BellmanFordTests.cs b/Algorithms.Tests/Graph/BellmanFordTests.cs new file mode 100644 index 00000000..c38727ec --- /dev/null +++ b/Algorithms.Tests/Graph/BellmanFordTests.cs @@ -0,0 +1,75 @@ +using Algorithms.Graph; +using DataStructures.Graph; +using NUnit.Framework; +using FluentAssertions; +using System.Collections.Generic; +using System; + +namespace Algorithms.Tests.Graph +{ + public class BellmanFordTests + { + [Test] + public void CorrectDistancesTest() + { + var graph = new DirectedWeightedGraph(10); + + var vertex1 = graph.AddVertex(1); + var vertex2 = graph.AddVertex(2); + var vertex3 = graph.AddVertex(3); + var vertex4 = graph.AddVertex(4); + var vertex5 = graph.AddVertex(5); + + graph.AddEdge(vertex1, vertex2, 3); + graph.AddEdge(vertex1, vertex5, -4); + graph.AddEdge(vertex1, vertex3, 8); + graph.AddEdge(vertex2, vertex5, 7); + graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex3, vertex2, 4); + graph.AddEdge(vertex4, vertex3, -5); + graph.AddEdge(vertex4, vertex1, 2); + graph.AddEdge(vertex5, vertex4, 6); + + var expectedDistances = new Dictionary, double> + { + { vertex1, 0 }, + { vertex2, 1 }, + { vertex3, -3 }, + { vertex4, 2 }, + { vertex5, -4 } + }; + + var bellmanFord = new BellmanFord(graph, new Dictionary, double>(), new Dictionary, Vertex?>()); + + var calculatedDistances = bellmanFord.Run(vertex1); + + foreach (var vertex in graph.Vertices) + { + if (vertex != null) + { + calculatedDistances[vertex].Should().BeApproximately(expectedDistances[vertex], 0.001); + } + } + } + + [Test] + public void NegativeWeightCycleTest() + { + var graph = new DirectedWeightedGraph(3); + + var vertex1 = graph.AddVertex(1); + var vertex2 = graph.AddVertex(2); + var vertex3 = graph.AddVertex(3); + + graph.AddEdge(vertex1, vertex2, -1); + graph.AddEdge(vertex2, vertex3, -2); + graph.AddEdge(vertex3, vertex1, -3); + + var bellmanFord = new BellmanFord(graph, new Dictionary, double>(), new Dictionary, Vertex?>()); + + Action action = () => bellmanFord.Run(vertex1); + + action.Should().Throw().WithMessage("Graph contains a negative weight cycle."); + } + } +} diff --git a/Algorithms/Graph/BellmanFord.cs b/Algorithms/Graph/BellmanFord.cs new file mode 100644 index 00000000..6605a6cf --- /dev/null +++ b/Algorithms/Graph/BellmanFord.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using DataStructures.Graph; + +namespace Algorithms.Graph +{ + /// + /// Bellman-Ford algorithm on directed weighted graph. + /// + /// Generic type of data in the graph. + public class BellmanFord + { + private readonly DirectedWeightedGraph graph; + private readonly Dictionary, double> distances; + private readonly Dictionary, Vertex?> predecessors; + + public BellmanFord(DirectedWeightedGraph graph, Dictionary, double> distances, Dictionary, Vertex?> predecessors) + { + this.graph = graph; + this.distances = distances; + this.predecessors = predecessors; + } + + /// + /// Runs the Bellman-Ford algorithm to find the shortest distances from the source vertex to all other vertices. + /// + /// Source vertex for shortest path calculation. + /// + /// A dictionary containing the shortest distances from the source vertex to all other vertices. + /// If a vertex is unreachable from the source, it will have a value of double.PositiveInfinity. + /// + public Dictionary, double> Run(Vertex sourceVertex) + { + InitializeDistances(sourceVertex); + RelaxEdges(); + CheckForNegativeCycles(); + return distances; + } + + private void InitializeDistances(Vertex sourceVertex) + { + foreach (var vertex in graph.Vertices) + { + if (vertex != null) + { + distances[vertex] = double.PositiveInfinity; + predecessors[vertex] = null; + } + } + + distances[sourceVertex] = 0; + } + + private void RelaxEdges() + { + int vertexCount = graph.Count; + + for (int i = 0; i < vertexCount - 1; i++) + { + foreach (var vertex in graph.Vertices) + { + if (vertex != null) + { + RelaxEdgesForVertex(vertex); + } + } + } + } + + private void RelaxEdgesForVertex(Vertex u) + { + foreach (var neighbor in graph.GetNeighbors(u)) + { + if (neighbor == null) + { + continue; + } + + var v = neighbor; + var weight = graph.AdjacentDistance(u, v); + + if (distances[u] + weight < distances[v]) + { + distances[v] = distances[u] + weight; + predecessors[v] = u; + } + } + } + + private void CheckForNegativeCycles() + { + foreach (var vertex in graph.Vertices) + { + if (vertex != null) + { + CheckForNegativeCyclesForVertex(vertex); + } + } + } + + private void CheckForNegativeCyclesForVertex(Vertex u) + { + foreach (var neighbor in graph.GetNeighbors(u)) + { + if (neighbor == null) + { + continue; + } + + var v = neighbor; + var weight = graph.AdjacentDistance(u, v); + + if (distances[u] + weight < distances[v]) + { + throw new InvalidOperationException("Graph contains a negative weight cycle."); + } + } + } + } +} From 8dfab4858ba3d0a22194d7be76ce2de74467d62f Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Sat, 14 Oct 2023 15:42:41 +0300 Subject: [PATCH 074/138] Reorganize String Algorithms (#418) --- .../{ => PatternMatching}/BoyerMoreTests.cs | 1 + .../KnuthMorrisPrattSearcherTests.cs | 1 + .../NaiveStringSearchTests.cs | 1 + .../{ => PatternMatching}/RabinKarpTests.cs | 1 + .../ZblockSubstringSearchTest.cs | 1 + .../{ => Similarity}/HammingDistanceTests.cs | 1 + .../{ => Similarity}/JaroSimilarityTests.cs | 1 + .../JaroWinklerDistanceTests.cs | 1 + .../{ => PatternMatching}/BoyerMoore.cs | 2 +- .../KnuthMorrisPrattSearcher.cs | 2 +- .../NaiveStringSearch.cs | 2 +- .../{ => PatternMatching}/RabinKarp.cs | 2 +- .../ZblockSubstringSearch.cs | 2 +- .../{ => Similarity}/HammingDistance.cs | 2 +- .../{ => Similarity}/JaroSimilarity.cs | 2 +- .../{ => Similarity}/JaroWinklerDistance.cs | 3 +-- README.md | 21 +++++++++---------- 17 files changed, 26 insertions(+), 20 deletions(-) rename Algorithms.Tests/Strings/{ => PatternMatching}/BoyerMoreTests.cs (94%) rename Algorithms.Tests/Strings/{ => PatternMatching}/KnuthMorrisPrattSearcherTests.cs (98%) rename Algorithms.Tests/Strings/{ => PatternMatching}/NaiveStringSearchTests.cs (97%) rename Algorithms.Tests/Strings/{ => PatternMatching}/RabinKarpTests.cs (95%) rename Algorithms.Tests/Strings/{ => PatternMatching}/ZblockSubstringSearchTest.cs (95%) rename Algorithms.Tests/Strings/{ => Similarity}/HammingDistanceTests.cs (95%) rename Algorithms.Tests/Strings/{ => Similarity}/JaroSimilarityTests.cs (94%) rename Algorithms.Tests/Strings/{ => Similarity}/JaroWinklerDistanceTests.cs (94%) rename Algorithms/Strings/{ => PatternMatching}/BoyerMoore.cs (99%) rename Algorithms/Strings/{ => PatternMatching}/KnuthMorrisPrattSearcher.cs (98%) rename Algorithms/Strings/{ => PatternMatching}/NaiveStringSearch.cs (96%) rename Algorithms/Strings/{ => PatternMatching}/RabinKarp.cs (98%) rename Algorithms/Strings/{ => PatternMatching}/ZblockSubstringSearch.cs (97%) rename Algorithms/Strings/{ => Similarity}/HammingDistance.cs (96%) rename Algorithms/Strings/{ => Similarity}/JaroSimilarity.cs (98%) rename Algorithms/Strings/{ => Similarity}/JaroWinklerDistance.cs (97%) diff --git a/Algorithms.Tests/Strings/BoyerMoreTests.cs b/Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs similarity index 94% rename from Algorithms.Tests/Strings/BoyerMoreTests.cs rename to Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs index f3f44771..09247560 100644 --- a/Algorithms.Tests/Strings/BoyerMoreTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs @@ -1,4 +1,5 @@ using Algorithms.Strings; +using Algorithms.Strings.PatternMatching; using NUnit.Framework; namespace Algorithms.Tests.Strings diff --git a/Algorithms.Tests/Strings/KnuthMorrisPrattSearcherTests.cs b/Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs similarity index 98% rename from Algorithms.Tests/Strings/KnuthMorrisPrattSearcherTests.cs rename to Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs index 0f169db4..e8744b8a 100644 --- a/Algorithms.Tests/Strings/KnuthMorrisPrattSearcherTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs @@ -1,4 +1,5 @@ using Algorithms.Strings; +using Algorithms.Strings.PatternMatching; using NUnit.Framework; namespace Algorithms.Tests.Strings diff --git a/Algorithms.Tests/Strings/NaiveStringSearchTests.cs b/Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs similarity index 97% rename from Algorithms.Tests/Strings/NaiveStringSearchTests.cs rename to Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs index b73a6008..abeb0912 100644 --- a/Algorithms.Tests/Strings/NaiveStringSearchTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs @@ -1,5 +1,6 @@ using System.Linq; using Algorithms.Strings; +using Algorithms.Strings.PatternMatching; using NUnit.Framework; namespace Algorithms.Tests.Strings diff --git a/Algorithms.Tests/Strings/RabinKarpTests.cs b/Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs similarity index 95% rename from Algorithms.Tests/Strings/RabinKarpTests.cs rename to Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs index df971f6b..7c9fe7fe 100644 --- a/Algorithms.Tests/Strings/RabinKarpTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Algorithms.Strings; +using Algorithms.Strings.PatternMatching; using NUnit.Framework; namespace Algorithms.Tests.Strings diff --git a/Algorithms.Tests/Strings/ZblockSubstringSearchTest.cs b/Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs similarity index 95% rename from Algorithms.Tests/Strings/ZblockSubstringSearchTest.cs rename to Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs index 262e8344..de9cdf1f 100644 --- a/Algorithms.Tests/Strings/ZblockSubstringSearchTest.cs +++ b/Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs @@ -1,4 +1,5 @@ using Algorithms.Strings; +using Algorithms.Strings.PatternMatching; using NUnit.Framework; namespace Algorithms.Tests.Strings diff --git a/Algorithms.Tests/Strings/HammingDistanceTests.cs b/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs similarity index 95% rename from Algorithms.Tests/Strings/HammingDistanceTests.cs rename to Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs index 1a2c7702..2f21cf3a 100644 --- a/Algorithms.Tests/Strings/HammingDistanceTests.cs +++ b/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs @@ -1,6 +1,7 @@ using Algorithms.Strings; using NUnit.Framework; using System; +using Algorithms.Strings.Similarity; namespace Algorithms.Tests.Strings { diff --git a/Algorithms.Tests/Strings/JaroSimilarityTests.cs b/Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs similarity index 94% rename from Algorithms.Tests/Strings/JaroSimilarityTests.cs rename to Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs index 390e69d6..48800e14 100644 --- a/Algorithms.Tests/Strings/JaroSimilarityTests.cs +++ b/Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs @@ -1,4 +1,5 @@ using Algorithms.Strings; +using Algorithms.Strings.Similarity; using FluentAssertions; using NUnit.Framework; diff --git a/Algorithms.Tests/Strings/JaroWinklerDistanceTests.cs b/Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs similarity index 94% rename from Algorithms.Tests/Strings/JaroWinklerDistanceTests.cs rename to Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs index 7f908c96..e3a07247 100644 --- a/Algorithms.Tests/Strings/JaroWinklerDistanceTests.cs +++ b/Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs @@ -1,4 +1,5 @@ using Algorithms.Strings; +using Algorithms.Strings.Similarity; using FluentAssertions; using NUnit.Framework; diff --git a/Algorithms/Strings/BoyerMoore.cs b/Algorithms/Strings/PatternMatching/BoyerMoore.cs similarity index 99% rename from Algorithms/Strings/BoyerMoore.cs rename to Algorithms/Strings/PatternMatching/BoyerMoore.cs index b5b36d1e..c415d79c 100644 --- a/Algorithms/Strings/BoyerMoore.cs +++ b/Algorithms/Strings/PatternMatching/BoyerMoore.cs @@ -1,6 +1,6 @@ using System; -namespace Algorithms.Strings +namespace Algorithms.Strings.PatternMatching { /// /// The idea: You compare the pattern with the text from right to left. diff --git a/Algorithms/Strings/KnuthMorrisPrattSearcher.cs b/Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs similarity index 98% rename from Algorithms/Strings/KnuthMorrisPrattSearcher.cs rename to Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs index 879f6fff..d4a4a2b8 100644 --- a/Algorithms/Strings/KnuthMorrisPrattSearcher.cs +++ b/Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Algorithms.Strings +namespace Algorithms.Strings.PatternMatching { public class KnuthMorrisPrattSearcher { diff --git a/Algorithms/Strings/NaiveStringSearch.cs b/Algorithms/Strings/PatternMatching/NaiveStringSearch.cs similarity index 96% rename from Algorithms/Strings/NaiveStringSearch.cs rename to Algorithms/Strings/PatternMatching/NaiveStringSearch.cs index acab102a..e9c84e37 100644 --- a/Algorithms/Strings/NaiveStringSearch.cs +++ b/Algorithms/Strings/PatternMatching/NaiveStringSearch.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; // Implements the traditional naive string matching algorithm in C# for TheAlgorithms/C-Sharp. -namespace Algorithms.Strings +namespace Algorithms.Strings.PatternMatching { /// /// Implements the traditional naive string matching algorithm in C#. diff --git a/Algorithms/Strings/RabinKarp.cs b/Algorithms/Strings/PatternMatching/RabinKarp.cs similarity index 98% rename from Algorithms/Strings/RabinKarp.cs rename to Algorithms/Strings/PatternMatching/RabinKarp.cs index 294f4075..24e1f190 100644 --- a/Algorithms/Strings/RabinKarp.cs +++ b/Algorithms/Strings/PatternMatching/RabinKarp.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Algorithms.Strings +namespace Algorithms.Strings.PatternMatching { /// /// The idea: You calculate the hash for the pattern p and the hash values for all the prefixes of the text diff --git a/Algorithms/Strings/ZblockSubstringSearch.cs b/Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs similarity index 97% rename from Algorithms/Strings/ZblockSubstringSearch.cs rename to Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs index dc96b537..1c6db18f 100644 --- a/Algorithms/Strings/ZblockSubstringSearch.cs +++ b/Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs @@ -1,4 +1,4 @@ -namespace Algorithms.Strings +namespace Algorithms.Strings.PatternMatching { /// Implementation Z-block substring search. /// diff --git a/Algorithms/Strings/HammingDistance.cs b/Algorithms/Strings/Similarity/HammingDistance.cs similarity index 96% rename from Algorithms/Strings/HammingDistance.cs rename to Algorithms/Strings/Similarity/HammingDistance.cs index 2490bd67..f1d22ce1 100644 --- a/Algorithms/Strings/HammingDistance.cs +++ b/Algorithms/Strings/Similarity/HammingDistance.cs @@ -1,6 +1,6 @@ using System; -namespace Algorithms.Strings +namespace Algorithms.Strings.Similarity { /// /// diff --git a/Algorithms/Strings/JaroSimilarity.cs b/Algorithms/Strings/Similarity/JaroSimilarity.cs similarity index 98% rename from Algorithms/Strings/JaroSimilarity.cs rename to Algorithms/Strings/Similarity/JaroSimilarity.cs index 82db856c..95a69af9 100644 --- a/Algorithms/Strings/JaroSimilarity.cs +++ b/Algorithms/Strings/Similarity/JaroSimilarity.cs @@ -1,6 +1,6 @@ using System; -namespace Algorithms.Strings +namespace Algorithms.Strings.Similarity { /// /// diff --git a/Algorithms/Strings/JaroWinklerDistance.cs b/Algorithms/Strings/Similarity/JaroWinklerDistance.cs similarity index 97% rename from Algorithms/Strings/JaroWinklerDistance.cs rename to Algorithms/Strings/Similarity/JaroWinklerDistance.cs index cb2c5492..488ea381 100644 --- a/Algorithms/Strings/JaroWinklerDistance.cs +++ b/Algorithms/Strings/Similarity/JaroWinklerDistance.cs @@ -1,7 +1,6 @@ -using System; using System.Linq; -namespace Algorithms.Strings +namespace Algorithms.Strings.Similarity { /// /// diff --git a/README.md b/README.md index fde4001d..be77da6d 100644 --- a/README.md +++ b/README.md @@ -177,20 +177,19 @@ find more than one implementation for the same objective but using different alg * [A057588 Kummer Numbers](./Algorithms/Sequences/KummerNumbersSequence.cs) * [A019434 Fermat Primes](./Algorithms/Sequences/FermatPrimesSequence.cs) * [A181391 Van Eck's](./Algorithms/Sequences/VanEcksSequence.cs) - * [String](./Algorithms/Strings) + * [String](./Algorithms/Strings) * [Similarity](./Algorithms/Strings/Similarity/) - * [Jaccard Similarity](./Algorithms/Strings/Similarity/JaccardSimilarity.cs) - * [Jaccard Distance](./Algorithms/Strings/Similarity/JaccardDistance.cs) - * [Longest Consecutive Character](./Algorithms/Strings/GeneralStringAlgorithms.cs) - * [Naive String Search](./Algorithms/Strings/NaiveStringSearch.cs) - * [Rabin Karp](./Algorithms/Strings/RabinKarp.cs) - * [Boyer Moore](./Algorithms/Strings/BoyerMoore.cs) + * [Hamming Distance](./Algorithms/Strings/HammingDistance.cs) + * [Jaro Similarity](./Algorithms/Strings/JaroSimilarity.cs) + * [Jaro-Winkler Distance](./Algorithms/Strings/JaroWinklerDistance.cs) + * [Pattern Matching](./Algorithms/Strings/PatternMatching/) + * [Longest Consecutive Character](./Algorithms/Strings/PatternMatching/GeneralStringAlgorithms.cs) + * [Naive String Search](./Algorithms/Strings/PatternMatching/NaiveStringSearch.cs) + * [Rabin Karp](./Algorithms/Strings/PatternMatching/RabinKarp.cs) + * [Boyer Moore](./Algorithms/Strings/PatternMatching/BoyerMoore.cs) * [Palindrome Checker](./Algorithms/Strings/Palindrome.cs) * [Get all permutations of a string](./Algorithms/Strings/Permutation.cs) - * [Levenshtein Distance](./Algorithms/Strings/LevenshteinDistance.cs) - * [Hamming Distance](./Algorithms/Strings/HammingDistance.cs) - * [Jaro Similarity](./Algorithms/Strings/JaroSimilarity.cs) - * [Jaro-Winkler Distance](./Algorithms/Strings/JaroWinklerDistance.cs) + * [Z-block substring search](./Algorithms/Strings/ZblockSubstringSearch.cs) * [Other](./Algorithms/Other) * [Fermat Prime Checker](./Algorithms/Other/FermatPrimeChecker.cs) From e9537abce04c5d9c984fd8f89bf30254c757656d Mon Sep 17 00:00:00 2001 From: Ravi Kishan <57055822+Ravikisha@users.noreply.github.com> Date: Sat, 14 Oct 2023 20:35:16 +0530 Subject: [PATCH 075/138] Add HashTable (#417) --- .../Hashing/HashTableTests.cs | 385 ++++++++++++++++++ .../Hashing/NumberTheory/PrimeNumberTests.cs | 112 +++++ DataStructures/Hashing/Entry.cs | 28 ++ DataStructures/Hashing/HashTable.cs | 328 +++++++++++++++ .../Hashing/NumberTheory/PrimeNumber.cs | 76 ++++ README.md | 8 +- 6 files changed, 933 insertions(+), 4 deletions(-) create mode 100644 DataStructures.Tests/Hashing/HashTableTests.cs create mode 100644 DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs create mode 100644 DataStructures/Hashing/Entry.cs create mode 100644 DataStructures/Hashing/HashTable.cs create mode 100644 DataStructures/Hashing/NumberTheory/PrimeNumber.cs diff --git a/DataStructures.Tests/Hashing/HashTableTests.cs b/DataStructures.Tests/Hashing/HashTableTests.cs new file mode 100644 index 00000000..ede5c14b --- /dev/null +++ b/DataStructures.Tests/Hashing/HashTableTests.cs @@ -0,0 +1,385 @@ +using System; +using System.Collections.Generic; +using DataStructures.Hashing; +using NUnit.Framework; + +namespace DataStructures.Tests.Hashing +{ + [TestFixture] + public class HashTableTests + { + [Test] + public void Add_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(); + + Assert.Throws(() => hashTable.Add(null, 1)); + } + + [Test] + public void Add_ThrowsException_WhenKeyAlreadyExists() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + + Assert.Throws(() => hashTable.Add("a", 2)); + } + + [Test] + public void Add_IncreasesCount_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + + Assert.AreEqual(1, hashTable.Count); + } + + [Test] + public void Add_DoesNotIncreaseCount_WhenKeyAlreadyExists() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + try + { + hashTable.Add("a", 2); + } + catch (ArgumentException) + { + Console.WriteLine("ArgumentException"); + } + Assert.AreEqual(1, hashTable.Count); + } + + [Test] + public void Add_ThrowsException_WhenValueIsNull() + { + var hashTable = new HashTable(); + + Assert.Throws(() => hashTable.Add("a", null)); + } + + [Test] + public void Add_IncreasesCount_WhenValueDoesNotExist() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + + Assert.AreEqual(1, hashTable.Count); + } + + [Test] + public void Add_DoesNotIncreaseCount_WhenValueAlreadyExists() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + + try + { + hashTable.Add("b", 1); + } + catch (ArgumentException) + { + Console.WriteLine("ArgumentException"); + } + + Assert.AreEqual(2, hashTable.Count); + } + + [Test] + public void Add_IncreasesCount_WhenValueIsNull() + { + var hashTable = new HashTable(); + + try + { + hashTable.Add("a", null); + } + catch (ArgumentNullException) + { + Console.WriteLine("ArgumentNullException"); + } + Assert.AreEqual(0, hashTable.Count); + } + + [Test] + public void Add_IncreasesCount_WhenValueAlreadyExists() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + hashTable.Add("b", 1); + Assert.AreEqual(2, hashTable.Count); + } + + [Test] + public void Remove_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(); + + Assert.Throws(() => hashTable.Remove(null)); + } + + [Test] + public void Remove_ReturnsFalse_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(); + + Assert.IsFalse(hashTable.Remove("a")); + } + + [Test] + public void Remove_ReturnsTrue_WhenKeyExists() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + + Assert.IsTrue(hashTable.Remove("a")); + } + + [Test] + public void Remove_DecreasesCount_WhenKeyExists() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + hashTable.Remove("a"); + + Assert.AreEqual(0, hashTable.Count); + } + + [Test] + public void Remove_DoesNotDecreaseCount_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(); + + hashTable.Remove("a"); + + Assert.AreEqual(0, hashTable.Count); + } + + [Test] + public void ContainsValue_ReturnsFalse_WhenValueDoesNotExist() + { + var hashTable = new HashTable(); + + Assert.IsFalse(hashTable.ContainsValue(1)); + } + + [Test] + public void ContainsValue_ReturnsTrue_WhenValueExists() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + + Assert.IsTrue(hashTable.ContainsValue(1)); + } + + [Test] + public void ContainsValue_ReturnsFalse_WhenValueIsNull() + { + var hashTable = new HashTable(); + + Assert.Throws(() => hashTable.ContainsValue(null)); + } + + [Test] + public void ContainsKey_ReturnsFalse_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(); + + Assert.IsFalse(hashTable.ContainsKey("a")); + } + + [Test] + public void ContainsKey_ReturnsTrue_WhenKeyExists() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + + Assert.IsTrue(hashTable.ContainsKey("a")); + } + + [Test] + public void ContainsKey_ReturnsFalse_WhenKeyIsNull() + { + var hashTable = new HashTable(); + + Assert.Throws(() => hashTable.ContainsKey(null)); + } + + [Test] + public void Clear_SetsCountToZero() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + hashTable.Clear(); + + Assert.AreEqual(0, hashTable.Count); + } + + [Test] + public void Clear_RemovesAllElements() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + hashTable.Clear(); + + Assert.IsFalse(hashTable.ContainsKey("a")); + } + + [Test] + public void Resize_IncreasesCapacity() + { + var hashTable = new HashTable(4); + + hashTable.Add("one", 1); + hashTable.Add("two", 2); + hashTable.Add("three", 3); + hashTable.Add("four", 4); + hashTable.Add("humour", 5); + + /// Next Prime number after 4 is 5 + /// Capacity should be 5 + /// After resizing, the capacity should be 10 + Assert.AreEqual(10, hashTable.Capacity); + } + [Test] + public void LoadFactor_ReturnsCorrectValue() + { + var hashTable = new HashTable(4); + + hashTable.Add("one", 1); + hashTable.Add("two", 2); + hashTable.Add("three", 3); + hashTable.Add("four", 4); + hashTable.Add("humour", 5); + Assert.AreEqual(0.75f, hashTable.LoadFactor); + } + + [Test] + public void Keys_ReturnsCorrectKeys() + { + var hashTable = new HashTable(); + hashTable.Add(1, "one"); + hashTable.Add(2, "two"); + hashTable.Add(3, "three"); + + var keys = new List { 1,2,3 }; + + CollectionAssert.AreEquivalent(keys, hashTable.Keys); + } + + [Test] + public void Values_ReturnsCorrectValues() + { + var hashTable = new HashTable(); + hashTable.Add(1, "one"); + hashTable.Add(2, "two"); + hashTable.Add(3, "three"); + + var values = new List { "one", "two", "three" }; + + CollectionAssert.AreEquivalent(values, hashTable?.Values); + } + + [Test] + public void Constructor_ThrowsException_WhenCapacityIsZero() + { + Assert.Throws(() => new HashTable(0)); + } + + [Test] + public void Constructor_ThrowsException_WhenLoadFactorIsZero() + { + Assert.Throws(() => new HashTable(4, 0)); + } + + [Test] + public void Constructor_ThrowsException_WhenLoadFactorIsLessThanZero() + { + Assert.Throws(() => new HashTable(4, -1)); + } + + [Test] + public void Constructor_ThrowsException_WhenLoadFactorIsGreaterThanOne() + { + Assert.Throws(() => new HashTable(4, 2)); + } + + [Test] + public void GetIndex_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(4); + Assert.Throws(() => hashTable.GetIndex(null)); + } + + [Test] + public void FindEntry_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(4); + Assert.Throws(() => hashTable.FindEntry(null)); + } + + [Test] + public void This_Get_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(4); + Assert.Throws(() => + { + var value = hashTable[null]; + Console.WriteLine(value); + }); + } + + [Test] + public void This_Set_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(4); + Assert.Throws(() => hashTable[null] = 1); + } + + [Test] + public void This_Get_ReturnsCorrectValue() + { + var hashTable = new HashTable(4); + hashTable.Add("one", 1); + Assert.AreEqual(1, hashTable["one"]); + } + + [Test] + public void This_Set_UpdatesValue() + { + var hashTable = new HashTable(4); + hashTable.Add("one", 1); + hashTable["one"] = 2; + Assert.AreEqual(2, hashTable["one"]); + } + + [Test] + public void This_Set_KeyNotFoundException_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(4); + Assert.Throws(() => hashTable["one"] = 2); + } + + [Test] + public void This_Get_KeyNotFoundException_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(4); + Assert.Throws(() => { + var value = hashTable["one"]; + Console.WriteLine(value); + }); + } + } +} diff --git a/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs b/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs new file mode 100644 index 00000000..d0c9db47 --- /dev/null +++ b/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using DataStructures.Hashing.NumberTheory; +using NUnit.Framework; + +namespace DataStructures.Tests.Hashing.NumberTheory +{ + [TestFixture] + public static class PrimeNumberTests + { + private static readonly object[] IsPrimeSource = + { + new object[] { 0, false }, + new object[] { 1, false }, + new object[] { 2, true }, + new object[] { 3, true }, + new object[] { 4, false }, + new object[] { 5, true }, + new object[] { 6, false }, + new object[] { 7, true }, + new object[] { 8, false }, + new object[] { 9, false }, + new object[] { 10, false }, + new object[] { 11, true }, + new object[] { 12, false }, + new object[] { 13, true }, + new object[] { 14, false }, + new object[] { 15, false }, + new object[] { 16, false }, + new object[] { 17, true }, + new object[] { 18, false }, + new object[] { 19, true }, + new object[] { 20, false }, + new object[] { 21, false }, + new object[] { 22, false }, + new object[] { 23, true }, + new object[] { 24, false }, + new object[] { 25, false }, + new object[] { 26, false }, + new object[] { 27, false }, + new object[] { 28, false }, + new object[] { 29, true }, + new object[] { 30, false }, + new object[] { 31, true }, + new object[] { 32, false }, + new object[] { 33, false }, + new object[] { 34, false }, + new object[] { 35, false }, + new object[] { 36, false }, + new object[] { 37, true }, + new object[] { 38, false }, + new object[] { 39, false }, + new object[] { 40, false }, + }; + + private static readonly object[] NextPrimeSource = + { + new object[] { 0, 1, false, 2 }, + new object[] { 1, 1, false, 2 }, + new object[] { 3, 1, false, 5 }, + new object[] { 4, 1, false, 5 }, + new object[] { 5, 1, false, 7 }, + new object[] { 6, 1, false, 7 }, + new object[] { 7, 1, false, 11 }, + new object[] { 8, 1, false, 11 }, + new object[] { 9, 1, false, 11 }, + new object[] { 10, 1, false, 11 }, + new object[] { 11, 1, false, 13 }, + new object[] { 12, 1, false, 13 }, + new object[] { 13, 1, false, 17 }, + new object[] { 14, 1, false, 17 }, + new object[] { 15, 1, false, 17 }, + new object[] { 16, 1, false, 17 }, + new object[] { 17, 1, false, 19 }, + new object[] { 18, 1, false, 19 }, + new object[] { 19, 1, false, 23 }, + new object[] { 20, 1, false, 23 }, + new object[] { 21, 1, false, 23 }, + new object[] { 22, 1, false, 23 }, + new object[] { 23, 1, false, 29 }, + new object[] { 24, 1, false, 29 }, + new object[] { 25, 1, false, 29 }, + new object[] { 26, 1, false, 29 }, + new object[] { 27, 1, false, 29 }, + new object[] { 28, 1, false, 29 }, + new object[] { 29, 1, false, 31 }, + new object[] { 4, 1, true, 3 }, + new object[] { 5, 1, true, 3 }, + new object[] { 6, 1, true, 5 }, + new object[] { 7, 1, true, 5 }, + new object[] { 8, 1, true, 7 }, + new object[] { 9, 1, true, 7 }, + new object[] { 10, 1, true, 7 } + }; + + [Test] + [TestCaseSource("IsPrimeSource")] + public static void IsPrimeTest(int number, bool expected) + { + var actual = PrimeNumber.IsPrime(number); + Assert.AreEqual(expected, actual); + } + + [Test] + [TestCaseSource("NextPrimeSource")] + public static void NextPrimeTest(int number, int factor, bool desc, int expected) + { + var actual = PrimeNumber.NextPrime(number, factor, desc); + Assert.AreEqual(expected, actual); + } + } +} diff --git a/DataStructures/Hashing/Entry.cs b/DataStructures/Hashing/Entry.cs new file mode 100644 index 00000000..f7b1fd6c --- /dev/null +++ b/DataStructures/Hashing/Entry.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using DataStructures.Hashing.NumberTheory; + +namespace DataStructures.Hashing +{ + /// + /// Entry in the hash table. + /// + /// Type of the key. + /// Type of the value. + /// + /// This class is used to store the key-value pairs in the hash table. + /// + public class Entry + { + public TKey? Key { get; set; } + + public TValue? Value { get; set; } + + public Entry(TKey key, TValue value) + { + Key = key; + Value = value; + } + } +} diff --git a/DataStructures/Hashing/HashTable.cs b/DataStructures/Hashing/HashTable.cs new file mode 100644 index 00000000..f50b1776 --- /dev/null +++ b/DataStructures/Hashing/HashTable.cs @@ -0,0 +1,328 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using DataStructures.Hashing.NumberTheory; + +namespace DataStructures.Hashing +{ + /// + /// Hash table implementation. + /// + /// Type of the key. + /// Type of the value. + public class HashTable + { + private const int DefaultCapacity = 16; + private const float DefaultLoadFactor = 0.75f; + + private readonly float loadFactor; + private int capacity; + private int size; + private int threshold; + private int version; + + private Entry?[] entries; + + /// + /// Gets the number of elements in the hash table. + /// + public int Count => size; + + /// + /// Gets the capacity of the hash table. + /// + public int Capacity => capacity; + + /// + /// Gets the load factor of the hash table. + /// + public float LoadFactor => loadFactor; + + /// + /// Gets the keys in the hash table. + /// + public IEnumerable Keys => entries.Where(e => e != null).Select(e => e!.Key!); + + /// + /// Gets the values in the hash table. + /// + public IEnumerable Values => entries.Where(e => e != null).Select(e => e!.Value!); + + /// + /// Gets or sets the value associated with the specified key. + /// + /// Key to get or set. + /// Value associated with the key. + public TValue this[TKey? key] + { + get + { + if (EqualityComparer.Default.Equals(key, default(TKey))) + { + throw new ArgumentNullException(nameof(key)); + } + + var entry = FindEntry(key); + if (entry == null) + { + throw new KeyNotFoundException(); + } + + return entry.Value!; + } + + set + { + if (EqualityComparer.Default.Equals(key, default(TKey))) + { + throw new ArgumentNullException(nameof(key)); + } + + var entry = FindEntry(key); + if (entry == null) + { + throw new KeyNotFoundException(); + } + + entry.Value = value; + version++; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// Initial capacity of the hash table. + /// Load factor of the hash table. + /// Thrown when is less than or equal to 0. + /// Thrown when is less than or equal to 0. + /// Thrown when is greater than 1. + /// + /// is rounded to the next prime number. + /// + /// + /// + public HashTable(int capacity = DefaultCapacity, float loadFactor = DefaultLoadFactor) + { + if (capacity <= 0) + { + throw new ArgumentOutOfRangeException(nameof(capacity), "Capacity must be greater than 0"); + } + + if (loadFactor <= 0) + { + throw new ArgumentOutOfRangeException(nameof(loadFactor), "Load factor must be greater than 0"); + } + + if (loadFactor > 1) + { + throw new ArgumentOutOfRangeException(nameof(loadFactor), "Load factor must be less than or equal to 1"); + } + + this.capacity = PrimeNumber.NextPrime(capacity); + this.loadFactor = loadFactor; + threshold = (int)(this.capacity * loadFactor); + entries = new Entry[this.capacity]; + } + + /// + /// Adds a key-value pair to the hash table. + /// + /// Key to add. + /// Value to add. + /// Thrown when is null. + /// Thrown when already exists in the hash table. + /// + /// If the number of elements in the hash table is greater than or equal to the threshold, the hash table is resized. + /// + public void Add(TKey? key, TValue? value) + { + if (EqualityComparer.Default.Equals(key, default(TKey))) + { + throw new ArgumentNullException(nameof(key)); + } + + if (size >= threshold) + { + Resize(); + } + + var index = GetIndex(key); + if ( + entries[index] != null && + EqualityComparer.Default.Equals(entries[index] !.Key!, key)) + { + throw new ArgumentException("Key already exists"); + } + + if (EqualityComparer.Default.Equals(value, default(TValue))) + { + throw new ArgumentNullException(nameof(value)); + } + + entries[index] = new Entry(key!, value!); + size++; + version++; + } + + /// + /// Removes the key-value pair associated with the specified key. + /// + /// Key to remove. + /// True if the key-value pair was removed, false otherwise. + /// Thrown when is null. + /// + /// If the number of elements in the hash table is less than or equal to the threshold divided by 4, the hash table is resized. + /// + public bool Remove(TKey? key) + { + if (EqualityComparer.Default.Equals(key, default(TKey))) + { + throw new ArgumentNullException(nameof(key)); + } + + var index = GetIndex(key); + if (entries[index] == null) + { + return false; + } + + entries[index] = null; + size--; + version++; + + if (size <= threshold / 4) + { + Resize(); + } + + return true; + } + + /// + /// Find the index of the entry associated with the specified key. + /// + /// Key to find. + /// Index of the entry associated with the key. + /// Thrown when is null. + public int GetIndex(TKey? key) + { + if (EqualityComparer.Default.Equals(key, default(TKey))) + { + throw new ArgumentNullException(nameof(key)); + } + + var hash = key!.GetHashCode(); + var index = hash % capacity; + + if (index < 0) + { + index += capacity; + } + + return index; + } + + /// + /// Finds the entry associated with the specified key. + /// + /// Key to find. + /// Entry associated with the key. + /// Thrown when is null. + /// + /// This method uses internally. + /// + public Entry? FindEntry(TKey? key) + { + if (EqualityComparer.Default.Equals(key, default(TKey))) + { + throw new ArgumentNullException(nameof(key)); + } + + var index = GetIndex(key); + return entries[index]; + } + + /// + /// Checks if the hash table contains the specified key. + /// + /// Key to check. + /// True if the hash table contains the key, false otherwise. + /// Thrown when is null. + /// + /// This method uses internally. + /// + public bool ContainsKey(TKey? key) + { + if (EqualityComparer.Default.Equals(key, default(TKey))) + { + throw new ArgumentNullException(nameof(key)); + } + + return FindEntry(key) != null; + } + + /// + /// Checks if the hash table contains the specified value. + /// + /// Value to check. + /// True if the hash table contains the value, false otherwise. + public bool ContainsValue(TValue? value) + { + if (EqualityComparer.Default.Equals(value, default(TValue))) + { + throw new ArgumentNullException(nameof(value)); + } + + return entries.Any(e => e != null && e.Value!.Equals(value)); + } + + /// + /// Clears the hash table. + /// + /// + /// This method resets the capacity of the hash table to the default capacity. + /// + public void Clear() + { + capacity = DefaultCapacity; + threshold = (int)(capacity * loadFactor); + entries = new Entry[capacity]; + size = 0; + version++; + } + + /// + /// Resizes the hash table. + /// + /// + /// This method doubles the capacity of the hash table and rehashes all the elements. + /// + public void Resize() + { + var newCapacity = capacity * 2; + var newEntries = new Entry[newCapacity]; + + foreach (var entry in entries) + { + if (entry == null) + { + continue; + } + + var index = entry.Key!.GetHashCode() % newCapacity; + if (index < 0) + { + index += newCapacity; + } + + newEntries[index] = entry; + } + + capacity = newCapacity; + threshold = (int)(capacity * loadFactor); + entries = newEntries; + version++; + } + } +} diff --git a/DataStructures/Hashing/NumberTheory/PrimeNumber.cs b/DataStructures/Hashing/NumberTheory/PrimeNumber.cs new file mode 100644 index 00000000..278201a7 --- /dev/null +++ b/DataStructures/Hashing/NumberTheory/PrimeNumber.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace DataStructures.Hashing.NumberTheory +{ + /// + /// Class for prime number operations. + /// + /// + /// A prime number is a natural number greater than 1 that is not a product of two smaller natural numbers. + /// + public static class PrimeNumber + { + /// + /// Checks if a number is prime or not. + /// + /// Number to check. + /// True if number is prime, false otherwise. + public static bool IsPrime(int number) + { + if (number <= 1) + { + return false; + } + + if (number <= 3) + { + return true; + } + + if (number % 2 == 0 || number % 3 == 0) + { + return false; + } + + for (int i = 5; i * i <= number; i += 6) + { + if (number % i == 0 || number % (i + 2) == 0) + { + return false; + } + } + + return true; + } + + /// + /// Gets the next prime number. + /// + /// Number to start from. + /// Factor to multiply the number by. + /// True to get the previous prime number, false otherwise. + /// The next prime number. + public static int NextPrime(int number, int factor = 1, bool desc = false) + { + number = factor * number; + int firstValue = number; + + while (!IsPrime(number)) + { + number += desc ? -1 : 1; + } + + if (number == firstValue) + { + return NextPrime( + number + (desc ? -1 : 1), + factor, + desc); + } + + return number; + } + } +} diff --git a/README.md b/README.md index be77da6d..b320d1e1 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,11 @@ find more than one implementation for the same objective but using different alg * [Paddings](./Algorithms/Crypto/Paddings/) * [ISO 10125-2 Padding](./Algorithms/Crypto/Paddings/ISO10126d2Padding.cs) * [ISO 7816-4 Padding](./Algorithms/Crypto/Paddings/ISO7816d4Padding.cs) - * [X9.32 Padding](./Algorithms/Crypto/Paddings/X932Padding.cs) - * [TBC Padding](./Algorithms/Crypto/Paddings/TbcPadding.cs) + * [X9.32 Padding](./Algorithms/Crypto/Paddings/X932Padding.cs) + * [TBC Padding](./Algorithms/Crypto/Paddings/TbcPadding.cs) * [PKCS7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) * [Digests](./Algorithms/Crypto/Digests/) - * [MD2 Digest](./Algorithms/Crypto/Digests/Md2Digest.cs) + * [MD2 Digest](./Algorithms/Crypto/Digests/Md2Digest.cs) * [Data Compression](./Algorithms/DataCompression) * [Burrows-Wheeler transform](./Algorithms/DataCompression/BurrowsWheelerTransform.cs) * [Huffman Compressor](./Algorithms/DataCompression/HuffmanCompressor.cs) @@ -258,11 +258,11 @@ find more than one implementation for the same objective but using different alg * [Inverted index](./DataStructures/InvertedIndex.cs) * [Unrolled linked list](./DataStructures/UnrolledList/UnrolledLinkedList.cs) * [Tries](./DataStructures/Tries/Trie.cs) + * [HashTable](./DataStructures/Hashing/HashTable.cs) * [Cache](./DataStructures/Cache) * [Least Frequently Used (LFU) Cache](./DataStructures/Cache/LfuCache.cs) * [Least Recently Used (LRU) Cache](./DataStructures/Cache/LruCache.cs) - ## Contributing You can contribute with pleasure to this repository. From 60d4de0ca7fc806f0a5946b516ab3f3cf05c8664 Mon Sep 17 00:00:00 2001 From: Sid Chalke Date: Mon, 16 Oct 2023 12:13:39 -0400 Subject: [PATCH 076/138] Fix README (#422) --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b320d1e1..dae5c09f 100644 --- a/README.md +++ b/README.md @@ -214,8 +214,9 @@ find more than one implementation for the same objective but using different alg * [Proposer](./Algorithms/Problems/StableMarriage/Proposer.cs) * [N-Queens](./Algorithms/Problems/NQueens) * [Backtracking](./Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs) - * [Dynamic Coin Change](./Algorithms/Problems/CoinChange) - * [Dynamic](./Algorithms/Problems/CoinChange/DynamicCoinChangeSolver.cs) + * [Dynamic Programming](./Algorithms/Problems/DynamicProgramming) + * [Coin Change](./Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs) + * [Levenshtein Distance](./Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs) * [Data Structures](./DataStructures) * [Bit Array](./DataStructures/BitArray.cs) From 7de8efbe5d4a91a954fc53f2525490969ca43f69 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Tue, 17 Oct 2023 13:19:48 +0300 Subject: [PATCH 077/138] Add common interface for padding (#420) --- .../Crypto/Paddings/Pkcs7PaddingTests.cs | 12 +++++- .../Crypto/Paddings/TbcPaddingTests.cs | 6 +-- .../Crypto/Paddings/IBlockCipherPadding.cs | 39 +++++++++++++++++++ .../Crypto/Paddings/Iso10126D2Padding.cs | 2 +- .../Crypto/Paddings/Iso7816D4Padding.cs | 2 +- Algorithms/Crypto/Paddings/Pkcs7Padding.cs | 2 +- Algorithms/Crypto/Paddings/TbcPadding.cs | 4 +- Algorithms/Crypto/Paddings/X932Padding.cs | 2 +- 8 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 Algorithms/Crypto/Paddings/IBlockCipherPadding.cs diff --git a/Algorithms.Tests/Crypto/Paddings/Pkcs7PaddingTests.cs b/Algorithms.Tests/Crypto/Paddings/Pkcs7PaddingTests.cs index 1c159183..40454a63 100644 --- a/Algorithms.Tests/Crypto/Paddings/Pkcs7PaddingTests.cs +++ b/Algorithms.Tests/Crypto/Paddings/Pkcs7PaddingTests.cs @@ -141,10 +141,20 @@ public void RemovePadding_WhenInvalidPadding_ShouldThrowArgumentException() .WithMessage("Invalid padding"); } + [Test] + public void GetPaddingCount_WhenArrayIsNull_ShouldThrowArgumentNullException() + { + var padding = new Pkcs7Padding(DefaultBlockSize); + + Action act = () => padding.GetPaddingCount(null!); + + act.Should().Throw(); + } + [Test] public void GetPaddingCount_WhenInputArrayIsValid_ShouldReturnCorrectPaddingCount() { - var paddingSize = 5; + const int paddingSize = 5; var size32Input = new byte[32]; for (var i = 0; i < paddingSize; i++) diff --git a/Algorithms.Tests/Crypto/Paddings/TbcPaddingTests.cs b/Algorithms.Tests/Crypto/Paddings/TbcPaddingTests.cs index 1bf131d4..c8779e86 100644 --- a/Algorithms.Tests/Crypto/Paddings/TbcPaddingTests.cs +++ b/Algorithms.Tests/Crypto/Paddings/TbcPaddingTests.cs @@ -128,7 +128,7 @@ public void GetPaddingBytes_WhenCalledWithPaddedData_ShouldReturnCorrectPaddingC var paddedData = new byte[] { 0x01, 0x02, 0x03, 0xff, 0xff }; const int expectedPaddingCount = 2; - var result = padding.GetPaddingBytes(paddedData); + var result = padding.GetPaddingCount(paddedData); result.Should().Be(expectedPaddingCount); } @@ -138,7 +138,7 @@ public void GetPaddingBytes_WhenCalledWithUnpaddedData_ShouldReturnZero() { var unpaddedData = new byte[] { 0x01, 0x02, 0x03 }; - Action action = () => padding.GetPaddingBytes(unpaddedData); + Action action = () => padding.GetPaddingCount(unpaddedData); action.Should().Throw() .WithMessage("No padding found"); @@ -149,7 +149,7 @@ public void GetPaddingBytes_WhenCalledWithEmptyArray_ShouldReturnZero() { var emptyData = Array.Empty(); - Action action = () => padding.GetPaddingBytes(emptyData); + Action action = () => padding.GetPaddingCount(emptyData); action.Should().Throw() .WithMessage("No padding found."); diff --git a/Algorithms/Crypto/Paddings/IBlockCipherPadding.cs b/Algorithms/Crypto/Paddings/IBlockCipherPadding.cs new file mode 100644 index 00000000..e451f377 --- /dev/null +++ b/Algorithms/Crypto/Paddings/IBlockCipherPadding.cs @@ -0,0 +1,39 @@ +using System; + +namespace Algorithms.Crypto.Paddings; + +/// +/// A common interface that all block cipher padding schemes should follow. +/// +public interface IBlockCipherPadding +{ + /// + /// Adds padding bytes to the end of the given block of the data and returns the number of bytes that were added. + /// + /// The input data array that needs padding. + /// The offset in the input array where the padding should start. + /// The number of bytes added. + /// + /// This method expects that the input parameter contains the last block of plain text + /// that needs to be padded. This means that the value of has to have the same value as + /// the last block of plain text. The reason for this is that some modes such as the base the + /// padding value on the last byte of the plain text. + /// + public int AddPadding(byte[] inputData, int inputOffset); + + /// + /// Removes the padding bytes from the given block of data and returns the original data as a new array. + /// + /// The input data array containing the padding. + /// The input data without the padding as a new byte array. + /// Thrown when the input data has invalid padding. + public byte[] RemovePadding(byte[] inputData); + + /// + /// Gets the number of padding bytes in the input data. + /// + /// The input data array that has padding. + /// The number of padding bytes in the input data. + /// Thrown when the input data has invalid padding. + public int GetPaddingCount(byte[] input); +} diff --git a/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs b/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs index 26c4385a..51bfca39 100644 --- a/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs +++ b/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs @@ -19,7 +19,7 @@ namespace Algorithms.Crypto.Paddings; /// the end of the data. /// /// -public class Iso10126D2Padding +public class Iso10126D2Padding : IBlockCipherPadding { /// /// Adds random padding to the input data array to make it a multiple of the block size according to the diff --git a/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs b/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs index be794ac1..df12c5da 100644 --- a/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs +++ b/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs @@ -28,7 +28,7 @@ namespace Algorithms.Crypto.Paddings; /// depend on any specific character encoding or representation. /// /// -public class Iso7816D4Padding +public class Iso7816D4Padding : IBlockCipherPadding { /// /// Adds padding to the input data according to the ISO 7816-4 standard. diff --git a/Algorithms/Crypto/Paddings/Pkcs7Padding.cs b/Algorithms/Crypto/Paddings/Pkcs7Padding.cs index 114cdd4d..ef2cdc07 100644 --- a/Algorithms/Crypto/Paddings/Pkcs7Padding.cs +++ b/Algorithms/Crypto/Paddings/Pkcs7Padding.cs @@ -20,7 +20,7 @@ namespace Algorithms.Crypto.Paddings; /// padding, such as AES. /// /// -public class Pkcs7Padding +public class Pkcs7Padding : IBlockCipherPadding { private readonly int blockSize; diff --git a/Algorithms/Crypto/Paddings/TbcPadding.cs b/Algorithms/Crypto/Paddings/TbcPadding.cs index 97b7a4b8..d9386dc6 100644 --- a/Algorithms/Crypto/Paddings/TbcPadding.cs +++ b/Algorithms/Crypto/Paddings/TbcPadding.cs @@ -15,7 +15,7 @@ namespace Algorithms.Crypto.Paddings; /// The padding bytes are added at the end of the data block until the desired length is reached. /// /// -public class TbcPadding +public class TbcPadding : IBlockCipherPadding { /// /// Adds padding to the input array according to the TBC standard. @@ -121,7 +121,7 @@ public byte[] RemovePadding(byte[] input) /// avoid branching. If the input array is not padded or has an invalid padding, the method may return incorrect /// results. /// - public int GetPaddingBytes(byte[] input) + public int GetPaddingCount(byte[] input) { var length = input.Length; diff --git a/Algorithms/Crypto/Paddings/X932Padding.cs b/Algorithms/Crypto/Paddings/X932Padding.cs index ea03fa32..6a4f5f45 100644 --- a/Algorithms/Crypto/Paddings/X932Padding.cs +++ b/Algorithms/Crypto/Paddings/X932Padding.cs @@ -18,7 +18,7 @@ namespace Algorithms.Crypto.Paddings; /// bytes. /// /// -public class X932Padding +public class X932Padding : IBlockCipherPadding { private readonly bool useRandomPadding; From d656655355049fc3f2610a8e4620ea5d4fd603e6 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Tue, 19 Dec 2023 10:39:51 +0200 Subject: [PATCH 078/138] Remove old references --- C-Sharp.sln | 2 -- 1 file changed, 2 deletions(-) diff --git a/C-Sharp.sln b/C-Sharp.sln index f8072b77..857df3e5 100644 --- a/C-Sharp.sln +++ b/C-Sharp.sln @@ -9,14 +9,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{DAB16DEC-A CONTRIBUTING.md = CONTRIBUTING.md LICENSE = LICENSE README.md = README.md - DIRECTORY.md = DIRECTORY.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Configs", "Configs", "{F3AC2246-318B-4EE4-BD9E-D751D3044901}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig .gitignore = .gitignore - .travis.yml = .travis.yml stylecop.json = stylecop.json stylecop.ruleset = stylecop.ruleset EndProjectSection From 915e364a55f2421b4659b68c23ca7ce5630af85a Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Fri, 29 Dec 2023 23:59:08 +0530 Subject: [PATCH 079/138] Fix flaky BlowfishEncoder tests (#428) --- .../Encoders/BlowfishEncoderTests.cs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Algorithms.Tests/Encoders/BlowfishEncoderTests.cs b/Algorithms.Tests/Encoders/BlowfishEncoderTests.cs index 3f2087b8..4520e616 100644 --- a/Algorithms.Tests/Encoders/BlowfishEncoderTests.cs +++ b/Algorithms.Tests/Encoders/BlowfishEncoderTests.cs @@ -8,37 +8,39 @@ namespace Algorithms.Tests.Encoders; public class BlowfishEncoderTests { - private BlowfishEncoder _encoder = new(); - const string key = "aabb09182736ccdd"; - - [SetUp] - public void Setup() - { - _encoder = new BlowfishEncoder(); - _encoder.GenerateKey(key); - } + private const string Key = "aabb09182736ccdd"; [Test] public void BlowfishEncoder_Encryption_ShouldWorkCorrectly() { - const string plainText = "123456abcd132536"; + // Arrange + var encoder = new BlowfishEncoder(); + encoder.GenerateKey(Key); + const string plainText = "123456abcd132536"; const string cipherText = "d748ec383d3405f7"; - var result = _encoder.Encrypt(plainText); + // Act + var result = encoder.Encrypt(plainText); + // Assert result.Should().Be(cipherText); } [Test] public void BlowfishEncoder_Decryption_ShouldWorkCorrectly() { - const string cipherText = "d748ec383d3405f7"; + // Arrange + var encoder = new BlowfishEncoder(); + encoder.GenerateKey(Key); + const string cipherText = "d748ec383d3405f7"; const string plainText = "123456abcd132536"; - var result = _encoder.Decrypt(cipherText); + // Act + var result = encoder.Decrypt(cipherText); + // Assert result.Should().Be(plainText); } } From 821f492e227b5fbb437b1dd118aa9455ae8c7044 Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Fri, 29 Dec 2023 18:53:26 +0000 Subject: [PATCH 080/138] Migrate to .NET 8 (#426) --- .github/workflows/ci.yml | 2 +- Algorithms.Tests/Algorithms.Tests.csproj | 2 +- Algorithms/Algorithms.csproj | 2 +- .../DataStructures.Tests.csproj | 2 +- DataStructures/DataStructures.csproj | 2 +- README.md | 19 +++++++++++++++++++ Utilities.Tests/Utilities.Tests.csproj | 2 +- Utilities/Utilities.csproj | 2 +- 8 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee961f95..26f7b3d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: - name: Setup .NET SDK uses: actions/setup-dotnet@v3 with: - dotnet-version: 6.x + dotnet-version: 8.x - name: Restore run: dotnet restore - name: Build diff --git a/Algorithms.Tests/Algorithms.Tests.csproj b/Algorithms.Tests/Algorithms.Tests.csproj index 7d601849..05714b3a 100644 --- a/Algorithms.Tests/Algorithms.Tests.csproj +++ b/Algorithms.Tests/Algorithms.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 false ..\stylecop.ruleset true diff --git a/Algorithms/Algorithms.csproj b/Algorithms/Algorithms.csproj index dc8491dc..01c73e2a 100644 --- a/Algorithms/Algorithms.csproj +++ b/Algorithms/Algorithms.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 ..\stylecop.ruleset true enable diff --git a/DataStructures.Tests/DataStructures.Tests.csproj b/DataStructures.Tests/DataStructures.Tests.csproj index 732a0089..e4ad4d0c 100644 --- a/DataStructures.Tests/DataStructures.Tests.csproj +++ b/DataStructures.Tests/DataStructures.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 false ..\stylecop.ruleset true diff --git a/DataStructures/DataStructures.csproj b/DataStructures/DataStructures.csproj index 9803466f..06f645a3 100644 --- a/DataStructures/DataStructures.csproj +++ b/DataStructures/DataStructures.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 ..\stylecop.ruleset true enable diff --git a/README.md b/README.md index dae5c09f..43ac9a56 100644 --- a/README.md +++ b/README.md @@ -264,6 +264,25 @@ find more than one implementation for the same objective but using different alg * [Least Frequently Used (LFU) Cache](./DataStructures/Cache/LfuCache.cs) * [Least Recently Used (LRU) Cache](./DataStructures/Cache/LruCache.cs) +## Project Update: .NET 8 Migration + +As part of our continuous effort to stay up-to-date with the latest technologies, we have migrated our project to .NET 8. This upgrade enhances our project with the latest features and improvements from the .NET ecosystem. + +### New Requirements + +* To build and run this project, **.NET 8 SDK** is now required. +* Ensure your development tools are compatible with .NET 8. + +### Building the Project + +* With .NET 8 SDK installed, you can build the project using the standard `dotnet build` command. +* All existing build scripts have been updated to accommodate the .NET 8 SDK. + +### Running Tests + +* Our comprehensive suite of unit tests ensures compatibility with .NET 8. +* Run tests using the `dotnet test` command as usual. + ## Contributing You can contribute with pleasure to this repository. diff --git a/Utilities.Tests/Utilities.Tests.csproj b/Utilities.Tests/Utilities.Tests.csproj index 7b1fcf7b..bb7f17db 100644 --- a/Utilities.Tests/Utilities.Tests.csproj +++ b/Utilities.Tests/Utilities.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 false ..\stylecop.ruleset true diff --git a/Utilities/Utilities.csproj b/Utilities/Utilities.csproj index 6cb21c39..8c289a07 100644 --- a/Utilities/Utilities.csproj +++ b/Utilities/Utilities.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 ..\stylecop.ruleset true enable From 231167fabb0327e772b5abbb4a91346b3aef47ab Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Fri, 29 Dec 2023 21:05:58 +0000 Subject: [PATCH 081/138] Switch to file-scoped namespaces (#429) --- .../BurrowsWheelerTransform.cs | 103 +++---- .../DataCompression/HuffmanCompressor.cs | 231 +++++++------- .../DataCompression/ShannonFanoCompressor.cs | 189 ++++++------ Algorithms/DataCompression/Translator.cs | 45 ++- Algorithms/Encoders/CaesarEncoder.cs | 83 +++-- Algorithms/Encoders/FeistelCipher.cs | 265 ++++++++-------- Algorithms/Encoders/HillEncoder.cs | 291 +++++++++--------- Algorithms/Encoders/IEncoder.cs | 39 ++- Algorithms/Encoders/NysiisEncoder.cs | 269 ++++++++-------- Algorithms/Encoders/SoundexEncoder.cs | 165 +++++----- Algorithms/Encoders/VigenereEncoder.cs | 105 ++++--- Algorithms/Graph/BellmanFord.cs | 153 +++++---- Algorithms/Graph/BreadthFirstSearch.cs | 81 +++-- Algorithms/Graph/BreadthFirstTreeTraversal.cs | 125 ++++---- Algorithms/Graph/DepthFirstSearch.cs | 67 ++-- .../Graph/Dijkstra/DijkstraAlgorithm.cs | 167 +++++----- Algorithms/Graph/Dijkstra/DistanceModel.cs | 41 ++- Algorithms/Graph/FloydWarshall.cs | 87 +++--- Algorithms/Graph/IGraphSearch.cs | 21 +- Algorithms/Graph/Kosaraju.cs | 189 ++++++------ .../Graph/MinimumSpanningTree/Kruskal.cs | 271 ++++++++-------- .../Graph/MinimumSpanningTree/PrimMatrix.cs | 211 +++++++------ 22 files changed, 1588 insertions(+), 1610 deletions(-) diff --git a/Algorithms/DataCompression/BurrowsWheelerTransform.cs b/Algorithms/DataCompression/BurrowsWheelerTransform.cs index 3316b6ed..e84aab8d 100644 --- a/Algorithms/DataCompression/BurrowsWheelerTransform.cs +++ b/Algorithms/DataCompression/BurrowsWheelerTransform.cs @@ -1,74 +1,73 @@ -using System; +using System; using System.Linq; -namespace Algorithms.DataCompression +namespace Algorithms.DataCompression; + +/// +/// The Burrows–Wheeler transform (BWT) rearranges a character string into runs of similar characters. +/// This is useful for compression, since it tends to be easy to compress a string that has runs of repeated +/// characters. +/// See here for more info. +/// +public class BurrowsWheelerTransform { /// - /// The Burrows–Wheeler transform (BWT) rearranges a character string into runs of similar characters. - /// This is useful for compression, since it tends to be easy to compress a string that has runs of repeated - /// characters. - /// See here for more info. + /// Encodes the input string using BWT and returns encoded string and the index of original string in the sorted + /// rotation matrix. /// - public class BurrowsWheelerTransform + /// Input string. + public (string encoded, int index) Encode(string s) { - /// - /// Encodes the input string using BWT and returns encoded string and the index of original string in the sorted - /// rotation matrix. - /// - /// Input string. - public (string encoded, int index) Encode(string s) + if (s.Length == 0) { - if (s.Length == 0) - { - return (string.Empty, 0); - } - - var rotations = GetRotations(s); - Array.Sort(rotations, StringComparer.Ordinal); - var lastColumn = rotations - .Select(x => x[^1]) - .ToArray(); - var encoded = new string(lastColumn); - return (encoded, Array.IndexOf(rotations, s)); + return (string.Empty, 0); } - /// - /// Decodes the input string and returns original string. - /// - /// Encoded string. - /// Index of original string in the sorted rotation matrix. - public string Decode(string s, int index) + var rotations = GetRotations(s); + Array.Sort(rotations, StringComparer.Ordinal); + var lastColumn = rotations + .Select(x => x[^1]) + .ToArray(); + var encoded = new string(lastColumn); + return (encoded, Array.IndexOf(rotations, s)); + } + + /// + /// Decodes the input string and returns original string. + /// + /// Encoded string. + /// Index of original string in the sorted rotation matrix. + public string Decode(string s, int index) + { + if (s.Length == 0) { - if (s.Length == 0) - { - return string.Empty; - } + return string.Empty; + } - var rotations = new string[s.Length]; + var rotations = new string[s.Length]; - for (var i = 0; i < s.Length; i++) + for (var i = 0; i < s.Length; i++) + { + for (var j = 0; j < s.Length; j++) { - for (var j = 0; j < s.Length; j++) - { - rotations[j] = s[j] + rotations[j]; - } - - Array.Sort(rotations, StringComparer.Ordinal); + rotations[j] = s[j] + rotations[j]; } - return rotations[index]; + Array.Sort(rotations, StringComparer.Ordinal); } - private string[] GetRotations(string s) - { - var result = new string[s.Length]; + return rotations[index]; + } - for (var i = 0; i < s.Length; i++) - { - result[i] = s.Substring(i) + s.Substring(0, i); - } + private string[] GetRotations(string s) + { + var result = new string[s.Length]; - return result; + for (var i = 0; i < s.Length; i++) + { + result[i] = s.Substring(i) + s.Substring(0, i); } + + return result; } } diff --git a/Algorithms/DataCompression/HuffmanCompressor.cs b/Algorithms/DataCompression/HuffmanCompressor.cs index 558b87c4..a9d3f689 100644 --- a/Algorithms/DataCompression/HuffmanCompressor.cs +++ b/Algorithms/DataCompression/HuffmanCompressor.cs @@ -4,164 +4,163 @@ using Algorithms.Sorters.Comparison; using Utilities.Extensions; -namespace Algorithms.DataCompression +namespace Algorithms.DataCompression; + +/// +/// Greedy lossless compression algorithm. +/// +public class HuffmanCompressor { + // TODO: Use partial sorter + private readonly IComparisonSorter sorter; + private readonly Translator translator; + + public HuffmanCompressor(IComparisonSorter sorter, Translator translator) + { + this.sorter = sorter; + this.translator = translator; + } + /// - /// Greedy lossless compression algorithm. + /// Given an input string, returns a new compressed string + /// using huffman encoding. /// - public class HuffmanCompressor + /// Text message to compress. + /// Compressed string and keys to decompress it. + public (string compressedText, Dictionary decompressionKeys) Compress(string uncompressedText) { - // TODO: Use partial sorter - private readonly IComparisonSorter sorter; - private readonly Translator translator; - - public HuffmanCompressor(IComparisonSorter sorter, Translator translator) + if (string.IsNullOrEmpty(uncompressedText)) { - this.sorter = sorter; - this.translator = translator; + return (string.Empty, new Dictionary()); } - /// - /// Given an input string, returns a new compressed string - /// using huffman encoding. - /// - /// Text message to compress. - /// Compressed string and keys to decompress it. - public (string compressedText, Dictionary decompressionKeys) Compress(string uncompressedText) + if (uncompressedText.Distinct().Count() == 1) { - if (string.IsNullOrEmpty(uncompressedText)) + var dict = new Dictionary { - return (string.Empty, new Dictionary()); - } + { "1", uncompressedText[0].ToString() }, + }; + return (new string('1', uncompressedText.Length), dict); + } - if (uncompressedText.Distinct().Count() == 1) - { - var dict = new Dictionary - { - { "1", uncompressedText[0].ToString() }, - }; - return (new string('1', uncompressedText.Length), dict); - } + var nodes = GetListNodesFromText(uncompressedText); + var tree = GenerateHuffmanTree(nodes); + var (compressionKeys, decompressionKeys) = GetKeys(tree); + return (translator.Translate(uncompressedText, compressionKeys), decompressionKeys); + } - var nodes = GetListNodesFromText(uncompressedText); - var tree = GenerateHuffmanTree(nodes); - var (compressionKeys, decompressionKeys) = GetKeys(tree); - return (translator.Translate(uncompressedText, compressionKeys), decompressionKeys); - } + /// + /// Finds frequency for each character in the text. + /// + /// Symbol-frequency array. + private static ListNode[] GetListNodesFromText(string text) + { + var occurenceCounts = new Dictionary(); - /// - /// Finds frequency for each character in the text. - /// - /// Symbol-frequency array. - private static ListNode[] GetListNodesFromText(string text) + foreach (var ch in text) { - var occurenceCounts = new Dictionary(); - - foreach (var ch in text) + if (!occurenceCounts.ContainsKey(ch)) { - if (!occurenceCounts.ContainsKey(ch)) - { - occurenceCounts.Add(ch, 0); - } - - occurenceCounts[ch]++; + occurenceCounts.Add(ch, 0); } - return occurenceCounts.Select(kvp => new ListNode(kvp.Key, 1d * kvp.Value / text.Length)).ToArray(); + occurenceCounts[ch]++; } - private (Dictionary compressionKeys, Dictionary decompressionKeys) GetKeys( - ListNode tree) - { - var compressionKeys = new Dictionary(); - var decompressionKeys = new Dictionary(); + return occurenceCounts.Select(kvp => new ListNode(kvp.Key, 1d * kvp.Value / text.Length)).ToArray(); + } - if (tree.HasData) - { - compressionKeys.Add(tree.Data.ToString(), string.Empty); - decompressionKeys.Add(string.Empty, tree.Data.ToString()); - return (compressionKeys, decompressionKeys); - } + private (Dictionary compressionKeys, Dictionary decompressionKeys) GetKeys( + ListNode tree) + { + var compressionKeys = new Dictionary(); + var decompressionKeys = new Dictionary(); - if (tree.LeftChild is not null) - { - var (lsck, lsdk) = GetKeys(tree.LeftChild); - compressionKeys.AddMany(lsck.Select(kvp => (kvp.Key, "0" + kvp.Value))); - decompressionKeys.AddMany(lsdk.Select(kvp => ("0" + kvp.Key, kvp.Value))); - } + if (tree.HasData) + { + compressionKeys.Add(tree.Data.ToString(), string.Empty); + decompressionKeys.Add(string.Empty, tree.Data.ToString()); + return (compressionKeys, decompressionKeys); + } - if (tree.RightChild is not null) - { - var (rsck, rsdk) = GetKeys(tree.RightChild); - compressionKeys.AddMany(rsck.Select(kvp => (kvp.Key, "1" + kvp.Value))); - decompressionKeys.AddMany(rsdk.Select(kvp => ("1" + kvp.Key, kvp.Value))); + if (tree.LeftChild is not null) + { + var (lsck, lsdk) = GetKeys(tree.LeftChild); + compressionKeys.AddMany(lsck.Select(kvp => (kvp.Key, "0" + kvp.Value))); + decompressionKeys.AddMany(lsdk.Select(kvp => ("0" + kvp.Key, kvp.Value))); + } - return (compressionKeys, decompressionKeys); - } + if (tree.RightChild is not null) + { + var (rsck, rsdk) = GetKeys(tree.RightChild); + compressionKeys.AddMany(rsck.Select(kvp => (kvp.Key, "1" + kvp.Value))); + decompressionKeys.AddMany(rsdk.Select(kvp => ("1" + kvp.Key, kvp.Value))); return (compressionKeys, decompressionKeys); } - private ListNode GenerateHuffmanTree(ListNode[] nodes) - { - var comparer = new ListNodeComparer(); - while (nodes.Length > 1) - { - sorter.Sort(nodes, comparer); + return (compressionKeys, decompressionKeys); + } - var left = nodes[0]; - var right = nodes[1]; + private ListNode GenerateHuffmanTree(ListNode[] nodes) + { + var comparer = new ListNodeComparer(); + while (nodes.Length > 1) + { + sorter.Sort(nodes, comparer); - var newNodes = new ListNode[nodes.Length - 1]; - Array.Copy(nodes, 2, newNodes, 1, nodes.Length - 2); - newNodes[0] = new ListNode(left, right); - nodes = newNodes; - } + var left = nodes[0]; + var right = nodes[1]; - return nodes[0]; + var newNodes = new ListNode[nodes.Length - 1]; + Array.Copy(nodes, 2, newNodes, 1, nodes.Length - 2); + newNodes[0] = new ListNode(left, right); + nodes = newNodes; } - /// - /// Represents tree structure for the algorithm. - /// - public class ListNode + return nodes[0]; + } + + /// + /// Represents tree structure for the algorithm. + /// + public class ListNode + { + public ListNode(char data, double frequency) { - public ListNode(char data, double frequency) - { - HasData = true; - Data = data; - Frequency = frequency; - } + HasData = true; + Data = data; + Frequency = frequency; + } - public ListNode(ListNode leftChild, ListNode rightChild) - { - LeftChild = leftChild; - RightChild = rightChild; - Frequency = leftChild.Frequency + rightChild.Frequency; - } + public ListNode(ListNode leftChild, ListNode rightChild) + { + LeftChild = leftChild; + RightChild = rightChild; + Frequency = leftChild.Frequency + rightChild.Frequency; + } - public char Data { get; } + public char Data { get; } - public bool HasData { get; } + public bool HasData { get; } - public double Frequency { get; } + public double Frequency { get; } - public ListNode? RightChild { get; } + public ListNode? RightChild { get; } - public ListNode? LeftChild { get; } - } + public ListNode? LeftChild { get; } + } - public class ListNodeComparer : IComparer + public class ListNodeComparer : IComparer + { + public int Compare(ListNode? x, ListNode? y) { - public int Compare(ListNode? x, ListNode? y) + if (x is null || y is null) { - if (x is null || y is null) - { - return 0; - } - - return x.Frequency.CompareTo(y.Frequency); + return 0; } + + return x.Frequency.CompareTo(y.Frequency); } } } diff --git a/Algorithms/DataCompression/ShannonFanoCompressor.cs b/Algorithms/DataCompression/ShannonFanoCompressor.cs index e4245201..6a48e7b4 100644 --- a/Algorithms/DataCompression/ShannonFanoCompressor.cs +++ b/Algorithms/DataCompression/ShannonFanoCompressor.cs @@ -3,132 +3,131 @@ using Algorithms.Knapsack; using Utilities.Extensions; -namespace Algorithms.DataCompression +namespace Algorithms.DataCompression; + +/// +/// Greedy lossless compression algorithm. +/// +public class ShannonFanoCompressor { + private readonly IHeuristicKnapsackSolver<(char symbol, double frequency)> splitter; + private readonly Translator translator; + + public ShannonFanoCompressor( + IHeuristicKnapsackSolver<(char symbol, double frequency)> splitter, + Translator translator) + { + this.splitter = splitter; + this.translator = translator; + } + /// - /// Greedy lossless compression algorithm. + /// Given an input string, returns a new compressed string + /// using Shannon-Fano encoding. /// - public class ShannonFanoCompressor + /// Text message to compress. + /// Compressed string and keys to decompress it. + public (string compressedText, Dictionary decompressionKeys) Compress(string uncompressedText) { - private readonly IHeuristicKnapsackSolver<(char symbol, double frequency)> splitter; - private readonly Translator translator; - - public ShannonFanoCompressor( - IHeuristicKnapsackSolver<(char symbol, double frequency)> splitter, - Translator translator) + if (string.IsNullOrEmpty(uncompressedText)) { - this.splitter = splitter; - this.translator = translator; + return (string.Empty, new Dictionary()); } - /// - /// Given an input string, returns a new compressed string - /// using Shannon-Fano encoding. - /// - /// Text message to compress. - /// Compressed string and keys to decompress it. - public (string compressedText, Dictionary decompressionKeys) Compress(string uncompressedText) + if (uncompressedText.Distinct().Count() == 1) { - if (string.IsNullOrEmpty(uncompressedText)) + var dict = new Dictionary { - return (string.Empty, new Dictionary()); - } - - if (uncompressedText.Distinct().Count() == 1) - { - var dict = new Dictionary - { - { "1", uncompressedText[0].ToString() }, - }; - return (new string('1', uncompressedText.Length), dict); - } - - var node = GetListNodeFromText(uncompressedText); - var tree = GenerateShannonFanoTree(node); - var (compressionKeys, decompressionKeys) = GetKeys(tree); - return (translator.Translate(uncompressedText, compressionKeys), decompressionKeys); + { "1", uncompressedText[0].ToString() }, + }; + return (new string('1', uncompressedText.Length), dict); } - private (Dictionary compressionKeys, Dictionary decompressionKeys) GetKeys( - ListNode tree) - { - var compressionKeys = new Dictionary(); - var decompressionKeys = new Dictionary(); - - if (tree.Data.Length == 1) - { - compressionKeys.Add(tree.Data[0].symbol.ToString(), string.Empty); - decompressionKeys.Add(string.Empty, tree.Data[0].symbol.ToString()); - return (compressionKeys, decompressionKeys); - } - - if (tree.LeftChild is not null) - { - var (lsck, lsdk) = GetKeys(tree.LeftChild); - compressionKeys.AddMany(lsck.Select(kvp => (kvp.Key, "0" + kvp.Value))); - decompressionKeys.AddMany(lsdk.Select(kvp => ("0" + kvp.Key, kvp.Value))); - } + var node = GetListNodeFromText(uncompressedText); + var tree = GenerateShannonFanoTree(node); + var (compressionKeys, decompressionKeys) = GetKeys(tree); + return (translator.Translate(uncompressedText, compressionKeys), decompressionKeys); + } - if (tree.RightChild is not null) - { - var (rsck, rsdk) = GetKeys(tree.RightChild); - compressionKeys.AddMany(rsck.Select(kvp => (kvp.Key, "1" + kvp.Value))); - decompressionKeys.AddMany(rsdk.Select(kvp => ("1" + kvp.Key, kvp.Value))); - } + private (Dictionary compressionKeys, Dictionary decompressionKeys) GetKeys( + ListNode tree) + { + var compressionKeys = new Dictionary(); + var decompressionKeys = new Dictionary(); + if (tree.Data.Length == 1) + { + compressionKeys.Add(tree.Data[0].symbol.ToString(), string.Empty); + decompressionKeys.Add(string.Empty, tree.Data[0].symbol.ToString()); return (compressionKeys, decompressionKeys); } - private ListNode GenerateShannonFanoTree(ListNode node) + if (tree.LeftChild is not null) { - if (node.Data.Length == 1) - { - return node; - } + var (lsck, lsdk) = GetKeys(tree.LeftChild); + compressionKeys.AddMany(lsck.Select(kvp => (kvp.Key, "0" + kvp.Value))); + decompressionKeys.AddMany(lsdk.Select(kvp => ("0" + kvp.Key, kvp.Value))); + } - var left = splitter.Solve(node.Data, 0.5 * node.Data.Sum(x => x.frequency), x => x.frequency, _ => 1); - var right = node.Data.Except(left).ToArray(); + if (tree.RightChild is not null) + { + var (rsck, rsdk) = GetKeys(tree.RightChild); + compressionKeys.AddMany(rsck.Select(kvp => (kvp.Key, "1" + kvp.Value))); + decompressionKeys.AddMany(rsdk.Select(kvp => ("1" + kvp.Key, kvp.Value))); + } - node.LeftChild = GenerateShannonFanoTree(new ListNode(left)); - node.RightChild = GenerateShannonFanoTree(new ListNode(right)); + return (compressionKeys, decompressionKeys); + } + private ListNode GenerateShannonFanoTree(ListNode node) + { + if (node.Data.Length == 1) + { return node; } - /// - /// Finds frequency for each character in the text. - /// - /// Symbol-frequency array. - private ListNode GetListNodeFromText(string text) - { - var occurenceCounts = new Dictionary(); + var left = splitter.Solve(node.Data, 0.5 * node.Data.Sum(x => x.frequency), x => x.frequency, _ => 1); + var right = node.Data.Except(left).ToArray(); - for (var i = 0; i < text.Length; i++) - { - var ch = text[i]; - if (!occurenceCounts.ContainsKey(ch)) - { - occurenceCounts.Add(ch, 0); - } + node.LeftChild = GenerateShannonFanoTree(new ListNode(left)); + node.RightChild = GenerateShannonFanoTree(new ListNode(right)); + + return node; + } + + /// + /// Finds frequency for each character in the text. + /// + /// Symbol-frequency array. + private ListNode GetListNodeFromText(string text) + { + var occurenceCounts = new Dictionary(); - occurenceCounts[ch]++; + for (var i = 0; i < text.Length; i++) + { + var ch = text[i]; + if (!occurenceCounts.ContainsKey(ch)) + { + occurenceCounts.Add(ch, 0); } - return new ListNode(occurenceCounts.Select(kvp => (kvp.Key, 1d * kvp.Value / text.Length)).ToArray()); + occurenceCounts[ch]++; } - /// - /// Represents tree structure for the algorithm. - /// - public class ListNode - { - public ListNode((char symbol, double frequency)[] data) => Data = data; + return new ListNode(occurenceCounts.Select(kvp => (kvp.Key, 1d * kvp.Value / text.Length)).ToArray()); + } + + /// + /// Represents tree structure for the algorithm. + /// + public class ListNode + { + public ListNode((char symbol, double frequency)[] data) => Data = data; - public (char symbol, double frequency)[] Data { get; } + public (char symbol, double frequency)[] Data { get; } - public ListNode? RightChild { get; set; } + public ListNode? RightChild { get; set; } - public ListNode? LeftChild { get; set; } - } + public ListNode? LeftChild { get; set; } } } diff --git a/Algorithms/DataCompression/Translator.cs b/Algorithms/DataCompression/Translator.cs index 8372a52b..3bf0106a 100644 --- a/Algorithms/DataCompression/Translator.cs +++ b/Algorithms/DataCompression/Translator.cs @@ -1,35 +1,34 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Text; -namespace Algorithms.DataCompression +namespace Algorithms.DataCompression; + +/// +/// Provides method for text conversion by key mapping. +/// +public class Translator { /// - /// Provides method for text conversion by key mapping. + /// Converts the input text according to the translation keys. /// - public class Translator + /// Input text. + /// Translation keys used for text matching. + /// Converted text according to the translation keys. + public string Translate(string text, Dictionary translationKeys) { - /// - /// Converts the input text according to the translation keys. - /// - /// Input text. - /// Translation keys used for text matching. - /// Converted text according to the translation keys. - public string Translate(string text, Dictionary translationKeys) - { - var sb = new StringBuilder(); + var sb = new StringBuilder(); - var start = 0; - for (var i = 0; i < text.Length; i++) + var start = 0; + for (var i = 0; i < text.Length; i++) + { + var key = text.Substring(start, i - start + 1); + if (translationKeys.ContainsKey(key)) { - var key = text.Substring(start, i - start + 1); - if (translationKeys.ContainsKey(key)) - { - _ = sb.Append(translationKeys[key]); - start = i + 1; - } + _ = sb.Append(translationKeys[key]); + start = i + 1; } - - return sb.ToString(); } + + return sb.ToString(); } } diff --git a/Algorithms/Encoders/CaesarEncoder.cs b/Algorithms/Encoders/CaesarEncoder.cs index cf24c44e..8efb2a25 100644 --- a/Algorithms/Encoders/CaesarEncoder.cs +++ b/Algorithms/Encoders/CaesarEncoder.cs @@ -1,56 +1,55 @@ using System.Text; -namespace Algorithms.Encoders +namespace Algorithms.Encoders; + +/// +/// Encodes using caesar cypher. +/// +public class CaesarEncoder : IEncoder { /// - /// Encodes using caesar cypher. + /// Encodes text using specified key, + /// time complexity: O(n), + /// space complexity: O(n), + /// where n - text length. /// - public class CaesarEncoder : IEncoder + /// Text to be encoded. + /// Key that will be used to encode the text. + /// Encoded text. + public string Encode(string text, int key) => Cipher(text, key); + + /// + /// Decodes text that was encoded using specified key, + /// time complexity: O(n), + /// space complexity: O(n), + /// where n - text length. + /// + /// Text to be decoded. + /// Key that was used to encode the text. + /// Decoded text. + public string Decode(string text, int key) => Cipher(text, -key); + + private static string Cipher(string text, int key) { - /// - /// Encodes text using specified key, - /// time complexity: O(n), - /// space complexity: O(n), - /// where n - text length. - /// - /// Text to be encoded. - /// Key that will be used to encode the text. - /// Encoded text. - public string Encode(string text, int key) => Cipher(text, key); - - /// - /// Decodes text that was encoded using specified key, - /// time complexity: O(n), - /// space complexity: O(n), - /// where n - text length. - /// - /// Text to be decoded. - /// Key that was used to encode the text. - /// Decoded text. - public string Decode(string text, int key) => Cipher(text, -key); - - private static string Cipher(string text, int key) + var newText = new StringBuilder(text.Length); + for (var i = 0; i < text.Length; i++) { - var newText = new StringBuilder(text.Length); - for (var i = 0; i < text.Length; i++) + if (!char.IsLetter(text[i])) { - if (!char.IsLetter(text[i])) - { - _ = newText.Append(text[i]); - continue; - } - - var letterA = char.IsUpper(text[i]) ? 'A' : 'a'; - var letterZ = char.IsUpper(text[i]) ? 'Z' : 'z'; + _ = newText.Append(text[i]); + continue; + } - var c = text[i] + key; - c -= c > letterZ ? 26 * (1 + (c - letterZ - 1) / 26) : 0; - c += c < letterA ? 26 * (1 + (letterA - c - 1) / 26) : 0; + var letterA = char.IsUpper(text[i]) ? 'A' : 'a'; + var letterZ = char.IsUpper(text[i]) ? 'Z' : 'z'; - _ = newText.Append((char)c); - } + var c = text[i] + key; + c -= c > letterZ ? 26 * (1 + (c - letterZ - 1) / 26) : 0; + c += c < letterA ? 26 * (1 + (letterA - c - 1) / 26) : 0; - return newText.ToString(); + _ = newText.Append((char)c); } + + return newText.ToString(); } } diff --git a/Algorithms/Encoders/FeistelCipher.cs b/Algorithms/Encoders/FeistelCipher.cs index 6fdd4110..99b50e4b 100644 --- a/Algorithms/Encoders/FeistelCipher.cs +++ b/Algorithms/Encoders/FeistelCipher.cs @@ -2,176 +2,175 @@ using System.Collections.Generic; using System.Text; -namespace Algorithms.Encoders +namespace Algorithms.Encoders; + +/// +/// Encodes using Feistel cipher. +/// https://en.wikipedia.org/wiki/Feistel_cipher +/// In cryptography, a Feistel cipher (also known as Luby–Rackoff block cipher) +/// is a symmetric structure used in the construction of block ciphers, +/// named after the German-born physicist and cryptographer Horst Feistel +/// who did pioneering research while working for IBM (USA) +/// A large proportion of block ciphers use the scheme, including the US DES, +/// the Soviet/Russian GOST and the more recent Blowfish and Twofish ciphers. +/// +public class FeistelCipher : IEncoder { + // number of rounds to transform data block, each round a new "round" key is generated. + private const int Rounds = 32; + /// - /// Encodes using Feistel cipher. - /// https://en.wikipedia.org/wiki/Feistel_cipher - /// In cryptography, a Feistel cipher (also known as Luby–Rackoff block cipher) - /// is a symmetric structure used in the construction of block ciphers, - /// named after the German-born physicist and cryptographer Horst Feistel - /// who did pioneering research while working for IBM (USA) - /// A large proportion of block ciphers use the scheme, including the US DES, - /// the Soviet/Russian GOST and the more recent Blowfish and Twofish ciphers. + /// Encodes text using specified key, + /// where n - text length. /// - public class FeistelCipher : IEncoder + /// Text to be encoded. + /// Key that will be used to encode the text. + /// Error: key should be more than 0x00001111 for better encoding, key=0 will throw DivideByZero exception. + /// Encoded text. + public string Encode(string text, uint key) { - // number of rounds to transform data block, each round a new "round" key is generated. - private const int Rounds = 32; - - /// - /// Encodes text using specified key, - /// where n - text length. - /// - /// Text to be encoded. - /// Key that will be used to encode the text. - /// Error: key should be more than 0x00001111 for better encoding, key=0 will throw DivideByZero exception. - /// Encoded text. - public string Encode(string text, uint key) - { - List blocksListPlain = SplitTextToBlocks(text); - StringBuilder encodedText = new(); - - foreach (ulong block in blocksListPlain) - { - uint temp = 0; - - // decompose a block to two subblocks 0x0123456789ABCDEF => 0x01234567 & 0x89ABCDEF - uint rightSubblock = (uint)(block & 0x00000000FFFFFFFF); - uint leftSubblock = (uint)(block >> 32); - - uint roundKey; + List blocksListPlain = SplitTextToBlocks(text); + StringBuilder encodedText = new(); - // Feistel "network" itself - for (int round = 0; round < Rounds; round++) - { - roundKey = GetRoundKey(key, round); - temp = rightSubblock ^ BlockModification(leftSubblock, roundKey); - rightSubblock = leftSubblock; - leftSubblock = temp; - } + foreach (ulong block in blocksListPlain) + { + uint temp = 0; - // compile text string formating the block value to text (hex based), length of the output = 16 byte always - ulong encodedBlock = leftSubblock; - encodedBlock = (encodedBlock << 32) | rightSubblock; - encodedText.Append(string.Format("{0:X16}", encodedBlock)); - } + // decompose a block to two subblocks 0x0123456789ABCDEF => 0x01234567 & 0x89ABCDEF + uint rightSubblock = (uint)(block & 0x00000000FFFFFFFF); + uint leftSubblock = (uint)(block >> 32); - return encodedText.ToString(); - } + uint roundKey; - /// - /// Decodes text that was encoded using specified key. - /// - /// Text to be decoded. - /// Key that was used to encode the text. - /// Error: key should be more than 0x00001111 for better encoding, key=0 will throw DivideByZero exception. - /// Error: The length of text should be divisible by 16 as it the block lenght is 16 bytes. - /// Decoded text. - public string Decode(string text, uint key) - { - // The plain text will be padded to fill the size of block (16 bytes) - if (text.Length % 16 != 0) + // Feistel "network" itself + for (int round = 0; round < Rounds; round++) { - throw new ArgumentException($"The length of {nameof(key)} should be divisible by 16"); + roundKey = GetRoundKey(key, round); + temp = rightSubblock ^ BlockModification(leftSubblock, roundKey); + rightSubblock = leftSubblock; + leftSubblock = temp; } - List blocksListEncoded = GetBlocksFromEncodedText(text); - StringBuilder decodedTextHex = new(); - - foreach (ulong block in blocksListEncoded) - { - uint temp = 0; + // compile text string formating the block value to text (hex based), length of the output = 16 byte always + ulong encodedBlock = leftSubblock; + encodedBlock = (encodedBlock << 32) | rightSubblock; + encodedText.Append(string.Format("{0:X16}", encodedBlock)); + } - // decompose a block to two subblocks 0x0123456789ABCDEF => 0x01234567 & 0x89ABCDEF - uint rightSubblock = (uint)(block & 0x00000000FFFFFFFF); - uint leftSubblock = (uint)(block >> 32); + return encodedText.ToString(); + } - // Feistel "network" - decoding, the order of rounds and operations on the blocks is reverted - uint roundKey; - for (int round = Rounds - 1; round >= 0; round--) - { - roundKey = GetRoundKey(key, round); - temp = leftSubblock ^ BlockModification(rightSubblock, roundKey); - leftSubblock = rightSubblock; - rightSubblock = temp; - } + /// + /// Decodes text that was encoded using specified key. + /// + /// Text to be decoded. + /// Key that was used to encode the text. + /// Error: key should be more than 0x00001111 for better encoding, key=0 will throw DivideByZero exception. + /// Error: The length of text should be divisible by 16 as it the block lenght is 16 bytes. + /// Decoded text. + public string Decode(string text, uint key) + { + // The plain text will be padded to fill the size of block (16 bytes) + if (text.Length % 16 != 0) + { + throw new ArgumentException($"The length of {nameof(key)} should be divisible by 16"); + } - // compose decoded block - ulong decodedBlock = leftSubblock; - decodedBlock = (decodedBlock << 32) | rightSubblock; + List blocksListEncoded = GetBlocksFromEncodedText(text); + StringBuilder decodedTextHex = new(); - for(int i = 0; i < 8; i++) - { - ulong a = (decodedBlock & 0xFF00000000000000) >> 56; + foreach (ulong block in blocksListEncoded) + { + uint temp = 0; - // it's a trick, the code works with non zero characters, if your text has ASCII code 0x00 it will be skipped. - if (a != 0) - { - decodedTextHex.Append((char)a); - } + // decompose a block to two subblocks 0x0123456789ABCDEF => 0x01234567 & 0x89ABCDEF + uint rightSubblock = (uint)(block & 0x00000000FFFFFFFF); + uint leftSubblock = (uint)(block >> 32); - decodedBlock = decodedBlock << 8; - } + // Feistel "network" - decoding, the order of rounds and operations on the blocks is reverted + uint roundKey; + for (int round = Rounds - 1; round >= 0; round--) + { + roundKey = GetRoundKey(key, round); + temp = leftSubblock ^ BlockModification(rightSubblock, roundKey); + leftSubblock = rightSubblock; + rightSubblock = temp; } - return decodedTextHex.ToString(); - } + // compose decoded block + ulong decodedBlock = leftSubblock; + decodedBlock = (decodedBlock << 32) | rightSubblock; - // Using the size of block = 8 bytes this function splts the text and returns set of 8 bytes (ulong) blocks - // the last block is extended up to 8 bytes if the tail of the text is smaller than 8 bytes - private static List SplitTextToBlocks(string text) - { - List blocksListPlain = new(); - byte[] textArray = Encoding.ASCII.GetBytes(text); - int offset = 8; - for(int i = 0; i < text.Length; i += 8) + for(int i = 0; i < 8; i++) { - // text not always has len%16 == 0, that's why the offset should be adjusted for the last part of the text - if (i > text.Length - 8) + ulong a = (decodedBlock & 0xFF00000000000000) >> 56; + + // it's a trick, the code works with non zero characters, if your text has ASCII code 0x00 it will be skipped. + if (a != 0) { - offset = text.Length - i; + decodedTextHex.Append((char)a); } - string block = Convert.ToHexString(textArray, i, offset); - blocksListPlain.Add(Convert.ToUInt64(block, 16)); + decodedBlock = decodedBlock << 8; } - - return blocksListPlain; } - // convert the encoded text to the set of ulong values (blocks for decoding) - private static List GetBlocksFromEncodedText(string text) + return decodedTextHex.ToString(); + } + + // Using the size of block = 8 bytes this function splts the text and returns set of 8 bytes (ulong) blocks + // the last block is extended up to 8 bytes if the tail of the text is smaller than 8 bytes + private static List SplitTextToBlocks(string text) + { + List blocksListPlain = new(); + byte[] textArray = Encoding.ASCII.GetBytes(text); + int offset = 8; + for(int i = 0; i < text.Length; i += 8) { - List blocksListPlain = new(); - for(int i = 0; i < text.Length; i += 16) + // text not always has len%16 == 0, that's why the offset should be adjusted for the last part of the text + if (i > text.Length - 8) { - ulong block = Convert.ToUInt64(text.Substring(i, 16), 16); - blocksListPlain.Add(block); + offset = text.Length - i; } - return blocksListPlain; + string block = Convert.ToHexString(textArray, i, offset); + blocksListPlain.Add(Convert.ToUInt64(block, 16)); } - // here might be any deterministic math formula - private static uint BlockModification(uint block, uint key) - { - for (int i = 0; i < 32; i++) - { - // 0x55555555 for the better distribution 0 an 1 in the block - block = ((block ^ 0x55555555) * block) % key; - block = block ^ key; - } + return blocksListPlain; + } - return block; + // convert the encoded text to the set of ulong values (blocks for decoding) + private static List GetBlocksFromEncodedText(string text) + { + List blocksListPlain = new(); + for(int i = 0; i < text.Length; i += 16) + { + ulong block = Convert.ToUInt64(text.Substring(i, 16), 16); + blocksListPlain.Add(block); } - // There are many ways to generate a round key, any deterministic math formula does work - private static uint GetRoundKey(uint key, int round) + return blocksListPlain; + } + + // here might be any deterministic math formula + private static uint BlockModification(uint block, uint key) + { + for (int i = 0; i < 32; i++) { - // "round + 2" - to avoid a situation when pow(key,1) ^ key = key ^ key = 0 - uint a = (uint)Math.Pow((double)key, round + 2); - return a ^ key; + // 0x55555555 for the better distribution 0 an 1 in the block + block = ((block ^ 0x55555555) * block) % key; + block = block ^ key; } + + return block; + } + + // There are many ways to generate a round key, any deterministic math formula does work + private static uint GetRoundKey(uint key, int round) + { + // "round + 2" - to avoid a situation when pow(key,1) ^ key = key ^ key = 0 + uint a = (uint)Math.Pow((double)key, round + 2); + return a ^ key; } } diff --git a/Algorithms/Encoders/HillEncoder.cs b/Algorithms/Encoders/HillEncoder.cs index c314d42a..c6a84e7c 100644 --- a/Algorithms/Encoders/HillEncoder.cs +++ b/Algorithms/Encoders/HillEncoder.cs @@ -1,192 +1,191 @@ -using System; +using System; using System.Linq; using Algorithms.Numeric; -namespace Algorithms.Encoders +namespace Algorithms.Encoders; + +/// +/// Lester S. Hill's polygraphic substitution cipher, +/// without representing letters using mod26, using +/// corresponding "(char)value" instead. +/// +public class HillEncoder : IEncoder { - /// - /// Lester S. Hill's polygraphic substitution cipher, - /// without representing letters using mod26, using - /// corresponding "(char)value" instead. - /// - public class HillEncoder : IEncoder + private readonly GaussJordanElimination linearEquationSolver; + + public HillEncoder() => linearEquationSolver = new GaussJordanElimination(); // TODO: add DI + + public string Encode(string text, double[,] key) { - private readonly GaussJordanElimination linearEquationSolver; + var preparedText = FillGaps(text); + var chunked = ChunkTextToArray(preparedText); + var splitted = SplitToCharArray(chunked); - public HillEncoder() => linearEquationSolver = new GaussJordanElimination(); // TODO: add DI + var ciphered = new double[chunked.Length][]; - public string Encode(string text, double[,] key) + for (var i = 0; i < chunked.Length; i++) { - var preparedText = FillGaps(text); - var chunked = ChunkTextToArray(preparedText); - var splitted = SplitToCharArray(chunked); + var vector = new double[3]; + Array.Copy(splitted, i * 3, vector, 0, 3); + var product = MatrixCipher(vector, key); + ciphered[i] = product; + } - var ciphered = new double[chunked.Length][]; + var merged = MergeArrayList(ciphered); - for (var i = 0; i < chunked.Length; i++) - { - var vector = new double[3]; - Array.Copy(splitted, i * 3, vector, 0, 3); - var product = MatrixCipher(vector, key); - ciphered[i] = product; - } + return BuildStringFromArray(merged); + } - var merged = MergeArrayList(ciphered); + public string Decode(string text, double[,] key) + { + var chunked = ChunkTextToArray(text); + var split = SplitToCharArray(chunked); - return BuildStringFromArray(merged); - } + var deciphered = new double[chunked.Length][]; - public string Decode(string text, double[,] key) + for (var i = 0; i < chunked.Length; i++) { - var chunked = ChunkTextToArray(text); - var split = SplitToCharArray(chunked); + var vector = new double[3]; + Array.Copy(split, i * 3, vector, 0, 3); + var product = MatrixDeCipher(vector, key); + deciphered[i] = product; + } - var deciphered = new double[chunked.Length][]; + var merged = MergeArrayList(deciphered); + var str = BuildStringFromArray(merged); - for (var i = 0; i < chunked.Length; i++) - { - var vector = new double[3]; - Array.Copy(split, i * 3, vector, 0, 3); - var product = MatrixDeCipher(vector, key); - deciphered[i] = product; - } + return UnFillGaps(str); + } - var merged = MergeArrayList(deciphered); - var str = BuildStringFromArray(merged); + /// + /// Converts elements from the array to their corresponding Unicode characters. + /// + /// array of vectors. + /// Message. + private static string BuildStringFromArray(double[] arr) => new(arr.Select(c => (char)c).ToArray()); - return UnFillGaps(str); - } + /// + /// Multiplies the key for the given scalar. + /// + /// list of splitted words as numbers. + /// Cipher selected key. + /// Ciphered vector. + private static double[] MatrixCipher(double[] vector, double[,] key) + { + var multiplied = new double[vector.Length]; - /// - /// Converts elements from the array to their corresponding Unicode characters. - /// - /// array of vectors. - /// Message. - private static string BuildStringFromArray(double[] arr) => new(arr.Select(c => (char)c).ToArray()); - - /// - /// Multiplies the key for the given scalar. - /// - /// list of splitted words as numbers. - /// Cipher selected key. - /// Ciphered vector. - private static double[] MatrixCipher(double[] vector, double[,] key) + for (var i = 0; i < key.GetLength(1); i++) { - var multiplied = new double[vector.Length]; - - for (var i = 0; i < key.GetLength(1); i++) + for (var j = 0; j < key.GetLength(0); j++) { - for (var j = 0; j < key.GetLength(0); j++) - { - multiplied[i] += key[i, j] * vector[j]; - } + multiplied[i] += key[i, j] * vector[j]; } - - return multiplied; } - /// - /// Given a list of vectors, returns a single array of elements. - /// - /// List of ciphered arrays. - /// unidimensional list. - private static double[] MergeArrayList(double[][] list) - { - var merged = new double[list.Length * 3]; - - for (var i = 0; i < list.Length; i++) - { - Array.Copy(list[i], 0, merged, i * 3, list[0].Length); - } + return multiplied; + } - return merged; - } + /// + /// Given a list of vectors, returns a single array of elements. + /// + /// List of ciphered arrays. + /// unidimensional list. + private static double[] MergeArrayList(double[][] list) + { + var merged = new double[list.Length * 3]; - /// - /// Splits the input text message as chunks of words. - /// - /// chunked words list. - /// spliiter char array. - private static char[] SplitToCharArray(string[] chunked) + for (var i = 0; i < list.Length; i++) { - var splitted = new char[chunked.Length * 3]; + Array.Copy(list[i], 0, merged, i * 3, list[0].Length); + } - for (var i = 0; i < chunked.Length; i++) - { - for (var j = 0; j < 3; j++) - { - splitted[i * 3 + j] = chunked[i].ToCharArray()[j]; - } - } + return merged; + } - return splitted; - } + /// + /// Splits the input text message as chunks of words. + /// + /// chunked words list. + /// spliiter char array. + private static char[] SplitToCharArray(string[] chunked) + { + var splitted = new char[chunked.Length * 3]; - /// - /// Chunks the input text message. - /// - /// text message. - /// array of words. - private static string[] ChunkTextToArray(string text) + for (var i = 0; i < chunked.Length; i++) { - // To split the message into chunks - var div = text.Length / 3; - var chunks = new string[div]; - - for (var i = 0; i < div; i++) + for (var j = 0; j < 3; j++) { - chunks.SetValue(text.Substring(i * 3, 3), i); + splitted[i * 3 + j] = chunked[i].ToCharArray()[j]; } - - return chunks; } - /// - /// Fills a text message with spaces at the end - /// to enable a simple split by 3-length-word. - /// - /// Text Message. - /// Modified text Message. - private static string FillGaps(string text) + return splitted; + } + + /// + /// Chunks the input text message. + /// + /// text message. + /// array of words. + private static string[] ChunkTextToArray(string text) + { + // To split the message into chunks + var div = text.Length / 3; + var chunks = new string[div]; + + for (var i = 0; i < div; i++) { - var remainder = text.Length % 3; - return remainder == 0 ? text : text + new string(' ', 3 - remainder); + chunks.SetValue(text.Substring(i * 3, 3), i); } - /// - /// Removes the extra spaces included on the cipher phase. - /// - /// Text message. - /// Deciphered Message. - private static string UnFillGaps(string text) => text.TrimEnd(); - - /// - /// Finds the inverse of the given matrix using a linear equation solver. - /// - /// Splitted words vector. - /// Key used for the cipher. - /// TODO. - private double[] MatrixDeCipher(double[] vector, double[,] key) - { - // To augment the original key with the given vector. - var augM = new double[3, 4]; + return chunks; + } - for (var i = 0; i < key.GetLength(0); i++) - { - for (var j = 0; j < key.GetLength(1); j++) - { - augM[i, j] = key[i, j]; - } - } + /// + /// Fills a text message with spaces at the end + /// to enable a simple split by 3-length-word. + /// + /// Text Message. + /// Modified text Message. + private static string FillGaps(string text) + { + var remainder = text.Length % 3; + return remainder == 0 ? text : text + new string(' ', 3 - remainder); + } - for (var k = 0; k < vector.Length; k++) + /// + /// Removes the extra spaces included on the cipher phase. + /// + /// Text message. + /// Deciphered Message. + private static string UnFillGaps(string text) => text.TrimEnd(); + + /// + /// Finds the inverse of the given matrix using a linear equation solver. + /// + /// Splitted words vector. + /// Key used for the cipher. + /// TODO. + private double[] MatrixDeCipher(double[] vector, double[,] key) + { + // To augment the original key with the given vector. + var augM = new double[3, 4]; + + for (var i = 0; i < key.GetLength(0); i++) + { + for (var j = 0; j < key.GetLength(1); j++) { - augM[k, 3] = vector[k]; + augM[i, j] = key[i, j]; } + } - _ = linearEquationSolver.Solve(augM); - - return new[] { augM[0, 3], augM[1, 3], augM[2, 3] }; + for (var k = 0; k < vector.Length; k++) + { + augM[k, 3] = vector[k]; } + + _ = linearEquationSolver.Solve(augM); + + return new[] { augM[0, 3], augM[1, 3], augM[2, 3] }; } } diff --git a/Algorithms/Encoders/IEncoder.cs b/Algorithms/Encoders/IEncoder.cs index d8ed4541..e79129c0 100644 --- a/Algorithms/Encoders/IEncoder.cs +++ b/Algorithms/Encoders/IEncoder.cs @@ -1,25 +1,24 @@ -namespace Algorithms.Encoders +namespace Algorithms.Encoders; + +/// +/// Encodes and decodes text based on specified key. +/// +/// Type of the key. +public interface IEncoder { /// - /// Encodes and decodes text based on specified key. + /// Encodes text using specified key. /// - /// Type of the key. - public interface IEncoder - { - /// - /// Encodes text using specified key. - /// - /// Text to be encoded. - /// Key that will be used to encode the text. - /// Encoded text. - string Encode(string text, TKey key); + /// Text to be encoded. + /// Key that will be used to encode the text. + /// Encoded text. + string Encode(string text, TKey key); - /// - /// Decodes text that was encoded using specified key. - /// - /// Text to be decoded. - /// Key that was used to encode the text. - /// Decoded text. - string Decode(string text, TKey key); - } + /// + /// Decodes text that was encoded using specified key. + /// + /// Text to be decoded. + /// Key that was used to encode the text. + /// Decoded text. + string Decode(string text, TKey key); } diff --git a/Algorithms/Encoders/NysiisEncoder.cs b/Algorithms/Encoders/NysiisEncoder.cs index b28c5e8d..a5e98747 100644 --- a/Algorithms/Encoders/NysiisEncoder.cs +++ b/Algorithms/Encoders/NysiisEncoder.cs @@ -2,179 +2,178 @@ using System.Linq; using System.Text; -namespace Algorithms.Encoders +namespace Algorithms.Encoders; + +/// +/// Class for NYSIIS encoding strings. +/// +public class NysiisEncoder { + private static readonly char[] Vowels = { 'A', 'E', 'I', 'O', 'U' }; + /// - /// Class for NYSIIS encoding strings. + /// Encodes a string using the NYSIIS Algorithm. /// - public class NysiisEncoder + /// The string to encode. + /// The NYSIIS encoded string (all uppercase). + public string Encode(string text) { - private static readonly char[] Vowels = { 'A', 'E', 'I', 'O', 'U' }; - - /// - /// Encodes a string using the NYSIIS Algorithm. - /// - /// The string to encode. - /// The NYSIIS encoded string (all uppercase). - public string Encode(string text) - { - text = text.ToUpper(CultureInfo.CurrentCulture); - text = TrimSpaces(text); - text = StartReplace(text); - text = EndReplace(text); + text = text.ToUpper(CultureInfo.CurrentCulture); + text = TrimSpaces(text); + text = StartReplace(text); + text = EndReplace(text); - for (var i = 1; i < text.Length; i++) - { - text = ReplaceStep(text, i); - } - - text = RemoveDuplicates(text); - return TrimEnd(text); + for (var i = 1; i < text.Length; i++) + { + text = ReplaceStep(text, i); } - private string TrimSpaces(string text) => text.Replace(" ", string.Empty); + text = RemoveDuplicates(text); + return TrimEnd(text); + } + + private string TrimSpaces(string text) => text.Replace(" ", string.Empty); - private string RemoveDuplicates(string text) + private string RemoveDuplicates(string text) + { + var sb = new StringBuilder(); + sb.Append(text[0]); + foreach (var c in text) { - var sb = new StringBuilder(); - sb.Append(text[0]); - foreach (var c in text) + if (sb[^1] != c) { - if (sb[^1] != c) - { - sb.Append(c); - } + sb.Append(c); } - - return sb.ToString(); } - private string TrimEnd(string text) + return sb.ToString(); + } + + private string TrimEnd(string text) + { + var checks = new (string from, string to)?[] { - var checks = new (string from, string to)?[] - { - ("S", string.Empty), - ("AY", "Y"), - ("A", string.Empty), - }; - var replacement = checks.FirstOrDefault(t => text.EndsWith(t!.Value.from)); - if (replacement is { }) - { - var (from, to) = replacement!.Value; - text = Replace(text, text.Length - from.Length, from.Length, to); - } + ("S", string.Empty), + ("AY", "Y"), + ("A", string.Empty), + }; + var replacement = checks.FirstOrDefault(t => text.EndsWith(t!.Value.from)); + if (replacement is { }) + { + var (from, to) = replacement!.Value; + text = Replace(text, text.Length - from.Length, from.Length, to); + } + + return text; + } + private string ReplaceStep(string text, int i) + { + (string from, string to)[] replacements = + { + ("EV", "AF"), + ("E", "A"), + ("I", "A"), + ("O", "A"), + ("U", "A"), + ("Q", "G"), + ("Z", "S"), + ("M", "N"), + ("KN", "NN"), + ("K", "C"), + ("SCH", "SSS"), + ("PH", "FF"), + }; + var replaced = TryReplace(text, i, replacements, out text); + if (replaced) + { return text; } - private string ReplaceStep(string text, int i) + // H[vowel] or [vowel]H -> text[i-1] + if (text[i] == 'H') { - (string from, string to)[] replacements = - { - ("EV", "AF"), - ("E", "A"), - ("I", "A"), - ("O", "A"), - ("U", "A"), - ("Q", "G"), - ("Z", "S"), - ("M", "N"), - ("KN", "NN"), - ("K", "C"), - ("SCH", "SSS"), - ("PH", "FF"), - }; - var replaced = TryReplace(text, i, replacements, out text); - if (replaced) - { - return text; - } - - // H[vowel] or [vowel]H -> text[i-1] - if (text[i] == 'H') + if (!Vowels.Contains(text[i - 1])) { - if (!Vowels.Contains(text[i - 1])) - { - return ReplaceWithPrevious(); - } - - if (i < text.Length - 1 && !Vowels.Contains(text[i + 1])) - { - return ReplaceWithPrevious(); - } + return ReplaceWithPrevious(); } - // [vowel]W -> [vowel] - if (text[i] == 'W' && Vowels.Contains(text[i - 1])) + if (i < text.Length - 1 && !Vowels.Contains(text[i + 1])) { return ReplaceWithPrevious(); } - - return text; - - string ReplaceWithPrevious() => Replace(text, i, 1, text[i - 1].ToString()); } - private bool TryReplace(string text, int index, (string, string)[] opts, out string result) + // [vowel]W -> [vowel] + if (text[i] == 'W' && Vowels.Contains(text[i - 1])) { - for (var i = 0; i < opts.Length; i++) - { - var check = opts[i].Item1; - var repl = opts[i].Item2; - if (text.Length >= index + check.Length && text.Substring(index, check.Length) == check) - { - result = Replace(text, index, check.Length, repl); - return true; - } - } - - result = text; - return false; + return ReplaceWithPrevious(); } - private string StartReplace(string start) + return text; + + string ReplaceWithPrevious() => Replace(text, i, 1, text[i - 1].ToString()); + } + + private bool TryReplace(string text, int index, (string, string)[] opts, out string result) + { + for (var i = 0; i < opts.Length; i++) { - var checks = new (string from, string to)?[] + var check = opts[i].Item1; + var repl = opts[i].Item2; + if (text.Length >= index + check.Length && text.Substring(index, check.Length) == check) { - ("MAC", "MCC"), - ("KN", "NN"), - ("K", "C"), - ("PH", "FF"), - ("PF", "FF"), - ("SCH", "SSS"), - }; - var replacement = checks.FirstOrDefault(t => start.StartsWith(t!.Value.from)); - if (replacement is { }) - { - var (from, to) = replacement!.Value; - start = Replace(start, 0, from.Length, to); + result = Replace(text, index, check.Length, repl); + return true; } - - return start; } - private string EndReplace(string end) + result = text; + return false; + } + + private string StartReplace(string start) + { + var checks = new (string from, string to)?[] { - var checks = new (string from, string to)?[] - { - ("EE", "Y"), - ("IE", "Y"), - ("DT", "D"), - ("RT", "D"), - ("NT", "D"), - ("ND", "D"), - }; - var replacement = checks.FirstOrDefault(t => end.EndsWith(t!.Value.from)); - if (replacement is { }) - { - var (from, to) = replacement!.Value; - end = Replace(end, end.Length - from.Length, from.Length, to); - } + ("MAC", "MCC"), + ("KN", "NN"), + ("K", "C"), + ("PH", "FF"), + ("PF", "FF"), + ("SCH", "SSS"), + }; + var replacement = checks.FirstOrDefault(t => start.StartsWith(t!.Value.from)); + if (replacement is { }) + { + var (from, to) = replacement!.Value; + start = Replace(start, 0, from.Length, to); + } - return end; + return start; + } + + private string EndReplace(string end) + { + var checks = new (string from, string to)?[] + { + ("EE", "Y"), + ("IE", "Y"), + ("DT", "D"), + ("RT", "D"), + ("NT", "D"), + ("ND", "D"), + }; + var replacement = checks.FirstOrDefault(t => end.EndsWith(t!.Value.from)); + if (replacement is { }) + { + var (from, to) = replacement!.Value; + end = Replace(end, end.Length - from.Length, from.Length, to); } - private string Replace(string text, int index, int length, string substitute) => - text[..index] + substitute + text[(index + length) ..]; + return end; } + + private string Replace(string text, int index, int length, string substitute) => + text[..index] + substitute + text[(index + length) ..]; } diff --git a/Algorithms/Encoders/SoundexEncoder.cs b/Algorithms/Encoders/SoundexEncoder.cs index 1dded601..bebcf002 100644 --- a/Algorithms/Encoders/SoundexEncoder.cs +++ b/Algorithms/Encoders/SoundexEncoder.cs @@ -1,111 +1,110 @@ using System.Collections.Generic; using System.Linq; -namespace Algorithms.Encoders +namespace Algorithms.Encoders; + +/// +/// Class for Soundex encoding strings. +/// +public class SoundexEncoder { /// - /// Class for Soundex encoding strings. + /// Encodes a string using the Soundex Algorithm. /// - public class SoundexEncoder + /// The string to encode. + /// The Soundex encoded string (one uppercase character and three digits). + public string Encode(string text) { - /// - /// Encodes a string using the Soundex Algorithm. - /// - /// The string to encode. - /// The Soundex encoded string (one uppercase character and three digits). - public string Encode(string text) - { - text = text.ToLowerInvariant(); - var chars = OmitHAndW(text); - IEnumerable numbers = ProduceNumberCoding(chars); - numbers = CollapseDoubles(numbers); - numbers = OmitVowels(numbers); - numbers = CollapseLeadingDigit(numbers, text[0]); - numbers = numbers.Take(3); - numbers = PadTo3Numbers(numbers); - var final = numbers.ToArray(); - return $"{text.ToUpperInvariant()[0]}{final[0]}{final[1]}{final[2]}"; - } + text = text.ToLowerInvariant(); + var chars = OmitHAndW(text); + IEnumerable numbers = ProduceNumberCoding(chars); + numbers = CollapseDoubles(numbers); + numbers = OmitVowels(numbers); + numbers = CollapseLeadingDigit(numbers, text[0]); + numbers = numbers.Take(3); + numbers = PadTo3Numbers(numbers); + var final = numbers.ToArray(); + return $"{text.ToUpperInvariant()[0]}{final[0]}{final[1]}{final[2]}"; + } - private IEnumerable CollapseLeadingDigit(IEnumerable numbers, char c) + private IEnumerable CollapseLeadingDigit(IEnumerable numbers, char c) + { + using var enumerator = numbers.GetEnumerator(); + enumerator.MoveNext(); + if (enumerator.Current == MapToNumber(c)) { - using var enumerator = numbers.GetEnumerator(); enumerator.MoveNext(); - if (enumerator.Current == MapToNumber(c)) - { - enumerator.MoveNext(); - } + } - do - { - yield return enumerator.Current; - } - while (enumerator.MoveNext()); + do + { + yield return enumerator.Current; } + while (enumerator.MoveNext()); + } - private IEnumerable PadTo3Numbers(IEnumerable numbers) + private IEnumerable PadTo3Numbers(IEnumerable numbers) + { + using var enumerator = numbers.GetEnumerator(); + for (var i = 0; i < 3; i++) { - using var enumerator = numbers.GetEnumerator(); - for (var i = 0; i < 3; i++) - { - yield return enumerator.MoveNext() - ? enumerator.Current - : 0; - } + yield return enumerator.MoveNext() + ? enumerator.Current + : 0; } + } - private IEnumerable OmitVowels(IEnumerable numbers) => numbers.Where(i => i != 0); + private IEnumerable OmitVowels(IEnumerable numbers) => numbers.Where(i => i != 0); - private IEnumerable OmitHAndW(string text) => text.Where(c => c != 'h' && c != 'w'); + private IEnumerable OmitHAndW(string text) => text.Where(c => c != 'h' && c != 'w'); - private IEnumerable CollapseDoubles(IEnumerable numbers) + private IEnumerable CollapseDoubles(IEnumerable numbers) + { + var previous = int.MinValue; + foreach (var i in numbers) { - var previous = int.MinValue; - foreach (var i in numbers) + if (previous != i) { - if (previous != i) - { - yield return i; - previous = i; - } + yield return i; + previous = i; } } + } - private IEnumerable ProduceNumberCoding(IEnumerable text) => text.Select(MapToNumber); + private IEnumerable ProduceNumberCoding(IEnumerable text) => text.Select(MapToNumber); - private int MapToNumber(char ch) + private int MapToNumber(char ch) + { + var mapping = new Dictionary { - var mapping = new Dictionary - { - ['a'] = 0, - ['e'] = 0, - ['i'] = 0, - ['o'] = 0, - ['u'] = 0, - ['y'] = 0, - ['h'] = 8, - ['w'] = 8, - ['b'] = 1, - ['f'] = 1, - ['p'] = 1, - ['v'] = 1, - ['c'] = 2, - ['g'] = 2, - ['j'] = 2, - ['k'] = 2, - ['q'] = 2, - ['s'] = 2, - ['x'] = 2, - ['z'] = 2, - ['d'] = 3, - ['t'] = 3, - ['l'] = 4, - ['m'] = 5, - ['n'] = 5, - ['r'] = 6, - }; + ['a'] = 0, + ['e'] = 0, + ['i'] = 0, + ['o'] = 0, + ['u'] = 0, + ['y'] = 0, + ['h'] = 8, + ['w'] = 8, + ['b'] = 1, + ['f'] = 1, + ['p'] = 1, + ['v'] = 1, + ['c'] = 2, + ['g'] = 2, + ['j'] = 2, + ['k'] = 2, + ['q'] = 2, + ['s'] = 2, + ['x'] = 2, + ['z'] = 2, + ['d'] = 3, + ['t'] = 3, + ['l'] = 4, + ['m'] = 5, + ['n'] = 5, + ['r'] = 6, + }; - return mapping[ch]; - } + return mapping[ch]; } } diff --git a/Algorithms/Encoders/VigenereEncoder.cs b/Algorithms/Encoders/VigenereEncoder.cs index 68bea0ac..f4fe9036 100644 --- a/Algorithms/Encoders/VigenereEncoder.cs +++ b/Algorithms/Encoders/VigenereEncoder.cs @@ -1,71 +1,70 @@ -using System; +using System; using System.Text; -namespace Algorithms.Encoders +namespace Algorithms.Encoders; + +/// +/// Encodes using vigenere cypher. +/// +public class VigenereEncoder : IEncoder { + private readonly CaesarEncoder caesarEncoder = new(); + /// - /// Encodes using vigenere cypher. + /// Encodes text using specified key, + /// time complexity: O(n), + /// space complexity: O(n), + /// where n - text length. /// - public class VigenereEncoder : IEncoder - { - private readonly CaesarEncoder caesarEncoder = new(); + /// Text to be encoded. + /// Key that will be used to encode the text. + /// Encoded text. + public string Encode(string text, string key) => Cipher(text, key, caesarEncoder.Encode); - /// - /// Encodes text using specified key, - /// time complexity: O(n), - /// space complexity: O(n), - /// where n - text length. - /// - /// Text to be encoded. - /// Key that will be used to encode the text. - /// Encoded text. - public string Encode(string text, string key) => Cipher(text, key, caesarEncoder.Encode); - - /// - /// Decodes text that was encoded using specified key, - /// time complexity: O(n), - /// space complexity: O(n), - /// where n - text length. - /// - /// Text to be decoded. - /// Key that was used to encode the text. - /// Decoded text. - public string Decode(string text, string key) => Cipher(text, key, caesarEncoder.Decode); + /// + /// Decodes text that was encoded using specified key, + /// time complexity: O(n), + /// space complexity: O(n), + /// where n - text length. + /// + /// Text to be decoded. + /// Key that was used to encode the text. + /// Decoded text. + public string Decode(string text, string key) => Cipher(text, key, caesarEncoder.Decode); - private string Cipher(string text, string key, Func symbolCipher) + private string Cipher(string text, string key, Func symbolCipher) + { + key = AppendKey(key, text.Length); + var encodedTextBuilder = new StringBuilder(text.Length); + for (var i = 0; i < text.Length; i++) { - key = AppendKey(key, text.Length); - var encodedTextBuilder = new StringBuilder(text.Length); - for (var i = 0; i < text.Length; i++) + if (!char.IsLetter(text[i])) { - if (!char.IsLetter(text[i])) - { - _ = encodedTextBuilder.Append(text[i]); - continue; - } - - var letterZ = char.IsUpper(key[i]) ? 'Z' : 'z'; - var encodedSymbol = symbolCipher(text[i].ToString(), letterZ - key[i]); - _ = encodedTextBuilder.Append(encodedSymbol); + _ = encodedTextBuilder.Append(text[i]); + continue; } - return encodedTextBuilder.ToString(); + var letterZ = char.IsUpper(key[i]) ? 'Z' : 'z'; + var encodedSymbol = symbolCipher(text[i].ToString(), letterZ - key[i]); + _ = encodedTextBuilder.Append(encodedSymbol); } - private string AppendKey(string key, int length) - { - if (string.IsNullOrEmpty(key)) - { - throw new ArgumentOutOfRangeException($"{nameof(key)} must be non-empty string"); - } + return encodedTextBuilder.ToString(); + } - var keyBuilder = new StringBuilder(key, length); - while (keyBuilder.Length < length) - { - _ = keyBuilder.Append(key); - } + private string AppendKey(string key, int length) + { + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentOutOfRangeException($"{nameof(key)} must be non-empty string"); + } - return keyBuilder.ToString(); + var keyBuilder = new StringBuilder(key, length); + while (keyBuilder.Length < length) + { + _ = keyBuilder.Append(key); } + + return keyBuilder.ToString(); } } diff --git a/Algorithms/Graph/BellmanFord.cs b/Algorithms/Graph/BellmanFord.cs index 6605a6cf..cec67ae0 100644 --- a/Algorithms/Graph/BellmanFord.cs +++ b/Algorithms/Graph/BellmanFord.cs @@ -2,118 +2,117 @@ using System.Collections.Generic; using DataStructures.Graph; -namespace Algorithms.Graph +namespace Algorithms.Graph; + +/// +/// Bellman-Ford algorithm on directed weighted graph. +/// +/// Generic type of data in the graph. +public class BellmanFord { + private readonly DirectedWeightedGraph graph; + private readonly Dictionary, double> distances; + private readonly Dictionary, Vertex?> predecessors; + + public BellmanFord(DirectedWeightedGraph graph, Dictionary, double> distances, Dictionary, Vertex?> predecessors) + { + this.graph = graph; + this.distances = distances; + this.predecessors = predecessors; + } + /// - /// Bellman-Ford algorithm on directed weighted graph. + /// Runs the Bellman-Ford algorithm to find the shortest distances from the source vertex to all other vertices. /// - /// Generic type of data in the graph. - public class BellmanFord + /// Source vertex for shortest path calculation. + /// + /// A dictionary containing the shortest distances from the source vertex to all other vertices. + /// If a vertex is unreachable from the source, it will have a value of double.PositiveInfinity. + /// + public Dictionary, double> Run(Vertex sourceVertex) { - private readonly DirectedWeightedGraph graph; - private readonly Dictionary, double> distances; - private readonly Dictionary, Vertex?> predecessors; + InitializeDistances(sourceVertex); + RelaxEdges(); + CheckForNegativeCycles(); + return distances; + } - public BellmanFord(DirectedWeightedGraph graph, Dictionary, double> distances, Dictionary, Vertex?> predecessors) + private void InitializeDistances(Vertex sourceVertex) + { + foreach (var vertex in graph.Vertices) { - this.graph = graph; - this.distances = distances; - this.predecessors = predecessors; + if (vertex != null) + { + distances[vertex] = double.PositiveInfinity; + predecessors[vertex] = null; + } } - /// - /// Runs the Bellman-Ford algorithm to find the shortest distances from the source vertex to all other vertices. - /// - /// Source vertex for shortest path calculation. - /// - /// A dictionary containing the shortest distances from the source vertex to all other vertices. - /// If a vertex is unreachable from the source, it will have a value of double.PositiveInfinity. - /// - public Dictionary, double> Run(Vertex sourceVertex) - { - InitializeDistances(sourceVertex); - RelaxEdges(); - CheckForNegativeCycles(); - return distances; - } + distances[sourceVertex] = 0; + } + + private void RelaxEdges() + { + int vertexCount = graph.Count; - private void InitializeDistances(Vertex sourceVertex) + for (int i = 0; i < vertexCount - 1; i++) { foreach (var vertex in graph.Vertices) { if (vertex != null) { - distances[vertex] = double.PositiveInfinity; - predecessors[vertex] = null; + RelaxEdgesForVertex(vertex); } } - - distances[sourceVertex] = 0; } + } - private void RelaxEdges() + private void RelaxEdgesForVertex(Vertex u) + { + foreach (var neighbor in graph.GetNeighbors(u)) { - int vertexCount = graph.Count; - - for (int i = 0; i < vertexCount - 1; i++) + if (neighbor == null) { - foreach (var vertex in graph.Vertices) - { - if (vertex != null) - { - RelaxEdgesForVertex(vertex); - } - } + continue; } - } - private void RelaxEdgesForVertex(Vertex u) - { - foreach (var neighbor in graph.GetNeighbors(u)) - { - if (neighbor == null) - { - continue; - } + var v = neighbor; + var weight = graph.AdjacentDistance(u, v); - var v = neighbor; - var weight = graph.AdjacentDistance(u, v); - - if (distances[u] + weight < distances[v]) - { - distances[v] = distances[u] + weight; - predecessors[v] = u; - } + if (distances[u] + weight < distances[v]) + { + distances[v] = distances[u] + weight; + predecessors[v] = u; } } + } - private void CheckForNegativeCycles() + private void CheckForNegativeCycles() + { + foreach (var vertex in graph.Vertices) { - foreach (var vertex in graph.Vertices) + if (vertex != null) { - if (vertex != null) - { - CheckForNegativeCyclesForVertex(vertex); - } + CheckForNegativeCyclesForVertex(vertex); } } + } - private void CheckForNegativeCyclesForVertex(Vertex u) + private void CheckForNegativeCyclesForVertex(Vertex u) + { + foreach (var neighbor in graph.GetNeighbors(u)) { - foreach (var neighbor in graph.GetNeighbors(u)) + if (neighbor == null) { - if (neighbor == null) - { - continue; - } + continue; + } - var v = neighbor; - var weight = graph.AdjacentDistance(u, v); + var v = neighbor; + var weight = graph.AdjacentDistance(u, v); - if (distances[u] + weight < distances[v]) - { - throw new InvalidOperationException("Graph contains a negative weight cycle."); - } + if (distances[u] + weight < distances[v]) + { + throw new InvalidOperationException("Graph contains a negative weight cycle."); } } } diff --git a/Algorithms/Graph/BreadthFirstSearch.cs b/Algorithms/Graph/BreadthFirstSearch.cs index 00b8f8a3..187c1ff9 100644 --- a/Algorithms/Graph/BreadthFirstSearch.cs +++ b/Algorithms/Graph/BreadthFirstSearch.cs @@ -2,58 +2,57 @@ using System.Collections.Generic; using DataStructures.Graph; -namespace Algorithms.Graph +namespace Algorithms.Graph; + +/// +/// Breadth First Search - algorithm for traversing graph. +/// Algorithm starts from root node that is selected by the user. +/// Algorithm explores all nodes at the present depth. +/// +/// Vertex data type. +public class BreadthFirstSearch : IGraphSearch where T : IComparable { /// - /// Breadth First Search - algorithm for traversing graph. - /// Algorithm starts from root node that is selected by the user. - /// Algorithm explores all nodes at the present depth. + /// Traverses graph from start vertex. /// - /// Vertex data type. - public class BreadthFirstSearch : IGraphSearch where T : IComparable + /// Graph instance. + /// Vertex that search starts from. + /// Action that needs to be executed on each graph vertex. + public void VisitAll(IDirectedWeightedGraph graph, Vertex startVertex, Action>? action = default) { - /// - /// Traverses graph from start vertex. - /// - /// Graph instance. - /// Vertex that search starts from. - /// Action that needs to be executed on each graph vertex. - public void VisitAll(IDirectedWeightedGraph graph, Vertex startVertex, Action>? action = default) - { - Bfs(graph, startVertex, action, new HashSet>()); - } + Bfs(graph, startVertex, action, new HashSet>()); + } - /// - /// Traverses graph from start vertex. - /// - /// Graph instance. - /// Vertex that search starts from. - /// Action that needs to be executed on each graph vertex. - /// Hash set with visited vertices. - private void Bfs(IDirectedWeightedGraph graph, Vertex startVertex, Action>? action, HashSet> visited) - { - var queue = new Queue>(); + /// + /// Traverses graph from start vertex. + /// + /// Graph instance. + /// Vertex that search starts from. + /// Action that needs to be executed on each graph vertex. + /// Hash set with visited vertices. + private void Bfs(IDirectedWeightedGraph graph, Vertex startVertex, Action>? action, HashSet> visited) + { + var queue = new Queue>(); - queue.Enqueue(startVertex); + queue.Enqueue(startVertex); - while (queue.Count > 0) - { - var currentVertex = queue.Dequeue(); + while (queue.Count > 0) + { + var currentVertex = queue.Dequeue(); - if (currentVertex == null || visited.Contains(currentVertex)) - { - continue; - } + if (currentVertex == null || visited.Contains(currentVertex)) + { + continue; + } - foreach (var vertex in graph.GetNeighbors(currentVertex)) - { - queue.Enqueue(vertex!); - } + foreach (var vertex in graph.GetNeighbors(currentVertex)) + { + queue.Enqueue(vertex!); + } - action?.Invoke(currentVertex); + action?.Invoke(currentVertex); - visited.Add(currentVertex); - } + visited.Add(currentVertex); } } } diff --git a/Algorithms/Graph/BreadthFirstTreeTraversal.cs b/Algorithms/Graph/BreadthFirstTreeTraversal.cs index 04b5ef0b..76f16b72 100644 --- a/Algorithms/Graph/BreadthFirstTreeTraversal.cs +++ b/Algorithms/Graph/BreadthFirstTreeTraversal.cs @@ -2,89 +2,88 @@ using System.Collections.Generic; using DataStructures.BinarySearchTree; -namespace Algorithms.Graph +namespace Algorithms.Graph; + +/// +/// Breadth first tree traversal traverses through a binary tree +/// by iterating through each level first. +/// time complexity: O(n). +/// space complexity: O(w) where w is the max width of a binary tree. +/// +/// Type of key held in binary search tree. +public static class BreadthFirstTreeTraversal { /// - /// Breadth first tree traversal traverses through a binary tree - /// by iterating through each level first. - /// time complexity: O(n). - /// space complexity: O(w) where w is the max width of a binary tree. + /// Level Order Traversal returns an array of integers in order + /// of each level of a binary tree. It uses a queue to iterate + /// through each node following breadth first search traversal. /// - /// Type of key held in binary search tree. - public static class BreadthFirstTreeTraversal + /// Passes the binary tree to traverse. + /// Returns level order traversal. + public static TKey[] LevelOrderTraversal(BinarySearchTree tree) { - /// - /// Level Order Traversal returns an array of integers in order - /// of each level of a binary tree. It uses a queue to iterate - /// through each node following breadth first search traversal. - /// - /// Passes the binary tree to traverse. - /// Returns level order traversal. - public static TKey[] LevelOrderTraversal(BinarySearchTree tree) + BinarySearchTreeNode? root = tree.Root; + TKey[] levelOrder = new TKey[tree.Count]; + if (root is null) + { + return Array.Empty(); + } + + Queue> breadthTraversal = new Queue>(); + breadthTraversal.Enqueue(root); + for (int i = 0; i < levelOrder.Length; i++) { - BinarySearchTreeNode? root = tree.Root; - TKey[] levelOrder = new TKey[tree.Count]; - if (root is null) + BinarySearchTreeNode current = breadthTraversal.Dequeue(); + levelOrder[i] = current.Key; + if (current.Left is not null) { - return Array.Empty(); + breadthTraversal.Enqueue(current.Left); } - Queue> breadthTraversal = new Queue>(); - breadthTraversal.Enqueue(root); - for (int i = 0; i < levelOrder.Length; i++) + if (current.Right is not null) { - BinarySearchTreeNode current = breadthTraversal.Dequeue(); - levelOrder[i] = current.Key; - if (current.Left is not null) - { - breadthTraversal.Enqueue(current.Left); - } - - if (current.Right is not null) - { - breadthTraversal.Enqueue(current.Right); - } + breadthTraversal.Enqueue(current.Right); } + } + + return levelOrder; + } - return levelOrder; + /// + /// Deepest Node return the deepest node in a binary tree. If more + /// than one node is on the deepest level, it is defined as the + /// right-most node of a binary tree. Deepest node uses breadth + /// first traversal to reach the end. + /// + /// Tree passed to find deepest node. + /// Returns the deepest node in the tree. + public static TKey? DeepestNode(BinarySearchTree tree) + { + BinarySearchTreeNode? root = tree.Root; + if (root is null) + { + return default(TKey); } - /// - /// Deepest Node return the deepest node in a binary tree. If more - /// than one node is on the deepest level, it is defined as the - /// right-most node of a binary tree. Deepest node uses breadth - /// first traversal to reach the end. - /// - /// Tree passed to find deepest node. - /// Returns the deepest node in the tree. - public static TKey? DeepestNode(BinarySearchTree tree) + Queue> breadthTraversal = new Queue>(); + breadthTraversal.Enqueue(root); + TKey deepest = root.Key; + while (breadthTraversal.Count > 0) { - BinarySearchTreeNode? root = tree.Root; - if (root is null) + BinarySearchTreeNode current = breadthTraversal.Dequeue(); + if (current.Left is not null) { - return default(TKey); + breadthTraversal.Enqueue(current.Left); } - Queue> breadthTraversal = new Queue>(); - breadthTraversal.Enqueue(root); - TKey deepest = root.Key; - while (breadthTraversal.Count > 0) + if (current.Right is not null) { - BinarySearchTreeNode current = breadthTraversal.Dequeue(); - if (current.Left is not null) - { - breadthTraversal.Enqueue(current.Left); - } - - if (current.Right is not null) - { - breadthTraversal.Enqueue(current.Right); - } - - deepest = current.Key; + breadthTraversal.Enqueue(current.Right); } - return deepest; + deepest = current.Key; } + + return deepest; } } diff --git a/Algorithms/Graph/DepthFirstSearch.cs b/Algorithms/Graph/DepthFirstSearch.cs index 2f19a2b1..805a067f 100644 --- a/Algorithms/Graph/DepthFirstSearch.cs +++ b/Algorithms/Graph/DepthFirstSearch.cs @@ -2,49 +2,48 @@ using System.Collections.Generic; using DataStructures.Graph; -namespace Algorithms.Graph +namespace Algorithms.Graph; + +/// +/// Depth First Search - algorithm for traversing graph. +/// Algorithm starts from root node that is selected by the user. +/// Algorithm explores as far as possible along each branch before backtracking. +/// +/// Vertex data type. +public class DepthFirstSearch : IGraphSearch where T : IComparable { /// - /// Depth First Search - algorithm for traversing graph. - /// Algorithm starts from root node that is selected by the user. - /// Algorithm explores as far as possible along each branch before backtracking. + /// Traverses graph from start vertex. /// - /// Vertex data type. - public class DepthFirstSearch : IGraphSearch where T : IComparable + /// Graph instance. + /// Vertex that search starts from. + /// Action that needs to be executed on each graph vertex. + public void VisitAll(IDirectedWeightedGraph graph, Vertex startVertex, Action>? action = default) { - /// - /// Traverses graph from start vertex. - /// - /// Graph instance. - /// Vertex that search starts from. - /// Action that needs to be executed on each graph vertex. - public void VisitAll(IDirectedWeightedGraph graph, Vertex startVertex, Action>? action = default) - { - Dfs(graph, startVertex, action, new HashSet>()); - } + Dfs(graph, startVertex, action, new HashSet>()); + } - /// - /// Traverses graph from start vertex. - /// - /// Graph instance. - /// Vertex that search starts from. - /// Action that needs to be executed on each graph vertex. - /// Hash set with visited vertices. - private void Dfs(IDirectedWeightedGraph graph, Vertex startVertex, Action>? action, HashSet> visited) - { - action?.Invoke(startVertex); + /// + /// Traverses graph from start vertex. + /// + /// Graph instance. + /// Vertex that search starts from. + /// Action that needs to be executed on each graph vertex. + /// Hash set with visited vertices. + private void Dfs(IDirectedWeightedGraph graph, Vertex startVertex, Action>? action, HashSet> visited) + { + action?.Invoke(startVertex); - visited.Add(startVertex); + visited.Add(startVertex); - foreach (var vertex in graph.GetNeighbors(startVertex)) + foreach (var vertex in graph.GetNeighbors(startVertex)) + { + if (vertex == null || visited.Contains(vertex)) { - if (vertex == null || visited.Contains(vertex)) - { - continue; - } - - Dfs(graph, vertex!, action, visited); + continue; } + + Dfs(graph, vertex!, action, visited); } } } diff --git a/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs b/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs index 977e7362..113b1ece 100644 --- a/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs +++ b/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs @@ -1,124 +1,123 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using DataStructures.Graph; -namespace Algorithms.Graph.Dijkstra +namespace Algorithms.Graph.Dijkstra; + +public static class DijkstraAlgorithm { - public static class DijkstraAlgorithm + /// + /// Implementation of the Dijkstra shortest path algorithm for cyclic graphs. + /// https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm. + /// + /// Graph instance. + /// Starting vertex instance. + /// Generic Parameter. + /// List of distances from current vertex to all other vertices. + /// Exception thrown in case when graph is null or start + /// vertex does not belong to graph instance. + public static DistanceModel[] GenerateShortestPath(DirectedWeightedGraph graph, Vertex startVertex) { - /// - /// Implementation of the Dijkstra shortest path algorithm for cyclic graphs. - /// https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm. - /// - /// Graph instance. - /// Starting vertex instance. - /// Generic Parameter. - /// List of distances from current vertex to all other vertices. - /// Exception thrown in case when graph is null or start - /// vertex does not belong to graph instance. - public static DistanceModel[] GenerateShortestPath(DirectedWeightedGraph graph, Vertex startVertex) - { - ValidateGraphAndStartVertex(graph, startVertex); - - var visitedVertices = new List>(); - - var distanceArray = InitializeDistanceArray(graph, startVertex); - - var currentVertex = startVertex; + ValidateGraphAndStartVertex(graph, startVertex); - var currentPath = 0d; + var visitedVertices = new List>(); - while (true) - { - visitedVertices.Add(currentVertex); + var distanceArray = InitializeDistanceArray(graph, startVertex); - var neighborVertices = graph - .GetNeighbors(currentVertex) - .Where(x => x != null && !visitedVertices.Contains(x)) - .ToList(); + var currentVertex = startVertex; - foreach (var vertex in neighborVertices) - { - var adjacentDistance = graph.AdjacentDistance(currentVertex, vertex!); + var currentPath = 0d; - var distance = distanceArray[vertex!.Index]; + while (true) + { + visitedVertices.Add(currentVertex); - if (distance.Distance <= currentPath + adjacentDistance) - { - continue; - } + var neighborVertices = graph + .GetNeighbors(currentVertex) + .Where(x => x != null && !visitedVertices.Contains(x)) + .ToList(); - distance.Distance = currentPath + adjacentDistance; - distance.PreviousVertex = currentVertex; - } + foreach (var vertex in neighborVertices) + { + var adjacentDistance = graph.AdjacentDistance(currentVertex, vertex!); - var minimalAdjacentVertex = GetMinimalUnvisitedAdjacentVertex(graph, currentVertex, neighborVertices); + var distance = distanceArray[vertex!.Index]; - if (neighborVertices.Count == 0 || minimalAdjacentVertex is null) + if (distance.Distance <= currentPath + adjacentDistance) { - break; + continue; } - currentPath += graph.AdjacentDistance(currentVertex, minimalAdjacentVertex); + distance.Distance = currentPath + adjacentDistance; + distance.PreviousVertex = currentVertex; + } + + var minimalAdjacentVertex = GetMinimalUnvisitedAdjacentVertex(graph, currentVertex, neighborVertices); - currentVertex = minimalAdjacentVertex; + if (neighborVertices.Count == 0 || minimalAdjacentVertex is null) + { + break; } - return distanceArray; + currentPath += graph.AdjacentDistance(currentVertex, minimalAdjacentVertex); + + currentVertex = minimalAdjacentVertex; } - private static DistanceModel[] InitializeDistanceArray( - IDirectedWeightedGraph graph, - Vertex startVertex) - { - var distArray = new DistanceModel[graph.Count]; + return distanceArray; + } - distArray[startVertex.Index] = new DistanceModel(startVertex, startVertex, 0); + private static DistanceModel[] InitializeDistanceArray( + IDirectedWeightedGraph graph, + Vertex startVertex) + { + var distArray = new DistanceModel[graph.Count]; - foreach (var vertex in graph.Vertices.Where(x => x != null && !x.Equals(startVertex))) - { - distArray[vertex!.Index] = new DistanceModel(vertex, null, double.MaxValue); - } + distArray[startVertex.Index] = new DistanceModel(startVertex, startVertex, 0); - return distArray; + foreach (var vertex in graph.Vertices.Where(x => x != null && !x.Equals(startVertex))) + { + distArray[vertex!.Index] = new DistanceModel(vertex, null, double.MaxValue); } - private static void ValidateGraphAndStartVertex(DirectedWeightedGraph graph, Vertex startVertex) - { - if (graph is null) - { - throw new ArgumentNullException(nameof(graph)); - } + return distArray; + } - if (startVertex.Graph != null && !startVertex.Graph.Equals(graph)) - { - throw new ArgumentNullException(nameof(graph)); - } + private static void ValidateGraphAndStartVertex(DirectedWeightedGraph graph, Vertex startVertex) + { + if (graph is null) + { + throw new ArgumentNullException(nameof(graph)); } - private static Vertex? GetMinimalUnvisitedAdjacentVertex( - IDirectedWeightedGraph graph, - Vertex startVertex, - IEnumerable?> adjacentVertices) + if (startVertex.Graph != null && !startVertex.Graph.Equals(graph)) { - var minDistance = double.MaxValue; - Vertex? minVertex = default; + throw new ArgumentNullException(nameof(graph)); + } + } - foreach (var vertex in adjacentVertices) - { - var currentDistance = graph.AdjacentDistance(startVertex, vertex!); + private static Vertex? GetMinimalUnvisitedAdjacentVertex( + IDirectedWeightedGraph graph, + Vertex startVertex, + IEnumerable?> adjacentVertices) + { + var minDistance = double.MaxValue; + Vertex? minVertex = default; - if (minDistance <= currentDistance) - { - continue; - } + foreach (var vertex in adjacentVertices) + { + var currentDistance = graph.AdjacentDistance(startVertex, vertex!); - minDistance = currentDistance; - minVertex = vertex; + if (minDistance <= currentDistance) + { + continue; } - return minVertex; + minDistance = currentDistance; + minVertex = vertex; } + + return minVertex; } } diff --git a/Algorithms/Graph/Dijkstra/DistanceModel.cs b/Algorithms/Graph/Dijkstra/DistanceModel.cs index d2028717..133fa6d1 100644 --- a/Algorithms/Graph/Dijkstra/DistanceModel.cs +++ b/Algorithms/Graph/Dijkstra/DistanceModel.cs @@ -1,28 +1,27 @@ -using DataStructures.Graph; +using DataStructures.Graph; -namespace Algorithms.Graph.Dijkstra -{ - /// - /// Entity which represents the Dijkstra shortest distance. - /// Contains: Vertex, Previous Vertex and minimal distance from start vertex. - /// - /// Generic parameter. - public class DistanceModel - { - public Vertex? Vertex { get; } +namespace Algorithms.Graph.Dijkstra; - public Vertex? PreviousVertex { get; set; } +/// +/// Entity which represents the Dijkstra shortest distance. +/// Contains: Vertex, Previous Vertex and minimal distance from start vertex. +/// +/// Generic parameter. +public class DistanceModel +{ + public Vertex? Vertex { get; } - public double Distance { get; set; } + public Vertex? PreviousVertex { get; set; } - public DistanceModel(Vertex? vertex, Vertex? previousVertex, double distance) - { - Vertex = vertex; - PreviousVertex = previousVertex; - Distance = distance; - } + public double Distance { get; set; } - public override string ToString() => - $"Vertex: {Vertex} - Distance: {Distance} - Previous: {PreviousVertex}"; + public DistanceModel(Vertex? vertex, Vertex? previousVertex, double distance) + { + Vertex = vertex; + PreviousVertex = previousVertex; + Distance = distance; } + + public override string ToString() => + $"Vertex: {Vertex} - Distance: {Distance} - Previous: {PreviousVertex}"; } diff --git a/Algorithms/Graph/FloydWarshall.cs b/Algorithms/Graph/FloydWarshall.cs index a7a4d357..7bb9d707 100644 --- a/Algorithms/Graph/FloydWarshall.cs +++ b/Algorithms/Graph/FloydWarshall.cs @@ -1,65 +1,64 @@ using System; using DataStructures.Graph; -namespace Algorithms.Graph +namespace Algorithms.Graph; + +/// +/// Floyd Warshall algorithm on directed weighted graph. +/// +/// generic type of data in graph. +public class FloydWarshall { /// - /// Floyd Warshall algorithm on directed weighted graph. + /// runs the algorithm. /// - /// generic type of data in graph. - public class FloydWarshall + /// graph upon which to run. + /// + /// a 2D array of shortest paths between any two vertices. + /// where there is no path between two vertices - double.PositiveInfinity is placed. + /// + public double[,] Run(DirectedWeightedGraph graph) { - /// - /// runs the algorithm. - /// - /// graph upon which to run. - /// - /// a 2D array of shortest paths between any two vertices. - /// where there is no path between two vertices - double.PositiveInfinity is placed. - /// - public double[,] Run(DirectedWeightedGraph graph) + var distances = SetupDistances(graph); + var vertexCount = distances.GetLength(0); + for (var k = 0; k < vertexCount; k++) { - var distances = SetupDistances(graph); - var vertexCount = distances.GetLength(0); - for (var k = 0; k < vertexCount; k++) + for (var i = 0; i < vertexCount; i++) { - for (var i = 0; i < vertexCount; i++) + for (var j = 0; j < vertexCount; j++) { - for (var j = 0; j < vertexCount; j++) - { - distances[i, j] = distances[i, j] > distances[i, k] + distances[k, j] - ? distances[i, k] + distances[k, j] - : distances[i, j]; - } + distances[i, j] = distances[i, j] > distances[i, k] + distances[k, j] + ? distances[i, k] + distances[k, j] + : distances[i, j]; } } - - return distances; } - /// - /// setup adjacency matrix for use by main algorithm run. - /// - /// graph to dissect adjacency matrix from. - /// the adjacency matrix in the format mentioned in Run. - private double[,] SetupDistances(DirectedWeightedGraph graph) - { - var distances = new double[graph.Count, graph.Count]; - for (int i = 0; i < distances.GetLength(0); i++) - { - for (var j = 0; j < distances.GetLength(0); j++) - { - var dist = graph.AdjacentDistance(graph.Vertices[i] !, graph.Vertices[j] !); - distances[i, j] = dist != 0 ? dist : double.PositiveInfinity; - } - } + return distances; + } - for (var i = 0; i < distances.GetLength(0); i++) + /// + /// setup adjacency matrix for use by main algorithm run. + /// + /// graph to dissect adjacency matrix from. + /// the adjacency matrix in the format mentioned in Run. + private double[,] SetupDistances(DirectedWeightedGraph graph) + { + var distances = new double[graph.Count, graph.Count]; + for (int i = 0; i < distances.GetLength(0); i++) + { + for (var j = 0; j < distances.GetLength(0); j++) { - distances[i, i] = 0; + var dist = graph.AdjacentDistance(graph.Vertices[i] !, graph.Vertices[j] !); + distances[i, j] = dist != 0 ? dist : double.PositiveInfinity; } + } - return distances; + for (var i = 0; i < distances.GetLength(0); i++) + { + distances[i, i] = 0; } + + return distances; } } diff --git a/Algorithms/Graph/IGraphSearch.cs b/Algorithms/Graph/IGraphSearch.cs index d1a5c1a0..9a4a0e42 100644 --- a/Algorithms/Graph/IGraphSearch.cs +++ b/Algorithms/Graph/IGraphSearch.cs @@ -1,16 +1,15 @@ using System; using DataStructures.Graph; -namespace Algorithms.Graph +namespace Algorithms.Graph; + +public interface IGraphSearch { - public interface IGraphSearch - { - /// - /// Traverses graph from start vertex. - /// - /// Graph instance. - /// Vertex that search starts from. - /// Action that needs to be executed on each graph vertex. - void VisitAll(IDirectedWeightedGraph graph, Vertex startVertex, Action>? action = null); - } + /// + /// Traverses graph from start vertex. + /// + /// Graph instance. + /// Vertex that search starts from. + /// Action that needs to be executed on each graph vertex. + void VisitAll(IDirectedWeightedGraph graph, Vertex startVertex, Action>? action = null); } diff --git a/Algorithms/Graph/Kosaraju.cs b/Algorithms/Graph/Kosaraju.cs index d31fa7b5..10cdb53e 100644 --- a/Algorithms/Graph/Kosaraju.cs +++ b/Algorithms/Graph/Kosaraju.cs @@ -2,126 +2,125 @@ using System.Linq; using DataStructures.Graph; -namespace Algorithms.Graph +namespace Algorithms.Graph; + +/// +/// Implementation of Kosaraju-Sharir's algorithm (also known as Kosaraju's algorithm) to find the +/// strongly connected components (SCC) of a directed graph. +/// See https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm. +/// +/// Vertex data type. +public static class Kosaraju { /// - /// Implementation of Kosaraju-Sharir's algorithm (also known as Kosaraju's algorithm) to find the - /// strongly connected components (SCC) of a directed graph. - /// See https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm. + /// First DFS for Kosaraju algorithm: traverse the graph creating a reverse order explore list . /// - /// Vertex data type. - public static class Kosaraju + /// Vertex to explore. + /// Graph instance. + /// List of already visited vertex. + /// Reversed list of vertex for the second DFS. + public static void Visit(Vertex v, IDirectedWeightedGraph graph, HashSet> visited, Stack> reversed) { - /// - /// First DFS for Kosaraju algorithm: traverse the graph creating a reverse order explore list . - /// - /// Vertex to explore. - /// Graph instance. - /// List of already visited vertex. - /// Reversed list of vertex for the second DFS. - public static void Visit(Vertex v, IDirectedWeightedGraph graph, HashSet> visited, Stack> reversed) + if (visited.Contains(v)) { - if (visited.Contains(v)) - { - return; - } + return; + } - // Set v as visited - visited.Add(v); + // Set v as visited + visited.Add(v); - // Push v in the stack. - // This can also be done with a List, inserting v at the begining of the list - // after visit the neighbors. - reversed.Push(v); + // Push v in the stack. + // This can also be done with a List, inserting v at the begining of the list + // after visit the neighbors. + reversed.Push(v); - // Visit neighbors - foreach (var u in graph.GetNeighbors(v)) - { - Visit(u!, graph, visited, reversed); - } + // Visit neighbors + foreach (var u in graph.GetNeighbors(v)) + { + Visit(u!, graph, visited, reversed); } + } - /// - /// Second DFS for Kosaraju algorithm. Traverse the graph in reversed order - /// assigning a root vertex for every vertex that belong to the same SCC. - /// - /// Vertex to assign. - /// Root vertext, representative of the SCC. - /// Graph with vertex and edges. - /// - /// Dictionary that assigns to each vertex the root of the SCC to which it corresponds. - /// - public static void Assign(Vertex v, Vertex root, IDirectedWeightedGraph graph, Dictionary, Vertex> roots) + /// + /// Second DFS for Kosaraju algorithm. Traverse the graph in reversed order + /// assigning a root vertex for every vertex that belong to the same SCC. + /// + /// Vertex to assign. + /// Root vertext, representative of the SCC. + /// Graph with vertex and edges. + /// + /// Dictionary that assigns to each vertex the root of the SCC to which it corresponds. + /// + public static void Assign(Vertex v, Vertex root, IDirectedWeightedGraph graph, Dictionary, Vertex> roots) + { + // If v already has a representative vertex (root) already assigned, do nothing. + if (roots.ContainsKey(v)) { - // If v already has a representative vertex (root) already assigned, do nothing. - if (roots.ContainsKey(v)) - { - return; - } + return; + } - // Assign the root to the vertex. - roots.Add(v, root); + // Assign the root to the vertex. + roots.Add(v, root); - // Assign the current root vertex to v neighbors. - foreach (var u in graph.GetNeighbors(v)) - { - Assign(u!, root, graph, roots); - } + // Assign the current root vertex to v neighbors. + foreach (var u in graph.GetNeighbors(v)) + { + Assign(u!, root, graph, roots); } + } - /// - /// Find the representative vertex of the SCC for each vertex on the graph. - /// - /// Graph to explore. - /// A dictionary that assigns to each vertex a root vertex of the SCC they belong. - public static Dictionary, Vertex> GetRepresentatives(IDirectedWeightedGraph graph) - { - HashSet> visited = new HashSet>(); - Stack> reversedL = new Stack>(); - Dictionary, Vertex> representatives = new Dictionary, Vertex>(); + /// + /// Find the representative vertex of the SCC for each vertex on the graph. + /// + /// Graph to explore. + /// A dictionary that assigns to each vertex a root vertex of the SCC they belong. + public static Dictionary, Vertex> GetRepresentatives(IDirectedWeightedGraph graph) + { + HashSet> visited = new HashSet>(); + Stack> reversedL = new Stack>(); + Dictionary, Vertex> representatives = new Dictionary, Vertex>(); - foreach (var v in graph.Vertices) + foreach (var v in graph.Vertices) + { + if (v != null) { - if (v != null) - { - Visit(v, graph, visited, reversedL); - } + Visit(v, graph, visited, reversedL); } + } - visited.Clear(); - - while (reversedL.Count > 0) - { - Vertex v = reversedL.Pop(); - Assign(v, v, graph, representatives); - } + visited.Clear(); - return representatives; + while (reversedL.Count > 0) + { + Vertex v = reversedL.Pop(); + Assign(v, v, graph, representatives); } - /// - /// Get the Strongly Connected Components for the graph. - /// - /// Graph to explore. - /// An array of SCC. - public static IEnumerable>[] GetScc(IDirectedWeightedGraph graph) + return representatives; + } + + /// + /// Get the Strongly Connected Components for the graph. + /// + /// Graph to explore. + /// An array of SCC. + public static IEnumerable>[] GetScc(IDirectedWeightedGraph graph) + { + var representatives = GetRepresentatives(graph); + Dictionary, List>> scc = new Dictionary, List>>(); + foreach (var kv in representatives) { - var representatives = GetRepresentatives(graph); - Dictionary, List>> scc = new Dictionary, List>>(); - foreach (var kv in representatives) + // Assign all vertex (key) that have the seem root (value) to a single list. + if (scc.ContainsKey(kv.Value)) { - // Assign all vertex (key) that have the seem root (value) to a single list. - if (scc.ContainsKey(kv.Value)) - { - scc[kv.Value].Add(kv.Key); - } - else - { - scc.Add(kv.Value, new List> { kv.Key }); - } + scc[kv.Value].Add(kv.Key); + } + else + { + scc.Add(kv.Value, new List> { kv.Key }); } - - return scc.Values.ToArray(); } + + return scc.Values.ToArray(); } } diff --git a/Algorithms/Graph/MinimumSpanningTree/Kruskal.cs b/Algorithms/Graph/MinimumSpanningTree/Kruskal.cs index 2106180d..4d070bcb 100644 --- a/Algorithms/Graph/MinimumSpanningTree/Kruskal.cs +++ b/Algorithms/Graph/MinimumSpanningTree/Kruskal.cs @@ -2,191 +2,190 @@ using System.Collections.Generic; using DataStructures.DisjointSet; -namespace Algorithms.Graph.MinimumSpanningTree +namespace Algorithms.Graph.MinimumSpanningTree; + +/// +/// Algorithm to determine the minimum spanning forest of an undirected graph. +/// +/// +/// Kruskal's algorithm is a greedy algorithm that can determine the +/// minimum spanning tree or minimum spanning forest of any undirected +/// graph. Unlike Prim's algorithm, Kruskal's algorithm will work on +/// graphs that are unconnected. This algorithm will always have a +/// running time of O(E log V) where E is the number of edges and V is +/// the number of vertices/nodes. +/// More information: https://en.wikipedia.org/wiki/Kruskal%27s_algorithm . +/// Pseudocode and analysis: https://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/primAlgor.htm . +/// +public static class Kruskal { /// - /// Algorithm to determine the minimum spanning forest of an undirected graph. + /// Determine the minimum spanning tree/forest of the given graph. /// - /// - /// Kruskal's algorithm is a greedy algorithm that can determine the - /// minimum spanning tree or minimum spanning forest of any undirected - /// graph. Unlike Prim's algorithm, Kruskal's algorithm will work on - /// graphs that are unconnected. This algorithm will always have a - /// running time of O(E log V) where E is the number of edges and V is - /// the number of vertices/nodes. - /// More information: https://en.wikipedia.org/wiki/Kruskal%27s_algorithm . - /// Pseudocode and analysis: https://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/primAlgor.htm . - /// - public static class Kruskal + /// Adjacency matrix representing the graph. + /// Adjacency matrix of the minimum spanning tree/forest. + public static float[,] Solve(float[,] adjacencyMatrix) { - /// - /// Determine the minimum spanning tree/forest of the given graph. - /// - /// Adjacency matrix representing the graph. - /// Adjacency matrix of the minimum spanning tree/forest. - public static float[,] Solve(float[,] adjacencyMatrix) - { - ValidateGraph(adjacencyMatrix); + ValidateGraph(adjacencyMatrix); - var numNodes = adjacencyMatrix.GetLength(0); - var set = new DisjointSet(); - var nodes = new Node[numNodes]; - var edgeWeightList = new List(); - var nodeConnectList = new List<(int, int)>(); + var numNodes = adjacencyMatrix.GetLength(0); + var set = new DisjointSet(); + var nodes = new Node[numNodes]; + var edgeWeightList = new List(); + var nodeConnectList = new List<(int, int)>(); - // Add nodes to disjoint set - for (var i = 0; i < numNodes; i++) - { - nodes[i] = set.MakeSet(i); - } + // Add nodes to disjoint set + for (var i = 0; i < numNodes; i++) + { + nodes[i] = set.MakeSet(i); + } - // Create lists with edge weights and associated connectivity - for (var i = 0; i < numNodes - 1; i++) + // Create lists with edge weights and associated connectivity + for (var i = 0; i < numNodes - 1; i++) + { + for (var j = i + 1; j < numNodes; j++) { - for (var j = i + 1; j < numNodes; j++) + if (float.IsFinite(adjacencyMatrix[i, j])) { - if (float.IsFinite(adjacencyMatrix[i, j])) - { - edgeWeightList.Add(adjacencyMatrix[i, j]); - nodeConnectList.Add((i, j)); - } + edgeWeightList.Add(adjacencyMatrix[i, j]); + nodeConnectList.Add((i, j)); } } + } - var edges = Solve(set, nodes, edgeWeightList.ToArray(), nodeConnectList.ToArray()); - - // Initialize minimum spanning tree - var mst = new float[numNodes, numNodes]; - for (var i = 0; i < numNodes; i++) - { - mst[i, i] = float.PositiveInfinity; + var edges = Solve(set, nodes, edgeWeightList.ToArray(), nodeConnectList.ToArray()); - for (var j = i + 1; j < numNodes; j++) - { - mst[i, j] = float.PositiveInfinity; - mst[j, i] = float.PositiveInfinity; - } - } + // Initialize minimum spanning tree + var mst = new float[numNodes, numNodes]; + for (var i = 0; i < numNodes; i++) + { + mst[i, i] = float.PositiveInfinity; - foreach (var (node1, node2) in edges) + for (var j = i + 1; j < numNodes; j++) { - mst[node1, node2] = adjacencyMatrix[node1, node2]; - mst[node2, node1] = adjacencyMatrix[node1, node2]; + mst[i, j] = float.PositiveInfinity; + mst[j, i] = float.PositiveInfinity; } - - return mst; } - /// - /// Determine the minimum spanning tree/forest of the given graph. - /// - /// Adjacency list representing the graph. - /// Adjacency list of the minimum spanning tree/forest. - public static Dictionary[] Solve(Dictionary[] adjacencyList) + foreach (var (node1, node2) in edges) { - ValidateGraph(adjacencyList); + mst[node1, node2] = adjacencyMatrix[node1, node2]; + mst[node2, node1] = adjacencyMatrix[node1, node2]; + } - var numNodes = adjacencyList.Length; - var set = new DisjointSet(); - var nodes = new Node[numNodes]; - var edgeWeightList = new List(); - var nodeConnectList = new List<(int, int)>(); + return mst; + } - // Add nodes to disjoint set and create list of edge weights and associated connectivity - for (var i = 0; i < numNodes; i++) - { - nodes[i] = set.MakeSet(i); + /// + /// Determine the minimum spanning tree/forest of the given graph. + /// + /// Adjacency list representing the graph. + /// Adjacency list of the minimum spanning tree/forest. + public static Dictionary[] Solve(Dictionary[] adjacencyList) + { + ValidateGraph(adjacencyList); - foreach(var (node, weight) in adjacencyList[i]) - { - edgeWeightList.Add(weight); - nodeConnectList.Add((i, node)); - } - } + var numNodes = adjacencyList.Length; + var set = new DisjointSet(); + var nodes = new Node[numNodes]; + var edgeWeightList = new List(); + var nodeConnectList = new List<(int, int)>(); - var edges = Solve(set, nodes, edgeWeightList.ToArray(), nodeConnectList.ToArray()); + // Add nodes to disjoint set and create list of edge weights and associated connectivity + for (var i = 0; i < numNodes; i++) + { + nodes[i] = set.MakeSet(i); - // Create minimum spanning tree - var mst = new Dictionary[numNodes]; - for (var i = 0; i < numNodes; i++) + foreach(var (node, weight) in adjacencyList[i]) { - mst[i] = new Dictionary(); + edgeWeightList.Add(weight); + nodeConnectList.Add((i, node)); } + } - foreach (var (node1, node2) in edges) - { - mst[node1].Add(node2, adjacencyList[node1][node2]); - mst[node2].Add(node1, adjacencyList[node1][node2]); - } + var edges = Solve(set, nodes, edgeWeightList.ToArray(), nodeConnectList.ToArray()); - return mst; + // Create minimum spanning tree + var mst = new Dictionary[numNodes]; + for (var i = 0; i < numNodes; i++) + { + mst[i] = new Dictionary(); } - /// - /// Ensure that the given graph is undirected. - /// - /// Adjacency matrix of graph to check. - private static void ValidateGraph(float[,] adj) + foreach (var (node1, node2) in edges) { - if (adj.GetLength(0) != adj.GetLength(1)) - { - throw new ArgumentException("Matrix must be square!"); - } + mst[node1].Add(node2, adjacencyList[node1][node2]); + mst[node2].Add(node1, adjacencyList[node1][node2]); + } + + return mst; + } + + /// + /// Ensure that the given graph is undirected. + /// + /// Adjacency matrix of graph to check. + private static void ValidateGraph(float[,] adj) + { + if (adj.GetLength(0) != adj.GetLength(1)) + { + throw new ArgumentException("Matrix must be square!"); + } - for (var i = 0; i < adj.GetLength(0) - 1; i++) + for (var i = 0; i < adj.GetLength(0) - 1; i++) + { + for (var j = i + 1; j < adj.GetLength(1); j++) { - for (var j = i + 1; j < adj.GetLength(1); j++) + if (Math.Abs(adj[i, j] - adj[j, i]) > 1e-6) { - if (Math.Abs(adj[i, j] - adj[j, i]) > 1e-6) - { - throw new ArgumentException("Matrix must be symmetric!"); - } + throw new ArgumentException("Matrix must be symmetric!"); } } } + } - /// - /// Ensure that the given graph is undirected. - /// - /// Adjacency list of graph to check. - private static void ValidateGraph(Dictionary[] adj) + /// + /// Ensure that the given graph is undirected. + /// + /// Adjacency list of graph to check. + private static void ValidateGraph(Dictionary[] adj) + { + for (var i = 0; i < adj.Length; i++) { - for (var i = 0; i < adj.Length; i++) + foreach (var edge in adj[i]) { - foreach (var edge in adj[i]) + if (!adj[edge.Key].ContainsKey(i) || Math.Abs(edge.Value - adj[edge.Key][i]) > 1e-6) { - if (!adj[edge.Key].ContainsKey(i) || Math.Abs(edge.Value - adj[edge.Key][i]) > 1e-6) - { - throw new ArgumentException("Graph must be undirected!"); - } + throw new ArgumentException("Graph must be undirected!"); } } } + } - /// - /// Determine the minimum spanning tree/forest. - /// - /// Disjoint set needed for set operations. - /// List of nodes in disjoint set associated with each node. - /// Weights of each edge. - /// Nodes associated with each item in the parameter. - /// Array of edges in the minimum spanning tree/forest. - private static (int, int)[] Solve(DisjointSet set, Node[] nodes, float[] edgeWeights, (int, int)[] connections) - { - var edges = new List<(int, int)>(); + /// + /// Determine the minimum spanning tree/forest. + /// + /// Disjoint set needed for set operations. + /// List of nodes in disjoint set associated with each node. + /// Weights of each edge. + /// Nodes associated with each item in the parameter. + /// Array of edges in the minimum spanning tree/forest. + private static (int, int)[] Solve(DisjointSet set, Node[] nodes, float[] edgeWeights, (int, int)[] connections) + { + var edges = new List<(int, int)>(); - Array.Sort(edgeWeights, connections); + Array.Sort(edgeWeights, connections); - foreach (var (node1, node2) in connections) + foreach (var (node1, node2) in connections) + { + if (set.FindSet(nodes[node1]) != set.FindSet(nodes[node2])) { - if (set.FindSet(nodes[node1]) != set.FindSet(nodes[node2])) - { - set.UnionSet(nodes[node1], nodes[node2]); - edges.Add((node1, node2)); - } + set.UnionSet(nodes[node1], nodes[node2]); + edges.Add((node1, node2)); } - - return edges.ToArray(); } + + return edges.ToArray(); } } diff --git a/Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs b/Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs index 75d5479b..55b6a2d5 100644 --- a/Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs +++ b/Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs @@ -1,149 +1,148 @@ using System; -namespace Algorithms.Graph.MinimumSpanningTree +namespace Algorithms.Graph.MinimumSpanningTree; + +/// +/// Class that uses Prim's (Jarnik's algorithm) to determine the minimum +/// spanning tree (MST) of a given graph. Prim's algorithm is a greedy +/// algorithm that can determine the MST of a weighted undirected graph +/// in O(V^2) time where V is the number of nodes/vertices when using an +/// adjacency matrix representation. +/// More information: https://en.wikipedia.org/wiki/Prim%27s_algorithm +/// Pseudocode and runtime analysis: https://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/primAlgor.htm . +/// +public static class PrimMatrix { /// - /// Class that uses Prim's (Jarnik's algorithm) to determine the minimum - /// spanning tree (MST) of a given graph. Prim's algorithm is a greedy - /// algorithm that can determine the MST of a weighted undirected graph - /// in O(V^2) time where V is the number of nodes/vertices when using an - /// adjacency matrix representation. - /// More information: https://en.wikipedia.org/wiki/Prim%27s_algorithm - /// Pseudocode and runtime analysis: https://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/primAlgor.htm . + /// Determine the minimum spanning tree for a given weighted undirected graph. /// - public static class PrimMatrix + /// Adjacency matrix for graph to find MST of. + /// Node to start search from. + /// Adjacency matrix of the found MST. + public static float[,] Solve(float[,] adjacencyMatrix, int start) { - /// - /// Determine the minimum spanning tree for a given weighted undirected graph. - /// - /// Adjacency matrix for graph to find MST of. - /// Node to start search from. - /// Adjacency matrix of the found MST. - public static float[,] Solve(float[,] adjacencyMatrix, int start) - { - ValidateMatrix(adjacencyMatrix); + ValidateMatrix(adjacencyMatrix); - var numNodes = adjacencyMatrix.GetLength(0); + var numNodes = adjacencyMatrix.GetLength(0); - // Create array to represent minimum spanning tree - var mst = new float[numNodes, numNodes]; + // Create array to represent minimum spanning tree + var mst = new float[numNodes, numNodes]; - // Create array to keep track of which nodes are in the MST already - var added = new bool[numNodes]; + // Create array to keep track of which nodes are in the MST already + var added = new bool[numNodes]; - // Create array to keep track of smallest edge weight for node - var key = new float[numNodes]; + // Create array to keep track of smallest edge weight for node + var key = new float[numNodes]; - // Create array to store parent of node - var parent = new int[numNodes]; + // Create array to store parent of node + var parent = new int[numNodes]; - for (var i = 0; i < numNodes; i++) - { - mst[i, i] = float.PositiveInfinity; - key[i] = float.PositiveInfinity; + for (var i = 0; i < numNodes; i++) + { + mst[i, i] = float.PositiveInfinity; + key[i] = float.PositiveInfinity; - for (var j = i + 1; j < numNodes; j++) - { - mst[i, j] = float.PositiveInfinity; - mst[j, i] = float.PositiveInfinity; - } + for (var j = i + 1; j < numNodes; j++) + { + mst[i, j] = float.PositiveInfinity; + mst[j, i] = float.PositiveInfinity; } + } - // Ensures that the starting node is added first - key[start] = 0; + // Ensures that the starting node is added first + key[start] = 0; - // Keep looping until all nodes are in tree - for (var i = 0; i < numNodes - 1; i++) - { - GetNextNode(adjacencyMatrix, key, added, parent); - } + // Keep looping until all nodes are in tree + for (var i = 0; i < numNodes - 1; i++) + { + GetNextNode(adjacencyMatrix, key, added, parent); + } - // Build adjacency matrix for tree - for (var i = 0; i < numNodes; i++) + // Build adjacency matrix for tree + for (var i = 0; i < numNodes; i++) + { + if (i == start) { - if (i == start) - { - continue; - } - - mst[i, parent[i]] = adjacencyMatrix[i, parent[i]]; - mst[parent[i], i] = adjacencyMatrix[i, parent[i]]; + continue; } - return mst; + mst[i, parent[i]] = adjacencyMatrix[i, parent[i]]; + mst[parent[i], i] = adjacencyMatrix[i, parent[i]]; } - /// - /// Ensure that the given adjacency matrix represents a weighted undirected graph. - /// - /// Adjacency matric to check. - private static void ValidateMatrix(float[,] adjacencyMatrix) + return mst; + } + + /// + /// Ensure that the given adjacency matrix represents a weighted undirected graph. + /// + /// Adjacency matric to check. + private static void ValidateMatrix(float[,] adjacencyMatrix) + { + // Matrix should be square + if (adjacencyMatrix.GetLength(0) != adjacencyMatrix.GetLength(1)) { - // Matrix should be square - if (adjacencyMatrix.GetLength(0) != adjacencyMatrix.GetLength(1)) - { - throw new ArgumentException("Adjacency matrix must be square!"); - } + throw new ArgumentException("Adjacency matrix must be square!"); + } - // Graph needs to be undirected and connected - for (var i = 0; i < adjacencyMatrix.GetLength(0); i++) + // Graph needs to be undirected and connected + for (var i = 0; i < adjacencyMatrix.GetLength(0); i++) + { + var connection = false; + for (var j = 0; j < adjacencyMatrix.GetLength(0); j++) { - var connection = false; - for (var j = 0; j < adjacencyMatrix.GetLength(0); j++) + if (Math.Abs(adjacencyMatrix[i, j] - adjacencyMatrix[j, i]) > 1e-6) { - if (Math.Abs(adjacencyMatrix[i, j] - adjacencyMatrix[j, i]) > 1e-6) - { - throw new ArgumentException("Adjacency matrix must be symmetric!"); - } - - if (!connection && float.IsFinite(adjacencyMatrix[i, j])) - { - connection = true; - } + throw new ArgumentException("Adjacency matrix must be symmetric!"); } - if (!connection) + if (!connection && float.IsFinite(adjacencyMatrix[i, j])) { - throw new ArgumentException("Graph must be connected!"); + connection = true; } } + + if (!connection) + { + throw new ArgumentException("Graph must be connected!"); + } } + } - /// - /// Determine which node should be added next to the MST. - /// - /// Adjacency matrix of graph. - /// Currently known minimum edge weight connected to each node. - /// Whether or not a node has been added to the MST. - /// The node that added the node to the MST. Used for building MST adjacency matrix. - private static void GetNextNode(float[,] adjacencyMatrix, float[] key, bool[] added, int[] parent) - { - var numNodes = adjacencyMatrix.GetLength(0); - var minWeight = float.PositiveInfinity; + /// + /// Determine which node should be added next to the MST. + /// + /// Adjacency matrix of graph. + /// Currently known minimum edge weight connected to each node. + /// Whether or not a node has been added to the MST. + /// The node that added the node to the MST. Used for building MST adjacency matrix. + private static void GetNextNode(float[,] adjacencyMatrix, float[] key, bool[] added, int[] parent) + { + var numNodes = adjacencyMatrix.GetLength(0); + var minWeight = float.PositiveInfinity; - var node = -1; + var node = -1; - // Find node with smallest node with known edge weight not in tree. Will always start with starting node - for (var i = 0; i < numNodes; i++) + // Find node with smallest node with known edge weight not in tree. Will always start with starting node + for (var i = 0; i < numNodes; i++) + { + if (!added[i] && key[i] < minWeight) { - if (!added[i] && key[i] < minWeight) - { - minWeight = key[i]; - node = i; - } + minWeight = key[i]; + node = i; } + } - // Add node to mst - added[node] = true; + // Add node to mst + added[node] = true; - // Update smallest found edge weights and parent for adjacent nodes - for (var i = 0; i < numNodes; i++) + // Update smallest found edge weights and parent for adjacent nodes + for (var i = 0; i < numNodes; i++) + { + if (!added[i] && adjacencyMatrix[node, i] < key[i]) { - if (!added[i] && adjacencyMatrix[node, i] < key[i]) - { - key[i] = adjacencyMatrix[node, i]; - parent[i] = node; - } + key[i] = adjacencyMatrix[node, i]; + parent[i] = node; } } } From 3d92c39ade11a2e29fed46ce0a6eb42e4d5d8564 Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Sat, 30 Dec 2023 10:33:07 +0000 Subject: [PATCH 082/138] Switch to file-scoped namespaces (#430) --- .../Knapsack/BranchAndBoundKnapsackSolver.cs | 265 ++++++++-------- Algorithms/Knapsack/BranchAndBoundNode.cs | 41 ++- .../DynamicProgrammingKnapsackSolver.cs | 161 +++++----- .../Knapsack/IHeuristicKnapsackSolver.cs | 33 +- Algorithms/Knapsack/IKnapsackSolver.cs | 19 +- Algorithms/Knapsack/NaiveKnapsackSolver.cs | 51 ++- .../LinearAlgebra/Distances/Euclidean.cs | 36 +-- .../LinearAlgebra/Distances/Manhattan.cs | 44 ++- .../Eigenvalue/PowerIteration.cs | 139 ++++---- .../ChineseRemainderTheorem.cs | 297 +++++++++--------- .../ExtendedEuclideanAlgorithm.cs | 147 +++++---- .../ModularMultiplicativeInverse.cs | 95 +++--- Algorithms/Numeric/AliquotSumCalculator.cs | 51 ++- Algorithms/Numeric/AmicableNumbersChecker.cs | 51 ++- Algorithms/Numeric/AutomorphicNumber.cs | 101 +++--- Algorithms/Numeric/BinomialCoefficient.cs | 69 ++-- Algorithms/Numeric/Decomposition/LU.cs | 157 +++++---- Algorithms/Numeric/Decomposition/ThinSVD.cs | 235 +++++++------- Algorithms/Numeric/EulerMethod.cs | 139 ++++---- Algorithms/Numeric/Factorial.cs | 53 ++-- .../Numeric/Factorization/IFactorizer.cs | 21 +- .../Factorization/TrialDivisionFactorizer.cs | 29 +- Algorithms/Numeric/GaussJordanElimination.cs | 225 +++++++------ .../BinaryGreatestCommonDivisorFinder.cs | 105 +++---- .../EuclideanGreatestCommonDivisorFinder.cs | 59 ++-- .../IGreatestCommonDivisorFinder.cs | 9 +- Algorithms/Numeric/KeithNumberChecker.cs | 75 +++-- .../Numeric/KrishnamurthyNumberChecker.cs | 53 ++-- .../Numeric/MillerRabinPrimalityChecker.cs | 123 ++++---- Algorithms/Numeric/ModularExponentiation.cs | 61 ++-- .../Numeric/NarcissisticNumberChecker.cs | 57 ++-- Algorithms/Numeric/PerfectNumberChecker.cs | 49 ++- Algorithms/Numeric/PerfectSquareChecker.cs | 33 +- .../Numeric/Pseudoinverse/PseudoInverse.cs | 63 ++-- Algorithms/Numeric/RungeKuttaMethod.cs | 105 +++---- Algorithms/Numeric/Series/Maclaurin.cs | 239 +++++++------- 36 files changed, 1720 insertions(+), 1770 deletions(-) diff --git a/Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs b/Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs index a3c9c37e..c3f5b27d 100644 --- a/Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs +++ b/Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs @@ -2,164 +2,163 @@ using System.Collections.Generic; using System.Linq; -namespace Algorithms.Knapsack +namespace Algorithms.Knapsack; + +/// +/// Branch and bound Knapsack solver. +/// +/// Type of items in knapsack. +public class BranchAndBoundKnapsackSolver { /// - /// Branch and bound Knapsack solver. + /// Returns the knapsack containing the items that maximize value while not exceeding weight capacity. + /// Construct a tree structure with total number of items + 1 levels, each node have two child nodes, + /// starting with a dummy item root, each following levels are associated with 1 items, construct the + /// tree in breadth first order to identify the optimal item set. /// - /// Type of items in knapsack. - public class BranchAndBoundKnapsackSolver + /// All items to choose from. + /// The maximum weight capacity of the knapsack to be filled. + /// + /// A function that returns the value of the specified item + /// from the items list. + /// + /// + /// A function that returns the weight of the specified item + /// from the items list. + /// + /// + /// The array of items that provides the maximum value of the + /// knapsack without exceeding the specified weight capacity. + /// + public T[] Solve(T[] items, int capacity, Func weightSelector, Func valueSelector) { - /// - /// Returns the knapsack containing the items that maximize value while not exceeding weight capacity. - /// Construct a tree structure with total number of items + 1 levels, each node have two child nodes, - /// starting with a dummy item root, each following levels are associated with 1 items, construct the - /// tree in breadth first order to identify the optimal item set. - /// - /// All items to choose from. - /// The maximum weight capacity of the knapsack to be filled. - /// - /// A function that returns the value of the specified item - /// from the items list. - /// - /// - /// A function that returns the weight of the specified item - /// from the items list. - /// - /// - /// The array of items that provides the maximum value of the - /// knapsack without exceeding the specified weight capacity. - /// - public T[] Solve(T[] items, int capacity, Func weightSelector, Func valueSelector) - { - // This is required for greedy approach in upper bound calculation to work. - items = items.OrderBy(i => valueSelector(i) / weightSelector(i)).ToArray(); + // This is required for greedy approach in upper bound calculation to work. + items = items.OrderBy(i => valueSelector(i) / weightSelector(i)).ToArray(); - // nodesQueue --> used to construct tree in breadth first order - Queue nodesQueue = new(); + // nodesQueue --> used to construct tree in breadth first order + Queue nodesQueue = new(); - // maxCumulativeValue --> maximum value while not exceeding weight capacity. - var maxCumulativeValue = 0.0; + // maxCumulativeValue --> maximum value while not exceeding weight capacity. + var maxCumulativeValue = 0.0; - // starting node, associated with a temporary created dummy item - BranchAndBoundNode root = new(level: -1, taken: false); + // starting node, associated with a temporary created dummy item + BranchAndBoundNode root = new(level: -1, taken: false); - // lastNodeOfOptimalPat --> last item in the optimal item sets identified by this algorithm - BranchAndBoundNode lastNodeOfOptimalPath = root; + // lastNodeOfOptimalPat --> last item in the optimal item sets identified by this algorithm + BranchAndBoundNode lastNodeOfOptimalPath = root; - nodesQueue.Enqueue(root); + nodesQueue.Enqueue(root); + + while (nodesQueue.Count != 0) + { + // parent --> parent node which represents the previous item, may or may not be taken into the knapsack + BranchAndBoundNode parent = nodesQueue.Dequeue(); - while (nodesQueue.Count != 0) + // IF it is the last level, branching cannot be performed + if (parent.Level == items.Length - 1) { - // parent --> parent node which represents the previous item, may or may not be taken into the knapsack - BranchAndBoundNode parent = nodesQueue.Dequeue(); - - // IF it is the last level, branching cannot be performed - if (parent.Level == items.Length - 1) - { - continue; - } - - // create a child node where the associated item is taken into the knapsack - var left = new BranchAndBoundNode(parent.Level + 1, true, parent); - - // create a child node where the associated item is not taken into the knapsack - var right = new BranchAndBoundNode(parent.Level + 1, false, parent); - - // Since the associated item on current level is taken for the first node, - // set the cumulative weight of first node to cumulative weight of parent node + weight of the associated item, - // set the cumulative value of first node to cumulative value of parent node + value of current level's item. - left.CumulativeWeight = parent.CumulativeWeight + weightSelector(items[left.Level]); - left.CumulativeValue = parent.CumulativeValue + valueSelector(items[left.Level]); - right.CumulativeWeight = parent.CumulativeWeight; - right.CumulativeValue = parent.CumulativeValue; - - // IF cumulative weight is smaller than the weight capacity of the knapsack AND - // current cumulative value is larger then the current maxCumulativeValue, update the maxCumulativeValue - if (left.CumulativeWeight <= capacity && left.CumulativeValue > maxCumulativeValue) - { - maxCumulativeValue = left.CumulativeValue; - lastNodeOfOptimalPath = left; - } - - left.UpperBound = ComputeUpperBound(left, items, capacity, weightSelector, valueSelector); - right.UpperBound = ComputeUpperBound(right, items, capacity, weightSelector, valueSelector); - - // IF upperBound of this node is larger than maxCumulativeValue, - // the current path is still possible to reach or surpass the maximum value, - // add current node to nodesQueue so that nodes below it can be further explored - if (left.UpperBound > maxCumulativeValue && left.CumulativeWeight < capacity) - { - nodesQueue.Enqueue(left); - } - - // Cumulative weight is the same as for parent node and < capacity - if (right.UpperBound > maxCumulativeValue) - { - nodesQueue.Enqueue(right); - } + continue; } - return GetItemsFromPath(items, lastNodeOfOptimalPath); - } + // create a child node where the associated item is taken into the knapsack + var left = new BranchAndBoundNode(parent.Level + 1, true, parent); - // determine items taken based on the path - private static T[] GetItemsFromPath(T[] items, BranchAndBoundNode lastNodeOfPath) - { - List takenItems = new(); + // create a child node where the associated item is not taken into the knapsack + var right = new BranchAndBoundNode(parent.Level + 1, false, parent); - // only bogus initial node has no parent - for (var current = lastNodeOfPath; current.Parent is not null; current = current.Parent) + // Since the associated item on current level is taken for the first node, + // set the cumulative weight of first node to cumulative weight of parent node + weight of the associated item, + // set the cumulative value of first node to cumulative value of parent node + value of current level's item. + left.CumulativeWeight = parent.CumulativeWeight + weightSelector(items[left.Level]); + left.CumulativeValue = parent.CumulativeValue + valueSelector(items[left.Level]); + right.CumulativeWeight = parent.CumulativeWeight; + right.CumulativeValue = parent.CumulativeValue; + + // IF cumulative weight is smaller than the weight capacity of the knapsack AND + // current cumulative value is larger then the current maxCumulativeValue, update the maxCumulativeValue + if (left.CumulativeWeight <= capacity && left.CumulativeValue > maxCumulativeValue) { - if(current.IsTaken) - { - takenItems.Add(items[current.Level]); - } + maxCumulativeValue = left.CumulativeValue; + lastNodeOfOptimalPath = left; } - return takenItems.ToArray(); + left.UpperBound = ComputeUpperBound(left, items, capacity, weightSelector, valueSelector); + right.UpperBound = ComputeUpperBound(right, items, capacity, weightSelector, valueSelector); + + // IF upperBound of this node is larger than maxCumulativeValue, + // the current path is still possible to reach or surpass the maximum value, + // add current node to nodesQueue so that nodes below it can be further explored + if (left.UpperBound > maxCumulativeValue && left.CumulativeWeight < capacity) + { + nodesQueue.Enqueue(left); + } + + // Cumulative weight is the same as for parent node and < capacity + if (right.UpperBound > maxCumulativeValue) + { + nodesQueue.Enqueue(right); + } } - /// - /// Returns the upper bound value of a given node. - /// - /// The given node. - /// All items to choose from. - /// The maximum weight capacity of the knapsack to be filled. - /// - /// A function that returns the value of the specified item - /// from the items list. - /// - /// - /// A function that returns the weight of the specified item - /// from the items list. - /// - /// - /// upper bound value of the given node. - /// - private static double ComputeUpperBound(BranchAndBoundNode aNode, T[] items, int capacity, Func weightSelector, Func valueSelector) + return GetItemsFromPath(items, lastNodeOfOptimalPath); + } + + // determine items taken based on the path + private static T[] GetItemsFromPath(T[] items, BranchAndBoundNode lastNodeOfPath) + { + List takenItems = new(); + + // only bogus initial node has no parent + for (var current = lastNodeOfPath; current.Parent is not null; current = current.Parent) { - var upperBound = aNode.CumulativeValue; - var availableWeight = capacity - aNode.CumulativeWeight; - var nextLevel = aNode.Level + 1; + if(current.IsTaken) + { + takenItems.Add(items[current.Level]); + } + } + + return takenItems.ToArray(); + } - while (availableWeight > 0 && nextLevel < items.Length) + /// + /// Returns the upper bound value of a given node. + /// + /// The given node. + /// All items to choose from. + /// The maximum weight capacity of the knapsack to be filled. + /// + /// A function that returns the value of the specified item + /// from the items list. + /// + /// + /// A function that returns the weight of the specified item + /// from the items list. + /// + /// + /// upper bound value of the given node. + /// + private static double ComputeUpperBound(BranchAndBoundNode aNode, T[] items, int capacity, Func weightSelector, Func valueSelector) + { + var upperBound = aNode.CumulativeValue; + var availableWeight = capacity - aNode.CumulativeWeight; + var nextLevel = aNode.Level + 1; + + while (availableWeight > 0 && nextLevel < items.Length) + { + if (weightSelector(items[nextLevel]) <= availableWeight) { - if (weightSelector(items[nextLevel]) <= availableWeight) - { - upperBound += valueSelector(items[nextLevel]); - availableWeight -= weightSelector(items[nextLevel]); - } - else - { - upperBound += valueSelector(items[nextLevel]) / weightSelector(items[nextLevel]) * availableWeight; - availableWeight = 0; - } - - nextLevel++; + upperBound += valueSelector(items[nextLevel]); + availableWeight -= weightSelector(items[nextLevel]); + } + else + { + upperBound += valueSelector(items[nextLevel]) / weightSelector(items[nextLevel]) * availableWeight; + availableWeight = 0; } - return upperBound; + nextLevel++; } + + return upperBound; } } diff --git a/Algorithms/Knapsack/BranchAndBoundNode.cs b/Algorithms/Knapsack/BranchAndBoundNode.cs index 3d873739..0a65f16a 100644 --- a/Algorithms/Knapsack/BranchAndBoundNode.cs +++ b/Algorithms/Knapsack/BranchAndBoundNode.cs @@ -1,30 +1,29 @@ -namespace Algorithms.Knapsack +namespace Algorithms.Knapsack; + +public class BranchAndBoundNode { - public class BranchAndBoundNode - { - // isTaken --> true = the item where index = level is taken, vice versa - public bool IsTaken { get; } + // isTaken --> true = the item where index = level is taken, vice versa + public bool IsTaken { get; } - // cumulativeWeight --> um of weight of item associated in each nodes starting from root to this node (only item that is taken) - public int CumulativeWeight { get; set; } + // cumulativeWeight --> um of weight of item associated in each nodes starting from root to this node (only item that is taken) + public int CumulativeWeight { get; set; } - // cumulativeValue --> sum of value of item associated in each nodes starting from root to this node (only item that is taken) - public double CumulativeValue { get; set; } + // cumulativeValue --> sum of value of item associated in each nodes starting from root to this node (only item that is taken) + public double CumulativeValue { get; set; } - // upperBound --> largest possible value after taking/not taking the item associated to this node (fractional) - public double UpperBound { get; set; } + // upperBound --> largest possible value after taking/not taking the item associated to this node (fractional) + public double UpperBound { get; set; } - // level --> level of the node in the tree structure - public int Level { get; } + // level --> level of the node in the tree structure + public int Level { get; } - // parent node - public BranchAndBoundNode? Parent { get; } + // parent node + public BranchAndBoundNode? Parent { get; } - public BranchAndBoundNode(int level, bool taken, BranchAndBoundNode? parent = null) - { - Level = level; - IsTaken = taken; - Parent = parent; - } + public BranchAndBoundNode(int level, bool taken, BranchAndBoundNode? parent = null) + { + Level = level; + IsTaken = taken; + Parent = parent; } } diff --git a/Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs b/Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs index 2b5abc18..db60b55d 100644 --- a/Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs +++ b/Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs @@ -1,101 +1,100 @@ -using System; +using System; using System.Collections.Generic; -namespace Algorithms.Knapsack +namespace Algorithms.Knapsack; + +/// +/// Dynamic Programming Knapsack solver. +/// +/// Type of items in knapsack. +public class DynamicProgrammingKnapsackSolver { /// - /// Dynamic Programming Knapsack solver. + /// Returns the knapsack containing the items that + /// maximize value while not exceeding weight capacity. /// - /// Type of items in knapsack. - public class DynamicProgrammingKnapsackSolver + /// The list of items from which we select ones to be in the knapsack. + /// + /// The maximum weight capacity of the knapsack + /// to be filled. Only integer values of this capacity are tried. If + /// a greater resolution is needed, multiply the + /// weights/capacity by a factor of 10. + /// + /// + /// A function that returns the value of the specified item + /// from the items list. + /// + /// + /// A function that returns the weight of the specified item + /// from the items list. + /// + /// + /// The array of items that provides the maximum value of the + /// knapsack without exceeding the specified weight capacity. + /// + public T[] Solve(T[] items, int capacity, Func weightSelector, Func valueSelector) { - /// - /// Returns the knapsack containing the items that - /// maximize value while not exceeding weight capacity. - /// - /// The list of items from which we select ones to be in the knapsack. - /// - /// The maximum weight capacity of the knapsack - /// to be filled. Only integer values of this capacity are tried. If - /// a greater resolution is needed, multiply the - /// weights/capacity by a factor of 10. - /// - /// - /// A function that returns the value of the specified item - /// from the items list. - /// - /// - /// A function that returns the weight of the specified item - /// from the items list. - /// - /// - /// The array of items that provides the maximum value of the - /// knapsack without exceeding the specified weight capacity. - /// - public T[] Solve(T[] items, int capacity, Func weightSelector, Func valueSelector) - { - var cache = Tabulate(items, weightSelector, valueSelector, capacity); - return GetOptimalItems(items, weightSelector, cache, capacity); - } + var cache = Tabulate(items, weightSelector, valueSelector, capacity); + return GetOptimalItems(items, weightSelector, cache, capacity); + } - private static T[] GetOptimalItems(T[] items, Func weightSelector, double[,] cache, int capacity) - { - var currentCapacity = capacity; + private static T[] GetOptimalItems(T[] items, Func weightSelector, double[,] cache, int capacity) + { + var currentCapacity = capacity; - var result = new List(); - for (var i = items.Length - 1; i >= 0; i--) + var result = new List(); + for (var i = items.Length - 1; i >= 0; i--) + { + if (cache[i + 1, currentCapacity] > cache[i, currentCapacity]) { - if (cache[i + 1, currentCapacity] > cache[i, currentCapacity]) - { - var item = items[i]; - result.Add(item); - currentCapacity -= weightSelector(item); - } + var item = items[i]; + result.Add(item); + currentCapacity -= weightSelector(item); } - - result.Reverse(); // we added items back to front - return result.ToArray(); } - private static double[,] Tabulate( - T[] items, - Func weightSelector, - Func valueSelector, - int maxCapacity) + result.Reverse(); // we added items back to front + return result.ToArray(); + } + + private static double[,] Tabulate( + T[] items, + Func weightSelector, + Func valueSelector, + int maxCapacity) + { + // Store the incremental results in a bottom up manner + var n = items.Length; + var results = new double[n + 1, maxCapacity + 1]; + for (var i = 0; i <= n; i++) { - // Store the incremental results in a bottom up manner - var n = items.Length; - var results = new double[n + 1, maxCapacity + 1]; - for (var i = 0; i <= n; i++) + for (var w = 0; w <= maxCapacity; w++) { - for (var w = 0; w <= maxCapacity; w++) + if (i == 0 || w == 0) + { + // If we have no items to take, or + // if we have no capacity in our knapsack + // we cannot possibly have any value + results[i, w] = 0; + } + else if (weightSelector(items[i - 1]) <= w) { - if (i == 0 || w == 0) - { - // If we have no items to take, or - // if we have no capacity in our knapsack - // we cannot possibly have any value - results[i, w] = 0; - } - else if (weightSelector(items[i - 1]) <= w) - { - // Decide if it is better to take or not take this item - var iut = items[i - 1]; // iut = Item under test - var vut = valueSelector(iut); // vut = Value of item under test - var wut = weightSelector(iut); // wut = Weight of item under test - var valueIfTaken = vut + results[i - 1, w - wut]; - var valueIfNotTaken = results[i - 1, w]; - results[i, w] = Math.Max(valueIfTaken, valueIfNotTaken); - } - else - { - // There is not enough room to take this item - results[i, w] = results[i - 1, w]; - } + // Decide if it is better to take or not take this item + var iut = items[i - 1]; // iut = Item under test + var vut = valueSelector(iut); // vut = Value of item under test + var wut = weightSelector(iut); // wut = Weight of item under test + var valueIfTaken = vut + results[i - 1, w - wut]; + var valueIfNotTaken = results[i - 1, w]; + results[i, w] = Math.Max(valueIfTaken, valueIfNotTaken); + } + else + { + // There is not enough room to take this item + results[i, w] = results[i - 1, w]; } } - - return results; } + + return results; } } diff --git a/Algorithms/Knapsack/IHeuristicKnapsackSolver.cs b/Algorithms/Knapsack/IHeuristicKnapsackSolver.cs index b5403d2b..e73bcdd1 100644 --- a/Algorithms/Knapsack/IHeuristicKnapsackSolver.cs +++ b/Algorithms/Knapsack/IHeuristicKnapsackSolver.cs @@ -1,25 +1,24 @@ -using System; +using System; -namespace Algorithms.Knapsack +namespace Algorithms.Knapsack; + +/// +/// Solves knapsack problem using some heuristics +/// Sum of values of taken items -> max +/// Sum of weights of taken items. <= capacity. +/// +/// Type of items in knapsack. +public interface IHeuristicKnapsackSolver { /// /// Solves knapsack problem using some heuristics /// Sum of values of taken items -> max /// Sum of weights of taken items. <= capacity. /// - /// Type of items in knapsack. - public interface IHeuristicKnapsackSolver - { - /// - /// Solves knapsack problem using some heuristics - /// Sum of values of taken items -> max - /// Sum of weights of taken items. <= capacity. - /// - /// All items to choose from. - /// How much weight we can take. - /// Maps item to its weight. - /// Maps item to its value. - /// Items that were chosen. - T[] Solve(T[] items, double capacity, Func weightSelector, Func valueSelector); - } + /// All items to choose from. + /// How much weight we can take. + /// Maps item to its weight. + /// Maps item to its value. + /// Items that were chosen. + T[] Solve(T[] items, double capacity, Func weightSelector, Func valueSelector); } diff --git a/Algorithms/Knapsack/IKnapsackSolver.cs b/Algorithms/Knapsack/IKnapsackSolver.cs index fb1cdaa4..3eca055a 100644 --- a/Algorithms/Knapsack/IKnapsackSolver.cs +++ b/Algorithms/Knapsack/IKnapsackSolver.cs @@ -1,12 +1,11 @@ -namespace Algorithms.Knapsack +namespace Algorithms.Knapsack; + +/// +/// Solves knapsack problem: +/// to maximize sum of values of taken items, +/// while sum of weights of taken items is less than capacity. +/// +/// Type of items in knapsack. +public interface IKnapsackSolver : IHeuristicKnapsackSolver { - /// - /// Solves knapsack problem: - /// to maximize sum of values of taken items, - /// while sum of weights of taken items is less than capacity. - /// - /// Type of items in knapsack. - public interface IKnapsackSolver : IHeuristicKnapsackSolver - { - } } diff --git a/Algorithms/Knapsack/NaiveKnapsackSolver.cs b/Algorithms/Knapsack/NaiveKnapsackSolver.cs index f0bd1dd5..841b8750 100644 --- a/Algorithms/Knapsack/NaiveKnapsackSolver.cs +++ b/Algorithms/Knapsack/NaiveKnapsackSolver.cs @@ -1,38 +1,37 @@ -using System; +using System; using System.Collections.Generic; -namespace Algorithms.Knapsack +namespace Algorithms.Knapsack; + +/// +/// Greedy heurictic solver. +/// +/// Type of items in knapsack. +public class NaiveKnapsackSolver : IHeuristicKnapsackSolver { /// - /// Greedy heurictic solver. + /// TODO. /// - /// Type of items in knapsack. - public class NaiveKnapsackSolver : IHeuristicKnapsackSolver + /// TODO. 2. + /// TODO. 3. + /// TODO. 4. + /// TODO. 5. + /// TODO. 6. + public T[] Solve(T[] items, double capacity, Func weightSelector, Func valueSelector) { - /// - /// TODO. - /// - /// TODO. 2. - /// TODO. 3. - /// TODO. 4. - /// TODO. 5. - /// TODO. 6. - public T[] Solve(T[] items, double capacity, Func weightSelector, Func valueSelector) - { - var weight = 0d; - var left = new List(); + var weight = 0d; + var left = new List(); - foreach (var item in items) + foreach (var item in items) + { + var weightDelta = weightSelector(item); + if (weight + weightDelta <= capacity) { - var weightDelta = weightSelector(item); - if (weight + weightDelta <= capacity) - { - weight += weightDelta; - left.Add(item); - } + weight += weightDelta; + left.Add(item); } - - return left.ToArray(); } + + return left.ToArray(); } } diff --git a/Algorithms/LinearAlgebra/Distances/Euclidean.cs b/Algorithms/LinearAlgebra/Distances/Euclidean.cs index fc893036..67fd4129 100644 --- a/Algorithms/LinearAlgebra/Distances/Euclidean.cs +++ b/Algorithms/LinearAlgebra/Distances/Euclidean.cs @@ -1,31 +1,27 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.LinearAlgebra.Distances +namespace Algorithms.LinearAlgebra.Distances; + +/// +/// Implementation for Euclidean distance. +/// +public static class Euclidean { /// - /// Implementation for Euclidean distance. + /// Calculate Euclidean distance for two N-Dimensional points. /// - public static class Euclidean + /// First N-Dimensional point. + /// Second N-Dimensional point. + /// Calculated Euclidean distance. + public static double Distance(double[] point1, double[] point2) { - /// - /// Calculate Euclidean distance for two N-Dimensional points. - /// - /// First N-Dimensional point. - /// Second N-Dimensional point. - /// Calculated Euclidean distance. - public static double Distance(double[] point1, double[] point2) + if (point1.Length != point2.Length) { - if (point1.Length != point2.Length) - { - throw new ArgumentException("Both points should have the same dimensionality"); - } - - // distance = sqrt((x1-y1)^2 + (x2-y2)^2 + ... + (xn-yn)^2) - return Math.Sqrt(point1.Zip(point2, (x1, x2) => (x1 - x2) * (x1 - x2)).Sum()); + throw new ArgumentException("Both points should have the same dimensionality"); } + + // distance = sqrt((x1-y1)^2 + (x2-y2)^2 + ... + (xn-yn)^2) + return Math.Sqrt(point1.Zip(point2, (x1, x2) => (x1 - x2) * (x1 - x2)).Sum()); } } diff --git a/Algorithms/LinearAlgebra/Distances/Manhattan.cs b/Algorithms/LinearAlgebra/Distances/Manhattan.cs index 1b47563f..ea0dd96f 100644 --- a/Algorithms/LinearAlgebra/Distances/Manhattan.cs +++ b/Algorithms/LinearAlgebra/Distances/Manhattan.cs @@ -1,35 +1,31 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.LinearAlgebra.Distances +namespace Algorithms.LinearAlgebra.Distances; + +/// +/// Implementation fo Manhattan distance. +/// It is the sum of the lengths of the projections of the line segment between the points onto the coordinate axes. +/// In other words, it is the sum of absolute difference between the measures in all dimensions of two points. +/// +/// Its commonly used in regression analysis. +/// +public static class Manhattan { /// - /// Implementation fo Manhattan distance. - /// It is the sum of the lengths of the projections of the line segment between the points onto the coordinate axes. - /// In other words, it is the sum of absolute difference between the measures in all dimensions of two points. - /// - /// Its commonly used in regression analysis. + /// Calculate Manhattan distance for two N-Dimensional points. /// - public static class Manhattan + /// First N-Dimensional point. + /// Second N-Dimensional point. + /// Calculated Manhattan distance. + public static double Distance(double[] point1, double[] point2) { - /// - /// Calculate Manhattan distance for two N-Dimensional points. - /// - /// First N-Dimensional point. - /// Second N-Dimensional point. - /// Calculated Manhattan distance. - public static double Distance(double[] point1, double[] point2) + if (point1.Length != point2.Length) { - if (point1.Length != point2.Length) - { - throw new ArgumentException("Both points should have the same dimensionality"); - } - - // distance = |x1-y1| + |x2-y2| + ... + |xn-yn| - return point1.Zip(point2, (x1, x2) => Math.Abs(x1 - x2)).Sum(); + throw new ArgumentException("Both points should have the same dimensionality"); } + + // distance = |x1-y1| + |x2-y2| + ... + |xn-yn| + return point1.Zip(point2, (x1, x2) => Math.Abs(x1 - x2)).Sum(); } } diff --git a/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs b/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs index 51e3cf85..8e503992 100644 --- a/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs +++ b/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs @@ -2,86 +2,85 @@ using System.Linq; using Utilities.Extensions; -namespace Algorithms.LinearAlgebra.Eigenvalue +namespace Algorithms.LinearAlgebra.Eigenvalue; + +/// +/// Power iteration method - eigenvalue numeric algorithm, based on recurrent relation: +/// Li+1 = (A * Li) / || A * Li ||, where Li - eigenvector approximation. +/// +public static class PowerIteration { /// - /// Power iteration method - eigenvalue numeric algorithm, based on recurrent relation: - /// Li+1 = (A * Li) / || A * Li ||, where Li - eigenvector approximation. + /// Returns approximation of the dominant eigenvalue and eigenvector of matrix. /// - public static class PowerIteration + /// + /// + /// The algorithm will not converge if the start vector is orthogonal to the eigenvector. + /// + /// + /// The matrix must be square-shaped. + /// + /// + /// Source square-shaped matrix. + /// Start vector. + /// Accuracy of the result. + /// Dominant eigenvalue and eigenvector pair. + /// The matrix is not square-shaped. + /// The length of the start vector doesn't equal the size of the source matrix. + public static (double eigenvalue, double[] eigenvector) Dominant( + double[,] source, + double[] startVector, + double error = 0.00001) { - /// - /// Returns approximation of the dominant eigenvalue and eigenvector of matrix. - /// - /// - /// - /// The algorithm will not converge if the start vector is orthogonal to the eigenvector. - /// - /// - /// The matrix must be square-shaped. - /// - /// - /// Source square-shaped matrix. - /// Start vector. - /// Accuracy of the result. - /// Dominant eigenvalue and eigenvector pair. - /// The matrix is not square-shaped. - /// The length of the start vector doesn't equal the size of the source matrix. - public static (double eigenvalue, double[] eigenvector) Dominant( - double[,] source, - double[] startVector, - double error = 0.00001) + if (source.GetLength(0) != source.GetLength(1)) { - if (source.GetLength(0) != source.GetLength(1)) - { - throw new ArgumentException("The source matrix is not square-shaped."); - } - - if (source.GetLength(0) != startVector.Length) - { - throw new ArgumentException( - "The length of the start vector doesn't equal the size of the source matrix."); - } - - double eigenNorm; - double[] previousEigenVector; - double[] currentEigenVector = startVector; + throw new ArgumentException("The source matrix is not square-shaped."); + } - do - { - previousEigenVector = currentEigenVector; - currentEigenVector = source.Multiply( - previousEigenVector.ToColumnVector()) - .ToRowVector(); + if (source.GetLength(0) != startVector.Length) + { + throw new ArgumentException( + "The length of the start vector doesn't equal the size of the source matrix."); + } - eigenNorm = currentEigenVector.Magnitude(); - currentEigenVector = currentEigenVector.Select(x => x / eigenNorm).ToArray(); - } - while (Math.Abs(currentEigenVector.Dot(previousEigenVector)) < 1.0 - error); + double eigenNorm; + double[] previousEigenVector; + double[] currentEigenVector = startVector; - var eigenvalue = source.Multiply(currentEigenVector.ToColumnVector()).ToRowVector().Magnitude(); + do + { + previousEigenVector = currentEigenVector; + currentEigenVector = source.Multiply( + previousEigenVector.ToColumnVector()) + .ToRowVector(); - return (eigenvalue, eigenvector: currentEigenVector); + eigenNorm = currentEigenVector.Magnitude(); + currentEigenVector = currentEigenVector.Select(x => x / eigenNorm).ToArray(); } + while (Math.Abs(currentEigenVector.Dot(previousEigenVector)) < 1.0 - error); + + var eigenvalue = source.Multiply(currentEigenVector.ToColumnVector()).ToRowVector().Magnitude(); - /// - /// Returns approximation of the dominant eigenvalue and eigenvector of matrix. - /// Random normalized vector is used as the start vector to decrease chance of orthogonality to the eigenvector. - /// - /// - /// - /// The algorithm will not converge if the start vector is orthogonal to the eigenvector. - /// - /// - /// The matrix should be square-shaped. - /// - /// - /// Source square-shaped matrix. - /// Accuracy of the result. - /// Dominant eigenvalue and eigenvector pair. - /// The matrix is not square-shaped. - /// The length of the start vector doesn't equal the size of the source matrix. - public static (double eigenvalue, double[] eigenvector) Dominant(double[,] source, double error = 0.00001) => - Dominant(source, new Random().NextVector(source.GetLength(1)), error); + return (eigenvalue, eigenvector: currentEigenVector); } + + /// + /// Returns approximation of the dominant eigenvalue and eigenvector of matrix. + /// Random normalized vector is used as the start vector to decrease chance of orthogonality to the eigenvector. + /// + /// + /// + /// The algorithm will not converge if the start vector is orthogonal to the eigenvector. + /// + /// + /// The matrix should be square-shaped. + /// + /// + /// Source square-shaped matrix. + /// Accuracy of the result. + /// Dominant eigenvalue and eigenvector pair. + /// The matrix is not square-shaped. + /// The length of the start vector doesn't equal the size of the source matrix. + public static (double eigenvalue, double[] eigenvector) Dominant(double[,] source, double error = 0.00001) => + Dominant(source, new Random().NextVector(source.GetLength(1)), error); } diff --git a/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs b/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs index a8b702a6..1eeaef76 100644 --- a/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs +++ b/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs @@ -3,189 +3,188 @@ using System.Linq; using System.Numerics; -namespace Algorithms.ModularArithmetic +namespace Algorithms.ModularArithmetic; + +/// +/// Chinese Remainder Theorem: https://en.wikipedia.org/wiki/Chinese_remainder_theorem. +/// +public static class ChineseRemainderTheorem { /// - /// Chinese Remainder Theorem: https://en.wikipedia.org/wiki/Chinese_remainder_theorem. + /// The Chinese Remainder Theorem is used to compute x for given set of pairs of integers (a_i, n_i) with: + /// + /// x = a_0 mod n_0 + /// x = a_1 mod n_1 + /// ... + /// x = a_k mod n_k + /// + /// for 0 <= i < k, for some positive integer k. Additional requirements are: + /// + /// n_i > 1 for 0 <= i < k + /// n_i and n_j are coprime, for all 0 <= i < j < k + /// 0 <= a_i < n_i, for all 0 <= i < k + /// 0 <= x < n_0 * n_1 * ... * n_(k-1) + /// /// - public static class ChineseRemainderTheorem + /// An ordered list of a_0, a_1, ..., a_k. + /// An ordered list of n_0, n_1, ..., n_k. + /// The value x. + /// If any of the requirements is not fulfilled. + public static long Compute(List listOfAs, List listOfNs) { - /// - /// The Chinese Remainder Theorem is used to compute x for given set of pairs of integers (a_i, n_i) with: - /// - /// x = a_0 mod n_0 - /// x = a_1 mod n_1 - /// ... - /// x = a_k mod n_k - /// - /// for 0 <= i < k, for some positive integer k. Additional requirements are: - /// - /// n_i > 1 for 0 <= i < k - /// n_i and n_j are coprime, for all 0 <= i < j < k - /// 0 <= a_i < n_i, for all 0 <= i < k - /// 0 <= x < n_0 * n_1 * ... * n_(k-1) - /// - /// - /// An ordered list of a_0, a_1, ..., a_k. - /// An ordered list of n_0, n_1, ..., n_k. - /// The value x. - /// If any of the requirements is not fulfilled. - public static long Compute(List listOfAs, List listOfNs) + // Check the requirements for this algorithm: + CheckRequirements(listOfAs, listOfNs); + + // For performance-reasons compute the product of all n_i as prodN, because we're going to need access to (prodN / n_i) for all i: + var prodN = 1L; + foreach (var n in listOfNs) { - // Check the requirements for this algorithm: - CheckRequirements(listOfAs, listOfNs); + prodN *= n; + } - // For performance-reasons compute the product of all n_i as prodN, because we're going to need access to (prodN / n_i) for all i: - var prodN = 1L; - foreach (var n in listOfNs) - { - prodN *= n; - } + var result = 0L; + for (var i = 0; i < listOfNs.Count; i++) + { + var a_i = listOfAs[i]; + var n_i = listOfNs[i]; + var modulus_i = prodN / n_i; - var result = 0L; - for (var i = 0; i < listOfNs.Count; i++) - { - var a_i = listOfAs[i]; - var n_i = listOfNs[i]; - var modulus_i = prodN / n_i; + var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).bezoutB; + result += a_i * bezout_modulus_i * modulus_i; + } - var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).bezoutB; - result += a_i * bezout_modulus_i * modulus_i; - } + // Make sure, result is in [0, prodN). + result %= prodN; + if (result < 0) + { + result += prodN; + } - // Make sure, result is in [0, prodN). - result %= prodN; - if (result < 0) - { - result += prodN; - } + return result; + } - return result; - } + /// + /// The Chinese Remainder Theorem is used to compute x for given set of pairs of integers (a_i, n_i) with: + /// + /// x = a_0 mod n_0 + /// x = a_1 mod n_1 + /// ... + /// x = a_k mod n_k + /// + /// for 0 <= i < k, for some positive integer k. Additional requirements are: + /// + /// n_i > 1 for 0 <= i < k + /// n_i and n_j are coprime, for all 0 <= i < j < k + /// 0 <= a_i < n_i, for all 0 <= i < k + /// 0 <= x < n_0 * n_1 * ... * n_(k-1) + /// + /// + /// An ordered list of a_0, a_1, ..., a_k. + /// An ordered list of n_0, n_1, ..., n_k. + /// The value x. + /// If any of the requirements is not fulfilled. + public static BigInteger Compute(List listOfAs, List listOfNs) + { + // Check the requirements for this algorithm: + CheckRequirements(listOfAs, listOfNs); - /// - /// The Chinese Remainder Theorem is used to compute x for given set of pairs of integers (a_i, n_i) with: - /// - /// x = a_0 mod n_0 - /// x = a_1 mod n_1 - /// ... - /// x = a_k mod n_k - /// - /// for 0 <= i < k, for some positive integer k. Additional requirements are: - /// - /// n_i > 1 for 0 <= i < k - /// n_i and n_j are coprime, for all 0 <= i < j < k - /// 0 <= a_i < n_i, for all 0 <= i < k - /// 0 <= x < n_0 * n_1 * ... * n_(k-1) - /// - /// - /// An ordered list of a_0, a_1, ..., a_k. - /// An ordered list of n_0, n_1, ..., n_k. - /// The value x. - /// If any of the requirements is not fulfilled. - public static BigInteger Compute(List listOfAs, List listOfNs) + // For performance-reasons compute the product of all n_i as prodN, because we're going to need access to (prodN / n_i) for all i: + var prodN = BigInteger.One; + foreach (var n in listOfNs) { - // Check the requirements for this algorithm: - CheckRequirements(listOfAs, listOfNs); + prodN *= n; + } - // For performance-reasons compute the product of all n_i as prodN, because we're going to need access to (prodN / n_i) for all i: - var prodN = BigInteger.One; - foreach (var n in listOfNs) - { - prodN *= n; - } + var result = BigInteger.Zero; + for (var i = 0; i < listOfNs.Count; i++) + { + var a_i = listOfAs[i]; + var n_i = listOfNs[i]; + var modulus_i = prodN / n_i; - var result = BigInteger.Zero; - for (var i = 0; i < listOfNs.Count; i++) - { - var a_i = listOfAs[i]; - var n_i = listOfNs[i]; - var modulus_i = prodN / n_i; + var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).bezoutB; + result += a_i * bezout_modulus_i * modulus_i; + } - var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).bezoutB; - result += a_i * bezout_modulus_i * modulus_i; - } + // Make sure, result is in [0, prodN). + result %= prodN; + if (result < 0) + { + result += prodN; + } - // Make sure, result is in [0, prodN). - result %= prodN; - if (result < 0) - { - result += prodN; - } + return result; + } - return result; + /// + /// Checks the requirements for the algorithm and throws an ArgumentException if they are not being met. + /// + /// An ordered list of a_0, a_1, ..., a_k. + /// An ordered list of n_0, n_1, ..., n_k. + /// If any of the requirements is not fulfilled. + private static void CheckRequirements(List listOfAs, List listOfNs) + { + if (listOfAs == null || listOfNs == null || listOfAs.Count != listOfNs.Count) + { + throw new ArgumentException("The parameters 'listOfAs' and 'listOfNs' must not be null and have to be of equal length!"); } - /// - /// Checks the requirements for the algorithm and throws an ArgumentException if they are not being met. - /// - /// An ordered list of a_0, a_1, ..., a_k. - /// An ordered list of n_0, n_1, ..., n_k. - /// If any of the requirements is not fulfilled. - private static void CheckRequirements(List listOfAs, List listOfNs) + if (listOfNs.Any(x => x <= 1)) { - if (listOfAs == null || listOfNs == null || listOfAs.Count != listOfNs.Count) - { - throw new ArgumentException("The parameters 'listOfAs' and 'listOfNs' must not be null and have to be of equal length!"); - } - - if (listOfNs.Any(x => x <= 1)) - { - throw new ArgumentException($"The value {listOfNs.First(x => x <= 1)} for some n_i is smaller than or equal to 1."); - } + throw new ArgumentException($"The value {listOfNs.First(x => x <= 1)} for some n_i is smaller than or equal to 1."); + } - if (listOfAs.Any(x => x < 0)) - { - throw new ArgumentException($"The value {listOfAs.First(x => x < 0)} for some a_i is smaller than 0."); - } + if (listOfAs.Any(x => x < 0)) + { + throw new ArgumentException($"The value {listOfAs.First(x => x < 0)} for some a_i is smaller than 0."); + } - // Check if all pairs of (n_i, n_j) are coprime: - for (var i = 0; i < listOfNs.Count; i++) + // Check if all pairs of (n_i, n_j) are coprime: + for (var i = 0; i < listOfNs.Count; i++) + { + for (var j = i + 1; j < listOfNs.Count; j++) { - for (var j = i + 1; j < listOfNs.Count; j++) + long gcd; + if ((gcd = ExtendedEuclideanAlgorithm.Compute(listOfNs[i], listOfNs[j]).gcd) != 1L) { - long gcd; - if ((gcd = ExtendedEuclideanAlgorithm.Compute(listOfNs[i], listOfNs[j]).gcd) != 1L) - { - throw new ArgumentException($"The GCD of n_{i} = {listOfNs[i]} and n_{j} = {listOfNs[j]} equals {gcd} and thus these values aren't coprime."); - } + throw new ArgumentException($"The GCD of n_{i} = {listOfNs[i]} and n_{j} = {listOfNs[j]} equals {gcd} and thus these values aren't coprime."); } } } + } - /// - /// Checks the requirements for the algorithm and throws an ArgumentException if they are not being met. - /// - /// An ordered list of a_0, a_1, ..., a_k. - /// An ordered list of n_0, n_1, ..., n_k. - /// If any of the requirements is not fulfilled. - private static void CheckRequirements(List listOfAs, List listOfNs) + /// + /// Checks the requirements for the algorithm and throws an ArgumentException if they are not being met. + /// + /// An ordered list of a_0, a_1, ..., a_k. + /// An ordered list of n_0, n_1, ..., n_k. + /// If any of the requirements is not fulfilled. + private static void CheckRequirements(List listOfAs, List listOfNs) + { + if (listOfAs == null || listOfNs == null || listOfAs.Count != listOfNs.Count) { - if (listOfAs == null || listOfNs == null || listOfAs.Count != listOfNs.Count) - { - throw new ArgumentException("The parameters 'listOfAs' and 'listOfNs' must not be null and have to be of equal length!"); - } + throw new ArgumentException("The parameters 'listOfAs' and 'listOfNs' must not be null and have to be of equal length!"); + } - if (listOfNs.Any(x => x <= 1)) - { - throw new ArgumentException($"The value {listOfNs.First(x => x <= 1)} for some n_i is smaller than or equal to 1."); - } + if (listOfNs.Any(x => x <= 1)) + { + throw new ArgumentException($"The value {listOfNs.First(x => x <= 1)} for some n_i is smaller than or equal to 1."); + } - if (listOfAs.Any(x => x < 0)) - { - throw new ArgumentException($"The value {listOfAs.First(x => x < 0)} for some a_i is smaller than 0."); - } + if (listOfAs.Any(x => x < 0)) + { + throw new ArgumentException($"The value {listOfAs.First(x => x < 0)} for some a_i is smaller than 0."); + } - // Check if all pairs of (n_i, n_j) are coprime: - for (var i = 0; i < listOfNs.Count; i++) + // Check if all pairs of (n_i, n_j) are coprime: + for (var i = 0; i < listOfNs.Count; i++) + { + for (var j = i + 1; j < listOfNs.Count; j++) { - for (var j = i + 1; j < listOfNs.Count; j++) + BigInteger gcd; + if ((gcd = ExtendedEuclideanAlgorithm.Compute(listOfNs[i], listOfNs[j]).gcd) != BigInteger.One) { - BigInteger gcd; - if ((gcd = ExtendedEuclideanAlgorithm.Compute(listOfNs[i], listOfNs[j]).gcd) != BigInteger.One) - { - throw new ArgumentException($"The GCD of n_{i} = {listOfNs[i]} and n_{j} = {listOfNs[j]} equals {gcd} and thus these values aren't coprime."); - } + throw new ArgumentException($"The GCD of n_{i} = {listOfNs[i]} and n_{j} = {listOfNs[j]} equals {gcd} and thus these values aren't coprime."); } } } diff --git a/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs b/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs index 19481fcd..aed5b219 100644 --- a/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs +++ b/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs @@ -1,95 +1,94 @@ using System.Numerics; -namespace Algorithms.ModularArithmetic +namespace Algorithms.ModularArithmetic; + +/// +/// Extended Euclidean algorithm: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm. +/// +public static class ExtendedEuclideanAlgorithm { /// - /// Extended Euclidean algorithm: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm. + /// Computes the greatest common divisor (gcd) of integers a and b, also the coefficients of Bézout's identity, + /// which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = gcd(a, b). /// - public static class ExtendedEuclideanAlgorithm + /// Input number. + /// Second input number. + /// A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the gcd(a,b). + public static ExtendedEuclideanAlgorithmResult Compute(long a, long b) { - /// - /// Computes the greatest common divisor (gcd) of integers a and b, also the coefficients of Bézout's identity, - /// which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = gcd(a, b). - /// - /// Input number. - /// Second input number. - /// A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the gcd(a,b). - public static ExtendedEuclideanAlgorithmResult Compute(long a, long b) - { - long quotient; - long tmp; - var s = 0L; - var bezoutOfA = 1L; - var r = b; - var gcd = a; - var bezoutOfB = 0L; - - while (r != 0) - { - quotient = gcd / r; // integer division + long quotient; + long tmp; + var s = 0L; + var bezoutOfA = 1L; + var r = b; + var gcd = a; + var bezoutOfB = 0L; - tmp = gcd; - gcd = r; - r = tmp - quotient * r; - - tmp = bezoutOfA; - bezoutOfA = s; - s = tmp - quotient * s; - } + while (r != 0) + { + quotient = gcd / r; // integer division - if (b != 0) - { - bezoutOfB = (gcd - bezoutOfA * a) / b; // integer division - } + tmp = gcd; + gcd = r; + r = tmp - quotient * r; - return new ExtendedEuclideanAlgorithmResult(bezoutOfA, bezoutOfB, gcd); + tmp = bezoutOfA; + bezoutOfA = s; + s = tmp - quotient * s; } - /// - /// Computes the greatest common divisor (gcd) of integers a and b, also the coefficients of Bézout's identity, - /// which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = gcd(a, b). - /// - /// Input number. - /// Second input number. - /// A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the gcd(a,b). - public static ExtendedEuclideanAlgorithmResult Compute(BigInteger a, BigInteger b) + if (b != 0) { - BigInteger quotient; - BigInteger tmp; - var s = BigInteger.Zero; - var bezoutOfA = BigInteger.One; - var r = b; - var gcd = a; - var bezoutOfB = BigInteger.Zero; + bezoutOfB = (gcd - bezoutOfA * a) / b; // integer division + } - while (r != 0) - { - quotient = gcd / r; // integer division + return new ExtendedEuclideanAlgorithmResult(bezoutOfA, bezoutOfB, gcd); + } - tmp = gcd; - gcd = r; - r = tmp - quotient * r; + /// + /// Computes the greatest common divisor (gcd) of integers a and b, also the coefficients of Bézout's identity, + /// which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = gcd(a, b). + /// + /// Input number. + /// Second input number. + /// A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the gcd(a,b). + public static ExtendedEuclideanAlgorithmResult Compute(BigInteger a, BigInteger b) + { + BigInteger quotient; + BigInteger tmp; + var s = BigInteger.Zero; + var bezoutOfA = BigInteger.One; + var r = b; + var gcd = a; + var bezoutOfB = BigInteger.Zero; + + while (r != 0) + { + quotient = gcd / r; // integer division - tmp = bezoutOfA; - bezoutOfA = s; - s = tmp - quotient * s; - } + tmp = gcd; + gcd = r; + r = tmp - quotient * r; - if (b != 0) - { - bezoutOfB = (gcd - bezoutOfA * a) / b; // integer division - } + tmp = bezoutOfA; + bezoutOfA = s; + s = tmp - quotient * s; + } - return new ExtendedEuclideanAlgorithmResult(bezoutOfA, bezoutOfB, gcd); + if (b != 0) + { + bezoutOfB = (gcd - bezoutOfA * a) / b; // integer division } - /// - /// The result type for the computation of the Extended Euclidean Algorithm. - /// - /// The data type of the computation (i.e. long or BigInteger). - /// The bezout coefficient of the parameter a to the computation. - /// The bezout coefficient of the parameter b to the computation. - /// The greatest common divisor of the parameters a and b to the computation. - public record ExtendedEuclideanAlgorithmResult(T bezoutA, T bezoutB, T gcd); + return new ExtendedEuclideanAlgorithmResult(bezoutOfA, bezoutOfB, gcd); } + + /// + /// The result type for the computation of the Extended Euclidean Algorithm. + /// + /// The data type of the computation (i.e. long or BigInteger). + /// The bezout coefficient of the parameter a to the computation. + /// The bezout coefficient of the parameter b to the computation. + /// The greatest common divisor of the parameters a and b to the computation. + public record ExtendedEuclideanAlgorithmResult(T bezoutA, T bezoutB, T gcd); } diff --git a/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs b/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs index e1ba724c..0e42cd68 100644 --- a/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs +++ b/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs @@ -1,65 +1,64 @@ using System; using System.Numerics; -namespace Algorithms.ModularArithmetic +namespace Algorithms.ModularArithmetic; + +/// +/// Modular multiplicative inverse: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse. +/// +public static class ModularMultiplicativeInverse { /// - /// Modular multiplicative inverse: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse. + /// Computes the modular multiplicative inverse of a in Z/nZ, if there is any (i.e. if a and n are coprime). /// - public static class ModularMultiplicativeInverse + /// The number a, of which to compute the multiplicative inverse. + /// The modulus n. + /// The multiplicative inverse of a in Z/nZ, a value in the interval [0, n). + /// If there exists no multiplicative inverse of a in Z/nZ. + public static long Compute(long a, long n) { - /// - /// Computes the modular multiplicative inverse of a in Z/nZ, if there is any (i.e. if a and n are coprime). - /// - /// The number a, of which to compute the multiplicative inverse. - /// The modulus n. - /// The multiplicative inverse of a in Z/nZ, a value in the interval [0, n). - /// If there exists no multiplicative inverse of a in Z/nZ. - public static long Compute(long a, long n) - { - var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, n); - - // Check if there is an inverse: - if (eeaResult.gcd != 1) - { - throw new ArithmeticException($"{a} is not invertible in Z/{n}Z."); - } - - // Make sure, inverseOfA (i.e. the bezout coefficient of a) is in the interval [0, n). - var inverseOfA = eeaResult.bezoutA; - if (inverseOfA < 0) - { - inverseOfA += n; - } + var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, n); - return inverseOfA; + // Check if there is an inverse: + if (eeaResult.gcd != 1) + { + throw new ArithmeticException($"{a} is not invertible in Z/{n}Z."); } - /// - /// Computes the modular multiplicative inverse of a in Z/nZ, if there is any (i.e. if a and n are coprime). - /// - /// The number a, of which to compute the multiplicative inverse. - /// The modulus n. - /// The multiplicative inverse of a in Z/nZ, a value in the interval [0, n). - /// If there exists no multiplicative inverse of a in Z/nZ. - public static BigInteger Compute(BigInteger a, BigInteger n) + // Make sure, inverseOfA (i.e. the bezout coefficient of a) is in the interval [0, n). + var inverseOfA = eeaResult.bezoutA; + if (inverseOfA < 0) { - var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, n); + inverseOfA += n; + } - // Check if there is an inverse: - if (eeaResult.gcd != 1) - { - throw new ArithmeticException($"{a} is not invertible in Z/{n}Z."); - } + return inverseOfA; + } - // Make sure, inverseOfA (i.e. the bezout coefficient of a) is in the interval [0, n). - var inverseOfA = eeaResult.bezoutA; - if (inverseOfA < 0) - { - inverseOfA += n; - } + /// + /// Computes the modular multiplicative inverse of a in Z/nZ, if there is any (i.e. if a and n are coprime). + /// + /// The number a, of which to compute the multiplicative inverse. + /// The modulus n. + /// The multiplicative inverse of a in Z/nZ, a value in the interval [0, n). + /// If there exists no multiplicative inverse of a in Z/nZ. + public static BigInteger Compute(BigInteger a, BigInteger n) + { + var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, n); - return inverseOfA; + // Check if there is an inverse: + if (eeaResult.gcd != 1) + { + throw new ArithmeticException($"{a} is not invertible in Z/{n}Z."); } + + // Make sure, inverseOfA (i.e. the bezout coefficient of a) is in the interval [0, n). + var inverseOfA = eeaResult.bezoutA; + if (inverseOfA < 0) + { + inverseOfA += n; + } + + return inverseOfA; } } diff --git a/Algorithms/Numeric/AliquotSumCalculator.cs b/Algorithms/Numeric/AliquotSumCalculator.cs index b2703a3a..b74b550f 100644 --- a/Algorithms/Numeric/AliquotSumCalculator.cs +++ b/Algorithms/Numeric/AliquotSumCalculator.cs @@ -1,38 +1,37 @@ -using System; +using System; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// In number theory, the aliquot sum s(n) of a positive integer n is the sum of all proper divisors +/// of n, that is, all divisors of n other than n itself. For example, the proper divisors of 15 +/// (that is, the positive divisors of 15 that are not equal to 15) are 1, 3 and 5, so the aliquot +/// sum of 15 is 9 i.e. (1 + 3 + 5). Wikipedia: https://en.wikipedia.org/wiki/Aliquot_sum. +/// +public static class AliquotSumCalculator { /// - /// In number theory, the aliquot sum s(n) of a positive integer n is the sum of all proper divisors - /// of n, that is, all divisors of n other than n itself. For example, the proper divisors of 15 - /// (that is, the positive divisors of 15 that are not equal to 15) are 1, 3 and 5, so the aliquot - /// sum of 15 is 9 i.e. (1 + 3 + 5). Wikipedia: https://en.wikipedia.org/wiki/Aliquot_sum. + /// Finds the aliquot sum of an integer number. /// - public static class AliquotSumCalculator + /// Positive number. + /// The Aliquot Sum. + /// Error number is not on interval (0.0; int.MaxValue). + public static int CalculateAliquotSum(int number) { - /// - /// Finds the aliquot sum of an integer number. - /// - /// Positive number. - /// The Aliquot Sum. - /// Error number is not on interval (0.0; int.MaxValue). - public static int CalculateAliquotSum(int number) + if (number < 0) { - if (number < 0) - { - throw new ArgumentException($"{nameof(number)} cannot be negative"); - } + throw new ArgumentException($"{nameof(number)} cannot be negative"); + } - var sum = 0; - for (int i = 1, limit = number / 2; i <= limit; ++i) + var sum = 0; + for (int i = 1, limit = number / 2; i <= limit; ++i) + { + if (number % i == 0) { - if (number % i == 0) - { - sum += i; - } + sum += i; } - - return sum; } + + return sum; } } diff --git a/Algorithms/Numeric/AmicableNumbersChecker.cs b/Algorithms/Numeric/AmicableNumbersChecker.cs index ad18cd8c..3b80037b 100644 --- a/Algorithms/Numeric/AmicableNumbersChecker.cs +++ b/Algorithms/Numeric/AmicableNumbersChecker.cs @@ -1,41 +1,34 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Algorithms.Numeric; -namespace Algorithms.Numeric +/// +/// Amicable numbers are two different natural numbers related in such a way that the sum of the proper divisors of +/// each is equal to the other number. That is, σ(a)=b+a and σ(b)=a+b, where σ(n) is equal to the sum of positive divisors of n (see also divisor function). +/// See here for more info. +/// +public static class AmicableNumbersChecker { /// - /// Amicable numbers are two different natural numbers related in such a way that the sum of the proper divisors of - /// each is equal to the other number. That is, σ(a)=b+a and σ(b)=a+b, where σ(n) is equal to the sum of positive divisors of n (see also divisor function). - /// See here for more info. + /// Checks if two numbers are amicable or not. /// - public static class AmicableNumbersChecker + /// First number to check. + /// Second number to check. + /// True if they are amicable numbers. False if not. + public static bool AreAmicableNumbers(int x, int y) { - /// - /// Checks if two numbers are amicable or not. - /// - /// First number to check. - /// Second number to check. - /// True if they are amicable numbers. False if not. - public static bool AreAmicableNumbers(int x, int y) - { - return SumOfDivisors(x) == y && SumOfDivisors(y) == x; - } + return SumOfDivisors(x) == y && SumOfDivisors(y) == x; + } - private static int SumOfDivisors(int number) + private static int SumOfDivisors(int number) + { + var sum = 0; /* sum of its positive divisors */ + for (var i = 1; i < number; ++i) { - var sum = 0; /* sum of its positive divisors */ - for (var i = 1; i < number; ++i) + if (number % i == 0) { - if (number % i == 0) - { - sum += i; - } + sum += i; } - - return sum; } + + return sum; } } diff --git a/Algorithms/Numeric/AutomorphicNumber.cs b/Algorithms/Numeric/AutomorphicNumber.cs index c3bd9991..159f4988 100644 --- a/Algorithms/Numeric/AutomorphicNumber.cs +++ b/Algorithms/Numeric/AutomorphicNumber.cs @@ -3,72 +3,71 @@ using System.Linq; using System.Numerics; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// Calculates Automorphic numbers. A number is said to be an Automorphic number +/// if the square of the number will contain the number itself at the end. +/// +public static class AutomorphicNumber { /// - /// Calculates Automorphic numbers. A number is said to be an Automorphic number - /// if the square of the number will contain the number itself at the end. + /// Generates a list of automorphic numbers that are between and + /// inclusive. /// - public static class AutomorphicNumber + /// The lower bound of the list. + /// The upper bound of the list. + /// A list that contains all of the automorphic numbers between and inclusive. + /// If the + /// or is not greater than zero + /// or is lower than the . + public static IEnumerable GetAutomorphicNumbers(int lowerBound, int upperBound) { - /// - /// Generates a list of automorphic numbers that are between and - /// inclusive. - /// - /// The lower bound of the list. - /// The upper bound of the list. - /// A list that contains all of the automorphic numbers between and inclusive. - /// If the - /// or is not greater than zero - /// or is lower than the . - public static IEnumerable GetAutomorphicNumbers(int lowerBound, int upperBound) + if (lowerBound < 1) { - if (lowerBound < 1) - { - throw new ArgumentException($"Lower bound must be greater than 0."); - } - - if (upperBound < 1) - { - throw new ArgumentException($"Upper bound must be greater than 0."); - } + throw new ArgumentException($"Lower bound must be greater than 0."); + } - if (lowerBound > upperBound) - { - throw new ArgumentException($"The lower bound must be less than or equal to the upper bound."); - } + if (upperBound < 1) + { + throw new ArgumentException($"Upper bound must be greater than 0."); + } - return Enumerable.Range(lowerBound, upperBound).Where(IsAutomorphic); + if (lowerBound > upperBound) + { + throw new ArgumentException($"The lower bound must be less than or equal to the upper bound."); } - /// - /// Checks if a given natural number is automorphic or not. - /// - /// The number to check. - /// True if the number is automorphic, false otherwise. - /// If the number is non-positive. - public static bool IsAutomorphic(int number) + return Enumerable.Range(lowerBound, upperBound).Where(IsAutomorphic); + } + + /// + /// Checks if a given natural number is automorphic or not. + /// + /// The number to check. + /// True if the number is automorphic, false otherwise. + /// If the number is non-positive. + public static bool IsAutomorphic(int number) + { + if (number < 1) { - if (number < 1) - { - throw new ArgumentException($"An automorphic number must always be positive."); - } + throw new ArgumentException($"An automorphic number must always be positive."); + } - BigInteger square = BigInteger.Pow(number, 2); + BigInteger square = BigInteger.Pow(number, 2); - // Extract the last digits of both numbers - while (number > 0) + // Extract the last digits of both numbers + while (number > 0) + { + if (number % 10 != square % 10) { - if (number % 10 != square % 10) - { - return false; - } - - number /= 10; - square /= 10; + return false; } - return true; + number /= 10; + square /= 10; } + + return true; } } diff --git a/Algorithms/Numeric/BinomialCoefficient.cs b/Algorithms/Numeric/BinomialCoefficient.cs index cb61239c..e2fe6fed 100644 --- a/Algorithms/Numeric/BinomialCoefficient.cs +++ b/Algorithms/Numeric/BinomialCoefficient.cs @@ -1,49 +1,48 @@ using System; using System.Numerics; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// The binomial coefficients are the positive integers +/// that occur as coefficients in the binomial theorem. +/// +public static class BinomialCoefficient { /// - /// The binomial coefficients are the positive integers - /// that occur as coefficients in the binomial theorem. + /// Calculates Binomial coefficients for given input. /// - public static class BinomialCoefficient + /// First number. + /// Second number. + /// Binimial Coefficients. + public static BigInteger Calculate(BigInteger num, BigInteger k) { - /// - /// Calculates Binomial coefficients for given input. - /// - /// First number. - /// Second number. - /// Binimial Coefficients. - public static BigInteger Calculate(BigInteger num, BigInteger k) + if (num < k || k < 0) { - if (num < k || k < 0) - { - throw new ArgumentException("num ≥ k ≥ 0"); - } - - // Tricks to gain performance: - // 1. Because (num over k) equals (num over (num-k)), we can save multiplications and divisions - // by replacing k with the minimum of k and (num - k). - k = BigInteger.Min(k, num - k); + throw new ArgumentException("num ≥ k ≥ 0"); + } - // 2. We can simplify the computation of (num! / (k! * (num - k)!)) to ((num * (num - 1) * ... * (num - k + 1) / (k!)) - // and thus save some multiplications and divisions. - var numerator = BigInteger.One; - for (var val = num - k + 1; val <= num; val++) - { - numerator *= val; - } + // Tricks to gain performance: + // 1. Because (num over k) equals (num over (num-k)), we can save multiplications and divisions + // by replacing k with the minimum of k and (num - k). + k = BigInteger.Min(k, num - k); - // 3. Typically multiplication is a lot faster than division, therefore compute the value of k! first (i.e. k - 1 multiplications) - // and then divide the numerator by the denominator (i.e. 1 division); instead of performing k - 1 divisions (1 for each factor in k!). - var denominator = BigInteger.One; - for (var val = k; val > BigInteger.One; val--) - { - denominator *= val; - } + // 2. We can simplify the computation of (num! / (k! * (num - k)!)) to ((num * (num - 1) * ... * (num - k + 1) / (k!)) + // and thus save some multiplications and divisions. + var numerator = BigInteger.One; + for (var val = num - k + 1; val <= num; val++) + { + numerator *= val; + } - return numerator / denominator; + // 3. Typically multiplication is a lot faster than division, therefore compute the value of k! first (i.e. k - 1 multiplications) + // and then divide the numerator by the denominator (i.e. 1 division); instead of performing k - 1 divisions (1 for each factor in k!). + var denominator = BigInteger.One; + for (var val = k; val > BigInteger.One; val--) + { + denominator *= val; } + + return numerator / denominator; } } diff --git a/Algorithms/Numeric/Decomposition/LU.cs b/Algorithms/Numeric/Decomposition/LU.cs index eb369a85..8b4ccc6f 100644 --- a/Algorithms/Numeric/Decomposition/LU.cs +++ b/Algorithms/Numeric/Decomposition/LU.cs @@ -1,114 +1,113 @@ using System; -namespace Algorithms.Numeric.Decomposition +namespace Algorithms.Numeric.Decomposition; + +/// +/// LU-decomposition factors the "source" matrix as the product of lower triangular matrix +/// and upper triangular matrix. +/// +public static class Lu { /// - /// LU-decomposition factors the "source" matrix as the product of lower triangular matrix - /// and upper triangular matrix. + /// Performs LU-decomposition on "source" matrix. + /// Lower and upper matrices have same shapes as source matrix. + /// Note: Decomposition can be applied only to square matrices. /// - public static class Lu + /// Square matrix to decompose. + /// Tuple of lower and upper matrix. + /// Source matrix is not square shaped. + public static (double[,] L, double[,] U) Decompose(double[,] source) { - /// - /// Performs LU-decomposition on "source" matrix. - /// Lower and upper matrices have same shapes as source matrix. - /// Note: Decomposition can be applied only to square matrices. - /// - /// Square matrix to decompose. - /// Tuple of lower and upper matrix. - /// Source matrix is not square shaped. - public static (double[,] L, double[,] U) Decompose(double[,] source) + if (source.GetLength(0) != source.GetLength(1)) { - if (source.GetLength(0) != source.GetLength(1)) - { - throw new ArgumentException("Source matrix is not square shaped."); - } + throw new ArgumentException("Source matrix is not square shaped."); + } - var pivot = source.GetLength(0); - var lower = new double[pivot, pivot]; - var upper = new double[pivot, pivot]; + var pivot = source.GetLength(0); + var lower = new double[pivot, pivot]; + var upper = new double[pivot, pivot]; - for (var i = 0; i < pivot; i++) + for (var i = 0; i < pivot; i++) + { + for (var k = i; k < pivot; k++) { - for (var k = i; k < pivot; k++) + double sum = 0; + + for (var j = 0; j < i; j++) { - double sum = 0; + sum += lower[i, j] * upper[j, k]; + } - for (var j = 0; j < i; j++) - { - sum += lower[i, j] * upper[j, k]; - } + upper[i, k] = source[i, k] - sum; + } - upper[i, k] = source[i, k] - sum; + for (var k = i; k < pivot; k++) + { + if (i == k) + { + lower[i, i] = 1; } - - for (var k = i; k < pivot; k++) + else { - if (i == k) + double sum = 0; + + for (var j = 0; j < i; j++) { - lower[i, i] = 1; + sum += lower[k, j] * upper[j, i]; } - else - { - double sum = 0; - - for (var j = 0; j < i; j++) - { - sum += lower[k, j] * upper[j, i]; - } - lower[k, i] = (source[k, i] - sum) / upper[i, i]; - } + lower[k, i] = (source[k, i] - sum) / upper[i, i]; } } - - return (L: lower, U: upper); } - /// - /// Eliminates linear equations system represented as A*x=b, using LU-decomposition, - /// where A - matrix of equation coefficients, b - vector of absolute terms of equations. - /// - /// Matrix of equation coefficients. - /// Vector of absolute terms of equations. - /// Vector-solution for linear equations system. - /// Matrix of equation coefficients is not square shaped. - public static double[] Eliminate(double[,] matrix, double[] coefficients) - { - if (matrix.GetLength(0) != matrix.GetLength(1)) - { - throw new ArgumentException("Matrix of equation coefficients is not square shaped."); - } + return (L: lower, U: upper); + } - var pivot = matrix.GetLength(0); - var upperTransform = new double[pivot, 1]; // U * upperTransform = coefficients - var solution = new double[pivot]; // L * solution = upperTransform - (double[,] l, double[,] u) = Decompose(matrix); + /// + /// Eliminates linear equations system represented as A*x=b, using LU-decomposition, + /// where A - matrix of equation coefficients, b - vector of absolute terms of equations. + /// + /// Matrix of equation coefficients. + /// Vector of absolute terms of equations. + /// Vector-solution for linear equations system. + /// Matrix of equation coefficients is not square shaped. + public static double[] Eliminate(double[,] matrix, double[] coefficients) + { + if (matrix.GetLength(0) != matrix.GetLength(1)) + { + throw new ArgumentException("Matrix of equation coefficients is not square shaped."); + } - for (var i = 0; i < pivot; i++) - { - double pivotPointSum = 0; + var pivot = matrix.GetLength(0); + var upperTransform = new double[pivot, 1]; // U * upperTransform = coefficients + var solution = new double[pivot]; // L * solution = upperTransform + (double[,] l, double[,] u) = Decompose(matrix); - for (var j = 0; j < i; j++) - { - pivotPointSum += upperTransform[j, 0] * l[i, j]; - } + for (var i = 0; i < pivot; i++) + { + double pivotPointSum = 0; - upperTransform[i, 0] = (coefficients[i] - pivotPointSum) / l[i, i]; + for (var j = 0; j < i; j++) + { + pivotPointSum += upperTransform[j, 0] * l[i, j]; } - for (var i = pivot - 1; i >= 0; i--) - { - double pivotPointSum = 0; + upperTransform[i, 0] = (coefficients[i] - pivotPointSum) / l[i, i]; + } - for (var j = i; j < pivot; j++) - { - pivotPointSum += solution[j] * u[i, j]; - } + for (var i = pivot - 1; i >= 0; i--) + { + double pivotPointSum = 0; - solution[i] = (upperTransform[i, 0] - pivotPointSum) / u[i, i]; + for (var j = i; j < pivot; j++) + { + pivotPointSum += solution[j] * u[i, j]; } - return solution; + solution[i] = (upperTransform[i, 0] - pivotPointSum) / u[i, i]; } + + return solution; } } diff --git a/Algorithms/Numeric/Decomposition/ThinSVD.cs b/Algorithms/Numeric/Decomposition/ThinSVD.cs index 4af41275..8c07f2e6 100644 --- a/Algorithms/Numeric/Decomposition/ThinSVD.cs +++ b/Algorithms/Numeric/Decomposition/ThinSVD.cs @@ -1,145 +1,142 @@ using System; using Utilities.Extensions; -using M = Utilities.Extensions.MatrixExtensions; -using V = Utilities.Extensions.VectorExtensions; -namespace Algorithms.Numeric.Decomposition +namespace Algorithms.Numeric.Decomposition; + +/// +/// Singular Vector Decomposition decomposes any general matrix into its +/// singular values and a set of orthonormal bases. +/// +public static class ThinSvd { /// - /// Singular Vector Decomposition decomposes any general matrix into its - /// singular values and a set of orthonormal bases. + /// Computes a random unit vector. /// - public static class ThinSvd + /// The dimensions of the required vector. + /// The unit vector. + public static double[] RandomUnitVector(int dimensions) { - /// - /// Computes a random unit vector. - /// - /// The dimensions of the required vector. - /// The unit vector. - public static double[] RandomUnitVector(int dimensions) + Random random = new(); + double[] result = new double[dimensions]; + for (var i = 0; i < dimensions; i++) { - Random random = new(); - double[] result = new double[dimensions]; - for (var i = 0; i < dimensions; i++) - { - result[i] = 2 * random.NextDouble() - 1; - } - - var magnitude = result.Magnitude(); - result = result.Scale(1 / magnitude); - return result; + result[i] = 2 * random.NextDouble() - 1; } - /// - /// Computes a single singular vector for the given matrix, corresponding to the largest singular value. - /// - /// The matrix. - /// A singular vector, with dimension equal to number of columns of the matrix. - public static double[] Decompose1D(double[,] matrix) => - Decompose1D(matrix, 1E-5, 100); - - /// - /// Computes a single singular vector for the given matrix, corresponding to the largest singular value. - /// - /// The matrix. - /// The error margin. - /// The maximum number of iterations. - /// A singular vector, with dimension equal to number of columns of the matrix. - public static double[] Decompose1D(double[,] matrix, double epsilon, int maxIterations) + var magnitude = result.Magnitude(); + result = result.Scale(1 / magnitude); + return result; + } + + /// + /// Computes a single singular vector for the given matrix, corresponding to the largest singular value. + /// + /// The matrix. + /// A singular vector, with dimension equal to number of columns of the matrix. + public static double[] Decompose1D(double[,] matrix) => + Decompose1D(matrix, 1E-5, 100); + + /// + /// Computes a single singular vector for the given matrix, corresponding to the largest singular value. + /// + /// The matrix. + /// The error margin. + /// The maximum number of iterations. + /// A singular vector, with dimension equal to number of columns of the matrix. + public static double[] Decompose1D(double[,] matrix, double epsilon, int maxIterations) + { + var n = matrix.GetLength(1); + var iterations = 0; + double mag; + double[] lastIteration; + double[] currIteration = RandomUnitVector(n); + double[,] b = matrix.Transpose().Multiply(matrix); + do { - var n = matrix.GetLength(1); - var iterations = 0; - double mag; - double[] lastIteration; - double[] currIteration = RandomUnitVector(n); - double[,] b = matrix.Transpose().Multiply(matrix); - do + lastIteration = currIteration.Copy(); + currIteration = b.MultiplyVector(lastIteration); + currIteration = currIteration.Scale(100); + mag = currIteration.Magnitude(); + if (mag > epsilon) { - lastIteration = currIteration.Copy(); - currIteration = b.MultiplyVector(lastIteration); - currIteration = currIteration.Scale(100); - mag = currIteration.Magnitude(); - if (mag > epsilon) - { - currIteration = currIteration.Scale(1 / mag); - } - - iterations++; + currIteration = currIteration.Scale(1 / mag); } - while (lastIteration.Dot(currIteration) < 1 - epsilon && iterations < maxIterations); - return currIteration; + iterations++; } + while (lastIteration.Dot(currIteration) < 1 - epsilon && iterations < maxIterations); - public static (double[,] U, double[] S, double[,] V) Decompose(double[,] matrix) => - Decompose(matrix, 1E-5, 100); - - /// - /// Computes the SVD for the given matrix, with singular values arranged from greatest to least. - /// - /// The matrix. - /// The error margin. - /// The maximum number of iterations. - /// The SVD. - public static (double[,] U, double[] S, double[,] V) Decompose( - double[,] matrix, - double epsilon, - int maxIterations) + return currIteration; + } + + public static (double[,] U, double[] S, double[,] V) Decompose(double[,] matrix) => + Decompose(matrix, 1E-5, 100); + + /// + /// Computes the SVD for the given matrix, with singular values arranged from greatest to least. + /// + /// The matrix. + /// The error margin. + /// The maximum number of iterations. + /// The SVD. + public static (double[,] U, double[] S, double[,] V) Decompose( + double[,] matrix, + double epsilon, + int maxIterations) + { + var m = matrix.GetLength(0); + var n = matrix.GetLength(1); + var numValues = Math.Min(m, n); + + // sigmas is be a diagonal matrix, hence only a vector is needed + double[] sigmas = new double[numValues]; + double[,] us = new double[m, numValues]; + double[,] vs = new double[n, numValues]; + + // keep track of progress + double[,] remaining = matrix.Copy(); + + // for each singular value + for (var i = 0; i < numValues; i++) { - var m = matrix.GetLength(0); - var n = matrix.GetLength(1); - var numValues = Math.Min(m, n); + // compute the v singular vector + double[] v = Decompose1D(remaining, epsilon, maxIterations); + double[] u = matrix.MultiplyVector(v); - // sigmas is be a diagonal matrix, hence only a vector is needed - double[] sigmas = new double[numValues]; - double[,] us = new double[m, numValues]; - double[,] vs = new double[n, numValues]; + // compute the contribution of this pair of singular vectors + double[,] contrib = u.OuterProduct(v); - // keep track of progress - double[,] remaining = matrix.Copy(); + // extract the singular value + var s = u.Magnitude(); - // for each singular value - for (var i = 0; i < numValues; i++) + // v and u should be unit vectors + if (s < epsilon) + { + u = new double[m]; + v = new double[n]; + } + else { - // compute the v singular vector - double[] v = Decompose1D(remaining, epsilon, maxIterations); - double[] u = matrix.MultiplyVector(v); - - // compute the contribution of this pair of singular vectors - double[,] contrib = u.OuterProduct(v); - - // extract the singular value - var s = u.Magnitude(); - - // v and u should be unit vectors - if (s < epsilon) - { - u = new double[m]; - v = new double[n]; - } - else - { - u = u.Scale(1 / s); - } - - // save u, v and s into the result - for (var j = 0; j < u.Length; j++) - { - us[j, i] = u[j]; - } - - for (var j = 0; j < v.Length; j++) - { - vs[j, i] = v[j]; - } - - sigmas[i] = s; - - // remove the contribution of this pair and compute the rest - remaining = remaining.Subtract(contrib); + u = u.Scale(1 / s); } - return (U: us, S: sigmas, V: vs); + // save u, v and s into the result + for (var j = 0; j < u.Length; j++) + { + us[j, i] = u[j]; + } + + for (var j = 0; j < v.Length; j++) + { + vs[j, i] = v[j]; + } + + sigmas[i] = s; + + // remove the contribution of this pair and compute the rest + remaining = remaining.Subtract(contrib); } + + return (U: us, S: sigmas, V: vs); } } diff --git a/Algorithms/Numeric/EulerMethod.cs b/Algorithms/Numeric/EulerMethod.cs index 043fd26f..20112c2b 100644 --- a/Algorithms/Numeric/EulerMethod.cs +++ b/Algorithms/Numeric/EulerMethod.cs @@ -1,85 +1,84 @@ using System; using System.Collections.Generic; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// In mathematics and computational science, the Euler method (also called forward Euler method) +/// is a first-order numerical procedure for solving ordinary differential equations (ODEs) +/// with a given initial value (aka. Cauchy problem). It is the most basic explicit method for numerical integration +/// of ordinary differential equations. The method proceeds in a series of steps. At each step +/// the y-value is calculated by evaluating the differential equation at the previous step, +/// multiplying the result with the step-size and adding it to the last y-value: +/// y_n+1 = y_n + stepSize * f(x_n, y_n). +/// (description adapted from https://en.wikipedia.org/wiki/Euler_method ) +/// (see also: https://www.geeksforgeeks.org/euler-method-solving-differential-equation/ ). +/// +public static class EulerMethod { /// - /// In mathematics and computational science, the Euler method (also called forward Euler method) - /// is a first-order numerical procedure for solving ordinary differential equations (ODEs) - /// with a given initial value (aka. Cauchy problem). It is the most basic explicit method for numerical integration - /// of ordinary differential equations. The method proceeds in a series of steps. At each step - /// the y-value is calculated by evaluating the differential equation at the previous step, - /// multiplying the result with the step-size and adding it to the last y-value: - /// y_n+1 = y_n + stepSize * f(x_n, y_n). - /// (description adapted from https://en.wikipedia.org/wiki/Euler_method ) - /// (see also: https://www.geeksforgeeks.org/euler-method-solving-differential-equation/ ). + /// Loops through all the steps until xEnd is reached, adds a point for each step and then + /// returns all the points. /// - public static class EulerMethod + /// Initial conditions x-value. + /// Last x-value. + /// Step-size on the x-axis. + /// Initial conditions y-value. + /// The right hand side of the differential equation. + /// The solution of the Cauchy problem. + public static List EulerFull( + double xStart, + double xEnd, + double stepSize, + double yStart, + Func yDerivative) { - /// - /// Loops through all the steps until xEnd is reached, adds a point for each step and then - /// returns all the points. - /// - /// Initial conditions x-value. - /// Last x-value. - /// Step-size on the x-axis. - /// Initial conditions y-value. - /// The right hand side of the differential equation. - /// The solution of the Cauchy problem. - public static List EulerFull( - double xStart, - double xEnd, - double stepSize, - double yStart, - Func yDerivative) + if (xStart >= xEnd) { - if (xStart >= xEnd) - { - throw new ArgumentOutOfRangeException( - nameof(xEnd), - $"{nameof(xEnd)} should be greater than {nameof(xStart)}"); - } - - if (stepSize <= 0) - { - throw new ArgumentOutOfRangeException( - nameof(stepSize), - $"{nameof(stepSize)} should be greater than zero"); - } - - List points = new(); - double[] firstPoint = { xStart, yStart }; - points.Add(firstPoint); - var yCurrent = yStart; - var xCurrent = xStart; - - while (xCurrent < xEnd) - { - yCurrent = EulerStep(xCurrent, stepSize, yCurrent, yDerivative); - xCurrent += stepSize; - double[] point = { xCurrent, yCurrent }; - points.Add(point); - } + throw new ArgumentOutOfRangeException( + nameof(xEnd), + $"{nameof(xEnd)} should be greater than {nameof(xStart)}"); + } - return points; + if (stepSize <= 0) + { + throw new ArgumentOutOfRangeException( + nameof(stepSize), + $"{nameof(stepSize)} should be greater than zero"); } - /// - /// Calculates the next y-value based on the current value of x, y and the stepSize. - /// - /// Current x-value. - /// Step-size on the x-axis. - /// Current y-value. - /// The right hand side of the differential equation. - /// The next y-value. - private static double EulerStep( - double xCurrent, - double stepSize, - double yCurrent, - Func yDerivative) + List points = new(); + double[] firstPoint = { xStart, yStart }; + points.Add(firstPoint); + var yCurrent = yStart; + var xCurrent = xStart; + + while (xCurrent < xEnd) { - var yNext = yCurrent + stepSize * yDerivative(xCurrent, yCurrent); - return yNext; + yCurrent = EulerStep(xCurrent, stepSize, yCurrent, yDerivative); + xCurrent += stepSize; + double[] point = { xCurrent, yCurrent }; + points.Add(point); } + + return points; + } + + /// + /// Calculates the next y-value based on the current value of x, y and the stepSize. + /// + /// Current x-value. + /// Step-size on the x-axis. + /// Current y-value. + /// The right hand side of the differential equation. + /// The next y-value. + private static double EulerStep( + double xCurrent, + double stepSize, + double yCurrent, + Func yDerivative) + { + var yNext = yCurrent + stepSize * yDerivative(xCurrent, yCurrent); + return yNext; } } diff --git a/Algorithms/Numeric/Factorial.cs b/Algorithms/Numeric/Factorial.cs index 845a92ea..6c30f50e 100644 --- a/Algorithms/Numeric/Factorial.cs +++ b/Algorithms/Numeric/Factorial.cs @@ -1,39 +1,38 @@ -using System; +using System; using System.Numerics; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// The factorial of a positive integer n, denoted by n!, +/// is the product of all positive integers less than or equal to n. +/// +public static class Factorial { /// - /// The factorial of a positive integer n, denoted by n!, - /// is the product of all positive integers less than or equal to n. + /// Calculates factorial of a integer number. /// - public static class Factorial + /// Integer Input number. + /// Factorial of integer input number. + public static BigInteger Calculate(int inputNum) { - /// - /// Calculates factorial of a integer number. - /// - /// Integer Input number. - /// Factorial of integer input number. - public static BigInteger Calculate(int inputNum) - { - // Convert integer input to BigInteger - BigInteger num = new BigInteger(inputNum); + // Convert integer input to BigInteger + BigInteger num = new BigInteger(inputNum); - // Don't calculate factorial if input is a negative number. - if (BigInteger.Compare(num, BigInteger.Zero) < 0) - { - throw new ArgumentException("Only for num >= 0"); - } - - // Factorial of numbers greater than 0. - BigInteger result = BigInteger.One; + // Don't calculate factorial if input is a negative number. + if (BigInteger.Compare(num, BigInteger.Zero) < 0) + { + throw new ArgumentException("Only for num >= 0"); + } - for (BigInteger i = BigInteger.One; BigInteger.Compare(i, num) <= 0; i = BigInteger.Add(i, BigInteger.One)) - { - result = BigInteger.Multiply(result, i); - } + // Factorial of numbers greater than 0. + BigInteger result = BigInteger.One; - return result; + for (BigInteger i = BigInteger.One; BigInteger.Compare(i, num) <= 0; i = BigInteger.Add(i, BigInteger.One)) + { + result = BigInteger.Multiply(result, i); } + + return result; } } diff --git a/Algorithms/Numeric/Factorization/IFactorizer.cs b/Algorithms/Numeric/Factorization/IFactorizer.cs index dcce13d6..4a45f86e 100755 --- a/Algorithms/Numeric/Factorization/IFactorizer.cs +++ b/Algorithms/Numeric/Factorization/IFactorizer.cs @@ -1,16 +1,15 @@ -namespace Algorithms.Numeric.Factorization +namespace Algorithms.Numeric.Factorization; + +/// +/// Finds a factor of a given number or returns false if it's prime. +/// +public interface IFactorizer { /// /// Finds a factor of a given number or returns false if it's prime. /// - public interface IFactorizer - { - /// - /// Finds a factor of a given number or returns false if it's prime. - /// - /// Integer to factor. - /// Found factor. - /// if factor is found, if is prime. - bool TryFactor(int n, out int factor); - } + /// Integer to factor. + /// Found factor. + /// if factor is found, if is prime. + bool TryFactor(int n, out int factor); } diff --git a/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs b/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs index 43820e24..f105fd6d 100755 --- a/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs +++ b/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs @@ -1,24 +1,23 @@ using System; using System.Linq; -namespace Algorithms.Numeric.Factorization +namespace Algorithms.Numeric.Factorization; + +/// +/// Factors number using trial division algorithm. +/// +public class TrialDivisionFactorizer : IFactorizer { /// - /// Factors number using trial division algorithm. + /// Finds the smallest non trivial factor (i.e.: 1 < factor <= sqrt()) of a given number or returns false if it's prime. /// - public class TrialDivisionFactorizer : IFactorizer + /// Integer to factor. + /// Found factor. + /// if factor is found, if is prime. + public bool TryFactor(int n, out int factor) { - /// - /// Finds the smallest non trivial factor (i.e.: 1 < factor <= sqrt()) of a given number or returns false if it's prime. - /// - /// Integer to factor. - /// Found factor. - /// if factor is found, if is prime. - public bool TryFactor(int n, out int factor) - { - n = Math.Abs(n); - factor = Enumerable.Range(2, (int)Math.Sqrt(n) - 1).FirstOrDefault(i => n % i == 0); - return factor != 0; - } + n = Math.Abs(n); + factor = Enumerable.Range(2, (int)Math.Sqrt(n) - 1).FirstOrDefault(i => n % i == 0); + return factor != 0; } } diff --git a/Algorithms/Numeric/GaussJordanElimination.cs b/Algorithms/Numeric/GaussJordanElimination.cs index 27a54dd8..3ef7969b 100644 --- a/Algorithms/Numeric/GaussJordanElimination.cs +++ b/Algorithms/Numeric/GaussJordanElimination.cs @@ -1,153 +1,152 @@ -using System; +using System; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// Algorithm used to find the inverse of any matrix that can be inverted. +/// +public class GaussJordanElimination { + private int RowCount { get; set; } + /// - /// Algorithm used to find the inverse of any matrix that can be inverted. + /// Method to find a linear equation system using gaussian elimination. /// - public class GaussJordanElimination + /// The key matrix to solve via algorithm. + /// + /// whether the input matrix has a unique solution or not. + /// and solves on the given matrix. + /// + public bool Solve(double[,] matrix) { - private int RowCount { get; set; } - - /// - /// Method to find a linear equation system using gaussian elimination. - /// - /// The key matrix to solve via algorithm. - /// - /// whether the input matrix has a unique solution or not. - /// and solves on the given matrix. - /// - public bool Solve(double[,] matrix) + RowCount = matrix.GetUpperBound(0) + 1; + + if (!CanMatrixBeUsed(matrix)) { - RowCount = matrix.GetUpperBound(0) + 1; + throw new ArgumentException("Please use a n*(n+1) matrix with Length > 0."); + } - if (!CanMatrixBeUsed(matrix)) - { - throw new ArgumentException("Please use a n*(n+1) matrix with Length > 0."); - } + var pivot = PivotMatrix(ref matrix); + if (!pivot) + { + return false; + } - var pivot = PivotMatrix(ref matrix); - if (!pivot) - { - return false; - } + Elimination(ref matrix); - Elimination(ref matrix); + return ElementaryReduction(ref matrix); + } - return ElementaryReduction(ref matrix); - } + /// + /// To make simple validation of the matrix to be used. + /// + /// Multidimensional array matrix. + /// + /// True: if algorithm can be use for given matrix; + /// False: Otherwise. + /// + private bool CanMatrixBeUsed(double[,] matrix) => matrix?.Length == RowCount * (RowCount + 1) && RowCount > 1; - /// - /// To make simple validation of the matrix to be used. - /// - /// Multidimensional array matrix. - /// - /// True: if algorithm can be use for given matrix; - /// False: Otherwise. - /// - private bool CanMatrixBeUsed(double[,] matrix) => matrix?.Length == RowCount * (RowCount + 1) && RowCount > 1; - - /// - /// To prepare given matrix by pivoting rows. - /// - /// Input matrix. - /// Matrix. - private bool PivotMatrix(ref double[,] matrix) + /// + /// To prepare given matrix by pivoting rows. + /// + /// Input matrix. + /// Matrix. + private bool PivotMatrix(ref double[,] matrix) + { + for (var col = 0; col + 1 < RowCount; col++) { - for (var col = 0; col + 1 < RowCount; col++) + if (matrix[col, col] == 0) { - if (matrix[col, col] == 0) - { - // To find a non-zero coefficient - var rowToSwap = FindNonZeroCoefficient(ref matrix, col); + // To find a non-zero coefficient + var rowToSwap = FindNonZeroCoefficient(ref matrix, col); - if (matrix[rowToSwap, col] != 0) - { - var tmp = new double[RowCount + 1]; - for (var i = 0; i < RowCount + 1; i++) - { - // To make the swap with the element above. - tmp[i] = matrix[rowToSwap, i]; - matrix[rowToSwap, i] = matrix[col, i]; - matrix[col, i] = tmp[i]; - } - } - else + if (matrix[rowToSwap, col] != 0) + { + var tmp = new double[RowCount + 1]; + for (var i = 0; i < RowCount + 1; i++) { - // To return that the matrix doesn't have a unique solution. - return false; + // To make the swap with the element above. + tmp[i] = matrix[rowToSwap, i]; + matrix[rowToSwap, i] = matrix[col, i]; + matrix[col, i] = tmp[i]; } } + else + { + // To return that the matrix doesn't have a unique solution. + return false; + } } - - return true; } - private int FindNonZeroCoefficient(ref double[,] matrix, int col) - { - var rowToSwap = col + 1; + return true; + } - // To find a non-zero coefficient - for (; rowToSwap < RowCount; rowToSwap++) + private int FindNonZeroCoefficient(ref double[,] matrix, int col) + { + var rowToSwap = col + 1; + + // To find a non-zero coefficient + for (; rowToSwap < RowCount; rowToSwap++) + { + if (matrix[rowToSwap, col] != 0) { - if (matrix[rowToSwap, col] != 0) - { - return rowToSwap; - } + return rowToSwap; } - - return col + 1; } - /// - /// Applies REF. - /// - /// Input matrix. - private void Elimination(ref double[,] matrix) + return col + 1; + } + + /// + /// Applies REF. + /// + /// Input matrix. + private void Elimination(ref double[,] matrix) + { + for (var srcRow = 0; srcRow + 1 < RowCount; srcRow++) { - for (var srcRow = 0; srcRow + 1 < RowCount; srcRow++) + for (var destRow = srcRow + 1; destRow < RowCount; destRow++) { - for (var destRow = srcRow + 1; destRow < RowCount; destRow++) - { - var df = matrix[srcRow, srcRow]; - var sf = matrix[destRow, srcRow]; + var df = matrix[srcRow, srcRow]; + var sf = matrix[destRow, srcRow]; - for (var i = 0; i < RowCount + 1; i++) - { - matrix[destRow, i] = matrix[destRow, i] * df - matrix[srcRow, i] * sf; - } + for (var i = 0; i < RowCount + 1; i++) + { + matrix[destRow, i] = matrix[destRow, i] * df - matrix[srcRow, i] * sf; } } } + } - /// - /// To continue reducing the matrix using RREF. - /// - /// Input matrix. - /// True if it has a unique solution; false otherwise. - private bool ElementaryReduction(ref double[,] matrix) + /// + /// To continue reducing the matrix using RREF. + /// + /// Input matrix. + /// True if it has a unique solution; false otherwise. + private bool ElementaryReduction(ref double[,] matrix) + { + for (var row = RowCount - 1; row >= 0; row--) { - for (var row = RowCount - 1; row >= 0; row--) + var element = matrix[row, row]; + if (element == 0) { - var element = matrix[row, row]; - if (element == 0) - { - return false; - } - - for (var i = 0; i < RowCount + 1; i++) - { - matrix[row, i] /= element; - } + return false; + } - for (var destRow = 0; destRow < row; destRow++) - { - matrix[destRow, RowCount] -= matrix[destRow, row] * matrix[row, RowCount]; - matrix[destRow, row] = 0; - } + for (var i = 0; i < RowCount + 1; i++) + { + matrix[row, i] /= element; } - return true; + for (var destRow = 0; destRow < row; destRow++) + { + matrix[destRow, RowCount] -= matrix[destRow, row] * matrix[row, RowCount]; + matrix[destRow, row] = 0; + } } + + return true; } } diff --git a/Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs b/Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs index 935488d2..691a855a 100644 --- a/Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs +++ b/Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs @@ -1,71 +1,70 @@ using System; -namespace Algorithms.Numeric.GreatestCommonDivisor +namespace Algorithms.Numeric.GreatestCommonDivisor; + +/// +/// Finds greatest common divisor for numbers u and v +/// using binary algorithm. +/// Wiki: https://en.wikipedia.org/wiki/Binary_GCD_algorithm. +/// +public class BinaryGreatestCommonDivisorFinder : IGreatestCommonDivisorFinder { - /// - /// Finds greatest common divisor for numbers u and v - /// using binary algorithm. - /// Wiki: https://en.wikipedia.org/wiki/Binary_GCD_algorithm. - /// - public class BinaryGreatestCommonDivisorFinder : IGreatestCommonDivisorFinder + public int FindGcd(int u, int v) { - public int FindGcd(int u, int v) + // GCD(0, 0) = 0 + if (u == 0 && v == 0) { - // GCD(0, 0) = 0 - if (u == 0 && v == 0) - { - return 0; - } + return 0; + } - // GCD(0, v) = v; GCD(u, 0) = u - if (u == 0 || v == 0) - { - return u + v; - } + // GCD(0, v) = v; GCD(u, 0) = u + if (u == 0 || v == 0) + { + return u + v; + } - // GCD(-a, -b) = GCD(-a, b) = GCD(a, -b) = GCD(a, b) - u = Math.Sign(u) * u; - v = Math.Sign(v) * v; + // GCD(-a, -b) = GCD(-a, b) = GCD(a, -b) = GCD(a, b) + u = Math.Sign(u) * u; + v = Math.Sign(v) * v; - // Let shift := lg K, where K is the greatest power of 2 dividing both u and v - var shift = 0; - while (((u | v) & 1) == 0) - { - u >>= 1; - v >>= 1; - shift++; - } + // Let shift := lg K, where K is the greatest power of 2 dividing both u and v + var shift = 0; + while (((u | v) & 1) == 0) + { + u >>= 1; + v >>= 1; + shift++; + } + + while ((u & 1) == 0) + { + u >>= 1; + } - while ((u & 1) == 0) + // From here on, u is always odd + do + { + // Remove all factors of 2 in v as they are not common + // v is not zero, so while will terminate + while ((v & 1) == 0) { - u >>= 1; + v >>= 1; } - // From here on, u is always odd - do + // Now u and v are both odd. Swap if necessary so u <= v, + if (u > v) { - // Remove all factors of 2 in v as they are not common - // v is not zero, so while will terminate - while ((v & 1) == 0) - { - v >>= 1; - } - - // Now u and v are both odd. Swap if necessary so u <= v, - if (u > v) - { - var t = v; - v = u; - u = t; - } - - // Here v >= u and v - u is even - v -= u; + var t = v; + v = u; + u = t; } - while (v != 0); - // Restore common factors of 2 - return u << shift; + // Here v >= u and v - u is even + v -= u; } + while (v != 0); + + // Restore common factors of 2 + return u << shift; } } diff --git a/Algorithms/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinder.cs b/Algorithms/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinder.cs index fdbdafdf..df93caf9 100644 --- a/Algorithms/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinder.cs +++ b/Algorithms/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinder.cs @@ -1,41 +1,40 @@ -namespace Algorithms.Numeric.GreatestCommonDivisor +namespace Algorithms.Numeric.GreatestCommonDivisor; + +/// +/// TODO. +/// +public class EuclideanGreatestCommonDivisorFinder : IGreatestCommonDivisorFinder { /// - /// TODO. + /// Finds greatest common divisor for numbers a and b + /// using euclidean algorithm. /// - public class EuclideanGreatestCommonDivisorFinder : IGreatestCommonDivisorFinder + /// TODO. + /// TODO. 2. + /// Greatest common divisor. + public int FindGcd(int a, int b) { - /// - /// Finds greatest common divisor for numbers a and b - /// using euclidean algorithm. - /// - /// TODO. - /// TODO. 2. - /// Greatest common divisor. - public int FindGcd(int a, int b) + if (a == 0 && b == 0) { - if (a == 0 && b == 0) - { - return int.MaxValue; - } - - if (a == 0 || b == 0) - { - return a + b; - } + return int.MaxValue; + } - var aa = a; - var bb = b; - var cc = aa % bb; + if (a == 0 || b == 0) + { + return a + b; + } - while (cc != 0) - { - aa = bb; - bb = cc; - cc = aa % bb; - } + var aa = a; + var bb = b; + var cc = aa % bb; - return bb; + while (cc != 0) + { + aa = bb; + bb = cc; + cc = aa % bb; } + + return bb; } } diff --git a/Algorithms/Numeric/GreatestCommonDivisor/IGreatestCommonDivisorFinder.cs b/Algorithms/Numeric/GreatestCommonDivisor/IGreatestCommonDivisorFinder.cs index f0e40e61..49fa8ed5 100644 --- a/Algorithms/Numeric/GreatestCommonDivisor/IGreatestCommonDivisorFinder.cs +++ b/Algorithms/Numeric/GreatestCommonDivisor/IGreatestCommonDivisorFinder.cs @@ -1,7 +1,6 @@ -namespace Algorithms.Numeric.GreatestCommonDivisor +namespace Algorithms.Numeric.GreatestCommonDivisor; + +public interface IGreatestCommonDivisorFinder { - public interface IGreatestCommonDivisorFinder - { - int FindGcd(int a, int b); - } + int FindGcd(int a, int b); } diff --git a/Algorithms/Numeric/KeithNumberChecker.cs b/Algorithms/Numeric/KeithNumberChecker.cs index 92be23a5..e1a91f93 100644 --- a/Algorithms/Numeric/KeithNumberChecker.cs +++ b/Algorithms/Numeric/KeithNumberChecker.cs @@ -1,57 +1,56 @@ using System; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// In number theory, a Keith number or repfigit number is a natural number n in a given number base b with k digits such that +/// when a sequence is created such that the first k terms are the k digits of n and each subsequent term is the sum of the +/// previous k terms, n is part of the sequence. +/// +public static class KeithNumberChecker { /// - /// In number theory, a Keith number or repfigit number is a natural number n in a given number base b with k digits such that - /// when a sequence is created such that the first k terms are the k digits of n and each subsequent term is the sum of the - /// previous k terms, n is part of the sequence. + /// Checks if a number is a Keith number or not. /// - public static class KeithNumberChecker + /// Number to check. + /// True if it is a Keith number; False otherwise. + public static bool IsKeithNumber(int number) { - /// - /// Checks if a number is a Keith number or not. - /// - /// Number to check. - /// True if it is a Keith number; False otherwise. - public static bool IsKeithNumber(int number) + if (number < 0) { - if (number < 0) - { - throw new ArgumentException($"{nameof(number)} cannot be negative"); - } - - var tempNumber = number; + throw new ArgumentException($"{nameof(number)} cannot be negative"); + } - var stringNumber = number.ToString(); + var tempNumber = number; - var digitsInNumber = stringNumber.Length; + var stringNumber = number.ToString(); - /* storing the terms of the series */ - var termsArray = new int[number]; + var digitsInNumber = stringNumber.Length; - for (var i = digitsInNumber - 1; i >= 0; i--) - { - termsArray[i] = tempNumber % 10; - tempNumber /= 10; - } + /* storing the terms of the series */ + var termsArray = new int[number]; - var sum = 0; - var k = digitsInNumber; - while (sum < number) - { - sum = 0; + for (var i = digitsInNumber - 1; i >= 0; i--) + { + termsArray[i] = tempNumber % 10; + tempNumber /= 10; + } - for (var j = 1; j <= digitsInNumber; j++) - { - sum += termsArray[k - j]; - } + var sum = 0; + var k = digitsInNumber; + while (sum < number) + { + sum = 0; - termsArray[k] = sum; - k++; + for (var j = 1; j <= digitsInNumber; j++) + { + sum += termsArray[k - j]; } - return sum == number; + termsArray[k] = sum; + k++; } + + return sum == number; } } diff --git a/Algorithms/Numeric/KrishnamurthyNumberChecker.cs b/Algorithms/Numeric/KrishnamurthyNumberChecker.cs index 95a199e0..c4d245a0 100644 --- a/Algorithms/Numeric/KrishnamurthyNumberChecker.cs +++ b/Algorithms/Numeric/KrishnamurthyNumberChecker.cs @@ -1,38 +1,37 @@ using System; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// A Krishnamurthy number is a number whose sum of the factorial of digits +/// is equal to the number itself. +/// +/// For example, 145 is a Krishnamurthy number since: 1! + 4! + 5! = 1 + 24 + 120 = 145. +/// +public static class KrishnamurthyNumberChecker { /// - /// A Krishnamurthy number is a number whose sum of the factorial of digits - /// is equal to the number itself. - /// - /// For example, 145 is a Krishnamurthy number since: 1! + 4! + 5! = 1 + 24 + 120 = 145. + /// Check if a number is Krishnamurthy number or not. /// - public static class KrishnamurthyNumberChecker + /// The number to check. + /// True if the number is Krishnamurthy, false otherwise. + public static bool IsKMurthyNumber(int n) { - /// - /// Check if a number is Krishnamurthy number or not. - /// - /// The number to check. - /// True if the number is Krishnamurthy, false otherwise. - public static bool IsKMurthyNumber(int n) - { - int sumOfFactorials = 0; - int tmp = n; + int sumOfFactorials = 0; + int tmp = n; - if (n <= 0) - { - return false; - } - - while (n != 0) - { - int factorial = (int)Factorial.Calculate(n % 10); - sumOfFactorials += factorial; - n = n / 10; - } + if (n <= 0) + { + return false; + } - return tmp == sumOfFactorials; + while (n != 0) + { + int factorial = (int)Factorial.Calculate(n % 10); + sumOfFactorials += factorial; + n = n / 10; } + + return tmp == sumOfFactorials; } } diff --git a/Algorithms/Numeric/MillerRabinPrimalityChecker.cs b/Algorithms/Numeric/MillerRabinPrimalityChecker.cs index b458888a..0850a43c 100644 --- a/Algorithms/Numeric/MillerRabinPrimalityChecker.cs +++ b/Algorithms/Numeric/MillerRabinPrimalityChecker.cs @@ -1,84 +1,83 @@ using System; using System.Numerics; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// https://en.wikipedia.org/wiki/Miller-Rabin_primality_test +/// The Miller–Rabin primality test or Rabin–Miller primality test is a probabilistic primality test: +/// an algorithm which determines whether a given number is likely to be prime, +/// similar to the Fermat primality test and the Solovay–Strassen primality test. +/// It is of historical significance in the search for a polynomial-time deterministic primality test. +/// Its probabilistic variant remains widely used in practice, as one of the simplest and fastest tests known. +/// +public static class MillerRabinPrimalityChecker { /// - /// https://en.wikipedia.org/wiki/Miller-Rabin_primality_test - /// The Miller–Rabin primality test or Rabin–Miller primality test is a probabilistic primality test: - /// an algorithm which determines whether a given number is likely to be prime, - /// similar to the Fermat primality test and the Solovay–Strassen primality test. - /// It is of historical significance in the search for a polynomial-time deterministic primality test. - /// Its probabilistic variant remains widely used in practice, as one of the simplest and fastest tests known. - /// - public static class MillerRabinPrimalityChecker + /// Run the probabilistic primality test. + /// + /// Number to check. + /// Number of rounds, the parameter determines the accuracy of the test, recommended value is Log2(n). + /// Seed for random number generator. + /// True if is a highly likely prime number; False otherwise. + /// Error: number should be more than 3. + public static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds, int? seed = null) + { + Random rand = seed is null + ? new() + : new(seed.Value); + return IsProbablyPrimeNumber(n, rounds, rand); + } + + private static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds, Random rand) { - /// - /// Run the probabilistic primality test. - /// - /// Number to check. - /// Number of rounds, the parameter determines the accuracy of the test, recommended value is Log2(n). - /// Seed for random number generator. - /// True if is a highly likely prime number; False otherwise. - /// Error: number should be more than 3. - public static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds, int? seed = null) + if (n <= 3) { - Random rand = seed is null - ? new() - : new(seed.Value); - return IsProbablyPrimeNumber(n, rounds, rand); + throw new ArgumentException($"{nameof(n)} should be more than 3"); } - private static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds, Random rand) + // Input #1: n > 3, an odd integer to be tested for primality + // Input #2: k, the number of rounds of testing to perform, recommended k = Log2(n) + // Output: false = “composite” + // true = “probably prime” + + // write n as 2r·d + 1 with d odd(by factoring out powers of 2 from n − 1) + BigInteger r = 0; + BigInteger d = n - 1; + while (d % 2 == 0) { - if (n <= 3) - { - throw new ArgumentException($"{nameof(n)} should be more than 3"); - } + r++; + d /= 2; + } - // Input #1: n > 3, an odd integer to be tested for primality - // Input #2: k, the number of rounds of testing to perform, recommended k = Log2(n) - // Output: false = “composite” - // true = “probably prime” + // as there is no native random function for BigInteger we suppose a random int number is sufficient + int nMaxValue = (n > int.MaxValue) ? int.MaxValue : (int)n; + BigInteger a = rand.Next(2, nMaxValue - 2); // ; pick a random integer a in the range[2, n − 2] - // write n as 2r·d + 1 with d odd(by factoring out powers of 2 from n − 1) - BigInteger r = 0; - BigInteger d = n - 1; - while (d % 2 == 0) + while (rounds > 0) + { + rounds--; + var x = BigInteger.ModPow(a, d, n); + if (x == 1 || x == (n - 1)) { - r++; - d /= 2; + continue; } - // as there is no native random function for BigInteger we suppose a random int number is sufficient - int nMaxValue = (n > int.MaxValue) ? int.MaxValue : (int)n; - BigInteger a = rand.Next(2, nMaxValue - 2); // ; pick a random integer a in the range[2, n − 2] - - while (rounds > 0) + BigInteger tempr = r - 1; + while (tempr > 0 && (x != n - 1)) { - rounds--; - var x = BigInteger.ModPow(a, d, n); - if (x == 1 || x == (n - 1)) - { - continue; - } - - BigInteger tempr = r - 1; - while (tempr > 0 && (x != n - 1)) - { - tempr--; - x = BigInteger.ModPow(x, 2, n); - } - - if (x == n - 1) - { - continue; - } + tempr--; + x = BigInteger.ModPow(x, 2, n); + } - return false; + if (x == n - 1) + { + continue; } - return true; + return false; } + + return true; } } diff --git a/Algorithms/Numeric/ModularExponentiation.cs b/Algorithms/Numeric/ModularExponentiation.cs index 30c09b28..c7f4f2e9 100644 --- a/Algorithms/Numeric/ModularExponentiation.cs +++ b/Algorithms/Numeric/ModularExponentiation.cs @@ -1,43 +1,42 @@ using System; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// Modular exponentiation is a type of exponentiation performed over a modulus +/// Modular exponentiation c is: c = b^e mod m where b is base, e is exponent, m is modulus +/// (Wiki: https://en.wikipedia.org/wiki/Modular_exponentiation). +/// +public class ModularExponentiation { /// - /// Modular exponentiation is a type of exponentiation performed over a modulus - /// Modular exponentiation c is: c = b^e mod m where b is base, e is exponent, m is modulus - /// (Wiki: https://en.wikipedia.org/wiki/Modular_exponentiation). + /// Performs Modular Exponentiation on b, e, m. /// - public class ModularExponentiation + /// Base. + /// Exponent. + /// Modulus. + /// Modular Exponential. + public int ModularPow(int b, int e, int m) { - /// - /// Performs Modular Exponentiation on b, e, m. - /// - /// Base. - /// Exponent. - /// Modulus. - /// Modular Exponential. - public int ModularPow(int b, int e, int m) + // initialize result in variable res + int res = 1; + if (m == 1) { - // initialize result in variable res - int res = 1; - if (m == 1) - { - // 1 divides every number - return 0; - } - - if (m <= 0) - { - // exponential not defined in this case - throw new ArgumentException(string.Format("{0} is not a positive integer", m)); - } + // 1 divides every number + return 0; + } - for (int i = 0; i < e; i++) - { - res = (res * b) % m; - } + if (m <= 0) + { + // exponential not defined in this case + throw new ArgumentException(string.Format("{0} is not a positive integer", m)); + } - return res; + for (int i = 0; i < e; i++) + { + res = (res * b) % m; } + + return res; } } diff --git a/Algorithms/Numeric/NarcissisticNumberChecker.cs b/Algorithms/Numeric/NarcissisticNumberChecker.cs index 17e13960..4e6283d8 100644 --- a/Algorithms/Numeric/NarcissisticNumberChecker.cs +++ b/Algorithms/Numeric/NarcissisticNumberChecker.cs @@ -1,40 +1,39 @@ -using System; +using System; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// A Narcissistic number is equal to the sum of the cubes of its digits. For example, 370 is a +/// Narcissistic number because 3*3*3 + 7*7*7 + 0*0*0 = 370. +/// +public static class NarcissisticNumberChecker { /// - /// A Narcissistic number is equal to the sum of the cubes of its digits. For example, 370 is a - /// Narcissistic number because 3*3*3 + 7*7*7 + 0*0*0 = 370. + /// Checks if a number is a Narcissistic number or not. /// - public static class NarcissisticNumberChecker + /// Number to check. + /// True if is a Narcissistic number; False otherwise. + public static bool IsNarcissistic(int number) { - /// - /// Checks if a number is a Narcissistic number or not. - /// - /// Number to check. - /// True if is a Narcissistic number; False otherwise. - public static bool IsNarcissistic(int number) + var sum = 0; + var temp = number; + var numberOfDigits = 0; + while (temp != 0) { - var sum = 0; - var temp = number; - var numberOfDigits = 0; - while (temp != 0) - { - numberOfDigits++; - temp /= 10; - } - - temp = number; - while (number > 0) - { - var remainder = number % 10; - var power = (int)Math.Pow(remainder, numberOfDigits); + numberOfDigits++; + temp /= 10; + } - sum += power; - number /= 10; - } + temp = number; + while (number > 0) + { + var remainder = number % 10; + var power = (int)Math.Pow(remainder, numberOfDigits); - return sum == temp; + sum += power; + number /= 10; } + + return sum == temp; } } diff --git a/Algorithms/Numeric/PerfectNumberChecker.cs b/Algorithms/Numeric/PerfectNumberChecker.cs index 1a91def9..4abd55f8 100644 --- a/Algorithms/Numeric/PerfectNumberChecker.cs +++ b/Algorithms/Numeric/PerfectNumberChecker.cs @@ -1,37 +1,36 @@ -using System; +using System; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// In number theory, a perfect number is a positive integer that is equal to the sum of its positive +/// divisors, excluding the number itself.For instance, 6 has divisors 1, 2 and 3 (excluding +/// itself), and 1 + 2 + 3 = 6, so 6 is a perfect number. +/// +public static class PerfectNumberChecker { /// - /// In number theory, a perfect number is a positive integer that is equal to the sum of its positive - /// divisors, excluding the number itself.For instance, 6 has divisors 1, 2 and 3 (excluding - /// itself), and 1 + 2 + 3 = 6, so 6 is a perfect number. + /// Checks if a number is a perfect number or not. /// - public static class PerfectNumberChecker + /// Number to check. + /// True if is a perfect number; False otherwise. + /// Error number is not on interval (0.0; int.MaxValue). + public static bool IsPerfectNumber(int number) { - /// - /// Checks if a number is a perfect number or not. - /// - /// Number to check. - /// True if is a perfect number; False otherwise. - /// Error number is not on interval (0.0; int.MaxValue). - public static bool IsPerfectNumber(int number) + if (number < 0) { - if (number < 0) - { - throw new ArgumentException($"{nameof(number)} cannot be negative"); - } + throw new ArgumentException($"{nameof(number)} cannot be negative"); + } - var sum = 0; /* sum of its positive divisors */ - for (var i = 1; i < number; ++i) + var sum = 0; /* sum of its positive divisors */ + for (var i = 1; i < number; ++i) + { + if (number % i == 0) { - if (number % i == 0) - { - sum += i; - } + sum += i; } - - return sum == number; } + + return sum == number; } } diff --git a/Algorithms/Numeric/PerfectSquareChecker.cs b/Algorithms/Numeric/PerfectSquareChecker.cs index 8a8d937a..6465c3b6 100644 --- a/Algorithms/Numeric/PerfectSquareChecker.cs +++ b/Algorithms/Numeric/PerfectSquareChecker.cs @@ -1,26 +1,25 @@ -using System; +using System; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// A perfect square is an element of algebraic structure that is equal to the square of another element. +/// +public static class PerfectSquareChecker { /// - /// A perfect square is an element of algebraic structure that is equal to the square of another element. + /// Checks if a number is a perfect square or not. /// - public static class PerfectSquareChecker + /// Number too check. + /// True if is a perfect square; False otherwise. + public static bool IsPerfectSquare(int number) { - /// - /// Checks if a number is a perfect square or not. - /// - /// Number too check. - /// True if is a perfect square; False otherwise. - public static bool IsPerfectSquare(int number) + if (number < 0) { - if (number < 0) - { - return false; - } - - var sqrt = (int)Math.Sqrt(number); - return sqrt * sqrt == number; + return false; } + + var sqrt = (int)Math.Sqrt(number); + return sqrt * sqrt == number; } } diff --git a/Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs b/Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs index 5e8d6938..0e9317aa 100644 --- a/Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs +++ b/Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs @@ -1,46 +1,45 @@ -using System; +using System; using Algorithms.Numeric.Decomposition; using Utilities.Extensions; -namespace Algorithms.Numeric.Pseudoinverse +namespace Algorithms.Numeric.Pseudoinverse; + +/// +/// The Moore–Penrose pseudo-inverse A+ of a matrix A, +/// is a general way to find the solution to the following system of linear equations: +/// ~b = A ~y. ~b e R^m; ~y e R^n; A e Rm×n. +/// There are varios methods for construction the pseudo-inverse. +/// This one is based on Singular Value Decomposition (SVD). +/// +public static class PseudoInverse { /// - /// The Moore–Penrose pseudo-inverse A+ of a matrix A, - /// is a general way to find the solution to the following system of linear equations: - /// ~b = A ~y. ~b e R^m; ~y e R^n; A e Rm×n. - /// There are varios methods for construction the pseudo-inverse. - /// This one is based on Singular Value Decomposition (SVD). + /// Return the pseudoinverse of a matrix based on the Moore-Penrose Algorithm. + /// using Singular Value Decomposition (SVD). /// - public static class PseudoInverse + /// Input matrix to find its inverse to. + /// The inverse matrix approximation of the input matrix. + public static double[,] PInv(double[,] inMat) { - /// - /// Return the pseudoinverse of a matrix based on the Moore-Penrose Algorithm. - /// using Singular Value Decomposition (SVD). - /// - /// Input matrix to find its inverse to. - /// The inverse matrix approximation of the input matrix. - public static double[,] PInv(double[,] inMat) - { - // To compute the SVD of the matrix to find Sigma. - var (u, s, v) = ThinSvd.Decompose(inMat); + // To compute the SVD of the matrix to find Sigma. + var (u, s, v) = ThinSvd.Decompose(inMat); - // To take the reciprocal of each non-zero element on the diagonal. - var len = s.Length; + // To take the reciprocal of each non-zero element on the diagonal. + var len = s.Length; - var sigma = new double[len]; - for (var i = 0; i < len; i++) - { - sigma[i] = Math.Abs(s[i]) < 0.0001 ? 0 : 1 / s[i]; - } + var sigma = new double[len]; + for (var i = 0; i < len; i++) + { + sigma[i] = Math.Abs(s[i]) < 0.0001 ? 0 : 1 / s[i]; + } - // To construct a diagonal matrix based on the vector result. - var diag = sigma.ToDiagonalMatrix(); + // To construct a diagonal matrix based on the vector result. + var diag = sigma.ToDiagonalMatrix(); - // To construct the pseudo-inverse using the computed information above. - var matinv = u.Multiply(diag).Multiply(v.Transpose()); + // To construct the pseudo-inverse using the computed information above. + var matinv = u.Multiply(diag).Multiply(v.Transpose()); - // To Transpose the result matrix. - return matinv.Transpose(); - } + // To Transpose the result matrix. + return matinv.Transpose(); } } diff --git a/Algorithms/Numeric/RungeKuttaMethod.cs b/Algorithms/Numeric/RungeKuttaMethod.cs index 6f694e6e..2ef987bd 100644 --- a/Algorithms/Numeric/RungeKuttaMethod.cs +++ b/Algorithms/Numeric/RungeKuttaMethod.cs @@ -1,69 +1,68 @@ using System; using System.Collections.Generic; -namespace Algorithms.Numeric +namespace Algorithms.Numeric; + +/// +/// In numerical analysis, the Runge–Kutta methods are a family of implicit and explicit iterative methods, +/// used in temporal discretization for the approximate solutions of simultaneous nonlinear equations. +/// The most widely known member of the Runge–Kutta family is generally referred to as +/// "RK4", the "classic Runge–Kutta method" or simply as "the Runge–Kutta method". +/// +public static class RungeKuttaMethod { /// - /// In numerical analysis, the Runge–Kutta methods are a family of implicit and explicit iterative methods, - /// used in temporal discretization for the approximate solutions of simultaneous nonlinear equations. - /// The most widely known member of the Runge–Kutta family is generally referred to as - /// "RK4", the "classic Runge–Kutta method" or simply as "the Runge–Kutta method". - /// - public static class RungeKuttaMethod + /// Loops through all the steps until xEnd is reached, adds a point for each step and then + /// returns all the points. + /// + /// Initial conditions x-value. + /// Last x-value. + /// Step-size on the x-axis. + /// Initial conditions y-value. + /// The right hand side of the differential equation. + /// The solution of the Cauchy problem. + public static List ClassicRungeKuttaMethod( + double xStart, + double xEnd, + double stepSize, + double yStart, + Func function) { - /// - /// Loops through all the steps until xEnd is reached, adds a point for each step and then - /// returns all the points. - /// - /// Initial conditions x-value. - /// Last x-value. - /// Step-size on the x-axis. - /// Initial conditions y-value. - /// The right hand side of the differential equation. - /// The solution of the Cauchy problem. - public static List ClassicRungeKuttaMethod( - double xStart, - double xEnd, - double stepSize, - double yStart, - Func function) + if (xStart >= xEnd) { - if (xStart >= xEnd) - { - throw new ArgumentOutOfRangeException( - nameof(xEnd), - $"{nameof(xEnd)} should be greater than {nameof(xStart)}"); - } - - if (stepSize <= 0) - { - throw new ArgumentOutOfRangeException( - nameof(stepSize), - $"{nameof(stepSize)} should be greater than zero"); - } + throw new ArgumentOutOfRangeException( + nameof(xEnd), + $"{nameof(xEnd)} should be greater than {nameof(xStart)}"); + } - List points = new(); - double[] firstPoint = { xStart, yStart }; - points.Add(firstPoint); + if (stepSize <= 0) + { + throw new ArgumentOutOfRangeException( + nameof(stepSize), + $"{nameof(stepSize)} should be greater than zero"); + } - var yCurrent = yStart; - var xCurrent = xStart; + List points = new(); + double[] firstPoint = { xStart, yStart }; + points.Add(firstPoint); - while (xCurrent < xEnd) - { - var k1 = function(xCurrent, yCurrent); - var k2 = function(xCurrent + 0.5 * stepSize, yCurrent + 0.5 * stepSize * k1); - var k3 = function(xCurrent + 0.5 * stepSize, yCurrent + 0.5 * stepSize * k2); - var k4 = function(xCurrent + stepSize, yCurrent + stepSize * k3); + var yCurrent = yStart; + var xCurrent = xStart; - yCurrent += (1.0 / 6.0) * stepSize * (k1 + 2 * k2 + 2 * k3 + k4); - xCurrent += stepSize; + while (xCurrent < xEnd) + { + var k1 = function(xCurrent, yCurrent); + var k2 = function(xCurrent + 0.5 * stepSize, yCurrent + 0.5 * stepSize * k1); + var k3 = function(xCurrent + 0.5 * stepSize, yCurrent + 0.5 * stepSize * k2); + var k4 = function(xCurrent + stepSize, yCurrent + stepSize * k3); - double[] newPoint = { xCurrent, yCurrent }; - points.Add(newPoint); - } + yCurrent += (1.0 / 6.0) * stepSize * (k1 + 2 * k2 + 2 * k3 + k4); + xCurrent += stepSize; - return points; + double[] newPoint = { xCurrent, yCurrent }; + points.Add(newPoint); } + + return points; } } diff --git a/Algorithms/Numeric/Series/Maclaurin.cs b/Algorithms/Numeric/Series/Maclaurin.cs index cfae31a3..75924a50 100644 --- a/Algorithms/Numeric/Series/Maclaurin.cs +++ b/Algorithms/Numeric/Series/Maclaurin.cs @@ -1,140 +1,139 @@ using System; using System.Linq; -namespace Algorithms.Numeric.Series +namespace Algorithms.Numeric.Series; + +/// +/// Maclaurin series calculates nonlinear functions approximation +/// starting from point x = 0 in a form of infinite power series: +/// f(x) = f(0) + f'(0) * x + ... + (f'n(0) * (x ^ n)) / n! + ..., +/// where n is natural number. +/// +public static class Maclaurin { /// - /// Maclaurin series calculates nonlinear functions approximation - /// starting from point x = 0 in a form of infinite power series: - /// f(x) = f(0) + f'(0) * x + ... + (f'n(0) * (x ^ n)) / n! + ..., - /// where n is natural number. + /// Calculates approximation of e^x function: + /// e^x = 1 + x + x^2 / 2! + ... + x^n / n! + ..., + /// where n is number of terms (natural number), + /// and x is given point (rational number). /// - public static class Maclaurin - { - /// - /// Calculates approximation of e^x function: - /// e^x = 1 + x + x^2 / 2! + ... + x^n / n! + ..., - /// where n is number of terms (natural number), - /// and x is given point (rational number). - /// - /// Given point. - /// The number of terms in polynomial. - /// Approximated value of the function in the given point. - public static double Exp(double x, int n) => - Enumerable.Range(0, n).Sum(i => ExpTerm(x, i)); + /// Given point. + /// The number of terms in polynomial. + /// Approximated value of the function in the given point. + public static double Exp(double x, int n) => + Enumerable.Range(0, n).Sum(i => ExpTerm(x, i)); - /// - /// Calculates approximation of sin(x) function: - /// sin(x) = x - x^3 / 3! + ... + (-1)^n * x^(2*n + 1) / (2*n + 1)! + ..., - /// where n is number of terms (natural number), - /// and x is given point (rational number). - /// - /// Given point. - /// The number of terms in polynomial. - /// Approximated value of the function in the given point. - public static double Sin(double x, int n) => - Enumerable.Range(0, n).Sum(i => SinTerm(x, i)); + /// + /// Calculates approximation of sin(x) function: + /// sin(x) = x - x^3 / 3! + ... + (-1)^n * x^(2*n + 1) / (2*n + 1)! + ..., + /// where n is number of terms (natural number), + /// and x is given point (rational number). + /// + /// Given point. + /// The number of terms in polynomial. + /// Approximated value of the function in the given point. + public static double Sin(double x, int n) => + Enumerable.Range(0, n).Sum(i => SinTerm(x, i)); - /// - /// Calculates approximation of cos(x) function: - /// cos(x) = 1 - x^2 / 2! + ... + (-1)^n * x^(2*n) / (2*n)! + ..., - /// where n is number of terms (natural number), - /// and x is given point (rational number). - /// - /// Given point. - /// The number of terms in polynomial. - /// Approximated value of the function in the given point. - public static double Cos(double x, int n) => - Enumerable.Range(0, n).Sum(i => CosTerm(x, i)); + /// + /// Calculates approximation of cos(x) function: + /// cos(x) = 1 - x^2 / 2! + ... + (-1)^n * x^(2*n) / (2*n)! + ..., + /// where n is number of terms (natural number), + /// and x is given point (rational number). + /// + /// Given point. + /// The number of terms in polynomial. + /// Approximated value of the function in the given point. + public static double Cos(double x, int n) => + Enumerable.Range(0, n).Sum(i => CosTerm(x, i)); - /// - /// Calculates approximation of e^x function: - /// e^x = 1 + x + x^2 / 2! + ... + x^n / n! + ..., - /// and x is given point (rational number). - /// - /// Given point. - /// Last term error value. - /// Approximated value of the function in the given point. - /// Error value is not on interval (0.0; 1.0). - public static double Exp(double x, double error = 0.00001) => ErrorTermWrapper(x, error, ExpTerm); + /// + /// Calculates approximation of e^x function: + /// e^x = 1 + x + x^2 / 2! + ... + x^n / n! + ..., + /// and x is given point (rational number). + /// + /// Given point. + /// Last term error value. + /// Approximated value of the function in the given point. + /// Error value is not on interval (0.0; 1.0). + public static double Exp(double x, double error = 0.00001) => ErrorTermWrapper(x, error, ExpTerm); - /// - /// Calculates approximation of sin(x) function: - /// sin(x) = x - x^3 / 3! + ... + (-1)^n * x^(2*n + 1) / (2*n + 1)! + ..., - /// and x is given point (rational number). - /// - /// Given point. - /// Last term error value. - /// Approximated value of the function in the given point. - /// Error value is not on interval (0.0; 1.0). - public static double Sin(double x, double error = 0.00001) => ErrorTermWrapper(x, error, SinTerm); + /// + /// Calculates approximation of sin(x) function: + /// sin(x) = x - x^3 / 3! + ... + (-1)^n * x^(2*n + 1) / (2*n + 1)! + ..., + /// and x is given point (rational number). + /// + /// Given point. + /// Last term error value. + /// Approximated value of the function in the given point. + /// Error value is not on interval (0.0; 1.0). + public static double Sin(double x, double error = 0.00001) => ErrorTermWrapper(x, error, SinTerm); - /// - /// Calculates approximation of cos(x) function: - /// cos(x) = 1 - x^2 / 2! + ... + (-1)^n * x^(2*n) / (2*n)! + ..., - /// and x is given point (rational number). - /// - /// Given point. - /// Last term error value. - /// Approximated value of the function in the given point. - /// Error value is not on interval (0.0; 1.0). - public static double Cos(double x, double error = 0.00001) => ErrorTermWrapper(x, error, CosTerm); + /// + /// Calculates approximation of cos(x) function: + /// cos(x) = 1 - x^2 / 2! + ... + (-1)^n * x^(2*n) / (2*n)! + ..., + /// and x is given point (rational number). + /// + /// Given point. + /// Last term error value. + /// Approximated value of the function in the given point. + /// Error value is not on interval (0.0; 1.0). + public static double Cos(double x, double error = 0.00001) => ErrorTermWrapper(x, error, CosTerm); - /// - /// Wrapper function for calculating approximation with estimated - /// count of terms, where last term value is less than given error. - /// - /// Given point. - /// Last term error value. - /// Indexed term of approximation series. - /// Approximated value of the function in the given point. - /// Error value is not on interval (0.0; 1.0). - private static double ErrorTermWrapper(double x, double error, Func term) + /// + /// Wrapper function for calculating approximation with estimated + /// count of terms, where last term value is less than given error. + /// + /// Given point. + /// Last term error value. + /// Indexed term of approximation series. + /// Approximated value of the function in the given point. + /// Error value is not on interval (0.0; 1.0). + private static double ErrorTermWrapper(double x, double error, Func term) + { + if (error <= 0.0 || error >= 1.0) { - if (error <= 0.0 || error >= 1.0) - { - throw new ArgumentException("Error value is not on interval (0.0; 1.0)."); - } - - var i = 0; - var termCoefficient = 0.0; - var result = 0.0; + throw new ArgumentException("Error value is not on interval (0.0; 1.0)."); + } - do - { - result += termCoefficient; - termCoefficient = term(x, i); - i++; - } - while (Math.Abs(termCoefficient) > error); + var i = 0; + var termCoefficient = 0.0; + var result = 0.0; - return result; + do + { + result += termCoefficient; + termCoefficient = term(x, i); + i++; } + while (Math.Abs(termCoefficient) > error); - /// - /// Single term for e^x function approximation: x^i / i!. - /// - /// Given point. - /// Term index from 0 to n. - /// Single term value. - private static double ExpTerm(double x, int i) => Math.Pow(x, i) / (long)Factorial.Calculate(i); + return result; + } - /// - /// Single term for sin(x) function approximation: (-1)^i * x^(2*i + 1) / (2*i + 1)!. - /// - /// Given point. - /// Term index from 0 to n. - /// Single term value. - private static double SinTerm(double x, int i) => - Math.Pow(-1, i) / ((long)Factorial.Calculate(2 * i + 1)) * Math.Pow(x, 2 * i + 1); + /// + /// Single term for e^x function approximation: x^i / i!. + /// + /// Given point. + /// Term index from 0 to n. + /// Single term value. + private static double ExpTerm(double x, int i) => Math.Pow(x, i) / (long)Factorial.Calculate(i); - /// - /// Single term for cos(x) function approximation: (-1)^i * x^(2*i) / (2*i)!. - /// - /// Given point. - /// Term index from 0 to n. - /// Single term value. - private static double CosTerm(double x, int i) => - Math.Pow(-1, i) / ((long)Factorial.Calculate(2 * i)) * Math.Pow(x, 2 * i); - } + /// + /// Single term for sin(x) function approximation: (-1)^i * x^(2*i + 1) / (2*i + 1)!. + /// + /// Given point. + /// Term index from 0 to n. + /// Single term value. + private static double SinTerm(double x, int i) => + Math.Pow(-1, i) / ((long)Factorial.Calculate(2 * i + 1)) * Math.Pow(x, 2 * i + 1); + + /// + /// Single term for cos(x) function approximation: (-1)^i * x^(2*i) / (2*i)!. + /// + /// Given point. + /// Term index from 0 to n. + /// Single term value. + private static double CosTerm(double x, int i) => + Math.Pow(-1, i) / ((long)Factorial.Calculate(2 * i)) * Math.Pow(x, 2 * i); } From fdfc76515e7f8bd4e6df606ab5704e4f1e8188f5 Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Sun, 31 Dec 2023 09:48:57 +0000 Subject: [PATCH 083/138] Switch to file-scoped namespaces (#431) --- Algorithms/Other/DecisionsConvolutions.cs | 108 +++---- Algorithms/Other/FermatPrimeChecker.cs | 59 ++-- Algorithms/Other/FloodFill.cs | 134 ++++---- Algorithms/Other/GaussOptimization.cs | 123 ++++---- Algorithms/Other/GeoLocation.cs | 57 ++-- Algorithms/Other/Int2Binary.cs | 137 ++++---- Algorithms/Other/JulianEaster.cs | 41 ++- Algorithms/Other/KochSnowflake.cs | 257 ++++++++------- Algorithms/Other/Luhn.cs | 113 ++++--- Algorithms/Other/Mandelbrot.cs | 297 +++++++++--------- Algorithms/Other/ParetoOptimization.cs | 100 +++--- Algorithms/Other/PollardsRhoFactorizing.cs | 53 ++-- Algorithms/Other/RGBHSVConversion.cs | 255 ++++++++------- Algorithms/Other/SieveOfEratosthenes.cs | 94 +++--- Algorithms/Other/WelfordsVariance.cs | 97 +++--- .../CoinChange/DynamicCoinChangeSolver.cs | 255 ++++++++------- .../LevenshteinDistance.cs | 67 ++-- .../NQueens/BacktrackingNQueensSolver.cs | 147 +++++---- .../Problems/StableMarriage/Accepter.cs | 19 +- .../Problems/StableMarriage/GaleShapley.cs | 89 +++--- .../Problems/StableMarriage/Proposer.cs | 13 +- Algorithms/Search/AStar/AStar.cs | 215 +++++++------ Algorithms/Search/AStar/Node.cs | 193 ++++++------ Algorithms/Search/AStar/NodeState.cs | 33 +- .../Search/AStar/PathfindingException.cs | 19 +- Algorithms/Search/AStar/PriorityQueue.cs | 229 +++++++------- Algorithms/Search/AStar/VecN.cs | 185 ++++++----- Algorithms/Search/BinarySearcher.cs | 67 ++-- Algorithms/Search/BoyerMoore.cs | 79 +++-- Algorithms/Search/FastSearcher.cs | 117 ++++--- Algorithms/Search/FibonacciSearcher.cs | 135 ++++---- Algorithms/Search/InterpolationSearch.cs | 75 +++-- Algorithms/Search/JumpSearcher.cs | 83 +++-- Algorithms/Search/LinearSearcher.cs | 71 +++-- Algorithms/Search/RecursiveBinarySearcher.cs | 99 +++--- 35 files changed, 2031 insertions(+), 2084 deletions(-) diff --git a/Algorithms/Other/DecisionsConvolutions.cs b/Algorithms/Other/DecisionsConvolutions.cs index fcb23342..cb0eedbd 100644 --- a/Algorithms/Other/DecisionsConvolutions.cs +++ b/Algorithms/Other/DecisionsConvolutions.cs @@ -1,78 +1,74 @@ -using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// Almost all real complex decision-making task is described by more than one criterion. +/// There are different methods to select the best decisions from the defined set of decisions. +/// This class contains implementations of the popular convolution methods: linear and maxmin. +/// +public static class DecisionsConvolutions { /// - /// Almost all real complex decision-making task is described by more than one criterion. - /// There are different methods to select the best decisions from the defined set of decisions. - /// This class contains implementations of the popular convolution methods: linear and maxmin. + /// This method implements the linear method of decision selection. It is based on + /// the calculation of the "value" for each decision and the selection of the most + /// valuable one. /// - public static class DecisionsConvolutions + /// Contains a collection of the criteria sets. + /// Contains a set of priorities for each criterion. + /// The most effective decision that is represented by a set of criterias. + public static List Linear(List> matrix, List priorities) { - /// - /// This method implements the linear method of decision selection. It is based on - /// the calculation of the "value" for each decision and the selection of the most - /// valuable one. - /// - /// Contains a collection of the criteria sets. - /// Contains a set of priorities for each criterion. - /// The most effective decision that is represented by a set of criterias. - public static List Linear(List> matrix, List priorities) - { - var decisionValues = new List(); + var decisionValues = new List(); - foreach (var decision in matrix) + foreach (var decision in matrix) + { + decimal sum = 0; + for (int i = 0; i < decision.Count; i++) { - decimal sum = 0; - for (int i = 0; i < decision.Count; i++) - { - sum += decision[i] * priorities[i]; - } - - decisionValues.Add(sum); + sum += decision[i] * priorities[i]; } - decimal bestDecisionValue = decisionValues.Max(); - int bestDecisionIndex = decisionValues.IndexOf(bestDecisionValue); - - return matrix[bestDecisionIndex]; + decisionValues.Add(sum); } - /// - /// This method implements maxmin method of the decision selection. It is based on - /// the calculation of the least criteria value and comparison of decisions based - /// on the calculated results. - /// - /// Contains a collection of the criteria sets. - /// Contains a set of priorities for each criterion. - /// The most effective decision that is represented by a set of criterias. - public static List MaxMin(List> matrix, List priorities) - { - var decisionValues = new List(); + decimal bestDecisionValue = decisionValues.Max(); + int bestDecisionIndex = decisionValues.IndexOf(bestDecisionValue); + + return matrix[bestDecisionIndex]; + } - foreach (var decision in matrix) + /// + /// This method implements maxmin method of the decision selection. It is based on + /// the calculation of the least criteria value and comparison of decisions based + /// on the calculated results. + /// + /// Contains a collection of the criteria sets. + /// Contains a set of priorities for each criterion. + /// The most effective decision that is represented by a set of criterias. + public static List MaxMin(List> matrix, List priorities) + { + var decisionValues = new List(); + + foreach (var decision in matrix) + { + decimal minValue = decimal.MaxValue; + for (int i = 0; i < decision.Count; i++) { - decimal minValue = decimal.MaxValue; - for (int i = 0; i < decision.Count; i++) + decimal result = decision[i] * priorities[i]; + if (result < minValue) { - decimal result = decision[i] * priorities[i]; - if (result < minValue) - { - minValue = result; - } + minValue = result; } - - decisionValues.Add(minValue); } - decimal bestDecisionValue = decisionValues.Max(); - int bestDecisionIndex = decisionValues.IndexOf(bestDecisionValue); - - return matrix[bestDecisionIndex]; + decisionValues.Add(minValue); } + + decimal bestDecisionValue = decisionValues.Max(); + int bestDecisionIndex = decisionValues.IndexOf(bestDecisionValue); + + return matrix[bestDecisionIndex]; } } diff --git a/Algorithms/Other/FermatPrimeChecker.cs b/Algorithms/Other/FermatPrimeChecker.cs index 1c186b12..9f277d2c 100644 --- a/Algorithms/Other/FermatPrimeChecker.cs +++ b/Algorithms/Other/FermatPrimeChecker.cs @@ -1,46 +1,45 @@ using System; using System.Numerics; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// Fermat's prime tester https://en.wikipedia.org/wiki/Fermat_primality_test. +/// +public static class FermatPrimeChecker { /// - /// Fermat's prime tester https://en.wikipedia.org/wiki/Fermat_primality_test. + /// Checks if input number is a probable prime. /// - public static class FermatPrimeChecker + /// Input number. + /// Number of times to check. + /// True if is a prime; False otherwise. + public static bool IsPrime(int numberToTest, int timesToCheck) { - /// - /// Checks if input number is a probable prime. - /// - /// Input number. - /// Number of times to check. - /// True if is a prime; False otherwise. - public static bool IsPrime(int numberToTest, int timesToCheck) - { - // You have to use BigInteger for two reasons: - // 1. The pow operation between two int numbers usually overflows an int - // 2. The pow and modular operation is very optimized - var numberToTestBigInteger = new BigInteger(numberToTest); - var exponentBigInteger = new BigInteger(numberToTest - 1); + // You have to use BigInteger for two reasons: + // 1. The pow operation between two int numbers usually overflows an int + // 2. The pow and modular operation is very optimized + var numberToTestBigInteger = new BigInteger(numberToTest); + var exponentBigInteger = new BigInteger(numberToTest - 1); - // Create a random number generator using the current time as seed - var r = new Random(default(DateTime).Millisecond); + // Create a random number generator using the current time as seed + var r = new Random(default(DateTime).Millisecond); - var iterator = 1; - var prime = true; + var iterator = 1; + var prime = true; - while (iterator < timesToCheck && prime) + while (iterator < timesToCheck && prime) + { + var randomNumber = r.Next(1, numberToTest); + var randomNumberBigInteger = new BigInteger(randomNumber); + if (BigInteger.ModPow(randomNumberBigInteger, exponentBigInteger, numberToTestBigInteger) != 1) { - var randomNumber = r.Next(1, numberToTest); - var randomNumberBigInteger = new BigInteger(randomNumber); - if (BigInteger.ModPow(randomNumberBigInteger, exponentBigInteger, numberToTestBigInteger) != 1) - { - prime = false; - } - - iterator++; + prime = false; } - return prime; + iterator++; } + + return prime; } } diff --git a/Algorithms/Other/FloodFill.cs b/Algorithms/Other/FloodFill.cs index f851fdb6..0904e9c9 100644 --- a/Algorithms/Other/FloodFill.cs +++ b/Algorithms/Other/FloodFill.cs @@ -1,97 +1,95 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; -using System.Numerics; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// Flood fill, also called seed fill, is an algorithm that determines and +/// alters the area connected to a given node in a multi-dimensional array with +/// some matching attribute. It is used in the "bucket" fill tool of paint +/// programs to fill connected, similarly-colored areas with a different color. +/// (description adapted from https://en.wikipedia.org/wiki/Flood_fill) +/// (see also: https://www.techiedelight.com/flood-fill-algorithm/). +/// +public static class FloodFill { + private static readonly List<(int xOffset, int yOffset)> Neighbors = new() { (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1) }; + /// - /// Flood fill, also called seed fill, is an algorithm that determines and - /// alters the area connected to a given node in a multi-dimensional array with - /// some matching attribute. It is used in the "bucket" fill tool of paint - /// programs to fill connected, similarly-colored areas with a different color. - /// (description adapted from https://en.wikipedia.org/wiki/Flood_fill) - /// (see also: https://www.techiedelight.com/flood-fill-algorithm/). + /// Implements the flood fill algorithm through a breadth-first approach using a queue. /// - public static class FloodFill + /// The bitmap to which the algorithm is applied. + /// The start location on the bitmap. + /// The old color to be replaced. + /// The new color to replace the old one. + public static void BreadthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) { - private static readonly List<(int xOffset, int yOffset)> Neighbors = new() { (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1) }; - - /// - /// Implements the flood fill algorithm through a breadth-first approach using a queue. - /// - /// The bitmap to which the algorithm is applied. - /// The start location on the bitmap. - /// The old color to be replaced. - /// The new color to replace the old one. - public static void BreadthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) + if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) { - if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) - { - throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap"); - } + throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap"); + } - var queue = new List<(int x, int y)>(); - queue.Add(location); + var queue = new List<(int x, int y)>(); + queue.Add(location); - while (queue.Count > 0) - { - BreadthFirstFill(bitmap, location, targetColor, replacementColor, queue); - } + while (queue.Count > 0) + { + BreadthFirstFill(bitmap, location, targetColor, replacementColor, queue); } + } - /// - /// Implements the flood fill algorithm through a depth-first approach through recursion. - /// - /// The bitmap to which the algorithm is applied. - /// The start location on the bitmap. - /// The old color to be replaced. - /// The new color to replace the old one. - public static void DepthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) + /// + /// Implements the flood fill algorithm through a depth-first approach through recursion. + /// + /// The bitmap to which the algorithm is applied. + /// The start location on the bitmap. + /// The old color to be replaced. + /// The new color to replace the old one. + public static void DepthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) + { + if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) { - if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) - { - throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap"); - } - - DepthFirstFill(bitmap, location, targetColor, replacementColor); + throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap"); } - private static void BreadthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor, List<(int x, int y)> queue) + DepthFirstFill(bitmap, location, targetColor, replacementColor); + } + + private static void BreadthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor, List<(int x, int y)> queue) + { + (int x, int y) currentLocation = queue[0]; + queue.RemoveAt(0); + + if (bitmap.GetPixel(currentLocation.x, currentLocation.y) == targetColor) { - (int x, int y) currentLocation = queue[0]; - queue.RemoveAt(0); + bitmap.SetPixel(currentLocation.x, currentLocation.y, replacementColor); - if (bitmap.GetPixel(currentLocation.x, currentLocation.y) == targetColor) + for (int i = 0; i < Neighbors.Count; i++) { - bitmap.SetPixel(currentLocation.x, currentLocation.y, replacementColor); - - for (int i = 0; i < Neighbors.Count; i++) + int x = currentLocation.x + Neighbors[i].xOffset; + int y = currentLocation.y + Neighbors[i].yOffset; + if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height) { - int x = currentLocation.x + Neighbors[i].xOffset; - int y = currentLocation.y + Neighbors[i].yOffset; - if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height) - { - queue.Add((x, y)); - } + queue.Add((x, y)); } } } + } - private static void DepthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) + private static void DepthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) + { + if (bitmap.GetPixel(location.x, location.y) == targetColor) { - if (bitmap.GetPixel(location.x, location.y) == targetColor) - { - bitmap.SetPixel(location.x, location.y, replacementColor); + bitmap.SetPixel(location.x, location.y, replacementColor); - for (int i = 0; i < Neighbors.Count; i++) + for (int i = 0; i < Neighbors.Count; i++) + { + int x = location.x + Neighbors[i].xOffset; + int y = location.y + Neighbors[i].yOffset; + if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height) { - int x = location.x + Neighbors[i].xOffset; - int y = location.y + Neighbors[i].yOffset; - if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height) - { - DepthFirstFill(bitmap, (x, y), targetColor, replacementColor); - } + DepthFirstFill(bitmap, (x, y), targetColor, replacementColor); } } } diff --git a/Algorithms/Other/GaussOptimization.cs b/Algorithms/Other/GaussOptimization.cs index 117ef910..3387a1e1 100644 --- a/Algorithms/Other/GaussOptimization.cs +++ b/Algorithms/Other/GaussOptimization.cs @@ -1,80 +1,77 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// The Gaussian method (coordinate descent method) refers to zero-order methods in which only the value +/// of the function Q(X) at different points in the space of variables is used to organize the search +/// for the extremum. This reduces the overall computational cost of finding the extremum. Also in +/// the Gaussian method, the procedures for finding and moving the operating point are simplified as +/// much as possible. +/// +public class GaussOptimization { /// - /// The Gaussian method (coordinate descent method) refers to zero-order methods in which only the value - /// of the function Q(X) at different points in the space of variables is used to organize the search - /// for the extremum. This reduces the overall computational cost of finding the extremum. Also in - /// the Gaussian method, the procedures for finding and moving the operating point are simplified as - /// much as possible. + /// Implementation of function extremum search by the Gauss optimization algorithm. /// - public class GaussOptimization + /// Function for which extremum has to be found. + /// This parameter identifies how much step size will be decreased each iteration. + /// The initial shift step. + /// This value is used to control the accuracy of the optimization. In case if the error is less than eps, + /// optimization will be stopped. + /// The first function parameter. + /// The second function parameter. + /// A tuple of coordinates of function extremum. + public (double, double) Optimize( + Func func, + double n, + double step, + double eps, + double x1, + double x2) { - /// - /// Implementation of function extremum search by the Gauss optimization algorithm. - /// - /// Function for which extremum has to be found. - /// This parameter identifies how much step size will be decreased each iteration. - /// The initial shift step. - /// This value is used to control the accuracy of the optimization. In case if the error is less than eps, - /// optimization will be stopped. - /// The first function parameter. - /// The second function parameter. - /// A tuple of coordinates of function extremum. - public (double, double) Optimize( - Func func, - double n, - double step, - double eps, - double x1, - double x2) - { - // The initial value of the error - double error = 1; - - while (Math.Abs(error) > eps) - { - // Calculation of the function with coordinates that are calculated with shift - double bottom = func(x1, x2 - step); - double top = func(x1, x2 + step); - double left = func(x1 - step, x2); - double right = func(x1 + step, x2); + // The initial value of the error + double error = 1; - // Determination of the best option. - var possibleFunctionValues = new List { bottom, top, left, right }; - double maxValue = possibleFunctionValues.Max(); - double maxValueIndex = possibleFunctionValues.IndexOf(maxValue); + while (Math.Abs(error) > eps) + { + // Calculation of the function with coordinates that are calculated with shift + double bottom = func(x1, x2 - step); + double top = func(x1, x2 + step); + double left = func(x1 - step, x2); + double right = func(x1 + step, x2); - // Error evaluation - error = maxValue - func(x1, x2); + // Determination of the best option. + var possibleFunctionValues = new List { bottom, top, left, right }; + double maxValue = possibleFunctionValues.Max(); + double maxValueIndex = possibleFunctionValues.IndexOf(maxValue); - // Coordinates update for the best option - switch (maxValueIndex) - { - case 0: - x2 -= step; - break; - case 1: - x2 += step; - break; - case 2: - x1 -= step; - break; - default: - x1 += step; - break; - } + // Error evaluation + error = maxValue - func(x1, x2); - // Step reduction - step /= n; + // Coordinates update for the best option + switch (maxValueIndex) + { + case 0: + x2 -= step; + break; + case 1: + x2 += step; + break; + case 2: + x1 -= step; + break; + default: + x1 += step; + break; } - return (x1, x2); + // Step reduction + step /= n; } + + return (x1, x2); } } diff --git a/Algorithms/Other/GeoLocation.cs b/Algorithms/Other/GeoLocation.cs index 4078ca26..1cc39adb 100644 --- a/Algorithms/Other/GeoLocation.cs +++ b/Algorithms/Other/GeoLocation.cs @@ -1,37 +1,36 @@ -using System; +using System; -namespace Algorithms.Other +namespace Algorithms.Other; + +public static class GeoLocation { - public static class GeoLocation - { - private const double EarthRadiusKm = 6371.01d; + private const double EarthRadiusKm = 6371.01d; - /// - /// Calculates spherical distance between 2 points given their latitude, longitude coordinates. - /// https://www.movable-type.co.uk/scripts/latlong.html. - /// - /// Latitude of point A. - /// Longitude of point A. - /// Latitude of point B. - /// Longitude of point B. - /// Spherical distance between A and B. - public static double CalculateDistanceFromLatLng(double lat1, double lng1, double lat2, double lng2) - { - var pi180 = Math.PI / 180d; - var lat1Radian = lat1 * pi180; - var lng1Radian = lng1 * pi180; - var lat2Radian = lat2 * pi180; - var lng2Radian = lng2 * pi180; + /// + /// Calculates spherical distance between 2 points given their latitude, longitude coordinates. + /// https://www.movable-type.co.uk/scripts/latlong.html. + /// + /// Latitude of point A. + /// Longitude of point A. + /// Latitude of point B. + /// Longitude of point B. + /// Spherical distance between A and B. + public static double CalculateDistanceFromLatLng(double lat1, double lng1, double lat2, double lng2) + { + var pi180 = Math.PI / 180d; + var lat1Radian = lat1 * pi180; + var lng1Radian = lng1 * pi180; + var lat2Radian = lat2 * pi180; + var lng2Radian = lng2 * pi180; - var diffLat = lat2Radian - lat1Radian; - var diffLng = lng2Radian - lng1Radian; + var diffLat = lat2Radian - lat1Radian; + var diffLng = lng2Radian - lng1Radian; - var haversine = - Math.Sin(diffLat / 2) * Math.Sin(diffLat / 2) - + Math.Cos(lat1Radian) * Math.Cos(lat2Radian) * Math.Sin(diffLng / 2) * Math.Sin(diffLng / 2); - var distance = EarthRadiusKm * (2d * Math.Atan2(Math.Sqrt(haversine), Math.Sqrt(1 - haversine))); + var haversine = + Math.Sin(diffLat / 2) * Math.Sin(diffLat / 2) + + Math.Cos(lat1Radian) * Math.Cos(lat2Radian) * Math.Sin(diffLng / 2) * Math.Sin(diffLng / 2); + var distance = EarthRadiusKm * (2d * Math.Atan2(Math.Sqrt(haversine), Math.Sqrt(1 - haversine))); - return distance * 1000; // Convert from km -> m - } + return distance * 1000; // Convert from km -> m } } diff --git a/Algorithms/Other/Int2Binary.cs b/Algorithms/Other/Int2Binary.cs index ec0fe38f..07cd57ff 100644 --- a/Algorithms/Other/Int2Binary.cs +++ b/Algorithms/Other/Int2Binary.cs @@ -1,91 +1,90 @@ using System.Text; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// Manually converts an integer of certain size to a string of the binary representation. +/// +public static class Int2Binary { /// - /// Manually converts an integer of certain size to a string of the binary representation. + /// Returns string of the binary representation of given Int. /// - public static class Int2Binary + /// Number to be converted. + /// Binary representation of input. + public static string Int2Bin(ushort input) { - /// - /// Returns string of the binary representation of given Int. - /// - /// Number to be converted. - /// Binary representation of input. - public static string Int2Bin(ushort input) + ushort msb = ushort.MaxValue / 2 + 1; + var output = new StringBuilder(); + for (var i = 0; i < 16; i++) { - ushort msb = ushort.MaxValue / 2 + 1; - var output = new StringBuilder(); - for (var i = 0; i < 16; i++) + if (input >= msb) { - if (input >= msb) - { - output.Append("1"); - input -= msb; - msb /= 2; - } - else - { - output.Append("0"); - msb /= 2; - } + output.Append("1"); + input -= msb; + msb /= 2; + } + else + { + output.Append("0"); + msb /= 2; } - - return output.ToString(); } - /// - /// Returns string of the binary representation of given Int. - /// - /// Number to be converted. - /// Binary representation of input. - public static string Int2Bin(uint input) + return output.ToString(); + } + + /// + /// Returns string of the binary representation of given Int. + /// + /// Number to be converted. + /// Binary representation of input. + public static string Int2Bin(uint input) + { + var msb = uint.MaxValue / 2 + 1; + var output = new StringBuilder(); + for (var i = 0; i < 32; i++) { - var msb = uint.MaxValue / 2 + 1; - var output = new StringBuilder(); - for (var i = 0; i < 32; i++) + if (input >= msb) { - if (input >= msb) - { - output.Append("1"); - input -= msb; - msb /= 2; - } - else - { - output.Append("0"); - msb /= 2; - } + output.Append("1"); + input -= msb; + msb /= 2; + } + else + { + output.Append("0"); + msb /= 2; } - - return output.ToString(); } - /// - /// Returns string of the binary representation of given Int. - /// - /// Number to be converted. - /// Binary representation of input. - public static string Int2Bin(ulong input) + return output.ToString(); + } + + /// + /// Returns string of the binary representation of given Int. + /// + /// Number to be converted. + /// Binary representation of input. + public static string Int2Bin(ulong input) + { + var msb = ulong.MaxValue / 2 + 1; + var output = new StringBuilder(); + for (var i = 0; i < 64; i++) { - var msb = ulong.MaxValue / 2 + 1; - var output = new StringBuilder(); - for (var i = 0; i < 64; i++) + if (input >= msb) { - if (input >= msb) - { - output.Append("1"); - input -= msb; - msb /= 2; - } - else - { - output.Append("0"); - msb /= 2; - } + output.Append("1"); + input -= msb; + msb /= 2; + } + else + { + output.Append("0"); + msb /= 2; } - - return output.ToString(); } + + return output.ToString(); } } diff --git a/Algorithms/Other/JulianEaster.cs b/Algorithms/Other/JulianEaster.cs index 6224f72c..0717a11a 100644 --- a/Algorithms/Other/JulianEaster.cs +++ b/Algorithms/Other/JulianEaster.cs @@ -1,32 +1,31 @@ using System; using System.Globalization; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// Date of Easter calculated with Meeus's Julian algorithm. +/// The algorithm is described in Jean Meeus' Astronomical Algorithms (1991, p. 69). +/// +public static class JulianEaster { /// - /// Date of Easter calculated with Meeus's Julian algorithm. - /// The algorithm is described in Jean Meeus' Astronomical Algorithms (1991, p. 69). + /// Calculates the date of Easter. /// - public static class JulianEaster + /// Year to calculate the date of Easter. + /// Date of Easter as a DateTime. + public static DateTime Calculate(int year) { - /// - /// Calculates the date of Easter. - /// - /// Year to calculate the date of Easter. - /// Date of Easter as a DateTime. - public static DateTime Calculate(int year) - { - var a = year % 4; - var b = year % 7; - var c = year % 19; - var d = (19 * c + 15) % 30; - var e = (2 * a + 4 * b - d + 34) % 7; - var month = (int)Math.Floor((d + e + 114) / 31M); - var day = ((d + e + 114) % 31) + 1; + var a = year % 4; + var b = year % 7; + var c = year % 19; + var d = (19 * c + 15) % 30; + var e = (2 * a + 4 * b - d + 34) % 7; + var month = (int)Math.Floor((d + e + 114) / 31M); + var day = ((d + e + 114) % 31) + 1; - DateTime easter = new(year, month, day, new JulianCalendar()); + DateTime easter = new(year, month, day, new JulianCalendar()); - return easter; - } + return easter; } } diff --git a/Algorithms/Other/KochSnowflake.cs b/Algorithms/Other/KochSnowflake.cs index 5c3cd415..6ad5d6e4 100644 --- a/Algorithms/Other/KochSnowflake.cs +++ b/Algorithms/Other/KochSnowflake.cs @@ -3,155 +3,154 @@ using System.Drawing; using System.Numerics; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// The Koch snowflake is a fractal curve and one of the earliest fractals to +/// have been described. The Koch snowflake can be built up iteratively, in a +/// sequence of stages. The first stage is an equilateral triangle, and each +/// successive stage is formed by adding outward bends to each side of the +/// previous stage, making smaller equilateral triangles. +/// This can be achieved through the following steps for each line: +/// 1. divide the line segment into three segments of equal length. +/// 2. draw an equilateral triangle that has the middle segment from step 1 +/// as its base and points outward. +/// 3. remove the line segment that is the base of the triangle from step 2. +/// (description adapted from https://en.wikipedia.org/wiki/Koch_snowflake ) +/// (for a more detailed explanation and an implementation in the +/// Processing language, see https://natureofcode.com/book/chapter-8-fractals/ +/// #84-the-koch-curve-and-the-arraylist-technique ). +/// +public static class KochSnowflake { /// - /// The Koch snowflake is a fractal curve and one of the earliest fractals to - /// have been described. The Koch snowflake can be built up iteratively, in a - /// sequence of stages. The first stage is an equilateral triangle, and each - /// successive stage is formed by adding outward bends to each side of the - /// previous stage, making smaller equilateral triangles. - /// This can be achieved through the following steps for each line: - /// 1. divide the line segment into three segments of equal length. - /// 2. draw an equilateral triangle that has the middle segment from step 1 - /// as its base and points outward. - /// 3. remove the line segment that is the base of the triangle from step 2. - /// (description adapted from https://en.wikipedia.org/wiki/Koch_snowflake ) - /// (for a more detailed explanation and an implementation in the - /// Processing language, see https://natureofcode.com/book/chapter-8-fractals/ - /// #84-the-koch-curve-and-the-arraylist-technique ). + /// Go through the number of iterations determined by the argument "steps". + /// Be careful with high values (above 5) since the time to calculate increases + /// exponentially. /// - public static class KochSnowflake + /// + /// The vectors composing the shape to which + /// the algorithm is applied. + /// + /// The number of iterations. + /// The transformed vectors after the iteration-steps. + public static List Iterate(List initialVectors, int steps = 5) { - /// - /// Go through the number of iterations determined by the argument "steps". - /// Be careful with high values (above 5) since the time to calculate increases - /// exponentially. - /// - /// - /// The vectors composing the shape to which - /// the algorithm is applied. - /// - /// The number of iterations. - /// The transformed vectors after the iteration-steps. - public static List Iterate(List initialVectors, int steps = 5) + List vectors = initialVectors; + for (var i = 0; i < steps; i++) { - List vectors = initialVectors; - for (var i = 0; i < steps; i++) - { - vectors = IterationStep(vectors); - } - - return vectors; + vectors = IterationStep(vectors); } - /// - /// Method to render the Koch snowflake to a bitmap. To save the - /// bitmap the command 'GetKochSnowflake().Save("KochSnowflake.png")' can be used. - /// - /// The width of the rendered bitmap. - /// The number of iterations. - /// The bitmap of the rendered Koch snowflake. - public static Bitmap GetKochSnowflake( - int bitmapWidth = 600, - int steps = 5) - { - if (bitmapWidth <= 0) - { - throw new ArgumentOutOfRangeException( - nameof(bitmapWidth), - $"{nameof(bitmapWidth)} should be greater than zero"); - } - - var offsetX = bitmapWidth / 10f; - var offsetY = bitmapWidth / 3.7f; - var vector1 = new Vector2(offsetX, offsetY); - var vector2 = new Vector2(bitmapWidth / 2, (float)Math.Sin(Math.PI / 3) * bitmapWidth * 0.8f + offsetY); - var vector3 = new Vector2(bitmapWidth - offsetX, offsetY); - List initialVectors = new() { vector1, vector2, vector3, vector1 }; - List vectors = Iterate(initialVectors, steps); - return GetBitmap(vectors, bitmapWidth, bitmapWidth); - } + return vectors; + } - /// - /// Loops through each pair of adjacent vectors. Each line between two adjacent - /// vectors is divided into 4 segments by adding 3 additional vectors in-between - /// the original two vectors. The vector in the middle is constructed through a - /// 60 degree rotation so it is bent outwards. - /// - /// - /// The vectors composing the shape to which - /// the algorithm is applied. - /// - /// The transformed vectors after the iteration-step. - private static List IterationStep(List vectors) + /// + /// Method to render the Koch snowflake to a bitmap. To save the + /// bitmap the command 'GetKochSnowflake().Save("KochSnowflake.png")' can be used. + /// + /// The width of the rendered bitmap. + /// The number of iterations. + /// The bitmap of the rendered Koch snowflake. + public static Bitmap GetKochSnowflake( + int bitmapWidth = 600, + int steps = 5) + { + if (bitmapWidth <= 0) { - List newVectors = new(); - for (var i = 0; i < vectors.Count - 1; i++) - { - var startVector = vectors[i]; - var endVector = vectors[i + 1]; - newVectors.Add(startVector); - var differenceVector = endVector - startVector; - newVectors.Add(startVector + differenceVector / 3); - newVectors.Add(startVector + differenceVector / 3 + Rotate(differenceVector / 3, 60)); - newVectors.Add(startVector + differenceVector * 2 / 3); - } - - newVectors.Add(vectors[^1]); - return newVectors; + throw new ArgumentOutOfRangeException( + nameof(bitmapWidth), + $"{nameof(bitmapWidth)} should be greater than zero"); } - /// - /// Standard rotation of a 2D vector with a rotation matrix - /// (see https://en.wikipedia.org/wiki/Rotation_matrix ). - /// - /// The vector to be rotated. - /// The angle by which to rotate the vector. - /// The rotated vector. - private static Vector2 Rotate(Vector2 vector, float angleInDegrees) + var offsetX = bitmapWidth / 10f; + var offsetY = bitmapWidth / 3.7f; + var vector1 = new Vector2(offsetX, offsetY); + var vector2 = new Vector2(bitmapWidth / 2, (float)Math.Sin(Math.PI / 3) * bitmapWidth * 0.8f + offsetY); + var vector3 = new Vector2(bitmapWidth - offsetX, offsetY); + List initialVectors = new() { vector1, vector2, vector3, vector1 }; + List vectors = Iterate(initialVectors, steps); + return GetBitmap(vectors, bitmapWidth, bitmapWidth); + } + + /// + /// Loops through each pair of adjacent vectors. Each line between two adjacent + /// vectors is divided into 4 segments by adding 3 additional vectors in-between + /// the original two vectors. The vector in the middle is constructed through a + /// 60 degree rotation so it is bent outwards. + /// + /// + /// The vectors composing the shape to which + /// the algorithm is applied. + /// + /// The transformed vectors after the iteration-step. + private static List IterationStep(List vectors) + { + List newVectors = new(); + for (var i = 0; i < vectors.Count - 1; i++) { - var radians = angleInDegrees * (float)Math.PI / 180; - var ca = (float)Math.Cos(radians); - var sa = (float)Math.Sin(radians); - return new Vector2(ca * vector.X - sa * vector.Y, sa * vector.X + ca * vector.Y); + var startVector = vectors[i]; + var endVector = vectors[i + 1]; + newVectors.Add(startVector); + var differenceVector = endVector - startVector; + newVectors.Add(startVector + differenceVector / 3); + newVectors.Add(startVector + differenceVector / 3 + Rotate(differenceVector / 3, 60)); + newVectors.Add(startVector + differenceVector * 2 / 3); } - /// - /// Utility-method to render the Koch snowflake to a bitmap. - /// - /// The vectors defining the edges to be rendered. - /// The width of the rendered bitmap. - /// The height of the rendered bitmap. - /// The bitmap of the rendered edges. - private static Bitmap GetBitmap( - List vectors, - int bitmapWidth, - int bitmapHeight) + newVectors.Add(vectors[^1]); + return newVectors; + } + + /// + /// Standard rotation of a 2D vector with a rotation matrix + /// (see https://en.wikipedia.org/wiki/Rotation_matrix ). + /// + /// The vector to be rotated. + /// The angle by which to rotate the vector. + /// The rotated vector. + private static Vector2 Rotate(Vector2 vector, float angleInDegrees) + { + var radians = angleInDegrees * (float)Math.PI / 180; + var ca = (float)Math.Cos(radians); + var sa = (float)Math.Sin(radians); + return new Vector2(ca * vector.X - sa * vector.Y, sa * vector.X + ca * vector.Y); + } + + /// + /// Utility-method to render the Koch snowflake to a bitmap. + /// + /// The vectors defining the edges to be rendered. + /// The width of the rendered bitmap. + /// The height of the rendered bitmap. + /// The bitmap of the rendered edges. + private static Bitmap GetBitmap( + List vectors, + int bitmapWidth, + int bitmapHeight) + { + Bitmap bitmap = new(bitmapWidth, bitmapHeight); + + using (Graphics graphics = Graphics.FromImage(bitmap)) { - Bitmap bitmap = new(bitmapWidth, bitmapHeight); + // Set the background white + var imageSize = new Rectangle(0, 0, bitmapWidth, bitmapHeight); + graphics.FillRectangle(Brushes.White, imageSize); - using (Graphics graphics = Graphics.FromImage(bitmap)) + // Draw the edges + for (var i = 0; i < vectors.Count - 1; i++) { - // Set the background white - var imageSize = new Rectangle(0, 0, bitmapWidth, bitmapHeight); - graphics.FillRectangle(Brushes.White, imageSize); - - // Draw the edges - for (var i = 0; i < vectors.Count - 1; i++) - { - Pen blackPen = new(Color.Black, 1); + Pen blackPen = new(Color.Black, 1); - var x1 = vectors[i].X; - var y1 = vectors[i].Y; - var x2 = vectors[i + 1].X; - var y2 = vectors[i + 1].Y; + var x1 = vectors[i].X; + var y1 = vectors[i].Y; + var x2 = vectors[i + 1].X; + var y2 = vectors[i + 1].Y; - graphics.DrawLine(blackPen, x1, y1, x2, y2); - } + graphics.DrawLine(blackPen, x1, y1, x2, y2); } - - return bitmap; } + + return bitmap; } } diff --git a/Algorithms/Other/Luhn.cs b/Algorithms/Other/Luhn.cs index dc977d82..e9b1e54e 100644 --- a/Algorithms/Other/Luhn.cs +++ b/Algorithms/Other/Luhn.cs @@ -1,74 +1,73 @@ -using System; +using System; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// Luhn algorithm is a simple +/// checksum formula used to validate +/// a variety of identification numbers, +/// such as credit card numbers. +/// More information on the link: +/// https://en.wikipedia.org/wiki/Luhn_algorithm. +/// +public static class Luhn { /// - /// Luhn algorithm is a simple - /// checksum formula used to validate - /// a variety of identification numbers, - /// such as credit card numbers. - /// More information on the link: - /// https://en.wikipedia.org/wiki/Luhn_algorithm. + /// Checking the validity of a sequence of numbers. + /// + /// The number that will be checked for validity. + /// + /// True: Number is valid. + /// False: Number isn`t valid. + /// + public static bool Validate(string number) => GetSum(number) % 10 == 0; + + /// + /// This algorithm only finds one number. + /// In place of the unknown digit, put "x". /// - public static class Luhn + /// The number in which to find the missing digit. + /// Missing digit. + public static int GetLostNum(string number) { - /// - /// Checking the validity of a sequence of numbers. - /// - /// The number that will be checked for validity. - /// - /// True: Number is valid. - /// False: Number isn`t valid. - /// - public static bool Validate(string number) => GetSum(number) % 10 == 0; + var lostIndex = number.Length - 1 - number.LastIndexOf("x", StringComparison.CurrentCultureIgnoreCase); + var lostNum = GetSum(number.Replace("x", "0", StringComparison.CurrentCultureIgnoreCase)) * 9 % 10; - /// - /// This algorithm only finds one number. - /// In place of the unknown digit, put "x". - /// - /// The number in which to find the missing digit. - /// Missing digit. - public static int GetLostNum(string number) + // Case 1: If the index of the lost digit is even. + if (lostIndex % 2 == 0) { - var lostIndex = number.Length - 1 - number.LastIndexOf("x", StringComparison.CurrentCultureIgnoreCase); - var lostNum = GetSum(number.Replace("x", "0", StringComparison.CurrentCultureIgnoreCase)) * 9 % 10; - - // Case 1: If the index of the lost digit is even. - if (lostIndex % 2 == 0) - { - return lostNum; - } + return lostNum; + } - var tempLostNum = lostNum / 2; + var tempLostNum = lostNum / 2; - // Case 2: if the index of the lost digit isn`t even and that number <= 4. - // Case 3: if the index of the lost digit isn`t even and that number > 4. - return Validate(number.Replace("x", tempLostNum.ToString())) ? tempLostNum : (lostNum + 9) / 2; - } + // Case 2: if the index of the lost digit isn`t even and that number <= 4. + // Case 3: if the index of the lost digit isn`t even and that number > 4. + return Validate(number.Replace("x", tempLostNum.ToString())) ? tempLostNum : (lostNum + 9) / 2; + } - /// - /// Computes the sum found by the algorithm. - /// - /// The number for which the sum will be found. - /// Sum. - private static int GetSum(string number) + /// + /// Computes the sum found by the algorithm. + /// + /// The number for which the sum will be found. + /// Sum. + private static int GetSum(string number) + { + var sum = 0; + for (var i = 0; i < number.Length; i++) { - var sum = 0; - for (var i = 0; i < number.Length; i++) + var d = number[i] - '0'; + d = (i + number.Length) % 2 == 0 + ? 2 * d + : d; + if (d > 9) { - var d = number[i] - '0'; - d = (i + number.Length) % 2 == 0 - ? 2 * d - : d; - if (d > 9) - { - d -= 9; - } - - sum += d; + d -= 9; } - return sum; + sum += d; } + + return sum; } } diff --git a/Algorithms/Other/Mandelbrot.cs b/Algorithms/Other/Mandelbrot.cs index ac572db7..777bca2f 100644 --- a/Algorithms/Other/Mandelbrot.cs +++ b/Algorithms/Other/Mandelbrot.cs @@ -1,177 +1,176 @@ using System; using System.Drawing; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// The Mandelbrot set is the set of complex numbers "c" for which the series +/// "z_(n+1) = z_n * z_n + c" does not diverge, i.e. remains bounded. Thus, a +/// complex number "c" is a member of the Mandelbrot set if, when starting with +/// "z_0 = 0" and applying the iteration repeatedly, the absolute value of +/// "z_n" remains bounded for all "n > 0". Complex numbers can be written as +/// "a + b*i": "a" is the real component, usually drawn on the x-axis, and "b*i" +/// is the imaginary component, usually drawn on the y-axis. Most visualizations +/// of the Mandelbrot set use a color-coding to indicate after how many steps in +/// the series the numbers outside the set cross the divergence threshold. +/// Images of the Mandelbrot set exhibit an elaborate and infinitely +/// complicated boundary that reveals progressively ever-finer recursive detail +/// at increasing magnifications, making the boundary of the Mandelbrot set a +/// fractal curve. +/// (description adapted from https://en.wikipedia.org/wiki/Mandelbrot_set) +/// (see also https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set). +/// +public static class Mandelbrot { /// - /// The Mandelbrot set is the set of complex numbers "c" for which the series - /// "z_(n+1) = z_n * z_n + c" does not diverge, i.e. remains bounded. Thus, a - /// complex number "c" is a member of the Mandelbrot set if, when starting with - /// "z_0 = 0" and applying the iteration repeatedly, the absolute value of - /// "z_n" remains bounded for all "n > 0". Complex numbers can be written as - /// "a + b*i": "a" is the real component, usually drawn on the x-axis, and "b*i" - /// is the imaginary component, usually drawn on the y-axis. Most visualizations - /// of the Mandelbrot set use a color-coding to indicate after how many steps in - /// the series the numbers outside the set cross the divergence threshold. - /// Images of the Mandelbrot set exhibit an elaborate and infinitely - /// complicated boundary that reveals progressively ever-finer recursive detail - /// at increasing magnifications, making the boundary of the Mandelbrot set a - /// fractal curve. - /// (description adapted from https://en.wikipedia.org/wiki/Mandelbrot_set) - /// (see also https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set). + /// Method to generate the bitmap of the Mandelbrot set. Two types of coordinates + /// are used: bitmap-coordinates that refer to the pixels and figure-coordinates + /// that refer to the complex numbers inside and outside the Mandelbrot set. The + /// figure-coordinates in the arguments of this method determine which section + /// of the Mandelbrot set is viewed. The main area of the Mandelbrot set is + /// roughly between "-1.5 < x < 0.5" and "-1 < y < 1" in the figure-coordinates. + /// To save the bitmap the command 'GetBitmap().Save("Mandelbrot.png")' can be used. /// - public static class Mandelbrot + /// The width of the rendered bitmap. + /// The height of the rendered bitmap. + /// The x-coordinate of the center of the figure. + /// The y-coordinate of the center of the figure. + /// The width of the figure. + /// Maximum number of steps to check for divergent behavior. + /// Render in color or black and white. + /// The bitmap of the rendered Mandelbrot set. + public static Bitmap GetBitmap( + int bitmapWidth = 800, + int bitmapHeight = 600, + double figureCenterX = -0.6, + double figureCenterY = 0, + double figureWidth = 3.2, + int maxStep = 50, + bool useDistanceColorCoding = true) { - /// - /// Method to generate the bitmap of the Mandelbrot set. Two types of coordinates - /// are used: bitmap-coordinates that refer to the pixels and figure-coordinates - /// that refer to the complex numbers inside and outside the Mandelbrot set. The - /// figure-coordinates in the arguments of this method determine which section - /// of the Mandelbrot set is viewed. The main area of the Mandelbrot set is - /// roughly between "-1.5 < x < 0.5" and "-1 < y < 1" in the figure-coordinates. - /// To save the bitmap the command 'GetBitmap().Save("Mandelbrot.png")' can be used. - /// - /// The width of the rendered bitmap. - /// The height of the rendered bitmap. - /// The x-coordinate of the center of the figure. - /// The y-coordinate of the center of the figure. - /// The width of the figure. - /// Maximum number of steps to check for divergent behavior. - /// Render in color or black and white. - /// The bitmap of the rendered Mandelbrot set. - public static Bitmap GetBitmap( - int bitmapWidth = 800, - int bitmapHeight = 600, - double figureCenterX = -0.6, - double figureCenterY = 0, - double figureWidth = 3.2, - int maxStep = 50, - bool useDistanceColorCoding = true) + if (bitmapWidth <= 0) { - if (bitmapWidth <= 0) - { - throw new ArgumentOutOfRangeException( - nameof(bitmapWidth), - $"{nameof(bitmapWidth)} should be greater than zero"); - } + throw new ArgumentOutOfRangeException( + nameof(bitmapWidth), + $"{nameof(bitmapWidth)} should be greater than zero"); + } - if (bitmapHeight <= 0) - { - throw new ArgumentOutOfRangeException( - nameof(bitmapHeight), - $"{nameof(bitmapHeight)} should be greater than zero"); - } + if (bitmapHeight <= 0) + { + throw new ArgumentOutOfRangeException( + nameof(bitmapHeight), + $"{nameof(bitmapHeight)} should be greater than zero"); + } - if (maxStep <= 0) - { - throw new ArgumentOutOfRangeException( - nameof(maxStep), - $"{nameof(maxStep)} should be greater than zero"); - } + if (maxStep <= 0) + { + throw new ArgumentOutOfRangeException( + nameof(maxStep), + $"{nameof(maxStep)} should be greater than zero"); + } - var bitmap = new Bitmap(bitmapWidth, bitmapHeight); - var figureHeight = figureWidth / bitmapWidth * bitmapHeight; + var bitmap = new Bitmap(bitmapWidth, bitmapHeight); + var figureHeight = figureWidth / bitmapWidth * bitmapHeight; - // loop through the bitmap-coordinates - for (var bitmapX = 0; bitmapX < bitmapWidth; bitmapX++) + // loop through the bitmap-coordinates + for (var bitmapX = 0; bitmapX < bitmapWidth; bitmapX++) + { + for (var bitmapY = 0; bitmapY < bitmapHeight; bitmapY++) { - for (var bitmapY = 0; bitmapY < bitmapHeight; bitmapY++) - { - // determine the figure-coordinates based on the bitmap-coordinates - var figureX = figureCenterX + ((double)bitmapX / bitmapWidth - 0.5) * figureWidth; - var figureY = figureCenterY + ((double)bitmapY / bitmapHeight - 0.5) * figureHeight; - - var distance = GetDistance(figureX, figureY, maxStep); - - // color the corresponding pixel based on the selected coloring-function - bitmap.SetPixel( - bitmapX, - bitmapY, - useDistanceColorCoding ? ColorCodedColorMap(distance) : BlackAndWhiteColorMap(distance)); - } - } + // determine the figure-coordinates based on the bitmap-coordinates + var figureX = figureCenterX + ((double)bitmapX / bitmapWidth - 0.5) * figureWidth; + var figureY = figureCenterY + ((double)bitmapY / bitmapHeight - 0.5) * figureHeight; + + var distance = GetDistance(figureX, figureY, maxStep); - return bitmap; + // color the corresponding pixel based on the selected coloring-function + bitmap.SetPixel( + bitmapX, + bitmapY, + useDistanceColorCoding ? ColorCodedColorMap(distance) : BlackAndWhiteColorMap(distance)); + } } - /// - /// Black and white color-coding that ignores the relative distance. The Mandelbrot - /// set is black, everything else is white. - /// - /// Distance until divergence threshold. - /// The color corresponding to the distance. - private static Color BlackAndWhiteColorMap(double distance) => - distance >= 1 - ? Color.FromArgb(255, 0, 0, 0) - : Color.FromArgb(255, 255, 255, 255); - - /// - /// Color-coding taking the relative distance into account. The Mandelbrot set - /// is black. - /// - /// Distance until divergence threshold. - /// The color corresponding to the distance. - private static Color ColorCodedColorMap(double distance) + return bitmap; + } + + /// + /// Black and white color-coding that ignores the relative distance. The Mandelbrot + /// set is black, everything else is white. + /// + /// Distance until divergence threshold. + /// The color corresponding to the distance. + private static Color BlackAndWhiteColorMap(double distance) => + distance >= 1 + ? Color.FromArgb(255, 0, 0, 0) + : Color.FromArgb(255, 255, 255, 255); + + /// + /// Color-coding taking the relative distance into account. The Mandelbrot set + /// is black. + /// + /// Distance until divergence threshold. + /// The color corresponding to the distance. + private static Color ColorCodedColorMap(double distance) + { + if (distance >= 1) { - if (distance >= 1) - { - return Color.FromArgb(255, 0, 0, 0); - } + return Color.FromArgb(255, 0, 0, 0); + } - // simplified transformation of HSV to RGB - // distance determines hue - var hue = 360 * distance; - double saturation = 1; - double val = 255; - var hi = (int)Math.Floor(hue / 60) % 6; - var f = hue / 60 - Math.Floor(hue / 60); + // simplified transformation of HSV to RGB + // distance determines hue + var hue = 360 * distance; + double saturation = 1; + double val = 255; + var hi = (int)Math.Floor(hue / 60) % 6; + var f = hue / 60 - Math.Floor(hue / 60); - var v = (int)val; - var p = 0; - var q = (int)(val * (1 - f * saturation)); - var t = (int)(val * (1 - (1 - f) * saturation)); + var v = (int)val; + var p = 0; + var q = (int)(val * (1 - f * saturation)); + var t = (int)(val * (1 - (1 - f) * saturation)); - switch (hi) - { - case 0: return Color.FromArgb(255, v, t, p); - case 1: return Color.FromArgb(255, q, v, p); - case 2: return Color.FromArgb(255, p, v, t); - case 3: return Color.FromArgb(255, p, q, v); - case 4: return Color.FromArgb(255, t, p, v); - default: return Color.FromArgb(255, v, p, q); - } + switch (hi) + { + case 0: return Color.FromArgb(255, v, t, p); + case 1: return Color.FromArgb(255, q, v, p); + case 2: return Color.FromArgb(255, p, v, t); + case 3: return Color.FromArgb(255, p, q, v); + case 4: return Color.FromArgb(255, t, p, v); + default: return Color.FromArgb(255, v, p, q); } + } - /// - /// Return the relative distance (ratio of steps taken to maxStep) after which the complex number - /// constituted by this x-y-pair diverges. Members of the Mandelbrot set do not - /// diverge so their distance is 1. - /// - /// The x-coordinate within the figure. - /// The y-coordinate within the figure. - /// Maximum number of steps to check for divergent behavior. - /// The relative distance as the ratio of steps taken to maxStep. - private static double GetDistance(double figureX, double figureY, int maxStep) + /// + /// Return the relative distance (ratio of steps taken to maxStep) after which the complex number + /// constituted by this x-y-pair diverges. Members of the Mandelbrot set do not + /// diverge so their distance is 1. + /// + /// The x-coordinate within the figure. + /// The y-coordinate within the figure. + /// Maximum number of steps to check for divergent behavior. + /// The relative distance as the ratio of steps taken to maxStep. + private static double GetDistance(double figureX, double figureY, int maxStep) + { + var a = figureX; + var b = figureY; + var currentStep = 0; + for (var step = 0; step < maxStep; step++) { - var a = figureX; - var b = figureY; - var currentStep = 0; - for (var step = 0; step < maxStep; step++) + currentStep = step; + var aNew = a * a - b * b + figureX; + b = 2 * a * b + figureY; + a = aNew; + + // divergence happens for all complex number with an absolute value + // greater than 4 (= divergence threshold) + if (a * a + b * b > 4) { - currentStep = step; - var aNew = a * a - b * b + figureX; - b = 2 * a * b + figureY; - a = aNew; - - // divergence happens for all complex number with an absolute value - // greater than 4 (= divergence threshold) - if (a * a + b * b > 4) - { - break; - } + break; } - - return (double)currentStep / (maxStep - 1); } + + return (double)currentStep / (maxStep - 1); } } diff --git a/Algorithms/Other/ParetoOptimization.cs b/Algorithms/Other/ParetoOptimization.cs index 8f6ec2a5..1f5d198d 100644 --- a/Algorithms/Other/ParetoOptimization.cs +++ b/Algorithms/Other/ParetoOptimization.cs @@ -1,75 +1,71 @@ -using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// Almost all real complex decision-making task is described by more than one criterion. +/// Therefore, the methods of multicriteria optimization are important. For a wide range +/// of tasks multicriteria optimization, described by some axioms of "reasonable" +/// behavior in the process of choosing from a set of possible solutions X, each set of +/// selected solutions Sel X should be contained in a set optimal for Pareto. +/// +public class ParetoOptimization { /// - /// Almost all real complex decision-making task is described by more than one criterion. - /// Therefore, the methods of multicriteria optimization are important. For a wide range - /// of tasks multicriteria optimization, described by some axioms of "reasonable" - /// behavior in the process of choosing from a set of possible solutions X, each set of - /// selected solutions Sel X should be contained in a set optimal for Pareto. + /// Performs decision optimizations by using Paretor's optimization algorithm. /// - public class ParetoOptimization + /// Contains a collection of the criterias sets. + /// An optimized collection of the criterias sets. + public List> Optimize(List> matrix) { - /// - /// Performs decision optimizations by using Paretor's optimization algorithm. - /// - /// Contains a collection of the criterias sets. - /// An optimized collection of the criterias sets. - public List> Optimize(List> matrix) + var optimizedMatrix = new List>(matrix.Select(i => i)); + int i = 0; + while (i < optimizedMatrix.Count) { - var optimizedMatrix = new List>(matrix.Select(i => i)); - int i = 0; - while (i < optimizedMatrix.Count) + for (int j = i + 1; j < optimizedMatrix.Count; j++) { - for (int j = i + 1; j < optimizedMatrix.Count; j++) + decimal directParwiseDifference = GetMinimalPairwiseDifference(optimizedMatrix[i], optimizedMatrix[j]); + decimal indirectParwiseDifference = GetMinimalPairwiseDifference(optimizedMatrix[j], optimizedMatrix[i]); + /* + * in case all criteria of one set are larger that the criteria of another, this + * decision is not optimal and it has to be removed + */ + if (directParwiseDifference >= 0 || indirectParwiseDifference >= 0) { - decimal directParwiseDifference = GetMinimalPairwiseDifference(optimizedMatrix[i], optimizedMatrix[j]); - decimal indirectParwiseDifference = GetMinimalPairwiseDifference(optimizedMatrix[j], optimizedMatrix[i]); - /* - * in case all criteria of one set are larger that the criteria of another, this - * decision is not optimal and it has to be removed - */ - if (directParwiseDifference >= 0 || indirectParwiseDifference >= 0) - { - optimizedMatrix.RemoveAt(directParwiseDifference >= 0 ? j : i); - i--; - break; - } + optimizedMatrix.RemoveAt(directParwiseDifference >= 0 ? j : i); + i--; + break; } - - i++; } - return optimizedMatrix; + i++; } - /// - /// Calculates the smallest difference between criteria of input decisions. - /// - /// Criterias of the first decision. - /// Criterias of the second decision. - /// Values that represent the smallest difference between criteria of input decisions. - private decimal GetMinimalPairwiseDifference(List arr1, List arr2) + return optimizedMatrix; + } + + /// + /// Calculates the smallest difference between criteria of input decisions. + /// + /// Criterias of the first decision. + /// Criterias of the second decision. + /// Values that represent the smallest difference between criteria of input decisions. + private decimal GetMinimalPairwiseDifference(List arr1, List arr2) + { + decimal min = decimal.MaxValue; + if (arr1.Count == arr2.Count) { - decimal min = decimal.MaxValue; - if (arr1.Count == arr2.Count) + for (int i = 0; i < arr1.Count; i++) { - for (int i = 0; i < arr1.Count; i++) + decimal difference = arr1[i] - arr2[i]; + if (min > difference) { - decimal difference = arr1[i] - arr2[i]; - if (min > difference) - { - min = difference; - } + min = difference; } } - - return min; } + + return min; } } diff --git a/Algorithms/Other/PollardsRhoFactorizing.cs b/Algorithms/Other/PollardsRhoFactorizing.cs index b9c95a85..ceef6a8e 100644 --- a/Algorithms/Other/PollardsRhoFactorizing.cs +++ b/Algorithms/Other/PollardsRhoFactorizing.cs @@ -1,37 +1,36 @@ using System; using Algorithms.Numeric.GreatestCommonDivisor; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// Implementation of the Pollard's rho algorithm. +/// Algorithm for integer factorization. +/// Wiki: https://en.wikipedia.org/wiki/Pollard's_rho_algorithm. +/// +public static class PollardsRhoFactorizing { - /// Implementation of the Pollard's rho algorithm. - /// Algorithm for integer factorization. - /// Wiki: https://en.wikipedia.org/wiki/Pollard's_rho_algorithm. - /// - public static class PollardsRhoFactorizing + public static int Calculate(int number) { - public static int Calculate(int number) - { - var x = 2; - var y = 2; - var d = 1; - var p = number; - var i = 0; - var gcd = new BinaryGreatestCommonDivisorFinder(); - - while (d == 1) - { - x = Fun_g(x, p); - y = Fun_g(Fun_g(y, p), p); - d = gcd.FindGcd(Math.Abs(x - y), p); - i++; - } - - return d; - } + var x = 2; + var y = 2; + var d = 1; + var p = number; + var i = 0; + var gcd = new BinaryGreatestCommonDivisorFinder(); - private static int Fun_g(int x, int p) + while (d == 1) { - return (x * x + 1) % p; + x = Fun_g(x, p); + y = Fun_g(Fun_g(y, p), p); + d = gcd.FindGcd(Math.Abs(x - y), p); + i++; } + + return d; + } + + private static int Fun_g(int x, int p) + { + return (x * x + 1) % p; } } diff --git a/Algorithms/Other/RGBHSVConversion.cs b/Algorithms/Other/RGBHSVConversion.cs index d482222c..ecad76d3 100644 --- a/Algorithms/Other/RGBHSVConversion.cs +++ b/Algorithms/Other/RGBHSVConversion.cs @@ -1,149 +1,148 @@ -using System; +using System; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// The RGB color model is an additive color model in which red, green, and +/// blue light are added together in various ways to reproduce a broad array of +/// colors. The name of the model comes from the initials of the three additive +/// primary colors, red, green, and blue. Meanwhile, the HSV representation +/// models how colors appear under light. In it, colors are represented using +/// three components: hue, saturation and (brightness-)value. This class +/// provides methods for converting colors from one representation to the other. +/// (description adapted from https://en.wikipedia.org/wiki/RGB_color_model and +/// https://en.wikipedia.org/wiki/HSL_and_HSV). +/// +public static class RgbHsvConversion { /// - /// The RGB color model is an additive color model in which red, green, and - /// blue light are added together in various ways to reproduce a broad array of - /// colors. The name of the model comes from the initials of the three additive - /// primary colors, red, green, and blue. Meanwhile, the HSV representation - /// models how colors appear under light. In it, colors are represented using - /// three components: hue, saturation and (brightness-)value. This class - /// provides methods for converting colors from one representation to the other. - /// (description adapted from https://en.wikipedia.org/wiki/RGB_color_model and - /// https://en.wikipedia.org/wiki/HSL_and_HSV). + /// Conversion from the HSV-representation to the RGB-representation. /// - public static class RgbHsvConversion + /// Hue of the color. + /// Saturation of the color. + /// Brightness-value of the color. + /// The tuple of RGB-components. + public static (byte red, byte green, byte blue) HsvToRgb( + double hue, + double saturation, + double value) { - /// - /// Conversion from the HSV-representation to the RGB-representation. - /// - /// Hue of the color. - /// Saturation of the color. - /// Brightness-value of the color. - /// The tuple of RGB-components. - public static (byte red, byte green, byte blue) HsvToRgb( - double hue, - double saturation, - double value) + if (hue < 0 || hue > 360) { - if (hue < 0 || hue > 360) - { - throw new ArgumentOutOfRangeException(nameof(hue), $"{nameof(hue)} should be between 0 and 360"); - } - - if (saturation < 0 || saturation > 1) - { - throw new ArgumentOutOfRangeException( - nameof(saturation), - $"{nameof(saturation)} should be between 0 and 1"); - } - - if (value < 0 || value > 1) - { - throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(value)} should be between 0 and 1"); - } - - var chroma = value * saturation; - var hueSection = hue / 60; - var secondLargestComponent = chroma * (1 - Math.Abs(hueSection % 2 - 1)); - var matchValue = value - chroma; + throw new ArgumentOutOfRangeException(nameof(hue), $"{nameof(hue)} should be between 0 and 360"); + } - return GetRgbBySection(hueSection, chroma, matchValue, secondLargestComponent); + if (saturation < 0 || saturation > 1) + { + throw new ArgumentOutOfRangeException( + nameof(saturation), + $"{nameof(saturation)} should be between 0 and 1"); } - /// - /// Conversion from the RGB-representation to the HSV-representation. - /// - /// Red-component of the color. - /// Green-component of the color. - /// Blue-component of the color. - /// The tuple of HSV-components. - public static (double hue, double saturation, double value) RgbToHsv( - byte red, - byte green, - byte blue) + if (value < 0 || value > 1) { - var dRed = (double)red / 255; - var dGreen = (double)green / 255; - var dBlue = (double)blue / 255; - var value = Math.Max(Math.Max(dRed, dGreen), dBlue); - var chroma = value - Math.Min(Math.Min(dRed, dGreen), dBlue); - var saturation = value.Equals(0) ? 0 : chroma / value; - double hue; + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(value)} should be between 0 and 1"); + } - if (chroma.Equals(0)) - { - hue = 0; - } - else if (value.Equals(dRed)) - { - hue = 60 * (0 + (dGreen - dBlue) / chroma); - } - else if (value.Equals(dGreen)) - { - hue = 60 * (2 + (dBlue - dRed) / chroma); - } - else - { - hue = 60 * (4 + (dRed - dGreen) / chroma); - } + var chroma = value * saturation; + var hueSection = hue / 60; + var secondLargestComponent = chroma * (1 - Math.Abs(hueSection % 2 - 1)); + var matchValue = value - chroma; - hue = (hue + 360) % 360; + return GetRgbBySection(hueSection, chroma, matchValue, secondLargestComponent); + } - return (hue, saturation, value); - } + /// + /// Conversion from the RGB-representation to the HSV-representation. + /// + /// Red-component of the color. + /// Green-component of the color. + /// Blue-component of the color. + /// The tuple of HSV-components. + public static (double hue, double saturation, double value) RgbToHsv( + byte red, + byte green, + byte blue) + { + var dRed = (double)red / 255; + var dGreen = (double)green / 255; + var dBlue = (double)blue / 255; + var value = Math.Max(Math.Max(dRed, dGreen), dBlue); + var chroma = value - Math.Min(Math.Min(dRed, dGreen), dBlue); + var saturation = value.Equals(0) ? 0 : chroma / value; + double hue; - private static (byte red, byte green, byte blue) GetRgbBySection( - double hueSection, - double chroma, - double matchValue, - double secondLargestComponent) + if (chroma.Equals(0)) + { + hue = 0; + } + else if (value.Equals(dRed)) + { + hue = 60 * (0 + (dGreen - dBlue) / chroma); + } + else if (value.Equals(dGreen)) + { + hue = 60 * (2 + (dBlue - dRed) / chroma); + } + else { - byte red; - byte green; - byte blue; + hue = 60 * (4 + (dRed - dGreen) / chroma); + } + + hue = (hue + 360) % 360; - if (hueSection >= 0 && hueSection <= 1) - { - red = ConvertToByte(chroma + matchValue); - green = ConvertToByte(secondLargestComponent + matchValue); - blue = ConvertToByte(matchValue); - } - else if (hueSection > 1 && hueSection <= 2) - { - red = ConvertToByte(secondLargestComponent + matchValue); - green = ConvertToByte(chroma + matchValue); - blue = ConvertToByte(matchValue); - } - else if (hueSection > 2 && hueSection <= 3) - { - red = ConvertToByte(matchValue); - green = ConvertToByte(chroma + matchValue); - blue = ConvertToByte(secondLargestComponent + matchValue); - } - else if (hueSection > 3 && hueSection <= 4) - { - red = ConvertToByte(matchValue); - green = ConvertToByte(secondLargestComponent + matchValue); - blue = ConvertToByte(chroma + matchValue); - } - else if (hueSection > 4 && hueSection <= 5) - { - red = ConvertToByte(secondLargestComponent + matchValue); - green = ConvertToByte(matchValue); - blue = ConvertToByte(chroma + matchValue); - } - else - { - red = ConvertToByte(chroma + matchValue); - green = ConvertToByte(matchValue); - blue = ConvertToByte(secondLargestComponent + matchValue); - } + return (hue, saturation, value); + } + + private static (byte red, byte green, byte blue) GetRgbBySection( + double hueSection, + double chroma, + double matchValue, + double secondLargestComponent) + { + byte red; + byte green; + byte blue; - return (red, green, blue); + if (hueSection >= 0 && hueSection <= 1) + { + red = ConvertToByte(chroma + matchValue); + green = ConvertToByte(secondLargestComponent + matchValue); + blue = ConvertToByte(matchValue); + } + else if (hueSection > 1 && hueSection <= 2) + { + red = ConvertToByte(secondLargestComponent + matchValue); + green = ConvertToByte(chroma + matchValue); + blue = ConvertToByte(matchValue); + } + else if (hueSection > 2 && hueSection <= 3) + { + red = ConvertToByte(matchValue); + green = ConvertToByte(chroma + matchValue); + blue = ConvertToByte(secondLargestComponent + matchValue); + } + else if (hueSection > 3 && hueSection <= 4) + { + red = ConvertToByte(matchValue); + green = ConvertToByte(secondLargestComponent + matchValue); + blue = ConvertToByte(chroma + matchValue); + } + else if (hueSection > 4 && hueSection <= 5) + { + red = ConvertToByte(secondLargestComponent + matchValue); + green = ConvertToByte(matchValue); + blue = ConvertToByte(chroma + matchValue); + } + else + { + red = ConvertToByte(chroma + matchValue); + green = ConvertToByte(matchValue); + blue = ConvertToByte(secondLargestComponent + matchValue); } - private static byte ConvertToByte(double input) => (byte)Math.Round(255 * input); + return (red, green, blue); } + + private static byte ConvertToByte(double input) => (byte)Math.Round(255 * input); } diff --git a/Algorithms/Other/SieveOfEratosthenes.cs b/Algorithms/Other/SieveOfEratosthenes.cs index a118a5c7..72943fa0 100644 --- a/Algorithms/Other/SieveOfEratosthenes.cs +++ b/Algorithms/Other/SieveOfEratosthenes.cs @@ -1,70 +1,66 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Runtime.CompilerServices; -namespace Algorithms.Other +namespace Algorithms.Other; + +/// +/// Implements the Sieve of Eratosthenes. +/// +public class SieveOfEratosthenes { + private readonly bool[] primes; + /// - /// Implements the Sieve of Eratosthenes. + /// Initializes a new instance of the class. + /// Uses the Sieve of Eratosthenes to precalculate the primes from 0 up to maximumNumberToCheck. + /// Requires enough memory to allocate maximumNumberToCheck bytes. + /// https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes . /// - public class SieveOfEratosthenes + /// long which specifies the largest number you wish to know if it is prime. + public SieveOfEratosthenes(long maximumNumberToCheck) { - private readonly bool[] primes; - - /// - /// Initializes a new instance of the class. - /// Uses the Sieve of Eratosthenes to precalculate the primes from 0 up to maximumNumberToCheck. - /// Requires enough memory to allocate maximumNumberToCheck bytes. - /// https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes . - /// - /// long which specifies the largest number you wish to know if it is prime. - public SieveOfEratosthenes(long maximumNumberToCheck) - { - primes = new bool[maximumNumberToCheck + 1]; + primes = new bool[maximumNumberToCheck + 1]; - // initialize primes array - Array.Fill(this.primes, true, 2, primes.Length - 2); + // initialize primes array + Array.Fill(this.primes, true, 2, primes.Length - 2); - for(long i = 2; i * i <= maximumNumberToCheck; i++) + for(long i = 2; i * i <= maximumNumberToCheck; i++) + { + if (!primes[i]) { - if (!primes[i]) - { - continue; - } + continue; + } - for(long composite = i * i; composite <= maximumNumberToCheck; composite += i) - { - primes[composite] = false; - } + for(long composite = i * i; composite <= maximumNumberToCheck; composite += i) + { + primes[composite] = false; } } + } - /// - /// Gets the maximumNumberToCheck the class was instantiated with. - /// - public long MaximumNumber => primes.Length - 1; + /// + /// Gets the maximumNumberToCheck the class was instantiated with. + /// + public long MaximumNumber => primes.Length - 1; - /// - /// Returns a boolean indicating whether the number is prime. - /// - /// The number you desire to know if it is prime or not. - /// A boolean indicating whether the number is prime or not. - public bool IsPrime(long numberToCheck) => primes[numberToCheck]; + /// + /// Returns a boolean indicating whether the number is prime. + /// + /// The number you desire to know if it is prime or not. + /// A boolean indicating whether the number is prime or not. + public bool IsPrime(long numberToCheck) => primes[numberToCheck]; - /// - /// Returns an IEnumerable of long primes in asending order. - /// - /// Primes in ascending order. - public IEnumerable GetPrimes() + /// + /// Returns an IEnumerable of long primes in asending order. + /// + /// Primes in ascending order. + public IEnumerable GetPrimes() + { + for(long i = 2; i < primes.Length; i++) { - for(long i = 2; i < primes.Length; i++) + if (primes[i]) { - if (primes[i]) - { - yield return i; - } + yield return i; } } } diff --git a/Algorithms/Other/WelfordsVariance.cs b/Algorithms/Other/WelfordsVariance.cs index 9ed51edf..69235a34 100644 --- a/Algorithms/Other/WelfordsVariance.cs +++ b/Algorithms/Other/WelfordsVariance.cs @@ -1,72 +1,65 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Algorithms.Other; -namespace Algorithms.Other +/// Implementation of Welford's variance algorithm. +/// +public class WelfordsVariance { - /// Implementation of Welford's variance algorithm. + /// + /// Mean accumulates the mean of the entire dataset, + /// m2 aggregates the squared distance from the mean, + /// count aggregates the number of samples seen so far. /// - public class WelfordsVariance - { - /// - /// Mean accumulates the mean of the entire dataset, - /// m2 aggregates the squared distance from the mean, - /// count aggregates the number of samples seen so far. - /// - private int count; + private int count; - public double Count => count; + public double Count => count; - private double mean; + private double mean; - public double Mean => count > 1 ? mean : double.NaN; + public double Mean => count > 1 ? mean : double.NaN; - private double m2; + private double m2; - public double Variance => count > 1 ? m2 / count : double.NaN; + public double Variance => count > 1 ? m2 / count : double.NaN; - public double SampleVariance => count > 1 ? m2 / (count - 1) : double.NaN; + public double SampleVariance => count > 1 ? m2 / (count - 1) : double.NaN; - public WelfordsVariance() - { - count = 0; - mean = 0; - } + public WelfordsVariance() + { + count = 0; + mean = 0; + } - public WelfordsVariance(double[] values) - { - count = 0; - mean = 0; - AddRange(values); - } + public WelfordsVariance(double[] values) + { + count = 0; + mean = 0; + AddRange(values); + } - public void AddValue(double newValue) - { - count++; - AddValueToDataset(newValue); - } + public void AddValue(double newValue) + { + count++; + AddValueToDataset(newValue); + } - public void AddRange(double[] values) + public void AddRange(double[] values) + { + var length = values.Length; + for (var i = 1; i <= length; i++) { - var length = values.Length; - for (var i = 1; i <= length; i++) - { - count++; - AddValueToDataset(values[i - 1]); - } + count++; + AddValueToDataset(values[i - 1]); } + } - private void AddValueToDataset(double newValue) - { - var delta1 = newValue - mean; - var newMean = mean + delta1 / count; + private void AddValueToDataset(double newValue) + { + var delta1 = newValue - mean; + var newMean = mean + delta1 / count; - var delta2 = newValue - newMean; - m2 += delta1 * delta2; + var delta2 = newValue - newMean; + m2 += delta1 * delta2; - mean = newMean; - } + mean = newMean; } } diff --git a/Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs b/Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs index e05f4593..b6faeb8d 100644 --- a/Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs +++ b/Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs @@ -1,174 +1,173 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace Algorithms.Problems.DynamicProgramming.CoinChange +namespace Algorithms.Problems.DynamicProgramming.CoinChange; + +public static class DynamicCoinChangeSolver { - public static class DynamicCoinChangeSolver + /// + /// Generates an array of changes for current coin. + /// For instance, having coin C = 6 and array A = [1,3,4] it returns an array R = [2,3,5]. + /// Because, 6 - 4 = 2, 6 - 3 = 3, 6 - 1 = 5. + /// + /// The value of the coin to be exchanged. + /// An array of available coins. + /// Array of changes of current coins by available coins. + public static int[] GenerateSingleCoinChanges(int coin, int[] coins) { - /// - /// Generates an array of changes for current coin. - /// For instance, having coin C = 6 and array A = [1,3,4] it returns an array R = [2,3,5]. - /// Because, 6 - 4 = 2, 6 - 3 = 3, 6 - 1 = 5. - /// - /// The value of the coin to be exchanged. - /// An array of available coins. - /// Array of changes of current coins by available coins. - public static int[] GenerateSingleCoinChanges(int coin, int[] coins) - { - ValidateCoin(coin); - ValidateCoinsArray(coins); + ValidateCoin(coin); + ValidateCoinsArray(coins); - var coinsArrayCopy = new int[coins.Length]; + var coinsArrayCopy = new int[coins.Length]; - Array.Copy(coins, coinsArrayCopy, coins.Length); - Array.Sort(coinsArrayCopy); - Array.Reverse(coinsArrayCopy); + Array.Copy(coins, coinsArrayCopy, coins.Length); + Array.Sort(coinsArrayCopy); + Array.Reverse(coinsArrayCopy); - var list = new List(); + var list = new List(); - foreach (var item in coinsArrayCopy) + foreach (var item in coinsArrayCopy) + { + if (item > coin) { - if (item > coin) - { - continue; - } - - var difference = coin - item; - - list.Add(difference); + continue; } - var result = list.ToArray(); + var difference = coin - item; - return result; + list.Add(difference); } - /// - /// Given a positive integer N, such as coin. - /// Generates a change dictionary for all values [1,N]. - /// Used in so-called backward induction in search of the minimum exchange. - /// - /// The value of coin. - /// Array of available coins. - /// Change dictionary for all values [1,N], where N is the coin. - public static Dictionary GenerateChangesDictionary(int coin, int[] coins) - { - var dict = new Dictionary(); - var currentCoin = 1; + var result = list.ToArray(); - while (currentCoin <= coin) - { - var changeArray = GenerateSingleCoinChanges(currentCoin, coins); - dict[currentCoin] = changeArray; - currentCoin++; - } + return result; + } - return dict; - } + /// + /// Given a positive integer N, such as coin. + /// Generates a change dictionary for all values [1,N]. + /// Used in so-called backward induction in search of the minimum exchange. + /// + /// The value of coin. + /// Array of available coins. + /// Change dictionary for all values [1,N], where N is the coin. + public static Dictionary GenerateChangesDictionary(int coin, int[] coins) + { + var dict = new Dictionary(); + var currentCoin = 1; - /// - /// Gets a next coin value, such that changes array contains the minimal change overall possible changes. - /// For example, having coin N = 6 and A = [1,3,4] coins array. - /// The minimum next coin for 6 will be 3, because changes of 3 by A = [1,3,4] contains 0, the minimal change. - /// - /// Coin to be exchanged. - /// Dictionary of exchanges for [1, coin]. - /// Index of the next coin with minimal exchange. - public static int GetMinimalNextCoin(int coin, Dictionary exchanges) + while (currentCoin <= coin) { - var nextCoin = int.MaxValue; - var minChange = int.MaxValue; - - var coinChanges = exchanges[coin]; + var changeArray = GenerateSingleCoinChanges(currentCoin, coins); + dict[currentCoin] = changeArray; + currentCoin++; + } - foreach (var change in coinChanges) - { - if (change == 0) - { - return 0; - } + return dict; + } - var currentChange = exchanges[change]; - var min = currentChange.Min(); + /// + /// Gets a next coin value, such that changes array contains the minimal change overall possible changes. + /// For example, having coin N = 6 and A = [1,3,4] coins array. + /// The minimum next coin for 6 will be 3, because changes of 3 by A = [1,3,4] contains 0, the minimal change. + /// + /// Coin to be exchanged. + /// Dictionary of exchanges for [1, coin]. + /// Index of the next coin with minimal exchange. + public static int GetMinimalNextCoin(int coin, Dictionary exchanges) + { + var nextCoin = int.MaxValue; + var minChange = int.MaxValue; - var minIsLesser = min < minChange; + var coinChanges = exchanges[coin]; - if (minIsLesser) - { - nextCoin = change; - minChange = min; - } + foreach (var change in coinChanges) + { + if (change == 0) + { + return 0; } - return nextCoin; - } + var currentChange = exchanges[change]; + var min = currentChange.Min(); - /// - /// Performs a coin change such that an amount of coins is minimal. - /// - /// The value of coin to be exchanged. - /// An array of available coins. - /// Array of exchanges. - public static int[] MakeCoinChangeDynamic(int coin, int[] coins) - { - var changesTable = GenerateChangesDictionary(coin, coins); - var list = new List(); + var minIsLesser = min < minChange; - var currentCoin = coin; - var nextCoin = int.MaxValue; - - while (nextCoin != 0) + if (minIsLesser) { - nextCoin = GetMinimalNextCoin(currentCoin, changesTable); - var difference = currentCoin - nextCoin; - list.Add(difference); - currentCoin = nextCoin; + nextCoin = change; + minChange = min; } + } + + return nextCoin; + } - var result = list.ToArray(); + /// + /// Performs a coin change such that an amount of coins is minimal. + /// + /// The value of coin to be exchanged. + /// An array of available coins. + /// Array of exchanges. + public static int[] MakeCoinChangeDynamic(int coin, int[] coins) + { + var changesTable = GenerateChangesDictionary(coin, coins); + var list = new List(); - return result; - } + var currentCoin = coin; + var nextCoin = int.MaxValue; - private static void ValidateCoin(int coin) + while (nextCoin != 0) { - if (coin <= 0) - { - throw new InvalidOperationException($"The coin cannot be lesser or equal to zero {nameof(coin)}."); - } + nextCoin = GetMinimalNextCoin(currentCoin, changesTable); + var difference = currentCoin - nextCoin; + list.Add(difference); + currentCoin = nextCoin; } - private static void ValidateCoinsArray(int[] coinsArray) + var result = list.ToArray(); + + return result; + } + + private static void ValidateCoin(int coin) + { + if (coin <= 0) { - var coinsAsArray = coinsArray.ToArray(); + throw new InvalidOperationException($"The coin cannot be lesser or equal to zero {nameof(coin)}."); + } + } - if (coinsAsArray.Length == 0) - { - throw new InvalidOperationException($"Coins array cannot be empty {nameof(coinsAsArray)}."); - } + private static void ValidateCoinsArray(int[] coinsArray) + { + var coinsAsArray = coinsArray.ToArray(); - var coinsContainOne = coinsAsArray.Any(x => x == 1); + if (coinsAsArray.Length == 0) + { + throw new InvalidOperationException($"Coins array cannot be empty {nameof(coinsAsArray)}."); + } - if (!coinsContainOne) - { - throw new InvalidOperationException($"Coins array must contain coin 1 {nameof(coinsAsArray)}."); - } + var coinsContainOne = coinsAsArray.Any(x => x == 1); - var containsNonPositive = coinsAsArray.Any(x => x <= 0); + if (!coinsContainOne) + { + throw new InvalidOperationException($"Coins array must contain coin 1 {nameof(coinsAsArray)}."); + } - if (containsNonPositive) - { - throw new InvalidOperationException( - $"{nameof(coinsAsArray)} cannot contain numbers less than or equal to zero"); - } + var containsNonPositive = coinsAsArray.Any(x => x <= 0); - var containsDuplicates = coinsAsArray.GroupBy(x => x).Any(g => g.Count() > 1); + if (containsNonPositive) + { + throw new InvalidOperationException( + $"{nameof(coinsAsArray)} cannot contain numbers less than or equal to zero"); + } - if (containsDuplicates) - { - throw new InvalidOperationException($"Coins array cannot contain duplicates {nameof(coinsAsArray)}."); - } + var containsDuplicates = coinsAsArray.GroupBy(x => x).Any(g => g.Count() > 1); + + if (containsDuplicates) + { + throw new InvalidOperationException($"Coins array cannot contain duplicates {nameof(coinsAsArray)}."); } } } diff --git a/Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs b/Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs index 30a33846..4adb3e27 100644 --- a/Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs +++ b/Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs @@ -1,48 +1,47 @@ using System; -namespace Algorithms.Problems.DynamicProgramming +namespace Algorithms.Problems.DynamicProgramming; + +/// +/// +/// Levenshtein distance between two words is the minimum number of single-character edits (insertions, deletions or substitutions) required to change one word into the other. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Levenshtein_distance. +/// +/// +public static class LevenshteinDistance { /// - /// - /// Levenshtein distance between two words is the minimum number of single-character edits (insertions, deletions or substitutions) required to change one word into the other. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Levenshtein_distance. - /// + /// Calculates Levenshtein distance. + /// Time and space complexity is O(ab) where a and b are the lengths of the source and target strings. /// - public static class LevenshteinDistance + /// Source string. + /// Target string. + /// Levenshtein distance between source and target strings. + public static int Calculate(string source, string target) { - /// - /// Calculates Levenshtein distance. - /// Time and space complexity is O(ab) where a and b are the lengths of the source and target strings. - /// - /// Source string. - /// Target string. - /// Levenshtein distance between source and target strings. - public static int Calculate(string source, string target) - { - var distances = new int[source.Length + 1, target.Length + 1]; + var distances = new int[source.Length + 1, target.Length + 1]; - for(var i = 0; i <= source.Length; i++) - { - distances[i, 0] = i; - } + for(var i = 0; i <= source.Length; i++) + { + distances[i, 0] = i; + } - for (var i = 0; i <= target.Length; i++) - { - distances[0, i] = i; - } + for (var i = 0; i <= target.Length; i++) + { + distances[0, i] = i; + } - for (var i = 1; i <= source.Length; i++) + for (var i = 1; i <= source.Length; i++) + { + for (var j = 1; j <= target.Length; j++) { - for (var j = 1; j <= target.Length; j++) - { - var substitionCost = source[i - 1] == target[j - 1] ? 0 : 1; - distances[i, j] = Math.Min(distances[i - 1, j] + 1, Math.Min(distances[i, j - 1] + 1, distances[i - 1, j - 1] + substitionCost)); - } + var substitionCost = source[i - 1] == target[j - 1] ? 0 : 1; + distances[i, j] = Math.Min(distances[i - 1, j] + 1, Math.Min(distances[i, j - 1] + 1, distances[i - 1, j - 1] + substitionCost)); } - - return distances[source.Length, target.Length]; } + + return distances[source.Length, target.Length]; } } diff --git a/Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs b/Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs index 217c53b6..744c6214 100644 --- a/Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs +++ b/Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs @@ -1,108 +1,107 @@ -using System; +using System; using System.Collections.Generic; -namespace Algorithms.Problems.NQueens +namespace Algorithms.Problems.NQueens; + +public class BacktrackingNQueensSolver { - public class BacktrackingNQueensSolver + /// + /// Solves N-Queen Problem given a n dimension chessboard and using backtracking with recursion algorithm. + /// If we find a dead-end within or current solution we go back and try another position for queen. + /// + /// Number of rows. + /// All solutions. + public IEnumerable BacktrackSolve(int n) { - /// - /// Solves N-Queen Problem given a n dimension chessboard and using backtracking with recursion algorithm. - /// If we find a dead-end within or current solution we go back and try another position for queen. - /// - /// Number of rows. - /// All solutions. - public IEnumerable BacktrackSolve(int n) + if (n < 0) { - if (n < 0) - { - throw new ArgumentException(nameof(n)); - } - - return BacktrackSolve(new bool[n, n], 0); + throw new ArgumentException(nameof(n)); } - private static IEnumerable BacktrackSolve(bool[,] board, int col) - { - var solutions = col < board.GetLength(0) - 1 - ? HandleIntermediateColumn(board, col) - : HandleLastColumn(board); - return solutions; - } + return BacktrackSolve(new bool[n, n], 0); + } - private static IEnumerable HandleIntermediateColumn(bool[,] board, int col) + private static IEnumerable BacktrackSolve(bool[,] board, int col) + { + var solutions = col < board.GetLength(0) - 1 + ? HandleIntermediateColumn(board, col) + : HandleLastColumn(board); + return solutions; + } + + private static IEnumerable HandleIntermediateColumn(bool[,] board, int col) + { + // To start placing queens on possible spaces within the board. + for (var i = 0; i < board.GetLength(0); i++) { - // To start placing queens on possible spaces within the board. - for (var i = 0; i < board.GetLength(0); i++) + if (CanPlace(board, i, col)) { - if (CanPlace(board, i, col)) - { - board[i, col] = true; - - foreach (var solution in BacktrackSolve(board, col + 1)) - { - yield return solution; - } + board[i, col] = true; - board[i, col] = false; + foreach (var solution in BacktrackSolve(board, col + 1)) + { + yield return solution; } + + board[i, col] = false; } } + } - private static IEnumerable HandleLastColumn(bool[,] board) + private static IEnumerable HandleLastColumn(bool[,] board) + { + var n = board.GetLength(0); + for (var i = 0; i < n; i++) { - var n = board.GetLength(0); - for (var i = 0; i < n; i++) + if (CanPlace(board, i, n - 1)) { - if (CanPlace(board, i, n - 1)) - { - board[i, n - 1] = true; + board[i, n - 1] = true; - yield return (bool[,])board.Clone(); + yield return (bool[,])board.Clone(); - board[i, n - 1] = false; - } + board[i, n - 1] = false; } } + } - /// - /// Checks whether current queen can be placed in current position, - /// outside attacking range of another queen. - /// - /// Source board. - /// Row coordinate. - /// Col coordinate. - /// true if queen can be placed in given chessboard coordinates; false otherwise. - private static bool CanPlace(bool[,] board, int row, int col) + /// + /// Checks whether current queen can be placed in current position, + /// outside attacking range of another queen. + /// + /// Source board. + /// Row coordinate. + /// Col coordinate. + /// true if queen can be placed in given chessboard coordinates; false otherwise. + private static bool CanPlace(bool[,] board, int row, int col) + { + // To check whether there are any queens on current row. + for (var i = 0; i < col; i++) { - // To check whether there are any queens on current row. - for (var i = 0; i < col; i++) + if (board[row, i]) { - if (board[row, i]) - { - return false; - } + return false; } + } - // To check diagonal attack top-left range. - for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) + // To check diagonal attack top-left range. + for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) + { + if (board[i, j]) { - if (board[i, j]) - { - return false; - } + return false; } + } - // To check diagonal attack bottom-left range. - for (int i = row + 1, j = col - 1; j >= 0 && i < board.GetLength(0); i++, j--) + // To check diagonal attack bottom-left range. + for (int i = row + 1, j = col - 1; j >= 0 && i < board.GetLength(0); i++, j--) + { + if (board[i, j]) { - if (board[i, j]) - { - return false; - } + return false; } - - // Return true if it can use position. - return true; } + + // Return true if it can use position. + return true; } } diff --git a/Algorithms/Problems/StableMarriage/Accepter.cs b/Algorithms/Problems/StableMarriage/Accepter.cs index 10a15d3b..430e2cd2 100644 --- a/Algorithms/Problems/StableMarriage/Accepter.cs +++ b/Algorithms/Problems/StableMarriage/Accepter.cs @@ -1,15 +1,14 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Problems.StableMarriage +namespace Algorithms.Problems.StableMarriage; + +public class Accepter { - public class Accepter - { - public Proposer? EngagedTo { get; set; } + public Proposer? EngagedTo { get; set; } - public List PreferenceOrder { get; set; } = new(); + public List PreferenceOrder { get; set; } = new(); - public bool PrefersOverCurrent(Proposer newProposer) => - EngagedTo is null || - PreferenceOrder.IndexOf(newProposer) < PreferenceOrder.IndexOf(EngagedTo); - } + public bool PrefersOverCurrent(Proposer newProposer) => + EngagedTo is null || + PreferenceOrder.IndexOf(newProposer) < PreferenceOrder.IndexOf(EngagedTo); } diff --git a/Algorithms/Problems/StableMarriage/GaleShapley.cs b/Algorithms/Problems/StableMarriage/GaleShapley.cs index f25edd29..521e2be0 100644 --- a/Algorithms/Problems/StableMarriage/GaleShapley.cs +++ b/Algorithms/Problems/StableMarriage/GaleShapley.cs @@ -1,66 +1,65 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace Algorithms.Problems.StableMarriage +namespace Algorithms.Problems.StableMarriage; + +public static class GaleShapley { - public static class GaleShapley + /// + /// Finds a stable matching between two equal sets of elements (fills EngagedTo properties). + /// time complexity: O(n^2), where n - array size. + /// Guarantees: + /// - Everyone is matched + /// - Matches are stable (there is no better accepter, for any given proposer, which would accept a new match). + /// Presented and proven by David Gale and Lloyd Shapley in 1962. + /// + public static void Match(Proposer[] proposers, Accepter[] accepters) { - /// - /// Finds a stable matching between two equal sets of elements (fills EngagedTo properties). - /// time complexity: O(n^2), where n - array size. - /// Guarantees: - /// - Everyone is matched - /// - Matches are stable (there is no better accepter, for any given proposer, which would accept a new match). - /// Presented and proven by David Gale and Lloyd Shapley in 1962. - /// - public static void Match(Proposer[] proposers, Accepter[] accepters) + if (proposers.Length != accepters.Length) { - if (proposers.Length != accepters.Length) - { - throw new ArgumentException("Collections must have equal count"); - } + throw new ArgumentException("Collections must have equal count"); + } - while (proposers.Any(m => !IsEngaged(m))) - { - DoSingleMatchingRound(proposers.Where(m => !IsEngaged(m))); - } + while (proposers.Any(m => !IsEngaged(m))) + { + DoSingleMatchingRound(proposers.Where(m => !IsEngaged(m))); } + } - private static bool IsEngaged(Proposer proposer) => proposer.EngagedTo is not null; + private static bool IsEngaged(Proposer proposer) => proposer.EngagedTo is not null; - private static void DoSingleMatchingRound(IEnumerable proposers) + private static void DoSingleMatchingRound(IEnumerable proposers) + { + foreach (var newProposer in proposers) { - foreach (var newProposer in proposers) - { - var accepter = newProposer.PreferenceOrder.First!.Value; + var accepter = newProposer.PreferenceOrder.First!.Value; - if (accepter.EngagedTo is null) + if (accepter.EngagedTo is null) + { + Engage(newProposer, accepter); + } + else + { + if (accepter.PrefersOverCurrent(newProposer)) { + Free(accepter.EngagedTo); Engage(newProposer, accepter); } - else - { - if (accepter.PrefersOverCurrent(newProposer)) - { - Free(accepter.EngagedTo); - Engage(newProposer, accepter); - } - } - - newProposer.PreferenceOrder.RemoveFirst(); } - } - private static void Free(Proposer proposer) - { - proposer.EngagedTo = null; + newProposer.PreferenceOrder.RemoveFirst(); } + } - private static void Engage(Proposer proposer, Accepter accepter) - { - proposer.EngagedTo = accepter; - accepter.EngagedTo = proposer; - } + private static void Free(Proposer proposer) + { + proposer.EngagedTo = null; + } + + private static void Engage(Proposer proposer, Accepter accepter) + { + proposer.EngagedTo = accepter; + accepter.EngagedTo = proposer; } } diff --git a/Algorithms/Problems/StableMarriage/Proposer.cs b/Algorithms/Problems/StableMarriage/Proposer.cs index 913f08c2..bb05f26a 100644 --- a/Algorithms/Problems/StableMarriage/Proposer.cs +++ b/Algorithms/Problems/StableMarriage/Proposer.cs @@ -1,11 +1,10 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Problems.StableMarriage +namespace Algorithms.Problems.StableMarriage; + +public class Proposer { - public class Proposer - { - public Accepter? EngagedTo { get; set; } + public Accepter? EngagedTo { get; set; } - public LinkedList PreferenceOrder { get; set; } = new(); - } + public LinkedList PreferenceOrder { get; set; } = new(); } diff --git a/Algorithms/Search/AStar/AStar.cs b/Algorithms/Search/AStar/AStar.cs index 52101695..d5e86eaa 100644 --- a/Algorithms/Search/AStar/AStar.cs +++ b/Algorithms/Search/AStar/AStar.cs @@ -1,143 +1,142 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Search.AStar +namespace Algorithms.Search.AStar; + +/// +/// Contains the code for A* Pathfinding. +/// +public static class AStar { /// - /// Contains the code for A* Pathfinding. + /// Resets the Nodes in the list. /// - public static class AStar + /// Resets the nodes to be used again. + public static void ResetNodes(List nodes) { - /// - /// Resets the Nodes in the list. - /// - /// Resets the nodes to be used again. - public static void ResetNodes(List nodes) + foreach (var node in nodes) { - foreach (var node in nodes) - { - node.CurrentCost = 0; - node.EstimatedCost = 0; - node.Parent = null; - node.State = NodeState.Unconsidered; - } + node.CurrentCost = 0; + node.EstimatedCost = 0; + node.Parent = null; + node.State = NodeState.Unconsidered; } + } - /// - /// Generates the Path from an (solved) node graph, before it gets reset. - /// - /// The node where we want to go. - /// The Path to the target node. - public static List GeneratePath(Node target) + /// + /// Generates the Path from an (solved) node graph, before it gets reset. + /// + /// The node where we want to go. + /// The Path to the target node. + public static List GeneratePath(Node target) + { + var ret = new List(); + var current = target; + while (!(current is null)) { - var ret = new List(); - var current = target; - while (!(current is null)) - { - ret.Add(current); - current = current.Parent; - } - - ret.Reverse(); - return ret; + ret.Add(current); + current = current.Parent; } - /// - /// Computes the path from => to. - /// - /// Start node. - /// end node. - /// Path from start to end. - public static List Compute(Node from, Node to) - { - var done = new List(); + ret.Reverse(); + return ret; + } + + /// + /// Computes the path from => to. + /// + /// Start node. + /// end node. + /// Path from start to end. + public static List Compute(Node from, Node to) + { + var done = new List(); - // A priority queue that will sort our nodes based on the total cost estimate - var open = new PriorityQueue(); - foreach (var node in from.ConnectedNodes) + // A priority queue that will sort our nodes based on the total cost estimate + var open = new PriorityQueue(); + foreach (var node in from.ConnectedNodes) + { + // Add connecting nodes if traversable + if (node.Traversable) { - // Add connecting nodes if traversable - if (node.Traversable) - { - // Calculate the Costs - node.CurrentCost = from.CurrentCost + from.DistanceTo(node) * node.TraversalCostMultiplier; - node.EstimatedCost = from.CurrentCost + node.DistanceTo(to); + // Calculate the Costs + node.CurrentCost = from.CurrentCost + from.DistanceTo(node) * node.TraversalCostMultiplier; + node.EstimatedCost = from.CurrentCost + node.DistanceTo(to); - // Enqueue - open.Enqueue(node); - } + // Enqueue + open.Enqueue(node); } + } - while (true) + while (true) + { + // End Condition( Path not found ) + if (open.Count == 0) { - // End Condition( Path not found ) - if (open.Count == 0) - { - ResetNodes(done); - ResetNodes(open.GetData()); - return new List(); - } - - // Selecting next Element from queue - var current = open.Dequeue(); + ResetNodes(done); + ResetNodes(open.GetData()); + return new List(); + } - // Add it to the done list - done.Add(current); + // Selecting next Element from queue + var current = open.Dequeue(); - current.State = NodeState.Closed; + // Add it to the done list + done.Add(current); - // EndCondition( Path was found ) - if (current == to) - { - var ret = GeneratePath(to); // Create the Path + current.State = NodeState.Closed; - // Reset all Nodes that were used. - ResetNodes(done); - ResetNodes(open.GetData()); - return ret; - } + // EndCondition( Path was found ) + if (current == to) + { + var ret = GeneratePath(to); // Create the Path - AddOrUpdateConnected(current, to, open); + // Reset all Nodes that were used. + ResetNodes(done); + ResetNodes(open.GetData()); + return ret; } + + AddOrUpdateConnected(current, to, open); } + } - private static void AddOrUpdateConnected(Node current, Node to, PriorityQueue queue) + private static void AddOrUpdateConnected(Node current, Node to, PriorityQueue queue) + { + foreach (var connected in current.ConnectedNodes) { - foreach (var connected in current.ConnectedNodes) + if (!connected.Traversable || + connected.State == NodeState.Closed) { - if (!connected.Traversable || - connected.State == NodeState.Closed) - { - continue; // Do ignore already checked and not traversable nodes. - } + continue; // Do ignore already checked and not traversable nodes. + } - // Adds a previously not "seen" node into the Queue - if (connected.State == NodeState.Unconsidered) + // Adds a previously not "seen" node into the Queue + if (connected.State == NodeState.Unconsidered) + { + connected.Parent = current; + connected.CurrentCost = + current.CurrentCost + current.DistanceTo(connected) * connected.TraversalCostMultiplier; + connected.EstimatedCost = connected.CurrentCost + connected.DistanceTo(to); + connected.State = NodeState.Open; + queue.Enqueue(connected); + } + else if (current != connected) + { + // Updating the cost of the node if the current way is cheaper than the previous + var newCCost = current.CurrentCost + current.DistanceTo(connected); + var newTCost = newCCost + current.EstimatedCost; + if (newTCost < connected.TotalCost) { connected.Parent = current; - connected.CurrentCost = - current.CurrentCost + current.DistanceTo(connected) * connected.TraversalCostMultiplier; - connected.EstimatedCost = connected.CurrentCost + connected.DistanceTo(to); - connected.State = NodeState.Open; - queue.Enqueue(connected); - } - else if (current != connected) - { - // Updating the cost of the node if the current way is cheaper than the previous - var newCCost = current.CurrentCost + current.DistanceTo(connected); - var newTCost = newCCost + current.EstimatedCost; - if (newTCost < connected.TotalCost) - { - connected.Parent = current; - connected.CurrentCost = newCCost; - } - } - else - { - // Codacy made me do it. - throw new PathfindingException( - "Detected the same node twice. Confusion how this could ever happen"); + connected.CurrentCost = newCCost; } } + else + { + // Codacy made me do it. + throw new PathfindingException( + "Detected the same node twice. Confusion how this could ever happen"); + } } } } diff --git a/Algorithms/Search/AStar/Node.cs b/Algorithms/Search/AStar/Node.cs index 4f80bf10..fbc353ce 100644 --- a/Algorithms/Search/AStar/Node.cs +++ b/Algorithms/Search/AStar/Node.cs @@ -1,102 +1,101 @@ -using System; +using System; -namespace Algorithms.Search.AStar +namespace Algorithms.Search.AStar; + +/// +/// Contains Positional and other information about a single node. +/// +public class Node : IComparable, IEquatable { - /// - /// Contains Positional and other information about a single node. - /// - public class Node : IComparable, IEquatable + public Node(VecN position, bool traversable, double traverseMultiplier) { - public Node(VecN position, bool traversable, double traverseMultiplier) - { - Traversable = traversable; - Position = position; - TraversalCostMultiplier = traverseMultiplier; - } - - /// - /// Gets the Total cost of the Node. - /// The Current Costs + the estimated costs. - /// - public double TotalCost => EstimatedCost + CurrentCost; - - /// - /// Gets or sets the Distance between this node and the target node. - /// - public double EstimatedCost { get; set; } - - /// - /// Gets a value indicating whether how costly it is to traverse over this node. - /// - public double TraversalCostMultiplier { get; } - - /// - /// Gets or sets a value indicating whether to go from the start node to this node. - /// - public double CurrentCost { get; set; } - - /// - /// Gets or sets the state of the Node - /// Can be Unconsidered(Default), Open and Closed. - /// - public NodeState State { get; set; } - - /// - /// Gets a value indicating whether the node is traversable. - /// - public bool Traversable { get; } - - /// - /// Gets or sets a list of all connected nodes. - /// - public Node[] ConnectedNodes { get; set; } = new Node[0]; - - /// - /// Gets or sets he "previous" node that was processed before this node. - /// - public Node? Parent { get; set; } - - /// - /// Gets the positional information of the node. - /// - public VecN Position { get; } - - /// - /// Compares the Nodes based on their total costs. - /// Total Costs: A* Pathfinding. - /// Current: Djikstra Pathfinding. - /// Estimated: Greedy Pathfinding. - /// - /// The other node. - /// A comparison between the costs. - public int CompareTo(Node? other) => TotalCost.CompareTo(other?.TotalCost ?? 0); - - public bool Equals(Node? other) => CompareTo(other) == 0; - - public static bool operator ==(Node left, Node right) => left?.Equals(right) != false; - - public static bool operator >(Node left, Node right) => left.CompareTo(right) > 0; - - public static bool operator <(Node left, Node right) => left.CompareTo(right) < 0; - - public static bool operator !=(Node left, Node right) => !(left == right); - - public static bool operator <=(Node left, Node right) => left.CompareTo(right) <= 0; - - public static bool operator >=(Node left, Node right) => left.CompareTo(right) >= 0; - - public override bool Equals(object? obj) => obj is Node other && Equals(other); - - public override int GetHashCode() => - Position.GetHashCode() - + Traversable.GetHashCode() - + TraversalCostMultiplier.GetHashCode(); - - /// - /// Returns the distance to the other node. - /// - /// The other node. - /// Distance between this and other. - public double DistanceTo(Node other) => Math.Sqrt(Position.SqrDistance(other.Position)); + Traversable = traversable; + Position = position; + TraversalCostMultiplier = traverseMultiplier; } + + /// + /// Gets the Total cost of the Node. + /// The Current Costs + the estimated costs. + /// + public double TotalCost => EstimatedCost + CurrentCost; + + /// + /// Gets or sets the Distance between this node and the target node. + /// + public double EstimatedCost { get; set; } + + /// + /// Gets a value indicating whether how costly it is to traverse over this node. + /// + public double TraversalCostMultiplier { get; } + + /// + /// Gets or sets a value indicating whether to go from the start node to this node. + /// + public double CurrentCost { get; set; } + + /// + /// Gets or sets the state of the Node + /// Can be Unconsidered(Default), Open and Closed. + /// + public NodeState State { get; set; } + + /// + /// Gets a value indicating whether the node is traversable. + /// + public bool Traversable { get; } + + /// + /// Gets or sets a list of all connected nodes. + /// + public Node[] ConnectedNodes { get; set; } = new Node[0]; + + /// + /// Gets or sets he "previous" node that was processed before this node. + /// + public Node? Parent { get; set; } + + /// + /// Gets the positional information of the node. + /// + public VecN Position { get; } + + /// + /// Compares the Nodes based on their total costs. + /// Total Costs: A* Pathfinding. + /// Current: Djikstra Pathfinding. + /// Estimated: Greedy Pathfinding. + /// + /// The other node. + /// A comparison between the costs. + public int CompareTo(Node? other) => TotalCost.CompareTo(other?.TotalCost ?? 0); + + public bool Equals(Node? other) => CompareTo(other) == 0; + + public static bool operator ==(Node left, Node right) => left?.Equals(right) != false; + + public static bool operator >(Node left, Node right) => left.CompareTo(right) > 0; + + public static bool operator <(Node left, Node right) => left.CompareTo(right) < 0; + + public static bool operator !=(Node left, Node right) => !(left == right); + + public static bool operator <=(Node left, Node right) => left.CompareTo(right) <= 0; + + public static bool operator >=(Node left, Node right) => left.CompareTo(right) >= 0; + + public override bool Equals(object? obj) => obj is Node other && Equals(other); + + public override int GetHashCode() => + Position.GetHashCode() + + Traversable.GetHashCode() + + TraversalCostMultiplier.GetHashCode(); + + /// + /// Returns the distance to the other node. + /// + /// The other node. + /// Distance between this and other. + public double DistanceTo(Node other) => Math.Sqrt(Position.SqrDistance(other.Position)); } diff --git a/Algorithms/Search/AStar/NodeState.cs b/Algorithms/Search/AStar/NodeState.cs index a95db5a6..40714a28 100644 --- a/Algorithms/Search/AStar/NodeState.cs +++ b/Algorithms/Search/AStar/NodeState.cs @@ -1,23 +1,22 @@ -namespace Algorithms.Search.AStar +namespace Algorithms.Search.AStar; + +/// +/// The states the nodes can have. +/// +public enum NodeState { /// - /// The states the nodes can have. + /// TODO. /// - public enum NodeState - { - /// - /// TODO. - /// - Unconsidered = 0, + Unconsidered = 0, - /// - /// TODO. - /// - Open = 1, + /// + /// TODO. + /// + Open = 1, - /// - /// TODO. - /// - Closed = 2, - } + /// + /// TODO. + /// + Closed = 2, } diff --git a/Algorithms/Search/AStar/PathfindingException.cs b/Algorithms/Search/AStar/PathfindingException.cs index 2de9d1d6..62559c01 100644 --- a/Algorithms/Search/AStar/PathfindingException.cs +++ b/Algorithms/Search/AStar/PathfindingException.cs @@ -1,15 +1,14 @@ -using System; +using System; -namespace Algorithms.Search.AStar +namespace Algorithms.Search.AStar; + +/// +/// A pathfinding exception is thrown when the Pathfinder encounters a critical error and can not continue. +/// +public class PathfindingException : Exception { - /// - /// A pathfinding exception is thrown when the Pathfinder encounters a critical error and can not continue. - /// - public class PathfindingException : Exception + public PathfindingException(string message) + : base(message) { - public PathfindingException(string message) - : base(message) - { - } } } diff --git a/Algorithms/Search/AStar/PriorityQueue.cs b/Algorithms/Search/AStar/PriorityQueue.cs index 58af7e41..bb63950d 100644 --- a/Algorithms/Search/AStar/PriorityQueue.cs +++ b/Algorithms/Search/AStar/PriorityQueue.cs @@ -1,148 +1,147 @@ -using System; +using System; using System.Collections.Generic; // todo: extract to data structures -namespace Algorithms.Search.AStar +namespace Algorithms.Search.AStar; + +/// +/// Generic Priority Queue. +/// List based. +/// +/// +/// The type that will be stored. +/// Has to be IComparable of T. +/// +public class PriorityQueue + where T : IComparable { + private readonly bool isDescending; + + // The underlying structure. + private readonly List list; + + public PriorityQueue(bool isDescending = false) + { + this.isDescending = isDescending; + list = new List(); + } + /// - /// Generic Priority Queue. - /// List based. + /// Initializes a new instance of the class. /// - /// - /// The type that will be stored. - /// Has to be IComparable of T. - /// - public class PriorityQueue - where T : IComparable + /// Initial capacity. + /// Should Reverse Sort order? Default: false. + public PriorityQueue(int capacity, bool isDescending = false) { - private readonly bool isDescending; - - // The underlying structure. - private readonly List list; - - public PriorityQueue(bool isDescending = false) - { - this.isDescending = isDescending; - list = new List(); - } + list = new List(capacity); + this.isDescending = isDescending; + } - /// - /// Initializes a new instance of the class. - /// - /// Initial capacity. - /// Should Reverse Sort order? Default: false. - public PriorityQueue(int capacity, bool isDescending = false) + /// + /// Initializes a new instance of the class. + /// + /// Internal data. + /// Should Reverse Sort order? Default: false. + public PriorityQueue(IEnumerable collection, bool isDescending = false) + : this() + { + this.isDescending = isDescending; + foreach (var item in collection) { - list = new List(capacity); - this.isDescending = isDescending; + Enqueue(item); } + } - /// - /// Initializes a new instance of the class. - /// - /// Internal data. - /// Should Reverse Sort order? Default: false. - public PriorityQueue(IEnumerable collection, bool isDescending = false) - : this() - { - this.isDescending = isDescending; - foreach (var item in collection) - { - Enqueue(item); - } - } + /// + /// Gets Number of enqueued items. + /// + public int Count => list.Count; - /// - /// Gets Number of enqueued items. - /// - public int Count => list.Count; + /// + /// Enqueues an item into the Queue. + /// + /// The item to Enqueue. + public void Enqueue(T x) + { + list.Add(x); + var i = Count - 1; // Position of x - /// - /// Enqueues an item into the Queue. - /// - /// The item to Enqueue. - public void Enqueue(T x) + while (i > 0) { - list.Add(x); - var i = Count - 1; // Position of x - - while (i > 0) + var p = (i - 1) / 2; // Start at half of i + if ((isDescending ? -1 : 1) * list[p].CompareTo(x) <= 0) { - var p = (i - 1) / 2; // Start at half of i - if ((isDescending ? -1 : 1) * list[p].CompareTo(x) <= 0) - { - break; - } - - list[i] = list[p]; // Put P to position of i - i = p; // I = (I-1)/2 + break; } - if (Count > 0) - { - list[i] = x; // If while loop way executed at least once(X got replaced by some p), add it to the list - } + list[i] = list[p]; // Put P to position of i + i = p; // I = (I-1)/2 } - /// - /// Dequeues the item at the end of the queue. - /// - /// The dequeued item. - public T Dequeue() + if (Count > 0) { - var target = Peek(); // Get first in list - var root = list[Count - 1]; // Hold last of the list - list.RemoveAt(Count - 1); // But remove it from the list + list[i] = x; // If while loop way executed at least once(X got replaced by some p), add it to the list + } + } - var i = 0; - while (i * 2 + 1 < Count) - { - var a = i * 2 + 1; // Every second entry starting by 1 - var b = i * 2 + 2; // Every second entries neighbour - var c = b < Count && (isDescending ? -1 : 1) * list[b].CompareTo(list[a]) < 0 - ? b - : a; // Whether B(B is in range && B is smaller than A) or A - - if ((isDescending ? -1 : 1) * list[c].CompareTo(root) >= 0) - { - break; - } - - list[i] = list[c]; - i = c; - } + /// + /// Dequeues the item at the end of the queue. + /// + /// The dequeued item. + public T Dequeue() + { + var target = Peek(); // Get first in list + var root = list[Count - 1]; // Hold last of the list + list.RemoveAt(Count - 1); // But remove it from the list - if (Count > 0) + var i = 0; + while (i * 2 + 1 < Count) + { + var a = i * 2 + 1; // Every second entry starting by 1 + var b = i * 2 + 2; // Every second entries neighbour + var c = b < Count && (isDescending ? -1 : 1) * list[b].CompareTo(list[a]) < 0 + ? b + : a; // Whether B(B is in range && B is smaller than A) or A + + if ((isDescending ? -1 : 1) * list[c].CompareTo(root) >= 0) { - list[i] = root; + break; } - return target; + list[i] = list[c]; + i = c; } - /// - /// Returns the next element in the queue without dequeuing. - /// - /// The next element of the queue. - public T Peek() + if (Count > 0) { - if (Count == 0) - { - throw new InvalidOperationException("Queue is empty."); - } - - return list[0]; + list[i] = root; } - /// - /// Clears the Queue. - /// - public void Clear() => list.Clear(); + return target; + } - /// - /// Returns the Internal Data. - /// - /// The internal data structure. - public List GetData() => list; + /// + /// Returns the next element in the queue without dequeuing. + /// + /// The next element of the queue. + public T Peek() + { + if (Count == 0) + { + throw new InvalidOperationException("Queue is empty."); + } + + return list[0]; } + + /// + /// Clears the Queue. + /// + public void Clear() => list.Clear(); + + /// + /// Returns the Internal Data. + /// + /// The internal data structure. + public List GetData() => list; } diff --git a/Algorithms/Search/AStar/VecN.cs b/Algorithms/Search/AStar/VecN.cs index 329ef889..4f28072c 100644 --- a/Algorithms/Search/AStar/VecN.cs +++ b/Algorithms/Search/AStar/VecN.cs @@ -1,116 +1,115 @@ -using System; +using System; -namespace Algorithms.Search.AStar +namespace Algorithms.Search.AStar; + +/// +/// Vector Struct with N Dimensions. +/// +public struct VecN : IEquatable { + private readonly double[] data; + /// - /// Vector Struct with N Dimensions. + /// Initializes a new instance of the struct. /// - public struct VecN : IEquatable - { - private readonly double[] data; - - /// - /// Initializes a new instance of the struct. - /// - /// Vector components as array. - public VecN(params double[] vals) => data = vals; - - /// - /// Gets the dimension count of this vector. - /// - public int N => data.Length; - - /// - /// Returns the Length squared. - /// - /// The squared length of the vector. - public double SqrLength() - { - double ret = 0; - for (var i = 0; i < data.Length; i++) - { - ret += data[i] * data[i]; - } + /// Vector components as array. + public VecN(params double[] vals) => data = vals; - return ret; - } + /// + /// Gets the dimension count of this vector. + /// + public int N => data.Length; - /// - /// Returns the Length of the vector. - /// - /// Length of the Vector. - public double Length() => Math.Sqrt(SqrLength()); - - /// - /// Returns the Distance between this and other. - /// - /// Other vector. - /// The distance between this and other. - public double Distance(VecN other) + /// + /// Returns the Length squared. + /// + /// The squared length of the vector. + public double SqrLength() + { + double ret = 0; + for (var i = 0; i < data.Length; i++) { - var delta = Subtract(other); - return delta.Length(); + ret += data[i] * data[i]; } - /// - /// Returns the squared Distance between this and other. - /// - /// Other vector. - /// The squared distance between this and other. - public double SqrDistance(VecN other) - { - var delta = Subtract(other); - return delta.SqrLength(); - } + return ret; + } + + /// + /// Returns the Length of the vector. + /// + /// Length of the Vector. + public double Length() => Math.Sqrt(SqrLength()); - /// - /// Substracts other from this vector. - /// - /// Other vector. - /// The new vector. - public VecN Subtract(VecN other) + /// + /// Returns the Distance between this and other. + /// + /// Other vector. + /// The distance between this and other. + public double Distance(VecN other) + { + var delta = Subtract(other); + return delta.Length(); + } + + /// + /// Returns the squared Distance between this and other. + /// + /// Other vector. + /// The squared distance between this and other. + public double SqrDistance(VecN other) + { + var delta = Subtract(other); + return delta.SqrLength(); + } + + /// + /// Substracts other from this vector. + /// + /// Other vector. + /// The new vector. + public VecN Subtract(VecN other) + { + var dd = new double[Math.Max(data.Length, other.data.Length)]; + for (var i = 0; i < dd.Length; i++) { - var dd = new double[Math.Max(data.Length, other.data.Length)]; - for (var i = 0; i < dd.Length; i++) + double val = 0; + if (data.Length > i) + { + val = data[i]; + } + + if (other.data.Length > i) { - double val = 0; - if (data.Length > i) - { - val = data[i]; - } - - if (other.data.Length > i) - { - val -= other.data[i]; - } - - dd[i] = val; + val -= other.data[i]; } - return new VecN(dd); + dd[i] = val; } - /// - /// Is used to compare Vectors with each other. - /// - /// The vector to be compared. - /// A value indicating if other has the same values as this. - public bool Equals(VecN other) + return new VecN(dd); + } + + /// + /// Is used to compare Vectors with each other. + /// + /// The vector to be compared. + /// A value indicating if other has the same values as this. + public bool Equals(VecN other) + { + if (other.N != N) { - if (other.N != N) - { - return false; - } + return false; + } - for (var i = 0; i < other.data.Length; i++) + for (var i = 0; i < other.data.Length; i++) + { + if (Math.Abs(data[i] - other.data[i]) > 0.000001) { - if (Math.Abs(data[i] - other.data[i]) > 0.000001) - { - return false; - } + return false; } - - return true; } + + return true; } } diff --git a/Algorithms/Search/BinarySearcher.cs b/Algorithms/Search/BinarySearcher.cs index 4ff4234e..4146be49 100644 --- a/Algorithms/Search/BinarySearcher.cs +++ b/Algorithms/Search/BinarySearcher.cs @@ -1,48 +1,47 @@ -using System; +using System; -namespace Algorithms.Search +namespace Algorithms.Search; + +/// +/// Binary Searcher checks an array for element specified by checking +/// if element is greater or less than the half being checked. +/// time complexity: O(log(n)), +/// space complexity: O(1). +/// Note: Array must be sorted beforehand. +/// +/// Type of element stored inside array. 2. +public class BinarySearcher where T : IComparable { /// - /// Binary Searcher checks an array for element specified by checking - /// if element is greater or less than the half being checked. - /// time complexity: O(log(n)), - /// space complexity: O(1). - /// Note: Array must be sorted beforehand. + /// Finds index of an array by using binary search. /// - /// Type of element stored inside array. 2. - public class BinarySearcher where T : IComparable + /// Sorted array to search in. + /// Item to search for. + /// Index of item that equals to item searched for or -1 if none found. + public int FindIndex(T[] sortedData, T item) { - /// - /// Finds index of an array by using binary search. - /// - /// Sorted array to search in. - /// Item to search for. - /// Index of item that equals to item searched for or -1 if none found. - public int FindIndex(T[] sortedData, T item) + var leftIndex = 0; + var rightIndex = sortedData.Length - 1; + + while (leftIndex <= rightIndex) { - var leftIndex = 0; - var rightIndex = sortedData.Length - 1; + var middleIndex = leftIndex + (rightIndex - leftIndex) / 2; - while (leftIndex <= rightIndex) + if (item.CompareTo(sortedData[middleIndex]) > 0) { - var middleIndex = leftIndex + (rightIndex - leftIndex) / 2; - - if (item.CompareTo(sortedData[middleIndex]) > 0) - { - leftIndex = middleIndex + 1; - continue; - } - - if (item.CompareTo(sortedData[middleIndex]) < 0) - { - rightIndex = middleIndex - 1; - continue; - } + leftIndex = middleIndex + 1; + continue; + } - return middleIndex; + if (item.CompareTo(sortedData[middleIndex]) < 0) + { + rightIndex = middleIndex - 1; + continue; } - return -1; + return middleIndex; } + + return -1; } } diff --git a/Algorithms/Search/BoyerMoore.cs b/Algorithms/Search/BoyerMoore.cs index cb86d0ad..dcbd1966 100644 --- a/Algorithms/Search/BoyerMoore.cs +++ b/Algorithms/Search/BoyerMoore.cs @@ -2,57 +2,56 @@ using System.Collections.Generic; using System.Linq; -namespace Algorithms.Search +namespace Algorithms.Search; + +/// +/// A Boyer-Moore majority finder algorithm implementation. +/// +/// Type of element stored inside array. +public static class BoyerMoore where T : IComparable { - /// - /// A Boyer-Moore majority finder algorithm implementation. - /// - /// Type of element stored inside array. - public static class BoyerMoore where T : IComparable + public static T? FindMajority(IEnumerable input) { - public static T? FindMajority(IEnumerable input) + var candidate = FindMajorityCandidate(input, input.Count()); + + if (VerifyMajority(input, input.Count(), candidate)) { - var candidate = FindMajorityCandidate(input, input.Count()); + return candidate; + } - if (VerifyMajority(input, input.Count(), candidate)) - { - return candidate; - } + return default(T?); + } - return default(T?); - } + // Find majority candidate + private static T FindMajorityCandidate(IEnumerable input, int length) + { + int count = 1; + T candidate = input.First(); - // Find majority candidate - private static T FindMajorityCandidate(IEnumerable input, int length) + foreach (var element in input.Skip(1)) { - int count = 1; - T candidate = input.First(); - - foreach (var element in input.Skip(1)) + if (candidate.Equals(element)) { - if (candidate.Equals(element)) - { - count++; - } - else - { - count--; - } - - if (count == 0) - { - candidate = element; - count = 1; - } + count++; + } + else + { + count--; } - return candidate; + if (count == 0) + { + candidate = element; + count = 1; + } } - // Verify that candidate is indeed the majority - private static bool VerifyMajority(IEnumerable input, int size, T candidate) - { - return input.Count(x => x.Equals(candidate)) > size / 2; - } + return candidate; + } + + // Verify that candidate is indeed the majority + private static bool VerifyMajority(IEnumerable input, int size, T candidate) + { + return input.Count(x => x.Equals(candidate)) > size / 2; } } diff --git a/Algorithms/Search/FastSearcher.cs b/Algorithms/Search/FastSearcher.cs index 33653f11..b11989df 100644 --- a/Algorithms/Search/FastSearcher.cs +++ b/Algorithms/Search/FastSearcher.cs @@ -1,80 +1,79 @@ -using System; +using System; using Utilities.Exceptions; -namespace Algorithms.Search +namespace Algorithms.Search; + +/// +/// The idea: you could combine the advantages from both binary-search and interpolation search algorithm. +/// Time complexity: +/// worst case: Item couldn't be found: O(log n), +/// average case: O(log log n), +/// best case: O(1). +/// Note: This algorithm is recursive and the array has to be sorted beforehand. +/// +public class FastSearcher { /// - /// The idea: you could combine the advantages from both binary-search and interpolation search algorithm. - /// Time complexity: - /// worst case: Item couldn't be found: O(log n), - /// average case: O(log log n), - /// best case: O(1). - /// Note: This algorithm is recursive and the array has to be sorted beforehand. + /// Finds index of first item in array that satisfies specified term + /// throws ItemNotFoundException if the item couldn't be found. /// - public class FastSearcher + /// Span of sorted numbers which will be used to find the item. + /// Term to check against. + /// Index of first item that satisfies term. + /// Gets thrown when the given item couldn't be found in the array. + public int FindIndex(Span array, int item) { - /// - /// Finds index of first item in array that satisfies specified term - /// throws ItemNotFoundException if the item couldn't be found. - /// - /// Span of sorted numbers which will be used to find the item. - /// Term to check against. - /// Index of first item that satisfies term. - /// Gets thrown when the given item couldn't be found in the array. - public int FindIndex(Span array, int item) + if (array.Length == 0) { - if (array.Length == 0) - { - throw new ItemNotFoundException(); - } + throw new ItemNotFoundException(); + } - if (item < array[0] || item > array[^1]) - { - throw new ItemNotFoundException(); - } + if (item < array[0] || item > array[^1]) + { + throw new ItemNotFoundException(); + } - if (array[0] == array[^1]) - { - return item == array[0] ? 0 : throw new ItemNotFoundException(); - } + if (array[0] == array[^1]) + { + return item == array[0] ? 0 : throw new ItemNotFoundException(); + } - var (left, right) = ComputeIndices(array, item); - var (from, to) = SelectSegment(array, left, right, item); + var (left, right) = ComputeIndices(array, item); + var (from, to) = SelectSegment(array, left, right, item); - return from + FindIndex(array.Slice(from, to - from + 1), item); - } + return from + FindIndex(array.Slice(from, to - from + 1), item); + } - private (int left, int right) ComputeIndices(Span array, int item) + private (int left, int right) ComputeIndices(Span array, int item) + { + var indexBinary = array.Length / 2; + + int[] section = { - var indexBinary = array.Length / 2; + array.Length - 1, + item - array[0], + array[^1] - array[0], + }; + var indexInterpolation = section[0] * section[1] / section[2]; - int[] section = - { - array.Length - 1, - item - array[0], - array[^1] - array[0], - }; - var indexInterpolation = section[0] * section[1] / section[2]; + // Left is min and right is max of the indices + return indexInterpolation > indexBinary + ? (indexBinary, indexInterpolation) + : (indexInterpolation, indexBinary); + } - // Left is min and right is max of the indices - return indexInterpolation > indexBinary - ? (indexBinary, indexInterpolation) - : (indexInterpolation, indexBinary); + private (int from, int to) SelectSegment(Span array, int left, int right, int item) + { + if (item < array[left]) + { + return (0, left - 1); } - private (int from, int to) SelectSegment(Span array, int left, int right, int item) + if (item < array[right]) { - if (item < array[left]) - { - return (0, left - 1); - } - - if (item < array[right]) - { - return (left, right - 1); - } - - return (right, array.Length - 1); + return (left, right - 1); } + + return (right, array.Length - 1); } } diff --git a/Algorithms/Search/FibonacciSearcher.cs b/Algorithms/Search/FibonacciSearcher.cs index bbf91ae6..c58ef979 100644 --- a/Algorithms/Search/FibonacciSearcher.cs +++ b/Algorithms/Search/FibonacciSearcher.cs @@ -1,90 +1,89 @@ using System; -namespace Algorithms.Search +namespace Algorithms.Search; + +/// +/// Class that implements Fibonacci search algorithm. +/// +/// Type of array element. +public class FibonacciSearcher where T : IComparable { /// - /// Class that implements Fibonacci search algorithm. + /// Finds the index of the item searched for in the array. + /// Time complexity: + /// worst-case: O(log n), + /// average-case: O(log n), + /// best-case: O(1). /// - /// Type of array element. - public class FibonacciSearcher where T : IComparable + /// Sorted array to be searched in. Cannot be null. + /// Item to be searched for. Cannot be null. + /// If an item is found, return index. If the array is empty or an item is not found, return -1. + /// Gets thrown when the given array or item is null. + public int FindIndex(T[] array, T item) { - /// - /// Finds the index of the item searched for in the array. - /// Time complexity: - /// worst-case: O(log n), - /// average-case: O(log n), - /// best-case: O(1). - /// - /// Sorted array to be searched in. Cannot be null. - /// Item to be searched for. Cannot be null. - /// If an item is found, return index. If the array is empty or an item is not found, return -1. - /// Gets thrown when the given array or item is null. - public int FindIndex(T[] array, T item) + if (array is null) { - if (array is null) - { - throw new ArgumentNullException("array"); - } + throw new ArgumentNullException("array"); + } - if (item is null) - { - throw new ArgumentNullException("item"); - } + if (item is null) + { + throw new ArgumentNullException("item"); + } - var arrayLength = array.Length; + var arrayLength = array.Length; - if (arrayLength > 0) + if (arrayLength > 0) + { + // find the smallest Fibonacci number that equals or is greater than the array length + var fibonacciNumberBeyondPrevious = 0; + var fibonacciNumPrevious = 1; + var fibonacciNum = fibonacciNumPrevious; + + while (fibonacciNum <= arrayLength) { - // find the smallest Fibonacci number that equals or is greater than the array length - var fibonacciNumberBeyondPrevious = 0; - var fibonacciNumPrevious = 1; - var fibonacciNum = fibonacciNumPrevious; + fibonacciNumberBeyondPrevious = fibonacciNumPrevious; + fibonacciNumPrevious = fibonacciNum; + fibonacciNum = fibonacciNumberBeyondPrevious + fibonacciNumPrevious; + } - while (fibonacciNum <= arrayLength) - { - fibonacciNumberBeyondPrevious = fibonacciNumPrevious; - fibonacciNumPrevious = fibonacciNum; - fibonacciNum = fibonacciNumberBeyondPrevious + fibonacciNumPrevious; - } + // offset to drop the left part of the array + var offset = -1; - // offset to drop the left part of the array - var offset = -1; + while (fibonacciNum > 1) + { + var index = Math.Min(offset + fibonacciNumberBeyondPrevious, arrayLength - 1); - while (fibonacciNum > 1) + switch (item.CompareTo(array[index])) { - var index = Math.Min(offset + fibonacciNumberBeyondPrevious, arrayLength - 1); - - switch (item.CompareTo(array[index])) - { - // reject approximately 1/3 of the existing array in front - // by moving Fibonacci numbers - case > 0: - fibonacciNum = fibonacciNumPrevious; - fibonacciNumPrevious = fibonacciNumberBeyondPrevious; - fibonacciNumberBeyondPrevious = fibonacciNum - fibonacciNumPrevious; - offset = index; - break; - - // reject approximately 2/3 of the existing array behind - // by moving Fibonacci numbers - case < 0: - fibonacciNum = fibonacciNumberBeyondPrevious; - fibonacciNumPrevious = fibonacciNumPrevious - fibonacciNumberBeyondPrevious; - fibonacciNumberBeyondPrevious = fibonacciNum - fibonacciNumPrevious; - break; - default: - return index; - } - } + // reject approximately 1/3 of the existing array in front + // by moving Fibonacci numbers + case > 0: + fibonacciNum = fibonacciNumPrevious; + fibonacciNumPrevious = fibonacciNumberBeyondPrevious; + fibonacciNumberBeyondPrevious = fibonacciNum - fibonacciNumPrevious; + offset = index; + break; - // check the last element - if (fibonacciNumPrevious == 1 && item.Equals(array[^1])) - { - return arrayLength - 1; + // reject approximately 2/3 of the existing array behind + // by moving Fibonacci numbers + case < 0: + fibonacciNum = fibonacciNumberBeyondPrevious; + fibonacciNumPrevious = fibonacciNumPrevious - fibonacciNumberBeyondPrevious; + fibonacciNumberBeyondPrevious = fibonacciNum - fibonacciNumPrevious; + break; + default: + return index; } } - return -1; + // check the last element + if (fibonacciNumPrevious == 1 && item.Equals(array[^1])) + { + return arrayLength - 1; + } } + + return -1; } } diff --git a/Algorithms/Search/InterpolationSearch.cs b/Algorithms/Search/InterpolationSearch.cs index baad76ef..dac312bc 100644 --- a/Algorithms/Search/InterpolationSearch.cs +++ b/Algorithms/Search/InterpolationSearch.cs @@ -1,52 +1,51 @@ -namespace Algorithms.Search +namespace Algorithms.Search; + +/// +/// Class that implements interpolation search algorithm. +/// +public static class InterpolationSearch { /// - /// Class that implements interpolation search algorithm. + /// Finds the index of the item searched for in the array. + /// Algorithm performance: + /// worst-case: O(n), + /// average-case: O(log(log(n))), + /// best-case: O(1). /// - public static class InterpolationSearch + /// Array with sorted elements to be searched in. Cannot be null. + /// Value to be searched for. Cannot be null. + /// If an item is found, return index, else return -1. + public static int FindIndex(int[] sortedArray, int val) { - /// - /// Finds the index of the item searched for in the array. - /// Algorithm performance: - /// worst-case: O(n), - /// average-case: O(log(log(n))), - /// best-case: O(1). - /// - /// Array with sorted elements to be searched in. Cannot be null. - /// Value to be searched for. Cannot be null. - /// If an item is found, return index, else return -1. - public static int FindIndex(int[] sortedArray, int val) + var start = 0; + var end = sortedArray.Length - 1; + + while (start <= end && val >= sortedArray[start] && val <= sortedArray[end]) { - var start = 0; - var end = sortedArray.Length - 1; + var denominator = (sortedArray[end] - sortedArray[start]) * (val - sortedArray[start]); - while (start <= end && val >= sortedArray[start] && val <= sortedArray[end]) + if (denominator == 0) { - var denominator = (sortedArray[end] - sortedArray[start]) * (val - sortedArray[start]); - - if (denominator == 0) - { - denominator = 1; - } - - var pos = start + (end - start) / denominator; + denominator = 1; + } - if (sortedArray[pos] == val) - { - return pos; - } + var pos = start + (end - start) / denominator; - if (sortedArray[pos] < val) - { - start = pos + 1; - } - else - { - end = pos - 1; - } + if (sortedArray[pos] == val) + { + return pos; } - return -1; + if (sortedArray[pos] < val) + { + start = pos + 1; + } + else + { + end = pos - 1; + } } + + return -1; } } diff --git a/Algorithms/Search/JumpSearcher.cs b/Algorithms/Search/JumpSearcher.cs index 6b4fa488..cb379e31 100644 --- a/Algorithms/Search/JumpSearcher.cs +++ b/Algorithms/Search/JumpSearcher.cs @@ -1,62 +1,61 @@ using System; -namespace Algorithms.Search +namespace Algorithms.Search; + +/// +/// Jump Search checks fewer elements by jumping ahead by fixed steps. +/// The optimal steps to jump is √n, where n refers to the number of elements in the array. +/// Time Complexity: O(√n) +/// Note: The array has to be sorted beforehand. +/// +/// Type of the array element. +public class JumpSearcher where T : IComparable { /// - /// Jump Search checks fewer elements by jumping ahead by fixed steps. - /// The optimal steps to jump is √n, where n refers to the number of elements in the array. - /// Time Complexity: O(√n) - /// Note: The array has to be sorted beforehand. + /// Find the index of the item searched for in the array. /// - /// Type of the array element. - public class JumpSearcher where T : IComparable + /// Sorted array to be search in. Cannot be null. + /// Item to be search for. Cannot be null. + /// If item is found, return index. If array is empty or item not found, return -1. + public int FindIndex(T[] sortedArray, T searchItem) { - /// - /// Find the index of the item searched for in the array. - /// - /// Sorted array to be search in. Cannot be null. - /// Item to be search for. Cannot be null. - /// If item is found, return index. If array is empty or item not found, return -1. - public int FindIndex(T[] sortedArray, T searchItem) + if (sortedArray is null) { - if (sortedArray is null) - { - throw new ArgumentNullException("sortedArray"); - } + throw new ArgumentNullException("sortedArray"); + } - if (searchItem is null) - { - throw new ArgumentNullException("searchItem"); - } + if (searchItem is null) + { + throw new ArgumentNullException("searchItem"); + } - int jumpStep = (int)Math.Floor(Math.Sqrt(sortedArray.Length)); - int currentIndex = 0; - int nextIndex = jumpStep; + int jumpStep = (int)Math.Floor(Math.Sqrt(sortedArray.Length)); + int currentIndex = 0; + int nextIndex = jumpStep; - if (sortedArray.Length != 0) + if (sortedArray.Length != 0) + { + while (sortedArray[nextIndex - 1].CompareTo(searchItem) < 0) { - while (sortedArray[nextIndex - 1].CompareTo(searchItem) < 0) + currentIndex = nextIndex; + nextIndex += jumpStep; + + if (nextIndex >= sortedArray.Length) { - currentIndex = nextIndex; - nextIndex += jumpStep; - - if (nextIndex >= sortedArray.Length) - { - nextIndex = sortedArray.Length - 1; - break; - } + nextIndex = sortedArray.Length - 1; + break; } + } - for (int i = currentIndex; i <= nextIndex; i++) + for (int i = currentIndex; i <= nextIndex; i++) + { + if (sortedArray[i].CompareTo(searchItem) == 0) { - if (sortedArray[i].CompareTo(searchItem) == 0) - { - return i; - } + return i; } } - - return -1; } + + return -1; } } diff --git a/Algorithms/Search/LinearSearcher.cs b/Algorithms/Search/LinearSearcher.cs index cb6f070d..9361dcfd 100644 --- a/Algorithms/Search/LinearSearcher.cs +++ b/Algorithms/Search/LinearSearcher.cs @@ -1,54 +1,53 @@ using System; using Utilities.Exceptions; -namespace Algorithms.Search +namespace Algorithms.Search; + +/// +/// Class that implements linear search algorithm. +/// +/// Type of array element. +public class LinearSearcher { /// - /// Class that implements linear search algorithm. + /// Finds first item in array that satisfies specified term + /// Time complexity: O(n) + /// Space complexity: O(1). /// - /// Type of array element. - public class LinearSearcher + /// Array to search in. + /// Term to check against. + /// First item that satisfies term. + public T Find(T[] data, Func term) { - /// - /// Finds first item in array that satisfies specified term - /// Time complexity: O(n) - /// Space complexity: O(1). - /// - /// Array to search in. - /// Term to check against. - /// First item that satisfies term. - public T Find(T[] data, Func term) + for (var i = 0; i < data.Length; i++) { - for (var i = 0; i < data.Length; i++) + if (term(data[i])) { - if (term(data[i])) - { - return data[i]; - } + return data[i]; } - - throw new ItemNotFoundException(); } - /// - /// Finds index of first item in array that satisfies specified term - /// Time complexity: O(n) - /// Space complexity: O(1). - /// - /// Array to search in. - /// Term to check against. - /// Index of first item that satisfies term or -1 if none found. - public int FindIndex(T[] data, Func term) + throw new ItemNotFoundException(); + } + + /// + /// Finds index of first item in array that satisfies specified term + /// Time complexity: O(n) + /// Space complexity: O(1). + /// + /// Array to search in. + /// Term to check against. + /// Index of first item that satisfies term or -1 if none found. + public int FindIndex(T[] data, Func term) + { + for (var i = 0; i < data.Length; i++) { - for (var i = 0; i < data.Length; i++) + if (term(data[i])) { - if (term(data[i])) - { - return i; - } + return i; } - - return -1; } + + return -1; } } diff --git a/Algorithms/Search/RecursiveBinarySearcher.cs b/Algorithms/Search/RecursiveBinarySearcher.cs index 01b66edb..daf36cad 100644 --- a/Algorithms/Search/RecursiveBinarySearcher.cs +++ b/Algorithms/Search/RecursiveBinarySearcher.cs @@ -1,65 +1,64 @@ -using System; +using System; using System.Collections.Generic; -namespace Algorithms.Search +namespace Algorithms.Search; + +/// +/// RecursiveBinarySearcher. +/// +/// Type of searcher target. +public class RecursiveBinarySearcher where T : IComparable { /// - /// RecursiveBinarySearcher. + /// Finds index of item in collection that equals to item searched for, + /// time complexity: O(log(n)), + /// space complexity: O(1), + /// where n - collection size. /// - /// Type of searcher target. - public class RecursiveBinarySearcher where T : IComparable + /// Sorted collection to search in. + /// Item to search for. + /// Thrown if input collection is null. + /// Index of item that equals to item searched for or -1 if none found. + public int FindIndex(IList? collection, T item) { - /// - /// Finds index of item in collection that equals to item searched for, - /// time complexity: O(log(n)), - /// space complexity: O(1), - /// where n - collection size. - /// - /// Sorted collection to search in. - /// Item to search for. - /// Thrown if input collection is null. - /// Index of item that equals to item searched for or -1 if none found. - public int FindIndex(IList? collection, T item) + if (collection is null) { - if (collection is null) - { - throw new ArgumentNullException(nameof(collection)); - } + throw new ArgumentNullException(nameof(collection)); + } - var leftIndex = 0; - var rightIndex = collection.Count - 1; + var leftIndex = 0; + var rightIndex = collection.Count - 1; - return FindIndex(collection, item, leftIndex, rightIndex); - } + return FindIndex(collection, item, leftIndex, rightIndex); + } - /// - /// Finds index of item in array that equals to item searched for, - /// time complexity: O(log(n)), - /// space complexity: O(1), - /// where n - array size. - /// - /// Sorted array to search in. - /// Item to search for. - /// Minimum search range. - /// Maximum search range. - /// Index of item that equals to item searched for or -1 if none found. - private int FindIndex(IList collection, T item, int leftIndex, int rightIndex) + /// + /// Finds index of item in array that equals to item searched for, + /// time complexity: O(log(n)), + /// space complexity: O(1), + /// where n - array size. + /// + /// Sorted array to search in. + /// Item to search for. + /// Minimum search range. + /// Maximum search range. + /// Index of item that equals to item searched for or -1 if none found. + private int FindIndex(IList collection, T item, int leftIndex, int rightIndex) + { + if (leftIndex > rightIndex) { - if (leftIndex > rightIndex) - { - return -1; - } + return -1; + } - var middleIndex = leftIndex + (rightIndex - leftIndex) / 2; - var result = item.CompareTo(collection[middleIndex]); + var middleIndex = leftIndex + (rightIndex - leftIndex) / 2; + var result = item.CompareTo(collection[middleIndex]); - return result switch - { - var r when r == 0 => middleIndex, - var r when r > 0 => FindIndex(collection, item, middleIndex + 1, rightIndex), - var r when r < 0 => FindIndex(collection, item, leftIndex, middleIndex - 1), - _ => -1, - }; - } + return result switch + { + var r when r == 0 => middleIndex, + var r when r > 0 => FindIndex(collection, item, middleIndex + 1, rightIndex), + var r when r < 0 => FindIndex(collection, item, leftIndex, middleIndex - 1), + _ => -1, + }; } } From 691d270faf56283f3e95c46828176160ff4760cd Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Wed, 3 Jan 2024 22:51:46 +0000 Subject: [PATCH 084/138] Switch to file-scoped namespaces (#432) --- .../Sequences/BinaryPrimeConstantSequence.cs | 53 ++++--- Algorithms/Sequences/BinomialSequence.cs | 91 ++++++------ Algorithms/Sequences/CatalanSequence.cs | 49 +++--- Algorithms/Sequences/CubesSequence.cs | 45 +++--- Algorithms/Sequences/DivisorsCountSequence.cs | 47 +++--- Algorithms/Sequences/EuclidNumbersSequence.cs | 43 +++--- Algorithms/Sequences/EulerTotientSequence.cs | 139 +++++++++--------- Algorithms/Sequences/FactorialSequence.cs | 49 +++--- Algorithms/Sequences/FermatNumbersSequence.cs | 47 +++--- Algorithms/Sequences/FermatPrimesSequence.cs | 45 +++--- Algorithms/Sequences/FibonacciSequence.cs | 55 ++++--- Algorithms/Sequences/GolombsSequence.cs | 58 ++++---- Algorithms/Sequences/ISequence.cs | 19 ++- Algorithms/Sequences/KolakoskiSequence.cs | 63 ++++---- Algorithms/Sequences/KolakoskiSequence2.cs | 57 ++++--- Algorithms/Sequences/KummerNumbersSequence.cs | 47 +++--- .../LucasNumbersBeginningAt2Sequence.cs | 91 ++++++------ Algorithms/Sequences/MakeChangeSequence.cs | 74 +++++----- .../Sequences/MatchstickTriangleSequence.cs | 1 - Algorithms/Sequences/NaturalSequence.cs | 43 +++--- .../Sequences/NegativeIntegersSequence.cs | 45 +++--- .../NumberOfBooleanFunctionsSequence.cs | 49 +++--- .../NumberOfPrimesByNumberOfDigitsSequence.cs | 59 ++++---- .../NumberOfPrimesByPowersOf10Sequence.cs | 55 ++++--- Algorithms/Sequences/PowersOf10Sequence.cs | 45 +++--- Algorithms/Sequences/PowersOf2Sequence.cs | 47 +++--- Algorithms/Sequences/PrimePiSequence.cs | 53 ++++--- Algorithms/Sequences/PrimesSequence.cs | 61 ++++---- .../Sequences/PrimorialNumbersSequence.cs | 47 +++--- Algorithms/Sequences/RecamansSequence.cs | 63 ++++---- Algorithms/Sequences/SquaresSequence.cs | 47 +++--- .../Sequences/ThreeNPlusOneStepsSequence.cs | 67 +++++---- Algorithms/Sequences/VanEcksSequence.cs | 55 ++++--- Algorithms/Sequences/ZeroSequence.cs | 32 ++-- Algorithms/Shufflers/FisherYatesShuffler.cs | 41 +++--- Algorithms/Shufflers/IShuffler.cs | 19 ++- 36 files changed, 931 insertions(+), 970 deletions(-) diff --git a/Algorithms/Sequences/BinaryPrimeConstantSequence.cs b/Algorithms/Sequences/BinaryPrimeConstantSequence.cs index 8a78ee93..d09097c4 100644 --- a/Algorithms/Sequences/BinaryPrimeConstantSequence.cs +++ b/Algorithms/Sequences/BinaryPrimeConstantSequence.cs @@ -1,41 +1,40 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of binary prime constant +/// (Characteristic function of primes: 1 if n is prime, else 0). +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Prime_constant. +/// +/// +/// OEIS: https://oeis.org/A010051. +/// +/// +public class BinaryPrimeConstantSequence : ISequence { /// - /// - /// Sequence of binary prime constant - /// (Characteristic function of primes: 1 if n is prime, else 0). - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Prime_constant. - /// - /// - /// OEIS: https://oeis.org/A010051. - /// + /// Gets sequence of binary prime constant. /// - public class BinaryPrimeConstantSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of binary prime constant. - /// - public IEnumerable Sequence + get { - get - { - ISequence primes = new PrimesSequence(); - var n = new BigInteger(0); + ISequence primes = new PrimesSequence(); + var n = new BigInteger(0); - foreach (var p in primes.Sequence) + foreach (var p in primes.Sequence) + { + for (n++; n < p; n++) { - for (n++; n < p; n++) - { - yield return 0; - } - - yield return 1; + yield return 0; } + + yield return 1; } } } diff --git a/Algorithms/Sequences/BinomialSequence.cs b/Algorithms/Sequences/BinomialSequence.cs index f6bc134a..6e20f3f0 100644 --- a/Algorithms/Sequences/BinomialSequence.cs +++ b/Algorithms/Sequences/BinomialSequence.cs @@ -1,67 +1,66 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of binomial coefficients. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Binomial_coefficient. +/// +/// +/// OEIS: http://oeis.org/A007318. +/// +/// +public class BinomialSequence : ISequence { /// - /// - /// Sequence of binomial coefficients. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Binomial_coefficient. - /// - /// - /// OEIS: http://oeis.org/A007318. - /// + /// Gets sequence of binomial coefficients. /// - public class BinomialSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of binomial coefficients. - /// - public IEnumerable Sequence + get { - get - { - var i = 0; + var i = 0; - while (true) + while (true) + { + var row = GenerateRow(i); + foreach (var coefficient in row) { - var row = GenerateRow(i); - foreach (var coefficient in row) - { - yield return coefficient; - } - - i++; + yield return coefficient; } + + i++; } } + } - private static BigInteger BinomialCoefficient(long n, long k) + private static BigInteger BinomialCoefficient(long n, long k) + { + if (k == 0 || k == n) { - if (k == 0 || k == n) - { - return new BigInteger(1); - } - - if (n < 0) - { - return new BigInteger(0); - } - - return BinomialCoefficient(n - 1, k) + BinomialCoefficient(n - 1, k - 1); + return new BigInteger(1); } - private static IEnumerable GenerateRow(long n) + if (n < 0) { - long k = 0; + return new BigInteger(0); + } - while (k <= n) - { - yield return BinomialCoefficient(n, k); - k++; - } + return BinomialCoefficient(n - 1, k) + BinomialCoefficient(n - 1, k - 1); + } + + private static IEnumerable GenerateRow(long n) + { + long k = 0; + + while (k <= n) + { + yield return BinomialCoefficient(n, k); + k++; } } } diff --git a/Algorithms/Sequences/CatalanSequence.cs b/Algorithms/Sequences/CatalanSequence.cs index 07c8f7c3..0ed4f6b0 100644 --- a/Algorithms/Sequences/CatalanSequence.cs +++ b/Algorithms/Sequences/CatalanSequence.cs @@ -1,37 +1,36 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Catalan numbers: C[n+1] = (2*(2*n+1)*C[n])/(n+2). +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Catalan_number. +/// +/// +/// OEIS:http://oeis.org/A000108. +/// +/// +public class CatalanSequence : ISequence { /// - /// - /// Catalan numbers: C[n+1] = (2*(2*n+1)*C[n])/(n+2). - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Catalan_number. - /// - /// - /// OEIS:http://oeis.org/A000108. - /// + /// Gets sequence of Catalan numbers. /// - public class CatalanSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of Catalan numbers. - /// - public IEnumerable Sequence + get { - get + // initialize the first element (1) and define it's enumerator (0) + var catalan = new BigInteger(1); + var n = 0; + while (true) { - // initialize the first element (1) and define it's enumerator (0) - var catalan = new BigInteger(1); - var n = 0; - while (true) - { - yield return catalan; - catalan = (2 * (2 * n + 1) * catalan) / (n + 2); - n++; - } + yield return catalan; + catalan = (2 * (2 * n + 1) * catalan) / (n + 2); + n++; } } } diff --git a/Algorithms/Sequences/CubesSequence.cs b/Algorithms/Sequences/CubesSequence.cs index 887a5651..287d0b8a 100644 --- a/Algorithms/Sequences/CubesSequence.cs +++ b/Algorithms/Sequences/CubesSequence.cs @@ -1,35 +1,34 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of cube numbers. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Cube_(algebra). +/// +/// +/// OEIS: https://oeis.org/A000578. +/// +/// +public class CubesSequence : ISequence { /// - /// - /// Sequence of cube numbers. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Cube_(algebra). - /// - /// - /// OEIS: https://oeis.org/A000578. - /// + /// Gets sequence of cube numbers. /// - public class CubesSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of cube numbers. - /// - public IEnumerable Sequence + get { - get - { - var n = BigInteger.Zero; + var n = BigInteger.Zero; - while (true) - { - yield return n * n * n; - n++; - } + while (true) + { + yield return n * n * n; + n++; } } } diff --git a/Algorithms/Sequences/DivisorsCountSequence.cs b/Algorithms/Sequences/DivisorsCountSequence.cs index ab223363..da80737b 100644 --- a/Algorithms/Sequences/DivisorsCountSequence.cs +++ b/Algorithms/Sequences/DivisorsCountSequence.cs @@ -1,40 +1,39 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of the number of divisors of n, starting with 1. +/// +/// +/// OEIS: https://oeis.org/A000005. +/// +/// +public class DivisorsCountSequence : ISequence { /// - /// - /// Sequence of the number of divisors of n, starting with 1. - /// - /// - /// OEIS: https://oeis.org/A000005. - /// + /// Gets sequence of number of divisors for n, starting at 1. /// - public class DivisorsCountSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of number of divisors for n, starting at 1. - /// - public IEnumerable Sequence + get { - get + yield return BigInteger.One; + for (var n = new BigInteger(2); ; n++) { - yield return BigInteger.One; - for (var n = new BigInteger(2); ; n++) + var count = 2; + for (var k = 2; k < n; k++) { - var count = 2; - for (var k = 2; k < n; k++) + BigInteger.DivRem(n, k, out var remainder); + if (remainder == 0) { - BigInteger.DivRem(n, k, out var remainder); - if (remainder == 0) - { - count++; - } + count++; } - - yield return count; } + + yield return count; } } } diff --git a/Algorithms/Sequences/EuclidNumbersSequence.cs b/Algorithms/Sequences/EuclidNumbersSequence.cs index 341fabf4..36d703d9 100644 --- a/Algorithms/Sequences/EuclidNumbersSequence.cs +++ b/Algorithms/Sequences/EuclidNumbersSequence.cs @@ -1,34 +1,33 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of Euclid numbers: 1 + product of the first n primes. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Euclid_number. +/// +/// +/// OEIS: https://oeis.org/A006862. +/// +/// +public class EuclidNumbersSequence : ISequence { /// - /// - /// Sequence of Euclid numbers: 1 + product of the first n primes. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Euclid_number. - /// - /// - /// OEIS: https://oeis.org/A006862. - /// + /// Gets sequence of Euclid numbers. /// - public class EuclidNumbersSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of Euclid numbers. - /// - public IEnumerable Sequence + get { - get - { - var primorialNumbers = new PrimorialNumbersSequence().Sequence; + var primorialNumbers = new PrimorialNumbersSequence().Sequence; - foreach (var n in primorialNumbers) - { - yield return n + 1; - } + foreach (var n in primorialNumbers) + { + yield return n + 1; } } } diff --git a/Algorithms/Sequences/EulerTotientSequence.cs b/Algorithms/Sequences/EulerTotientSequence.cs index 1a9482d9..9921a5cb 100644 --- a/Algorithms/Sequences/EulerTotientSequence.cs +++ b/Algorithms/Sequences/EulerTotientSequence.cs @@ -2,97 +2,96 @@ using System.Linq; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of Euler totient function phi(n). +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Euler%27s_totient_function. +/// +/// +/// OEIS: https://oeis.org/A000010. +/// +/// +public class EulerTotientSequence : ISequence { /// /// - /// Sequence of Euler totient function phi(n). + /// Gets sequence of Euler totient function phi(n). /// /// - /// Wikipedia: https://en.wikipedia.org/wiki/Euler%27s_totient_function. + /// 'n' is copied from value of the loop of i that's being enumerated over. + /// 1) Initialize result as n + /// 2) Consider every number 'factor' (where 'factor' is a prime divisor of n). + /// If factor divides n, then do following + /// a) Subtract all multiples of factor from 1 to n [all multiples of factor + /// will have gcd more than 1 (at least factor) with n] + /// b) Update n by repeatedly dividing it by factor. + /// 3) If the reduced n is more than 1, then remove all multiples + /// of n from result. /// /// - /// OEIS: https://oeis.org/A000010. + /// Base code was from https://www.geeksforgeeks.org/eulers-totient-function/. + /// + /// + /// Implementation avoiding floating point operations was used for base + /// and replacement of loop going from 1 to sqrt(n) was replaced with + /// List of prime factors. /// /// - public class EulerTotientSequence : ISequence + public IEnumerable Sequence { - /// - /// - /// Gets sequence of Euler totient function phi(n). - /// - /// - /// 'n' is copied from value of the loop of i that's being enumerated over. - /// 1) Initialize result as n - /// 2) Consider every number 'factor' (where 'factor' is a prime divisor of n). - /// If factor divides n, then do following - /// a) Subtract all multiples of factor from 1 to n [all multiples of factor - /// will have gcd more than 1 (at least factor) with n] - /// b) Update n by repeatedly dividing it by factor. - /// 3) If the reduced n is more than 1, then remove all multiples - /// of n from result. - /// - /// - /// Base code was from https://www.geeksforgeeks.org/eulers-totient-function/. - /// - /// - /// Implementation avoiding floating point operations was used for base - /// and replacement of loop going from 1 to sqrt(n) was replaced with - /// List of prime factors. - /// - /// - public IEnumerable Sequence + get { - get + yield return BigInteger.One; + + for (BigInteger i = 2; ; i++) { - yield return BigInteger.One; + var n = i; + var result = n; - for (BigInteger i = 2; ; i++) + var factors = PrimeFactors(i); + foreach (var factor in factors) { - var n = i; - var result = n; - - var factors = PrimeFactors(i); - foreach (var factor in factors) + while (n % factor == 0) { - while (n % factor == 0) - { - n /= factor; - } - - result -= result / factor; + n /= factor; } - if (n > 1) - { - result -= result / n; - } + result -= result / factor; + } - yield return result; + if (n > 1) + { + result -= result / n; } + + yield return result; } } + } - /// - /// - /// Uses the prime sequence to find all prime factors of the - /// number we're looking at. - /// - /// - /// The prime sequence is examined until its value squared is - /// less than or equal to target, and checked to make sure it - /// evenly divides the target. If it evenly divides, it's added - /// to the result which is returned as a List. - /// - /// - /// Number that is being factored. - /// List of prime factors of target. - private static IEnumerable PrimeFactors(BigInteger target) - { - return new PrimesSequence() - .Sequence.TakeWhile(prime => prime * prime <= target) - .Where(prime => target % prime == 0) - .ToList(); - } + /// + /// + /// Uses the prime sequence to find all prime factors of the + /// number we're looking at. + /// + /// + /// The prime sequence is examined until its value squared is + /// less than or equal to target, and checked to make sure it + /// evenly divides the target. If it evenly divides, it's added + /// to the result which is returned as a List. + /// + /// + /// Number that is being factored. + /// List of prime factors of target. + private static IEnumerable PrimeFactors(BigInteger target) + { + return new PrimesSequence() + .Sequence.TakeWhile(prime => prime * prime <= target) + .Where(prime => target % prime == 0) + .ToList(); } } diff --git a/Algorithms/Sequences/FactorialSequence.cs b/Algorithms/Sequences/FactorialSequence.cs index 9d6e2be5..8bbd6fbc 100644 --- a/Algorithms/Sequences/FactorialSequence.cs +++ b/Algorithms/Sequences/FactorialSequence.cs @@ -1,36 +1,35 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of factorial numbers. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Factorial. +/// +/// +/// OEIS: https://oeis.org/A000142. +/// +/// +public class FactorialSequence : ISequence { /// - /// - /// Sequence of factorial numbers. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Factorial. - /// - /// - /// OEIS: https://oeis.org/A000142. - /// + /// Gets sequence of factorial numbers. /// - public class FactorialSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of factorial numbers. - /// - public IEnumerable Sequence + get { - get + var n = 0; + var factorial = new BigInteger(1); + while (true) { - var n = 0; - var factorial = new BigInteger(1); - while (true) - { - yield return factorial; - n++; - factorial *= n; - } + yield return factorial; + n++; + factorial *= n; } } } diff --git a/Algorithms/Sequences/FermatNumbersSequence.cs b/Algorithms/Sequences/FermatNumbersSequence.cs index 0fe902b9..308e4379 100644 --- a/Algorithms/Sequences/FermatNumbersSequence.cs +++ b/Algorithms/Sequences/FermatNumbersSequence.cs @@ -1,35 +1,34 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of Fermat numbers: a(n) = 2^(2^n) + 1. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Fermat_number. +/// +/// +/// OEIS: https://oeis.org/A000215. +/// +/// +public class FermatNumbersSequence : ISequence { /// - /// - /// Sequence of Fermat numbers: a(n) = 2^(2^n) + 1. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Fermat_number. - /// - /// - /// OEIS: https://oeis.org/A000215. - /// + /// Gets sequence of Fermat numbers. /// - public class FermatNumbersSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of Fermat numbers. - /// - public IEnumerable Sequence + get { - get - { - var n = new BigInteger(2); + var n = new BigInteger(2); - while (true) - { - yield return n + 1; - n *= n; - } + while (true) + { + yield return n + 1; + n *= n; } } } diff --git a/Algorithms/Sequences/FermatPrimesSequence.cs b/Algorithms/Sequences/FermatPrimesSequence.cs index a3d533f7..b7a13984 100644 --- a/Algorithms/Sequences/FermatPrimesSequence.cs +++ b/Algorithms/Sequences/FermatPrimesSequence.cs @@ -1,35 +1,34 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of Fermat primes: primes of the form 2^(2^k) + 1, for some k >= 0. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Fermat_number. +/// +/// +/// OEIS: https://oeis.org/A019434. +/// +/// +public class FermatPrimesSequence : ISequence { /// - /// - /// Sequence of Fermat primes: primes of the form 2^(2^k) + 1, for some k >= 0. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Fermat_number. - /// - /// - /// OEIS: https://oeis.org/A019434. - /// + /// Gets sequence of Fermat primes. /// - public class FermatPrimesSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of Fermat primes. - /// - public IEnumerable Sequence + get { - get - { - var fermatNumbers = new FermatNumbersSequence().Sequence.Take(5); + var fermatNumbers = new FermatNumbersSequence().Sequence.Take(5); - foreach (var n in fermatNumbers) - { - yield return n; - } + foreach (var n in fermatNumbers) + { + yield return n; } } } diff --git a/Algorithms/Sequences/FibonacciSequence.cs b/Algorithms/Sequences/FibonacciSequence.cs index d3c7b9c0..47546ad7 100644 --- a/Algorithms/Sequences/FibonacciSequence.cs +++ b/Algorithms/Sequences/FibonacciSequence.cs @@ -1,39 +1,38 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Fibonacci sequence. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Fibonacci_number. +/// +/// +/// OEIS: https://oeis.org/A000045. +/// +/// +public class FibonacciSequence : ISequence { /// - /// - /// Fibonacci sequence. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Fibonacci_number. - /// - /// - /// OEIS: https://oeis.org/A000045. - /// + /// Gets Fibonacci sequence. /// - public class FibonacciSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets Fibonacci sequence. - /// - public IEnumerable Sequence + get { - get + yield return 0; + yield return 1; + BigInteger previous = 0; + BigInteger current = 1; + while (true) { - yield return 0; - yield return 1; - BigInteger previous = 0; - BigInteger current = 1; - while (true) - { - var next = previous + current; - previous = current; - current = next; - yield return next; - } + var next = previous + current; + previous = current; + current = next; + yield return next; } } } diff --git a/Algorithms/Sequences/GolombsSequence.cs b/Algorithms/Sequences/GolombsSequence.cs index 6567c470..b60d5415 100644 --- a/Algorithms/Sequences/GolombsSequence.cs +++ b/Algorithms/Sequences/GolombsSequence.cs @@ -1,44 +1,42 @@ using System.Collections.Generic; -using System.Linq; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Golomb's sequence. a(n) is the number of times n occurs in the sequence, starting with a(1) = 1. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Golomb_sequence. +/// +/// +/// OEIS: https://oeis.org/A001462. +/// +/// +public class GolombsSequence : ISequence { /// - /// - /// Golomb's sequence. a(n) is the number of times n occurs in the sequence, starting with a(1) = 1. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Golomb_sequence. - /// - /// - /// OEIS: https://oeis.org/A001462. - /// + /// Gets Golomb's sequence. /// - public class GolombsSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets Golomb's sequence. - /// - public IEnumerable Sequence + get { - get - { - yield return 1; - yield return 2; - yield return 2; + yield return 1; + yield return 2; + yield return 2; - var queue = new Queue(); - queue.Enqueue(2); + var queue = new Queue(); + queue.Enqueue(2); - for (var i = 3; ; i++) + for (var i = 3; ; i++) + { + var repetitions = queue.Dequeue(); + for (var j = 0; j < repetitions; j++) { - var repetitions = queue.Dequeue(); - for (var j = 0; j < repetitions; j++) - { - queue.Enqueue(i); - yield return i; - } + queue.Enqueue(i); + yield return i; } } } diff --git a/Algorithms/Sequences/ISequence.cs b/Algorithms/Sequences/ISequence.cs index 326549f3..6de87764 100644 --- a/Algorithms/Sequences/ISequence.cs +++ b/Algorithms/Sequences/ISequence.cs @@ -1,16 +1,15 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// Common interface for all integer sequences. +/// +public interface ISequence { /// - /// Common interface for all integer sequences. + /// Gets sequence as enumerable. /// - public interface ISequence - { - /// - /// Gets sequence as enumerable. - /// - IEnumerable Sequence { get; } - } + IEnumerable Sequence { get; } } diff --git a/Algorithms/Sequences/KolakoskiSequence.cs b/Algorithms/Sequences/KolakoskiSequence.cs index 29720e97..d791027d 100644 --- a/Algorithms/Sequences/KolakoskiSequence.cs +++ b/Algorithms/Sequences/KolakoskiSequence.cs @@ -1,46 +1,45 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Kolakoski sequence; n-th element is the length of the n-th run in the sequence itself. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Kolakoski_sequence. +/// +/// +/// OEIS: https://oeis.org/A000002. +/// +/// +public class KolakoskiSequence : ISequence { /// - /// - /// Kolakoski sequence; n-th element is the length of the n-th run in the sequence itself. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Kolakoski_sequence. - /// - /// - /// OEIS: https://oeis.org/A000002. - /// + /// Gets Kolakoski sequence. /// - public class KolakoskiSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets Kolakoski sequence. - /// - public IEnumerable Sequence + get { - get - { - yield return 1; - yield return 2; - yield return 2; + yield return 1; + yield return 2; + yield return 2; - var queue = new Queue(); - queue.Enqueue(2); - var nextElement = 1; - while (true) + var queue = new Queue(); + queue.Enqueue(2); + var nextElement = 1; + while (true) + { + var nextRun = queue.Dequeue(); + for (var i = 0; i < nextRun; i++) { - var nextRun = queue.Dequeue(); - for (var i = 0; i < nextRun; i++) - { - queue.Enqueue(nextElement); - yield return nextElement; - } - - nextElement = 1 + nextElement % 2; + queue.Enqueue(nextElement); + yield return nextElement; } + + nextElement = 1 + nextElement % 2; } } } diff --git a/Algorithms/Sequences/KolakoskiSequence2.cs b/Algorithms/Sequences/KolakoskiSequence2.cs index d5464d6a..22bbc7ae 100644 --- a/Algorithms/Sequences/KolakoskiSequence2.cs +++ b/Algorithms/Sequences/KolakoskiSequence2.cs @@ -2,44 +2,43 @@ using System.Linq; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Kolakoski sequence; n-th element is the length of the n-th run in the sequence itself. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Kolakoski_sequence. +/// +/// +/// OEIS: https://oeis.org/A000002. +/// +/// +public class KolakoskiSequence2 : ISequence { /// - /// - /// Kolakoski sequence; n-th element is the length of the n-th run in the sequence itself. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Kolakoski_sequence. - /// - /// - /// OEIS: https://oeis.org/A000002. - /// + /// Gets Kolakoski sequence. /// - public class KolakoskiSequence2 : ISequence + public IEnumerable Sequence { - /// - /// Gets Kolakoski sequence. - /// - public IEnumerable Sequence + get { - get - { - yield return 1; - yield return 2; - yield return 2; + yield return 1; + yield return 2; + yield return 2; - var inner = new KolakoskiSequence2().Sequence.Skip(2); - var nextElement = 1; - foreach (var runLength in inner) + var inner = new KolakoskiSequence2().Sequence.Skip(2); + var nextElement = 1; + foreach (var runLength in inner) + { + yield return nextElement; + if (runLength > 1) { yield return nextElement; - if (runLength > 1) - { - yield return nextElement; - } - - nextElement = 1 + nextElement % 2; } + + nextElement = 1 + nextElement % 2; } } } diff --git a/Algorithms/Sequences/KummerNumbersSequence.cs b/Algorithms/Sequences/KummerNumbersSequence.cs index df7b2c12..3f94b7b7 100644 --- a/Algorithms/Sequences/KummerNumbersSequence.cs +++ b/Algorithms/Sequences/KummerNumbersSequence.cs @@ -1,36 +1,35 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of Kummer numbers (also called Euclid numbers of the second kind): +/// -1 + product of first n consecutive primes. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Euclid_number. +/// +/// +/// OEIS: https://oeis.org/A057588. +/// +/// +public class KummerNumbersSequence : ISequence { /// - /// - /// Sequence of Kummer numbers (also called Euclid numbers of the second kind): - /// -1 + product of first n consecutive primes. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Euclid_number. - /// - /// - /// OEIS: https://oeis.org/A057588. - /// + /// Gets sequence of Kummer numbers. /// - public class KummerNumbersSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of Kummer numbers. - /// - public IEnumerable Sequence + get { - get - { - var primorialNumbers = new PrimorialNumbersSequence().Sequence.Skip(1); + var primorialNumbers = new PrimorialNumbersSequence().Sequence.Skip(1); - foreach (var n in primorialNumbers) - { - yield return n - 1; - } + foreach (var n in primorialNumbers) + { + yield return n - 1; } } } diff --git a/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs b/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs index d915d5fb..269035eb 100644 --- a/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs +++ b/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs @@ -1,64 +1,63 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of Lucas number values. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Lucas_number. +/// +/// +/// OEIS: http://oeis.org/A000032. +/// +/// +public class LucasNumbersBeginningAt2Sequence : ISequence { /// /// - /// Sequence of Lucas number values. + /// Gets Lucas number sequence. + /// + /// + /// Lucas numbers follow the same type of operation that the Fibonacci (A000045) + /// sequence performs with starting values of 2, 1 versus 0,1. As Fibonacci does, + /// the ratio between two consecutive Lucas numbers converges to phi. /// /// - /// Wikipedia: https://en.wikipedia.org/wiki/Lucas_number. + /// This implementation is similar to A000204, but starts with the index of 0, thus having the + /// initial values being (2,1) instead of starting at index 1 with initial values of (1,3). /// /// - /// OEIS: http://oeis.org/A000032. + /// A simple relationship to Fibonacci can be shown with L(n) = F(n-1) + F(n+1), n>= 1. + /// + /// n | L(n) | F(n-1) | F(n+1) + /// --|-------|--------+--------+ + /// 0 | 2 | | | + /// 1 | 1 | 0 | 1 | + /// 2 | 3 | 1 | 2 | + /// 3 | 4 | 1 | 3 | + /// 4 | 7 | 2 | 5 | + /// 5 | 11 | 3 | 8 | + /// --|-------|--------+--------+. /// /// - public class LucasNumbersBeginningAt2Sequence : ISequence + public IEnumerable Sequence { - /// - /// - /// Gets Lucas number sequence. - /// - /// - /// Lucas numbers follow the same type of operation that the Fibonacci (A000045) - /// sequence performs with starting values of 2, 1 versus 0,1. As Fibonacci does, - /// the ratio between two consecutive Lucas numbers converges to phi. - /// - /// - /// This implementation is similar to A000204, but starts with the index of 0, thus having the - /// initial values being (2,1) instead of starting at index 1 with initial values of (1,3). - /// - /// - /// A simple relationship to Fibonacci can be shown with L(n) = F(n-1) + F(n+1), n>= 1. - /// - /// n | L(n) | F(n-1) | F(n+1) - /// --|-------|--------+--------+ - /// 0 | 2 | | | - /// 1 | 1 | 0 | 1 | - /// 2 | 3 | 1 | 2 | - /// 3 | 4 | 1 | 3 | - /// 4 | 7 | 2 | 5 | - /// 5 | 11 | 3 | 8 | - /// --|-------|--------+--------+. - /// - /// - public IEnumerable Sequence + get { - get + yield return 2; + yield return 1; + BigInteger previous = 2; + BigInteger current = 1; + while (true) { - yield return 2; - yield return 1; - BigInteger previous = 2; - BigInteger current = 1; - while (true) - { - var next = previous + current; - previous = current; - current = next; + var next = previous + current; + previous = current; + current = next; - yield return next; - } + yield return next; } } } diff --git a/Algorithms/Sequences/MakeChangeSequence.cs b/Algorithms/Sequences/MakeChangeSequence.cs index 78f3acc7..1574f133 100644 --- a/Algorithms/Sequences/MakeChangeSequence.cs +++ b/Algorithms/Sequences/MakeChangeSequence.cs @@ -1,56 +1,54 @@ -using System; using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Number of ways of making change for n cents using coins of 1, 2, 5, 10 cents. +/// +/// +/// OEIS: https://oeis.org/A000008. +/// +/// +public class MakeChangeSequence : ISequence { /// /// - /// Number of ways of making change for n cents using coins of 1, 2, 5, 10 cents. + /// Gets sequence of number of ways of making change for n cents + /// using coins of 1, 2, 5, 10 cents. + /// + /// + /// Uses formula from OEIS page by Michael Somos + /// along with first 17 values to prevent index issues. /// /// - /// OEIS: https://oeis.org/A000008. + /// Formula: + /// a(n) = a(n-2) +a(n-5) - a(n-7) + a(n-10) - a(n-12) - a(n-15) + a(n-17) + 1. /// /// - public class MakeChangeSequence : ISequence + public IEnumerable Sequence { - /// - /// - /// Gets sequence of number of ways of making change for n cents - /// using coins of 1, 2, 5, 10 cents. - /// - /// - /// Uses formula from OEIS page by Michael Somos - /// along with first 17 values to prevent index issues. - /// - /// - /// Formula: - /// a(n) = a(n-2) +a(n-5) - a(n-7) + a(n-10) - a(n-12) - a(n-15) + a(n-17) + 1. - /// - /// - public IEnumerable Sequence + get { - get + var seed = new List + { + 1, 1, 2, 2, 3, 4, 5, 6, 7, 8, + 11, 12, 15, 16, 19, 22, 25, + }; + foreach (var value in seed) { - var seed = new List - { - 1, 1, 2, 2, 3, 4, 5, 6, 7, 8, - 11, 12, 15, 16, 19, 22, 25, - }; - foreach (var value in seed) - { - yield return value; - } + yield return value; + } - for(var index = 17; ; index++) - { - BigInteger newValue = seed[index - 2] + seed[index - 5] - seed[index - 7] - + seed[index - 10] - seed[index - 12] - seed[index - 15] - + seed[index - 17] + 1; + for(var index = 17; ; index++) + { + BigInteger newValue = seed[index - 2] + seed[index - 5] - seed[index - 7] + + seed[index - 10] - seed[index - 12] - seed[index - 15] + + seed[index - 17] + 1; - seed.Add(newValue); - yield return newValue; - } + seed.Add(newValue); + yield return newValue; } } } diff --git a/Algorithms/Sequences/MatchstickTriangleSequence.cs b/Algorithms/Sequences/MatchstickTriangleSequence.cs index 9033cab1..d2dd075b 100644 --- a/Algorithms/Sequences/MatchstickTriangleSequence.cs +++ b/Algorithms/Sequences/MatchstickTriangleSequence.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Numerics; diff --git a/Algorithms/Sequences/NaturalSequence.cs b/Algorithms/Sequences/NaturalSequence.cs index 2acc020b..a7115119 100644 --- a/Algorithms/Sequences/NaturalSequence.cs +++ b/Algorithms/Sequences/NaturalSequence.cs @@ -1,33 +1,32 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of natural numbers. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Natural_number. +/// +/// +/// OEIS: https://oeis.org/A000027. +/// +/// +public class NaturalSequence : ISequence { /// - /// - /// Sequence of natural numbers. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Natural_number. - /// - /// - /// OEIS: https://oeis.org/A000027. - /// + /// Gets sequence of natural numbers. /// - public class NaturalSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of natural numbers. - /// - public IEnumerable Sequence + get { - get + var n = new BigInteger(1); + while (true) { - var n = new BigInteger(1); - while (true) - { - yield return n++; - } + yield return n++; } } } diff --git a/Algorithms/Sequences/NegativeIntegersSequence.cs b/Algorithms/Sequences/NegativeIntegersSequence.cs index 8b872ec2..826999d5 100644 --- a/Algorithms/Sequences/NegativeIntegersSequence.cs +++ b/Algorithms/Sequences/NegativeIntegersSequence.cs @@ -1,34 +1,33 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of negative integers. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Negative_number. +/// +/// +/// OEIS: http://oeis.org/A001478. +/// +/// +public class NegativeIntegersSequence : ISequence { /// - /// - /// Sequence of negative integers. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Negative_number. - /// - /// - /// OEIS: http://oeis.org/A001478. - /// + /// Gets sequence of negative integers. /// - public class NegativeIntegersSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of negative integers. - /// - public IEnumerable Sequence + get { - get - { - var n = new BigInteger(-1); + var n = new BigInteger(-1); - while (true) - { - yield return n--; - } + while (true) + { + yield return n--; } } } diff --git a/Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs b/Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs index 5ab961d4..5d6c8b2a 100644 --- a/Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs +++ b/Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs @@ -1,36 +1,35 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of number of truth tables generated by Boolean expressions of n variables +/// (Double exponentials of 2: a(n) = 2^(2^n)). +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Truth_table. +/// +/// +/// OEIS: https://oeis.org/A001146. +/// +/// +public class NumberOfBooleanFunctionsSequence : ISequence { /// - /// - /// Sequence of number of truth tables generated by Boolean expressions of n variables - /// (Double exponentials of 2: a(n) = 2^(2^n)). - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Truth_table. - /// - /// - /// OEIS: https://oeis.org/A001146. - /// + /// Gets sequence of number Of Boolean functions. /// - public class NumberOfBooleanFunctionsSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of number Of Boolean functions. - /// - public IEnumerable Sequence + get { - get - { - var n = new BigInteger(2); + var n = new BigInteger(2); - while (true) - { - yield return n; - n *= n; - } + while (true) + { + yield return n; + n *= n; } } } diff --git a/Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs b/Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs index 66dbc736..edee1c62 100644 --- a/Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs +++ b/Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs @@ -1,44 +1,43 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Number of primes with n digits +/// (The number of primes between 10^(n-1) and 10^n). +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Prime-counting_function. +/// +/// +/// OEIS: https://oeis.org/A006879. +/// +/// +public class NumberOfPrimesByNumberOfDigitsSequence : ISequence { /// - /// - /// Number of primes with n digits - /// (The number of primes between 10^(n-1) and 10^n). - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Prime-counting_function. - /// - /// - /// OEIS: https://oeis.org/A006879. - /// + /// Gets sequence of number of primes. /// - public class NumberOfPrimesByNumberOfDigitsSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of number of primes. - /// - public IEnumerable Sequence + get { - get - { - ISequence primes = new PrimesSequence(); - var powerOf10 = new BigInteger(1); - var counter = new BigInteger(0); + ISequence primes = new PrimesSequence(); + var powerOf10 = new BigInteger(1); + var counter = new BigInteger(0); - foreach (var p in primes.Sequence) + foreach (var p in primes.Sequence) + { + if (p > powerOf10) { - if (p > powerOf10) - { - yield return counter; - counter = 0; - powerOf10 *= 10; - } - - counter++; + yield return counter; + counter = 0; + powerOf10 *= 10; } + + counter++; } } } diff --git a/Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs b/Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs index 9ce9f504..9873d566 100644 --- a/Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs +++ b/Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs @@ -1,42 +1,41 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of number of primes less than 10^n (with at most n digits). +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Prime-counting_function. +/// +/// +/// OEIS: https://oeis.org/A006880. +/// +/// +public class NumberOfPrimesByPowersOf10Sequence : ISequence { /// - /// - /// Sequence of number of primes less than 10^n (with at most n digits). - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Prime-counting_function. - /// - /// - /// OEIS: https://oeis.org/A006880. - /// + /// Gets sequence of numbers of primes. /// - public class NumberOfPrimesByPowersOf10Sequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of numbers of primes. - /// - public IEnumerable Sequence + get { - get - { - ISequence primes = new PrimesSequence(); - var powerOf10 = new BigInteger(1); - var counter = new BigInteger(0); + ISequence primes = new PrimesSequence(); + var powerOf10 = new BigInteger(1); + var counter = new BigInteger(0); - foreach (var p in primes.Sequence) + foreach (var p in primes.Sequence) + { + if (p > powerOf10) { - if (p > powerOf10) - { - yield return counter; - powerOf10 *= 10; - } - - counter++; + yield return counter; + powerOf10 *= 10; } + + counter++; } } } diff --git a/Algorithms/Sequences/PowersOf10Sequence.cs b/Algorithms/Sequences/PowersOf10Sequence.cs index 65fa0032..5fdd1a64 100644 --- a/Algorithms/Sequences/PowersOf10Sequence.cs +++ b/Algorithms/Sequences/PowersOf10Sequence.cs @@ -1,35 +1,34 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of powers of 10: a(n) = 10^n. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Power_of_10. +/// +/// +/// OEIS: https://oeis.org/A011557. +/// +/// +public class PowersOf10Sequence : ISequence { /// - /// - /// Sequence of powers of 10: a(n) = 10^n. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Power_of_10. - /// - /// - /// OEIS: https://oeis.org/A011557. - /// + /// Gets sequence of powers of 10. /// - public class PowersOf10Sequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of powers of 10. - /// - public IEnumerable Sequence + get { - get - { - var n = new BigInteger(1); + var n = new BigInteger(1); - while (true) - { - yield return n; - n *= 10; - } + while (true) + { + yield return n; + n *= 10; } } } diff --git a/Algorithms/Sequences/PowersOf2Sequence.cs b/Algorithms/Sequences/PowersOf2Sequence.cs index 7d4bb994..80d20c74 100644 --- a/Algorithms/Sequences/PowersOf2Sequence.cs +++ b/Algorithms/Sequences/PowersOf2Sequence.cs @@ -1,35 +1,34 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of powers of 2: a(n) = 2^n. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Power_of_two. +/// +/// +/// OEIS: https://oeis.org/A000079. +/// +/// +public class PowersOf2Sequence : ISequence { /// - /// - /// Sequence of powers of 2: a(n) = 2^n. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Power_of_two. - /// - /// - /// OEIS: https://oeis.org/A000079. - /// + /// Gets sequence of powers of 2. /// - public class PowersOf2Sequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of powers of 2. - /// - public IEnumerable Sequence + get { - get - { - var n = new BigInteger(1); + var n = new BigInteger(1); - while (true) - { - yield return n; - n *= 2; - } + while (true) + { + yield return n; + n *= 2; } } } diff --git a/Algorithms/Sequences/PrimePiSequence.cs b/Algorithms/Sequences/PrimePiSequence.cs index 3e1b9ab5..84c19076 100644 --- a/Algorithms/Sequences/PrimePiSequence.cs +++ b/Algorithms/Sequences/PrimePiSequence.cs @@ -1,41 +1,40 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of number of primes less than or equal to n (PrimePi(n)). +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Prime-counting_function. +/// +/// +/// OEIS: https://oeis.org/A000720. +/// +/// +public class PrimePiSequence : ISequence { /// - /// - /// Sequence of number of primes less than or equal to n (PrimePi(n)). - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Prime-counting_function. - /// - /// - /// OEIS: https://oeis.org/A000720. - /// + /// Gets sequence of number of primes. /// - public class PrimePiSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of number of primes. - /// - public IEnumerable Sequence + get { - get - { - ISequence primes = new PrimesSequence(); - var n = new BigInteger(0); - var counter = new BigInteger(0); + ISequence primes = new PrimesSequence(); + var n = new BigInteger(0); + var counter = new BigInteger(0); - foreach (var p in primes.Sequence) + foreach (var p in primes.Sequence) + { + for (n++; n < p; n++) { - for (n++; n < p; n++) - { - yield return counter; - } - - yield return ++counter; + yield return counter; } + + yield return ++counter; } } } diff --git a/Algorithms/Sequences/PrimesSequence.cs b/Algorithms/Sequences/PrimesSequence.cs index c38c75cc..ad4d9e1d 100644 --- a/Algorithms/Sequences/PrimesSequence.cs +++ b/Algorithms/Sequences/PrimesSequence.cs @@ -1,46 +1,45 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of prime numbers. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Prime_number. +/// +/// +/// OEIS: https://oeis.org/A000040. +/// +/// +public class PrimesSequence : ISequence { /// - /// - /// Sequence of prime numbers. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Prime_number. - /// - /// - /// OEIS: https://oeis.org/A000040. - /// + /// Gets sequence of prime numbers. /// - public class PrimesSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of prime numbers. - /// - public IEnumerable Sequence + get { - get + yield return 2; + var primes = new List { - yield return 2; - var primes = new List - { - 2, - }; - var n = new BigInteger(3); + 2, + }; + var n = new BigInteger(3); - while (true) + while (true) + { + if (primes.All(p => n % p != 0)) { - if (primes.All(p => n % p != 0)) - { - yield return n; - primes.Add(n); - } - - n += 2; + yield return n; + primes.Add(n); } + + n += 2; } } } diff --git a/Algorithms/Sequences/PrimorialNumbersSequence.cs b/Algorithms/Sequences/PrimorialNumbersSequence.cs index de43ec1e..dc5a3a14 100644 --- a/Algorithms/Sequences/PrimorialNumbersSequence.cs +++ b/Algorithms/Sequences/PrimorialNumbersSequence.cs @@ -1,36 +1,35 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of primorial numbers: product of first n primes. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Primorial. +/// +/// +/// OEIS: https://oeis.org/A002110. +/// +/// +public class PrimorialNumbersSequence : ISequence { /// - /// - /// Sequence of primorial numbers: product of first n primes. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Primorial. - /// - /// - /// OEIS: https://oeis.org/A002110. - /// + /// Gets sequence of primorial numbers. /// - public class PrimorialNumbersSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of primorial numbers. - /// - public IEnumerable Sequence + get { - get - { - var primes = new PrimesSequence().Sequence; - var n = new BigInteger(1); + var primes = new PrimesSequence().Sequence; + var n = new BigInteger(1); - foreach (var p in primes) - { - yield return n; - n *= p; - } + foreach (var p in primes) + { + yield return n; + n *= p; } } } diff --git a/Algorithms/Sequences/RecamansSequence.cs b/Algorithms/Sequences/RecamansSequence.cs index 03376201..5e749bc7 100644 --- a/Algorithms/Sequences/RecamansSequence.cs +++ b/Algorithms/Sequences/RecamansSequence.cs @@ -1,46 +1,45 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Recaman's sequence. a(0) = 0; for n > 0, a(n) = a(n-1) - n if nonnegative and not already in the sequence, otherwise a(n) = a(n-1) + n. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Recam%C3%A1n%27s_sequence. +/// +/// +/// OEIS: http://oeis.org/A005132. +/// +/// +public class RecamansSequence : ISequence { /// - /// - /// Recaman's sequence. a(0) = 0; for n > 0, a(n) = a(n-1) - n if nonnegative and not already in the sequence, otherwise a(n) = a(n-1) + n. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Recam%C3%A1n%27s_sequence. - /// - /// - /// OEIS: http://oeis.org/A005132. - /// + /// Gets Recaman's sequence. /// - public class RecamansSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets Recaman's sequence. - /// - public IEnumerable Sequence + get { - get - { - yield return 0; - var elements = new HashSet { 0 }; - var previous = 0; - var i = 1; + yield return 0; + var elements = new HashSet { 0 }; + var previous = 0; + var i = 1; - while (true) + while (true) + { + var current = previous - i; + if (current < 0 || elements.Contains(current)) { - var current = previous - i; - if (current < 0 || elements.Contains(current)) - { - current = previous + i; - } - - yield return current; - previous = current; - elements.Add(current); - i++; + current = previous + i; } + + yield return current; + previous = current; + elements.Add(current); + i++; } } } diff --git a/Algorithms/Sequences/SquaresSequence.cs b/Algorithms/Sequences/SquaresSequence.cs index 70ff9ed9..4e910191 100644 --- a/Algorithms/Sequences/SquaresSequence.cs +++ b/Algorithms/Sequences/SquaresSequence.cs @@ -1,35 +1,34 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Sequence of square numbers. +/// +/// +/// Wikipedia: https://wikipedia.org/wiki/Square_number. +/// +/// +/// OEIS: http://oeis.org/A000290. +/// +/// +public class SquaresSequence : ISequence { /// - /// - /// Sequence of square numbers. - /// - /// - /// Wikipedia: https://wikipedia.org/wiki/Square_number. - /// - /// - /// OEIS: http://oeis.org/A000290. - /// + /// Gets sequence of square numbers. /// - public class SquaresSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of square numbers. - /// - public IEnumerable Sequence + get { - get - { - var n = new BigInteger(0); + var n = new BigInteger(0); - while (true) - { - yield return n * n; - n++; - } + while (true) + { + yield return n * n; + n++; } } } diff --git a/Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs b/Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs index 6d70da5e..ce690a13 100644 --- a/Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs +++ b/Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs @@ -1,52 +1,51 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Number of halving and tripling steps to reach 1 in the '3n+1' problem. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Collatz_conjecture. +/// +/// +/// OEIS: https://oeis.org/A006577. +/// +/// +public class ThreeNPlusOneStepsSequence : ISequence { /// - /// - /// Number of halving and tripling steps to reach 1 in the '3n+1' problem. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Collatz_conjecture. - /// - /// - /// OEIS: https://oeis.org/A006577. - /// + /// Gets sequence of number of halving and tripling steps to reach 1 in the '3n+1' problem. /// - public class ThreeNPlusOneStepsSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets sequence of number of halving and tripling steps to reach 1 in the '3n+1' problem. - /// - public IEnumerable Sequence + get { - get + BigInteger startingValue = 1; + + while (true) { - BigInteger startingValue = 1; + BigInteger counter = 0; + BigInteger currentValue = startingValue; - while (true) + while (currentValue != 1) { - BigInteger counter = 0; - BigInteger currentValue = startingValue; - - while (currentValue != 1) + if (currentValue.IsEven) { - if (currentValue.IsEven) - { - currentValue /= 2; - } - else - { - currentValue = 3 * currentValue + 1; - } - - counter++; + currentValue /= 2; + } + else + { + currentValue = 3 * currentValue + 1; } - yield return counter; - startingValue++; + counter++; } + + yield return counter; + startingValue++; } } } diff --git a/Algorithms/Sequences/VanEcksSequence.cs b/Algorithms/Sequences/VanEcksSequence.cs index 1b63fc94..9fbf8d84 100644 --- a/Algorithms/Sequences/VanEcksSequence.cs +++ b/Algorithms/Sequences/VanEcksSequence.cs @@ -1,43 +1,42 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// Van Eck's sequence. For n >= 1, if there exists an m < n such that a(m) = a(n), take the largest such m and set a(n+1) = n-m; otherwise a(n+1) = 0. Start with a(1)=0. +/// +/// +/// OEIS: http://oeis.org/A181391. +/// +/// +public class VanEcksSequence : ISequence { /// - /// - /// Van Eck's sequence. For n >= 1, if there exists an m < n such that a(m) = a(n), take the largest such m and set a(n+1) = n-m; otherwise a(n+1) = 0. Start with a(1)=0. - /// - /// - /// OEIS: http://oeis.org/A181391. - /// + /// Gets Van Eck's sequence. /// - public class VanEcksSequence : ISequence + public IEnumerable Sequence { - /// - /// Gets Van Eck's sequence. - /// - public IEnumerable Sequence + get { - get + yield return 0; + var dictionary = new Dictionary(); + BigInteger previous = 0; + BigInteger currentIndex = 2; // 1-based index + while (true) { - yield return 0; - var dictionary = new Dictionary(); - BigInteger previous = 0; - BigInteger currentIndex = 2; // 1-based index - while (true) + BigInteger element = 0; + if (dictionary.TryGetValue(previous, out var previousIndex)) { - BigInteger element = 0; - if (dictionary.TryGetValue(previous, out var previousIndex)) - { - element = currentIndex - previousIndex; - } + element = currentIndex - previousIndex; + } - yield return element; + yield return element; - dictionary[previous] = currentIndex; - previous = element; - currentIndex++; - } + dictionary[previous] = currentIndex; + previous = element; + currentIndex++; } } } diff --git a/Algorithms/Sequences/ZeroSequence.cs b/Algorithms/Sequences/ZeroSequence.cs index 431a2d25..0bdf7abf 100644 --- a/Algorithms/Sequences/ZeroSequence.cs +++ b/Algorithms/Sequences/ZeroSequence.cs @@ -1,27 +1,25 @@ -using System.Collections; using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Sequences +namespace Algorithms.Sequences; + +/// +/// +/// The zero sequence. +/// +/// +/// OEIS: https://oeis.org/A000004. +/// +/// +public class ZeroSequence : ISequence { - /// - /// - /// The zero sequence. - /// - /// - /// OEIS: https://oeis.org/A000004. - /// - /// - public class ZeroSequence : ISequence + public IEnumerable Sequence { - public IEnumerable Sequence + get { - get + while (true) { - while (true) - { - yield return 0; - } + yield return 0; } } } diff --git a/Algorithms/Shufflers/FisherYatesShuffler.cs b/Algorithms/Shufflers/FisherYatesShuffler.cs index 0682625c..53f457f8 100644 --- a/Algorithms/Shufflers/FisherYatesShuffler.cs +++ b/Algorithms/Shufflers/FisherYatesShuffler.cs @@ -1,32 +1,31 @@ using System; -namespace Algorithms.Shufflers +namespace Algorithms.Shufflers; + +/// +/// Fisher-Yates shuffle is a simple shuffling algorithm, +/// which is usually used to shuffle a deck of cards. +/// +/// Type array input. +public class FisherYatesShuffler : IShuffler { /// - /// Fisher-Yates shuffle is a simple shuffling algorithm, - /// which is usually used to shuffle a deck of cards. + /// Shuffles input array using Fisher-Yates algorithm. + /// The algorithm starts shuffling from the last element + /// and swap elements one by one. We use random index to + /// choose element we use in swap operation. /// - /// Type array input. - public class FisherYatesShuffler : IShuffler + /// Array to shuffle. + /// Random generator seed. Used to repeat the shuffle. + public void Shuffle(T[] array, int? seed = null) { - /// - /// Shuffles input array using Fisher-Yates algorithm. - /// The algorithm starts shuffling from the last element - /// and swap elements one by one. We use random index to - /// choose element we use in swap operation. - /// - /// Array to shuffle. - /// Random generator seed. Used to repeat the shuffle. - public void Shuffle(T[] array, int? seed = null) - { - var random = seed is null ? new Random() : new Random(seed.Value); + var random = seed is null ? new Random() : new Random(seed.Value); - for (var i = array.Length - 1; i > 0; i--) - { - var j = random.Next(0, i + 1); + for (var i = array.Length - 1; i > 0; i--) + { + var j = random.Next(0, i + 1); - (array[i], array[j]) = (array[j], array[i]); - } + (array[i], array[j]) = (array[j], array[i]); } } } diff --git a/Algorithms/Shufflers/IShuffler.cs b/Algorithms/Shufflers/IShuffler.cs index 821f711a..3cc2745e 100644 --- a/Algorithms/Shufflers/IShuffler.cs +++ b/Algorithms/Shufflers/IShuffler.cs @@ -1,15 +1,14 @@ -namespace Algorithms.Shufflers +namespace Algorithms.Shufflers; + +/// +/// Shuffles array. +/// +/// Type of array item. +public interface IShuffler { /// /// Shuffles array. /// - /// Type of array item. - public interface IShuffler - { - /// - /// Shuffles array. - /// - /// Array to Shuffle. - void Shuffle(T[] array, int? seed = null); - } + /// Array to Shuffle. + void Shuffle(T[] array, int? seed = null); } From a354d01e6b6e003ac0969320314bbb4bdc97434a Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Fri, 5 Jan 2024 20:45:32 +0000 Subject: [PATCH 085/138] Switch to file-scoped namespaces (#433) --- .../Comparison/BinaryInsertionSorter.cs | 107 +- Algorithms/Sorters/Comparison/BogoSorter.cs | 81 +- Algorithms/Sorters/Comparison/BubbleSorter.cs | 57 +- .../Sorters/Comparison/CocktailSorter.cs | 83 +- Algorithms/Sorters/Comparison/CombSorter.cs | 73 +- Algorithms/Sorters/Comparison/CycleSorter.cs | 105 +- .../Sorters/Comparison/ExchangeSorter.cs | 41 +- Algorithms/Sorters/Comparison/HeapSorter.cs | 97 +- .../Sorters/Comparison/IComparisonSorter.cs | 25 +- .../Sorters/Comparison/InsertionSorter.cs | 41 +- .../Comparison/MedianOfThreeQuickSorter.cs | 75 +- Algorithms/Sorters/Comparison/MergeSorter.cs | 95 +- .../Comparison/MiddlePointQuickSorter.cs | 21 +- .../Sorters/Comparison/PancakeSorter.cs | 113 +- Algorithms/Sorters/Comparison/QuickSorter.cs | 99 +- .../Comparison/RandomPivotQuickSorter.cs | 23 +- .../Sorters/Comparison/SelectionSorter.cs | 49 +- Algorithms/Sorters/Comparison/ShellSorter.cs | 71 +- Algorithms/Sorters/Comparison/TimSorter.cs | 1001 ++++++++--------- .../Sorters/External/ExternalMergeSorter.cs | 185 ++- .../Sorters/External/IExternalSorter.cs | 19 +- .../Sorters/External/ISequentialStorage.cs | 13 +- .../External/ISequentialStorageReader.cs | 9 +- .../External/ISequentialStorageWriter.cs | 9 +- .../External/Storages/IntFileStorage.cs | 51 +- .../External/Storages/IntInMemoryStorage.cs | 57 +- Algorithms/Sorters/Integer/BucketSorter.cs | 157 ++- Algorithms/Sorters/Integer/CountingSorter.cs | 89 +- Algorithms/Sorters/Integer/IIntegerSorter.cs | 19 +- Algorithms/Sorters/Integer/RadixSorter.cs | 73 +- Algorithms/Sorters/String/IStringSorter.cs | 19 +- .../Sorters/String/MsdRadixStringSorter.cs | 99 +- Algorithms/Strings/GeneralStringAlgorithms.cs | 53 +- Algorithms/Strings/Palindrome.cs | 57 +- .../Strings/PatternMatching/BoyerMoore.cs | 253 +++-- .../KnuthMorrisPrattSearcher.cs | 119 +- .../PatternMatching/NaiveStringSearch.cs | 53 +- .../Strings/PatternMatching/RabinKarp.cs | 123 +- .../PatternMatching/ZblockSubstringSearch.cs | 95 +- Algorithms/Strings/Permutation.cs | 43 +- .../Strings/Similarity/HammingDistance.cs | 53 +- .../Strings/Similarity/JaroSimilarity.cs | 135 ++- .../Strings/Similarity/JaroWinklerDistance.cs | 47 +- 43 files changed, 2022 insertions(+), 2065 deletions(-) diff --git a/Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs b/Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs index 1de28571..1b089bf8 100644 --- a/Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs +++ b/Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs @@ -1,72 +1,71 @@ using System; using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// TODO. +/// +/// TODO. 2. +public class BinaryInsertionSorter : IComparisonSorter { /// - /// TODO. + /// Sorts array using specified comparer, + /// variant of insertion sort where binary search is used to find place for next element + /// internal, in-place, unstable, + /// time complexity: O(n^2), + /// space complexity: O(1), + /// where n - array length. /// - /// TODO. 2. - public class BinaryInsertionSorter : IComparisonSorter + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) { - /// - /// Sorts array using specified comparer, - /// variant of insertion sort where binary search is used to find place for next element - /// internal, in-place, unstable, - /// time complexity: O(n^2), - /// space complexity: O(1), - /// where n - array length. - /// - /// Array to sort. - /// Compares elements. - public void Sort(T[] array, IComparer comparer) + for (var i = 1; i < array.Length; i++) { - for (var i = 1; i < array.Length; i++) - { - var target = array[i]; - var moveIndex = i - 1; - var targetInsertLocation = BinarySearch(array, 0, moveIndex, target, comparer); - Array.Copy(array, targetInsertLocation, array, targetInsertLocation + 1, i - targetInsertLocation); + var target = array[i]; + var moveIndex = i - 1; + var targetInsertLocation = BinarySearch(array, 0, moveIndex, target, comparer); + Array.Copy(array, targetInsertLocation, array, targetInsertLocation + 1, i - targetInsertLocation); - array[targetInsertLocation] = target; - } + array[targetInsertLocation] = target; } + } - /// Implementation of Binary Search using an iterative approach. - /// - /// An array of values sorted in ascending order between the index values left and right to search - /// through. - /// - /// Left index to search from (inclusive). - /// Right index to search to (inclusive). - /// The value to find placefor in the provided array. - /// TODO. - /// The index where to insert target value. - private static int BinarySearch(T[] array, int from, int to, T target, IComparer comparer) + /// Implementation of Binary Search using an iterative approach. + /// + /// An array of values sorted in ascending order between the index values left and right to search + /// through. + /// + /// Left index to search from (inclusive). + /// Right index to search to (inclusive). + /// The value to find placefor in the provided array. + /// TODO. + /// The index where to insert target value. + private static int BinarySearch(T[] array, int from, int to, T target, IComparer comparer) + { + var left = from; + var right = to; + while (right > left) { - var left = from; - var right = to; - while (right > left) - { - var middle = (left + right) / 2; - var comparisonResult = comparer.Compare(target, array[middle]); - - if (comparisonResult == 0) - { - return middle + 1; - } + var middle = (left + right) / 2; + var comparisonResult = comparer.Compare(target, array[middle]); - if (comparisonResult > 0) - { - left = middle + 1; - } - else - { - right = middle - 1; - } + if (comparisonResult == 0) + { + return middle + 1; } - return comparer.Compare(target, array[left]) < 0 ? left : left + 1; + if (comparisonResult > 0) + { + left = middle + 1; + } + else + { + right = middle - 1; + } } + + return comparer.Compare(target, array[left]) < 0 ? left : left + 1; } } diff --git a/Algorithms/Sorters/Comparison/BogoSorter.cs b/Algorithms/Sorters/Comparison/BogoSorter.cs index 4bac7639..9a25cd08 100644 --- a/Algorithms/Sorters/Comparison/BogoSorter.cs +++ b/Algorithms/Sorters/Comparison/BogoSorter.cs @@ -1,63 +1,62 @@ using System; using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Class that implements bogo sort algorithm. +/// +/// Type of array element. +public class BogoSorter : IComparisonSorter { + private readonly Random random = new(); + /// - /// Class that implements bogo sort algorithm. + /// TODO. /// - /// Type of array element. - public class BogoSorter : IComparisonSorter + /// TODO. 2. + /// TODO. 3. + public void Sort(T[] array, IComparer comparer) { - private readonly Random random = new(); - - /// - /// TODO. - /// - /// TODO. 2. - /// TODO. 3. - public void Sort(T[] array, IComparer comparer) + while (!IsSorted(array, comparer)) { - while (!IsSorted(array, comparer)) - { - Shuffle(array); - } + Shuffle(array); } + } - private bool IsSorted(T[] array, IComparer comparer) + private bool IsSorted(T[] array, IComparer comparer) + { + for (var i = 0; i < array.Length - 1; i++) { - for (var i = 0; i < array.Length - 1; i++) + if (comparer.Compare(array[i], array[i + 1]) > 0) { - if (comparer.Compare(array[i], array[i + 1]) > 0) - { - return false; - } + return false; } - - return true; } - private void Shuffle(T[] array) + return true; + } + + private void Shuffle(T[] array) + { + var taken = new bool[array.Length]; + var newArray = new T[array.Length]; + for (var i = 0; i < array.Length; i++) { - var taken = new bool[array.Length]; - var newArray = new T[array.Length]; - for (var i = 0; i < array.Length; i++) + int nextPos; + do { - int nextPos; - do - { - nextPos = random.Next(0, int.MaxValue) % array.Length; - } - while (taken[nextPos]); - - taken[nextPos] = true; - newArray[nextPos] = array[i]; + nextPos = random.Next(0, int.MaxValue) % array.Length; } + while (taken[nextPos]); - for (var i = 0; i < array.Length; i++) - { - array[i] = newArray[i]; - } + taken[nextPos] = true; + newArray[nextPos] = array[i]; + } + + for (var i = 0; i < array.Length; i++) + { + array[i] = newArray[i]; } } } diff --git a/Algorithms/Sorters/Comparison/BubbleSorter.cs b/Algorithms/Sorters/Comparison/BubbleSorter.cs index 59237bd1..0a3e707e 100644 --- a/Algorithms/Sorters/Comparison/BubbleSorter.cs +++ b/Algorithms/Sorters/Comparison/BubbleSorter.cs @@ -1,42 +1,41 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Class that implements bubble sort algorithm. +/// +/// Type of array element. +public class BubbleSorter : IComparisonSorter { /// - /// Class that implements bubble sort algorithm. + /// Sorts array using specified comparer, + /// internal, in-place, stable, + /// time complexity: O(n^2), + /// space complexity: O(1), + /// where n - array length. /// - /// Type of array element. - public class BubbleSorter : IComparisonSorter + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) { - /// - /// Sorts array using specified comparer, - /// internal, in-place, stable, - /// time complexity: O(n^2), - /// space complexity: O(1), - /// where n - array length. - /// - /// Array to sort. - /// Compares elements. - public void Sort(T[] array, IComparer comparer) + for (var i = 0; i < array.Length - 1; i++) { - for (var i = 0; i < array.Length - 1; i++) + var wasChanged = false; + for (var j = 0; j < array.Length - i - 1; j++) { - var wasChanged = false; - for (var j = 0; j < array.Length - i - 1; j++) + if (comparer.Compare(array[j], array[j + 1]) > 0) { - if (comparer.Compare(array[j], array[j + 1]) > 0) - { - var temp = array[j]; - array[j] = array[j + 1]; - array[j + 1] = temp; - wasChanged = true; - } + var temp = array[j]; + array[j] = array[j + 1]; + array[j + 1] = temp; + wasChanged = true; } + } - if (!wasChanged) - { - break; - } + if (!wasChanged) + { + break; } } } diff --git a/Algorithms/Sorters/Comparison/CocktailSorter.cs b/Algorithms/Sorters/Comparison/CocktailSorter.cs index 5a3d2186..d73576ad 100644 --- a/Algorithms/Sorters/Comparison/CocktailSorter.cs +++ b/Algorithms/Sorters/Comparison/CocktailSorter.cs @@ -1,61 +1,60 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Cocktail Sort is a variation of Bubble sort, where Cocktail +/// Sort traverses through a given array in both directions alternatively. +/// +/// Array input type. +public class CocktailSorter : IComparisonSorter { /// - /// Cocktail Sort is a variation of Bubble sort, where Cocktail - /// Sort traverses through a given array in both directions alternatively. + /// Sorts array using Cocktail sort algorithm. /// - /// Array input type. - public class CocktailSorter : IComparisonSorter + /// Input array. + /// Type of comparer for array elements. + public void Sort(T[] array, IComparer comparer) => CocktailSort(array, comparer); + + private static void CocktailSort(IList array, IComparer comparer) { - /// - /// Sorts array using Cocktail sort algorithm. - /// - /// Input array. - /// Type of comparer for array elements. - public void Sort(T[] array, IComparer comparer) => CocktailSort(array, comparer); - - private static void CocktailSort(IList array, IComparer comparer) - { - var swapped = true; + var swapped = true; - var startIndex = 0; - var endIndex = array.Count - 1; + var startIndex = 0; + var endIndex = array.Count - 1; - while (swapped) + while (swapped) + { + for (var i = startIndex; i < endIndex; i++) { - for (var i = startIndex; i < endIndex; i++) + if (comparer.Compare(array[i], array[i + 1]) != 1) { - if (comparer.Compare(array[i], array[i + 1]) != 1) - { - continue; - } - - var highValue = array[i]; - array[i] = array[i + 1]; - array[i + 1] = highValue; + continue; } - endIndex--; - swapped = false; - - for (var i = endIndex; i > startIndex; i--) - { - if (comparer.Compare(array[i], array[i - 1]) != -1) - { - continue; - } + var highValue = array[i]; + array[i] = array[i + 1]; + array[i + 1] = highValue; + } - var highValue = array[i]; - array[i] = array[i - 1]; - array[i - 1] = highValue; + endIndex--; + swapped = false; - swapped = true; + for (var i = endIndex; i > startIndex; i--) + { + if (comparer.Compare(array[i], array[i - 1]) != -1) + { + continue; } - startIndex++; + var highValue = array[i]; + array[i] = array[i - 1]; + array[i - 1] = highValue; + + swapped = true; } + + startIndex++; } } } diff --git a/Algorithms/Sorters/Comparison/CombSorter.cs b/Algorithms/Sorters/Comparison/CombSorter.cs index f3cdb810..ac6e2a19 100644 --- a/Algorithms/Sorters/Comparison/CombSorter.cs +++ b/Algorithms/Sorters/Comparison/CombSorter.cs @@ -1,50 +1,49 @@ -using System; +using System; using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Comb sort is a relatively simple sorting algorithm that improves on bubble sort. +/// +/// Type of array element. +public class CombSorter : IComparisonSorter { + public CombSorter(double shrinkFactor = 1.3) => ShrinkFactor = shrinkFactor; + + private double ShrinkFactor { get; } + /// - /// Comb sort is a relatively simple sorting algorithm that improves on bubble sort. + /// Sorts array using specified comparer, + /// internal, in-place, unstable, + /// worst case performance: O(n^2), + /// best case performance: O(n log(n)), + /// average performance: O(n^2 / 2^p), + /// space complexity: O(1), + /// where n - array length and p - number of increments. + /// See here for more info. /// - /// Type of array element. - public class CombSorter : IComparisonSorter + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) { - public CombSorter(double shrinkFactor = 1.3) => ShrinkFactor = shrinkFactor; - - private double ShrinkFactor { get; } - - /// - /// Sorts array using specified comparer, - /// internal, in-place, unstable, - /// worst case performance: O(n^2), - /// best case performance: O(n log(n)), - /// average performance: O(n^2 / 2^p), - /// space complexity: O(1), - /// where n - array length and p - number of increments. - /// See here for more info. - /// - /// Array to sort. - /// Compares elements. - public void Sort(T[] array, IComparer comparer) + var gap = array.Length; + var sorted = false; + while (!sorted) { - var gap = array.Length; - var sorted = false; - while (!sorted) + gap = (int)Math.Floor(gap / ShrinkFactor); + if (gap <= 1) { - gap = (int)Math.Floor(gap / ShrinkFactor); - if (gap <= 1) - { - gap = 1; - sorted = true; - } + gap = 1; + sorted = true; + } - for (var i = 0; i < array.Length - gap; i++) + for (var i = 0; i < array.Length - gap; i++) + { + if (comparer.Compare(array[i], array[i + gap]) > 0) { - if (comparer.Compare(array[i], array[i + gap]) > 0) - { - (array[i], array[i + gap]) = (array[i + gap], array[i]); - sorted = false; - } + (array[i], array[i + gap]) = (array[i + gap], array[i]); + sorted = false; } } } diff --git a/Algorithms/Sorters/Comparison/CycleSorter.cs b/Algorithms/Sorters/Comparison/CycleSorter.cs index 19d92927..fd81320d 100644 --- a/Algorithms/Sorters/Comparison/CycleSorter.cs +++ b/Algorithms/Sorters/Comparison/CycleSorter.cs @@ -1,79 +1,78 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Cycle sort is an in-place, unstable sorting algorithm, +/// a comparison sort that is theoretically optimal in terms of the total +/// number of writes to the original array. +/// It is based on the idea that the permutation to be sorted can be factored +/// into cycles, which can individually be rotated to give a sorted result. +/// +/// Type array input. +public class CycleSorter : IComparisonSorter { /// - /// Cycle sort is an in-place, unstable sorting algorithm, - /// a comparison sort that is theoretically optimal in terms of the total - /// number of writes to the original array. - /// It is based on the idea that the permutation to be sorted can be factored - /// into cycles, which can individually be rotated to give a sorted result. + /// Sorts input array using Cycle sort. /// - /// Type array input. - public class CycleSorter : IComparisonSorter + /// Input array. + /// Integer comparer. + public void Sort(T[] array, IComparer comparer) { - /// - /// Sorts input array using Cycle sort. - /// - /// Input array. - /// Integer comparer. - public void Sort(T[] array, IComparer comparer) + for (var i = 0; i < array.Length - 1; i++) { - for (var i = 0; i < array.Length - 1; i++) - { - MoveCycle(array, i, comparer); - } + MoveCycle(array, i, comparer); } + } - private static void MoveCycle(T[] array, int startingIndex, IComparer comparer) + private static void MoveCycle(T[] array, int startingIndex, IComparer comparer) + { + var item = array[startingIndex]; + var pos = startingIndex + CountSmallerElements(array, startingIndex + 1, item, comparer); + + if (pos == startingIndex) { - var item = array[startingIndex]; - var pos = startingIndex + CountSmallerElements(array, startingIndex + 1, item, comparer); + return; + } - if (pos == startingIndex) - { - return; - } + pos = SkipSameElements(array, pos, item, comparer); + + var temp = array[pos]; + array[pos] = item; + item = temp; + while (pos != startingIndex) + { + pos = startingIndex + CountSmallerElements(array, startingIndex + 1, item, comparer); pos = SkipSameElements(array, pos, item, comparer); - var temp = array[pos]; + temp = array[pos]; array[pos] = item; item = temp; - - while (pos != startingIndex) - { - pos = startingIndex + CountSmallerElements(array, startingIndex + 1, item, comparer); - pos = SkipSameElements(array, pos, item, comparer); - - temp = array[pos]; - array[pos] = item; - item = temp; - } } + } - private static int SkipSameElements(T[] array, int nextIndex, T item, IComparer comparer) + private static int SkipSameElements(T[] array, int nextIndex, T item, IComparer comparer) + { + while (comparer.Compare(array[nextIndex], item) == 0) { - while (comparer.Compare(array[nextIndex], item) == 0) - { - nextIndex++; - } - - return nextIndex; + nextIndex++; } - private static int CountSmallerElements(T[] array, int startingIndex, T element, IComparer comparer) + return nextIndex; + } + + private static int CountSmallerElements(T[] array, int startingIndex, T element, IComparer comparer) + { + var smallerElements = 0; + for (var i = startingIndex; i < array.Length; i++) { - var smallerElements = 0; - for (var i = startingIndex; i < array.Length; i++) + if (comparer.Compare(array[i], element) < 0) { - if (comparer.Compare(array[i], element) < 0) - { - smallerElements++; - } + smallerElements++; } - - return smallerElements; } + + return smallerElements; } } diff --git a/Algorithms/Sorters/Comparison/ExchangeSorter.cs b/Algorithms/Sorters/Comparison/ExchangeSorter.cs index 113a4ac6..c109b91c 100644 --- a/Algorithms/Sorters/Comparison/ExchangeSorter.cs +++ b/Algorithms/Sorters/Comparison/ExchangeSorter.cs @@ -1,32 +1,31 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Class that implements exchange sort algorithm. +/// +/// Type of array element. +public class ExchangeSorter : IComparisonSorter { /// - /// Class that implements exchange sort algorithm. + /// Sorts array using specified comparer, + /// internal, in-place, stable, + /// time complexity: O(n^2), + /// space complexity: O(1), + /// where n - array length. /// - /// Type of array element. - public class ExchangeSorter : IComparisonSorter + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) { - /// - /// Sorts array using specified comparer, - /// internal, in-place, stable, - /// time complexity: O(n^2), - /// space complexity: O(1), - /// where n - array length. - /// - /// Array to sort. - /// Compares elements. - public void Sort(T[] array, IComparer comparer) + for (var i = 0; i < array.Length - 1; i++) { - for (var i = 0; i < array.Length - 1; i++) + for (var j = i + 1; j < array.Length; j++) { - for (var j = i + 1; j < array.Length; j++) + if (comparer.Compare(array[i], array[j]) > 0) { - if (comparer.Compare(array[i], array[j]) > 0) - { - (array[j], array[i]) = (array[i], array[j]); - } + (array[j], array[i]) = (array[i], array[j]); } } } diff --git a/Algorithms/Sorters/Comparison/HeapSorter.cs b/Algorithms/Sorters/Comparison/HeapSorter.cs index 3631e4f7..c2dbf5b5 100644 --- a/Algorithms/Sorters/Comparison/HeapSorter.cs +++ b/Algorithms/Sorters/Comparison/HeapSorter.cs @@ -1,68 +1,67 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Heap sort is a comparison based sorting technique +/// based on Binary Heap data structure. +/// +/// Input array type. +public class HeapSorter : IComparisonSorter { /// - /// Heap sort is a comparison based sorting technique - /// based on Binary Heap data structure. + /// Sorts input array using heap sort algorithm. /// - /// Input array type. - public class HeapSorter : IComparisonSorter - { - /// - /// Sorts input array using heap sort algorithm. - /// - /// Input array. - /// Comparer type for elements. - public void Sort(T[] array, IComparer comparer) => HeapSort(array, comparer); + /// Input array. + /// Comparer type for elements. + public void Sort(T[] array, IComparer comparer) => HeapSort(array, comparer); - private static void HeapSort(IList data, IComparer comparer) + private static void HeapSort(IList data, IComparer comparer) + { + var heapSize = data.Count; + for (var p = (heapSize - 1) / 2; p >= 0; p--) { - var heapSize = data.Count; - for (var p = (heapSize - 1) / 2; p >= 0; p--) - { - MakeHeap(data, heapSize, p, comparer); - } + MakeHeap(data, heapSize, p, comparer); + } - for (var i = data.Count - 1; i > 0; i--) - { - var temp = data[i]; - data[i] = data[0]; - data[0] = temp; + for (var i = data.Count - 1; i > 0; i--) + { + var temp = data[i]; + data[i] = data[0]; + data[0] = temp; - heapSize--; - MakeHeap(data, heapSize, 0, comparer); - } + heapSize--; + MakeHeap(data, heapSize, 0, comparer); } + } + + private static void MakeHeap(IList input, int heapSize, int index, IComparer comparer) + { + var rIndex = index; - private static void MakeHeap(IList input, int heapSize, int index, IComparer comparer) + while (true) { - var rIndex = index; + var left = (rIndex + 1) * 2 - 1; + var right = (rIndex + 1) * 2; + var largest = left < heapSize && comparer.Compare(input[left], input[rIndex]) == 1 ? left : rIndex; - while (true) + // finds the index of the largest + if (right < heapSize && comparer.Compare(input[right], input[largest]) == 1) { - var left = (rIndex + 1) * 2 - 1; - var right = (rIndex + 1) * 2; - var largest = left < heapSize && comparer.Compare(input[left], input[rIndex]) == 1 ? left : rIndex; - - // finds the index of the largest - if (right < heapSize && comparer.Compare(input[right], input[largest]) == 1) - { - largest = right; - } + largest = right; + } - if (largest == rIndex) - { - return; - } + if (largest == rIndex) + { + return; + } - // process of reheaping / swapping - var temp = input[rIndex]; - input[rIndex] = input[largest]; - input[largest] = temp; + // process of reheaping / swapping + var temp = input[rIndex]; + input[rIndex] = input[largest]; + input[largest] = temp; - rIndex = largest; - } + rIndex = largest; } } } diff --git a/Algorithms/Sorters/Comparison/IComparisonSorter.cs b/Algorithms/Sorters/Comparison/IComparisonSorter.cs index da8e3383..7d6fa798 100644 --- a/Algorithms/Sorters/Comparison/IComparisonSorter.cs +++ b/Algorithms/Sorters/Comparison/IComparisonSorter.cs @@ -1,18 +1,17 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Sorts array in ascending order using comparison sort. +/// +/// Type of array item. +public interface IComparisonSorter { /// - /// Sorts array in ascending order using comparison sort. + /// Sorts array in ascending order. /// - /// Type of array item. - public interface IComparisonSorter - { - /// - /// Sorts array in ascending order. - /// - /// Array to sort. - /// Comparer to compare items of . - void Sort(T[] array, IComparer comparer); - } + /// Array to sort. + /// Comparer to compare items of . + void Sort(T[] array, IComparer comparer); } diff --git a/Algorithms/Sorters/Comparison/InsertionSorter.cs b/Algorithms/Sorters/Comparison/InsertionSorter.cs index 367b7c1a..755f422b 100644 --- a/Algorithms/Sorters/Comparison/InsertionSorter.cs +++ b/Algorithms/Sorters/Comparison/InsertionSorter.cs @@ -1,32 +1,31 @@ using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Class that implements insertion sort algorithm. +/// +/// Type of array element. +public class InsertionSorter : IComparisonSorter { /// - /// Class that implements insertion sort algorithm. + /// Sorts array using specified comparer, + /// internal, in-place, stable, + /// time complexity: O(n^2), + /// space complexity: O(1), + /// where n - array length. /// - /// Type of array element. - public class InsertionSorter : IComparisonSorter + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) { - /// - /// Sorts array using specified comparer, - /// internal, in-place, stable, - /// time complexity: O(n^2), - /// space complexity: O(1), - /// where n - array length. - /// - /// Array to sort. - /// Compares elements. - public void Sort(T[] array, IComparer comparer) + for (var i = 1; i < array.Length; i++) { - for (var i = 1; i < array.Length; i++) + for (var j = i; j > 0 && comparer.Compare(array[j], array[j - 1]) < 0; j--) { - for (var j = i; j > 0 && comparer.Compare(array[j], array[j - 1]) < 0; j--) - { - var temp = array[j - 1]; - array[j - 1] = array[j]; - array[j] = temp; - } + var temp = array[j - 1]; + array[j - 1] = array[j]; + array[j] = temp; } } } diff --git a/Algorithms/Sorters/Comparison/MedianOfThreeQuickSorter.cs b/Algorithms/Sorters/Comparison/MedianOfThreeQuickSorter.cs index 4feff2dd..abede8f5 100644 --- a/Algorithms/Sorters/Comparison/MedianOfThreeQuickSorter.cs +++ b/Algorithms/Sorters/Comparison/MedianOfThreeQuickSorter.cs @@ -1,56 +1,55 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Sorts arrays using quicksort (selecting median of three as a pivot). +/// +/// Type of array element. +public sealed class MedianOfThreeQuickSorter : QuickSorter { - /// - /// Sorts arrays using quicksort (selecting median of three as a pivot). - /// - /// Type of array element. - public sealed class MedianOfThreeQuickSorter : QuickSorter + protected override T SelectPivot(T[] array, IComparer comparer, int left, int right) { - protected override T SelectPivot(T[] array, IComparer comparer, int left, int right) - { - var leftPoint = array[left]; - var middlePoint = array[left + (right - left) / 2]; - var rightPoint = array[right]; + var leftPoint = array[left]; + var middlePoint = array[left + (right - left) / 2]; + var rightPoint = array[right]; - return FindMedian(comparer, leftPoint, middlePoint, rightPoint); - } + return FindMedian(comparer, leftPoint, middlePoint, rightPoint); + } - private static T FindMedian(IComparer comparer, T a, T b, T c) + private static T FindMedian(IComparer comparer, T a, T b, T c) + { + if (comparer.Compare(a, b) <= 0) { - if (comparer.Compare(a, b) <= 0) - { - // a <= b <= c - if (comparer.Compare(b, c) <= 0) - { - return b; - } - - // a <= c < b - if (comparer.Compare(a, c) <= 0) - { - return c; - } - - // c < a <= b - return a; - } - - // a > b >= c - if (comparer.Compare(b, c) >= 0) + // a <= b <= c + if (comparer.Compare(b, c) <= 0) { return b; } - // a >= c > b - if (comparer.Compare(a, c) >= 0) + // a <= c < b + if (comparer.Compare(a, c) <= 0) { return c; } - // c > a > b + // c < a <= b return a; } + + // a > b >= c + if (comparer.Compare(b, c) >= 0) + { + return b; + } + + // a >= c > b + if (comparer.Compare(a, c) >= 0) + { + return c; + } + + // c > a > b + return a; } } diff --git a/Algorithms/Sorters/Comparison/MergeSorter.cs b/Algorithms/Sorters/Comparison/MergeSorter.cs index 20957118..b86af4b6 100644 --- a/Algorithms/Sorters/Comparison/MergeSorter.cs +++ b/Algorithms/Sorters/Comparison/MergeSorter.cs @@ -1,66 +1,65 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Divide and Conquer algorithm, which splits +/// array in two halves, calls itself for the two +/// halves and then merges the two sorted halves. +/// +/// Type of array elements. +public class MergeSorter : IComparisonSorter { /// - /// Divide and Conquer algorithm, which splits - /// array in two halves, calls itself for the two - /// halves and then merges the two sorted halves. + /// Sorts array using merge sort algorithm, + /// originally designed as external sorting algorithm, + /// internal, stable, + /// time complexity: O(n log(n)), + /// space complexity: O(n), + /// where n - array length. /// - /// Type of array elements. - public class MergeSorter : IComparisonSorter + /// Array to sort. + /// Comparer to compare elements of . + public void Sort(T[] array, IComparer comparer) { - /// - /// Sorts array using merge sort algorithm, - /// originally designed as external sorting algorithm, - /// internal, stable, - /// time complexity: O(n log(n)), - /// space complexity: O(n), - /// where n - array length. - /// - /// Array to sort. - /// Comparer to compare elements of . - public void Sort(T[] array, IComparer comparer) + if (array.Length <= 1) { - if (array.Length <= 1) - { - return; - } - - var (left, right) = Split(array); - Sort(left, comparer); - Sort(right, comparer); - Merge(array, left, right, comparer); + return; } - private static void Merge(T[] array, T[] left, T[] right, IComparer comparer) - { - var mainIndex = 0; - var leftIndex = 0; - var rightIndex = 0; + var (left, right) = Split(array); + Sort(left, comparer); + Sort(right, comparer); + Merge(array, left, right, comparer); + } - while (leftIndex < left.Length && rightIndex < right.Length) - { - var compResult = comparer.Compare(left[leftIndex], right[rightIndex]); - array[mainIndex++] = compResult <= 0 ? left[leftIndex++] : right[rightIndex++]; - } + private static void Merge(T[] array, T[] left, T[] right, IComparer comparer) + { + var mainIndex = 0; + var leftIndex = 0; + var rightIndex = 0; - while (leftIndex < left.Length) - { - array[mainIndex++] = left[leftIndex++]; - } + while (leftIndex < left.Length && rightIndex < right.Length) + { + var compResult = comparer.Compare(left[leftIndex], right[rightIndex]); + array[mainIndex++] = compResult <= 0 ? left[leftIndex++] : right[rightIndex++]; + } - while (rightIndex < right.Length) - { - array[mainIndex++] = right[rightIndex++]; - } + while (leftIndex < left.Length) + { + array[mainIndex++] = left[leftIndex++]; } - private static (T[] left, T[] right) Split(T[] array) + while (rightIndex < right.Length) { - var mid = array.Length / 2; - return (array.Take(mid).ToArray(), array.Skip(mid).ToArray()); + array[mainIndex++] = right[rightIndex++]; } } + + private static (T[] left, T[] right) Split(T[] array) + { + var mid = array.Length / 2; + return (array.Take(mid).ToArray(), array.Skip(mid).ToArray()); + } } diff --git a/Algorithms/Sorters/Comparison/MiddlePointQuickSorter.cs b/Algorithms/Sorters/Comparison/MiddlePointQuickSorter.cs index 2da9c892..25806e4a 100644 --- a/Algorithms/Sorters/Comparison/MiddlePointQuickSorter.cs +++ b/Algorithms/Sorters/Comparison/MiddlePointQuickSorter.cs @@ -1,14 +1,13 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Sorts arrays using quicksort (selecting middle point as a pivot). +/// +/// Type of array element. +public sealed class MiddlePointQuickSorter : QuickSorter { - /// - /// Sorts arrays using quicksort (selecting middle point as a pivot). - /// - /// Type of array element. - public sealed class MiddlePointQuickSorter : QuickSorter - { - protected override T SelectPivot(T[] array, IComparer comparer, int left, int right) => - array[left + (right - left) / 2]; - } + protected override T SelectPivot(T[] array, IComparer comparer, int left, int right) => + array[left + (right - left) / 2]; } diff --git a/Algorithms/Sorters/Comparison/PancakeSorter.cs b/Algorithms/Sorters/Comparison/PancakeSorter.cs index b7e972c7..478ae926 100644 --- a/Algorithms/Sorters/Comparison/PancakeSorter.cs +++ b/Algorithms/Sorters/Comparison/PancakeSorter.cs @@ -1,78 +1,77 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Class that implements pancake sort algorithm. +/// +/// Type of array element. +public class PancakeSorter : IComparisonSorter { /// - /// Class that implements pancake sort algorithm. + /// Sorts array using specified comparer, + /// internal, in-place, stable, + /// time complexity: O(n^2), + /// space complexity: O(1), + /// where n - array length. /// - /// Type of array element. - public class PancakeSorter : IComparisonSorter + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) { - /// - /// Sorts array using specified comparer, - /// internal, in-place, stable, - /// time complexity: O(n^2), - /// space complexity: O(1), - /// where n - array length. - /// - /// Array to sort. - /// Compares elements. - public void Sort(T[] array, IComparer comparer) + var n = array.Length; + + // Start from the complete array and one by one + // reduce current size by one + for (var currSize = n; currSize > 1; --currSize) { - var n = array.Length; + // Find index of the maximum element in + // array[0..curr_size-1] + var mi = FindMax(array, currSize, comparer); - // Start from the complete array and one by one - // reduce current size by one - for (var currSize = n; currSize > 1; --currSize) + // Move the maximum element to end of current array + // if it's not already at the end + if (mi != currSize - 1) { - // Find index of the maximum element in - // array[0..curr_size-1] - var mi = FindMax(array, currSize, comparer); - - // Move the maximum element to end of current array - // if it's not already at the end - if (mi != currSize - 1) - { - // To move to the end, first move maximum - // number to beginning - Flip(array, mi); + // To move to the end, first move maximum + // number to beginning + Flip(array, mi); - // Now move the maximum number to end by - // reversing current array - Flip(array, currSize - 1); - } + // Now move the maximum number to end by + // reversing current array + Flip(array, currSize - 1); } } + } - // Reverses array[0..i] - private void Flip(T[] array, int i) + // Reverses array[0..i] + private void Flip(T[] array, int i) + { + T temp; + var start = 0; + while (start < i) { - T temp; - var start = 0; - while (start < i) - { - temp = array[start]; - array[start] = array[i]; - array[i] = temp; - start++; - i--; - } + temp = array[start]; + array[start] = array[i]; + array[i] = temp; + start++; + i--; } + } - // Returns index of the maximum element - // in array[0..n-1] - private int FindMax(T[] array, int n, IComparer comparer) + // Returns index of the maximum element + // in array[0..n-1] + private int FindMax(T[] array, int n, IComparer comparer) + { + var mi = 0; + for (var i = 0; i < n; i++) { - var mi = 0; - for (var i = 0; i < n; i++) + if (comparer.Compare(array[i], array[mi]) == 1) { - if (comparer.Compare(array[i], array[mi]) == 1) - { - mi = i; - } + mi = i; } - - return mi; } + + return mi; } } diff --git a/Algorithms/Sorters/Comparison/QuickSorter.cs b/Algorithms/Sorters/Comparison/QuickSorter.cs index 3b0f74cc..e4615577 100644 --- a/Algorithms/Sorters/Comparison/QuickSorter.cs +++ b/Algorithms/Sorters/Comparison/QuickSorter.cs @@ -1,68 +1,67 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Sorts arrays using quicksort. +/// +/// Type of array element. +public abstract class QuickSorter : IComparisonSorter { /// - /// Sorts arrays using quicksort. + /// Sorts array using Hoare partition scheme, + /// internal, in-place, + /// time complexity average: O(n log(n)), + /// time complexity worst: O(n^2), + /// space complexity: O(log(n)), + /// where n - array length. /// - /// Type of array element. - public abstract class QuickSorter : IComparisonSorter - { - /// - /// Sorts array using Hoare partition scheme, - /// internal, in-place, - /// time complexity average: O(n log(n)), - /// time complexity worst: O(n^2), - /// space complexity: O(log(n)), - /// where n - array length. - /// - /// Array to sort. - /// Compares elements. - public void Sort(T[] array, IComparer comparer) => Sort(array, comparer, 0, array.Length - 1); + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) => Sort(array, comparer, 0, array.Length - 1); - protected abstract T SelectPivot(T[] array, IComparer comparer, int left, int right); + protected abstract T SelectPivot(T[] array, IComparer comparer, int left, int right); - private void Sort(T[] array, IComparer comparer, int left, int right) + private void Sort(T[] array, IComparer comparer, int left, int right) + { + if (left >= right) { - if (left >= right) - { - return; - } - - var p = Partition(array, comparer, left, right); - Sort(array, comparer, left, p); - Sort(array, comparer, p + 1, right); + return; } - private int Partition(T[] array, IComparer comparer, int left, int right) + var p = Partition(array, comparer, left, right); + Sort(array, comparer, left, p); + Sort(array, comparer, p + 1, right); + } + + private int Partition(T[] array, IComparer comparer, int left, int right) + { + var pivot = SelectPivot(array, comparer, left, right); + var nleft = left; + var nright = right; + while (true) { - var pivot = SelectPivot(array, comparer, left, right); - var nleft = left; - var nright = right; - while (true) + while (comparer.Compare(array[nleft], pivot) < 0) { - while (comparer.Compare(array[nleft], pivot) < 0) - { - nleft++; - } + nleft++; + } - while (comparer.Compare(array[nright], pivot) > 0) - { - nright--; - } + while (comparer.Compare(array[nright], pivot) > 0) + { + nright--; + } - if (nleft >= nright) - { - return nright; - } + if (nleft >= nright) + { + return nright; + } - var t = array[nleft]; - array[nleft] = array[nright]; - array[nright] = t; + var t = array[nleft]; + array[nleft] = array[nright]; + array[nright] = t; - nleft++; - nright--; - } + nleft++; + nright--; } } } diff --git a/Algorithms/Sorters/Comparison/RandomPivotQuickSorter.cs b/Algorithms/Sorters/Comparison/RandomPivotQuickSorter.cs index e26a183f..a9515ed4 100644 --- a/Algorithms/Sorters/Comparison/RandomPivotQuickSorter.cs +++ b/Algorithms/Sorters/Comparison/RandomPivotQuickSorter.cs @@ -1,17 +1,16 @@ -using System; +using System; using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Sorts arrays using quicksort (selecting random point as a pivot). +/// +/// Type of array element. +public sealed class RandomPivotQuickSorter : QuickSorter { - /// - /// Sorts arrays using quicksort (selecting random point as a pivot). - /// - /// Type of array element. - public sealed class RandomPivotQuickSorter : QuickSorter - { - private readonly Random random = new(); + private readonly Random random = new(); - protected override T SelectPivot(T[] array, IComparer comparer, int left, int right) => - array[random.Next(left, right + 1)]; - } + protected override T SelectPivot(T[] array, IComparer comparer, int left, int right) => + array[random.Next(left, right + 1)]; } diff --git a/Algorithms/Sorters/Comparison/SelectionSorter.cs b/Algorithms/Sorters/Comparison/SelectionSorter.cs index 99f01961..167bf454 100644 --- a/Algorithms/Sorters/Comparison/SelectionSorter.cs +++ b/Algorithms/Sorters/Comparison/SelectionSorter.cs @@ -1,39 +1,38 @@ using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Class that implements selection sort algorithm. +/// +/// Type of array element. +public class SelectionSorter : IComparisonSorter { /// - /// Class that implements selection sort algorithm. + /// Sorts array using specified comparer, + /// internal, in-place, stable, + /// time complexity: O(n^2), + /// space complexity: O(1), + /// where n - array length. /// - /// Type of array element. - public class SelectionSorter : IComparisonSorter + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) { - /// - /// Sorts array using specified comparer, - /// internal, in-place, stable, - /// time complexity: O(n^2), - /// space complexity: O(1), - /// where n - array length. - /// - /// Array to sort. - /// Compares elements. - public void Sort(T[] array, IComparer comparer) + for (var i = 0; i < array.Length - 1; i++) { - for (var i = 0; i < array.Length - 1; i++) + var jmin = i; + for (var j = i + 1; j < array.Length; j++) { - var jmin = i; - for (var j = i + 1; j < array.Length; j++) + if (comparer.Compare(array[jmin], array[j]) > 0) { - if (comparer.Compare(array[jmin], array[j]) > 0) - { - jmin = j; - } + jmin = j; } - - var t = array[i]; - array[i] = array[jmin]; - array[jmin] = t; } + + var t = array[i]; + array[i] = array[jmin]; + array[jmin] = t; } } } diff --git a/Algorithms/Sorters/Comparison/ShellSorter.cs b/Algorithms/Sorters/Comparison/ShellSorter.cs index 42b4bbf0..f00c1155 100644 --- a/Algorithms/Sorters/Comparison/ShellSorter.cs +++ b/Algorithms/Sorters/Comparison/ShellSorter.cs @@ -1,54 +1,53 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// TODO. +/// +/// TODO. 2. +public class ShellSorter : IComparisonSorter { /// - /// TODO. + /// Sorts array using specified comparer, + /// based on bubble sort, + /// internal, in-place, unstable, + /// worst-case time complexity: O(n^2), + /// space complexity: O(1), + /// where n - array length. /// - /// TODO. 2. - public class ShellSorter : IComparisonSorter + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) { - /// - /// Sorts array using specified comparer, - /// based on bubble sort, - /// internal, in-place, unstable, - /// worst-case time complexity: O(n^2), - /// space complexity: O(1), - /// where n - array length. - /// - /// Array to sort. - /// Compares elements. - public void Sort(T[] array, IComparer comparer) + for (var step = array.Length / 2; step > 0; step /= 2) { - for (var step = array.Length / 2; step > 0; step /= 2) + for (var i = 0; i < step; i++) { - for (var i = 0; i < step; i++) - { - GappedBubbleSort(array, comparer, i, step); - } + GappedBubbleSort(array, comparer, i, step); } } + } - private static void GappedBubbleSort(T[] array, IComparer comparer, int start, int step) + private static void GappedBubbleSort(T[] array, IComparer comparer, int start, int step) + { + for (var j = start; j < array.Length - step; j += step) { - for (var j = start; j < array.Length - step; j += step) + var wasChanged = false; + for (var k = start; k < array.Length - j - step; k += step) { - var wasChanged = false; - for (var k = start; k < array.Length - j - step; k += step) + if (comparer.Compare(array[k], array[k + step]) > 0) { - if (comparer.Compare(array[k], array[k + step]) > 0) - { - var temp = array[k]; - array[k] = array[k + step]; - array[k + step] = temp; - wasChanged = true; - } + var temp = array[k]; + array[k] = array[k + step]; + array[k + step] = temp; + wasChanged = true; } + } - if (!wasChanged) - { - break; - } + if (!wasChanged) + { + break; } } } diff --git a/Algorithms/Sorters/Comparison/TimSorter.cs b/Algorithms/Sorters/Comparison/TimSorter.cs index b57a49f5..df2220ac 100755 --- a/Algorithms/Sorters/Comparison/TimSorter.cs +++ b/Algorithms/Sorters/Comparison/TimSorter.cs @@ -1,634 +1,633 @@ using System; using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// Timsort is a hybrid stable sorting algorithm, derived from merge sort and insertion sort, designed to perform well on many kinds of real-world data. +/// It was originally implemented by Tim Peters in 2002 for use in the Python programming language. +/// +/// This class is based on a Java interpretation of Tim Peter's original work. +/// Java class is viewable here: +/// http://cr.openjdk.java.net/~martin/webrevs/openjdk7/timsort/raw_files/new/src/share/classes/java/util/TimSort.java +/// +/// Tim Peters's list sort for Python, is described in detail here: +/// http://svn.python.org/projects/python/trunk/Objects/listsort.txt +/// +/// Tim's C code may be found here: http://svn.python.org/projects/python/trunk/Objects/listobject.c +/// +/// The underlying techniques are described in this paper (and may have even earlier origins): +/// "Optimistic Sorting and Information Theoretic Complexity" +/// Peter McIlroy +/// SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), +/// pp 467-474, Austin, Texas, 25-27 January 1993. +/// +/// Type of array element. +public class TimSorter : IComparisonSorter { - /// - /// Timsort is a hybrid stable sorting algorithm, derived from merge sort and insertion sort, designed to perform well on many kinds of real-world data. - /// It was originally implemented by Tim Peters in 2002 for use in the Python programming language. - /// - /// This class is based on a Java interpretation of Tim Peter's original work. - /// Java class is viewable here: - /// http://cr.openjdk.java.net/~martin/webrevs/openjdk7/timsort/raw_files/new/src/share/classes/java/util/TimSort.java - /// - /// Tim Peters's list sort for Python, is described in detail here: - /// http://svn.python.org/projects/python/trunk/Objects/listsort.txt - /// - /// Tim's C code may be found here: http://svn.python.org/projects/python/trunk/Objects/listobject.c - /// - /// The underlying techniques are described in this paper (and may have even earlier origins): - /// "Optimistic Sorting and Information Theoretic Complexity" - /// Peter McIlroy - /// SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), - /// pp 467-474, Austin, Texas, 25-27 January 1993. - /// - /// Type of array element. - public class TimSorter : IComparisonSorter - { - private readonly int minMerge; - private readonly int initMinGallop; - private readonly int[] runBase; - private readonly int[] runLengths; + private readonly int minMerge; + private readonly int initMinGallop; + private readonly int[] runBase; + private readonly int[] runLengths; - private int minGallop; - private int stackSize; - - private IComparer comparer = default!; - - /// - /// Private class for handling gallop merges, allows for tracking array indexes and wins. - /// - /// Type of array element. - private class TimChunk - { - public Tc[] Array { get; set; } = default!; + private int minGallop; + private int stackSize; + + private IComparer comparer = default!; + + /// + /// Private class for handling gallop merges, allows for tracking array indexes and wins. + /// + /// Type of array element. + private class TimChunk + { + public Tc[] Array { get; set; } = default!; - public int Index { get; set; } + public int Index { get; set; } - public int Remaining { get; set; } + public int Remaining { get; set; } - public int Wins { get; set; } - } + public int Wins { get; set; } + } - public TimSorter(int minMerge = 32, int minGallop = 7) - { - initMinGallop = minGallop; - this.minMerge = minMerge; - runBase = new int[85]; - runLengths = new int[85]; + public TimSorter(int minMerge = 32, int minGallop = 7) + { + initMinGallop = minGallop; + this.minMerge = minMerge; + runBase = new int[85]; + runLengths = new int[85]; - stackSize = 0; - this.minGallop = minGallop; - } + stackSize = 0; + this.minGallop = minGallop; + } - /// - /// Sorts array using specified comparer - /// worst case performance: O(n log(n)), - /// best case performance: O(n), - /// See here for more info. - /// - /// Array to sort. - /// Compares elements. - public void Sort(T[] array, IComparer comparer) - { - this.comparer = comparer; - var start = 0; - var remaining = array.Length; + /// + /// Sorts array using specified comparer + /// worst case performance: O(n log(n)), + /// best case performance: O(n), + /// See here for more info. + /// + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) + { + this.comparer = comparer; + var start = 0; + var remaining = array.Length; - if (remaining < minMerge) + if (remaining < minMerge) + { + if (remaining < 2) { - if (remaining < 2) - { - // Arrays of size 0 or 1 are always sorted. - return; - } - - // Don't need to merge, just binary sort - BinarySort(array, start, remaining, start); + // Arrays of size 0 or 1 are always sorted. return; } - var minRun = MinRunLength(remaining, minMerge); + // Don't need to merge, just binary sort + BinarySort(array, start, remaining, start); + return; + } - do - { - // Identify next run - var runLen = CountRunAndMakeAscending(array, start); + var minRun = MinRunLength(remaining, minMerge); - // If the run is too short extend to Min(MIN_RUN, remaining) - if (runLen < minRun) - { - var force = Math.Min(minRun, remaining); - BinarySort(array, start, start + force, start + runLen); - runLen = force; - } + do + { + // Identify next run + var runLen = CountRunAndMakeAscending(array, start); - runBase[stackSize] = start; - runLengths[stackSize] = runLen; - stackSize++; + // If the run is too short extend to Min(MIN_RUN, remaining) + if (runLen < minRun) + { + var force = Math.Min(minRun, remaining); + BinarySort(array, start, start + force, start + runLen); + runLen = force; + } - MergeCollapse(array); + runBase[stackSize] = start; + runLengths[stackSize] = runLen; + stackSize++; - start += runLen; - remaining -= runLen; - } - while (remaining != 0); + MergeCollapse(array); - MergeForceCollapse(array); + start += runLen; + remaining -= runLen; } + while (remaining != 0); - /// - /// Returns the minimum acceptable run length for an array of the specified - /// length.Natural runs shorter than this will be extended. - /// - /// Computation is: - /// If total less than minRun, return n (it's too small to bother with fancy stuff). - /// Else if total is an exact power of 2, return minRun/2. - /// Else return an int k, where , such that total/k - /// is close to, but strictly less than, an exact power of 2. - /// - /// Total length remaining to sort. - /// Minimum run length to be merged. - private static int MinRunLength(int total, int minRun) - { - var r = 0; - while (total >= minRun) - { - r |= total & 1; - total >>= 1; - } + MergeForceCollapse(array); + } - return total + r; + /// + /// Returns the minimum acceptable run length for an array of the specified + /// length.Natural runs shorter than this will be extended. + /// + /// Computation is: + /// If total less than minRun, return n (it's too small to bother with fancy stuff). + /// Else if total is an exact power of 2, return minRun/2. + /// Else return an int k, where , such that total/k + /// is close to, but strictly less than, an exact power of 2. + /// + /// Total length remaining to sort. + /// Minimum run length to be merged. + private static int MinRunLength(int total, int minRun) + { + var r = 0; + while (total >= minRun) + { + r |= total & 1; + total >>= 1; } - /// - /// Reverse the specified range of the specified array. - /// - /// the array in which a range is to be reversed. - /// the index of the first element in the range to be reversed. - /// the index after the last element in the range to be reversed. - private static void ReverseRange(T[] array, int start, int end) + return total + r; + } + + /// + /// Reverse the specified range of the specified array. + /// + /// the array in which a range is to be reversed. + /// the index of the first element in the range to be reversed. + /// the index after the last element in the range to be reversed. + private static void ReverseRange(T[] array, int start, int end) + { + end--; + while (start < end) { - end--; - while (start < end) - { - var t = array[start]; - array[start++] = array[end]; - array[end--] = t; - } - } + var t = array[start]; + array[start++] = array[end]; + array[end--] = t; + } + } - /// - /// Left shift a value, preventing a roll over to negative numbers. - /// - /// int value to left shift. - /// Left shifted value, bound to 2,147,483,647. - private static int BoundLeftShift(int shiftable) => (shiftable << 1) < 0 - ? (shiftable << 1) + 1 - : int.MaxValue; - - /// - /// Check the chunks before getting in to a merge to make sure there's something to actually do. - /// - /// TimChunk of the left hand side. - /// TimChunk of the right hand side. - /// The current target point for the remaining values. - /// If a merge is required. - private static bool NeedsMerge(TimChunk left, TimChunk right, ref int dest) - { - right.Array[dest++] = right.Array[right.Index++]; - if (--right.Remaining == 0) - { - Array.Copy(left.Array, left.Index, right.Array, dest, left.Remaining); - return false; - } - - if (left.Remaining == 1) - { - Array.Copy(right.Array, right.Index, right.Array, dest, right.Remaining); - right.Array[dest + right.Remaining] = left.Array[left.Index]; - return false; - } + /// + /// Left shift a value, preventing a roll over to negative numbers. + /// + /// int value to left shift. + /// Left shifted value, bound to 2,147,483,647. + private static int BoundLeftShift(int shiftable) => (shiftable << 1) < 0 + ? (shiftable << 1) + 1 + : int.MaxValue; - return true; + /// + /// Check the chunks before getting in to a merge to make sure there's something to actually do. + /// + /// TimChunk of the left hand side. + /// TimChunk of the right hand side. + /// The current target point for the remaining values. + /// If a merge is required. + private static bool NeedsMerge(TimChunk left, TimChunk right, ref int dest) + { + right.Array[dest++] = right.Array[right.Index++]; + if (--right.Remaining == 0) + { + Array.Copy(left.Array, left.Index, right.Array, dest, left.Remaining); + return false; + } + + if (left.Remaining == 1) + { + Array.Copy(right.Array, right.Index, right.Array, dest, right.Remaining); + right.Array[dest + right.Remaining] = left.Array[left.Index]; + return false; } - /// - /// Moves over the last parts of the chunks. - /// - /// TimChunk of the left hand side. - /// TimChunk of the right hand side. - /// The current target point for the remaining values. - private static void FinalizeMerge(TimChunk left, TimChunk right, int dest) - { - if (left.Remaining == 1) - { - Array.Copy(right.Array, right.Index, right.Array, dest, right.Remaining); - right.Array[dest + right.Remaining] = left.Array[left.Index]; - } - else if (left.Remaining == 0) - { - throw new ArgumentException("Comparison method violates its general contract!"); - } - else - { - Array.Copy(left.Array, left.Index, right.Array, dest, left.Remaining); - } + return true; + } + + /// + /// Moves over the last parts of the chunks. + /// + /// TimChunk of the left hand side. + /// TimChunk of the right hand side. + /// The current target point for the remaining values. + private static void FinalizeMerge(TimChunk left, TimChunk right, int dest) + { + if (left.Remaining == 1) + { + Array.Copy(right.Array, right.Index, right.Array, dest, right.Remaining); + right.Array[dest + right.Remaining] = left.Array[left.Index]; + } + else if (left.Remaining == 0) + { + throw new ArgumentException("Comparison method violates its general contract!"); + } + else + { + Array.Copy(left.Array, left.Index, right.Array, dest, left.Remaining); } + } - /// - /// Returns the length of the run beginning at the specified position in - /// the specified array and reverses the run if it is descending (ensuring - /// that the run will always be ascending when the method returns). - /// - /// A run is the longest ascending sequence with: - /// - /// - /// - /// or the longest descending sequence with: - /// - /// a[lo + 1] > a[lo + 2] > ...]]> - /// - /// For its intended use in a stable mergesort, the strictness of the - /// definition of "descending" is needed so that the call can safely - /// reverse a descending sequence without violating stability. - /// - /// the array in which a run is to be counted and possibly reversed. - /// index of the first element in the run. - /// the length of the run beginning at the specified position in the specified array. - private int CountRunAndMakeAscending(T[] array, int start) + /// + /// Returns the length of the run beginning at the specified position in + /// the specified array and reverses the run if it is descending (ensuring + /// that the run will always be ascending when the method returns). + /// + /// A run is the longest ascending sequence with: + /// + /// + /// + /// or the longest descending sequence with: + /// + /// a[lo + 1] > a[lo + 2] > ...]]> + /// + /// For its intended use in a stable mergesort, the strictness of the + /// definition of "descending" is needed so that the call can safely + /// reverse a descending sequence without violating stability. + /// + /// the array in which a run is to be counted and possibly reversed. + /// index of the first element in the run. + /// the length of the run beginning at the specified position in the specified array. + private int CountRunAndMakeAscending(T[] array, int start) + { + var runHi = start + 1; + if (runHi == array.Length) { - var runHi = start + 1; - if (runHi == array.Length) - { - return 1; - } + return 1; + } - // Find end of run, and reverse range if descending - if (comparer.Compare(array[runHi++], array[start]) < 0) - { // Descending - while (runHi < array.Length && comparer.Compare(array[runHi], array[runHi - 1]) < 0) - { - runHi++; - } - - ReverseRange(array, start, runHi); + // Find end of run, and reverse range if descending + if (comparer.Compare(array[runHi++], array[start]) < 0) + { // Descending + while (runHi < array.Length && comparer.Compare(array[runHi], array[runHi - 1]) < 0) + { + runHi++; } - else - { // Ascending - while (runHi < array.Length && comparer.Compare(array[runHi], array[runHi - 1]) >= 0) - { - runHi++; - } - } - return runHi - start; + ReverseRange(array, start, runHi); } + else + { // Ascending + while (runHi < array.Length && comparer.Compare(array[runHi], array[runHi - 1]) >= 0) + { + runHi++; + } + } + + return runHi - start; + } - /// - /// Find the position in the array that a key should fit to the left of where it currently sits. - /// - /// Array to search. - /// Key to place in the array. - /// Base index for the key. - /// Length of the chunk to run through. - /// Initial starting position to start from. - /// Offset for the key's location. - private int GallopLeft(T[] array, T key, int i, int len, int hint) - { - var (offset, lastOfs) = comparer.Compare(key, array[i + hint]) > 0 - ? RightRun(array, key, i, len, hint, 0) - : LeftRun(array, key, i, hint, 1); + /// + /// Find the position in the array that a key should fit to the left of where it currently sits. + /// + /// Array to search. + /// Key to place in the array. + /// Base index for the key. + /// Length of the chunk to run through. + /// Initial starting position to start from. + /// Offset for the key's location. + private int GallopLeft(T[] array, T key, int i, int len, int hint) + { + var (offset, lastOfs) = comparer.Compare(key, array[i + hint]) > 0 + ? RightRun(array, key, i, len, hint, 0) + : LeftRun(array, key, i, hint, 1); - return FinalOffset(array, key, i, offset, lastOfs, 1); - } + return FinalOffset(array, key, i, offset, lastOfs, 1); + } - /// - /// Find the position in the array that a key should fit to the right of where it currently sits. - /// - /// Array to search. - /// Key to place in the array. - /// Base index for the key. - /// Length of the chunk to run through. - /// Initial starting position to start from. - /// Offset for the key's location. - private int GallopRight(T[] array, T key, int i, int len, int hint) - { - var (offset, lastOfs) = comparer.Compare(key, array[i + hint]) < 0 - ? LeftRun(array, key, i, hint, 0) - : RightRun(array, key, i, len, hint, -1); + /// + /// Find the position in the array that a key should fit to the right of where it currently sits. + /// + /// Array to search. + /// Key to place in the array. + /// Base index for the key. + /// Length of the chunk to run through. + /// Initial starting position to start from. + /// Offset for the key's location. + private int GallopRight(T[] array, T key, int i, int len, int hint) + { + var (offset, lastOfs) = comparer.Compare(key, array[i + hint]) < 0 + ? LeftRun(array, key, i, hint, 0) + : RightRun(array, key, i, len, hint, -1); + + return FinalOffset(array, key, i, offset, lastOfs, 0); + } + + private (int offset, int lastOfs) LeftRun(T[] array, T key, int i, int hint, int lt) + { + var maxOfs = hint + 1; + var (offset, tmp) = (1, 0); - return FinalOffset(array, key, i, offset, lastOfs, 0); + while (offset < maxOfs && comparer.Compare(key, array[i + hint - offset]) < lt) + { + tmp = offset; + offset = BoundLeftShift(offset); } - private (int offset, int lastOfs) LeftRun(T[] array, T key, int i, int hint, int lt) + if (offset > maxOfs) { - var maxOfs = hint + 1; - var (offset, tmp) = (1, 0); + offset = maxOfs; + } - while (offset < maxOfs && comparer.Compare(key, array[i + hint - offset]) < lt) - { - tmp = offset; - offset = BoundLeftShift(offset); - } + var lastOfs = hint - offset; + offset = hint - tmp; - if (offset > maxOfs) - { - offset = maxOfs; - } + return (offset, lastOfs); + } - var lastOfs = hint - offset; - offset = hint - tmp; + private (int offset, int lastOfs) RightRun(T[] array, T key, int i, int len, int hint, int gt) + { + var (offset, lastOfs) = (1, 0); + var maxOfs = len - hint; + while (offset < maxOfs && comparer.Compare(key, array[i + hint + offset]) > gt) + { + lastOfs = offset; + offset = BoundLeftShift(offset); + } - return (offset, lastOfs); + if (offset > maxOfs) + { + offset = maxOfs; } - private (int offset, int lastOfs) RightRun(T[] array, T key, int i, int len, int hint, int gt) + offset += hint; + lastOfs += hint; + + return (offset, lastOfs); + } + + private int FinalOffset(T[] array, T key, int i, int offset, int lastOfs, int lt) + { + lastOfs++; + while (lastOfs < offset) { - var (offset, lastOfs) = (1, 0); - var maxOfs = len - hint; - while (offset < maxOfs && comparer.Compare(key, array[i + hint + offset]) > gt) + var m = lastOfs + (int)((uint)(offset - lastOfs) >> 1); + + if (comparer.Compare(key, array[i + m]) < lt) { - lastOfs = offset; - offset = BoundLeftShift(offset); + offset = m; } - - if (offset > maxOfs) + else { - offset = maxOfs; + lastOfs = m + 1; } + } - offset += hint; - lastOfs += hint; + return offset; + } - return (offset, lastOfs); + /// + /// Sorts the specified portion of the specified array using a binary + /// insertion sort. It requires O(n log n) compares, but O(n^2) data movement. + /// + /// Array to sort. + /// The index of the first element in the range to be sorted. + /// The index after the last element in the range to be sorted. + /// The index of the first element in the range that is not already known to be sorted, must be between start and end. + private void BinarySort(T[] array, int start, int end, int first) + { + if (first >= end || first <= start) + { + first = start + 1; } - private int FinalOffset(T[] array, T key, int i, int offset, int lastOfs, int lt) + for (; first < end; first++) { - lastOfs++; - while (lastOfs < offset) - { - var m = lastOfs + (int)((uint)(offset - lastOfs) >> 1); + var target = array[first]; + var targetInsertLocation = BinarySearch(array, start, first - 1, target); + Array.Copy(array, targetInsertLocation, array, targetInsertLocation + 1, first - targetInsertLocation); - if (comparer.Compare(key, array[i + m]) < lt) - { - offset = m; - } - else - { - lastOfs = m + 1; - } - } - - return offset; + array[targetInsertLocation] = target; } + } - /// - /// Sorts the specified portion of the specified array using a binary - /// insertion sort. It requires O(n log n) compares, but O(n^2) data movement. - /// - /// Array to sort. - /// The index of the first element in the range to be sorted. - /// The index after the last element in the range to be sorted. - /// The index of the first element in the range that is not already known to be sorted, must be between start and end. - private void BinarySort(T[] array, int start, int end, int first) + private int BinarySearch(T[] array, int left, int right, T target) + { + while (left < right) { - if (first >= end || first <= start) + var mid = (left + right) >> 1; + if (comparer.Compare(target, array[mid]) < 0) { - first = start + 1; + right = mid; } - - for (; first < end; first++) + else { - var target = array[first]; - var targetInsertLocation = BinarySearch(array, start, first - 1, target); - Array.Copy(array, targetInsertLocation, array, targetInsertLocation + 1, first - targetInsertLocation); - - array[targetInsertLocation] = target; + left = mid + 1; } } - private int BinarySearch(T[] array, int left, int right, T target) + return comparer.Compare(target, array[left]) < 0 + ? left + : left + 1; + } + + private void MergeCollapse(T[] array) + { + while (stackSize > 1) { - while (left < right) + var n = stackSize - 2; + if (n > 0 && runLengths[n - 1] <= runLengths[n] + runLengths[n + 1]) { - var mid = (left + right) >> 1; - if (comparer.Compare(target, array[mid]) < 0) - { - right = mid; - } - else + if (runLengths[n - 1] < runLengths[n + 1]) { - left = mid + 1; + n--; } - } - - return comparer.Compare(target, array[left]) < 0 - ? left - : left + 1; - } - private void MergeCollapse(T[] array) - { - while (stackSize > 1) + MergeAt(array, n); + } + else if (runLengths[n] <= runLengths[n + 1]) { - var n = stackSize - 2; - if (n > 0 && runLengths[n - 1] <= runLengths[n] + runLengths[n + 1]) - { - if (runLengths[n - 1] < runLengths[n + 1]) - { - n--; - } - - MergeAt(array, n); - } - else if (runLengths[n] <= runLengths[n + 1]) - { - MergeAt(array, n); - } - else - { - break; - } + MergeAt(array, n); + } + else + { + break; } } + } - private void MergeForceCollapse(T[] array) + private void MergeForceCollapse(T[] array) + { + while (stackSize > 1) { - while (stackSize > 1) - { - var n = stackSize - 2; - if (n > 0 && runLengths[n - 1] < runLengths[n + 1]) - { - n--; - } + var n = stackSize - 2; + if (n > 0 && runLengths[n - 1] < runLengths[n + 1]) + { + n--; + } - MergeAt(array, n); - } - } - - private void MergeAt(T[] array, int index) - { - var baseA = runBase[index]; - var lenA = runLengths[index]; - var baseB = runBase[index + 1]; - var lenB = runLengths[index + 1]; + MergeAt(array, n); + } + } - runLengths[index] = lenA + lenB; + private void MergeAt(T[] array, int index) + { + var baseA = runBase[index]; + var lenA = runLengths[index]; + var baseB = runBase[index + 1]; + var lenB = runLengths[index + 1]; - if (index == stackSize - 3) - { - runBase[index + 1] = runBase[index + 2]; - runLengths[index + 1] = runLengths[index + 2]; - } + runLengths[index] = lenA + lenB; - stackSize--; + if (index == stackSize - 3) + { + runBase[index + 1] = runBase[index + 2]; + runLengths[index + 1] = runLengths[index + 2]; + } - var k = GallopRight(array, array[baseB], baseA, lenA, 0); + stackSize--; - baseA += k; - lenA -= k; + var k = GallopRight(array, array[baseB], baseA, lenA, 0); - if (lenA <= 0) - { - return; - } + baseA += k; + lenA -= k; - lenB = GallopLeft(array, array[baseA + lenA - 1], baseB, lenB, lenB - 1); + if (lenA <= 0) + { + return; + } - if (lenB <= 0) - { - return; - } + lenB = GallopLeft(array, array[baseA + lenA - 1], baseB, lenB, lenB - 1); - Merge(array, baseA, lenA, baseB, lenB); + if (lenB <= 0) + { + return; } - private void Merge(T[] array, int baseA, int lenA, int baseB, int lenB) - { - var endA = baseA + lenA; - var dest = baseA; + Merge(array, baseA, lenA, baseB, lenB); + } - TimChunk left = new() - { - Array = array[baseA..endA], - Remaining = lenA, - }; + private void Merge(T[] array, int baseA, int lenA, int baseB, int lenB) + { + var endA = baseA + lenA; + var dest = baseA; + + TimChunk left = new() + { + Array = array[baseA..endA], + Remaining = lenA, + }; - TimChunk right = new() - { - Array = array, - Index = baseB, - Remaining = lenB, - }; + TimChunk right = new() + { + Array = array, + Index = baseB, + Remaining = lenB, + }; - // Move first element of the right chunk and deal with degenerate cases. - if (!TimSorter.NeedsMerge(left, right, ref dest)) - { - // One of the chunks had 0-1 items in it, so no need to merge anything. - return; - } + // Move first element of the right chunk and deal with degenerate cases. + if (!TimSorter.NeedsMerge(left, right, ref dest)) + { + // One of the chunks had 0-1 items in it, so no need to merge anything. + return; + } - var gallop = minGallop; + var gallop = minGallop; - while (RunMerge(left, right, ref dest, ref gallop)) - { - // Penalize for leaving gallop mode - gallop = gallop > 0 - ? gallop + 2 - : 2; - } + while (RunMerge(left, right, ref dest, ref gallop)) + { + // Penalize for leaving gallop mode + gallop = gallop > 0 + ? gallop + 2 + : 2; + } - minGallop = gallop >= 1 - ? gallop - : 1; + minGallop = gallop >= 1 + ? gallop + : 1; - FinalizeMerge(left, right, dest); - } + FinalizeMerge(left, right, dest); + } - private bool RunMerge(TimChunk left, TimChunk right, ref int dest, ref int gallop) + private bool RunMerge(TimChunk left, TimChunk right, ref int dest, ref int gallop) + { + // Reset the number of times in row a run wins. + left.Wins = 0; + right.Wins = 0; + + // Run a stable merge sort until (if ever) one run starts winning consistently. + if (StableMerge(left, right, ref dest, gallop)) { - // Reset the number of times in row a run wins. - left.Wins = 0; - right.Wins = 0; + // Stable merge sort completed with no viable gallops, time to exit. + return false; + } - // Run a stable merge sort until (if ever) one run starts winning consistently. - if (StableMerge(left, right, ref dest, gallop)) + // One run is winning so consistently that galloping may be a huge win. + // So try that, and continue galloping until (if ever) neither run appears to be winning consistently anymore. + do + { + if (GallopMerge(left, right, ref dest)) { - // Stable merge sort completed with no viable gallops, time to exit. + // Galloped all the way to the end, merge is complete. return false; } - // One run is winning so consistently that galloping may be a huge win. - // So try that, and continue galloping until (if ever) neither run appears to be winning consistently anymore. - do - { - if (GallopMerge(left, right, ref dest)) - { - // Galloped all the way to the end, merge is complete. - return false; - } - - // We had a bit of a run, so make it easier to get started again. - gallop--; - } - while (left.Wins >= initMinGallop || right.Wins >= initMinGallop); - - return true; + // We had a bit of a run, so make it easier to get started again. + gallop--; } + while (left.Wins >= initMinGallop || right.Wins >= initMinGallop); - private bool StableMerge(TimChunk left, TimChunk right, ref int dest, int gallop) + return true; + } + + private bool StableMerge(TimChunk left, TimChunk right, ref int dest, int gallop) + { + do { - do + if (comparer.Compare(right.Array[right.Index], left.Array[left.Index]) < 0) { - if (comparer.Compare(right.Array[right.Index], left.Array[left.Index]) < 0) - { - right.Array[dest++] = right.Array[right.Index++]; - right.Wins++; - left.Wins = 0; - if (--right.Remaining == 0) - { - return true; - } - } - else + right.Array[dest++] = right.Array[right.Index++]; + right.Wins++; + left.Wins = 0; + if (--right.Remaining == 0) { - right.Array[dest++] = left.Array[left.Index++]; - left.Wins++; - right.Wins = 0; - if (--left.Remaining == 1) - { - return true; - } + return true; } } - while ((left.Wins | right.Wins) < gallop); - - return false; - } - - private bool GallopMerge(TimChunk left, TimChunk right, ref int dest) - { - left.Wins = GallopRight(left.Array, right.Array[right.Index], left.Index, left.Remaining, 0); - if (left.Wins != 0) + else { - Array.Copy(left.Array, left.Index, right.Array, dest, left.Wins); - dest += left.Wins; - left.Index += left.Wins; - left.Remaining -= left.Wins; - if (left.Remaining <= 1) + right.Array[dest++] = left.Array[left.Index++]; + left.Wins++; + right.Wins = 0; + if (--left.Remaining == 1) { return true; } } + } + while ((left.Wins | right.Wins) < gallop); + + return false; + } - right.Array[dest++] = right.Array[right.Index++]; - if (--right.Remaining == 0) + private bool GallopMerge(TimChunk left, TimChunk right, ref int dest) + { + left.Wins = GallopRight(left.Array, right.Array[right.Index], left.Index, left.Remaining, 0); + if (left.Wins != 0) + { + Array.Copy(left.Array, left.Index, right.Array, dest, left.Wins); + dest += left.Wins; + left.Index += left.Wins; + left.Remaining -= left.Wins; + if (left.Remaining <= 1) { return true; } + } - right.Wins = GallopLeft(right.Array, left.Array[left.Index], right.Index, right.Remaining, 0); - if (right.Wins != 0) - { - Array.Copy(right.Array, right.Index, right.Array, dest, right.Wins); - dest += right.Wins; - right.Index += right.Wins; - right.Remaining -= right.Wins; - if (right.Remaining == 0) - { - return true; - } - } + right.Array[dest++] = right.Array[right.Index++]; + if (--right.Remaining == 0) + { + return true; + } - right.Array[dest++] = left.Array[left.Index++]; - if (--left.Remaining == 1) + right.Wins = GallopLeft(right.Array, left.Array[left.Index], right.Index, right.Remaining, 0); + if (right.Wins != 0) + { + Array.Copy(right.Array, right.Index, right.Array, dest, right.Wins); + dest += right.Wins; + right.Index += right.Wins; + right.Remaining -= right.Wins; + if (right.Remaining == 0) { return true; } + } - return false; + right.Array[dest++] = left.Array[left.Index++]; + if (--left.Remaining == 1) + { + return true; } + + return false; } } diff --git a/Algorithms/Sorters/External/ExternalMergeSorter.cs b/Algorithms/Sorters/External/ExternalMergeSorter.cs index 6a2da5e7..5b45aef3 100644 --- a/Algorithms/Sorters/External/ExternalMergeSorter.cs +++ b/Algorithms/Sorters/External/ExternalMergeSorter.cs @@ -1,129 +1,128 @@ using System; using System.Collections.Generic; -namespace Algorithms.Sorters.External +namespace Algorithms.Sorters.External; + +public class ExternalMergeSorter : IExternalSorter { - public class ExternalMergeSorter : IExternalSorter + public void Sort( + ISequentialStorage mainMemory, + ISequentialStorage temporaryMemory, + IComparer comparer) { - public void Sort( - ISequentialStorage mainMemory, - ISequentialStorage temporaryMemory, - IComparer comparer) + var originalSource = mainMemory; + var source = mainMemory; + var temp = temporaryMemory; + var totalLength = mainMemory.Length; + for (var stripLength = 1L; stripLength < totalLength; stripLength *= 2) { - var originalSource = mainMemory; - var source = mainMemory; - var temp = temporaryMemory; - var totalLength = mainMemory.Length; - for (var stripLength = 1L; stripLength < totalLength; stripLength *= 2) + using var left = source.GetReader(); + using var right = source.GetReader(); + using var output = temp.GetWriter(); + + for (var i = 0L; i < stripLength; i++) { - using var left = source.GetReader(); - using var right = source.GetReader(); - using var output = temp.GetWriter(); + right.Read(); + } + Merge(left, right, output, stripLength, Math.Min(stripLength, totalLength - stripLength), comparer); + var step = 2 * stripLength; + long rightStripStart; + for (rightStripStart = stripLength + step; rightStripStart < mainMemory.Length; rightStripStart += step) + { for (var i = 0L; i < stripLength; i++) { + left.Read(); right.Read(); } - Merge(left, right, output, stripLength, Math.Min(stripLength, totalLength - stripLength), comparer); - var step = 2 * stripLength; - long rightStripStart; - for (rightStripStart = stripLength + step; rightStripStart < mainMemory.Length; rightStripStart += step) - { - for (var i = 0L; i < stripLength; i++) - { - left.Read(); - right.Read(); - } - - Merge( - left, - right, - output, - stripLength, - Math.Min(stripLength, totalLength - rightStripStart), - comparer); - } - - for (var i = 0L; i < totalLength + stripLength - rightStripStart; i++) - { - output.Write(right.Read()); - } - - (source, temp) = (temp, source); + Merge( + left, + right, + output, + stripLength, + Math.Min(stripLength, totalLength - rightStripStart), + comparer); } - if (source == originalSource) + for (var i = 0L; i < totalLength + stripLength - rightStripStart; i++) { - return; + output.Write(right.Read()); } - using var sorted = source.GetReader(); - using var dest = originalSource.GetWriter(); - for (var i = 0; i < totalLength; i++) - { - dest.Write(sorted.Read()); - } + (source, temp) = (temp, source); + } + + if (source == originalSource) + { + return; } - private static void Merge( - ISequentialStorageReader left, - ISequentialStorageReader right, - ISequentialStorageWriter output, - long leftLength, - long rightLength, - IComparer comparer) + using var sorted = source.GetReader(); + using var dest = originalSource.GetWriter(); + for (var i = 0; i < totalLength; i++) { - var leftIndex = 0L; - var rightIndex = 0L; + dest.Write(sorted.Read()); + } + } - var l = left.Read(); - var r = right.Read(); - while (true) + private static void Merge( + ISequentialStorageReader left, + ISequentialStorageReader right, + ISequentialStorageWriter output, + long leftLength, + long rightLength, + IComparer comparer) + { + var leftIndex = 0L; + var rightIndex = 0L; + + var l = left.Read(); + var r = right.Read(); + while (true) + { + if (comparer.Compare(l, r) < 0) { - if (comparer.Compare(l, r) < 0) - { - output.Write(l); - leftIndex++; - if (leftIndex == leftLength) - { - break; - } - - l = left.Read(); - } - else + output.Write(l); + leftIndex++; + if (leftIndex == leftLength) { - output.Write(r); - rightIndex++; - if (rightIndex == rightLength) - { - break; - } - - r = right.Read(); + break; } - } - if (leftIndex < leftLength) - { - output.Write(l); - Copy(left, output, leftLength - leftIndex - 1); + l = left.Read(); } - - if (rightIndex < rightLength) + else { output.Write(r); - Copy(right, output, rightLength - rightIndex - 1); + rightIndex++; + if (rightIndex == rightLength) + { + break; + } + + r = right.Read(); } } - private static void Copy(ISequentialStorageReader from, ISequentialStorageWriter to, long count) + if (leftIndex < leftLength) { - for (var i = 0; i < count; i++) - { - to.Write(from.Read()); - } + output.Write(l); + Copy(left, output, leftLength - leftIndex - 1); + } + + if (rightIndex < rightLength) + { + output.Write(r); + Copy(right, output, rightLength - rightIndex - 1); + } + } + + private static void Copy(ISequentialStorageReader from, ISequentialStorageWriter to, long count) + { + for (var i = 0; i < count; i++) + { + to.Write(from.Read()); } } } diff --git a/Algorithms/Sorters/External/IExternalSorter.cs b/Algorithms/Sorters/External/IExternalSorter.cs index ebfbf761..f6929656 100644 --- a/Algorithms/Sorters/External/IExternalSorter.cs +++ b/Algorithms/Sorters/External/IExternalSorter.cs @@ -1,14 +1,13 @@ using System.Collections.Generic; -namespace Algorithms.Sorters.External +namespace Algorithms.Sorters.External; + +public interface IExternalSorter { - public interface IExternalSorter - { - /// - /// Sorts elements in sequential storage in ascending order. - /// - /// Memory that contains array to sort and will contain the result. - /// Temporary memory for working purposes. - void Sort(ISequentialStorage mainMemory, ISequentialStorage temporaryMemory, IComparer comparer); - } + /// + /// Sorts elements in sequential storage in ascending order. + /// + /// Memory that contains array to sort and will contain the result. + /// Temporary memory for working purposes. + void Sort(ISequentialStorage mainMemory, ISequentialStorage temporaryMemory, IComparer comparer); } diff --git a/Algorithms/Sorters/External/ISequentialStorage.cs b/Algorithms/Sorters/External/ISequentialStorage.cs index 2ae78e30..8138f1c3 100644 --- a/Algorithms/Sorters/External/ISequentialStorage.cs +++ b/Algorithms/Sorters/External/ISequentialStorage.cs @@ -1,11 +1,10 @@ -namespace Algorithms.Sorters.External +namespace Algorithms.Sorters.External; + +public interface ISequentialStorage { - public interface ISequentialStorage - { - public int Length { get; } + public int Length { get; } - ISequentialStorageReader GetReader(); + ISequentialStorageReader GetReader(); - ISequentialStorageWriter GetWriter(); - } + ISequentialStorageWriter GetWriter(); } diff --git a/Algorithms/Sorters/External/ISequentialStorageReader.cs b/Algorithms/Sorters/External/ISequentialStorageReader.cs index 47fc50cf..1158362a 100644 --- a/Algorithms/Sorters/External/ISequentialStorageReader.cs +++ b/Algorithms/Sorters/External/ISequentialStorageReader.cs @@ -1,9 +1,8 @@ using System; -namespace Algorithms.Sorters.External +namespace Algorithms.Sorters.External; + +public interface ISequentialStorageReader : IDisposable { - public interface ISequentialStorageReader : IDisposable - { - T Read(); - } + T Read(); } diff --git a/Algorithms/Sorters/External/ISequentialStorageWriter.cs b/Algorithms/Sorters/External/ISequentialStorageWriter.cs index 93a188aa..6b48dfb6 100644 --- a/Algorithms/Sorters/External/ISequentialStorageWriter.cs +++ b/Algorithms/Sorters/External/ISequentialStorageWriter.cs @@ -1,9 +1,8 @@ using System; -namespace Algorithms.Sorters.External +namespace Algorithms.Sorters.External; + +public interface ISequentialStorageWriter : IDisposable { - public interface ISequentialStorageWriter : IDisposable - { - void Write(T value); - } + void Write(T value); } diff --git a/Algorithms/Sorters/External/Storages/IntFileStorage.cs b/Algorithms/Sorters/External/Storages/IntFileStorage.cs index 83fae46f..154245b6 100644 --- a/Algorithms/Sorters/External/Storages/IntFileStorage.cs +++ b/Algorithms/Sorters/External/Storages/IntFileStorage.cs @@ -1,43 +1,42 @@ using System.IO; -namespace Algorithms.Sorters.External.Storages +namespace Algorithms.Sorters.External.Storages; + +public class IntFileStorage : ISequentialStorage { - public class IntFileStorage : ISequentialStorage - { - private readonly string filename; + private readonly string filename; - public IntFileStorage(string filename, int length) - { - Length = length; - this.filename = filename; - } + public IntFileStorage(string filename, int length) + { + Length = length; + this.filename = filename; + } - public int Length { get; } + public int Length { get; } - public ISequentialStorageReader GetReader() => new FileReader(filename); + public ISequentialStorageReader GetReader() => new FileReader(filename); - public ISequentialStorageWriter GetWriter() => new FileWriter(filename); + public ISequentialStorageWriter GetWriter() => new FileWriter(filename); - private class FileReader : ISequentialStorageReader - { - private readonly BinaryReader reader; + private class FileReader : ISequentialStorageReader + { + private readonly BinaryReader reader; - public FileReader(string filename) => reader = new BinaryReader(File.OpenRead(filename)); + public FileReader(string filename) => reader = new BinaryReader(File.OpenRead(filename)); - public void Dispose() => reader.Dispose(); + public void Dispose() => reader.Dispose(); - public int Read() => reader.ReadInt32(); - } + public int Read() => reader.ReadInt32(); + } - private class FileWriter : ISequentialStorageWriter - { - private readonly BinaryWriter writer; + private class FileWriter : ISequentialStorageWriter + { + private readonly BinaryWriter writer; - public FileWriter(string filename) => writer = new BinaryWriter(File.OpenWrite(filename)); + public FileWriter(string filename) => writer = new BinaryWriter(File.OpenWrite(filename)); - public void Write(int value) => writer.Write(value); + public void Write(int value) => writer.Write(value); - public void Dispose() => writer.Dispose(); - } + public void Dispose() => writer.Dispose(); } } diff --git a/Algorithms/Sorters/External/Storages/IntInMemoryStorage.cs b/Algorithms/Sorters/External/Storages/IntInMemoryStorage.cs index 6cc4d4aa..e0a84031 100644 --- a/Algorithms/Sorters/External/Storages/IntInMemoryStorage.cs +++ b/Algorithms/Sorters/External/Storages/IntInMemoryStorage.cs @@ -1,45 +1,44 @@ -namespace Algorithms.Sorters.External.Storages +namespace Algorithms.Sorters.External.Storages; + +public class IntInMemoryStorage : ISequentialStorage { - public class IntInMemoryStorage : ISequentialStorage - { - private readonly int[] storage; + private readonly int[] storage; - public IntInMemoryStorage(int[] array) => storage = array; + public IntInMemoryStorage(int[] array) => storage = array; - public int Length => storage.Length; + public int Length => storage.Length; - public ISequentialStorageReader GetReader() => new InMemoryReader(storage); + public ISequentialStorageReader GetReader() => new InMemoryReader(storage); - public ISequentialStorageWriter GetWriter() => new InMemoryWriter(storage); + public ISequentialStorageWriter GetWriter() => new InMemoryWriter(storage); - private class InMemoryReader : ISequentialStorageReader - { - private readonly int[] storage; - private int offset; - - public InMemoryReader(int[] storage) => this.storage = storage; + private class InMemoryReader : ISequentialStorageReader + { + private readonly int[] storage; + private int offset; - public void Dispose() - { - // Nothing to dispose here - } + public InMemoryReader(int[] storage) => this.storage = storage; - public int Read() => storage[offset++]; + public void Dispose() + { + // Nothing to dispose here } - private class InMemoryWriter : ISequentialStorageWriter - { - private readonly int[] storage; - private int offset; + public int Read() => storage[offset++]; + } - public InMemoryWriter(int[] storage) => this.storage = storage; + private class InMemoryWriter : ISequentialStorageWriter + { + private readonly int[] storage; + private int offset; + + public InMemoryWriter(int[] storage) => this.storage = storage; - public void Write(int value) => storage[offset++] = value; + public void Write(int value) => storage[offset++] = value; - public void Dispose() - { - // Nothing to dispose here - } + public void Dispose() + { + // Nothing to dispose here } } } diff --git a/Algorithms/Sorters/Integer/BucketSorter.cs b/Algorithms/Sorters/Integer/BucketSorter.cs index 19932e59..843d7c80 100644 --- a/Algorithms/Sorters/Integer/BucketSorter.cs +++ b/Algorithms/Sorters/Integer/BucketSorter.cs @@ -1,108 +1,107 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace Algorithms.Sorters.Integer +namespace Algorithms.Sorters.Integer; + +/// +/// Class that implements bucket sort algorithm. +/// +public class BucketSorter : IIntegerSorter { + private const int NumOfDigitsInBase10 = 10; + /// - /// Class that implements bucket sort algorithm. + /// Sorts array elements using BucketSort Algorithm. /// - public class BucketSorter : IIntegerSorter + /// Array to sort. + public void Sort(int[] array) { - private const int NumOfDigitsInBase10 = 10; - - /// - /// Sorts array elements using BucketSort Algorithm. - /// - /// Array to sort. - public void Sort(int[] array) + if (array.Length <= 1) { - if (array.Length <= 1) - { - return; - } + return; + } - // store maximum number of digits in numbers to sort - var totalDigits = NumberOfDigits(array); + // store maximum number of digits in numbers to sort + var totalDigits = NumberOfDigits(array); - // bucket array where numbers will be placed - var buckets = new int[NumOfDigitsInBase10, array.Length + 1]; + // bucket array where numbers will be placed + var buckets = new int[NumOfDigitsInBase10, array.Length + 1]; - // go through all digit places and sort each number - // according to digit place value - for (var pass = 1; pass <= totalDigits; pass++) - { - DistributeElements(array, buckets, pass); // distribution pass - CollectElements(array, buckets); // gathering pass + // go through all digit places and sort each number + // according to digit place value + for (var pass = 1; pass <= totalDigits; pass++) + { + DistributeElements(array, buckets, pass); // distribution pass + CollectElements(array, buckets); // gathering pass - if (pass != totalDigits) - { - EmptyBucket(buckets); // set size of buckets to 0 - } + if (pass != totalDigits) + { + EmptyBucket(buckets); // set size of buckets to 0 } } + } - /// - /// Determines the number of digits in the largest number. - /// - /// Input array. - /// Number of digits. - private static int NumberOfDigits(IEnumerable array) => (int)Math.Floor(Math.Log10(array.Max()) + 1); + /// + /// Determines the number of digits in the largest number. + /// + /// Input array. + /// Number of digits. + private static int NumberOfDigits(IEnumerable array) => (int)Math.Floor(Math.Log10(array.Max()) + 1); - /// - /// To distribute elements into buckets based on specified digit. - /// - /// Input array. - /// Array of buckets. - /// Digit. - private static void DistributeElements(IEnumerable data, int[,] buckets, int digit) - { - // determine the divisor used to get specific digit - var divisor = (int)Math.Pow(10, digit); + /// + /// To distribute elements into buckets based on specified digit. + /// + /// Input array. + /// Array of buckets. + /// Digit. + private static void DistributeElements(IEnumerable data, int[,] buckets, int digit) + { + // determine the divisor used to get specific digit + var divisor = (int)Math.Pow(10, digit); - foreach (var element in data) - { - // bucketNumber example for hundreds digit: - // ( 1234 % 1000 ) / 100 --> 2 - var bucketNumber = NumOfDigitsInBase10 * (element % divisor) / divisor; + foreach (var element in data) + { + // bucketNumber example for hundreds digit: + // ( 1234 % 1000 ) / 100 --> 2 + var bucketNumber = NumOfDigitsInBase10 * (element % divisor) / divisor; - // retrieve value in pail[ bucketNumber , 0 ] to - // determine the location in row to store element - var elementNumber = ++buckets[bucketNumber, 0]; // location in bucket to place element - buckets[bucketNumber, elementNumber] = element; - } + // retrieve value in pail[ bucketNumber , 0 ] to + // determine the location in row to store element + var elementNumber = ++buckets[bucketNumber, 0]; // location in bucket to place element + buckets[bucketNumber, elementNumber] = element; } + } - /// - /// Return elements to original array. - /// - /// Input array. - /// Array of buckets. - private static void CollectElements(IList data, int[,] buckets) - { - var subscript = 0; // initialize location in data + /// + /// Return elements to original array. + /// + /// Input array. + /// Array of buckets. + private static void CollectElements(IList data, int[,] buckets) + { + var subscript = 0; // initialize location in data - // loop over buckets - for (var i = 0; i < NumOfDigitsInBase10; i++) + // loop over buckets + for (var i = 0; i < NumOfDigitsInBase10; i++) + { + // loop over elements in each bucket + for (var j = 1; j <= buckets[i, 0]; j++) { - // loop over elements in each bucket - for (var j = 1; j <= buckets[i, 0]; j++) - { - data[subscript++] = buckets[i, j]; // add element to array - } + data[subscript++] = buckets[i, j]; // add element to array } } + } - /// - /// Sets size of all buckets to zero. - /// - /// Array of buckets. - private static void EmptyBucket(int[,] buckets) + /// + /// Sets size of all buckets to zero. + /// + /// Array of buckets. + private static void EmptyBucket(int[,] buckets) + { + for (var i = 0; i < NumOfDigitsInBase10; i++) { - for (var i = 0; i < NumOfDigitsInBase10; i++) - { - buckets[i, 0] = 0; // set size of bucket to 0 - } + buckets[i, 0] = 0; // set size of bucket to 0 } } } diff --git a/Algorithms/Sorters/Integer/CountingSorter.cs b/Algorithms/Sorters/Integer/CountingSorter.cs index 2d0ce004..fc43b153 100644 --- a/Algorithms/Sorters/Integer/CountingSorter.cs +++ b/Algorithms/Sorters/Integer/CountingSorter.cs @@ -1,59 +1,58 @@ using System; using System.Linq; -namespace Algorithms.Sorters.Integer +namespace Algorithms.Sorters.Integer; + +/// +/// Counting sort is an algorithm for sorting a collection of objects according to keys that are small integers; that +/// is, it is an integer sorting algorithm. It operates by counting the number of objects that have each distinct key +/// value, and using arithmetic on those counts to determine the positions of each key value in the output sequence. +/// Its running time is linear in the number of items and the difference between the maximum and minimum key values, so +/// it is only suitable for direct use in situations where the variation in keys is not significantly greater than the +/// number of items. However, it is often used as a subroutine in another sorting algorithm, radix sort, that can +/// handle larger keys more efficiently. +/// +public class CountingSorter : IIntegerSorter { /// - /// Counting sort is an algorithm for sorting a collection of objects according to keys that are small integers; that - /// is, it is an integer sorting algorithm. It operates by counting the number of objects that have each distinct key - /// value, and using arithmetic on those counts to determine the positions of each key value in the output sequence. - /// Its running time is linear in the number of items and the difference between the maximum and minimum key values, so - /// it is only suitable for direct use in situations where the variation in keys is not significantly greater than the - /// number of items. However, it is often used as a subroutine in another sorting algorithm, radix sort, that can - /// handle larger keys more efficiently. + /// + /// Sorts input array using counting sort algorithm. + /// + /// + /// Time complexity: O(n+k), where k is the range of the non-negative key values. + /// + /// + /// Space complexity: O(n+k), where k is the range of the non-negative key values. + /// /// - public class CountingSorter : IIntegerSorter + /// Input array. + public void Sort(int[] array) { - /// - /// - /// Sorts input array using counting sort algorithm. - /// - /// - /// Time complexity: O(n+k), where k is the range of the non-negative key values. - /// - /// - /// Space complexity: O(n+k), where k is the range of the non-negative key values. - /// - /// - /// Input array. - public void Sort(int[] array) + if (array.Length == 0) { - if (array.Length == 0) - { - return; - } - - var max = array.Max(); - var min = array.Min(); - var count = new int[max - min + 1]; - var output = new int[array.Length]; - for (var i = 0; i < array.Length; i++) - { - count[array[i] - min]++; - } + return; + } - for (var i = 1; i < count.Length; i++) - { - count[i] += count[i - 1]; - } + var max = array.Max(); + var min = array.Min(); + var count = new int[max - min + 1]; + var output = new int[array.Length]; + for (var i = 0; i < array.Length; i++) + { + count[array[i] - min]++; + } - for (var i = array.Length - 1; i >= 0; i--) - { - output[count[array[i] - min] - 1] = array[i]; - count[array[i] - min]--; - } + for (var i = 1; i < count.Length; i++) + { + count[i] += count[i - 1]; + } - Array.Copy(output, array, array.Length); + for (var i = array.Length - 1; i >= 0; i--) + { + output[count[array[i] - min] - 1] = array[i]; + count[array[i] - min]--; } + + Array.Copy(output, array, array.Length); } } diff --git a/Algorithms/Sorters/Integer/IIntegerSorter.cs b/Algorithms/Sorters/Integer/IIntegerSorter.cs index f5705749..a17dc4ab 100644 --- a/Algorithms/Sorters/Integer/IIntegerSorter.cs +++ b/Algorithms/Sorters/Integer/IIntegerSorter.cs @@ -1,14 +1,13 @@ -namespace Algorithms.Sorters.Integer +namespace Algorithms.Sorters.Integer; + +/// +/// Sorts array of integers without comparing them. +/// +public interface IIntegerSorter { /// - /// Sorts array of integers without comparing them. + /// Sorts array in ascending order. /// - public interface IIntegerSorter - { - /// - /// Sorts array in ascending order. - /// - /// Array to sort. - void Sort(int[] array); - } + /// Array to sort. + void Sort(int[] array); } diff --git a/Algorithms/Sorters/Integer/RadixSorter.cs b/Algorithms/Sorters/Integer/RadixSorter.cs index 263768f0..f2d0289d 100644 --- a/Algorithms/Sorters/Integer/RadixSorter.cs +++ b/Algorithms/Sorters/Integer/RadixSorter.cs @@ -1,49 +1,48 @@ -namespace Algorithms.Sorters.Integer +namespace Algorithms.Sorters.Integer; + +/// +/// Radix sort is a non-comparative integer sorting algorithm that sorts data with integer keys by grouping keys by the +/// individual +/// digits which share the same significant position and value. A positional notation is required, but because integers +/// can represent +/// strings of characters (e.g., names or dates) and specially formatted floating point numbers, radix sort is not +/// limited to integers. +/// +public class RadixSorter : IIntegerSorter { /// - /// Radix sort is a non-comparative integer sorting algorithm that sorts data with integer keys by grouping keys by the - /// individual - /// digits which share the same significant position and value. A positional notation is required, but because integers - /// can represent - /// strings of characters (e.g., names or dates) and specially formatted floating point numbers, radix sort is not - /// limited to integers. + /// Sorts array in ascending order. /// - public class RadixSorter : IIntegerSorter + /// Array to sort. + public void Sort(int[] array) { - /// - /// Sorts array in ascending order. - /// - /// Array to sort. - public void Sort(int[] array) + var bits = 4; + var b = new int[array.Length]; + var rshift = 0; + for (var mask = ~(-1 << bits); mask != 0; mask <<= bits, rshift += bits) { - var bits = 4; - var b = new int[array.Length]; - var rshift = 0; - for (var mask = ~(-1 << bits); mask != 0; mask <<= bits, rshift += bits) + var cntarray = new int[1 << bits]; + foreach (var t in array) { - var cntarray = new int[1 << bits]; - foreach (var t in array) - { - var key = (t & mask) >> rshift; - ++cntarray[key]; - } - - for (var i = 1; i < cntarray.Length; ++i) - { - cntarray[i] += cntarray[i - 1]; - } + var key = (t & mask) >> rshift; + ++cntarray[key]; + } - for (var p = array.Length - 1; p >= 0; --p) - { - var key = (array[p] & mask) >> rshift; - --cntarray[key]; - b[cntarray[key]] = array[p]; - } + for (var i = 1; i < cntarray.Length; ++i) + { + cntarray[i] += cntarray[i - 1]; + } - var temp = b; - b = array; - array = temp; + for (var p = array.Length - 1; p >= 0; --p) + { + var key = (array[p] & mask) >> rshift; + --cntarray[key]; + b[cntarray[key]] = array[p]; } + + var temp = b; + b = array; + array = temp; } } } diff --git a/Algorithms/Sorters/String/IStringSorter.cs b/Algorithms/Sorters/String/IStringSorter.cs index 16af326c..8a2159db 100644 --- a/Algorithms/Sorters/String/IStringSorter.cs +++ b/Algorithms/Sorters/String/IStringSorter.cs @@ -1,14 +1,13 @@ -namespace Algorithms.Sorters.String +namespace Algorithms.Sorters.String; + +/// +/// Sorts array of strings without comparing them. +/// +public interface IStringSorter { /// - /// Sorts array of strings without comparing them. + /// Sorts array in ascending order. /// - public interface IStringSorter - { - /// - /// Sorts array in ascending order. - /// - /// Array to sort. - void Sort(string[] array); - } + /// Array to sort. + void Sort(string[] array); } diff --git a/Algorithms/Sorters/String/MsdRadixStringSorter.cs b/Algorithms/Sorters/String/MsdRadixStringSorter.cs index ae75344c..1b1b0b5c 100644 --- a/Algorithms/Sorters/String/MsdRadixStringSorter.cs +++ b/Algorithms/Sorters/String/MsdRadixStringSorter.cs @@ -1,59 +1,58 @@ -namespace Algorithms.Sorters.String +namespace Algorithms.Sorters.String; + +/// +/// Radix sort is a non-comparative sorting algorithm. It avoids comparison by creating +/// and distributing elements into buckets according to their radix. +/// Radix sorts can be implemented to start at either the most significant digit (MSD) +/// or least significant digit (LSD). +/// MSD radix sorts are most suitable for sorting array of strings with variable length +/// in lexicographical order. +/// +public class MsdRadixStringSorter : IStringSorter { /// - /// Radix sort is a non-comparative sorting algorithm. It avoids comparison by creating - /// and distributing elements into buckets according to their radix. - /// Radix sorts can be implemented to start at either the most significant digit (MSD) - /// or least significant digit (LSD). - /// MSD radix sorts are most suitable for sorting array of strings with variable length - /// in lexicographical order. + /// Sort array of strings using MSD radix sort algorithm. /// - public class MsdRadixStringSorter : IStringSorter + /// Array to sort. + public void Sort(string[] array) => Sort(array, 0, array.Length - 1, 0, new string[array.Length]); + + private static void Sort(string[] array, int l, int r, int d, string[] temp) { - /// - /// Sort array of strings using MSD radix sort algorithm. - /// - /// Array to sort. - public void Sort(string[] array) => Sort(array, 0, array.Length - 1, 0, new string[array.Length]); + if (l >= r) + { + return; + } - private static void Sort(string[] array, int l, int r, int d, string[] temp) + const int k = 256; + + var count = new int[k + 2]; + for (var i = l; i <= r; i++) { - if (l >= r) - { - return; - } - - const int k = 256; - - var count = new int[k + 2]; - for (var i = l; i <= r; i++) - { - var j = Key(array[i]); - count[j + 2]++; - } - - for (var i = 1; i < count.Length; i++) - { - count[i] += count[i - 1]; - } - - for (var i = l; i <= r; i++) - { - var j = Key(array[i]); - temp[count[j + 1]++] = array[i]; - } - - for (var i = l; i <= r; i++) - { - array[i] = temp[i - l]; - } - - for (var i = 0; i < k; i++) - { - Sort(array, l + count[i], l + count[i + 1] - 1, d + 1, temp); - } - - int Key(string s) => d >= s.Length ? -1 : s[d]; + var j = Key(array[i]); + count[j + 2]++; } + + for (var i = 1; i < count.Length; i++) + { + count[i] += count[i - 1]; + } + + for (var i = l; i <= r; i++) + { + var j = Key(array[i]); + temp[count[j + 1]++] = array[i]; + } + + for (var i = l; i <= r; i++) + { + array[i] = temp[i - l]; + } + + for (var i = 0; i < k; i++) + { + Sort(array, l + count[i], l + count[i + 1] - 1, d + 1, temp); + } + + int Key(string s) => d >= s.Length ? -1 : s[d]; } } diff --git a/Algorithms/Strings/GeneralStringAlgorithms.cs b/Algorithms/Strings/GeneralStringAlgorithms.cs index 1fc2b9aa..6e1822c6 100644 --- a/Algorithms/Strings/GeneralStringAlgorithms.cs +++ b/Algorithms/Strings/GeneralStringAlgorithms.cs @@ -1,42 +1,41 @@ using System; -namespace Algorithms.Strings +namespace Algorithms.Strings; + +/// +/// Implements simple algorithms on strings. +/// +public static class GeneralStringAlgorithms { /// - /// Implements simple algorithms on strings. + /// Finds character that creates longest consecutive substring with single character. /// - public static class GeneralStringAlgorithms + /// String to find in. + /// Tuple containing char and number of times it appeared in a row. + public static Tuple FindLongestConsecutiveCharacters(string input) { - /// - /// Finds character that creates longest consecutive substring with single character. - /// - /// String to find in. - /// Tuple containing char and number of times it appeared in a row. - public static Tuple FindLongestConsecutiveCharacters(string input) - { - var maxChar = input[0]; + var maxChar = input[0]; - var max = 1; - var current = 1; + var max = 1; + var current = 1; - for (var i = 1; i < input.Length; i++) + for (var i = 1; i < input.Length; i++) + { + if (input[i] == input[i - 1]) { - if (input[i] == input[i - 1]) - { - current++; - if (current > max) - { - max = current; - maxChar = input[i]; - } - } - else + current++; + if (current > max) { - current = 1; + max = current; + maxChar = input[i]; } } - - return new Tuple(maxChar, max); + else + { + current = 1; + } } + + return new Tuple(maxChar, max); } } diff --git a/Algorithms/Strings/Palindrome.cs b/Algorithms/Strings/Palindrome.cs index 7d88f077..21be50a5 100644 --- a/Algorithms/Strings/Palindrome.cs +++ b/Algorithms/Strings/Palindrome.cs @@ -1,39 +1,38 @@ using System; using System.Text.RegularExpressions; -namespace Algorithms.Strings +namespace Algorithms.Strings; + +/// +/// Palindrome a series of characters or a string that when reversed, +/// equals the original string. +/// +public static class Palindrome { /// - /// Palindrome a series of characters or a string that when reversed, - /// equals the original string. + /// Function to check if a string is a palindrome. /// - public static class Palindrome - { - /// - /// Function to check if a string is a palindrome. - /// - /// String being checked. - public static bool IsStringPalindrome(string word) => - TypifyString(word).Equals(TypifyString(ReverseString(word))); + /// String being checked. + public static bool IsStringPalindrome(string word) => + TypifyString(word).Equals(TypifyString(ReverseString(word))); - /// - /// Typify string to lower and remove white spaces. - /// - /// String to remove spaces. - /// Returns original string without spaces. - private static string TypifyString(string word) => - Regex.Replace(word.ToLowerInvariant(), @"\s+", string.Empty); + /// + /// Typify string to lower and remove white spaces. + /// + /// String to remove spaces. + /// Returns original string without spaces. + private static string TypifyString(string word) => + Regex.Replace(word.ToLowerInvariant(), @"\s+", string.Empty); - /// - /// Helper function that returns a reversed string inputed. - /// - /// String to be reversed. - /// Returns s reversed. - private static string ReverseString(string s) - { - var arr = s.ToCharArray(); - Array.Reverse(arr); - return new string(arr); - } + /// + /// Helper function that returns a reversed string inputed. + /// + /// String to be reversed. + /// Returns s reversed. + private static string ReverseString(string s) + { + var arr = s.ToCharArray(); + Array.Reverse(arr); + return new string(arr); } } diff --git a/Algorithms/Strings/PatternMatching/BoyerMoore.cs b/Algorithms/Strings/PatternMatching/BoyerMoore.cs index c415d79c..a00e93c4 100644 --- a/Algorithms/Strings/PatternMatching/BoyerMoore.cs +++ b/Algorithms/Strings/PatternMatching/BoyerMoore.cs @@ -1,167 +1,166 @@ using System; -namespace Algorithms.Strings.PatternMatching +namespace Algorithms.Strings.PatternMatching; + +/// +/// The idea: You compare the pattern with the text from right to left. +/// If the text symbol that is compared with the rightmost pattern symbol +/// does not occur in the pattern at all, then the pattern can be shifted +/// by m positions behind this text symbol. +/// Complexity: +/// Time: Preprocessing: O(m²) +/// Comparison: O(mn) +/// Space: O(m + a) +/// where m - pattern length +/// n - text length +/// a - alphabet length. +/// Source: https://www.inf.hs-flensburg.de/lang/algorithmen/pattern/bmen.htm +/// https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string-search_algorithm. +/// +public static class BoyerMoore { /// - /// The idea: You compare the pattern with the text from right to left. - /// If the text symbol that is compared with the rightmost pattern symbol - /// does not occur in the pattern at all, then the pattern can be shifted - /// by m positions behind this text symbol. - /// Complexity: - /// Time: Preprocessing: O(m²) - /// Comparison: O(mn) - /// Space: O(m + a) - /// where m - pattern length - /// n - text length - /// a - alphabet length. - /// Source: https://www.inf.hs-flensburg.de/lang/algorithmen/pattern/bmen.htm - /// https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string-search_algorithm. + /// Finds the index of the first occurrence of the pattern p in t. /// - public static class BoyerMoore + /// Input text. + /// Search pattern. + /// Index of the pattern in text or -1 if the pattern was not found. + public static int FindFirstOccurrence(string t, string p) { - /// - /// Finds the index of the first occurrence of the pattern p in t. - /// - /// Input text. - /// Search pattern. - /// Index of the pattern in text or -1 if the pattern was not found. - public static int FindFirstOccurrence(string t, string p) - { - // Pattern length - var m = p.Length; - - // Text length - var n = t.Length; + // Pattern length + var m = p.Length; - // For each symbol of the alphabet, the position of its rightmost occurrence in the pattern, - // or -1 if the symbol does not occur in the pattern. - int[] badChar = BadCharacterRule(p, m); + // Text length + var n = t.Length; - // Each entry goodSuffix[i] contains the shift distance of the pattern - // if a mismatch at position i – 1 occurs, i.e. if the suffix of the pattern starting at position i has matched. - int[] goodSuffix = GoodSuffixRule(p, m); + // For each symbol of the alphabet, the position of its rightmost occurrence in the pattern, + // or -1 if the symbol does not occur in the pattern. + int[] badChar = BadCharacterRule(p, m); - // Index in text - var i = 0; + // Each entry goodSuffix[i] contains the shift distance of the pattern + // if a mismatch at position i – 1 occurs, i.e. if the suffix of the pattern starting at position i has matched. + int[] goodSuffix = GoodSuffixRule(p, m); - // Index in pattern - int j; + // Index in text + var i = 0; - while (i <= n - m) - { - // Starting at end of pattern - j = m - 1; + // Index in pattern + int j; - // While matching - while (j >= 0 && p[j] == t[i + j]) - { - j--; - } + while (i <= n - m) + { + // Starting at end of pattern + j = m - 1; - // Pattern found - if (j < 0) - { - return i; - } + // While matching + while (j >= 0 && p[j] == t[i + j]) + { + j--; + } - // Pattern is shifted by the maximum of the values - // given by the good-suffix and the bad-character heuristics - i += Math.Max(goodSuffix[j + 1], j - badChar[t[i + j]]); + // Pattern found + if (j < 0) + { + return i; } - // Pattern not found - return -1; + // Pattern is shifted by the maximum of the values + // given by the good-suffix and the bad-character heuristics + i += Math.Max(goodSuffix[j + 1], j - badChar[t[i + j]]); } - /// - /// Finds out the position of its rightmost occurrence in the pattern for each symbol of the alphabet, - /// or -1 if the symbol does not occur in the pattern. - /// - /// Search pattern. - /// Length of the pattern. - /// Array of the named postition for each symbol of the alphabet. - private static int[] BadCharacterRule(string p, int m) - { - // For each character (note that there are more than 256 characters) - int[] badChar = new int[256]; - Array.Fill(badChar, -1); + // Pattern not found + return -1; + } - // Iterate from left to right over the pattern - for (var j = 0; j < m; j++) - { - badChar[p[j]] = j; - } + /// + /// Finds out the position of its rightmost occurrence in the pattern for each symbol of the alphabet, + /// or -1 if the symbol does not occur in the pattern. + /// + /// Search pattern. + /// Length of the pattern. + /// Array of the named postition for each symbol of the alphabet. + private static int[] BadCharacterRule(string p, int m) + { + // For each character (note that there are more than 256 characters) + int[] badChar = new int[256]; + Array.Fill(badChar, -1); - return badChar; + // Iterate from left to right over the pattern + for (var j = 0; j < m; j++) + { + badChar[p[j]] = j; } - /// - /// Finds out the shift distance of the pattern if a mismatch at position i – 1 occurs - /// for each character of the pattern, i.e. if the suffix of the pattern starting at position i has matched. - /// - /// Search pattern. - /// Length of the pattern. - /// Array of the named shift distance for each character of the pattern. - private static int[] GoodSuffixRule(string p, int m) - { - // CASE 1 - // The matching suffix occurs somewhere else in the pattern - // --> matching suffix is a border of a suffix of the pattern + return badChar; + } + + /// + /// Finds out the shift distance of the pattern if a mismatch at position i – 1 occurs + /// for each character of the pattern, i.e. if the suffix of the pattern starting at position i has matched. + /// + /// Search pattern. + /// Length of the pattern. + /// Array of the named shift distance for each character of the pattern. + private static int[] GoodSuffixRule(string p, int m) + { + // CASE 1 + // The matching suffix occurs somewhere else in the pattern + // --> matching suffix is a border of a suffix of the pattern - // f[i] contains starting position of the widest border of the suffix of the pattern beginning at position i - int[] f = new int[p.Length + 1]; + // f[i] contains starting position of the widest border of the suffix of the pattern beginning at position i + int[] f = new int[p.Length + 1]; - // Suffix of p[m] has no border --> f[m] = m+1 - f[m] = m + 1; + // Suffix of p[m] has no border --> f[m] = m+1 + f[m] = m + 1; - // Corresponding shift distance - int[] s = new int[p.Length + 1]; + // Corresponding shift distance + int[] s = new int[p.Length + 1]; - // Start of suffix including border of the pattern - // (hint: https://www.inf.hs-flensburg.de/lang/algorithmen/pattern/kmpen.htm#section2) - var i = m; + // Start of suffix including border of the pattern + // (hint: https://www.inf.hs-flensburg.de/lang/algorithmen/pattern/kmpen.htm#section2) + var i = m; - // Start of suffix of the pattern - var j = m + 1; + // Start of suffix of the pattern + var j = m + 1; - while (i > 0) + while (i > 0) + { + // checking if a shorter border that is already known can be extended to the left by the same symbol + while (j <= m && p[i - 1] != p[j - 1]) { - // checking if a shorter border that is already known can be extended to the left by the same symbol - while (j <= m && p[i - 1] != p[j - 1]) + if (s[j] == 0) { - if (s[j] == 0) - { - s[j] = j - i; - } - - j = f[j]; + s[j] = j - i; } - --i; - --j; - f[i] = j; + j = f[j]; } - // CASE 2 - // Only a part of the matching suffix occurs at the beginning of the pattern - // (filling remaining entries) - j = f[0]; - for (i = 0; i <= m; i++) - { - // Starting postition of the greates border - if (s[i] == 0) - { - s[i] = j; - } + --i; + --j; + f[i] = j; + } - // From position i = j, it switches to the next narrower border f[j] - if (i == j) - { - j = f[j]; - } + // CASE 2 + // Only a part of the matching suffix occurs at the beginning of the pattern + // (filling remaining entries) + j = f[0]; + for (i = 0; i <= m; i++) + { + // Starting postition of the greates border + if (s[i] == 0) + { + s[i] = j; } - return s; + // From position i = j, it switches to the next narrower border f[j] + if (i == j) + { + j = f[j]; + } } + + return s; } } diff --git a/Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs b/Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs index d4a4a2b8..3b31e614 100644 --- a/Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs +++ b/Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs @@ -1,82 +1,81 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Strings.PatternMatching +namespace Algorithms.Strings.PatternMatching; + +public class KnuthMorrisPrattSearcher { - public class KnuthMorrisPrattSearcher + /// + /// An implementation of Knuth–Morris–Pratt Algorithm. + /// Worst case time complexity: O(n + k) + /// where n - text length, k - pattern length. + /// + /// The string to look in. + /// The pattern to look for. + /// + /// The zero-based positions of all occurrences of in . + /// + public IEnumerable FindIndexes(string str, string pat) { - /// - /// An implementation of Knuth–Morris–Pratt Algorithm. - /// Worst case time complexity: O(n + k) - /// where n - text length, k - pattern length. - /// - /// The string to look in. - /// The pattern to look for. - /// - /// The zero-based positions of all occurrences of in . - /// - public IEnumerable FindIndexes(string str, string pat) + var lps = FindLongestPrefixSuffixValues(pat); + + for (int i = 0, j = 0; i < str.Length;) { - var lps = FindLongestPrefixSuffixValues(pat); + if (pat[j] == str[i]) + { + j++; + i++; + } - for (int i = 0, j = 0; i < str.Length;) + if (j == pat.Length) { - if (pat[j] == str[i]) - { - j++; - i++; - } + yield return i - j; + j = lps[j - 1]; + continue; + } - if (j == pat.Length) + if (i < str.Length && pat[j] != str[i]) + { + if (j != 0) { - yield return i - j; j = lps[j - 1]; - continue; } - - if (i < str.Length && pat[j] != str[i]) + else { - if (j != 0) - { - j = lps[j - 1]; - } - else - { - i += 1; - } + i += 1; } } } + } - /// - /// Return the longest prefix suffix values for pattern. - /// - /// pattern to seek. - /// The longest prefix suffix values for . - public int[] FindLongestPrefixSuffixValues(string pat) + /// + /// Return the longest prefix suffix values for pattern. + /// + /// pattern to seek. + /// The longest prefix suffix values for . + public int[] FindLongestPrefixSuffixValues(string pat) + { + var lps = new int[pat.Length]; + for (int i = 1, len = 0; i < pat.Length;) { - var lps = new int[pat.Length]; - for (int i = 1, len = 0; i < pat.Length;) + if (pat[i] == pat[len]) { - if (pat[i] == pat[len]) - { - len++; - lps[i] = len; - i++; - continue; - } - - if (len != 0) - { - len = lps[len - 1]; - } - else - { - lps[i] = 0; - i++; - } + len++; + lps[i] = len; + i++; + continue; } - return lps; + if (len != 0) + { + len = lps[len - 1]; + } + else + { + lps[i] = 0; + i++; + } } + + return lps; } } diff --git a/Algorithms/Strings/PatternMatching/NaiveStringSearch.cs b/Algorithms/Strings/PatternMatching/NaiveStringSearch.cs index e9c84e37..184c8067 100644 --- a/Algorithms/Strings/PatternMatching/NaiveStringSearch.cs +++ b/Algorithms/Strings/PatternMatching/NaiveStringSearch.cs @@ -1,43 +1,42 @@ using System.Collections.Generic; // Implements the traditional naive string matching algorithm in C# for TheAlgorithms/C-Sharp. -namespace Algorithms.Strings.PatternMatching +namespace Algorithms.Strings.PatternMatching; + +/// +/// Implements the traditional naive string matching algorithm in C#. +/// +public static class NaiveStringSearch { /// - /// Implements the traditional naive string matching algorithm in C#. + /// NaiveSearch(Content, Pattern) will return an array containing each index of Content in which Pattern appears. + /// Cost: O(n*m). /// - public static class NaiveStringSearch + /// The text body across which to search for a given pattern. + /// The pattern against which to check the given text body. + /// Array containing each index of Content in which Pattern appears. + public static int[] NaiveSearch(string content, string pattern) { - /// - /// NaiveSearch(Content, Pattern) will return an array containing each index of Content in which Pattern appears. - /// Cost: O(n*m). - /// - /// The text body across which to search for a given pattern. - /// The pattern against which to check the given text body. - /// Array containing each index of Content in which Pattern appears. - public static int[] NaiveSearch(string content, string pattern) + var m = pattern.Length; + var n = content.Length; + List indices = new(); + for (var e = 0; e <= n - m; e++) { - var m = pattern.Length; - var n = content.Length; - List indices = new(); - for (var e = 0; e <= n - m; e++) + int j; + for (j = 0; j < m; j++) { - int j; - for (j = 0; j < m; j++) - { - if (content[e + j] != pattern[j]) - { - break; - } - } - - if (j == m) + if (content[e + j] != pattern[j]) { - indices.Add(e); + break; } } - return indices.ToArray(); + if (j == m) + { + indices.Add(e); + } } + + return indices.ToArray(); } } diff --git a/Algorithms/Strings/PatternMatching/RabinKarp.cs b/Algorithms/Strings/PatternMatching/RabinKarp.cs index 24e1f190..3dc19321 100644 --- a/Algorithms/Strings/PatternMatching/RabinKarp.cs +++ b/Algorithms/Strings/PatternMatching/RabinKarp.cs @@ -1,82 +1,81 @@ using System; using System.Collections.Generic; -namespace Algorithms.Strings.PatternMatching +namespace Algorithms.Strings.PatternMatching; + +/// +/// The idea: You calculate the hash for the pattern p and the hash values for all the prefixes of the text +/// t. +/// Now, you can compare a substring in constant time using the calculated hashes. +/// time complexity: O(p + t), +/// space complexity: O(t), +/// where t - text length +/// p - pattern length. +/// +public static class RabinKarp { /// - /// The idea: You calculate the hash for the pattern p and the hash values for all the prefixes of the text - /// t. - /// Now, you can compare a substring in constant time using the calculated hashes. - /// time complexity: O(p + t), - /// space complexity: O(t), - /// where t - text length - /// p - pattern length. + /// Finds the index of all occurrences of the pattern p int t. /// - public static class RabinKarp + /// List of starting indices of the pattern in the text. + public static List FindAllOccurrences(string text, string pattern) { - /// - /// Finds the index of all occurrences of the pattern p int t. - /// - /// List of starting indices of the pattern in the text. - public static List FindAllOccurrences(string text, string pattern) - { - // Prime number - const ulong p = 65537; + // Prime number + const ulong p = 65537; - // Modulo coefficient - const ulong m = (ulong)1e9 + 7; + // Modulo coefficient + const ulong m = (ulong)1e9 + 7; - // p_pow[i] = P^i mod M - ulong[] pPow = new ulong[Math.Max(pattern.Length, text.Length)]; - pPow[0] = 1; - for (var i = 1; i < pPow.Length; i++) - { - pPow[i] = pPow[i - 1] * p % m; - } + // p_pow[i] = P^i mod M + ulong[] pPow = new ulong[Math.Max(pattern.Length, text.Length)]; + pPow[0] = 1; + for (var i = 1; i < pPow.Length; i++) + { + pPow[i] = pPow[i - 1] * p % m; + } - // hash_t[i] is the sum of the previous hash values of the letters (t[0], t[1], ..., t[i-1]) and the hash value of t[i] itself (mod M). - // The hash value of a letter t[i] is equal to the product of t[i] and p_pow[i] (mod M). - ulong[] hashT = new ulong[text.Length + 1]; - for (var i = 0; i < text.Length; i++) - { - hashT[i + 1] = (hashT[i] + text[i] * pPow[i]) % m; - } + // hash_t[i] is the sum of the previous hash values of the letters (t[0], t[1], ..., t[i-1]) and the hash value of t[i] itself (mod M). + // The hash value of a letter t[i] is equal to the product of t[i] and p_pow[i] (mod M). + ulong[] hashT = new ulong[text.Length + 1]; + for (var i = 0; i < text.Length; i++) + { + hashT[i + 1] = (hashT[i] + text[i] * pPow[i]) % m; + } - // hash_s is equal to sum of the hash values of the pattern (mod M). - ulong hashS = 0; - for (var i = 0; i < pattern.Length; i++) - { - hashS = (hashS + pattern[i] * pPow[i]) % m; - } + // hash_s is equal to sum of the hash values of the pattern (mod M). + ulong hashS = 0; + for (var i = 0; i < pattern.Length; i++) + { + hashS = (hashS + pattern[i] * pPow[i]) % m; + } - // In the next step you iterate over the text with the pattern. - List occurrences = new(); - for (var i = 0; i + pattern.Length - 1 < text.Length; i++) - { - // In each step you calculate the hash value of the substring to be tested. - // By storing the hash values of the letters as a prefixes you can do this in constant time. - var currentHash = (hashT[i + pattern.Length] + m - hashT[i]) % m; + // In the next step you iterate over the text with the pattern. + List occurrences = new(); + for (var i = 0; i + pattern.Length - 1 < text.Length; i++) + { + // In each step you calculate the hash value of the substring to be tested. + // By storing the hash values of the letters as a prefixes you can do this in constant time. + var currentHash = (hashT[i + pattern.Length] + m - hashT[i]) % m; - // Now you can compare the hash value of the substring with the product of the hash value of the pattern and p_pow[i]. - if (currentHash == hashS * pPow[i] % m) + // Now you can compare the hash value of the substring with the product of the hash value of the pattern and p_pow[i]. + if (currentHash == hashS * pPow[i] % m) + { + // If the hash values are identical, do a double-check in case a hash collision occurs. + var j = 0; + while (j < pattern.Length && text[i + j] == pattern[j]) { - // If the hash values are identical, do a double-check in case a hash collision occurs. - var j = 0; - while (j < pattern.Length && text[i + j] == pattern[j]) - { - ++j; - } + ++j; + } - if (j == pattern.Length) - { - // If the hash values are identical and the double-check passes, a substring was found that matches the pattern. - // In this case you add the index i to the list of occurences. - occurrences.Add(i); - } + if (j == pattern.Length) + { + // If the hash values are identical and the double-check passes, a substring was found that matches the pattern. + // In this case you add the index i to the list of occurences. + occurrences.Add(i); } } - - return occurrences; } + + return occurrences; } } diff --git a/Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs b/Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs index 1c6db18f..63a71470 100644 --- a/Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs +++ b/Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs @@ -1,69 +1,68 @@ -namespace Algorithms.Strings.PatternMatching +namespace Algorithms.Strings.PatternMatching; + +/// Implementation Z-block substring search. +/// +public static class ZblockSubstringSearch { - /// Implementation Z-block substring search. + /// + /// This algorithm finds all occurrences of a pattern in a text in linear time - O(m+n). /// - public static class ZblockSubstringSearch + public static int FindSubstring(string pattern, string text) { - /// - /// This algorithm finds all occurrences of a pattern in a text in linear time - O(m+n). - /// - public static int FindSubstring(string pattern, string text) - { - var concatStr = $"{pattern}${text}"; - var patternLength = pattern.Length; - var n = concatStr.Length; - var zArray = new int[n]; + var concatStr = $"{pattern}${text}"; + var patternLength = pattern.Length; + var n = concatStr.Length; + var zArray = new int[n]; - var left = 0; - var right = 0; + var left = 0; + var right = 0; - for(var i = 1; i < n; i++) + for(var i = 1; i < n; i++) + { + if(i > right) { - if(i > right) - { - left = i; - right = ComputeNewRightValue(concatStr, n, left, i); + left = i; + right = ComputeNewRightValue(concatStr, n, left, i); - zArray[i] = right - left; - right--; - } - else - { - var k = i - left; - if (zArray[k] < (right - i + 1)) - { - zArray[i] = zArray[k]; - } - else - { - left = i; - right = ComputeNewRightValue(concatStr, n, left, right); - zArray[i] = right - left; - right--; - } - } + zArray[i] = right - left; + right--; } - - var found = 0; - foreach(var z_value in zArray) + else { - if(z_value == patternLength) + var k = i - left; + if (zArray[k] < (right - i + 1)) { - found++; + zArray[i] = zArray[k]; + } + else + { + left = i; + right = ComputeNewRightValue(concatStr, n, left, right); + zArray[i] = right - left; + right--; } } - - return found; } - private static int ComputeNewRightValue(string concatStr, int n, int left, int right) + var found = 0; + foreach(var z_value in zArray) { - while (right < n && concatStr[right - left].Equals(concatStr[right])) + if(z_value == patternLength) { - right++; + found++; } + } + + return found; + } - return right; + private static int ComputeNewRightValue(string concatStr, int n, int left, int right) + { + while (right < n && concatStr[right - left].Equals(concatStr[right])) + { + right++; } + + return right; } } diff --git a/Algorithms/Strings/Permutation.cs b/Algorithms/Strings/Permutation.cs index 2e4822c3..201d5583 100644 --- a/Algorithms/Strings/Permutation.cs +++ b/Algorithms/Strings/Permutation.cs @@ -1,34 +1,33 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -namespace Algorithms.Strings +namespace Algorithms.Strings; + +public static class Permutation { - public static class Permutation + /// + /// Returns every anagram of a given word. + /// + /// List of anagrams. + public static List GetEveryUniquePermutation(string word) { - /// - /// Returns every anagram of a given word. - /// - /// List of anagrams. - public static List GetEveryUniquePermutation(string word) + if (word.Length < 2) { - if (word.Length < 2) + return new List { - return new List - { - word, - }; - } - - var result = new HashSet(); + word, + }; + } - for (var i = 0; i < word.Length; i++) - { - var temp = GetEveryUniquePermutation(word.Remove(i, 1)); + var result = new HashSet(); - result.UnionWith(temp.Select(subPerm => word[i] + subPerm)); - } + for (var i = 0; i < word.Length; i++) + { + var temp = GetEveryUniquePermutation(word.Remove(i, 1)); - return result.ToList(); + result.UnionWith(temp.Select(subPerm => word[i] + subPerm)); } + + return result.ToList(); } } diff --git a/Algorithms/Strings/Similarity/HammingDistance.cs b/Algorithms/Strings/Similarity/HammingDistance.cs index f1d22ce1..9b061e6a 100644 --- a/Algorithms/Strings/Similarity/HammingDistance.cs +++ b/Algorithms/Strings/Similarity/HammingDistance.cs @@ -1,38 +1,37 @@ using System; -namespace Algorithms.Strings.Similarity +namespace Algorithms.Strings.Similarity; + +/// +/// +/// Hamming distance between two strings of equal length is the number of positions at which the corresponding symbols are different. +/// Time complexity is O(n) where n is the length of the string. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Hamming_distance. +/// +/// +public static class HammingDistance { /// - /// - /// Hamming distance between two strings of equal length is the number of positions at which the corresponding symbols are different. - /// Time complexity is O(n) where n is the length of the string. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Hamming_distance. - /// + /// Calculates Hamming distance between two strings of equal length. /// - public static class HammingDistance + /// First string. + /// Second string. + /// Levenshtein distance between source and target strings. + public static int Calculate(string s1, string s2) { - /// - /// Calculates Hamming distance between two strings of equal length. - /// - /// First string. - /// Second string. - /// Levenshtein distance between source and target strings. - public static int Calculate(string s1, string s2) + if(s1.Length != s2.Length) { - if(s1.Length != s2.Length) - { - throw new ArgumentException("Strings must be equal length."); - } - - var distance = 0; - for (var i = 0; i < s1.Length; i++) - { - distance += s1[i] != s2[i] ? 1 : 0; - } + throw new ArgumentException("Strings must be equal length."); + } - return distance; + var distance = 0; + for (var i = 0; i < s1.Length; i++) + { + distance += s1[i] != s2[i] ? 1 : 0; } + + return distance; } } diff --git a/Algorithms/Strings/Similarity/JaroSimilarity.cs b/Algorithms/Strings/Similarity/JaroSimilarity.cs index 95a69af9..35741b66 100644 --- a/Algorithms/Strings/Similarity/JaroSimilarity.cs +++ b/Algorithms/Strings/Similarity/JaroSimilarity.cs @@ -1,97 +1,96 @@ using System; -namespace Algorithms.Strings.Similarity +namespace Algorithms.Strings.Similarity; + +/// +/// +/// Jaro Similarity measures how similar two strings are. +/// Result is between 0 and 1 where 0 represnts that there is no similarity between strings and 1 represents equal strings. +/// Time complexity is O(a*b) where a is the length of the first string and b is the length of the second string. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance#Jaro_similarity. +/// +/// +public static class JaroSimilarity { /// - /// - /// Jaro Similarity measures how similar two strings are. - /// Result is between 0 and 1 where 0 represnts that there is no similarity between strings and 1 represents equal strings. - /// Time complexity is O(a*b) where a is the length of the first string and b is the length of the second string. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance#Jaro_similarity. - /// + /// Calculates Jaro Similarity between two strings. /// - public static class JaroSimilarity + /// First string. + /// Second string. + public static double Calculate(string s1, string s2) { - /// - /// Calculates Jaro Similarity between two strings. - /// - /// First string. - /// Second string. - public static double Calculate(string s1, string s2) + if (s1 == s2) { - if (s1 == s2) - { - return 1; - } + return 1; + } - var longerString = s1.Length > s2.Length ? s1 : s2; - var shorterString = s1.Length < s2.Length ? s1 : s2; + var longerString = s1.Length > s2.Length ? s1 : s2; + var shorterString = s1.Length < s2.Length ? s1 : s2; - // will look for matching characters in this range - var matchingCharacterRange = Math.Max((longerString.Length / 2) - 1, 0); - var matches = 0d; + // will look for matching characters in this range + var matchingCharacterRange = Math.Max((longerString.Length / 2) - 1, 0); + var matches = 0d; - // true if i-th index of s1 was matched in s2 - var s1MatchedIndeces = new bool[s1.Length]; + // true if i-th index of s1 was matched in s2 + var s1MatchedIndeces = new bool[s1.Length]; - // true if i-th index of s2 was matched in s1 - var s2MatchedIndeces = new bool[s2.Length]; + // true if i-th index of s2 was matched in s1 + var s2MatchedIndeces = new bool[s2.Length]; - for (var i = 0; i < longerString.Length; i++) + for (var i = 0; i < longerString.Length; i++) + { + var startIndex = Math.Max(i - matchingCharacterRange, 0); + var endIndex = Math.Min(i + matchingCharacterRange, shorterString.Length - 1); + for (var j = startIndex; j <= endIndex; j++) { - var startIndex = Math.Max(i - matchingCharacterRange, 0); - var endIndex = Math.Min(i + matchingCharacterRange, shorterString.Length - 1); - for (var j = startIndex; j <= endIndex; j++) + if (s1[i] == s2[j] && !s2MatchedIndeces[j]) { - if (s1[i] == s2[j] && !s2MatchedIndeces[j]) - { - matches++; - s1MatchedIndeces[i] = true; - s2MatchedIndeces[j] = true; - break; - } + matches++; + s1MatchedIndeces[i] = true; + s2MatchedIndeces[j] = true; + break; } } + } - if (matches == 0) - { - return 0; - } + if (matches == 0) + { + return 0; + } - var transpositions = CalculateTranspositions(s1, s2, s1MatchedIndeces, s2MatchedIndeces); + var transpositions = CalculateTranspositions(s1, s2, s1MatchedIndeces, s2MatchedIndeces); - return ((matches / s1.Length) + (matches / s2.Length) + ((matches - transpositions) / matches)) / 3; - } + return ((matches / s1.Length) + (matches / s2.Length) + ((matches - transpositions) / matches)) / 3; + } - /// - /// Calculates number of matched characters that are not in the right order. - /// - private static int CalculateTranspositions(string s1, string s2, bool[] s1MatchedIndeces, bool[] s2MatchedIndeces) + /// + /// Calculates number of matched characters that are not in the right order. + /// + private static int CalculateTranspositions(string s1, string s2, bool[] s1MatchedIndeces, bool[] s2MatchedIndeces) + { + var transpositions = 0; + var s2Index = 0; + for (var s1Index = 0; s1Index < s1.Length; s1Index++) { - var transpositions = 0; - var s2Index = 0; - for (var s1Index = 0; s1Index < s1.Length; s1Index++) + if (s1MatchedIndeces[s1Index]) { - if (s1MatchedIndeces[s1Index]) + while (!s2MatchedIndeces[s2Index]) { - while (!s2MatchedIndeces[s2Index]) - { - s2Index++; - } - - if (s1[s1Index] != s2[s2Index]) - { - transpositions++; - } - s2Index++; } - } - transpositions /= 2; - return transpositions; + if (s1[s1Index] != s2[s2Index]) + { + transpositions++; + } + + s2Index++; + } } + + transpositions /= 2; + return transpositions; } } diff --git a/Algorithms/Strings/Similarity/JaroWinklerDistance.cs b/Algorithms/Strings/Similarity/JaroWinklerDistance.cs index 488ea381..481f5ba9 100644 --- a/Algorithms/Strings/Similarity/JaroWinklerDistance.cs +++ b/Algorithms/Strings/Similarity/JaroWinklerDistance.cs @@ -1,33 +1,32 @@ using System.Linq; -namespace Algorithms.Strings.Similarity +namespace Algorithms.Strings.Similarity; + +/// +/// +/// Jaro–Winkler distance is a string metric measuring an edit distance between two sequences. +/// The score is normalized such that 1 means an exact match and 0 means there is no similarity. +/// Time complexity is O(a*b) where a is the length of the first string and b is the length of the second string. +/// +/// +/// Wikipedia: https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance. +/// +/// +public static class JaroWinklerDistance { /// - /// - /// Jaro–Winkler distance is a string metric measuring an edit distance between two sequences. - /// The score is normalized such that 1 means an exact match and 0 means there is no similarity. - /// Time complexity is O(a*b) where a is the length of the first string and b is the length of the second string. - /// - /// - /// Wikipedia: https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance. - /// + /// Calculates Jaro–Winkler distance. /// - public static class JaroWinklerDistance + /// First string. + /// Second string. + /// Scaling factor for how much the score is adjusted upwards for having common prefixes. Default is 0.1. + /// Distance between two strings. + public static double Calculate(string s1, string s2, double scalingFactor = 0.1) { - /// - /// Calculates Jaro–Winkler distance. - /// - /// First string. - /// Second string. - /// Scaling factor for how much the score is adjusted upwards for having common prefixes. Default is 0.1. - /// Distance between two strings. - public static double Calculate(string s1, string s2, double scalingFactor = 0.1) - { - var jaroSimilarity = JaroSimilarity.Calculate(s1, s2); - var commonPrefixLength = s1.Zip(s2).Take(4).TakeWhile(x => x.First == x.Second).Count(); - var jaroWinklerSimilarity = jaroSimilarity + commonPrefixLength * scalingFactor * (1 - jaroSimilarity); + var jaroSimilarity = JaroSimilarity.Calculate(s1, s2); + var commonPrefixLength = s1.Zip(s2).Take(4).TakeWhile(x => x.First == x.Second).Count(); + var jaroWinklerSimilarity = jaroSimilarity + commonPrefixLength * scalingFactor * (1 - jaroSimilarity); - return 1 - jaroWinklerSimilarity; - } + return 1 - jaroWinklerSimilarity; } } From 789b6e60873dd66154d78b4493b5ac6379fa1949 Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Mon, 8 Jan 2024 14:18:50 +0000 Subject: [PATCH 086/138] Switch to file-scoped namespaces (#434) --- DataStructures/AATree/AATree.cs | 615 ++++---- DataStructures/AATree/AATreeNode.cs | 61 +- DataStructures/AVLTree/AVLTree.cs | 655 ++++---- DataStructures/AVLTree/AVLTreeNode.cs | 115 +- .../BinarySearchTree/BinarySearchTree.cs | 657 ++++---- .../BinarySearchTree/BinarySearchTreeNode.cs | 47 +- DataStructures/BitArray.cs | 1133 +++++++------ DataStructures/Cache/LfuCache.cs | 247 ++- DataStructures/Cache/LruCache.cs | 181 ++- DataStructures/DisjointSet/DisjointSet.cs | 95 +- DataStructures/DisjointSet/Node.cs | 29 +- DataStructures/Fenwick/BinaryIndexedTree.cs | 98 +- DataStructures/Graph/DirectedWeightedGraph.cs | 307 ++-- .../Graph/IDirectedWeightedGraph.cs | 25 +- DataStructures/Graph/Vertex.cs | 97 +- DataStructures/Hashing/Entry.cs | 35 +- DataStructures/Hashing/HashTable.cs | 523 +++--- .../Hashing/NumberTheory/PrimeNumber.cs | 107 +- DataStructures/Heap/BinaryHeap.cs | 389 +++-- .../Heap/FibonacciHeap/FHeapNode.cs | 223 ++- .../Heap/FibonacciHeap/FibonacciHeap.cs | 743 +++++---- DataStructures/Heap/MinMaxHeap.cs | 569 ++++--- .../Heap/PairingHeap/PairingHeap.cs | 365 +++-- .../Heap/PairingHeap/PairingHeapNode.cs | 31 +- .../Heap/PairingHeap/PairingNodeComparer.cs | 49 +- DataStructures/Heap/PairingHeap/Sorting.cs | 23 +- DataStructures/InvertedIndex.cs | 125 +- .../DoublyLinkedList/DoublyLinkedList.cs | 521 +++--- .../DoublyLinkedList/DoublyLinkedListNode.cs | 45 +- .../SinglyLinkedList/SinglyLinkedList.cs | 235 ++- .../SinglyLinkedList/SinglyLinkedListNode.cs | 19 +- .../LinkedList/SkipList/SkipList.cs | 349 ++-- .../LinkedList/SkipList/SkipListNode.cs | 30 +- DataStructures/Probabilistic/BloomFilter.cs | 137 +- .../Probabilistic/CountMinSketch.cs | 121 +- DataStructures/Probabilistic/HyperLogLog.cs | 111 +- DataStructures/Queue/ArrayBasedQueue.cs | 169 +- DataStructures/Queue/ListBasedQueue.cs | 113 +- DataStructures/Queue/StackBasedQueue.cs | 141 +- DataStructures/RedBlackTree/RedBlackTree.cs | 1401 ++++++++--------- .../RedBlackTree/RedBlackTreeNode.cs | 103 +- DataStructures/ScapegoatTree/Extensions.cs | 81 +- DataStructures/ScapegoatTree/Node.cs | 133 +- DataStructures/ScapegoatTree/ScapegoatTree.cs | 565 ++++--- DataStructures/SegmentTrees/SegmentTree.cs | 165 +- .../SegmentTrees/SegmentTreeApply.cs | 173 +- .../SegmentTrees/SegmentTreeUpdate.cs | 75 +- DataStructures/SortedList.cs | 215 ++- DataStructures/Stack/ArrayBasedStack.cs | 204 ++- DataStructures/Stack/ListBasedStack.cs | 145 +- DataStructures/Stack/QueueBasedStack.cs | 105 +- DataStructures/Timeline.cs | 941 ++++++----- DataStructures/Tries/Trie.cs | 191 ++- DataStructures/Tries/TrieNode.cs | 107 +- .../UnrolledList/UnrolledLinkedList.cs | 125 +- .../UnrolledList/UnrolledLinkedListNode.cs | 83 +- 56 files changed, 7140 insertions(+), 7207 deletions(-) diff --git a/DataStructures/AATree/AATree.cs b/DataStructures/AATree/AATree.cs index e8579821..f4322cbf 100644 --- a/DataStructures/AATree/AATree.cs +++ b/DataStructures/AATree/AATree.cs @@ -1,393 +1,392 @@ -using System; +using System; using System.Collections.Generic; -namespace DataStructures.AATree +namespace DataStructures.AATree; + +/// +/// A simple self-balancing binary search tree. +/// +/// +/// AA Trees are a form of self-balancing binary search tree named after their inventor +/// Arne Anderson. AA Trees are designed to be simple to understand and implement. +/// This is accomplished by limiting how nodes can be added to the tree. +/// This simplifies rebalancing operations. +/// More information: https://en.wikipedia.org/wiki/AA_tree . +/// +/// The type of key for the AA tree. +public class AaTree { /// - /// A simple self-balancing binary search tree. + /// The comparer function to use to compare the keys. /// - /// - /// AA Trees are a form of self-balancing binary search tree named after their inventor - /// Arne Anderson. AA Trees are designed to be simple to understand and implement. - /// This is accomplished by limiting how nodes can be added to the tree. - /// This simplifies rebalancing operations. - /// More information: https://en.wikipedia.org/wiki/AA_tree . - /// - /// The type of key for the AA tree. - public class AaTree + private readonly Comparer comparer; + + /// + /// Initializes a new instance of the class. + /// + public AaTree() + : this(Comparer.Default) { - /// - /// The comparer function to use to compare the keys. - /// - private readonly Comparer comparer; - - /// - /// Initializes a new instance of the class. - /// - public AaTree() - : this(Comparer.Default) - { - } + } + + /// + /// Initializes a new instance of the class with a custom comparer. + /// + /// The custom comparer to use to compare keys. + public AaTree(Comparer customComparer) => comparer = customComparer; + + /// + /// Gets the root of the tree. + /// + public AaTreeNode? Root { get; private set; } + + /// + /// Gets the number of elements in the tree. + /// + public int Count { get; private set; } + + /// + /// Add a single element to the tree. + /// + /// The element to add to the tree. + public void Add(TKey key) + { + Root = Add(key, Root); + Count++; + } - /// - /// Initializes a new instance of the class with a custom comparer. - /// - /// The custom comparer to use to compare keys. - public AaTree(Comparer customComparer) => comparer = customComparer; - - /// - /// Gets the root of the tree. - /// - public AaTreeNode? Root { get; private set; } - - /// - /// Gets the number of elements in the tree. - /// - public int Count { get; private set; } - - /// - /// Add a single element to the tree. - /// - /// The element to add to the tree. - public void Add(TKey key) + /// + /// Add multiple elements to the tree. + /// + /// The elements to add to the tree. + public void AddRange(IEnumerable keys) + { + foreach (var key in keys) { Root = Add(key, Root); Count++; } + } - /// - /// Add multiple elements to the tree. - /// - /// The elements to add to the tree. - public void AddRange(IEnumerable keys) + /// + /// Remove a single element from the tree. + /// + /// Element to remove. + public void Remove(TKey key) + { + if (!Contains(key, Root)) { - foreach (var key in keys) - { - Root = Add(key, Root); - Count++; - } + throw new InvalidOperationException($"{nameof(key)} is not in the tree"); } - /// - /// Remove a single element from the tree. - /// - /// Element to remove. - public void Remove(TKey key) + Root = Remove(key, Root); + Count--; + } + + /// + /// Checks if the specified element is in the tree. + /// + /// The element to look for. + /// true if the element is in the tree, false otherwise. + public bool Contains(TKey key) => Contains(key, Root); + + /// + /// Gets the largest element in the tree. (ie. the element in the right most node). + /// + /// The largest element in the tree according to the stored comparer. + /// Thrown if the tree is empty. + public TKey GetMax() + { + if (Root is null) { - if (!Contains(key, Root)) - { - throw new InvalidOperationException($"{nameof(key)} is not in the tree"); - } + throw new InvalidOperationException("Tree is empty!"); + } - Root = Remove(key, Root); - Count--; + return GetMax(Root).Key; + } + + /// + /// Gets the smallest element in the tree. (ie. the element in the left most node). + /// + /// The smallest element in the tree according to the stored comparer. + /// InvalidOperationException if the tree is empty. + public TKey GetMin() + { + if (Root is null) + { + throw new InvalidOperationException("Tree is empty!"); } - /// - /// Checks if the specified element is in the tree. - /// - /// The element to look for. - /// true if the element is in the tree, false otherwise. - public bool Contains(TKey key) => Contains(key, Root); - - /// - /// Gets the largest element in the tree. (ie. the element in the right most node). - /// - /// The largest element in the tree according to the stored comparer. - /// Thrown if the tree is empty. - public TKey GetMax() + return GetMin(Root).Key; + } + + /// + /// Gets all the elements in the tree in in-order order. + /// + /// Sequence of elements in in-order order. + public IEnumerable GetKeysInOrder() + { + var result = new List(); + InOrderWalk(Root); + return result; + + void InOrderWalk(AaTreeNode? node) { - if (Root is null) + if (node is null) { - throw new InvalidOperationException("Tree is empty!"); + return; } - return GetMax(Root).Key; + InOrderWalk(node.Left); + result.Add(node.Key); + InOrderWalk(node.Right); } + } + + /// + /// Gets all the elements in the tree in pre-order order. + /// + /// Sequence of elements in pre-order order. + public IEnumerable GetKeysPreOrder() + { + var result = new List(); + PreOrderWalk(Root); + return result; - /// - /// Gets the smallest element in the tree. (ie. the element in the left most node). - /// - /// The smallest element in the tree according to the stored comparer. - /// InvalidOperationException if the tree is empty. - public TKey GetMin() + void PreOrderWalk(AaTreeNode? node) { - if (Root is null) + if (node is null) { - throw new InvalidOperationException("Tree is empty!"); + return; } - return GetMin(Root).Key; + result.Add(node.Key); + PreOrderWalk(node.Left); + PreOrderWalk(node.Right); } + } - /// - /// Gets all the elements in the tree in in-order order. - /// - /// Sequence of elements in in-order order. - public IEnumerable GetKeysInOrder() - { - var result = new List(); - InOrderWalk(Root); - return result; + /// + /// Gets all the elements in the tree in post-order order. + /// + /// Sequence of elements in post-order order. + public IEnumerable GetKeysPostOrder() + { + var result = new List(); + PostOrderWalk(Root); + return result; - void InOrderWalk(AaTreeNode? node) + void PostOrderWalk(AaTreeNode? node) + { + if (node is null) { - if (node is null) - { - return; - } - - InOrderWalk(node.Left); - result.Add(node.Key); - InOrderWalk(node.Right); + return; } + + PostOrderWalk(node.Left); + PostOrderWalk(node.Right); + result.Add(node.Key); } + } - /// - /// Gets all the elements in the tree in pre-order order. - /// - /// Sequence of elements in pre-order order. - public IEnumerable GetKeysPreOrder() + /// + /// Recursive function to add an element to the tree. + /// + /// The element to add. + /// The node to search for a empty spot. + /// The node with the added element. + /// Thrown if key is already in the tree. + private AaTreeNode Add(TKey key, AaTreeNode? node) + { + if (node is null) { - var result = new List(); - PreOrderWalk(Root); - return result; - - void PreOrderWalk(AaTreeNode? node) - { - if (node is null) - { - return; - } - - result.Add(node.Key); - PreOrderWalk(node.Left); - PreOrderWalk(node.Right); - } + return new AaTreeNode(key, 1); } - /// - /// Gets all the elements in the tree in post-order order. - /// - /// Sequence of elements in post-order order. - public IEnumerable GetKeysPostOrder() + if (comparer.Compare(key, node.Key) < 0) { - var result = new List(); - PostOrderWalk(Root); - return result; - - void PostOrderWalk(AaTreeNode? node) - { - if (node is null) - { - return; - } - - PostOrderWalk(node.Left); - PostOrderWalk(node.Right); - result.Add(node.Key); - } + node.Left = Add(key, node.Left); } - - /// - /// Recursive function to add an element to the tree. - /// - /// The element to add. - /// The node to search for a empty spot. - /// The node with the added element. - /// Thrown if key is already in the tree. - private AaTreeNode Add(TKey key, AaTreeNode? node) + else if (comparer.Compare(key, node.Key) > 0) { - if (node is null) - { - return new AaTreeNode(key, 1); - } + node.Right = Add(key, node.Right); + } + else + { + throw new ArgumentException($"Key \"{key}\" already in tree!", nameof(key)); + } - if (comparer.Compare(key, node.Key) < 0) - { - node.Left = Add(key, node.Left); - } - else if (comparer.Compare(key, node.Key) > 0) - { - node.Right = Add(key, node.Right); - } - else - { - throw new ArgumentException($"Key \"{key}\" already in tree!", nameof(key)); - } + return Split(Skew(node)) !; + } - return Split(Skew(node)) !; + /// + /// Recursive function to remove an element from the tree. + /// + /// The element to remove. + /// The node to search from. + /// The node with the specified element removed. + private AaTreeNode? Remove(TKey key, AaTreeNode? node) + { + if (node is null) + { + return null; } - /// - /// Recursive function to remove an element from the tree. - /// - /// The element to remove. - /// The node to search from. - /// The node with the specified element removed. - private AaTreeNode? Remove(TKey key, AaTreeNode? node) + if (comparer.Compare(key, node.Key) < 0) { - if (node is null) + node.Left = Remove(key, node.Left); + } + else if (comparer.Compare(key, node.Key) > 0) + { + node.Right = Remove(key, node.Right); + } + else + { + if (node.Left is null && node.Right is null) { return null; } - if (comparer.Compare(key, node.Key) < 0) + if (node.Left is null) { - node.Left = Remove(key, node.Left); - } - else if (comparer.Compare(key, node.Key) > 0) - { - node.Right = Remove(key, node.Right); + var successor = GetMin(node.Right!); + node.Right = Remove(successor.Key, node.Right); + node.Key = successor.Key; } else { - if (node.Left is null && node.Right is null) - { - return null; - } - - if (node.Left is null) - { - var successor = GetMin(node.Right!); - node.Right = Remove(successor.Key, node.Right); - node.Key = successor.Key; - } - else - { - var predecessor = GetMax(node.Left); - node.Left = Remove(predecessor.Key, node.Left); - node.Key = predecessor.Key; - } - } - - node = DecreaseLevel(node); - node = Skew(node); - node!.Right = Skew(node.Right); - - if (node.Right is not null) - { - node.Right.Right = Skew(node.Right.Right); + var predecessor = GetMax(node.Left); + node.Left = Remove(predecessor.Key, node.Left); + node.Key = predecessor.Key; } - - node = Split(node); - node!.Right = Split(node.Right); - return node; } - /// - /// Recursive function to check if the element exists in the tree. - /// - /// The element to check for. - /// The node to search from. - /// true if the element exists in the tree, false otherwise. - private bool Contains(TKey key, AaTreeNode? node) => - node is { } - && comparer.Compare(key, node.Key) is { } v - && v switch - { - { } when v > 0 => Contains(key, node.Right), - { } when v < 0 => Contains(key, node.Left), - _ => true, - }; - - /// - /// Recursive to find the maximum/right-most element. - /// - /// The node to traverse from. - /// The node with the maximum/right-most element. - private AaTreeNode GetMax(AaTreeNode node) - { - while (true) - { - if (node.Right is null) - { - return node; - } + node = DecreaseLevel(node); + node = Skew(node); + node!.Right = Skew(node.Right); - node = node.Right; - } + if (node.Right is not null) + { + node.Right.Right = Skew(node.Right.Right); } - /// - /// Recursive to find the minimum/left-most element. - /// - /// The node to traverse from. - /// The node with the minimum/left-most element. - private AaTreeNode GetMin(AaTreeNode node) - { - while (true) - { - if (node.Left is null) - { - return node; - } + node = Split(node); + node!.Right = Split(node.Right); + return node; + } - node = node.Left; - } - } + /// + /// Recursive function to check if the element exists in the tree. + /// + /// The element to check for. + /// The node to search from. + /// true if the element exists in the tree, false otherwise. + private bool Contains(TKey key, AaTreeNode? node) => + node is { } + && comparer.Compare(key, node.Key) is { } v + && v switch + { + { } when v > 0 => Contains(key, node.Right), + { } when v < 0 => Contains(key, node.Left), + _ => true, + }; - /// - /// Remove right-horizontal links and replaces them with left-horizontal links. - /// Accomplishes this by performing a right rotation. - /// - /// The node to rebalance from. - /// The rebalanced node. - private AaTreeNode? Skew(AaTreeNode? node) + /// + /// Recursive to find the maximum/right-most element. + /// + /// The node to traverse from. + /// The node with the maximum/right-most element. + private AaTreeNode GetMax(AaTreeNode node) + { + while (true) { - if (node?.Left is null || node.Left.Level != node.Level) + if (node.Right is null) { return node; } - var left = node.Left; - node.Left = left.Right; - left.Right = node; - return left; + node = node.Right; } + } - /// - /// Reduces the number of right-horizontal links. - /// Accomplishes this by performing a left rotation, and incrementing level. - /// - /// The node to rebalance from. - /// The rebalanced node. - private AaTreeNode? Split(AaTreeNode? node) + /// + /// Recursive to find the minimum/left-most element. + /// + /// The node to traverse from. + /// The node with the minimum/left-most element. + private AaTreeNode GetMin(AaTreeNode node) + { + while (true) { - if (node?.Right?.Right is null || node.Level != node.Right.Right.Level) + if (node.Left is null) { return node; } - var right = node.Right; - node.Right = right.Left; - right.Left = node; - right.Level++; - return right; + node = node.Left; } + } - /// - /// Decreases the level of node if necessary. - /// - /// The node to decrease level from. - /// The node with modified level. - private AaTreeNode DecreaseLevel(AaTreeNode node) + /// + /// Remove right-horizontal links and replaces them with left-horizontal links. + /// Accomplishes this by performing a right rotation. + /// + /// The node to rebalance from. + /// The rebalanced node. + private AaTreeNode? Skew(AaTreeNode? node) + { + if (node?.Left is null || node.Left.Level != node.Level) { - var newLevel = Math.Min(GetLevel(node.Left), GetLevel(node.Right)) + 1; - if (newLevel >= node.Level) - { - return node; - } + return node; + } - node.Level = newLevel; - if (node.Right is { } && newLevel < node.Right.Level) - { - node.Right.Level = newLevel; - } + var left = node.Left; + node.Left = left.Right; + left.Right = node; + return left; + } + /// + /// Reduces the number of right-horizontal links. + /// Accomplishes this by performing a left rotation, and incrementing level. + /// + /// The node to rebalance from. + /// The rebalanced node. + private AaTreeNode? Split(AaTreeNode? node) + { + if (node?.Right?.Right is null || node.Level != node.Right.Right.Level) + { return node; + } - static int GetLevel(AaTreeNode? x) => x?.Level ?? 0; + var right = node.Right; + node.Right = right.Left; + right.Left = node; + right.Level++; + return right; + } + + /// + /// Decreases the level of node if necessary. + /// + /// The node to decrease level from. + /// The node with modified level. + private AaTreeNode DecreaseLevel(AaTreeNode node) + { + var newLevel = Math.Min(GetLevel(node.Left), GetLevel(node.Right)) + 1; + if (newLevel >= node.Level) + { + return node; } + + node.Level = newLevel; + if (node.Right is { } && newLevel < node.Right.Level) + { + node.Right.Level = newLevel; + } + + return node; + + static int GetLevel(AaTreeNode? x) => x?.Level ?? 0; } } diff --git a/DataStructures/AATree/AATreeNode.cs b/DataStructures/AATree/AATreeNode.cs index 96b0829c..03565e67 100644 --- a/DataStructures/AATree/AATreeNode.cs +++ b/DataStructures/AATree/AATreeNode.cs @@ -1,40 +1,39 @@ -namespace DataStructures.AATree +namespace DataStructures.AATree; + +/// +/// Generic node class for AATree. +/// +/// Type of key for node. +public class AaTreeNode { /// - /// Generic node class for AATree. + /// Initializes a new instance of the class. /// - /// Type of key for node. - public class AaTreeNode + /// The initial key of this node. + /// The level of this node. See for more details. + public AaTreeNode(TKey key, int level) { - /// - /// Initializes a new instance of the class. - /// - /// The initial key of this node. - /// The level of this node. See for more details. - public AaTreeNode(TKey key, int level) - { - Key = key; - Level = level; - } + Key = key; + Level = level; + } - /// - /// Gets or Sets key for this node. - /// - public TKey Key { get; set; } + /// + /// Gets or Sets key for this node. + /// + public TKey Key { get; set; } - /// - /// Gets or Sets level for this node. - /// - public int Level { get; set; } + /// + /// Gets or Sets level for this node. + /// + public int Level { get; set; } - /// - /// Gets or sets the left subtree of this node. - /// - public AaTreeNode? Left { get; set; } + /// + /// Gets or sets the left subtree of this node. + /// + public AaTreeNode? Left { get; set; } - /// - /// Gets or sets the right subtree of this node. - /// - public AaTreeNode? Right { get; set; } - } + /// + /// Gets or sets the right subtree of this node. + /// + public AaTreeNode? Right { get; set; } } diff --git a/DataStructures/AVLTree/AVLTree.cs b/DataStructures/AVLTree/AVLTree.cs index 665aa055..8ac665aa 100644 --- a/DataStructures/AVLTree/AVLTree.cs +++ b/DataStructures/AVLTree/AVLTree.cs @@ -1,426 +1,425 @@ using System; using System.Collections.Generic; -namespace DataStructures.AVLTree +namespace DataStructures.AVLTree; + +/// +/// A simple self-balancing binary tree. +/// +/// +/// An AVL tree is a self-balancing binary search tree (BST) named after +/// its inventors: Adelson, Velsky, and Landis. It is the first self- +/// balancing BST invented. The primary property of an AVL tree is that +/// the height of both child subtrees for any node only differ by one. +/// Due to the balanced nature of the tree, its time complexities for +/// insertion, deletion, and search all have a worst-case time +/// complexity of O(log n). Which is an improvement over the worst-case +/// O(n) for a regular BST. +/// See https://en.wikipedia.org/wiki/AVL_tree for more information. +/// Visualizer: https://visualgo.net/en/bst. +/// +/// Type of key for the tree. +public class AvlTree { /// - /// A simple self-balancing binary tree. + /// Gets the number of nodes in the tree. /// - /// - /// An AVL tree is a self-balancing binary search tree (BST) named after - /// its inventors: Adelson, Velsky, and Landis. It is the first self- - /// balancing BST invented. The primary property of an AVL tree is that - /// the height of both child subtrees for any node only differ by one. - /// Due to the balanced nature of the tree, its time complexities for - /// insertion, deletion, and search all have a worst-case time - /// complexity of O(log n). Which is an improvement over the worst-case - /// O(n) for a regular BST. - /// See https://en.wikipedia.org/wiki/AVL_tree for more information. - /// Visualizer: https://visualgo.net/en/bst. - /// - /// Type of key for the tree. - public class AvlTree + public int Count { get; private set; } + + /// + /// Comparer to use when comparing key values. + /// + private readonly Comparer comparer; + + /// + /// Reference to the root node. + /// + private AvlTreeNode? root; + + /// + /// Initializes a new instance of the + /// class. + /// + public AvlTree() + { + comparer = Comparer.Default; + } + + /// + /// Initializes a new instance of the + /// class using the specified comparer. + /// + /// + /// Comparer to use when comparing keys. + /// + public AvlTree(Comparer customComparer) + { + comparer = customComparer; + } + + /// + /// Add a single node to the tree. + /// + /// Key value to add. + public void Add(TKey key) { - /// - /// Gets the number of nodes in the tree. - /// - public int Count { get; private set; } - - /// - /// Comparer to use when comparing key values. - /// - private readonly Comparer comparer; - - /// - /// Reference to the root node. - /// - private AvlTreeNode? root; - - /// - /// Initializes a new instance of the - /// class. - /// - public AvlTree() + if (root is null) { - comparer = Comparer.Default; + root = new AvlTreeNode(key); + } + else + { + root = Add(root, key); } - /// - /// Initializes a new instance of the - /// class using the specified comparer. - /// - /// - /// Comparer to use when comparing keys. - /// - public AvlTree(Comparer customComparer) + Count++; + } + + /// + /// Add multiple nodes to the tree. + /// + /// Key values to add. + public void AddRange(IEnumerable keys) + { + foreach (var key in keys) { - comparer = customComparer; + Add(key); } + } - /// - /// Add a single node to the tree. - /// - /// Key value to add. - public void Add(TKey key) + /// + /// Remove a node from the tree. + /// + /// Key value to remove. + public void Remove(TKey key) + { + root = Remove(root, key); + Count--; + } + + /// + /// Check if given node is in the tree. + /// + /// Key value to search for. + /// Whether or not the node is in the tree. + public bool Contains(TKey key) + { + var node = root; + while (node is not null) { - if (root is null) + var compareResult = comparer.Compare(key, node.Key); + if (compareResult < 0) + { + node = node.Left; + } + else if (compareResult > 0) { - root = new AvlTreeNode(key); + node = node.Right; } else { - root = Add(root, key); + return true; } - - Count++; } - /// - /// Add multiple nodes to the tree. - /// - /// Key values to add. - public void AddRange(IEnumerable keys) + return false; + } + + /// + /// Get the minimum value in the tree. + /// + /// Minimum value in tree. + public TKey GetMin() + { + if (root is null) { - foreach (var key in keys) - { - Add(key); - } + throw new InvalidOperationException("AVL tree is empty."); } - /// - /// Remove a node from the tree. - /// - /// Key value to remove. - public void Remove(TKey key) + return GetMin(root).Key; + } + + /// + /// Get the maximum value in the tree. + /// + /// Maximum value in tree. + public TKey GetMax() + { + if (root is null) { - root = Remove(root, key); - Count--; + throw new InvalidOperationException("AVL tree is empty."); } - /// - /// Check if given node is in the tree. - /// - /// Key value to search for. - /// Whether or not the node is in the tree. - public bool Contains(TKey key) - { - var node = root; - while (node is not null) - { - var compareResult = comparer.Compare(key, node.Key); - if (compareResult < 0) - { - node = node.Left; - } - else if (compareResult > 0) - { - node = node.Right; - } - else - { - return true; - } - } + return GetMax(root).Key; + } - return false; - } + /// + /// Get keys in order from smallest to largest as defined by the + /// comparer. + /// + /// Keys in tree in order from smallest to largest. + public IEnumerable GetKeysInOrder() + { + List result = new(); + InOrderWalk(root); + return result; - /// - /// Get the minimum value in the tree. - /// - /// Minimum value in tree. - public TKey GetMin() + void InOrderWalk(AvlTreeNode? node) { - if (root is null) + if (node is null) { - throw new InvalidOperationException("AVL tree is empty."); + return; } - return GetMin(root).Key; + InOrderWalk(node.Left); + result.Add(node.Key); + InOrderWalk(node.Right); } + } - /// - /// Get the maximum value in the tree. - /// - /// Maximum value in tree. - public TKey GetMax() + /// + /// Get keys in the pre-order order. + /// + /// Keys in pre-order order. + public IEnumerable GetKeysPreOrder() + { + var result = new List(); + PreOrderWalk(root); + return result; + + void PreOrderWalk(AvlTreeNode? node) { - if (root is null) + if (node is null) { - throw new InvalidOperationException("AVL tree is empty."); + return; } - return GetMax(root).Key; + result.Add(node.Key); + PreOrderWalk(node.Left); + PreOrderWalk(node.Right); } + } - /// - /// Get keys in order from smallest to largest as defined by the - /// comparer. - /// - /// Keys in tree in order from smallest to largest. - public IEnumerable GetKeysInOrder() - { - List result = new(); - InOrderWalk(root); - return result; + /// + /// Get keys in the post-order order. + /// + /// Keys in the post-order order. + public IEnumerable GetKeysPostOrder() + { + var result = new List(); + PostOrderWalk(root); + return result; - void InOrderWalk(AvlTreeNode? node) + void PostOrderWalk(AvlTreeNode? node) + { + if (node is null) { - if (node is null) - { - return; - } - - InOrderWalk(node.Left); - result.Add(node.Key); - InOrderWalk(node.Right); + return; } + + PostOrderWalk(node.Left); + PostOrderWalk(node.Right); + result.Add(node.Key); } + } - /// - /// Get keys in the pre-order order. - /// - /// Keys in pre-order order. - public IEnumerable GetKeysPreOrder() + /// + /// Helper function to rebalance the tree so that all nodes have a + /// balance factor in the range [-1, 1]. + /// + /// Node to rebalance. + /// New node that has been rebalanced. + private static AvlTreeNode Rebalance(AvlTreeNode node) + { + if (node.BalanceFactor > 1) { - var result = new List(); - PreOrderWalk(root); - return result; - - void PreOrderWalk(AvlTreeNode? node) + if (node.Right!.BalanceFactor == -1) { - if (node is null) - { - return; - } - - result.Add(node.Key); - PreOrderWalk(node.Left); - PreOrderWalk(node.Right); + node.Right = RotateRight(node.Right); } + + return RotateLeft(node); } - /// - /// Get keys in the post-order order. - /// - /// Keys in the post-order order. - public IEnumerable GetKeysPostOrder() + if (node.BalanceFactor < -1) { - var result = new List(); - PostOrderWalk(root); - return result; - - void PostOrderWalk(AvlTreeNode? node) + if (node.Left!.BalanceFactor == 1) { - if (node is null) - { - return; - } - - PostOrderWalk(node.Left); - PostOrderWalk(node.Right); - result.Add(node.Key); + node.Left = RotateLeft(node.Left); } - } - /// - /// Helper function to rebalance the tree so that all nodes have a - /// balance factor in the range [-1, 1]. - /// - /// Node to rebalance. - /// New node that has been rebalanced. - private static AvlTreeNode Rebalance(AvlTreeNode node) - { - if (node.BalanceFactor > 1) - { - if (node.Right!.BalanceFactor == -1) - { - node.Right = RotateRight(node.Right); - } + return RotateRight(node); + } - return RotateLeft(node); - } + return node; + } - if (node.BalanceFactor < -1) - { - if (node.Left!.BalanceFactor == 1) - { - node.Left = RotateLeft(node.Left); - } + /// + /// Perform a left (counter-clockwise) rotation. + /// + /// Node to rotate about. + /// New node with rotation applied. + private static AvlTreeNode RotateLeft(AvlTreeNode node) + { + var temp1 = node; + var temp2 = node.Right!.Left; + node = node.Right; + node.Left = temp1; + node.Left.Right = temp2; - return RotateRight(node); - } + node.Left.UpdateBalanceFactor(); + node.UpdateBalanceFactor(); - return node; - } + return node; + } - /// - /// Perform a left (counter-clockwise) rotation. - /// - /// Node to rotate about. - /// New node with rotation applied. - private static AvlTreeNode RotateLeft(AvlTreeNode node) - { - var temp1 = node; - var temp2 = node.Right!.Left; - node = node.Right; - node.Left = temp1; - node.Left.Right = temp2; + /// + /// Perform a right (clockwise) rotation. + /// + /// Node to rotate about. + /// New node with rotation applied. + private static AvlTreeNode RotateRight(AvlTreeNode node) + { + var temp1 = node; + var temp2 = node.Left!.Right; + node = node.Left; + node.Right = temp1; + node.Right.Left = temp2; - node.Left.UpdateBalanceFactor(); - node.UpdateBalanceFactor(); + node.Right.UpdateBalanceFactor(); + node.UpdateBalanceFactor(); - return node; - } + return node; + } - /// - /// Perform a right (clockwise) rotation. - /// - /// Node to rotate about. - /// New node with rotation applied. - private static AvlTreeNode RotateRight(AvlTreeNode node) + /// + /// Helper function to get node instance with minimum key value + /// in the specified subtree. + /// + /// Node specifying root of subtree. + /// Minimum value in node's subtree. + private static AvlTreeNode GetMin(AvlTreeNode node) + { + while (node.Left is not null) { - var temp1 = node; - var temp2 = node.Left!.Right; node = node.Left; - node.Right = temp1; - node.Right.Left = temp2; + } - node.Right.UpdateBalanceFactor(); - node.UpdateBalanceFactor(); + return node; + } - return node; + /// + /// Helper function to get node instance with maximum key value + /// in the specified subtree. + /// + /// Node specifying root of subtree. + /// Maximum value in node's subtree. + private static AvlTreeNode GetMax(AvlTreeNode node) + { + while (node.Right is not null) + { + node = node.Right; } - /// - /// Helper function to get node instance with minimum key value - /// in the specified subtree. - /// - /// Node specifying root of subtree. - /// Minimum value in node's subtree. - private static AvlTreeNode GetMin(AvlTreeNode node) + return node; + } + + /// + /// Recursively function to add a node to the tree. + /// + /// Node to check for null leaf. + /// Key value to add. + /// New node with key inserted. + private AvlTreeNode Add(AvlTreeNode node, TKey key) + { + // Regular binary search tree insertion + var compareResult = comparer.Compare(key, node.Key); + if (compareResult < 0) { - while (node.Left is not null) + if (node.Left is null) { - node = node.Left; + var newNode = new AvlTreeNode(key); + node.Left = newNode; } - - return node; - } - - /// - /// Helper function to get node instance with maximum key value - /// in the specified subtree. - /// - /// Node specifying root of subtree. - /// Maximum value in node's subtree. - private static AvlTreeNode GetMax(AvlTreeNode node) - { - while (node.Right is not null) + else { - node = node.Right; + node.Left = Add(node.Left, key); } - - return node; } - - /// - /// Recursively function to add a node to the tree. - /// - /// Node to check for null leaf. - /// Key value to add. - /// New node with key inserted. - private AvlTreeNode Add(AvlTreeNode node, TKey key) + else if (compareResult > 0) { - // Regular binary search tree insertion - var compareResult = comparer.Compare(key, node.Key); - if (compareResult < 0) + if (node.Right is null) { - if (node.Left is null) - { - var newNode = new AvlTreeNode(key); - node.Left = newNode; - } - else - { - node.Left = Add(node.Left, key); - } - } - else if (compareResult > 0) - { - if (node.Right is null) - { - var newNode = new AvlTreeNode(key); - node.Right = newNode; - } - else - { - node.Right = Add(node.Right, key); - } + var newNode = new AvlTreeNode(key); + node.Right = newNode; } else { - throw new ArgumentException( - $"Key \"{key}\" already exists in AVL tree."); + node.Right = Add(node.Right, key); } + } + else + { + throw new ArgumentException( + $"Key \"{key}\" already exists in AVL tree."); + } + + // Check all of the new node's ancestors for inbalance and perform + // necessary rotations + node.UpdateBalanceFactor(); - // Check all of the new node's ancestors for inbalance and perform - // necessary rotations - node.UpdateBalanceFactor(); + return Rebalance(node); + } - return Rebalance(node); + /// + /// Recursive function to remove node from tree. + /// + /// Node to check for key. + /// Key value to remove. + /// New node with key removed. + private AvlTreeNode? Remove(AvlTreeNode? node, TKey key) + { + if (node == null) + { + throw new KeyNotFoundException( + $"Key \"{key}\" is not in the AVL tree."); } - /// - /// Recursive function to remove node from tree. - /// - /// Node to check for key. - /// Key value to remove. - /// New node with key removed. - private AvlTreeNode? Remove(AvlTreeNode? node, TKey key) + // Normal binary search tree removal + var compareResult = comparer.Compare(key, node.Key); + if (compareResult < 0) + { + node.Left = Remove(node.Left, key); + } + else if (compareResult > 0) { - if (node == null) + node.Right = Remove(node.Right, key); + } + else + { + if (node.Left is null && node.Right is null) { - throw new KeyNotFoundException( - $"Key \"{key}\" is not in the AVL tree."); + return null; } - // Normal binary search tree removal - var compareResult = comparer.Compare(key, node.Key); - if (compareResult < 0) + if (node.Left is null) { - node.Left = Remove(node.Left, key); - } - else if (compareResult > 0) - { - node.Right = Remove(node.Right, key); + var successor = GetMin(node.Right!); + node.Right = Remove(node.Right!, successor.Key); + node.Key = successor.Key; } else { - if (node.Left is null && node.Right is null) - { - return null; - } - - if (node.Left is null) - { - var successor = GetMin(node.Right!); - node.Right = Remove(node.Right!, successor.Key); - node.Key = successor.Key; - } - else - { - var predecessor = GetMax(node.Left!); - node.Left = Remove(node.Left!, predecessor.Key); - node.Key = predecessor.Key; - } + var predecessor = GetMax(node.Left!); + node.Left = Remove(node.Left!, predecessor.Key); + node.Key = predecessor.Key; } + } - // Check all of the removed node's ancestors for rebalance and - // perform necessary rotations. - node.UpdateBalanceFactor(); + // Check all of the removed node's ancestors for rebalance and + // perform necessary rotations. + node.UpdateBalanceFactor(); - return Rebalance(node); - } + return Rebalance(node); } } diff --git a/DataStructures/AVLTree/AVLTreeNode.cs b/DataStructures/AVLTree/AVLTreeNode.cs index 49050f83..5f88e8e1 100644 --- a/DataStructures/AVLTree/AVLTreeNode.cs +++ b/DataStructures/AVLTree/AVLTreeNode.cs @@ -1,74 +1,73 @@ using System; -namespace DataStructures.AVLTree +namespace DataStructures.AVLTree; + +/// +/// Generic class to represent nodes in an +/// instance. +/// +/// The type of key for the node. +internal class AvlTreeNode { /// - /// Generic class to represent nodes in an - /// instance. + /// Gets or sets key value of node. /// - /// The type of key for the node. - internal class AvlTreeNode - { - /// - /// Gets or sets key value of node. - /// - public TKey Key { get; set; } + public TKey Key { get; set; } - /// - /// Gets the balance factor of the node. - /// - public int BalanceFactor { get; private set; } + /// + /// Gets the balance factor of the node. + /// + public int BalanceFactor { get; private set; } - /// - /// Gets or sets the left child of the node. - /// - public AvlTreeNode? Left { get; set; } + /// + /// Gets or sets the left child of the node. + /// + public AvlTreeNode? Left { get; set; } - /// - /// Gets or sets the right child of the node. - /// - public AvlTreeNode? Right { get; set; } + /// + /// Gets or sets the right child of the node. + /// + public AvlTreeNode? Right { get; set; } - /// - /// Gets or sets the height of the node. - /// - private int Height { get; set; } + /// + /// Gets or sets the height of the node. + /// + private int Height { get; set; } - /// - /// Initializes a new instance of the - /// class. - /// - /// Key value for node. - public AvlTreeNode(TKey key) + /// + /// Initializes a new instance of the + /// class. + /// + /// Key value for node. + public AvlTreeNode(TKey key) + { + Key = key; + } + + /// + /// Update the node's height and balance factor. + /// + public void UpdateBalanceFactor() + { + if (Left is null && Right is null) { - Key = key; + Height = 0; + BalanceFactor = 0; } - - /// - /// Update the node's height and balance factor. - /// - public void UpdateBalanceFactor() + else if (Left is null) + { + Height = Right!.Height + 1; + BalanceFactor = Height; + } + else if (Right is null) + { + Height = Left!.Height + 1; + BalanceFactor = -Height; + } + else { - if (Left is null && Right is null) - { - Height = 0; - BalanceFactor = 0; - } - else if (Left is null) - { - Height = Right!.Height + 1; - BalanceFactor = Height; - } - else if (Right is null) - { - Height = Left!.Height + 1; - BalanceFactor = -Height; - } - else - { - Height = Math.Max(Left.Height, Right.Height) + 1; - BalanceFactor = Right.Height - Left.Height; - } + Height = Math.Max(Left.Height, Right.Height) + 1; + BalanceFactor = Right.Height - Left.Height; } } } diff --git a/DataStructures/BinarySearchTree/BinarySearchTree.cs b/DataStructures/BinarySearchTree/BinarySearchTree.cs index 70a416a9..96afd6c2 100644 --- a/DataStructures/BinarySearchTree/BinarySearchTree.cs +++ b/DataStructures/BinarySearchTree/BinarySearchTree.cs @@ -1,404 +1,403 @@ -using System; +using System; using System.Collections.Generic; -namespace DataStructures.BinarySearchTree +namespace DataStructures.BinarySearchTree; + +/// +/// An ordered tree with efficient insertion, removal, and lookup. +/// +/// +/// A Binary Search Tree (BST) is a tree that satisfies the following properties: +/// +/// All nodes in the tree contain two children, usually called Left and Right. +/// All nodes in the Left subtree contain keys that are less than the node's key. +/// All nodes in the Right subtree contain keys that are greater than the node's key. +/// +/// A BST will have an average complexity of O(log n) for insertion, removal, and lookup operations. +/// +/// Type of key for the BST. Keys must implement IComparable. +public class BinarySearchTree { /// - /// An ordered tree with efficient insertion, removal, and lookup. + /// Comparer to use when comparing node elements/keys. /// - /// - /// A Binary Search Tree (BST) is a tree that satisfies the following properties: - /// - /// All nodes in the tree contain two children, usually called Left and Right. - /// All nodes in the Left subtree contain keys that are less than the node's key. - /// All nodes in the Right subtree contain keys that are greater than the node's key. - /// - /// A BST will have an average complexity of O(log n) for insertion, removal, and lookup operations. - /// - /// Type of key for the BST. Keys must implement IComparable. - public class BinarySearchTree + private readonly Comparer comparer; + + /// + /// Gets the root of the BST. + /// + public BinarySearchTreeNode? Root { get; private set; } + + public BinarySearchTree() { - /// - /// Comparer to use when comparing node elements/keys. - /// - private readonly Comparer comparer; + Root = null; + Count = 0; + comparer = Comparer.Default; + } - /// - /// Gets the root of the BST. - /// - public BinarySearchTreeNode? Root { get; private set; } + public BinarySearchTree(Comparer customComparer) + { + Root = null; + Count = 0; + comparer = customComparer; + } - public BinarySearchTree() - { - Root = null; - Count = 0; - comparer = Comparer.Default; - } + /// + /// Gets the number nodes currently in the BST. + /// + public int Count { get; private set; } - public BinarySearchTree(Comparer customComparer) + /// + /// Insert a key into the BST. + /// + /// The key to insert. + /// + /// Thrown if key is already in BST. + /// + public void Add(TKey key) + { + if (Root is null) { - Root = null; - Count = 0; - comparer = customComparer; + Root = new BinarySearchTreeNode(key); } - - /// - /// Gets the number nodes currently in the BST. - /// - public int Count { get; private set; } - - /// - /// Insert a key into the BST. - /// - /// The key to insert. - /// - /// Thrown if key is already in BST. - /// - public void Add(TKey key) + else { - if (Root is null) - { - Root = new BinarySearchTreeNode(key); - } - else - { - Add(Root, key); - } - - Count++; + Add(Root, key); } - /// - /// Insert multiple keys into the BST. - /// Keys are inserted in the order they appear in the sequence. - /// - /// Sequence of keys to insert. - public void AddRange(IEnumerable keys) - { - foreach (var key in keys) - { - Add(key); - } - } + Count++; + } - /// - /// Find a node with the specified key. - /// - /// The key to search for. - /// The node with the specified key if it exists, otherwise a default value is returned. - public BinarySearchTreeNode? Search(TKey key) => Search(Root, key); - - /// - /// Checks if the specified key is in the BST. - /// - /// The key to search for. - /// true if the key is in the BST, false otherwise. - public bool Contains(TKey key) => Search(Root, key) is not null; - - /// - /// Removes a node with a key that matches . - /// - /// The key to search for. - /// true if the removal was successful, false otherwise. - public bool Remove(TKey key) + /// + /// Insert multiple keys into the BST. + /// Keys are inserted in the order they appear in the sequence. + /// + /// Sequence of keys to insert. + public void AddRange(IEnumerable keys) + { + foreach (var key in keys) { - if (Root is null) - { - return false; - } + Add(key); + } + } - var result = Remove(Root, Root, key); - if (result) - { - Count--; - } + /// + /// Find a node with the specified key. + /// + /// The key to search for. + /// The node with the specified key if it exists, otherwise a default value is returned. + public BinarySearchTreeNode? Search(TKey key) => Search(Root, key); - return result; - } + /// + /// Checks if the specified key is in the BST. + /// + /// The key to search for. + /// true if the key is in the BST, false otherwise. + public bool Contains(TKey key) => Search(Root, key) is not null; - /// - /// Returns a node with the smallest key. - /// - /// The node if possible, a default value otherwise. - public BinarySearchTreeNode? GetMin() + /// + /// Removes a node with a key that matches . + /// + /// The key to search for. + /// true if the removal was successful, false otherwise. + public bool Remove(TKey key) + { + if (Root is null) { - if (Root is null) - { - return default; - } - - return GetMin(Root); + return false; } - /// - /// Returns a node with the largest key. - /// - /// The node if possible, a default value otherwise. - public BinarySearchTreeNode? GetMax() + var result = Remove(Root, Root, key); + if (result) { - if (Root is null) - { - return default; - } - - return GetMax(Root); + Count--; } - /// - /// Returns all the keys in the BST, sorted In-Order. - /// - /// A list of keys in the BST. - public ICollection GetKeysInOrder() => GetKeysInOrder(Root); - - /// - /// Returns all the keys in the BST, sorted Pre-Order. - /// - /// A list of keys in the BST. - public ICollection GetKeysPreOrder() => GetKeysPreOrder(Root); - - /// - /// Returns all the keys in the BST, sorted Post-Order. - /// - /// A list of keys in the BST. - public ICollection GetKeysPostOrder() => GetKeysPostOrder(Root); - - /// - /// Recursive method to add a key to the BST. - /// - /// Node to search from. - /// Key to add. - /// - /// Thrown if key is already in the BST. - /// - private void Add(BinarySearchTreeNode node, TKey key) - { - var compareResult = comparer.Compare(node.Key, key); - if (compareResult > 0) - { - if (node.Left is not null) - { - Add(node.Left, key); - } - else - { - var newNode = new BinarySearchTreeNode(key); - node.Left = newNode; - } - } - else if (compareResult < 0) - { - if (node.Right is not null) - { - Add(node.Right, key); - } - else - { - var newNode = new BinarySearchTreeNode(key); - node.Right = newNode; - } - } + return result; + } - // Key is already in tree. - else - { - throw new ArgumentException($"Key \"{key}\" already exists in tree!"); - } + /// + /// Returns a node with the smallest key. + /// + /// The node if possible, a default value otherwise. + public BinarySearchTreeNode? GetMin() + { + if (Root is null) + { + return default; } - /// - /// Removes a node with the specified key from the BST. - /// - /// The parent node of . - /// The node to check/search from. - /// The key to remove. - /// true if the operation was successful, false otherwise. - /// - /// Removing a node from the BST can be split into three cases: - ///

- /// 0. The node to be removed has no children. In this case, the node can just be removed from the tree. - ///

- /// 1. The node to be removed has one child. In this case, the node's child is moved to the node's parent, - /// then the node is removed from the tree. - ///

- /// 2. The node to be removed has two children. In this case, we must find a suitable node among the children - /// subtrees to replace the node. This can be done with either the in-order predecessor or the in-order successor. - /// The in-order predecessor is the largest node in Left subtree, or the largest node that is still smaller then the - /// current node. The in-order successor is the smallest node in the Right subtree, or the smallest node that is - /// still larger than the current node. Either way, once this suitable node is found, remove it from the tree (it - /// should be either a case 1 or 2 node) and replace the node to be removed with this suitable node. - ///

- /// More information: https://en.wikipedia.org/wiki/Binary_search_tree#Deletion . - ///
- private bool Remove(BinarySearchTreeNode? parent, BinarySearchTreeNode? node, TKey key) + return GetMin(Root); + } + + /// + /// Returns a node with the largest key. + /// + /// The node if possible, a default value otherwise. + public BinarySearchTreeNode? GetMax() + { + if (Root is null) { - if (node is null || parent is null) - { - return false; - } + return default; + } - var compareResult = comparer.Compare(node.Key, key); + return GetMax(Root); + } - if (compareResult > 0) - { - return Remove(node, node.Left, key); - } + /// + /// Returns all the keys in the BST, sorted In-Order. + /// + /// A list of keys in the BST. + public ICollection GetKeysInOrder() => GetKeysInOrder(Root); - if (compareResult < 0) - { - return Remove(node, node.Right, key); - } + /// + /// Returns all the keys in the BST, sorted Pre-Order. + /// + /// A list of keys in the BST. + public ICollection GetKeysPreOrder() => GetKeysPreOrder(Root); - BinarySearchTreeNode? replacementNode; + /// + /// Returns all the keys in the BST, sorted Post-Order. + /// + /// A list of keys in the BST. + public ICollection GetKeysPostOrder() => GetKeysPostOrder(Root); - // Case 0: Node has no children. - // Case 1: Node has one child. - if (node.Left is null || node.Right is null) + /// + /// Recursive method to add a key to the BST. + /// + /// Node to search from. + /// Key to add. + /// + /// Thrown if key is already in the BST. + /// + private void Add(BinarySearchTreeNode node, TKey key) + { + var compareResult = comparer.Compare(node.Key, key); + if (compareResult > 0) + { + if (node.Left is not null) { - replacementNode = node.Left ?? node.Right; + Add(node.Left, key); } - - // Case 2: Node has two children. (This implementation uses the in-order predecessor to replace node.) else { - var predecessorNode = GetMax(node.Left); - Remove(Root, Root, predecessorNode.Key); - replacementNode = new BinarySearchTreeNode(predecessorNode.Key) - { - Left = node.Left, - Right = node.Right, - }; - } - - // Replace the relevant node with a replacement found in the previous stages. - // Special case for replacing the root node. - if (node == Root) - { - Root = replacementNode; + var newNode = new BinarySearchTreeNode(key); + node.Left = newNode; } - else if (parent.Left == node) + } + else if (compareResult < 0) + { + if (node.Right is not null) { - parent.Left = replacementNode; + Add(node.Right, key); } else { - parent.Right = replacementNode; + var newNode = new BinarySearchTreeNode(key); + node.Right = newNode; } + } - return true; + // Key is already in tree. + else + { + throw new ArgumentException($"Key \"{key}\" already exists in tree!"); } + } - /// - /// Recursive method to get node with largest key. - /// - /// Node to search from. - /// Node with largest value. - private BinarySearchTreeNode GetMax(BinarySearchTreeNode node) + /// + /// Removes a node with the specified key from the BST. + /// + /// The parent node of . + /// The node to check/search from. + /// The key to remove. + /// true if the operation was successful, false otherwise. + /// + /// Removing a node from the BST can be split into three cases: + ///

+ /// 0. The node to be removed has no children. In this case, the node can just be removed from the tree. + ///

+ /// 1. The node to be removed has one child. In this case, the node's child is moved to the node's parent, + /// then the node is removed from the tree. + ///

+ /// 2. The node to be removed has two children. In this case, we must find a suitable node among the children + /// subtrees to replace the node. This can be done with either the in-order predecessor or the in-order successor. + /// The in-order predecessor is the largest node in Left subtree, or the largest node that is still smaller then the + /// current node. The in-order successor is the smallest node in the Right subtree, or the smallest node that is + /// still larger than the current node. Either way, once this suitable node is found, remove it from the tree (it + /// should be either a case 1 or 2 node) and replace the node to be removed with this suitable node. + ///

+ /// More information: https://en.wikipedia.org/wiki/Binary_search_tree#Deletion . + ///
+ private bool Remove(BinarySearchTreeNode? parent, BinarySearchTreeNode? node, TKey key) + { + if (node is null || parent is null) { - if (node.Right is null) - { - return node; - } + return false; + } + + var compareResult = comparer.Compare(node.Key, key); - return GetMax(node.Right); + if (compareResult > 0) + { + return Remove(node, node.Left, key); } - /// - /// Recursive method to get node with smallest key. - /// - /// Node to search from. - /// Node with smallest value. - private BinarySearchTreeNode GetMin(BinarySearchTreeNode node) + if (compareResult < 0) { - if (node.Left is null) - { - return node; - } + return Remove(node, node.Right, key); + } + + BinarySearchTreeNode? replacementNode; - return GetMin(node.Left); + // Case 0: Node has no children. + // Case 1: Node has one child. + if (node.Left is null || node.Right is null) + { + replacementNode = node.Left ?? node.Right; } - /// - /// Recursive method to get a list with the keys sorted in in-order order. - /// - /// Node to traverse from. - /// List of keys in in-order order. - private IList GetKeysInOrder(BinarySearchTreeNode? node) + // Case 2: Node has two children. (This implementation uses the in-order predecessor to replace node.) + else { - if (node is null) + var predecessorNode = GetMax(node.Left); + Remove(Root, Root, predecessorNode.Key); + replacementNode = new BinarySearchTreeNode(predecessorNode.Key) { - return new List(); - } + Left = node.Left, + Right = node.Right, + }; + } - var result = new List(); - result.AddRange(GetKeysInOrder(node.Left)); - result.Add(node.Key); - result.AddRange(GetKeysInOrder(node.Right)); - return result; + // Replace the relevant node with a replacement found in the previous stages. + // Special case for replacing the root node. + if (node == Root) + { + Root = replacementNode; + } + else if (parent.Left == node) + { + parent.Left = replacementNode; + } + else + { + parent.Right = replacementNode; } - /// - /// Recursive method to get a list with the keys sorted in pre-order order. - /// - /// Node to traverse from. - /// List of keys in pre-order order. - private IList GetKeysPreOrder(BinarySearchTreeNode? node) + return true; + } + + /// + /// Recursive method to get node with largest key. + /// + /// Node to search from. + /// Node with largest value. + private BinarySearchTreeNode GetMax(BinarySearchTreeNode node) + { + if (node.Right is null) { - if (node is null) - { - return new List(); - } + return node; + } + + return GetMax(node.Right); + } - var result = new List(); - result.Add(node.Key); - result.AddRange(GetKeysPreOrder(node.Left)); - result.AddRange(GetKeysPreOrder(node.Right)); - return result; + /// + /// Recursive method to get node with smallest key. + /// + /// Node to search from. + /// Node with smallest value. + private BinarySearchTreeNode GetMin(BinarySearchTreeNode node) + { + if (node.Left is null) + { + return node; } - /// - /// Recursive method to get a list with the keys sorted in post-order order. - /// - /// Node to traverse from. - /// List of keys in post-order order. - private IList GetKeysPostOrder(BinarySearchTreeNode? node) + return GetMin(node.Left); + } + + /// + /// Recursive method to get a list with the keys sorted in in-order order. + /// + /// Node to traverse from. + /// List of keys in in-order order. + private IList GetKeysInOrder(BinarySearchTreeNode? node) + { + if (node is null) { - if (node is null) - { - return new List(); - } + return new List(); + } + + var result = new List(); + result.AddRange(GetKeysInOrder(node.Left)); + result.Add(node.Key); + result.AddRange(GetKeysInOrder(node.Right)); + return result; + } - var result = new List(); - result.AddRange(GetKeysPostOrder(node.Left)); - result.AddRange(GetKeysPostOrder(node.Right)); - result.Add(node.Key); - return result; + /// + /// Recursive method to get a list with the keys sorted in pre-order order. + /// + /// Node to traverse from. + /// List of keys in pre-order order. + private IList GetKeysPreOrder(BinarySearchTreeNode? node) + { + if (node is null) + { + return new List(); } - /// - /// Recursive method to find a node with a matching key. - /// - /// Node to search from. - /// Key to find. - /// The node with the specified if it exists, a default value otherwise. - private BinarySearchTreeNode? Search(BinarySearchTreeNode? node, TKey key) + var result = new List(); + result.Add(node.Key); + result.AddRange(GetKeysPreOrder(node.Left)); + result.AddRange(GetKeysPreOrder(node.Right)); + return result; + } + + /// + /// Recursive method to get a list with the keys sorted in post-order order. + /// + /// Node to traverse from. + /// List of keys in post-order order. + private IList GetKeysPostOrder(BinarySearchTreeNode? node) + { + if (node is null) { - if (node is null) - { - return default; - } + return new List(); + } - var compareResult = comparer.Compare(node.Key, key); - if (compareResult > 0) - { - return Search(node.Left, key); - } + var result = new List(); + result.AddRange(GetKeysPostOrder(node.Left)); + result.AddRange(GetKeysPostOrder(node.Right)); + result.Add(node.Key); + return result; + } - if (compareResult < 0) - { - return Search(node.Right, key); - } + /// + /// Recursive method to find a node with a matching key. + /// + /// Node to search from. + /// Key to find. + /// The node with the specified if it exists, a default value otherwise. + private BinarySearchTreeNode? Search(BinarySearchTreeNode? node, TKey key) + { + if (node is null) + { + return default; + } - return node; + var compareResult = comparer.Compare(node.Key, key); + if (compareResult > 0) + { + return Search(node.Left, key); } + + if (compareResult < 0) + { + return Search(node.Right, key); + } + + return node; } } diff --git a/DataStructures/BinarySearchTree/BinarySearchTreeNode.cs b/DataStructures/BinarySearchTree/BinarySearchTreeNode.cs index 711cc223..865dd3d0 100644 --- a/DataStructures/BinarySearchTree/BinarySearchTreeNode.cs +++ b/DataStructures/BinarySearchTree/BinarySearchTreeNode.cs @@ -1,31 +1,30 @@ -namespace DataStructures.BinarySearchTree +namespace DataStructures.BinarySearchTree; + +/// +/// Generic node class for BinarySearchTree. +/// Keys for each node are immutable. +/// +/// Type of key for the node. Keys must implement IComparable. +public class BinarySearchTreeNode { /// - /// Generic node class for BinarySearchTree. - /// Keys for each node are immutable. + /// Initializes a new instance of the class. /// - /// Type of key for the node. Keys must implement IComparable. - public class BinarySearchTreeNode - { - /// - /// Initializes a new instance of the class. - /// - /// The key of this node. - public BinarySearchTreeNode(TKey key) => Key = key; + /// The key of this node. + public BinarySearchTreeNode(TKey key) => Key = key; - /// - /// Gets the key for this node. - /// - public TKey Key { get; } + /// + /// Gets the key for this node. + /// + public TKey Key { get; } - /// - /// Gets or sets the reference to a child node that precedes/comes before this node. - /// - public BinarySearchTreeNode? Left { get; set; } + /// + /// Gets or sets the reference to a child node that precedes/comes before this node. + /// + public BinarySearchTreeNode? Left { get; set; } - /// - /// Gets or sets the reference to a child node that follows/comes after this node. - /// - public BinarySearchTreeNode? Right { get; set; } - } + /// + /// Gets or sets the reference to a child node that follows/comes after this node. + /// + public BinarySearchTreeNode? Right { get; set; } } diff --git a/DataStructures/BitArray.cs b/DataStructures/BitArray.cs index ac54bc51..6b5baeb2 100644 --- a/DataStructures/BitArray.cs +++ b/DataStructures/BitArray.cs @@ -1,4 +1,4 @@ -// Original Author: Christian Bender +// Original Author: Christian Bender // Class: BitArray // // implements IComparable, ICloneable, IEnumerator, IEnumerable @@ -120,723 +120,722 @@ using System.Linq; using System.Text; -namespace DataStructures +namespace DataStructures; + +/// +/// This class implements a bit-array and provides some +/// useful functions/operations to deal with this type of +/// data structure. +/// +public sealed class BitArray : ICloneable, IEnumerator, IEnumerable { + private readonly bool[] field; // the actual bit-field + private int position = -1; // position for enumerator + /// - /// This class implements a bit-array and provides some - /// useful functions/operations to deal with this type of - /// data structure. + /// Initializes a new instance of the class. + /// setups the array with false-values. /// - public sealed class BitArray : ICloneable, IEnumerator, IEnumerable + /// length of the array. + public BitArray(int n) { - private readonly bool[] field; // the actual bit-field - private int position = -1; // position for enumerator - - /// - /// Initializes a new instance of the class. - /// setups the array with false-values. - /// - /// length of the array. - public BitArray(int n) + if (n < 1) { - if (n < 1) - { - field = new bool[0]; - } - - field = new bool[n]; + field = new bool[0]; } - /// - /// Initializes a new instance of the class. - /// Setups the array with the input sequence. - /// purpose: Setups the array with the input sequence. - /// assumes: sequence must been greater or equal to 1. - /// the sequence may only contain ones or zeros. - /// - /// A string sequence of 0's and 1's. - public BitArray(string sequence) - { - // precondition I - if (sequence.Length <= 0) - { - throw new ArgumentException("Sequence must been greater than or equal to 1"); - } - - // precondition II - ThrowIfSequenceIsInvalid(sequence); + field = new bool[n]; + } - field = new bool[sequence.Length]; - Compile(sequence); + /// + /// Initializes a new instance of the class. + /// Setups the array with the input sequence. + /// purpose: Setups the array with the input sequence. + /// assumes: sequence must been greater or equal to 1. + /// the sequence may only contain ones or zeros. + /// + /// A string sequence of 0's and 1's. + public BitArray(string sequence) + { + // precondition I + if (sequence.Length <= 0) + { + throw new ArgumentException("Sequence must been greater than or equal to 1"); } - /// - /// Initializes a new instance of the class. - /// Setups the bit-array with the input array. - /// - /// A boolean array of bits. - public BitArray(bool[] bits) => field = bits; + // precondition II + ThrowIfSequenceIsInvalid(sequence); - /// - /// Gets the length of the current bit array. - /// - private int Length => field.Length; + field = new bool[sequence.Length]; + Compile(sequence); + } - /// - /// Gets element given an offset. - /// - /// Position. - /// Element on array. - public bool this[int offset] - { - get => field[offset]; - private set => field[offset] = value; - } + /// + /// Initializes a new instance of the class. + /// Setups the bit-array with the input array. + /// + /// A boolean array of bits. + public BitArray(bool[] bits) => field = bits; - /// - /// Returns a copy of the current bit-array. - /// - /// Bit-array clone. - public object Clone() - { - var theClone = new BitArray(Length); + /// + /// Gets the length of the current bit array. + /// + private int Length => field.Length; - for (var i = 0; i < Length; i++) - { - theClone[i] = field[i]; - } + /// + /// Gets element given an offset. + /// + /// Position. + /// Element on array. + public bool this[int offset] + { + get => field[offset]; + private set => field[offset] = value; + } - return theClone; + /// + /// Returns a copy of the current bit-array. + /// + /// Bit-array clone. + public object Clone() + { + var theClone = new BitArray(Length); + + for (var i = 0; i < Length; i++) + { + theClone[i] = field[i]; } - /// - /// Gets a enumerator for this BitArray-Object. - /// - /// Returns a enumerator for this BitArray-Object. - public IEnumerator GetEnumerator() => this; + return theClone; + } - /// - /// Gets a enumerator for this BitArray-Object. - /// - /// Returns a enumerator for this BitArray-Object. - IEnumerator IEnumerable.GetEnumerator() => this; + /// + /// Gets a enumerator for this BitArray-Object. + /// + /// Returns a enumerator for this BitArray-Object. + public IEnumerator GetEnumerator() => this; - /// - /// Gets a value indicating whether the current bit of the array is set. - /// - public bool Current => field[position]; + /// + /// Gets a enumerator for this BitArray-Object. + /// + /// Returns a enumerator for this BitArray-Object. + IEnumerator IEnumerable.GetEnumerator() => this; - /// - /// Gets a value indicating whether the current bit of the array is set. - /// - object IEnumerator.Current => field[position]; + /// + /// Gets a value indicating whether the current bit of the array is set. + /// + public bool Current => field[position]; - /// - /// MoveNext (for interface IEnumerator). - /// - /// Returns True if 'position' successful increased; False otherwise. - public bool MoveNext() - { - if (position + 1 >= field.Length) - { - return false; - } + /// + /// Gets a value indicating whether the current bit of the array is set. + /// + object IEnumerator.Current => field[position]; - position++; - return true; + /// + /// MoveNext (for interface IEnumerator). + /// + /// Returns True if 'position' successful increased; False otherwise. + public bool MoveNext() + { + if (position + 1 >= field.Length) + { + return false; } - /// - /// Resets the position of the enumerator. - /// Reset (for interface IEnumerator). - /// - public void Reset() => position = -1; + position++; + return true; + } - /// - /// Disposes object, nothing to dispose here though. - /// - public void Dispose() - { - // Done - } + /// + /// Resets the position of the enumerator. + /// Reset (for interface IEnumerator). + /// + public void Reset() => position = -1; - /// - /// Returns a bit-array that represents the bit by bit AND (&). - /// Assumes arrays have the same length. - /// - /// First bit-array. - /// Second bit-array. - /// bit-array. - public static BitArray operator &(BitArray one, BitArray two) - { - var sequence1 = one.ToString(); - var sequence2 = two.ToString(); - var result = new StringBuilder(); - var tmp = new StringBuilder(); + /// + /// Disposes object, nothing to dispose here though. + /// + public void Dispose() + { + // Done + } - // for scaling of same length. - if (one.Length != two.Length) - { - int difference; - if (one.Length > two.Length) - { - // one is greater - difference = one.Length - two.Length; + /// + /// Returns a bit-array that represents the bit by bit AND (&). + /// Assumes arrays have the same length. + /// + /// First bit-array. + /// Second bit-array. + /// bit-array. + public static BitArray operator &(BitArray one, BitArray two) + { + var sequence1 = one.ToString(); + var sequence2 = two.ToString(); + var result = new StringBuilder(); + var tmp = new StringBuilder(); - // fills up with 0's - for (var i = 0; i < difference; i++) - { - tmp.Append('0'); - } + // for scaling of same length. + if (one.Length != two.Length) + { + int difference; + if (one.Length > two.Length) + { + // one is greater + difference = one.Length - two.Length; - tmp.Append(two); - sequence2 = tmp.ToString(); - } - else + // fills up with 0's + for (var i = 0; i < difference; i++) { - // two is greater - difference = two.Length - one.Length; + tmp.Append('0'); + } - // fills up with 0's - for (var i = 0; i < difference; i++) - { - tmp.Append('0'); - } + tmp.Append(two); + sequence2 = tmp.ToString(); + } + else + { + // two is greater + difference = two.Length - one.Length; - tmp.Append(one); - sequence1 = tmp.ToString(); + // fills up with 0's + for (var i = 0; i < difference; i++) + { + tmp.Append('0'); } - } // end scaling - - var len = one.Length > two.Length ? one.Length : two.Length; - var ans = new BitArray(len); - for (var i = 0; i < one.Length; i++) - { - result.Append(sequence1[i].Equals('1') && sequence2[i].Equals('1') ? '1' : '0'); + tmp.Append(one); + sequence1 = tmp.ToString(); } + } // end scaling - ans.Compile(result.ToString().Trim()); + var len = one.Length > two.Length ? one.Length : two.Length; + var ans = new BitArray(len); - return ans; + for (var i = 0; i < one.Length; i++) + { + result.Append(sequence1[i].Equals('1') && sequence2[i].Equals('1') ? '1' : '0'); } - /// - /// Returns a bit-array that represents the bit by bit OR. - /// Assumes arrays have the same length. - /// - /// First bit-array. - /// Second bit-array. - /// bit-array that represents the bit by bit OR. - public static BitArray operator |(BitArray one, BitArray two) - { - var sequence1 = one.ToString(); - var sequence2 = two.ToString(); - var result = string.Empty; - var tmp = string.Empty; + ans.Compile(result.ToString().Trim()); - // for scaling of same length. - if (one.Length != two.Length) - { - int difference; - if (one.Length > two.Length) - { - // one is greater - difference = one.Length - two.Length; + return ans; + } - // fills up with 0's - for (var i = 0; i < difference; i++) - { - tmp += '0'; - } + /// + /// Returns a bit-array that represents the bit by bit OR. + /// Assumes arrays have the same length. + /// + /// First bit-array. + /// Second bit-array. + /// bit-array that represents the bit by bit OR. + public static BitArray operator |(BitArray one, BitArray two) + { + var sequence1 = one.ToString(); + var sequence2 = two.ToString(); + var result = string.Empty; + var tmp = string.Empty; - tmp += two.ToString(); - sequence2 = tmp; - } - else + // for scaling of same length. + if (one.Length != two.Length) + { + int difference; + if (one.Length > two.Length) + { + // one is greater + difference = one.Length - two.Length; + + // fills up with 0's + for (var i = 0; i < difference; i++) { - // two is greater - difference = two.Length - one.Length; + tmp += '0'; + } - // fills up with 0's - for (var i = 0; i < difference; i++) - { - tmp += '0'; - } + tmp += two.ToString(); + sequence2 = tmp; + } + else + { + // two is greater + difference = two.Length - one.Length; - tmp += one.ToString(); - sequence1 = tmp; + // fills up with 0's + for (var i = 0; i < difference; i++) + { + tmp += '0'; } - } // end scaling - - var len = one.Length > two.Length ? one.Length : two.Length; - var ans = new BitArray(len); - for (var i = 0; i < len; i++) - { - result += sequence1[i].Equals('0') && sequence2[i].Equals('0') ? '0' : '1'; + tmp += one.ToString(); + sequence1 = tmp; } + } // end scaling - result = result.Trim(); - ans.Compile(result); + var len = one.Length > two.Length ? one.Length : two.Length; + var ans = new BitArray(len); - return ans; + for (var i = 0; i < len; i++) + { + result += sequence1[i].Equals('0') && sequence2[i].Equals('0') ? '0' : '1'; } - /// - /// Returns a bit-array that represents the operator ~ (NOT). - /// Assumes arrays have the same length. - /// - /// Bit-array. - /// bitwise not. - public static BitArray operator ~(BitArray one) - { - var ans = new BitArray(one.Length); - var sequence = one.ToString(); - var result = string.Empty; + result = result.Trim(); + ans.Compile(result); - foreach (var ch in sequence) + return ans; + } + + /// + /// Returns a bit-array that represents the operator ~ (NOT). + /// Assumes arrays have the same length. + /// + /// Bit-array. + /// bitwise not. + public static BitArray operator ~(BitArray one) + { + var ans = new BitArray(one.Length); + var sequence = one.ToString(); + var result = string.Empty; + + foreach (var ch in sequence) + { + if (ch == '1') { - if (ch == '1') - { - result += '0'; - } - else - { - result += '1'; - } + result += '0'; + } + else + { + result += '1'; } + } - result = result.Trim(); - ans.Compile(result); + result = result.Trim(); + ans.Compile(result); - return ans; - } + return ans; + } + + /// + /// Returns a bit-array that represents bitwise shift left (>>). + /// Assumes arrays have the same length. + /// + /// Bit-array. + /// Number of bits. + /// Bitwise shifted BitArray. + public static BitArray operator <<(BitArray other, int n) + { + var ans = new BitArray(other.Length + n); - /// - /// Returns a bit-array that represents bitwise shift left (>>). - /// Assumes arrays have the same length. - /// - /// Bit-array. - /// Number of bits. - /// Bitwise shifted BitArray. - public static BitArray operator <<(BitArray other, int n) + // actual shifting process + for (var i = 0; i < other.Length; i++) { - var ans = new BitArray(other.Length + n); + ans[i] = other[i]; + } - // actual shifting process - for (var i = 0; i < other.Length; i++) - { - ans[i] = other[i]; - } + return ans; + } - return ans; - } + /// + /// Returns a bit-array that represents the bit by bit XOR. + /// Assumes arrays have the same length. + /// + /// First bit-array. + /// Second bit-array. + /// bit-array. + public static BitArray operator ^(BitArray one, BitArray two) + { + var sequence1 = one.ToString(); + var sequence2 = two.ToString(); + var tmp = string.Empty; - /// - /// Returns a bit-array that represents the bit by bit XOR. - /// Assumes arrays have the same length. - /// - /// First bit-array. - /// Second bit-array. - /// bit-array. - public static BitArray operator ^(BitArray one, BitArray two) + // for scaling of same length. + if (one.Length != two.Length) { - var sequence1 = one.ToString(); - var sequence2 = two.ToString(); - var tmp = string.Empty; - - // for scaling of same length. - if (one.Length != two.Length) + int difference; + if (one.Length > two.Length) { - int difference; - if (one.Length > two.Length) + // one is greater + difference = one.Length - two.Length; + + // fills up with 0's + for (var i = 0; i < difference; i++) { - // one is greater - difference = one.Length - two.Length; + tmp += '0'; + } - // fills up with 0's - for (var i = 0; i < difference; i++) - { - tmp += '0'; - } + tmp += two.ToString(); + sequence2 = tmp; + } + else + { + // two is greater + difference = two.Length - one.Length; - tmp += two.ToString(); - sequence2 = tmp; - } - else + // fills up with 0's + for (var i = 0; i < difference; i++) { - // two is greater - difference = two.Length - one.Length; + tmp += '0'; + } - // fills up with 0's - for (var i = 0; i < difference; i++) - { - tmp += '0'; - } + tmp += one.ToString(); + sequence1 = tmp; + } + } // end scaling - tmp += one.ToString(); - sequence1 = tmp; - } - } // end scaling + var len = one.Length > two.Length ? one.Length : two.Length; + var ans = new BitArray(len); - var len = one.Length > two.Length ? one.Length : two.Length; - var ans = new BitArray(len); + var sb = new StringBuilder(); - var sb = new StringBuilder(); + for (var i = 0; i < len; i++) + { + _ = sb.Append(sequence1[i] == sequence2[i] ? '0' : '1'); + } - for (var i = 0; i < len; i++) - { - _ = sb.Append(sequence1[i] == sequence2[i] ? '0' : '1'); - } + var result = sb.ToString().Trim(); + ans.Compile(result); - var result = sb.ToString().Trim(); - ans.Compile(result); + return ans; + } - return ans; - } + /// + /// Returns a bit-array that represents bitwise shift right (>>). + /// Assumes arrays have the same length. + /// + /// Bit-array. + /// Number of bits. + /// Bitwise shifted BitArray. + public static BitArray operator >>(BitArray other, int n) + { + var ans = new BitArray(other.Length - n); - /// - /// Returns a bit-array that represents bitwise shift right (>>). - /// Assumes arrays have the same length. - /// - /// Bit-array. - /// Number of bits. - /// Bitwise shifted BitArray. - public static BitArray operator >>(BitArray other, int n) + // actual shifting process. + for (var i = 0; i < other.Length - n; i++) { - var ans = new BitArray(other.Length - n); + ans[i] = other[i]; + } - // actual shifting process. - for (var i = 0; i < other.Length - n; i++) - { - ans[i] = other[i]; - } + return ans; + } - return ans; + /// + /// Checks if both arrays are == (equal). + /// The input assumes arrays have the same length. + /// + /// First bit-array. + /// Second bit-array. + /// Returns True if there inputs are equal; False otherwise. + public static bool operator ==(BitArray one, BitArray two) + { + if (ReferenceEquals(one, two)) + { + return true; } - /// - /// Checks if both arrays are == (equal). - /// The input assumes arrays have the same length. - /// - /// First bit-array. - /// Second bit-array. - /// Returns True if there inputs are equal; False otherwise. - public static bool operator ==(BitArray one, BitArray two) + if (one.Length != two.Length) { - if (ReferenceEquals(one, two)) - { - return true; - } + return false; + } - if (one.Length != two.Length) + var status = true; + for (var i = 0; i < one.Length; i++) + { + if (one[i] != two[i]) { - return false; + status = false; + break; } + } - var status = true; - for (var i = 0; i < one.Length; i++) - { - if (one[i] != two[i]) - { - status = false; - break; - } - } + return status; + } - return status; + /// + /// Checks if both arrays are != (not-equal). + /// The input assumes arrays have the same length. + /// + /// First bit-array. + /// Second bit-array. + /// Returns True if there inputs aren't equal; False otherwise. + public static bool operator !=(BitArray one, BitArray two) => !(one == two); + + /// + /// Compiles the binary sequence into the inner data structure. + /// The sequence must have the same length, as the bit-array. + /// The sequence may only be allowed contains ones or zeros. + /// + /// A string sequence of 0's and 1's. + public void Compile(string sequence) + { + // precondition I + if (sequence.Length > field.Length) + { + throw new ArgumentException($"{nameof(sequence)} must be not longer than the bit array length"); } - /// - /// Checks if both arrays are != (not-equal). - /// The input assumes arrays have the same length. - /// - /// First bit-array. - /// Second bit-array. - /// Returns True if there inputs aren't equal; False otherwise. - public static bool operator !=(BitArray one, BitArray two) => !(one == two); + // precondition II + ThrowIfSequenceIsInvalid(sequence); - /// - /// Compiles the binary sequence into the inner data structure. - /// The sequence must have the same length, as the bit-array. - /// The sequence may only be allowed contains ones or zeros. - /// - /// A string sequence of 0's and 1's. - public void Compile(string sequence) + // for appropriate scaling + var tmp = string.Empty; + if (sequence.Length < field.Length) { - // precondition I - if (sequence.Length > field.Length) + var difference = field.Length - sequence.Length; + + for (var i = 0; i < difference; i++) { - throw new ArgumentException($"{nameof(sequence)} must be not longer than the bit array length"); + tmp += '0'; } - // precondition II - ThrowIfSequenceIsInvalid(sequence); + tmp += sequence; + sequence = tmp; + } - // for appropriate scaling - var tmp = string.Empty; - if (sequence.Length < field.Length) - { - var difference = field.Length - sequence.Length; + // actual compile procedure. + for (var i = 0; i < sequence.Length; i++) + { + field[i] = sequence[i] == '1'; + } + } - for (var i = 0; i < difference; i++) - { - tmp += '0'; - } + /// + /// Compiles integer number into the inner data structure. + /// Assumes: the number must have the same bit length. + /// + /// A positive integer number. + public void Compile(int number) + { + var tmp = string.Empty; - tmp += sequence; - sequence = tmp; - } + // precondition I + if (number <= 0) + { + throw new ArgumentException($"{nameof(number)} must be positive"); + } - // actual compile procedure. - for (var i = 0; i < sequence.Length; i++) - { - field[i] = sequence[i] == '1'; - } + // converts to binary representation + var binaryNumber = Convert.ToString(number, 2); + + // precondition II + if (binaryNumber.Length > field.Length) + { + throw new ArgumentException("Provided number is too big"); } - /// - /// Compiles integer number into the inner data structure. - /// Assumes: the number must have the same bit length. - /// - /// A positive integer number. - public void Compile(int number) + // for appropriate scaling + if (binaryNumber.Length < field.Length) { - var tmp = string.Empty; + var difference = field.Length - binaryNumber.Length; - // precondition I - if (number <= 0) + for (var i = 0; i < difference; i++) { - throw new ArgumentException($"{nameof(number)} must be positive"); + tmp += '0'; } - // converts to binary representation - var binaryNumber = Convert.ToString(number, 2); + tmp += binaryNumber; + binaryNumber = tmp; + } - // precondition II - if (binaryNumber.Length > field.Length) - { - throw new ArgumentException("Provided number is too big"); - } + // actual compile procedure. + for (var i = 0; i < binaryNumber.Length; i++) + { + field[i] = binaryNumber[i] == '1'; + } + } - // for appropriate scaling - if (binaryNumber.Length < field.Length) - { - var difference = field.Length - binaryNumber.Length; + /// + /// Compiles integer number into the inner data structure. + /// The number must have the same bit length. + /// + /// A positive long integer number. + public void Compile(long number) + { + var tmp = string.Empty; - for (var i = 0; i < difference; i++) - { - tmp += '0'; - } + // precondition I + if (number <= 0) + { + throw new ArgumentException($"{nameof(number)} must be positive"); + } - tmp += binaryNumber; - binaryNumber = tmp; - } + // converts to binary representation + var binaryNumber = Convert.ToString(number, 2); - // actual compile procedure. - for (var i = 0; i < binaryNumber.Length; i++) - { - field[i] = binaryNumber[i] == '1'; - } + // precondition II + if (binaryNumber.Length > field.Length) + { + throw new ArgumentException("Provided number is too big"); } - /// - /// Compiles integer number into the inner data structure. - /// The number must have the same bit length. - /// - /// A positive long integer number. - public void Compile(long number) + // for appropriate scaling + if (binaryNumber.Length < field.Length) { - var tmp = string.Empty; + var difference = field.Length - binaryNumber.Length; - // precondition I - if (number <= 0) + for (var i = 0; i < difference; i++) { - throw new ArgumentException($"{nameof(number)} must be positive"); + tmp += '0'; } - // converts to binary representation - var binaryNumber = Convert.ToString(number, 2); + tmp += binaryNumber; + binaryNumber = tmp; + } - // precondition II - if (binaryNumber.Length > field.Length) - { - throw new ArgumentException("Provided number is too big"); - } + // actual compile procedure. + for (var i = 0; i < binaryNumber.Length; i++) + { + field[i] = binaryNumber[i] == '1'; + } + } - // for appropriate scaling - if (binaryNumber.Length < field.Length) - { - var difference = field.Length - binaryNumber.Length; + /// + /// Is the opposit of the Compile(...) method. + /// + /// Returns a string representation of the inner data structure. + public override string ToString() + { + // creates return-string + return field.Aggregate(string.Empty, (current, t) => current + (t ? "1" : "0")); + } - for (var i = 0; i < difference; i++) - { - tmp += '0'; - } + /// + /// Gets the number of one-bits in the field. + /// + /// quantity of bits in current bit-array. + public int NumberOfOneBits() + { + // counting one-bits. + return field.Count(bit => bit); + } - tmp += binaryNumber; - binaryNumber = tmp; - } + /// + /// Gets the number of zero-bits in the field. + /// + /// quantity of bits. + public int NumberOfZeroBits() + { + // counting zero-bits + return field.Count(bit => !bit); + } - // actual compile procedure. - for (var i = 0; i < binaryNumber.Length; i++) - { - field[i] = binaryNumber[i] == '1'; - } - } + /// + /// To check for even parity. + /// + /// Returns True if parity is even; False otherwise. + public bool EvenParity() => NumberOfOneBits() % 2 == 0; - /// - /// Is the opposit of the Compile(...) method. - /// - /// Returns a string representation of the inner data structure. - public override string ToString() - { - // creates return-string - return field.Aggregate(string.Empty, (current, t) => current + (t ? "1" : "0")); - } + /// + /// To check for odd parity. + /// + /// Returns True if parity is odd; False otherwise. + public bool OddParity() => NumberOfOneBits() % 2 != 0; - /// - /// Gets the number of one-bits in the field. - /// - /// quantity of bits in current bit-array. - public int NumberOfOneBits() + /// + /// Returns a long integer representation of the bit-array. + /// Assumes the bit-array length must been smaller or equal to 64 bit. + /// + /// Long integer array. + public long ToInt64() + { + // Precondition + if (field.Length > 64) { - // counting one-bits. - return field.Count(bit => bit); + throw new InvalidOperationException("Value is too big to fit into Int64"); } - /// - /// Gets the number of zero-bits in the field. - /// - /// quantity of bits. - public int NumberOfZeroBits() + var sequence = ToString(); + return Convert.ToInt64(sequence, 2); + } + + /// + /// Returns a long integer representation of the bit-array. + /// Assumes the bit-array length must been smaller or equal to 32 bit. + /// + /// integer array. + public int ToInt32() + { + // Precondition + if (field.Length > 32) { - // counting zero-bits - return field.Count(bit => !bit); + throw new InvalidOperationException("Value is too big to fit into Int32"); } - /// - /// To check for even parity. - /// - /// Returns True if parity is even; False otherwise. - public bool EvenParity() => NumberOfOneBits() % 2 == 0; - - /// - /// To check for odd parity. - /// - /// Returns True if parity is odd; False otherwise. - public bool OddParity() => NumberOfOneBits() % 2 != 0; + var sequence = ToString(); + return Convert.ToInt32(sequence, 2); + } - /// - /// Returns a long integer representation of the bit-array. - /// Assumes the bit-array length must been smaller or equal to 64 bit. - /// - /// Long integer array. - public long ToInt64() + /// + /// Sets all bits on false. + /// + public void ResetField() + { + for (var i = 0; i < field.Length; i++) { - // Precondition - if (field.Length > 64) - { - throw new InvalidOperationException("Value is too big to fit into Int64"); - } - - var sequence = ToString(); - return Convert.ToInt64(sequence, 2); + field[i] = false; } + } - /// - /// Returns a long integer representation of the bit-array. - /// Assumes the bit-array length must been smaller or equal to 32 bit. - /// - /// integer array. - public int ToInt32() + /// + /// Sets all bits on the value of the flag. + /// + /// Bollean flag (false-true). + public void SetAll(bool flag) + { + for (var i = 0; i < field.Length; i++) { - // Precondition - if (field.Length > 32) - { - throw new InvalidOperationException("Value is too big to fit into Int32"); - } - - var sequence = ToString(); - return Convert.ToInt32(sequence, 2); + field[i] = flag; } + } - /// - /// Sets all bits on false. - /// - public void ResetField() + /// + /// Checks if bit-array are equal. + /// Assumes the input bit-arrays must have same length. + /// + /// Bit-array object. + /// Returns true if there inputs are equal otherwise false. + public override bool Equals(object? obj) + { + if (obj is null) { - for (var i = 0; i < field.Length; i++) - { - field[i] = false; - } + return false; } - /// - /// Sets all bits on the value of the flag. - /// - /// Bollean flag (false-true). - public void SetAll(bool flag) + var otherBitArray = (BitArray)obj; + + if (Length != otherBitArray.Length) { - for (var i = 0; i < field.Length; i++) - { - field[i] = flag; - } + return false; } - /// - /// Checks if bit-array are equal. - /// Assumes the input bit-arrays must have same length. - /// - /// Bit-array object. - /// Returns true if there inputs are equal otherwise false. - public override bool Equals(object? obj) + for (var i = 0; i < Length; i++) { - if (obj is null) - { - return false; - } - - var otherBitArray = (BitArray)obj; - - if (Length != otherBitArray.Length) + if (field[i] != otherBitArray[i]) { return false; } - - for (var i = 0; i < Length; i++) - { - if (field[i] != otherBitArray[i]) - { - return false; - } - } - - return true; } - /// - /// Gets has-code of bit-array. - /// Assumes bit-array length must been smaller or equal to 32. - /// - /// hash-code for this BitArray instance. - public override int GetHashCode() => ToInt32(); + return true; + } - private static void ThrowIfSequenceIsInvalid(string sequence) + /// + /// Gets has-code of bit-array. + /// Assumes bit-array length must been smaller or equal to 32. + /// + /// hash-code for this BitArray instance. + public override int GetHashCode() => ToInt32(); + + private static void ThrowIfSequenceIsInvalid(string sequence) + { + if (!Match(sequence)) { - if (!Match(sequence)) - { - throw new ArgumentException("The sequence may only contain ones or zeros"); - } + throw new ArgumentException("The sequence may only contain ones or zeros"); } - - /// - /// Utility method foir checking a given sequence contains only zeros and ones. - /// This method will used in Constructor (sequence : string) and Compile(sequence : string). - /// - /// String sequence. - /// returns True if sequence contains only zeros and ones; False otherwise. - private static bool Match(string sequence) => sequence.All(ch => ch == '0' || ch == '1'); } + + /// + /// Utility method foir checking a given sequence contains only zeros and ones. + /// This method will used in Constructor (sequence : string) and Compile(sequence : string). + /// + /// String sequence. + /// returns True if sequence contains only zeros and ones; False otherwise. + private static bool Match(string sequence) => sequence.All(ch => ch == '0' || ch == '1'); } diff --git a/DataStructures/Cache/LfuCache.cs b/DataStructures/Cache/LfuCache.cs index 7c460ef2..93f9ffd0 100644 --- a/DataStructures/Cache/LfuCache.cs +++ b/DataStructures/Cache/LfuCache.cs @@ -1,158 +1,157 @@ using System; using System.Collections.Generic; -namespace DataStructures.Cache +namespace DataStructures.Cache; + +/// +/// Least Frequently Used (LFU) cache implementation. +/// +/// The type of the key (must be not null). +/// The type of the value. +/// +/// Cache keeps up to capacity items. When new item is added and cache is full, +/// one of the least frequently used item is removed (e.g. it keeps N items that were the most +/// frequently requested using Get() or Put() methods). +/// When there are multiple items with the same frequency, the least recently used item is removed. +/// +/// Cache is built on top of two data structures: +/// - Dictionary. Allows items to be looked up by key in O(1) time. Another dictionary +/// is used to store the frequency of each key. +/// - LinkedList - Allows items with the same frequency to be ordered by the last +/// usage in O(1) time. +/// +/// Useful links: +/// https://en.wikipedia.org/wiki/Cache_replacement_policies +/// https://www.enjoyalgorithms.com/blog/least-frequently-used-cache +/// https://www.educative.io/answers/what-is-least-frequently-used-cache-replace-policy +/// https://leetcode.com/problems/lfu-cache/ . +/// +public class LfuCache where TKey : notnull { - /// - /// Least Frequently Used (LFU) cache implementation. - /// - /// The type of the key (must be not null). - /// The type of the value. - /// - /// Cache keeps up to capacity items. When new item is added and cache is full, - /// one of the least frequently used item is removed (e.g. it keeps N items that were the most - /// frequently requested using Get() or Put() methods). - /// When there are multiple items with the same frequency, the least recently used item is removed. - /// - /// Cache is built on top of two data structures: - /// - Dictionary. Allows items to be looked up by key in O(1) time. Another dictionary - /// is used to store the frequency of each key. - /// - LinkedList - Allows items with the same frequency to be ordered by the last - /// usage in O(1) time. - /// - /// Useful links: - /// https://en.wikipedia.org/wiki/Cache_replacement_policies - /// https://www.enjoyalgorithms.com/blog/least-frequently-used-cache - /// https://www.educative.io/answers/what-is-least-frequently-used-cache-replace-policy - /// https://leetcode.com/problems/lfu-cache/ . - /// - public class LfuCache where TKey : notnull + private class CachedItem { - private class CachedItem - { - public TKey Key { get; set; } = default!; + public TKey Key { get; set; } = default!; - public TValue? Value { get; set; } + public TValue? Value { get; set; } - public int Frequency { get; set; } - } + public int Frequency { get; set; } + } + + private const int DefaultCapacity = 100; - private const int DefaultCapacity = 100; + private readonly int capacity; - private readonly int capacity; + // Note that Dictionary stores LinkedListNode as it allows + // removing the node from the LinkedList in O(1) time. + private readonly Dictionary> cache = new(); - // Note that Dictionary stores LinkedListNode as it allows - // removing the node from the LinkedList in O(1) time. - private readonly Dictionary> cache = new(); + // Map frequency (number of times the item was requested or updated) + // to the LRU linked list. + private readonly Dictionary> frequencies = new(); - // Map frequency (number of times the item was requested or updated) - // to the LRU linked list. - private readonly Dictionary> frequencies = new(); + // Track the minimum frequency with non-empty linked list in frequencies. + // When the last item with the minFrequency is promoted (after being requested or updated), + // the minFrequency is increased. + // When a new item is added, the minFrequency is set to 1. + private int minFrequency = -1; - // Track the minimum frequency with non-empty linked list in frequencies. - // When the last item with the minFrequency is promoted (after being requested or updated), - // the minFrequency is increased. - // When a new item is added, the minFrequency is set to 1. - private int minFrequency = -1; + /// + /// Initializes a new instance of the class. + /// + /// The max number of items the cache can store. + public LfuCache(int capacity = DefaultCapacity) + { + this.capacity = capacity; + } - /// - /// Initializes a new instance of the class. - /// - /// The max number of items the cache can store. - public LfuCache(int capacity = DefaultCapacity) + public bool Contains(TKey key) => cache.ContainsKey(key); + + /// + /// Gets the cached item by key. + /// + /// The key of cached item. + /// The cached item or default if item is not found. + /// Time complexity: O(1). + public TValue? Get(TKey key) + { + if (!cache.ContainsKey(key)) { - this.capacity = capacity; + return default; } - public bool Contains(TKey key) => cache.ContainsKey(key); + var node = cache[key]; + UpdateFrequency(node, isNew: false); + return node.Value.Value; + } - /// - /// Gets the cached item by key. - /// - /// The key of cached item. - /// The cached item or default if item is not found. - /// Time complexity: O(1). - public TValue? Get(TKey key) + /// + /// Adds or updates the value in the cache. + /// + /// The key of item to cache. + /// The value to cache. + /// + /// Time complexity: O(1). + /// If the value is already cached, it is updated and the item is moved + /// to the end of the LRU list. + /// If the cache is full, one of the least frequently used items is removed. + /// + public void Put(TKey key, TValue value) + { + if (cache.ContainsKey(key)) { - if (!cache.ContainsKey(key)) - { - return default; - } - - var node = cache[key]; - UpdateFrequency(node, isNew: false); - return node.Value.Value; + var existingNode = cache[key]; + existingNode.Value.Value = value; + UpdateFrequency(existingNode, isNew: false); + return; } - /// - /// Adds or updates the value in the cache. - /// - /// The key of item to cache. - /// The value to cache. - /// - /// Time complexity: O(1). - /// If the value is already cached, it is updated and the item is moved - /// to the end of the LRU list. - /// If the cache is full, one of the least frequently used items is removed. - /// - public void Put(TKey key, TValue value) + if (cache.Count >= capacity) { - if (cache.ContainsKey(key)) - { - var existingNode = cache[key]; - existingNode.Value.Value = value; - UpdateFrequency(existingNode, isNew: false); - return; - } - - if (cache.Count >= capacity) - { - EvictOneItem(); - } - - var item = new CachedItem { Key = key, Value = value }; - var newNode = new LinkedListNode(item); - UpdateFrequency(newNode, isNew: true); - cache.Add(key, newNode); + EvictOneItem(); } - private void UpdateFrequency(LinkedListNode node, bool isNew) - { - var item = node.Value; + var item = new CachedItem { Key = key, Value = value }; + var newNode = new LinkedListNode(item); + UpdateFrequency(newNode, isNew: true); + cache.Add(key, newNode); + } - if (isNew) - { - item.Frequency = 1; - minFrequency = 1; - } - else - { - // Remove the existing node from the LRU list with its previous frequency. - var lruList = frequencies[item.Frequency]; - lruList.Remove(node); - if (lruList.Count == 0 && minFrequency == item.Frequency) - { - minFrequency++; - } - - item.Frequency++; - } + private void UpdateFrequency(LinkedListNode node, bool isNew) + { + var item = node.Value; - // Insert item to the end of the LRU list that corresponds to its new frequency. - if (!frequencies.ContainsKey(item.Frequency)) + if (isNew) + { + item.Frequency = 1; + minFrequency = 1; + } + else + { + // Remove the existing node from the LRU list with its previous frequency. + var lruList = frequencies[item.Frequency]; + lruList.Remove(node); + if (lruList.Count == 0 && minFrequency == item.Frequency) { - frequencies[item.Frequency] = new LinkedList(); + minFrequency++; } - frequencies[item.Frequency].AddLast(node); + item.Frequency++; } - private void EvictOneItem() + // Insert item to the end of the LRU list that corresponds to its new frequency. + if (!frequencies.ContainsKey(item.Frequency)) { - var lruList = frequencies[minFrequency]; - var itemToRemove = lruList.First!.Value; - lruList.RemoveFirst(); - cache.Remove(itemToRemove.Key); + frequencies[item.Frequency] = new LinkedList(); } + + frequencies[item.Frequency].AddLast(node); + } + + private void EvictOneItem() + { + var lruList = frequencies[minFrequency]; + var itemToRemove = lruList.First!.Value; + lruList.RemoveFirst(); + cache.Remove(itemToRemove.Key); } } diff --git a/DataStructures/Cache/LruCache.cs b/DataStructures/Cache/LruCache.cs index b82abe18..9bbbbce3 100644 --- a/DataStructures/Cache/LruCache.cs +++ b/DataStructures/Cache/LruCache.cs @@ -1,112 +1,111 @@ using System; using System.Collections.Generic; -namespace DataStructures.Cache +namespace DataStructures.Cache; + +/// +/// Least Recently Used (LRU) cache implementation. +/// +/// The type of the key (must be not null). +/// The type of the value. +/// +/// Cache keeps up to capacity items. When new item is added and cache is full, +/// the least recently used item is removed (e.g. it keeps N items that were recently requested +/// using Get() or Put() methods). +/// +/// Cache is built on top of two data structures: +/// - Dictionary - allows items to be looked up by key in O(1) time. +/// - LinkedList - allows items to be ordered by last usage time in O(1) time. +/// +/// Useful links: +/// https://en.wikipedia.org/wiki/Cache_replacement_policies +/// https://www.educative.io/m/implement-least-recently-used-cache +/// https://leetcode.com/problems/lru-cache/ +/// +/// In order to make the most recently used (MRU) cache, when the cache is full, +/// just remove the last node from the linked list in the method Put +/// (replace RemoveFirst with RemoveLast). +/// +public class LruCache where TKey : notnull { - /// - /// Least Recently Used (LRU) cache implementation. - /// - /// The type of the key (must be not null). - /// The type of the value. - /// - /// Cache keeps up to capacity items. When new item is added and cache is full, - /// the least recently used item is removed (e.g. it keeps N items that were recently requested - /// using Get() or Put() methods). - /// - /// Cache is built on top of two data structures: - /// - Dictionary - allows items to be looked up by key in O(1) time. - /// - LinkedList - allows items to be ordered by last usage time in O(1) time. - /// - /// Useful links: - /// https://en.wikipedia.org/wiki/Cache_replacement_policies - /// https://www.educative.io/m/implement-least-recently-used-cache - /// https://leetcode.com/problems/lru-cache/ - /// - /// In order to make the most recently used (MRU) cache, when the cache is full, - /// just remove the last node from the linked list in the method Put - /// (replace RemoveFirst with RemoveLast). - /// - public class LruCache where TKey : notnull + private class CachedItem { - private class CachedItem - { - public TKey Key { get; set; } = default!; + public TKey Key { get; set; } = default!; - public TValue? Value { get; set; } - } + public TValue? Value { get; set; } + } - private const int DefaultCapacity = 100; + private const int DefaultCapacity = 100; - private readonly int capacity; + private readonly int capacity; - // Note that Dictionary stores LinkedListNode as it allows - // removing the node from the LinkedList in O(1) time. - private readonly Dictionary> cache = new(); - private readonly LinkedList lruList = new(); + // Note that Dictionary stores LinkedListNode as it allows + // removing the node from the LinkedList in O(1) time. + private readonly Dictionary> cache = new(); + private readonly LinkedList lruList = new(); - /// - /// Initializes a new instance of the class. - /// - /// The max number of items the cache can store. - public LruCache(int capacity = DefaultCapacity) - { - this.capacity = capacity; - } + /// + /// Initializes a new instance of the class. + /// + /// The max number of items the cache can store. + public LruCache(int capacity = DefaultCapacity) + { + this.capacity = capacity; + } - public bool Contains(TKey key) => cache.ContainsKey(key); + public bool Contains(TKey key) => cache.ContainsKey(key); - /// - /// Gets the cached item by key. - /// - /// The key of cached item. - /// The cached item or default if item is not found. - /// Time complexity: O(1). - public TValue? Get(TKey key) + /// + /// Gets the cached item by key. + /// + /// The key of cached item. + /// The cached item or default if item is not found. + /// Time complexity: O(1). + public TValue? Get(TKey key) + { + if (!cache.ContainsKey(key)) { - if (!cache.ContainsKey(key)) - { - return default; - } + return default; + } - var node = cache[key]; - lruList.Remove(node); - lruList.AddLast(node); + var node = cache[key]; + lruList.Remove(node); + lruList.AddLast(node); - return node.Value.Value; - } + return node.Value.Value; + } - /// - /// Adds or updates the value in the cache. - /// - /// The key of item to cache. - /// The value to cache. - /// - /// Time complexity: O(1). - /// If the value is already cached, it is updated and the item is moved - /// to the end of the LRU list. - /// If the cache is full, the least recently used item is removed. - /// - public void Put(TKey key, TValue value) + /// + /// Adds or updates the value in the cache. + /// + /// The key of item to cache. + /// The value to cache. + /// + /// Time complexity: O(1). + /// If the value is already cached, it is updated and the item is moved + /// to the end of the LRU list. + /// If the cache is full, the least recently used item is removed. + /// + public void Put(TKey key, TValue value) + { + if (cache.ContainsKey(key)) { - if (cache.ContainsKey(key)) - { - var existingNode = cache[key]; - existingNode.Value.Value = value; - lruList.Remove(existingNode); - lruList.AddLast(existingNode); - return; - } - - if (cache.Count >= capacity) - { - var first = lruList.First!; - lruList.RemoveFirst(); - cache.Remove(first.Value.Key); - } + var existingNode = cache[key]; + existingNode.Value.Value = value; + lruList.Remove(existingNode); + lruList.AddLast(existingNode); + return; + } - var item = new CachedItem { Key = key, Value = value }; - var newNode = lruList.AddLast(item); - cache.Add(key, newNode); + if (cache.Count >= capacity) + { + var first = lruList.First!; + lruList.RemoveFirst(); + cache.Remove(first.Value.Key); } + + var item = new CachedItem { Key = key, Value = value }; + var newNode = lruList.AddLast(item); + cache.Add(key, newNode); } } diff --git a/DataStructures/DisjointSet/DisjointSet.cs b/DataStructures/DisjointSet/DisjointSet.cs index 26506362..1f7b6618 100644 --- a/DataStructures/DisjointSet/DisjointSet.cs +++ b/DataStructures/DisjointSet/DisjointSet.cs @@ -1,62 +1,61 @@ using System.Collections; -namespace DataStructures.DisjointSet +namespace DataStructures.DisjointSet; + +/// +/// Implementation of Disjoint Set with Union By Rank and Path Compression heuristics. +/// +/// generic type for implementation. +public class DisjointSet { /// - /// Implementation of Disjoint Set with Union By Rank and Path Compression heuristics. + /// make a new set and return its representative. /// - /// generic type for implementation. - public class DisjointSet - { - /// - /// make a new set and return its representative. - /// - /// element to add in to the DS. - /// representative of x. - public Node MakeSet(T x) => new(x); + /// element to add in to the DS. + /// representative of x. + public Node MakeSet(T x) => new(x); - /// - /// find the representative of a certain node. - /// - /// node to find representative. - /// representative of x. - public Node FindSet(Node node) + /// + /// find the representative of a certain node. + /// + /// node to find representative. + /// representative of x. + public Node FindSet(Node node) + { + if (node != node.Parent) { - if (node != node.Parent) - { - node.Parent = FindSet(node.Parent); - } - - return node.Parent; + node.Parent = FindSet(node.Parent); } - /// - /// merge two sets. - /// - /// first set member. - /// second set member. - public void UnionSet(Node x, Node y) + return node.Parent; + } + + /// + /// merge two sets. + /// + /// first set member. + /// second set member. + public void UnionSet(Node x, Node y) + { + Node nx = FindSet(x); + Node ny = FindSet(y); + if (nx == ny) { - Node nx = FindSet(x); - Node ny = FindSet(y); - if (nx == ny) - { - return; - } + return; + } - if (nx.Rank > ny.Rank) - { - ny.Parent = nx; - } - else if (ny.Rank > nx.Rank) - { - nx.Parent = ny; - } - else - { - nx.Parent = ny; - ny.Rank++; - } + if (nx.Rank > ny.Rank) + { + ny.Parent = nx; + } + else if (ny.Rank > nx.Rank) + { + nx.Parent = ny; + } + else + { + nx.Parent = ny; + ny.Rank++; } } } diff --git a/DataStructures/DisjointSet/Node.cs b/DataStructures/DisjointSet/Node.cs index 42a4ae13..ee453a51 100644 --- a/DataStructures/DisjointSet/Node.cs +++ b/DataStructures/DisjointSet/Node.cs @@ -1,21 +1,20 @@ -namespace DataStructures.DisjointSet +namespace DataStructures.DisjointSet; + +/// +/// node class to be used by disjoint set to represent nodes in Disjoint Set forest. +/// +/// generic type for data to be stored. +public class Node { - /// - /// node class to be used by disjoint set to represent nodes in Disjoint Set forest. - /// - /// generic type for data to be stored. - public class Node - { - public int Rank { get; set; } + public int Rank { get; set; } - public Node Parent { get; set; } + public Node Parent { get; set; } - public T Data { get; set; } + public T Data { get; set; } - public Node(T data) - { - Data = data; - Parent = this; - } + public Node(T data) + { + Data = data; + Parent = this; } } diff --git a/DataStructures/Fenwick/BinaryIndexedTree.cs b/DataStructures/Fenwick/BinaryIndexedTree.cs index 36686160..9547a59b 100644 --- a/DataStructures/Fenwick/BinaryIndexedTree.cs +++ b/DataStructures/Fenwick/BinaryIndexedTree.cs @@ -1,68 +1,64 @@ -using System.Collections.Generic; -using System.Linq; +namespace DataStructures.Fenwick; -namespace DataStructures.Fenwick +/// +/// Represent classical realization of Fenwiсk tree or Binary Indexed tree. +/// +/// BITree[0..n] --> Array that represents Binary Indexed Tree. +/// arr[0..n-1] --> Input array for which prefix sum is evaluated. +/// +public class BinaryIndexedTree { + private readonly int[] fenwickTree; + /// - /// Represent classical realization of Fenwiсk tree or Binary Indexed tree. - /// - /// BITree[0..n] --> Array that represents Binary Indexed Tree. - /// arr[0..n-1] --> Input array for which prefix sum is evaluated. + /// Initializes a new instance of the class. + /// Create Binary indexed tree from the given array. /// - public class BinaryIndexedTree + /// Initial array. + public BinaryIndexedTree(int[] array) { - private readonly int[] fenwickTree; + fenwickTree = new int[array.Length + 1]; - /// - /// Initializes a new instance of the class. - /// Create Binary indexed tree from the given array. - /// - /// Initial array. - public BinaryIndexedTree(int[] array) + for (var i = 0; i < array.Length; i++) { - fenwickTree = new int[array.Length + 1]; - - for (var i = 0; i < array.Length; i++) - { - UpdateTree(i, array[i]); - } + UpdateTree(i, array[i]); } + } + + /// + /// This method assumes that the array is preprocessed and + /// partial sums of array elements are stored in BITree[]. + /// + /// The position to sum from. + /// Returns sum of arr[0..index]. + public int GetSum(int index) + { + var sum = 0; + var startFrom = index + 1; - /// - /// This method assumes that the array is preprocessed and - /// partial sums of array elements are stored in BITree[]. - /// - /// The position to sum from. - /// Returns sum of arr[0..index]. - public int GetSum(int index) + while (startFrom > 0) { - var sum = 0; - var startFrom = index + 1; + sum += fenwickTree[startFrom]; + startFrom -= startFrom & (-startFrom); + } - while (startFrom > 0) - { - sum += fenwickTree[startFrom]; - startFrom -= startFrom & (-startFrom); - } + return sum; + } - return sum; - } + /// + /// Updates a node in Binary Index Tree at given index. + /// The given value 'val' is added to BITree[i] and all of its ancestors in tree. + /// + /// Given index. + /// Value to be update on. + public void UpdateTree(int index, int val) + { + var startFrom = index + 1; - /// - /// Updates a node in Binary Index Tree at given index. - /// The given value 'val' is added to BITree[i] and all of its ancestors in tree. - /// - /// Given index. - /// Value to be update on. - public void UpdateTree(int index, int val) + while (startFrom <= fenwickTree.Length) { - var startFrom = index + 1; - - while (startFrom <= fenwickTree.Length) - { - fenwickTree[startFrom] += val; - startFrom += startFrom & (-startFrom); - } + fenwickTree[startFrom] += val; + startFrom += startFrom & (-startFrom); } } } diff --git a/DataStructures/Graph/DirectedWeightedGraph.cs b/DataStructures/Graph/DirectedWeightedGraph.cs index fc320396..7385e03f 100644 --- a/DataStructures/Graph/DirectedWeightedGraph.cs +++ b/DataStructures/Graph/DirectedWeightedGraph.cs @@ -1,201 +1,200 @@ -using System; +using System; using System.Collections.Generic; -namespace DataStructures.Graph +namespace DataStructures.Graph; + +/// +/// Implementation of the directed weighted graph via adjacency matrix. +/// +/// Generic Type. +public class DirectedWeightedGraph : IDirectedWeightedGraph { /// - /// Implementation of the directed weighted graph via adjacency matrix. + /// Capacity of the graph, indicates the maximum amount of vertices. + /// + private readonly int capacity; + + /// + /// Adjacency matrix which reflects the edges between vertices and their weight. + /// Zero value indicates no edge between two vertices. + /// + private readonly double[,] adjacencyMatrix; + + /// + /// Initializes a new instance of the class. /// - /// Generic Type. - public class DirectedWeightedGraph : IDirectedWeightedGraph + /// Capacity of the graph, indicates the maximum amount of vertices. + public DirectedWeightedGraph(int capacity) { - /// - /// Capacity of the graph, indicates the maximum amount of vertices. - /// - private readonly int capacity; - - /// - /// Adjacency matrix which reflects the edges between vertices and their weight. - /// Zero value indicates no edge between two vertices. - /// - private readonly double[,] adjacencyMatrix; - - /// - /// Initializes a new instance of the class. - /// - /// Capacity of the graph, indicates the maximum amount of vertices. - public DirectedWeightedGraph(int capacity) - { - ThrowIfNegativeCapacity(capacity); + ThrowIfNegativeCapacity(capacity); - this.capacity = capacity; - Vertices = new Vertex[capacity]; - adjacencyMatrix = new double[capacity, capacity]; - Count = 0; - } + this.capacity = capacity; + Vertices = new Vertex[capacity]; + adjacencyMatrix = new double[capacity, capacity]; + Count = 0; + } - /// - /// Gets list of vertices of the graph. - /// - public Vertex?[] Vertices { get; private set; } - - /// - /// Gets current amount of vertices in the graph. - /// - public int Count { get; private set; } - - /// - /// Adds new vertex to the graph. - /// - /// Data of the vertex. - /// Reference to created vertex. - public Vertex AddVertex(T data) - { - ThrowIfOverflow(); - var vertex = new Vertex(data, Count, this); - Vertices[Count] = vertex; - Count++; - return vertex; - } + /// + /// Gets list of vertices of the graph. + /// + public Vertex?[] Vertices { get; private set; } - /// - /// Creates an edge between two vertices of the graph. - /// - /// Vertex, edge starts at. - /// Vertex, edge ends at. - /// Double weight of an edge. - public void AddEdge(Vertex startVertex, Vertex endVertex, double weight) - { - ThrowIfVertexNotInGraph(startVertex); - ThrowIfVertexNotInGraph(endVertex); + /// + /// Gets current amount of vertices in the graph. + /// + public int Count { get; private set; } - ThrowIfWeightZero(weight); + /// + /// Adds new vertex to the graph. + /// + /// Data of the vertex. + /// Reference to created vertex. + public Vertex AddVertex(T data) + { + ThrowIfOverflow(); + var vertex = new Vertex(data, Count, this); + Vertices[Count] = vertex; + Count++; + return vertex; + } - var currentEdgeWeight = adjacencyMatrix[startVertex.Index, endVertex.Index]; + /// + /// Creates an edge between two vertices of the graph. + /// + /// Vertex, edge starts at. + /// Vertex, edge ends at. + /// Double weight of an edge. + public void AddEdge(Vertex startVertex, Vertex endVertex, double weight) + { + ThrowIfVertexNotInGraph(startVertex); + ThrowIfVertexNotInGraph(endVertex); - ThrowIfEdgeExists(currentEdgeWeight); + ThrowIfWeightZero(weight); - adjacencyMatrix[startVertex.Index, endVertex.Index] = weight; - } + var currentEdgeWeight = adjacencyMatrix[startVertex.Index, endVertex.Index]; - /// - /// Removes vertex from the graph. - /// - /// Vertex to be removed. - public void RemoveVertex(Vertex vertex) - { - ThrowIfVertexNotInGraph(vertex); + ThrowIfEdgeExists(currentEdgeWeight); - Vertices[vertex.Index] = null; - vertex.SetGraphNull(); + adjacencyMatrix[startVertex.Index, endVertex.Index] = weight; + } - for (var i = 0; i < Count; i++) - { - adjacencyMatrix[i, vertex.Index] = 0; - adjacencyMatrix[vertex.Index, i] = 0; - } + /// + /// Removes vertex from the graph. + /// + /// Vertex to be removed. + public void RemoveVertex(Vertex vertex) + { + ThrowIfVertexNotInGraph(vertex); - Count--; - } + Vertices[vertex.Index] = null; + vertex.SetGraphNull(); - /// - /// Removes edge between two vertices. - /// - /// Vertex, edge starts at. - /// Vertex, edge ends at. - public void RemoveEdge(Vertex startVertex, Vertex endVertex) + for (var i = 0; i < Count; i++) { - ThrowIfVertexNotInGraph(startVertex); - ThrowIfVertexNotInGraph(endVertex); - adjacencyMatrix[startVertex.Index, endVertex.Index] = 0; + adjacencyMatrix[i, vertex.Index] = 0; + adjacencyMatrix[vertex.Index, i] = 0; } - /// - /// Gets a neighbors of particular vertex. - /// - /// Vertex, method gets list of neighbors for. - /// Collection of the neighbors of particular vertex. - public IEnumerable?> GetNeighbors(Vertex vertex) - { - ThrowIfVertexNotInGraph(vertex); + Count--; + } + + /// + /// Removes edge between two vertices. + /// + /// Vertex, edge starts at. + /// Vertex, edge ends at. + public void RemoveEdge(Vertex startVertex, Vertex endVertex) + { + ThrowIfVertexNotInGraph(startVertex); + ThrowIfVertexNotInGraph(endVertex); + adjacencyMatrix[startVertex.Index, endVertex.Index] = 0; + } - for (var i = 0; i < Count; i++) + /// + /// Gets a neighbors of particular vertex. + /// + /// Vertex, method gets list of neighbors for. + /// Collection of the neighbors of particular vertex. + public IEnumerable?> GetNeighbors(Vertex vertex) + { + ThrowIfVertexNotInGraph(vertex); + + for (var i = 0; i < Count; i++) + { + if (adjacencyMatrix[vertex.Index, i] != 0) { - if (adjacencyMatrix[vertex.Index, i] != 0) - { - yield return Vertices[i]; - } + yield return Vertices[i]; } } + } - /// - /// Returns true, if there is an edge between two vertices. - /// - /// Vertex, edge starts at. - /// Vertex, edge ends at. - /// True if edge exists, otherwise false. - public bool AreAdjacent(Vertex startVertex, Vertex endVertex) - { - ThrowIfVertexNotInGraph(startVertex); - ThrowIfVertexNotInGraph(endVertex); + /// + /// Returns true, if there is an edge between two vertices. + /// + /// Vertex, edge starts at. + /// Vertex, edge ends at. + /// True if edge exists, otherwise false. + public bool AreAdjacent(Vertex startVertex, Vertex endVertex) + { + ThrowIfVertexNotInGraph(startVertex); + ThrowIfVertexNotInGraph(endVertex); - return adjacencyMatrix[startVertex.Index, endVertex.Index] != 0; - } + return adjacencyMatrix[startVertex.Index, endVertex.Index] != 0; + } - /// - /// Return the distance between two vertices in the graph. - /// - /// first vertex in edge. - /// secnod vertex in edge. - /// distance between the two. - public double AdjacentDistance(Vertex startVertex, Vertex endVertex) + /// + /// Return the distance between two vertices in the graph. + /// + /// first vertex in edge. + /// secnod vertex in edge. + /// distance between the two. + public double AdjacentDistance(Vertex startVertex, Vertex endVertex) + { + if (AreAdjacent(startVertex, endVertex)) { - if (AreAdjacent(startVertex, endVertex)) - { - return adjacencyMatrix[startVertex.Index, endVertex.Index]; - } - - return 0; + return adjacencyMatrix[startVertex.Index, endVertex.Index]; } - private static void ThrowIfNegativeCapacity(int capacity) + return 0; + } + + private static void ThrowIfNegativeCapacity(int capacity) + { + if (capacity < 0) { - if (capacity < 0) - { - throw new InvalidOperationException("Graph capacity should always be a non-negative integer."); - } + throw new InvalidOperationException("Graph capacity should always be a non-negative integer."); } + } - private static void ThrowIfWeightZero(double weight) + private static void ThrowIfWeightZero(double weight) + { + if (weight.Equals(0.0d)) { - if (weight.Equals(0.0d)) - { - throw new InvalidOperationException("Edge weight cannot be zero."); - } + throw new InvalidOperationException("Edge weight cannot be zero."); } + } - private static void ThrowIfEdgeExists(double currentEdgeWeight) + private static void ThrowIfEdgeExists(double currentEdgeWeight) + { + if (!currentEdgeWeight.Equals(0.0d)) { - if (!currentEdgeWeight.Equals(0.0d)) - { - throw new InvalidOperationException($"Vertex already exists: {currentEdgeWeight}"); - } + throw new InvalidOperationException($"Vertex already exists: {currentEdgeWeight}"); } + } - private void ThrowIfOverflow() + private void ThrowIfOverflow() + { + if (Count == capacity) { - if (Count == capacity) - { - throw new InvalidOperationException("Graph overflow."); - } + throw new InvalidOperationException("Graph overflow."); } + } - private void ThrowIfVertexNotInGraph(Vertex vertex) + private void ThrowIfVertexNotInGraph(Vertex vertex) + { + if (vertex.Graph != this) { - if (vertex.Graph != this) - { - throw new InvalidOperationException($"Vertex does not belong to graph: {vertex}."); - } + throw new InvalidOperationException($"Vertex does not belong to graph: {vertex}."); } } } diff --git a/DataStructures/Graph/IDirectedWeightedGraph.cs b/DataStructures/Graph/IDirectedWeightedGraph.cs index 73b8f817..4325b870 100644 --- a/DataStructures/Graph/IDirectedWeightedGraph.cs +++ b/DataStructures/Graph/IDirectedWeightedGraph.cs @@ -1,25 +1,24 @@ using System.Collections.Generic; -namespace DataStructures.Graph +namespace DataStructures.Graph; + +public interface IDirectedWeightedGraph { - public interface IDirectedWeightedGraph - { - int Count { get; } + int Count { get; } - Vertex?[] Vertices { get; } + Vertex?[] Vertices { get; } - void AddEdge(Vertex startVertex, Vertex endVertex, double weight); + void AddEdge(Vertex startVertex, Vertex endVertex, double weight); - Vertex AddVertex(T data); + Vertex AddVertex(T data); - bool AreAdjacent(Vertex startVertex, Vertex endVertex); + bool AreAdjacent(Vertex startVertex, Vertex endVertex); - double AdjacentDistance(Vertex startVertex, Vertex endVertex); + double AdjacentDistance(Vertex startVertex, Vertex endVertex); - IEnumerable?> GetNeighbors(Vertex vertex); + IEnumerable?> GetNeighbors(Vertex vertex); - void RemoveEdge(Vertex startVertex, Vertex endVertex); + void RemoveEdge(Vertex startVertex, Vertex endVertex); - void RemoveVertex(Vertex vertex); - } + void RemoveVertex(Vertex vertex); } diff --git a/DataStructures/Graph/Vertex.cs b/DataStructures/Graph/Vertex.cs index 7ac505d3..072366d8 100644 --- a/DataStructures/Graph/Vertex.cs +++ b/DataStructures/Graph/Vertex.cs @@ -1,59 +1,58 @@ -namespace DataStructures.Graph +namespace DataStructures.Graph; + +/// +/// Implementation of graph vertex. +/// +/// Generic Type. +public class Vertex { /// - /// Implementation of graph vertex. + /// Gets vertex data. /// - /// Generic Type. - public class Vertex - { - /// - /// Gets vertex data. - /// - public T Data { get; } + public T Data { get; } - /// - /// Gets an index of the vertex in graph adjacency matrix. - /// - public int Index { get; } + /// + /// Gets an index of the vertex in graph adjacency matrix. + /// + public int Index { get; } - /// - /// Gets reference to the graph this vertex belongs to. - /// - public DirectedWeightedGraph? Graph { get; private set; } + /// + /// Gets reference to the graph this vertex belongs to. + /// + public DirectedWeightedGraph? Graph { get; private set; } - /// - /// Initializes a new instance of the class. - /// - /// Vertex data. Generic type. - /// Index of the vertex in graph adjacency matrix. - /// Graph this vertex belongs to. - public Vertex(T data, int index, DirectedWeightedGraph? graph) - { - Data = data; - Index = index; - Graph = graph; - } + /// + /// Initializes a new instance of the class. + /// + /// Vertex data. Generic type. + /// Index of the vertex in graph adjacency matrix. + /// Graph this vertex belongs to. + public Vertex(T data, int index, DirectedWeightedGraph? graph) + { + Data = data; + Index = index; + Graph = graph; + } - /// - /// Initializes a new instance of the class. - /// - /// Vertex data. Generic type. - /// Index of the vertex in graph adjacency matrix. - public Vertex(T data, int index) - { - Data = data; - Index = index; - } + /// + /// Initializes a new instance of the class. + /// + /// Vertex data. Generic type. + /// Index of the vertex in graph adjacency matrix. + public Vertex(T data, int index) + { + Data = data; + Index = index; + } - /// - /// Sets graph reference to the null. This method called when vertex removed from the graph. - /// - public void SetGraphNull() => Graph = null; + /// + /// Sets graph reference to the null. This method called when vertex removed from the graph. + /// + public void SetGraphNull() => Graph = null; - /// - /// Override of base ToString method. Prints vertex data and index in graph adjacency matrix. - /// - /// String which contains vertex data and index in graph adjacency matrix.. - public override string ToString() => $"Vertex Data: {Data}, Index: {Index}"; - } + /// + /// Override of base ToString method. Prints vertex data and index in graph adjacency matrix. + /// + /// String which contains vertex data and index in graph adjacency matrix.. + public override string ToString() => $"Vertex Data: {Data}, Index: {Index}"; } diff --git a/DataStructures/Hashing/Entry.cs b/DataStructures/Hashing/Entry.cs index f7b1fd6c..e7afe8f4 100644 --- a/DataStructures/Hashing/Entry.cs +++ b/DataStructures/Hashing/Entry.cs @@ -3,26 +3,25 @@ using System.Linq; using DataStructures.Hashing.NumberTheory; -namespace DataStructures.Hashing +namespace DataStructures.Hashing; + +/// +/// Entry in the hash table. +/// +/// Type of the key. +/// Type of the value. +/// +/// This class is used to store the key-value pairs in the hash table. +/// +public class Entry { - /// - /// Entry in the hash table. - /// - /// Type of the key. - /// Type of the value. - /// - /// This class is used to store the key-value pairs in the hash table. - /// - public class Entry - { - public TKey? Key { get; set; } + public TKey? Key { get; set; } - public TValue? Value { get; set; } + public TValue? Value { get; set; } - public Entry(TKey key, TValue value) - { - Key = key; - Value = value; - } + public Entry(TKey key, TValue value) + { + Key = key; + Value = value; } } diff --git a/DataStructures/Hashing/HashTable.cs b/DataStructures/Hashing/HashTable.cs index f50b1776..05dde26a 100644 --- a/DataStructures/Hashing/HashTable.cs +++ b/DataStructures/Hashing/HashTable.cs @@ -3,326 +3,325 @@ using System.Linq; using DataStructures.Hashing.NumberTheory; -namespace DataStructures.Hashing +namespace DataStructures.Hashing; + +/// +/// Hash table implementation. +/// +/// Type of the key. +/// Type of the value. +public class HashTable { - /// - /// Hash table implementation. - /// - /// Type of the key. - /// Type of the value. - public class HashTable - { - private const int DefaultCapacity = 16; - private const float DefaultLoadFactor = 0.75f; - - private readonly float loadFactor; - private int capacity; - private int size; - private int threshold; - private int version; - - private Entry?[] entries; - - /// - /// Gets the number of elements in the hash table. - /// - public int Count => size; - - /// - /// Gets the capacity of the hash table. - /// - public int Capacity => capacity; - - /// - /// Gets the load factor of the hash table. - /// - public float LoadFactor => loadFactor; - - /// - /// Gets the keys in the hash table. - /// - public IEnumerable Keys => entries.Where(e => e != null).Select(e => e!.Key!); - - /// - /// Gets the values in the hash table. - /// - public IEnumerable Values => entries.Where(e => e != null).Select(e => e!.Value!); - - /// - /// Gets or sets the value associated with the specified key. - /// - /// Key to get or set. - /// Value associated with the key. - public TValue this[TKey? key] - { - get - { - if (EqualityComparer.Default.Equals(key, default(TKey))) - { - throw new ArgumentNullException(nameof(key)); - } - - var entry = FindEntry(key); - if (entry == null) - { - throw new KeyNotFoundException(); - } - - return entry.Value!; - } + private const int DefaultCapacity = 16; + private const float DefaultLoadFactor = 0.75f; - set - { - if (EqualityComparer.Default.Equals(key, default(TKey))) - { - throw new ArgumentNullException(nameof(key)); - } - - var entry = FindEntry(key); - if (entry == null) - { - throw new KeyNotFoundException(); - } - - entry.Value = value; - version++; - } - } + private readonly float loadFactor; + private int capacity; + private int size; + private int threshold; + private int version; - /// - /// Initializes a new instance of the class. - /// - /// Initial capacity of the hash table. - /// Load factor of the hash table. - /// Thrown when is less than or equal to 0. - /// Thrown when is less than or equal to 0. - /// Thrown when is greater than 1. - /// - /// is rounded to the next prime number. - /// - /// - /// - public HashTable(int capacity = DefaultCapacity, float loadFactor = DefaultLoadFactor) - { - if (capacity <= 0) - { - throw new ArgumentOutOfRangeException(nameof(capacity), "Capacity must be greater than 0"); - } + private Entry?[] entries; - if (loadFactor <= 0) - { - throw new ArgumentOutOfRangeException(nameof(loadFactor), "Load factor must be greater than 0"); - } + /// + /// Gets the number of elements in the hash table. + /// + public int Count => size; - if (loadFactor > 1) - { - throw new ArgumentOutOfRangeException(nameof(loadFactor), "Load factor must be less than or equal to 1"); - } + /// + /// Gets the capacity of the hash table. + /// + public int Capacity => capacity; - this.capacity = PrimeNumber.NextPrime(capacity); - this.loadFactor = loadFactor; - threshold = (int)(this.capacity * loadFactor); - entries = new Entry[this.capacity]; - } + /// + /// Gets the load factor of the hash table. + /// + public float LoadFactor => loadFactor; + + /// + /// Gets the keys in the hash table. + /// + public IEnumerable Keys => entries.Where(e => e != null).Select(e => e!.Key!); + + /// + /// Gets the values in the hash table. + /// + public IEnumerable Values => entries.Where(e => e != null).Select(e => e!.Value!); - /// - /// Adds a key-value pair to the hash table. - /// - /// Key to add. - /// Value to add. - /// Thrown when is null. - /// Thrown when already exists in the hash table. - /// - /// If the number of elements in the hash table is greater than or equal to the threshold, the hash table is resized. - /// - public void Add(TKey? key, TValue? value) + /// + /// Gets or sets the value associated with the specified key. + /// + /// Key to get or set. + /// Value associated with the key. + public TValue this[TKey? key] + { + get { if (EqualityComparer.Default.Equals(key, default(TKey))) { throw new ArgumentNullException(nameof(key)); } - if (size >= threshold) + var entry = FindEntry(key); + if (entry == null) { - Resize(); + throw new KeyNotFoundException(); } - var index = GetIndex(key); - if ( - entries[index] != null && - EqualityComparer.Default.Equals(entries[index] !.Key!, key)) - { - throw new ArgumentException("Key already exists"); - } - - if (EqualityComparer.Default.Equals(value, default(TValue))) - { - throw new ArgumentNullException(nameof(value)); - } - - entries[index] = new Entry(key!, value!); - size++; - version++; + return entry.Value!; } - /// - /// Removes the key-value pair associated with the specified key. - /// - /// Key to remove. - /// True if the key-value pair was removed, false otherwise. - /// Thrown when is null. - /// - /// If the number of elements in the hash table is less than or equal to the threshold divided by 4, the hash table is resized. - /// - public bool Remove(TKey? key) + set { if (EqualityComparer.Default.Equals(key, default(TKey))) { throw new ArgumentNullException(nameof(key)); } - var index = GetIndex(key); - if (entries[index] == null) + var entry = FindEntry(key); + if (entry == null) { - return false; + throw new KeyNotFoundException(); } - entries[index] = null; - size--; + entry.Value = value; version++; + } + } - if (size <= threshold / 4) - { - Resize(); - } + /// + /// Initializes a new instance of the class. + /// + /// Initial capacity of the hash table. + /// Load factor of the hash table. + /// Thrown when is less than or equal to 0. + /// Thrown when is less than or equal to 0. + /// Thrown when is greater than 1. + /// + /// is rounded to the next prime number. + /// + /// + /// + public HashTable(int capacity = DefaultCapacity, float loadFactor = DefaultLoadFactor) + { + if (capacity <= 0) + { + throw new ArgumentOutOfRangeException(nameof(capacity), "Capacity must be greater than 0"); + } - return true; + if (loadFactor <= 0) + { + throw new ArgumentOutOfRangeException(nameof(loadFactor), "Load factor must be greater than 0"); } - /// - /// Find the index of the entry associated with the specified key. - /// - /// Key to find. - /// Index of the entry associated with the key. - /// Thrown when is null. - public int GetIndex(TKey? key) + if (loadFactor > 1) { - if (EqualityComparer.Default.Equals(key, default(TKey))) - { - throw new ArgumentNullException(nameof(key)); - } + throw new ArgumentOutOfRangeException(nameof(loadFactor), "Load factor must be less than or equal to 1"); + } - var hash = key!.GetHashCode(); - var index = hash % capacity; + this.capacity = PrimeNumber.NextPrime(capacity); + this.loadFactor = loadFactor; + threshold = (int)(this.capacity * loadFactor); + entries = new Entry[this.capacity]; + } - if (index < 0) - { - index += capacity; - } + /// + /// Adds a key-value pair to the hash table. + /// + /// Key to add. + /// Value to add. + /// Thrown when is null. + /// Thrown when already exists in the hash table. + /// + /// If the number of elements in the hash table is greater than or equal to the threshold, the hash table is resized. + /// + public void Add(TKey? key, TValue? value) + { + if (EqualityComparer.Default.Equals(key, default(TKey))) + { + throw new ArgumentNullException(nameof(key)); + } - return index; + if (size >= threshold) + { + Resize(); } - /// - /// Finds the entry associated with the specified key. - /// - /// Key to find. - /// Entry associated with the key. - /// Thrown when is null. - /// - /// This method uses internally. - /// - public Entry? FindEntry(TKey? key) + var index = GetIndex(key); + if ( + entries[index] != null && + EqualityComparer.Default.Equals(entries[index] !.Key!, key)) { - if (EqualityComparer.Default.Equals(key, default(TKey))) - { - throw new ArgumentNullException(nameof(key)); - } + throw new ArgumentException("Key already exists"); + } - var index = GetIndex(key); - return entries[index]; + if (EqualityComparer.Default.Equals(value, default(TValue))) + { + throw new ArgumentNullException(nameof(value)); } - /// - /// Checks if the hash table contains the specified key. - /// - /// Key to check. - /// True if the hash table contains the key, false otherwise. - /// Thrown when is null. - /// - /// This method uses internally. - /// - public bool ContainsKey(TKey? key) + entries[index] = new Entry(key!, value!); + size++; + version++; + } + + /// + /// Removes the key-value pair associated with the specified key. + /// + /// Key to remove. + /// True if the key-value pair was removed, false otherwise. + /// Thrown when is null. + /// + /// If the number of elements in the hash table is less than or equal to the threshold divided by 4, the hash table is resized. + /// + public bool Remove(TKey? key) + { + if (EqualityComparer.Default.Equals(key, default(TKey))) { - if (EqualityComparer.Default.Equals(key, default(TKey))) - { - throw new ArgumentNullException(nameof(key)); - } + throw new ArgumentNullException(nameof(key)); + } - return FindEntry(key) != null; + var index = GetIndex(key); + if (entries[index] == null) + { + return false; } - /// - /// Checks if the hash table contains the specified value. - /// - /// Value to check. - /// True if the hash table contains the value, false otherwise. - public bool ContainsValue(TValue? value) + entries[index] = null; + size--; + version++; + + if (size <= threshold / 4) { - if (EqualityComparer.Default.Equals(value, default(TValue))) - { - throw new ArgumentNullException(nameof(value)); - } + Resize(); + } + + return true; + } - return entries.Any(e => e != null && e.Value!.Equals(value)); + /// + /// Find the index of the entry associated with the specified key. + /// + /// Key to find. + /// Index of the entry associated with the key. + /// Thrown when is null. + public int GetIndex(TKey? key) + { + if (EqualityComparer.Default.Equals(key, default(TKey))) + { + throw new ArgumentNullException(nameof(key)); } - /// - /// Clears the hash table. - /// - /// - /// This method resets the capacity of the hash table to the default capacity. - /// - public void Clear() + var hash = key!.GetHashCode(); + var index = hash % capacity; + + if (index < 0) { - capacity = DefaultCapacity; - threshold = (int)(capacity * loadFactor); - entries = new Entry[capacity]; - size = 0; - version++; + index += capacity; + } + + return index; + } + + /// + /// Finds the entry associated with the specified key. + /// + /// Key to find. + /// Entry associated with the key. + /// Thrown when is null. + /// + /// This method uses internally. + /// + public Entry? FindEntry(TKey? key) + { + if (EqualityComparer.Default.Equals(key, default(TKey))) + { + throw new ArgumentNullException(nameof(key)); } - /// - /// Resizes the hash table. - /// - /// - /// This method doubles the capacity of the hash table and rehashes all the elements. - /// - public void Resize() + var index = GetIndex(key); + return entries[index]; + } + + /// + /// Checks if the hash table contains the specified key. + /// + /// Key to check. + /// True if the hash table contains the key, false otherwise. + /// Thrown when is null. + /// + /// This method uses internally. + /// + public bool ContainsKey(TKey? key) + { + if (EqualityComparer.Default.Equals(key, default(TKey))) { - var newCapacity = capacity * 2; - var newEntries = new Entry[newCapacity]; + throw new ArgumentNullException(nameof(key)); + } + + return FindEntry(key) != null; + } + + /// + /// Checks if the hash table contains the specified value. + /// + /// Value to check. + /// True if the hash table contains the value, false otherwise. + public bool ContainsValue(TValue? value) + { + if (EqualityComparer.Default.Equals(value, default(TValue))) + { + throw new ArgumentNullException(nameof(value)); + } + + return entries.Any(e => e != null && e.Value!.Equals(value)); + } - foreach (var entry in entries) + /// + /// Clears the hash table. + /// + /// + /// This method resets the capacity of the hash table to the default capacity. + /// + public void Clear() + { + capacity = DefaultCapacity; + threshold = (int)(capacity * loadFactor); + entries = new Entry[capacity]; + size = 0; + version++; + } + + /// + /// Resizes the hash table. + /// + /// + /// This method doubles the capacity of the hash table and rehashes all the elements. + /// + public void Resize() + { + var newCapacity = capacity * 2; + var newEntries = new Entry[newCapacity]; + + foreach (var entry in entries) + { + if (entry == null) { - if (entry == null) - { - continue; - } - - var index = entry.Key!.GetHashCode() % newCapacity; - if (index < 0) - { - index += newCapacity; - } - - newEntries[index] = entry; + continue; } - capacity = newCapacity; - threshold = (int)(capacity * loadFactor); - entries = newEntries; - version++; + var index = entry.Key!.GetHashCode() % newCapacity; + if (index < 0) + { + index += newCapacity; + } + + newEntries[index] = entry; } + + capacity = newCapacity; + threshold = (int)(capacity * loadFactor); + entries = newEntries; + version++; } } diff --git a/DataStructures/Hashing/NumberTheory/PrimeNumber.cs b/DataStructures/Hashing/NumberTheory/PrimeNumber.cs index 278201a7..3dc55e26 100644 --- a/DataStructures/Hashing/NumberTheory/PrimeNumber.cs +++ b/DataStructures/Hashing/NumberTheory/PrimeNumber.cs @@ -2,75 +2,74 @@ using System.Collections.Generic; using System.Linq; -namespace DataStructures.Hashing.NumberTheory +namespace DataStructures.Hashing.NumberTheory; + +/// +/// Class for prime number operations. +/// +/// +/// A prime number is a natural number greater than 1 that is not a product of two smaller natural numbers. +/// +public static class PrimeNumber { /// - /// Class for prime number operations. + /// Checks if a number is prime or not. /// - /// - /// A prime number is a natural number greater than 1 that is not a product of two smaller natural numbers. - /// - public static class PrimeNumber + /// Number to check. + /// True if number is prime, false otherwise. + public static bool IsPrime(int number) { - /// - /// Checks if a number is prime or not. - /// - /// Number to check. - /// True if number is prime, false otherwise. - public static bool IsPrime(int number) + if (number <= 1) { - if (number <= 1) - { - return false; - } - - if (number <= 3) - { - return true; - } - - if (number % 2 == 0 || number % 3 == 0) - { - return false; - } - - for (int i = 5; i * i <= number; i += 6) - { - if (number % i == 0 || number % (i + 2) == 0) - { - return false; - } - } + return false; + } + if (number <= 3) + { return true; } - /// - /// Gets the next prime number. - /// - /// Number to start from. - /// Factor to multiply the number by. - /// True to get the previous prime number, false otherwise. - /// The next prime number. - public static int NextPrime(int number, int factor = 1, bool desc = false) + if (number % 2 == 0 || number % 3 == 0) { - number = factor * number; - int firstValue = number; + return false; + } - while (!IsPrime(number)) + for (int i = 5; i * i <= number; i += 6) + { + if (number % i == 0 || number % (i + 2) == 0) { - number += desc ? -1 : 1; + return false; } + } - if (number == firstValue) - { - return NextPrime( - number + (desc ? -1 : 1), - factor, - desc); - } + return true; + } + + /// + /// Gets the next prime number. + /// + /// Number to start from. + /// Factor to multiply the number by. + /// True to get the previous prime number, false otherwise. + /// The next prime number. + public static int NextPrime(int number, int factor = 1, bool desc = false) + { + number = factor * number; + int firstValue = number; + + while (!IsPrime(number)) + { + number += desc ? -1 : 1; + } - return number; + if (number == firstValue) + { + return NextPrime( + number + (desc ? -1 : 1), + factor, + desc); } + + return number; } } diff --git a/DataStructures/Heap/BinaryHeap.cs b/DataStructures/Heap/BinaryHeap.cs index 83dddc7f..a7f3a060 100644 --- a/DataStructures/Heap/BinaryHeap.cs +++ b/DataStructures/Heap/BinaryHeap.cs @@ -1,237 +1,236 @@ -using System; +using System; using System.Collections.Generic; -namespace DataStructures.Heap +namespace DataStructures.Heap; + +/// +/// A generic implementation of a binary heap. +/// +/// +/// A binary heap is a complete binary tree that satisfies the heap property; +/// that is every node in the tree compares greater/less than or equal to its left and right +/// child nodes. Note that this is different from a binary search tree, where every node +/// must be the largest/smallest node of all of its children. +/// Although binary heaps are not very efficient, they are (probably) the simpliest heaps +/// to understand and implement. +/// More information: https://en.wikipedia.org/wiki/Binary_heap . +/// +/// Type of elements in binary heap. +public class BinaryHeap { /// - /// A generic implementation of a binary heap. + /// Comparer to use when comparing elements. + /// + private readonly Comparer comparer; + + /// + /// List to hold the elements of the heap. + /// + private readonly List data; + + /// + /// Initializes a new instance of the class. + /// + public BinaryHeap() + { + data = new List(); + comparer = Comparer.Default; + } + + /// + /// Initializes a new instance of the class with a custom comparision function. + /// + /// The custom comparing function to use to compare elements. + public BinaryHeap(Comparer customComparer) + { + data = new List(); + comparer = customComparer; + } + + /// + /// Gets the number of elements in the heap. + /// + public int Count => data.Count; + + /// + /// Add an element to the binary heap. + /// + /// + /// Adding to the heap is done by append the element to the end of the backing list, + /// and pushing the added element up until the heap property is restored. + /// + /// The element to add to the heap. + /// Thrown if element is already in heap. + public void Push(T element) + { + data.Add(element); + HeapifyUp(data.Count - 1); + } + + /// + /// Remove the top/root of the binary heap (ie: the largest/smallest element). /// /// - /// A binary heap is a complete binary tree that satisfies the heap property; - /// that is every node in the tree compares greater/less than or equal to its left and right - /// child nodes. Note that this is different from a binary search tree, where every node - /// must be the largest/smallest node of all of its children. - /// Although binary heaps are not very efficient, they are (probably) the simpliest heaps - /// to understand and implement. - /// More information: https://en.wikipedia.org/wiki/Binary_heap . + /// Removing from the heap is done by swapping the top/root with the last element in + /// the backing list, removing the last element, and pushing the new root down + /// until the heap property is restored. /// - /// Type of elements in binary heap. - public class BinaryHeap + /// The top/root of the heap. + /// Thrown if heap is empty. + public T Pop() { - /// - /// Comparer to use when comparing elements. - /// - private readonly Comparer comparer; - - /// - /// List to hold the elements of the heap. - /// - private readonly List data; - - /// - /// Initializes a new instance of the class. - /// - public BinaryHeap() + if (Count == 0) { - data = new List(); - comparer = Comparer.Default; + throw new InvalidOperationException("Heap is empty!"); } - /// - /// Initializes a new instance of the class with a custom comparision function. - /// - /// The custom comparing function to use to compare elements. - public BinaryHeap(Comparer customComparer) + var elem = data[0]; + data[0] = data[^1]; + data.RemoveAt(data.Count - 1); + HeapifyDown(0); + + return elem; + } + + /// + /// Return the top/root of the heap without removing it. + /// + /// The top/root of the heap. + /// Thrown if heap is empty. + public T Peek() + { + if (Count == 0) { - data = new List(); - comparer = customComparer; + throw new InvalidOperationException("Heap is empty!"); } - /// - /// Gets the number of elements in the heap. - /// - public int Count => data.Count; - - /// - /// Add an element to the binary heap. - /// - /// - /// Adding to the heap is done by append the element to the end of the backing list, - /// and pushing the added element up until the heap property is restored. - /// - /// The element to add to the heap. - /// Thrown if element is already in heap. - public void Push(T element) + return data[0]; + } + + /// + /// Returns element if it compares larger to the top/root of the heap, else + /// inserts element into the heap and returns the top/root of the heap. + /// + /// The element to check/insert. + /// element if element compares larger than top/root of heap, top/root of heap otherwise. + public T PushPop(T element) + { + if (Count == 0) { - data.Add(element); - HeapifyUp(data.Count - 1); + return element; } - /// - /// Remove the top/root of the binary heap (ie: the largest/smallest element). - /// - /// - /// Removing from the heap is done by swapping the top/root with the last element in - /// the backing list, removing the last element, and pushing the new root down - /// until the heap property is restored. - /// - /// The top/root of the heap. - /// Thrown if heap is empty. - public T Pop() + if (comparer.Compare(element, data[0]) < 0) { - if (Count == 0) - { - throw new InvalidOperationException("Heap is empty!"); - } - - var elem = data[0]; - data[0] = data[^1]; - data.RemoveAt(data.Count - 1); + var tmp = data[0]; + data[0] = element; HeapifyDown(0); - - return elem; + return tmp; } - /// - /// Return the top/root of the heap without removing it. - /// - /// The top/root of the heap. - /// Thrown if heap is empty. - public T Peek() - { - if (Count == 0) - { - throw new InvalidOperationException("Heap is empty!"); - } - - return data[0]; - } + return element; + } - /// - /// Returns element if it compares larger to the top/root of the heap, else - /// inserts element into the heap and returns the top/root of the heap. - /// - /// The element to check/insert. - /// element if element compares larger than top/root of heap, top/root of heap otherwise. - public T PushPop(T element) - { - if (Count == 0) - { - return element; - } + /// + /// Check if element is in the heap. + /// + /// The element to check for. + /// true if element is in the heap, false otherwise. + public bool Contains(T element) => data.Contains(element); - if (comparer.Compare(element, data[0]) < 0) - { - var tmp = data[0]; - data[0] = element; - HeapifyDown(0); - return tmp; - } + /// + /// Remove an element from the heap. + /// + /// + /// In removing an element from anywhere in the heap, we only need to push down or up + /// the replacement value depending on how the removed value compares to its + /// replacement value. + /// + /// The element to remove from the heap. + /// Thrown if element is not in heap. + public void Remove(T element) + { + var idx = data.IndexOf(element); - return element; + if (idx == -1) + { + throw new ArgumentException($"{element} not in heap!"); } - /// - /// Check if element is in the heap. - /// - /// The element to check for. - /// true if element is in the heap, false otherwise. - public bool Contains(T element) => data.Contains(element); - - /// - /// Remove an element from the heap. - /// - /// - /// In removing an element from anywhere in the heap, we only need to push down or up - /// the replacement value depending on how the removed value compares to its - /// replacement value. - /// - /// The element to remove from the heap. - /// Thrown if element is not in heap. - public void Remove(T element) - { - var idx = data.IndexOf(element); + Swap(idx, data.Count - 1); + var tmp = data[^1]; + data.RemoveAt(data.Count - 1); - if (idx == -1) + if (idx < data.Count) + { + if (comparer.Compare(tmp, data[idx]) > 0) { - throw new ArgumentException($"{element} not in heap!"); + HeapifyDown(idx); } - - Swap(idx, data.Count - 1); - var tmp = data[^1]; - data.RemoveAt(data.Count - 1); - - if (idx < data.Count) + else { - if (comparer.Compare(tmp, data[idx]) > 0) - { - HeapifyDown(idx); - } - else - { - HeapifyUp(idx); - } + HeapifyUp(idx); } } + } - /// - /// Swap the elements in the heap array at the given indices. - /// - /// First index. - /// Second index. - private void Swap(int idx1, int idx2) - { - var tmp = data[idx1]; - data[idx1] = data[idx2]; - data[idx2] = tmp; - } + /// + /// Swap the elements in the heap array at the given indices. + /// + /// First index. + /// Second index. + private void Swap(int idx1, int idx2) + { + var tmp = data[idx1]; + data[idx1] = data[idx2]; + data[idx2] = tmp; + } - /// - /// Recursive function to restore heap properties. - /// - /// - /// Restores heap property by swapping the element at - /// with its parent if the element compares greater than its parent. - /// - /// The element to check with its parent. - private void HeapifyUp(int elemIdx) - { - var parent = (elemIdx - 1) / 2; + /// + /// Recursive function to restore heap properties. + /// + /// + /// Restores heap property by swapping the element at + /// with its parent if the element compares greater than its parent. + /// + /// The element to check with its parent. + private void HeapifyUp(int elemIdx) + { + var parent = (elemIdx - 1) / 2; - if (parent >= 0 && comparer.Compare(data[elemIdx], data[parent]) > 0) - { - Swap(elemIdx, parent); - HeapifyUp(parent); - } + if (parent >= 0 && comparer.Compare(data[elemIdx], data[parent]) > 0) + { + Swap(elemIdx, parent); + HeapifyUp(parent); } + } - /// - /// Recursive function to restore heap properties. - /// - /// - /// Restores heap property by swapping the element at - /// with the larger of its children. - /// - /// The element to check with its children. - private void HeapifyDown(int elemIdx) - { - var left = 2 * elemIdx + 1; - var right = 2 * elemIdx + 2; + /// + /// Recursive function to restore heap properties. + /// + /// + /// Restores heap property by swapping the element at + /// with the larger of its children. + /// + /// The element to check with its children. + private void HeapifyDown(int elemIdx) + { + var left = 2 * elemIdx + 1; + var right = 2 * elemIdx + 2; - var leftLargerThanElem = left < Count && comparer.Compare(data[elemIdx], data[left]) < 0; - var rightLargerThanElem = right < Count && comparer.Compare(data[elemIdx], data[right]) < 0; - var leftLargerThanRight = left < Count && right < Count && comparer.Compare(data[left], data[right]) > 0; + var leftLargerThanElem = left < Count && comparer.Compare(data[elemIdx], data[left]) < 0; + var rightLargerThanElem = right < Count && comparer.Compare(data[elemIdx], data[right]) < 0; + var leftLargerThanRight = left < Count && right < Count && comparer.Compare(data[left], data[right]) > 0; - if (leftLargerThanElem && leftLargerThanRight) - { - Swap(elemIdx, left); - HeapifyDown(left); - } - else if (rightLargerThanElem && !leftLargerThanRight) - { - Swap(elemIdx, right); - HeapifyDown(right); - } + if (leftLargerThanElem && leftLargerThanRight) + { + Swap(elemIdx, left); + HeapifyDown(left); + } + else if (rightLargerThanElem && !leftLargerThanRight) + { + Swap(elemIdx, right); + HeapifyDown(right); } } } diff --git a/DataStructures/Heap/FibonacciHeap/FHeapNode.cs b/DataStructures/Heap/FibonacciHeap/FHeapNode.cs index 8bd3a02a..88eb476b 100644 --- a/DataStructures/Heap/FibonacciHeap/FHeapNode.cs +++ b/DataStructures/Heap/FibonacciHeap/FHeapNode.cs @@ -1,132 +1,131 @@ using System; -namespace DataStructures.Heap.FibonacciHeap +namespace DataStructures.Heap.FibonacciHeap; + +/// +/// These FHeapNodes are the bulk of the data structure. The have pointers to +/// their parent, a left and right sibling, and to a child. A node and its +/// siblings comprise a circularly doubly linked list. +/// +/// A type that can be compared. +public class FHeapNode where T : IComparable { /// - /// These FHeapNodes are the bulk of the data structure. The have pointers to - /// their parent, a left and right sibling, and to a child. A node and its - /// siblings comprise a circularly doubly linked list. + /// Initializes a new instance of the class. /// - /// A type that can be compared. - public class FHeapNode where T : IComparable + /// An item in the Fibonacci heap. + public FHeapNode(T key) { - /// - /// Initializes a new instance of the class. - /// - /// An item in the Fibonacci heap. - public FHeapNode(T key) - { - Key = key; + Key = key; - // Since even a single node must form a circularly doubly linked list, - // initialize it as such - Left = Right = this; - Parent = Child = null; - } + // Since even a single node must form a circularly doubly linked list, + // initialize it as such + Left = Right = this; + Parent = Child = null; + } - /// - /// Gets or sets the data of this node. - /// - public T Key { get; set; } - - /// - /// Gets or sets a reference to the parent. - /// - public FHeapNode? Parent { get; set; } - - /// - /// Gets or sets a reference to the left sibling. - /// - public FHeapNode Left { get; set; } - - /// - /// Gets or sets a reference to the right sibling. - /// - public FHeapNode Right { get; set; } - - /// - /// Gets or sets a reference to one of the children, there may be more that - /// are siblings the this child, however this structure only maintains a - /// reference to one of them. - /// - public FHeapNode? Child { get; set; } - - /// - /// Gets or sets a value indicating whether this node has been marked, - /// used in some operations. - /// - public bool Mark { get; set; } - - /// - /// Gets or sets the number of nodes in the child linked list. - /// - public int Degree { get; set; } - - public void SetSiblings(FHeapNode left, FHeapNode right) - { - Left = left; - Right = right; - } + /// + /// Gets or sets the data of this node. + /// + public T Key { get; set; } - /// - /// A helper function to add a node to the right of this one in the current - /// circularly doubly linked list. - /// - /// A node to go in the linked list. - public void AddRight(FHeapNode node) - { - Right.Left = node; - node.Right = Right; - node.Left = this; - Right = node; - } + /// + /// Gets or sets a reference to the parent. + /// + public FHeapNode? Parent { get; set; } - /// - /// Similar to AddRight, but adds the node as a sibling to the child node. - /// - /// A node to add to the child list of this node. - public void AddChild(FHeapNode node) - { - Degree++; + /// + /// Gets or sets a reference to the left sibling. + /// + public FHeapNode Left { get; set; } - if (Child == null) - { - Child = node; - Child.Parent = this; - Child.Left = Child.Right = Child; + /// + /// Gets or sets a reference to the right sibling. + /// + public FHeapNode Right { get; set; } - return; - } + /// + /// Gets or sets a reference to one of the children, there may be more that + /// are siblings the this child, however this structure only maintains a + /// reference to one of them. + /// + public FHeapNode? Child { get; set; } - Child.AddRight(node); - } + /// + /// Gets or sets a value indicating whether this node has been marked, + /// used in some operations. + /// + public bool Mark { get; set; } - /// - /// Remove this item from the linked list it's in. - /// - public void Remove() - { - Left.Right = Right; - Right.Left = Left; - } + /// + /// Gets or sets the number of nodes in the child linked list. + /// + public int Degree { get; set; } - /// - /// Combine the linked list that otherList sits inside, with the - /// linked list this is in. Do this by cutting the link between this node, - /// and the node to the right of this, and inserting the contents of the - /// otherList in between. - /// - /// - /// A node from another list whose elements we want - /// to concatenate to this list. - /// - public void ConcatenateRight(FHeapNode otherList) + public void SetSiblings(FHeapNode left, FHeapNode right) + { + Left = left; + Right = right; + } + + /// + /// A helper function to add a node to the right of this one in the current + /// circularly doubly linked list. + /// + /// A node to go in the linked list. + public void AddRight(FHeapNode node) + { + Right.Left = node; + node.Right = Right; + node.Left = this; + Right = node; + } + + /// + /// Similar to AddRight, but adds the node as a sibling to the child node. + /// + /// A node to add to the child list of this node. + public void AddChild(FHeapNode node) + { + Degree++; + + if (Child == null) { - Right.Left = otherList.Left; - otherList.Left.Right = Right; + Child = node; + Child.Parent = this; + Child.Left = Child.Right = Child; - Right = otherList; - otherList.Left = this; + return; } + + Child.AddRight(node); + } + + /// + /// Remove this item from the linked list it's in. + /// + public void Remove() + { + Left.Right = Right; + Right.Left = Left; + } + + /// + /// Combine the linked list that otherList sits inside, with the + /// linked list this is in. Do this by cutting the link between this node, + /// and the node to the right of this, and inserting the contents of the + /// otherList in between. + /// + /// + /// A node from another list whose elements we want + /// to concatenate to this list. + /// + public void ConcatenateRight(FHeapNode otherList) + { + Right.Left = otherList.Left; + otherList.Left.Right = Right; + + Right = otherList; + otherList.Left = this; } } diff --git a/DataStructures/Heap/FibonacciHeap/FibonacciHeap.cs b/DataStructures/Heap/FibonacciHeap/FibonacciHeap.cs index bbd15151..2d004ea1 100644 --- a/DataStructures/Heap/FibonacciHeap/FibonacciHeap.cs +++ b/DataStructures/Heap/FibonacciHeap/FibonacciHeap.cs @@ -2,462 +2,461 @@ using System.Collections.Generic; using System.Linq; -namespace DataStructures.Heap.FibonacciHeap +namespace DataStructures.Heap.FibonacciHeap; + +/// +/// A generic implementation of a Fibonacci heap. +/// +/// +/// +/// A Fibonacci heap is similar to a standard binary heap +/// , however it uses concepts +/// of amortized analysis to provide theoretical speedups on common operations like +/// insert, union, and decrease-key while maintaining the same speed on all other +/// operations. +/// +/// +/// In practice, Fibonacci heaps are more complicated than binary heaps and require +/// a large input problems before the benifits of the theoretical speed up +/// begin to show. +/// +/// +/// References: +/// [1] Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, +/// and Clifford Stein. 2009. Introduction to Algorithms, Third Edition (3rd. ed.). +/// The MIT Press. +/// +/// +/// Type of elements in binary heap. +public class FibonacciHeap where T : IComparable { /// - /// A generic implementation of a Fibonacci heap. + /// Gets or sets the count of the number of nodes in the Fibonacci heap. + /// + public int Count { get; set; } + + /// + /// Gets or sets a reference to the MinItem. The MinItem and all of its siblings + /// comprise the root list, a list of trees that satisfy the heap property and + /// are joined in a circularly doubly linked list. + /// + private FHeapNode? MinItem { get; set; } + + /// + /// Add item x to this Fibonacci heap. /// /// - /// - /// A Fibonacci heap is similar to a standard binary heap - /// , however it uses concepts - /// of amortized analysis to provide theoretical speedups on common operations like - /// insert, union, and decrease-key while maintaining the same speed on all other - /// operations. - /// - /// - /// In practice, Fibonacci heaps are more complicated than binary heaps and require - /// a large input problems before the benifits of the theoretical speed up - /// begin to show. - /// - /// - /// References: - /// [1] Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, - /// and Clifford Stein. 2009. Introduction to Algorithms, Third Edition (3rd. ed.). - /// The MIT Press. - /// + /// To add an item to a Fibonacci heap, we simply add it to the "root list", + /// a circularly doubly linked list where our minimum item sits. Since adding + /// items to a linked list takes O(1) time, the overall time to perform this + /// operation is O(1). /// - /// Type of elements in binary heap. - public class FibonacciHeap where T : IComparable + /// An item to push onto the heap. + /// + /// A reference to the item as it is in the heap. This is used for + /// operations like decresing key. + /// + public FHeapNode Push(T x) { - /// - /// Gets or sets the count of the number of nodes in the Fibonacci heap. - /// - public int Count { get; set; } - - /// - /// Gets or sets a reference to the MinItem. The MinItem and all of its siblings - /// comprise the root list, a list of trees that satisfy the heap property and - /// are joined in a circularly doubly linked list. - /// - private FHeapNode? MinItem { get; set; } - - /// - /// Add item x to this Fibonacci heap. - /// - /// - /// To add an item to a Fibonacci heap, we simply add it to the "root list", - /// a circularly doubly linked list where our minimum item sits. Since adding - /// items to a linked list takes O(1) time, the overall time to perform this - /// operation is O(1). - /// - /// An item to push onto the heap. - /// - /// A reference to the item as it is in the heap. This is used for - /// operations like decresing key. - /// - public FHeapNode Push(T x) - { - Count++; + Count++; - var newItem = new FHeapNode(x); + var newItem = new FHeapNode(x); - if (MinItem == null) + if (MinItem == null) + { + MinItem = newItem; + } + else + { + MinItem.AddRight(newItem); + + if (newItem.Key.CompareTo(MinItem.Key) < 0) { MinItem = newItem; } - else - { - MinItem.AddRight(newItem); + } - if (newItem.Key.CompareTo(MinItem.Key) < 0) - { - MinItem = newItem; - } - } + return newItem; + } - return newItem; + /// + /// Combines all the elements of two fibonacci heaps. + /// + /// + /// To union two Fibonacci heaps is a single fibonacci heap is a single heap + /// that contains all the elements of both heaps. This can be done in O(1) time + /// by concatenating the root lists together. + /// For more details on how two circularly linked lists are concatenated, see + /// + /// Finally, check to see which of this.MinItem and other.MinItem + /// is smaller, and set this.MinItem accordingly + /// This operation destroys other. + /// + /// + /// Another heap whose elements we wish to add to this heap. + /// The other heap will be destroyed as a result. + /// + public void Union(FibonacciHeap other) + { + // If there are no items in the other heap, then there is nothing to do. + if (other.MinItem == null) + { + return; } - /// - /// Combines all the elements of two fibonacci heaps. - /// - /// - /// To union two Fibonacci heaps is a single fibonacci heap is a single heap - /// that contains all the elements of both heaps. This can be done in O(1) time - /// by concatenating the root lists together. - /// For more details on how two circularly linked lists are concatenated, see - /// - /// Finally, check to see which of this.MinItem and other.MinItem - /// is smaller, and set this.MinItem accordingly - /// This operation destroys other. - /// - /// - /// Another heap whose elements we wish to add to this heap. - /// The other heap will be destroyed as a result. - /// - public void Union(FibonacciHeap other) + // If this heap is empty, simply set it equal to the other heap + if (MinItem == null) { - // If there are no items in the other heap, then there is nothing to do. - if (other.MinItem == null) - { - return; - } + // Set this heap to the other one + MinItem = other.MinItem; + Count = other.Count; - // If this heap is empty, simply set it equal to the other heap - if (MinItem == null) - { - // Set this heap to the other one - MinItem = other.MinItem; - Count = other.Count; + // Destroy the other heap + other.MinItem = null; + other.Count = 0; - // Destroy the other heap - other.MinItem = null; - other.Count = 0; + return; + } - return; - } + Count += other.Count; - Count += other.Count; + // + MinItem.ConcatenateRight(other.MinItem); - // - MinItem.ConcatenateRight(other.MinItem); + // Set the MinItem to the smaller of the two MinItems + if (other.MinItem.Key.CompareTo(MinItem.Key) < 0) + { + MinItem = other.MinItem; + } - // Set the MinItem to the smaller of the two MinItems - if (other.MinItem.Key.CompareTo(MinItem.Key) < 0) - { - MinItem = other.MinItem; - } + other.MinItem = null; + other.Count = 0; + } - other.MinItem = null; - other.Count = 0; + /// + /// Return the MinItem and remove it from the heap. + /// + /// + /// This function (with all of its helper functions) is the most complicated + /// part of the Fibonacci Heap. However, it can be broken down into a few steps. + /// + /// + /// Add the children of MinItem to the root list. Either one of these children, + /// or another of the items in the root list is a candidate to become the new + /// MinItem. + /// + /// + /// Remove the MinItem from the root list and appoint a new MinItem temporarily. + /// + /// + /// what's left + /// of the heap. + /// + /// + /// + /// The minimum item from the heap. + public T Pop() + { + FHeapNode? z = null; + if (MinItem == null) + { + throw new InvalidOperationException("Heap is empty!"); } - /// - /// Return the MinItem and remove it from the heap. - /// - /// - /// This function (with all of its helper functions) is the most complicated - /// part of the Fibonacci Heap. However, it can be broken down into a few steps. - /// - /// - /// Add the children of MinItem to the root list. Either one of these children, - /// or another of the items in the root list is a candidate to become the new - /// MinItem. - /// - /// - /// Remove the MinItem from the root list and appoint a new MinItem temporarily. - /// - /// - /// what's left - /// of the heap. - /// - /// - /// - /// The minimum item from the heap. - public T Pop() + z = MinItem; + + // Since z is leaving the heap, add its children to the root list + if (z.Child != null) { - FHeapNode? z = null; - if (MinItem == null) + foreach (var x in SiblingIterator(z.Child)) { - throw new InvalidOperationException("Heap is empty!"); + x.Parent = null; } - z = MinItem; - - // Since z is leaving the heap, add its children to the root list - if (z.Child != null) - { - foreach (var x in SiblingIterator(z.Child)) - { - x.Parent = null; - } + // This effectively adds each child x to the root list + z.ConcatenateRight(z.Child); + } - // This effectively adds each child x to the root list - z.ConcatenateRight(z.Child); - } + if (Count == 1) + { + MinItem = null; + Count = 0; + return z.Key; + } - if (Count == 1) - { - MinItem = null; - Count = 0; - return z.Key; - } + // Temporarily reassign MinItem to an arbitrary item in the root + // list + MinItem = MinItem.Right; - // Temporarily reassign MinItem to an arbitrary item in the root - // list - MinItem = MinItem.Right; + // Remove the old MinItem from the root list altogether + z.Remove(); - // Remove the old MinItem from the root list altogether - z.Remove(); + // Consolidate the heap + Consolidate(); - // Consolidate the heap - Consolidate(); + Count -= 1; - Count -= 1; + return z.Key; + } - return z.Key; + /// + /// A method to see what's on top of the heap without changing its structure. + /// + /// + /// Returns the top element without popping it from the structure of + /// the heap. + /// + public T Peek() + { + if (MinItem == null) + { + throw new InvalidOperationException("The heap is empty"); } - /// - /// A method to see what's on top of the heap without changing its structure. - /// - /// - /// Returns the top element without popping it from the structure of - /// the heap. - /// - public T Peek() - { - if (MinItem == null) - { - throw new InvalidOperationException("The heap is empty"); - } + return MinItem.Key; + } - return MinItem.Key; + /// + /// Reduce the key of x to be k. + /// + /// + /// k must be less than x.Key, increasing the key of an item is not supported. + /// + /// The item you want to reduce in value. + /// The new value for the item. + public void DecreaseKey(FHeapNode x, T k) + { + if (MinItem == null) + { + throw new ArgumentException($"{nameof(x)} is not from the heap"); } - /// - /// Reduce the key of x to be k. - /// - /// - /// k must be less than x.Key, increasing the key of an item is not supported. - /// - /// The item you want to reduce in value. - /// The new value for the item. - public void DecreaseKey(FHeapNode x, T k) + if (x.Key == null) { - if (MinItem == null) - { - throw new ArgumentException($"{nameof(x)} is not from the heap"); - } + throw new ArgumentException("x has no value"); + } - if (x.Key == null) - { - throw new ArgumentException("x has no value"); - } + if (k.CompareTo(x.Key) > 0) + { + throw new InvalidOperationException("Value cannot be increased"); + } - if (k.CompareTo(x.Key) > 0) - { - throw new InvalidOperationException("Value cannot be increased"); - } + x.Key = k; + var y = x.Parent; + if (y != null && x.Key.CompareTo(y.Key) < 0) + { + Cut(x, y); + CascadingCut(y); + } - x.Key = k; - var y = x.Parent; - if (y != null && x.Key.CompareTo(y.Key) < 0) - { - Cut(x, y); - CascadingCut(y); - } + if (x.Key.CompareTo(MinItem.Key) < 0) + { + MinItem = x; + } + } - if (x.Key.CompareTo(MinItem.Key) < 0) - { - MinItem = x; - } + /// + /// Remove x from the child list of y. + /// + /// A child of y we just decreased the value of. + /// The now former parent of x. + protected void Cut(FHeapNode x, FHeapNode y) + { + if (MinItem == null) + { + throw new InvalidOperationException("Heap malformed"); } - /// - /// Remove x from the child list of y. - /// - /// A child of y we just decreased the value of. - /// The now former parent of x. - protected void Cut(FHeapNode x, FHeapNode y) + if (y.Degree == 1) { - if (MinItem == null) - { - throw new InvalidOperationException("Heap malformed"); - } + y.Child = null; + MinItem.AddRight(x); + } + else if (y.Degree > 1) + { + x.Remove(); + } + else + { + throw new InvalidOperationException("Heap malformed"); + } - if (y.Degree == 1) - { - y.Child = null; - MinItem.AddRight(x); - } - else if (y.Degree > 1) + y.Degree--; + x.Mark = false; + x.Parent = null; + } + + /// + /// Rebalances the heap after the decrease operation takes place. + /// + /// An item that may no longer obey the heap property. + protected void CascadingCut(FHeapNode y) + { + var z = y.Parent; + if (z != null) + { + if (!y.Mark) { - x.Remove(); + y.Mark = true; } else { - throw new InvalidOperationException("Heap malformed"); + Cut(y, z); + CascadingCut(z); } - - y.Degree--; - x.Mark = false; - x.Parent = null; } + } - /// - /// Rebalances the heap after the decrease operation takes place. - /// - /// An item that may no longer obey the heap property. - protected void CascadingCut(FHeapNode y) + /// + /// + /// Consolidate is analogous to Heapify in . + /// + /// + /// First, an array A [0...D(H.n)] is created where H.n is the number + /// of items in this heap, and D(x) is the max degree any node can have in a + /// Fibonacci heap with x nodes. + /// + /// + /// For each node x in the root list, try to add it to A[d] where + /// d is the degree of x. + /// If there is already a node in A[d], call it y, and make + /// y a child of x. (Swap x and y beforehand if + /// x is greater than y). Now that x has one more child, + /// remove if from A[d] and add it to A[d+1] to reflect that its + /// degree is one more. Loop this behavior until we find an empty spot to put + /// x. + /// + /// + /// With A all filled, empty the root list of the heap. And add each item + /// from A into the root list, one by one, making sure to keep track of + /// which is smallest. + /// + /// + protected void Consolidate() + { + if (MinItem == null) { - var z = y.Parent; - if (z != null) - { - if (!y.Mark) - { - y.Mark = true; - } - else - { - Cut(y, z); - CascadingCut(z); - } - } + return; } - /// - /// - /// Consolidate is analogous to Heapify in . - /// - /// - /// First, an array A [0...D(H.n)] is created where H.n is the number - /// of items in this heap, and D(x) is the max degree any node can have in a - /// Fibonacci heap with x nodes. - /// - /// - /// For each node x in the root list, try to add it to A[d] where - /// d is the degree of x. - /// If there is already a node in A[d], call it y, and make - /// y a child of x. (Swap x and y beforehand if - /// x is greater than y). Now that x has one more child, - /// remove if from A[d] and add it to A[d+1] to reflect that its - /// degree is one more. Loop this behavior until we find an empty spot to put - /// x. - /// - /// - /// With A all filled, empty the root list of the heap. And add each item - /// from A into the root list, one by one, making sure to keep track of - /// which is smallest. - /// - /// - protected void Consolidate() + // There's a fact in Intro to Algorithms: + // "the max degree of any node in an n-node fibonacci heap is O(lg(n)). + // In particular, we shall show that D(n) <= floor(log_phi(n)) where phi is + // the golden ratio, defined in equation 3.24 as phi = (1 + sqrt(5))/2" + // + // For a proof, see [1] + var maxDegree = 1 + (int)Math.Log(Count, (1 + Math.Sqrt(5)) / 2); + + // Create slots for every possible node degree of x + var a = new FHeapNode?[maxDegree]; + var siblings = SiblingIterator(MinItem).ToList(); + foreach (var w in siblings) { - if (MinItem == null) - { - return; - } - - // There's a fact in Intro to Algorithms: - // "the max degree of any node in an n-node fibonacci heap is O(lg(n)). - // In particular, we shall show that D(n) <= floor(log_phi(n)) where phi is - // the golden ratio, defined in equation 3.24 as phi = (1 + sqrt(5))/2" - // - // For a proof, see [1] - var maxDegree = 1 + (int)Math.Log(Count, (1 + Math.Sqrt(5)) / 2); - - // Create slots for every possible node degree of x - var a = new FHeapNode?[maxDegree]; - var siblings = SiblingIterator(MinItem).ToList(); - foreach (var w in siblings) - { - var x = w; - var d = x.Degree; + var x = w; + var d = x.Degree; - var y = a[d]; + var y = a[d]; - // While A[d] is not empty, we can't blindly put x here - while (y != null) + // While A[d] is not empty, we can't blindly put x here + while (y != null) + { + if (x.Key.CompareTo(y.Key) > 0) { - if (x.Key.CompareTo(y.Key) > 0) - { - // Exchange x and y - var temp = x; - x = y; - y = temp; - } - - // Make y a child of x - FibHeapLink(y, x); + // Exchange x and y + var temp = x; + x = y; + y = temp; + } - // Empty out this spot since x now has a higher degree - a[d] = null; + // Make y a child of x + FibHeapLink(y, x); - // Add 1 to x's degree before going back into the loop - d++; + // Empty out this spot since x now has a higher degree + a[d] = null; - y = a[d]; - } + // Add 1 to x's degree before going back into the loop + d++; - // Now that there's an empty spot for x, place it there - a[d] = x; + y = a[d]; } - ReconstructHeap(a); + // Now that there's an empty spot for x, place it there + a[d] = x; } - /// - /// Reconstructs the heap based on the array of node degrees created by the consolidate step. - /// - /// An array of FHeapNodes where a[i] represents a node of degree i. - private void ReconstructHeap(FHeapNode?[] a) + ReconstructHeap(a); + } + + /// + /// Reconstructs the heap based on the array of node degrees created by the consolidate step. + /// + /// An array of FHeapNodes where a[i] represents a node of degree i. + private void ReconstructHeap(FHeapNode?[] a) + { + // Once all items are in A, empty out the root list + MinItem = null; + + for (var i = 0; i < a.Length; i++) { - // Once all items are in A, empty out the root list - MinItem = null; + var r = a[i]; + if (r == null) + { + continue; + } - for (var i = 0; i < a.Length; i++) + if (MinItem == null) { - var r = a[i]; - if (r == null) - { - continue; - } + // If the root list is completely empty, make this the new + // MinItem + MinItem = r; + + // Make a new root list with just this item. Make sure to make + // it its own list. + MinItem.SetSiblings(MinItem, MinItem); + MinItem.Parent = null; + } + else + { + // Add A[i] to the root list + MinItem.AddRight(r); - if (MinItem == null) + // If this item is smaller, make it the new min item + if (MinItem.Key.CompareTo(r.Key) > 0) { - // If the root list is completely empty, make this the new - // MinItem - MinItem = r; - - // Make a new root list with just this item. Make sure to make - // it its own list. - MinItem.SetSiblings(MinItem, MinItem); - MinItem.Parent = null; - } - else - { - // Add A[i] to the root list - MinItem.AddRight(r); - - // If this item is smaller, make it the new min item - if (MinItem.Key.CompareTo(r.Key) > 0) - { - MinItem = a[i]; - } + MinItem = a[i]; } } } + } - /// - /// Make y a child of x. - /// - /// A node to become the child of x. - /// A node to become the parent of y. - private void FibHeapLink(FHeapNode y, FHeapNode x) - { - y.Remove(); - x.AddChild(y); - y.Mark = false; - } + /// + /// Make y a child of x. + /// + /// A node to become the child of x. + /// A node to become the parent of y. + private void FibHeapLink(FHeapNode y, FHeapNode x) + { + y.Remove(); + x.AddChild(y); + y.Mark = false; + } - /// - /// A helper function to iterate through all the siblings of this node in the - /// circularly doubly linked list. - /// - /// A node we want the siblings of. - /// An iterator over all of the siblings. - private IEnumerable> SiblingIterator(FHeapNode node) + /// + /// A helper function to iterate through all the siblings of this node in the + /// circularly doubly linked list. + /// + /// A node we want the siblings of. + /// An iterator over all of the siblings. + private IEnumerable> SiblingIterator(FHeapNode node) + { + var currentNode = node; + yield return currentNode; + + currentNode = node.Right; + while (currentNode != node) { - var currentNode = node; yield return currentNode; - - currentNode = node.Right; - while (currentNode != node) - { - yield return currentNode; - currentNode = currentNode.Right; - } + currentNode = currentNode.Right; } } } diff --git a/DataStructures/Heap/MinMaxHeap.cs b/DataStructures/Heap/MinMaxHeap.cs index e9720856..a5770d91 100644 --- a/DataStructures/Heap/MinMaxHeap.cs +++ b/DataStructures/Heap/MinMaxHeap.cs @@ -1,381 +1,380 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace DataStructures.Heap +namespace DataStructures.Heap; + +/// +/// This class implements min-max heap. +/// It provides functionality of both min-heap and max-heap with the same time complexity. +/// Therefore it provides constant time retrieval and logarithmic time removal +/// of both the minimum and maximum elements in it. +/// +/// Generic type. +public class MinMaxHeap { + private readonly List heap; + /// - /// This class implements min-max heap. - /// It provides functionality of both min-heap and max-heap with the same time complexity. - /// Therefore it provides constant time retrieval and logarithmic time removal - /// of both the minimum and maximum elements in it. + /// Initializes a new instance of the class that contains + /// elements copied from a specified enumerable collection and that uses a specified comparer. /// - /// Generic type. - public class MinMaxHeap + /// The enumerable collection to be copied. + /// The default comparer to use for comparing objects. + public MinMaxHeap(IEnumerable? collection = null, IComparer? comparer = null) { - private readonly List heap; - - /// - /// Initializes a new instance of the class that contains - /// elements copied from a specified enumerable collection and that uses a specified comparer. - /// - /// The enumerable collection to be copied. - /// The default comparer to use for comparing objects. - public MinMaxHeap(IEnumerable? collection = null, IComparer? comparer = null) - { - Comparer = comparer ?? Comparer.Default; - collection ??= Enumerable.Empty(); + Comparer = comparer ?? Comparer.Default; + collection ??= Enumerable.Empty(); - heap = collection.ToList(); - for (var i = Count / 2 - 1; i >= 0; --i) - { - PushDown(i); - } + heap = collection.ToList(); + for (var i = Count / 2 - 1; i >= 0; --i) + { + PushDown(i); } + } + + /// + /// Gets the . object that is used to order the values in the . + /// + public IComparer Comparer { get; } - /// - /// Gets the . object that is used to order the values in the . - /// - public IComparer Comparer { get; } - - /// - /// Gets the number of elements in the . - /// - public int Count => heap.Count; - - /// - /// Adds an element to the heap. - /// - /// The element to add to the heap. - public void Add(T item) + /// + /// Gets the number of elements in the . + /// + public int Count => heap.Count; + + /// + /// Adds an element to the heap. + /// + /// The element to add to the heap. + public void Add(T item) + { + heap.Add(item); + PushUp(Count - 1); + } + + /// + /// Removes the maximum node from the heap and returns its value. + /// + /// Thrown if heap is empty. + /// Value of the removed maximum node. + public T ExtractMax() + { + if (Count == 0) { - heap.Add(item); - PushUp(Count - 1); + throw new InvalidOperationException("Heap is empty"); } - /// - /// Removes the maximum node from the heap and returns its value. - /// - /// Thrown if heap is empty. - /// Value of the removed maximum node. - public T ExtractMax() - { - if (Count == 0) - { - throw new InvalidOperationException("Heap is empty"); - } + var max = GetMax(); + RemoveNode(GetMaxNodeIndex()); + return max; + } - var max = GetMax(); - RemoveNode(GetMaxNodeIndex()); - return max; + /// + /// Removes the minimum node from the heap and returns its value. + /// + /// Thrown if heap is empty. + /// Value of the removed minimum node. + public T ExtractMin() + { + if (Count == 0) + { + throw new InvalidOperationException("Heap is empty"); } - /// - /// Removes the minimum node from the heap and returns its value. - /// - /// Thrown if heap is empty. - /// Value of the removed minimum node. - public T ExtractMin() - { - if (Count == 0) - { - throw new InvalidOperationException("Heap is empty"); - } + var min = GetMin(); + RemoveNode(0); + return min; + } - var min = GetMin(); - RemoveNode(0); - return min; + /// + /// Gets the maximum value in the heap, as defined by the comparer. + /// + /// Thrown if heap is empty. + /// The maximum value in the heap. + public T GetMax() + { + if (Count == 0) + { + throw new InvalidOperationException("Heap is empty"); } - /// - /// Gets the maximum value in the heap, as defined by the comparer. - /// - /// Thrown if heap is empty. - /// The maximum value in the heap. - public T GetMax() - { - if (Count == 0) - { - throw new InvalidOperationException("Heap is empty"); - } + return heap[GetMaxNodeIndex()]; + } - return heap[GetMaxNodeIndex()]; + /// + /// Gets the minimum value in the heap, as defined by the comparer. + /// + /// Thrown if heap is empty. + /// The minimum value in the heap. + public T GetMin() + { + if (Count == 0) + { + throw new InvalidOperationException("Heap is empty"); } - /// - /// Gets the minimum value in the heap, as defined by the comparer. - /// - /// Thrown if heap is empty. - /// The minimum value in the heap. - public T GetMin() + return heap[0]; + } + + /// + /// Finds maximum value among children and grandchildren of the specified node. + /// + /// Index of the node in the Heap array. + /// Index of the maximum descendant. + private int IndexOfMaxChildOrGrandchild(int index) + { + var descendants = new[] + { + 2 * index + 1, + 2 * index + 2, + 4 * index + 3, + 4 * index + 4, + 4 * index + 5, + 4 * index + 6, + }; + var resIndex = descendants[0]; + foreach (var descendant in descendants) { - if (Count == 0) + if (descendant >= Count) { - throw new InvalidOperationException("Heap is empty"); + break; } - return heap[0]; - } - - /// - /// Finds maximum value among children and grandchildren of the specified node. - /// - /// Index of the node in the Heap array. - /// Index of the maximum descendant. - private int IndexOfMaxChildOrGrandchild(int index) - { - var descendants = new[] + if (Comparer.Compare(heap[descendant], heap[resIndex]) > 0) { - 2 * index + 1, - 2 * index + 2, - 4 * index + 3, - 4 * index + 4, - 4 * index + 5, - 4 * index + 6, - }; - var resIndex = descendants[0]; - foreach (var descendant in descendants) - { - if (descendant >= Count) - { - break; - } - - if (Comparer.Compare(heap[descendant], heap[resIndex]) > 0) - { - resIndex = descendant; - } + resIndex = descendant; } - - return resIndex; } - /// - /// Finds minumum value among children and grandchildren of the specified node. - /// - /// Index of the node in the Heap array. - /// Index of the minimum descendant. - private int IndexOfMinChildOrGrandchild(int index) + return resIndex; + } + + /// + /// Finds minumum value among children and grandchildren of the specified node. + /// + /// Index of the node in the Heap array. + /// Index of the minimum descendant. + private int IndexOfMinChildOrGrandchild(int index) + { + var descendants = new[] { 2 * index + 1, 2 * index + 2, 4 * index + 3, 4 * index + 4, 4 * index + 5, 4 * index + 6 }; + var resIndex = descendants[0]; + foreach (var descendant in descendants) { - var descendants = new[] { 2 * index + 1, 2 * index + 2, 4 * index + 3, 4 * index + 4, 4 * index + 5, 4 * index + 6 }; - var resIndex = descendants[0]; - foreach (var descendant in descendants) + if (descendant >= Count) { - if (descendant >= Count) - { - break; - } - - if (Comparer.Compare(heap[descendant], heap[resIndex]) < 0) - { - resIndex = descendant; - } + break; } - return resIndex; + if (Comparer.Compare(heap[descendant], heap[resIndex]) < 0) + { + resIndex = descendant; + } } - private int GetMaxNodeIndex() + return resIndex; + } + + private int GetMaxNodeIndex() + { + return Count switch { - return Count switch - { - 0 => throw new InvalidOperationException("Heap is empty"), - 1 => 0, - 2 => 1, - _ => Comparer.Compare(heap[1], heap[2]) > 0 ? 1 : 2, - }; - } + 0 => throw new InvalidOperationException("Heap is empty"), + 1 => 0, + 2 => 1, + _ => Comparer.Compare(heap[1], heap[2]) > 0 ? 1 : 2, + }; + } - private bool HasChild(int index) => index * 2 + 1 < Count; + private bool HasChild(int index) => index * 2 + 1 < Count; - private bool IsGrandchild(int node, int grandchild) => grandchild > 2 && Grandparent(grandchild) == node; + private bool IsGrandchild(int node, int grandchild) => grandchild > 2 && Grandparent(grandchild) == node; - /// - /// Checks if node at index belongs to Min or Max level of the heap. - /// Root node belongs to Min level, its children - Max level, - /// its grandchildren - Min level, and so on. - /// - /// Index to check. - /// true if index is at Min level; false if it is at Max Level. - private bool IsMinLevelIndex(int index) - { - // For all Min levels, value (index + 1) has the leftmost bit set to '1' at even position. - const uint minLevelsBits = 0x55555555; - const uint maxLevelsBits = 0xAAAAAAAA; - return ((index + 1) & minLevelsBits) > ((index + 1) & maxLevelsBits); - } + /// + /// Checks if node at index belongs to Min or Max level of the heap. + /// Root node belongs to Min level, its children - Max level, + /// its grandchildren - Min level, and so on. + /// + /// Index to check. + /// true if index is at Min level; false if it is at Max Level. + private bool IsMinLevelIndex(int index) + { + // For all Min levels, value (index + 1) has the leftmost bit set to '1' at even position. + const uint minLevelsBits = 0x55555555; + const uint maxLevelsBits = 0xAAAAAAAA; + return ((index + 1) & minLevelsBits) > ((index + 1) & maxLevelsBits); + } - private int Parent(int index) => (index - 1) / 2; + private int Parent(int index) => (index - 1) / 2; - private int Grandparent(int index) => ((index - 1) / 2 - 1) / 2; + private int Grandparent(int index) => ((index - 1) / 2 - 1) / 2; - /// - /// Assuming that children sub-trees are valid heaps, pushes node to lower levels - /// to make heap valid. - /// - /// Node index. - private void PushDown(int index) + /// + /// Assuming that children sub-trees are valid heaps, pushes node to lower levels + /// to make heap valid. + /// + /// Node index. + private void PushDown(int index) + { + if (IsMinLevelIndex(index)) { - if (IsMinLevelIndex(index)) - { - PushDownMin(index); - } - else - { - PushDownMax(index); - } + PushDownMin(index); + } + else + { + PushDownMax(index); } + } - private void PushDownMax(int index) + private void PushDownMax(int index) + { + if (!HasChild(index)) { - if (!HasChild(index)) - { - return; - } + return; + } - var maxIndex = IndexOfMaxChildOrGrandchild(index); + var maxIndex = IndexOfMaxChildOrGrandchild(index); - // If smaller element are put at min level (as result of swaping), it doesn't affect sub-tree validity. - // If smaller element are put at max level, PushDownMax() should be called for that node. - if (IsGrandchild(index, maxIndex)) + // If smaller element are put at min level (as result of swaping), it doesn't affect sub-tree validity. + // If smaller element are put at max level, PushDownMax() should be called for that node. + if (IsGrandchild(index, maxIndex)) + { + if (Comparer.Compare(heap[maxIndex], heap[index]) > 0) { - if (Comparer.Compare(heap[maxIndex], heap[index]) > 0) + SwapNodes(maxIndex, index); + if (Comparer.Compare(heap[maxIndex], heap[Parent(maxIndex)]) < 0) { - SwapNodes(maxIndex, index); - if (Comparer.Compare(heap[maxIndex], heap[Parent(maxIndex)]) < 0) - { - SwapNodes(maxIndex, Parent(maxIndex)); - } - - PushDownMax(maxIndex); + SwapNodes(maxIndex, Parent(maxIndex)); } + + PushDownMax(maxIndex); } - else + } + else + { + if (Comparer.Compare(heap[maxIndex], heap[index]) > 0) { - if (Comparer.Compare(heap[maxIndex], heap[index]) > 0) - { - SwapNodes(maxIndex, index); - } + SwapNodes(maxIndex, index); } } + } - private void PushDownMin(int index) + private void PushDownMin(int index) + { + if (!HasChild(index)) { - if (!HasChild(index)) - { - return; - } + return; + } - var minIndex = IndexOfMinChildOrGrandchild(index); + var minIndex = IndexOfMinChildOrGrandchild(index); - // If bigger element are put at max level (as result of swaping), it doesn't affect sub-tree validity. - // If bigger element are put at min level, PushDownMin() should be called for that node. - if (IsGrandchild(index, minIndex)) + // If bigger element are put at max level (as result of swaping), it doesn't affect sub-tree validity. + // If bigger element are put at min level, PushDownMin() should be called for that node. + if (IsGrandchild(index, minIndex)) + { + if (Comparer.Compare(heap[minIndex], heap[index]) < 0) { - if (Comparer.Compare(heap[minIndex], heap[index]) < 0) + SwapNodes(minIndex, index); + if (Comparer.Compare(heap[minIndex], heap[Parent(minIndex)]) > 0) { - SwapNodes(minIndex, index); - if (Comparer.Compare(heap[minIndex], heap[Parent(minIndex)]) > 0) - { - SwapNodes(minIndex, Parent(minIndex)); - } - - PushDownMin(minIndex); + SwapNodes(minIndex, Parent(minIndex)); } + + PushDownMin(minIndex); } - else + } + else + { + if (Comparer.Compare(heap[minIndex], heap[index]) < 0) { - if (Comparer.Compare(heap[minIndex], heap[index]) < 0) - { - SwapNodes(minIndex, index); - } + SwapNodes(minIndex, index); } } + } - /// - /// Having a new node in the heap, swaps this node with its ancestors to make heap valid. - /// For node at min level. If new node is less than its parent, then it is surely less then - /// all other nodes on max levels on path to the root of the heap. So node are pushed up, by - /// swaping with its grandparent, until they are ordered correctly. - /// For node at max level algorithm is analogical. - /// - /// Index of the new node. - private void PushUp(int index) + /// + /// Having a new node in the heap, swaps this node with its ancestors to make heap valid. + /// For node at min level. If new node is less than its parent, then it is surely less then + /// all other nodes on max levels on path to the root of the heap. So node are pushed up, by + /// swaping with its grandparent, until they are ordered correctly. + /// For node at max level algorithm is analogical. + /// + /// Index of the new node. + private void PushUp(int index) + { + if (index == 0) { - if (index == 0) - { - return; - } + return; + } - var parent = Parent(index); + var parent = Parent(index); - if (IsMinLevelIndex(index)) + if (IsMinLevelIndex(index)) + { + if (Comparer.Compare(heap[index], heap[parent]) > 0) { - if (Comparer.Compare(heap[index], heap[parent]) > 0) - { - SwapNodes(index, parent); - PushUpMax(parent); - } - else - { - PushUpMin(index); - } + SwapNodes(index, parent); + PushUpMax(parent); } else { - if (Comparer.Compare(heap[index], heap[parent]) < 0) - { - SwapNodes(index, parent); - PushUpMin(parent); - } - else - { - PushUpMax(index); - } + PushUpMin(index); } } - - private void PushUpMax(int index) + else { - if (index > 2) + if (Comparer.Compare(heap[index], heap[parent]) < 0) { - var grandparent = Grandparent(index); - if (Comparer.Compare(heap[index], heap[grandparent]) > 0) - { - SwapNodes(index, grandparent); - PushUpMax(grandparent); - } + SwapNodes(index, parent); + PushUpMin(parent); + } + else + { + PushUpMax(index); } } + } - private void PushUpMin(int index) + private void PushUpMax(int index) + { + if (index > 2) { - if (index > 2) + var grandparent = Grandparent(index); + if (Comparer.Compare(heap[index], heap[grandparent]) > 0) { - var grandparent = Grandparent(index); - if (Comparer.Compare(heap[index], heap[grandparent]) < 0) - { - SwapNodes(index, grandparent); - PushUpMin(grandparent); - } + SwapNodes(index, grandparent); + PushUpMax(grandparent); } } + } - private void RemoveNode(int index) + private void PushUpMin(int index) + { + if (index > 2) { - SwapNodes(index, Count - 1); - heap.RemoveAt(Count - 1); - if (Count != 0) + var grandparent = Grandparent(index); + if (Comparer.Compare(heap[index], heap[grandparent]) < 0) { - PushDown(index); + SwapNodes(index, grandparent); + PushUpMin(grandparent); } } + } - private void SwapNodes(int i, int j) + private void RemoveNode(int index) + { + SwapNodes(index, Count - 1); + heap.RemoveAt(Count - 1); + if (Count != 0) { - var temp = heap[i]; - heap[i] = heap[j]; - heap[j] = temp; + PushDown(index); } } + + private void SwapNodes(int i, int j) + { + var temp = heap[i]; + heap[i] = heap[j]; + heap[j] = temp; + } } diff --git a/DataStructures/Heap/PairingHeap/PairingHeap.cs b/DataStructures/Heap/PairingHeap/PairingHeap.cs index 9f995eb1..2f898720 100644 --- a/DataStructures/Heap/PairingHeap/PairingHeap.cs +++ b/DataStructures/Heap/PairingHeap/PairingHeap.cs @@ -1,255 +1,254 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; -namespace DataStructures.Heap.PairingHeap +namespace DataStructures.Heap.PairingHeap; + +/// +/// A pairing minMax heap implementation. +/// +/// Base type. +public class PairingHeap : IEnumerable where T : IComparable { + private readonly Sorting sorting; + private readonly IComparer comparer; + private readonly Dictionary>> mapping = new(); + + private PairingHeapNode root = null!; + + public int Count { get; private set; } + + public PairingHeap(Sorting sortDirection = Sorting.Ascending) + { + sorting = sortDirection; + comparer = new PairingNodeComparer(sortDirection, Comparer.Default); + } + /// - /// A pairing minMax heap implementation. + /// Insert a new Node [O(1)]. /// - /// Base type. - public class PairingHeap : IEnumerable where T : IComparable + public void Insert(T newItem) { - private readonly Sorting sorting; - private readonly IComparer comparer; - private readonly Dictionary>> mapping = new(); + var newNode = new PairingHeapNode(newItem); - private PairingHeapNode root = null!; + root = RebuildHeap(root, newNode); + Map(newItem, newNode); - public int Count { get; private set; } - - public PairingHeap(Sorting sortDirection = Sorting.Ascending) - { - sorting = sortDirection; - comparer = new PairingNodeComparer(sortDirection, Comparer.Default); - } + Count++; + } - /// - /// Insert a new Node [O(1)]. - /// - public void Insert(T newItem) - { - var newNode = new PairingHeapNode(newItem); + /// + /// Get the element from heap [O(log(n))]. + /// + public T Extract() + { + var minMax = root; - root = RebuildHeap(root, newNode); - Map(newItem, newNode); + RemoveMapping(minMax.Value, minMax); + RebuildHeap(root.ChildrenHead); - Count++; - } + Count--; + return minMax.Value; + } - /// - /// Get the element from heap [O(log(n))]. - /// - public T Extract() + /// + /// Update heap key [O(log(n))]. + /// + public void UpdateKey(T currentValue, T newValue) + { + if(!mapping.ContainsKey(currentValue)) { - var minMax = root; - - RemoveMapping(minMax.Value, minMax); - RebuildHeap(root.ChildrenHead); - - Count--; - return minMax.Value; + throw new ArgumentException("Current value is not present in this heap."); } - /// - /// Update heap key [O(log(n))]. - /// - public void UpdateKey(T currentValue, T newValue) + var node = mapping[currentValue]?.Where(x => x.Value.Equals(currentValue)).FirstOrDefault(); + + if (comparer.Compare(newValue, node!.Value) > 0) { - if(!mapping.ContainsKey(currentValue)) - { - throw new ArgumentException("Current value is not present in this heap."); - } + throw new ArgumentException($"New value is not {(sorting != Sorting.Descending ? "less" : "greater")} than old value."); + } - var node = mapping[currentValue]?.Where(x => x.Value.Equals(currentValue)).FirstOrDefault(); + UpdateNodeValue(currentValue, newValue, node); - if (comparer.Compare(newValue, node!.Value) > 0) - { - throw new ArgumentException($"New value is not {(sorting != Sorting.Descending ? "less" : "greater")} than old value."); - } + if (node == root) + { + return; + } - UpdateNodeValue(currentValue, newValue, node); + DeleteChild(node); - if (node == root) - { - return; - } + root = RebuildHeap(root, node); + } - DeleteChild(node); + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } - root = RebuildHeap(root, node); - } + public IEnumerator GetEnumerator() + { + return mapping.SelectMany(x => x.Value).Select(x => x.Value).GetEnumerator(); + } - IEnumerator IEnumerable.GetEnumerator() + /// + /// Rebuild heap on action [O(log(n))]. + /// + private void RebuildHeap(PairingHeapNode headNode) + { + if (headNode == null) { - return GetEnumerator(); + return; } - public IEnumerator GetEnumerator() + var passOneResult = new List>(); + var current = headNode; + + if (current.Next == null) { - return mapping.SelectMany(x => x.Value).Select(x => x.Value).GetEnumerator(); + headNode.Next = null!; + headNode.Previous = null!; + passOneResult.Add(headNode); } - - /// - /// Rebuild heap on action [O(log(n))]. - /// - private void RebuildHeap(PairingHeapNode headNode) + else { - if (headNode == null) + while (true) { - return; - } - - var passOneResult = new List>(); - var current = headNode; + if (current == null) + { + break; + } - if (current.Next == null) - { - headNode.Next = null!; - headNode.Previous = null!; - passOneResult.Add(headNode); - } - else - { - while (true) + if (current.Next != null) + { + var next = current.Next; + var nextNext = next.Next; + passOneResult.Add(RebuildHeap(current, next)); + current = nextNext; + } + else { - if (current == null) - { - break; - } - - if (current.Next != null) - { - var next = current.Next; - var nextNext = next.Next; - passOneResult.Add(RebuildHeap(current, next)); - current = nextNext; - } - else - { - var lastInserted = passOneResult[^1]; - passOneResult[^1] = RebuildHeap(lastInserted, current); - break; - } + var lastInserted = passOneResult[^1]; + passOneResult[^1] = RebuildHeap(lastInserted, current); + break; } } + } - var passTwoResult = passOneResult[^1]; + var passTwoResult = passOneResult[^1]; - if (passOneResult.Count == 1) - { - root = passTwoResult; - return; - } + if (passOneResult.Count == 1) + { + root = passTwoResult; + return; + } - for (var i = passOneResult.Count - 2; i >= 0; i--) - { - current = passOneResult[i]; - passTwoResult = RebuildHeap(passTwoResult, current); - } + for (var i = passOneResult.Count - 2; i >= 0; i--) + { + current = passOneResult[i]; + passTwoResult = RebuildHeap(passTwoResult, current); + } - root = passTwoResult; + root = passTwoResult; + } + + private PairingHeapNode RebuildHeap(PairingHeapNode node1, PairingHeapNode node2) + { + if (node2 != null) + { + node2.Previous = null!; + node2.Next = null!; } - private PairingHeapNode RebuildHeap(PairingHeapNode node1, PairingHeapNode node2) + if (node1 == null) { - if (node2 != null) - { - node2.Previous = null!; - node2.Next = null!; - } + return node2!; + } - if (node1 == null) - { - return node2!; - } + node1.Previous = null!; + node1.Next = null!; - node1.Previous = null!; - node1.Next = null!; + if (node2 != null && comparer.Compare(node1.Value, node2.Value) <= 0) + { + AddChild(ref node1, node2); + return node1; + } - if (node2 != null && comparer.Compare(node1.Value, node2.Value) <= 0) - { - AddChild(ref node1, node2); - return node1; - } + AddChild(ref node2!, node1); + return node2; + } - AddChild(ref node2!, node1); - return node2; + private void AddChild(ref PairingHeapNode parent, PairingHeapNode child) + { + if (parent.ChildrenHead == null) + { + parent.ChildrenHead = child; + child.Previous = parent; + return; } - private void AddChild(ref PairingHeapNode parent, PairingHeapNode child) + var head = parent.ChildrenHead; + + child.Previous = head; + child.Next = head.Next; + + if (head.Next != null) { - if (parent.ChildrenHead == null) - { - parent.ChildrenHead = child; - child.Previous = parent; - return; - } + head.Next.Previous = child; + } - var head = parent.ChildrenHead; + head.Next = child; + } - child.Previous = head; - child.Next = head.Next; + private void DeleteChild(PairingHeapNode node) + { + if (node.IsHeadChild) + { + var parent = node.Previous; - if (head.Next != null) + if (node.Next != null) { - head.Next.Previous = child; + node.Next.Previous = parent; } - head.Next = child; + parent.ChildrenHead = node.Next!; } - - private void DeleteChild(PairingHeapNode node) + else { - if (node.IsHeadChild) - { - var parent = node.Previous; - - if (node.Next != null) - { - node.Next.Previous = parent; - } + node.Previous.Next = node.Next; - parent.ChildrenHead = node.Next!; - } - else + if (node.Next != null) { - node.Previous.Next = node.Next; - - if (node.Next != null) - { - node.Next.Previous = node.Previous; - } + node.Next.Previous = node.Previous; } } + } - private void Map(T newItem, PairingHeapNode newNode) + private void Map(T newItem, PairingHeapNode newNode) + { + if (mapping.ContainsKey(newItem)) { - if (mapping.ContainsKey(newItem)) - { - mapping[newItem].Add(newNode); - } - else - { - mapping[newItem] = new List>(new[] { newNode }); - } + mapping[newItem].Add(newNode); } - - private void UpdateNodeValue(T currentValue, T newValue, PairingHeapNode node) + else { - RemoveMapping(currentValue, node); - node.Value = newValue; - Map(newValue, node); + mapping[newItem] = new List>(new[] { newNode }); } + } - private void RemoveMapping(T currentValue, PairingHeapNode node) + private void UpdateNodeValue(T currentValue, T newValue, PairingHeapNode node) + { + RemoveMapping(currentValue, node); + node.Value = newValue; + Map(newValue, node); + } + + private void RemoveMapping(T currentValue, PairingHeapNode node) + { + mapping[currentValue].Remove(node); + if (mapping[currentValue].Count == 0) { - mapping[currentValue].Remove(node); - if (mapping[currentValue].Count == 0) - { - mapping.Remove(currentValue); - } + mapping.Remove(currentValue); } } } diff --git a/DataStructures/Heap/PairingHeap/PairingHeapNode.cs b/DataStructures/Heap/PairingHeap/PairingHeapNode.cs index fb05edd5..f0ab4865 100644 --- a/DataStructures/Heap/PairingHeap/PairingHeapNode.cs +++ b/DataStructures/Heap/PairingHeap/PairingHeapNode.cs @@ -1,26 +1,23 @@ -using System; +namespace DataStructures.Heap.PairingHeap; -namespace DataStructures.Heap.PairingHeap +/// +/// Node represented the value and connections. +/// +/// Type, supported comparing. +public class PairingHeapNode { - /// - /// Node represented the value and connections. - /// - /// Type, supported comparing. - public class PairingHeapNode + public PairingHeapNode(T value) { - public PairingHeapNode(T value) - { - Value = value; - } + Value = value; + } - public T Value { get; set; } + public T Value { get; set; } - public PairingHeapNode ChildrenHead { get; set; } = null!; + public PairingHeapNode ChildrenHead { get; set; } = null!; - public bool IsHeadChild => Previous != null && Previous.ChildrenHead == this; + public bool IsHeadChild => Previous != null && Previous.ChildrenHead == this; - public PairingHeapNode Previous { get; set; } = null!; + public PairingHeapNode Previous { get; set; } = null!; - public PairingHeapNode Next { get; set; } = null!; - } + public PairingHeapNode Next { get; set; } = null!; } diff --git a/DataStructures/Heap/PairingHeap/PairingNodeComparer.cs b/DataStructures/Heap/PairingHeap/PairingNodeComparer.cs index 729b2885..6ffcb581 100644 --- a/DataStructures/Heap/PairingHeap/PairingNodeComparer.cs +++ b/DataStructures/Heap/PairingHeap/PairingNodeComparer.cs @@ -1,33 +1,32 @@ -using System; +using System; using System.Collections.Generic; -namespace DataStructures.Heap.PairingHeap +namespace DataStructures.Heap.PairingHeap; + +/// +/// Node comparer. +/// +/// Node type. +public class PairingNodeComparer : IComparer where T : IComparable { - /// - /// Node comparer. - /// - /// Node type. - public class PairingNodeComparer : IComparer where T : IComparable - { - private readonly bool isMax; - private readonly IComparer nodeComparer; + private readonly bool isMax; + private readonly IComparer nodeComparer; - public PairingNodeComparer(Sorting sortDirection, IComparer comparer) - { - isMax = sortDirection == Sorting.Descending; - nodeComparer = comparer; - } + public PairingNodeComparer(Sorting sortDirection, IComparer comparer) + { + isMax = sortDirection == Sorting.Descending; + nodeComparer = comparer; + } - public int Compare(T? x, T? y) - { - return !isMax - ? CompareNodes(x, y) - : CompareNodes(y, x); - } + public int Compare(T? x, T? y) + { + return !isMax + ? CompareNodes(x, y) + : CompareNodes(y, x); + } - private int CompareNodes(T? one, T? second) - { - return nodeComparer.Compare(one, second); - } + private int CompareNodes(T? one, T? second) + { + return nodeComparer.Compare(one, second); } } diff --git a/DataStructures/Heap/PairingHeap/Sorting.cs b/DataStructures/Heap/PairingHeap/Sorting.cs index f156d531..8c2403dc 100644 --- a/DataStructures/Heap/PairingHeap/Sorting.cs +++ b/DataStructures/Heap/PairingHeap/Sorting.cs @@ -1,15 +1,14 @@ -namespace DataStructures.Heap.PairingHeap +namespace DataStructures.Heap.PairingHeap; + +public enum Sorting { - public enum Sorting - { - /// - /// Ascending order. - /// - Ascending = 0, + /// + /// Ascending order. + /// + Ascending = 0, - /// - /// Descending order. - /// - Descending = 1, - } + /// + /// Descending order. + /// + Descending = 1, } diff --git a/DataStructures/InvertedIndex.cs b/DataStructures/InvertedIndex.cs index 5580abf8..3dc3f039 100644 --- a/DataStructures/InvertedIndex.cs +++ b/DataStructures/InvertedIndex.cs @@ -1,82 +1,81 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -namespace DataStructures +namespace DataStructures; + +/// +/// Inverted index is the simplest form of document indexing, +/// allowing performing boolean queries on text data. +/// +/// This realization is just simplified for better understanding the process of indexing +/// and working on straightforward string inputs. +/// +public class InvertedIndex { + private readonly Dictionary> invertedIndex = new(); + /// - /// Inverted index is the simplest form of document indexing, - /// allowing performing boolean queries on text data. - /// - /// This realization is just simplified for better understanding the process of indexing - /// and working on straightforward string inputs. + /// Build inverted index with source name and source content. /// - public class InvertedIndex + /// Name of the source. + /// Content of the source. + public void AddToIndex(string sourceName, string sourceContent) { - private readonly Dictionary> invertedIndex = new(); - - /// - /// Build inverted index with source name and source content. - /// - /// Name of the source. - /// Content of the source. - public void AddToIndex(string sourceName, string sourceContent) + var context = sourceContent.Split(' ').Distinct(); + foreach (var word in context) { - var context = sourceContent.Split(' ').Distinct(); - foreach (var word in context) + if (!invertedIndex.ContainsKey(word)) + { + invertedIndex.Add(word, new List { sourceName }); + } + else { - if (!invertedIndex.ContainsKey(word)) - { - invertedIndex.Add(word, new List { sourceName }); - } - else - { - invertedIndex[word].Add(sourceName); - } + invertedIndex[word].Add(sourceName); } } + } - /// - /// Returns the source names contains ALL terms inside at same time. - /// - /// List of terms. - /// Source names. - public IEnumerable And(IEnumerable terms) - { - var entries = terms - .Select(term => invertedIndex - .Where(x => x.Key.Equals(term)) - .SelectMany(x => x.Value)) - .ToList(); + /// + /// Returns the source names contains ALL terms inside at same time. + /// + /// List of terms. + /// Source names. + public IEnumerable And(IEnumerable terms) + { + var entries = terms + .Select(term => invertedIndex + .Where(x => x.Key.Equals(term)) + .SelectMany(x => x.Value)) + .ToList(); - var intersection = entries - .Skip(1) - .Aggregate(new HashSet(entries.First()), (hashSet, enumerable) => - { - hashSet.IntersectWith(enumerable); - return hashSet; - }); + var intersection = entries + .Skip(1) + .Aggregate(new HashSet(entries.First()), (hashSet, enumerable) => + { + hashSet.IntersectWith(enumerable); + return hashSet; + }); - return intersection; - } + return intersection; + } - /// - /// Returns the source names contains AT LEAST ONE from terms inside. - /// - /// List of terms. - /// Source names. - public IEnumerable Or(IEnumerable terms) + /// + /// Returns the source names contains AT LEAST ONE from terms inside. + /// + /// List of terms. + /// Source names. + public IEnumerable Or(IEnumerable terms) + { + var sources = new List(); + foreach (var term in terms) { - var sources = new List(); - foreach (var term in terms) - { - var source = invertedIndex - .Where(x => x.Key.Equals(term)) - .SelectMany(x => x.Value); + var source = invertedIndex + .Where(x => x.Key.Equals(term)) + .SelectMany(x => x.Value); - sources.AddRange(source); - } - - return sources.Distinct(); + sources.AddRange(source); } + + return sources.Distinct(); } } diff --git a/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs b/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs index 72a8bb1e..d976cc87 100644 --- a/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs +++ b/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs @@ -2,333 +2,332 @@ using System.Collections.Generic; using Utilities.Exceptions; -namespace DataStructures.LinkedList.DoublyLinkedList +namespace DataStructures.LinkedList.DoublyLinkedList; + +/// +/// Similar to a Singly Linked List but each node contains a refenrence to the previous node in the list. +/// is a doubly linked list. +/// Compared to singly linked lists it can be traversed forwards and backwards. +/// Adding a node to a doubly linked list is simpler because ever node contains a reference to the previous node. +/// +/// Generic type. +public class DoublyLinkedList { /// - /// Similar to a Singly Linked List but each node contains a refenrence to the previous node in the list. - /// is a doubly linked list. - /// Compared to singly linked lists it can be traversed forwards and backwards. - /// Adding a node to a doubly linked list is simpler because ever node contains a reference to the previous node. + /// Initializes a new instance of the class. /// - /// Generic type. - public class DoublyLinkedList + /// Data of the original head of the list. + public DoublyLinkedList(T data) { - /// - /// Initializes a new instance of the class. - /// - /// Data of the original head of the list. - public DoublyLinkedList(T data) - { - Head = new DoublyLinkedListNode(data); - Tail = Head; - Count = 1; - } + Head = new DoublyLinkedListNode(data); + Tail = Head; + Count = 1; + } - /// - /// Initializes a new instance of the class from an enumerable. - /// - /// Enumerable of data to be stored in the list. - public DoublyLinkedList(IEnumerable data) + /// + /// Initializes a new instance of the class from an enumerable. + /// + /// Enumerable of data to be stored in the list. + public DoublyLinkedList(IEnumerable data) + { + foreach (var d in data) { - foreach (var d in data) - { - Add(d); - } + Add(d); } + } - /// - /// Gets the amount of nodes in the list. - /// - public int Count { get; private set; } - - /// - /// Gets or sets the first node of the list. - /// - private DoublyLinkedListNode? Head { get; set; } - - /// - /// Gets or sets the last node of the list. - /// - private DoublyLinkedListNode? Tail { get; set; } - - /// - /// Replaces the Head of the list with the new value. - /// - /// Value for the new Head of the list. - /// The new Head node. - public DoublyLinkedListNode AddHead(T data) - { - var node = new DoublyLinkedListNode(data); + /// + /// Gets the amount of nodes in the list. + /// + public int Count { get; private set; } - if (Head is null) - { - Head = node; - Tail = node; - Count = 1; - return node; - } + /// + /// Gets or sets the first node of the list. + /// + private DoublyLinkedListNode? Head { get; set; } - Head.Previous = node; - node.Next = Head; - Head = node; - Count++; - return node; - } + /// + /// Gets or sets the last node of the list. + /// + private DoublyLinkedListNode? Tail { get; set; } - /// - /// Adds a new value at the end of the list. - /// - /// New value to be added to the list. - /// The new node created based on the new value. - public DoublyLinkedListNode Add(T data) - { - if (Head is null) - { - return AddHead(data); - } + /// + /// Replaces the Head of the list with the new value. + /// + /// Value for the new Head of the list. + /// The new Head node. + public DoublyLinkedListNode AddHead(T data) + { + var node = new DoublyLinkedListNode(data); - var node = new DoublyLinkedListNode(data); - Tail!.Next = node; - node.Previous = Tail; + if (Head is null) + { + Head = node; Tail = node; - Count++; + Count = 1; return node; } - /// - /// Adds a new value after an existing node. - /// - /// New value to be added to the list. - /// An existing node in the list. - /// The new node created based on the new value. - public DoublyLinkedListNode AddAfter(T data, DoublyLinkedListNode existingNode) - { - if (existingNode == Tail) - { - return Add(data); - } + Head.Previous = node; + node.Next = Head; + Head = node; + Count++; + return node; + } - var node = new DoublyLinkedListNode(data); - node.Next = existingNode.Next; - node.Previous = existingNode; - existingNode.Next = node; + /// + /// Adds a new value at the end of the list. + /// + /// New value to be added to the list. + /// The new node created based on the new value. + public DoublyLinkedListNode Add(T data) + { + if (Head is null) + { + return AddHead(data); + } - if (node.Next is not null) - { - node.Next.Previous = node; - } + var node = new DoublyLinkedListNode(data); + Tail!.Next = node; + node.Previous = Tail; + Tail = node; + Count++; + return node; + } - Count++; - return node; + /// + /// Adds a new value after an existing node. + /// + /// New value to be added to the list. + /// An existing node in the list. + /// The new node created based on the new value. + public DoublyLinkedListNode AddAfter(T data, DoublyLinkedListNode existingNode) + { + if (existingNode == Tail) + { + return Add(data); } - /// - /// Gets an enumerable based on the data in the list. - /// - /// The data in the list in an IEnumerable. It can used to create a list or an array with LINQ. - public IEnumerable GetData() + var node = new DoublyLinkedListNode(data); + node.Next = existingNode.Next; + node.Previous = existingNode; + existingNode.Next = node; + + if (node.Next is not null) { - var current = Head; - while (current is not null) - { - yield return current.Data; - current = current.Next; - } + node.Next.Previous = node; } - /// - /// Gets an enumerable based on the data in the list reversed. - /// - /// The data in the list in an IEnumerable. It can used to create a list or an array with LINQ. - public IEnumerable GetDataReversed() + Count++; + return node; + } + + /// + /// Gets an enumerable based on the data in the list. + /// + /// The data in the list in an IEnumerable. It can used to create a list or an array with LINQ. + public IEnumerable GetData() + { + var current = Head; + while (current is not null) { - var current = Tail; - while (current is not null) - { - yield return current.Data; - current = current.Previous; - } + yield return current.Data; + current = current.Next; } + } - /// - /// Reverses the list. Because of how doubly linked list are structured this is not a complex action. - /// - public void Reverse() + /// + /// Gets an enumerable based on the data in the list reversed. + /// + /// The data in the list in an IEnumerable. It can used to create a list or an array with LINQ. + public IEnumerable GetDataReversed() + { + var current = Tail; + while (current is not null) { - var current = Head; - DoublyLinkedListNode? temp = null; - - while (current is not null) - { - temp = current.Previous; - current.Previous = current.Next; - current.Next = temp; - current = current.Previous; - } - - Tail = Head; - - // temp can be null on empty list - if (temp is not null) - { - Head = temp.Previous; - } + yield return current.Data; + current = current.Previous; } + } - /// - /// Looks for a node in the list that contains the value of the parameter. - /// - /// Value to be looked for in a node. - /// The node in the list the has the paramater as a value or null if not found. - public DoublyLinkedListNode Find(T data) + /// + /// Reverses the list. Because of how doubly linked list are structured this is not a complex action. + /// + public void Reverse() + { + var current = Head; + DoublyLinkedListNode? temp = null; + + while (current is not null) { - var current = Head; - while (current is not null) - { - if (current.Data is null && data is null || current.Data is not null && current.Data.Equals(data)) - { - return current; - } + temp = current.Previous; + current.Previous = current.Next; + current.Next = temp; + current = current.Previous; + } - current = current.Next; - } + Tail = Head; - throw new ItemNotFoundException(); + // temp can be null on empty list + if (temp is not null) + { + Head = temp.Previous; } + } - /// - /// Looks for a node in the list that contains the value of the parameter. - /// - /// Position in the list. - /// The node in the list the has the paramater as a value or null if not found. - /// Thrown when position is negative or out range of the list. - public DoublyLinkedListNode GetAt(int position) + /// + /// Looks for a node in the list that contains the value of the parameter. + /// + /// Value to be looked for in a node. + /// The node in the list the has the paramater as a value or null if not found. + public DoublyLinkedListNode Find(T data) + { + var current = Head; + while (current is not null) { - if (position < 0 || position >= Count) + if (current.Data is null && data is null || current.Data is not null && current.Data.Equals(data)) { - throw new ArgumentOutOfRangeException($"Max count is {Count}"); + return current; } - var current = Head; - for (var i = 0; i < position; i++) - { - current = current!.Next; - } + current = current.Next; + } + + throw new ItemNotFoundException(); + } - return current ?? throw new ArgumentOutOfRangeException($"{nameof(position)} must be an index in the list"); + /// + /// Looks for a node in the list that contains the value of the parameter. + /// + /// Position in the list. + /// The node in the list the has the paramater as a value or null if not found. + /// Thrown when position is negative or out range of the list. + public DoublyLinkedListNode GetAt(int position) + { + if (position < 0 || position >= Count) + { + throw new ArgumentOutOfRangeException($"Max count is {Count}"); } - /// - /// Removes the Head and replaces it with the second node in the list. - /// - public void RemoveHead() + var current = Head; + for (var i = 0; i < position; i++) { - if (Head is null) - { - throw new InvalidOperationException(); - } + current = current!.Next; + } - Head = Head.Next; - if (Head is null) - { - Tail = null; - Count = 0; - return; - } + return current ?? throw new ArgumentOutOfRangeException($"{nameof(position)} must be an index in the list"); + } - Head.Previous = null; - Count--; + /// + /// Removes the Head and replaces it with the second node in the list. + /// + public void RemoveHead() + { + if (Head is null) + { + throw new InvalidOperationException(); } - /// - /// Removes the last node in the list. - /// - public void Remove() + Head = Head.Next; + if (Head is null) { - if (Tail is null) - { - throw new InvalidOperationException("Cannot prune empty list"); - } + Tail = null; + Count = 0; + return; + } - Tail = Tail.Previous; - if (Tail is null) - { - Head = null; - Count = 0; - return; - } + Head.Previous = null; + Count--; + } - Tail.Next = null; - Count--; + /// + /// Removes the last node in the list. + /// + public void Remove() + { + if (Tail is null) + { + throw new InvalidOperationException("Cannot prune empty list"); } - /// - /// Removes specific node. - /// - /// Node to be removed. - public void RemoveNode(DoublyLinkedListNode node) + Tail = Tail.Previous; + if (Tail is null) { - if (node == Head) - { - RemoveHead(); - return; - } + Head = null; + Count = 0; + return; + } - if (node == Tail) - { - Remove(); - return; - } + Tail.Next = null; + Count--; + } - if (node.Previous is null || node.Next is null) - { - throw new ArgumentException( - $"{nameof(node)} cannot have Previous or Next null if it's an internal node"); - } + /// + /// Removes specific node. + /// + /// Node to be removed. + public void RemoveNode(DoublyLinkedListNode node) + { + if (node == Head) + { + RemoveHead(); + return; + } - node.Previous.Next = node.Next; - node.Next.Previous = node.Previous; - Count--; + if (node == Tail) + { + Remove(); + return; } - /// - /// Removes a node that contains the data from the parameter. - /// - /// Data to be removed form the list. - public void Remove(T data) + if (node.Previous is null || node.Next is null) { - var node = Find(data); - RemoveNode(node); + throw new ArgumentException( + $"{nameof(node)} cannot have Previous or Next null if it's an internal node"); } - /// - /// Looks for the index of the node with the parameter as data. - /// - /// Data to look for. - /// Returns the index of the node if it is found or -1 if the node is not found. - public int IndexOf(T data) + node.Previous.Next = node.Next; + node.Next.Previous = node.Previous; + Count--; + } + + /// + /// Removes a node that contains the data from the parameter. + /// + /// Data to be removed form the list. + public void Remove(T data) + { + var node = Find(data); + RemoveNode(node); + } + + /// + /// Looks for the index of the node with the parameter as data. + /// + /// Data to look for. + /// Returns the index of the node if it is found or -1 if the node is not found. + public int IndexOf(T data) + { + var current = Head; + var index = 0; + while (current is not null) { - var current = Head; - var index = 0; - while (current is not null) + if (current.Data is null && data is null || current.Data is not null && current.Data.Equals(data)) { - if (current.Data is null && data is null || current.Data is not null && current.Data.Equals(data)) - { - return index; - } - - index++; - current = current.Next; + return index; } - return -1; + index++; + current = current.Next; } - /// - /// List contains a node that has the parameter as data. - /// - /// Node to be removed. - /// True if the node is found. False if it isn't. - public bool Contains(T data) => IndexOf(data) != -1; + return -1; } + + /// + /// List contains a node that has the parameter as data. + /// + /// Node to be removed. + /// True if the node is found. False if it isn't. + public bool Contains(T data) => IndexOf(data) != -1; } diff --git a/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedListNode.cs b/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedListNode.cs index 37a3e6a8..85951407 100644 --- a/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedListNode.cs +++ b/DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedListNode.cs @@ -1,30 +1,29 @@ -namespace DataStructures.LinkedList.DoublyLinkedList +namespace DataStructures.LinkedList.DoublyLinkedList; + +/// +/// Generic node class for Doubly Linked List. +/// +/// Generic type. +public class DoublyLinkedListNode { /// - /// Generic node class for Doubly Linked List. + /// Initializes a new instance of the class. /// - /// Generic type. - public class DoublyLinkedListNode - { - /// - /// Initializes a new instance of the class. - /// - /// Data to be stored in this node. - public DoublyLinkedListNode(T data) => Data = data; + /// Data to be stored in this node. + public DoublyLinkedListNode(T data) => Data = data; - /// - /// Gets the data stored on this node. - /// - public T Data { get; } + /// + /// Gets the data stored on this node. + /// + public T Data { get; } - /// - /// Gets or sets the reference to the next node in the Doubly Linked List. - /// - public DoublyLinkedListNode? Next { get; set; } + /// + /// Gets or sets the reference to the next node in the Doubly Linked List. + /// + public DoublyLinkedListNode? Next { get; set; } - /// - /// Gets or sets the reference to the previous node in the Doubly Linked List. - /// - public DoublyLinkedListNode? Previous { get; set; } - } + /// + /// Gets or sets the reference to the previous node in the Doubly Linked List. + /// + public DoublyLinkedListNode? Previous { get; set; } } diff --git a/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs b/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs index 9cdb0387..12f6ff75 100644 --- a/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs +++ b/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs @@ -1,157 +1,156 @@ -using System; +using System; using System.Collections.Generic; -namespace DataStructures.LinkedList.SinglyLinkedList +namespace DataStructures.LinkedList.SinglyLinkedList; + +public class SinglyLinkedList { - public class SinglyLinkedList + // points to the start of the list + private SinglyLinkedListNode? Head { get; set; } + + /// + /// Adds new node to the start of the list, + /// time complexity: O(1), + /// space complexity: O(1). + /// + /// Contents of newly added node. + /// Added list node. + public SinglyLinkedListNode AddFirst(T data) { - // points to the start of the list - private SinglyLinkedListNode? Head { get; set; } - - /// - /// Adds new node to the start of the list, - /// time complexity: O(1), - /// space complexity: O(1). - /// - /// Contents of newly added node. - /// Added list node. - public SinglyLinkedListNode AddFirst(T data) + var newListElement = new SinglyLinkedListNode(data) { - var newListElement = new SinglyLinkedListNode(data) - { - Next = Head, - }; + Next = Head, + }; + + Head = newListElement; + return newListElement; + } + /// + /// Adds new node to the end of the list, + /// time complexity: O(n), + /// space complexity: O(1), + /// where n - number of nodes in the list. + /// + /// Contents of newly added node. + /// Added list node. + public SinglyLinkedListNode AddLast(T data) + { + var newListElement = new SinglyLinkedListNode(data); + + // if head is null, the added element is the first, hence it is the head + if (Head is null) + { Head = newListElement; return newListElement; } - /// - /// Adds new node to the end of the list, - /// time complexity: O(n), - /// space complexity: O(1), - /// where n - number of nodes in the list. - /// - /// Contents of newly added node. - /// Added list node. - public SinglyLinkedListNode AddLast(T data) + // temp ListElement to avoid overwriting the original + var tempElement = Head; + + // iterates through all elements + while (tempElement.Next is not null) { - var newListElement = new SinglyLinkedListNode(data); + tempElement = tempElement.Next; + } - // if head is null, the added element is the first, hence it is the head - if (Head is null) - { - Head = newListElement; - return newListElement; - } + // adds the new element to the last one + tempElement.Next = newListElement; + return newListElement; + } - // temp ListElement to avoid overwriting the original - var tempElement = Head; + /// + /// Returns element at index in the list. + /// + /// Index of an element to be returned. + /// Element at index . + public T GetElementByIndex(int index) + { + if (index < 0) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } - // iterates through all elements - while (tempElement.Next is not null) - { - tempElement = tempElement.Next; - } + var tempElement = Head; - // adds the new element to the last one - tempElement.Next = newListElement; - return newListElement; + for (var i = 0; tempElement is not null && i < index; i++) + { + tempElement = tempElement.Next; } - /// - /// Returns element at index in the list. - /// - /// Index of an element to be returned. - /// Element at index . - public T GetElementByIndex(int index) + if (tempElement is null) { - if (index < 0) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - var tempElement = Head; - - for (var i = 0; tempElement is not null && i < index; i++) - { - tempElement = tempElement.Next; - } + throw new ArgumentOutOfRangeException(nameof(index)); + } - if (tempElement is null) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } + return tempElement.Data; + } - return tempElement.Data; + public int Length() + { + // checks if there is a head + if (Head is null) + { + return 0; } - public int Length() - { - // checks if there is a head - if (Head is null) - { - return 0; - } + var tempElement = Head; + var length = 1; - var tempElement = Head; - var length = 1; + while (tempElement.Next is not null) + { + tempElement = tempElement.Next; + length++; + } - while (tempElement.Next is not null) - { - tempElement = tempElement.Next; - length++; - } + return length; + } - return length; - } + public IEnumerable GetListData() + { + // temp ListElement to avoid overwriting the original + var tempElement = Head; - public IEnumerable GetListData() + // all elements where a next attribute exists + while (tempElement is not null) { - // temp ListElement to avoid overwriting the original - var tempElement = Head; - - // all elements where a next attribute exists - while (tempElement is not null) - { - yield return tempElement.Data; - tempElement = tempElement.Next; - } + yield return tempElement.Data; + tempElement = tempElement.Next; } + } - public bool DeleteElement(T element) - { - var currentElement = Head; - SinglyLinkedListNode? previousElement = null; + public bool DeleteElement(T element) + { + var currentElement = Head; + SinglyLinkedListNode? previousElement = null; - // iterates through all elements - while (currentElement is not null) + // iterates through all elements + while (currentElement is not null) + { + // checks if the element, which should get deleted is in this list element + if (currentElement.Data is null && element is null || + currentElement.Data is not null && currentElement.Data.Equals(element)) { - // checks if the element, which should get deleted is in this list element - if (currentElement.Data is null && element is null || - currentElement.Data is not null && currentElement.Data.Equals(element)) + // if element is head just take the next one as head + if (currentElement.Equals(Head)) { - // if element is head just take the next one as head - if (currentElement.Equals(Head)) - { - Head = Head.Next; - return true; - } - - // else take the prev one and overwrite the next with the one behind the deleted - if (previousElement is not null) - { - previousElement.Next = currentElement.Next; - return true; - } + Head = Head.Next; + return true; } - // iterating - previousElement = currentElement; - currentElement = currentElement.Next; + // else take the prev one and overwrite the next with the one behind the deleted + if (previousElement is not null) + { + previousElement.Next = currentElement.Next; + return true; + } } - return false; + // iterating + previousElement = currentElement; + currentElement = currentElement.Next; } + + return false; } } diff --git a/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedListNode.cs b/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedListNode.cs index d6077b38..4d0aa4cb 100644 --- a/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedListNode.cs +++ b/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedListNode.cs @@ -1,15 +1,14 @@ -namespace DataStructures.LinkedList.SinglyLinkedList +namespace DataStructures.LinkedList.SinglyLinkedList; + +public class SinglyLinkedListNode { - public class SinglyLinkedListNode + public SinglyLinkedListNode(T data) { - public SinglyLinkedListNode(T data) - { - Data = data; - Next = null; - } + Data = data; + Next = null; + } - public T Data { get; } + public T Data { get; } - public SinglyLinkedListNode? Next { get; set; } - } + public SinglyLinkedListNode? Next { get; set; } } diff --git a/DataStructures/LinkedList/SkipList/SkipList.cs b/DataStructures/LinkedList/SkipList/SkipList.cs index cb07af0e..590b4bda 100644 --- a/DataStructures/LinkedList/SkipList/SkipList.cs +++ b/DataStructures/LinkedList/SkipList/SkipList.cs @@ -3,218 +3,217 @@ using System.Diagnostics; using System.Linq; -namespace DataStructures.LinkedList.SkipList +namespace DataStructures.LinkedList.SkipList; + +/// +/// Skip list implementation that is based on the singly linked list, +/// but offers O(log n) time complexity on most operations. +/// +/// The type of the values in the list. +/// +/// Skip list nodes sorted by key. +/// The "skip lanes" allow searching for a node in O(log n) time on average. +/// The worst case performence is O(n) when the height of all nodes is 1 (very +/// unluckily to happen on any decent list size). +/// These two properties make the skip list an excellent data structure for +/// implementing additional operations like finding min/max value in the list, +/// finding values with the key in a given range, etc. +/// +/// Sourses: +/// - "Skip Lists: A Probabilistic Alternative to Balanced Trees" by William Pugh. +/// - https://en.wikipedia.org/wiki/Skip_list +/// - https://iq.opengenus.org/skip-list/ +/// - https://medium.com/simple-computer-science/data-structures-basics-skip-list-8b8c69f9a044 +/// - https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java +/// +/// The key is hardcoded to be of type int to simplify the implementation, +/// but it can be easily an any generic type that implements IComparable. +/// +[DebuggerDisplay("Count = {Count}")] +public class SkipList { + private const double Probability = 0.5; + private readonly int maxLevels; + private readonly SkipListNode head; + private readonly SkipListNode tail; + private readonly Random random = new Random(); + /// - /// Skip list implementation that is based on the singly linked list, - /// but offers O(log n) time complexity on most operations. + /// Initializes a new instance of the class. /// - /// The type of the values in the list. - /// - /// Skip list nodes sorted by key. - /// The "skip lanes" allow searching for a node in O(log n) time on average. - /// The worst case performence is O(n) when the height of all nodes is 1 (very - /// unluckily to happen on any decent list size). - /// These two properties make the skip list an excellent data structure for - /// implementing additional operations like finding min/max value in the list, - /// finding values with the key in a given range, etc. - /// - /// Sourses: - /// - "Skip Lists: A Probabilistic Alternative to Balanced Trees" by William Pugh. - /// - https://en.wikipedia.org/wiki/Skip_list - /// - https://iq.opengenus.org/skip-list/ - /// - https://medium.com/simple-computer-science/data-structures-basics-skip-list-8b8c69f9a044 - /// - https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java - /// - /// The key is hardcoded to be of type int to simplify the implementation, - /// but it can be easily an any generic type that implements IComparable. - /// - [DebuggerDisplay("Count = {Count}")] - public class SkipList + /// Expected number of elements the list might contain. + public SkipList(int capacity = 255) { - private const double Probability = 0.5; - private readonly int maxLevels; - private readonly SkipListNode head; - private readonly SkipListNode tail; - private readonly Random random = new Random(); - - /// - /// Initializes a new instance of the class. - /// - /// Expected number of elements the list might contain. - public SkipList(int capacity = 255) - { - maxLevels = (int)Math.Log2(capacity) + 1; + maxLevels = (int)Math.Log2(capacity) + 1; - head = new(int.MinValue, default(TValue), maxLevels); - tail = new(int.MaxValue, default(TValue), maxLevels); + head = new(int.MinValue, default(TValue), maxLevels); + tail = new(int.MaxValue, default(TValue), maxLevels); - for(int i = 0; i < maxLevels; i++) - { - head.Next[i] = tail; - } + for(int i = 0; i < maxLevels; i++) + { + head.Next[i] = tail; } + } - /// - /// Gets the number of elements currently in the list. - /// - public int Count { get; private set; } + /// + /// Gets the number of elements currently in the list. + /// + public int Count { get; private set; } - /// - /// Gets or sets the element with the specified key. - /// - /// The key is not present in the list. - public TValue this[int key] + /// + /// Gets or sets the element with the specified key. + /// + /// The key is not present in the list. + public TValue this[int key] + { + get { - get + var previousNode = GetSkipNodes(key).First(); + if(previousNode.Next[0].Key == key) { - var previousNode = GetSkipNodes(key).First(); - if(previousNode.Next[0].Key == key) - { - return previousNode.Next[0].Value!; - } - else - { - throw new KeyNotFoundException(); - } + return previousNode.Next[0].Value!; } - - set => AddOrUpdate(key, value); - } - - /// - /// Adds an element with the specified key and value to the list. - /// If an element with the same key already exists, updates its value. - /// - /// The key of the element to add. - /// The value of the element to add. - /// - /// Time complexity: O(log n) where n is the number of elements in the list. - /// - public void AddOrUpdate(int key, TValue value) - { - var skipNodes = GetSkipNodes(key); - - var previousNode = skipNodes.First(); - if (previousNode.Next[0].Key == key) + else { - // Node with the given key already exists. - // Update its value. - previousNode.Next[0].Value = value; - return; + throw new KeyNotFoundException(); } + } - // Node with the given key does not exist. - // Insert the new one and update the skip nodes. - var newNode = new SkipListNode(key, value, GetRandomHeight()); - for (var level = 0; level < newNode.Height; level++) - { - newNode.Next[level] = skipNodes[level].Next[level]; - skipNodes[level].Next[level] = newNode; - } + set => AddOrUpdate(key, value); + } - Count++; - } + /// + /// Adds an element with the specified key and value to the list. + /// If an element with the same key already exists, updates its value. + /// + /// The key of the element to add. + /// The value of the element to add. + /// + /// Time complexity: O(log n) where n is the number of elements in the list. + /// + public void AddOrUpdate(int key, TValue value) + { + var skipNodes = GetSkipNodes(key); - /// - /// Returns whether a value with the given key exists in the list. - /// - /// - /// Time complexity: O(log n) where n is the number of elements in the list. - /// - public bool Contains(int key) + var previousNode = skipNodes.First(); + if (previousNode.Next[0].Key == key) { - var previousNode = GetSkipNodes(key).First(); - return previousNode.Next[0].Key == key; + // Node with the given key already exists. + // Update its value. + previousNode.Next[0].Value = value; + return; } - /// - /// Removes the value with the given key from the list. - /// - /// - /// true if the value was removed; otherwise, false. - /// - /// - /// Time complexity: O(log n) where n is the number of elements in the list. - /// - public bool Remove(int key) + // Node with the given key does not exist. + // Insert the new one and update the skip nodes. + var newNode = new SkipListNode(key, value, GetRandomHeight()); + for (var level = 0; level < newNode.Height; level++) { - var skipNodes = GetSkipNodes(key); - var previousNode = skipNodes.First(); - if (previousNode.Next[0].Key != key) - { - return false; - } + newNode.Next[level] = skipNodes[level].Next[level]; + skipNodes[level].Next[level] = newNode; + } - // Key exists in the list, remove it and update the skip nodes. - var nodeToRemove = previousNode.Next[0]; - for (var level = 0; level < nodeToRemove.Height; level++) - { - skipNodes[level].Next[level] = nodeToRemove.Next[level]; - } + Count++; + } - Count--; + /// + /// Returns whether a value with the given key exists in the list. + /// + /// + /// Time complexity: O(log n) where n is the number of elements in the list. + /// + public bool Contains(int key) + { + var previousNode = GetSkipNodes(key).First(); + return previousNode.Next[0].Key == key; + } - return true; + /// + /// Removes the value with the given key from the list. + /// + /// + /// true if the value was removed; otherwise, false. + /// + /// + /// Time complexity: O(log n) where n is the number of elements in the list. + /// + public bool Remove(int key) + { + var skipNodes = GetSkipNodes(key); + var previousNode = skipNodes.First(); + if (previousNode.Next[0].Key != key) + { + return false; } - /// - /// Returns an enumerator that iterates through the list. - /// - /// - /// Order of values is the ascending order of their keys. - /// Time complexity: O(n) where n is the number of elements in the list. - /// - public IEnumerable GetValues() + // Key exists in the list, remove it and update the skip nodes. + var nodeToRemove = previousNode.Next[0]; + for (var level = 0; level < nodeToRemove.Height; level++) { - var current = head.Next[0]; - while (current.Key != tail.Key) - { - yield return current.Value!; - current = current.Next[0]; - } + skipNodes[level].Next[level] = nodeToRemove.Next[level]; } - /// - /// Builds a list of skip nodes on each level that - /// are closest, but smaller than the given key. - /// - /// - /// The node on level 0 will point to the node with the given key, if it exists. - /// Time complexity: O(log n) where n is the number of elements in the list. - /// - private SkipListNode[] GetSkipNodes(int key) - { - var skipNodes = new SkipListNode[maxLevels]; - var current = head; - for (var level = head.Height - 1; level >= 0; level--) - { - while (current.Next[level].Key < key) - { - current = current.Next[level]; - } + Count--; - skipNodes[level] = current; - } + return true; + } - return skipNodes; + /// + /// Returns an enumerator that iterates through the list. + /// + /// + /// Order of values is the ascending order of their keys. + /// Time complexity: O(n) where n is the number of elements in the list. + /// + public IEnumerable GetValues() + { + var current = head.Next[0]; + while (current.Key != tail.Key) + { + yield return current.Value!; + current = current.Next[0]; } + } - /// - /// Determines the height of skip levels for the new node. - /// - /// - /// Probability of the next level is 1/(2^level). - /// - private int GetRandomHeight() + /// + /// Builds a list of skip nodes on each level that + /// are closest, but smaller than the given key. + /// + /// + /// The node on level 0 will point to the node with the given key, if it exists. + /// Time complexity: O(log n) where n is the number of elements in the list. + /// + private SkipListNode[] GetSkipNodes(int key) + { + var skipNodes = new SkipListNode[maxLevels]; + var current = head; + for (var level = head.Height - 1; level >= 0; level--) { - int height = 1; - while (random.NextDouble() < Probability && height < maxLevels) + while (current.Next[level].Key < key) { - height++; + current = current.Next[level]; } - return height; + skipNodes[level] = current; } + + return skipNodes; + } + + /// + /// Determines the height of skip levels for the new node. + /// + /// + /// Probability of the next level is 1/(2^level). + /// + private int GetRandomHeight() + { + int height = 1; + while (random.NextDouble() < Probability && height < maxLevels) + { + height++; + } + + return height; } } diff --git a/DataStructures/LinkedList/SkipList/SkipListNode.cs b/DataStructures/LinkedList/SkipList/SkipListNode.cs index 38965ac2..73fc3efd 100644 --- a/DataStructures/LinkedList/SkipList/SkipListNode.cs +++ b/DataStructures/LinkedList/SkipList/SkipListNode.cs @@ -1,25 +1,23 @@ -using System; using System.Diagnostics; -namespace DataStructures.LinkedList.SkipList +namespace DataStructures.LinkedList.SkipList; + +[DebuggerDisplay("Key = {Key}, Height = {Height}, Value = {Value}")] +internal class SkipListNode { - [DebuggerDisplay("Key = {Key}, Height = {Height}, Value = {Value}")] - internal class SkipListNode + public SkipListNode(int key, TValue? value, int height) { - public SkipListNode(int key, TValue? value, int height) - { - Key = key; - Value = value; - Height = height; - Next = new SkipListNode[height]; - } + Key = key; + Value = value; + Height = height; + Next = new SkipListNode[height]; + } - public int Key { get; } + public int Key { get; } - public TValue? Value { get; set; } + public TValue? Value { get; set; } - public SkipListNode[] Next { get; } + public SkipListNode[] Next { get; } - public int Height { get; } - } + public int Height { get; } } diff --git a/DataStructures/Probabilistic/BloomFilter.cs b/DataStructures/Probabilistic/BloomFilter.cs index 80cbb5f3..7d2d00d1 100644 --- a/DataStructures/Probabilistic/BloomFilter.cs +++ b/DataStructures/Probabilistic/BloomFilter.cs @@ -1,90 +1,85 @@ -using System; -using System.Collections; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Json; -namespace DataStructures.Probabilistic +namespace DataStructures.Probabilistic; + +public class BloomFilter where T : notnull { - public class BloomFilter where T : notnull + private const uint FnvPrime = 16777619; + private const uint FnvOffsetBasis = 2166136261; + private readonly byte[] filter; + private readonly int numHashes; + private readonly int sizeBits; + + /// + /// Initializes a new instance of the class. This constructor will create a Bloom Filter + /// of an optimal size with the optimal number of hashes to minimize the error rate. + /// + /// Expected number of unique elements that could be added to the filter. + public BloomFilter(int expectedNumElements) { - private const uint FnvPrime = 16777619; - private const uint FnvOffsetBasis = 2166136261; - private readonly byte[] filter; - private readonly int numHashes; - private readonly int sizeBits; + numHashes = (int)Math.Ceiling(.693 * 8 * expectedNumElements / expectedNumElements); // compute optimal number of hashes + filter = new byte[expectedNumElements]; // set up filter with 8 times as many bits as elements + sizeBits = expectedNumElements * 8; // number of bit slots in the filter + } - /// - /// Initializes a new instance of the class. This constructor will create a Bloom Filter - /// of an optimal size with the optimal number of hashes to minimize the error rate. - /// - /// Expected number of unique elements that could be added to the filter. - public BloomFilter(int expectedNumElements) - { - numHashes = (int)Math.Ceiling(.693 * 8 * expectedNumElements / expectedNumElements); // compute optimal number of hashes - filter = new byte[expectedNumElements]; // set up filter with 8 times as many bits as elements - sizeBits = expectedNumElements * 8; // number of bit slots in the filter - } + /// + /// Initializes a new instance of the class. + /// This constructor let's you decide how large you want the filter to be as well as allowing you to specify + /// how many hashes it will use. Only use if you don't care to optimize false positivity. + /// + /// size in bits you want the filter to be. + /// number of hash functions to be used. + public BloomFilter(int sizeBits, int numHashes) + { + filter = new byte[sizeBits / 8 + 1]; + this.numHashes = numHashes; + this.sizeBits = sizeBits; + } - /// - /// Initializes a new instance of the class. - /// This constructor let's you decide how large you want the filter to be as well as allowing you to specify - /// how many hashes it will use. Only use if you don't care to optimize false positivity. - /// - /// size in bits you want the filter to be. - /// number of hash functions to be used. - public BloomFilter(int sizeBits, int numHashes) + /// + /// Inserts an item into the bloom filter. + /// + /// The item being inserted into the Bloom Filter. + public void Insert(T item) + { + foreach (var slot in GetSlots(item)) { - filter = new byte[sizeBits / 8 + 1]; - this.numHashes = numHashes; - this.sizeBits = sizeBits; + filter[slot / 8] |= (byte)(1 << (slot % 8)); // set the filter at the decided slot to 1. } + } - /// - /// Inserts an item into the bloom filter. - /// - /// The item being inserted into the Bloom Filter. - public void Insert(T item) + /// + /// Searches the Bloom Filter to determine if the item exists in the Bloom Filter. + /// + /// The item being searched for in the Bloom Filter. + /// true if the item has been added to the Bloom Filter, false otherwise. + public bool Search(T item) + { + foreach (var slot in GetSlots(item)) { - foreach (var slot in GetSlots(item)) + var @byte = filter[slot / 8]; // Extract the byte in the filter. + var mask = 1 << (slot % 8); // Build the mask for the slot number. + if ((@byte & mask) != mask) { - filter[slot / 8] |= (byte)(1 << (slot % 8)); // set the filter at the decided slot to 1. + return false; } } - /// - /// Searches the Bloom Filter to determine if the item exists in the Bloom Filter. - /// - /// The item being searched for in the Bloom Filter. - /// true if the item has been added to the Bloom Filter, false otherwise. - public bool Search(T item) - { - foreach (var slot in GetSlots(item)) - { - var @byte = filter[slot / 8]; // Extract the byte in the filter. - var mask = 1 << (slot % 8); // Build the mask for the slot number. - if ((@byte & mask) != mask) - { - return false; - } - } - - return true; - } + return true; + } - /// - /// Yields the appropriate slots for the given item. - /// - /// The item to determine the slots for. - /// The slots of the filter to flip or check. - private IEnumerable GetSlots(T item) + /// + /// Yields the appropriate slots for the given item. + /// + /// The item to determine the slots for. + /// The slots of the filter to flip or check. + private IEnumerable GetSlots(T item) + { + var hash = item.GetHashCode(); + for (var i = 0; i < numHashes; i++) { - var hash = item.GetHashCode(); - for (var i = 0; i < numHashes; i++) - { - yield return Math.Abs((i + 1) * hash) % sizeBits; - } + yield return Math.Abs((i + 1) * hash) % sizeBits; } } } diff --git a/DataStructures/Probabilistic/CountMinSketch.cs b/DataStructures/Probabilistic/CountMinSketch.cs index 403aee6d..e45f9ed2 100644 --- a/DataStructures/Probabilistic/CountMinSketch.cs +++ b/DataStructures/Probabilistic/CountMinSketch.cs @@ -1,78 +1,77 @@ -using System; +using System; -namespace DataStructures.Probabilistic +namespace DataStructures.Probabilistic; + +public class CountMinSketch where T : notnull { - public class CountMinSketch where T : notnull - { - private readonly int[][] sketch; - private readonly int numHashes; + private readonly int[][] sketch; + private readonly int numHashes; - /// - /// Initializes a new instance of the class based off dimensions - /// passed by the user. - /// - /// The width of the sketch. - /// The number of hashes to use in the sketch. - public CountMinSketch(int width, int numHashes) + /// + /// Initializes a new instance of the class based off dimensions + /// passed by the user. + /// + /// The width of the sketch. + /// The number of hashes to use in the sketch. + public CountMinSketch(int width, int numHashes) + { + sketch = new int[numHashes][]; + for (var i = 0; i < numHashes; i++) { - sketch = new int[numHashes][]; - for (var i = 0; i < numHashes; i++) - { - sketch[i] = new int[width]; - } - - this.numHashes = numHashes; + sketch[i] = new int[width]; } - /// - /// Initializes a new instance of the class based off the optimizing error rate - /// and error probability formula width = e/errorRate numHashes = ln(1.0/errorProp). - /// - /// The amount of acceptable over counting for the sketch. - /// The probability that an item will be over counted. - public CountMinSketch(double errorRate, double errorProb) + this.numHashes = numHashes; + } + + /// + /// Initializes a new instance of the class based off the optimizing error rate + /// and error probability formula width = e/errorRate numHashes = ln(1.0/errorProp). + /// + /// The amount of acceptable over counting for the sketch. + /// The probability that an item will be over counted. + public CountMinSketch(double errorRate, double errorProb) + { + var width = (int)Math.Ceiling(Math.E / errorRate); + numHashes = (int)Math.Ceiling(Math.Log(1.0 / errorProb)); + sketch = new int[numHashes][]; + for (var i = 0; i < numHashes; i++) { - var width = (int)Math.Ceiling(Math.E / errorRate); - numHashes = (int)Math.Ceiling(Math.Log(1.0 / errorProb)); - sketch = new int[numHashes][]; - for (var i = 0; i < numHashes; i++) - { - sketch[i] = new int[width]; - } + sketch[i] = new int[width]; } + } - /// - /// Inserts the provided item into the sketch. - /// - /// Item to insert. - public void Insert(T item) + /// + /// Inserts the provided item into the sketch. + /// + /// Item to insert. + public void Insert(T item) + { + var initialHash = item.GetHashCode(); + for (int i = 0; i < numHashes; i++) { - var initialHash = item.GetHashCode(); - for (int i = 0; i < numHashes; i++) - { - var slot = GetSlot(i, initialHash); - sketch[i][slot]++; - } + var slot = GetSlot(i, initialHash); + sketch[i][slot]++; } + } - /// - /// Queries the count of the given item that have been inserted into the sketch. - /// - /// item to insert into the sketch. - /// the number of times the provided item has been inserted into the sketch. - public int Query(T item) + /// + /// Queries the count of the given item that have been inserted into the sketch. + /// + /// item to insert into the sketch. + /// the number of times the provided item has been inserted into the sketch. + public int Query(T item) + { + var initialHash = item.GetHashCode(); + var min = int.MaxValue; + for (int i = 0; i < numHashes; i++) { - var initialHash = item.GetHashCode(); - var min = int.MaxValue; - for (int i = 0; i < numHashes; i++) - { - var slot = GetSlot(i, initialHash); - min = Math.Min(sketch[i][slot], min); - } - - return min; + var slot = GetSlot(i, initialHash); + min = Math.Min(sketch[i][slot], min); } - private int GetSlot(int i, int initialHash) => Math.Abs((i + 1) * initialHash) % sketch[0].Length; + return min; } + + private int GetSlot(int i, int initialHash) => Math.Abs((i + 1) * initialHash) % sketch[0].Length; } diff --git a/DataStructures/Probabilistic/HyperLogLog.cs b/DataStructures/Probabilistic/HyperLogLog.cs index d0ec709b..a7ec7148 100644 --- a/DataStructures/Probabilistic/HyperLogLog.cs +++ b/DataStructures/Probabilistic/HyperLogLog.cs @@ -1,70 +1,69 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace DataStructures.Probabilistic +namespace DataStructures.Probabilistic; + +public class HyperLogLog where T : notnull { - public class HyperLogLog where T : notnull + private const int P = 16; + private const double Alpha = .673; + private readonly int[] registers; + private readonly HashSet setRegisters; + + /// + /// Initializes a new instance of the class. + /// + public HyperLogLog() { - private const int P = 16; - private const double Alpha = .673; - private readonly int[] registers; - private readonly HashSet setRegisters; + var m = 1 << P; + registers = new int[m]; + setRegisters = new HashSet(); + } - /// - /// Initializes a new instance of the class. - /// - public HyperLogLog() + /// + /// Merge's two HyperLogLog's together to form a union HLL. + /// + /// the first HLL. + /// The second HLL. + /// A HyperLogLog with the combined values of the two sets of registers. + public static HyperLogLog Merge(HyperLogLog first, HyperLogLog second) + { + var output = new HyperLogLog(); + for (var i = 0; i < second.registers.Length; i++) { - var m = 1 << P; - registers = new int[m]; - setRegisters = new HashSet(); + output.registers[i] = Math.Max(first.registers[i], second.registers[i]); } - /// - /// Merge's two HyperLogLog's together to form a union HLL. - /// - /// the first HLL. - /// The second HLL. - /// A HyperLogLog with the combined values of the two sets of registers. - public static HyperLogLog Merge(HyperLogLog first, HyperLogLog second) - { - var output = new HyperLogLog(); - for (var i = 0; i < second.registers.Length; i++) - { - output.registers[i] = Math.Max(first.registers[i], second.registers[i]); - } - - output.setRegisters.UnionWith(first.setRegisters); - output.setRegisters.UnionWith(second.setRegisters); - return output; - } + output.setRegisters.UnionWith(first.setRegisters); + output.setRegisters.UnionWith(second.setRegisters); + return output; + } - /// - /// Adds an item to the HyperLogLog. - /// - /// The Item to be added. - public void Add(T item) - { - var x = item.GetHashCode(); - var binString = Convert.ToString(x, 2); // converts hash to binary - var j = Convert.ToInt32(binString.Substring(0, Math.Min(P, binString.Length)), 2); // convert first b bits to register index - var w = (int)Math.Log2(x ^ (x & (x - 1))); // find position of the right most 1. - registers[j] = Math.Max(registers[j], w); // set the appropriate register to the appropriate value. - setRegisters.Add(j); - } + /// + /// Adds an item to the HyperLogLog. + /// + /// The Item to be added. + public void Add(T item) + { + var x = item.GetHashCode(); + var binString = Convert.ToString(x, 2); // converts hash to binary + var j = Convert.ToInt32(binString.Substring(0, Math.Min(P, binString.Length)), 2); // convert first b bits to register index + var w = (int)Math.Log2(x ^ (x & (x - 1))); // find position of the right most 1. + registers[j] = Math.Max(registers[j], w); // set the appropriate register to the appropriate value. + setRegisters.Add(j); + } - /// - /// Determines the approximate cardinality of the HyperLogLog. - /// - /// the approximate cardinality. - public int Cardinality() - { - // calculate the bottom part of the harmonic mean of the registers - double z = setRegisters.Sum(index => Math.Pow(2, -1 * registers[index])); + /// + /// Determines the approximate cardinality of the HyperLogLog. + /// + /// the approximate cardinality. + public int Cardinality() + { + // calculate the bottom part of the harmonic mean of the registers + double z = setRegisters.Sum(index => Math.Pow(2, -1 * registers[index])); - // calculate the harmonic mean of the set registers - return (int)Math.Ceiling(Alpha * setRegisters.Count * (setRegisters.Count / z)); - } + // calculate the harmonic mean of the set registers + return (int)Math.Ceiling(Alpha * setRegisters.Count * (setRegisters.Count / z)); } } diff --git a/DataStructures/Queue/ArrayBasedQueue.cs b/DataStructures/Queue/ArrayBasedQueue.cs index da5c9581..8b220fc4 100644 --- a/DataStructures/Queue/ArrayBasedQueue.cs +++ b/DataStructures/Queue/ArrayBasedQueue.cs @@ -1,108 +1,107 @@ using System; -namespace DataStructures.Queue +namespace DataStructures.Queue; + +/// +/// Implementation of an array based queue. FIFO style. +/// +/// Generic Type. +public class ArrayBasedQueue { + private readonly T[] queue; + private int endIndex; + private bool isEmpty; + private bool isFull; + private int startIndex; + + /// + /// Initializes a new instance of the class. + /// + public ArrayBasedQueue(int capacity) + { + queue = new T[capacity]; + Clear(); + } + /// - /// Implementation of an array based queue. FIFO style. + /// Clears the queue. /// - /// Generic Type. - public class ArrayBasedQueue + public void Clear() { - private readonly T[] queue; - private int endIndex; - private bool isEmpty; - private bool isFull; - private int startIndex; - - /// - /// Initializes a new instance of the class. - /// - public ArrayBasedQueue(int capacity) + startIndex = 0; + endIndex = 0; + isEmpty = true; + isFull = false; + } + + /// + /// Returns the first item in the queue and removes it from the queue. + /// + /// Thrown if the queue is empty. + public T Dequeue() + { + if (IsEmpty()) { - queue = new T[capacity]; - Clear(); + throw new InvalidOperationException("There are no items in the queue."); } - /// - /// Clears the queue. - /// - public void Clear() + var dequeueIndex = endIndex; + endIndex++; + if (endIndex >= queue.Length) { - startIndex = 0; endIndex = 0; - isEmpty = true; - isFull = false; } - /// - /// Returns the first item in the queue and removes it from the queue. - /// - /// Thrown if the queue is empty. - public T Dequeue() - { - if (IsEmpty()) - { - throw new InvalidOperationException("There are no items in the queue."); - } - - var dequeueIndex = endIndex; - endIndex++; - if (endIndex >= queue.Length) - { - endIndex = 0; - } - - isFull = false; - isEmpty = startIndex == endIndex; - - return queue[dequeueIndex]; - } + isFull = false; + isEmpty = startIndex == endIndex; - /// - /// Returns a boolean indicating whether the queue is empty. - /// - public bool IsEmpty() => isEmpty; - - /// - /// Returns a boolean indicating whether the queue is full. - /// - public bool IsFull() => isFull; - - /// - /// Returns the first item in the queue and keeps it in the queue. - /// - /// Thrown if the queue is empty. - public T Peek() - { - if (IsEmpty()) - { - throw new InvalidOperationException("There are no items in the queue."); - } + return queue[dequeueIndex]; + } - return queue[endIndex]; - } + /// + /// Returns a boolean indicating whether the queue is empty. + /// + public bool IsEmpty() => isEmpty; - /// - /// Adds an item at the last position in the queue. - /// - /// Thrown if the queue is full. - public void Enqueue(T item) + /// + /// Returns a boolean indicating whether the queue is full. + /// + public bool IsFull() => isFull; + + /// + /// Returns the first item in the queue and keeps it in the queue. + /// + /// Thrown if the queue is empty. + public T Peek() + { + if (IsEmpty()) { - if (IsFull()) - { - throw new InvalidOperationException("The queue has reached its capacity."); - } + throw new InvalidOperationException("There are no items in the queue."); + } + + return queue[endIndex]; + } - queue[startIndex] = item; + /// + /// Adds an item at the last position in the queue. + /// + /// Thrown if the queue is full. + public void Enqueue(T item) + { + if (IsFull()) + { + throw new InvalidOperationException("The queue has reached its capacity."); + } - startIndex++; - if (startIndex >= queue.Length) - { - startIndex = 0; - } + queue[startIndex] = item; - isEmpty = false; - isFull = startIndex == endIndex; + startIndex++; + if (startIndex >= queue.Length) + { + startIndex = 0; } + + isEmpty = false; + isFull = startIndex == endIndex; } } diff --git a/DataStructures/Queue/ListBasedQueue.cs b/DataStructures/Queue/ListBasedQueue.cs index d5b53ca1..e6e49cba 100644 --- a/DataStructures/Queue/ListBasedQueue.cs +++ b/DataStructures/Queue/ListBasedQueue.cs @@ -2,76 +2,75 @@ using System.Collections.Generic; using System.Linq; -namespace DataStructures.Queue +namespace DataStructures.Queue; + +/// +/// Implementation of a list based queue. FIFO style. +/// +/// Generic Type. +public class ListBasedQueue { + private readonly LinkedList queue; + /// - /// Implementation of a list based queue. FIFO style. + /// Initializes a new instance of the class. /// - /// Generic Type. - public class ListBasedQueue - { - private readonly LinkedList queue; + public ListBasedQueue() => queue = new LinkedList(); - /// - /// Initializes a new instance of the class. - /// - public ListBasedQueue() => queue = new LinkedList(); + /// + /// Clears the queue. + /// + public void Clear() + { + queue.Clear(); + } - /// - /// Clears the queue. - /// - public void Clear() + /// + /// Returns the first item in the queue and removes it from the queue. + /// + /// Thrown if the queue is empty. + public T Dequeue() + { + if (queue.First is null) { - queue.Clear(); + throw new InvalidOperationException("There are no items in the queue."); } - /// - /// Returns the first item in the queue and removes it from the queue. - /// - /// Thrown if the queue is empty. - public T Dequeue() - { - if (queue.First is null) - { - throw new InvalidOperationException("There are no items in the queue."); - } - - var item = queue.First; - queue.RemoveFirst(); - return item.Value; - } + var item = queue.First; + queue.RemoveFirst(); + return item.Value; + } - /// - /// Returns a boolean indicating whether the queue is empty. - /// - public bool IsEmpty() => !queue.Any(); + /// + /// Returns a boolean indicating whether the queue is empty. + /// + public bool IsEmpty() => !queue.Any(); - /// - /// Returns a boolean indicating whether the queue is full. - /// - public bool IsFull() => false; + /// + /// Returns a boolean indicating whether the queue is full. + /// + public bool IsFull() => false; - /// - /// Returns the first item in the queue and keeps it in the queue. - /// - /// Thrown if the queue is empty. - public T Peek() + /// + /// Returns the first item in the queue and keeps it in the queue. + /// + /// Thrown if the queue is empty. + public T Peek() + { + if (queue.First is null) { - if (queue.First is null) - { - throw new InvalidOperationException("There are no items in the queue."); - } - - return queue.First.Value; + throw new InvalidOperationException("There are no items in the queue."); } - /// - /// Adds an item at the last position in the queue. - /// - /// Thrown if the queue is full. - public void Enqueue(T item) - { - queue.AddLast(item); - } + return queue.First.Value; + } + + /// + /// Adds an item at the last position in the queue. + /// + /// Thrown if the queue is full. + public void Enqueue(T item) + { + queue.AddLast(item); } } diff --git a/DataStructures/Queue/StackBasedQueue.cs b/DataStructures/Queue/StackBasedQueue.cs index 2b42d0ec..7b3277d0 100644 --- a/DataStructures/Queue/StackBasedQueue.cs +++ b/DataStructures/Queue/StackBasedQueue.cs @@ -1,97 +1,96 @@ -using System; +using System; using System.Collections.Generic; -namespace DataStructures.Queue +namespace DataStructures.Queue; + +/// +/// Implementation of a stack based queue. FIFO style. +/// +/// +/// Enqueue is O(1) and Dequeue is amortized O(1). +/// +/// Generic Type. +public class StackBasedQueue { + private readonly Stack input; + private readonly Stack output; + /// - /// Implementation of a stack based queue. FIFO style. + /// Initializes a new instance of the class. /// - /// - /// Enqueue is O(1) and Dequeue is amortized O(1). - /// - /// Generic Type. - public class StackBasedQueue + public StackBasedQueue() { - private readonly Stack input; - private readonly Stack output; + input = new Stack(); + output = new Stack(); + } - /// - /// Initializes a new instance of the class. - /// - public StackBasedQueue() - { - input = new Stack(); - output = new Stack(); - } + /// + /// Clears the queue. + /// + public void Clear() + { + input.Clear(); + output.Clear(); + } - /// - /// Clears the queue. - /// - public void Clear() + /// + /// Returns the first item in the queue and removes it from the queue. + /// + /// Thrown if the queue is empty. + public T Dequeue() + { + if (input.Count == 0 && output.Count == 0) { - input.Clear(); - output.Clear(); + throw new InvalidOperationException("The queue contains no items."); } - /// - /// Returns the first item in the queue and removes it from the queue. - /// - /// Thrown if the queue is empty. - public T Dequeue() + if (output.Count == 0) { - if (input.Count == 0 && output.Count == 0) - { - throw new InvalidOperationException("The queue contains no items."); - } - - if (output.Count == 0) + while (input.Count > 0) { - while (input.Count > 0) - { - var item = input.Pop(); - output.Push(item); - } + var item = input.Pop(); + output.Push(item); } - - return output.Pop(); } - /// - /// Returns a boolean indicating whether the queue is empty. - /// - public bool IsEmpty() => input.Count == 0 && output.Count == 0; + return output.Pop(); + } - /// - /// Returns a boolean indicating whether the queue is full. - /// - public bool IsFull() => false; + /// + /// Returns a boolean indicating whether the queue is empty. + /// + public bool IsEmpty() => input.Count == 0 && output.Count == 0; + + /// + /// Returns a boolean indicating whether the queue is full. + /// + public bool IsFull() => false; - /// - /// Returns the first item in the queue and keeps it in the queue. - /// - /// Thrown if the queue is empty. - public T Peek() + /// + /// Returns the first item in the queue and keeps it in the queue. + /// + /// Thrown if the queue is empty. + public T Peek() + { + if (input.Count == 0 && output.Count == 0) { - if (input.Count == 0 && output.Count == 0) - { - throw new InvalidOperationException("The queue contains no items."); - } + throw new InvalidOperationException("The queue contains no items."); + } - if (output.Count == 0) + if (output.Count == 0) + { + while (input.Count > 0) { - while (input.Count > 0) - { - var item = input.Pop(); - output.Push(item); - } + var item = input.Pop(); + output.Push(item); } - - return output.Peek(); } - /// - /// Adds an item at the last position in the queue. - /// - public void Enqueue(T item) => input.Push(item); + return output.Peek(); } + + /// + /// Adds an item at the last position in the queue. + /// + public void Enqueue(T item) => input.Push(item); } diff --git a/DataStructures/RedBlackTree/RedBlackTree.cs b/DataStructures/RedBlackTree/RedBlackTree.cs index 0a09d88a..e9cd0c30 100644 --- a/DataStructures/RedBlackTree/RedBlackTree.cs +++ b/DataStructures/RedBlackTree/RedBlackTree.cs @@ -1,872 +1,871 @@ using System; using System.Collections.Generic; -namespace DataStructures.RedBlackTree +namespace DataStructures.RedBlackTree; + +/// +/// A self-balancing bindary tree. +/// +/// +/// A red-black tree is a self-balancing binary search tree (BST) that +/// stores a color with each node. A node's color can either be red or +/// black. Several properties are maintained to ensure the tree remains +/// balanced. +/// +/// +/// A red node does not have a red child. +/// +/// +/// All null nodes are considered black. +/// +/// +/// +/// Every path from a node to its descendant leaf nodes +/// has the same number of black nodes. +/// +/// +/// +/// (Optional) The root is always black. +/// +/// +/// Red-black trees are generally slightly more unbalanced than an +/// AVL tree, but insertion and deletion is generally faster. +/// See https://en.wikipedia.org/wiki/Red%E2%80%93black_tree for more information. +/// +/// Type of key for the tree. +public class RedBlackTree { /// - /// A self-balancing bindary tree. - /// - /// - /// A red-black tree is a self-balancing binary search tree (BST) that - /// stores a color with each node. A node's color can either be red or - /// black. Several properties are maintained to ensure the tree remains - /// balanced. - /// - /// - /// A red node does not have a red child. - /// - /// - /// All null nodes are considered black. - /// - /// - /// - /// Every path from a node to its descendant leaf nodes - /// has the same number of black nodes. - /// - /// - /// - /// (Optional) The root is always black. - /// - /// - /// Red-black trees are generally slightly more unbalanced than an - /// AVL tree, but insertion and deletion is generally faster. - /// See https://en.wikipedia.org/wiki/Red%E2%80%93black_tree for more information. - /// - /// Type of key for the tree. - public class RedBlackTree - { - /// - /// Gets the number of nodes in the tree. - /// - public int Count { get; private set; } + /// Gets the number of nodes in the tree. + ///
+ public int Count { get; private set; } - /// - /// Comparer to use when comparing key values. - /// - private readonly Comparer comparer; + /// + /// Comparer to use when comparing key values. + /// + private readonly Comparer comparer; - /// - /// Reference to the root node. - /// - private RedBlackTreeNode? root; + /// + /// Reference to the root node. + /// + private RedBlackTreeNode? root; - /// - /// Initializes a new instance of the class. - /// - public RedBlackTree() - { - comparer = Comparer.Default; - } + /// + /// Initializes a new instance of the class. + /// + public RedBlackTree() + { + comparer = Comparer.Default; + } + + /// + /// Initializes a new instance of the class + /// using the specified comparer. + /// + /// Comparer to use when comparing keys. + public RedBlackTree(Comparer customComparer) + { + comparer = customComparer; + } - /// - /// Initializes a new instance of the class - /// using the specified comparer. - /// - /// Comparer to use when comparing keys. - public RedBlackTree(Comparer customComparer) + /// + /// Add a single node to the tree. + /// + /// Key value to add. + public void Add(TKey key) + { + if (root is null) { - comparer = customComparer; + // Case 3 + // New node is root + root = new RedBlackTreeNode(key, null) + { + Color = NodeColor.Black, + }; + Count++; + return; } - /// - /// Add a single node to the tree. - /// - /// Key value to add. - public void Add(TKey key) + // Regular binary tree insertion + var node = Add(root, key); + + // Get which side child was added to + var childDir = comparer.Compare(node.Key, node.Parent!.Key); + + // Set node to be new node's parent for easier handling + node = node.Parent; + + // Return tree to valid state + int addCase; + do { - if (root is null) + addCase = GetAddCase(node); + + switch(addCase) { - // Case 3 - // New node is root - root = new RedBlackTreeNode(key, null) - { - Color = NodeColor.Black, - }; - Count++; - return; + case 1: + break; + case 2: + var oldParent = node.Parent; + node = AddCase2(node); + + if (node is not null) + { + childDir = comparer.Compare(oldParent!.Key, oldParent.Parent!.Key); + } + + break; + case 4: + node.Color = NodeColor.Black; + break; + case 56: + AddCase56(node, comparer.Compare(node.Key, node.Parent!.Key), childDir); + break; + default: + throw new InvalidOperationException("It should not be possible to get here!"); } + } + while (addCase == 2 && node is not null); - // Regular binary tree insertion - var node = Add(root, key); + Count++; + } - // Get which side child was added to - var childDir = comparer.Compare(node.Key, node.Parent!.Key); + /// + /// Add multiple nodes to the tree. + /// + /// Key values to add. + public void AddRange(IEnumerable keys) + { + foreach (var key in keys) + { + Add(key); + } + } - // Set node to be new node's parent for easier handling - node = node.Parent; + /// + /// Remove a node from the tree. + /// + /// Key value to remove. + public void Remove(TKey key) + { + // Search for node + var node = Remove(root, key); - // Return tree to valid state - int addCase; - do - { - addCase = GetAddCase(node); + // Simple cases + node = RemoveSimpleCases(node); - switch(addCase) - { - case 1: - break; - case 2: - var oldParent = node.Parent; - node = AddCase2(node); - - if (node is not null) - { - childDir = comparer.Compare(oldParent!.Key, oldParent.Parent!.Key); - } - - break; - case 4: - node.Color = NodeColor.Black; - break; - case 56: - AddCase56(node, comparer.Compare(node.Key, node.Parent!.Key), childDir); - break; - default: - throw new InvalidOperationException("It should not be possible to get here!"); - } - } - while (addCase == 2 && node is not null); + // Exit if deleted node was not non-root black leaf + if (node is null) + { + return; + } - Count++; + // Delete node + DeleteLeaf(node.Parent!, comparer.Compare(node.Key, node.Parent!.Key)); + + // Recolor tree + do + { + node = RemoveRecolor(node); } + while (node is not null && node.Parent is not null); // Case 2: Reached root - /// - /// Add multiple nodes to the tree. - /// - /// Key values to add. - public void AddRange(IEnumerable keys) + Count--; + } + + /// + /// Check if given node is in the tree. + /// + /// Key value to search for. + /// Whether or not the node is in the tree. + public bool Contains(TKey key) + { + var node = root; + while (node is not null) { - foreach (var key in keys) + var compareResult = comparer.Compare(key, node.Key); + if (compareResult < 0) + { + node = node.Left; + } + else if (compareResult > 0) + { + node = node.Right; + } + else { - Add(key); + return true; } } - /// - /// Remove a node from the tree. - /// - /// Key value to remove. - public void Remove(TKey key) + return false; + } + + /// + /// Get the minimum value in the tree. + /// + /// Minimum value in tree. + public TKey GetMin() + { + if (root is null) + { + throw new InvalidOperationException("Tree is empty!"); + } + + return GetMin(root).Key; + } + + /// + /// Get the maximum value in the tree. + /// + /// Maximum value in tree. + public TKey GetMax() + { + if (root is null) { - // Search for node - var node = Remove(root, key); + throw new InvalidOperationException("Tree is empty!"); + } + + return GetMax(root).Key; + } - // Simple cases - node = RemoveSimpleCases(node); + /// + /// Get keys in order from smallest to largest as defined by the comparer. + /// + /// Keys in tree in order from smallest to largest. + public IEnumerable GetKeysInOrder() + { + var result = new List(); + InOrderWalk(root); + return result; - // Exit if deleted node was not non-root black leaf + void InOrderWalk(RedBlackTreeNode? node) + { if (node is null) { return; } - // Delete node - DeleteLeaf(node.Parent!, comparer.Compare(node.Key, node.Parent!.Key)); + InOrderWalk(node.Left); + result.Add(node.Key); + InOrderWalk(node.Right); + } + } + + /// + /// Get keys in the pre-order order. + /// + /// Keys in pre-order order. + public IEnumerable GetKeysPreOrder() + { + var result = new List(); + PreOrderWalk(root); + return result; - // Recolor tree - do + void PreOrderWalk(RedBlackTreeNode? node) + { + if (node is null) { - node = RemoveRecolor(node); + return; } - while (node is not null && node.Parent is not null); // Case 2: Reached root - Count--; + result.Add(node.Key); + PreOrderWalk(node.Left); + PreOrderWalk(node.Right); } + } + + /// + /// Get keys in the post-order order. + /// + /// Keys in the post-order order. + public IEnumerable GetKeysPostOrder() + { + var result = new List(); + PostOrderWalk(root); + return result; - /// - /// Check if given node is in the tree. - /// - /// Key value to search for. - /// Whether or not the node is in the tree. - public bool Contains(TKey key) + void PostOrderWalk(RedBlackTreeNode? node) { - var node = root; - while (node is not null) + if (node is null) { - var compareResult = comparer.Compare(key, node.Key); - if (compareResult < 0) + return; + } + + PostOrderWalk(node.Left); + PostOrderWalk(node.Right); + result.Add(node.Key); + } + } + + /// + /// Perform binary tree insertion. + /// + /// Root of subtree to search from. + /// Key value to insert. + /// Node that was added. + private RedBlackTreeNode Add(RedBlackTreeNode node, TKey key) + { + int compareResult; + RedBlackTreeNode newNode; + while (true) + { + compareResult = comparer.Compare(key, node!.Key); + if (compareResult < 0) + { + if (node.Left is null) + { + newNode = new RedBlackTreeNode(key, node); + node.Left = newNode; + break; + } + else { node = node.Left; } - else if (compareResult > 0) + } + else if (compareResult > 0) + { + if (node.Right is null) { - node = node.Right; + newNode = new RedBlackTreeNode(key, node); + node.Right = newNode; + break; } else { - return true; + node = node.Right; } } + else + { + throw new ArgumentException($"Key \"{key}\" already exists in tree!"); + } + } + + return newNode; + } + + /// + /// Perform case 2 of insertion by pushing blackness down from parent. + /// + /// Parent of inserted node. + /// Grandparent of inserted node. + private RedBlackTreeNode? AddCase2(RedBlackTreeNode node) + { + var grandparent = node.Parent; + var parentDir = comparer.Compare(node.Key, node.Parent!.Key); + var uncle = parentDir < 0 ? grandparent!.Right : grandparent!.Left; + + node.Color = NodeColor.Black; + uncle!.Color = NodeColor.Black; + grandparent.Color = NodeColor.Red; - return false; + // Keep root black + if (node.Parent.Parent is null) + { + node.Parent.Color = NodeColor.Black; } - /// - /// Get the minimum value in the tree. - /// - /// Minimum value in tree. - public TKey GetMin() + // Set current node as parent to move up tree + return node.Parent.Parent; + } + + /// + /// Perform rotations needed for cases 5 and 6 of insertion. + /// + /// Parent of node just inserted. + /// The side node is on of its parent. + /// The side the child node is on. + private void AddCase56(RedBlackTreeNode node, int parentDir, int childDir) + { + if (parentDir < 0) { - if (root is null) + // Case 5 + if (childDir > 0) { - throw new InvalidOperationException("Tree is empty!"); + node = RotateLeft(node); } - return GetMin(root).Key; + // Case 6 + node = RotateRight(node.Parent!); + node.Color = NodeColor.Black; + node.Right!.Color = NodeColor.Red; } - - /// - /// Get the maximum value in the tree. - /// - /// Maximum value in tree. - public TKey GetMax() + else { - if (root is null) + // Case 5 + if (childDir < 0) { - throw new InvalidOperationException("Tree is empty!"); + node = RotateRight(node); } - return GetMax(root).Key; + // Case 6 + node = RotateLeft(node.Parent!); + node.Color = NodeColor.Black; + node.Left!.Color = NodeColor.Red; } + } - /// - /// Get keys in order from smallest to largest as defined by the comparer. - /// - /// Keys in tree in order from smallest to largest. - public IEnumerable GetKeysInOrder() + /// + /// Determine which add case applies to inserted node. + /// + /// Parent of inserted node. + /// Case number needed to get tree in valid state. Cases 5 and 6 are represented by 56. + private int GetAddCase(RedBlackTreeNode node) + { + if (node.Color == NodeColor.Black) { - var result = new List(); - InOrderWalk(root); - return result; - - void InOrderWalk(RedBlackTreeNode? node) - { - if (node is null) - { - return; - } - - InOrderWalk(node.Left); - result.Add(node.Key); - InOrderWalk(node.Right); - } + return 1; } - - /// - /// Get keys in the pre-order order. - /// - /// Keys in pre-order order. - public IEnumerable GetKeysPreOrder() + else if (node.Parent is null) { - var result = new List(); - PreOrderWalk(root); - return result; - - void PreOrderWalk(RedBlackTreeNode? node) - { - if (node is null) - { - return; - } - - result.Add(node.Key); - PreOrderWalk(node.Left); - PreOrderWalk(node.Right); - } + return 4; } - - /// - /// Get keys in the post-order order. - /// - /// Keys in the post-order order. - public IEnumerable GetKeysPostOrder() + else { - var result = new List(); - PostOrderWalk(root); - return result; + // Remaining insert cases need uncle + var grandparent = node.Parent; + var parentDir = comparer.Compare(node.Key, node.Parent.Key); + var uncle = parentDir < 0 ? grandparent.Right : grandparent.Left; - void PostOrderWalk(RedBlackTreeNode? node) + // Case 5 & 6 + if (uncle is null || uncle.Color == NodeColor.Black) { - if (node is null) - { - return; - } - - PostOrderWalk(node.Left); - PostOrderWalk(node.Right); - result.Add(node.Key); + return 56; } + + return 2; } + } - /// - /// Perform binary tree insertion. - /// - /// Root of subtree to search from. - /// Key value to insert. - /// Node that was added. - private RedBlackTreeNode Add(RedBlackTreeNode node, TKey key) + /// + /// Search for the node to be deleted. + /// + /// Node to start search from. + /// Key to search for. + /// Node to be deleted. + private RedBlackTreeNode Remove(RedBlackTreeNode? node, TKey key) + { + if (node is null) + { + throw new InvalidOperationException("Tree is empty!"); + } + else if (!Contains(key)) { - int compareResult; - RedBlackTreeNode newNode; + throw new KeyNotFoundException($"Key {key} is not in the tree!"); + } + else + { + // Find node + int dir; while (true) { - compareResult = comparer.Compare(key, node!.Key); - if (compareResult < 0) + dir = comparer.Compare(key, node!.Key); + if (dir < 0) { - if (node.Left is null) - { - newNode = new RedBlackTreeNode(key, node); - node.Left = newNode; - break; - } - else - { - node = node.Left; - } + node = node.Left; } - else if (compareResult > 0) + else if (dir > 0) { - if (node.Right is null) - { - newNode = new RedBlackTreeNode(key, node); - node.Right = newNode; - break; - } - else - { - node = node.Right; - } + node = node.Right; } else { - throw new ArgumentException($"Key \"{key}\" already exists in tree!"); + break; } } - return newNode; + return node; } + } - /// - /// Perform case 2 of insertion by pushing blackness down from parent. - /// - /// Parent of inserted node. - /// Grandparent of inserted node. - private RedBlackTreeNode? AddCase2(RedBlackTreeNode node) - { - var grandparent = node.Parent; - var parentDir = comparer.Compare(node.Key, node.Parent!.Key); - var uncle = parentDir < 0 ? grandparent!.Right : grandparent!.Left; - - node.Color = NodeColor.Black; - uncle!.Color = NodeColor.Black; - grandparent.Color = NodeColor.Red; + /// + /// Get the tree back into a valid state after removing non-root black leaf. + /// + /// Non-root black leaf being removed. + private RedBlackTreeNode? RemoveRecolor(RedBlackTreeNode node) + { + var removeCase = GetRemoveCase(node); - // Keep root black - if (node.Parent.Parent is null) - { - node.Parent.Color = NodeColor.Black; - } + var dir = comparer.Compare(node.Key, node.Parent!.Key); - // Set current node as parent to move up tree - return node.Parent.Parent; - } + // Determine current node's sibling and nephews + var sibling = dir < 0 ? node.Parent.Right : node.Parent.Left; + var closeNewphew = dir < 0 ? sibling!.Left : sibling!.Right; + var distantNephew = dir < 0 ? sibling!.Right : sibling!.Left; - /// - /// Perform rotations needed for cases 5 and 6 of insertion. - /// - /// Parent of node just inserted. - /// The side node is on of its parent. - /// The side the child node is on. - private void AddCase56(RedBlackTreeNode node, int parentDir, int childDir) + switch (removeCase) { - if (parentDir < 0) - { - // Case 5 - if (childDir > 0) - { - node = RotateLeft(node); - } + case 1: + sibling.Color = NodeColor.Red; + return node.Parent; + case 3: + RemoveCase3(node, closeNewphew, dir); + break; + case 4: + RemoveCase4(sibling); + break; + case 5: + RemoveCase5(node, sibling, dir); + break; + case 6: + RemoveCase6(node, distantNephew!, dir); + break; + default: + throw new InvalidOperationException("It should not be possible to get here!"); + } - // Case 6 - node = RotateRight(node.Parent!); - node.Color = NodeColor.Black; - node.Right!.Color = NodeColor.Red; - } - else - { - // Case 5 - if (childDir < 0) - { - node = RotateRight(node); - } + return null; + } - // Case 6 - node = RotateLeft(node.Parent!); - node.Color = NodeColor.Black; - node.Left!.Color = NodeColor.Red; - } + /// + /// Simple removal cases where black height doesn't change. + /// + /// Node to remove. + /// Non-root black leaf node or null. Null indicates that removal was performed. + private RedBlackTreeNode? RemoveSimpleCases(RedBlackTreeNode node) + { + // Node to delete is root and has no children + if (node.Parent is null && node.Left is null && node.Right is null) + { + root = null; + Count--; + return null; } - /// - /// Determine which add case applies to inserted node. - /// - /// Parent of inserted node. - /// Case number needed to get tree in valid state. Cases 5 and 6 are represented by 56. - private int GetAddCase(RedBlackTreeNode node) + // Node has two children. Swap pointers + if (node.Left is not null && node.Right is not null) { - if (node.Color == NodeColor.Black) - { - return 1; - } - else if (node.Parent is null) - { - return 4; - } - else - { - // Remaining insert cases need uncle - var grandparent = node.Parent; - var parentDir = comparer.Compare(node.Key, node.Parent.Key); - var uncle = parentDir < 0 ? grandparent.Right : grandparent.Left; - - // Case 5 & 6 - if (uncle is null || uncle.Color == NodeColor.Black) - { - return 56; - } - - return 2; - } + var successor = GetMin(node.Right); + node.Key = successor.Key; + node = successor; } - /// - /// Search for the node to be deleted. - /// - /// Node to start search from. - /// Key to search for. - /// Node to be deleted. - private RedBlackTreeNode Remove(RedBlackTreeNode? node, TKey key) + // At this point node should have at most one child + if (node.Color == NodeColor.Red) { - if (node is null) - { - throw new InvalidOperationException("Tree is empty!"); - } - else if (!Contains(key)) - { - throw new KeyNotFoundException($"Key {key} is not in the tree!"); - } - else - { - // Find node - int dir; - while (true) - { - dir = comparer.Compare(key, node!.Key); - if (dir < 0) - { - node = node.Left; - } - else if (dir > 0) - { - node = node.Right; - } - else - { - break; - } - } + // Node is red so it must have no children since it doesn't have two children + DeleteLeaf(node.Parent!, comparer.Compare(node.Key, node.Parent!.Key)); - return node; - } + Count--; + return null; } - - /// - /// Get the tree back into a valid state after removing non-root black leaf. - /// - /// Non-root black leaf being removed. - private RedBlackTreeNode? RemoveRecolor(RedBlackTreeNode node) + else { - var removeCase = GetRemoveCase(node); - - var dir = comparer.Compare(node.Key, node.Parent!.Key); - - // Determine current node's sibling and nephews - var sibling = dir < 0 ? node.Parent.Right : node.Parent.Left; - var closeNewphew = dir < 0 ? sibling!.Left : sibling!.Right; - var distantNephew = dir < 0 ? sibling!.Right : sibling!.Left; + // Node is black and may or may not be node + return RemoveBlackNode(node); + } + } - switch (removeCase) - { - case 1: - sibling.Color = NodeColor.Red; - return node.Parent; - case 3: - RemoveCase3(node, closeNewphew, dir); - break; - case 4: - RemoveCase4(sibling); - break; - case 5: - RemoveCase5(node, sibling, dir); - break; - case 6: - RemoveCase6(node, distantNephew!, dir); - break; - default: - throw new InvalidOperationException("It should not be possible to get here!"); - } + /// + /// Node to delete is black. If it is a leaf then we need to recolor, otherwise remove it. + /// + /// Black node to examine. + /// Node to start recoloring from. Null if deletion occurred. + private RedBlackTreeNode? RemoveBlackNode(RedBlackTreeNode node) + { + // Node is black and has at most one child. If it has a child it must be red. + var child = node.Left ?? node.Right; - return null; + // Continue to recoloring if node is leaf + if (child is null) + { + return node; } - /// - /// Simple removal cases where black height doesn't change. - /// - /// Node to remove. - /// Non-root black leaf node or null. Null indicates that removal was performed. - private RedBlackTreeNode? RemoveSimpleCases(RedBlackTreeNode node) - { - // Node to delete is root and has no children - if (node.Parent is null && node.Left is null && node.Right is null) - { - root = null; - Count--; - return null; - } + // Recolor child + child.Color = NodeColor.Black; + child.Parent = node.Parent; - // Node has two children. Swap pointers - if (node.Left is not null && node.Right is not null) - { - var successor = GetMin(node.Right); - node.Key = successor.Key; - node = successor; - } + var childDir = node.Parent is null ? 0 : comparer.Compare(node.Key, node.Parent.Key); - // At this point node should have at most one child - if (node.Color == NodeColor.Red) - { - // Node is red so it must have no children since it doesn't have two children - DeleteLeaf(node.Parent!, comparer.Compare(node.Key, node.Parent!.Key)); + // Replace node with child + Transplant(node.Parent, child, childDir); - Count--; - return null; - } - else - { - // Node is black and may or may not be node - return RemoveBlackNode(node); - } + Count--; + return null; + } + + /// + /// Perform case 3 of removal. + /// + /// Node that was removed. + /// Close nephew of removed node. + /// Side of parent the removed node was. + private void RemoveCase3(RedBlackTreeNode node, RedBlackTreeNode? closeNephew, int childDir) + { + // Rotate and recolor + var sibling = childDir < 0 ? RotateLeft(node.Parent!) : RotateRight(node.Parent!); + sibling.Color = NodeColor.Black; + if (childDir < 0) + { + sibling.Left!.Color = NodeColor.Red; + } + else + { + sibling.Right!.Color = NodeColor.Red; } - /// - /// Node to delete is black. If it is a leaf then we need to recolor, otherwise remove it. - /// - /// Black node to examine. - /// Node to start recoloring from. Null if deletion occurred. - private RedBlackTreeNode? RemoveBlackNode(RedBlackTreeNode node) + // Get new distant newphew + sibling = closeNephew!; + var distantNephew = childDir < 0 ? sibling.Right : sibling.Left; + + // Parent is red, sibling is black + if (distantNephew is not null && distantNephew.Color == NodeColor.Red) { - // Node is black and has at most one child. If it has a child it must be red. - var child = node.Left ?? node.Right; + RemoveCase6(node, distantNephew, childDir); + return; + } - // Continue to recoloring if node is leaf - if (child is null) - { - return node; - } + // Get new close nephew + closeNephew = childDir < 0 ? sibling!.Left : sibling!.Right; - // Recolor child - child.Color = NodeColor.Black; - child.Parent = node.Parent; + // Sibling is black, distant nephew is black + if (closeNephew is not null && closeNephew.Color == NodeColor.Red) + { + RemoveCase5(node, sibling!, childDir); + return; + } - var childDir = node.Parent is null ? 0 : comparer.Compare(node.Key, node.Parent.Key); + // Final recoloring + RemoveCase4(sibling!); + } - // Replace node with child - Transplant(node.Parent, child, childDir); + /// + /// Perform case 4 of removal. + /// + /// Sibling of removed node. + private void RemoveCase4(RedBlackTreeNode sibling) + { + sibling.Color = NodeColor.Red; + sibling.Parent!.Color = NodeColor.Black; + } - Count--; - return null; - } + /// + /// Perform case 5 of removal. + /// + /// Node that was removed. + /// Sibling of removed node. + /// Side of parent removed node was on. + private void RemoveCase5(RedBlackTreeNode node, RedBlackTreeNode sibling, int childDir) + { + sibling = childDir < 0 ? RotateRight(sibling) : RotateLeft(sibling); + var distantNephew = childDir < 0 ? sibling.Right! : sibling.Left!; - /// - /// Perform case 3 of removal. - /// - /// Node that was removed. - /// Close nephew of removed node. - /// Side of parent the removed node was. - private void RemoveCase3(RedBlackTreeNode node, RedBlackTreeNode? closeNephew, int childDir) - { - // Rotate and recolor - var sibling = childDir < 0 ? RotateLeft(node.Parent!) : RotateRight(node.Parent!); - sibling.Color = NodeColor.Black; - if (childDir < 0) - { - sibling.Left!.Color = NodeColor.Red; - } - else - { - sibling.Right!.Color = NodeColor.Red; - } + sibling.Color = NodeColor.Black; + distantNephew.Color = NodeColor.Red; - // Get new distant newphew - sibling = closeNephew!; - var distantNephew = childDir < 0 ? sibling.Right : sibling.Left; + RemoveCase6(node, distantNephew, childDir); + } - // Parent is red, sibling is black - if (distantNephew is not null && distantNephew.Color == NodeColor.Red) - { - RemoveCase6(node, distantNephew, childDir); - return; - } + /// + /// Perform case 6 of removal. + /// + /// Node that was removed. + /// Distant nephew of removed node. + /// Side of parent removed node was on. + private void RemoveCase6(RedBlackTreeNode node, RedBlackTreeNode distantNephew, int childDir) + { + var oldParent = node.Parent!; + node = childDir < 0 ? RotateLeft(oldParent) : RotateRight(oldParent); + node.Color = oldParent.Color; + oldParent.Color = NodeColor.Black; + distantNephew.Color = NodeColor.Black; + } - // Get new close nephew - closeNephew = childDir < 0 ? sibling!.Left : sibling!.Right; + /// + /// Determine which removal case is required. + /// + /// Node being removed. + /// Which removal case should be performed. + private int GetRemoveCase(RedBlackTreeNode node) + { + var dir = comparer.Compare(node.Key, node.Parent!.Key); - // Sibling is black, distant nephew is black - if (closeNephew is not null && closeNephew.Color == NodeColor.Red) - { - RemoveCase5(node, sibling!, childDir); - return; - } + // Determine current node's sibling and nephews + var sibling = dir < 0 ? node.Parent.Right : node.Parent.Left; + var closeNewphew = dir < 0 ? sibling!.Left : sibling!.Right; + var distantNephew = dir < 0 ? sibling!.Right : sibling!.Left; - // Final recoloring - RemoveCase4(sibling!); + if (sibling.Color == NodeColor.Red) + { + return 3; } - - /// - /// Perform case 4 of removal. - /// - /// Sibling of removed node. - private void RemoveCase4(RedBlackTreeNode sibling) + else if (distantNephew is not null && distantNephew.Color == NodeColor.Red) { - sibling.Color = NodeColor.Red; - sibling.Parent!.Color = NodeColor.Black; + return 6; } - - /// - /// Perform case 5 of removal. - /// - /// Node that was removed. - /// Sibling of removed node. - /// Side of parent removed node was on. - private void RemoveCase5(RedBlackTreeNode node, RedBlackTreeNode sibling, int childDir) + else if (closeNewphew is not null && closeNewphew.Color == NodeColor.Red) { - sibling = childDir < 0 ? RotateRight(sibling) : RotateLeft(sibling); - var distantNephew = childDir < 0 ? sibling.Right! : sibling.Left!; - - sibling.Color = NodeColor.Black; - distantNephew.Color = NodeColor.Red; - - RemoveCase6(node, distantNephew, childDir); + return 5; } - - /// - /// Perform case 6 of removal. - /// - /// Node that was removed. - /// Distant nephew of removed node. - /// Side of parent removed node was on. - private void RemoveCase6(RedBlackTreeNode node, RedBlackTreeNode distantNephew, int childDir) + else if (node.Parent.Color == NodeColor.Red) { - var oldParent = node.Parent!; - node = childDir < 0 ? RotateLeft(oldParent) : RotateRight(oldParent); - node.Color = oldParent.Color; - oldParent.Color = NodeColor.Black; - distantNephew.Color = NodeColor.Black; + return 4; } - - /// - /// Determine which removal case is required. - /// - /// Node being removed. - /// Which removal case should be performed. - private int GetRemoveCase(RedBlackTreeNode node) + else { - var dir = comparer.Compare(node.Key, node.Parent!.Key); - - // Determine current node's sibling and nephews - var sibling = dir < 0 ? node.Parent.Right : node.Parent.Left; - var closeNewphew = dir < 0 ? sibling!.Left : sibling!.Right; - var distantNephew = dir < 0 ? sibling!.Right : sibling!.Left; - - if (sibling.Color == NodeColor.Red) - { - return 3; - } - else if (distantNephew is not null && distantNephew.Color == NodeColor.Red) - { - return 6; - } - else if (closeNewphew is not null && closeNewphew.Color == NodeColor.Red) - { - return 5; - } - else if (node.Parent.Color == NodeColor.Red) - { - return 4; - } - else - { - return 1; - } + return 1; } + } - /// - /// Set child of node or delete leaf. - /// - /// Node to set child of. Set to null for root. - /// Node to set as child. - /// Which side of node to place child. - private void Transplant(RedBlackTreeNode? node, RedBlackTreeNode? child, int dir) + /// + /// Set child of node or delete leaf. + /// + /// Node to set child of. Set to null for root. + /// Node to set as child. + /// Which side of node to place child. + private void Transplant(RedBlackTreeNode? node, RedBlackTreeNode? child, int dir) + { + if (node is null) { - if (node is null) - { - root = child; - } - else if (child is null) - { - DeleteLeaf(node, dir); - } - else if (dir < 0) - { - node.Left = child; - } - else - { - node.Right = child; - } + root = child; } - - /// - /// Delete leaf node. - /// - /// Parent of leaf node to delete. - /// Side of parent leaf is on. - private void DeleteLeaf(RedBlackTreeNode node, int dir) + else if (child is null) { - if (dir < 0) - { - node.Left = null; - } - else - { - node.Right = null; - } + DeleteLeaf(node, dir); } - - /// - /// Perform a left (counter-clockwise) rotation. - /// - /// Node to rotate about. - /// New node with rotation applied. - private RedBlackTreeNode RotateLeft(RedBlackTreeNode node) + else if (dir < 0) + { + node.Left = child; + } + else { - var temp1 = node; - var temp2 = node!.Right!.Left; + node.Right = child; + } + } - node = node.Right; - node.Parent = temp1.Parent; - if (node.Parent is not null) - { - var nodeDir = comparer.Compare(node.Key, node.Parent.Key); - if (nodeDir < 0) - { - node.Parent.Left = node; - } - else - { - node.Parent.Right = node; - } - } + /// + /// Delete leaf node. + /// + /// Parent of leaf node to delete. + /// Side of parent leaf is on. + private void DeleteLeaf(RedBlackTreeNode node, int dir) + { + if (dir < 0) + { + node.Left = null; + } + else + { + node.Right = null; + } + } - node.Left = temp1; - node.Left.Parent = node; + /// + /// Perform a left (counter-clockwise) rotation. + /// + /// Node to rotate about. + /// New node with rotation applied. + private RedBlackTreeNode RotateLeft(RedBlackTreeNode node) + { + var temp1 = node; + var temp2 = node!.Right!.Left; - node.Left.Right = temp2; - if (temp2 is not null) + node = node.Right; + node.Parent = temp1.Parent; + if (node.Parent is not null) + { + var nodeDir = comparer.Compare(node.Key, node.Parent.Key); + if (nodeDir < 0) { - node.Left.Right!.Parent = temp1; + node.Parent.Left = node; } - - if (node.Parent is null) + else { - root = node; + node.Parent.Right = node; } + } - return node; + node.Left = temp1; + node.Left.Parent = node; + + node.Left.Right = temp2; + if (temp2 is not null) + { + node.Left.Right!.Parent = temp1; } - /// - /// Perform a right (clockwise) rotation. - /// - /// Node to rotate about. - /// New node with rotation applied. - private RedBlackTreeNode RotateRight(RedBlackTreeNode node) + if (node.Parent is null) { - var temp1 = node; - var temp2 = node!.Left!.Right; + root = node; + } - node = node.Left; - node.Parent = temp1.Parent; - if (node.Parent is not null) - { - var nodeDir = comparer.Compare(node.Key, node.Parent.Key); - if (nodeDir < 0) - { - node.Parent.Left = node; - } - else - { - node.Parent.Right = node; - } - } + return node; + } - node.Right = temp1; - node.Right.Parent = node; + /// + /// Perform a right (clockwise) rotation. + /// + /// Node to rotate about. + /// New node with rotation applied. + private RedBlackTreeNode RotateRight(RedBlackTreeNode node) + { + var temp1 = node; + var temp2 = node!.Left!.Right; - node.Right.Left = temp2; - if (temp2 is not null) + node = node.Left; + node.Parent = temp1.Parent; + if (node.Parent is not null) + { + var nodeDir = comparer.Compare(node.Key, node.Parent.Key); + if (nodeDir < 0) { - node.Right.Left!.Parent = temp1; + node.Parent.Left = node; } - - if (node.Parent is null) + else { - root = node; + node.Parent.Right = node; } - - return node; } - /// - /// Helper function to get node instance with minimum key value - /// in the specified subtree. - /// - /// Node specifying root of subtree. - /// Minimum value in node's subtree. - private RedBlackTreeNode GetMin(RedBlackTreeNode node) + node.Right = temp1; + node.Right.Parent = node; + + node.Right.Left = temp2; + if (temp2 is not null) { - while (node.Left is not null) - { - node = node.Left; - } + node.Right.Left!.Parent = temp1; + } - return node; + if (node.Parent is null) + { + root = node; } - /// - /// Helper function to get node instance with maximum key value - /// in the specified subtree. - /// - /// Node specifyng root of subtree. - /// Maximum value in node's subtree. - private RedBlackTreeNode GetMax(RedBlackTreeNode node) + return node; + } + + /// + /// Helper function to get node instance with minimum key value + /// in the specified subtree. + /// + /// Node specifying root of subtree. + /// Minimum value in node's subtree. + private RedBlackTreeNode GetMin(RedBlackTreeNode node) + { + while (node.Left is not null) { - while (node.Right is not null) - { - node = node.Right; - } + node = node.Left; + } - return node; + return node; + } + + /// + /// Helper function to get node instance with maximum key value + /// in the specified subtree. + /// + /// Node specifyng root of subtree. + /// Maximum value in node's subtree. + private RedBlackTreeNode GetMax(RedBlackTreeNode node) + { + while (node.Right is not null) + { + node = node.Right; } + + return node; } } diff --git a/DataStructures/RedBlackTree/RedBlackTreeNode.cs b/DataStructures/RedBlackTree/RedBlackTreeNode.cs index f4f2ad66..5c888b38 100644 --- a/DataStructures/RedBlackTree/RedBlackTreeNode.cs +++ b/DataStructures/RedBlackTree/RedBlackTreeNode.cs @@ -1,61 +1,60 @@ -namespace DataStructures.RedBlackTree +namespace DataStructures.RedBlackTree; + +/// +/// Enum to represent node colors. +/// +public enum NodeColor : byte { /// - /// Enum to represent node colors. + /// Represents red node /// - public enum NodeColor : byte - { - /// - /// Represents red node - /// - Red, - - /// - /// Represents black node - /// - Black, - } + Red, + + /// + /// Represents black node + /// + Black, +} + +/// +/// Generic class to represent nodes in an instance. +/// +/// The type of key for the node. +public class RedBlackTreeNode +{ + /// + /// Gets or sets key value of node. + /// + public TKey Key { get; set; } + + /// + /// Gets or sets the color of the node. + /// + public NodeColor Color { get; set; } + + /// + /// Gets or sets the parent of the node. + /// + public RedBlackTreeNode? Parent { get; set; } + + /// + /// Gets or sets left child of the node. + /// + public RedBlackTreeNode? Left { get; set; } + + /// + /// Gets or sets the right child of the node. + /// + public RedBlackTreeNode? Right { get; set; } /// - /// Generic class to represent nodes in an instance. + /// Initializes a new instance of the class. /// - /// The type of key for the node. - public class RedBlackTreeNode + /// Key value for node. + /// Parent of node. + public RedBlackTreeNode(TKey key, RedBlackTreeNode? parent) { - /// - /// Gets or sets key value of node. - /// - public TKey Key { get; set; } - - /// - /// Gets or sets the color of the node. - /// - public NodeColor Color { get; set; } - - /// - /// Gets or sets the parent of the node. - /// - public RedBlackTreeNode? Parent { get; set; } - - /// - /// Gets or sets left child of the node. - /// - public RedBlackTreeNode? Left { get; set; } - - /// - /// Gets or sets the right child of the node. - /// - public RedBlackTreeNode? Right { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// Key value for node. - /// Parent of node. - public RedBlackTreeNode(TKey key, RedBlackTreeNode? parent) - { - Key = key; - Parent = parent; - } + Key = key; + Parent = parent; } } diff --git a/DataStructures/ScapegoatTree/Extensions.cs b/DataStructures/ScapegoatTree/Extensions.cs index acfecac3..8146088a 100644 --- a/DataStructures/ScapegoatTree/Extensions.cs +++ b/DataStructures/ScapegoatTree/Extensions.cs @@ -1,56 +1,55 @@ using System; using System.Collections.Generic; -namespace DataStructures.ScapegoatTree +namespace DataStructures.ScapegoatTree; + +public static class Extensions { - public static class Extensions + /// + /// Flattens scapegoat tree into a list of nodes. + /// + /// Scapegoat tree provided as root node. + /// An empty list. + /// Scapegoat tree node key type. + public static void FlattenTree(Node root, List> list) where TKey : IComparable { - /// - /// Flattens scapegoat tree into a list of nodes. - /// - /// Scapegoat tree provided as root node. - /// An empty list. - /// Scapegoat tree node key type. - public static void FlattenTree(Node root, List> list) where TKey : IComparable + if (root.Left != null) { - if (root.Left != null) - { - FlattenTree(root.Left, list); - } + FlattenTree(root.Left, list); + } - list.Add(root); + list.Add(root); - if (root.Right != null) - { - FlattenTree(root.Right, list); - } + if (root.Right != null) + { + FlattenTree(root.Right, list); } + } - /// - /// Rebuilds a scapegoat tree from list of nodes. - /// Use with method. - /// - /// Flattened tree. - /// Start index. - /// End index. - /// Scapegoat tree node key type. - /// Scapegoat tree root node. - /// Thrown if start index is invalid. - public static Node RebuildFromList(IList> list, int start, int end) - where TKey : IComparable + /// + /// Rebuilds a scapegoat tree from list of nodes. + /// Use with method. + /// + /// Flattened tree. + /// Start index. + /// End index. + /// Scapegoat tree node key type. + /// Scapegoat tree root node. + /// Thrown if start index is invalid. + public static Node RebuildFromList(IList> list, int start, int end) + where TKey : IComparable + { + if (start > end) { - if (start > end) - { - throw new ArgumentException("The parameter's value is invalid.", nameof(start)); - } + throw new ArgumentException("The parameter's value is invalid.", nameof(start)); + } - var pivot = Convert.ToInt32(Math.Ceiling(start + (end - start) / 2.0)); + var pivot = Convert.ToInt32(Math.Ceiling(start + (end - start) / 2.0)); - return new Node(list[pivot].Key) - { - Left = start > (pivot - 1) ? null : RebuildFromList(list, start, pivot - 1), - Right = (pivot + 1) > end ? null : RebuildFromList(list, pivot + 1, end), - }; - } + return new Node(list[pivot].Key) + { + Left = start > (pivot - 1) ? null : RebuildFromList(list, start, pivot - 1), + Right = (pivot + 1) > end ? null : RebuildFromList(list, pivot + 1, end), + }; } } diff --git a/DataStructures/ScapegoatTree/Node.cs b/DataStructures/ScapegoatTree/Node.cs index 343a2606..624c25f1 100644 --- a/DataStructures/ScapegoatTree/Node.cs +++ b/DataStructures/ScapegoatTree/Node.cs @@ -1,88 +1,87 @@ using System; -namespace DataStructures.ScapegoatTree +namespace DataStructures.ScapegoatTree; + +/// +/// Scapegoat tree node class. +/// +/// Scapegoat tree node key type. +public class Node where TKey : IComparable { - /// - /// Scapegoat tree node class. - /// - /// Scapegoat tree node key type. - public class Node where TKey : IComparable - { - private Node? right; - private Node? left; + private Node? right; + private Node? left; - public TKey Key { get; } + public TKey Key { get; } - public Node? Right + public Node? Right + { + get => right; + set { - get => right; - set + if (value != null && !value.IsGreaterThanOrSameAs(Key)) { - if (value != null && !value.IsGreaterThanOrSameAs(Key)) - { - throw new ArgumentException("The value's key is smaller than or equal to node's right child's key.", nameof(value)); - } - - right = value; + throw new ArgumentException("The value's key is smaller than or equal to node's right child's key.", nameof(value)); } + + right = value; } + } - public Node? Left + public Node? Left + { + get => left; + set { - get => left; - set + if (value != null && value.IsGreaterThanOrSameAs(Key)) { - if (value != null && value.IsGreaterThanOrSameAs(Key)) - { - throw new ArgumentException("The value's key is greater than or equal to node's left child's key.", nameof(value)); - } - - left = value; + throw new ArgumentException("The value's key is greater than or equal to node's left child's key.", nameof(value)); } + + left = value; } + } - public Node(TKey key) => Key = key; + public Node(TKey key) => Key = key; - public Node(TKey key, Node? right, Node? left) - : this(key) - { - Right = right; - Left = left; - } + public Node(TKey key, Node? right, Node? left) + : this(key) + { + Right = right; + Left = left; + } - /// - /// Returns number of elements in the tree. - /// - /// Number of elements in the tree. - public int GetSize() => (Left?.GetSize() ?? 0) + 1 + (Right?.GetSize() ?? 0); - - /// - /// Gets alpha height of the current node. - /// - /// Alpha value. - /// Alpha height value. - public double GetAlphaHeight(double alpha) => Math.Floor(Math.Log(GetSize(), 1.0 / alpha)); - - public Node GetSmallestKeyNode() => Left?.GetSmallestKeyNode() ?? this; - - public Node GetLargestKeyNode() => Right?.GetLargestKeyNode() ?? this; - - /// - /// Checks if the current node is alpha weight balanced. - /// - /// Alpha value. - /// True - if node is alpha weight balanced. If not - false. - public bool IsAlphaWeightBalanced(double a) - { - var isLeftBalanced = (Left?.GetSize() ?? 0) <= a * GetSize(); - var isRightBalanced = (Right?.GetSize() ?? 0) <= a * GetSize(); + /// + /// Returns number of elements in the tree. + /// + /// Number of elements in the tree. + public int GetSize() => (Left?.GetSize() ?? 0) + 1 + (Right?.GetSize() ?? 0); - return isLeftBalanced && isRightBalanced; - } + /// + /// Gets alpha height of the current node. + /// + /// Alpha value. + /// Alpha height value. + public double GetAlphaHeight(double alpha) => Math.Floor(Math.Log(GetSize(), 1.0 / alpha)); - private bool IsGreaterThanOrSameAs(TKey key) - { - return Key.CompareTo(key) >= 0; - } + public Node GetSmallestKeyNode() => Left?.GetSmallestKeyNode() ?? this; + + public Node GetLargestKeyNode() => Right?.GetLargestKeyNode() ?? this; + + /// + /// Checks if the current node is alpha weight balanced. + /// + /// Alpha value. + /// True - if node is alpha weight balanced. If not - false. + public bool IsAlphaWeightBalanced(double a) + { + var isLeftBalanced = (Left?.GetSize() ?? 0) <= a * GetSize(); + var isRightBalanced = (Right?.GetSize() ?? 0) <= a * GetSize(); + + return isLeftBalanced && isRightBalanced; + } + + private bool IsGreaterThanOrSameAs(TKey key) + { + return Key.CompareTo(key) >= 0; } } diff --git a/DataStructures/ScapegoatTree/ScapegoatTree.cs b/DataStructures/ScapegoatTree/ScapegoatTree.cs index 04cfacb4..a5262152 100644 --- a/DataStructures/ScapegoatTree/ScapegoatTree.cs +++ b/DataStructures/ScapegoatTree/ScapegoatTree.cs @@ -1,373 +1,372 @@ using System; using System.Collections.Generic; -namespace DataStructures.ScapegoatTree +namespace DataStructures.ScapegoatTree; + +/// +/// A scapegoat implementation class. +/// See https://en.wikipedia.org/wiki/Scapegoat_tree for more information about scapegoat tree. +/// +/// The scapegoat tree key type. +public class ScapegoatTree where TKey : IComparable { /// - /// A scapegoat implementation class. - /// See https://en.wikipedia.org/wiki/Scapegoat_tree for more information about scapegoat tree. + /// Gets the α (alpha) value of the tree. /// - /// The scapegoat tree key type. - public class ScapegoatTree where TKey : IComparable + public double Alpha { get; private set; } + + /// + /// Gets the root node of the tree. + /// + public Node? Root { get; private set; } + + /// + /// Gets the number of nodes in the tree. + /// + public int Size { get; private set; } + + /// + /// Gets the maximal value of the tree Size since the last time the tree was completely rebuilt. + /// + public int MaxSize { get; private set; } + + /// + /// Gets an event handler which will fire when tree is being balanced. + /// + public event EventHandler? TreeIsUnbalanced; + + public ScapegoatTree() + : this(alpha: 0.5, size: 0) { - /// - /// Gets the α (alpha) value of the tree. - /// - public double Alpha { get; private set; } - - /// - /// Gets the root node of the tree. - /// - public Node? Root { get; private set; } - - /// - /// Gets the number of nodes in the tree. - /// - public int Size { get; private set; } - - /// - /// Gets the maximal value of the tree Size since the last time the tree was completely rebuilt. - /// - public int MaxSize { get; private set; } - - /// - /// Gets an event handler which will fire when tree is being balanced. - /// - public event EventHandler? TreeIsUnbalanced; - - public ScapegoatTree() - : this(alpha: 0.5, size: 0) - { - } + } - public ScapegoatTree(double alpha) - : this(alpha, size: 0) - { - } + public ScapegoatTree(double alpha) + : this(alpha, size: 0) + { + } - public ScapegoatTree(Node node, double alpha) - : this(alpha, size: node.GetSize()) - { - Root = node; - } + public ScapegoatTree(Node node, double alpha) + : this(alpha, size: node.GetSize()) + { + Root = node; + } - public ScapegoatTree(TKey key, double alpha = 0.5) - : this(alpha, size: 1) - { - Root = new Node(key); - } + public ScapegoatTree(TKey key, double alpha = 0.5) + : this(alpha, size: 1) + { + Root = new Node(key); + } - private ScapegoatTree(double alpha, int size) - { - CheckAlpha(alpha); + private ScapegoatTree(double alpha, int size) + { + CheckAlpha(alpha); - Alpha = alpha; + Alpha = alpha; - Size = size; - MaxSize = size; - } + Size = size; + MaxSize = size; + } - /// - /// Checks if current instance of the scapegoat tree is alpha weight balanced. - /// - /// True - if tree is alpha weight balanced. Otherwise, false. - public bool IsAlphaWeightBalanced() - { - return Root?.IsAlphaWeightBalanced(Alpha) ?? true; - } + /// + /// Checks if current instance of the scapegoat tree is alpha weight balanced. + /// + /// True - if tree is alpha weight balanced. Otherwise, false. + public bool IsAlphaWeightBalanced() + { + return Root?.IsAlphaWeightBalanced(Alpha) ?? true; + } + + /// + /// Check if any node in the tree has specified key value. + /// + /// Key value. + /// Returns true if node exists, false if not. + public bool Contains(TKey key) + { + return Search(key) != null; + } - /// - /// Check if any node in the tree has specified key value. - /// - /// Key value. - /// Returns true if node exists, false if not. - public bool Contains(TKey key) + /// + /// Searches current instance of the scapegoat tree for specified key. + /// + /// Key value. + /// Node with the specified key or null. + public Node? Search(TKey key) + { + if (Root == null) { - return Search(key) != null; + return null; } - /// - /// Searches current instance of the scapegoat tree for specified key. - /// - /// Key value. - /// Node with the specified key or null. - public Node? Search(TKey key) - { - if (Root == null) - { - return null; - } + var current = Root; - var current = Root; + while (true) + { + var result = current.Key.CompareTo(key); - while (true) + switch (result) { - var result = current.Key.CompareTo(key); - - switch (result) - { - case 0: - return current; - case > 0 when current.Left != null: - current = current.Left; - break; - case < 0 when current.Right != null: - current = current.Right; - break; - default: - return null; - } + case 0: + return current; + case > 0 when current.Left != null: + current = current.Left; + break; + case < 0 when current.Right != null: + current = current.Right; + break; + default: + return null; } } + } + + /// + /// Inserts a new key into current instance of the scapegoat tree. Rebuilds tree if it's unbalanced. + /// + /// Key value. + /// True - if insertion is successful, false - if the key is already present in the tree. + public bool Insert(TKey key) + { + var node = new Node(key); - /// - /// Inserts a new key into current instance of the scapegoat tree. Rebuilds tree if it's unbalanced. - /// - /// Key value. - /// True - if insertion is successful, false - if the key is already present in the tree. - public bool Insert(TKey key) + if (Root == null) { - var node = new Node(key); + Root = node; - if (Root == null) - { - Root = node; + UpdateSizes(); + + return true; + } - UpdateSizes(); + var path = new Stack>(); - return true; - } + var current = Root; - var path = new Stack>(); + var found = false; - var current = Root; + while (!found) + { + path.Push(current); - var found = false; + var result = current.Key.CompareTo(node.Key); - while (!found) + switch (result) { - path.Push(current); - - var result = current.Key.CompareTo(node.Key); - - switch (result) - { - case < 0 when current.Right != null: - current = current.Right; - continue; - case < 0: - current.Right = node; - found = true; - break; - case > 0 when current.Left != null: - current = current.Left; - continue; - case > 0: - current.Left = node; - found = true; - break; - default: - return false; - } + case < 0 when current.Right != null: + current = current.Right; + continue; + case < 0: + current.Right = node; + found = true; + break; + case > 0 when current.Left != null: + current = current.Left; + continue; + case > 0: + current.Left = node; + found = true; + break; + default: + return false; } + } - UpdateSizes(); + UpdateSizes(); - if (path.Count > Root.GetAlphaHeight(Alpha)) - { - TreeIsUnbalanced?.Invoke(this, EventArgs.Empty); + if (path.Count > Root.GetAlphaHeight(Alpha)) + { + TreeIsUnbalanced?.Invoke(this, EventArgs.Empty); - BalanceFromPath(path); + BalanceFromPath(path); - MaxSize = Math.Max(MaxSize, Size); - } + MaxSize = Math.Max(MaxSize, Size); + } - return true; + return true; + } + + /// + /// Removes the specified key from the current instance of the scapegoat tree. Rebuilds tree if it's unbalanced. + /// + /// Key value. + /// True - if key was successfully removed, false - if the key wasn't found in the tree. + public bool Delete(TKey key) + { + if (Root == null) + { + return false; } - /// - /// Removes the specified key from the current instance of the scapegoat tree. Rebuilds tree if it's unbalanced. - /// - /// Key value. - /// True - if key was successfully removed, false - if the key wasn't found in the tree. - public bool Delete(TKey key) + if (Remove(Root, Root, key)) { - if (Root == null) - { - return false; - } + Size--; - if (Remove(Root, Root, key)) + if (Root != null && Size < Alpha * MaxSize) { - Size--; - - if (Root != null && Size < Alpha * MaxSize) - { - TreeIsUnbalanced?.Invoke(this, EventArgs.Empty); - - var list = new List>(); + TreeIsUnbalanced?.Invoke(this, EventArgs.Empty); - Extensions.FlattenTree(Root, list); + var list = new List>(); - Root = Extensions.RebuildFromList(list, 0, list.Count - 1); + Extensions.FlattenTree(Root, list); - MaxSize = Size; - } + Root = Extensions.RebuildFromList(list, 0, list.Count - 1); - return true; + MaxSize = Size; } - return false; + return true; } - /// - /// Clears the tree. - /// - public void Clear() - { - Size = 0; - MaxSize = 0; - Root = null; - } + return false; + } + + /// + /// Clears the tree. + /// + public void Clear() + { + Size = 0; + MaxSize = 0; + Root = null; + } + + /// + /// Changes value to adjust balancing. + /// + /// New alpha value. + public void Tune(double value) + { + CheckAlpha(value); + Alpha = value; + } - /// - /// Changes value to adjust balancing. - /// - /// New alpha value. - public void Tune(double value) + /// + /// Searches for a scapegoat node in provided stack. + /// + /// Stack instance with nodes, starting with root node. + /// Scapegoat node with its parent node. Parent can be null if scapegoat node is root node. + /// Thrown if path stack is empty. + /// Thrown if scapegoat wasn't found. + public (Node? parent, Node scapegoat) FindScapegoatInPath(Stack> path) + { + if (path.Count == 0) { - CheckAlpha(value); - Alpha = value; + throw new ArgumentException("The path collection should not be empty.", nameof(path)); } - /// - /// Searches for a scapegoat node in provided stack. - /// - /// Stack instance with nodes, starting with root node. - /// Scapegoat node with its parent node. Parent can be null if scapegoat node is root node. - /// Thrown if path stack is empty. - /// Thrown if scapegoat wasn't found. - public (Node? parent, Node scapegoat) FindScapegoatInPath(Stack> path) + var depth = 1; + + while (path.TryPop(out var next)) { - if (path.Count == 0) + if (depth > next.GetAlphaHeight(Alpha)) { - throw new ArgumentException("The path collection should not be empty.", nameof(path)); + return path.TryPop(out var parent) ? (parent, next) : (null, next); } - var depth = 1; - - while (path.TryPop(out var next)) - { - if (depth > next.GetAlphaHeight(Alpha)) - { - return path.TryPop(out var parent) ? (parent, next) : (null, next); - } + depth++; + } - depth++; - } + throw new InvalidOperationException("Scapegoat node wasn't found. The tree should be unbalanced."); + } - throw new InvalidOperationException("Scapegoat node wasn't found. The tree should be unbalanced."); + private static void CheckAlpha(double alpha) + { + if (alpha is < 0.5 or > 1.0) + { + throw new ArgumentException("The alpha parameter's value should be in 0.5..1.0 range.", nameof(alpha)); } + } - private static void CheckAlpha(double alpha) + private bool Remove(Node? parent, Node? node, TKey key) + { + if (node is null || parent is null) { - if (alpha is < 0.5 or > 1.0) - { - throw new ArgumentException("The alpha parameter's value should be in 0.5..1.0 range.", nameof(alpha)); - } + return false; } - private bool Remove(Node? parent, Node? node, TKey key) - { - if (node is null || parent is null) - { - return false; - } + var compareResult = node.Key.CompareTo(key); - var compareResult = node.Key.CompareTo(key); + if (compareResult > 0) + { + return Remove(node, node.Left, key); + } - if (compareResult > 0) - { - return Remove(node, node.Left, key); - } + if (compareResult < 0) + { + return Remove(node, node.Right, key); + } - if (compareResult < 0) - { - return Remove(node, node.Right, key); - } + Node? replacementNode; - Node? replacementNode; + // Case 0: Node has no children. + // Case 1: Node has one child. + if (node.Left is null || node.Right is null) + { + replacementNode = node.Left ?? node.Right; + } - // Case 0: Node has no children. - // Case 1: Node has one child. - if (node.Left is null || node.Right is null) + // Case 2: Node has two children. (This implementation uses the in-order predecessor to replace node.) + else + { + var predecessorNode = node.Left.GetLargestKeyNode(); + Remove(Root, Root, predecessorNode.Key); + replacementNode = new Node(predecessorNode.Key) { - replacementNode = node.Left ?? node.Right; - } + Left = node.Left, + Right = node.Right, + }; + } - // Case 2: Node has two children. (This implementation uses the in-order predecessor to replace node.) - else - { - var predecessorNode = node.Left.GetLargestKeyNode(); - Remove(Root, Root, predecessorNode.Key); - replacementNode = new Node(predecessorNode.Key) - { - Left = node.Left, - Right = node.Right, - }; - } + // Replace the relevant node with a replacement found in the previous stages. + // Special case for replacing the root node. + if (node == Root) + { + Root = replacementNode; + } + else if (parent.Left == node) + { + parent.Left = replacementNode; + } + else + { + parent.Right = replacementNode; + } - // Replace the relevant node with a replacement found in the previous stages. - // Special case for replacing the root node. - if (node == Root) - { - Root = replacementNode; - } - else if (parent.Left == node) - { - parent.Left = replacementNode; - } - else - { - parent.Right = replacementNode; - } + return true; + } - return true; - } + private void BalanceFromPath(Stack> path) + { + var (parent, scapegoat) = FindScapegoatInPath(path); - private void BalanceFromPath(Stack> path) - { - var (parent, scapegoat) = FindScapegoatInPath(path); + var list = new List>(); - var list = new List>(); + Extensions.FlattenTree(scapegoat, list); - Extensions.FlattenTree(scapegoat, list); + var tree = Extensions.RebuildFromList(list, 0, list.Count - 1); - var tree = Extensions.RebuildFromList(list, 0, list.Count - 1); + if (parent == null) + { + Root = tree; + } + else + { + var result = parent.Key.CompareTo(tree.Key); - if (parent == null) + if (result < 0) { - Root = tree; + parent.Right = tree; } else { - var result = parent.Key.CompareTo(tree.Key); - - if (result < 0) - { - parent.Right = tree; - } - else - { - parent.Left = tree; - } + parent.Left = tree; } } + } - private void UpdateSizes() - { - Size += 1; - MaxSize = Math.Max(Size, MaxSize); - } + private void UpdateSizes() + { + Size += 1; + MaxSize = Math.Max(Size, MaxSize); } } diff --git a/DataStructures/SegmentTrees/SegmentTree.cs b/DataStructures/SegmentTrees/SegmentTree.cs index 1583bb5c..24961af0 100644 --- a/DataStructures/SegmentTrees/SegmentTree.cs +++ b/DataStructures/SegmentTrees/SegmentTree.cs @@ -1,104 +1,103 @@ using System; -namespace DataStructures.SegmentTrees +namespace DataStructures.SegmentTrees; + +/// +/// Goal: Data structure with which you can quickly perform queries on an array (i.e. sum of subarray) +/// and at the same time efficiently update an entry +/// or apply a distributive operation to a subarray. +/// Idea: Preprocessing special queries +/// Hint: The query operation HAS to be associative (in this example addition). +/// +public class SegmentTree { /// - /// Goal: Data structure with which you can quickly perform queries on an array (i.e. sum of subarray) - /// and at the same time efficiently update an entry - /// or apply a distributive operation to a subarray. - /// Idea: Preprocessing special queries - /// Hint: The query operation HAS to be associative (in this example addition). + /// Initializes a new instance of the class. + /// Runtime complexity: O(n) where n equals the array-length. /// - public class SegmentTree + /// Array on which the queries should be made. + public SegmentTree(int[] arr) { - /// - /// Initializes a new instance of the class. - /// Runtime complexity: O(n) where n equals the array-length. - /// - /// Array on which the queries should be made. - public SegmentTree(int[] arr) - { - // Calculates next power of two - var pow = (int)Math.Pow(2, Math.Ceiling(Math.Log(arr.Length, 2))); - Tree = new int[2 * pow]; + // Calculates next power of two + var pow = (int)Math.Pow(2, Math.Ceiling(Math.Log(arr.Length, 2))); + Tree = new int[2 * pow]; - // Transfers the input array into the last half of the segment tree array - Array.Copy(arr, 0, Tree, pow, arr.Length); + // Transfers the input array into the last half of the segment tree array + Array.Copy(arr, 0, Tree, pow, arr.Length); - // Calculates the first half - for (var i = pow - 1; i > 0; --i) - { - Tree[i] = Tree[Left(i)] + Tree[Right(i)]; - } + // Calculates the first half + for (var i = pow - 1; i > 0; --i) + { + Tree[i] = Tree[Left(i)] + Tree[Right(i)]; } + } - /// Gets the segment tree array. - public int[] Tree { get; } + /// Gets the segment tree array. + public int[] Tree { get; } - /// - /// Starts a query. - /// Runtime complexity: O(logN) where n equals the array-length. - /// - /// Left border of the query. - /// Right border of the query. - /// Sum of the subarray between l and r (including l and r). - // Editing of query start at node with 1. - // Node with index 1 includes the whole input subarray. - public int Query(int l, int r) => - Query(++l, ++r, 1, Tree.Length / 2, 1); + /// + /// Starts a query. + /// Runtime complexity: O(logN) where n equals the array-length. + /// + /// Left border of the query. + /// Right border of the query. + /// Sum of the subarray between l and r (including l and r). + // Editing of query start at node with 1. + // Node with index 1 includes the whole input subarray. + public int Query(int l, int r) => + Query(++l, ++r, 1, Tree.Length / 2, 1); - /// - /// Calculates the right child of a node. - /// - /// Current node. - /// Index of the right child. - protected int Right(int node) => 2 * node + 1; + /// + /// Calculates the right child of a node. + /// + /// Current node. + /// Index of the right child. + protected int Right(int node) => 2 * node + 1; - /// - /// Calculates the left child of a node. - /// - /// Current node. - /// Index of the left child. - protected int Left(int node) => 2 * node; + /// + /// Calculates the left child of a node. + /// + /// Current node. + /// Index of the left child. + protected int Left(int node) => 2 * node; - /// - /// Calculates the parent of a node. - /// - /// Current node. - /// Index of the parent node. - protected int Parent(int node) => node / 2; + /// + /// Calculates the parent of a node. + /// + /// Current node. + /// Index of the parent node. + protected int Parent(int node) => node / 2; - /// - /// Edits a query. - /// - /// Left border of the query. - /// Right border of the query. - /// Left end of the subarray enclosed by i. - /// Right end of the subarray enclosed by i. - /// Current node. - /// Sum of a subarray between l and r (including l and r). - protected virtual int Query(int l, int r, int a, int b, int i) + /// + /// Edits a query. + /// + /// Left border of the query. + /// Right border of the query. + /// Left end of the subarray enclosed by i. + /// Right end of the subarray enclosed by i. + /// Current node. + /// Sum of a subarray between l and r (including l and r). + protected virtual int Query(int l, int r, int a, int b, int i) + { + // If a and b are in the (by l and r) specified subarray + if (l <= a && b <= r) { - // If a and b are in the (by l and r) specified subarray - if (l <= a && b <= r) - { - return Tree[i]; - } + return Tree[i]; + } - // If a or b are out of the by l and r specified subarray - if (r < a || b < l) - { - // Returns the neutral value of the operation - // (in this case 0, because x + 0 = x) - return 0; - } + // If a or b are out of the by l and r specified subarray + if (r < a || b < l) + { + // Returns the neutral value of the operation + // (in this case 0, because x + 0 = x) + return 0; + } - // Calculates index m of the node that cuts the current subarray in half - var m = (a + b) / 2; + // Calculates index m of the node that cuts the current subarray in half + var m = (a + b) / 2; - // Start query of new two subarrays a:m and m+1:b - // The right and left child cover this intervals - return Query(l, r, a, m, Left(i)) + Query(l, r, m + 1, b, Right(i)); - } + // Start query of new two subarrays a:m and m+1:b + // The right and left child cover this intervals + return Query(l, r, a, m, Left(i)) + Query(l, r, m + 1, b, Right(i)); } } diff --git a/DataStructures/SegmentTrees/SegmentTreeApply.cs b/DataStructures/SegmentTrees/SegmentTreeApply.cs index 767160ec..e28d0364 100644 --- a/DataStructures/SegmentTrees/SegmentTreeApply.cs +++ b/DataStructures/SegmentTrees/SegmentTreeApply.cs @@ -1,110 +1,109 @@ using System; -namespace DataStructures.SegmentTrees +namespace DataStructures.SegmentTrees; + +/// +/// This is an extension of a segment tree, which allows applying distributive operations to a subarray +/// (in this case multiplication). +/// +public class SegmentTreeApply : SegmentTree { /// - /// This is an extension of a segment tree, which allows applying distributive operations to a subarray - /// (in this case multiplication). + /// Initializes a new instance of the class. + /// Runtime complexity: O(n) where n equals the array-length. /// - public class SegmentTreeApply : SegmentTree + /// Array on which the operations should be made. + public SegmentTreeApply(int[] arr) + : base(arr) { - /// - /// Initializes a new instance of the class. - /// Runtime complexity: O(n) where n equals the array-length. - /// - /// Array on which the operations should be made. - public SegmentTreeApply(int[] arr) - : base(arr) - { - // Initilizes and fills "operand" array with neutral element (in this case 1, because value * 1 = value) - Operand = new int[Tree.Length]; - Array.Fill(Operand, 1); - } + // Initilizes and fills "operand" array with neutral element (in this case 1, because value * 1 = value) + Operand = new int[Tree.Length]; + Array.Fill(Operand, 1); + } + + /// + /// Gets an array that stores for each node an operand, + /// which must be applied to all direct and indirect child nodes of this node + /// (but not to the node itself). + /// + public int[] Operand { get; } - /// - /// Gets an array that stores for each node an operand, - /// which must be applied to all direct and indirect child nodes of this node - /// (but not to the node itself). - /// - public int[] Operand { get; } + /// + /// Applies a distributive operation to a subarray defined by l and r + /// (in this case multiplication by value). + /// Runtime complexity: O(logN) where N equals the initial array-length. + /// + /// Left border of the subarray. + /// Right border of the subarray. + /// Value with which each element of the interval is calculated. + public void Apply(int l, int r, int value) + { + // The Application start at node with 1 + // Node with index 1 includes the whole input subarray + Apply(++l, ++r, value, 1, Tree.Length / 2, 1); + } - /// - /// Applies a distributive operation to a subarray defined by l and r - /// (in this case multiplication by value). - /// Runtime complexity: O(logN) where N equals the initial array-length. - /// - /// Left border of the subarray. - /// Right border of the subarray. - /// Value with which each element of the interval is calculated. - public void Apply(int l, int r, int value) + /// + /// Edits a query. + /// + /// Left border of the query. + /// Right border of the query. + /// Left end of the subarray enclosed by i. + /// Right end of the subarray enclosed by i. + /// Current node. + /// Sum of a subarray between l and r (including l and r). + protected override int Query(int l, int r, int a, int b, int i) + { + if (l <= a && b <= r) { - // The Application start at node with 1 - // Node with index 1 includes the whole input subarray - Apply(++l, ++r, value, 1, Tree.Length / 2, 1); + return Tree[i]; } - /// - /// Edits a query. - /// - /// Left border of the query. - /// Right border of the query. - /// Left end of the subarray enclosed by i. - /// Right end of the subarray enclosed by i. - /// Current node. - /// Sum of a subarray between l and r (including l and r). - protected override int Query(int l, int r, int a, int b, int i) + if (r < a || b < l) { - if (l <= a && b <= r) - { - return Tree[i]; - } + return 0; + } - if (r < a || b < l) - { - return 0; - } + var m = (a + b) / 2; - var m = (a + b) / 2; + // Application of the saved operand to the direct and indrect child nodes + return Operand[i] * (Query(l, r, a, m, Left(i)) + Query(l, r, m + 1, b, Right(i))); + } - // Application of the saved operand to the direct and indrect child nodes - return Operand[i] * (Query(l, r, a, m, Left(i)) + Query(l, r, m + 1, b, Right(i))); + /// + /// Applies the operation. + /// + /// Left border of the Application. + /// Right border of the Application. + /// Multiplier by which the subarray is to be multiplied. + /// Left end of the subarray enclosed by i. + /// Right end of the subarray enclosed by i. + /// Current node. + private void Apply(int l, int r, int value, int a, int b, int i) + { + // If a and b are in the (by l and r) specified subarray + if (l <= a && b <= r) + { + // Applies the operation to the current node and saves it for the direct and indirect child nodes + Operand[i] = value * Operand[i]; + Tree[i] = value * Tree[i]; + return; } - /// - /// Applies the operation. - /// - /// Left border of the Application. - /// Right border of the Application. - /// Multiplier by which the subarray is to be multiplied. - /// Left end of the subarray enclosed by i. - /// Right end of the subarray enclosed by i. - /// Current node. - private void Apply(int l, int r, int value, int a, int b, int i) + // If a or b are out of the by l and r specified subarray stop application at this node + if (r < a || b < l) { - // If a and b are in the (by l and r) specified subarray - if (l <= a && b <= r) - { - // Applies the operation to the current node and saves it for the direct and indirect child nodes - Operand[i] = value * Operand[i]; - Tree[i] = value * Tree[i]; - return; - } - - // If a or b are out of the by l and r specified subarray stop application at this node - if (r < a || b < l) - { - return; - } + return; + } - // Calculates index m of the node that cuts the current subarray in half - var m = (a + b) / 2; + // Calculates index m of the node that cuts the current subarray in half + var m = (a + b) / 2; - // Applies the operation to both halfes - Apply(l, r, value, a, m, Left(i)); - Apply(l, r, value, m + 1, b, Right(i)); + // Applies the operation to both halfes + Apply(l, r, value, a, m, Left(i)); + Apply(l, r, value, m + 1, b, Right(i)); - // Recalculates the value of this node by its (possibly new) children. - Tree[i] = Operand[i] * (Tree[Left(i)] + Tree[Right(i)]); - } + // Recalculates the value of this node by its (possibly new) children. + Tree[i] = Operand[i] * (Tree[Left(i)] + Tree[Right(i)]); } } diff --git a/DataStructures/SegmentTrees/SegmentTreeUpdate.cs b/DataStructures/SegmentTrees/SegmentTreeUpdate.cs index ed62b4bf..fc3a7734 100644 --- a/DataStructures/SegmentTrees/SegmentTreeUpdate.cs +++ b/DataStructures/SegmentTrees/SegmentTreeUpdate.cs @@ -1,48 +1,47 @@ -namespace DataStructures.SegmentTrees +namespace DataStructures.SegmentTrees; + +/// +/// This is an extension of a segment tree, which allows the update of a single element. +/// +public class SegmentTreeUpdate : SegmentTree { /// - /// This is an extension of a segment tree, which allows the update of a single element. + /// Initializes a new instance of the class. + /// Runtime complexity: O(n) where n equals the array-length. /// - public class SegmentTreeUpdate : SegmentTree + /// Array on which the queries should be made. + public SegmentTreeUpdate(int[] arr) + : base(arr) { - /// - /// Initializes a new instance of the class. - /// Runtime complexity: O(n) where n equals the array-length. - /// - /// Array on which the queries should be made. - public SegmentTreeUpdate(int[] arr) - : base(arr) - { - } + } - /// - /// Updates a single element of the input array. - /// Changes the leaf first and updates its parents afterwards. - /// Runtime complexity: O(logN) where N equals the initial array-length. - /// - /// Index of the node that should be updated. - /// New Value of the element. - public void Update(int node, int value) - { - Tree[node + Tree.Length / 2] = value; - Propagate(Parent(node + Tree.Length / 2)); - } + /// + /// Updates a single element of the input array. + /// Changes the leaf first and updates its parents afterwards. + /// Runtime complexity: O(logN) where N equals the initial array-length. + /// + /// Index of the node that should be updated. + /// New Value of the element. + public void Update(int node, int value) + { + Tree[node + Tree.Length / 2] = value; + Propagate(Parent(node + Tree.Length / 2)); + } - /// - /// Recalculates the value of node by its children. - /// Calls its parent to do the same. - /// - /// Index of current node. - private void Propagate(int node) + /// + /// Recalculates the value of node by its children. + /// Calls its parent to do the same. + /// + /// Index of current node. + private void Propagate(int node) + { + if (node == 0) { - if (node == 0) - { - // passed root - return; - } - - Tree[node] = Tree[Left(node)] + Tree[Right(node)]; - Propagate(Parent(node)); + // passed root + return; } + + Tree[node] = Tree[Left(node)] + Tree[Right(node)]; + Propagate(Parent(node)); } } diff --git a/DataStructures/SortedList.cs b/DataStructures/SortedList.cs index 581dab6d..1729547c 100644 --- a/DataStructures/SortedList.cs +++ b/DataStructures/SortedList.cs @@ -1,132 +1,131 @@ using System.Collections; using System.Collections.Generic; -namespace DataStructures +namespace DataStructures; + +/// +/// Implementation of SortedList using binary search. +/// +/// Generic Type. +public class SortedList : IEnumerable { + private readonly IComparer comparer; + private readonly List memory; + /// - /// Implementation of SortedList using binary search. + /// Initializes a new instance of the class. Uses a Comparer.Default for type T. /// - /// Generic Type. - public class SortedList : IEnumerable + public SortedList() + : this(Comparer.Default) { - private readonly IComparer comparer; - private readonly List memory; - - /// - /// Initializes a new instance of the class. Uses a Comparer.Default for type T. - /// - public SortedList() - : this(Comparer.Default) - { - } + } - /// - /// Gets the number of elements containing in . - /// - public int Count => memory.Count; + /// + /// Gets the number of elements containing in . + /// + public int Count => memory.Count; - /// - /// Initializes a new instance of the class. - /// - /// Comparer user for binary search. - public SortedList(IComparer comparer) - { - memory = new List(); - this.comparer = comparer; - } + /// + /// Initializes a new instance of the class. + /// + /// Comparer user for binary search. + public SortedList(IComparer comparer) + { + memory = new List(); + this.comparer = comparer; + } - /// - /// Adds new item to instance, maintaining the order. - /// - /// An element to insert. - public void Add(T item) - { - var index = IndexFor(item, out _); - memory.Insert(index, item); - } + /// + /// Adds new item to instance, maintaining the order. + /// + /// An element to insert. + public void Add(T item) + { + var index = IndexFor(item, out _); + memory.Insert(index, item); + } + + /// + /// Gets an element of at specified index. + /// + /// Index. + public T this[int i] => memory[i]; - /// - /// Gets an element of at specified index. - /// - /// Index. - public T this[int i] => memory[i]; - - /// - /// Removes all elements from . - /// - public void Clear() - => memory.Clear(); - - /// - /// Indicates whether a contains a certain element. - /// - /// An element to search. - /// true - contains an element, otherwise - false. - public bool Contains(T item) + /// + /// Removes all elements from . + /// + public void Clear() + => memory.Clear(); + + /// + /// Indicates whether a contains a certain element. + /// + /// An element to search. + /// true - contains an element, otherwise - false. + public bool Contains(T item) + { + _ = IndexFor(item, out var found); + return found; + } + + /// + /// Removes a certain element from . + /// + /// An element to remove. + /// true - element is found and removed, otherwise false. + public bool TryRemove(T item) + { + var index = IndexFor(item, out var found); + + if (found) { - _ = IndexFor(item, out var found); - return found; + memory.RemoveAt(index); } - /// - /// Removes a certain element from . - /// - /// An element to remove. - /// true - element is found and removed, otherwise false. - public bool TryRemove(T item) - { - var index = IndexFor(item, out var found); + return found; + } - if (found) - { - memory.RemoveAt(index); - } + /// + /// Returns an enumerator that iterates through the . + /// + /// A Enumerator for the . + public IEnumerator GetEnumerator() + => memory.GetEnumerator(); - return found; - } + /// + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); - /// - /// Returns an enumerator that iterates through the . - /// - /// A Enumerator for the . - public IEnumerator GetEnumerator() - => memory.GetEnumerator(); - - /// - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); - - /// - /// Binary search algorithm for finding element index in . - /// - /// Element. - /// Indicates whether the equal value was found in . - /// Index for the Element. - private int IndexFor(T item, out bool found) + /// + /// Binary search algorithm for finding element index in . + /// + /// Element. + /// Indicates whether the equal value was found in . + /// Index for the Element. + private int IndexFor(T item, out bool found) + { + var left = 0; + var right = memory.Count; + + while (right - left > 0) { - var left = 0; - var right = memory.Count; + var mid = (left + right) / 2; - while (right - left > 0) + switch (comparer.Compare(item, memory[mid])) { - var mid = (left + right) / 2; - - switch (comparer.Compare(item, memory[mid])) - { - case > 0: - left = mid + 1; - break; - case < 0: - right = mid; - break; - default: - found = true; - return mid; - } + case > 0: + left = mid + 1; + break; + case < 0: + right = mid; + break; + default: + found = true; + return mid; } - - found = false; - return left; } + + found = false; + return left; } } diff --git a/DataStructures/Stack/ArrayBasedStack.cs b/DataStructures/Stack/ArrayBasedStack.cs index 41654fa7..06c561d9 100644 --- a/DataStructures/Stack/ArrayBasedStack.cs +++ b/DataStructures/Stack/ArrayBasedStack.cs @@ -1,123 +1,121 @@ -using System; -using System.Collections.Generic; +using System; -namespace DataStructures.Stack +namespace DataStructures.Stack; + +/// +/// Implementation of an array-based stack. LIFO style. +/// +/// Generic Type. +public class ArrayBasedStack { + private const int DefaultCapacity = 10; + private const string StackEmptyErrorMessage = "Stack is empty"; + + /// + /// based stack. + /// + private T[] stack; + + /// + /// How many items are in the stack right now. + /// + private int top; + /// - /// Implementation of an array-based stack. LIFO style. + /// Initializes a new instance of the class. /// - /// Generic Type. - public class ArrayBasedStack + public ArrayBasedStack() { - private const int DefaultCapacity = 10; - private const string StackEmptyErrorMessage = "Stack is empty"; - - /// - /// based stack. - /// - private T[] stack; - - /// - /// How many items are in the stack right now. - /// - private int top; - - /// - /// Initializes a new instance of the class. - /// - public ArrayBasedStack() - { - stack = new T[DefaultCapacity]; - top = -1; - } + stack = new T[DefaultCapacity]; + top = -1; + } - /// - /// Initializes a new instance of the class. - /// - /// Item to push onto the . - public ArrayBasedStack(T item) - : this() => Push(item); - - /// - /// Initializes a new instance of the class. - /// - /// Items to push onto the . - public ArrayBasedStack(T[] items) - { - stack = items; - top = items.Length - 1; - } + /// + /// Initializes a new instance of the class. + /// + /// Item to push onto the . + public ArrayBasedStack(T item) + : this() => Push(item); - /// - /// Gets the number of elements on the . - /// - public int Top => top; + /// + /// Initializes a new instance of the class. + /// + /// Items to push onto the . + public ArrayBasedStack(T[] items) + { + stack = items; + top = items.Length - 1; + } - /// - /// Gets or sets the Capacity of the . - /// - public int Capacity - { - get => stack.Length; - set => Array.Resize(ref stack, value); - } + /// + /// Gets the number of elements on the . + /// + public int Top => top; - /// - /// Removes all items from the . - /// - public void Clear() - { - top = -1; - Capacity = DefaultCapacity; - } + /// + /// Gets or sets the Capacity of the . + /// + public int Capacity + { + get => stack.Length; + set => Array.Resize(ref stack, value); + } - /// - /// Determines whether an element is in the . - /// - /// The item to locate in the . - /// True, if the item is in the stack. - public bool Contains(T item) => Array.IndexOf(stack, item, 0, top + 1) > -1; - - /// - /// Returns the item at the top of the without removing it. - /// - /// The item at the top of the . - public T Peek() - { - if (top == -1) - { - throw new InvalidOperationException(StackEmptyErrorMessage); - } + /// + /// Removes all items from the . + /// + public void Clear() + { + top = -1; + Capacity = DefaultCapacity; + } - return stack[top]; - } + /// + /// Determines whether an element is in the . + /// + /// The item to locate in the . + /// True, if the item is in the stack. + public bool Contains(T item) => Array.IndexOf(stack, item, 0, top + 1) > -1; - /// - /// Removes and returns the item at the top of the . - /// - /// The item removed from the top of the . - public T Pop() + /// + /// Returns the item at the top of the without removing it. + /// + /// The item at the top of the . + public T Peek() + { + if (top == -1) { - if (top == -1) - { - throw new InvalidOperationException(StackEmptyErrorMessage); - } - - return stack[top--]; + throw new InvalidOperationException(StackEmptyErrorMessage); } - /// - /// Inserts an item at the top of the . - /// - /// The item to push onto the . - public void Push(T item) + return stack[top]; + } + + /// + /// Removes and returns the item at the top of the . + /// + /// The item removed from the top of the . + public T Pop() + { + if (top == -1) { - if (top == Capacity - 1) - { - Capacity *= 2; - } + throw new InvalidOperationException(StackEmptyErrorMessage); + } - stack[++top] = item; + return stack[top--]; + } + + /// + /// Inserts an item at the top of the . + /// + /// The item to push onto the . + public void Push(T item) + { + if (top == Capacity - 1) + { + Capacity *= 2; } + + stack[++top] = item; } } diff --git a/DataStructures/Stack/ListBasedStack.cs b/DataStructures/Stack/ListBasedStack.cs index 23bd4ac2..bd1b6d11 100644 --- a/DataStructures/Stack/ListBasedStack.cs +++ b/DataStructures/Stack/ListBasedStack.cs @@ -1,95 +1,94 @@ -using System; +using System; using System.Collections.Generic; -namespace DataStructures.Stack +namespace DataStructures.Stack; + +/// +/// Implementation of a list based stack. FILO style. +/// +/// Generic Type. +public class ListBasedStack { /// - /// Implementation of a list based stack. FILO style. + /// based stack. /// - /// Generic Type. - public class ListBasedStack - { - /// - /// based stack. - /// - private readonly LinkedList stack; + private readonly LinkedList stack; - /// - /// Initializes a new instance of the class. - /// - public ListBasedStack() => stack = new LinkedList(); + /// + /// Initializes a new instance of the class. + /// + public ListBasedStack() => stack = new LinkedList(); - /// - /// Initializes a new instance of the class. - /// - /// Item to push onto the . - public ListBasedStack(T item) - : this() => Push(item); + /// + /// Initializes a new instance of the class. + /// + /// Item to push onto the . + public ListBasedStack(T item) + : this() => Push(item); - /// - /// Initializes a new instance of the class. - /// - /// Items to push onto the . - public ListBasedStack(IEnumerable items) - : this() + /// + /// Initializes a new instance of the class. + /// + /// Items to push onto the . + public ListBasedStack(IEnumerable items) + : this() + { + foreach (var item in items) { - foreach (var item in items) - { - Push(item); - } + Push(item); } + } - /// - /// Gets the number of elements on the . - /// - public int Count => stack.Count; + /// + /// Gets the number of elements on the . + /// + public int Count => stack.Count; - /// - /// Removes all items from the . - /// - public void Clear() => stack.Clear(); + /// + /// Removes all items from the . + /// + public void Clear() => stack.Clear(); - /// - /// Determines whether an element is in the . - /// - /// The item to locate in the . - /// True, if the item is in the stack. - public bool Contains(T item) => stack.Contains(item); + /// + /// Determines whether an element is in the . + /// + /// The item to locate in the . + /// True, if the item is in the stack. + public bool Contains(T item) => stack.Contains(item); - /// - /// Returns the item at the top of the without removing it. - /// - /// The item at the top of the . - public T Peek() + /// + /// Returns the item at the top of the without removing it. + /// + /// The item at the top of the . + public T Peek() + { + if (stack.First is null) { - if (stack.First is null) - { - throw new InvalidOperationException("Stack is empty"); - } - - return stack.First.Value; + throw new InvalidOperationException("Stack is empty"); } - /// - /// Removes and returns the item at the top of the . - /// - /// The item removed from the top of the . - public T Pop() - { - if (stack.First is null) - { - throw new InvalidOperationException("Stack is empty"); - } + return stack.First.Value; + } - var item = stack.First.Value; - stack.RemoveFirst(); - return item; + /// + /// Removes and returns the item at the top of the . + /// + /// The item removed from the top of the . + public T Pop() + { + if (stack.First is null) + { + throw new InvalidOperationException("Stack is empty"); } - /// - /// Inserts an item at the top of the . - /// - /// The item to push onto the . - public void Push(T item) => stack.AddFirst(item); + var item = stack.First.Value; + stack.RemoveFirst(); + return item; } + + /// + /// Inserts an item at the top of the . + /// + /// The item to push onto the . + public void Push(T item) => stack.AddFirst(item); } diff --git a/DataStructures/Stack/QueueBasedStack.cs b/DataStructures/Stack/QueueBasedStack.cs index ea5af6b4..5ac0e4a3 100644 --- a/DataStructures/Stack/QueueBasedStack.cs +++ b/DataStructures/Stack/QueueBasedStack.cs @@ -4,73 +4,72 @@ using System.Text; using System.Threading.Tasks; -namespace DataStructures.Stack +namespace DataStructures.Stack; + +public class QueueBasedStack { - public class QueueBasedStack - { - private readonly Queue queue; + private readonly Queue queue; - public QueueBasedStack() => queue = new Queue(); + public QueueBasedStack() => queue = new Queue(); - /// - /// Clears the stack. - /// - public void Clear() => queue.Clear(); + /// + /// Clears the stack. + /// + public void Clear() => queue.Clear(); - public bool IsEmpty() => queue.Count == 0; + public bool IsEmpty() => queue.Count == 0; - /// - /// Adds an item on top of the stack. - /// - /// Item to be added on top of stack. - public void Push(T item) => queue.Enqueue(item); + /// + /// Adds an item on top of the stack. + /// + /// Item to be added on top of stack. + public void Push(T item) => queue.Enqueue(item); - /// - /// Removes an item from top of the stack and returns it. - /// - /// item on top of stack. - /// Throw if stack is empty. - public T Pop() + /// + /// Removes an item from top of the stack and returns it. + /// + /// item on top of stack. + /// Throw if stack is empty. + public T Pop() + { + if (IsEmpty()) { - if (IsEmpty()) - { - throw new InvalidOperationException("The stack contains no items."); - } - - for (int i = 0; i < queue.Count - 1; i++) - { - queue.Enqueue(queue.Dequeue()); - } - - return queue.Dequeue(); + throw new InvalidOperationException("The stack contains no items."); } - /// - /// return an item from the top of the stack without removing it. - /// - /// item on top of the stack. - /// Throw if stack is empty. - public T Peek() + for (int i = 0; i < queue.Count - 1; i++) { - if (IsEmpty()) - { - throw new InvalidOperationException("The stack contains no items."); - } + queue.Enqueue(queue.Dequeue()); + } - for (int i = 0; i < queue.Count - 1; i++) - { - queue.Enqueue(queue.Dequeue()); - } + return queue.Dequeue(); + } - var item = queue.Peek(); + /// + /// return an item from the top of the stack without removing it. + /// + /// item on top of the stack. + /// Throw if stack is empty. + public T Peek() + { + if (IsEmpty()) + { + throw new InvalidOperationException("The stack contains no items."); + } + + for (int i = 0; i < queue.Count - 1; i++) + { queue.Enqueue(queue.Dequeue()); - return item; } - /// - /// returns the count of items on the stack. - /// - /// number of items on the stack. - public int Length() => queue.Count; + var item = queue.Peek(); + queue.Enqueue(queue.Dequeue()); + return item; } + + /// + /// returns the count of items on the stack. + /// + /// number of items on the stack. + public int Length() => queue.Count; } diff --git a/DataStructures/Timeline.cs b/DataStructures/Timeline.cs index 4e66fc97..45bc638d 100644 --- a/DataStructures/Timeline.cs +++ b/DataStructures/Timeline.cs @@ -17,520 +17,519 @@ this data structure can be used to represent an ordered series of dates or times using System.Collections.Generic; using System.Linq; -namespace DataStructures +namespace DataStructures; + +/// +/// A collection of and +/// sorted by field. +/// +/// Value associated with a . +public class Timeline : ICollection<(DateTime Time, TValue Value)>, IEquatable> { /// - /// A collection of and - /// sorted by field. + /// Inner collection storing the timeline events as key-tuples. /// - /// Value associated with a . - public class Timeline : ICollection<(DateTime Time, TValue Value)>, IEquatable> + private readonly List<(DateTime Time, TValue Value)> timeline = new(); + + /// + /// Initializes a new instance of the class. + /// + public Timeline() { - /// - /// Inner collection storing the timeline events as key-tuples. - /// - private readonly List<(DateTime Time, TValue Value)> timeline = new(); - - /// - /// Initializes a new instance of the class. - /// - public Timeline() - { - } + } - /// - /// Initializes a new instance of the class populated with an initial event. - /// - /// The time at which the given event occurred. - /// The event's content. - public Timeline(DateTime time, TValue value) - => timeline = new List<(DateTime, TValue)> - { - (time, value), - }; - - /// - /// Initializes a new instance of the class containing the provided events - /// ordered chronologically. - /// - /// The timeline to represent. - public Timeline(params (DateTime, TValue)[] timeline) - => this.timeline = timeline - .OrderBy(pair => pair.Item1) - .ToList(); - - /// - /// Gets he number of unique times within this timeline. - /// - public int TimesCount - => GetAllTimes().Length; - - /// - /// Gets all events that has occurred in this timeline. - /// - public int ValuesCount - => GetAllValues().Length; - - /// - /// Get all values associated with . - /// - /// Time to get values for. - /// Values associated with . - public TValue[] this[DateTime time] + /// + /// Initializes a new instance of the class populated with an initial event. + /// + /// The time at which the given event occurred. + /// The event's content. + public Timeline(DateTime time, TValue value) + => timeline = new List<(DateTime, TValue)> { - get => GetValuesByTime(time); - set - { - var overridenEvents = timeline.Where(@event => @event.Time == time).ToList(); - foreach (var @event in overridenEvents) - { - timeline.Remove(@event); - } - - foreach (var v in value) - { - Add(time, v); - } - } - } + (time, value), + }; - /// - bool ICollection<(DateTime Time, TValue Value)>.IsReadOnly - => false; - - /// - /// Gets the count of pairs. - /// - public int Count - => timeline.Count; - - /// - /// Clear the timeline, removing all events. - /// - public void Clear() - => timeline.Clear(); - - /// - /// Copy a value to an array. - /// - /// Destination array. - /// The start index. - public void CopyTo((DateTime, TValue)[] array, int arrayIndex) - => timeline.CopyTo(array, arrayIndex); - - /// - /// Add an event at a given time. - /// - /// The tuple containing the event date and value. - void ICollection<(DateTime Time, TValue Value)>.Add((DateTime Time, TValue Value) item) - => Add(item.Time, item.Value); - - /// - /// Check whether or not a event exists at a specific date in the timeline. - /// - /// The tuple containing the event date and value. - /// True if this event exists at the given date, false otherwise. - bool ICollection<(DateTime Time, TValue Value)>.Contains((DateTime Time, TValue Value) item) - => Contains(item.Time, item.Value); - - /// - /// Remove an event at a specific date. - /// - /// The tuple containing the event date and value. - /// True if the event was removed, false otherwise. - bool ICollection<(DateTime Time, TValue Value)>.Remove((DateTime Time, TValue Value) item) - => Remove(item.Time, item.Value); - - /// - IEnumerator IEnumerable.GetEnumerator() - => timeline.GetEnumerator(); - - /// - IEnumerator<(DateTime Time, TValue Value)> IEnumerable<(DateTime Time, TValue Value)>.GetEnumerator() - => timeline.GetEnumerator(); - - /// - public bool Equals(Timeline? other) - => other is not null && this == other; - - /// - /// Checks whether or not two are equals. - /// - /// The first timeline. - /// The other timeline to be checked against the one. - /// True if both timelines are similar, false otherwise. - public static bool operator ==(Timeline left, Timeline right) - { - var leftArray = left.ToArray(); - var rightArray = right.ToArray(); + /// + /// Initializes a new instance of the class containing the provided events + /// ordered chronologically. + /// + /// The timeline to represent. + public Timeline(params (DateTime, TValue)[] timeline) + => this.timeline = timeline + .OrderBy(pair => pair.Item1) + .ToList(); - if (left.Count != rightArray.Length) + /// + /// Gets he number of unique times within this timeline. + /// + public int TimesCount + => GetAllTimes().Length; + + /// + /// Gets all events that has occurred in this timeline. + /// + public int ValuesCount + => GetAllValues().Length; + + /// + /// Get all values associated with . + /// + /// Time to get values for. + /// Values associated with . + public TValue[] this[DateTime time] + { + get => GetValuesByTime(time); + set + { + var overridenEvents = timeline.Where(@event => @event.Time == time).ToList(); + foreach (var @event in overridenEvents) { - return false; + timeline.Remove(@event); } - for (var i = 0; i < leftArray.Length; i++) + foreach (var v in value) { - if (leftArray[i].Time != rightArray[i].Time - && !leftArray[i].Value!.Equals(rightArray[i].Value)) - { - return false; - } + Add(time, v); } - - return true; } + } - /// - /// Checks whether or not two are not equals. - /// - /// The first timeline. - /// The other timeline to be checked against the one. - /// False if both timelines are similar, true otherwise. - public static bool operator !=(Timeline left, Timeline right) - => !(left == right); - - /// - /// Get all of the timeline. - /// - public DateTime[] GetAllTimes() - => timeline.Select(t => t.Time) - .Distinct() - .ToArray(); - - /// - /// Get values of the timeline that have this . - /// - public DateTime[] GetTimesByValue(TValue value) - => timeline.Where(pair => pair.Value!.Equals(value)) - .Select(pair => pair.Time) - .ToArray(); - - /// - /// Get all before . - /// - public DateTime[] GetTimesBefore(DateTime time) - => GetAllTimes() - .Where(t => t < time) - .OrderBy(t => t) - .ToArray(); - - /// - /// Get all after . - /// - public DateTime[] GetTimesAfter(DateTime time) - => GetAllTimes() - .Where(t => t > time) - .OrderBy(t => t) - .ToArray(); - - /// - /// Get all of the timeline. - /// - public TValue[] GetAllValues() - => timeline.Select(pair => pair.Value) - .ToArray(); - - /// - /// Get all associated with . - /// - public TValue[] GetValuesByTime(DateTime time) - => timeline.Where(pair => pair.Time == time) - .Select(pair => pair.Value) - .ToArray(); - - /// - /// Get all before . - /// - public Timeline GetValuesBefore(DateTime time) - => new(this.Where(pair => pair.Time < time).ToArray()); - - /// - /// Get all before . - /// - public Timeline GetValuesAfter(DateTime time) - => new(this.Where(pair => pair.Time > time).ToArray()); - - /// - /// Gets all values that happened at specified millisecond. - /// - /// Value to look for. - /// Array of values. - public Timeline GetValuesByMillisecond(int millisecond) - => new(timeline.Where(pair => pair.Time.Millisecond == millisecond).ToArray()); - - /// - /// Gets all values that happened at specified second. - /// - /// Value to look for. - /// Array of values. - public Timeline GetValuesBySecond(int second) - => new(timeline.Where(pair => pair.Time.Second == second).ToArray()); - - /// - /// Gets all values that happened at specified minute. - /// - /// Value to look for. - /// Array of values. - public Timeline GetValuesByMinute(int minute) - => new(timeline.Where(pair => pair.Time.Minute == minute).ToArray()); - - /// - /// Gets all values that happened at specified hour. - /// - /// Value to look for. - /// Array of values. - public Timeline GetValuesByHour(int hour) - => new(timeline.Where(pair => pair.Time.Hour == hour).ToArray()); - - /// - /// Gets all values that happened at specified day. - /// - /// Value to look for. - /// Array of values. - public Timeline GetValuesByDay(int day) - => new(timeline.Where(pair => pair.Time.Day == day).ToArray()); - - /// - /// Gets all values that happened at specified time of the day. - /// - /// Value to look for. - /// Array of values. - public Timeline GetValuesByTimeOfDay(TimeSpan timeOfDay) - => new(timeline.Where(pair => pair.Time.TimeOfDay == timeOfDay).ToArray()); - - /// - /// Gets all values that happened at specified day of the week. - /// - /// Value to look for. - /// Array of values. - public Timeline GetValuesByDayOfWeek(DayOfWeek dayOfWeek) - => new(timeline.Where(pair => pair.Time.DayOfWeek == dayOfWeek).ToArray()); - - /// - /// Gets all values that happened at specified day of the year. - /// - /// Value to look for. - /// Array of values. - public Timeline GetValuesByDayOfYear(int dayOfYear) - => new(timeline.Where(pair => pair.Time.DayOfYear == dayOfYear).ToArray()); - - /// - /// Gets all values that happened at specified month. - /// - /// Value to look for. - /// Array of values. - public Timeline GetValuesByMonth(int month) - => new(timeline.Where(pair => pair.Time.Month == month).ToArray()); - - /// - /// Gets all values that happened at specified year. - /// - /// Value to look for. - /// Array of values. - public Timeline GetValuesByYear(int year) - => new(timeline.Where(pair => pair.Time.Year == year).ToArray()); - - /// - /// Add an event at a given . - /// - /// The date at which the event occurred. - /// The event value. - public void Add(DateTime time, TValue value) - { - timeline.Add((time, value)); - } + /// + bool ICollection<(DateTime Time, TValue Value)>.IsReadOnly + => false; + + /// + /// Gets the count of pairs. + /// + public int Count + => timeline.Count; + + /// + /// Clear the timeline, removing all events. + /// + public void Clear() + => timeline.Clear(); + + /// + /// Copy a value to an array. + /// + /// Destination array. + /// The start index. + public void CopyTo((DateTime, TValue)[] array, int arrayIndex) + => timeline.CopyTo(array, arrayIndex); + + /// + /// Add an event at a given time. + /// + /// The tuple containing the event date and value. + void ICollection<(DateTime Time, TValue Value)>.Add((DateTime Time, TValue Value) item) + => Add(item.Time, item.Value); + + /// + /// Check whether or not a event exists at a specific date in the timeline. + /// + /// The tuple containing the event date and value. + /// True if this event exists at the given date, false otherwise. + bool ICollection<(DateTime Time, TValue Value)>.Contains((DateTime Time, TValue Value) item) + => Contains(item.Time, item.Value); + + /// + /// Remove an event at a specific date. + /// + /// The tuple containing the event date and value. + /// True if the event was removed, false otherwise. + bool ICollection<(DateTime Time, TValue Value)>.Remove((DateTime Time, TValue Value) item) + => Remove(item.Time, item.Value); + + /// + IEnumerator IEnumerable.GetEnumerator() + => timeline.GetEnumerator(); - /// - /// Add a set of and to the timeline. - /// - public void Add(params (DateTime, TValue)[] timeline) + /// + IEnumerator<(DateTime Time, TValue Value)> IEnumerable<(DateTime Time, TValue Value)>.GetEnumerator() + => timeline.GetEnumerator(); + + /// + public bool Equals(Timeline? other) + => other is not null && this == other; + + /// + /// Checks whether or not two are equals. + /// + /// The first timeline. + /// The other timeline to be checked against the one. + /// True if both timelines are similar, false otherwise. + public static bool operator ==(Timeline left, Timeline right) + { + var leftArray = left.ToArray(); + var rightArray = right.ToArray(); + + if (left.Count != rightArray.Length) { - this.timeline.AddRange(timeline); + return false; } - /// - /// Append an existing timeline to this one. - /// - public void Add(Timeline timeline) - => Add(timeline.ToArray()); - - /// - /// Add a associated with to the timeline. - /// - public void AddNow(params TValue[] value) + for (var i = 0; i < leftArray.Length; i++) { - var now = DateTime.Now; - foreach (var v in value) + if (leftArray[i].Time != rightArray[i].Time + && !leftArray[i].Value!.Equals(rightArray[i].Value)) { - Add(now, v); + return false; } } - /// - /// Check whether or not a event exists at a specific date in the timeline. - /// - /// The date at which the event occurred. - /// The event value. - /// True if this event exists at the given date, false otherwise. - public bool Contains(DateTime time, TValue value) - => timeline.Contains((time, value)); - - /// - /// Check if timeline contains this set of value pairs. - /// - /// The events to checks. - /// True if any of the events has occurred in the timeline. - public bool Contains(params (DateTime, TValue)[] timeline) - => timeline.Any(@event => Contains(@event.Item1, @event.Item2)); - - /// - /// Check if timeline contains any of the event of the provided . - /// - /// The events to checks. - /// True if any of the events has occurred in the timeline. - public bool Contains(Timeline timeline) - => Contains(timeline.ToArray()); - - /// - /// Check if timeline contains any of the time of the provided . - /// - /// The times to checks. - /// True if any of the times is stored in the timeline. - public bool ContainsTime(params DateTime[] times) - { - var storedTimes = GetAllTimes(); - return times.Any(value => storedTimes.Contains(value)); - } + return true; + } + + /// + /// Checks whether or not two are not equals. + /// + /// The first timeline. + /// The other timeline to be checked against the one. + /// False if both timelines are similar, true otherwise. + public static bool operator !=(Timeline left, Timeline right) + => !(left == right); + + /// + /// Get all of the timeline. + /// + public DateTime[] GetAllTimes() + => timeline.Select(t => t.Time) + .Distinct() + .ToArray(); + + /// + /// Get values of the timeline that have this . + /// + public DateTime[] GetTimesByValue(TValue value) + => timeline.Where(pair => pair.Value!.Equals(value)) + .Select(pair => pair.Time) + .ToArray(); + + /// + /// Get all before . + /// + public DateTime[] GetTimesBefore(DateTime time) + => GetAllTimes() + .Where(t => t < time) + .OrderBy(t => t) + .ToArray(); + + /// + /// Get all after . + /// + public DateTime[] GetTimesAfter(DateTime time) + => GetAllTimes() + .Where(t => t > time) + .OrderBy(t => t) + .ToArray(); + + /// + /// Get all of the timeline. + /// + public TValue[] GetAllValues() + => timeline.Select(pair => pair.Value) + .ToArray(); + + /// + /// Get all associated with . + /// + public TValue[] GetValuesByTime(DateTime time) + => timeline.Where(pair => pair.Time == time) + .Select(pair => pair.Value) + .ToArray(); + + /// + /// Get all before . + /// + public Timeline GetValuesBefore(DateTime time) + => new(this.Where(pair => pair.Time < time).ToArray()); + + /// + /// Get all before . + /// + public Timeline GetValuesAfter(DateTime time) + => new(this.Where(pair => pair.Time > time).ToArray()); + + /// + /// Gets all values that happened at specified millisecond. + /// + /// Value to look for. + /// Array of values. + public Timeline GetValuesByMillisecond(int millisecond) + => new(timeline.Where(pair => pair.Time.Millisecond == millisecond).ToArray()); + + /// + /// Gets all values that happened at specified second. + /// + /// Value to look for. + /// Array of values. + public Timeline GetValuesBySecond(int second) + => new(timeline.Where(pair => pair.Time.Second == second).ToArray()); + + /// + /// Gets all values that happened at specified minute. + /// + /// Value to look for. + /// Array of values. + public Timeline GetValuesByMinute(int minute) + => new(timeline.Where(pair => pair.Time.Minute == minute).ToArray()); + + /// + /// Gets all values that happened at specified hour. + /// + /// Value to look for. + /// Array of values. + public Timeline GetValuesByHour(int hour) + => new(timeline.Where(pair => pair.Time.Hour == hour).ToArray()); - /// - /// Check if timeline contains any of the event of the provided . - /// - /// The events to checks. - /// True if any of the events has occurred in the timeline. - public bool ContainsValue(params TValue[] values) + /// + /// Gets all values that happened at specified day. + /// + /// Value to look for. + /// Array of values. + public Timeline GetValuesByDay(int day) + => new(timeline.Where(pair => pair.Time.Day == day).ToArray()); + + /// + /// Gets all values that happened at specified time of the day. + /// + /// Value to look for. + /// Array of values. + public Timeline GetValuesByTimeOfDay(TimeSpan timeOfDay) + => new(timeline.Where(pair => pair.Time.TimeOfDay == timeOfDay).ToArray()); + + /// + /// Gets all values that happened at specified day of the week. + /// + /// Value to look for. + /// Array of values. + public Timeline GetValuesByDayOfWeek(DayOfWeek dayOfWeek) + => new(timeline.Where(pair => pair.Time.DayOfWeek == dayOfWeek).ToArray()); + + /// + /// Gets all values that happened at specified day of the year. + /// + /// Value to look for. + /// Array of values. + public Timeline GetValuesByDayOfYear(int dayOfYear) + => new(timeline.Where(pair => pair.Time.DayOfYear == dayOfYear).ToArray()); + + /// + /// Gets all values that happened at specified month. + /// + /// Value to look for. + /// Array of values. + public Timeline GetValuesByMonth(int month) + => new(timeline.Where(pair => pair.Time.Month == month).ToArray()); + + /// + /// Gets all values that happened at specified year. + /// + /// Value to look for. + /// Array of values. + public Timeline GetValuesByYear(int year) + => new(timeline.Where(pair => pair.Time.Year == year).ToArray()); + + /// + /// Add an event at a given . + /// + /// The date at which the event occurred. + /// The event value. + public void Add(DateTime time, TValue value) + { + timeline.Add((time, value)); + } + + /// + /// Add a set of and to the timeline. + /// + public void Add(params (DateTime, TValue)[] timeline) + { + this.timeline.AddRange(timeline); + } + + /// + /// Append an existing timeline to this one. + /// + public void Add(Timeline timeline) + => Add(timeline.ToArray()); + + /// + /// Add a associated with to the timeline. + /// + public void AddNow(params TValue[] value) + { + var now = DateTime.Now; + foreach (var v in value) { - var storedValues = GetAllValues(); - return values.Any(value => storedValues.Contains(value)); + Add(now, v); } + } - /// - /// Remove an event at a specific date. - /// - /// The date at which the event occurred. - /// The event value. - /// True if the event was removed, false otherwise. - public bool Remove(DateTime time, TValue value) - => timeline.Remove((time, value)); - - /// - /// Remove a set of value pairs from the timeline. - /// - /// An collection of all events to remove. - /// Returns true if the operation completed successfully. - public bool Remove(params (DateTime, TValue)[] timeline) - { - var result = false; - foreach (var (time, value) in timeline) - { - result |= this.timeline.Remove((time, value)); - } + /// + /// Check whether or not a event exists at a specific date in the timeline. + /// + /// The date at which the event occurred. + /// The event value. + /// True if this event exists at the given date, false otherwise. + public bool Contains(DateTime time, TValue value) + => timeline.Contains((time, value)); - return result; - } + /// + /// Check if timeline contains this set of value pairs. + /// + /// The events to checks. + /// True if any of the events has occurred in the timeline. + public bool Contains(params (DateTime, TValue)[] timeline) + => timeline.Any(@event => Contains(@event.Item1, @event.Item2)); + + /// + /// Check if timeline contains any of the event of the provided . + /// + /// The events to checks. + /// True if any of the events has occurred in the timeline. + public bool Contains(Timeline timeline) + => Contains(timeline.ToArray()); + + /// + /// Check if timeline contains any of the time of the provided . + /// + /// The times to checks. + /// True if any of the times is stored in the timeline. + public bool ContainsTime(params DateTime[] times) + { + var storedTimes = GetAllTimes(); + return times.Any(value => storedTimes.Contains(value)); + } - /// - /// Remove an existing timeline from this timeline. - /// - /// An collection of all events to remove. - /// Returns true if the operation completed successfully. - public bool Remove(Timeline timeline) - => Remove(timeline.ToArray()); - - /// - /// Remove a value pair from the timeline if the time is equal to . - /// - /// Returns true if the operation completed successfully. - public bool RemoveTimes(params DateTime[] times) + /// + /// Check if timeline contains any of the event of the provided . + /// + /// The events to checks. + /// True if any of the events has occurred in the timeline. + public bool ContainsValue(params TValue[] values) + { + var storedValues = GetAllValues(); + return values.Any(value => storedValues.Contains(value)); + } + + /// + /// Remove an event at a specific date. + /// + /// The date at which the event occurred. + /// The event value. + /// True if the event was removed, false otherwise. + public bool Remove(DateTime time, TValue value) + => timeline.Remove((time, value)); + + /// + /// Remove a set of value pairs from the timeline. + /// + /// An collection of all events to remove. + /// Returns true if the operation completed successfully. + public bool Remove(params (DateTime, TValue)[] timeline) + { + var result = false; + foreach (var (time, value) in timeline) { - var isTimeContainedInTheTimeline = times.Any(time => GetAllTimes().Contains(time)); + result |= this.timeline.Remove((time, value)); + } - if (!isTimeContainedInTheTimeline) - { - return false; - } + return result; + } - var eventsToRemove = times.SelectMany(time => - timeline.Where(@event => @event.Time == time)) - .ToList(); + /// + /// Remove an existing timeline from this timeline. + /// + /// An collection of all events to remove. + /// Returns true if the operation completed successfully. + public bool Remove(Timeline timeline) + => Remove(timeline.ToArray()); - foreach (var @event in eventsToRemove) - { - timeline.Remove(@event); - } + /// + /// Remove a value pair from the timeline if the time is equal to . + /// + /// Returns true if the operation completed successfully. + public bool RemoveTimes(params DateTime[] times) + { + var isTimeContainedInTheTimeline = times.Any(time => GetAllTimes().Contains(time)); - return true; + if (!isTimeContainedInTheTimeline) + { + return false; } - /// - /// Remove a value pair from the timeline if the value is equal to . - /// - /// Returns true if the operation completed successfully. - public bool RemoveValues(params TValue[] values) + var eventsToRemove = times.SelectMany(time => + timeline.Where(@event => @event.Time == time)) + .ToList(); + + foreach (var @event in eventsToRemove) { - var isValueContainedInTheTimeline = values.Any(v => GetAllValues().Contains(v)); + timeline.Remove(@event); + } - if (!isValueContainedInTheTimeline) - { - return false; - } + return true; + } - var eventsToRemove = values.SelectMany(value => - timeline.Where(@event => EqualityComparer.Default.Equals(@event.Value, value))) - .ToList(); + /// + /// Remove a value pair from the timeline if the value is equal to . + /// + /// Returns true if the operation completed successfully. + public bool RemoveValues(params TValue[] values) + { + var isValueContainedInTheTimeline = values.Any(v => GetAllValues().Contains(v)); - foreach (var @event in eventsToRemove) - { - timeline.Remove(@event); - } + if (!isValueContainedInTheTimeline) + { + return false; + } + + var eventsToRemove = values.SelectMany(value => + timeline.Where(@event => EqualityComparer.Default.Equals(@event.Value, value))) + .ToList(); - return true; + foreach (var @event in eventsToRemove) + { + timeline.Remove(@event); } - /// - /// Convert the timeline to an array. - /// - /// - /// The timeline as an array of tuples of (, ). - /// - public (DateTime Time, TValue Value)[] ToArray() - => timeline.ToArray(); - - /// - /// Convert the timeline to a list. - /// - /// - /// The timeline as a list of tuples of (, ). - /// - public IList<(DateTime Time, TValue Value)> ToList() - => timeline; - - /// - /// Convert the timeline to a dictionary. - /// - /// - /// The timeline as an dictionary of by . - /// - public IDictionary ToDictionary() - => timeline.ToDictionary(@event => @event.Time, @event => @event.Value); - - /// - public override bool Equals(object? obj) - => obj is Timeline otherTimeline - && this == otherTimeline; - - /// - public override int GetHashCode() - => timeline.GetHashCode(); + return true; } + + /// + /// Convert the timeline to an array. + /// + /// + /// The timeline as an array of tuples of (, ). + /// + public (DateTime Time, TValue Value)[] ToArray() + => timeline.ToArray(); + + /// + /// Convert the timeline to a list. + /// + /// + /// The timeline as a list of tuples of (, ). + /// + public IList<(DateTime Time, TValue Value)> ToList() + => timeline; + + /// + /// Convert the timeline to a dictionary. + /// + /// + /// The timeline as an dictionary of by . + /// + public IDictionary ToDictionary() + => timeline.ToDictionary(@event => @event.Time, @event => @event.Value); + + /// + public override bool Equals(object? obj) + => obj is Timeline otherTimeline + && this == otherTimeline; + + /// + public override int GetHashCode() + => timeline.GetHashCode(); } diff --git a/DataStructures/Tries/Trie.cs b/DataStructures/Tries/Trie.cs index 41c36995..803a4146 100644 --- a/DataStructures/Tries/Trie.cs +++ b/DataStructures/Tries/Trie.cs @@ -1,124 +1,123 @@ using System; using System.Collections.Generic; -namespace DataStructures.Tries +namespace DataStructures.Tries; + +/// +/// A Trie is a data structure (particular case of m-ary tree) used to efficiently represent strings with common prefixes. +/// Originally posed by E. Fredkin in 1960. +/// Fredkin, Edward (Sept. 1960), "Trie Memory", Communications of the ACM 3 (9): 490-499. +/// Its name is due to retrieval because its main application is in the field of "Information Retrieval" (information retrieval). +/// +public class Trie { /// - /// A Trie is a data structure (particular case of m-ary tree) used to efficiently represent strings with common prefixes. - /// Originally posed by E. Fredkin in 1960. - /// Fredkin, Edward (Sept. 1960), "Trie Memory", Communications of the ACM 3 (9): 490-499. - /// Its name is due to retrieval because its main application is in the field of "Information Retrieval" (information retrieval). + /// This character marks the end of a string. /// - public class Trie - { - /// - /// This character marks the end of a string. - /// - private const char Mark = '$'; + private const char Mark = '$'; - /// - /// This property represents the root node of the trie. - /// - private readonly TrieNode root; + /// + /// This property represents the root node of the trie. + /// + private readonly TrieNode root; - /// - /// Initializes a new instance of the class. This instances was created without text strings, generating the root node of the trie, without children. - /// - public Trie() - { - root = new TrieNode(Mark); - } + /// + /// Initializes a new instance of the class. This instances was created without text strings, generating the root node of the trie, without children. + /// + public Trie() + { + root = new TrieNode(Mark); + } - /// - /// Initializes a new instance of the class. Given a set of text strings, each of those strings inserts them into the trie using the Insert (string) method. - /// - /// The array with text strings to insert in the trie. - public Trie(IEnumerable words) - : this() + /// + /// Initializes a new instance of the class. Given a set of text strings, each of those strings inserts them into the trie using the Insert (string) method. + /// + /// The array with text strings to insert in the trie. + public Trie(IEnumerable words) + : this() + { + foreach (string s in words) { - foreach (string s in words) - { - Insert(s); - } + Insert(s); } + } - /// - /// Insert a string s to the trie. The $ mark is added to the end of the chain and then it is added, this in order to indicate the end of the chain in the trie. - /// - /// The string to insert into the trie. - public void Insert(string s) - { - s += Mark; + /// + /// Insert a string s to the trie. The $ mark is added to the end of the chain and then it is added, this in order to indicate the end of the chain in the trie. + /// + /// The string to insert into the trie. + public void Insert(string s) + { + s += Mark; - int index = 0; - TrieNode match = PrefixQuery(s, ref index); + int index = 0; + TrieNode match = PrefixQuery(s, ref index); - for (int i = index; i < s.Length; i++) - { - TrieNode t = new(s[i], match); - match[s[i]] = t; - match = t; - } + for (int i = index; i < s.Length; i++) + { + TrieNode t = new(s[i], match); + match[s[i]] = t; + match = t; } + } - /// - /// Remove a text string from the trie. - /// - /// The text string to be removed from the trie. - public void Remove(string s) + /// + /// Remove a text string from the trie. + /// + /// The text string to be removed from the trie. + public void Remove(string s) + { + s += Mark; + int index = 0; + TrieNode match = PrefixQuery(s, ref index); + while(match.IsLeaf()) { - s += Mark; - int index = 0; - TrieNode match = PrefixQuery(s, ref index); - while(match.IsLeaf()) + char c = match.Value; + if(match.Parent == null) { - char c = match.Value; - if(match.Parent == null) - { - break; - } - - match = match.Parent; - match.Children.Remove(c); + break; } - } - /// - /// Know if a text string is in the trie. - /// - /// The string s that you want to know if it is in the trie. - /// If the string is found, it returns true, otherwise false. - public bool Find(string s) - { - int index = 0; - return PrefixQuery(s + Mark, ref index).IsLeaf(); + match = match.Parent; + match.Children.Remove(c); } + } - /// - /// This method analyzes which is the longest common prefix of a string s in the trie. If the string is in the trie then it is equivalent to doing Find (s). - /// - /// The string for which you want to know the longest common prefix. - /// The index to which the longest common prefix goes. - /// - /// Returns the longest common prefix node found in the trie with the string s. - /// - private TrieNode PrefixQuery(string s, ref int index) + /// + /// Know if a text string is in the trie. + /// + /// The string s that you want to know if it is in the trie. + /// If the string is found, it returns true, otherwise false. + public bool Find(string s) + { + int index = 0; + return PrefixQuery(s + Mark, ref index).IsLeaf(); + } + + /// + /// This method analyzes which is the longest common prefix of a string s in the trie. If the string is in the trie then it is equivalent to doing Find (s). + /// + /// The string for which you want to know the longest common prefix. + /// The index to which the longest common prefix goes. + /// + /// Returns the longest common prefix node found in the trie with the string s. + /// + private TrieNode PrefixQuery(string s, ref int index) + { + TrieNode current = root; + for (int i = 0; i < s.Length && current != null; i++) { - TrieNode current = root; - for (int i = 0; i < s.Length && current != null; i++) + if (current[s[i]] != null) { - if (current[s[i]] != null) - { - current = current[s[i]] ?? throw new NullReferenceException(); - index = i + 1; - } - else - { - break; - } + current = current[s[i]] ?? throw new NullReferenceException(); + index = i + 1; + } + else + { + break; } - - return current ?? throw new NullReferenceException(); } + + return current ?? throw new NullReferenceException(); } } diff --git a/DataStructures/Tries/TrieNode.cs b/DataStructures/Tries/TrieNode.cs index 8d7cb8db..b356b1cf 100644 --- a/DataStructures/Tries/TrieNode.cs +++ b/DataStructures/Tries/TrieNode.cs @@ -1,69 +1,68 @@ using System; using System.Collections.Generic; -namespace DataStructures.Tries +namespace DataStructures.Tries; + +/// +/// This class represents the nodes of a trie. +/// +internal class TrieNode { /// - /// This class represents the nodes of a trie. + /// Initializes a new instance of the class. This instance was created with a character from the alphabet, and its parent will be null. /// - internal class TrieNode + /// Character of the alphabet that represents the node. + internal TrieNode(char value) + : this(value, null) { - /// - /// Initializes a new instance of the class. This instance was created with a character from the alphabet, and its parent will be null. - /// - /// Character of the alphabet that represents the node. - internal TrieNode(char value) - : this(value, null) - { - } + } - /// - /// Initializes a new instance of the class. This instance was created with a character from the alphabet, and its parent. - /// - /// Character of the alphabet that represents the node. - /// The parent or ancestor of the node in the trie structure. - internal TrieNode(char value, TrieNode? parent) - { - Children = new SortedList(); - Parent = parent; - Value = value; - } + /// + /// Initializes a new instance of the class. This instance was created with a character from the alphabet, and its parent. + /// + /// Character of the alphabet that represents the node. + /// The parent or ancestor of the node in the trie structure. + internal TrieNode(char value, TrieNode? parent) + { + Children = new SortedList(); + Parent = parent; + Value = value; + } - /// - /// Gets all the descendants of the current node. - /// - /// A sorted set with all the descendants. - internal SortedList Children { get; private set; } + /// + /// Gets all the descendants of the current node. + /// + /// A sorted set with all the descendants. + internal SortedList Children { get; private set; } - /// - /// Gets the parent or ancestor of the node in the trie structure. - /// - /// A TrieNode that represent a parent. - internal TrieNode? Parent { get; private set; } + /// + /// Gets the parent or ancestor of the node in the trie structure. + /// + /// A TrieNode that represent a parent. + internal TrieNode? Parent { get; private set; } - /// - /// Gets the character of the alphabet that represents the node. - /// - /// A character of the alphabet. - internal char Value { get; private set; } + /// + /// Gets the character of the alphabet that represents the node. + /// + /// A character of the alphabet. + internal char Value { get; private set; } - /// - /// Index the descendants of the current node given an alphabet character. - /// - /// A TrieNode with the character c in Children. - public TrieNode? this[char c] - { - get => Children.ContainsKey(c) ? Children[c] : null; - set => Children[c] = value ?? throw new NullReferenceException(); - } + /// + /// Index the descendants of the current node given an alphabet character. + /// + /// A TrieNode with the character c in Children. + public TrieNode? this[char c] + { + get => Children.ContainsKey(c) ? Children[c] : null; + set => Children[c] = value ?? throw new NullReferenceException(); + } - /// - /// Method that checks if the current node is a trie leaf. - /// - /// Returns true if the current node has no children, false otherwise. - public bool IsLeaf() - { - return Children.Count == 0; - } + /// + /// Method that checks if the current node is a trie leaf. + /// + /// Returns true if the current node has no children, false otherwise. + public bool IsLeaf() + { + return Children.Count == 0; } } diff --git a/DataStructures/UnrolledList/UnrolledLinkedList.cs b/DataStructures/UnrolledList/UnrolledLinkedList.cs index 0feaf5dd..006bdfc9 100644 --- a/DataStructures/UnrolledList/UnrolledLinkedList.cs +++ b/DataStructures/UnrolledList/UnrolledLinkedList.cs @@ -1,86 +1,85 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace DataStructures.UnrolledList +namespace DataStructures.UnrolledList; + +/// +/// Unrolled linked list is a linked list of small arrays, +/// all of the same size where each is so small that the insertion +/// or deletion is fast and quick, but large enough to fill the cache line. +/// +public class UnrolledLinkedList { + private readonly int sizeNode; + + private UnrolledLinkedListNode start = null!; + private UnrolledLinkedListNode end = null!; + /// - /// Unrolled linked list is a linked list of small arrays, - /// all of the same size where each is so small that the insertion - /// or deletion is fast and quick, but large enough to fill the cache line. + /// Initializes a new instance of the class. + /// Create a unrolled list with start chunk size. /// - public class UnrolledLinkedList + /// The size of signe chunk. + public UnrolledLinkedList(int chunkSize) { - private readonly int sizeNode; - - private UnrolledLinkedListNode start = null!; - private UnrolledLinkedListNode end = null!; + sizeNode = chunkSize + 1; + } - /// - /// Initializes a new instance of the class. - /// Create a unrolled list with start chunk size. - /// - /// The size of signe chunk. - public UnrolledLinkedList(int chunkSize) + /// + /// Add value to list [O(n)]. + /// + /// The entered value. + public void Insert(int value) + { + if (start == null) { - sizeNode = chunkSize + 1; + start = new UnrolledLinkedListNode(sizeNode); + start.Set(0, value); + + end = start; + return; } - /// - /// Add value to list [O(n)]. - /// - /// The entered value. - public void Insert(int value) + if (end.Count + 1 < sizeNode) { - if (start == null) - { - start = new UnrolledLinkedListNode(sizeNode); - start.Set(0, value); - - end = start; - return; - } - - if (end.Count + 1 < sizeNode) + end.Set(end.Count, value); + } + else + { + var pointer = new UnrolledLinkedListNode(sizeNode); + var j = 0; + for (var pos = end.Count / 2 + 1; pos < end.Count; pos++) { - end.Set(end.Count, value); + pointer.Set(j++, end.Get(pos)); } - else - { - var pointer = new UnrolledLinkedListNode(sizeNode); - var j = 0; - for (var pos = end.Count / 2 + 1; pos < end.Count; pos++) - { - pointer.Set(j++, end.Get(pos)); - } - pointer.Set(j++, value); - pointer.Count = j; + pointer.Set(j++, value); + pointer.Count = j; - end.Count = end.Count / 2 + 1; - end.Next = pointer; - end = pointer; - } + end.Count = end.Count / 2 + 1; + end.Next = pointer; + end = pointer; } + } - /// - /// Help method. Get all list inside to check the state. - /// - /// Items from all nodes. - public IEnumerable GetRolledItems() - { - UnrolledLinkedListNode pointer = start; - List result = new(); + /// + /// Help method. Get all list inside to check the state. + /// + /// Items from all nodes. + public IEnumerable GetRolledItems() + { + UnrolledLinkedListNode pointer = start; + List result = new(); - while (pointer != null) + while (pointer != null) + { + for (var i = 0; i < pointer.Count; i++) { - for (var i = 0; i < pointer.Count; i++) - { - result.Add(pointer.Get(i)); - } - - pointer = pointer.Next; + result.Add(pointer.Get(i)); } - return result; + pointer = pointer.Next; } + + return result; } } diff --git a/DataStructures/UnrolledList/UnrolledLinkedListNode.cs b/DataStructures/UnrolledList/UnrolledLinkedListNode.cs index d82523e7..b59c6ac0 100644 --- a/DataStructures/UnrolledList/UnrolledLinkedListNode.cs +++ b/DataStructures/UnrolledList/UnrolledLinkedListNode.cs @@ -1,56 +1,55 @@ -using System; +using System; -namespace DataStructures.UnrolledList +namespace DataStructures.UnrolledList; + +/// +/// Single node with array buffer for unrolled list. +/// +public class UnrolledLinkedListNode { - /// - /// Single node with array buffer for unrolled list. - /// - public class UnrolledLinkedListNode - { - private readonly int[] array; + private readonly int[] array; - public UnrolledLinkedListNode(int nodeSize) - { - Next = null!; + public UnrolledLinkedListNode(int nodeSize) + { + Next = null!; - Count = 0; - array = new int[nodeSize]; - } + Count = 0; + array = new int[nodeSize]; + } - public UnrolledLinkedListNode Next { get; set; } + public UnrolledLinkedListNode Next { get; set; } - public int Count { get; set; } + public int Count { get; set; } - /// - /// Set new item in array buffer. - /// - /// Index in array. - /// The entered value. - /// Index is out of scope. - public void Set(int pos, int val) + /// + /// Set new item in array buffer. + /// + /// Index in array. + /// The entered value. + /// Index is out of scope. + public void Set(int pos, int val) + { + if (pos < 0 || pos > array.Length - 1) { - if (pos < 0 || pos > array.Length - 1) - { - throw new ArgumentException("Position is out of size", nameof(pos)); - } - - array[pos] = val; - Count++; + throw new ArgumentException("Position is out of size", nameof(pos)); } - /// - /// Get item from array buffer. - /// - /// Index in array. - /// Index is out of scope. - public int Get(int pos) - { - if (pos < 0 || pos > array.Length - 1) - { - throw new ArgumentException("Position is out of size", nameof(pos)); - } + array[pos] = val; + Count++; + } - return array[pos]; + /// + /// Get item from array buffer. + /// + /// Index in array. + /// Index is out of scope. + public int Get(int pos) + { + if (pos < 0 || pos > array.Length - 1) + { + throw new ArgumentException("Position is out of size", nameof(pos)); } + + return array[pos]; } } From e8ca3f4b4202b859f88bcf9011a8dfe3c33203ea Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Tue, 9 Jan 2024 09:51:46 +0000 Subject: [PATCH 087/138] Switch to file-scoped namespaces (#435) --- .../Extensions/DictionaryExtensionsTests.cs | 43 ++- .../Extensions/MatrixExtensionsTests.cs | 353 +++++++++--------- .../Extensions/RandomExtensionsTests.cs | 21 +- .../Extensions/VectorExtensionsTests.cs | 197 +++++----- Utilities/Exceptions/ItemNotFoundException.cs | 15 +- Utilities/Extensions/DictionaryExtensions.cs | 39 +- Utilities/Extensions/MatrixExtensions.cs | 267 +++++++------ Utilities/Extensions/RandomExtensions.cs | 29 +- Utilities/Extensions/VectorExtensions.cs | 235 ++++++------ 9 files changed, 595 insertions(+), 604 deletions(-) diff --git a/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs b/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs index 7d34d509..059c454b 100644 --- a/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs +++ b/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs @@ -1,37 +1,36 @@ -using System; +using System; using System.Collections.Generic; using FluentAssertions; using NUnit.Framework; using Utilities.Extensions; -namespace Utilities.Tests.Extensions +namespace Utilities.Tests.Extensions; + +public class DictionaryExtensionsTests { - public class DictionaryExtensionsTests + [Test] + public void AddMany_ShouldThrowArgumentException_WhenKeyAlreadyExists() { - [Test] - public void AddMany_ShouldThrowArgumentException_WhenKeyAlreadyExists() - { - var dictionary = new Dictionary { ["one"] = 1 }; - var enumerable = new[] { ("one", 1), ("two", 2) }; + var dictionary = new Dictionary { ["one"] = 1 }; + var enumerable = new[] { ("one", 1), ("two", 2) }; - var action = () => dictionary.AddMany(enumerable); + var action = () => dictionary.AddMany(enumerable); - action.Should().Throw(); - } + action.Should().Throw(); + } - [Test] - public void AddMany_ShouldAddAllKeyValuePairs() - { - var dictionary = new Dictionary { ["one"] = 1 }; - var enumerable = new[] { ("two", 2), ("three", 3) }; + [Test] + public void AddMany_ShouldAddAllKeyValuePairs() + { + var dictionary = new Dictionary { ["one"] = 1 }; + var enumerable = new[] { ("two", 2), ("three", 3) }; - dictionary.AddMany(enumerable); + dictionary.AddMany(enumerable); - dictionary.Should().HaveCount(3); + dictionary.Should().HaveCount(3); - dictionary.Should().ContainKey("one").WhichValue.Should().Be(1); - dictionary.Should().ContainKey("two").WhichValue.Should().Be(2); - dictionary.Should().ContainKey("three").WhichValue.Should().Be(3); - } + dictionary.Should().ContainKey("one").WhichValue.Should().Be(1); + dictionary.Should().ContainKey("two").WhichValue.Should().Be(2); + dictionary.Should().ContainKey("three").WhichValue.Should().Be(3); } } diff --git a/Utilities.Tests/Extensions/MatrixExtensionsTests.cs b/Utilities.Tests/Extensions/MatrixExtensionsTests.cs index 952dc257..8d99f4d3 100644 --- a/Utilities.Tests/Extensions/MatrixExtensionsTests.cs +++ b/Utilities.Tests/Extensions/MatrixExtensionsTests.cs @@ -3,209 +3,208 @@ using NUnit.Framework; using Utilities.Extensions; -namespace Utilities.Tests.Extensions +namespace Utilities.Tests.Extensions; + +public class MatrixExtensionsTests { - public class MatrixExtensionsTests + private static readonly object[] MatrixMultiplyTestCases = { - private static readonly object[] MatrixMultiplyTestCases = + new object[] { - new object[] - { - new double[,] { { 2, 2, -1 }, { 0, -2, -1 }, { 0, 0, 5 } }, - new double[,] { { 2 }, { 2 }, { 3 } }, - new double[,] { { 5 }, { -7 }, { 15 } }, - }, - new object[] - { - new double[,] { { 5, 8, -4 }, { 6, 9, -5 }, { 4, 7, -3 } }, - new double[,] { { 3, 2, 5 }, { 4, -1, 3 }, { 9, 6, 5 } }, - new double[,] { { 11, -22, 29 }, { 9, -27, 32 }, { 13, -17, 26 } }, - }, - }; - - private static readonly object[] MatrixTransposeTestCases = + new double[,] { { 2, 2, -1 }, { 0, -2, -1 }, { 0, 0, 5 } }, + new double[,] { { 2 }, { 2 }, { 3 } }, + new double[,] { { 5 }, { -7 }, { 15 } }, + }, + new object[] { - new object[] - { - new double[,] { { 2, 2, 3 } }, - new double[,] { { 2 }, { 2 }, { 3 } }, - }, - new object[] - { - new double[,] { { 5, 8 }, { 6, 9 } }, - new double[,] { { 5, 6 }, { 8, 9 } }, - }, - }; + new double[,] { { 5, 8, -4 }, { 6, 9, -5 }, { 4, 7, -3 } }, + new double[,] { { 3, 2, 5 }, { 4, -1, 3 }, { 9, 6, 5 } }, + new double[,] { { 11, -22, 29 }, { 9, -27, 32 }, { 13, -17, 26 } }, + }, + }; - private static readonly object[] MatrixSubtractTestCases = + private static readonly object[] MatrixTransposeTestCases = + { + new object[] { - new object[] - { - new double[,] { { 0, 0 }, { 0, 0 } }, - new double[,] { { 1, 1 }, { 1, 1 } }, - new double[,] { { -1, -1 }, { -1, -1 } }, - }, - new object[] - { - new double[,] { { 1, 2 }, { 2, 3 }, { 3, 4 } }, - new double[,] { { 1, 1 }, { 1, 1 }, { 1, 1 } }, - new double[,] { { 0, 1 }, { 1, 2 }, { 2, 3 } }, - }, - new object[] - { - new double[,] { { -1, -2, 0 }, { 2, -3, 2 }, { 3, 4, 1 } }, - new double[,] { { 2, 5, 12 }, { 0, 5, 1 }, { 1, 1, 4 } }, - new double[,] { { -3, -7, -12 }, { 2, -8, 1 }, { 2, 3, -3 } }, - }, - }; + new double[,] { { 2, 2, 3 } }, + new double[,] { { 2 }, { 2 }, { 3 } }, + }, + new object[] + { + new double[,] { { 5, 8 }, { 6, 9 } }, + new double[,] { { 5, 6 }, { 8, 9 } }, + }, + }; - [Test] - public void Multiply_ShouldThrowInvalidOperationException_WhenOperandsAreNotCompatible() + private static readonly object[] MatrixSubtractTestCases = + { + new object[] + { + new double[,] { { 0, 0 }, { 0, 0 } }, + new double[,] { { 1, 1 }, { 1, 1 } }, + new double[,] { { -1, -1 }, { -1, -1 } }, + }, + new object[] { - // Arrange - var source = new double[,] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } }; - var operand = new double[,] { { 1 }, { 1 } }; - - // Act - Action action = () => source.Multiply(operand); - - // Assert - action.Should().Throw() - .WithMessage("The width of a first operand should match the height of a second."); - } - - [TestCaseSource(nameof(MatrixMultiplyTestCases))] - public void Multiply_ShouldCalculateDotProductMultiplicationResult( - double[,] source, - double[,] operand, - double[,] result) => - source.Multiply(operand).Should().BeEquivalentTo(result); - - [Test] - public void Copy_ShouldReturnImmutableCopyOfMatrix() + new double[,] { { 1, 2 }, { 2, 3 }, { 3, 4 } }, + new double[,] { { 1, 1 }, { 1, 1 }, { 1, 1 } }, + new double[,] { { 0, 1 }, { 1, 2 }, { 2, 3 } }, + }, + new object[] { - // Arrange - var sutMatrix = new double[,] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } }; + new double[,] { { -1, -2, 0 }, { 2, -3, 2 }, { 3, 4, 1 } }, + new double[,] { { 2, 5, 12 }, { 0, 5, 1 }, { 1, 1, 4 } }, + new double[,] { { -3, -7, -12 }, { 2, -8, 1 }, { 2, 3, -3 } }, + }, + }; + + [Test] + public void Multiply_ShouldThrowInvalidOperationException_WhenOperandsAreNotCompatible() + { + // Arrange + var source = new double[,] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } }; + var operand = new double[,] { { 1 }, { 1 } }; - // Act - var actualMatrix = sutMatrix.Copy(); + // Act + Action action = () => source.Multiply(operand); - // Assert - actualMatrix.Should().NotBeSameAs(sutMatrix); - actualMatrix.Should().BeEquivalentTo(sutMatrix); - } + // Assert + action.Should().Throw() + .WithMessage("The width of a first operand should match the height of a second."); + } - [TestCaseSource(nameof(MatrixTransposeTestCases))] - public void Transpose_ShouldReturnTransposedMatrix( - double[,] source, - double[,] target) => - source.Transpose().Should().BeEquivalentTo(target); + [TestCaseSource(nameof(MatrixMultiplyTestCases))] + public void Multiply_ShouldCalculateDotProductMultiplicationResult( + double[,] source, + double[,] operand, + double[,] result) => + source.Multiply(operand).Should().BeEquivalentTo(result); - [Test] - public void MultiplyVector_ShouldCalculateDotProductMultiplicationResult() - { - // Arrange - var source = new double[,] { { 2, 2, -1 }, { 0, -2, -1 }, { 0, 0, 5 } }; - var operand = new double[] { 2, 2, 3 }; - var result = new double[] { 5, -7, 15 }; + [Test] + public void Copy_ShouldReturnImmutableCopyOfMatrix() + { + // Arrange + var sutMatrix = new double[,] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } }; - // Act - var actualMatrix = source.MultiplyVector(operand); + // Act + var actualMatrix = sutMatrix.Copy(); - // Assert - actualMatrix.Should().BeEquivalentTo(result); - } + // Assert + actualMatrix.Should().NotBeSameAs(sutMatrix); + actualMatrix.Should().BeEquivalentTo(sutMatrix); + } - [Test] - public void Subtract_ShouldThrowArgumentException_WhenOperandsAreNotCompatible() - { - // Arrange - var source = new double[,] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } }; - var operand = new double[,] { { 1 }, { 1 } }; + [TestCaseSource(nameof(MatrixTransposeTestCases))] + public void Transpose_ShouldReturnTransposedMatrix( + double[,] source, + double[,] target) => + source.Transpose().Should().BeEquivalentTo(target); - // Act - Action action = () => source.Subtract(operand); + [Test] + public void MultiplyVector_ShouldCalculateDotProductMultiplicationResult() + { + // Arrange + var source = new double[,] { { 2, 2, -1 }, { 0, -2, -1 }, { 0, 0, 5 } }; + var operand = new double[] { 2, 2, 3 }; + var result = new double[] { 5, -7, 15 }; - // Assert - action.Should().Throw() - .WithMessage("Dimensions of matrices must be the same"); - } + // Act + var actualMatrix = source.MultiplyVector(operand); - [Test] - public static void EqualMatricesShouldReturnTrue() - { - // Arrange - var a = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; - var b = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; + // Assert + actualMatrix.Should().BeEquivalentTo(result); + } - // Act - var result = a.IsEqual(b); + [Test] + public void Subtract_ShouldThrowArgumentException_WhenOperandsAreNotCompatible() + { + // Arrange + var source = new double[,] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } }; + var operand = new double[,] { { 1 }, { 1 } }; - // Assert - Assert.True(result); - } + // Act + Action action = () => source.Subtract(operand); - [Test] - public static void NonEqualMatricesShouldReturnFalse() - { - // Arrange - var a = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; - var b = new double[,] { { 1, 2, 3 }, { 1, 2, 6 }, { 1, 2, 3 } }; + // Assert + action.Should().Throw() + .WithMessage("Dimensions of matrices must be the same"); + } - // Act - var result = a.IsEqual(b); + [Test] + public static void EqualMatricesShouldReturnTrue() + { + // Arrange + var a = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; + var b = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; + + // Act + var result = a.IsEqual(b); + + // Assert + Assert.True(result); + } + + [Test] + public static void NonEqualMatricesShouldReturnFalse() + { + // Arrange + var a = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; + var b = new double[,] { { 1, 2, 3 }, { 1, 2, 6 }, { 1, 2, 3 } }; + + // Act + var result = a.IsEqual(b); + + // Assert + Assert.False(result); + } + + [Test] + public static void DifferentSizeMatricesShouldReturnFalse() + { + // Arrange + var a = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; + var b = new double[,] { { 1, 2, 3 }, { 1, 2, 3 } }; + + // Act + var result = a.IsEqual(b); - // Assert - Assert.False(result); - } + // Assert + Assert.False(result); + } - [Test] - public static void DifferentSizeMatricesShouldReturnFalse() + [TestCaseSource(nameof(MatrixSubtractTestCases))] + public void Subtract_ShouldCalculateSubtractionResult( + double[,] source, + double[,] operand, + double[,] result) => + source.Subtract(operand).Should().BeEquivalentTo(result); + + [Test] + public void RoundToNextInt_ShouldReturnRoundedMatrix() + { + var source = new[,] { - // Arrange - var a = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; - var b = new double[,] { { 1, 2, 3 }, { 1, 2, 3 } }; - - // Act - var result = a.IsEqual(b); - - // Assert - Assert.False(result); - } - - [TestCaseSource(nameof(MatrixSubtractTestCases))] - public void Subtract_ShouldCalculateSubtractionResult( - double[,] source, - double[,] operand, - double[,] result) => - source.Subtract(operand).Should().BeEquivalentTo(result); - - [Test] - public void RoundToNextInt_ShouldReturnRoundedMatrix() + { -1.9, 1.9 }, + { -1.5, 1.5 }, + { -1.1, 1.1 }, + { -0.9, 0.9 }, + { -0.5, 0.5 }, + { -0.1, 0.1 }, + }; + + var result = new double[,] { - var source = new[,] - { - { -1.9, 1.9 }, - { -1.5, 1.5 }, - { -1.1, 1.1 }, - { -0.9, 0.9 }, - { -0.5, 0.5 }, - { -0.1, 0.1 }, - }; - - var result = new double[,] - { - { -2, 2 }, - { -2, 2 }, - { -1, 1 }, - { -1, 1 }, - { 0, 0 }, - { 0, 0 }, - }; - - var actualResult = source.RoundToNextInt(); - - actualResult.Should().BeEquivalentTo(result); - } + { -2, 2 }, + { -2, 2 }, + { -1, 1 }, + { -1, 1 }, + { 0, 0 }, + { 0, 0 }, + }; + + var actualResult = source.RoundToNextInt(); + + actualResult.Should().BeEquivalentTo(result); } } diff --git a/Utilities.Tests/Extensions/RandomExtensionsTests.cs b/Utilities.Tests/Extensions/RandomExtensionsTests.cs index c3c5abb0..a26922f6 100644 --- a/Utilities.Tests/Extensions/RandomExtensionsTests.cs +++ b/Utilities.Tests/Extensions/RandomExtensionsTests.cs @@ -1,21 +1,20 @@ -using System; +using System; using FluentAssertions; using NUnit.Framework; using Utilities.Extensions; -namespace Utilities.Tests.Extensions +namespace Utilities.Tests.Extensions; + +public class RandomExtensionsTests { - public class RandomExtensionsTests + [Test] + public void NextVector_ShouldReturnNormalizedVector() { - [Test] - public void NextVector_ShouldReturnNormalizedVector() - { - var random = new Random(0); + var random = new Random(0); - var result = random.NextVector(10); + var result = random.NextVector(10); - result.Length.Should().Be(10); - result.Magnitude().Should().BeApproximately(1.0, 1e-6); - } + result.Length.Should().Be(10); + result.Magnitude().Should().BeApproximately(1.0, 1e-6); } } diff --git a/Utilities.Tests/Extensions/VectorExtensionsTests.cs b/Utilities.Tests/Extensions/VectorExtensionsTests.cs index 3c24de8a..e4c5320f 100644 --- a/Utilities.Tests/Extensions/VectorExtensionsTests.cs +++ b/Utilities.Tests/Extensions/VectorExtensionsTests.cs @@ -1,137 +1,136 @@ -using System; +using System; using FluentAssertions; using NUnit.Framework; using Utilities.Extensions; -namespace Utilities.Tests.Extensions +namespace Utilities.Tests.Extensions; + +public class VectorExtensionsTests { - public class VectorExtensionsTests + [Test] + public void Copy_ShouldReturnCopyOfVector() { - [Test] - public void Copy_ShouldReturnCopyOfVector() - { - var vector = new double[] { 0, 1, 2, 3 }; + var vector = new double[] { 0, 1, 2, 3 }; - var vectorCopy = vector.Copy(); + var vectorCopy = vector.Copy(); - vectorCopy.Should().BeEquivalentTo(vector); - vectorCopy.Should().NotBeSameAs(vector); - } + vectorCopy.Should().BeEquivalentTo(vector); + vectorCopy.Should().NotBeSameAs(vector); + } - [Test] - public void OuterProduct_ShouldCalculateOuterProduct() - { - var lhs = new double[] { -2, -1, 0, 1, 2 }; - var rhs = new double[] { 1, 2, 3 }; + [Test] + public void OuterProduct_ShouldCalculateOuterProduct() + { + var lhs = new double[] { -2, -1, 0, 1, 2 }; + var rhs = new double[] { 1, 2, 3 }; - var result = new double[,] - { - { -2, -4, -6 }, - { -1, -2, -3 }, - { 0, 0, 0 }, - { 1, 2, 3 }, - { 2, 4, 6 }, - }; + var result = new double[,] + { + { -2, -4, -6 }, + { -1, -2, -3 }, + { 0, 0, 0 }, + { 1, 2, 3 }, + { 2, 4, 6 }, + }; - var actualResult = lhs.OuterProduct(rhs); + var actualResult = lhs.OuterProduct(rhs); - actualResult.Should().BeEquivalentTo(result); - } + actualResult.Should().BeEquivalentTo(result); + } - [Test] - public void Dot_ShouldThrowArgumentException_WhenDimensionsDoNotMatch() - { - var lhs = new double[] { 1, 2, 3 }; - var rhs = new double[] { 1, 2, 3, 4 }; + [Test] + public void Dot_ShouldThrowArgumentException_WhenDimensionsDoNotMatch() + { + var lhs = new double[] { 1, 2, 3 }; + var rhs = new double[] { 1, 2, 3, 4 }; - var func = () => lhs.Dot(rhs); + var func = () => lhs.Dot(rhs); - func.Should().Throw() - .WithMessage("Dot product arguments must have same dimension"); - } + func.Should().Throw() + .WithMessage("Dot product arguments must have same dimension"); + } - [Test] - public void Dot_ShouldCalculateDotProduct() - { - var lhs = new double[] { 1, 2, 3 }; - var rhs = new double[] { 4, 5, 6 }; + [Test] + public void Dot_ShouldCalculateDotProduct() + { + var lhs = new double[] { 1, 2, 3 }; + var rhs = new double[] { 4, 5, 6 }; - var actualResult = lhs.Dot(rhs); + var actualResult = lhs.Dot(rhs); - actualResult.Should().Be(32); - } + actualResult.Should().Be(32); + } - [Test] - public void Magnitude_ShouldCalculateMagnitude() - { - var vector = new double[] { -3, 4 }; + [Test] + public void Magnitude_ShouldCalculateMagnitude() + { + var vector = new double[] { -3, 4 }; - var actualResult = vector.Magnitude(); + var actualResult = vector.Magnitude(); - actualResult.Should().BeApproximately(5.0, 0.0001); - } + actualResult.Should().BeApproximately(5.0, 0.0001); + } - [Test] - public void Scale_ShouldCalculateScale() - { - var vector = new double[] { -1, 0, 1 }; - var factor = 2; + [Test] + public void Scale_ShouldCalculateScale() + { + var vector = new double[] { -1, 0, 1 }; + var factor = 2; - var result = new double[] { -2, 0, 2 }; + var result = new double[] { -2, 0, 2 }; - var actualResult = vector.Scale(factor); + var actualResult = vector.Scale(factor); - actualResult.Should().BeEquivalentTo(result); - } + actualResult.Should().BeEquivalentTo(result); + } - [Test] - public void ToColumnVector_ShouldReturnColumnVector() - { - var vector = new double[] { 1, 2, 3, 4 }; - var result = new double[,] { { 1 }, { 2 }, { 3 }, { 4 } }; + [Test] + public void ToColumnVector_ShouldReturnColumnVector() + { + var vector = new double[] { 1, 2, 3, 4 }; + var result = new double[,] { { 1 }, { 2 }, { 3 }, { 4 } }; - var actualResult = vector.ToColumnVector(); + var actualResult = vector.ToColumnVector(); - actualResult.Should().BeEquivalentTo(result); - } + actualResult.Should().BeEquivalentTo(result); + } - [Test] - public void ToRowVector_ShouldThrowInvalidOperationException_WhenSourceIsNotAColumnVector() - { - var source = new double[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } }; + [Test] + public void ToRowVector_ShouldThrowInvalidOperationException_WhenSourceIsNotAColumnVector() + { + var source = new double[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } }; - var func = () => source.ToRowVector(); + var func = () => source.ToRowVector(); - func.Should().Throw() - .WithMessage("The column vector should have only 1 element in width."); - } + func.Should().Throw() + .WithMessage("The column vector should have only 1 element in width."); + } - [Test] - public void ToRowVector_ShouldReturnRowVector() - { - var source = new double[,] { { 1 }, { 2 }, { 3 }, { 4 } }; - var result = new double[] { 1, 2, 3, 4 }; + [Test] + public void ToRowVector_ShouldReturnRowVector() + { + var source = new double[,] { { 1 }, { 2 }, { 3 }, { 4 } }; + var result = new double[] { 1, 2, 3, 4 }; - var actualResult = source.ToRowVector(); + var actualResult = source.ToRowVector(); - actualResult.Should().BeEquivalentTo(result); - } + actualResult.Should().BeEquivalentTo(result); + } - [Test] - public void ToDiagonalMatrix_ShouldReturnDiagonalMatrix() + [Test] + public void ToDiagonalMatrix_ShouldReturnDiagonalMatrix() + { + var source = new double[] { 1, 2, 3, 4 }; + var result = new double[,] { - var source = new double[] { 1, 2, 3, 4 }; - var result = new double[,] - { - { 1, 0, 0, 0 }, - { 0, 2, 0, 0 }, - { 0, 0, 3, 0 }, - { 0, 0, 0, 4 }, - }; - - var actualResult = source.ToDiagonalMatrix(); - - actualResult.Should().BeEquivalentTo(result); - } + { 1, 0, 0, 0 }, + { 0, 2, 0, 0 }, + { 0, 0, 3, 0 }, + { 0, 0, 0, 4 }, + }; + + var actualResult = source.ToDiagonalMatrix(); + + actualResult.Should().BeEquivalentTo(result); } } diff --git a/Utilities/Exceptions/ItemNotFoundException.cs b/Utilities/Exceptions/ItemNotFoundException.cs index 6b35580b..580fc691 100644 --- a/Utilities/Exceptions/ItemNotFoundException.cs +++ b/Utilities/Exceptions/ItemNotFoundException.cs @@ -1,11 +1,10 @@ -using System; +using System; -namespace Utilities.Exceptions +namespace Utilities.Exceptions; + +/// +/// Signs that sequence doesn't contain any items that one was looking for. +/// +public class ItemNotFoundException : Exception { - /// - /// Signs that sequence doesn't contain any items that one was looking for. - /// - public class ItemNotFoundException : Exception - { - } } diff --git a/Utilities/Extensions/DictionaryExtensions.cs b/Utilities/Extensions/DictionaryExtensions.cs index 714232a1..03638290 100644 --- a/Utilities/Extensions/DictionaryExtensions.cs +++ b/Utilities/Extensions/DictionaryExtensions.cs @@ -1,28 +1,27 @@ -using System; +using System; using System.Collections.Generic; -namespace Utilities.Extensions +namespace Utilities.Extensions; + +public static class DictionaryExtensions { - public static class DictionaryExtensions + /// + /// Adds the specified key value tuples to the dictionary. + /// + /// The dictionary. + /// The collection of key value tuples to add. + /// The type of the keys in the dictionary. + /// The type of the values in the dictionary. + /// + /// A key from the already exists in . + /// + public static void AddMany( + this Dictionary keys, + IEnumerable<(TKey, TValue)> enumerable) where TKey : notnull { - /// - /// Adds the specified key value tuples to the dictionary. - /// - /// The dictionary. - /// The collection of key value tuples to add. - /// The type of the keys in the dictionary. - /// The type of the values in the dictionary. - /// - /// A key from the already exists in . - /// - public static void AddMany( - this Dictionary keys, - IEnumerable<(TKey, TValue)> enumerable) where TKey : notnull + foreach (var (key, value) in enumerable) { - foreach (var (key, value) in enumerable) - { - keys.Add(key, value); - } + keys.Add(key, value); } } } diff --git a/Utilities/Extensions/MatrixExtensions.cs b/Utilities/Extensions/MatrixExtensions.cs index bbce2bb2..780f6e73 100644 --- a/Utilities/Extensions/MatrixExtensions.cs +++ b/Utilities/Extensions/MatrixExtensions.cs @@ -1,184 +1,183 @@ using System; -namespace Utilities.Extensions +namespace Utilities.Extensions; + +public static class MatrixExtensions { - public static class MatrixExtensions + /// + /// Performs immutable dot product multiplication on source matrix to operand. + /// + /// Source left matrix. + /// Operand right matrix. + /// Dot product result. + /// The width of a first operand should match the height of a second. + public static double[,] Multiply(this double[,] source, double[,] operand) { - /// - /// Performs immutable dot product multiplication on source matrix to operand. - /// - /// Source left matrix. - /// Operand right matrix. - /// Dot product result. - /// The width of a first operand should match the height of a second. - public static double[,] Multiply(this double[,] source, double[,] operand) + if (source.GetLength(1) != operand.GetLength(0)) { - if (source.GetLength(1) != operand.GetLength(0)) - { - throw new InvalidOperationException( - "The width of a first operand should match the height of a second."); - } + throw new InvalidOperationException( + "The width of a first operand should match the height of a second."); + } - var result = new double[source.GetLength(0), operand.GetLength(1)]; + var result = new double[source.GetLength(0), operand.GetLength(1)]; - for (var i = 0; i < result.GetLength(0); i++) + for (var i = 0; i < result.GetLength(0); i++) + { + for (var j = 0; j < result.GetLength(1); j++) { - for (var j = 0; j < result.GetLength(1); j++) - { - double elementProduct = 0; - - for (var k = 0; k < source.GetLength(1); k++) - { - elementProduct += source[i, k] * operand[k, j]; - } + double elementProduct = 0; - result[i, j] = elementProduct; + for (var k = 0; k < source.GetLength(1); k++) + { + elementProduct += source[i, k] * operand[k, j]; } - } - return result; + result[i, j] = elementProduct; + } } - /// - /// Makes a copy of a matrix. Changes to the copy should not affect the original. - /// - /// The matrix. - /// A copy of the matrix. - public static double[,] Copy(this double[,] matrix) + return result; + } + + /// + /// Makes a copy of a matrix. Changes to the copy should not affect the original. + /// + /// The matrix. + /// A copy of the matrix. + public static double[,] Copy(this double[,] matrix) + { + var result = new double[matrix.GetLength(0), matrix.GetLength(1)]; + for (var i = 0; i < matrix.GetLength(0); i++) { - var result = new double[matrix.GetLength(0), matrix.GetLength(1)]; - for (var i = 0; i < matrix.GetLength(0); i++) + for (var j = 0; j < matrix.GetLength(1); j++) { - for (var j = 0; j < matrix.GetLength(1); j++) - { - result[i, j] = matrix[i, j]; - } + result[i, j] = matrix[i, j]; } - - return result; } - /// - /// Transposes a matrix. - /// - /// The matrix. - /// The transposed matrix. - public static double[,] Transpose(this double[,] matrix) + return result; + } + + /// + /// Transposes a matrix. + /// + /// The matrix. + /// The transposed matrix. + public static double[,] Transpose(this double[,] matrix) + { + var result = new double[matrix.GetLength(1), matrix.GetLength(0)]; + for (var i = 0; i < matrix.GetLength(0); i++) { - var result = new double[matrix.GetLength(1), matrix.GetLength(0)]; - for (var i = 0; i < matrix.GetLength(0); i++) + for (var j = 0; j < matrix.GetLength(1); j++) { - for (var j = 0; j < matrix.GetLength(1); j++) - { - result[j, i] = matrix[i, j]; - } + result[j, i] = matrix[i, j]; } + } + + return result; + } - return result; + /// + /// Multiplies a matrix by a vector. + /// + /// The matrix. + /// The vector. + /// The product of the matrix and the vector, which is a vector. + /// Dimensions of matrix and vector do not match. + public static double[] MultiplyVector(this double[,] matrix, double[] vector) + { + var vectorReshaped = new double[vector.Length, 1]; + for (var i = 0; i < vector.Length; i++) + { + vectorReshaped[i, 0] = vector[i]; } - /// - /// Multiplies a matrix by a vector. - /// - /// The matrix. - /// The vector. - /// The product of the matrix and the vector, which is a vector. - /// Dimensions of matrix and vector do not match. - public static double[] MultiplyVector(this double[,] matrix, double[] vector) + var resultMatrix = matrix.Multiply(vectorReshaped); + var result = new double[resultMatrix.GetLength(0)]; + for (var i = 0; i < result.Length; i++) { - var vectorReshaped = new double[vector.Length, 1]; - for (var i = 0; i < vector.Length; i++) - { - vectorReshaped[i, 0] = vector[i]; - } + result[i] = resultMatrix[i, 0]; + } - var resultMatrix = matrix.Multiply(vectorReshaped); - var result = new double[resultMatrix.GetLength(0)]; - for (var i = 0; i < result.Length; i++) - { - result[i] = resultMatrix[i, 0]; - } + return result; + } - return result; + /// + /// Performs matrix subtraction. + /// + /// The LHS matrix. + /// The RHS matrix. + /// The difference of the two matrices. + /// Dimensions of matrices do not match. + public static double[,] Subtract(this double[,] lhs, double[,] rhs) + { + if (lhs.GetLength(0) != rhs.GetLength(0) || + lhs.GetLength(1) != rhs.GetLength(1)) + { + throw new ArgumentException("Dimensions of matrices must be the same"); } - /// - /// Performs matrix subtraction. - /// - /// The LHS matrix. - /// The RHS matrix. - /// The difference of the two matrices. - /// Dimensions of matrices do not match. - public static double[,] Subtract(this double[,] lhs, double[,] rhs) + var result = new double[lhs.GetLength(0), lhs.GetLength(1)]; + for (var i = 0; i < lhs.GetLength(0); i++) { - if (lhs.GetLength(0) != rhs.GetLength(0) || - lhs.GetLength(1) != rhs.GetLength(1)) + for (var j = 0; j < lhs.GetLength(1); j++) { - throw new ArgumentException("Dimensions of matrices must be the same"); + result[i, j] = lhs[i, j] - rhs[i, j]; } + } - var result = new double[lhs.GetLength(0), lhs.GetLength(1)]; - for (var i = 0; i < lhs.GetLength(0); i++) - { - for (var j = 0; j < lhs.GetLength(1); j++) - { - result[i, j] = lhs[i, j] - rhs[i, j]; - } - } + return result; + } - return result; + /// + /// Performs an element by element comparison on both matrices. + /// + /// Source left matrix. + /// Openrand right matrix. + /// true: if all elements are the same; false otherwise. + public static bool IsEqual(this double[,] source, double[,] operand) + { + if (source.Length != operand.Length || + source.GetLength(0) != operand.GetLength(0) || + source.GetLength(1) != operand.GetLength(1)) + { + return false; } - /// - /// Performs an element by element comparison on both matrices. - /// - /// Source left matrix. - /// Openrand right matrix. - /// true: if all elements are the same; false otherwise. - public static bool IsEqual(this double[,] source, double[,] operand) + for (var i = 0; i < source.GetLength(0); i++) { - if (source.Length != operand.Length || - source.GetLength(0) != operand.GetLength(0) || - source.GetLength(1) != operand.GetLength(1)) + for (var j = 0; j < source.GetLength(0); j++) { - return false; - } - - for (var i = 0; i < source.GetLength(0); i++) - { - for (var j = 0; j < source.GetLength(0); j++) + if (Math.Abs(source[i, j] - operand[i, j]) >= 0.0001) { - if (Math.Abs(source[i, j] - operand[i, j]) >= 0.0001) - { - return false; - } + return false; } } - - return true; } - /// - /// Performs a round operation on every element of the input matrix up to the neareast integer. - /// - /// Input matrix. - /// Matrix with rounded elements. - public static double[,] RoundToNextInt(this double[,] source) - { - var rows = source.GetLength(0); - var cols = source.GetLength(1); + return true; + } - var result = new double[rows, cols]; + /// + /// Performs a round operation on every element of the input matrix up to the neareast integer. + /// + /// Input matrix. + /// Matrix with rounded elements. + public static double[,] RoundToNextInt(this double[,] source) + { + var rows = source.GetLength(0); + var cols = source.GetLength(1); - for (var i = 0; i < rows; i++) + var result = new double[rows, cols]; + + for (var i = 0; i < rows; i++) + { + for (var j = 0; j < cols; j++) { - for (var j = 0; j < cols; j++) - { - result[i, j] = Math.Round(source[i, j]); - } + result[i, j] = Math.Round(source[i, j]); } - - return result; } + + return result; } } diff --git a/Utilities/Extensions/RandomExtensions.cs b/Utilities/Extensions/RandomExtensions.cs index 87138957..eb7f7f47 100644 --- a/Utilities/Extensions/RandomExtensions.cs +++ b/Utilities/Extensions/RandomExtensions.cs @@ -1,22 +1,21 @@ using System; using System.Linq; -namespace Utilities.Extensions +namespace Utilities.Extensions; + +public static class RandomExtensions { - public static class RandomExtensions + /// + /// Returns a random normalized vector of the specified size. + /// + /// The random number generator. + /// The size of the vector to return. + /// A random normalized vector. + public static double[] NextVector(this Random rand, int size) { - /// - /// Returns a random normalized vector of the specified size. - /// - /// The random number generator. - /// The size of the vector to return. - /// A random normalized vector. - public static double[] NextVector(this Random rand, int size) - { - var vector = Enumerable.Range(0, size) - .Select(_ => rand.NextDouble()).ToArray(); - var norm = vector.Magnitude(); - return vector.Select(x => x / norm).ToArray(); - } + var vector = Enumerable.Range(0, size) + .Select(_ => rand.NextDouble()).ToArray(); + var norm = vector.Magnitude(); + return vector.Select(x => x / norm).ToArray(); } } diff --git a/Utilities/Extensions/VectorExtensions.cs b/Utilities/Extensions/VectorExtensions.cs index 8ec87f6c..bfb807f0 100644 --- a/Utilities/Extensions/VectorExtensions.cs +++ b/Utilities/Extensions/VectorExtensions.cs @@ -1,153 +1,152 @@ using System; -namespace Utilities.Extensions +namespace Utilities.Extensions; + +public static class VectorExtensions { - public static class VectorExtensions + /// + /// Makes a copy of a vector. Changes to the copy should not affect the original. + /// + /// The vector. + /// The copy. + public static double[] Copy(this double[] vector) { - /// - /// Makes a copy of a vector. Changes to the copy should not affect the original. - /// - /// The vector. - /// The copy. - public static double[] Copy(this double[] vector) + var result = new double[vector.Length]; + for (var i = 0; i < vector.Length; i++) { - var result = new double[vector.Length]; - for (var i = 0; i < vector.Length; i++) - { - result[i] = vector[i]; - } - - return result; + result[i] = vector[i]; } - /// - /// Computes the outer product of two vectors. - /// - /// The LHS vector. - /// The RHS vector. - /// The outer product of the two vector. - public static double[,] OuterProduct(this double[] lhs, double[] rhs) - { - var result = new double[lhs.Length, rhs.Length]; - for (var i = 0; i < lhs.Length; i++) - { - for (var j = 0; j < rhs.Length; j++) - { - result[i, j] = lhs[i] * rhs[j]; - } - } - - return result; - } + return result; + } - /// - /// Computes the dot product of two vectors. - /// - /// The LHS vector. - /// The RHS vector. - /// The dot product of the two vector. - /// Dimensions of vectors do not match. - public static double Dot(this double[] lhs, double[] rhs) + /// + /// Computes the outer product of two vectors. + /// + /// The LHS vector. + /// The RHS vector. + /// The outer product of the two vector. + public static double[,] OuterProduct(this double[] lhs, double[] rhs) + { + var result = new double[lhs.Length, rhs.Length]; + for (var i = 0; i < lhs.Length; i++) { - if (lhs.Length != rhs.Length) + for (var j = 0; j < rhs.Length; j++) { - throw new ArgumentException("Dot product arguments must have same dimension"); + result[i, j] = lhs[i] * rhs[j]; } + } - double result = 0; - for (var i = 0; i < lhs.Length; i++) - { - result += lhs[i] * rhs[i]; - } + return result; + } - return result; + /// + /// Computes the dot product of two vectors. + /// + /// The LHS vector. + /// The RHS vector. + /// The dot product of the two vector. + /// Dimensions of vectors do not match. + public static double Dot(this double[] lhs, double[] rhs) + { + if (lhs.Length != rhs.Length) + { + throw new ArgumentException("Dot product arguments must have same dimension"); } - /// - /// Computes the magnitude of a vector. - /// - /// The vector. - /// The magnitude. - public static double Magnitude(this double[] vector) + double result = 0; + for (var i = 0; i < lhs.Length; i++) { - var magnitude = Dot(vector, vector); - magnitude = Math.Sqrt(magnitude); - return magnitude; + result += lhs[i] * rhs[i]; } - /// - /// Returns the scaled vector. - /// - /// The vector. - /// Scale factor. - /// The unit vector. - public static double[] Scale(this double[] vector, double factor) - { - var result = new double[vector.Length]; - for (var i = 0; i < vector.Length; i++) - { - result[i] = vector[i] * factor; - } + return result; + } - return result; - } + /// + /// Computes the magnitude of a vector. + /// + /// The vector. + /// The magnitude. + public static double Magnitude(this double[] vector) + { + var magnitude = Dot(vector, vector); + magnitude = Math.Sqrt(magnitude); + return magnitude; + } - /// - /// Transpose 1d row vector to column vector. - /// - /// Input 1d vector. - /// Column vector. - public static double[,] ToColumnVector(this double[] source) + /// + /// Returns the scaled vector. + /// + /// The vector. + /// Scale factor. + /// The unit vector. + public static double[] Scale(this double[] vector, double factor) + { + var result = new double[vector.Length]; + for (var i = 0; i < vector.Length; i++) { - var columnVector = new double[source.Length, 1]; + result[i] = vector[i] * factor; + } - for (var i = 0; i < source.Length; i++) - { - columnVector[i, 0] = source[i]; - } + return result; + } - return columnVector; - } + /// + /// Transpose 1d row vector to column vector. + /// + /// Input 1d vector. + /// Column vector. + public static double[,] ToColumnVector(this double[] source) + { + var columnVector = new double[source.Length, 1]; - /// - /// Transpose column vector to 1d row vector. - /// - /// Input column vector. - /// Row vector. - /// The column vector should have only 1 element in width. - public static double[] ToRowVector(this double[,] source) + for (var i = 0; i < source.Length; i++) { - if (source.GetLength(1) != 1) - { - throw new InvalidOperationException("The column vector should have only 1 element in width."); - } - - var rowVector = new double[source.Length]; + columnVector[i, 0] = source[i]; + } - for (var i = 0; i < rowVector.Length; i++) - { - rowVector[i] = source[i, 0]; - } + return columnVector; + } - return rowVector; + /// + /// Transpose column vector to 1d row vector. + /// + /// Input column vector. + /// Row vector. + /// The column vector should have only 1 element in width. + public static double[] ToRowVector(this double[,] source) + { + if (source.GetLength(1) != 1) + { + throw new InvalidOperationException("The column vector should have only 1 element in width."); } - /// - /// Generates a diagonal matrix from an specified vector. - /// - /// The input vector. - /// A Diagonal matrix. - public static double[,] ToDiagonalMatrix(this double[] vector) + var rowVector = new double[source.Length]; + + for (var i = 0; i < rowVector.Length; i++) { - var len = vector.Length; - var result = new double[len, len]; + rowVector[i] = source[i, 0]; + } - for (var i = 0; i < len; i++) - { - result[i, i] = vector[i]; - } + return rowVector; + } + + /// + /// Generates a diagonal matrix from an specified vector. + /// + /// The input vector. + /// A Diagonal matrix. + public static double[,] ToDiagonalMatrix(this double[] vector) + { + var len = vector.Length; + var result = new double[len, len]; - return result; + for (var i = 0; i < len; i++) + { + result[i, i] = vector[i]; } + + return result; } } From d79e725654ceb79f84d392d4a1f3be2a173d4500 Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Tue, 9 Jan 2024 20:08:09 +0000 Subject: [PATCH 088/138] Switch to file-scoped namespaces (#436) --- DataStructures.Tests/AATreeTests.cs | 491 +++-- DataStructures.Tests/AVLTreeTests.cs | 637 +++--- DataStructures.Tests/BinarySearchTreeTests.cs | 549 +++-- DataStructures.Tests/BitArrayTests.cs | 821 ++++---- DataStructures.Tests/Cache/LfuCacheTests.cs | 140 +- DataStructures.Tests/Cache/LruCacheTests.cs | 106 +- .../DisjointSet/DisjointSetTests.cs | 51 +- .../Fenwick/BinaryIndexedTreeTests.cs | 48 +- .../Graph/DirectedWeightedGraphTests.cs | 343 ++-- .../Hashing/HashTableTests.cs | 595 +++--- .../Hashing/NumberTheory/PrimeNumberTests.cs | 199 +- DataStructures.Tests/Heap/BinaryHeapTests.cs | 231 ++- .../Heap/FibonacciHeaps/FibonacciHeapTests.cs | 399 ++-- DataStructures.Tests/Heap/MinMaxHeapTests.cs | 243 ++- .../PairingHeap/PairingHeapComparerTests.cs | 41 +- .../Heap/PairingHeap/PairingHeapTests.cs | 245 ++- DataStructures.Tests/InvertedIndexTests.cs | 49 +- .../LinkedList/DoublyLinkedListTests.cs | 251 ++- .../LinkedList/LinkedListTests.cs | 181 +- .../LinkedList/SkipListTests.cs | 225 +-- .../Probabilistic/BloomFilterTests.cs | 169 +- .../Probabilistic/CountMinSketchTests.cs | 125 +- .../Probabilistic/HyperLogLogTest.cs | 89 +- .../Queue/ArrayBasedQueueTests.cs | 215 +- .../Queue/ListBasedQueueTests.cs | 177 +- .../Queue/StackBasedQueueTests.cs | 177 +- DataStructures.Tests/RedBlackTreeTests.cs | 675 ++++--- .../ScapegoatTree/ExtensionsTests.cs | 85 +- .../ScapegoatTree/ScapegoatTreeNodeTests.cs | 359 ++-- .../ScapegoatTree/ScapegoatTreeTests.cs | 661 +++--- .../SegmentTrees/SegmentTreeApplyTests.cs | 25 +- .../SegmentTrees/SegmentTreeTests.cs | 33 +- .../SegmentTrees/SegmentTreeUpdateTest.cs | 31 +- DataStructures.Tests/SortedListTests.cs | 175 +- .../Stack/ArrayBasedStackTests.cs | 215 +- .../Stack/ListBasedStackTests.cs | 125 +- .../Stack/QueueBasedStackTests.cs | 202 +- DataStructures.Tests/TimelineTests.cs | 1797 ++++++++--------- DataStructures.Tests/Tries/TrieTests.cs | 195 +- .../UnrolledLinkedListNodeTests.cs | 77 +- .../UnrolledList/UnrolledLinkedListTests.cs | 27 +- 41 files changed, 5716 insertions(+), 5763 deletions(-) diff --git a/DataStructures.Tests/AATreeTests.cs b/DataStructures.Tests/AATreeTests.cs index e077a3a1..9a34ad8f 100644 --- a/DataStructures.Tests/AATreeTests.cs +++ b/DataStructures.Tests/AATreeTests.cs @@ -1,297 +1,296 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using DataStructures.AATree; using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests +namespace DataStructures.Tests; + +internal class AaTreeTests { - internal class AaTreeTests + [Test] + public void Constructor_UseCustomComparer_FormsCorrectTree() { - [Test] - public void Constructor_UseCustomComparer_FormsCorrectTree() - { - var tree = new AaTree(Comparer.Create((x, y) => y.CompareTo(x))); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetMax().Should().Be(1); - tree.GetMin().Should().Be(10); - tree.GetKeysInOrder().SequenceEqual(new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }).Should().BeTrue(); - Validate(tree.Root); - } + var tree = new AaTree(Comparer.Create((x, y) => y.CompareTo(x))); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetMax().Should().Be(1); + tree.GetMin().Should().Be(10); + tree.GetKeysInOrder().SequenceEqual(new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }).Should().BeTrue(); + Validate(tree.Root); + } - [Test] - public void Add_MultipleKeys_FormsCorrectTree() - { - var tree = new AaTree(); - - foreach (var elem in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }) - { - tree.Add(elem); - tree.Count.Should().Be(elem); - tree.Contains(elem).Should().BeTrue(); - } - - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); - tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }).Should().BeTrue(); - Validate(tree.Root); - } + [Test] + public void Add_MultipleKeys_FormsCorrectTree() + { + var tree = new AaTree(); - [Test] - public void Add_KeyAlreadyInTree_ThrowsException() + foreach (var elem in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }) { - var tree = new AaTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - Assert.Throws(() => tree.Add(1)); + tree.Add(elem); + tree.Count.Should().Be(elem); + tree.Contains(elem).Should().BeTrue(); } - [Test] - public void AddRange_MultipleKeys_FormsCorrectTree() - { - var tree = new AaTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.Count.Should().Be(10); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); - tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }).Should().BeTrue(); - Validate(tree.Root); - } + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); + tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }).Should().BeTrue(); + Validate(tree.Root); + } - [Test] - public void Remove_MultipleKeys_TreeStillValid() - { - var tree = new AaTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + [Test] + public void Add_KeyAlreadyInTree_ThrowsException() + { + var tree = new AaTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + Assert.Throws(() => tree.Add(1)); + } - Remove(4).Should().NotThrow(); - tree.Contains(4).Should().BeFalse(); - tree.Count.Should().Be(9); + [Test] + public void AddRange_MultipleKeys_FormsCorrectTree() + { + var tree = new AaTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.Count.Should().Be(10); + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); + tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }).Should().BeTrue(); + Validate(tree.Root); + } - Remove(8).Should().NotThrow(); - tree.Contains(8).Should().BeFalse(); - tree.Count.Should().Be(8); + [Test] + public void Remove_MultipleKeys_TreeStillValid() + { + var tree = new AaTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - Remove(1).Should().NotThrow(); - tree.Contains(1).Should().BeFalse(); - tree.Count.Should().Be(7); + Remove(4).Should().NotThrow(); + tree.Contains(4).Should().BeFalse(); + tree.Count.Should().Be(9); - Validate(tree.Root); + Remove(8).Should().NotThrow(); + tree.Contains(8).Should().BeFalse(); + tree.Count.Should().Be(8); - Action Remove(int x) => () => tree.Remove(x); - } + Remove(1).Should().NotThrow(); + tree.Contains(1).Should().BeFalse(); + tree.Count.Should().Be(7); - [Test] - public void Remove_KeyNotInTree_Throws() - { - var tree = new AaTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + Validate(tree.Root); - Action act = () => tree.Remove(999); - act.Should().Throw(); - } + Action Remove(int x) => () => tree.Remove(x); + } - [Test] - public void Remove_EmptyTree_Throws() - { - var tree = new AaTree(); + [Test] + public void Remove_KeyNotInTree_Throws() + { + var tree = new AaTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - Action act = () => tree.Remove(999); - act.Should().Throw(); - } + Action act = () => tree.Remove(999); + act.Should().Throw(); + } - [Test] - public void Contains_NonEmptyTree_ReturnsCorrectAnswer() - { - var tree = new AaTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.Contains(6).Should().BeTrue(); - tree.Contains(999).Should().BeFalse(); - } + [Test] + public void Remove_EmptyTree_Throws() + { + var tree = new AaTree(); - [Test] - public void Contains_EmptyTree_ReturnsFalse() - { - var tree = new AaTree(); - tree.Contains(999).Should().BeFalse(); - } + Action act = () => tree.Remove(999); + act.Should().Throw(); + } - [Test] - public void GetMax_NonEmptyTree_ReturnsCorrectAnswer() - { - var tree = new AaTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetMax().Should().Be(10); - } + [Test] + public void Contains_NonEmptyTree_ReturnsCorrectAnswer() + { + var tree = new AaTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.Contains(6).Should().BeTrue(); + tree.Contains(999).Should().BeFalse(); + } - [Test] - public void GetMax_EmptyTree_ThrowsCorrectException() - { - var tree = new AaTree(); - Assert.Throws(() => tree.GetMax()); - } + [Test] + public void Contains_EmptyTree_ReturnsFalse() + { + var tree = new AaTree(); + tree.Contains(999).Should().BeFalse(); + } - [Test] - public void GetMin_NonEmptyTree_ReturnsCorrectAnswer() - { - var tree = new AaTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetMin().Should().Be(1); - } + [Test] + public void GetMax_NonEmptyTree_ReturnsCorrectAnswer() + { + var tree = new AaTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetMax().Should().Be(10); + } - [Test] - public void GetMin_EmptyTree_ThrowsCorrectException() - { - var tree = new AaTree(); - Assert.Throws(() => tree.GetMin()); - } + [Test] + public void GetMax_EmptyTree_ThrowsCorrectException() + { + var tree = new AaTree(); + Assert.Throws(() => tree.GetMax()); + } - [Test] - public void GetKeysInOrder_NonEmptyTree_ReturnsCorrectAnswer() - { - var tree = new AaTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); - } + [Test] + public void GetMin_NonEmptyTree_ReturnsCorrectAnswer() + { + var tree = new AaTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetMin().Should().Be(1); + } - [Test] - public void GetKeysInOrder_EmptyTree_ReturnsCorrectAnswer() - { - var tree = new AaTree(); - tree.GetKeysInOrder().ToList().Count.Should().Be(0); - } + [Test] + public void GetMin_EmptyTree_ThrowsCorrectException() + { + var tree = new AaTree(); + Assert.Throws(() => tree.GetMin()); + } - [Test] - public void GetKeysPreOrder_NonEmptyTree_ReturnsCorrectAnswer() - { - var tree = new AaTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 6, 5, 8, 7, 9, 10 }) - .Should().BeTrue(); - } + [Test] + public void GetKeysInOrder_NonEmptyTree_ReturnsCorrectAnswer() + { + var tree = new AaTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); + } - [Test] - public void GetKeysPreOrder_EmptyTree_ReturnsCorrectAnswer() - { - var tree = new AaTree(); - tree.GetKeysPreOrder().ToList().Count.Should().Be(0); - } + [Test] + public void GetKeysInOrder_EmptyTree_ReturnsCorrectAnswer() + { + var tree = new AaTree(); + tree.GetKeysInOrder().ToList().Count.Should().Be(0); + } - [Test] - public void GetKeysPostOrder_NonEmptyTree_ReturnsCorrectAnswer() - { - var tree = new AaTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }) - .Should().BeTrue(); - } + [Test] + public void GetKeysPreOrder_NonEmptyTree_ReturnsCorrectAnswer() + { + var tree = new AaTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 6, 5, 8, 7, 9, 10 }) + .Should().BeTrue(); + } - [Test] - public void GetKeysPostOrder_EmptyTree_ReturnsCorrectAnswer() - { - var tree = new AaTree(); - tree.GetKeysPostOrder().ToList().Count.Should().Be(0); - } + [Test] + public void GetKeysPreOrder_EmptyTree_ReturnsCorrectAnswer() + { + var tree = new AaTree(); + tree.GetKeysPreOrder().ToList().Count.Should().Be(0); + } + + [Test] + public void GetKeysPostOrder_NonEmptyTree_ReturnsCorrectAnswer() + { + var tree = new AaTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }) + .Should().BeTrue(); + } - /// - /// Checks various properties to determine if the tree is a valid AA Tree. - /// Throws exceptions if properties are violated. - /// Useful for debugging. - /// - /// - /// The properties that are checked are: - /// - /// The level of every leaf node is one. - /// The level of every left child is exactly one less than that of its parent. - /// The level of every right child is equal to or one less than that of its parent. - /// The level of every right grandchild is strictly less than that of its grandparent. - /// Every node of level greater than one has two children. - /// - /// More information: https://en.wikipedia.org/wiki/AA_tree . - /// - /// The node to check from. - /// true if node passes all checks, false otherwise. - private static bool Validate(AaTreeNode? node) + [Test] + public void GetKeysPostOrder_EmptyTree_ReturnsCorrectAnswer() + { + var tree = new AaTree(); + tree.GetKeysPostOrder().ToList().Count.Should().Be(0); + } + + /// + /// Checks various properties to determine if the tree is a valid AA Tree. + /// Throws exceptions if properties are violated. + /// Useful for debugging. + /// + /// + /// The properties that are checked are: + /// + /// The level of every leaf node is one. + /// The level of every left child is exactly one less than that of its parent. + /// The level of every right child is equal to or one less than that of its parent. + /// The level of every right grandchild is strictly less than that of its grandparent. + /// Every node of level greater than one has two children. + /// + /// More information: https://en.wikipedia.org/wiki/AA_tree . + /// + /// The node to check from. + /// true if node passes all checks, false otherwise. + private static bool Validate(AaTreeNode? node) + { + if (node is null) { - if (node is null) - { - return true; - } + return true; + } - // Check level == 1 if node if a leaf node. - var leafNodeCheck = CheckLeafNode(node); + // Check level == 1 if node if a leaf node. + var leafNodeCheck = CheckLeafNode(node); - // Check level of left child is exactly one less than parent. - var leftCheck = CheckLeftSubtree(node); + // Check level of left child is exactly one less than parent. + var leftCheck = CheckLeftSubtree(node); - // Check level of right child is equal or one less than parent. - var rightCheck = CheckRightSubtree(node); + // Check level of right child is equal or one less than parent. + var rightCheck = CheckRightSubtree(node); - // Check right grandchild level is less than node. - var grandchildCheck = CheckRightGrandChild(node); + // Check right grandchild level is less than node. + var grandchildCheck = CheckRightGrandChild(node); - // Check if node has two children if not leaf. - var nonLeafChildrenCheck = CheckNonLeafChildren(node); + // Check if node has two children if not leaf. + var nonLeafChildrenCheck = CheckNonLeafChildren(node); - var thisNodeResult = leafNodeCheck && leftCheck && rightCheck; - thisNodeResult = thisNodeResult && grandchildCheck && nonLeafChildrenCheck; + var thisNodeResult = leafNodeCheck && leftCheck && rightCheck; + thisNodeResult = thisNodeResult && grandchildCheck && nonLeafChildrenCheck; - return thisNodeResult && Validate(node.Left) && Validate(node.Right); - } + return thisNodeResult && Validate(node.Left) && Validate(node.Right); + } - /// - /// Checks if node is a leaf, and if so if its level is 1. - /// - /// The node to check. - /// true if node passes check, false otherwise. - private static bool CheckLeafNode(AaTreeNode node) - { - var condition = node.Left is null && node.Right is null && node.Level != 1; - return !condition; - } + /// + /// Checks if node is a leaf, and if so if its level is 1. + /// + /// The node to check. + /// true if node passes check, false otherwise. + private static bool CheckLeafNode(AaTreeNode node) + { + var condition = node.Left is null && node.Right is null && node.Level != 1; + return !condition; + } - /// - /// Checks if left node's level is exactly one less than node's level. - /// - /// The node to check. - /// true if node passes check, false otherwise. - private static bool CheckLeftSubtree(AaTreeNode node) - { - var condition = node.Left is not null && node.Level - node.Left.Level != 1; - return !condition; - } + /// + /// Checks if left node's level is exactly one less than node's level. + /// + /// The node to check. + /// true if node passes check, false otherwise. + private static bool CheckLeftSubtree(AaTreeNode node) + { + var condition = node.Left is not null && node.Level - node.Left.Level != 1; + return !condition; + } - /// - /// Checks if right node's level is either equal to or one less than node's level. - /// - /// The node to check. - /// true if node passes check, false otherwise. - private static bool CheckRightSubtree(AaTreeNode node) - { - var condition = node.Right is not null && - node.Level - node.Right.Level != 1 && - node.Level != node.Right.Level; - return !condition; - } + /// + /// Checks if right node's level is either equal to or one less than node's level. + /// + /// The node to check. + /// true if node passes check, false otherwise. + private static bool CheckRightSubtree(AaTreeNode node) + { + var condition = node.Right is not null && + node.Level - node.Right.Level != 1 && + node.Level != node.Right.Level; + return !condition; + } - /// - /// Checks if right grandchild's (right node's right node) level is less than node. - /// - /// The node to check. - /// true if node passes check, false otherwise. - private static bool CheckRightGrandChild(AaTreeNode node) - { - var condition = node.Right?.Right is not null && node.Right.Level < node.Right.Right.Level; - return !condition; - } + /// + /// Checks if right grandchild's (right node's right node) level is less than node. + /// + /// The node to check. + /// true if node passes check, false otherwise. + private static bool CheckRightGrandChild(AaTreeNode node) + { + var condition = node.Right?.Right is not null && node.Right.Level < node.Right.Right.Level; + return !condition; + } - /// - /// Checks if node is not a leaf, and if so if it has two children. - /// - /// The node to check. - /// true if node passes check, false otherwise. - private static bool CheckNonLeafChildren(AaTreeNode node) - { - var condition = node.Level > 1 && (node.Left is null || node.Right is null); - return !condition; - } + /// + /// Checks if node is not a leaf, and if so if it has two children. + /// + /// The node to check. + /// true if node passes check, false otherwise. + private static bool CheckNonLeafChildren(AaTreeNode node) + { + var condition = node.Level > 1 && (node.Left is null || node.Right is null); + return !condition; } } diff --git a/DataStructures.Tests/AVLTreeTests.cs b/DataStructures.Tests/AVLTreeTests.cs index f02d5b78..e3e3fe5e 100644 --- a/DataStructures.Tests/AVLTreeTests.cs +++ b/DataStructures.Tests/AVLTreeTests.cs @@ -6,384 +6,383 @@ using NUnit.Framework; using static FluentAssertions.FluentActions; -namespace DataStructures.Tests +namespace DataStructures.Tests; + +internal class AvlTreeTests { - internal class AvlTreeTests + private static readonly int[] Data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + private static readonly int[] PreOrder = { 4, 2, 1, 3, 8, 6, 5, 7, 9, 10 }; + private static readonly int[] PostOrder = { 1, 3, 2, 5, 7, 6, 10, 9, 8, 4 }; + + [Test] + public void Constructor_UseCustomComparer_FormsCorrectTree() { - private static readonly int[] Data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - private static readonly int[] PreOrder = { 4, 2, 1, 3, 8, 6, 5, 7, 9, 10 }; - private static readonly int[] PostOrder = { 1, 3, 2, 5, 7, 6, 10, 9, 8, 4 }; + var tree = new AvlTree(Comparer.Create((x, y) => y.CompareTo(x))); - [Test] - public void Constructor_UseCustomComparer_FormsCorrectTree() - { - var tree = new AvlTree(Comparer.Create((x, y) => y.CompareTo(x))); + tree.AddRange(Data); - tree.AddRange(Data); + tree.GetMin().Should().Be(10); - tree.GetMin().Should().Be(10); + tree.GetMax().Should().Be(1); - tree.GetMax().Should().Be(1); + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + Data.Reverse(), + config => config.WithStrictOrdering()); + } - tree.GetKeysInOrder() - .Should() - .BeEquivalentTo( - Data.Reverse(), - config => config.WithStrictOrdering()); - } + [Test] + public void Add_MultipleKeys_FormsCorrectTree() + { + var tree = new AvlTree(); - [Test] - public void Add_MultipleKeys_FormsCorrectTree() + for (var i = 0; i < Data.Length; ++i) { - var tree = new AvlTree(); - - for (var i = 0; i < Data.Length; ++i) - { - tree.Add(Data[i]); - tree.Count.Should().Be(i + 1); - } - - tree.GetKeysInOrder() - .Should() - .BeEquivalentTo( - Data, - config => config.WithStrictOrdering()); - - tree.GetKeysPreOrder() - .Should() - .BeEquivalentTo( - PreOrder, - config => config.WithStrictOrdering()); - - tree.GetKeysPostOrder() - .Should() - .BeEquivalentTo( - PostOrder, - config => config.WithStrictOrdering()); + tree.Add(Data[i]); + tree.Count.Should().Be(i + 1); } - [Test] - public void Add_KeyAlreadyInTree_ThrowsException() - { - var tree = new AvlTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5 }); + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + Data, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + PreOrder, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + PostOrder, + config => config.WithStrictOrdering()); + } - Invoking(() => tree.Add(1)).Should().ThrowExactly(); - } + [Test] + public void Add_KeyAlreadyInTree_ThrowsException() + { + var tree = new AvlTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5 }); - [Test] - public void AddRange_MultipleKeys_FormsCorrectTree() - { - var tree = new AvlTree(); - tree.AddRange(new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }); - - tree.Count.Should().Be(7); - - tree.GetKeysInOrder() - .Should() - .BeEquivalentTo( - new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }, - config => config.WithStrictOrdering()); - - tree.GetKeysPreOrder() - .Should() - .BeEquivalentTo( - new[] { 'd', 'b', 'a', 'c', 'f', 'e', 'g' }, - config => config.WithStrictOrdering()); - - tree.GetKeysPostOrder() - .Should() - .BeEquivalentTo( - new[] { 'a', 'c', 'b', 'e', 'g', 'f', 'd' }, - config => config.WithStrictOrdering()); - } + Invoking(() => tree.Add(1)).Should().ThrowExactly(); + } - [Test] - public void Remove_MultipleKeys_TreeStillValid() - { - var tree = new AvlTree(); - tree.AddRange(Data); - - tree.Remove(7); - - tree.Count.Should().Be(9); - tree.Contains(7).Should().BeFalse(); - - tree.GetKeysInOrder() - .Should() - .BeEquivalentTo( - new[] { 1, 2, 3, 4, 5, 6, 8, 9, 10 }, - config => config.WithStrictOrdering()); - - tree.GetKeysPreOrder() - .Should() - .BeEquivalentTo( - new[] { 4, 2, 1, 3, 8, 6, 5, 9, 10 }, - config => config.WithStrictOrdering()); - - tree.GetKeysPostOrder() - .Should() - .BeEquivalentTo( - new[] { 1, 3, 2, 5, 6, 10, 9, 8, 4 }, - config => config.WithStrictOrdering()); - - tree.Remove(2); - - tree.Count.Should().Be(8); - tree.Contains(2).Should().BeFalse(); - - tree.Remove(1); - - tree.Count.Should().Be(7); - tree.Contains(1).Should().BeFalse(); - - tree.GetKeysInOrder() - .Should() - .BeEquivalentTo( - new[] { 3, 4, 5, 6, 8, 9, 10 }, - config => config.WithStrictOrdering()); - - tree.GetKeysPreOrder() - .Should() - .BeEquivalentTo( - new[] { 8, 4, 3, 6, 5, 9, 10 }, - config => config.WithStrictOrdering()); - - tree.GetKeysPostOrder() - .Should() - .BeEquivalentTo( - new[] { 3, 5, 6, 4, 10, 9, 8 }, - config => config.WithStrictOrdering()); - - tree.Remove(9); - - tree.Count.Should().Be(6); - tree.Contains(9).Should().BeFalse(); - - tree.GetKeysInOrder() - .Should() - .BeEquivalentTo( - new[] { 3, 4, 5, 6, 8, 10 }, - config => config.WithStrictOrdering()); - - tree.GetKeysPreOrder() - .Should() - .BeEquivalentTo( - new[] { 6, 4, 3, 5, 8, 10 }, - config => config.WithStrictOrdering()); - - tree.GetKeysPostOrder() - .Should() - .BeEquivalentTo( - new[] { 3, 5, 4, 10, 8, 6 }, - config => config.WithStrictOrdering()); - - tree.Remove(3); - tree.Remove(4); - tree.Remove(5); - tree.Remove(6); - tree.Remove(8); - tree.Remove(10); - - tree.Count.Should().Be(0); - tree.GetKeysInOrder().Should().BeEmpty(); - } + [Test] + public void AddRange_MultipleKeys_FormsCorrectTree() + { + var tree = new AvlTree(); + tree.AddRange(new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }); + + tree.Count.Should().Be(7); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + new[] { 'd', 'b', 'a', 'c', 'f', 'e', 'g' }, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + new[] { 'a', 'c', 'b', 'e', 'g', 'f', 'd' }, + config => config.WithStrictOrdering()); + } - [Test] - public void Remove_MultipleKeys_TreeStillValid_Variant2() - { - var tree = new AvlTree(); - tree.AddRange(Data); + [Test] + public void Remove_MultipleKeys_TreeStillValid() + { + var tree = new AvlTree(); + tree.AddRange(Data); + + tree.Remove(7); + + tree.Count.Should().Be(9); + tree.Contains(7).Should().BeFalse(); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + new[] { 1, 2, 3, 4, 5, 6, 8, 9, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + new[] { 4, 2, 1, 3, 8, 6, 5, 9, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + new[] { 1, 3, 2, 5, 6, 10, 9, 8, 4 }, + config => config.WithStrictOrdering()); + + tree.Remove(2); + + tree.Count.Should().Be(8); + tree.Contains(2).Should().BeFalse(); + + tree.Remove(1); + + tree.Count.Should().Be(7); + tree.Contains(1).Should().BeFalse(); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + new[] { 3, 4, 5, 6, 8, 9, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + new[] { 8, 4, 3, 6, 5, 9, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + new[] { 3, 5, 6, 4, 10, 9, 8 }, + config => config.WithStrictOrdering()); + + tree.Remove(9); + + tree.Count.Should().Be(6); + tree.Contains(9).Should().BeFalse(); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + new[] { 3, 4, 5, 6, 8, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + new[] { 6, 4, 3, 5, 8, 10 }, + config => config.WithStrictOrdering()); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + new[] { 3, 5, 4, 10, 8, 6 }, + config => config.WithStrictOrdering()); + + tree.Remove(3); + tree.Remove(4); + tree.Remove(5); + tree.Remove(6); + tree.Remove(8); + tree.Remove(10); + + tree.Count.Should().Be(0); + tree.GetKeysInOrder().Should().BeEmpty(); + } - tree.Remove(10); + [Test] + public void Remove_MultipleKeys_TreeStillValid_Variant2() + { + var tree = new AvlTree(); + tree.AddRange(Data); - tree.Count.Should().Be(9); - tree.Contains(10).Should().BeFalse(); + tree.Remove(10); - tree.Remove(5); + tree.Count.Should().Be(9); + tree.Contains(10).Should().BeFalse(); - tree.Count.Should().Be(8); - tree.Contains(5).Should().BeFalse(); + tree.Remove(5); - tree.Remove(7); + tree.Count.Should().Be(8); + tree.Contains(5).Should().BeFalse(); - tree.Count.Should().Be(7); - tree.Contains(7).Should().BeFalse(); + tree.Remove(7); - tree.Remove(9); + tree.Count.Should().Be(7); + tree.Contains(7).Should().BeFalse(); - tree.Count.Should().Be(6); - tree.Contains(9).Should().BeFalse(); + tree.Remove(9); - tree.Remove(1); + tree.Count.Should().Be(6); + tree.Contains(9).Should().BeFalse(); - tree.Count.Should().Be(5); - tree.Contains(1).Should().BeFalse(); + tree.Remove(1); - tree.Remove(3); + tree.Count.Should().Be(5); + tree.Contains(1).Should().BeFalse(); - tree.Count.Should().Be(4); - tree.Contains(3).Should().BeFalse(); + tree.Remove(3); - tree.Remove(2); + tree.Count.Should().Be(4); + tree.Contains(3).Should().BeFalse(); - tree.Count.Should().Be(3); - tree.Contains(2).Should().BeFalse(); + tree.Remove(2); - tree.GetKeysInOrder() - .Should() - .BeEquivalentTo( - new[] { 4,6,8 }, - config => config.WithStrictOrdering()); + tree.Count.Should().Be(3); + tree.Contains(2).Should().BeFalse(); - tree.GetKeysPreOrder() - .Should() - .BeEquivalentTo( - new[] { 6,4,8 }, - config => config.WithStrictOrdering()); + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + new[] { 4,6,8 }, + config => config.WithStrictOrdering()); - tree.GetKeysPostOrder() - .Should() - .BeEquivalentTo( - new[] { 4,8,6 }, - config => config.WithStrictOrdering()); - } + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + new[] { 6,4,8 }, + config => config.WithStrictOrdering()); - [Test] - public void Remove_EmptyTree_ThrowsException() - { - var tree = new AvlTree(); + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + new[] { 4,8,6 }, + config => config.WithStrictOrdering()); + } - Invoking(() => tree.Remove(1)).Should().ThrowExactly(); - } + [Test] + public void Remove_EmptyTree_ThrowsException() + { + var tree = new AvlTree(); - [Test] - public void Remove_KeyNotInTree_ThrowsException() - { - var tree = new AvlTree(); - tree.AddRange(Data); + Invoking(() => tree.Remove(1)).Should().ThrowExactly(); + } - Invoking(() => tree.Remove(24)).Should().ThrowExactly(); - } + [Test] + public void Remove_KeyNotInTree_ThrowsException() + { + var tree = new AvlTree(); + tree.AddRange(Data); - [Test] - public void Contains_CorrectReturn() - { - var tree = new AvlTree(); + Invoking(() => tree.Remove(24)).Should().ThrowExactly(); + } - tree.AddRange(Data); + [Test] + public void Contains_CorrectReturn() + { + var tree = new AvlTree(); - tree.Contains(3).Should().BeTrue(); - tree.Contains(7).Should().BeTrue(); - tree.Contains(24).Should().BeFalse(); - tree.Contains(-1).Should().BeFalse(); - } + tree.AddRange(Data); - [Test] - public void Contains_EmptyTree_ReturnsFalse() - { - var tree = new AvlTree(); + tree.Contains(3).Should().BeTrue(); + tree.Contains(7).Should().BeTrue(); + tree.Contains(24).Should().BeFalse(); + tree.Contains(-1).Should().BeFalse(); + } - tree.Contains(5).Should().BeFalse(); - tree.Contains(-12).Should().BeFalse(); - } + [Test] + public void Contains_EmptyTree_ReturnsFalse() + { + var tree = new AvlTree(); - [Test] - public void GetMin_CorrectReturn() - { - var tree = new AvlTree(); - tree.AddRange(Data); + tree.Contains(5).Should().BeFalse(); + tree.Contains(-12).Should().BeFalse(); + } - tree.GetMin().Should().Be(1); - } + [Test] + public void GetMin_CorrectReturn() + { + var tree = new AvlTree(); + tree.AddRange(Data); - [Test] - public void GetMin_EmptyTree_ThrowsException() - { - var tree = new AvlTree(); + tree.GetMin().Should().Be(1); + } - Invoking(() => tree.GetMin()).Should().ThrowExactly(); - } + [Test] + public void GetMin_EmptyTree_ThrowsException() + { + var tree = new AvlTree(); - [Test] - public void GetMax_CorrectReturn() - { - var tree = new AvlTree(); - tree.AddRange(Data); + Invoking(() => tree.GetMin()).Should().ThrowExactly(); + } - tree.GetMax().Should().Be(10); - } + [Test] + public void GetMax_CorrectReturn() + { + var tree = new AvlTree(); + tree.AddRange(Data); - [Test] - public void GetMax_EmptyTree_ThrowsException() - { - var tree = new AvlTree(); + tree.GetMax().Should().Be(10); + } - Invoking(() => tree.GetMax()).Should().ThrowExactly(); - } + [Test] + public void GetMax_EmptyTree_ThrowsException() + { + var tree = new AvlTree(); - [Test] - public void GetKeysInOrder_CorrectReturn() - { - var tree = new AvlTree(); - tree.AddRange(Data); - - tree.GetKeysInOrder() - .Should() - .BeEquivalentTo( - Data, - config => config.WithStrictOrdering()); - } + Invoking(() => tree.GetMax()).Should().ThrowExactly(); + } - [Test] - public void GetKeysInOrder_EmptyTree_CorrectReturn() - { - var tree = new AvlTree(); + [Test] + public void GetKeysInOrder_CorrectReturn() + { + var tree = new AvlTree(); + tree.AddRange(Data); + + tree.GetKeysInOrder() + .Should() + .BeEquivalentTo( + Data, + config => config.WithStrictOrdering()); + } - tree.GetKeysInOrder().Should().BeEmpty(); - } + [Test] + public void GetKeysInOrder_EmptyTree_CorrectReturn() + { + var tree = new AvlTree(); - [Test] - public void GetKeysPreOrder_CorrectReturn() - { - var tree = new AvlTree(); + tree.GetKeysInOrder().Should().BeEmpty(); + } - tree.AddRange(Data); + [Test] + public void GetKeysPreOrder_CorrectReturn() + { + var tree = new AvlTree(); - tree.GetKeysPreOrder() - .Should() - .BeEquivalentTo( - PreOrder, - config => config.WithStrictOrdering()); - } + tree.AddRange(Data); - [Test] - public void GetKeysPreOrder_EmptyTree_CorrectReturn() - { - var tree = new AvlTree(); + tree.GetKeysPreOrder() + .Should() + .BeEquivalentTo( + PreOrder, + config => config.WithStrictOrdering()); + } - tree.GetKeysPreOrder().Should().BeEmpty(); - } + [Test] + public void GetKeysPreOrder_EmptyTree_CorrectReturn() + { + var tree = new AvlTree(); - [Test] - public void GetKeysPostOrder_CorrectReturn() - { - var tree = new AvlTree(); - tree.AddRange(Data); - - tree.GetKeysPostOrder() - .Should() - .BeEquivalentTo( - PostOrder, - config => config.WithStrictOrdering()); - } + tree.GetKeysPreOrder().Should().BeEmpty(); + } - [Test] - public void GetKeysPostOrder_EmptyTree_CorrectReturn() - { - var tree = new AvlTree(); + [Test] + public void GetKeysPostOrder_CorrectReturn() + { + var tree = new AvlTree(); + tree.AddRange(Data); + + tree.GetKeysPostOrder() + .Should() + .BeEquivalentTo( + PostOrder, + config => config.WithStrictOrdering()); + } - tree.GetKeysPostOrder().Should().BeEmpty(); - } + [Test] + public void GetKeysPostOrder_EmptyTree_CorrectReturn() + { + var tree = new AvlTree(); + + tree.GetKeysPostOrder().Should().BeEmpty(); } } diff --git a/DataStructures.Tests/BinarySearchTreeTests.cs b/DataStructures.Tests/BinarySearchTreeTests.cs index 84408b2e..52870283 100644 --- a/DataStructures.Tests/BinarySearchTreeTests.cs +++ b/DataStructures.Tests/BinarySearchTreeTests.cs @@ -1,284 +1,283 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using DataStructures.BinarySearchTree; using NUnit.Framework; -namespace DataStructures.Tests +namespace DataStructures.Tests; + +public static class BinarySearchTreeTests { - public static class BinarySearchTreeTests + [Test] + public static void Constructor_UseCustomComparer_FormsCorrectTree() + { + var cmpFunc = Comparer.Create((x, y) => x.Length - y.Length); + var tree = new BinarySearchTree(cmpFunc); + var elems = new[] { "z", "yy", "vvv", "bbbb", "fffff", "pppppp" }; + tree.AddRange(elems); + + Assert.IsNotNull(tree.Search("vvv")); + Assert.AreEqual("bbbb", tree.Search("vvv")!.Right!.Key); + } + + [Test] + public static void Add_MultipleKeys_FormsCorrectBST() + { + var tree = new BinarySearchTree(); + + tree.Add(5); + Assert.AreEqual(1, tree.Count); + + tree.Add(3); + Assert.AreEqual(2, tree.Count); + + tree.Add(4); + Assert.AreEqual(3, tree.Count); + + tree.Add(2); + Assert.AreEqual(4, tree.Count); + + var rootNode = tree.Search(5); + Assert.AreEqual(5, rootNode!.Key); + Assert.AreEqual(3, rootNode!.Left!.Key); + Assert.IsNull(rootNode!.Right); + + var threeNode = tree.Search(3); + Assert.AreEqual(3, threeNode!.Key); + Assert.AreEqual(2, threeNode!.Left!.Key); + Assert.AreEqual(4, threeNode!.Right!.Key); + + var twoNode = tree.Search(2); + Assert.IsNull(twoNode!.Left); + Assert.IsNull(twoNode!.Right); + + var fourNode = tree.Search(4); + Assert.IsNull(fourNode!.Left); + Assert.IsNull(fourNode!.Right); + } + + [Test] + public static void Add_KeyAlreadyInTree_ThrowsCorrectException() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2 }); + + _ = Assert.Throws(() => tree.Add(5)); + } + + [Test] + public static void AddRange_MultipleKeys_FormsCorrectBST() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2 }); + + var rootNode = tree.Search(5); + Assert.AreEqual(5, rootNode!.Key); + Assert.AreEqual(3, rootNode!.Left!.Key); + Assert.IsNull(rootNode!.Right); + + var threeNode = tree.Search(3); + Assert.AreEqual(3, threeNode!.Key); + Assert.AreEqual(2, threeNode!.Left!.Key); + Assert.AreEqual(4, threeNode!.Right!.Key); + + var twoNode = tree.Search(2); + Assert.IsNull(twoNode!.Left); + Assert.IsNull(twoNode!.Right); + + var fourNode = tree.Search(4); + Assert.IsNull(fourNode!.Left); + Assert.IsNull(fourNode!.Right); + } + + [Test] + public static void Search_MultipleKeys_FindsAllKeys() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + Assert.AreEqual(2, tree.Search(2)!.Key); + Assert.AreEqual(3, tree.Search(3)!.Key); + Assert.AreEqual(4, tree.Search(4)!.Key); + Assert.AreEqual(5, tree.Search(5)!.Key); + Assert.AreEqual(6, tree.Search(6)!.Key); + Assert.AreEqual(7, tree.Search(7)!.Key); + Assert.AreEqual(8, tree.Search(8)!.Key); + } + + [Test] + public static void Contains_MultipleKeys_FindsAllKeys() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + Assert.IsTrue(tree.Contains(2)); + Assert.IsTrue(tree.Contains(3)); + Assert.IsTrue(tree.Contains(4)); + Assert.IsTrue(tree.Contains(5)); + Assert.IsTrue(tree.Contains(6)); + Assert.IsTrue(tree.Contains(7)); + Assert.IsTrue(tree.Contains(8)); + } + + [Test] + public static void Remove_LeafNodes_CorrectlyRemovesNodes() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + var twoRemoveResult = tree.Remove(2); + Assert.IsTrue(twoRemoveResult); + Assert.IsNull(tree.Search(2)); + Assert.IsNull(tree.Search(3)!.Left); + Assert.IsNotNull(tree.Search(3)!.Right); + Assert.AreEqual(6, tree.Count); + + var fourRemoveResult = tree.Remove(4); + Assert.IsTrue(fourRemoveResult); + Assert.IsNull(tree.Search(4)); + Assert.IsNull(tree.Search(3)!.Left); + Assert.IsNull(tree.Search(3)!.Right); + Assert.AreEqual(5, tree.Count); + } + + [Test] + public static void Remove_NodesWithOneChild_CorrectlyRemovesNodes() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + tree.Remove(4); + var threeRemoveResult = tree.Remove(3); + Assert.IsTrue(threeRemoveResult); + Assert.IsNull(tree.Search(3)); + Assert.IsNull(tree.Search(2)!.Left); + Assert.IsNull(tree.Search(2)!.Right); + Assert.AreEqual(5, tree.Count); + + tree.Remove(6); + var sevenRemoveResult = tree.Remove(7); + Assert.IsTrue(sevenRemoveResult); + Assert.IsNull(tree.Search(7)); + Assert.IsNull(tree.Search(8)!.Left); + Assert.IsNull(tree.Search(8)!.Right); + Assert.AreEqual(3, tree.Count); + } + + [Test] + public static void Remove_NodesWithTwoChildren_CorrectlyRemovesNodes() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + var sevenRemoveResult = tree.Remove(7); + Assert.IsTrue(sevenRemoveResult); + Assert.IsNull(tree.Search(7)); + Assert.IsNull(tree.Search(6)!.Left); + Assert.IsNotNull(tree.Search(6)!.Right); + Assert.AreEqual(6, tree.Count); + } + + [Test] + public static void Remove_NonExistentElement_ReturnsFalse() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + Assert.IsFalse(tree.Remove(999)); + Assert.AreEqual(7, tree.Count); + } + + [Test] + public static void Remove_EmptyTree_ReturnsFalse() { - [Test] - public static void Constructor_UseCustomComparer_FormsCorrectTree() - { - var cmpFunc = Comparer.Create((x, y) => x.Length - y.Length); - var tree = new BinarySearchTree(cmpFunc); - var elems = new[] { "z", "yy", "vvv", "bbbb", "fffff", "pppppp" }; - tree.AddRange(elems); - - Assert.IsNotNull(tree.Search("vvv")); - Assert.AreEqual("bbbb", tree.Search("vvv")!.Right!.Key); - } - - [Test] - public static void Add_MultipleKeys_FormsCorrectBST() - { - var tree = new BinarySearchTree(); - - tree.Add(5); - Assert.AreEqual(1, tree.Count); - - tree.Add(3); - Assert.AreEqual(2, tree.Count); - - tree.Add(4); - Assert.AreEqual(3, tree.Count); - - tree.Add(2); - Assert.AreEqual(4, tree.Count); - - var rootNode = tree.Search(5); - Assert.AreEqual(5, rootNode!.Key); - Assert.AreEqual(3, rootNode!.Left!.Key); - Assert.IsNull(rootNode!.Right); - - var threeNode = tree.Search(3); - Assert.AreEqual(3, threeNode!.Key); - Assert.AreEqual(2, threeNode!.Left!.Key); - Assert.AreEqual(4, threeNode!.Right!.Key); - - var twoNode = tree.Search(2); - Assert.IsNull(twoNode!.Left); - Assert.IsNull(twoNode!.Right); - - var fourNode = tree.Search(4); - Assert.IsNull(fourNode!.Left); - Assert.IsNull(fourNode!.Right); - } - - [Test] - public static void Add_KeyAlreadyInTree_ThrowsCorrectException() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2 }); - - _ = Assert.Throws(() => tree.Add(5)); - } - - [Test] - public static void AddRange_MultipleKeys_FormsCorrectBST() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2 }); - - var rootNode = tree.Search(5); - Assert.AreEqual(5, rootNode!.Key); - Assert.AreEqual(3, rootNode!.Left!.Key); - Assert.IsNull(rootNode!.Right); - - var threeNode = tree.Search(3); - Assert.AreEqual(3, threeNode!.Key); - Assert.AreEqual(2, threeNode!.Left!.Key); - Assert.AreEqual(4, threeNode!.Right!.Key); - - var twoNode = tree.Search(2); - Assert.IsNull(twoNode!.Left); - Assert.IsNull(twoNode!.Right); - - var fourNode = tree.Search(4); - Assert.IsNull(fourNode!.Left); - Assert.IsNull(fourNode!.Right); - } - - [Test] - public static void Search_MultipleKeys_FindsAllKeys() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - Assert.AreEqual(2, tree.Search(2)!.Key); - Assert.AreEqual(3, tree.Search(3)!.Key); - Assert.AreEqual(4, tree.Search(4)!.Key); - Assert.AreEqual(5, tree.Search(5)!.Key); - Assert.AreEqual(6, tree.Search(6)!.Key); - Assert.AreEqual(7, tree.Search(7)!.Key); - Assert.AreEqual(8, tree.Search(8)!.Key); - } - - [Test] - public static void Contains_MultipleKeys_FindsAllKeys() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - Assert.IsTrue(tree.Contains(2)); - Assert.IsTrue(tree.Contains(3)); - Assert.IsTrue(tree.Contains(4)); - Assert.IsTrue(tree.Contains(5)); - Assert.IsTrue(tree.Contains(6)); - Assert.IsTrue(tree.Contains(7)); - Assert.IsTrue(tree.Contains(8)); - } - - [Test] - public static void Remove_LeafNodes_CorrectlyRemovesNodes() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - var twoRemoveResult = tree.Remove(2); - Assert.IsTrue(twoRemoveResult); - Assert.IsNull(tree.Search(2)); - Assert.IsNull(tree.Search(3)!.Left); - Assert.IsNotNull(tree.Search(3)!.Right); - Assert.AreEqual(6, tree.Count); - - var fourRemoveResult = tree.Remove(4); - Assert.IsTrue(fourRemoveResult); - Assert.IsNull(tree.Search(4)); - Assert.IsNull(tree.Search(3)!.Left); - Assert.IsNull(tree.Search(3)!.Right); - Assert.AreEqual(5, tree.Count); - } - - [Test] - public static void Remove_NodesWithOneChild_CorrectlyRemovesNodes() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - tree.Remove(4); - var threeRemoveResult = tree.Remove(3); - Assert.IsTrue(threeRemoveResult); - Assert.IsNull(tree.Search(3)); - Assert.IsNull(tree.Search(2)!.Left); - Assert.IsNull(tree.Search(2)!.Right); - Assert.AreEqual(5, tree.Count); - - tree.Remove(6); - var sevenRemoveResult = tree.Remove(7); - Assert.IsTrue(sevenRemoveResult); - Assert.IsNull(tree.Search(7)); - Assert.IsNull(tree.Search(8)!.Left); - Assert.IsNull(tree.Search(8)!.Right); - Assert.AreEqual(3, tree.Count); - } - - [Test] - public static void Remove_NodesWithTwoChildren_CorrectlyRemovesNodes() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - var sevenRemoveResult = tree.Remove(7); - Assert.IsTrue(sevenRemoveResult); - Assert.IsNull(tree.Search(7)); - Assert.IsNull(tree.Search(6)!.Left); - Assert.IsNotNull(tree.Search(6)!.Right); - Assert.AreEqual(6, tree.Count); - } - - [Test] - public static void Remove_NonExistentElement_ReturnsFalse() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - Assert.IsFalse(tree.Remove(999)); - Assert.AreEqual(7, tree.Count); - } - - [Test] - public static void Remove_EmptyTree_ReturnsFalse() - { - var tree = new BinarySearchTree(); - Assert.IsFalse(tree.Remove(8)); - Assert.AreEqual(0, tree.Count); - } - - [Test] - public static void Remove_RemoveRoot_CorrectlyRemovesRoot() - { - var tree = new BinarySearchTree(); - tree.Add(5); - tree.Remove(5); - - Assert.AreEqual(0, tree.Count); - Assert.IsNull(tree.Search(5)); - - tree.AddRange(new List { 5, 4, 6 }); - tree.Remove(5); - - Assert.AreEqual(2, tree.Count); - Assert.IsNull(tree.Search(5)); - Assert.IsNotNull(tree.Search(4)); - Assert.IsNotNull(tree.Search(6)); - Assert.AreEqual(6, tree.Search(4)!.Right!.Key); - } - - [Test] - public static void GetMax_NonEmptyTree_ReturnsCorrectValue() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - Assert.AreEqual(8, tree.GetMax()!.Key); - } - - [Test] - public static void GetMax_EmptyTree_ReturnsDefaultValue() - { - var tree = new BinarySearchTree(); - Assert.IsNull(tree.GetMax()); - } - - [Test] - public static void GetMin_NonEmptyTree_ReturnsCorrectValue() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - Assert.AreEqual(2, tree.GetMin()!.Key); - } - - [Test] - public static void GetMin_EmptyTree_ReturnsDefaultValue() - { - var tree = new BinarySearchTree(); - Assert.IsNull(tree.GetMin()); - } - - [Test] - public static void GetKeysInOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - var keys = tree.GetKeysInOrder(); - var expected = new List { 2, 3, 4, 5, 6, 7, 8 }; - Assert.IsTrue(keys.SequenceEqual(expected)); - } - - [Test] - public static void GetKeysPreOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - var keys = tree.GetKeysPreOrder(); - var expected = new List { 5, 3, 2, 4, 7, 6, 8 }; - Assert.IsTrue(keys.SequenceEqual(expected)); - } - - [Test] - public static void GetKeysPostOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder() - { - var tree = new BinarySearchTree(); - tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - - var keys = tree.GetKeysPostOrder(); - var expected = new List { 2, 4, 3, 6, 8, 7, 5 }; - Assert.IsTrue(keys.SequenceEqual(expected)); - } + var tree = new BinarySearchTree(); + Assert.IsFalse(tree.Remove(8)); + Assert.AreEqual(0, tree.Count); + } + + [Test] + public static void Remove_RemoveRoot_CorrectlyRemovesRoot() + { + var tree = new BinarySearchTree(); + tree.Add(5); + tree.Remove(5); + + Assert.AreEqual(0, tree.Count); + Assert.IsNull(tree.Search(5)); + + tree.AddRange(new List { 5, 4, 6 }); + tree.Remove(5); + + Assert.AreEqual(2, tree.Count); + Assert.IsNull(tree.Search(5)); + Assert.IsNotNull(tree.Search(4)); + Assert.IsNotNull(tree.Search(6)); + Assert.AreEqual(6, tree.Search(4)!.Right!.Key); + } + + [Test] + public static void GetMax_NonEmptyTree_ReturnsCorrectValue() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + Assert.AreEqual(8, tree.GetMax()!.Key); + } + + [Test] + public static void GetMax_EmptyTree_ReturnsDefaultValue() + { + var tree = new BinarySearchTree(); + Assert.IsNull(tree.GetMax()); + } + + [Test] + public static void GetMin_NonEmptyTree_ReturnsCorrectValue() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + Assert.AreEqual(2, tree.GetMin()!.Key); + } + + [Test] + public static void GetMin_EmptyTree_ReturnsDefaultValue() + { + var tree = new BinarySearchTree(); + Assert.IsNull(tree.GetMin()); + } + + [Test] + public static void GetKeysInOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + var keys = tree.GetKeysInOrder(); + var expected = new List { 2, 3, 4, 5, 6, 7, 8 }; + Assert.IsTrue(keys.SequenceEqual(expected)); + } + + [Test] + public static void GetKeysPreOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + var keys = tree.GetKeysPreOrder(); + var expected = new List { 5, 3, 2, 4, 7, 6, 8 }; + Assert.IsTrue(keys.SequenceEqual(expected)); + } + + [Test] + public static void GetKeysPostOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder() + { + var tree = new BinarySearchTree(); + tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); + + var keys = tree.GetKeysPostOrder(); + var expected = new List { 2, 4, 3, 6, 8, 7, 5 }; + Assert.IsTrue(keys.SequenceEqual(expected)); } } diff --git a/DataStructures.Tests/BitArrayTests.cs b/DataStructures.Tests/BitArrayTests.cs index 93bc32fa..d99f8b8b 100644 --- a/DataStructures.Tests/BitArrayTests.cs +++ b/DataStructures.Tests/BitArrayTests.cs @@ -1,535 +1,534 @@ -using System; +using System; using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests +namespace DataStructures.Tests; + +/// +/// This class contains some tests for the class BitArray. +/// +public static class BitArrayTests { - /// - /// This class contains some tests for the class BitArray. - /// - public static class BitArrayTests + [Test] + public static void TestIndexer() { - [Test] - public static void TestIndexer() - { - // Arrange - var testObj = new BitArray(5); + // Arrange + var testObj = new BitArray(5); - // Act - testObj.Compile(24); + // Act + testObj.Compile(24); - // Assert - Assert.IsTrue(testObj[0]); - Assert.IsTrue(testObj[1]); - Assert.IsFalse(testObj[3]); - } + // Assert + Assert.IsTrue(testObj[0]); + Assert.IsTrue(testObj[1]); + Assert.IsFalse(testObj[3]); + } - [TestCase(19, 3)] - public static void TestNumberOfOneBits(int number, int expected) - { - // Arrange - var testObj = new BitArray(5); + [TestCase(19, 3)] + public static void TestNumberOfOneBits(int number, int expected) + { + // Arrange + var testObj = new BitArray(5); - // Act - testObj.Compile(number); + // Act + testObj.Compile(number); - // Assert - Assert.AreEqual(expected, testObj.NumberOfOneBits()); - } + // Assert + Assert.AreEqual(expected, testObj.NumberOfOneBits()); + } - [TestCase(26, 2)] - public static void TestNumberOfZeroBits(int number, int expected) - { - // Arrange - var testObj = new BitArray(5); + [TestCase(26, 2)] + public static void TestNumberOfZeroBits(int number, int expected) + { + // Arrange + var testObj = new BitArray(5); - // Act - testObj.Compile(number); + // Act + testObj.Compile(number); - // Assert - Assert.AreEqual(expected, testObj.NumberOfZeroBits()); - } + // Assert + Assert.AreEqual(expected, testObj.NumberOfZeroBits()); + } - [TestCase(33, 33)] - public static void TestToInt64(int number, int expected) - { - // Arrange - var testObj = new BitArray(6); + [TestCase(33, 33)] + public static void TestToInt64(int number, int expected) + { + // Arrange + var testObj = new BitArray(6); - // Act - testObj.Compile(number); + // Act + testObj.Compile(number); - // Assert - Assert.AreEqual(expected, testObj.ToInt64()); - } + // Assert + Assert.AreEqual(expected, testObj.ToInt64()); + } - [Test] - public static void TestToInt32MaxValue() - { - // Arrange - var testObj = new BitArray(33); + [Test] + public static void TestToInt32MaxValue() + { + // Arrange + var testObj = new BitArray(33); - // Act + // Act - // Assert - _ = Assert.Throws(() => testObj.ToInt32()); - } + // Assert + _ = Assert.Throws(() => testObj.ToInt32()); + } - [Test] - public static void TestToInt64MaxValue() - { - // Arrange - var testObj = new BitArray(65); + [Test] + public static void TestToInt64MaxValue() + { + // Arrange + var testObj = new BitArray(65); - // Act + // Act - // Assert - _ = Assert.Throws(() => testObj.ToInt64()); - } + // Assert + _ = Assert.Throws(() => testObj.ToInt64()); + } - [TestCase("110")] - public static void TestResetField(string sequence) - { - // Arrange - var testObj = new BitArray(sequence); + [TestCase("110")] + public static void TestResetField(string sequence) + { + // Arrange + var testObj = new BitArray(sequence); - // Act - testObj.ResetField(); + // Act + testObj.ResetField(); - // Assert - Assert.AreEqual(0, testObj.ToInt64()); - } + // Assert + Assert.AreEqual(0, testObj.ToInt64()); + } - [TestCase("101001", 63)] - public static void TestSetAll(string sequence, int expected) - { - // Arrange - var testObj = new BitArray(sequence); + [TestCase("101001", 63)] + public static void TestSetAll(string sequence, int expected) + { + // Arrange + var testObj = new BitArray(sequence); - // Act - testObj.SetAll(true); + // Act + testObj.SetAll(true); - // Assert - Assert.AreEqual(expected, testObj.ToInt64()); - } + // Assert + Assert.AreEqual(expected, testObj.ToInt64()); + } - [Test] - public static void TestCloneEquals() - { - // Arrange - var testObj1 = new BitArray("110"); + [Test] + public static void TestCloneEquals() + { + // Arrange + var testObj1 = new BitArray("110"); - // Act - var testObj2 = (BitArray)testObj1.Clone(); + // Act + var testObj2 = (BitArray)testObj1.Clone(); - // Assert - Assert.IsTrue(testObj1.Equals(testObj2)); - } + // Assert + Assert.IsTrue(testObj1.Equals(testObj2)); + } - [Test] - public static void TestCloneNotEquals() - { - // Arrange - var testObj1 = new BitArray("101"); - var testObj2 = new BitArray(15); - var testObj3 = new BitArray(3); + [Test] + public static void TestCloneNotEquals() + { + // Arrange + var testObj1 = new BitArray("101"); + var testObj2 = new BitArray(15); + var testObj3 = new BitArray(3); - // Act - testObj3.Reset(); + // Act + testObj3.Reset(); - // Assert - testObj1.Equals(testObj2).Should().BeFalse(); - testObj1.Equals(testObj3).Should().BeFalse(); - } + // Assert + testObj1.Equals(testObj2).Should().BeFalse(); + testObj1.Equals(testObj3).Should().BeFalse(); + } - [Test] - public static void TestHasCode() - { - // Arrange - const int num = 5; - var testObj = new BitArray(3); + [Test] + public static void TestHasCode() + { + // Arrange + const int num = 5; + var testObj = new BitArray(3); - // Act - testObj.Compile(num); - var result = testObj.GetHashCode(); + // Act + testObj.Compile(num); + var result = testObj.GetHashCode(); - // Assert - Assert.NotNull(result); - Assert.AreEqual(5, result); - } + // Assert + Assert.NotNull(result); + Assert.AreEqual(5, result); + } - [Test] - public static void TestMoveNextCurrent() - { - var testObj1 = new BitArray("1111010"); + [Test] + public static void TestMoveNextCurrent() + { + var testObj1 = new BitArray("1111010"); - var counterOnes = 0; - var counterZeros = 0; + var counterOnes = 0; + var counterZeros = 0; - foreach (var bit in testObj1) + foreach (var bit in testObj1) + { + if (bit) { - if (bit) - { - counterOnes++; - } - else - { - counterZeros++; - } + counterOnes++; } - - Assert.AreEqual(counterOnes, 5); - Assert.AreEqual(counterZeros, 2); - } - - [Test] - public static void IEnumerable_IterationWorks() - { - var arr = new BitArray("010101010101010101"); - var current = 0; - foreach (var b in arr) + else { - b.Should().Be(arr[current]); - current++; + counterZeros++; } } - [Test] - public static void Equals_NullIsNotEqualToNotNull() + Assert.AreEqual(counterOnes, 5); + Assert.AreEqual(counterZeros, 2); + } + + [Test] + public static void IEnumerable_IterationWorks() + { + var arr = new BitArray("010101010101010101"); + var current = 0; + foreach (var b in arr) { - var arr1 = new BitArray("010101010101010101"); - BitArray? arr2 = null; - arr1.Equals(arr2).Should().BeFalse(); + b.Should().Be(arr[current]); + current++; } + } - #region COMPILE TESTS + [Test] + public static void Equals_NullIsNotEqualToNotNull() + { + var arr1 = new BitArray("010101010101010101"); + BitArray? arr2 = null; + arr1.Equals(arr2).Should().BeFalse(); + } - [TestCase("00100", "00100")] - [TestCase("01101", "01101")] - [TestCase("100", "00100")] - public static void TestCompileToString(string sequence, string expectedSequence) - { - // Arrange - var testObj = new BitArray(5); + #region COMPILE TESTS - // Act - testObj.Compile(sequence); + [TestCase("00100", "00100")] + [TestCase("01101", "01101")] + [TestCase("100", "00100")] + public static void TestCompileToString(string sequence, string expectedSequence) + { + // Arrange + var testObj = new BitArray(5); - // Assert - Assert.AreEqual(expectedSequence, testObj.ToString()); - } + // Act + testObj.Compile(sequence); - [TestCase("klgml", 5)] - [TestCase("klgml", 3)] - public static void TestCompileToStringThorwsException(string sequence, int arrLen) - { - // Arrange - var testObj = new BitArray(arrLen); + // Assert + Assert.AreEqual(expectedSequence, testObj.ToString()); + } - // Act - void Act() => testObj.Compile(sequence); + [TestCase("klgml", 5)] + [TestCase("klgml", 3)] + public static void TestCompileToStringThorwsException(string sequence, int arrLen) + { + // Arrange + var testObj = new BitArray(arrLen); - // Assert - Assert.Throws(Act); - } + // Act + void Act() => testObj.Compile(sequence); - [TestCase(15, "01111")] - [TestCase(17, "10001")] - [TestCase(4, "00100")] - public static void TestCompileLong(int number, string expected) - { - // Arrange - var testObj = new BitArray(5); + // Assert + Assert.Throws(Act); + } - // Act - testObj.Compile((long)number); + [TestCase(15, "01111")] + [TestCase(17, "10001")] + [TestCase(4, "00100")] + public static void TestCompileLong(int number, string expected) + { + // Arrange + var testObj = new BitArray(5); - // Assert - Assert.AreEqual(expected, testObj.ToString()); - } + // Act + testObj.Compile((long)number); - [TestCase(46, 3)] - [TestCase(-46, 5)] - public static void TestCompileLongThrowsException(int number, int arrLen) - { - // Arrange - var testObj = new BitArray(arrLen); + // Assert + Assert.AreEqual(expected, testObj.ToString()); + } - // Act - void Act() => testObj.Compile((long)number); + [TestCase(46, 3)] + [TestCase(-46, 5)] + public static void TestCompileLongThrowsException(int number, int arrLen) + { + // Arrange + var testObj = new BitArray(arrLen); - // Assert - Assert.Throws(Act); - } + // Act + void Act() => testObj.Compile((long)number); - [TestCase(17, "10001")] - [TestCase(25, "11001")] - [TestCase(4, "00100")] - public static void TestCompileInteger(int number, string expected) - { - // Arrange - var testObj = new BitArray(5); + // Assert + Assert.Throws(Act); + } - // Act - testObj.Compile(number); + [TestCase(17, "10001")] + [TestCase(25, "11001")] + [TestCase(4, "00100")] + public static void TestCompileInteger(int number, string expected) + { + // Arrange + var testObj = new BitArray(5); - // Assert - Assert.AreEqual(expected, testObj.ToString()); - } + // Act + testObj.Compile(number); - [TestCase(-8, 5)] - [TestCase(18, 3)] - public static void TestCompileIntegerThrowsException(int number, int arrayLength) - { - // Arrange - var testObj = new BitArray(arrayLength); + // Assert + Assert.AreEqual(expected, testObj.ToString()); + } - // Act - void Act() => testObj.Compile(number); + [TestCase(-8, 5)] + [TestCase(18, 3)] + public static void TestCompileIntegerThrowsException(int number, int arrayLength) + { + // Arrange + var testObj = new BitArray(arrayLength); - // Assert - Assert.Throws(Act); - } + // Act + void Act() => testObj.Compile(number); - #endregion COMPILE TESTS + // Assert + Assert.Throws(Act); + } - #region CONSTRUCTOR TESTS + #endregion COMPILE TESTS - [TestCase("00100", 4)] - public static void TestConstructor(string sequence, int expected) - { - // Arrange - var testObj1 = new BitArray(sequence); + #region CONSTRUCTOR TESTS - // Act + [TestCase("00100", 4)] + public static void TestConstructor(string sequence, int expected) + { + // Arrange + var testObj1 = new BitArray(sequence); - // Assert - Assert.AreEqual(expected, testObj1.ToInt64()); - } + // Act - [TestCase(new[] { true, false, true }, 5)] - public static void TestConstructorBoolArray(bool[] sequence, int expected) - { - // Arrange - var testObj3 = new BitArray(sequence); + // Assert + Assert.AreEqual(expected, testObj1.ToInt64()); + } - // Act + [TestCase(new[] { true, false, true }, 5)] + public static void TestConstructorBoolArray(bool[] sequence, int expected) + { + // Arrange + var testObj3 = new BitArray(sequence); - // Assert - Assert.AreEqual(expected, testObj3.ToInt64()); - } + // Act - [TestCase("000120")] - [TestCase("")] - public static void TestConstructorThrowsException(string sequence) - { - // Arrange + // Assert + Assert.AreEqual(expected, testObj3.ToInt64()); + } - // Act - Action act = () => new BitArray(sequence); + [TestCase("000120")] + [TestCase("")] + public static void TestConstructorThrowsException(string sequence) + { + // Arrange - // Assert - act.Should().Throw(); - } + // Act + Action act = () => new BitArray(sequence); - #endregion CONSTRUCTOR TESTS + // Assert + act.Should().Throw(); + } - #region OPERATOR TESTS + #endregion CONSTRUCTOR TESTS - [TestCase(17, 17, "10001")] - [TestCase(25, 31, "11001")] - public static void TestOperatorAnd(int tObj1, int tObj2, string expected) - { - // Arrange - var testObj1 = new BitArray(5); - var testObj2 = new BitArray(5); + #region OPERATOR TESTS - // Act - testObj1.Compile(tObj1); - testObj2.Compile(tObj2); + [TestCase(17, 17, "10001")] + [TestCase(25, 31, "11001")] + public static void TestOperatorAnd(int tObj1, int tObj2, string expected) + { + // Arrange + var testObj1 = new BitArray(5); + var testObj2 = new BitArray(5); - var result = testObj1 & testObj2; + // Act + testObj1.Compile(tObj1); + testObj2.Compile(tObj2); - // Assert - Assert.AreEqual(expected, result.ToString()); - } + var result = testObj1 & testObj2; - [TestCase(1, 1, 1, 1, "0")] - [TestCase(5, 3, 8, 4, "1101")] - [TestCase(9, 4, 4, 3, "1101")] - public static void TestOperatorXorAndDiffSizes(int t1, int s1, int t2, int s2, string expected) - { - // Arrange - var testObj1 = new BitArray(s1); - var testObj2 = new BitArray(s2); + // Assert + Assert.AreEqual(expected, result.ToString()); + } - // Act - testObj1.Compile(t1); - testObj2.Compile(t2); - var result = testObj1 ^ testObj2; + [TestCase(1, 1, 1, 1, "0")] + [TestCase(5, 3, 8, 4, "1101")] + [TestCase(9, 4, 4, 3, "1101")] + public static void TestOperatorXorAndDiffSizes(int t1, int s1, int t2, int s2, string expected) + { + // Arrange + var testObj1 = new BitArray(s1); + var testObj2 = new BitArray(s2); - // Assert - Assert.AreEqual(expected, result.ToString()); - } + // Act + testObj1.Compile(t1); + testObj2.Compile(t2); + var result = testObj1 ^ testObj2; - [TestCase(9, 4, 4, 3, "1101")] - [TestCase(1, 1, 1, 1, "1")] - [TestCase(5, 3, 8, 4, "1101")] - public static void TestOperatorOrAndDiffSizes(int t1, int s1, int t2, int s2, string expected) - { - // Arrange - var testObj1 = new BitArray(s1); - var testObj2 = new BitArray(s2); + // Assert + Assert.AreEqual(expected, result.ToString()); + } - // Act - testObj1.Compile(t1); - testObj2.Compile(t2); - var result = testObj1 | testObj2; + [TestCase(9, 4, 4, 3, "1101")] + [TestCase(1, 1, 1, 1, "1")] + [TestCase(5, 3, 8, 4, "1101")] + public static void TestOperatorOrAndDiffSizes(int t1, int s1, int t2, int s2, string expected) + { + // Arrange + var testObj1 = new BitArray(s1); + var testObj2 = new BitArray(s2); - // Assert - Assert.AreEqual(expected, result.ToString()); - } + // Act + testObj1.Compile(t1); + testObj2.Compile(t2); + var result = testObj1 | testObj2; - [TestCase(1, 1, 1, 1, "1")] - [TestCase(5, 3, 8, 4, "0000")] - [TestCase(9, 4, 4, 3, "0000")] - public static void TestOperatorAndAndDiffSizes(int t1, int s1, int t2, int s2, string expected) - { - // Arrange - var testObj1 = new BitArray(s1); - var testObj2 = new BitArray(s2); + // Assert + Assert.AreEqual(expected, result.ToString()); + } - // Act - testObj1.Compile(t1); - testObj2.Compile(t2); - var result = testObj1 & testObj2; + [TestCase(1, 1, 1, 1, "1")] + [TestCase(5, 3, 8, 4, "0000")] + [TestCase(9, 4, 4, 3, "0000")] + public static void TestOperatorAndAndDiffSizes(int t1, int s1, int t2, int s2, string expected) + { + // Arrange + var testObj1 = new BitArray(s1); + var testObj2 = new BitArray(s2); - // Assert - Assert.AreEqual(expected, result.ToString()); - } + // Act + testObj1.Compile(t1); + testObj2.Compile(t2); + var result = testObj1 & testObj2; - [TestCase(25, 30, "11111")] - public static void TestOperatorOr(int tObj1, int tObj2, string expected) - { - // Arrange - var testObj1 = new BitArray(5); - var testObj2 = new BitArray(5); + // Assert + Assert.AreEqual(expected, result.ToString()); + } - // Act - testObj1.Compile(tObj1); - testObj2.Compile(tObj2); + [TestCase(25, 30, "11111")] + public static void TestOperatorOr(int tObj1, int tObj2, string expected) + { + // Arrange + var testObj1 = new BitArray(5); + var testObj2 = new BitArray(5); - var result = testObj1 | testObj2; + // Act + testObj1.Compile(tObj1); + testObj2.Compile(tObj2); - // Assert - Assert.AreEqual(expected, result.ToString()); - } + var result = testObj1 | testObj2; - [TestCase(16, "01111")] - public static void TestOperatorNot(int number, string expected) - { - // Arrange - var testObj = new BitArray(5); + // Assert + Assert.AreEqual(expected, result.ToString()); + } - // Act - testObj.Compile(number); - testObj = ~testObj; + [TestCase(16, "01111")] + public static void TestOperatorNot(int number, string expected) + { + // Arrange + var testObj = new BitArray(5); - // Assert - Assert.AreEqual(expected, testObj.ToString()); - } + // Act + testObj.Compile(number); + testObj = ~testObj; - [TestCase(25, 30, 7)] - public static void TestOperatorXor(int testNum, int testNum2, int expected) - { - // Arrange - var testObj1 = new BitArray(5); - var testObj2 = new BitArray(5); + // Assert + Assert.AreEqual(expected, testObj.ToString()); + } - // Act - testObj1.Compile(testNum); - testObj2.Compile(testNum2); + [TestCase(25, 30, 7)] + public static void TestOperatorXor(int testNum, int testNum2, int expected) + { + // Arrange + var testObj1 = new BitArray(5); + var testObj2 = new BitArray(5); - var result = testObj1 ^ testObj2; + // Act + testObj1.Compile(testNum); + testObj2.Compile(testNum2); - // Assert - Assert.AreEqual(expected, result.ToInt32()); - } + var result = testObj1 ^ testObj2; - [TestCase(16, "10000000")] - public static void TestOperatorShiftLeft(int number, string expected) - { - // Arrange - var testObj = new BitArray(5); + // Assert + Assert.AreEqual(expected, result.ToInt32()); + } - // Act - testObj.Compile(number); - testObj <<= 3; + [TestCase(16, "10000000")] + public static void TestOperatorShiftLeft(int number, string expected) + { + // Arrange + var testObj = new BitArray(5); - // Assert - Assert.AreEqual(expected, testObj.ToString()); - } + // Act + testObj.Compile(number); + testObj <<= 3; - [TestCase(24, "110")] - public static void TestOperatorShiftRight(int number, string expected) - { - // Arrange - var testObj = new BitArray(5); + // Assert + Assert.AreEqual(expected, testObj.ToString()); + } - // Act - testObj.Compile(number); - testObj >>= 2; + [TestCase(24, "110")] + public static void TestOperatorShiftRight(int number, string expected) + { + // Arrange + var testObj = new BitArray(5); - // Assert - Assert.AreEqual(expected, testObj.ToString()); - } + // Act + testObj.Compile(number); + testObj >>= 2; - #endregion OPERATOR TESTS + // Assert + Assert.AreEqual(expected, testObj.ToString()); + } - #region COMPARE TESTS + #endregion OPERATOR TESTS - [Test] - public static void TestParity() - { - // Arrange - var testObj = new BitArray(5); + #region COMPARE TESTS - // Act - testObj.Compile(26); + [Test] + public static void TestParity() + { + // Arrange + var testObj = new BitArray(5); - // Assert - Assert.IsFalse(testObj.EvenParity()); - Assert.IsTrue(testObj.OddParity()); - } + // Act + testObj.Compile(26); - [Test] - public static void TestCompare() - { - // Arrange - var testObj1 = new BitArray("110"); - var testObj2 = new BitArray("110"); - var testObj3 = new BitArray("100"); + // Assert + Assert.IsFalse(testObj.EvenParity()); + Assert.IsTrue(testObj.OddParity()); + } - // Act + [Test] + public static void TestCompare() + { + // Arrange + var testObj1 = new BitArray("110"); + var testObj2 = new BitArray("110"); + var testObj3 = new BitArray("100"); - // Assert - Assert.IsTrue(testObj1 == testObj2); - Assert.IsTrue(testObj1 != testObj3); - } + // Act - [Test] - public static void ArraysOfDifferentLengthsAreNotEqual() - { - // Arrange - var testObj1 = new BitArray("110"); - var testObj2 = new BitArray("10101"); + // Assert + Assert.IsTrue(testObj1 == testObj2); + Assert.IsTrue(testObj1 != testObj3); + } - // Act + [Test] + public static void ArraysOfDifferentLengthsAreNotEqual() + { + // Arrange + var testObj1 = new BitArray("110"); + var testObj2 = new BitArray("10101"); - // Assert - Assert.False(testObj1 == testObj2); - } + // Act - #endregion COMPARE TESTS + // Assert + Assert.False(testObj1 == testObj2); } + + #endregion COMPARE TESTS } diff --git a/DataStructures.Tests/Cache/LfuCacheTests.cs b/DataStructures.Tests/Cache/LfuCacheTests.cs index f349cead..f07112f8 100644 --- a/DataStructures.Tests/Cache/LfuCacheTests.cs +++ b/DataStructures.Tests/Cache/LfuCacheTests.cs @@ -1,78 +1,76 @@ -using System; using DataStructures.Cache; -using NUnit.Framework; using FluentAssertions; +using NUnit.Framework; -namespace DataStructures.Tests.Cache +namespace DataStructures.Tests.Cache; + +public static class LfuCacheTests { - public static class LfuCacheTests + [Test] + public static void TestPutGet() + { + var cache = new LfuCache(); + cache.Put(1, "one"); + + cache.Contains(1).Should().BeTrue(); + cache.Get(1).Should().Be("one"); + } + + [Test] + public static void TestCacheMiss() { - [Test] - public static void TestPutGet() - { - var cache = new LfuCache(); - cache.Put(1, "one"); - - cache.Contains(1).Should().BeTrue(); - cache.Get(1).Should().Be("one"); - } - - [Test] - public static void TestCacheMiss() - { - var cache = new LfuCache(); - cache.Put(1, "one"); - - cache.Contains(5).Should().BeFalse(); - cache.Get(5).Should().BeNull(); - } - - [Test] - public static void Evict_ItemWasNotUsed() - { - var cache = new LfuCache(capacity: 1); - cache.Put(1, "one"); - - // Add to the full cache, 1 will be removed - cache.Put(2, "two"); - - cache.Get(1).Should().BeNull(); - cache.Get(2).Should().Be("two"); - } - - [Test] - public static void Evict_OneItemWasUsed() - { - var cache = new LfuCache(capacity: 2); - cache.Put(1, "one"); - cache.Put(2, "two"); - - cache.Put(1, "ONE"); - - // Add to the full cache, 2 will be removed - cache.Put(3, "three"); - - cache.Get(1).Should().Be("ONE"); - cache.Get(2).Should().BeNull(); - cache.Get(3).Should().Be("three"); - } - - [Test] - public static void Evict_LruOrder() - { - var cache = new LfuCache(capacity: 2); - cache.Put(1, "one"); - cache.Put(2, "two"); - - cache.Put(1, "ONE"); - cache.Put(2, "TWO"); - - // Add to the full cache, 1 will be removed - cache.Put(3, "three"); - - cache.Get(1).Should().BeNull(); - cache.Get(2).Should().Be("TWO"); - cache.Get(3).Should().Be("three"); - } + var cache = new LfuCache(); + cache.Put(1, "one"); + + cache.Contains(5).Should().BeFalse(); + cache.Get(5).Should().BeNull(); + } + + [Test] + public static void Evict_ItemWasNotUsed() + { + var cache = new LfuCache(capacity: 1); + cache.Put(1, "one"); + + // Add to the full cache, 1 will be removed + cache.Put(2, "two"); + + cache.Get(1).Should().BeNull(); + cache.Get(2).Should().Be("two"); + } + + [Test] + public static void Evict_OneItemWasUsed() + { + var cache = new LfuCache(capacity: 2); + cache.Put(1, "one"); + cache.Put(2, "two"); + + cache.Put(1, "ONE"); + + // Add to the full cache, 2 will be removed + cache.Put(3, "three"); + + cache.Get(1).Should().Be("ONE"); + cache.Get(2).Should().BeNull(); + cache.Get(3).Should().Be("three"); + } + + [Test] + public static void Evict_LruOrder() + { + var cache = new LfuCache(capacity: 2); + cache.Put(1, "one"); + cache.Put(2, "two"); + + cache.Put(1, "ONE"); + cache.Put(2, "TWO"); + + // Add to the full cache, 1 will be removed + cache.Put(3, "three"); + + cache.Get(1).Should().BeNull(); + cache.Get(2).Should().Be("TWO"); + cache.Get(3).Should().Be("three"); } } diff --git a/DataStructures.Tests/Cache/LruCacheTests.cs b/DataStructures.Tests/Cache/LruCacheTests.cs index e39434d9..20eaec19 100644 --- a/DataStructures.Tests/Cache/LruCacheTests.cs +++ b/DataStructures.Tests/Cache/LruCacheTests.cs @@ -1,71 +1,69 @@ -using System; using DataStructures.Cache; -using NUnit.Framework; using FluentAssertions; +using NUnit.Framework; + +namespace DataStructures.Tests.Cache; -namespace DataStructures.Tests.Cache +public static class LruCacheTests { - public static class LruCacheTests + [Test] + public static void TestPutGet() { - [Test] - public static void TestPutGet() - { - var cache = new LruCache(); - cache.Put(1, "one"); + var cache = new LruCache(); + cache.Put(1, "one"); - cache.Contains(1).Should().BeTrue(); - cache.Get(1).Should().Be("one"); - } + cache.Contains(1).Should().BeTrue(); + cache.Get(1).Should().Be("one"); + } - [Test] - public static void TestCacheMiss() - { - var cache = new LruCache(); - cache.Put(1, "one"); + [Test] + public static void TestCacheMiss() + { + var cache = new LruCache(); + cache.Put(1, "one"); - cache.Contains(5).Should().BeFalse(); - cache.Get(5).Should().BeNull(); - } + cache.Contains(5).Should().BeFalse(); + cache.Get(5).Should().BeNull(); + } - [Test] - public static void TestCacheUpdate() - { - var cache = new LruCache(); - cache.Put(1, "one"); - cache.Put(1, "ONE"); + [Test] + public static void TestCacheUpdate() + { + var cache = new LruCache(); + cache.Put(1, "one"); + cache.Put(1, "ONE"); - cache.Get(1).Should().Be("ONE"); - } + cache.Get(1).Should().Be("ONE"); + } - [Test] - public static void RemoveOldestItem_ItemWasNotUsed() - { - var cache = new LruCache(capacity: 2); - cache.Put(1, "one"); - cache.Put(2, "two"); + [Test] + public static void RemoveOldestItem_ItemWasNotUsed() + { + var cache = new LruCache(capacity: 2); + cache.Put(1, "one"); + cache.Put(2, "two"); - // Add to the full cache, 1 will be removed - cache.Put(3, "three"); + // Add to the full cache, 1 will be removed + cache.Put(3, "three"); - cache.Get(1).Should().BeNull(); - cache.Get(2).Should().Be("two"); - cache.Get(3).Should().Be("three"); - } + cache.Get(1).Should().BeNull(); + cache.Get(2).Should().Be("two"); + cache.Get(3).Should().Be("three"); + } - [Test] - public static void RemoveOldestItem_ItemWasRecentlyUsed() - { - var cache = new LruCache(capacity: 2); - cache.Put(1, "one"); - cache.Put(2, "two"); - cache.Get(1); + [Test] + public static void RemoveOldestItem_ItemWasRecentlyUsed() + { + var cache = new LruCache(capacity: 2); + cache.Put(1, "one"); + cache.Put(2, "two"); + cache.Get(1); - // Add to the full cache, 1 was used, 2 should be removed - cache.Put(3, "three"); + // Add to the full cache, 1 was used, 2 should be removed + cache.Put(3, "three"); - cache.Get(1).Should().Be("one"); - cache.Get(2).Should().BeNull(); - cache.Get(3).Should().Be("three"); - } + cache.Get(1).Should().Be("one"); + cache.Get(2).Should().BeNull(); + cache.Get(3).Should().Be("three"); } -} \ No newline at end of file +} diff --git a/DataStructures.Tests/DisjointSet/DisjointSetTests.cs b/DataStructures.Tests/DisjointSet/DisjointSetTests.cs index 28ed521f..1a9a07f9 100644 --- a/DataStructures.Tests/DisjointSet/DisjointSetTests.cs +++ b/DataStructures.Tests/DisjointSet/DisjointSetTests.cs @@ -1,33 +1,32 @@ -using DataStructures.DisjointSet; +using DataStructures.DisjointSet; using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests.DisjointSet +namespace DataStructures.Tests.DisjointSet; + +[TestFixture] +public class DisjointSetTests { - [TestFixture] - public class DisjointSetTests + [Test] + public static void MakeSetDataInitializationTest() + { + DisjointSet ds = new(); + var one = ds.MakeSet(1); + var two = ds.MakeSet(2); + one.Data.Should().Be(1); + two.Data.Should().Be(2); + } + [Test] + public static void UnionTest() { - [Test] - public static void MakeSetDataInitializationTest() - { - DisjointSet ds = new(); - var one = ds.MakeSet(1); - var two = ds.MakeSet(2); - one.Data.Should().Be(1); - two.Data.Should().Be(2); - } - [Test] - public static void UnionTest() - { - DisjointSet ds = new(); - var one = ds.MakeSet(1); - var two = ds.MakeSet(2); - var three = ds.MakeSet(3); - ds.UnionSet(one, two); - ds.FindSet(one).Should().Be(ds.FindSet(two)); - ds.UnionSet(one, three); - ds.FindSet(two).Should().Be(ds.FindSet(three)); - (one.Rank + two.Rank + three.Rank).Should().Be(1); - } + DisjointSet ds = new(); + var one = ds.MakeSet(1); + var two = ds.MakeSet(2); + var three = ds.MakeSet(3); + ds.UnionSet(one, two); + ds.FindSet(one).Should().Be(ds.FindSet(two)); + ds.UnionSet(one, three); + ds.FindSet(two).Should().Be(ds.FindSet(three)); + (one.Rank + two.Rank + three.Rank).Should().Be(1); } } diff --git a/DataStructures.Tests/Fenwick/BinaryIndexedTreeTests.cs b/DataStructures.Tests/Fenwick/BinaryIndexedTreeTests.cs index cb8dbe9e..7de8a8b9 100644 --- a/DataStructures.Tests/Fenwick/BinaryIndexedTreeTests.cs +++ b/DataStructures.Tests/Fenwick/BinaryIndexedTreeTests.cs @@ -1,37 +1,35 @@ using DataStructures.Fenwick; -using NUnit.Framework; using FluentAssertions; -using System; +using NUnit.Framework; + +namespace DataStructures.Tests.Fenwick; -namespace DataStructures.Tests.Fenwick +[TestFixture] +internal class BinaryIndexedTreeTests { - [TestFixture] - internal class BinaryIndexedTreeTests + [Test] + public void GetSum_CreateBITAndRequestSum_ReturnCorrect() { - [Test] - public void GetSum_CreateBITAndRequestSum_ReturnCorrect() - { - int[] array = { 2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9 }; - var tree = new BinaryIndexedTree(array); - var expectedSum = 12; + int[] array = { 2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9 }; + var tree = new BinaryIndexedTree(array); + var expectedSum = 12; - var resultedSum = tree.GetSum(5); + var resultedSum = tree.GetSum(5); - resultedSum.Should().Be(expectedSum); - } + resultedSum.Should().Be(expectedSum); + } - [Test] - public void UpdateTree_UpdateTreeAndRequestSum_GetSum() - { - int[] array = { 2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9 }; - var tree = new BinaryIndexedTree(array); - var expectedSum = 18; + [Test] + public void UpdateTree_UpdateTreeAndRequestSum_GetSum() + { + int[] array = { 2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9 }; + var tree = new BinaryIndexedTree(array); + var expectedSum = 18; - array[3] += 6; - tree.UpdateTree(3, 6); + array[3] += 6; + tree.UpdateTree(3, 6); - var resultedSum = tree.GetSum(5); - resultedSum.Should().Be(expectedSum); - } + var resultedSum = tree.GetSum(5); + resultedSum.Should().Be(expectedSum); } } diff --git a/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs b/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs index 41a582d7..182c2d10 100644 --- a/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs +++ b/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs @@ -1,217 +1,216 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using DataStructures.Graph; using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests.Graph +namespace DataStructures.Tests.Graph; + +[TestFixture] +public class DirectedWeightedGraphTests { - [TestFixture] - public class DirectedWeightedGraphTests + [Test] + [TestCase(-1)] + [TestCase(-2)] + [TestCase(-3)] + public void GraphInitializationTest_ShouldThrowOverflow(int capacity) { - [Test] - [TestCase(-1)] - [TestCase(-2)] - [TestCase(-3)] - public void GraphInitializationTest_ShouldThrowOverflow(int capacity) - { - Func> createGraph = () => new DirectedWeightedGraph(capacity); + Func> createGraph = () => new DirectedWeightedGraph(capacity); - createGraph.Should().Throw() - .WithMessage("Graph capacity should always be a non-negative integer."); - } + createGraph.Should().Throw() + .WithMessage("Graph capacity should always be a non-negative integer."); + } - [Test] - [TestCase(1)] - [TestCase(10)] - [TestCase(20)] - [TestCase(30)] - public void GraphInitializationTest_Success(int capacity) - { - Func> createGraph = () => new DirectedWeightedGraph(capacity); + [Test] + [TestCase(1)] + [TestCase(10)] + [TestCase(20)] + [TestCase(30)] + public void GraphInitializationTest_Success(int capacity) + { + Func> createGraph = () => new DirectedWeightedGraph(capacity); - createGraph.Should().NotThrow(); - } + createGraph.Should().NotThrow(); + } - [Test] - public void GraphAddVertexTest_Success() - { - var graph = new DirectedWeightedGraph(10); + [Test] + public void GraphAddVertexTest_Success() + { + var graph = new DirectedWeightedGraph(10); - graph.AddVertex('A'); - graph.AddVertex('B'); - graph.AddVertex('C'); + graph.AddVertex('A'); + graph.AddVertex('B'); + graph.AddVertex('C'); - graph.Count.Should().Be(3); - } + graph.Count.Should().Be(3); + } - [Test] - public void GraphAddVertexTest_ShouldThrowOverflow() + [Test] + public void GraphAddVertexTest_ShouldThrowOverflow() + { + var graph = new DirectedWeightedGraph(10); + for (var i = 0; i < 10; i++) { - var graph = new DirectedWeightedGraph(10); - for (var i = 0; i < 10; i++) - { - graph.AddVertex('A'); - } - - Action addOverflow = () => graph.AddVertex('A'); - - graph.Count.Should().Be(10); - graph.Vertices.Should().OnlyContain(x => x != null && x.Data == 'A'); - addOverflow.Should().Throw() - .WithMessage("Graph overflow."); + graph.AddVertex('A'); } - [Test] - public void GraphRemoveVertexTest_Success() - { - var graph = new DirectedWeightedGraph(10); - var vertexA = graph.AddVertex('A'); - var vertexB = graph.AddVertex('B'); - var vertexC = graph.AddVertex('C'); - graph.AddEdge(vertexB, vertexA, 5); - graph.AddEdge(vertexC, vertexA, 5); - var neighborsB = graph.GetNeighbors(vertexB).ToList(); - var neighborsC = graph.GetNeighbors(vertexC).ToList(); - - graph.RemoveVertex(vertexA); - - neighborsB.Should().HaveCount(1); - neighborsB[0].Should().Be(vertexA); - neighborsC.Should().HaveCount(1); - neighborsC[0].Should().Be(vertexA); - graph.GetNeighbors(vertexB).Should().HaveCount(0); - graph.GetNeighbors(vertexC).Should().HaveCount(0); - } + Action addOverflow = () => graph.AddVertex('A'); - [Test] - public void GraphRemoveVertexTest_ShouldThrowVertexNotInGraph() - { - var graph = new DirectedWeightedGraph(10); - var vertexA = new Vertex('A', 0); + graph.Count.Should().Be(10); + graph.Vertices.Should().OnlyContain(x => x != null && x.Data == 'A'); + addOverflow.Should().Throw() + .WithMessage("Graph overflow."); + } - Action removeVertex = () => graph.RemoveVertex(vertexA); + [Test] + public void GraphRemoveVertexTest_Success() + { + var graph = new DirectedWeightedGraph(10); + var vertexA = graph.AddVertex('A'); + var vertexB = graph.AddVertex('B'); + var vertexC = graph.AddVertex('C'); + graph.AddEdge(vertexB, vertexA, 5); + graph.AddEdge(vertexC, vertexA, 5); + var neighborsB = graph.GetNeighbors(vertexB).ToList(); + var neighborsC = graph.GetNeighbors(vertexC).ToList(); + + graph.RemoveVertex(vertexA); + + neighborsB.Should().HaveCount(1); + neighborsB[0].Should().Be(vertexA); + neighborsC.Should().HaveCount(1); + neighborsC[0].Should().Be(vertexA); + graph.GetNeighbors(vertexB).Should().HaveCount(0); + graph.GetNeighbors(vertexC).Should().HaveCount(0); + } - removeVertex.Should().Throw() - .WithMessage($"Vertex does not belong to graph: {vertexA}."); - } + [Test] + public void GraphRemoveVertexTest_ShouldThrowVertexNotInGraph() + { + var graph = new DirectedWeightedGraph(10); + var vertexA = new Vertex('A', 0); - [Test] - public void GraphAddEdgeTest_Success() - { - var graph = new DirectedWeightedGraph(10); - var vertexA = graph.AddVertex('A'); - var vertexB = graph.AddVertex('B'); - var vertexC = graph.AddVertex('C'); + Action removeVertex = () => graph.RemoveVertex(vertexA); - graph.AddEdge(vertexA, vertexB, 5); + removeVertex.Should().Throw() + .WithMessage($"Vertex does not belong to graph: {vertexA}."); + } - graph.AreAdjacent(vertexA, vertexB).Should().BeTrue(); - graph.AreAdjacent(vertexA, vertexC).Should().BeFalse(); - } + [Test] + public void GraphAddEdgeTest_Success() + { + var graph = new DirectedWeightedGraph(10); + var vertexA = graph.AddVertex('A'); + var vertexB = graph.AddVertex('B'); + var vertexC = graph.AddVertex('C'); - [Test] - public void GraphAddEdgeTest_ShouldThrowZeroWeight() - { - var graph = new DirectedWeightedGraph(10); - var vertexA = graph.AddVertex('A'); - var vertexB = graph.AddVertex('B'); + graph.AddEdge(vertexA, vertexB, 5); + + graph.AreAdjacent(vertexA, vertexB).Should().BeTrue(); + graph.AreAdjacent(vertexA, vertexC).Should().BeFalse(); + } - Action addZeroEdge = () => graph.AddEdge(vertexA, vertexB, 0); + [Test] + public void GraphAddEdgeTest_ShouldThrowZeroWeight() + { + var graph = new DirectedWeightedGraph(10); + var vertexA = graph.AddVertex('A'); + var vertexB = graph.AddVertex('B'); - addZeroEdge.Should().Throw() - .WithMessage("Edge weight cannot be zero."); - } + Action addZeroEdge = () => graph.AddEdge(vertexA, vertexB, 0); - [Test] - public void GraphAddEdgeTest_ShouldThrowVertexNotInGraph() - { - var graph = new DirectedWeightedGraph(10); - var vertexA = graph.AddVertex('A'); - var vertexB = new Vertex('B', 1); + addZeroEdge.Should().Throw() + .WithMessage("Edge weight cannot be zero."); + } - Action addZeroEdge = () => graph.AddEdge(vertexA, vertexB, 0); + [Test] + public void GraphAddEdgeTest_ShouldThrowVertexNotInGraph() + { + var graph = new DirectedWeightedGraph(10); + var vertexA = graph.AddVertex('A'); + var vertexB = new Vertex('B', 1); - addZeroEdge.Should().Throw() - .WithMessage($"Vertex does not belong to graph: {vertexB}."); - } + Action addZeroEdge = () => graph.AddEdge(vertexA, vertexB, 0); - [Test] - public void GraphAddEdgeTest_ShouldThrowEdgeExists() - { - var graph = new DirectedWeightedGraph(10); - var vertexA = graph.AddVertex('A'); - var vertexB = graph.AddVertex('B'); - const int currentEdgeWeight = 5; - graph.AddEdge(vertexA, vertexB, currentEdgeWeight); + addZeroEdge.Should().Throw() + .WithMessage($"Vertex does not belong to graph: {vertexB}."); + } - Action addZeroEdge = () => graph.AddEdge(vertexA, vertexB, 10); + [Test] + public void GraphAddEdgeTest_ShouldThrowEdgeExists() + { + var graph = new DirectedWeightedGraph(10); + var vertexA = graph.AddVertex('A'); + var vertexB = graph.AddVertex('B'); + const int currentEdgeWeight = 5; + graph.AddEdge(vertexA, vertexB, currentEdgeWeight); - addZeroEdge.Should().Throw() - .WithMessage($"Vertex already exists: {currentEdgeWeight}"); - } + Action addZeroEdge = () => graph.AddEdge(vertexA, vertexB, 10); - [Test] - public void GraphRemoveEdgeTest_Success() - { - var graph = new DirectedWeightedGraph(10); - var vertexA = graph.AddVertex('A'); - var vertexB = graph.AddVertex('B'); - graph.AddEdge(vertexA, vertexB, 5); + addZeroEdge.Should().Throw() + .WithMessage($"Vertex already exists: {currentEdgeWeight}"); + } - graph.RemoveEdge(vertexA, vertexB); + [Test] + public void GraphRemoveEdgeTest_Success() + { + var graph = new DirectedWeightedGraph(10); + var vertexA = graph.AddVertex('A'); + var vertexB = graph.AddVertex('B'); + graph.AddEdge(vertexA, vertexB, 5); - graph.AreAdjacent(vertexA, vertexB).Should().BeFalse(); - } + graph.RemoveEdge(vertexA, vertexB); - [Test] - public void GraphRemoveEdgeTest_ShouldThrowVertexNotInGraph() - { - var graph = new DirectedWeightedGraph(10); - var vertexA = graph.AddVertex('A'); - var vertexB = new Vertex('B', 1); + graph.AreAdjacent(vertexA, vertexB).Should().BeFalse(); + } - Action removeEdge = () => graph.RemoveEdge(vertexA, vertexB); + [Test] + public void GraphRemoveEdgeTest_ShouldThrowVertexNotInGraph() + { + var graph = new DirectedWeightedGraph(10); + var vertexA = graph.AddVertex('A'); + var vertexB = new Vertex('B', 1); - removeEdge.Should().Throw() - .WithMessage($"Vertex does not belong to graph: {vertexB}."); - } + Action removeEdge = () => graph.RemoveEdge(vertexA, vertexB); - [Test] - public void GraphGetNeighborsTest_Success() - { - var graph = new DirectedWeightedGraph(10); - var vertexA = graph.AddVertex('A'); - var vertexB = graph.AddVertex('B'); - var vertexC = graph.AddVertex('C'); - var vertexD = graph.AddVertex('D'); - graph.AddEdge(vertexA, vertexB, 5); - graph.AddEdge(vertexA, vertexC, 5); - graph.AddEdge(vertexA, vertexD, 5); - - var neighborsA = graph.GetNeighbors(vertexA).ToArray(); - - neighborsA.Should().HaveCount(3); - neighborsA[0].Should().Be(vertexB); - neighborsA[1].Should().Be(vertexC); - neighborsA[2].Should().Be(vertexD); - } + removeEdge.Should().Throw() + .WithMessage($"Vertex does not belong to graph: {vertexB}."); + } - [Test] - public void GraphGetNeighborsTest_ShouldThrowVertexNotInGraph() - { - var graph = new DirectedWeightedGraph(10); - var vertexA = new Vertex('A', 0); + [Test] + public void GraphGetNeighborsTest_Success() + { + var graph = new DirectedWeightedGraph(10); + var vertexA = graph.AddVertex('A'); + var vertexB = graph.AddVertex('B'); + var vertexC = graph.AddVertex('C'); + var vertexD = graph.AddVertex('D'); + graph.AddEdge(vertexA, vertexB, 5); + graph.AddEdge(vertexA, vertexC, 5); + graph.AddEdge(vertexA, vertexD, 5); + + var neighborsA = graph.GetNeighbors(vertexA).ToArray(); + + neighborsA.Should().HaveCount(3); + neighborsA[0].Should().Be(vertexB); + neighborsA[1].Should().Be(vertexC); + neighborsA[2].Should().Be(vertexD); + } - Func?>> getNeighbors = () => - { - var enumerable = graph.GetNeighbors(vertexA); - return enumerable.ToList(); - }; + [Test] + public void GraphGetNeighborsTest_ShouldThrowVertexNotInGraph() + { + var graph = new DirectedWeightedGraph(10); + var vertexA = new Vertex('A', 0); - getNeighbors.Should().Throw() - .WithMessage($"Vertex does not belong to graph: {vertexA}."); - } + Func?>> getNeighbors = () => + { + var enumerable = graph.GetNeighbors(vertexA); + return enumerable.ToList(); + }; + + getNeighbors.Should().Throw() + .WithMessage($"Vertex does not belong to graph: {vertexA}."); } } diff --git a/DataStructures.Tests/Hashing/HashTableTests.cs b/DataStructures.Tests/Hashing/HashTableTests.cs index ede5c14b..786d2770 100644 --- a/DataStructures.Tests/Hashing/HashTableTests.cs +++ b/DataStructures.Tests/Hashing/HashTableTests.cs @@ -3,383 +3,382 @@ using DataStructures.Hashing; using NUnit.Framework; -namespace DataStructures.Tests.Hashing +namespace DataStructures.Tests.Hashing; + +[TestFixture] +public class HashTableTests { - [TestFixture] - public class HashTableTests + [Test] + public void Add_ThrowsException_WhenKeyIsNull() { - [Test] - public void Add_ThrowsException_WhenKeyIsNull() - { - var hashTable = new HashTable(); + var hashTable = new HashTable(); - Assert.Throws(() => hashTable.Add(null, 1)); - } + Assert.Throws(() => hashTable.Add(null, 1)); + } - [Test] - public void Add_ThrowsException_WhenKeyAlreadyExists() - { - var hashTable = new HashTable(); + [Test] + public void Add_ThrowsException_WhenKeyAlreadyExists() + { + var hashTable = new HashTable(); - hashTable.Add("a", 1); + hashTable.Add("a", 1); - Assert.Throws(() => hashTable.Add("a", 2)); - } + Assert.Throws(() => hashTable.Add("a", 2)); + } - [Test] - public void Add_IncreasesCount_WhenKeyDoesNotExist() - { - var hashTable = new HashTable(); + [Test] + public void Add_IncreasesCount_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(); - hashTable.Add("a", 1); + hashTable.Add("a", 1); - Assert.AreEqual(1, hashTable.Count); - } + Assert.AreEqual(1, hashTable.Count); + } - [Test] - public void Add_DoesNotIncreaseCount_WhenKeyAlreadyExists() + [Test] + public void Add_DoesNotIncreaseCount_WhenKeyAlreadyExists() + { + var hashTable = new HashTable(); + + hashTable.Add("a", 1); + try { - var hashTable = new HashTable(); - - hashTable.Add("a", 1); - try - { - hashTable.Add("a", 2); - } - catch (ArgumentException) - { - Console.WriteLine("ArgumentException"); - } - Assert.AreEqual(1, hashTable.Count); + hashTable.Add("a", 2); } - - [Test] - public void Add_ThrowsException_WhenValueIsNull() + catch (ArgumentException) { - var hashTable = new HashTable(); - - Assert.Throws(() => hashTable.Add("a", null)); + Console.WriteLine("ArgumentException"); } + Assert.AreEqual(1, hashTable.Count); + } - [Test] - public void Add_IncreasesCount_WhenValueDoesNotExist() - { - var hashTable = new HashTable(); + [Test] + public void Add_ThrowsException_WhenValueIsNull() + { + var hashTable = new HashTable(); - hashTable.Add("a", 1); + Assert.Throws(() => hashTable.Add("a", null)); + } - Assert.AreEqual(1, hashTable.Count); - } + [Test] + public void Add_IncreasesCount_WhenValueDoesNotExist() + { + var hashTable = new HashTable(); - [Test] - public void Add_DoesNotIncreaseCount_WhenValueAlreadyExists() - { - var hashTable = new HashTable(); + hashTable.Add("a", 1); - hashTable.Add("a", 1); + Assert.AreEqual(1, hashTable.Count); + } - try - { - hashTable.Add("b", 1); - } - catch (ArgumentException) - { - Console.WriteLine("ArgumentException"); - } + [Test] + public void Add_DoesNotIncreaseCount_WhenValueAlreadyExists() + { + var hashTable = new HashTable(); - Assert.AreEqual(2, hashTable.Count); - } + hashTable.Add("a", 1); - [Test] - public void Add_IncreasesCount_WhenValueIsNull() + try { - var hashTable = new HashTable(); - - try - { - hashTable.Add("a", null); - } - catch (ArgumentNullException) - { - Console.WriteLine("ArgumentNullException"); - } - Assert.AreEqual(0, hashTable.Count); + hashTable.Add("b", 1); } - - [Test] - public void Add_IncreasesCount_WhenValueAlreadyExists() + catch (ArgumentException) { - var hashTable = new HashTable(); - - hashTable.Add("a", 1); - hashTable.Add("b", 1); - Assert.AreEqual(2, hashTable.Count); + Console.WriteLine("ArgumentException"); } - [Test] - public void Remove_ThrowsException_WhenKeyIsNull() - { - var hashTable = new HashTable(); + Assert.AreEqual(2, hashTable.Count); + } - Assert.Throws(() => hashTable.Remove(null)); - } + [Test] + public void Add_IncreasesCount_WhenValueIsNull() + { + var hashTable = new HashTable(); - [Test] - public void Remove_ReturnsFalse_WhenKeyDoesNotExist() + try { - var hashTable = new HashTable(); - - Assert.IsFalse(hashTable.Remove("a")); + hashTable.Add("a", null); } - - [Test] - public void Remove_ReturnsTrue_WhenKeyExists() + catch (ArgumentNullException) { - var hashTable = new HashTable(); + Console.WriteLine("ArgumentNullException"); + } + Assert.AreEqual(0, hashTable.Count); + } - hashTable.Add("a", 1); + [Test] + public void Add_IncreasesCount_WhenValueAlreadyExists() + { + var hashTable = new HashTable(); - Assert.IsTrue(hashTable.Remove("a")); - } + hashTable.Add("a", 1); + hashTable.Add("b", 1); + Assert.AreEqual(2, hashTable.Count); + } - [Test] - public void Remove_DecreasesCount_WhenKeyExists() - { - var hashTable = new HashTable(); + [Test] + public void Remove_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(); - hashTable.Add("a", 1); - hashTable.Remove("a"); + Assert.Throws(() => hashTable.Remove(null)); + } - Assert.AreEqual(0, hashTable.Count); - } + [Test] + public void Remove_ReturnsFalse_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(); - [Test] - public void Remove_DoesNotDecreaseCount_WhenKeyDoesNotExist() - { - var hashTable = new HashTable(); + Assert.IsFalse(hashTable.Remove("a")); + } - hashTable.Remove("a"); + [Test] + public void Remove_ReturnsTrue_WhenKeyExists() + { + var hashTable = new HashTable(); - Assert.AreEqual(0, hashTable.Count); - } + hashTable.Add("a", 1); - [Test] - public void ContainsValue_ReturnsFalse_WhenValueDoesNotExist() - { - var hashTable = new HashTable(); + Assert.IsTrue(hashTable.Remove("a")); + } - Assert.IsFalse(hashTable.ContainsValue(1)); - } + [Test] + public void Remove_DecreasesCount_WhenKeyExists() + { + var hashTable = new HashTable(); - [Test] - public void ContainsValue_ReturnsTrue_WhenValueExists() - { - var hashTable = new HashTable(); + hashTable.Add("a", 1); + hashTable.Remove("a"); - hashTable.Add("a", 1); + Assert.AreEqual(0, hashTable.Count); + } - Assert.IsTrue(hashTable.ContainsValue(1)); - } + [Test] + public void Remove_DoesNotDecreaseCount_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(); - [Test] - public void ContainsValue_ReturnsFalse_WhenValueIsNull() - { - var hashTable = new HashTable(); + hashTable.Remove("a"); - Assert.Throws(() => hashTable.ContainsValue(null)); - } + Assert.AreEqual(0, hashTable.Count); + } - [Test] - public void ContainsKey_ReturnsFalse_WhenKeyDoesNotExist() - { - var hashTable = new HashTable(); + [Test] + public void ContainsValue_ReturnsFalse_WhenValueDoesNotExist() + { + var hashTable = new HashTable(); - Assert.IsFalse(hashTable.ContainsKey("a")); - } + Assert.IsFalse(hashTable.ContainsValue(1)); + } - [Test] - public void ContainsKey_ReturnsTrue_WhenKeyExists() - { - var hashTable = new HashTable(); + [Test] + public void ContainsValue_ReturnsTrue_WhenValueExists() + { + var hashTable = new HashTable(); - hashTable.Add("a", 1); + hashTable.Add("a", 1); - Assert.IsTrue(hashTable.ContainsKey("a")); - } + Assert.IsTrue(hashTable.ContainsValue(1)); + } - [Test] - public void ContainsKey_ReturnsFalse_WhenKeyIsNull() - { - var hashTable = new HashTable(); + [Test] + public void ContainsValue_ReturnsFalse_WhenValueIsNull() + { + var hashTable = new HashTable(); - Assert.Throws(() => hashTable.ContainsKey(null)); - } + Assert.Throws(() => hashTable.ContainsValue(null)); + } - [Test] - public void Clear_SetsCountToZero() - { - var hashTable = new HashTable(); + [Test] + public void ContainsKey_ReturnsFalse_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(); - hashTable.Add("a", 1); - hashTable.Clear(); + Assert.IsFalse(hashTable.ContainsKey("a")); + } - Assert.AreEqual(0, hashTable.Count); - } + [Test] + public void ContainsKey_ReturnsTrue_WhenKeyExists() + { + var hashTable = new HashTable(); - [Test] - public void Clear_RemovesAllElements() - { - var hashTable = new HashTable(); + hashTable.Add("a", 1); - hashTable.Add("a", 1); - hashTable.Clear(); + Assert.IsTrue(hashTable.ContainsKey("a")); + } - Assert.IsFalse(hashTable.ContainsKey("a")); - } + [Test] + public void ContainsKey_ReturnsFalse_WhenKeyIsNull() + { + var hashTable = new HashTable(); - [Test] - public void Resize_IncreasesCapacity() - { - var hashTable = new HashTable(4); - - hashTable.Add("one", 1); - hashTable.Add("two", 2); - hashTable.Add("three", 3); - hashTable.Add("four", 4); - hashTable.Add("humour", 5); - - /// Next Prime number after 4 is 5 - /// Capacity should be 5 - /// After resizing, the capacity should be 10 - Assert.AreEqual(10, hashTable.Capacity); - } - [Test] - public void LoadFactor_ReturnsCorrectValue() - { - var hashTable = new HashTable(4); - - hashTable.Add("one", 1); - hashTable.Add("two", 2); - hashTable.Add("three", 3); - hashTable.Add("four", 4); - hashTable.Add("humour", 5); - Assert.AreEqual(0.75f, hashTable.LoadFactor); - } + Assert.Throws(() => hashTable.ContainsKey(null)); + } - [Test] - public void Keys_ReturnsCorrectKeys() - { - var hashTable = new HashTable(); - hashTable.Add(1, "one"); - hashTable.Add(2, "two"); - hashTable.Add(3, "three"); + [Test] + public void Clear_SetsCountToZero() + { + var hashTable = new HashTable(); - var keys = new List { 1,2,3 }; + hashTable.Add("a", 1); + hashTable.Clear(); - CollectionAssert.AreEquivalent(keys, hashTable.Keys); - } + Assert.AreEqual(0, hashTable.Count); + } - [Test] - public void Values_ReturnsCorrectValues() - { - var hashTable = new HashTable(); - hashTable.Add(1, "one"); - hashTable.Add(2, "two"); - hashTable.Add(3, "three"); + [Test] + public void Clear_RemovesAllElements() + { + var hashTable = new HashTable(); - var values = new List { "one", "two", "three" }; + hashTable.Add("a", 1); + hashTable.Clear(); - CollectionAssert.AreEquivalent(values, hashTable?.Values); - } + Assert.IsFalse(hashTable.ContainsKey("a")); + } - [Test] - public void Constructor_ThrowsException_WhenCapacityIsZero() - { - Assert.Throws(() => new HashTable(0)); - } + [Test] + public void Resize_IncreasesCapacity() + { + var hashTable = new HashTable(4); + + hashTable.Add("one", 1); + hashTable.Add("two", 2); + hashTable.Add("three", 3); + hashTable.Add("four", 4); + hashTable.Add("humour", 5); + + /// Next Prime number after 4 is 5 + /// Capacity should be 5 + /// After resizing, the capacity should be 10 + Assert.AreEqual(10, hashTable.Capacity); + } + [Test] + public void LoadFactor_ReturnsCorrectValue() + { + var hashTable = new HashTable(4); + + hashTable.Add("one", 1); + hashTable.Add("two", 2); + hashTable.Add("three", 3); + hashTable.Add("four", 4); + hashTable.Add("humour", 5); + Assert.AreEqual(0.75f, hashTable.LoadFactor); + } - [Test] - public void Constructor_ThrowsException_WhenLoadFactorIsZero() - { - Assert.Throws(() => new HashTable(4, 0)); - } + [Test] + public void Keys_ReturnsCorrectKeys() + { + var hashTable = new HashTable(); + hashTable.Add(1, "one"); + hashTable.Add(2, "two"); + hashTable.Add(3, "three"); - [Test] - public void Constructor_ThrowsException_WhenLoadFactorIsLessThanZero() - { - Assert.Throws(() => new HashTable(4, -1)); - } + var keys = new List { 1,2,3 }; - [Test] - public void Constructor_ThrowsException_WhenLoadFactorIsGreaterThanOne() - { - Assert.Throws(() => new HashTable(4, 2)); - } + CollectionAssert.AreEquivalent(keys, hashTable.Keys); + } - [Test] - public void GetIndex_ThrowsException_WhenKeyIsNull() - { - var hashTable = new HashTable(4); - Assert.Throws(() => hashTable.GetIndex(null)); - } + [Test] + public void Values_ReturnsCorrectValues() + { + var hashTable = new HashTable(); + hashTable.Add(1, "one"); + hashTable.Add(2, "two"); + hashTable.Add(3, "three"); - [Test] - public void FindEntry_ThrowsException_WhenKeyIsNull() - { - var hashTable = new HashTable(4); - Assert.Throws(() => hashTable.FindEntry(null)); - } + var values = new List { "one", "two", "three" }; - [Test] - public void This_Get_ThrowsException_WhenKeyIsNull() - { - var hashTable = new HashTable(4); - Assert.Throws(() => - { - var value = hashTable[null]; - Console.WriteLine(value); - }); - } + CollectionAssert.AreEquivalent(values, hashTable?.Values); + } - [Test] - public void This_Set_ThrowsException_WhenKeyIsNull() - { - var hashTable = new HashTable(4); - Assert.Throws(() => hashTable[null] = 1); - } + [Test] + public void Constructor_ThrowsException_WhenCapacityIsZero() + { + Assert.Throws(() => new HashTable(0)); + } - [Test] - public void This_Get_ReturnsCorrectValue() - { - var hashTable = new HashTable(4); - hashTable.Add("one", 1); - Assert.AreEqual(1, hashTable["one"]); - } + [Test] + public void Constructor_ThrowsException_WhenLoadFactorIsZero() + { + Assert.Throws(() => new HashTable(4, 0)); + } - [Test] - public void This_Set_UpdatesValue() - { - var hashTable = new HashTable(4); - hashTable.Add("one", 1); - hashTable["one"] = 2; - Assert.AreEqual(2, hashTable["one"]); - } + [Test] + public void Constructor_ThrowsException_WhenLoadFactorIsLessThanZero() + { + Assert.Throws(() => new HashTable(4, -1)); + } - [Test] - public void This_Set_KeyNotFoundException_WhenKeyDoesNotExist() - { - var hashTable = new HashTable(4); - Assert.Throws(() => hashTable["one"] = 2); - } + [Test] + public void Constructor_ThrowsException_WhenLoadFactorIsGreaterThanOne() + { + Assert.Throws(() => new HashTable(4, 2)); + } - [Test] - public void This_Get_KeyNotFoundException_WhenKeyDoesNotExist() + [Test] + public void GetIndex_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(4); + Assert.Throws(() => hashTable.GetIndex(null)); + } + + [Test] + public void FindEntry_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(4); + Assert.Throws(() => hashTable.FindEntry(null)); + } + + [Test] + public void This_Get_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(4); + Assert.Throws(() => { - var hashTable = new HashTable(4); - Assert.Throws(() => { - var value = hashTable["one"]; - Console.WriteLine(value); - }); - } + var value = hashTable[null]; + Console.WriteLine(value); + }); + } + + [Test] + public void This_Set_ThrowsException_WhenKeyIsNull() + { + var hashTable = new HashTable(4); + Assert.Throws(() => hashTable[null] = 1); + } + + [Test] + public void This_Get_ReturnsCorrectValue() + { + var hashTable = new HashTable(4); + hashTable.Add("one", 1); + Assert.AreEqual(1, hashTable["one"]); + } + + [Test] + public void This_Set_UpdatesValue() + { + var hashTable = new HashTable(4); + hashTable.Add("one", 1); + hashTable["one"] = 2; + Assert.AreEqual(2, hashTable["one"]); + } + + [Test] + public void This_Set_KeyNotFoundException_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(4); + Assert.Throws(() => hashTable["one"] = 2); + } + + [Test] + public void This_Get_KeyNotFoundException_WhenKeyDoesNotExist() + { + var hashTable = new HashTable(4); + Assert.Throws(() => { + var value = hashTable["one"]; + Console.WriteLine(value); + }); } } diff --git a/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs b/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs index d0c9db47..d6e11c57 100644 --- a/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs +++ b/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs @@ -3,110 +3,109 @@ using DataStructures.Hashing.NumberTheory; using NUnit.Framework; -namespace DataStructures.Tests.Hashing.NumberTheory +namespace DataStructures.Tests.Hashing.NumberTheory; + +[TestFixture] +public static class PrimeNumberTests { - [TestFixture] - public static class PrimeNumberTests + private static readonly object[] IsPrimeSource = { - private static readonly object[] IsPrimeSource = - { - new object[] { 0, false }, - new object[] { 1, false }, - new object[] { 2, true }, - new object[] { 3, true }, - new object[] { 4, false }, - new object[] { 5, true }, - new object[] { 6, false }, - new object[] { 7, true }, - new object[] { 8, false }, - new object[] { 9, false }, - new object[] { 10, false }, - new object[] { 11, true }, - new object[] { 12, false }, - new object[] { 13, true }, - new object[] { 14, false }, - new object[] { 15, false }, - new object[] { 16, false }, - new object[] { 17, true }, - new object[] { 18, false }, - new object[] { 19, true }, - new object[] { 20, false }, - new object[] { 21, false }, - new object[] { 22, false }, - new object[] { 23, true }, - new object[] { 24, false }, - new object[] { 25, false }, - new object[] { 26, false }, - new object[] { 27, false }, - new object[] { 28, false }, - new object[] { 29, true }, - new object[] { 30, false }, - new object[] { 31, true }, - new object[] { 32, false }, - new object[] { 33, false }, - new object[] { 34, false }, - new object[] { 35, false }, - new object[] { 36, false }, - new object[] { 37, true }, - new object[] { 38, false }, - new object[] { 39, false }, - new object[] { 40, false }, - }; + new object[] { 0, false }, + new object[] { 1, false }, + new object[] { 2, true }, + new object[] { 3, true }, + new object[] { 4, false }, + new object[] { 5, true }, + new object[] { 6, false }, + new object[] { 7, true }, + new object[] { 8, false }, + new object[] { 9, false }, + new object[] { 10, false }, + new object[] { 11, true }, + new object[] { 12, false }, + new object[] { 13, true }, + new object[] { 14, false }, + new object[] { 15, false }, + new object[] { 16, false }, + new object[] { 17, true }, + new object[] { 18, false }, + new object[] { 19, true }, + new object[] { 20, false }, + new object[] { 21, false }, + new object[] { 22, false }, + new object[] { 23, true }, + new object[] { 24, false }, + new object[] { 25, false }, + new object[] { 26, false }, + new object[] { 27, false }, + new object[] { 28, false }, + new object[] { 29, true }, + new object[] { 30, false }, + new object[] { 31, true }, + new object[] { 32, false }, + new object[] { 33, false }, + new object[] { 34, false }, + new object[] { 35, false }, + new object[] { 36, false }, + new object[] { 37, true }, + new object[] { 38, false }, + new object[] { 39, false }, + new object[] { 40, false }, + }; - private static readonly object[] NextPrimeSource = - { - new object[] { 0, 1, false, 2 }, - new object[] { 1, 1, false, 2 }, - new object[] { 3, 1, false, 5 }, - new object[] { 4, 1, false, 5 }, - new object[] { 5, 1, false, 7 }, - new object[] { 6, 1, false, 7 }, - new object[] { 7, 1, false, 11 }, - new object[] { 8, 1, false, 11 }, - new object[] { 9, 1, false, 11 }, - new object[] { 10, 1, false, 11 }, - new object[] { 11, 1, false, 13 }, - new object[] { 12, 1, false, 13 }, - new object[] { 13, 1, false, 17 }, - new object[] { 14, 1, false, 17 }, - new object[] { 15, 1, false, 17 }, - new object[] { 16, 1, false, 17 }, - new object[] { 17, 1, false, 19 }, - new object[] { 18, 1, false, 19 }, - new object[] { 19, 1, false, 23 }, - new object[] { 20, 1, false, 23 }, - new object[] { 21, 1, false, 23 }, - new object[] { 22, 1, false, 23 }, - new object[] { 23, 1, false, 29 }, - new object[] { 24, 1, false, 29 }, - new object[] { 25, 1, false, 29 }, - new object[] { 26, 1, false, 29 }, - new object[] { 27, 1, false, 29 }, - new object[] { 28, 1, false, 29 }, - new object[] { 29, 1, false, 31 }, - new object[] { 4, 1, true, 3 }, - new object[] { 5, 1, true, 3 }, - new object[] { 6, 1, true, 5 }, - new object[] { 7, 1, true, 5 }, - new object[] { 8, 1, true, 7 }, - new object[] { 9, 1, true, 7 }, - new object[] { 10, 1, true, 7 } - }; + private static readonly object[] NextPrimeSource = + { + new object[] { 0, 1, false, 2 }, + new object[] { 1, 1, false, 2 }, + new object[] { 3, 1, false, 5 }, + new object[] { 4, 1, false, 5 }, + new object[] { 5, 1, false, 7 }, + new object[] { 6, 1, false, 7 }, + new object[] { 7, 1, false, 11 }, + new object[] { 8, 1, false, 11 }, + new object[] { 9, 1, false, 11 }, + new object[] { 10, 1, false, 11 }, + new object[] { 11, 1, false, 13 }, + new object[] { 12, 1, false, 13 }, + new object[] { 13, 1, false, 17 }, + new object[] { 14, 1, false, 17 }, + new object[] { 15, 1, false, 17 }, + new object[] { 16, 1, false, 17 }, + new object[] { 17, 1, false, 19 }, + new object[] { 18, 1, false, 19 }, + new object[] { 19, 1, false, 23 }, + new object[] { 20, 1, false, 23 }, + new object[] { 21, 1, false, 23 }, + new object[] { 22, 1, false, 23 }, + new object[] { 23, 1, false, 29 }, + new object[] { 24, 1, false, 29 }, + new object[] { 25, 1, false, 29 }, + new object[] { 26, 1, false, 29 }, + new object[] { 27, 1, false, 29 }, + new object[] { 28, 1, false, 29 }, + new object[] { 29, 1, false, 31 }, + new object[] { 4, 1, true, 3 }, + new object[] { 5, 1, true, 3 }, + new object[] { 6, 1, true, 5 }, + new object[] { 7, 1, true, 5 }, + new object[] { 8, 1, true, 7 }, + new object[] { 9, 1, true, 7 }, + new object[] { 10, 1, true, 7 } + }; - [Test] - [TestCaseSource("IsPrimeSource")] - public static void IsPrimeTest(int number, bool expected) - { - var actual = PrimeNumber.IsPrime(number); - Assert.AreEqual(expected, actual); - } + [Test] + [TestCaseSource("IsPrimeSource")] + public static void IsPrimeTest(int number, bool expected) + { + var actual = PrimeNumber.IsPrime(number); + Assert.AreEqual(expected, actual); + } - [Test] - [TestCaseSource("NextPrimeSource")] - public static void NextPrimeTest(int number, int factor, bool desc, int expected) - { - var actual = PrimeNumber.NextPrime(number, factor, desc); - Assert.AreEqual(expected, actual); - } + [Test] + [TestCaseSource("NextPrimeSource")] + public static void NextPrimeTest(int number, int factor, bool desc, int expected) + { + var actual = PrimeNumber.NextPrime(number, factor, desc); + Assert.AreEqual(expected, actual); } } diff --git a/DataStructures.Tests/Heap/BinaryHeapTests.cs b/DataStructures.Tests/Heap/BinaryHeapTests.cs index 45a066e8..3ebdf9c6 100644 --- a/DataStructures.Tests/Heap/BinaryHeapTests.cs +++ b/DataStructures.Tests/Heap/BinaryHeapTests.cs @@ -1,156 +1,155 @@ -using System; +using System; using System.Collections.Generic; using DataStructures.Heap; using NUnit.Framework; -namespace DataStructures.Tests.Heap +namespace DataStructures.Tests.Heap; + +internal static class BinaryHeapTests { - internal static class BinaryHeapTests + private static BinaryHeap BuildTestHeap() { - private static BinaryHeap BuildTestHeap() + var heap = new BinaryHeap(); + var elems = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + foreach (var i in elems) { - var heap = new BinaryHeap(); - var elems = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - foreach (var i in elems) - { - heap.Push(i); - } - - return heap; + heap.Push(i); } - [Test] - public static void Constructor_UseCustomComparer_BuildCorrectHeap() + return heap; + } + + [Test] + public static void Constructor_UseCustomComparer_BuildCorrectHeap() + { + var revHeap = new BinaryHeap(Comparer.Create((x, y) => y.CompareTo(x))); + foreach (var i in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }) { - var revHeap = new BinaryHeap(Comparer.Create((x, y) => y.CompareTo(x))); - foreach (var i in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }) - { - revHeap.Push(i); - } - - Assert.AreEqual(10, revHeap.Count); - Assert.AreEqual(1, revHeap.Peek()); - Assert.AreEqual(1, revHeap.Pop()); - Assert.AreEqual(2, revHeap.Peek()); + revHeap.Push(i); } - [Test] - public static void Push_AddElements_BuildCorrectHeap() - { - var heap = BuildTestHeap(); + Assert.AreEqual(10, revHeap.Count); + Assert.AreEqual(1, revHeap.Peek()); + Assert.AreEqual(1, revHeap.Pop()); + Assert.AreEqual(2, revHeap.Peek()); + } - Assert.AreEqual(10, heap.Peek()); - Assert.AreEqual(10, heap.Count); - } + [Test] + public static void Push_AddElements_BuildCorrectHeap() + { + var heap = BuildTestHeap(); - public static void Pop_RemoveElements_HeapStillValid() - { - var heap = BuildTestHeap(); + Assert.AreEqual(10, heap.Peek()); + Assert.AreEqual(10, heap.Count); + } - Assert.AreEqual(10, heap.Peek()); - Assert.AreEqual(10, heap.Count); + public static void Pop_RemoveElements_HeapStillValid() + { + var heap = BuildTestHeap(); - Assert.AreEqual(10, heap.Pop()); - Assert.AreEqual(9, heap.Count); - Assert.IsFalse(heap.Contains(10)); + Assert.AreEqual(10, heap.Peek()); + Assert.AreEqual(10, heap.Count); - Assert.AreEqual(9, heap.Pop()); - Assert.AreEqual(8, heap.Count); - Assert.IsFalse(heap.Contains(9)); - } + Assert.AreEqual(10, heap.Pop()); + Assert.AreEqual(9, heap.Count); + Assert.IsFalse(heap.Contains(10)); - [Test] - public static void Pop_EmptyHeap_ThrowsCorrectException() - { - var heap = new BinaryHeap(); + Assert.AreEqual(9, heap.Pop()); + Assert.AreEqual(8, heap.Count); + Assert.IsFalse(heap.Contains(9)); + } - Assert.Throws(() => heap.Pop()); - } + [Test] + public static void Pop_EmptyHeap_ThrowsCorrectException() + { + var heap = new BinaryHeap(); - [Test] - public static void Peek_NonEmptyHeap_ReturnsCorrectAnswer() - { - var heap = BuildTestHeap(); + Assert.Throws(() => heap.Pop()); + } - Assert.AreEqual(10, heap.Peek()); - } + [Test] + public static void Peek_NonEmptyHeap_ReturnsCorrectAnswer() + { + var heap = BuildTestHeap(); - [Test] - public static void Peek_EmptyHeap_ThrowsCorrectException() - { - var heap = new BinaryHeap(); + Assert.AreEqual(10, heap.Peek()); + } - Assert.Throws(() => heap.Peek()); - } + [Test] + public static void Peek_EmptyHeap_ThrowsCorrectException() + { + var heap = new BinaryHeap(); - [Test] - public static void PushPop_EmptyHeap_ReturnsCorrectAnswer() - { - var heap = new BinaryHeap(); + Assert.Throws(() => heap.Peek()); + } - Assert.AreEqual(10, heap.PushPop(10)); - } + [Test] + public static void PushPop_EmptyHeap_ReturnsCorrectAnswer() + { + var heap = new BinaryHeap(); - [Test] - public static void PushPop_NonEmptyHeap_ReturnsCorrectAnswer() - { - var heap = BuildTestHeap(); + Assert.AreEqual(10, heap.PushPop(10)); + } - Assert.AreEqual(20, heap.PushPop(20)); - Assert.AreEqual(10, heap.PushPop(-10)); - } + [Test] + public static void PushPop_NonEmptyHeap_ReturnsCorrectAnswer() + { + var heap = BuildTestHeap(); - [Test] - public static void Contains_NonEmptyHeap_ReturnsCorrectAnswer() - { - var heap = BuildTestHeap(); + Assert.AreEqual(20, heap.PushPop(20)); + Assert.AreEqual(10, heap.PushPop(-10)); + } - Assert.IsTrue(heap.Contains(1)); - Assert.IsTrue(heap.Contains(5)); - Assert.IsTrue(heap.Contains(10)); - Assert.IsFalse(heap.Contains(11)); - } + [Test] + public static void Contains_NonEmptyHeap_ReturnsCorrectAnswer() + { + var heap = BuildTestHeap(); - [Test] - public static void Contains_EmptyHeap_ReturnsCorrectAnswer() - { - var heap = new BinaryHeap(); + Assert.IsTrue(heap.Contains(1)); + Assert.IsTrue(heap.Contains(5)); + Assert.IsTrue(heap.Contains(10)); + Assert.IsFalse(heap.Contains(11)); + } - Assert.IsFalse(heap.Contains(1)); - Assert.IsFalse(heap.Contains(5)); - Assert.IsFalse(heap.Contains(10)); - Assert.IsFalse(heap.Contains(11)); - } + [Test] + public static void Contains_EmptyHeap_ReturnsCorrectAnswer() + { + var heap = new BinaryHeap(); - [Test] - public static void Remove_NonEmptyHeap_HeapStillValid() - { - var heap = BuildTestHeap(); + Assert.IsFalse(heap.Contains(1)); + Assert.IsFalse(heap.Contains(5)); + Assert.IsFalse(heap.Contains(10)); + Assert.IsFalse(heap.Contains(11)); + } + + [Test] + public static void Remove_NonEmptyHeap_HeapStillValid() + { + var heap = BuildTestHeap(); - heap.Remove(2); - Assert.IsFalse(heap.Contains(2)); - Assert.AreEqual(10, heap.Peek()); - Assert.AreEqual(9, heap.Count); + heap.Remove(2); + Assert.IsFalse(heap.Contains(2)); + Assert.AreEqual(10, heap.Peek()); + Assert.AreEqual(9, heap.Count); - heap.Remove(8); - Assert.IsFalse(heap.Contains(8)); - Assert.AreEqual(10, heap.Peek()); - Assert.AreEqual(8, heap.Count); + heap.Remove(8); + Assert.IsFalse(heap.Contains(8)); + Assert.AreEqual(10, heap.Peek()); + Assert.AreEqual(8, heap.Count); - heap.Remove(5); - Assert.IsFalse(heap.Contains(5)); - Assert.AreEqual(10, heap.Peek()); - Assert.AreEqual(7, heap.Count); + heap.Remove(5); + Assert.IsFalse(heap.Contains(5)); + Assert.AreEqual(10, heap.Peek()); + Assert.AreEqual(7, heap.Count); - Assert.Throws(() => heap.Remove(11)); - } + Assert.Throws(() => heap.Remove(11)); + } - [Test] - public static void Remove_EmptyHeap_ThrowsCorrectException() - { - var heap = new BinaryHeap(); + [Test] + public static void Remove_EmptyHeap_ThrowsCorrectException() + { + var heap = new BinaryHeap(); - Assert.Throws(() => heap.Remove(1)); - } + Assert.Throws(() => heap.Remove(1)); } } diff --git a/DataStructures.Tests/Heap/FibonacciHeaps/FibonacciHeapTests.cs b/DataStructures.Tests/Heap/FibonacciHeaps/FibonacciHeapTests.cs index 124ca31a..300a340f 100644 --- a/DataStructures.Tests/Heap/FibonacciHeaps/FibonacciHeapTests.cs +++ b/DataStructures.Tests/Heap/FibonacciHeaps/FibonacciHeapTests.cs @@ -1,278 +1,277 @@ -using System; +using System; using DataStructures.Heap.FibonacciHeap; using NUnit.Framework; -namespace DataStructures.Tests.Heap.FibonacciHeaps +namespace DataStructures.Tests.Heap.FibonacciHeaps; + +internal class TestFHeap : FibonacciHeap { - internal class TestFHeap : FibonacciHeap + public void RawCut(FHeapNode x, FHeapNode y) { - public void RawCut(FHeapNode x, FHeapNode y) - { - Cut(x, y); - } - - public void RawCascadingCut(FHeapNode y) - { - CascadingCut(y); - } + Cut(x, y); + } - public void RawConsolidate() - { - Consolidate(); - } + public void RawCascadingCut(FHeapNode y) + { + CascadingCut(y); } - internal static class FibonacciHeapTests + public void RawConsolidate() { - private static FibonacciHeap BuildTestHeap() - { - var heap = new FibonacciHeap(); - var elems = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - foreach (var i in elems) - { - heap.Push(i); - } - - return heap; - } + Consolidate(); + } +} - [Test] - public static void Push_AddElements_BuildCorrectHeap() +internal static class FibonacciHeapTests +{ + private static FibonacciHeap BuildTestHeap() + { + var heap = new FibonacciHeap(); + var elems = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + foreach (var i in elems) { - var heap = BuildTestHeap(); - - Assert.AreEqual(1, heap.Peek()); - Assert.AreEqual(10, heap.Count); + heap.Push(i); } - public static void Pop_RemoveElements_HeapStillValid() - { - var heap = BuildTestHeap(); + return heap; + } - Assert.AreEqual(1, heap.Peek()); - Assert.AreEqual(10, heap.Count); + [Test] + public static void Push_AddElements_BuildCorrectHeap() + { + var heap = BuildTestHeap(); - Assert.AreEqual(1, heap.Pop()); - Assert.AreEqual(9, heap.Count); + Assert.AreEqual(1, heap.Peek()); + Assert.AreEqual(10, heap.Count); + } - Assert.AreEqual(2, heap.Pop()); - Assert.AreEqual(8, heap.Count); - } + public static void Pop_RemoveElements_HeapStillValid() + { + var heap = BuildTestHeap(); - [Test] - public static void Pop_EmptyHeap_ThrowsCorrectException() - { - var heap = new FibonacciHeap(); + Assert.AreEqual(1, heap.Peek()); + Assert.AreEqual(10, heap.Count); - Assert.Throws(() => heap.Pop()); - } + Assert.AreEqual(1, heap.Pop()); + Assert.AreEqual(9, heap.Count); - [Test] - public static void Pop_NonEmptyHeap_ReturnsInSortedOrder() - { - var heap = new FibonacciHeap(); + Assert.AreEqual(2, heap.Pop()); + Assert.AreEqual(8, heap.Count); + } - var rand = new Random(); - var heapSize = 100; + [Test] + public static void Pop_EmptyHeap_ThrowsCorrectException() + { + var heap = new FibonacciHeap(); - for (var i = 0; i < heapSize; i++) - { - heap.Push(rand.Next(1000)); - } + Assert.Throws(() => heap.Pop()); + } - var element = heap.Pop(); + [Test] + public static void Pop_NonEmptyHeap_ReturnsInSortedOrder() + { + var heap = new FibonacciHeap(); - for (var i = 0; i < heapSize - 1; i++) - { - var newElement = heap.Pop(); - Assert.LessOrEqual(element, newElement); - element = newElement; - } + var rand = new Random(); + var heapSize = 100; - Assert.Zero(heap.Count); + for (var i = 0; i < heapSize; i++) + { + heap.Push(rand.Next(1000)); } - [Test] - public static void Peek_EmptyHeap_ThrowsCorrectException() - { - var heap = new FibonacciHeap(); + var element = heap.Pop(); - Assert.Throws(() => heap.Peek()); + for (var i = 0; i < heapSize - 1; i++) + { + var newElement = heap.Pop(); + Assert.LessOrEqual(element, newElement); + element = newElement; } - [Test] - public static void DecreaseKey_NonEmptyHeap_ReturnsCorrectAnswer() - { - var heap = BuildTestHeap(); + Assert.Zero(heap.Count); + } - var node = heap.Push(11); - heap.DecreaseKey(node, -1); + [Test] + public static void Peek_EmptyHeap_ThrowsCorrectException() + { + var heap = new FibonacciHeap(); - Assert.AreEqual(heap.Pop(), -1); - Assert.AreEqual(heap.Pop(), 1); + Assert.Throws(() => heap.Peek()); + } - node = heap.Push(5); - heap.DecreaseKey(node, 1); - Assert.AreEqual(heap.Pop(), 1); + [Test] + public static void DecreaseKey_NonEmptyHeap_ReturnsCorrectAnswer() + { + var heap = BuildTestHeap(); - Assert.AreEqual(heap.Pop(), 2); - Assert.AreEqual(heap.Pop(), 3); - } + var node = heap.Push(11); + heap.DecreaseKey(node, -1); - [Test] - public static void Union_NonEmptyHeap_ReturnsSortedOrder() - { - var oddHeap = new FibonacciHeap(); + Assert.AreEqual(heap.Pop(), -1); + Assert.AreEqual(heap.Pop(), 1); - for (var i = 1; i < 10; i += 2) - { - oddHeap.Push(i); - } + node = heap.Push(5); + heap.DecreaseKey(node, 1); + Assert.AreEqual(heap.Pop(), 1); - var evenHeap = new FibonacciHeap(); + Assert.AreEqual(heap.Pop(), 2); + Assert.AreEqual(heap.Pop(), 3); + } - for (var i = 0; i < 10; i += 2) - { - evenHeap.Push(i); - } + [Test] + public static void Union_NonEmptyHeap_ReturnsSortedOrder() + { + var oddHeap = new FibonacciHeap(); - oddHeap.Union(evenHeap); + for (var i = 1; i < 10; i += 2) + { + oddHeap.Push(i); + } - for (var i = 0; i < 10; i++) - { - Assert.AreEqual(i, oddHeap.Pop()); - } + var evenHeap = new FibonacciHeap(); - Assert.Zero(oddHeap.Count); - Assert.Zero(evenHeap.Count); + for (var i = 0; i < 10; i += 2) + { + evenHeap.Push(i); } - [Test] - public static void Union_EmptyHeap_BecomesOtherHeap() - { - var thisHeap = new FibonacciHeap(); - var otherHeap = BuildTestHeap(); + oddHeap.Union(evenHeap); - var minNode = otherHeap.Peek(); - var otherCount = otherHeap.Count; + for (var i = 0; i < 10; i++) + { + Assert.AreEqual(i, oddHeap.Pop()); + } - Assert.Zero(thisHeap.Count); + Assert.Zero(oddHeap.Count); + Assert.Zero(evenHeap.Count); + } - thisHeap.Union(otherHeap); + [Test] + public static void Union_EmptyHeap_BecomesOtherHeap() + { + var thisHeap = new FibonacciHeap(); + var otherHeap = BuildTestHeap(); - Assert.Zero(otherHeap.Count); - Assert.AreEqual(thisHeap.Peek(), minNode); - Assert.Throws(() => otherHeap.Peek()); + var minNode = otherHeap.Peek(); + var otherCount = otherHeap.Count; - Assert.AreEqual(otherCount, thisHeap.Count); - } + Assert.Zero(thisHeap.Count); - [Test] - public static void Union_FullHeapWithEmptyHeap_Unchanged() - { - var thisHeap = BuildTestHeap(); - var otherHeap = new FibonacciHeap(); + thisHeap.Union(otherHeap); - var previousCount = thisHeap.Count; - var previousMin = thisHeap.Peek(); + Assert.Zero(otherHeap.Count); + Assert.AreEqual(thisHeap.Peek(), minNode); + Assert.Throws(() => otherHeap.Peek()); - thisHeap.Union(otherHeap); + Assert.AreEqual(otherCount, thisHeap.Count); + } - Assert.AreEqual(thisHeap.Count, previousCount); - Assert.AreEqual(thisHeap.Peek(), previousMin); - } + [Test] + public static void Union_FullHeapWithEmptyHeap_Unchanged() + { + var thisHeap = BuildTestHeap(); + var otherHeap = new FibonacciHeap(); - [Test] - public static void DecreaseKey_EmptyHeap_ThrowsCorrectException() - { - var heap = new FibonacciHeap(); - var item = new FHeapNode(1); + var previousCount = thisHeap.Count; + var previousMin = thisHeap.Peek(); - Assert.Throws(() => heap.DecreaseKey(item, 0)); - } + thisHeap.Union(otherHeap); - [Test] - public static void DecreaseKey_TryIncreaseKey_ThrowsCorrectException() - { - var heap = new FibonacciHeap(); - var item = heap.Push(1); + Assert.AreEqual(thisHeap.Count, previousCount); + Assert.AreEqual(thisHeap.Peek(), previousMin); + } - Assert.Throws(() => heap.DecreaseKey(item, 2)); - } + [Test] + public static void DecreaseKey_EmptyHeap_ThrowsCorrectException() + { + var heap = new FibonacciHeap(); + var item = new FHeapNode(1); - [Test] - public static void DecreaseKey_NonEmptyHeap_PreservesHeapStructure() - { - var heap = new FibonacciHeap(); + Assert.Throws(() => heap.DecreaseKey(item, 0)); + } - for (var i = 11; i < 20; i++) - { - heap.Push(i); - } + [Test] + public static void DecreaseKey_TryIncreaseKey_ThrowsCorrectException() + { + var heap = new FibonacciHeap(); + var item = heap.Push(1); - var item = heap.Push(10); + Assert.Throws(() => heap.DecreaseKey(item, 2)); + } - for (var i = 0; i < 10; i++) - { - heap.Push(i); - } + [Test] + public static void DecreaseKey_NonEmptyHeap_PreservesHeapStructure() + { + var heap = new FibonacciHeap(); - var bigItem = heap.Push(20); + for (var i = 11; i < 20; i++) + { + heap.Push(i); + } - heap.DecreaseKey(item, -1); - Assert.AreEqual(heap.Pop(), -1); + var item = heap.Push(10); - var currentVal = -1; - for (var i = 0; i < 10; i++) - { - var newVal = heap.Pop(); - Assert.True(currentVal < newVal); + for (var i = 0; i < 10; i++) + { + heap.Push(i); + } - currentVal = newVal; - } + var bigItem = heap.Push(20); - heap.DecreaseKey(bigItem, -1); - Assert.AreEqual(heap.Pop(), -1); + heap.DecreaseKey(item, -1); + Assert.AreEqual(heap.Pop(), -1); - currentVal = -1; - for (var i = 0; i < 9; i++) - { - var newVal = heap.Pop(); - Assert.True(currentVal < newVal); + var currentVal = -1; + for (var i = 0; i < 10; i++) + { + var newVal = heap.Pop(); + Assert.True(currentVal < newVal); - currentVal = newVal; - } + currentVal = newVal; } - [Test] - public static void Cut_EmptyHeap_ThrowsCorrectExcpetion() + heap.DecreaseKey(bigItem, -1); + Assert.AreEqual(heap.Pop(), -1); + + currentVal = -1; + for (var i = 0; i < 9; i++) { - var heap = new TestFHeap(); - var item1 = new FHeapNode(1); - var item2 = new FHeapNode(2); + var newVal = heap.Pop(); + Assert.True(currentVal < newVal); - Assert.Throws(() => heap.RawCut(item1, item2)); + currentVal = newVal; } + } - [Test] - public static void Cut_FilledHeap_AlteredItem() - { - var heap = new TestFHeap(); - var item1 = heap.Push(1); - var item2 = heap.Push(2); + [Test] + public static void Cut_EmptyHeap_ThrowsCorrectExcpetion() + { + var heap = new TestFHeap(); + var item1 = new FHeapNode(1); + var item2 = new FHeapNode(2); - item2.Degree = -1; + Assert.Throws(() => heap.RawCut(item1, item2)); + } - Assert.Throws(() => heap.RawCut(item1, item2)); - } + [Test] + public static void Cut_FilledHeap_AlteredItem() + { + var heap = new TestFHeap(); + var item1 = heap.Push(1); + var item2 = heap.Push(2); - [Test] - public static void Consolidate_EmptyHeap_DoesNothing() - { - var heap = new TestFHeap(); - heap.RawConsolidate(); + item2.Degree = -1; - Assert.Throws(() => heap.Peek()); - } + Assert.Throws(() => heap.RawCut(item1, item2)); + } + + [Test] + public static void Consolidate_EmptyHeap_DoesNothing() + { + var heap = new TestFHeap(); + heap.RawConsolidate(); + + Assert.Throws(() => heap.Peek()); } } diff --git a/DataStructures.Tests/Heap/MinMaxHeapTests.cs b/DataStructures.Tests/Heap/MinMaxHeapTests.cs index 45053384..7752681a 100644 --- a/DataStructures.Tests/Heap/MinMaxHeapTests.cs +++ b/DataStructures.Tests/Heap/MinMaxHeapTests.cs @@ -1,163 +1,162 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using DataStructures.Heap; using NUnit.Framework; -namespace DataStructures.Tests.Heap +namespace DataStructures.Tests.Heap; + +[TestFixture] +public static class MinMaxHeapTests { - [TestFixture] - public static class MinMaxHeapTests + private static readonly object[] CollectionsSource = { - private static readonly object[] CollectionsSource = - { - new[] { 5, 10, -2, 0, 3, 13, 5, -8, 41, -5, -7, -60, -12 }, - new[] { 'e', '4', 'x', 'D', '!', '$', '-', '_', '2', ')', 'Z', 'q' }, - new[] { "abc", "abc", "xyz", "bcd", "klm", "opq", "ijk" }, - }; + new[] { 5, 10, -2, 0, 3, 13, 5, -8, 41, -5, -7, -60, -12 }, + new[] { 'e', '4', 'x', 'D', '!', '$', '-', '_', '2', ')', 'Z', 'q' }, + new[] { "abc", "abc", "xyz", "bcd", "klm", "opq", "ijk" }, + }; + + [Test] + public static void CustomComparerTest() + { + var arr = new[] { "aaaa", "c", "dd", "bbb" }; + var comparer = Comparer.Create((a, b) => Comparer.Default.Compare(a.Length, b.Length)); - [Test] - public static void CustomComparerTest() + var mmh = new MinMaxHeap(comparer: comparer); + foreach (var s in arr) { - var arr = new[] { "aaaa", "c", "dd", "bbb" }; - var comparer = Comparer.Create((a, b) => Comparer.Default.Compare(a.Length, b.Length)); + mmh.Add(s); + } - var mmh = new MinMaxHeap(comparer: comparer); - foreach (var s in arr) - { - mmh.Add(s); - } + Assert.AreEqual(comparer, mmh.Comparer); + Assert.AreEqual("c", mmh.GetMin()); + Assert.AreEqual("aaaa", mmh.GetMax()); + } - Assert.AreEqual(comparer, mmh.Comparer); - Assert.AreEqual("c", mmh.GetMin()); - Assert.AreEqual("aaaa", mmh.GetMax()); + [Test] + [TestCaseSource("CollectionsSource")] + public static void AddTest(IEnumerable collection) + { + var mmh = new MinMaxHeap(); + foreach (var item in collection) + { + mmh.Add(item); } - [Test] - [TestCaseSource("CollectionsSource")] - public static void AddTest(IEnumerable collection) - { - var mmh = new MinMaxHeap(); - foreach (var item in collection) - { - mmh.Add(item); - } + var minValue = mmh.GetMin(); + var maxValue = mmh.GetMax(); - var minValue = mmh.GetMin(); - var maxValue = mmh.GetMax(); + Assert.AreEqual(collection.Min(), minValue); + Assert.AreEqual(collection.Max(), maxValue); + Assert.AreEqual(collection.Count(), mmh.Count); + } - Assert.AreEqual(collection.Min(), minValue); - Assert.AreEqual(collection.Max(), maxValue); - Assert.AreEqual(collection.Count(), mmh.Count); - } + [Test] + [TestCaseSource("CollectionsSource")] + public static void ExtractMaxTest(IEnumerable collection) + { + var ordered = collection.OrderByDescending(x => x); + var mmh = new MinMaxHeap(collection); + var emptyHeap = new MinMaxHeap(); - [Test] - [TestCaseSource("CollectionsSource")] - public static void ExtractMaxTest(IEnumerable collection) - { - var ordered = collection.OrderByDescending(x => x); - var mmh = new MinMaxHeap(collection); - var emptyHeap = new MinMaxHeap(); + var first = mmh.ExtractMax(); + var second = mmh.GetMax(); - var first = mmh.ExtractMax(); - var second = mmh.GetMax(); + Assert.Throws(() => emptyHeap.ExtractMax()); + Assert.AreEqual(ordered.ElementAt(0), first); + Assert.AreEqual(ordered.ElementAt(1), second); + Assert.AreEqual(collection.Count() - 1, mmh.Count); + } - Assert.Throws(() => emptyHeap.ExtractMax()); - Assert.AreEqual(ordered.ElementAt(0), first); - Assert.AreEqual(ordered.ElementAt(1), second); - Assert.AreEqual(collection.Count() - 1, mmh.Count); - } + [Test] + [TestCaseSource("CollectionsSource")] + public static void ExtractMinTest(IEnumerable collection) + { + var ordered = collection.OrderBy(x => x); + var mmh = new MinMaxHeap(collection); + var emptyHeap = new MinMaxHeap(); - [Test] - [TestCaseSource("CollectionsSource")] - public static void ExtractMinTest(IEnumerable collection) - { - var ordered = collection.OrderBy(x => x); - var mmh = new MinMaxHeap(collection); - var emptyHeap = new MinMaxHeap(); + var first = mmh.ExtractMin(); + var second = mmh.GetMin(); - var first = mmh.ExtractMin(); - var second = mmh.GetMin(); + Assert.Throws(() => emptyHeap.ExtractMin()); + Assert.AreEqual(ordered.ElementAt(0), first); + Assert.AreEqual(ordered.ElementAt(1), second); + Assert.AreEqual(collection.Count() - 1, mmh.Count); + } - Assert.Throws(() => emptyHeap.ExtractMin()); - Assert.AreEqual(ordered.ElementAt(0), first); - Assert.AreEqual(ordered.ElementAt(1), second); - Assert.AreEqual(collection.Count() - 1, mmh.Count); - } + [Test] + [TestCaseSource("CollectionsSource")] + public static void GetMaxTest(IEnumerable collection) + { + var emptyHeap = new MinMaxHeap(); + var mmh = new MinMaxHeap(collection); - [Test] - [TestCaseSource("CollectionsSource")] - public static void GetMaxTest(IEnumerable collection) - { - var emptyHeap = new MinMaxHeap(); - var mmh = new MinMaxHeap(collection); + var maxValue = mmh.GetMax(); - var maxValue = mmh.GetMax(); + Assert.Throws(() => emptyHeap.GetMax()); + Assert.AreEqual(collection.Max(), maxValue); + } - Assert.Throws(() => emptyHeap.GetMax()); - Assert.AreEqual(collection.Max(), maxValue); - } + [Test] + [TestCaseSource("CollectionsSource")] + public static void GetMinTest(IEnumerable collection) + { + var emptyHeap = new MinMaxHeap(); + var mmh = new MinMaxHeap(collection); - [Test] - [TestCaseSource("CollectionsSource")] - public static void GetMinTest(IEnumerable collection) - { - var emptyHeap = new MinMaxHeap(); - var mmh = new MinMaxHeap(collection); + var minValue = mmh.GetMin(); - var minValue = mmh.GetMin(); + Assert.Throws(() => emptyHeap.GetMin()); + Assert.AreEqual(collection.Min(), minValue); + } - Assert.Throws(() => emptyHeap.GetMin()); - Assert.AreEqual(collection.Min(), minValue); - } + [Test] + public static void HeapSortUsingGet( + [ValueSource("CollectionsSource")] IEnumerable collection, + [Values] bool ascending) + { + var ordered = ascending ? collection.OrderBy(x => x) : collection.OrderByDescending(x => x); + var mmh = new MinMaxHeap(collection); + var extracted = new List(); - [Test] - public static void HeapSortUsingGet( - [ValueSource("CollectionsSource")] IEnumerable collection, - [Values] bool ascending) + while (mmh.Count > 0) { - var ordered = ascending ? collection.OrderBy(x => x) : collection.OrderByDescending(x => x); - var mmh = new MinMaxHeap(collection); - var extracted = new List(); - - while (mmh.Count > 0) + T value; + if (ascending) + { + value = mmh.GetMin(); + _ = mmh.ExtractMin(); + } + else { - T value; - if (ascending) - { - value = mmh.GetMin(); - _ = mmh.ExtractMin(); - } - else - { - value = mmh.GetMax(); - _ = mmh.ExtractMax(); - } - - extracted.Add(value); + value = mmh.GetMax(); + _ = mmh.ExtractMax(); } - Assert.IsTrue(ordered.SequenceEqual(extracted)); + extracted.Add(value); } - [Test] - public static void HeapSortUsingExtract( - [ValueSource("CollectionsSource")] IEnumerable collection, - [Values] bool ascending) - { - var ordered = ascending ? collection.OrderBy(x => x) : collection.OrderByDescending(x => x); - var mmh = new MinMaxHeap(collection); - var extracted = new List(); + Assert.IsTrue(ordered.SequenceEqual(extracted)); + } - while (mmh.Count > 0) - { - var value = ascending ? mmh.ExtractMin() : mmh.ExtractMax(); - extracted.Add(value); - } + [Test] + public static void HeapSortUsingExtract( + [ValueSource("CollectionsSource")] IEnumerable collection, + [Values] bool ascending) + { + var ordered = ascending ? collection.OrderBy(x => x) : collection.OrderByDescending(x => x); + var mmh = new MinMaxHeap(collection); + var extracted = new List(); - Assert.IsTrue(ordered.SequenceEqual(extracted)); + while (mmh.Count > 0) + { + var value = ascending ? mmh.ExtractMin() : mmh.ExtractMax(); + extracted.Add(value); } + + Assert.IsTrue(ordered.SequenceEqual(extracted)); } } diff --git a/DataStructures.Tests/Heap/PairingHeap/PairingHeapComparerTests.cs b/DataStructures.Tests/Heap/PairingHeap/PairingHeapComparerTests.cs index c9af781a..1fa1112d 100644 --- a/DataStructures.Tests/Heap/PairingHeap/PairingHeapComparerTests.cs +++ b/DataStructures.Tests/Heap/PairingHeap/PairingHeapComparerTests.cs @@ -1,34 +1,33 @@ -using System.Collections.Generic; +using System.Collections.Generic; using DataStructures.Heap.PairingHeap; using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests.Heap.PairingHeap +namespace DataStructures.Tests.Heap.PairingHeap; + +internal class PairingHeapComparerTests { - internal class PairingHeapComparerTests + [Test] + public void Compare_CheckAscending_ReturnNegative() { - [Test] - public void Compare_CheckAscending_ReturnNegative() - { - var minHeap = new PairingNodeComparer(Sorting.Ascending, Comparer.Default); - var node1 = new PairingHeapNode(10); - var node2 = new PairingHeapNode(20); + var minHeap = new PairingNodeComparer(Sorting.Ascending, Comparer.Default); + var node1 = new PairingHeapNode(10); + var node2 = new PairingHeapNode(20); - var items = minHeap.Compare(node1.Value, node2.Value); + var items = minHeap.Compare(node1.Value, node2.Value); - items.Should().Be(-1); - } + items.Should().Be(-1); + } - [Test] - public void Compare_CheckAscending_ReturnPositive() - { - var minHeap = new PairingNodeComparer(Sorting.Descending, Comparer.Default); - var node1 = new PairingHeapNode(10); - var node2 = new PairingHeapNode(20); + [Test] + public void Compare_CheckAscending_ReturnPositive() + { + var minHeap = new PairingNodeComparer(Sorting.Descending, Comparer.Default); + var node1 = new PairingHeapNode(10); + var node2 = new PairingHeapNode(20); - var items = minHeap.Compare(node1.Value, node2.Value); + var items = minHeap.Compare(node1.Value, node2.Value); - items.Should().Be(1); - } + items.Should().Be(1); } } diff --git a/DataStructures.Tests/Heap/PairingHeap/PairingHeapTests.cs b/DataStructures.Tests/Heap/PairingHeap/PairingHeapTests.cs index 09291132..c2a9630d 100644 --- a/DataStructures.Tests/Heap/PairingHeap/PairingHeapTests.cs +++ b/DataStructures.Tests/Heap/PairingHeap/PairingHeapTests.cs @@ -1,157 +1,156 @@ -using System; +using System; using System.Collections; using System.Linq; using DataStructures.Heap.PairingHeap; using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests.Heap.PairingHeap +namespace DataStructures.Tests.Heap.PairingHeap; + +internal class PairingHeapTests { - internal class PairingHeapTests + [Test] + public void BuildMinHeap_CheckEnumerator_NotThrowOnEnumerate() + { + var minHeap = new PairingHeap(); + minHeap.Insert(1); + + var items = minHeap.ToList(); + + items.Should().HaveCount(1); + } + + [Test] + public void BuildMinHeap_CheckEnumerable_NotThrowOnEnumerate() + { + var minHeap = new PairingHeap(); + minHeap.Insert(1); + + foreach (var node in (IEnumerable)minHeap) + { + node.Should().NotBe(null); + } + } + + [Test] + public void BuildMinHeap_UpdateNonExistingNode_ThrowException() + { + var minHeap = new PairingHeap(); + minHeap.Insert(1); + minHeap.Extract(); + + Action act = () => minHeap.UpdateKey(1, 10); + + act.Should().Throw(); + } + + [Test] + public void BuildMinHeap_UpdateBadNode_ThrowException() + { + var minHeap = new PairingHeap(); + minHeap.Insert(10); + + Action act = () => minHeap.UpdateKey(10, 11); + + act.Should().Throw(); + } + + [Test] + public void BuildMinHeap_CreateHeap_HeapIsCheked() { - [Test] - public void BuildMinHeap_CheckEnumerator_NotThrowOnEnumerate() + var nodeCount = 1000 * 10; + var minHeap = new PairingHeap(); + for (var i = 0; i <= nodeCount; i++) { - var minHeap = new PairingHeap(); - minHeap.Insert(1); + minHeap.Insert(i); + } - var items = minHeap.ToList(); + for (var i = 0; i <= nodeCount; i++) + { + minHeap.UpdateKey(i, i - 1); + } - items.Should().HaveCount(1); + var min = 0; + for (var i = 0; i <= nodeCount; i++) + { + min = minHeap.Extract(); + Assert.AreEqual(min, i - 1); } - [Test] - public void BuildMinHeap_CheckEnumerable_NotThrowOnEnumerate() + Assert.AreEqual(minHeap.Count, minHeap.Count); + + var rnd = new Random(); + var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(_ => rnd.Next()).ToList(); + + foreach (var item in testSeries) { - var minHeap = new PairingHeap(); - minHeap.Insert(1); + minHeap.Insert(item); + } - foreach (var node in (IEnumerable)minHeap) - { - node.Should().NotBe(null); - } + for (var i = 0; i < testSeries.Count; i++) + { + var decremented = testSeries[i] - rnd.Next(0, 1000); + minHeap.UpdateKey(testSeries[i], decremented); + testSeries[i] = decremented; } - [Test] - public void BuildMinHeap_UpdateNonExistingNode_ThrowException() + testSeries.Sort(); + + for (var i = 0; i < nodeCount - 2; i++) { - var minHeap = new PairingHeap(); - minHeap.Insert(1); - minHeap.Extract(); + min = minHeap.Extract(); + Assert.AreEqual(testSeries[i], min); + } - Action act = () => minHeap.UpdateKey(1, 10); + Assert.AreEqual(minHeap.Count, minHeap.Count); + } + + [Test] + public void BuildMaxHeap_CreateHeap_HeapIsCheked() + { + var nodeCount = 1000 * 10; + var maxHeap = new PairingHeap(Sorting.Descending); + for (var i = 0; i <= nodeCount; i++) + { + maxHeap.Insert(i); + } - act.Should().Throw(); + for (var i = 0; i <= nodeCount; i++) + { + maxHeap.UpdateKey(i, i + 1); } - [Test] - public void BuildMinHeap_UpdateBadNode_ThrowException() + Assert.AreEqual(maxHeap.Count, maxHeap.Count); + + var max = 0; + for (var i = nodeCount; i >= 0; i--) { - var minHeap = new PairingHeap(); - minHeap.Insert(10); + max = maxHeap.Extract(); + Assert.AreEqual(max, i + 1); + } - Action act = () => minHeap.UpdateKey(10, 11); + var rnd = new Random(); + var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(_ => rnd.Next()).ToList(); - act.Should().Throw(); + foreach (var item in testSeries) + { + maxHeap.Insert(item); } - [Test] - public void BuildMinHeap_CreateHeap_HeapIsCheked() + for (var i = 0; i < testSeries.Count; i++) { - var nodeCount = 1000 * 10; - var minHeap = new PairingHeap(); - for (var i = 0; i <= nodeCount; i++) - { - minHeap.Insert(i); - } - - for (var i = 0; i <= nodeCount; i++) - { - minHeap.UpdateKey(i, i - 1); - } - - var min = 0; - for (var i = 0; i <= nodeCount; i++) - { - min = minHeap.Extract(); - Assert.AreEqual(min, i - 1); - } - - Assert.AreEqual(minHeap.Count, minHeap.Count); - - var rnd = new Random(); - var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(_ => rnd.Next()).ToList(); - - foreach (var item in testSeries) - { - minHeap.Insert(item); - } - - for (var i = 0; i < testSeries.Count; i++) - { - var decremented = testSeries[i] - rnd.Next(0, 1000); - minHeap.UpdateKey(testSeries[i], decremented); - testSeries[i] = decremented; - } - - testSeries.Sort(); - - for (var i = 0; i < nodeCount - 2; i++) - { - min = minHeap.Extract(); - Assert.AreEqual(testSeries[i], min); - } - - Assert.AreEqual(minHeap.Count, minHeap.Count); + var incremented = testSeries[i] + rnd.Next(0, 1000); + maxHeap.UpdateKey(testSeries[i], incremented); + testSeries[i] = incremented; } - [Test] - public void BuildMaxHeap_CreateHeap_HeapIsCheked() + testSeries = testSeries.OrderByDescending(x => x).ToList(); + for (var i = 0; i < nodeCount - 2; i++) { - var nodeCount = 1000 * 10; - var maxHeap = new PairingHeap(Sorting.Descending); - for (var i = 0; i <= nodeCount; i++) - { - maxHeap.Insert(i); - } - - for (var i = 0; i <= nodeCount; i++) - { - maxHeap.UpdateKey(i, i + 1); - } - - Assert.AreEqual(maxHeap.Count, maxHeap.Count); - - var max = 0; - for (var i = nodeCount; i >= 0; i--) - { - max = maxHeap.Extract(); - Assert.AreEqual(max, i + 1); - } - - var rnd = new Random(); - var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(_ => rnd.Next()).ToList(); - - foreach (var item in testSeries) - { - maxHeap.Insert(item); - } - - for (var i = 0; i < testSeries.Count; i++) - { - var incremented = testSeries[i] + rnd.Next(0, 1000); - maxHeap.UpdateKey(testSeries[i], incremented); - testSeries[i] = incremented; - } - - testSeries = testSeries.OrderByDescending(x => x).ToList(); - for (var i = 0; i < nodeCount - 2; i++) - { - max = maxHeap.Extract(); - Assert.AreEqual(testSeries[i], max); - } - - Assert.AreEqual(maxHeap.Count, maxHeap.Count); + max = maxHeap.Extract(); + Assert.AreEqual(testSeries[i], max); } + + Assert.AreEqual(maxHeap.Count, maxHeap.Count); } } diff --git a/DataStructures.Tests/InvertedIndexTests.cs b/DataStructures.Tests/InvertedIndexTests.cs index 77542e4a..e1274e5f 100644 --- a/DataStructures.Tests/InvertedIndexTests.cs +++ b/DataStructures.Tests/InvertedIndexTests.cs @@ -1,37 +1,36 @@ -using System.Collections.Generic; +using System.Collections.Generic; using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests +namespace DataStructures.Tests; + +public class InvertedIndexTests { - public class InvertedIndexTests + [Test] + public void Or_GetSourcesWithAtLeastOneFromList_ReturnAllSources() { - [Test] - public void Or_GetSourcesWithAtLeastOneFromList_ReturnAllSources() - { - var index = new InvertedIndex(); - var source1 = "one star is sparkling bright"; - var source2 = "two stars are sparkling even brighter"; - index.AddToIndex(nameof(source1), source1); - index.AddToIndex(nameof(source2), source2); + var index = new InvertedIndex(); + var source1 = "one star is sparkling bright"; + var source2 = "two stars are sparkling even brighter"; + index.AddToIndex(nameof(source1), source1); + index.AddToIndex(nameof(source2), source2); - var or = index.Or(new List { "star", "sparkling" }); + var or = index.Or(new List { "star", "sparkling" }); - or.Should().BeEquivalentTo(nameof(source1), nameof(source2)); - } + or.Should().BeEquivalentTo(nameof(source1), nameof(source2)); + } - [Test] - public void And_GetSourcesWithAllInsideList_ReturnFirstSource() - { - var index = new InvertedIndex(); - var source1 = "one star is sparkling bright"; - var source2 = "two stars are sparkling even brighter"; - index.AddToIndex(nameof(source1), source1); - index.AddToIndex(nameof(source2), source2); + [Test] + public void And_GetSourcesWithAllInsideList_ReturnFirstSource() + { + var index = new InvertedIndex(); + var source1 = "one star is sparkling bright"; + var source2 = "two stars are sparkling even brighter"; + index.AddToIndex(nameof(source1), source1); + index.AddToIndex(nameof(source2), source2); - var and = index.And(new List { "star", "sparkling" }); + var and = index.And(new List { "star", "sparkling" }); - and.Should().BeEquivalentTo(nameof(source1)); - } + and.Should().BeEquivalentTo(nameof(source1)); } } diff --git a/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs b/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs index ba80c407..d8629ddb 100644 --- a/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs +++ b/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs @@ -3,133 +3,132 @@ using DataStructures.LinkedList.DoublyLinkedList; using NUnit.Framework; -namespace DataStructures.Tests.LinkedList +namespace DataStructures.Tests.LinkedList; + +public static class DoublyLinkedListTests { - public static class DoublyLinkedListTests + [Test] + public static void TestGetData() + { + var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); + var arr = dll.GetData().ToArray(); + + Assert.AreEqual(dll.Count, 5); + Assert.AreEqual(new[] { 0, 1, 2, 3, 4 }, arr); + } + + [Test] + public static void TestGetAt() { - [Test] - public static void TestGetData() - { - var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); - var arr = dll.GetData().ToArray(); - - Assert.AreEqual(dll.Count, 5); - Assert.AreEqual(new[] { 0, 1, 2, 3, 4 }, arr); - } - - [Test] - public static void TestGetAt() - { - var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); - - var one = dll.GetAt(1); - var three = dll.GetAt(3); - - Assert.AreEqual(one.Data, 1); - Assert.AreEqual(three.Data, 3); - Assert.Throws( - () => dll.GetAt(-1) - ); - Assert.Throws( - () => dll.GetAt(5) - ); - } - - [Test] - public static void TestAddtion() - { - var dll = new DoublyLinkedList(0); - var one = dll.Add(1); - - dll.Add(3); - dll.AddAfter(2, one); - dll.Add(4); - - var arr = dll.GetData().ToArray(); - var reversedArr = dll.GetDataReversed().ToArray(); - - Assert.AreEqual(dll.Count, 5); - Assert.AreEqual(new[] { 0, 1, 2, 3, 4 }, arr); - Assert.AreEqual(new[] { 4, 3, 2, 1, 0 }, reversedArr); - } - - [Test] - public static void TestRemove() - { - var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); - - dll.RemoveNode(dll.Find(2)); - dll.RemoveHead(); - dll.Remove(); - - var arr = dll.GetData().ToArray(); - var reversedArr = dll.GetDataReversed().ToArray(); - - Assert.AreEqual(dll.Count, 2); - Assert.AreEqual(new[] { 1, 3 }, arr); - Assert.AreEqual(new[] { 3, 1 }, reversedArr); - } - - [Test] - public static void TestFind() - { - var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); - - var one = dll.Find(1); - var three = dll.Find(3); - - Assert.AreEqual(one.Data, 1); - Assert.AreEqual(three.Data, 3); - } - - [Test] - public static void TestIndexOf() - { - var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); - - var one = dll.IndexOf(1); - var three = dll.IndexOf(3); - - Assert.AreEqual(one, 1); - Assert.AreEqual(three, 3); - } - - [Test] - public static void TestContains() - { - var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); - - var one = dll.Contains(1); - var six = dll.Contains(6); - - Assert.IsTrue(one); - Assert.IsFalse(six); - } - - [Test] - public static void TestReverse() - { - var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); - dll.Reverse(); - var arr = dll.GetData().ToArray(); - - var empty = new DoublyLinkedList(new int[] { }); - empty.Reverse(); - var emptyArr = empty.GetData().ToArray(); - - Assert.AreEqual(arr, new[] { 4, 3, 2, 1, 0 }); - Assert.AreEqual(emptyArr, new int[] { }); - } - - [Test] - public static void TestGetDataReversed() - { - var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); - var arr = dll.GetData().ToArray(); - var reversedArr = dll.GetDataReversed().ToArray(); - - Assert.AreEqual(arr, new[] { 0, 1, 2, 3, 4 }); - Assert.AreEqual(reversedArr, new[] { 4, 3, 2, 1, 0 }); - } + var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); + + var one = dll.GetAt(1); + var three = dll.GetAt(3); + + Assert.AreEqual(one.Data, 1); + Assert.AreEqual(three.Data, 3); + Assert.Throws( + () => dll.GetAt(-1) + ); + Assert.Throws( + () => dll.GetAt(5) + ); + } + + [Test] + public static void TestAddtion() + { + var dll = new DoublyLinkedList(0); + var one = dll.Add(1); + + dll.Add(3); + dll.AddAfter(2, one); + dll.Add(4); + + var arr = dll.GetData().ToArray(); + var reversedArr = dll.GetDataReversed().ToArray(); + + Assert.AreEqual(dll.Count, 5); + Assert.AreEqual(new[] { 0, 1, 2, 3, 4 }, arr); + Assert.AreEqual(new[] { 4, 3, 2, 1, 0 }, reversedArr); + } + + [Test] + public static void TestRemove() + { + var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); + + dll.RemoveNode(dll.Find(2)); + dll.RemoveHead(); + dll.Remove(); + + var arr = dll.GetData().ToArray(); + var reversedArr = dll.GetDataReversed().ToArray(); + + Assert.AreEqual(dll.Count, 2); + Assert.AreEqual(new[] { 1, 3 }, arr); + Assert.AreEqual(new[] { 3, 1 }, reversedArr); + } + + [Test] + public static void TestFind() + { + var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); + + var one = dll.Find(1); + var three = dll.Find(3); + + Assert.AreEqual(one.Data, 1); + Assert.AreEqual(three.Data, 3); + } + + [Test] + public static void TestIndexOf() + { + var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); + + var one = dll.IndexOf(1); + var three = dll.IndexOf(3); + + Assert.AreEqual(one, 1); + Assert.AreEqual(three, 3); + } + + [Test] + public static void TestContains() + { + var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); + + var one = dll.Contains(1); + var six = dll.Contains(6); + + Assert.IsTrue(one); + Assert.IsFalse(six); + } + + [Test] + public static void TestReverse() + { + var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); + dll.Reverse(); + var arr = dll.GetData().ToArray(); + + var empty = new DoublyLinkedList(new int[] { }); + empty.Reverse(); + var emptyArr = empty.GetData().ToArray(); + + Assert.AreEqual(arr, new[] { 4, 3, 2, 1, 0 }); + Assert.AreEqual(emptyArr, new int[] { }); + } + + [Test] + public static void TestGetDataReversed() + { + var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); + var arr = dll.GetData().ToArray(); + var reversedArr = dll.GetDataReversed().ToArray(); + + Assert.AreEqual(arr, new[] { 0, 1, 2, 3, 4 }); + Assert.AreEqual(reversedArr, new[] { 4, 3, 2, 1, 0 }); } } diff --git a/DataStructures.Tests/LinkedList/LinkedListTests.cs b/DataStructures.Tests/LinkedList/LinkedListTests.cs index 66c61a0a..7cc79db1 100644 --- a/DataStructures.Tests/LinkedList/LinkedListTests.cs +++ b/DataStructures.Tests/LinkedList/LinkedListTests.cs @@ -1,110 +1,109 @@ -using System; +using System; using System.Linq; using DataStructures.LinkedList.SinglyLinkedList; using NUnit.Framework; -namespace DataStructures.Tests.LinkedList +namespace DataStructures.Tests.LinkedList; + +public static class LinkedListTests { - public static class LinkedListTests + [Test] + public static void LengthWorksCorrectly([Random(0, 1000, 100)] int quantity) { - [Test] - public static void LengthWorksCorrectly([Random(0, 1000, 100)] int quantity) + // Arrange + var a = new SinglyLinkedList(); + + // Act + var r = TestContext.CurrentContext.Random; + for (var i = 0; i < quantity; i++) { - // Arrange - var a = new SinglyLinkedList(); - - // Act - var r = TestContext.CurrentContext.Random; - for (var i = 0; i < quantity; i++) - { - _ = a.AddFirst(r.Next()); - } - - // Assert - Assert.AreEqual(quantity, a.Length()); + _ = a.AddFirst(r.Next()); } - [Test] - public static void LengthOnEmptyListIsZero() - { - // Arrange - var a = new SinglyLinkedList(); + // Assert + Assert.AreEqual(quantity, a.Length()); + } - // Act + [Test] + public static void LengthOnEmptyListIsZero() + { + // Arrange + var a = new SinglyLinkedList(); - // Assert - Assert.AreEqual(0, a.Length()); - } + // Act - [Test] - public static void GetItemsFromLinkedList() - { - // Arrange - var testObj = new SinglyLinkedList(); - _ = testObj.AddLast("H"); - _ = testObj.AddLast("E"); - _ = testObj.AddLast("L"); - _ = testObj.AddLast("L"); - _ = testObj.AddLast("O"); - - // Act - var items = testObj.GetListData(); - - // Assert - Assert.AreEqual(5, items.Count()); - Assert.AreEqual("O", testObj.GetElementByIndex(4)); - } + // Assert + Assert.AreEqual(0, a.Length()); + } - [Test] - public static void GetElementByIndex_IndexOutOfRange_ArgumentOutOfRangeExceptionThrown() - { - // Arrange - var list = new SinglyLinkedList(); + [Test] + public static void GetItemsFromLinkedList() + { + // Arrange + var testObj = new SinglyLinkedList(); + _ = testObj.AddLast("H"); + _ = testObj.AddLast("E"); + _ = testObj.AddLast("L"); + _ = testObj.AddLast("L"); + _ = testObj.AddLast("O"); + + // Act + var items = testObj.GetListData(); + + // Assert + Assert.AreEqual(5, items.Count()); + Assert.AreEqual("O", testObj.GetElementByIndex(4)); + } - // Act - _ = list.AddFirst(1); - _ = list.AddFirst(2); - _ = list.AddFirst(3); + [Test] + public static void GetElementByIndex_IndexOutOfRange_ArgumentOutOfRangeExceptionThrown() + { + // Arrange + var list = new SinglyLinkedList(); - // Assert - _ = Assert.Throws(() => list.GetElementByIndex(-1)); - _ = Assert.Throws(() => list.GetElementByIndex(3)); - } + // Act + _ = list.AddFirst(1); + _ = list.AddFirst(2); + _ = list.AddFirst(3); + // Assert + _ = Assert.Throws(() => list.GetElementByIndex(-1)); + _ = Assert.Throws(() => list.GetElementByIndex(3)); + } - [Test] - public static void RemoveItemsFromList() - { - // Arrange - var testObj = new SinglyLinkedList(); - _ = testObj.AddLast("X"); - _ = testObj.AddLast("H"); - _ = testObj.AddLast("E"); - _ = testObj.AddLast("L"); - _ = testObj.AddLast("L"); - _ = testObj.AddLast("I"); - _ = testObj.AddLast("O"); - - // Act - var xRemoveSucess = testObj.DeleteElement("X"); - var oRemoveSucess = testObj.DeleteElement("O"); - var eRemoveSucess = testObj.DeleteElement("E"); - var lRemoveSucess = testObj.DeleteElement("L"); - var l2RemoveSucess = testObj.DeleteElement("L"); - var l3RemoveSucess = testObj.DeleteElement("L"); - var nonExistantRemoveSucess = testObj.DeleteElement("F"); - - var resultString = testObj.GetElementByIndex(0) + testObj.GetElementByIndex(1); - - // Assert - Assert.AreEqual("HI", resultString); - Assert.IsTrue(xRemoveSucess); - Assert.IsTrue(oRemoveSucess); - Assert.IsTrue(eRemoveSucess); - Assert.IsTrue(lRemoveSucess); - Assert.IsTrue(l2RemoveSucess); - Assert.IsFalse(l3RemoveSucess); - Assert.IsFalse(nonExistantRemoveSucess); - } + + [Test] + public static void RemoveItemsFromList() + { + // Arrange + var testObj = new SinglyLinkedList(); + _ = testObj.AddLast("X"); + _ = testObj.AddLast("H"); + _ = testObj.AddLast("E"); + _ = testObj.AddLast("L"); + _ = testObj.AddLast("L"); + _ = testObj.AddLast("I"); + _ = testObj.AddLast("O"); + + // Act + var xRemoveSucess = testObj.DeleteElement("X"); + var oRemoveSucess = testObj.DeleteElement("O"); + var eRemoveSucess = testObj.DeleteElement("E"); + var lRemoveSucess = testObj.DeleteElement("L"); + var l2RemoveSucess = testObj.DeleteElement("L"); + var l3RemoveSucess = testObj.DeleteElement("L"); + var nonExistantRemoveSucess = testObj.DeleteElement("F"); + + var resultString = testObj.GetElementByIndex(0) + testObj.GetElementByIndex(1); + + // Assert + Assert.AreEqual("HI", resultString); + Assert.IsTrue(xRemoveSucess); + Assert.IsTrue(oRemoveSucess); + Assert.IsTrue(eRemoveSucess); + Assert.IsTrue(lRemoveSucess); + Assert.IsTrue(l2RemoveSucess); + Assert.IsFalse(l3RemoveSucess); + Assert.IsFalse(nonExistantRemoveSucess); } } diff --git a/DataStructures.Tests/LinkedList/SkipListTests.cs b/DataStructures.Tests/LinkedList/SkipListTests.cs index 1fe69d17..c8d0873b 100644 --- a/DataStructures.Tests/LinkedList/SkipListTests.cs +++ b/DataStructures.Tests/LinkedList/SkipListTests.cs @@ -4,120 +4,119 @@ using FluentAssertions; using System.Collections.Generic; -namespace DataStructures.Tests.LinkedList +namespace DataStructures.Tests.LinkedList; + +public static class SkipListTests { - public static class SkipListTests + [Test] + public static void TestAdd() + { + var list = new SkipList(); + list.AddOrUpdate(1, 1); + list[2] = 2; + list[3] = 3; + + list.Count.Should().Be(3); + list.GetValues().Should().ContainInOrder(1, 2, 3); + } + + [Test] + public static void TestUpdate() + { + var list = new SkipList(); + + // Add some elements. + list[1] = "v1"; + list[2] = "v2"; + list[5] = "v5"; + + // Update + list.AddOrUpdate(1, "v1-updated"); + list[2] = "v2-updated"; + + list.Count.Should().Be(3); + list.GetValues().Should().ContainInOrder("v1-updated", "v2-updated", "v5"); + } + + [Test] + public static void TestContains() + { + var list = new SkipList(); + list.AddOrUpdate(1, 1); + list.AddOrUpdate(3, 3); + list.AddOrUpdate(5, 5); + + list.Contains(1).Should().BeTrue(); + list.Contains(3).Should().BeTrue(); + list.Contains(5).Should().BeTrue(); + list.Contains(0).Should().BeFalse(); + list.Contains(2).Should().BeFalse(); + list.Contains(9).Should().BeFalse(); + } + + [Test] + public static void TestGetByKey_Success() + { + var list = new SkipList(); + list[1] = "value1"; + + list[1].Should().Be("value1"); + } + + [Test] + public static void TestGetByKey_KeyNotFoundException() { - [Test] - public static void TestAdd() - { - var list = new SkipList(); - list.AddOrUpdate(1, 1); - list[2] = 2; - list[3] = 3; - - list.Count.Should().Be(3); - list.GetValues().Should().ContainInOrder(1, 2, 3); - } - - [Test] - public static void TestUpdate() - { - var list = new SkipList(); - - // Add some elements. - list[1] = "v1"; - list[2] = "v2"; - list[5] = "v5"; - - // Update - list.AddOrUpdate(1, "v1-updated"); - list[2] = "v2-updated"; - - list.Count.Should().Be(3); - list.GetValues().Should().ContainInOrder("v1-updated", "v2-updated", "v5"); - } - - [Test] - public static void TestContains() - { - var list = new SkipList(); - list.AddOrUpdate(1, 1); - list.AddOrUpdate(3, 3); - list.AddOrUpdate(5, 5); - - list.Contains(1).Should().BeTrue(); - list.Contains(3).Should().BeTrue(); - list.Contains(5).Should().BeTrue(); - list.Contains(0).Should().BeFalse(); - list.Contains(2).Should().BeFalse(); - list.Contains(9).Should().BeFalse(); - } - - [Test] - public static void TestGetByKey_Success() - { - var list = new SkipList(); - list[1] = "value1"; - - list[1].Should().Be("value1"); - } - - [Test] - public static void TestGetByKey_KeyNotFoundException() - { - var list = new SkipList(); - list[1] = "value1"; - - string value; - Action act = () => value = list[2]; - act.Should().Throw(); - } - - [Test] - public static void TestRemove_ItemRemoved() - { - var list = new SkipList(); - list.AddOrUpdate(1, 1); - list.AddOrUpdate(2, 2); - list.AddOrUpdate(3, 3); - - list.Count.Should().Be(3); - list.Contains(2).Should().BeTrue(); - - var isRemoved = list.Remove(2); - - list.Count.Should().Be(2); - list.Contains(2).Should().BeFalse(); - isRemoved.Should().BeTrue(); - } - - [Test] - public static void TestRemove_ItemNotFound() - { - var list = new SkipList(); - list.AddOrUpdate(1, 1); - list.AddOrUpdate(2, 2); - list.AddOrUpdate(3, 3); - - var isRemoved = list.Remove(222); - - list.Count.Should().Be(3); - isRemoved.Should().BeFalse(); - } - - [Test] - public static void TestGetValues() - { - var list = new SkipList(); - list[4] = "four"; - list[2] = "two"; - list[3] = "three"; - list[1] = "one"; - - var valuesSortedByKey = list.GetValues(); - - valuesSortedByKey.Should().ContainInOrder("one", "two", "three", "four"); - } + var list = new SkipList(); + list[1] = "value1"; + + string value; + Action act = () => value = list[2]; + act.Should().Throw(); + } + + [Test] + public static void TestRemove_ItemRemoved() + { + var list = new SkipList(); + list.AddOrUpdate(1, 1); + list.AddOrUpdate(2, 2); + list.AddOrUpdate(3, 3); + + list.Count.Should().Be(3); + list.Contains(2).Should().BeTrue(); + + var isRemoved = list.Remove(2); + + list.Count.Should().Be(2); + list.Contains(2).Should().BeFalse(); + isRemoved.Should().BeTrue(); + } + + [Test] + public static void TestRemove_ItemNotFound() + { + var list = new SkipList(); + list.AddOrUpdate(1, 1); + list.AddOrUpdate(2, 2); + list.AddOrUpdate(3, 3); + + var isRemoved = list.Remove(222); + + list.Count.Should().Be(3); + isRemoved.Should().BeFalse(); + } + + [Test] + public static void TestGetValues() + { + var list = new SkipList(); + list[4] = "four"; + list[2] = "two"; + list[3] = "three"; + list[1] = "one"; + + var valuesSortedByKey = list.GetValues(); + + valuesSortedByKey.Should().ContainInOrder("one", "two", "three", "four"); } } diff --git a/DataStructures.Tests/Probabilistic/BloomFilterTests.cs b/DataStructures.Tests/Probabilistic/BloomFilterTests.cs index aaa4ded0..c72d5640 100644 --- a/DataStructures.Tests/Probabilistic/BloomFilterTests.cs +++ b/DataStructures.Tests/Probabilistic/BloomFilterTests.cs @@ -1,118 +1,117 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using DataStructures.Probabilistic; using NUnit.Framework; -namespace DataStructures.Tests.Probabilistic +namespace DataStructures.Tests.Probabilistic; + +public class BloomFilterTests { - public class BloomFilterTests + static readonly string[] TestNames = { "kal;jsnfka", "alkjsdfn;lakm", "aljfopiawjf", "afowjeaofeij", "oajwsefoaiwje", "aoiwjfaoiejmf", "aoijfoawiejf" }; + + private class SimpleObject { - static readonly string[] TestNames = { "kal;jsnfka", "alkjsdfn;lakm", "aljfopiawjf", "afowjeaofeij", "oajwsefoaiwje", "aoiwjfaoiejmf", "aoijfoawiejf" }; + public string Name { get; set; } + public int Number { get; set; } - private class SimpleObject + public SimpleObject(string name, int number) { - public string Name { get; set; } - public int Number { get; set; } - - public SimpleObject(string name, int number) - { - Name = name; - Number = number; - } + Name = name; + Number = number; } + } - private class SimpleObjectOverridenHash - { - private const uint FnvPrime = 16777619; - private const uint FnvOffsetBasis = 2166136261; - public string Name { get; set; } - public int Number { get; set; } + private class SimpleObjectOverridenHash + { + private const uint FnvPrime = 16777619; + private const uint FnvOffsetBasis = 2166136261; + public string Name { get; set; } + public int Number { get; set; } - public SimpleObjectOverridenHash(string name, int number) - { - Name = name; - Number = number; - } + public SimpleObjectOverridenHash(string name, int number) + { + Name = name; + Number = number; + } - public override int GetHashCode() + public override int GetHashCode() + { + var bytes = Encoding.UTF8.GetBytes(Name).Concat(BitConverter.GetBytes(Number)); + var hash = FnvOffsetBasis; + foreach (var @byte in bytes) { - var bytes = Encoding.UTF8.GetBytes(Name).Concat(BitConverter.GetBytes(Number)); - var hash = FnvOffsetBasis; - foreach (var @byte in bytes) - { - hash = hash * FnvPrime; - hash ^= @byte; - } - - return (int)hash; + hash = hash * FnvPrime; + hash ^= @byte; } - public override bool Equals(object? obj) - { - return obj is SimpleObjectOverridenHash asSimpleObj && asSimpleObj.Name == Name && asSimpleObj.Number == Number; - } + return (int)hash; } - [Test] - public void TestBloomFilterInsertOptimalSize() + public override bool Equals(object? obj) { - var filter = new BloomFilter(1000); - var set = new HashSet(); - var rand = new Random(124); - var falsePositives = 0; - for (var i = 0; i < 1000; i++) - { - var k = rand.Next(0, 1000); - if (!set.Contains(k) && filter.Search(k)) - { - falsePositives++; - } - filter.Insert(k); - set.Add(k); - Assert.IsTrue(filter.Search(k)); - } - - Assert.True(.05 > falsePositives / 1000.0); // be a bit generous in our fault tolerance here + return obj is SimpleObjectOverridenHash asSimpleObj && asSimpleObj.Name == Name && asSimpleObj.Number == Number; } + } - [Test] - public void TestBloomFilterInsert() + [Test] + public void TestBloomFilterInsertOptimalSize() + { + var filter = new BloomFilter(1000); + var set = new HashSet(); + var rand = new Random(124); + var falsePositives = 0; + for (var i = 0; i < 1000; i++) { - var filter = new BloomFilter(100000, 3); - var rand = new Random(); - for (var i = 0; i < 1000; i++) + var k = rand.Next(0, 1000); + if (!set.Contains(k) && filter.Search(k)) { - var simpleObject = new SimpleObject(TestNames[rand.Next(TestNames.Length)], rand.Next(15)); - filter.Insert(simpleObject); - Assert.IsTrue(filter.Search(simpleObject)); + falsePositives++; } + filter.Insert(k); + set.Add(k); + Assert.IsTrue(filter.Search(k)); } - [Test] - public void TestBloomFilterSearchOverridenHash() + Assert.True(.05 > falsePositives / 1000.0); // be a bit generous in our fault tolerance here + } + + [Test] + public void TestBloomFilterInsert() + { + var filter = new BloomFilter(100000, 3); + var rand = new Random(); + for (var i = 0; i < 1000; i++) { - var filter = new BloomFilter(100000, 3); - var simpleObjectInserted = new SimpleObjectOverridenHash("foo", 1); - var simpleObjectInserted2 = new SimpleObjectOverridenHash("foo", 1); - var simpleObjectNotInserted = new SimpleObjectOverridenHash("bar", 2); - filter.Insert(simpleObjectInserted); - Assert.IsTrue(filter.Search(simpleObjectInserted)); - Assert.IsTrue(filter.Search(simpleObjectInserted2)); - Assert.IsFalse(filter.Search(simpleObjectNotInserted)); + var simpleObject = new SimpleObject(TestNames[rand.Next(TestNames.Length)], rand.Next(15)); + filter.Insert(simpleObject); + Assert.IsTrue(filter.Search(simpleObject)); } + } - [Test] - public void TestBloomFilterSearch() - { - var filter = new BloomFilter(10000, 3); - var simpleObjectInserted = new SimpleObject("foo", 1); - var simpleObjectNotInserted = new SimpleObject("foo", 1); - filter.Insert(simpleObjectInserted); - Assert.False(filter.Search(simpleObjectNotInserted)); - Assert.True(filter.Search(simpleObjectInserted)); + [Test] + public void TestBloomFilterSearchOverridenHash() + { + var filter = new BloomFilter(100000, 3); + var simpleObjectInserted = new SimpleObjectOverridenHash("foo", 1); + var simpleObjectInserted2 = new SimpleObjectOverridenHash("foo", 1); + var simpleObjectNotInserted = new SimpleObjectOverridenHash("bar", 2); + filter.Insert(simpleObjectInserted); + Assert.IsTrue(filter.Search(simpleObjectInserted)); + Assert.IsTrue(filter.Search(simpleObjectInserted2)); + Assert.IsFalse(filter.Search(simpleObjectNotInserted)); + } + + [Test] + public void TestBloomFilterSearch() + { + var filter = new BloomFilter(10000, 3); + var simpleObjectInserted = new SimpleObject("foo", 1); + var simpleObjectNotInserted = new SimpleObject("foo", 1); + filter.Insert(simpleObjectInserted); + Assert.False(filter.Search(simpleObjectNotInserted)); + Assert.True(filter.Search(simpleObjectInserted)); - } } } diff --git a/DataStructures.Tests/Probabilistic/CountMinSketchTests.cs b/DataStructures.Tests/Probabilistic/CountMinSketchTests.cs index b8905397..201cca96 100644 --- a/DataStructures.Tests/Probabilistic/CountMinSketchTests.cs +++ b/DataStructures.Tests/Probabilistic/CountMinSketchTests.cs @@ -1,91 +1,90 @@ -using System; +using System; using System.Collections.Generic; using DataStructures.Probabilistic; using NUnit.Framework; using FluentAssertions; -namespace DataStructures.Tests.Probabilistic +namespace DataStructures.Tests.Probabilistic; + +public class CountMinSketchTests { - public class CountMinSketchTests + public class SimpleObject { - public class SimpleObject - { - public string Name { get; set; } - public int Number { get; set; } + public string Name { get; set; } + public int Number { get; set; } - public SimpleObject(string name, int number) - { - Name = name; - Number = number; - } - } - - [Test] - public void TestInsertAndCount() + public SimpleObject(string name, int number) { - var obj1 = new SimpleObject("foo", 5); - var obj2 = new SimpleObject("bar", 6); + Name = name; + Number = number; + } + } - var sketch = new CountMinSketch(200, 5); + [Test] + public void TestInsertAndCount() + { + var obj1 = new SimpleObject("foo", 5); + var obj2 = new SimpleObject("bar", 6); - for (var i = 0; i < 5000; i++) - { - sketch.Insert(obj1); - sketch.Insert(obj2); - } + var sketch = new CountMinSketch(200, 5); - sketch.Query(obj1).Should().BeGreaterOrEqualTo(5000); - sketch.Query(obj2).Should().BeGreaterOrEqualTo(5000); + for (var i = 0; i < 5000; i++) + { + sketch.Insert(obj1); + sketch.Insert(obj2); } - [Test] - public void TestOptimalInitializer() - { - var obj1 = new SimpleObject("foo", 5); - var obj2 = new SimpleObject("bar", 6); + sketch.Query(obj1).Should().BeGreaterOrEqualTo(5000); + sketch.Query(obj2).Should().BeGreaterOrEqualTo(5000); + } - var sketch = new CountMinSketch(.001, .05); + [Test] + public void TestOptimalInitializer() + { + var obj1 = new SimpleObject("foo", 5); + var obj2 = new SimpleObject("bar", 6); - for (var i = 0; i < 5000; i++) - { - sketch.Insert(obj1); - sketch.Insert(obj2); - } + var sketch = new CountMinSketch(.001, .05); - sketch.Query(obj1).Should().BeGreaterOrEqualTo(5000); - sketch.Query(obj2).Should().BeGreaterOrEqualTo(5000); + for (var i = 0; i < 5000; i++) + { + sketch.Insert(obj1); + sketch.Insert(obj2); } - [Test] - public void TestProbabilities() + sketch.Query(obj1).Should().BeGreaterOrEqualTo(5000); + sketch.Query(obj2).Should().BeGreaterOrEqualTo(5000); + } + + [Test] + public void TestProbabilities() + { + var sketch = new CountMinSketch(.01, .05); + var random = new Random(); + var insertedItems = new Dictionary(); + for (var i = 0; i < 10000; i++) { - var sketch = new CountMinSketch(.01, .05); - var random = new Random(); - var insertedItems = new Dictionary(); - for (var i = 0; i < 10000; i++) + var item = random.Next(0, 1000000); + sketch.Insert(item); + if (insertedItems.ContainsKey(item)) { - var item = random.Next(0, 1000000); - sketch.Insert(item); - if (insertedItems.ContainsKey(item)) - { - insertedItems[item]++; - } - else - { - insertedItems.Add(item, 1); - } + insertedItems[item]++; } - - var numMisses = 0; - foreach (var item in insertedItems) + else { - if (sketch.Query(item.Key) - item.Value > .01 * 100000) - { - numMisses++; - } + insertedItems.Add(item, 1); } + } - (numMisses / (double)insertedItems.Count).Should().BeLessOrEqualTo(.05); + var numMisses = 0; + foreach (var item in insertedItems) + { + if (sketch.Query(item.Key) - item.Value > .01 * 100000) + { + numMisses++; + } } + + (numMisses / (double)insertedItems.Count).Should().BeLessOrEqualTo(.05); } } diff --git a/DataStructures.Tests/Probabilistic/HyperLogLogTest.cs b/DataStructures.Tests/Probabilistic/HyperLogLogTest.cs index 2b22a720..bd45c87c 100644 --- a/DataStructures.Tests/Probabilistic/HyperLogLogTest.cs +++ b/DataStructures.Tests/Probabilistic/HyperLogLogTest.cs @@ -1,61 +1,60 @@ -using System; +using System; using System.Collections.Generic; using DataStructures.Probabilistic; using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests.Probabilistic +namespace DataStructures.Tests.Probabilistic; + +public class HyperLogLogTest { - public class HyperLogLogTest + [Test] + public void TestHyperLogLog() { - [Test] - public void TestHyperLogLog() + var hll = new HyperLogLog(); + HashSet actual = new (); + + var rand = new Random(); + var tolerance = .05; + for (var i = 0; i < 10000; i++) { - var hll = new HyperLogLog(); - HashSet actual = new (); + var k = rand.Next(20000); + hll.Add(k); + actual.Add(k); + } - var rand = new Random(); - var tolerance = .05; - for (var i = 0; i < 10000; i++) - { - var k = rand.Next(20000); - hll.Add(k); - actual.Add(k); - } + hll.Cardinality().Should() + .BeGreaterOrEqualTo((int)(actual.Count * (1 - tolerance))) + .And + .BeLessOrEqualTo((int)(actual.Count * (1 + tolerance))); + } - hll.Cardinality().Should() - .BeGreaterOrEqualTo((int)(actual.Count * (1 - tolerance))) - .And - .BeLessOrEqualTo((int)(actual.Count * (1 + tolerance))); + [Test] + public void TestHyperLogLogMerge() + { + var hll1 = new HyperLogLog(); + var hll2 = new HyperLogLog(); + var rand = new Random(); + var tolerance = .05; + HashSet actual = new (); + for (var i = 0; i < 5000; i++) + { + var k = rand.Next(20000); + hll1.Add(k); + actual.Add(k); } - [Test] - public void TestHyperLogLogMerge() + for (var i = 0; i < 5000; i++) { - var hll1 = new HyperLogLog(); - var hll2 = new HyperLogLog(); - var rand = new Random(); - var tolerance = .05; - HashSet actual = new (); - for (var i = 0; i < 5000; i++) - { - var k = rand.Next(20000); - hll1.Add(k); - actual.Add(k); - } - - for (var i = 0; i < 5000; i++) - { - var k = rand.Next(20000); - hll2.Add(k); - actual.Add(k); - } - - var hll = HyperLogLog.Merge(hll1, hll2); - hll.Cardinality().Should() - .BeGreaterOrEqualTo((int)(actual.Count * (1 - tolerance))) - .And - .BeLessOrEqualTo((int)(actual.Count * (1 + tolerance))); + var k = rand.Next(20000); + hll2.Add(k); + actual.Add(k); } + + var hll = HyperLogLog.Merge(hll1, hll2); + hll.Cardinality().Should() + .BeGreaterOrEqualTo((int)(actual.Count * (1 - tolerance))) + .And + .BeLessOrEqualTo((int)(actual.Count * (1 + tolerance))); } } diff --git a/DataStructures.Tests/Queue/ArrayBasedQueueTests.cs b/DataStructures.Tests/Queue/ArrayBasedQueueTests.cs index 0ab39754..f980e041 100644 --- a/DataStructures.Tests/Queue/ArrayBasedQueueTests.cs +++ b/DataStructures.Tests/Queue/ArrayBasedQueueTests.cs @@ -1,133 +1,132 @@ -using System; +using System; using System.Text; using DataStructures.Queue; using NUnit.Framework; -namespace DataStructures.Tests.Queue +namespace DataStructures.Tests.Queue; + +public static class ArrayBasedQueueTests { - public static class ArrayBasedQueueTests + [Test] + public static void DequeueWorksCorrectly() { - [Test] - public static void DequeueWorksCorrectly() + // Arrange + var q = new ArrayBasedQueue(3); + q.Enqueue('A'); + q.Enqueue('B'); + q.Enqueue('C'); + var result = new StringBuilder(); + + // Act + for (var i = 0; i < 3; i++) { - // Arrange - var q = new ArrayBasedQueue(3); - q.Enqueue('A'); - q.Enqueue('B'); - q.Enqueue('C'); - var result = new StringBuilder(); - - // Act - for (var i = 0; i < 3; i++) - { - result.Append(q.Dequeue()); - } - - // Assert - Assert.AreEqual("ABC", result.ToString()); - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + result.Append(q.Dequeue()); } - [Test] - public static void PeekWorksCorrectly() - { - // Arrange - var q = new ArrayBasedQueue(2); - q.Enqueue(1); - q.Enqueue(2); - var peeked = 0; - - // Act - for (var i = 0; i < 3; i++) - { - peeked = q.Peek(); - } - - // Assert - Assert.AreEqual(1, peeked); - Assert.IsFalse(q.IsEmpty(), "Queue is empty"); - Assert.IsTrue(q.IsFull(), "Queue is full"); - } + // Assert + Assert.AreEqual("ABC", result.ToString()); + Assert.IsTrue(q.IsEmpty(), "Queue is empty"); + Assert.IsFalse(q.IsFull(), "Queue is full"); + } - [Test] - public static void DequeueEmptyQueueThrowsInvalidOperationException() + [Test] + public static void PeekWorksCorrectly() + { + // Arrange + var q = new ArrayBasedQueue(2); + q.Enqueue(1); + q.Enqueue(2); + var peeked = 0; + + // Act + for (var i = 0; i < 3; i++) { - // Arrange - var q = new ArrayBasedQueue(1); - Exception? exception = null; - - // Act - try - { - q.Dequeue(); - } - catch (Exception ex) - { - exception = ex; - } - - // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + peeked = q.Peek(); } - [Test] - public static void EnqueueFullQueueThrowsInvalidOperationException() + // Assert + Assert.AreEqual(1, peeked); + Assert.IsFalse(q.IsEmpty(), "Queue is empty"); + Assert.IsTrue(q.IsFull(), "Queue is full"); + } + + [Test] + public static void DequeueEmptyQueueThrowsInvalidOperationException() + { + // Arrange + var q = new ArrayBasedQueue(1); + Exception? exception = null; + + // Act + try { - // Arrange - var q = new ArrayBasedQueue(1); - q.Enqueue(0); - Exception? exception = null; - - // Act - try - { - q.Enqueue(1); - } - catch (Exception ex) - { - exception = ex; - } - - // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + q.Dequeue(); } - - [Test] - public static void PeekEmptyQueueThrowsInvalidOperationException() + catch (Exception ex) { - // Arrange - var q = new ArrayBasedQueue(1); - Exception? exception = null; - - // Act - try - { - q.Peek(); - } - catch (Exception ex) - { - exception = ex; - } - - // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + exception = ex; } - [Test] - public static void ClearWorksCorrectly() + // Assert + Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + } + + [Test] + public static void EnqueueFullQueueThrowsInvalidOperationException() + { + // Arrange + var q = new ArrayBasedQueue(1); + q.Enqueue(0); + Exception? exception = null; + + // Act + try { - // Arrange - var q = new ArrayBasedQueue(2); q.Enqueue(1); - q.Enqueue(2); + } + catch (Exception ex) + { + exception = ex; + } + + // Assert + Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + } - // Act - q.Clear(); + [Test] + public static void PeekEmptyQueueThrowsInvalidOperationException() + { + // Arrange + var q = new ArrayBasedQueue(1); + Exception? exception = null; - // Assert - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + // Act + try + { + q.Peek(); } + catch (Exception ex) + { + exception = ex; + } + + // Assert + Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + } + + [Test] + public static void ClearWorksCorrectly() + { + // Arrange + var q = new ArrayBasedQueue(2); + q.Enqueue(1); + q.Enqueue(2); + + // Act + q.Clear(); + + // Assert + Assert.IsTrue(q.IsEmpty(), "Queue is empty"); + Assert.IsFalse(q.IsFull(), "Queue is full"); } } diff --git a/DataStructures.Tests/Queue/ListBasedQueueTests.cs b/DataStructures.Tests/Queue/ListBasedQueueTests.cs index f99fa306..a3477d50 100644 --- a/DataStructures.Tests/Queue/ListBasedQueueTests.cs +++ b/DataStructures.Tests/Queue/ListBasedQueueTests.cs @@ -1,111 +1,110 @@ -using System; +using System; using System.Text; using DataStructures.Queue; using NUnit.Framework; -namespace DataStructures.Tests.Queue +namespace DataStructures.Tests.Queue; + +public static class ListBasedQueueTests { - public static class ListBasedQueueTests + [Test] + public static void DequeueWorksCorrectly() { - [Test] - public static void DequeueWorksCorrectly() + // Arrange + var q = new ListBasedQueue(); + q.Enqueue('A'); + q.Enqueue('B'); + q.Enqueue('C'); + var result = new StringBuilder(); + + // Act + for (var i = 0; i < 3; i++) { - // Arrange - var q = new ListBasedQueue(); - q.Enqueue('A'); - q.Enqueue('B'); - q.Enqueue('C'); - var result = new StringBuilder(); - - // Act - for (var i = 0; i < 3; i++) - { - result.Append(q.Dequeue()); - } - - // Assert - Assert.AreEqual("ABC", result.ToString()); - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + result.Append(q.Dequeue()); } - [Test] - public static void PeekWorksCorrectly() + // Assert + Assert.AreEqual("ABC", result.ToString()); + Assert.IsTrue(q.IsEmpty(), "Queue is empty"); + Assert.IsFalse(q.IsFull(), "Queue is full"); + } + + [Test] + public static void PeekWorksCorrectly() + { + // Arrange + var q = new ListBasedQueue(); + q.Enqueue(1); + q.Enqueue(2); + var peeked = 0; + + // Act + for (var i = 0; i < 3; i++) { - // Arrange - var q = new ListBasedQueue(); - q.Enqueue(1); - q.Enqueue(2); - var peeked = 0; - - // Act - for (var i = 0; i < 3; i++) - { - peeked = q.Peek(); - } - - // Assert - Assert.AreEqual(1, peeked); - Assert.IsFalse(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + peeked = q.Peek(); } - [Test] - public static void DequeueEmptyQueueThrowsInvalidOperationException() + // Assert + Assert.AreEqual(1, peeked); + Assert.IsFalse(q.IsEmpty(), "Queue is empty"); + Assert.IsFalse(q.IsFull(), "Queue is full"); + } + + [Test] + public static void DequeueEmptyQueueThrowsInvalidOperationException() + { + // Arrange + var q = new ListBasedQueue(); + Exception? exception = null; + + // Act + try { - // Arrange - var q = new ListBasedQueue(); - Exception? exception = null; - - // Act - try - { - q.Dequeue(); - } - catch (Exception ex) - { - exception = ex; - } - - // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + q.Dequeue(); } - - [Test] - public static void PeekEmptyQueueThrowsInvalidOperationException() + catch (Exception ex) { - // Arrange - var q = new ListBasedQueue(); - Exception? exception = null; - - // Act - try - { - q.Peek(); - } - catch (Exception ex) - { - exception = ex; - } - - // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + exception = ex; } - [Test] - public static void ClearWorksCorrectly() - { - // Arrange - var q = new ListBasedQueue(); - q.Enqueue(1); - q.Enqueue(2); + // Assert + Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + } - // Act - q.Clear(); + [Test] + public static void PeekEmptyQueueThrowsInvalidOperationException() + { + // Arrange + var q = new ListBasedQueue(); + Exception? exception = null; - // Assert - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + // Act + try + { + q.Peek(); } + catch (Exception ex) + { + exception = ex; + } + + // Assert + Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + } + + [Test] + public static void ClearWorksCorrectly() + { + // Arrange + var q = new ListBasedQueue(); + q.Enqueue(1); + q.Enqueue(2); + + // Act + q.Clear(); + + // Assert + Assert.IsTrue(q.IsEmpty(), "Queue is empty"); + Assert.IsFalse(q.IsFull(), "Queue is full"); } } diff --git a/DataStructures.Tests/Queue/StackBasedQueueTests.cs b/DataStructures.Tests/Queue/StackBasedQueueTests.cs index 3913b6ea..7d322bad 100644 --- a/DataStructures.Tests/Queue/StackBasedQueueTests.cs +++ b/DataStructures.Tests/Queue/StackBasedQueueTests.cs @@ -1,111 +1,110 @@ -using System; +using System; using System.Text; using DataStructures.Queue; using NUnit.Framework; -namespace DataStructures.Tests.Queue +namespace DataStructures.Tests.Queue; + +public static class StackBasedQueueTests { - public static class StackBasedQueueTests + [Test] + public static void DequeueWorksCorrectly() { - [Test] - public static void DequeueWorksCorrectly() + // Arrange + var q = new StackBasedQueue(); + q.Enqueue('A'); + q.Enqueue('B'); + q.Enqueue('C'); + var result = new StringBuilder(); + + // Act + for (var i = 0; i < 3; i++) { - // Arrange - var q = new StackBasedQueue(); - q.Enqueue('A'); - q.Enqueue('B'); - q.Enqueue('C'); - var result = new StringBuilder(); - - // Act - for (var i = 0; i < 3; i++) - { - result.Append(q.Dequeue()); - } - - // Assert - Assert.AreEqual("ABC", result.ToString()); - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + result.Append(q.Dequeue()); } - [Test] - public static void PeekWorksCorrectly() + // Assert + Assert.AreEqual("ABC", result.ToString()); + Assert.IsTrue(q.IsEmpty(), "Queue is empty"); + Assert.IsFalse(q.IsFull(), "Queue is full"); + } + + [Test] + public static void PeekWorksCorrectly() + { + // Arrange + var q = new StackBasedQueue(); + q.Enqueue(1); + q.Enqueue(2); + var peeked = 0; + + // Act + for (var i = 0; i < 3; i++) { - // Arrange - var q = new StackBasedQueue(); - q.Enqueue(1); - q.Enqueue(2); - var peeked = 0; - - // Act - for (var i = 0; i < 3; i++) - { - peeked = q.Peek(); - } - - // Assert - Assert.AreEqual(1, peeked); - Assert.IsFalse(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + peeked = q.Peek(); } - [Test] - public static void DequeueEmptyQueueThrowsInvalidOperationException() + // Assert + Assert.AreEqual(1, peeked); + Assert.IsFalse(q.IsEmpty(), "Queue is empty"); + Assert.IsFalse(q.IsFull(), "Queue is full"); + } + + [Test] + public static void DequeueEmptyQueueThrowsInvalidOperationException() + { + // Arrange + var q = new StackBasedQueue(); + Exception? exception = null; + + // Act + try { - // Arrange - var q = new StackBasedQueue(); - Exception? exception = null; - - // Act - try - { - q.Dequeue(); - } - catch (Exception ex) - { - exception = ex; - } - - // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + q.Dequeue(); } - - [Test] - public static void PeekEmptyQueueThrowsInvalidOperationException() + catch (Exception ex) { - // Arrange - var q = new StackBasedQueue(); - Exception? exception = null; - - // Act - try - { - q.Peek(); - } - catch (Exception ex) - { - exception = ex; - } - - // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + exception = ex; } - [Test] - public static void ClearWorksCorrectly() - { - // Arrange - var q = new StackBasedQueue(); - q.Enqueue(1); - q.Enqueue(2); + // Assert + Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + } - // Act - q.Clear(); + [Test] + public static void PeekEmptyQueueThrowsInvalidOperationException() + { + // Arrange + var q = new StackBasedQueue(); + Exception? exception = null; - // Assert - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + // Act + try + { + q.Peek(); } + catch (Exception ex) + { + exception = ex; + } + + // Assert + Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + } + + [Test] + public static void ClearWorksCorrectly() + { + // Arrange + var q = new StackBasedQueue(); + q.Enqueue(1); + q.Enqueue(2); + + // Act + q.Clear(); + + // Assert + Assert.IsTrue(q.IsEmpty(), "Queue is empty"); + Assert.IsFalse(q.IsFull(), "Queue is full"); } } diff --git a/DataStructures.Tests/RedBlackTreeTests.cs b/DataStructures.Tests/RedBlackTreeTests.cs index 4486e836..8dc0ad58 100644 --- a/DataStructures.Tests/RedBlackTreeTests.cs +++ b/DataStructures.Tests/RedBlackTreeTests.cs @@ -5,375 +5,374 @@ using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests +namespace DataStructures.Tests; + +internal class RedBlackTreeTests { - internal class RedBlackTreeTests + [Test] + public void Constructor_UseCustomComparer_FormsCorrect_Tree() { - [Test] - public void Constructor_UseCustomComparer_FormsCorrect_Tree() - { - var tree = new RedBlackTree(Comparer.Create((x, y) => y.CompareTo(x))); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetMin().Should().Be(10); - tree.GetMax().Should().Be(1); - tree.GetKeysInOrder().SequenceEqual(new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }).Should().BeTrue(); - } - - [Test] - public void Add_Case3_FormsCorrectTree() - { - var tree = new RedBlackTree(); - tree.Add(5); - tree.Count.Should().Be(1); - } - - [Test] - public void Add_Case24_FormsCorrectTree() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 5, 4, 6, 3 }); - tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 3, 6 }).Should().BeTrue(); - } + var tree = new RedBlackTree(Comparer.Create((x, y) => y.CompareTo(x))); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetMin().Should().Be(10); + tree.GetMax().Should().Be(1); + tree.GetKeysInOrder().SequenceEqual(new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }).Should().BeTrue(); + } - [Test] - public void Add_Case1_FormsCorrectTree() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 5, 4, 6, 3, 7 }); - tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 3, 6, 7 }).Should().BeTrue(); - } + [Test] + public void Add_Case3_FormsCorrectTree() + { + var tree = new RedBlackTree(); + tree.Add(5); + tree.Count.Should().Be(1); + } - [Test] - public void Add_Case6_FormsCorrectTree() - { - // Right rotation - var tree = new RedBlackTree(); - tree.AddRange(new[] { 5, 4, 6, 3, 2 }); - tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 3, 2, 4, 6 }).Should().BeTrue(); - - // Left rotation - tree = new RedBlackTree(); - tree.AddRange(new[] { 5, 4, 6, 7, 8 }); - tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 7, 6, 8 }).Should().BeTrue(); - } + [Test] + public void Add_Case24_FormsCorrectTree() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 5, 4, 6, 3 }); + tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 3, 6 }).Should().BeTrue(); + } - [Test] - public void Add_Case5_FormsCorrectTree() - { - // Left-right rotation - var tree = new RedBlackTree(); - tree.AddRange(new[] { 5, 4, 6, 2, 3 }); - tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 3, 2, 4, 6 }).Should().BeTrue(); - - // Right-left rotation - tree = new RedBlackTree(); - tree.AddRange(new[] { 5, 4, 6, 8, 7 }); - tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 7, 6, 8 }).Should().BeTrue(); - } + [Test] + public void Add_Case1_FormsCorrectTree() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 5, 4, 6, 3, 7 }); + tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 3, 6, 7 }).Should().BeTrue(); + } - [Test] - public void Add_MultipleKeys_FormsCorrectTree() - { - var tree = new RedBlackTree(); + [Test] + public void Add_Case6_FormsCorrectTree() + { + // Right rotation + var tree = new RedBlackTree(); + tree.AddRange(new[] { 5, 4, 6, 3, 2 }); + tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 3, 2, 4, 6 }).Should().BeTrue(); + + // Left rotation + tree = new RedBlackTree(); + tree.AddRange(new[] { 5, 4, 6, 7, 8 }); + tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 7, 6, 8 }).Should().BeTrue(); + } - foreach (var value in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }) - { - tree.Add(value); - tree.Count.Should().Be(value); - } + [Test] + public void Add_Case5_FormsCorrectTree() + { + // Left-right rotation + var tree = new RedBlackTree(); + tree.AddRange(new[] { 5, 4, 6, 2, 3 }); + tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 3, 2, 4, 6 }).Should().BeTrue(); + + // Right-left rotation + tree = new RedBlackTree(); + tree.AddRange(new[] { 5, 4, 6, 8, 7 }); + tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 7, 6, 8 }).Should().BeTrue(); + } - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 6, 5, 8, 7, 9, 10 }).Should().BeTrue(); - } + [Test] + public void Add_MultipleKeys_FormsCorrectTree() + { + var tree = new RedBlackTree(); - [Test] - public void Add_KeyAlreadyInTree_ThrowsException() + foreach (var value in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }) { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5 }); - Assert.Throws(() => tree.Add(1)); + tree.Add(value); + tree.Count.Should().Be(value); } - [Test] - public void AddRange_MultipleKeys_FormsCorrectTree() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 9, 0, 1, 6, 7, 5, 2, 8, 4, 3 }); - tree.Count.Should().Be(10); - tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 1, 0, 3, 2, 4, 7, 6, 9, 8 }).Should().BeTrue(); - } + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 6, 5, 8, 7, 9, 10 }).Should().BeTrue(); + } - [Test] - public void Remove_SimpleCases_TreeStillValid() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); - tree.Remove(6); - tree.Count.Should().Be(9); - tree.Contains(6).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 8, 11, 13, 15, 17, 22, 25, 27 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 1, 11, 17, 15, 25, 22, 27 }).Should().BeTrue(); - - tree = new RedBlackTree(); - tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); - tree.Remove(1); - tree.Count.Should().Be(9); - tree.Contains(1).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 6, 8, 11, 13, 15, 17, 22, 25, 27 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 6, 11, 17, 15, 25, 22, 27 }).Should().BeTrue(); - - tree = new RedBlackTree(); - tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); - tree.Remove(17); - tree.Count.Should().Be(9); - tree.Contains(17).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 8, 11, 13, 15, 22, 25, 27 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 1, 6, 11, 22, 15, 25, 27 }).Should().BeTrue(); - - tree = new RedBlackTree(); - tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); - tree.Remove(25); - tree.Count.Should().Be(9); - tree.Contains(25).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 8, 11, 13, 15, 17, 22, 27 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 1, 6, 11, 17, 15, 27, 22 }).Should().BeTrue(); - - tree = new RedBlackTree(); - tree.AddRange(new[] { 7, 3, 18, 10, 22, 8, 11, 26 }); - tree.Remove(18); - tree.Count.Should().Be(7); - tree.Contains(18).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 3, 7, 8, 10, 11, 22, 26 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 7, 3, 22, 10, 8, 11, 26 }).Should().BeTrue(); - - tree = new RedBlackTree(); - tree.Add(1); - tree.Add(2); - tree.Remove(1); - tree.Count.Should().Be(1); - tree.GetKeysInOrder().SequenceEqual(new[] { 2 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 2 }).Should().BeTrue(); - } + [Test] + public void Add_KeyAlreadyInTree_ThrowsException() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5 }); + Assert.Throws(() => tree.Add(1)); + } - [Test] - public void Remove_Case1_TreeStillValid() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 5, 2, 8, 1 }); - tree.Remove(1); - tree.Remove(2); - tree.Contains(2).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 5, 8 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 8 }).Should().BeTrue(); - } + [Test] + public void AddRange_MultipleKeys_FormsCorrectTree() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 9, 0, 1, 6, 7, 5, 2, 8, 4, 3 }); + tree.Count.Should().Be(10); + tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 1, 0, 3, 2, 4, 7, 6, 9, 8 }).Should().BeTrue(); + } - [Test] - public void Remove_Case3_TreeStillValid() - { - // Move to case 6 - var tree = new RedBlackTree(); - tree.AddRange(new[] { 7, 3, 18, 1, 10, 22, 8, 11, 26 }); - tree.Remove(1); - tree.Remove(3); - tree.Count.Should().Be(7); - tree.Contains(3).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 7, 8, 10, 11, 18, 22, 26 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 18, 10, 7, 8, 11, 22, 26 }).Should().BeTrue(); - - // Move to case 5 - tree = new RedBlackTree(); - tree.AddRange(new[] { 8, 3, 2, 0, 9, 4, 7, 6, 1, 5 }); - tree.Remove(8); - tree.Remove(6); - tree.Remove(9); - tree.Count.Should().Be(7); - tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 2, 3, 4, 5, 7 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 3, 1, 0, 2, 5, 4, 7 }).Should().BeTrue(); - - // Move to case 4 - tree = new RedBlackTree(); - tree.AddRange(new[] { 7, 5, 8, 4, 6, 3, 2, 9, 0, 1 }); - tree.Remove(9); - tree.Remove(6); - tree.Remove(5); - tree.Remove(8); - tree.Count.Should().Be(6); - tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 2, 3, 4, 7 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 3, 1, 0, 2, 7, 4 }).Should().BeTrue(); - } + [Test] + public void Remove_SimpleCases_TreeStillValid() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); + tree.Remove(6); + tree.Count.Should().Be(9); + tree.Contains(6).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 8, 11, 13, 15, 17, 22, 25, 27 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 1, 11, 17, 15, 25, 22, 27 }).Should().BeTrue(); + + tree = new RedBlackTree(); + tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); + tree.Remove(1); + tree.Count.Should().Be(9); + tree.Contains(1).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 6, 8, 11, 13, 15, 17, 22, 25, 27 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 6, 11, 17, 15, 25, 22, 27 }).Should().BeTrue(); + + tree = new RedBlackTree(); + tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); + tree.Remove(17); + tree.Count.Should().Be(9); + tree.Contains(17).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 8, 11, 13, 15, 22, 25, 27 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 1, 6, 11, 22, 15, 25, 27 }).Should().BeTrue(); + + tree = new RedBlackTree(); + tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); + tree.Remove(25); + tree.Count.Should().Be(9); + tree.Contains(25).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 8, 11, 13, 15, 17, 22, 27 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 1, 6, 11, 17, 15, 27, 22 }).Should().BeTrue(); + + tree = new RedBlackTree(); + tree.AddRange(new[] { 7, 3, 18, 10, 22, 8, 11, 26 }); + tree.Remove(18); + tree.Count.Should().Be(7); + tree.Contains(18).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 3, 7, 8, 10, 11, 22, 26 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 7, 3, 22, 10, 8, 11, 26 }).Should().BeTrue(); + + tree = new RedBlackTree(); + tree.Add(1); + tree.Add(2); + tree.Remove(1); + tree.Count.Should().Be(1); + tree.GetKeysInOrder().SequenceEqual(new[] { 2 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 2 }).Should().BeTrue(); + } - [Test] - public void Remove_Case4_TreeStillValid() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 5, 2, 8, 1, 4, 7, 9, 0, 3 }); - tree.Remove(0); - tree.Remove(3); - tree.Remove(2); - tree.Count.Should().Be(6); - tree.Contains(2).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 4, 5, 7, 8, 9 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 1, 8, 7, 9 }).Should().BeTrue(); - } + [Test] + public void Remove_Case1_TreeStillValid() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 5, 2, 8, 1 }); + tree.Remove(1); + tree.Remove(2); + tree.Contains(2).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 5, 8 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 8 }).Should().BeTrue(); + } - [Test] - public void Remove_Case5_TreeStillValid() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); - tree.Remove(8); - tree.Count.Should().Be(9); - tree.Contains(8).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 11, 13, 15, 17, 22, 25, 27 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 6, 1, 11, 17, 15, 25, 22, 27 }).Should().BeTrue(); - - tree = new RedBlackTree(); - tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 0, 6, 22 }); - tree.Remove(13); - tree.Count.Should().Be(9); - tree.Contains(13).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 6, 8, 11, 15, 17, 22, 25 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 15, 8, 1, 0, 6, 11, 22, 17, 25 }).Should().BeTrue(); - - tree = new RedBlackTree(); - tree.AddRange(new[] { 7, 0, 1, 4, 8, 2, 3, 6, 5, 9 }); - tree.Remove(7); - tree.Remove(0); - tree.Remove(1); - tree.Remove(4); - tree.Remove(8); - tree.GetKeysInOrder().SequenceEqual(new[] { 2, 3, 5, 6, 9 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 3, 2, 6, 5, 9 }).Should().BeTrue(); - } + [Test] + public void Remove_Case3_TreeStillValid() + { + // Move to case 6 + var tree = new RedBlackTree(); + tree.AddRange(new[] { 7, 3, 18, 1, 10, 22, 8, 11, 26 }); + tree.Remove(1); + tree.Remove(3); + tree.Count.Should().Be(7); + tree.Contains(3).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 7, 8, 10, 11, 18, 22, 26 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 18, 10, 7, 8, 11, 22, 26 }).Should().BeTrue(); + + // Move to case 5 + tree = new RedBlackTree(); + tree.AddRange(new[] { 8, 3, 2, 0, 9, 4, 7, 6, 1, 5 }); + tree.Remove(8); + tree.Remove(6); + tree.Remove(9); + tree.Count.Should().Be(7); + tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 2, 3, 4, 5, 7 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 3, 1, 0, 2, 5, 4, 7 }).Should().BeTrue(); + + // Move to case 4 + tree = new RedBlackTree(); + tree.AddRange(new[] { 7, 5, 8, 4, 6, 3, 2, 9, 0, 1 }); + tree.Remove(9); + tree.Remove(6); + tree.Remove(5); + tree.Remove(8); + tree.Count.Should().Be(6); + tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 2, 3, 4, 7 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 3, 1, 0, 2, 7, 4 }).Should().BeTrue(); + } - [Test] - public void Remove_Case6_TreeStillValid() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); - tree.Remove(13); - tree.Count.Should().Be(9); - tree.Contains(13).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 8, 11, 15, 17, 22, 25, 27 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 15, 8, 1, 6, 11, 25, 17, 22, 27 }).Should().BeTrue(); - - tree = new RedBlackTree(); - tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 0, 6, 22 }); - tree.Remove(8); - tree.Count.Should().Be(9); - tree.Contains(8).Should().BeFalse(); - tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 6, 11, 13, 15, 17, 22, 25 }).Should().BeTrue(); - tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 1, 0, 11, 6, 17, 15, 25, 22 }).Should().BeTrue(); - } + [Test] + public void Remove_Case4_TreeStillValid() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 5, 2, 8, 1, 4, 7, 9, 0, 3 }); + tree.Remove(0); + tree.Remove(3); + tree.Remove(2); + tree.Count.Should().Be(6); + tree.Contains(2).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 4, 5, 7, 8, 9 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 1, 8, 7, 9 }).Should().BeTrue(); + } - [Test] - public void Remove_EmptyTree_ThrowsException() - { - var tree = new RedBlackTree(); - Assert.Throws(() => tree.Remove(1)); - } + [Test] + public void Remove_Case5_TreeStillValid() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); + tree.Remove(8); + tree.Count.Should().Be(9); + tree.Contains(8).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 11, 13, 15, 17, 22, 25, 27 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 6, 1, 11, 17, 15, 25, 22, 27 }).Should().BeTrue(); + + tree = new RedBlackTree(); + tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 0, 6, 22 }); + tree.Remove(13); + tree.Count.Should().Be(9); + tree.Contains(13).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 6, 8, 11, 15, 17, 22, 25 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 15, 8, 1, 0, 6, 11, 22, 17, 25 }).Should().BeTrue(); + + tree = new RedBlackTree(); + tree.AddRange(new[] { 7, 0, 1, 4, 8, 2, 3, 6, 5, 9 }); + tree.Remove(7); + tree.Remove(0); + tree.Remove(1); + tree.Remove(4); + tree.Remove(8); + tree.GetKeysInOrder().SequenceEqual(new[] { 2, 3, 5, 6, 9 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 3, 2, 6, 5, 9 }).Should().BeTrue(); + } - [Test] - public void Remove_KeyNotInTree_ThrowsException() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - Assert.Throws(() => tree.Remove(24)); - } + [Test] + public void Remove_Case6_TreeStillValid() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 }); + tree.Remove(13); + tree.Count.Should().Be(9); + tree.Contains(13).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 8, 11, 15, 17, 22, 25, 27 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 15, 8, 1, 6, 11, 25, 17, 22, 27 }).Should().BeTrue(); + + tree = new RedBlackTree(); + tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 0, 6, 22 }); + tree.Remove(8); + tree.Count.Should().Be(9); + tree.Contains(8).Should().BeFalse(); + tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 6, 11, 13, 15, 17, 22, 25 }).Should().BeTrue(); + tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 1, 0, 11, 6, 17, 15, 25, 22 }).Should().BeTrue(); + } - [Test] - public void Contains_CorrectReturn() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.Contains(3).Should().BeTrue(); - tree.Contains(7).Should().BeTrue(); - tree.Contains(24).Should().BeFalse(); - tree.Contains(-1).Should().BeFalse(); - } + [Test] + public void Remove_EmptyTree_ThrowsException() + { + var tree = new RedBlackTree(); + Assert.Throws(() => tree.Remove(1)); + } - [Test] - public void Contains_EmptyTree_ReturnsFalse() - { - var tree = new RedBlackTree(); - tree.Contains(5).Should().BeFalse(); - tree.Contains(-12).Should().BeFalse(); - } + [Test] + public void Remove_KeyNotInTree_ThrowsException() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + Assert.Throws(() => tree.Remove(24)); + } - [Test] - public void GetMin_CorrectReturn() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetMin().Should().Be(1); - } + [Test] + public void Contains_CorrectReturn() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.Contains(3).Should().BeTrue(); + tree.Contains(7).Should().BeTrue(); + tree.Contains(24).Should().BeFalse(); + tree.Contains(-1).Should().BeFalse(); + } - [Test] - public void GetMin_EmptyTree_ThrowsException() - { - var tree = new RedBlackTree(); - Assert.Throws(() => tree.GetMin()); - } + [Test] + public void Contains_EmptyTree_ReturnsFalse() + { + var tree = new RedBlackTree(); + tree.Contains(5).Should().BeFalse(); + tree.Contains(-12).Should().BeFalse(); + } - [Test] - public void GetMax_CorrectReturn() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetMax().Should().Be(10); - } + [Test] + public void GetMin_CorrectReturn() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetMin().Should().Be(1); + } - [Test] - public void GetMax_EmptyTree_ThrowsException() - { - var tree = new RedBlackTree(); - Assert.Throws(() => tree.GetMax()); - } + [Test] + public void GetMin_EmptyTree_ThrowsException() + { + var tree = new RedBlackTree(); + Assert.Throws(() => tree.GetMin()); + } - [Test] - public void GetKeysInOrder_CorrectReturn() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); - } + [Test] + public void GetMax_CorrectReturn() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetMax().Should().Be(10); + } - [Test] - public void GetKeysInOrder_EmptyTree_CorrectReturn() - { - var tree = new RedBlackTree(); - tree.GetKeysInOrder().SequenceEqual(Array.Empty()).Should().BeTrue(); - } + [Test] + public void GetMax_EmptyTree_ThrowsException() + { + var tree = new RedBlackTree(); + Assert.Throws(() => tree.GetMax()); + } - [Test] - public void GetKeysPreOrder_CorrectReturn() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 6, 5, 8, 7, 9, 10 }).Should().BeTrue(); - } + [Test] + public void GetKeysInOrder_CorrectReturn() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue(); + } - [Test] - public void GetKeysPreOrder_EmptyTree_CorrectReturn() - { - var tree = new RedBlackTree(); - tree.GetKeysPreOrder().SequenceEqual(Array.Empty()).Should().BeTrue(); - } + [Test] + public void GetKeysInOrder_EmptyTree_CorrectReturn() + { + var tree = new RedBlackTree(); + tree.GetKeysInOrder().SequenceEqual(Array.Empty()).Should().BeTrue(); + } - [Test] - public void GetKeysPostOrder_CorrectReturn() - { - var tree = new RedBlackTree(); - tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }).Should().BeTrue(); - } + [Test] + public void GetKeysPreOrder_CorrectReturn() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 6, 5, 8, 7, 9, 10 }).Should().BeTrue(); + } - [Test] - public void GetKeysPostOrder_EmptyTree_CorrectReturn() - { - var tree = new RedBlackTree(); - tree.GetKeysPostOrder().SequenceEqual(Array.Empty()).Should().BeTrue(); - } + [Test] + public void GetKeysPreOrder_EmptyTree_CorrectReturn() + { + var tree = new RedBlackTree(); + tree.GetKeysPreOrder().SequenceEqual(Array.Empty()).Should().BeTrue(); + } + + [Test] + public void GetKeysPostOrder_CorrectReturn() + { + var tree = new RedBlackTree(); + tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }).Should().BeTrue(); + } + + [Test] + public void GetKeysPostOrder_EmptyTree_CorrectReturn() + { + var tree = new RedBlackTree(); + tree.GetKeysPostOrder().SequenceEqual(Array.Empty()).Should().BeTrue(); } } diff --git a/DataStructures.Tests/ScapegoatTree/ExtensionsTests.cs b/DataStructures.Tests/ScapegoatTree/ExtensionsTests.cs index 65bcb205..d81ca973 100644 --- a/DataStructures.Tests/ScapegoatTree/ExtensionsTests.cs +++ b/DataStructures.Tests/ScapegoatTree/ExtensionsTests.cs @@ -3,57 +3,56 @@ using DataStructures.ScapegoatTree; using NUnit.Framework; -namespace DataStructures.Tests.ScapegoatTree +namespace DataStructures.Tests.ScapegoatTree; + +public class ExtensionsTests { - public class ExtensionsTests + [Test] + public void RebuildFlatTree_ValidFlatTree_RebuildsTree() { - [Test] - public void RebuildFlatTree_ValidFlatTree_RebuildsTree() + var expected = new Node(3) { - var expected = new Node(3) + Left = new Node(1) + { + Left = new Node(-1), + Right = new Node(2), + }, + Right = new Node(6) { - Left = new Node(1) - { - Left = new Node(-1), - Right = new Node(2), - }, - Right = new Node(6) - { - Left = new Node(5), - }, - }; + Left = new Node(5), + }, + }; - var list = new List> - { - new(-1), - new(1), - new(2), - new(3), - new(5), - new(6), - }; + var list = new List> + { + new(-1), + new(1), + new(2), + new(3), + new(5), + new(6), + }; - var tree = Extensions.RebuildFromList(list, 0, list.Count - 1); + var tree = Extensions.RebuildFromList(list, 0, list.Count - 1); - Assert.AreEqual(list.Count, tree.GetSize()); - Assert.AreEqual(expected.Key, tree.Key); - Assert.IsNotNull(tree.Left); - Assert.IsNotNull(tree.Right); - Assert.AreEqual(expected.Left.Key, tree.Left!.Key); - Assert.AreEqual(expected.Right.Key, tree.Right!.Key); - Assert.IsNotNull(tree.Left.Left); - Assert.IsNotNull(tree.Left.Right); - Assert.AreEqual(expected.Left.Left.Key, tree.Left!.Left!.Key); - Assert.AreEqual(expected.Left.Right.Key, tree.Left!.Right!.Key); - Assert.IsNotNull(tree.Right.Left); - Assert.AreEqual(expected.Right.Left.Key, tree.Right!.Left!.Key); - } + Assert.AreEqual(list.Count, tree.GetSize()); + Assert.AreEqual(expected.Key, tree.Key); + Assert.IsNotNull(tree.Left); + Assert.IsNotNull(tree.Right); + Assert.AreEqual(expected.Left.Key, tree.Left!.Key); + Assert.AreEqual(expected.Right.Key, tree.Right!.Key); + Assert.IsNotNull(tree.Left.Left); + Assert.IsNotNull(tree.Left.Right); + Assert.AreEqual(expected.Left.Left.Key, tree.Left!.Left!.Key); + Assert.AreEqual(expected.Left.Right.Key, tree.Left!.Right!.Key); + Assert.IsNotNull(tree.Right.Left); + Assert.AreEqual(expected.Right.Left.Key, tree.Right!.Left!.Key); + } - [Test] - public void RebuildFromList_RangeIsInvalid_ThrowsException() - { - Assert.Throws(() => Extensions.RebuildFromList(new List>(), 1, 0)); - } + [Test] + public void RebuildFromList_RangeIsInvalid_ThrowsException() + { + Assert.Throws(() => Extensions.RebuildFromList(new List>(), 1, 0)); } } diff --git a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs index 196b65a9..39adf687 100644 --- a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs +++ b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs @@ -2,187 +2,186 @@ using DataStructures.ScapegoatTree; using NUnit.Framework; -namespace DataStructures.Tests.ScapegoatTree +namespace DataStructures.Tests.ScapegoatTree; + +[TestFixture] +public class ScapegoatTreeNodeTests { - [TestFixture] - public class ScapegoatTreeNodeTests + [Test] + [TestCase(2,1)] + [TestCase("B", "A")] + public void RightSetter_OtherKeyPrecedesRightKey_ThrowsException(TKey a, TKey b) + where TKey : IComparable + { + var instance = new Node(a); + var other = new Node(b); + + Assert.Throws(() => instance.Right = other); + } + + [Test] + [TestCase(1,2)] + [TestCase("A","B")] + public void RightSetter_OtherKeyFollowsRightKey_AddsChild(TKey a, TKey b) + where TKey : IComparable + { + var instance = new Node(a); + var other = new Node(b); + + Assert.DoesNotThrow(() => instance.Right = other); + } + + [Test] + [TestCase(1,2)] + [TestCase("A","B")] + public void LeftSetter_OtherKeyFollowsLeftKey_ThrowsException(TKey a, TKey b) + where TKey : IComparable + { + var instance = new Node(a); + var other = new Node(b); + + Assert.Throws(() => instance.Left = other); + } + + [Test] + [TestCase(2,1)] + [TestCase("B", "A")] + public void LeftSetter_OtherKeyPrecedesLeftKey_AddsChild(TKey a, TKey b) + where TKey : IComparable { - [Test] - [TestCase(2,1)] - [TestCase("B", "A")] - public void RightSetter_OtherKeyPrecedesRightKey_ThrowsException(TKey a, TKey b) - where TKey : IComparable - { - var instance = new Node(a); - var other = new Node(b); - - Assert.Throws(() => instance.Right = other); - } - - [Test] - [TestCase(1,2)] - [TestCase("A","B")] - public void RightSetter_OtherKeyFollowsRightKey_AddsChild(TKey a, TKey b) - where TKey : IComparable - { - var instance = new Node(a); - var other = new Node(b); - - Assert.DoesNotThrow(() => instance.Right = other); - } - - [Test] - [TestCase(1,2)] - [TestCase("A","B")] - public void LeftSetter_OtherKeyFollowsLeftKey_ThrowsException(TKey a, TKey b) - where TKey : IComparable - { - var instance = new Node(a); - var other = new Node(b); - - Assert.Throws(() => instance.Left = other); - } - - [Test] - [TestCase(2,1)] - [TestCase("B", "A")] - public void LeftSetter_OtherKeyPrecedesLeftKey_AddsChild(TKey a, TKey b) - where TKey : IComparable - { - var instance = new Node(a); - var other = new Node(b); - - Assert.DoesNotThrow(() => instance.Left = other); - } - - [Test] - [TestCase(1,2)] - [TestCase("A","B")] - public void CompareTo_InstanceKeyPrecedesOtherKey_ReturnsMinusOne(TKey a, TKey b) - where TKey : IComparable - { - var instance = new Node(a); - var other = new Node(b); - - var result = instance.Key.CompareTo(other.Key); - - Assert.AreEqual(result, -1); - } - - [Test] - [TestCase(2, 1)] - [TestCase("B","A")] - public void CompareTo_InstanceKeyFollowsOtherKey_ReturnsOne(TKey a, TKey b) - where TKey : IComparable - { - var instance = new Node(a); - var other = new Node(b); - - var result = instance.Key.CompareTo(other.Key); - - Assert.AreEqual(result, 1); - } - - [Test] - [TestCase(1, 1)] - [TestCase("A","A")] - public void CompareTo_InstanceKeyEqualsOtherKey_ReturnsZero(TKey a, TKey b) - where TKey : IComparable - { - var instance = new Node(a); - var other = new Node(b); - - var result = instance.Key.CompareTo(other.Key); - - Assert.AreEqual(result, 0); - } - - [Test] - public void GetSize_NodeHasNoChildren_ReturnsOne() - { - var node = new Node(1); - - Assert.AreEqual(node.GetSize(), 1); - } - - [Test] - public void GetSize_NodeHasChildren_ReturnsCorrectSize() - { - var node = new Node(1, new Node(2), new Node(0)); - - Assert.AreEqual(node.GetSize(), 3); - } - - [Test] - public void GetSmallestKeyNode_NodeHasNoLeftChildren_ReturnsNode() - { - var node = new Node(1); - - Assert.AreEqual(node.GetSmallestKeyNode(), node); - } - - [Test] - public void GetSmallestKeyNode_NodeHasSmallestChild_ReturnsChild() - { - var node = new Node(1); - var smaller = new Node(0); - var smallest = new Node(-1); - node.Left = smaller; - smaller.Left = smallest; - - Assert.AreEqual(node.GetSmallestKeyNode(), smallest); - } - - [Test] - public void GetLargestKeyNode_NodeHasNoRightChildren_ReturnsNode() - { - var node = new Node(1); - - Assert.AreEqual(node.GetLargestKeyNode(), node); - } - - [Test] - public void GetLargestKeyNode_NodeHasLargestChild_ReturnsChild() - { - var node = new Node(1); - var larger = new Node(2); - var largest = new Node(3); - node.Right = larger; - larger.Right = largest; - - Assert.AreEqual(node.GetLargestKeyNode(), largest); - } - - [Test] - public void IsAlphaWeightBalanced_TreeIsUnbalanced_ReturnsFalse() - { - var root = new Node(0); - var a = new Node(-1); - var b = new Node(-2); - var c = new Node(-3); - var d = new Node(1); - - root.Left = a; - a.Left = b; - b.Left = c; - root.Right = d; - - Assert.IsFalse(root.IsAlphaWeightBalanced(0.5)); - } - - [Test] - public void IsAlphaWeightBalanced_TreeIsBalanced_ReturnsTrue() - { - var root = new Node(0); - var a = new Node(-1); - var b = new Node(-2); - var d = new Node(1); - - root.Left = a; - a.Left = b; - root.Right = d; - - Assert.IsTrue(root.IsAlphaWeightBalanced(0.5)); - } + var instance = new Node(a); + var other = new Node(b); + + Assert.DoesNotThrow(() => instance.Left = other); + } + + [Test] + [TestCase(1,2)] + [TestCase("A","B")] + public void CompareTo_InstanceKeyPrecedesOtherKey_ReturnsMinusOne(TKey a, TKey b) + where TKey : IComparable + { + var instance = new Node(a); + var other = new Node(b); + + var result = instance.Key.CompareTo(other.Key); + + Assert.AreEqual(result, -1); + } + + [Test] + [TestCase(2, 1)] + [TestCase("B","A")] + public void CompareTo_InstanceKeyFollowsOtherKey_ReturnsOne(TKey a, TKey b) + where TKey : IComparable + { + var instance = new Node(a); + var other = new Node(b); + + var result = instance.Key.CompareTo(other.Key); + + Assert.AreEqual(result, 1); + } + + [Test] + [TestCase(1, 1)] + [TestCase("A","A")] + public void CompareTo_InstanceKeyEqualsOtherKey_ReturnsZero(TKey a, TKey b) + where TKey : IComparable + { + var instance = new Node(a); + var other = new Node(b); + + var result = instance.Key.CompareTo(other.Key); + + Assert.AreEqual(result, 0); + } + + [Test] + public void GetSize_NodeHasNoChildren_ReturnsOne() + { + var node = new Node(1); + + Assert.AreEqual(node.GetSize(), 1); + } + + [Test] + public void GetSize_NodeHasChildren_ReturnsCorrectSize() + { + var node = new Node(1, new Node(2), new Node(0)); + + Assert.AreEqual(node.GetSize(), 3); + } + + [Test] + public void GetSmallestKeyNode_NodeHasNoLeftChildren_ReturnsNode() + { + var node = new Node(1); + + Assert.AreEqual(node.GetSmallestKeyNode(), node); + } + + [Test] + public void GetSmallestKeyNode_NodeHasSmallestChild_ReturnsChild() + { + var node = new Node(1); + var smaller = new Node(0); + var smallest = new Node(-1); + node.Left = smaller; + smaller.Left = smallest; + + Assert.AreEqual(node.GetSmallestKeyNode(), smallest); + } + + [Test] + public void GetLargestKeyNode_NodeHasNoRightChildren_ReturnsNode() + { + var node = new Node(1); + + Assert.AreEqual(node.GetLargestKeyNode(), node); + } + + [Test] + public void GetLargestKeyNode_NodeHasLargestChild_ReturnsChild() + { + var node = new Node(1); + var larger = new Node(2); + var largest = new Node(3); + node.Right = larger; + larger.Right = largest; + + Assert.AreEqual(node.GetLargestKeyNode(), largest); + } + + [Test] + public void IsAlphaWeightBalanced_TreeIsUnbalanced_ReturnsFalse() + { + var root = new Node(0); + var a = new Node(-1); + var b = new Node(-2); + var c = new Node(-3); + var d = new Node(1); + + root.Left = a; + a.Left = b; + b.Left = c; + root.Right = d; + + Assert.IsFalse(root.IsAlphaWeightBalanced(0.5)); + } + + [Test] + public void IsAlphaWeightBalanced_TreeIsBalanced_ReturnsTrue() + { + var root = new Node(0); + var a = new Node(-1); + var b = new Node(-2); + var d = new Node(1); + + root.Left = a; + a.Left = b; + root.Right = d; + + Assert.IsTrue(root.IsAlphaWeightBalanced(0.5)); } } diff --git a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs index 4c128f92..08733c94 100644 --- a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs +++ b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs @@ -3,458 +3,457 @@ using DataStructures.ScapegoatTree; using NUnit.Framework; -namespace DataStructures.Tests.ScapegoatTree +namespace DataStructures.Tests.ScapegoatTree; + +public class ScapegoatTreeTests { - public class ScapegoatTreeTests + [Test] + public void Constructor_NoParameters_InstanceIsValid() { - [Test] - public void Constructor_NoParameters_InstanceIsValid() - { - var tree = new ScapegoatTree(); + var tree = new ScapegoatTree(); - Assert.IsNull(tree.Root); - Assert.IsTrue(tree.Size == 0); - Assert.IsTrue(tree.MaxSize == 0); - Assert.AreEqual(0.5, tree.Alpha); - } + Assert.IsNull(tree.Root); + Assert.IsTrue(tree.Size == 0); + Assert.IsTrue(tree.MaxSize == 0); + Assert.AreEqual(0.5, tree.Alpha); + } - [Test] - public void Constructor_AlphaParameter_InstanceIsValid() - { - var expected = 0.6; + [Test] + public void Constructor_AlphaParameter_InstanceIsValid() + { + var expected = 0.6; - var tree = new ScapegoatTree(expected); + var tree = new ScapegoatTree(expected); - Assert.IsNull(tree.Root); - Assert.IsTrue(tree.Size == 0); - Assert.IsTrue(tree.MaxSize == 0); - Assert.AreEqual(expected, tree.Alpha); - } + Assert.IsNull(tree.Root); + Assert.IsTrue(tree.Size == 0); + Assert.IsTrue(tree.MaxSize == 0); + Assert.AreEqual(expected, tree.Alpha); + } - [Test] - [TestCase(1.1)] - [TestCase(0.4)] - public void Constructor_AlphaParameterIsInvalid_ThrowsException(double alpha) - { - Assert.Throws(() => new ScapegoatTree(alpha)); - Assert.Throws(() => new ScapegoatTree(1, alpha)); - } + [Test] + [TestCase(1.1)] + [TestCase(0.4)] + public void Constructor_AlphaParameterIsInvalid_ThrowsException(double alpha) + { + Assert.Throws(() => new ScapegoatTree(alpha)); + Assert.Throws(() => new ScapegoatTree(1, alpha)); + } - [Test] - public void Constructor_KeyParameter_InstanceIsValid() - { - var expected = 10; + [Test] + public void Constructor_KeyParameter_InstanceIsValid() + { + var expected = 10; - var tree = new ScapegoatTree(expected); + var tree = new ScapegoatTree(expected); - Assert.IsNotNull(tree.Root); - Assert.IsTrue(tree.Root!.Key == expected); - Assert.IsTrue(tree.Size == 1); - Assert.IsTrue(tree.MaxSize == 1); - Assert.AreEqual(0.5, tree.Alpha); - } + Assert.IsNotNull(tree.Root); + Assert.IsTrue(tree.Root!.Key == expected); + Assert.IsTrue(tree.Size == 1); + Assert.IsTrue(tree.MaxSize == 1); + Assert.AreEqual(0.5, tree.Alpha); + } - [Test] - public void Constructor_KeyAndAlphaParameters_InstanceIsValid() - { - var key = 10; - var alpha = 0.8; + [Test] + public void Constructor_KeyAndAlphaParameters_InstanceIsValid() + { + var key = 10; + var alpha = 0.8; - var tree = new ScapegoatTree(key, alpha); + var tree = new ScapegoatTree(key, alpha); - Assert.IsNotNull(tree.Root); - Assert.IsTrue(tree.Size == 1); - Assert.IsTrue(tree.MaxSize == 1); - Assert.AreEqual(alpha, tree.Alpha); - } + Assert.IsNotNull(tree.Root); + Assert.IsTrue(tree.Size == 1); + Assert.IsTrue(tree.MaxSize == 1); + Assert.AreEqual(alpha, tree.Alpha); + } - [Test] - public void Constructor_NodeAndAlphaParameters_InstanceIsValid() - { - var node = new Node(10, new Node(11), new Node(1)); - var alpha = 0.8; + [Test] + public void Constructor_NodeAndAlphaParameters_InstanceIsValid() + { + var node = new Node(10, new Node(11), new Node(1)); + var alpha = 0.8; - var tree = new ScapegoatTree(node, alpha); + var tree = new ScapegoatTree(node, alpha); - Assert.IsNotNull(tree.Root); - Assert.IsTrue(tree.Size == 3); - Assert.IsTrue(tree.MaxSize == 3); - Assert.AreEqual(alpha, tree.Alpha); - } + Assert.IsNotNull(tree.Root); + Assert.IsTrue(tree.Size == 3); + Assert.IsTrue(tree.MaxSize == 3); + Assert.AreEqual(alpha, tree.Alpha); + } - [Test] - public void IsAlphaWeightBalanced_RootIsNull_ReturnsTrue() - { - var tree = new ScapegoatTree(); + [Test] + public void IsAlphaWeightBalanced_RootIsNull_ReturnsTrue() + { + var tree = new ScapegoatTree(); - var result = tree.IsAlphaWeightBalanced(); + var result = tree.IsAlphaWeightBalanced(); - Assert.IsTrue(result); - } + Assert.IsTrue(result); + } - [Test] - public void Search_RootIsNull_ReturnsNull() - { - var tree = new ScapegoatTree(); + [Test] + public void Search_RootIsNull_ReturnsNull() + { + var tree = new ScapegoatTree(); - var result = tree.Search(1); + var result = tree.Search(1); - Assert.IsNull(result); - } + Assert.IsNull(result); + } - [Test] - public void Search_KeyIsPresent_ReturnsKey() - { - var tree = new ScapegoatTree(key: 1); + [Test] + public void Search_KeyIsPresent_ReturnsKey() + { + var tree = new ScapegoatTree(key: 1); - var result = tree.Search(1); + var result = tree.Search(1); - Assert.IsNotNull(result); - Assert.AreEqual(1, result!.Key); - } + Assert.IsNotNull(result); + Assert.AreEqual(1, result!.Key); + } - [Test] - [TestCase(-2)] - [TestCase(3)] - public void Search_KeyIsNotPresent_ReturnsNull(int key) - { - var root = new Node(1, new Node(2), new Node(-1)); + [Test] + [TestCase(-2)] + [TestCase(3)] + public void Search_KeyIsNotPresent_ReturnsNull(int key) + { + var root = new Node(1, new Node(2), new Node(-1)); - var tree = new ScapegoatTree(root, 0.5); + var tree = new ScapegoatTree(root, 0.5); - var result = tree.Search(key); + var result = tree.Search(key); - Assert.IsNull(result); - } + Assert.IsNull(result); + } - [Test] - public void Insert_RootIsNull_InsertsRoot() - { - var tree = new ScapegoatTree(); + [Test] + public void Insert_RootIsNull_InsertsRoot() + { + var tree = new ScapegoatTree(); - var inserted = tree.Insert(1); + var inserted = tree.Insert(1); - Assert.IsTrue(inserted); - Assert.IsNotNull(tree.Root); - Assert.AreEqual(1, tree.Root!.Key); - Assert.AreEqual(1, tree.Size); - Assert.AreEqual(1, tree.MaxSize); - } + Assert.IsTrue(inserted); + Assert.IsNotNull(tree.Root); + Assert.AreEqual(1, tree.Root!.Key); + Assert.AreEqual(1, tree.Size); + Assert.AreEqual(1, tree.MaxSize); + } - [Test] - public void Delete_RootIsNull_ReturnsFalse() - { - var tree = new ScapegoatTree(); + [Test] + public void Delete_RootIsNull_ReturnsFalse() + { + var tree = new ScapegoatTree(); - var deleted = tree.Delete(1); + var deleted = tree.Delete(1); - Assert.IsFalse(deleted); - } + Assert.IsFalse(deleted); + } - [Test] - public void Delete_KeyIsNotPresent_ReturnsFalse() - { - var tree = new ScapegoatTree(1); + [Test] + public void Delete_KeyIsNotPresent_ReturnsFalse() + { + var tree = new ScapegoatTree(1); - var deleted = tree.Delete(2); + var deleted = tree.Delete(2); - Assert.IsFalse(deleted); - Assert.AreEqual(1, tree.Size); - } + Assert.IsFalse(deleted); + Assert.AreEqual(1, tree.Size); + } - [Test] - public void Insert_KeyIsPresent_ReturnsFalse() - { - var tree = new ScapegoatTree(1); + [Test] + public void Insert_KeyIsPresent_ReturnsFalse() + { + var tree = new ScapegoatTree(1); - var inserted = tree.Insert(1); + var inserted = tree.Insert(1); - Assert.IsFalse(inserted); - Assert.AreEqual(1, tree.Size); - Assert.AreEqual(1, tree.MaxSize); - } + Assert.IsFalse(inserted); + Assert.AreEqual(1, tree.Size); + Assert.AreEqual(1, tree.MaxSize); + } - [Test] - public void Remove_KeyIsPresent_RemovesKey() - { - var tree = new ScapegoatTree(1); + [Test] + public void Remove_KeyIsPresent_RemovesKey() + { + var tree = new ScapegoatTree(1); - var inserted = tree.Insert(2); + var inserted = tree.Insert(2); - Assert.IsTrue(inserted); + Assert.IsTrue(inserted); - var deleted = tree.Delete(2); + var deleted = tree.Delete(2); - Assert.IsTrue(deleted); - Assert.AreEqual(1, tree.Size); - } + Assert.IsTrue(deleted); + Assert.AreEqual(1, tree.Size); + } - [Test] - public void Remove_KeyIsRootWithNoChildren_RemovesKey() - { - var tree = new ScapegoatTree(1); + [Test] + public void Remove_KeyIsRootWithNoChildren_RemovesKey() + { + var tree = new ScapegoatTree(1); - var deleted = tree.Delete(1); + var deleted = tree.Delete(1); - Assert.IsTrue(deleted); - Assert.IsNull(tree.Root); - Assert.AreEqual(0, tree.Size); - } + Assert.IsTrue(deleted); + Assert.IsNull(tree.Root); + Assert.AreEqual(0, tree.Size); + } - [Test] - public void Remove_KeyIsRootWithOneLeftChild_RemovesKey() - { - var tree = new ScapegoatTree(1); + [Test] + public void Remove_KeyIsRootWithOneLeftChild_RemovesKey() + { + var tree = new ScapegoatTree(1); - var inserted = tree.Insert(-1); + var inserted = tree.Insert(-1); - Assert.IsTrue(inserted); + Assert.IsTrue(inserted); - var deleted = tree.Delete(1); + var deleted = tree.Delete(1); - Assert.IsTrue(deleted); - Assert.AreEqual(1, tree.Size); - } + Assert.IsTrue(deleted); + Assert.AreEqual(1, tree.Size); + } - [Test] - public void Remove_KeyIsRootWithOneRightChild_RemovesKey() - { - var tree = new ScapegoatTree(1); + [Test] + public void Remove_KeyIsRootWithOneRightChild_RemovesKey() + { + var tree = new ScapegoatTree(1); - var inserted = tree.Insert(2); + var inserted = tree.Insert(2); - Assert.IsTrue(inserted); + Assert.IsTrue(inserted); - var deleted = tree.Delete(1); + var deleted = tree.Delete(1); - Assert.IsTrue(deleted); - Assert.AreEqual(1, tree.Size); - } + Assert.IsTrue(deleted); + Assert.AreEqual(1, tree.Size); + } - [Test] - public void Remove_KeyIsRootWithTwoChildren_RemovesKey() - { - var tree = new ScapegoatTree(1); + [Test] + public void Remove_KeyIsRootWithTwoChildren_RemovesKey() + { + var tree = new ScapegoatTree(1); - var inserted = tree.Insert(-1); + var inserted = tree.Insert(-1); - Assert.IsTrue(inserted); + Assert.IsTrue(inserted); - inserted = tree.Insert(2); + inserted = tree.Insert(2); - Assert.IsTrue(inserted); + Assert.IsTrue(inserted); - var deleted = tree.Delete(1); + var deleted = tree.Delete(1); - Assert.IsTrue(deleted); - Assert.AreEqual(2, tree.Size); - } + Assert.IsTrue(deleted); + Assert.AreEqual(2, tree.Size); + } - [Test] - public void Insert_KeyIsNotPresent_KeyIsInserted() - { - var tree = new ScapegoatTree(1); + [Test] + public void Insert_KeyIsNotPresent_KeyIsInserted() + { + var tree = new ScapegoatTree(1); - var inserted = tree.Insert(2); + var inserted = tree.Insert(2); - Assert.IsTrue(inserted); - Assert.AreEqual(2, tree.Size); - Assert.AreEqual(2, tree.MaxSize); - } + Assert.IsTrue(inserted); + Assert.AreEqual(2, tree.Size); + Assert.AreEqual(2, tree.MaxSize); + } + + [Test] + [TestCase(3, new[]{2,5,1,6}, -1, 0.5)] + public void Insert_TreeIsUnbalanced_RebuildsTree(int root, int[] keys, int candidate, double alpha) + { + var tree = new ScapegoatTree(root, alpha); + + tree.TreeIsUnbalanced += FailTreeIsUnbalanced; - [Test] - [TestCase(3, new[]{2,5,1,6}, -1, 0.5)] - public void Insert_TreeIsUnbalanced_RebuildsTree(int root, int[] keys, int candidate, double alpha) + foreach (var item in keys) { - var tree = new ScapegoatTree(root, alpha); + Assert.DoesNotThrow(() => tree.Insert(item)); + } - tree.TreeIsUnbalanced += FailTreeIsUnbalanced; + tree.TreeIsUnbalanced -= FailTreeIsUnbalanced; + tree.TreeIsUnbalanced += PassTreeIsUnbalanced; - foreach (var item in keys) - { - Assert.DoesNotThrow(() => tree.Insert(item)); - } + Assert.Throws(() => tree.Insert(candidate)); + } - tree.TreeIsUnbalanced -= FailTreeIsUnbalanced; - tree.TreeIsUnbalanced += PassTreeIsUnbalanced; + [Test] + [TestCase(20, new[]{10,30,5,11,29,40,50, 1, 12}, new[]{50,40,30,29}, 0.7)] + public void Delete_TreeIsUnbalanced_BalancesTree(int root, int[] keys, int[] candidates, double alpha) + { + var tree = new ScapegoatTree(root, alpha); - Assert.Throws(() => tree.Insert(candidate)); - } + tree.TreeIsUnbalanced += FailTreeIsUnbalanced; - [Test] - [TestCase(20, new[]{10,30,5,11,29,40,50, 1, 12}, new[]{50,40,30,29}, 0.7)] - public void Delete_TreeIsUnbalanced_BalancesTree(int root, int[] keys, int[] candidates, double alpha) + foreach (var item in keys) { - var tree = new ScapegoatTree(root, alpha); + Assert.DoesNotThrow(() => tree.Insert(item)); + } - tree.TreeIsUnbalanced += FailTreeIsUnbalanced; + tree.TreeIsUnbalanced -= FailTreeIsUnbalanced; + tree.TreeIsUnbalanced += PassTreeIsUnbalanced; - foreach (var item in keys) + Assert.Throws(() => + { + foreach (var item in candidates) { - Assert.DoesNotThrow(() => tree.Insert(item)); + tree.Delete(item); } + }); + } - tree.TreeIsUnbalanced -= FailTreeIsUnbalanced; - tree.TreeIsUnbalanced += PassTreeIsUnbalanced; + [Test] + [TestCase(20, new[]{10,30,5,11,29,40,50}, 10, 1)] + public void Delete_TreeIsUnbalanced_MaxSizeEqualsSize(int root, int[] keys, int candidate, double alpha) + { + var tree = new ScapegoatTree(root, alpha); - Assert.Throws(() => - { - foreach (var item in candidates) - { - tree.Delete(item); - } - }); - } + tree.TreeIsUnbalanced += FailTreeIsUnbalanced; - [Test] - [TestCase(20, new[]{10,30,5,11,29,40,50}, 10, 1)] - public void Delete_TreeIsUnbalanced_MaxSizeEqualsSize(int root, int[] keys, int candidate, double alpha) + foreach (var item in keys) { - var tree = new ScapegoatTree(root, alpha); + Assert.DoesNotThrow(() => tree.Insert(item)); + } - tree.TreeIsUnbalanced += FailTreeIsUnbalanced; + tree.TreeIsUnbalanced -= FailTreeIsUnbalanced; - foreach (var item in keys) - { - Assert.DoesNotThrow(() => tree.Insert(item)); - } + tree.Delete(candidate); - tree.TreeIsUnbalanced -= FailTreeIsUnbalanced; + Assert.AreEqual(tree.Size, tree.MaxSize); + } - tree.Delete(candidate); + [Test] + [TestCase(3, new[]{2,5,1,6}, -1, 0.5)] + [TestCase(3, new[]{2,5,1,6}, 7, 0.5)] + public void Insert_TreeIsUnbalanced_BalancesTree(int root, int[] keys, int candidate, double alpha) + { + var tree = new ScapegoatTree(root, alpha); - Assert.AreEqual(tree.Size, tree.MaxSize); - } + tree.TreeIsUnbalanced += FailTreeIsUnbalanced; - [Test] - [TestCase(3, new[]{2,5,1,6}, -1, 0.5)] - [TestCase(3, new[]{2,5,1,6}, 7, 0.5)] - public void Insert_TreeIsUnbalanced_BalancesTree(int root, int[] keys, int candidate, double alpha) + foreach (var item in keys) { - var tree = new ScapegoatTree(root, alpha); - - tree.TreeIsUnbalanced += FailTreeIsUnbalanced; - - foreach (var item in keys) - { - Assert.DoesNotThrow(() => tree.Insert(item)); - } + Assert.DoesNotThrow(() => tree.Insert(item)); + } - tree.TreeIsUnbalanced -= FailTreeIsUnbalanced; + tree.TreeIsUnbalanced -= FailTreeIsUnbalanced; - var inserted = tree.Insert(candidate); + var inserted = tree.Insert(candidate); - Assert.True(inserted); - Assert.True(tree.Size == 6); - Assert.True(tree.IsAlphaWeightBalanced()); - } + Assert.True(inserted); + Assert.True(tree.Size == 6); + Assert.True(tree.IsAlphaWeightBalanced()); + } - [TestCase(3, 5, 0.5)] - public void Insert_TreeIsUnbalanced_BalancesTree2(int root, int candidate, double alpha) - { - var tree = new ScapegoatTree(root, alpha); + [TestCase(3, 5, 0.5)] + public void Insert_TreeIsUnbalanced_BalancesTree2(int root, int candidate, double alpha) + { + var tree = new ScapegoatTree(root, alpha); - var inserted = tree.Insert(candidate); + var inserted = tree.Insert(candidate); - Assert.True(inserted); - Assert.True(tree.Size == 2); - Assert.True(tree.IsAlphaWeightBalanced()); - } + Assert.True(inserted); + Assert.True(tree.Size == 2); + Assert.True(tree.IsAlphaWeightBalanced()); + } - [Test] - public void Contains_RootIsNull_ReturnsFalse() - { - var tree = new ScapegoatTree(); + [Test] + public void Contains_RootIsNull_ReturnsFalse() + { + var tree = new ScapegoatTree(); - Assert.IsFalse(tree.Contains(1)); - } + Assert.IsFalse(tree.Contains(1)); + } - [Test] - public void Contains_RootHasKey_ReturnsTrue() - { - var tree = new ScapegoatTree(1); + [Test] + public void Contains_RootHasKey_ReturnsTrue() + { + var tree = new ScapegoatTree(1); - Assert.IsTrue(tree.Contains(1)); - } + Assert.IsTrue(tree.Contains(1)); + } - [Test] - public void Contains_TreeHasKey_ReturnsTrue() - { - var tree = new ScapegoatTree(1); + [Test] + public void Contains_TreeHasKey_ReturnsTrue() + { + var tree = new ScapegoatTree(1); - tree.Insert(2); + tree.Insert(2); - Assert.IsTrue(tree.Contains(2)); - } + Assert.IsTrue(tree.Contains(2)); + } - [Test] - public void Contains_TreeDoesNotContainKey_ReturnsFalse() - { - var tree = new ScapegoatTree(1); + [Test] + public void Contains_TreeDoesNotContainKey_ReturnsFalse() + { + var tree = new ScapegoatTree(1); - tree.Insert(2); + tree.Insert(2); - Assert.IsFalse(tree.Contains(-1)); - } + Assert.IsFalse(tree.Contains(-1)); + } - [Test] - public void Clear_TreeHasKeys_ClearsTree() - { - var tree = new ScapegoatTree(1); + [Test] + public void Clear_TreeHasKeys_ClearsTree() + { + var tree = new ScapegoatTree(1); - tree.Clear(); + tree.Clear(); - Assert.IsTrue(tree.Size == 0); - Assert.IsTrue(tree.MaxSize == 0); - Assert.IsNull(tree.Root); - } + Assert.IsTrue(tree.Size == 0); + Assert.IsTrue(tree.MaxSize == 0); + Assert.IsNull(tree.Root); + } - [Test] - public void Tune_AlphaIsValid_ChangesAlpha() - { - var expected = 0.7; + [Test] + public void Tune_AlphaIsValid_ChangesAlpha() + { + var expected = 0.7; - var tree = new ScapegoatTree(); + var tree = new ScapegoatTree(); - tree.Tune(expected); + tree.Tune(expected); - Assert.AreEqual(expected, tree.Alpha); - } + Assert.AreEqual(expected, tree.Alpha); + } - [Test] - public void Tune_AlphaIsNotValid_ThrowsException() - { - var expected = 9.9; + [Test] + public void Tune_AlphaIsNotValid_ThrowsException() + { + var expected = 9.9; - var tree = new ScapegoatTree(); + var tree = new ScapegoatTree(); - Assert.Throws(() => tree.Tune(expected)); - } + Assert.Throws(() => tree.Tune(expected)); + } - [Test] - public void FindScapegoatInPath_PathIsEmpty_ThrowsAnException() - { - var tree = new ScapegoatTree(); - Assert.Throws(() => tree.FindScapegoatInPath(new Stack>())); - } + [Test] + public void FindScapegoatInPath_PathIsEmpty_ThrowsAnException() + { + var tree = new ScapegoatTree(); + Assert.Throws(() => tree.FindScapegoatInPath(new Stack>())); + } - [Test] - public void FindScapegoatInPath_ScapegoatIsNotPresent_ThrowsAnException() - { - var tree = new ScapegoatTree(1, 1); - var path = new Stack>(); - path.Push(tree.Root!); - Assert.Throws(() => tree.FindScapegoatInPath(path)); - } + [Test] + public void FindScapegoatInPath_ScapegoatIsNotPresent_ThrowsAnException() + { + var tree = new ScapegoatTree(1, 1); + var path = new Stack>(); + path.Push(tree.Root!); + Assert.Throws(() => tree.FindScapegoatInPath(path)); + } - private static void FailTreeIsUnbalanced(object? sender, EventArgs? e) - { - Assert.Fail(); - } + private static void FailTreeIsUnbalanced(object? sender, EventArgs? e) + { + Assert.Fail(); + } - private static void PassTreeIsUnbalanced(object? sender, EventArgs? e) - { - Assert.Pass(); - } + private static void PassTreeIsUnbalanced(object? sender, EventArgs? e) + { + Assert.Pass(); } } diff --git a/DataStructures.Tests/SegmentTrees/SegmentTreeApplyTests.cs b/DataStructures.Tests/SegmentTrees/SegmentTreeApplyTests.cs index 9d53805d..675c3a11 100644 --- a/DataStructures.Tests/SegmentTrees/SegmentTreeApplyTests.cs +++ b/DataStructures.Tests/SegmentTrees/SegmentTreeApplyTests.cs @@ -1,20 +1,19 @@ using DataStructures.SegmentTrees; using NUnit.Framework; -namespace DataStructures.Tests.SegmentTrees +namespace DataStructures.Tests.SegmentTrees; + +[TestFixture] +public class SegmentTreeApplyTests { - [TestFixture] - public class SegmentTreeApplyTests - { - private readonly SegmentTreeApply testTree = new(new[] { 8, 9, 1, 4, 8, 7, 2 }); + private readonly SegmentTreeApply testTree = new(new[] { 8, 9, 1, 4, 8, 7, 2 }); - [Test] - public void Apply_Query_Update_Query_Test() - { - Assert.AreEqual(22, testTree.Query(1, 4)); - testTree.Apply(0, 3, 2); - Assert.AreEqual(new[] { 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, testTree.Operand); - Assert.AreEqual(36, testTree.Query(1, 4)); - } + [Test] + public void Apply_Query_Update_Query_Test() + { + Assert.AreEqual(22, testTree.Query(1, 4)); + testTree.Apply(0, 3, 2); + Assert.AreEqual(new[] { 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, testTree.Operand); + Assert.AreEqual(36, testTree.Query(1, 4)); } } diff --git a/DataStructures.Tests/SegmentTrees/SegmentTreeTests.cs b/DataStructures.Tests/SegmentTrees/SegmentTreeTests.cs index 24017919..07a57713 100644 --- a/DataStructures.Tests/SegmentTrees/SegmentTreeTests.cs +++ b/DataStructures.Tests/SegmentTrees/SegmentTreeTests.cs @@ -1,25 +1,24 @@ using DataStructures.SegmentTrees; using NUnit.Framework; -namespace DataStructures.Tests.SegmentTrees +namespace DataStructures.Tests.SegmentTrees; + +[TestFixture] +public class SegmentTreeTests { - [TestFixture] - public class SegmentTreeTests - { - private readonly SegmentTree testTree = new(new[] { 8, 9, 1, 4, 8, 7, 2 }); + private readonly SegmentTree testTree = new(new[] { 8, 9, 1, 4, 8, 7, 2 }); - [Test] - public void TreeArray_Test() - { - int[] expectedArray = { 0, 39, 22, 17, 17, 5, 15, 2, 8, 9, 1, 4, 8, 7, 2, 0 }; - Assert.AreEqual(expectedArray, testTree.Tree); - } + [Test] + public void TreeArray_Test() + { + int[] expectedArray = { 0, 39, 22, 17, 17, 5, 15, 2, 8, 9, 1, 4, 8, 7, 2, 0 }; + Assert.AreEqual(expectedArray, testTree.Tree); + } - [TestCase(1, 4, 22)] - [TestCase(2, 2, 1)] - public void Query_Test(int left, int right, int expectedValue) - { - Assert.AreEqual(expectedValue, testTree.Query(left, right)); - } + [TestCase(1, 4, 22)] + [TestCase(2, 2, 1)] + public void Query_Test(int left, int right, int expectedValue) + { + Assert.AreEqual(expectedValue, testTree.Query(left, right)); } } diff --git a/DataStructures.Tests/SegmentTrees/SegmentTreeUpdateTest.cs b/DataStructures.Tests/SegmentTrees/SegmentTreeUpdateTest.cs index 87e3ace4..8bf1dd6b 100644 --- a/DataStructures.Tests/SegmentTrees/SegmentTreeUpdateTest.cs +++ b/DataStructures.Tests/SegmentTrees/SegmentTreeUpdateTest.cs @@ -1,25 +1,24 @@ using DataStructures.SegmentTrees; using NUnit.Framework; -namespace DataStructures.Tests.SegmentTrees +namespace DataStructures.Tests.SegmentTrees; + +[TestFixture] +public class SegmentTreeUpdateTests { - [TestFixture] - public class SegmentTreeUpdateTests + [SetUp] + public void Init() { - [SetUp] - public void Init() - { - testTree = new SegmentTreeUpdate(new[] { 8, 9, 1, 4, 8, 7, 2 }); - } + testTree = new SegmentTreeUpdate(new[] { 8, 9, 1, 4, 8, 7, 2 }); + } - private SegmentTreeUpdate testTree = new(new[] { 8, 9, 1, 4, 8, 7, 2 }); + private SegmentTreeUpdate testTree = new(new[] { 8, 9, 1, 4, 8, 7, 2 }); - [TestCase(2, 3, 1, 4, 24)] - [TestCase(0, 3, 1, 4, 22)] - public void Update_Test(int node, int value, int left, int right, int aftQuery) - { - testTree.Update(node, value); - Assert.AreEqual(aftQuery, testTree.Query(left, right)); - } + [TestCase(2, 3, 1, 4, 24)] + [TestCase(0, 3, 1, 4, 22)] + public void Update_Test(int node, int value, int left, int right, int aftQuery) + { + testTree.Update(node, value); + Assert.AreEqual(aftQuery, testTree.Query(left, right)); } } diff --git a/DataStructures.Tests/SortedListTests.cs b/DataStructures.Tests/SortedListTests.cs index dff30d15..b3ca7f6e 100644 --- a/DataStructures.Tests/SortedListTests.cs +++ b/DataStructures.Tests/SortedListTests.cs @@ -2,125 +2,124 @@ using System.Linq; using NUnit.Framework; -namespace DataStructures.Tests +namespace DataStructures.Tests; + +[TestFixture] +public class SortedListTests { - [TestFixture] - public class SortedListTests + [Test] + public void Add_AddMultipleValues_SortingCorrectly( + [Random(1, 1000, 100, Distinct = true)] + int count) { - [Test] - public void Add_AddMultipleValues_SortingCorrectly( - [Random(1, 1000, 100, Distinct = true)] - int count) - { - var values = GetValues(count); - var list = new SortedList(); + var values = GetValues(count); + var list = new SortedList(); - foreach (var value in values) - { - list.Add(value); - } - - CollectionAssert.AreEqual(values.OrderBy(i => i), list); + foreach (var value in values) + { + list.Add(value); } - [Test] - public void Contains_PositiveArrayAdded_NegativeNumberAsked_FalseReturned( - [Random(1, 200, 10, Distinct = true)] int count) - { - var values = GetValues(count); - const int value = -1; + CollectionAssert.AreEqual(values.OrderBy(i => i), list); + } - var list = new SortedList(); + [Test] + public void Contains_PositiveArrayAdded_NegativeNumberAsked_FalseReturned( + [Random(1, 200, 10, Distinct = true)] int count) + { + var values = GetValues(count); + const int value = -1; - foreach (var i in values) - { - list.Add(i); - } + var list = new SortedList(); - Assert.IsFalse(list.Contains(value)); + foreach (var i in values) + { + list.Add(i); } - [Test] - public void Contains_PositiveArrayAdded_ContainingValueAsked_TrueReturned( - [Random(1, 200, 10, Distinct = true)] int count) - { - var values = GetValues(count); - var value = values[TestContext.CurrentContext.Random.Next(count - 1)]; + Assert.IsFalse(list.Contains(value)); + } - var list = new SortedList(); + [Test] + public void Contains_PositiveArrayAdded_ContainingValueAsked_TrueReturned( + [Random(1, 200, 10, Distinct = true)] int count) + { + var values = GetValues(count); + var value = values[TestContext.CurrentContext.Random.Next(count - 1)]; - foreach (var i in values) - { - list.Add(i); - } + var list = new SortedList(); - Assert.IsTrue(list.Contains(value)); + foreach (var i in values) + { + list.Add(i); } + Assert.IsTrue(list.Contains(value)); + } - [Test] - public void Remove_PositiveArrayAdded_NegativeNumberAsked_FalseReturned( - [Random(1, 200, 10, Distinct = true)] int count) - { - var values = GetValues(count); - const int value = -1; - - var list = new SortedList(); - foreach (var i in values) - { - list.Add(i); - } + [Test] + public void Remove_PositiveArrayAdded_NegativeNumberAsked_FalseReturned( + [Random(1, 200, 10, Distinct = true)] int count) + { + var values = GetValues(count); + const int value = -1; - Assert.IsFalse(list.TryRemove(value)); - } + var list = new SortedList(); - [Test] - public void Remove_PositiveArrayAdded_ContainingValueAsked_TrueReturned( - [Random(1, 200, 10, Distinct = true)] int count) + foreach (var i in values) { - var values = GetValues(count); - var value = values[TestContext.CurrentContext.Random.Next(count - 1)]; - - var list = new SortedList(); + list.Add(i); + } - foreach (var i in values) - { - list.Add(i); - } + Assert.IsFalse(list.TryRemove(value)); + } - var expectingValues = values - .OrderBy(i => i) - .ToList(); + [Test] + public void Remove_PositiveArrayAdded_ContainingValueAsked_TrueReturned( + [Random(1, 200, 10, Distinct = true)] int count) + { + var values = GetValues(count); + var value = values[TestContext.CurrentContext.Random.Next(count - 1)]; - expectingValues.Remove(value); + var list = new SortedList(); - Assert.IsTrue(list.TryRemove(value)); - CollectionAssert.AreEqual(expectingValues, list); + foreach (var i in values) + { + list.Add(i); } - [Test] - public void Clear_ArrayAdded_ListCleaned_ListIsEmpty( - [Random(1, 20, 1, Distinct = true)] int count) - { - var values = GetValues(count); + var expectingValues = values + .OrderBy(i => i) + .ToList(); + + expectingValues.Remove(value); - var list = new SortedList(); + Assert.IsTrue(list.TryRemove(value)); + CollectionAssert.AreEqual(expectingValues, list); + } - foreach (var i in values) - { - list.Add(i); - } + [Test] + public void Clear_ArrayAdded_ListCleaned_ListIsEmpty( + [Random(1, 20, 1, Distinct = true)] int count) + { + var values = GetValues(count); - list.Clear(); + var list = new SortedList(); - CollectionAssert.IsEmpty(list); + foreach (var i in values) + { + list.Add(i); } - private static List GetValues(int count) - => Enumerable - .Range(0, count) - .Select(_ => TestContext.CurrentContext.Random.Next(1_000_000)) - .ToList(); + list.Clear(); + + CollectionAssert.IsEmpty(list); } + + private static List GetValues(int count) + => Enumerable + .Range(0, count) + .Select(_ => TestContext.CurrentContext.Random.Next(1_000_000)) + .ToList(); } diff --git a/DataStructures.Tests/Stack/ArrayBasedStackTests.cs b/DataStructures.Tests/Stack/ArrayBasedStackTests.cs index f0e9ce51..cfab5d5a 100644 --- a/DataStructures.Tests/Stack/ArrayBasedStackTests.cs +++ b/DataStructures.Tests/Stack/ArrayBasedStackTests.cs @@ -7,128 +7,127 @@ using System; using System.Linq; -namespace DataStructures.Tests.Stack +namespace DataStructures.Tests.Stack; + +public static class ArrayBasedStackTests { - public static class ArrayBasedStackTests - { - private const string StackEmptyErrorMessage = "Stack is empty"; + private const string StackEmptyErrorMessage = "Stack is empty"; - [Test] - public static void CountTest() - { - var stack = new ArrayBasedStack(new[] { 0, 1, 2, 3, 4 }); - stack.Top.Should().Be(4); - } + [Test] + public static void CountTest() + { + var stack = new ArrayBasedStack(new[] { 0, 1, 2, 3, 4 }); + stack.Top.Should().Be(4); + } - [Test] - public static void ClearTest() - { - var stack = new ArrayBasedStack(new[] { 0, 1, 2, 3, 4 }); + [Test] + public static void ClearTest() + { + var stack = new ArrayBasedStack(new[] { 0, 1, 2, 3, 4 }); - stack.Clear(); + stack.Clear(); - stack.Top.Should().Be(-1); - } + stack.Top.Should().Be(-1); + } - [Test] - public static void ContainsTest() - { - var stack = new ArrayBasedStack(new[] { 0, 1, 2, 3, 4 }); - - Assert.Multiple(() => - { - stack.Contains(0).Should().BeTrue(); - stack.Contains(1).Should().BeTrue(); - stack.Contains(2).Should().BeTrue(); - stack.Contains(3).Should().BeTrue(); - stack.Contains(4).Should().BeTrue(); - }); - } - - [Test] - public static void PeekTest() - { - var stack = new ArrayBasedStack(new[] { 0, 1, 2, 3, 4 }); - - Assert.Multiple(() => - { - stack.Peek().Should().Be(4); - stack.Peek().Should().Be(4); - stack.Peek().Should().Be(4); - }); - } - - [Test] - public static void PopTest() - { - var stack = new ArrayBasedStack(new[] { 0, 1, 2, 3, 4 }); - - Assert.Multiple(() => - { - stack.Pop().Should().Be(4); - stack.Pop().Should().Be(3); - stack.Pop().Should().Be(2); - stack.Pop().Should().Be(1); - stack.Pop().Should().Be(0); - }); - } - - [Test] - public static void PushTest() + [Test] + public static void ContainsTest() + { + var stack = new ArrayBasedStack(new[] { 0, 1, 2, 3, 4 }); + + Assert.Multiple(() => + { + stack.Contains(0).Should().BeTrue(); + stack.Contains(1).Should().BeTrue(); + stack.Contains(2).Should().BeTrue(); + stack.Contains(3).Should().BeTrue(); + stack.Contains(4).Should().BeTrue(); + }); + } + + [Test] + public static void PeekTest() + { + var stack = new ArrayBasedStack(new[] { 0, 1, 2, 3, 4 }); + + Assert.Multiple(() => { - var stack = new ArrayBasedStack(); - - Assert.Multiple(() => - Enumerable.Range(0, 5) - .ToList() - .ForEach(number => - { - stack.Push(number); - stack.Peek().Should().Be(number); - })); - } - - [Test] - public static void AutomaticResizesTest() + stack.Peek().Should().Be(4); + stack.Peek().Should().Be(4); + stack.Peek().Should().Be(4); + }); + } + + [Test] + public static void PopTest() + { + var stack = new ArrayBasedStack(new[] { 0, 1, 2, 3, 4 }); + + Assert.Multiple(() => { - const int initialCapacity = 2; - var stack = new ArrayBasedStack - { - Capacity = initialCapacity, - }; - - stack.Push(0); - stack.Push(1); - stack.Push(2); - stack.Push(3); - stack.Push(4); - - stack.Capacity.Should().BeGreaterThan(initialCapacity); - } - - [Test] - public static void ShouldThrowStackEmptyExceptionOnEmptyPopTest() + stack.Pop().Should().Be(4); + stack.Pop().Should().Be(3); + stack.Pop().Should().Be(2); + stack.Pop().Should().Be(1); + stack.Pop().Should().Be(0); + }); + } + + [Test] + public static void PushTest() + { + var stack = new ArrayBasedStack(); + + Assert.Multiple(() => + Enumerable.Range(0, 5) + .ToList() + .ForEach(number => + { + stack.Push(number); + stack.Peek().Should().Be(number); + })); + } + + [Test] + public static void AutomaticResizesTest() + { + const int initialCapacity = 2; + var stack = new ArrayBasedStack { - var stack = new ArrayBasedStack(); + Capacity = initialCapacity, + }; - Action poppingAnEmptyStack = () => stack.Pop(); + stack.Push(0); + stack.Push(1); + stack.Push(2); + stack.Push(3); + stack.Push(4); - poppingAnEmptyStack.Should() - .Throw() - .WithMessage(StackEmptyErrorMessage); + stack.Capacity.Should().BeGreaterThan(initialCapacity); + } + + [Test] + public static void ShouldThrowStackEmptyExceptionOnEmptyPopTest() + { + var stack = new ArrayBasedStack(); - } + Action poppingAnEmptyStack = () => stack.Pop(); - [Test] - public static void ShouldThrowStackEmptyExceptionOnEmptyPeekTest() - { - var stack = new ArrayBasedStack(); + poppingAnEmptyStack.Should() + .Throw() + .WithMessage(StackEmptyErrorMessage); + + } + + [Test] + public static void ShouldThrowStackEmptyExceptionOnEmptyPeekTest() + { + var stack = new ArrayBasedStack(); - Action peekingAnEmptyStack = () => stack.Peek(); + Action peekingAnEmptyStack = () => stack.Peek(); - peekingAnEmptyStack.Should() - .Throw() - .WithMessage(StackEmptyErrorMessage); - } + peekingAnEmptyStack.Should() + .Throw() + .WithMessage(StackEmptyErrorMessage); } } diff --git a/DataStructures.Tests/Stack/ListBasedStackTests.cs b/DataStructures.Tests/Stack/ListBasedStackTests.cs index 229e6bf4..9cdb30fa 100644 --- a/DataStructures.Tests/Stack/ListBasedStackTests.cs +++ b/DataStructures.Tests/Stack/ListBasedStackTests.cs @@ -6,81 +6,80 @@ using System.Linq; -namespace DataStructures.Tests.Stack +namespace DataStructures.Tests.Stack; + +public static class ListBasedStackTests { - public static class ListBasedStackTests + [Test] + public static void CountTest() { - [Test] - public static void CountTest() - { - var stack = new ListBasedStack(new[] { 0, 1, 2, 3, 4 }); - stack.Count.Should().Be(5); - } - - [Test] - public static void ClearTest() - { - var stack = new ListBasedStack(new[] { 0, 1, 2, 3, 4 }); - stack.Clear(); - stack.Count.Should().Be(0); - } + var stack = new ListBasedStack(new[] { 0, 1, 2, 3, 4 }); + stack.Count.Should().Be(5); + } - [Test] - public static void ContainsTest() - { - var stack = new ListBasedStack(new[] { 0, 1, 2, 3, 4 }); + [Test] + public static void ClearTest() + { + var stack = new ListBasedStack(new[] { 0, 1, 2, 3, 4 }); + stack.Clear(); + stack.Count.Should().Be(0); + } - Assert.Multiple(() => - { - stack.Contains(0).Should().BeTrue(); - stack.Contains(1).Should().BeTrue(); - stack.Contains(2).Should().BeTrue(); - stack.Contains(3).Should().BeTrue(); - stack.Contains(4).Should().BeTrue(); - }); - } + [Test] + public static void ContainsTest() + { + var stack = new ListBasedStack(new[] { 0, 1, 2, 3, 4 }); - [Test] - public static void PeekTest() + Assert.Multiple(() => { - var stack = new ListBasedStack(new[] { 0, 1, 2, 3, 4 }); + stack.Contains(0).Should().BeTrue(); + stack.Contains(1).Should().BeTrue(); + stack.Contains(2).Should().BeTrue(); + stack.Contains(3).Should().BeTrue(); + stack.Contains(4).Should().BeTrue(); + }); + } - Assert.Multiple(() => - { - stack.Peek().Should().Be(4); - stack.Peek().Should().Be(4); - stack.Peek().Should().Be(4); - }); - } + [Test] + public static void PeekTest() + { + var stack = new ListBasedStack(new[] { 0, 1, 2, 3, 4 }); - [Test] - public static void PopTest() + Assert.Multiple(() => { - var stack = new ListBasedStack(new[] { 0, 1, 2, 3, 4 }); + stack.Peek().Should().Be(4); + stack.Peek().Should().Be(4); + stack.Peek().Should().Be(4); + }); + } - Assert.Multiple(() => - { - stack.Pop().Should().Be(4); - stack.Pop().Should().Be(3); - stack.Pop().Should().Be(2); - stack.Pop().Should().Be(1); - stack.Pop().Should().Be(0); - }); - } + [Test] + public static void PopTest() + { + var stack = new ListBasedStack(new[] { 0, 1, 2, 3, 4 }); - [Test] - public static void PushTest() + Assert.Multiple(() => { - var stack = new ListBasedStack(); + stack.Pop().Should().Be(4); + stack.Pop().Should().Be(3); + stack.Pop().Should().Be(2); + stack.Pop().Should().Be(1); + stack.Pop().Should().Be(0); + }); + } + + [Test] + public static void PushTest() + { + var stack = new ListBasedStack(); - Assert.Multiple(() => - Enumerable.Range(0, 5) - .ToList() - .ForEach(number => - { - stack.Push(number); - stack.Peek().Should().Be(number); - })); - } + Assert.Multiple(() => + Enumerable.Range(0, 5) + .ToList() + .ForEach(number => + { + stack.Push(number); + stack.Peek().Should().Be(number); + })); } } diff --git a/DataStructures.Tests/Stack/QueueBasedStackTests.cs b/DataStructures.Tests/Stack/QueueBasedStackTests.cs index 69f67621..a95c451c 100644 --- a/DataStructures.Tests/Stack/QueueBasedStackTests.cs +++ b/DataStructures.Tests/Stack/QueueBasedStackTests.cs @@ -1,127 +1,123 @@ using DataStructures.Stack; using NUnit.Framework; using System; -using System.Collections.Generic; -using System.Linq; using System.Text; -using System.Threading.Tasks; -namespace DataStructures.Tests.Stack +namespace DataStructures.Tests.Stack; + +public static class QueueBasedStackTests { - public static class QueueBasedStackTests + [Test] + public static void PopWorksCorrectly() { - [Test] - public static void PopWorksCorrectly() + //Arrange + QueueBasedStack s = new QueueBasedStack(); + s.Push('A'); + s.Push('B'); + s.Push('C'); + var result = new StringBuilder(); + + //Act + for (int i = 0; i < 3; i++) { - //Arrange - QueueBasedStack s = new QueueBasedStack(); - s.Push('A'); - s.Push('B'); - s.Push('C'); - var result = new StringBuilder(); - - //Act - for (int i = 0; i < 3; i++) - { - result.Append(s.Pop()); - } - - - //Assert - Assert.That("CBA", Is.EqualTo(result.ToString())); - Assert.IsTrue(s.IsEmpty(), "Stack is Empty"); + result.Append(s.Pop()); } - [Test] - public static void PeekWorksCorrectly() + + + //Assert + Assert.That("CBA", Is.EqualTo(result.ToString())); + Assert.IsTrue(s.IsEmpty(), "Stack is Empty"); + } + [Test] + public static void PeekWorksCorrectly() + { + //Arrange + QueueBasedStack s = new QueueBasedStack(); + s.Push(1); + s.Push(2); + s.Push(3); + var peeked = 0; + + //Act + for (int i = 0; i < 3; i++) { - //Arrange - QueueBasedStack s = new QueueBasedStack(); - s.Push(1); - s.Push(2); - s.Push(3); - var peeked = 0; - - //Act - for (int i = 0; i < 3; i++) - { - peeked = s.Peek(); - } - - - //Assert - Assert.That(3, Is.EqualTo(peeked)); - Assert.IsFalse(s.IsEmpty(), "Stack is Empty"); + peeked = s.Peek(); } - [Test] - public static void PopEmptyStackThrowsInvalidOperationException() + + + //Assert + Assert.That(3, Is.EqualTo(peeked)); + Assert.IsFalse(s.IsEmpty(), "Stack is Empty"); + } + [Test] + public static void PopEmptyStackThrowsInvalidOperationException() + { + //Arrange + var s = new QueueBasedStack(); + Exception? exception = null; + + //Act + try { - //Arrange - var s = new QueueBasedStack(); - Exception? exception = null; - - //Act - try - { - s.Pop(); - } - catch (Exception ex) - { - exception = ex; - } - - //Assert - Assert.That(exception?.GetType(), Is.EqualTo(typeof(InvalidOperationException))); + s.Pop(); } - [Test] - public static void PeekEmptyStackThrowsInvalidOperationException() + catch (Exception ex) { - //Arrange - var s = new QueueBasedStack(); - Exception? exception = null; - - //Act - try - { - s.Peek(); - } - catch (Exception ex) - { - exception = ex; - } - - //Assert - Assert.That(exception?.GetType(), Is.EqualTo(typeof(InvalidOperationException))); + exception = ex; } - [Test] - public static void ClearWorksCorrectly() - { - // Arrange - var s = new QueueBasedStack(); - s.Push(1); - s.Push(2); - - // Act - s.Clear(); - // Assert - Assert.IsTrue(s.IsEmpty(), "Queue is empty"); + //Assert + Assert.That(exception?.GetType(), Is.EqualTo(typeof(InvalidOperationException))); + } + [Test] + public static void PeekEmptyStackThrowsInvalidOperationException() + { + //Arrange + var s = new QueueBasedStack(); + Exception? exception = null; + //Act + try + { + s.Peek(); } - [Test] - public static void LengthWorksCorrectly() + catch (Exception ex) { - // Arrange - var s = new QueueBasedStack(); - s.Push(1); - s.Push(2); - var length = 0; + exception = ex; + } - // Act - length = s.Length(); + //Assert + Assert.That(exception?.GetType(), Is.EqualTo(typeof(InvalidOperationException))); + } + [Test] + public static void ClearWorksCorrectly() + { + // Arrange + var s = new QueueBasedStack(); + s.Push(1); + s.Push(2); - // Assert - Assert.That(2, Is.EqualTo(length)); + // Act + s.Clear(); + + // Assert + Assert.IsTrue(s.IsEmpty(), "Queue is empty"); + + } + [Test] + public static void LengthWorksCorrectly() + { + // Arrange + var s = new QueueBasedStack(); + s.Push(1); + s.Push(2); + var length = 0; + + // Act + length = s.Length(); + + // Assert + Assert.That(2, Is.EqualTo(length)); - } } } diff --git a/DataStructures.Tests/TimelineTests.cs b/DataStructures.Tests/TimelineTests.cs index 9f76371e..be948c1c 100644 --- a/DataStructures.Tests/TimelineTests.cs +++ b/DataStructures.Tests/TimelineTests.cs @@ -5,667 +5,719 @@ using FluentAssertions.Execution; using NUnit.Framework; -namespace DataStructures.Tests +namespace DataStructures.Tests; + +public static class TimelineTests { - public static class TimelineTests + [Test] + public static void CountTest() { - [Test] - public static void CountTest() - { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - timeline.Count - .Should() - .Be(5); - } - - [Test] - public static void TimesCountTest() + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - timeline.TimesCount - .Should() - .Be(timeline.GetAllTimes().Length); - } + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.Count + .Should() + .Be(5); + } - [Test] - public static void ValuesCountTest() + [Test] + public static void TimesCountTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - timeline.ValuesCount - .Should() - .Be(timeline.GetAllValues().Length); - } + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.TimesCount + .Should() + .Be(timeline.GetAllTimes().Length); + } - [Test] - public static void IndexerGetTest() + [Test] + public static void ValuesCountTest() + { + var timeline = new Timeline { - const string eventName = "TestTime2"; - var eventDate = new DateTime(2000, 1, 1); - - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { eventDate, eventName }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.ValuesCount + .Should() + .Be(timeline.GetAllValues().Length); + } - timeline[eventDate][0] - .Should() - .Be(eventName); - } + [Test] + public static void IndexerGetTest() + { + const string eventName = "TestTime2"; + var eventDate = new DateTime(2000, 1, 1); - [Test] - public static void IndexerSetTest() + var timeline = new Timeline { - var eventDate = new DateTime(2000, 1, 1); + { new DateTime(1995, 1, 1), "TestTime1" }, + { eventDate, eventName }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline[eventDate][0] + .Should() + .Be(eventName); + } - const string formerEventName = "TestTime2"; - const string eventName = "TestTime2Modified"; + [Test] + public static void IndexerSetTest() + { + var eventDate = new DateTime(2000, 1, 1); - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { eventDate, formerEventName }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + const string formerEventName = "TestTime2"; + const string eventName = "TestTime2Modified"; - timeline[new DateTime(2000, 1, 1)] = new[] { eventName }; + var timeline = new Timeline + { + { new DateTime(1995, 1, 1), "TestTime1" }, + { eventDate, formerEventName }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline[new DateTime(2000, 1, 1)] = new[] { eventName }; + + timeline[new DateTime(2000, 1, 1)][0] + .Should() + .Be(eventName); + } - timeline[new DateTime(2000, 1, 1)][0] - .Should() - .Be(eventName); - } + [Test] + public static void EqualsTest() + { + var timeline1 = new Timeline + { + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + var timeline2 = new Timeline + { + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + (timeline1 == timeline2) + .Should() + .BeTrue(); + } - [Test] - public static void EqualsTest() + [Test] + public static void ClearTest() + { + var timeline = new Timeline { - var timeline1 = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - var timeline2 = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - (timeline1 == timeline2) - .Should() - .BeTrue(); - } + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.Clear(); + + timeline.Count + .Should() + .Be(0); + } - [Test] - public static void ClearTest() + [Test] + public static void CopyToTest() + { + var timeline = new Timeline { - var timeline = new Timeline + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + var array = new (DateTime Time, string Value)[timeline.Count]; + timeline.CopyTo(array, 0); + + timeline.Count + .Should() + .Be(array.Length); + + var i = 0; + using (new AssertionScope()) + { + foreach (var (time, value) in timeline) { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + array[i].Time + .Should() + .Be(time); - timeline.Clear(); + array[i].Value + .Should() + .Be(value); - timeline.Count - .Should() - .Be(0); + ++i; + } } + } - [Test] - public static void CopyToTest() + [Test] + public static void GetAllTimesTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - var array = new (DateTime Time, string Value)[timeline.Count]; - timeline.CopyTo(array, 0); + var times = timeline.GetAllTimes(); - timeline.Count - .Should() - .Be(array.Length); - - var i = 0; - using (new AssertionScope()) + var i = 0; + using (new AssertionScope()) + { + foreach (var (time, _) in timeline) { - foreach (var (time, value) in timeline) - { - array[i].Time - .Should() - .Be(time); - - array[i].Value - .Should() - .Be(value); - - ++i; - } + times[i++] + .Should() + .Be(time); } } + } + + [Test] + public static void GetTimesByValueTest() + { + var eventDate = new DateTime(2000, 1, 1); + const string eventName = "TestTime2"; - [Test] - public static void GetAllTimesTest() + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { eventDate, eventName }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.GetTimesByValue(eventName)[0] + .Should() + .Be(eventDate); + } - var times = timeline.GetAllTimes(); + [Test] + public static void GetTimesBeforeTest() + { + var timeline = new Timeline + { + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - var i = 0; - using (new AssertionScope()) - { - foreach (var (time, _) in timeline) - { - times[i++] - .Should() - .Be(time); - } - } - } + var times = timeline.GetTimesBefore(new DateTime(2003, 1, 1)); - [Test] - public static void GetTimesByValueTest() + using (new AssertionScope()) { - var eventDate = new DateTime(2000, 1, 1); - const string eventName = "TestTime2"; + times.Length + .Should() + .Be(2); - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { eventDate, eventName }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - timeline.GetTimesByValue(eventName)[0] + times[0] + .Should() + .Be(new DateTime(1995, 1, 1)); + + times[1] .Should() - .Be(eventDate); + .Be(new DateTime(2000, 1, 1)); } + } - [Test] - public static void GetTimesBeforeTest() + [Test] + public static void GetTimesAfterTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - var times = timeline.GetTimesBefore(new DateTime(2003, 1, 1)); + var times = timeline.GetTimesAfter(new DateTime(2003, 1, 1)); - using (new AssertionScope()) - { - times.Length - .Should() - .Be(2); + using (new AssertionScope()) + { + times.Length + .Should() + .Be(3); - times[0] - .Should() - .Be(new DateTime(1995, 1, 1)); + times[0] + .Should() + .Be(new DateTime(2005, 1, 1)); - times[1] - .Should() - .Be(new DateTime(2000, 1, 1)); - } + times[1] + .Should() + .Be(new DateTime(2010, 1, 1)); + + times[2] + .Should() + .Be(new DateTime(2015, 1, 1)); } + } - [Test] - public static void GetTimesAfterTest() + [Test] + public static void GetAllValuesTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - var times = timeline.GetTimesAfter(new DateTime(2003, 1, 1)); + var values = timeline.GetAllValues(); - using (new AssertionScope()) + var i = 0; + using (new AssertionScope()) + { + foreach (var (_, value) in timeline) { - times.Length + values[i++] .Should() - .Be(3); - - times[0] - .Should() - .Be(new DateTime(2005, 1, 1)); - - times[1] - .Should() - .Be(new DateTime(2010, 1, 1)); - - times[2] - .Should() - .Be(new DateTime(2015, 1, 1)); + .Be(value); } } + } - [Test] - public static void GetAllValuesTest() + [Test] + public static void GetValuesByTimeTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.GetValuesByTime(new DateTime(2000, 1, 1))[0] + .Should() + .Be("TestTime2"); + } - var values = timeline.GetAllValues(); + [Test] + public static void GetValuesBeforeTest() + { + var timeline = new Timeline + { + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - var i = 0; - using (new AssertionScope()) - { - foreach (var (_, value) in timeline) - { - values[i++] - .Should() - .Be(value); - } - } - } + var array = timeline.GetValuesBefore(new DateTime(2003, 1, 1)).ToArray(); - [Test] - public static void GetValuesByTimeTest() + using (new AssertionScope()) { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - timeline.GetValuesByTime(new DateTime(2000, 1, 1))[0] + array.Length + .Should() + .Be(2); + + array[0].Time .Should() - .Be("TestTime2"); + .Be(new DateTime(1995, 1, 1)); + + array[1].Time + .Should() + .Be(new DateTime(2000, 1, 1)); } + } - [Test] - public static void GetValuesBeforeTest() + [Test] + public static void GetValuesAfterTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - var array = timeline.GetValuesBefore(new DateTime(2003, 1, 1)).ToArray(); + var array = timeline.GetValuesAfter(new DateTime(2003, 1, 1)).ToArray(); - using (new AssertionScope()) - { - array.Length - .Should() - .Be(2); + using (new AssertionScope()) + { + array.Length + .Should() + .Be(3); - array[0].Time - .Should() - .Be(new DateTime(1995, 1, 1)); + array[0].Time + .Should() + .Be(new DateTime(2005, 1, 1)); - array[1].Time - .Should() - .Be(new DateTime(2000, 1, 1)); - } + array[1].Time + .Should() + .Be(new DateTime(2010, 1, 1)); + + array[2].Time + .Should() + .Be(new DateTime(2015, 1, 1)); } + } - [Test] - public static void GetValuesAfterTest() + [Test] + public static void GetValuesByMillisecondTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - var array = timeline.GetValuesAfter(new DateTime(2003, 1, 1)).ToArray(); + { new DateTime(1985, 1, 1, 10, 0, 0, 250), "TestTime1" }, + { new DateTime(1990, 1, 1, 10, 0, 0, 250), "TestTime2" }, + { new DateTime(1995, 1, 1, 10, 0, 0, 250), "TestTime3" }, + { new DateTime(2005, 1, 1, 10, 0, 0, 750), "TestTime4" }, + { new DateTime(2015, 1, 1, 10, 0, 0, 750), "TestTime5" }, + }; + + var query = timeline.GetValuesByMillisecond(750); + + query.Count + .Should() + .Be(2); + } - using (new AssertionScope()) - { - array.Length - .Should() - .Be(3); + [Test] + public static void GetValuesBySecondTest() + { + var timeline = new Timeline + { + { new DateTime(1985, 1, 1, 10, 0, 5), "TestTime1" }, + { new DateTime(1990, 1, 1, 10, 0, 5), "TestTime2" }, + { new DateTime(1995, 1, 1, 10, 0, 5), "TestTime3" }, + { new DateTime(2005, 1, 1, 10, 0, 20), "TestTime4" }, + { new DateTime(2015, 1, 1, 10, 0, 20), "TestTime5" }, + }; - array[0].Time - .Should() - .Be(new DateTime(2005, 1, 1)); + var query = timeline.GetValuesBySecond(20); - array[1].Time - .Should() - .Be(new DateTime(2010, 1, 1)); + using (new AssertionScope()) + { + query.Count + .Should() + .Be(2); - array[2].Time - .Should() - .Be(new DateTime(2015, 1, 1)); - } + timeline + .Should() + .Contain(query); } + } - [Test] - public static void GetValuesByMillisecondTest() + [Test] + public static void GetValuesByMinuteTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1985, 1, 1, 10, 0, 0, 250), "TestTime1" }, - { new DateTime(1990, 1, 1, 10, 0, 0, 250), "TestTime2" }, - { new DateTime(1995, 1, 1, 10, 0, 0, 250), "TestTime3" }, - { new DateTime(2005, 1, 1, 10, 0, 0, 750), "TestTime4" }, - { new DateTime(2015, 1, 1, 10, 0, 0, 750), "TestTime5" }, - }; + { new DateTime(1985, 1, 1, 10, 15, 0), "TestTime1" }, + { new DateTime(1990, 1, 1, 10, 15, 0), "TestTime2" }, + { new DateTime(1995, 1, 1, 10, 15, 0), "TestTime3" }, + { new DateTime(2005, 1, 1, 10, 40, 0), "TestTime4" }, + { new DateTime(2015, 1, 1, 10, 40, 0), "TestTime5" }, + }; - var query = timeline.GetValuesByMillisecond(750); + var query = timeline.GetValuesByMinute(40); + using (new AssertionScope()) + { query.Count .Should() .Be(2); + + timeline + .Should() + .Contain(query); } + } - [Test] - public static void GetValuesBySecondTest() + [Test] + public static void GetValuesByHourTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1985, 1, 1, 10, 0, 5), "TestTime1" }, - { new DateTime(1990, 1, 1, 10, 0, 5), "TestTime2" }, - { new DateTime(1995, 1, 1, 10, 0, 5), "TestTime3" }, - { new DateTime(2005, 1, 1, 10, 0, 20), "TestTime4" }, - { new DateTime(2015, 1, 1, 10, 0, 20), "TestTime5" }, - }; + { new DateTime(1985, 1, 1, 7, 0, 0), "TestTime1" }, + { new DateTime(1990, 1, 1, 7, 0, 0), "TestTime2" }, + { new DateTime(1995, 1, 1, 7, 0, 0), "TestTime3" }, + { new DateTime(2005, 1, 1, 16, 0, 0), "TestTime4" }, + { new DateTime(2015, 1, 1, 16, 0, 0), "TestTime5" }, + }; - var query = timeline.GetValuesBySecond(20); + var query = timeline.GetValuesByHour(16); - using (new AssertionScope()) - { - query.Count - .Should() - .Be(2); + using (new AssertionScope()) + { + query.Count + .Should() + .Be(2); - timeline - .Should() - .Contain(query); - } + timeline + .Should() + .Contain(query); } + } - [Test] - public static void GetValuesByMinuteTest() + [Test] + public static void GetValuesByDayTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1985, 1, 1, 10, 15, 0), "TestTime1" }, - { new DateTime(1990, 1, 1, 10, 15, 0), "TestTime2" }, - { new DateTime(1995, 1, 1, 10, 15, 0), "TestTime3" }, - { new DateTime(2005, 1, 1, 10, 40, 0), "TestTime4" }, - { new DateTime(2015, 1, 1, 10, 40, 0), "TestTime5" }, - }; + { new DateTime(1985, 1, 10), "TestTime1" }, + { new DateTime(1990, 1, 10), "TestTime2" }, + { new DateTime(1995, 1, 10), "TestTime3" }, + { new DateTime(2005, 1, 20), "TestTime4" }, + { new DateTime(2015, 1, 20), "TestTime5" }, + }; - var query = timeline.GetValuesByMinute(40); + var query = timeline.GetValuesByDay(20); - using (new AssertionScope()) - { - query.Count - .Should() - .Be(2); + using (new AssertionScope()) + { + query.Count + .Should() + .Be(2); - timeline - .Should() - .Contain(query); - } + timeline + .Should() + .Contain(query); } + } - [Test] - public static void GetValuesByHourTest() + [Test] + public static void GetValuesByTimeOfDayTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1985, 1, 1, 7, 0, 0), "TestTime1" }, - { new DateTime(1990, 1, 1, 7, 0, 0), "TestTime2" }, - { new DateTime(1995, 1, 1, 7, 0, 0), "TestTime3" }, - { new DateTime(2005, 1, 1, 16, 0, 0), "TestTime4" }, - { new DateTime(2015, 1, 1, 16, 0, 0), "TestTime5" }, - }; + { new DateTime(1985, 1, 1, 10, 30, 15, 500), "TestTime1" }, + { new DateTime(1990, 1, 1, 10, 30, 15, 500), "TestTime2" }, + { new DateTime(1995, 1, 1, 10, 30, 15, 500), "TestTime3" }, + { new DateTime(2005, 1, 1, 21, 15, 40, 600), "TestTime4" }, + { new DateTime(2015, 1, 1, 21, 15, 40, 600), "TestTime5" }, + }; - var query = timeline.GetValuesByHour(16); + var query = timeline.GetValuesByTimeOfDay(new TimeSpan(0, 21, 15, 40, 600)); - using (new AssertionScope()) - { - query.Count - .Should() - .Be(2); + using (new AssertionScope()) + { + query.Count + .Should() + .Be(2); - timeline - .Should() - .Contain(query); - } + timeline + .Should() + .Contain(query); } + } - [Test] - public static void GetValuesByDayTest() + [Test] + public static void GetValuesByDayOfWeekTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1985, 1, 10), "TestTime1" }, - { new DateTime(1990, 1, 10), "TestTime2" }, - { new DateTime(1995, 1, 10), "TestTime3" }, - { new DateTime(2005, 1, 20), "TestTime4" }, - { new DateTime(2015, 1, 20), "TestTime5" }, - }; + { new DateTime(2015, 1, 5), "TestTime1" }, //Monday + { new DateTime(2015, 2, 2), "TestTime2" }, //Monday + { new DateTime(2015, 1, 6), "TestTime3" }, //Tuesday + { new DateTime(2015, 1, 7), "TestTime4" }, //Wednesday + { new DateTime(2015, 1, 8), "TestTime5" }, //Thursday + }; - var query = timeline.GetValuesByDay(20); + var query = timeline.GetValuesByDayOfWeek(DayOfWeek.Monday); - using (new AssertionScope()) - { - query.Count - .Should() - .Be(2); + using (new AssertionScope()) + { + query.Count + .Should() + .Be(2); - timeline - .Should() - .Contain(query); - } + timeline + .Should() + .Contain(query); } + } - [Test] - public static void GetValuesByTimeOfDayTest() + [Test] + public static void GetValuesByDayOfYearTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1985, 1, 1, 10, 30, 15, 500), "TestTime1" }, - { new DateTime(1990, 1, 1, 10, 30, 15, 500), "TestTime2" }, - { new DateTime(1995, 1, 1, 10, 30, 15, 500), "TestTime3" }, - { new DateTime(2005, 1, 1, 21, 15, 40, 600), "TestTime4" }, - { new DateTime(2015, 1, 1, 21, 15, 40, 600), "TestTime5" }, - }; + { new DateTime(1985, 1, 3), "TestTime1" }, //3rd day of year + { new DateTime(1990, 1, 7), "TestTime2" }, //7th day of year + { new DateTime(1995, 1, 22), "TestTime3" }, //22th day of year + { new DateTime(2000, 2, 1), "TestTime4" }, //32th day of year + { new DateTime(2005, 2, 1), "TestTime5" }, //32th day of year + }; - var query = timeline.GetValuesByTimeOfDay(new TimeSpan(0, 21, 15, 40, 600)); + var query = timeline.GetValuesByDayOfYear(32); - using (new AssertionScope()) - { - query.Count - .Should() - .Be(2); + using (new AssertionScope()) + { + query.Count + .Should() + .Be(2); - timeline - .Should() - .Contain(query); - } + timeline + .Should() + .Contain(query); } + } - [Test] - public static void GetValuesByDayOfWeekTest() + [Test] + public static void GetValuesByMonthTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(2015, 1, 5), "TestTime1" }, //Monday - { new DateTime(2015, 2, 2), "TestTime2" }, //Monday - { new DateTime(2015, 1, 6), "TestTime3" }, //Tuesday - { new DateTime(2015, 1, 7), "TestTime4" }, //Wednesday - { new DateTime(2015, 1, 8), "TestTime5" }, //Thursday - }; + { new DateTime(1985, 1, 1), "TestTime1" }, + { new DateTime(1990, 2, 1), "TestTime2" }, + { new DateTime(1995, 3, 1), "TestTime3" }, + { new DateTime(2005, 4, 1), "TestTime4" }, + { new DateTime(2015, 4, 1), "TestTime5" }, + }; - var query = timeline.GetValuesByDayOfWeek(DayOfWeek.Monday); + var query = timeline.GetValuesByMonth(4); - using (new AssertionScope()) - { - query.Count - .Should() - .Be(2); + using (new AssertionScope()) + { + query.Count + .Should() + .Be(2); - timeline - .Should() - .Contain(query); - } + timeline + .Should() + .Contain(query); } + } - [Test] - public static void GetValuesByDayOfYearTest() + [Test] + public static void GetValuesByYearTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1985, 1, 3), "TestTime1" }, //3rd day of year - { new DateTime(1990, 1, 7), "TestTime2" }, //7th day of year - { new DateTime(1995, 1, 22), "TestTime3" }, //22th day of year - { new DateTime(2000, 2, 1), "TestTime4" }, //32th day of year - { new DateTime(2005, 2, 1), "TestTime5" }, //32th day of year - }; + { new DateTime(1985, 1, 2), "TestTime1" }, + { new DateTime(1990, 2, 1), "TestTime2" }, + { new DateTime(1995, 1, 2), "TestTime3" }, + { new DateTime(2005, 2, 1), "TestTime4" }, + { new DateTime(2005, 1, 2), "TestTime5" }, + }; - var query = timeline.GetValuesByDayOfYear(32); + var query = timeline.GetValuesByYear(2005); - using (new AssertionScope()) - { - query.Count - .Should() - .Be(2); + using (new AssertionScope()) + { + query.Count + .Should() + .Be(2); - timeline - .Should() - .Contain(query); - } + timeline + .Should() + .Contain(query); } + } - [Test] - public static void GetValuesByMonthTest() - { - var timeline = new Timeline - { - { new DateTime(1985, 1, 1), "TestTime1" }, - { new DateTime(1990, 2, 1), "TestTime2" }, - { new DateTime(1995, 3, 1), "TestTime3" }, - { new DateTime(2005, 4, 1), "TestTime4" }, - { new DateTime(2015, 4, 1), "TestTime5" }, - }; + [Test] + public static void AddDateTimeAndTValueTest() //void Add(DateTime time, TValue value) + { + var eventDate = new DateTime(2015, 1, 1); + const string eventName = "TestTime"; - var query = timeline.GetValuesByMonth(4); + var timeline = new Timeline(); - using (new AssertionScope()) - { - query.Count - .Should() - .Be(2); + timeline.Add(eventDate, eventName); - timeline - .Should() - .Contain(query); - } - } + timeline.Count + .Should() + .Be(1); - [Test] - public static void GetValuesByYearTest() - { - var timeline = new Timeline - { - { new DateTime(1985, 1, 2), "TestTime1" }, - { new DateTime(1990, 2, 1), "TestTime2" }, - { new DateTime(1995, 1, 2), "TestTime3" }, - { new DateTime(2005, 2, 1), "TestTime4" }, - { new DateTime(2005, 1, 2), "TestTime5" }, - }; + timeline[eventDate][0] + .Should() + .Be(eventName); + } - var query = timeline.GetValuesByYear(2005); + [Test] + public static void AddDateTimeAndTValueArrayTest() //void Add(params (DateTime, TValue)[] timeline) + { + var eventDate1 = new DateTime(2015, 1, 1); + const string eventName1 = "TestTime1"; - using (new AssertionScope()) - { - query.Count - .Should() - .Be(2); + var eventDate2 = new DateTime(1750, 1, 1); + const string eventName2 = "TestTime2"; - timeline - .Should() - .Contain(query); - } - } + var timeline = new Timeline(); + + timeline.Add( + (eventDate1, eventName1), + (eventDate2, eventName2)); - [Test] - public static void AddDateTimeAndTValueTest() //void Add(DateTime time, TValue value) + using (new AssertionScope()) { - var eventDate = new DateTime(2015, 1, 1); - const string eventName = "TestTime"; + timeline.Count + .Should() + .Be(2); + + timeline[eventDate1][0] + .Should() + .Be(eventName1); - var timeline = new Timeline(); + timeline[eventDate2][0] + .Should() + .Be(eventName2); + } + } - timeline.Add(eventDate, eventName); + [Test] + public static void AddTimelineTest() //void Add(Timeline timeline) + { + var eventDate = new DateTime(2015, 1, 1); + const string eventName = "TestTime"; + var timeline = new Timeline(); + + timeline.Add(new Timeline(eventDate, eventName)); + + using (new AssertionScope()) + { timeline.Count .Should() .Be(1); @@ -674,470 +726,417 @@ public static void AddDateTimeAndTValueTest() //void Add(DateTime time, TValue v .Should() .Be(eventName); } + } - [Test] - public static void AddDateTimeAndTValueArrayTest() //void Add(params (DateTime, TValue)[] timeline) - { - var eventDate1 = new DateTime(2015, 1, 1); - const string eventName1 = "TestTime1"; - - var eventDate2 = new DateTime(1750, 1, 1); - const string eventName2 = "TestTime2"; - - var timeline = new Timeline(); + [Test] + public static void AddNowTest() + { + var timeline = new Timeline(); - timeline.Add( - (eventDate1, eventName1), - (eventDate2, eventName2)); + timeline.AddNow("Now"); - using (new AssertionScope()) - { - timeline.Count - .Should() - .Be(2); - - timeline[eventDate1][0] - .Should() - .Be(eventName1); + using (new AssertionScope()) + { + timeline.Count + .Should() + .Be(1); - timeline[eventDate2][0] - .Should() - .Be(eventName2); - } + timeline.ContainsValue("Now") + .Should() + .BeTrue(); } + } - [Test] - public static void AddTimelineTest() //void Add(Timeline timeline) + [Test] + public static void ContainsDateTimeAndTValueTest() //bool Contains(DateTime time, TValue value) + { + var timeline = new Timeline { - var eventDate = new DateTime(2015, 1, 1); - const string eventName = "TestTime"; - - var timeline = new Timeline(); - - timeline.Add(new Timeline(eventDate, eventName)); + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.Contains(new DateTime(2000, 1, 1), "TestTime2") + .Should() + .BeTrue(); + } - using (new AssertionScope()) - { - timeline.Count - .Should() - .Be(1); + [Test] + public static void ContainsDateTimeAndTValueArrayTest() //bool Contains(params (DateTime, TValue)[] timeline) + { + var timeline = new Timeline + { + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.Contains( + (new DateTime(1995, 1, 1), "TestTime1"), + (new DateTime(2000, 1, 1), "TestTime2")) + .Should() + .BeTrue(); + } - timeline[eventDate][0] - .Should() - .Be(eventName); - } - } + [Test] + public static void ContainsTimelineTest() //bool Contains(Timeline timeline) + { + var timeline = new Timeline + { + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.Contains(new Timeline(new DateTime(2000, 1, 1), "TestTime2")) + .Should() + .BeTrue(); + } - [Test] - public static void AddNowTest() + [Test] + public static void ContainsTimeTest() + { + var timeline = new Timeline { - var timeline = new Timeline(); + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.ContainsTime(new DateTime(2000, 1, 1)) + .Should() + .BeTrue(); + } - timeline.AddNow("Now"); + [Test] + public static void ContainsValueTest() + { + var timeline = new Timeline + { + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.ContainsValue("TestTime1") + .Should() + .BeTrue(); + } - using (new AssertionScope()) - { - timeline.Count - .Should() - .Be(1); + [Test] + public static void RemoveDateTimeAndTValueTest() //bool Remove(DateTime time, TValue value) + { + var timeline = new Timeline + { + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - timeline.ContainsValue("Now") - .Should() - .BeTrue(); - } - } + timeline.Remove(new DateTime(2000, 1, 1), "TestTime2"); - [Test] - public static void ContainsDateTimeAndTValueTest() //bool Contains(DateTime time, TValue value) + using (new AssertionScope()) { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + timeline.Count + .Should() + .Be(4); timeline.Contains(new DateTime(2000, 1, 1), "TestTime2") .Should() - .BeTrue(); + .BeFalse(); } + } - [Test] - public static void ContainsDateTimeAndTValueArrayTest() //bool Contains(params (DateTime, TValue)[] timeline) + [Test] + public static void RemoveDateTimeAndTValueArrayTest() //bool Remove(params (DateTime, TValue)[] timeline) + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.Remove( + (new DateTime(1995, 1, 1), "TestTime1"), + (new DateTime(2000, 1, 1), "TestTime2")); + + using (new AssertionScope()) + { + timeline.Count + .Should() + .Be(3); timeline.Contains( (new DateTime(1995, 1, 1), "TestTime1"), (new DateTime(2000, 1, 1), "TestTime2")) .Should() - .BeTrue(); + .BeFalse(); } + } - [Test] - public static void ContainsTimelineTest() //bool Contains(Timeline timeline) + [Test] + public static void RemoveTimelineTest() //bool Remove(Timeline timeline) + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - timeline.Contains(new Timeline(new DateTime(2000, 1, 1), "TestTime2")) - .Should() - .BeTrue(); - } + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + timeline.Remove(new Timeline(new DateTime(2000, 1, 1), "TestTime2")); - [Test] - public static void ContainsTimeTest() + using (new AssertionScope()) { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + timeline.Count + .Should() + .Be(4); - timeline.ContainsTime(new DateTime(2000, 1, 1)) + timeline.Contains(new DateTime(2000, 1, 1), "TestTime2") .Should() - .BeTrue(); + .BeFalse(); } + } - [Test] - public static void ContainsValueTest() + [Test] + public static void RemoveTimeTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - timeline.ContainsValue("TestTime1") + timeline.RemoveTimes(new DateTime(2000, 1, 1)); + + using (new AssertionScope()) + { + timeline.Count .Should() - .BeTrue(); + .Be(4); + + timeline.ContainsTime(new DateTime(2000, 1, 1)) + .Should() + .BeFalse(); } + } - [Test] - public static void RemoveDateTimeAndTValueTest() //bool Remove(DateTime time, TValue value) + [Test] + public static void RemoveValueTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - timeline.Remove(new DateTime(2000, 1, 1), "TestTime2"); + timeline.RemoveValues("TestTime1"); - using (new AssertionScope()) - { - timeline.Count - .Should() - .Be(4); + using (new AssertionScope()) + { + timeline.Count + .Should() + .Be(4); - timeline.Contains(new DateTime(2000, 1, 1), "TestTime2") - .Should() - .BeFalse(); - } + timeline.ContainsValue("TestTime1") + .Should() + .BeFalse(); } + } - [Test] - public static void RemoveDateTimeAndTValueArrayTest() //bool Remove(params (DateTime, TValue)[] timeline) + [Test] + public static void ToArrayTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - timeline.Remove( - (new DateTime(1995, 1, 1), "TestTime1"), - (new DateTime(2000, 1, 1), "TestTime2")); + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - using (new AssertionScope()) - { - timeline.Count - .Should() - .Be(3); + var array = timeline.ToArray(); - timeline.Contains( - (new DateTime(1995, 1, 1), "TestTime1"), - (new DateTime(2000, 1, 1), "TestTime2")) - .Should() - .BeFalse(); - } - } + timeline.Count + .Should() + .Be(array.Length); - [Test] - public static void RemoveTimelineTest() //bool Remove(Timeline timeline) + using (new AssertionScope()) { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - timeline.Remove(new Timeline(new DateTime(2000, 1, 1), "TestTime2")); - - using (new AssertionScope()) + var i = 0; + foreach (var (time, value) in timeline) { - timeline.Count + time .Should() - .Be(4); + .Be(array[i].Time); - timeline.Contains(new DateTime(2000, 1, 1), "TestTime2") + value .Should() - .BeFalse(); + .Be(array[i].Value); + + ++i; } } + } - [Test] - public static void RemoveTimeTest() + [Test] + public static void ToListTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - timeline.RemoveTimes(new DateTime(2000, 1, 1)); + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - using (new AssertionScope()) - { - timeline.Count - .Should() - .Be(4); + var list = timeline.ToList(); - timeline.ContainsTime(new DateTime(2000, 1, 1)) - .Should() - .BeFalse(); - } - } + timeline.Count + .Should() + .Be(list.Count); - [Test] - public static void RemoveValueTest() + using (new AssertionScope()) { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - timeline.RemoveValues("TestTime1"); - - using (new AssertionScope()) + var i = 0; + foreach (var (time, value) in timeline) { - timeline.Count + time .Should() - .Be(4); + .Be(list[i].Time); - timeline.ContainsValue("TestTime1") + value .Should() - .BeFalse(); - } - } - - [Test] - public static void ToArrayTest() - { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - var array = timeline.ToArray(); + .Be(list[i].Value); - timeline.Count - .Should() - .Be(array.Length); - - using (new AssertionScope()) - { - var i = 0; - foreach (var (time, value) in timeline) - { - time - .Should() - .Be(array[i].Time); - - value - .Should() - .Be(array[i].Value); - - ++i; - } + ++i; } } + } - [Test] - public static void ToListTest() + [Test] + public static void ToDictionaryTest() + { + var timeline = new Timeline { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; - var list = timeline.ToList(); + var dictionary = timeline.ToDictionary(); - timeline.Count - .Should() - .Be(list.Count); - - using (new AssertionScope()) - { - var i = 0; - foreach (var (time, value) in timeline) - { - time - .Should() - .Be(list[i].Time); - - value - .Should() - .Be(list[i].Value); - - ++i; - } - } + var timelineList = new List<(DateTime Time, string Value)>(); + foreach (var pair in timeline) + { + timelineList.Add(pair); } - [Test] - public static void ToDictionaryTest() + var dictionaryList = new List<(DateTime Time, string Value)>(); + foreach (var (key, value) in dictionary) { - var timeline = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; + dictionaryList.Add((key, value)); + } - var dictionary = timeline.ToDictionary(); + timelineList.OrderBy(pair => pair.Time); + dictionaryList.OrderBy(pair => pair.Time); - var timelineList = new List<(DateTime Time, string Value)>(); - foreach (var pair in timeline) - { - timelineList.Add(pair); - } + timelineList.Count + .Should() + .Be(dictionaryList.Count); - var dictionaryList = new List<(DateTime Time, string Value)>(); - foreach (var (key, value) in dictionary) + using (new AssertionScope()) + { + for (var i = 0; i < timelineList.Count; ++i) { - dictionaryList.Add((key, value)); - } - - timelineList.OrderBy(pair => pair.Time); - dictionaryList.OrderBy(pair => pair.Time); - - timelineList.Count - .Should() - .Be(dictionaryList.Count); + timelineList[i].Time + .Should() + .Be(dictionaryList[i].Time); - using (new AssertionScope()) - { - for (var i = 0; i < timelineList.Count; ++i) - { - timelineList[i].Time - .Should() - .Be(dictionaryList[i].Time); - - timelineList[i].Value - .Should() - .Be(dictionaryList[i].Value); - } + timelineList[i].Value + .Should() + .Be(dictionaryList[i].Value); } } + } - [Test] - public static void EqualityOperatorTest() + [Test] + public static void EqualityOperatorTest() + { + var timeline1 = new Timeline { - var timeline1 = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - var timeline2 = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - (timeline1 == timeline2) - .Should() - .BeTrue(); - } + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + var timeline2 = new Timeline + { + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + (timeline1 == timeline2) + .Should() + .BeTrue(); + } - [Test] - public static void InequalityOperatorTest() + [Test] + public static void InequalityOperatorTest() + { + var timeline1 = new Timeline { - var timeline1 = new Timeline - { - { new DateTime(1995, 1, 1), "TestTime1" }, - { new DateTime(2000, 1, 1), "TestTime2" }, - { new DateTime(2005, 1, 1), "TestTime3" }, - { new DateTime(2010, 1, 1), "TestTime4" }, - { new DateTime(2015, 1, 1), "TestTime5" }, - }; - - var timeline2 = new Timeline - { - { new DateTime(1895, 1, 1), "TestTime6" }, - { new DateTime(1900, 1, 1), "TestTime7" }, - { new DateTime(1905, 1, 1), "TestTime8" }, - { new DateTime(1910, 1, 1), "TestTime9" }, - { new DateTime(1915, 1, 1), "TestTime10" }, - }; - - (timeline1 == timeline2) - .Should() - .BeFalse(); - } + { new DateTime(1995, 1, 1), "TestTime1" }, + { new DateTime(2000, 1, 1), "TestTime2" }, + { new DateTime(2005, 1, 1), "TestTime3" }, + { new DateTime(2010, 1, 1), "TestTime4" }, + { new DateTime(2015, 1, 1), "TestTime5" }, + }; + + var timeline2 = new Timeline + { + { new DateTime(1895, 1, 1), "TestTime6" }, + { new DateTime(1900, 1, 1), "TestTime7" }, + { new DateTime(1905, 1, 1), "TestTime8" }, + { new DateTime(1910, 1, 1), "TestTime9" }, + { new DateTime(1915, 1, 1), "TestTime10" }, + }; + + (timeline1 == timeline2) + .Should() + .BeFalse(); } } diff --git a/DataStructures.Tests/Tries/TrieTests.cs b/DataStructures.Tests/Tries/TrieTests.cs index 770a54c3..8b84356d 100644 --- a/DataStructures.Tests/Tries/TrieTests.cs +++ b/DataStructures.Tests/Tries/TrieTests.cs @@ -2,114 +2,113 @@ using DataStructures.Tries; using NUnit.Framework; -namespace DataStructures.Tests.Tries +namespace DataStructures.Tests.Tries; + +public static class TrieTests { - public static class TrieTests - { - [Test] - public static void FindWordInTrie(){ - // Arrange - string[] words = { - "trie", - "node", - "none", - "treatment", - }; - - // Act - Trie trie = new(words); - - // Assert - Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); - Assert.IsTrue(trie.Find("node"), "The word 'node' isn't in Trie structure"); - Assert.IsTrue(trie.Find("none"), "The word 'none' isn't in Trie structure"); - Assert.IsTrue(trie.Find("treatment"), "The word 'treatment' isn't in Trie structure"); - - Assert.IsFalse(trie.Find("nodes"), "The word 'nodes' is in Trie sturcture"); - Assert.IsFalse(trie.Find(""), "The word empty is in Trie structure"); - Assert.IsFalse(trie.Find("tri"), "The word 'tri' is in Trie structure"); - } + [Test] + public static void FindWordInTrie(){ + // Arrange + string[] words = { + "trie", + "node", + "none", + "treatment", + }; + + // Act + Trie trie = new(words); + + // Assert + Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); + Assert.IsTrue(trie.Find("node"), "The word 'node' isn't in Trie structure"); + Assert.IsTrue(trie.Find("none"), "The word 'none' isn't in Trie structure"); + Assert.IsTrue(trie.Find("treatment"), "The word 'treatment' isn't in Trie structure"); + + Assert.IsFalse(trie.Find("nodes"), "The word 'nodes' is in Trie sturcture"); + Assert.IsFalse(trie.Find(""), "The word empty is in Trie structure"); + Assert.IsFalse(trie.Find("tri"), "The word 'tri' is in Trie structure"); + } - [Test] - public static void InsertInTrie(){ - // Arrange - string[] words = { - "trie", - "node", - "none", - "treatment", - }; - - Trie trie = new(); - - // Act - foreach (var t in words) - { - trie.Insert(t); - } - - // Assert - Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); - Assert.IsTrue(trie.Find("node"), "The word 'node' isn't in Trie structure"); - Assert.IsTrue(trie.Find("none"), "The word 'none' isn't in Trie structure"); - Assert.IsTrue(trie.Find("treatment"), "The word 'treatment' isn't in Trie structure"); - } + [Test] + public static void InsertInTrie(){ + // Arrange + string[] words = { + "trie", + "node", + "none", + "treatment", + }; - [Test] - public static void RemoveFromTrie(){ - // Arrange - string[] words = { - "trie", - "node", - "none", - "treatment", - }; - - Trie trie = new(); - - // Act - foreach (var t in words) - { - trie.Insert(t); - } - trie.Remove("trie"); - - // Assert - Assert.IsFalse(trie.Find("trie"), "The word 'trie' is in Trie structure"); - Assert.IsTrue(trie.Find("treatment"), "The word 'treament' isn't in Trie structure"); - Assert.IsTrue(trie.Find("node"), "The word 'node' isn't in Trie structure"); - Assert.IsTrue(trie.Find("none"), "The word 'none' isn't in Trie structure"); - } + Trie trie = new(); - [Test] - public static void MultipleInsert() + // Act + foreach (var t in words) { - // Arrange - string w = "trie"; - Trie trie = new(); + trie.Insert(t); + } + + // Assert + Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); + Assert.IsTrue(trie.Find("node"), "The word 'node' isn't in Trie structure"); + Assert.IsTrue(trie.Find("none"), "The word 'none' isn't in Trie structure"); + Assert.IsTrue(trie.Find("treatment"), "The word 'treatment' isn't in Trie structure"); + } + + [Test] + public static void RemoveFromTrie(){ + // Arrange + string[] words = { + "trie", + "node", + "none", + "treatment", + }; - // Act - trie.Insert(w); - trie.Insert(w); + Trie trie = new(); - // Assert - Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); - Assert.IsFalse(trie.Find("nodes"), "The word 'nodes' is in Trie sturcture"); + // Act + foreach (var t in words) + { + trie.Insert(t); } + trie.Remove("trie"); - [Test] - public static void RemoveAWordThatIsNtInTrie(){ - // Arrange - const string w = "trie"; - Trie trie = new(); + // Assert + Assert.IsFalse(trie.Find("trie"), "The word 'trie' is in Trie structure"); + Assert.IsTrue(trie.Find("treatment"), "The word 'treament' isn't in Trie structure"); + Assert.IsTrue(trie.Find("node"), "The word 'node' isn't in Trie structure"); + Assert.IsTrue(trie.Find("none"), "The word 'none' isn't in Trie structure"); + } - // Act - trie.Insert(w); - trie.Remove("tri"); - trie.Remove("none"); + [Test] + public static void MultipleInsert() + { + // Arrange + string w = "trie"; + Trie trie = new(); - // Assert - Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); - } + // Act + trie.Insert(w); + trie.Insert(w); + + // Assert + Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); + Assert.IsFalse(trie.Find("nodes"), "The word 'nodes' is in Trie sturcture"); + } + + [Test] + public static void RemoveAWordThatIsNtInTrie(){ + // Arrange + const string w = "trie"; + Trie trie = new(); + + // Act + trie.Insert(w); + trie.Remove("tri"); + trie.Remove("none"); + + // Assert + Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); } } diff --git a/DataStructures.Tests/UnrolledList/UnrolledLinkedListNodeTests.cs b/DataStructures.Tests/UnrolledList/UnrolledLinkedListNodeTests.cs index 95b0bc1a..eb73b760 100644 --- a/DataStructures.Tests/UnrolledList/UnrolledLinkedListNodeTests.cs +++ b/DataStructures.Tests/UnrolledList/UnrolledLinkedListNodeTests.cs @@ -1,61 +1,60 @@ -using System; +using System; using DataStructures.UnrolledList; using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests.UnrolledList +namespace DataStructures.Tests.UnrolledList; + +public class UnrolledLinkedListNodeTests { - public class UnrolledLinkedListNodeTests + [Test] + public void GetAndSet_SetItemNodeAndGetIt_ReturnExpectedItem() { - [Test] - public void GetAndSet_SetItemNodeAndGetIt_ReturnExpectedItem() - { - var node = new UnrolledLinkedListNode(6); - node.Set(0, 1); + var node = new UnrolledLinkedListNode(6); + node.Set(0, 1); - var result = node.Get(0); + var result = node.Get(0); - result.Should().Be(1); - } + result.Should().Be(1); + } - [Test] - public void Get_GetLowIndex_ThrowArgumentException() - { - var node = new UnrolledLinkedListNode(6); + [Test] + public void Get_GetLowIndex_ThrowArgumentException() + { + var node = new UnrolledLinkedListNode(6); - Action action = () => node.Get(-1); + Action action = () => node.Get(-1); - action.Should().Throw(); - } + action.Should().Throw(); + } - [Test] - public void Get_GetHighIndex_ThrowArgumentException() - { - var node = new UnrolledLinkedListNode(6); + [Test] + public void Get_GetHighIndex_ThrowArgumentException() + { + var node = new UnrolledLinkedListNode(6); - Action action = () => node.Get(7); + Action action = () => node.Get(7); - action.Should().Throw(); - } + action.Should().Throw(); + } - [Test] - public void Set_SetLowIndex_ThrowArgumentException() - { - var node = new UnrolledLinkedListNode(6); + [Test] + public void Set_SetLowIndex_ThrowArgumentException() + { + var node = new UnrolledLinkedListNode(6); - Action action = () => node.Set(-1, 0); + Action action = () => node.Set(-1, 0); - action.Should().Throw(); - } + action.Should().Throw(); + } - [Test] - public void Set_SetHighIndex_ThrowArgumentException() - { - var node = new UnrolledLinkedListNode(6); + [Test] + public void Set_SetHighIndex_ThrowArgumentException() + { + var node = new UnrolledLinkedListNode(6); - Action action = () => node.Set(7, 0); + Action action = () => node.Set(7, 0); - action.Should().Throw(); - } + action.Should().Throw(); } } diff --git a/DataStructures.Tests/UnrolledList/UnrolledLinkedListTests.cs b/DataStructures.Tests/UnrolledList/UnrolledLinkedListTests.cs index 26761bf0..32a410d2 100644 --- a/DataStructures.Tests/UnrolledList/UnrolledLinkedListTests.cs +++ b/DataStructures.Tests/UnrolledList/UnrolledLinkedListTests.cs @@ -1,24 +1,23 @@ -using DataStructures.UnrolledList; +using DataStructures.UnrolledList; using FluentAssertions; using NUnit.Framework; -namespace DataStructures.Tests.UnrolledList +namespace DataStructures.Tests.UnrolledList; + +public class UnrolledLinkedListTests { - public class UnrolledLinkedListTests + [Test] + public void Insert_LinkArrayToLinkedList_ReturnArrayHaveSameItems() { - [Test] - public void Insert_LinkArrayToLinkedList_ReturnArrayHaveSameItems() + var linkedList = new UnrolledLinkedList(6); + var contest = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; + foreach (var number in contest) { - var linkedList = new UnrolledLinkedList(6); - var contest = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; - foreach (var number in contest) - { - linkedList.Insert(number); - } + linkedList.Insert(number); + } - var result = linkedList.GetRolledItems(); + var result = linkedList.GetRolledItems(); - result.Should().BeEquivalentTo(contest); - } + result.Should().BeEquivalentTo(contest); } } From 692279970b7ed6a2556a08545652f83811124166 Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Wed, 10 Jan 2024 19:39:16 +0000 Subject: [PATCH 089/138] Switch to file-scoped namespaces (#437) --- .../BurrowsWheelerTransformTests.cs | 85 +- .../Compressors/HuffmanCompressorTests.cs | 107 +- .../Compressors/ShannonFanoCompressorTests.cs | 67 +- .../Compressors/TranslatorTests.cs | 37 +- .../Encoders/CaesarEncoderTests.cs | 31 +- .../Encoders/FeistelCipherTest.cs | 71 +- .../Encoders/HillEnconderTests.cs | 35 +- .../Encoders/NysiisEncoderTests.cs | 39 +- .../Encoders/SoundexEncoderTest.cs | 29 +- .../Encoders/VigenereEncoderTests.cs | 95 +- Algorithms.Tests/Graph/BellmanFordTests.cs | 97 +- .../Graph/BreadthFirstSearchTests.cs | 153 +- .../Graph/BreadthFirstTreeTraversalTests.cs | 137 +- .../Graph/DepthFirstSearchTests.cs | 151 +- .../Graph/Dijkstra/DijkstraTests.cs | 439 +++--- Algorithms.Tests/Graph/FloydWarshallTests.cs | 61 +- Algorithms.Tests/Graph/KosarajuTests.cs | 181 ++- .../Graph/MinimumSpanningTree/KruskalTests.cs | 1381 ++++++++--------- .../MinimumSpanningTree/PrimMatrixTests.cs | 705 +++++---- Algorithms.Tests/Helpers/IntComparer.cs | 11 +- Algorithms.Tests/Helpers/RandomHelper.cs | 73 +- .../BranchAndBoundKnapsackSolverTests.cs | 211 ++- .../DynamicProgrammingKnapsackSolverTests.cs | 141 +- .../Knapsack/NaiveKnapsackSolverTests.cs | 33 +- .../LinearAlgebra/Distances/EuclideanTests.cs | 55 +- .../LinearAlgebra/Distances/ManhattanTests.cs | 59 +- .../Eigenvalue/PowerIterationTests.cs | 107 +- .../ChineseRemainderTheoremTest.cs | 271 ++-- .../ExtendedEuclideanAlgorithmTest.cs | 87 +- .../ModularMultiplicativeInverseTest.cs | 103 +- .../Numeric/AliquotSumCalculatorTests.cs | 49 +- .../Numeric/AmicableNumbersTest.cs | 34 +- .../Numeric/AutomorphicNumberTests.cs | 193 ++- .../Numeric/BinomialCoefficientTests.cs | 41 +- .../Numeric/Decomposition/LUTests.cs | 243 ++- .../Numeric/Decomposition/MaclaurinTests.cs | 245 ++- .../Numeric/Decomposition/SVDTests.cs | 195 ++- Algorithms.Tests/Numeric/EulerMethodTest.cs | 95 +- Algorithms.Tests/Numeric/FactorialTests.cs | 53 +- .../TrialDivisionFactorizerTests.cs | 69 +- .../Numeric/GaussJordanEliminationTests.cs | 55 +- .../BinaryGreatestCommonDivisorFinderTests.cs | 43 +- ...clideanGreatestCommonDivisorFinderTests.cs | 43 +- Algorithms.Tests/Numeric/KeithNumberTest.cs | 43 +- .../KrishnamurthyNumberCheckerTests.cs | 53 +- .../Numeric/MillerRabinPrimalityTest.cs | 67 +- .../Numeric/ModularExponentiationTest.cs | 51 +- .../Numeric/NarcissisticNumberTest.cs | 35 +- Algorithms.Tests/Numeric/PerfectNumberTest.cs | 47 +- Algorithms.Tests/Numeric/PerfectSquareTest.cs | 37 +- .../PseudoInverse/PseudoInverseTests.cs | 77 +- .../Numeric/RungeKuttaMethodTest.cs | 59 +- .../Other/DecisionsConvolutionsTest.cs | 87 +- .../Other/FermatPrimeCheckerTests.cs | 37 +- Algorithms.Tests/Other/FloodFillTest.cs | 161 +- .../Other/GaussOptimizationTest.cs | 138 +- Algorithms.Tests/Other/GeoLocationTests.cs | 35 +- Algorithms.Tests/Other/Int2BinaryTests.cs | 105 +- Algorithms.Tests/Other/JulianEasterTests.cs | 43 +- Algorithms.Tests/Other/KochSnowflakeTest.cs | 69 +- Algorithms.Tests/Other/LuhnTests.cs | 99 +- Algorithms.Tests/Other/MandelbrotTest.cs | 81 +- .../Other/ParetoOptimizationTests.cs | 63 +- .../Other/PollardsRhoFactorizingTests.cs | 23 +- .../Other/RGBHSVConversionTest.cs | 141 +- .../Other/SieveOfEratosthenesTests.cs | 1343 ++++++++-------- .../Other/WelfordsVarianceTest.cs | 285 ++-- 67 files changed, 4753 insertions(+), 4836 deletions(-) diff --git a/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs b/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs index 1dd5204d..cd5f4ea1 100644 --- a/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs +++ b/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs @@ -1,50 +1,49 @@ -using Algorithms.DataCompression; +using Algorithms.DataCompression; using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Compressors +namespace Algorithms.Tests.Compressors; + +public class BurrowsWheelerTransformTests { - public class BurrowsWheelerTransformTests + [Test] + [TestCase("banana", "nnbaaa", 3)] + [TestCase("SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES", "TEXYDST.E.IXIXIXXSSMPPS.B..E.S.EUSFXDIIOIIIT", 29)] + [TestCase("", "", 0)] + public void Encode(string input, string expectedString, int expectedIndex) { - [Test] - [TestCase("banana", "nnbaaa", 3)] - [TestCase("SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES", "TEXYDST.E.IXIXIXXSSMPPS.B..E.S.EUSFXDIIOIIIT", 29)] - [TestCase("", "", 0)] - public void Encode(string input, string expectedString, int expectedIndex) - { - var bwt = new BurrowsWheelerTransform(); - - var (encoded, index) = bwt.Encode(input); - - Assert.AreEqual(expectedString, encoded); - Assert.AreEqual(expectedIndex, index); - } - - [Test] - [TestCase("nnbaaa", 3, "banana")] - [TestCase("TEXYDST.E.IXIXIXXSSMPPS.B..E.S.EUSFXDIIOIIIT", 29, "SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES")] - [TestCase("", 0, "")] - public void Decode(string encoded, int index, string expected) - { - var bwt = new BurrowsWheelerTransform(); - - var result = bwt.Decode(encoded, index); - - Assert.AreEqual(expected, result); - } - - [Test] - [Repeat(100)] - public void RandomEncodeDecode() - { - var bwt = new BurrowsWheelerTransform(); - var random = new Randomizer(); - var inputString = random.GetString(); - - var (encoded, index) = bwt.Encode(inputString); - var result = bwt.Decode(encoded, index); - - Assert.AreEqual(inputString, result); - } + var bwt = new BurrowsWheelerTransform(); + + var (encoded, index) = bwt.Encode(input); + + Assert.AreEqual(expectedString, encoded); + Assert.AreEqual(expectedIndex, index); + } + + [Test] + [TestCase("nnbaaa", 3, "banana")] + [TestCase("TEXYDST.E.IXIXIXXSSMPPS.B..E.S.EUSFXDIIOIIIT", 29, "SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES")] + [TestCase("", 0, "")] + public void Decode(string encoded, int index, string expected) + { + var bwt = new BurrowsWheelerTransform(); + + var result = bwt.Decode(encoded, index); + + Assert.AreEqual(expected, result); + } + + [Test] + [Repeat(100)] + public void RandomEncodeDecode() + { + var bwt = new BurrowsWheelerTransform(); + var random = new Randomizer(); + var inputString = random.GetString(); + + var (encoded, index) = bwt.Encode(inputString); + var result = bwt.Decode(encoded, index); + + Assert.AreEqual(inputString, result); } } diff --git a/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs b/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs index 4ee7fb7f..70540020 100644 --- a/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs +++ b/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs @@ -1,63 +1,62 @@ -using Algorithms.DataCompression; +using Algorithms.DataCompression; using Algorithms.Sorters.Comparison; using FluentAssertions; using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Compressors +namespace Algorithms.Tests.Compressors; + +public static class HuffmanCompressorTests { - public static class HuffmanCompressorTests + [Test] + [TestCase("This is a string", "101010110111011101110111100011111010010010010011000")] + [TestCase("Hello", "1101110010")] + [TestCase("dddddddddd", "1111111111")] + [TestCase("a", "1")] + [TestCase("", "")] + public static void CompressingPhrase(string uncompressedText, string expectedCompressedText) + { + //Arrange + var sorter = new BubbleSorter(); + var translator = new Translator(); + var huffman = new HuffmanCompressor(sorter, translator); + + //Act + var (compressedText, decompressionKeys) = huffman.Compress(uncompressedText); + var decompressedText = translator.Translate(compressedText, decompressionKeys); + + //Assert + Assert.AreEqual(expectedCompressedText, compressedText); + Assert.AreEqual(uncompressedText, decompressedText); + } + + [Test] + public static void DecompressedTextTheSameAsOriginal( + [Random(0, 1000, 100, Distinct = true)] + int length) { - [Test] - [TestCase("This is a string", "101010110111011101110111100011111010010010010011000")] - [TestCase("Hello", "1101110010")] - [TestCase("dddddddddd", "1111111111")] - [TestCase("a", "1")] - [TestCase("", "")] - public static void CompressingPhrase(string uncompressedText, string expectedCompressedText) - { - //Arrange - var sorter = new BubbleSorter(); - var translator = new Translator(); - var huffman = new HuffmanCompressor(sorter, translator); - - //Act - var (compressedText, decompressionKeys) = huffman.Compress(uncompressedText); - var decompressedText = translator.Translate(compressedText, decompressionKeys); - - //Assert - Assert.AreEqual(expectedCompressedText, compressedText); - Assert.AreEqual(uncompressedText, decompressedText); - } - - [Test] - public static void DecompressedTextTheSameAsOriginal( - [Random(0, 1000, 100, Distinct = true)] - int length) - { - //Arrange - var sorter = new BubbleSorter(); - var translator = new Translator(); - var huffman = new HuffmanCompressor(sorter, translator); - var text = Randomizer.CreateRandomizer().GetString(length); - - //Act - var (compressedText, decompressionKeys) = huffman.Compress(text); - var decompressedText = translator.Translate(compressedText, decompressionKeys); - - //Assert - Assert.AreEqual(text, decompressedText); - } - - [Test] - public static void ListNodeComparer_NullIsUnordered() - { - var comparer = new HuffmanCompressor.ListNodeComparer(); - var node = new HuffmanCompressor.ListNode('a', 0.1); - - comparer.Compare(node, null).Should().Be(0); - comparer.Compare(null, node).Should().Be(0); - comparer.Compare(null, null).Should().Be(0); - } + //Arrange + var sorter = new BubbleSorter(); + var translator = new Translator(); + var huffman = new HuffmanCompressor(sorter, translator); + var text = Randomizer.CreateRandomizer().GetString(length); + + //Act + var (compressedText, decompressionKeys) = huffman.Compress(text); + var decompressedText = translator.Translate(compressedText, decompressionKeys); + + //Assert + Assert.AreEqual(text, decompressedText); + } + + [Test] + public static void ListNodeComparer_NullIsUnordered() + { + var comparer = new HuffmanCompressor.ListNodeComparer(); + var node = new HuffmanCompressor.ListNode('a', 0.1); + + comparer.Compare(node, null).Should().Be(0); + comparer.Compare(null, node).Should().Be(0); + comparer.Compare(null, null).Should().Be(0); } } diff --git a/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs b/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs index 33225ae3..ec847b2e 100644 --- a/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs +++ b/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs @@ -1,47 +1,46 @@ -using Algorithms.DataCompression; +using Algorithms.DataCompression; using Algorithms.Knapsack; using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Compressors +namespace Algorithms.Tests.Compressors; + +public static class ShannonFanoCompressorTests { - public static class ShannonFanoCompressorTests + [Test] + [TestCase("dddddddddd", "1111111111")] + [TestCase("a", "1")] + [TestCase("", "")] + public static void CompressingPhrase(string uncompressedText, string expectedCompressedText) { - [Test] - [TestCase("dddddddddd", "1111111111")] - [TestCase("a", "1")] - [TestCase("", "")] - public static void CompressingPhrase(string uncompressedText, string expectedCompressedText) - { - //Arrange - var solver = new NaiveKnapsackSolver<(char, double)>(); - var translator = new Translator(); - var shannonFanoCompressor = new ShannonFanoCompressor(solver, translator); + //Arrange + var solver = new NaiveKnapsackSolver<(char, double)>(); + var translator = new Translator(); + var shannonFanoCompressor = new ShannonFanoCompressor(solver, translator); - //Act - var (compressedText, decompressionKeys) = shannonFanoCompressor.Compress(uncompressedText); - var decompressedText = translator.Translate(compressedText, decompressionKeys); + //Act + var (compressedText, decompressionKeys) = shannonFanoCompressor.Compress(uncompressedText); + var decompressedText = translator.Translate(compressedText, decompressionKeys); - //Assert - Assert.AreEqual(expectedCompressedText, compressedText); - Assert.AreEqual(uncompressedText, decompressedText); - } + //Assert + Assert.AreEqual(expectedCompressedText, compressedText); + Assert.AreEqual(uncompressedText, decompressedText); + } - [Test] - public static void DecompressedTextTheSameAsOriginal([Random(0, 1000, 100)] int length) - { - //Arrange - var solver = new NaiveKnapsackSolver<(char, double)>(); - var translator = new Translator(); - var shannonFanoCompressor = new ShannonFanoCompressor(solver, translator); - var text = Randomizer.CreateRandomizer().GetString(length); + [Test] + public static void DecompressedTextTheSameAsOriginal([Random(0, 1000, 100)] int length) + { + //Arrange + var solver = new NaiveKnapsackSolver<(char, double)>(); + var translator = new Translator(); + var shannonFanoCompressor = new ShannonFanoCompressor(solver, translator); + var text = Randomizer.CreateRandomizer().GetString(length); - //Act - var (compressedText, decompressionKeys) = shannonFanoCompressor.Compress(text); - var decompressedText = translator.Translate(compressedText, decompressionKeys); + //Act + var (compressedText, decompressionKeys) = shannonFanoCompressor.Compress(text); + var decompressedText = translator.Translate(compressedText, decompressionKeys); - //Assert - Assert.AreEqual(text, decompressedText); - } + //Assert + Assert.AreEqual(text, decompressedText); } } diff --git a/Algorithms.Tests/Compressors/TranslatorTests.cs b/Algorithms.Tests/Compressors/TranslatorTests.cs index 3bae7637..487629fd 100644 --- a/Algorithms.Tests/Compressors/TranslatorTests.cs +++ b/Algorithms.Tests/Compressors/TranslatorTests.cs @@ -1,29 +1,28 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Algorithms.DataCompression; using NUnit.Framework; -namespace Algorithms.Tests.Compressors +namespace Algorithms.Tests.Compressors; + +public static class TranslatorTests { - public static class TranslatorTests + [Test] + public static void TranslateCorrectly() { - [Test] - public static void TranslateCorrectly() + // Arrange + var translator = new Translator(); + var dict = new Dictionary { - // Arrange - var translator = new Translator(); - var dict = new Dictionary - { - { "Hey", "Good day" }, - { " ", " " }, - { "man", "sir" }, - { "!", "." }, - }; + { "Hey", "Good day" }, + { " ", " " }, + { "man", "sir" }, + { "!", "." }, + }; - // Act - var translatedText = translator.Translate("Hey man!", dict); + // Act + var translatedText = translator.Translate("Hey man!", dict); - // Assert - Assert.AreEqual("Good day sir.", translatedText); - } + // Assert + Assert.AreEqual("Good day sir.", translatedText); } } diff --git a/Algorithms.Tests/Encoders/CaesarEncoderTests.cs b/Algorithms.Tests/Encoders/CaesarEncoderTests.cs index 10385c81..6db9421d 100644 --- a/Algorithms.Tests/Encoders/CaesarEncoderTests.cs +++ b/Algorithms.Tests/Encoders/CaesarEncoderTests.cs @@ -1,25 +1,24 @@ -using Algorithms.Encoders; +using Algorithms.Encoders; using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Encoders +namespace Algorithms.Tests.Encoders; + +public static class CaesarEncoderTests { - public static class CaesarEncoderTests + [Test] + public static void DecodedStringIsTheSame([Random(100)] int key) { - [Test] - public static void DecodedStringIsTheSame([Random(100)] int key) - { - // Arrange - var encoder = new CaesarEncoder(); - var random = new Randomizer(); - var message = random.GetString(); + // Arrange + var encoder = new CaesarEncoder(); + var random = new Randomizer(); + var message = random.GetString(); - // Act - var encoded = encoder.Encode(message, key); - var decoded = encoder.Decode(encoded, key); + // Act + var encoded = encoder.Encode(message, key); + var decoded = encoder.Decode(encoded, key); - // Assert - Assert.AreEqual(message, decoded); - } + // Assert + Assert.AreEqual(message, decoded); } } diff --git a/Algorithms.Tests/Encoders/FeistelCipherTest.cs b/Algorithms.Tests/Encoders/FeistelCipherTest.cs index 4cdc51bf..ea5763a9 100644 --- a/Algorithms.Tests/Encoders/FeistelCipherTest.cs +++ b/Algorithms.Tests/Encoders/FeistelCipherTest.cs @@ -3,43 +3,42 @@ using NUnit.Framework.Internal; using System; -namespace Algorithms.Tests.Encoders +namespace Algorithms.Tests.Encoders; + +public static class FeistelCipherTests { - public static class FeistelCipherTests + [Test] + public static void DecodedStringIsTheSame([Random(100)] uint key) { - [Test] - public static void DecodedStringIsTheSame([Random(100)] uint key) - { - // Arrange - var encoder = new FeistelCipher(); - var random = new Randomizer(); - - int lenOfString = random.Next(1000); - - string message = random.GetString(lenOfString); - - // Act - var encoded = encoder.Encode(message, key); - var decoded = encoder.Decode(encoded, key); - - // Assert - Assert.AreEqual(message, decoded); - } - - [Test] - [TestCase("00001111", (uint)0x12345678)] - [TestCase("00001111222233334444555566667", (uint)0x12345678)] - [TestCase("000011112222333344445555666677", (uint)0x12345678)] - [TestCase("0000111122223333444455556666777", (uint)0x12345678)] - // The plain text will be padded to fill the size of block (16 bytes), so the encoded message should be aligned with the rule - // (text.Length % 16 == 0) - public static void TestEncodedMessageSize(string testCase, uint key) - { - // Arrange - var encoder = new FeistelCipher(); - - // Assert - Assert.Throws(() => encoder.Decode(testCase, key)); - } + // Arrange + var encoder = new FeistelCipher(); + var random = new Randomizer(); + + int lenOfString = random.Next(1000); + + string message = random.GetString(lenOfString); + + // Act + var encoded = encoder.Encode(message, key); + var decoded = encoder.Decode(encoded, key); + + // Assert + Assert.AreEqual(message, decoded); + } + + [Test] + [TestCase("00001111", (uint)0x12345678)] + [TestCase("00001111222233334444555566667", (uint)0x12345678)] + [TestCase("000011112222333344445555666677", (uint)0x12345678)] + [TestCase("0000111122223333444455556666777", (uint)0x12345678)] + // The plain text will be padded to fill the size of block (16 bytes), so the encoded message should be aligned with the rule + // (text.Length % 16 == 0) + public static void TestEncodedMessageSize(string testCase, uint key) + { + // Arrange + var encoder = new FeistelCipher(); + + // Assert + Assert.Throws(() => encoder.Decode(testCase, key)); } } diff --git a/Algorithms.Tests/Encoders/HillEnconderTests.cs b/Algorithms.Tests/Encoders/HillEnconderTests.cs index 55e229c7..87709605 100644 --- a/Algorithms.Tests/Encoders/HillEnconderTests.cs +++ b/Algorithms.Tests/Encoders/HillEnconderTests.cs @@ -1,28 +1,27 @@ -using Algorithms.Encoders; +using Algorithms.Encoders; using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Encoders +namespace Algorithms.Tests.Encoders; + +public static class HillEnconderTests { - public static class HillEnconderTests + [Test] + [Repeat(100)] + public static void DecodedStringIsTheSame() { - [Test] - [Repeat(100)] - public static void DecodedStringIsTheSame() - { - // Arrange - var encoder = new HillEncoder(); - var random = new Randomizer(); - var message = random.GetString(); + // Arrange + var encoder = new HillEncoder(); + var random = new Randomizer(); + var message = random.GetString(); - var key = new double[,] { { 0, 4, 5 }, { 9, 2, -1 }, { 3, 17, 7 } }; + var key = new double[,] { { 0, 4, 5 }, { 9, 2, -1 }, { 3, 17, 7 } }; - // Act - var encodedText = encoder.Encode(message, key); - var decodeText = encoder.Decode(encodedText, key); + // Act + var encodedText = encoder.Encode(message, key); + var decodeText = encoder.Decode(encodedText, key); - // Assert - Assert.AreEqual(message, decodeText); - } + // Assert + Assert.AreEqual(message, decodeText); } } diff --git a/Algorithms.Tests/Encoders/NysiisEncoderTests.cs b/Algorithms.Tests/Encoders/NysiisEncoderTests.cs index 26d9c7ac..fdffcde1 100644 --- a/Algorithms.Tests/Encoders/NysiisEncoderTests.cs +++ b/Algorithms.Tests/Encoders/NysiisEncoderTests.cs @@ -3,30 +3,29 @@ using Algorithms.Encoders; using NUnit.Framework; -namespace Algorithms.Tests.Encoders +namespace Algorithms.Tests.Encoders; + +public class NysiisEncoderTests { - public class NysiisEncoderTests + private static readonly string[] Names = { - private static readonly string[] Names = - { - "Jay", "John", "Jane", "Zayne", "Guerra", "Iga", "Cowan", "Louisa", "Arnie", "Olsen", "Corban", "Nava", - "Cynthia Malone", "Amiee MacKee", "MacGyver", "Yasmin Edge", - }; + "Jay", "John", "Jane", "Zayne", "Guerra", "Iga", "Cowan", "Louisa", "Arnie", "Olsen", "Corban", "Nava", + "Cynthia Malone", "Amiee MacKee", "MacGyver", "Yasmin Edge", + }; - private static readonly string[] Expected = - { - "JY", "JAN", "JAN", "ZAYN", "GAR", "IG", "CAN", "LAS", "ARNY", "OLSAN", "CARBAN", "NAV", "CYNTANALAN", - "ANANACY", "MCGYVAR", "YASNANADG", - }; + private static readonly string[] Expected = + { + "JY", "JAN", "JAN", "ZAYN", "GAR", "IG", "CAN", "LAS", "ARNY", "OLSAN", "CARBAN", "NAV", "CYNTANALAN", + "ANANACY", "MCGYVAR", "YASNANADG", + }; - private static IEnumerable TestData => Names.Zip(Expected, (l, r) => new[] { l, r }); + private static IEnumerable TestData => Names.Zip(Expected, (l, r) => new[] { l, r }); - [TestCaseSource(nameof(TestData))] - public void AttemptNysiis(string source, string expected) - { - var enc = new NysiisEncoder(); - var nysiis = enc.Encode(source); - Assert.AreEqual(expected, nysiis); - } + [TestCaseSource(nameof(TestData))] + public void AttemptNysiis(string source, string expected) + { + var enc = new NysiisEncoder(); + var nysiis = enc.Encode(source); + Assert.AreEqual(expected, nysiis); } } diff --git a/Algorithms.Tests/Encoders/SoundexEncoderTest.cs b/Algorithms.Tests/Encoders/SoundexEncoderTest.cs index 342e9859..1c9a8206 100644 --- a/Algorithms.Tests/Encoders/SoundexEncoderTest.cs +++ b/Algorithms.Tests/Encoders/SoundexEncoderTest.cs @@ -3,25 +3,24 @@ using Algorithms.Encoders; using NUnit.Framework; -namespace Algorithms.Tests.Encoders +namespace Algorithms.Tests.Encoders; + +public static class SoundexEncoderTest { - public static class SoundexEncoderTest + private static readonly string[] Names = { - private static readonly string[] Names = - { - "Robert", "Rupert", "Rubin", "Ashcraft", "Ashcroft", "Tymczak", "Pfister", "Honeyman", - }; + "Robert", "Rupert", "Rubin", "Ashcraft", "Ashcroft", "Tymczak", "Pfister", "Honeyman", + }; - private static readonly string[] Expected = { "R163", "R163", "R150", "A261", "A261", "T522", "P236", "H555" }; + private static readonly string[] Expected = { "R163", "R163", "R150", "A261", "A261", "T522", "P236", "H555" }; - private static IEnumerable TestData => Names.Zip(Expected, (l, r) => new[] { l, r }); + private static IEnumerable TestData => Names.Zip(Expected, (l, r) => new[] { l, r }); - [TestCaseSource(nameof(TestData))] - public static void AttemptSoundex(string source, string encoded) - { - SoundexEncoder enc = new(); - var nysiis = enc.Encode(source); - Assert.AreEqual(nysiis, encoded); - } + [TestCaseSource(nameof(TestData))] + public static void AttemptSoundex(string source, string encoded) + { + SoundexEncoder enc = new(); + var nysiis = enc.Encode(source); + Assert.AreEqual(nysiis, encoded); } } diff --git a/Algorithms.Tests/Encoders/VigenereEncoderTests.cs b/Algorithms.Tests/Encoders/VigenereEncoderTests.cs index fbaad1fc..2d32703a 100644 --- a/Algorithms.Tests/Encoders/VigenereEncoderTests.cs +++ b/Algorithms.Tests/Encoders/VigenereEncoderTests.cs @@ -1,56 +1,55 @@ -using System; +using System; using Algorithms.Encoders; using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Encoders +namespace Algorithms.Tests.Encoders; + +public static class VigenereEncoderTests { - public static class VigenereEncoderTests + [Test] + [Repeat(100)] + public static void DecodedStringIsTheSame() + { + // Arrange + var random = new Randomizer(); + var encoder = new VigenereEncoder(); + var message = random.GetString(); + var key = random.GetString(random.Next(1, 1000)); + + // Act + var encoded = encoder.Encode(message, key); + var decoded = encoder.Decode(encoded, key); + + // Assert + Assert.AreEqual(message, decoded); + } + + [Test] + public static void Encode_KeyIsTooShort_KeyIsAppended() + { + // Arrange + var encoder = new VigenereEncoder(); + var message = new string('a', 2); + var key = new string('a', 1); + + // Act + var encoded = encoder.Encode(message, key); + var decoded = encoder.Decode(encoded, key); + + // Assert + Assert.AreEqual(message, decoded); + } + + [Test] + public static void EmptyKeyThrowsException() { - [Test] - [Repeat(100)] - public static void DecodedStringIsTheSame() - { - // Arrange - var random = new Randomizer(); - var encoder = new VigenereEncoder(); - var message = random.GetString(); - var key = random.GetString(random.Next(1, 1000)); - - // Act - var encoded = encoder.Encode(message, key); - var decoded = encoder.Decode(encoded, key); - - // Assert - Assert.AreEqual(message, decoded); - } - - [Test] - public static void Encode_KeyIsTooShort_KeyIsAppended() - { - // Arrange - var encoder = new VigenereEncoder(); - var message = new string('a', 2); - var key = new string('a', 1); - - // Act - var encoded = encoder.Encode(message, key); - var decoded = encoder.Decode(encoded, key); - - // Assert - Assert.AreEqual(message, decoded); - } - - [Test] - public static void EmptyKeyThrowsException() - { - var random = new Randomizer(); - var encoder = new VigenereEncoder(); - var message = random.GetString(); - var key = string.Empty; - - _ = Assert.Throws(() => encoder.Encode(message, key)); - _ = Assert.Throws(() => encoder.Decode(message, key)); - } + var random = new Randomizer(); + var encoder = new VigenereEncoder(); + var message = random.GetString(); + var key = string.Empty; + + _ = Assert.Throws(() => encoder.Encode(message, key)); + _ = Assert.Throws(() => encoder.Decode(message, key)); } } diff --git a/Algorithms.Tests/Graph/BellmanFordTests.cs b/Algorithms.Tests/Graph/BellmanFordTests.cs index c38727ec..80d6e01e 100644 --- a/Algorithms.Tests/Graph/BellmanFordTests.cs +++ b/Algorithms.Tests/Graph/BellmanFordTests.cs @@ -5,71 +5,70 @@ using System.Collections.Generic; using System; -namespace Algorithms.Tests.Graph +namespace Algorithms.Tests.Graph; + +public class BellmanFordTests { - public class BellmanFordTests + [Test] + public void CorrectDistancesTest() { - [Test] - public void CorrectDistancesTest() - { - var graph = new DirectedWeightedGraph(10); + var graph = new DirectedWeightedGraph(10); - var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(2); - var vertex3 = graph.AddVertex(3); - var vertex4 = graph.AddVertex(4); - var vertex5 = graph.AddVertex(5); + var vertex1 = graph.AddVertex(1); + var vertex2 = graph.AddVertex(2); + var vertex3 = graph.AddVertex(3); + var vertex4 = graph.AddVertex(4); + var vertex5 = graph.AddVertex(5); - graph.AddEdge(vertex1, vertex2, 3); - graph.AddEdge(vertex1, vertex5, -4); - graph.AddEdge(vertex1, vertex3, 8); - graph.AddEdge(vertex2, vertex5, 7); - graph.AddEdge(vertex2, vertex4, 1); - graph.AddEdge(vertex3, vertex2, 4); - graph.AddEdge(vertex4, vertex3, -5); - graph.AddEdge(vertex4, vertex1, 2); - graph.AddEdge(vertex5, vertex4, 6); + graph.AddEdge(vertex1, vertex2, 3); + graph.AddEdge(vertex1, vertex5, -4); + graph.AddEdge(vertex1, vertex3, 8); + graph.AddEdge(vertex2, vertex5, 7); + graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex3, vertex2, 4); + graph.AddEdge(vertex4, vertex3, -5); + graph.AddEdge(vertex4, vertex1, 2); + graph.AddEdge(vertex5, vertex4, 6); - var expectedDistances = new Dictionary, double> - { - { vertex1, 0 }, - { vertex2, 1 }, - { vertex3, -3 }, - { vertex4, 2 }, - { vertex5, -4 } - }; + var expectedDistances = new Dictionary, double> + { + { vertex1, 0 }, + { vertex2, 1 }, + { vertex3, -3 }, + { vertex4, 2 }, + { vertex5, -4 } + }; - var bellmanFord = new BellmanFord(graph, new Dictionary, double>(), new Dictionary, Vertex?>()); + var bellmanFord = new BellmanFord(graph, new Dictionary, double>(), new Dictionary, Vertex?>()); - var calculatedDistances = bellmanFord.Run(vertex1); + var calculatedDistances = bellmanFord.Run(vertex1); - foreach (var vertex in graph.Vertices) + foreach (var vertex in graph.Vertices) + { + if (vertex != null) { - if (vertex != null) - { - calculatedDistances[vertex].Should().BeApproximately(expectedDistances[vertex], 0.001); - } + calculatedDistances[vertex].Should().BeApproximately(expectedDistances[vertex], 0.001); } } + } - [Test] - public void NegativeWeightCycleTest() - { - var graph = new DirectedWeightedGraph(3); + [Test] + public void NegativeWeightCycleTest() + { + var graph = new DirectedWeightedGraph(3); - var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(2); - var vertex3 = graph.AddVertex(3); + var vertex1 = graph.AddVertex(1); + var vertex2 = graph.AddVertex(2); + var vertex3 = graph.AddVertex(3); - graph.AddEdge(vertex1, vertex2, -1); - graph.AddEdge(vertex2, vertex3, -2); - graph.AddEdge(vertex3, vertex1, -3); + graph.AddEdge(vertex1, vertex2, -1); + graph.AddEdge(vertex2, vertex3, -2); + graph.AddEdge(vertex3, vertex1, -3); - var bellmanFord = new BellmanFord(graph, new Dictionary, double>(), new Dictionary, Vertex?>()); + var bellmanFord = new BellmanFord(graph, new Dictionary, double>(), new Dictionary, Vertex?>()); - Action action = () => bellmanFord.Run(vertex1); + Action action = () => bellmanFord.Run(vertex1); - action.Should().Throw().WithMessage("Graph contains a negative weight cycle."); - } + action.Should().Throw().WithMessage("Graph contains a negative weight cycle."); } } diff --git a/Algorithms.Tests/Graph/BreadthFirstSearchTests.cs b/Algorithms.Tests/Graph/BreadthFirstSearchTests.cs index 9076c51b..253b49a6 100644 --- a/Algorithms.Tests/Graph/BreadthFirstSearchTests.cs +++ b/Algorithms.Tests/Graph/BreadthFirstSearchTests.cs @@ -3,130 +3,129 @@ using NUnit.Framework; using System.Collections.Generic; -namespace Algorithms.Tests.Graph +namespace Algorithms.Tests.Graph; + +public class BreadthFirstSearchTests { - public class BreadthFirstSearchTests + [Test] + public void VisitAll_ShouldCountNumberOfVisitedVertix_ResultShouldBeTheSameAsNumberOfVerticesInGraph() { - [Test] - public void VisitAll_ShouldCountNumberOfVisitedVertix_ResultShouldBeTheSameAsNumberOfVerticesInGraph() - { - //Arrange - var graph = new DirectedWeightedGraph(10); + //Arrange + var graph = new DirectedWeightedGraph(10); - var vertex1 = graph.AddVertex(1); + var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(20); + var vertex2 = graph.AddVertex(20); - var vertex3 = graph.AddVertex(40); + var vertex3 = graph.AddVertex(40); - var vertex4 = graph.AddVertex(40); + var vertex4 = graph.AddVertex(40); - graph.AddEdge(vertex1, vertex2, 1); + graph.AddEdge(vertex1, vertex2, 1); - graph.AddEdge(vertex2, vertex3, 1); + graph.AddEdge(vertex2, vertex3, 1); - graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex2, vertex4, 1); - graph.AddEdge(vertex4, vertex1, 1); + graph.AddEdge(vertex4, vertex1, 1); - var dfsSearcher = new BreadthFirstSearch(); + var dfsSearcher = new BreadthFirstSearch(); - long countOfVisitedVertices = 0; + long countOfVisitedVertices = 0; - //Act - dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVertices++); + //Act + dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVertices++); - //Assert - Assert.AreEqual(countOfVisitedVertices, graph.Count); - } + //Assert + Assert.AreEqual(countOfVisitedVertices, graph.Count); + } - [Test] - public void VisitAll_ShouldCountNumberOfVisitedVerices_TwoSeparatedGraphInOne() - { - //Arrange - var graph = new DirectedWeightedGraph(10); + [Test] + public void VisitAll_ShouldCountNumberOfVisitedVerices_TwoSeparatedGraphInOne() + { + //Arrange + var graph = new DirectedWeightedGraph(10); - var vertex1 = graph.AddVertex(1); + var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(20); + var vertex2 = graph.AddVertex(20); - var vertex3 = graph.AddVertex(40); + var vertex3 = graph.AddVertex(40); - var vertex4 = graph.AddVertex(40); + var vertex4 = graph.AddVertex(40); - var vertex5 = graph.AddVertex(40); + var vertex5 = graph.AddVertex(40); - var vertex6 = graph.AddVertex(40); + var vertex6 = graph.AddVertex(40); - graph.AddEdge(vertex1, vertex2, 1); + graph.AddEdge(vertex1, vertex2, 1); - graph.AddEdge(vertex2, vertex3, 1); + graph.AddEdge(vertex2, vertex3, 1); - graph.AddEdge(vertex4, vertex5, 1); + graph.AddEdge(vertex4, vertex5, 1); - graph.AddEdge(vertex5, vertex6, 1); + graph.AddEdge(vertex5, vertex6, 1); - var dfsSearcher = new BreadthFirstSearch(); + var dfsSearcher = new BreadthFirstSearch(); - long countOfVisitedVerticesPerFirstGraph = 0; + long countOfVisitedVerticesPerFirstGraph = 0; - long countOfVisitedVerticesPerSecondGraph = 0; + long countOfVisitedVerticesPerSecondGraph = 0; - //Act - dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVerticesPerFirstGraph++); + //Act + dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVerticesPerFirstGraph++); - dfsSearcher.VisitAll(graph, vertex4, _ => countOfVisitedVerticesPerSecondGraph++); + dfsSearcher.VisitAll(graph, vertex4, _ => countOfVisitedVerticesPerSecondGraph++); - //Assert - Assert.AreEqual(countOfVisitedVerticesPerFirstGraph, 3); + //Assert + Assert.AreEqual(countOfVisitedVerticesPerFirstGraph, 3); - Assert.AreEqual(countOfVisitedVerticesPerSecondGraph, 3); - } + Assert.AreEqual(countOfVisitedVerticesPerSecondGraph, 3); + } - [Test] - public void VisitAll_ReturnTheSuqenceOfVertices_ShouldBeTheSameAsExpected() - { - //Arrange - var graph = new DirectedWeightedGraph(10); + [Test] + public void VisitAll_ReturnTheSuqenceOfVertices_ShouldBeTheSameAsExpected() + { + //Arrange + var graph = new DirectedWeightedGraph(10); - var vertex1 = graph.AddVertex(1); + var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(20); + var vertex2 = graph.AddVertex(20); - var vertex3 = graph.AddVertex(40); + var vertex3 = graph.AddVertex(40); - var vertex4 = graph.AddVertex(40); + var vertex4 = graph.AddVertex(40); - var vertex5 = graph.AddVertex(40); + var vertex5 = graph.AddVertex(40); - graph.AddEdge(vertex1, vertex2, 1); + graph.AddEdge(vertex1, vertex2, 1); - graph.AddEdge(vertex1, vertex5, 1); + graph.AddEdge(vertex1, vertex5, 1); - graph.AddEdge(vertex2, vertex3, 1); + graph.AddEdge(vertex2, vertex3, 1); - graph.AddEdge(vertex2, vertex5, 1); + graph.AddEdge(vertex2, vertex5, 1); - graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex2, vertex4, 1); - var dfsSearcher = new BreadthFirstSearch(); + var dfsSearcher = new BreadthFirstSearch(); - var expectedSequenceOfVisitedVertices = new List> - { - vertex1, - vertex2, - vertex5, - vertex3, - vertex4, - }; + var expectedSequenceOfVisitedVertices = new List> + { + vertex1, + vertex2, + vertex5, + vertex3, + vertex4, + }; - var sequenceOfVisitedVertices = new List>(); + var sequenceOfVisitedVertices = new List>(); - //Act - dfsSearcher.VisitAll(graph, vertex1, vertex => sequenceOfVisitedVertices.Add(vertex)); + //Act + dfsSearcher.VisitAll(graph, vertex1, vertex => sequenceOfVisitedVertices.Add(vertex)); - //Assert - CollectionAssert.AreEqual(expectedSequenceOfVisitedVertices, sequenceOfVisitedVertices); - } + //Assert + CollectionAssert.AreEqual(expectedSequenceOfVisitedVertices, sequenceOfVisitedVertices); } } diff --git a/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs b/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs index 657e0df1..f6da0cb2 100644 --- a/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs +++ b/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs @@ -3,91 +3,90 @@ using DataStructures.BinarySearchTree; using System; -namespace Algorithms.Tests.Graph +namespace Algorithms.Tests.Graph; + +public static class BreadthFirstTreeTraversalTests { - public static class BreadthFirstTreeTraversalTests + [Test] + public static void CorrectLevelOrderTraversal() { - [Test] - public static void CorrectLevelOrderTraversal() + // Arrange + int[] correctPath = { 7, 4, 13, 2, 5, 11, 15, 14, 16 }; + int[] insertionOrder = { 7, 13, 11, 15, 14, 4, 5, 16, 2 }; + BinarySearchTree testTree = new BinarySearchTree(); + foreach (int data in insertionOrder) { - // Arrange - int[] correctPath = { 7, 4, 13, 2, 5, 11, 15, 14, 16 }; - int[] insertionOrder = { 7, 13, 11, 15, 14, 4, 5, 16, 2 }; - BinarySearchTree testTree = new BinarySearchTree(); - foreach (int data in insertionOrder) - { - testTree.Add(data); - } - - // Act - int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); - - // Assert - Assert.AreEqual(levelOrder, correctPath); + testTree.Add(data); } - [Test] - public static void EmptyArrayForNullRoot() - { - // Arrange - BinarySearchTree testTree = new BinarySearchTree(); + // Act + int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); - // Act - int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); + // Assert + Assert.AreEqual(levelOrder, correctPath); + } - // Assert - Assert.IsEmpty(levelOrder); - } + [Test] + public static void EmptyArrayForNullRoot() + { + // Arrange + BinarySearchTree testTree = new BinarySearchTree(); - [Test] - [TestCase(new [] {7, 9, 5})] - [TestCase(new [] { 7, 13, 11, 15, 14, 4, 5, 16, 2 })] - public static void IncorrectLevelOrderTraversal(int[] insertion) + // Act + int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); + + // Assert + Assert.IsEmpty(levelOrder); + } + + [Test] + [TestCase(new [] {7, 9, 5})] + [TestCase(new [] { 7, 13, 11, 15, 14, 4, 5, 16, 2 })] + public static void IncorrectLevelOrderTraversal(int[] insertion) + { + // Arrange + BinarySearchTree testTree = new BinarySearchTree(); + foreach (int data in insertion) { - // Arrange - BinarySearchTree testTree = new BinarySearchTree(); - foreach (int data in insertion) - { - testTree.Add(data); - } - - // Act - int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); - - // Assert - Assert.AreNotEqual(levelOrder, insertion); + testTree.Add(data); } - [Test] - public static void DeepestNodeInTree() + // Act + int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); + + // Assert + Assert.AreNotEqual(levelOrder, insertion); + } + + [Test] + public static void DeepestNodeInTree() + { + // Arrange + BinarySearchTree testTree = new BinarySearchTree(); + int[] insertion = { 7, 13, 11, 15, 4, 5, 12, 2, 9 }; + foreach (int data in insertion) { - // Arrange - BinarySearchTree testTree = new BinarySearchTree(); - int[] insertion = { 7, 13, 11, 15, 4, 5, 12, 2, 9 }; - foreach (int data in insertion) - { - testTree.Add(data); - } - - // Act - int deepest = BreadthFirstTreeTraversal.DeepestNode(testTree); - - // Assert - Assert.AreEqual(12, deepest); + testTree.Add(data); } - [Test] - public static void DeepestNodeOfEmptyTree() - { - // Arrange - BinarySearchTree testTree = new BinarySearchTree(); + // Act + int deepest = BreadthFirstTreeTraversal.DeepestNode(testTree); - // Act - int? deepest = BreadthFirstTreeTraversal.DeepestNode(testTree); + // Assert + Assert.AreEqual(12, deepest); + } - // Assert - Assert.IsNull(deepest); - } + [Test] + public static void DeepestNodeOfEmptyTree() + { + // Arrange + BinarySearchTree testTree = new BinarySearchTree(); + + // Act + int? deepest = BreadthFirstTreeTraversal.DeepestNode(testTree); + + // Assert + Assert.IsNull(deepest); } } diff --git a/Algorithms.Tests/Graph/DepthFirstSearchTests.cs b/Algorithms.Tests/Graph/DepthFirstSearchTests.cs index 209e0ab3..446403ba 100644 --- a/Algorithms.Tests/Graph/DepthFirstSearchTests.cs +++ b/Algorithms.Tests/Graph/DepthFirstSearchTests.cs @@ -3,128 +3,127 @@ using NUnit.Framework; using System.Collections.Generic; -namespace Algorithms.Tests.Graph +namespace Algorithms.Tests.Graph; + +public class DepthFirstSearchTests { - public class DepthFirstSearchTests + [Test] + public void VisitAll_ShouldCountNumberOfVisitedVertix_ResultShouldBeTheSameAsNumberOfVerticesInGraph() { - [Test] - public void VisitAll_ShouldCountNumberOfVisitedVertix_ResultShouldBeTheSameAsNumberOfVerticesInGraph() - { - //Arrange - var graph = new DirectedWeightedGraph(10); + //Arrange + var graph = new DirectedWeightedGraph(10); - var vertex1 = graph.AddVertex(1); + var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(20); + var vertex2 = graph.AddVertex(20); - var vertex3 = graph.AddVertex(40); + var vertex3 = graph.AddVertex(40); - var vertex4 = graph.AddVertex(40); + var vertex4 = graph.AddVertex(40); - graph.AddEdge(vertex1, vertex2, 1); + graph.AddEdge(vertex1, vertex2, 1); - graph.AddEdge(vertex2, vertex3, 1); + graph.AddEdge(vertex2, vertex3, 1); - graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex2, vertex4, 1); - graph.AddEdge(vertex4, vertex1, 1); + graph.AddEdge(vertex4, vertex1, 1); - var dfsSearcher = new DepthFirstSearch(); + var dfsSearcher = new DepthFirstSearch(); - long countOfVisitedVertices = 0; + long countOfVisitedVertices = 0; - //Act - dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVertices++); + //Act + dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVertices++); - //Assert - Assert.AreEqual(countOfVisitedVertices, graph.Count); - } + //Assert + Assert.AreEqual(countOfVisitedVertices, graph.Count); + } - [Test] - public void VisitAll_ShouldCountNumberOfVisitedVertices_TwoSeparatedGraphInOne() - { - //Arrange - var graph = new DirectedWeightedGraph(10); + [Test] + public void VisitAll_ShouldCountNumberOfVisitedVertices_TwoSeparatedGraphInOne() + { + //Arrange + var graph = new DirectedWeightedGraph(10); - var vertex1 = graph.AddVertex(1); + var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(20); + var vertex2 = graph.AddVertex(20); - var vertex3 = graph.AddVertex(40); + var vertex3 = graph.AddVertex(40); - var vertex4 = graph.AddVertex(40); + var vertex4 = graph.AddVertex(40); - var vertex5 = graph.AddVertex(40); + var vertex5 = graph.AddVertex(40); - var vertex6 = graph.AddVertex(40); + var vertex6 = graph.AddVertex(40); - graph.AddEdge(vertex1, vertex2, 1); + graph.AddEdge(vertex1, vertex2, 1); - graph.AddEdge(vertex2, vertex3, 1); + graph.AddEdge(vertex2, vertex3, 1); - graph.AddEdge(vertex4, vertex5, 1); + graph.AddEdge(vertex4, vertex5, 1); - graph.AddEdge(vertex5, vertex6, 1); + graph.AddEdge(vertex5, vertex6, 1); - var dfsSearcher = new DepthFirstSearch(); + var dfsSearcher = new DepthFirstSearch(); - long countOfVisitedVerticesPerFirstGraph = 0; + long countOfVisitedVerticesPerFirstGraph = 0; - long countOfVisitedVerticesPerSecondGraph = 0; + long countOfVisitedVerticesPerSecondGraph = 0; - //Act - dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVerticesPerFirstGraph++); + //Act + dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVerticesPerFirstGraph++); - dfsSearcher.VisitAll(graph, vertex4, _ => countOfVisitedVerticesPerSecondGraph++); + dfsSearcher.VisitAll(graph, vertex4, _ => countOfVisitedVerticesPerSecondGraph++); - //Assert - Assert.AreEqual(countOfVisitedVerticesPerFirstGraph, 3); + //Assert + Assert.AreEqual(countOfVisitedVerticesPerFirstGraph, 3); - Assert.AreEqual(countOfVisitedVerticesPerSecondGraph, 3); - } + Assert.AreEqual(countOfVisitedVerticesPerSecondGraph, 3); + } - [Test] - public void VisitAll_ReturnTheSuqenceOfVertices_ShouldBeTheSameAsExpected() - { - //Arrange - var graph = new DirectedWeightedGraph(10); + [Test] + public void VisitAll_ReturnTheSuqenceOfVertices_ShouldBeTheSameAsExpected() + { + //Arrange + var graph = new DirectedWeightedGraph(10); - var vertex1 = graph.AddVertex(1); + var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(20); + var vertex2 = graph.AddVertex(20); - var vertex3 = graph.AddVertex(40); + var vertex3 = graph.AddVertex(40); - var vertex4 = graph.AddVertex(40); + var vertex4 = graph.AddVertex(40); - var vertex5 = graph.AddVertex(40); + var vertex5 = graph.AddVertex(40); - graph.AddEdge(vertex1, vertex2, 1); + graph.AddEdge(vertex1, vertex2, 1); - graph.AddEdge(vertex2, vertex3, 1); + graph.AddEdge(vertex2, vertex3, 1); - graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex2, vertex4, 1); - graph.AddEdge(vertex3, vertex5, 1); + graph.AddEdge(vertex3, vertex5, 1); - var dfsSearcher = new DepthFirstSearch(); + var dfsSearcher = new DepthFirstSearch(); - var expectedSequenceOfVisitedVertices = new List> - { - vertex1, - vertex2, - vertex3, - vertex5, - vertex4, - }; + var expectedSequenceOfVisitedVertices = new List> + { + vertex1, + vertex2, + vertex3, + vertex5, + vertex4, + }; - var sequenceOfVisitedVertices = new List>(); + var sequenceOfVisitedVertices = new List>(); - //Act - dfsSearcher.VisitAll(graph, vertex1, vertex => sequenceOfVisitedVertices.Add(vertex)); + //Act + dfsSearcher.VisitAll(graph, vertex1, vertex => sequenceOfVisitedVertices.Add(vertex)); - //Assert - CollectionAssert.AreEqual(expectedSequenceOfVisitedVertices, sequenceOfVisitedVertices); - } + //Assert + CollectionAssert.AreEqual(expectedSequenceOfVisitedVertices, sequenceOfVisitedVertices); } } diff --git a/Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs b/Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs index 3b5ad380..5f450e08 100644 --- a/Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs +++ b/Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs @@ -1,229 +1,228 @@ -using System; +using System; using Algorithms.Graph.Dijkstra; using DataStructures.Graph; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Graph.Dijkstra +namespace Algorithms.Tests.Graph.Dijkstra; + +[TestFixture] +public class DijkstraTests { - [TestFixture] - public class DijkstraTests + [Test] + public void DijkstraTest1_Success() + { + // here test case is from https://www.youtube.com/watch?v=pVfj6mxhdMw + + var graph = new DirectedWeightedGraph(5); + var a = graph.AddVertex('A'); + var b = graph.AddVertex('B'); + var c = graph.AddVertex('C'); + var d = graph.AddVertex('D'); + var e = graph.AddVertex('E'); + + graph.AddEdge(a, b, 6); + graph.AddEdge(b, a, 6); + + graph.AddEdge(a, d, 1); + graph.AddEdge(d, a, 1); + + graph.AddEdge(d, e, 1); + graph.AddEdge(e, d, 1); + + graph.AddEdge(d, b, 2); + graph.AddEdge(b, d, 2); + + graph.AddEdge(e, b, 2); + graph.AddEdge(b, e, 2); + + graph.AddEdge(e, c, 5); + graph.AddEdge(c, e, 5); + + graph.AddEdge(c, b, 5); + graph.AddEdge(b, c, 5); + + var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); + shortestPathList.Length.Should().Be(5); + + shortestPathList[0].Vertex.Should().Be(a); + shortestPathList[0].Distance.Should().Be(0); + shortestPathList[0].PreviousVertex.Should().Be(a); + shortestPathList[0].ToString().Should() + .Be($"Vertex: {a} - Distance: {0} - Previous: {a}"); + + shortestPathList[1].Vertex.Should().Be(b); + shortestPathList[1].Distance.Should().Be(3); + shortestPathList[1].PreviousVertex.Should().Be(d); + shortestPathList[1].ToString().Should() + .Be($"Vertex: {b} - Distance: {3} - Previous: {d}"); + + shortestPathList[2].Vertex.Should().Be(c); + shortestPathList[2].Distance.Should().Be(7); + shortestPathList[2].PreviousVertex.Should().Be(e); + shortestPathList[2].ToString().Should() + .Be($"Vertex: {c} - Distance: {7} - Previous: {e}"); + + shortestPathList[3].Vertex.Should().Be(d); + shortestPathList[3].Distance.Should().Be(1); + shortestPathList[3].PreviousVertex.Should().Be(a); + shortestPathList[3].ToString().Should() + .Be($"Vertex: {d} - Distance: {1} - Previous: {a}"); + + shortestPathList[4].Vertex.Should().Be(e); + shortestPathList[4].Distance.Should().Be(2); + shortestPathList[4].PreviousVertex.Should().Be(d); + shortestPathList[4].ToString().Should() + .Be($"Vertex: {e} - Distance: {2} - Previous: {d}"); + } + + [Test] + public void DijkstraTest2_Success() + { + var graph = new DirectedWeightedGraph(5); + var a = graph.AddVertex('A'); + var b = graph.AddVertex('B'); + var c = graph.AddVertex('C'); + + graph.AddEdge(a, b, 1); + graph.AddEdge(b, a, 1); + + graph.AddEdge(b, c, 1); + graph.AddEdge(c, b, 1); + + graph.AddEdge(a, c, 3); + graph.AddEdge(c, a, 3); + + var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); + + shortestPathList.Length.Should().Be(3); + shortestPathList[0].Vertex.Should().Be(a); + shortestPathList[0].Distance.Should().Be(0); + shortestPathList[0].PreviousVertex.Should().Be(a); + shortestPathList[0].ToString().Should() + .Be($"Vertex: {a} - Distance: {0} - Previous: {a}"); + + shortestPathList[1].Vertex.Should().Be(b); + shortestPathList[1].Distance.Should().Be(1); + shortestPathList[1].PreviousVertex.Should().Be(a); + shortestPathList[1].ToString().Should() + .Be($"Vertex: {b} - Distance: {1} - Previous: {a}"); + + shortestPathList[2].Vertex.Should().Be(c); + shortestPathList[2].Distance.Should().Be(2); + shortestPathList[2].PreviousVertex.Should().Be(b); + shortestPathList[2].ToString().Should() + .Be($"Vertex: {c} - Distance: {2} - Previous: {b}"); + } + + [Test] + public void DijkstraTest3_Success() + { + var graph = new DirectedWeightedGraph(5); + var a = graph.AddVertex('A'); + var b = graph.AddVertex('B'); + var c = graph.AddVertex('C'); + + graph.AddEdge(a, b, 1); + graph.AddEdge(b, a, 1); + + graph.AddEdge(a, c, 3); + graph.AddEdge(c, a, 3); + + var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); + + shortestPathList.Length.Should().Be(3); + shortestPathList[0].Vertex.Should().Be(a); + shortestPathList[0].Distance.Should().Be(0); + shortestPathList[0].PreviousVertex.Should().Be(a); + shortestPathList[0].ToString().Should() + .Be($"Vertex: {a} - Distance: {0} - Previous: {a}"); + + shortestPathList[1].Vertex.Should().Be(b); + shortestPathList[1].Distance.Should().Be(1); + shortestPathList[1].PreviousVertex.Should().Be(a); + shortestPathList[1].ToString().Should() + .Be($"Vertex: {b} - Distance: {1} - Previous: {a}"); + + shortestPathList[2].Vertex.Should().Be(c); + shortestPathList[2].Distance.Should().Be(3); + shortestPathList[2].PreviousVertex.Should().Be(a); + shortestPathList[2].ToString().Should() + .Be($"Vertex: {c} - Distance: {3} - Previous: {a}"); + } + + [Test] + public void DijkstraTest4_Success() { - [Test] - public void DijkstraTest1_Success() - { - // here test case is from https://www.youtube.com/watch?v=pVfj6mxhdMw - - var graph = new DirectedWeightedGraph(5); - var a = graph.AddVertex('A'); - var b = graph.AddVertex('B'); - var c = graph.AddVertex('C'); - var d = graph.AddVertex('D'); - var e = graph.AddVertex('E'); - - graph.AddEdge(a, b, 6); - graph.AddEdge(b, a, 6); - - graph.AddEdge(a, d, 1); - graph.AddEdge(d, a, 1); - - graph.AddEdge(d, e, 1); - graph.AddEdge(e, d, 1); - - graph.AddEdge(d, b, 2); - graph.AddEdge(b, d, 2); - - graph.AddEdge(e, b, 2); - graph.AddEdge(b, e, 2); - - graph.AddEdge(e, c, 5); - graph.AddEdge(c, e, 5); - - graph.AddEdge(c, b, 5); - graph.AddEdge(b, c, 5); - - var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); - shortestPathList.Length.Should().Be(5); - - shortestPathList[0].Vertex.Should().Be(a); - shortestPathList[0].Distance.Should().Be(0); - shortestPathList[0].PreviousVertex.Should().Be(a); - shortestPathList[0].ToString().Should() - .Be($"Vertex: {a} - Distance: {0} - Previous: {a}"); - - shortestPathList[1].Vertex.Should().Be(b); - shortestPathList[1].Distance.Should().Be(3); - shortestPathList[1].PreviousVertex.Should().Be(d); - shortestPathList[1].ToString().Should() - .Be($"Vertex: {b} - Distance: {3} - Previous: {d}"); - - shortestPathList[2].Vertex.Should().Be(c); - shortestPathList[2].Distance.Should().Be(7); - shortestPathList[2].PreviousVertex.Should().Be(e); - shortestPathList[2].ToString().Should() - .Be($"Vertex: {c} - Distance: {7} - Previous: {e}"); - - shortestPathList[3].Vertex.Should().Be(d); - shortestPathList[3].Distance.Should().Be(1); - shortestPathList[3].PreviousVertex.Should().Be(a); - shortestPathList[3].ToString().Should() - .Be($"Vertex: {d} - Distance: {1} - Previous: {a}"); - - shortestPathList[4].Vertex.Should().Be(e); - shortestPathList[4].Distance.Should().Be(2); - shortestPathList[4].PreviousVertex.Should().Be(d); - shortestPathList[4].ToString().Should() - .Be($"Vertex: {e} - Distance: {2} - Previous: {d}"); - } - - [Test] - public void DijkstraTest2_Success() - { - var graph = new DirectedWeightedGraph(5); - var a = graph.AddVertex('A'); - var b = graph.AddVertex('B'); - var c = graph.AddVertex('C'); - - graph.AddEdge(a, b, 1); - graph.AddEdge(b, a, 1); - - graph.AddEdge(b, c, 1); - graph.AddEdge(c, b, 1); - - graph.AddEdge(a, c, 3); - graph.AddEdge(c, a, 3); - - var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); - - shortestPathList.Length.Should().Be(3); - shortestPathList[0].Vertex.Should().Be(a); - shortestPathList[0].Distance.Should().Be(0); - shortestPathList[0].PreviousVertex.Should().Be(a); - shortestPathList[0].ToString().Should() - .Be($"Vertex: {a} - Distance: {0} - Previous: {a}"); - - shortestPathList[1].Vertex.Should().Be(b); - shortestPathList[1].Distance.Should().Be(1); - shortestPathList[1].PreviousVertex.Should().Be(a); - shortestPathList[1].ToString().Should() - .Be($"Vertex: {b} - Distance: {1} - Previous: {a}"); - - shortestPathList[2].Vertex.Should().Be(c); - shortestPathList[2].Distance.Should().Be(2); - shortestPathList[2].PreviousVertex.Should().Be(b); - shortestPathList[2].ToString().Should() - .Be($"Vertex: {c} - Distance: {2} - Previous: {b}"); - } - - [Test] - public void DijkstraTest3_Success() - { - var graph = new DirectedWeightedGraph(5); - var a = graph.AddVertex('A'); - var b = graph.AddVertex('B'); - var c = graph.AddVertex('C'); - - graph.AddEdge(a, b, 1); - graph.AddEdge(b, a, 1); - - graph.AddEdge(a, c, 3); - graph.AddEdge(c, a, 3); - - var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); - - shortestPathList.Length.Should().Be(3); - shortestPathList[0].Vertex.Should().Be(a); - shortestPathList[0].Distance.Should().Be(0); - shortestPathList[0].PreviousVertex.Should().Be(a); - shortestPathList[0].ToString().Should() - .Be($"Vertex: {a} - Distance: {0} - Previous: {a}"); - - shortestPathList[1].Vertex.Should().Be(b); - shortestPathList[1].Distance.Should().Be(1); - shortestPathList[1].PreviousVertex.Should().Be(a); - shortestPathList[1].ToString().Should() - .Be($"Vertex: {b} - Distance: {1} - Previous: {a}"); - - shortestPathList[2].Vertex.Should().Be(c); - shortestPathList[2].Distance.Should().Be(3); - shortestPathList[2].PreviousVertex.Should().Be(a); - shortestPathList[2].ToString().Should() - .Be($"Vertex: {c} - Distance: {3} - Previous: {a}"); - } - - [Test] - public void DijkstraTest4_Success() - { - var graph = new DirectedWeightedGraph(5); - var a = graph.AddVertex('A'); - var b = graph.AddVertex('B'); - var c = graph.AddVertex('C'); - var d = graph.AddVertex('D'); - - graph.AddEdge(a, b, 1); - graph.AddEdge(b, a, 1); - - graph.AddEdge(a, c, 3); - graph.AddEdge(c, a, 3); - - graph.AddEdge(c, d, 5); - graph.AddEdge(d, c, 5); - - var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); - - shortestPathList.Length.Should().Be(4); - shortestPathList[0].Vertex.Should().Be(a); - shortestPathList[0].Distance.Should().Be(0); - shortestPathList[0].PreviousVertex.Should().Be(a); - shortestPathList[0].ToString().Should() - .Be($"Vertex: {a} - Distance: {0} - Previous: {a}"); - - shortestPathList[1].Vertex.Should().Be(b); - shortestPathList[1].Distance.Should().Be(1); - shortestPathList[1].PreviousVertex.Should().Be(a); - shortestPathList[1].ToString().Should() - .Be($"Vertex: {b} - Distance: {1} - Previous: {a}"); - - shortestPathList[2].Vertex.Should().Be(c); - shortestPathList[2].Distance.Should().Be(3); - shortestPathList[2].PreviousVertex.Should().Be(a); - shortestPathList[2].ToString().Should() - .Be($"Vertex: {c} - Distance: {3} - Previous: {a}"); - - // Vertex D won't be visited in this dijkstra implementation which is valid only for cyclic graphs, - // since it is necessary to backtrack all unvisited vertices and place them - // to the priority queue, which is not implemented yet in this repository. - // If algo goes to the next vertex with minimal distance and this vertex is leaf -- algorithm stops. - shortestPathList[3].Vertex.Should().Be(d); - shortestPathList[3].Distance.Should().Be(double.MaxValue); - shortestPathList[3].PreviousVertex.Should().BeNull(); - shortestPathList[3].ToString().Should() - .Be($"Vertex: {d} - Distance: {double.MaxValue} - Previous: {null}"); - } - - [Test] - public void DijkstraMethodTest_ShouldThrow_GraphIsNull() - { - var graph = new DirectedWeightedGraph(5); - var a = graph.AddVertex('A'); - - Func[]> action = () => DijkstraAlgorithm.GenerateShortestPath(null!, a); - - action.Should().Throw() - .WithMessage($"Value cannot be null. (Parameter '{nameof(graph)}')"); - } - - [Test] - public void DijkstraMethodTest_ShouldThrow_VertexDoesntBelongToGraph() - { - var graph = new DirectedWeightedGraph(5); - var startVertex = graph.AddVertex('A'); - - Func[]> action = () => DijkstraAlgorithm.GenerateShortestPath( - new DirectedWeightedGraph(5), startVertex); - - action.Should().Throw() - .WithMessage($"Value cannot be null. (Parameter '{nameof(graph)}')"); - } + var graph = new DirectedWeightedGraph(5); + var a = graph.AddVertex('A'); + var b = graph.AddVertex('B'); + var c = graph.AddVertex('C'); + var d = graph.AddVertex('D'); + + graph.AddEdge(a, b, 1); + graph.AddEdge(b, a, 1); + + graph.AddEdge(a, c, 3); + graph.AddEdge(c, a, 3); + + graph.AddEdge(c, d, 5); + graph.AddEdge(d, c, 5); + + var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); + + shortestPathList.Length.Should().Be(4); + shortestPathList[0].Vertex.Should().Be(a); + shortestPathList[0].Distance.Should().Be(0); + shortestPathList[0].PreviousVertex.Should().Be(a); + shortestPathList[0].ToString().Should() + .Be($"Vertex: {a} - Distance: {0} - Previous: {a}"); + + shortestPathList[1].Vertex.Should().Be(b); + shortestPathList[1].Distance.Should().Be(1); + shortestPathList[1].PreviousVertex.Should().Be(a); + shortestPathList[1].ToString().Should() + .Be($"Vertex: {b} - Distance: {1} - Previous: {a}"); + + shortestPathList[2].Vertex.Should().Be(c); + shortestPathList[2].Distance.Should().Be(3); + shortestPathList[2].PreviousVertex.Should().Be(a); + shortestPathList[2].ToString().Should() + .Be($"Vertex: {c} - Distance: {3} - Previous: {a}"); + + // Vertex D won't be visited in this dijkstra implementation which is valid only for cyclic graphs, + // since it is necessary to backtrack all unvisited vertices and place them + // to the priority queue, which is not implemented yet in this repository. + // If algo goes to the next vertex with minimal distance and this vertex is leaf -- algorithm stops. + shortestPathList[3].Vertex.Should().Be(d); + shortestPathList[3].Distance.Should().Be(double.MaxValue); + shortestPathList[3].PreviousVertex.Should().BeNull(); + shortestPathList[3].ToString().Should() + .Be($"Vertex: {d} - Distance: {double.MaxValue} - Previous: {null}"); + } + + [Test] + public void DijkstraMethodTest_ShouldThrow_GraphIsNull() + { + var graph = new DirectedWeightedGraph(5); + var a = graph.AddVertex('A'); + + Func[]> action = () => DijkstraAlgorithm.GenerateShortestPath(null!, a); + + action.Should().Throw() + .WithMessage($"Value cannot be null. (Parameter '{nameof(graph)}')"); + } + + [Test] + public void DijkstraMethodTest_ShouldThrow_VertexDoesntBelongToGraph() + { + var graph = new DirectedWeightedGraph(5); + var startVertex = graph.AddVertex('A'); + + Func[]> action = () => DijkstraAlgorithm.GenerateShortestPath( + new DirectedWeightedGraph(5), startVertex); + + action.Should().Throw() + .WithMessage($"Value cannot be null. (Parameter '{nameof(graph)}')"); } } diff --git a/Algorithms.Tests/Graph/FloydWarshallTests.cs b/Algorithms.Tests/Graph/FloydWarshallTests.cs index 0cf355d8..7e391954 100644 --- a/Algorithms.Tests/Graph/FloydWarshallTests.cs +++ b/Algorithms.Tests/Graph/FloydWarshallTests.cs @@ -3,55 +3,54 @@ using NUnit.Framework; using FluentAssertions; -namespace Algorithms.Tests.Graph +namespace Algorithms.Tests.Graph; + +public class FloydWarshallTests { - public class FloydWarshallTests + [Test] + public void CorrectMatrixTest() { - [Test] - public void CorrectMatrixTest() - { - var graph = new DirectedWeightedGraph(10); + var graph = new DirectedWeightedGraph(10); - var vertex1 = graph.AddVertex(1); + var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(2); + var vertex2 = graph.AddVertex(2); - var vertex3 = graph.AddVertex(3); + var vertex3 = graph.AddVertex(3); - var vertex4 = graph.AddVertex(4); + var vertex4 = graph.AddVertex(4); - var vertex5 = graph.AddVertex(5); + var vertex5 = graph.AddVertex(5); - graph.AddEdge(vertex1, vertex2, 3); + graph.AddEdge(vertex1, vertex2, 3); - graph.AddEdge(vertex1, vertex5, -4); + graph.AddEdge(vertex1, vertex5, -4); - graph.AddEdge(vertex1, vertex3, 8); + graph.AddEdge(vertex1, vertex3, 8); - graph.AddEdge(vertex2, vertex5, 7); + graph.AddEdge(vertex2, vertex5, 7); - graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex2, vertex4, 1); - graph.AddEdge(vertex3, vertex2, 4); + graph.AddEdge(vertex3, vertex2, 4); - graph.AddEdge(vertex4, vertex3, -5); + graph.AddEdge(vertex4, vertex3, -5); - graph.AddEdge(vertex4, vertex1, 2); + graph.AddEdge(vertex4, vertex1, 2); - graph.AddEdge(vertex5, vertex4, 6); + graph.AddEdge(vertex5, vertex4, 6); - var actualDistances = new double[,] - { - { 0, 1, -3, 2, -4 }, - { 3, 0, -4, 1, -1 }, - { 7, 4, 0, 5, 3 }, - { 2, -1, -5, 0, -2 }, - { 8, 5, 1, 6, 0 }, - }; + var actualDistances = new double[,] + { + { 0, 1, -3, 2, -4 }, + { 3, 0, -4, 1, -1 }, + { 7, 4, 0, 5, 3 }, + { 2, -1, -5, 0, -2 }, + { 8, 5, 1, 6, 0 }, + }; - var floydWarshaller = new FloydWarshall(); + var floydWarshaller = new FloydWarshall(); - floydWarshaller.Run(graph).Should().Equal(actualDistances); - } + floydWarshaller.Run(graph).Should().Equal(actualDistances); } } diff --git a/Algorithms.Tests/Graph/KosarajuTests.cs b/Algorithms.Tests/Graph/KosarajuTests.cs index 8e7e6582..a4b61f61 100644 --- a/Algorithms.Tests/Graph/KosarajuTests.cs +++ b/Algorithms.Tests/Graph/KosarajuTests.cs @@ -5,99 +5,98 @@ using System.Collections.Generic; using System.Linq; -namespace Algorithms.Tests.Graph +namespace Algorithms.Tests.Graph; + +public class KosarajuTests { - public class KosarajuTests + + [Test] + public void GetRepresentativesTest() { + // Create a graph with some SCC. + var graph = new DirectedWeightedGraph(10); + + var vertex1 = graph.AddVertex(1); + var vertex2 = graph.AddVertex(2); + var vertex3 = graph.AddVertex(3); + var vertex4 = graph.AddVertex(4); + var vertex5 = graph.AddVertex(5); + var vertex6 = graph.AddVertex(6); + var vertex7 = graph.AddVertex(7); + + graph.AddEdge(vertex1, vertex2, 1); + graph.AddEdge(vertex2, vertex3, 1); + graph.AddEdge(vertex3, vertex1, 1); + graph.AddEdge(vertex3, vertex2, 1); + graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex4, vertex5, 1); + graph.AddEdge(vertex5, vertex4, 1); + graph.AddEdge(vertex5, vertex6, 1); + + // Run the agorithm and obtain the representative vertex of the SCC to which each vertex belongs. + Dictionary,Vertex> result = Kosaraju.GetRepresentatives(graph); + + // Check every Vertex belongs to a SCC + result.Should().ContainKey(vertex1); + result.Should().ContainKey(vertex2); + result.Should().ContainKey(vertex3); + result.Should().ContainKey(vertex4); + result.Should().ContainKey(vertex5); + result.Should().ContainKey(vertex6); + result.Should().ContainKey(vertex7); + + // There should be 4 SCC: {1,2,3}, {4,5}, {6} and {7} + // Vertices 1, 2 and 3 are a SCC + result[vertex1].Should().Be(result[vertex2]).And.Be(result[vertex3]); + + // Vertices 4 and 5 are another SCC + result[vertex4].Should().Be(result[vertex5]); + + // And the should have a different representative vertex + result[vertex1].Should().NotBe(result[vertex4]); + + // Vertices 6 and 7 are their own SCC + result[vertex6].Should().Be(vertex6); + result[vertex7].Should().Be(vertex7); + } - [Test] - public void GetRepresentativesTest() - { - // Create a graph with some SCC. - var graph = new DirectedWeightedGraph(10); - - var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(2); - var vertex3 = graph.AddVertex(3); - var vertex4 = graph.AddVertex(4); - var vertex5 = graph.AddVertex(5); - var vertex6 = graph.AddVertex(6); - var vertex7 = graph.AddVertex(7); - - graph.AddEdge(vertex1, vertex2, 1); - graph.AddEdge(vertex2, vertex3, 1); - graph.AddEdge(vertex3, vertex1, 1); - graph.AddEdge(vertex3, vertex2, 1); - graph.AddEdge(vertex2, vertex4, 1); - graph.AddEdge(vertex4, vertex5, 1); - graph.AddEdge(vertex5, vertex4, 1); - graph.AddEdge(vertex5, vertex6, 1); - - // Run the agorithm and obtain the representative vertex of the SCC to which each vertex belongs. - Dictionary,Vertex> result = Kosaraju.GetRepresentatives(graph); - - // Check every Vertex belongs to a SCC - result.Should().ContainKey(vertex1); - result.Should().ContainKey(vertex2); - result.Should().ContainKey(vertex3); - result.Should().ContainKey(vertex4); - result.Should().ContainKey(vertex5); - result.Should().ContainKey(vertex6); - result.Should().ContainKey(vertex7); - - // There should be 4 SCC: {1,2,3}, {4,5}, {6} and {7} - // Vertices 1, 2 and 3 are a SCC - result[vertex1].Should().Be(result[vertex2]).And.Be(result[vertex3]); - - // Vertices 4 and 5 are another SCC - result[vertex4].Should().Be(result[vertex5]); - - // And the should have a different representative vertex - result[vertex1].Should().NotBe(result[vertex4]); - - // Vertices 6 and 7 are their own SCC - result[vertex6].Should().Be(vertex6); - result[vertex7].Should().Be(vertex7); - } - - [Test] - public void GetSccTest() - { - // Create a graph with some SCC. - var graph = new DirectedWeightedGraph(10); - - var vertex1 = graph.AddVertex(1); - var vertex2 = graph.AddVertex(2); - var vertex3 = graph.AddVertex(3); - var vertex4 = graph.AddVertex(4); - var vertex5 = graph.AddVertex(5); - var vertex6 = graph.AddVertex(6); - var vertex7 = graph.AddVertex(7); - - graph.AddEdge(vertex1, vertex2, 1); - graph.AddEdge(vertex2, vertex3, 1); - graph.AddEdge(vertex3, vertex1, 1); - graph.AddEdge(vertex3, vertex2, 1); - graph.AddEdge(vertex2, vertex4, 1); - graph.AddEdge(vertex4, vertex5, 1); - graph.AddEdge(vertex5, vertex4, 1); - graph.AddEdge(vertex5, vertex6, 1); - - // Run the algorithm and get SCC as lists of vertices. - var scc = Kosaraju.GetScc(graph); - - // There should be 4 SCC: {1,2,3}, {4,5}, {6} and {7} - scc.Should().HaveCount(4); - - // Vertices 1, 2 and 3 are a SCC - scc.First(c => c.Contains(vertex1)).Should().Contain(vertex2).And.Contain(vertex3); - - // Vertices 4 and 5 are another SCC - scc.First(c => c.Contains(vertex4)).Should().Contain(vertex5); - - // Vertices 6 and 7 are their own SCC - scc.First(c => c.Contains(vertex6)).Should().HaveCount(1); - scc.First(c => c.Contains(vertex7)).Should().HaveCount(1); - } + [Test] + public void GetSccTest() + { + // Create a graph with some SCC. + var graph = new DirectedWeightedGraph(10); + + var vertex1 = graph.AddVertex(1); + var vertex2 = graph.AddVertex(2); + var vertex3 = graph.AddVertex(3); + var vertex4 = graph.AddVertex(4); + var vertex5 = graph.AddVertex(5); + var vertex6 = graph.AddVertex(6); + var vertex7 = graph.AddVertex(7); + + graph.AddEdge(vertex1, vertex2, 1); + graph.AddEdge(vertex2, vertex3, 1); + graph.AddEdge(vertex3, vertex1, 1); + graph.AddEdge(vertex3, vertex2, 1); + graph.AddEdge(vertex2, vertex4, 1); + graph.AddEdge(vertex4, vertex5, 1); + graph.AddEdge(vertex5, vertex4, 1); + graph.AddEdge(vertex5, vertex6, 1); + + // Run the algorithm and get SCC as lists of vertices. + var scc = Kosaraju.GetScc(graph); + + // There should be 4 SCC: {1,2,3}, {4,5}, {6} and {7} + scc.Should().HaveCount(4); + + // Vertices 1, 2 and 3 are a SCC + scc.First(c => c.Contains(vertex1)).Should().Contain(vertex2).And.Contain(vertex3); + + // Vertices 4 and 5 are another SCC + scc.First(c => c.Contains(vertex4)).Should().Contain(vertex5); + + // Vertices 6 and 7 are their own SCC + scc.First(c => c.Contains(vertex6)).Should().HaveCount(1); + scc.First(c => c.Contains(vertex7)).Should().HaveCount(1); } } diff --git a/Algorithms.Tests/Graph/MinimumSpanningTree/KruskalTests.cs b/Algorithms.Tests/Graph/MinimumSpanningTree/KruskalTests.cs index 52d5fae2..b1a4bbb3 100644 --- a/Algorithms.Tests/Graph/MinimumSpanningTree/KruskalTests.cs +++ b/Algorithms.Tests/Graph/MinimumSpanningTree/KruskalTests.cs @@ -5,724 +5,723 @@ using System.Collections.Generic; using System.Linq; -namespace Algorithms.Tests.Graph.MinimumSpanningTree +namespace Algorithms.Tests.Graph.MinimumSpanningTree; + +internal class KruskalTests { - internal class KruskalTests + [Test] + public void ValidateGraph_adjWrongSize_ThrowsException() { - [Test] - public void ValidateGraph_adjWrongSize_ThrowsException() + // Wrong number of columns + var adj = new[,] { - // Wrong number of columns - var adj = new[,] - { - { 0, 3, 4, float.PositiveInfinity }, - { 3, 0, 5, 6 }, - { 4, 5, 0, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, 0 }, - { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity }, - }; - Assert.Throws(() => Kruskal.Solve(adj), "adj must be square!"); - - // Wrong number of rows - adj = new[,] - { - { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 0, 5, 6, 2 }, - { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, - }; - Assert.Throws(() => Kruskal.Solve(adj), "adj must be square!"); - } + { 0, 3, 4, float.PositiveInfinity }, + { 3, 0, 5, 6 }, + { 4, 5, 0, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, 0 }, + { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity }, + }; + Assert.Throws(() => Kruskal.Solve(adj), "adj must be square!"); + + // Wrong number of rows + adj = new[,] + { + { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 0, 5, 6, 2 }, + { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, + }; + Assert.Throws(() => Kruskal.Solve(adj), "adj must be square!"); + } - [Test] - public void ValidateGraph_adjDirectedGraph_ThrowsException() + [Test] + public void ValidateGraph_adjDirectedGraph_ThrowsException() + { + // Nodes 1 and 2 have a directed edge + var adj = new[,] { - // Nodes 1 and 2 have a directed edge - var adj = new[,] - { - { 0, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 0, 5, 6, 2 }, - { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, - { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 }, - }; - Assert.Throws(() => Kruskal.Solve(adj), "adj must be symmetric!"); - } + { 0, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 0, 5, 6, 2 }, + { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, + { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 }, + }; + Assert.Throws(() => Kruskal.Solve(adj), "adj must be symmetric!"); + } - [Test] - public void Solve_adjGraph1_CorrectAnswer() - { - /* Graph - * (1) - * / \ - * 3 2 - * / \ - * (0)--2--(2) - */ - var adj = new float[,] - { - { 0, 3, 2 }, - { 3, 0, 2 }, - { 2, 2, 0 }, - }; - - /* Expected MST - * (1) - * \ - * 2 - * \ - * (0)--2--(2) - */ - var expected = new[,] - { - { float.PositiveInfinity, float.PositiveInfinity, 2 }, - { float.PositiveInfinity, float.PositiveInfinity, 2 }, - { 2, 2, float.PositiveInfinity }, - }; + [Test] + public void Solve_adjGraph1_CorrectAnswer() + { + /* Graph + * (1) + * / \ + * 3 2 + * / \ + * (0)--2--(2) + */ + var adj = new float[,] + { + { 0, 3, 2 }, + { 3, 0, 2 }, + { 2, 2, 0 }, + }; + + /* Expected MST + * (1) + * \ + * 2 + * \ + * (0)--2--(2) + */ + var expected = new[,] + { + { float.PositiveInfinity, float.PositiveInfinity, 2 }, + { float.PositiveInfinity, float.PositiveInfinity, 2 }, + { 2, 2, float.PositiveInfinity }, + }; - Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); + } - [Test] - public void Solve_adjGraph2_CorrectAnswer() - { - /* Graph - * (0) (4) - * |\ / - * | 3 2 - * | \ / - * 4 (1) - * | / \ - * | 5 6 - * |/ \ - * (2) (3) - */ - var adj = new[,] - { - { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 0, 5, 6, 2 }, - { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, - { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 }, - }; - - /* Expected MST - * (0) (4) - * |\ / - * | 3 2 - * | \ / - * 4 (1) - * | \ - * | 6 - * | \ - * (2) (3) - */ - var expected = new[,] - { - { float.PositiveInfinity, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, - { 3, float.PositiveInfinity, float.PositiveInfinity, 6, 2 }, - { 4, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - }; - - Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + [Test] + public void Solve_adjGraph2_CorrectAnswer() + { + /* Graph + * (0) (4) + * |\ / + * | 3 2 + * | \ / + * 4 (1) + * | / \ + * | 5 6 + * |/ \ + * (2) (3) + */ + var adj = new[,] + { + { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 0, 5, 6, 2 }, + { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, + { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 }, + }; + + /* Expected MST + * (0) (4) + * |\ / + * | 3 2 + * | \ / + * 4 (1) + * | \ + * | 6 + * | \ + * (2) (3) + */ + var expected = new[,] + { + { float.PositiveInfinity, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, + { 3, float.PositiveInfinity, float.PositiveInfinity, 6, 2 }, + { 4, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + }; + + Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); + } - [Test] - public void Solve_adjGraph3_CorrectAnswer() - { - /* Graph - * (0)--3--(2) (4)--2--(5) - * \ / \ / - * 4 1 4 6 - * \ / \ / - * (1)--2--(3) - */ - var adj = new[,] - { - { 0, 4, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { 4, 0, 1, 2, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 1, 0, 4, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 2, 4, 0, 6, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 0, 2 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, 0 }, - }; - - /* Graph - * (0)--3--(2) (4)--2--(5) - * / / - * 1 6 - * / / - * (1)--2--(3) - */ - var expected = new[,] - { - { float.PositiveInfinity, float.PositiveInfinity, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, 1, 2, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 1, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, 2 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity }, - }; - - Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + [Test] + public void Solve_adjGraph3_CorrectAnswer() + { + /* Graph + * (0)--3--(2) (4)--2--(5) + * \ / \ / + * 4 1 4 6 + * \ / \ / + * (1)--2--(3) + */ + var adj = new[,] + { + { 0, 4, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { 4, 0, 1, 2, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 1, 0, 4, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 2, 4, 0, 6, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 0, 2 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, 0 }, + }; + + /* Graph + * (0)--3--(2) (4)--2--(5) + * / / + * 1 6 + * / / + * (1)--2--(3) + */ + var expected = new[,] + { + { float.PositiveInfinity, float.PositiveInfinity, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, 1, 2, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 1, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, 2 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity }, + }; + + Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); + } - [Test] - public void Solve_adjGraph4_CorrectAnswer() - { - /* Graph - * (0)--7--(1)--8--(2) - * \ / \ / - * 5 9 7 5 - * \ / \ / - * (3)--15-(4) - * \ / \ - * 6 8 9 - * \ / \ - * (5)--11-(6) - */ - var adj = new[,] - { - { 0, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { 7, 0, 8, 9, 7, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 8, 0, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity }, - { 5, 9, float.PositiveInfinity, 0, 15, 6, float.PositiveInfinity }, - { float.PositiveInfinity, 7, 5, 15, 0, 8, 9 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 8, 0, 11 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, 11, 0 }, - }; - - /* Expected MST - * (0)--7--(1) (2) - * \ \ / - * 5 7 5 - * \ \ / - * (3) (4) - * \ \ - * 6 9 - * \ \ - * (5) (6) - */ - var expected = new[,] - { - { float.PositiveInfinity, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { 7, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 7, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity }, - { 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity }, - { float.PositiveInfinity, 7, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity }, - }; - - Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + [Test] + public void Solve_adjGraph4_CorrectAnswer() + { + /* Graph + * (0)--7--(1)--8--(2) + * \ / \ / + * 5 9 7 5 + * \ / \ / + * (3)--15-(4) + * \ / \ + * 6 8 9 + * \ / \ + * (5)--11-(6) + */ + var adj = new[,] + { + { 0, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { 7, 0, 8, 9, 7, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 8, 0, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity }, + { 5, 9, float.PositiveInfinity, 0, 15, 6, float.PositiveInfinity }, + { float.PositiveInfinity, 7, 5, 15, 0, 8, 9 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 8, 0, 11 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, 11, 0 }, + }; + + /* Expected MST + * (0)--7--(1) (2) + * \ \ / + * 5 7 5 + * \ \ / + * (3) (4) + * \ \ + * 6 9 + * \ \ + * (5) (6) + */ + var expected = new[,] + { + { float.PositiveInfinity, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { 7, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 7, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity }, + { 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity }, + { float.PositiveInfinity, 7, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity }, + }; + + Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); + } - [Test] - public void Solve_adjGraph5_CorrectAnswer() - { - /* Graph - * (0)--8--(1)--15-(2) - * |\ / __/|\ - * | 4 5 __25 13 12 - * | \ /__/ | \ - * 10 (3)----14---(4) (5) - * | / \ _/| / - * | 9 6 __16 18 30 - * |/ \ / |/ - * (6)--18-(7)--20-(8) - */ - var adj = new[,] - { - { 0, 8, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity, 10, float.PositiveInfinity, float.PositiveInfinity }, - { 8, 0, 15, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 15, 0, 25, 13, 12, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { 4, 5, 25, 0, 14, float.PositiveInfinity, 9, 6, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, 13, 14, 0, float.PositiveInfinity, float.PositiveInfinity, 16, 18 }, - { float.PositiveInfinity, float.PositiveInfinity, 12, float.PositiveInfinity, float.PositiveInfinity, 0, float.PositiveInfinity, float.PositiveInfinity, 30 }, - { 10, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity, 0, 18, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 16, float.PositiveInfinity, 18, 0, 20 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 18, 30, float.PositiveInfinity, 20, 0 }, - }; - - /* Expected MST - * (0) (1) (2) - * \ / |\ - * 4 5 13 12 - * \ / | \ - * (3)----14---(4) (5) - * / \ | - * 9 6 18 - * / \ | - * (6) (7) (8) - */ - var expected = new[,] + [Test] + public void Solve_adjGraph5_CorrectAnswer() + { + /* Graph + * (0)--8--(1)--15-(2) + * |\ / __/|\ + * | 4 5 __25 13 12 + * | \ /__/ | \ + * 10 (3)----14---(4) (5) + * | / \ _/| / + * | 9 6 __16 18 30 + * |/ \ / |/ + * (6)--18-(7)--20-(8) + */ + var adj = new[,] + { + { 0, 8, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity, 10, float.PositiveInfinity, float.PositiveInfinity }, + { 8, 0, 15, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 15, 0, 25, 13, 12, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { 4, 5, 25, 0, 14, float.PositiveInfinity, 9, 6, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, 13, 14, 0, float.PositiveInfinity, float.PositiveInfinity, 16, 18 }, + { float.PositiveInfinity, float.PositiveInfinity, 12, float.PositiveInfinity, float.PositiveInfinity, 0, float.PositiveInfinity, float.PositiveInfinity, 30 }, + { 10, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity, 0, 18, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 16, float.PositiveInfinity, 18, 0, 20 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 18, 30, float.PositiveInfinity, 20, 0 }, + }; + + /* Expected MST + * (0) (1) (2) + * \ / |\ + * 4 5 13 12 + * \ / | \ + * (3)----14---(4) (5) + * / \ | + * 9 6 18 + * / \ | + * (6) (7) (8) + */ + var expected = new[,] + { { - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 4, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 5, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 13, - 12, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - 4, - 5, - float.PositiveInfinity, - float.PositiveInfinity, - 14, - float.PositiveInfinity, - 9, - 6, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - 13, - 14, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 18, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - 12, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 9, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 6, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 18, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - }; - - Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 4, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 5, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 13, + 12, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + 4, + 5, + float.PositiveInfinity, + float.PositiveInfinity, + 14, + float.PositiveInfinity, + 9, + 6, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + 13, + 14, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 18, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + 12, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 9, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 6, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 18, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + }; + + Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); + } - [Test] - public void Solve_adjGraph6_CorrectAnswer() - { - /* Graph - * (0)--7--(1) (2) - * \ / /| - * 5 9 5 | - * \ / / | - * (3) (4) 2 - * / \ | - * 8 9 | - * / \| - * (5)--11-(6) - */ - var adj = new[,] - { - { 0, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { 7, 0, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, 0, float.PositiveInfinity, 5, float.PositiveInfinity, 2 }, - { 5, 9, float.PositiveInfinity, 0, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, 0, 8, 9 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 8, 0, 11 }, - { float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity, 9, 11, 0 }, - }; - - /* Expected MST - * (0)--7--(1) (2) - * \ /| - * 5 5 | - * \ / | - * (3) (4) 2 - * / | - * 8 | - * / | - * (5) (6) - */ - var expected = new[,] - { - { float.PositiveInfinity, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { 7, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, 2 }, - { 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, 8, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 8, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - }; - - Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + [Test] + public void Solve_adjGraph6_CorrectAnswer() + { + /* Graph + * (0)--7--(1) (2) + * \ / /| + * 5 9 5 | + * \ / / | + * (3) (4) 2 + * / \ | + * 8 9 | + * / \| + * (5)--11-(6) + */ + var adj = new[,] + { + { 0, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { 7, 0, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, 0, float.PositiveInfinity, 5, float.PositiveInfinity, 2 }, + { 5, 9, float.PositiveInfinity, 0, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, 0, 8, 9 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 8, 0, 11 }, + { float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity, 9, 11, 0 }, + }; + + /* Expected MST + * (0)--7--(1) (2) + * \ /| + * 5 5 | + * \ / | + * (3) (4) 2 + * / | + * 8 | + * / | + * (5) (6) + */ + var expected = new[,] + { + { float.PositiveInfinity, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { 7, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, 2 }, + { 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, 8, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 8, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + }; + + Kruskal.Solve(adj).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); + } - [Test] - public void ValidateGraph_ListDirectedGraph_ThrowsException() + [Test] + public void ValidateGraph_ListDirectedGraph_ThrowsException() + { + var adj = new[] { - var adj = new[] - { - new Dictionary{ { 2, 4 } }, - new Dictionary{ { 0, 3 }, { 2, 5 }, { 3, 6 }, { 4, 2 } }, - new Dictionary{ { 0, 4 }, { 1, 5 } }, - new Dictionary{ { 1, 6 } }, - new Dictionary{ { 1, 2 } }, - }; - Assert.Throws(() => Kruskal.Solve(adj), "Graph must be undirected!"); - } + new Dictionary{ { 2, 4 } }, + new Dictionary{ { 0, 3 }, { 2, 5 }, { 3, 6 }, { 4, 2 } }, + new Dictionary{ { 0, 4 }, { 1, 5 } }, + new Dictionary{ { 1, 6 } }, + new Dictionary{ { 1, 2 } }, + }; + Assert.Throws(() => Kruskal.Solve(adj), "Graph must be undirected!"); + } - [Test] - public void Solve_ListGraph1_CorrectAnswer() - { - /* Graph - * (1) - * / \ - * 3 2 - * / \ - * (0)--2--(2) - */ - var adj = new[] - { - new Dictionary{ { 1, 3 }, { 2, 2 } }, - new Dictionary{ { 0, 3 }, { 2, 2 } }, - new Dictionary{ { 0, 2 }, { 1, 2 } }, - }; - - /* Expected MST - * (1) - * \ - * 2 - * \ - * (0)--2--(2) - */ - var expected = new[] - { - new Dictionary{ { 2, 2 } }, - new Dictionary{ { 2, 2 } }, - new Dictionary{ { 0, 2 }, { 1, 2 } }, - }; + [Test] + public void Solve_ListGraph1_CorrectAnswer() + { + /* Graph + * (1) + * / \ + * 3 2 + * / \ + * (0)--2--(2) + */ + var adj = new[] + { + new Dictionary{ { 1, 3 }, { 2, 2 } }, + new Dictionary{ { 0, 3 }, { 2, 2 } }, + new Dictionary{ { 0, 2 }, { 1, 2 } }, + }; + + /* Expected MST + * (1) + * \ + * 2 + * \ + * (0)--2--(2) + */ + var expected = new[] + { + new Dictionary{ { 2, 2 } }, + new Dictionary{ { 2, 2 } }, + new Dictionary{ { 0, 2 }, { 1, 2 } }, + }; - var res = Kruskal.Solve(adj); - for (var i = 0; i < adj.Length; i++) - { - res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); - } + var res = Kruskal.Solve(adj); + for (var i = 0; i < adj.Length; i++) + { + res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); } + } - [Test] - public void Solve_ListGraph2_CorrectAnswer() - { - /* Graph - * (0) (4) - * |\ / - * | 3 2 - * | \ / - * 4 (1) - * | / \ - * | 5 6 - * |/ \ - * (2) (3) - */ - var adj = new[] - { - new Dictionary{ { 1, 3 }, { 2, 4 } }, - new Dictionary{ { 0, 3 }, { 2, 5 }, { 3, 6 }, { 4, 2 } }, - new Dictionary{ { 0, 4 }, { 1, 5 } }, - new Dictionary{ { 1, 6 } }, - new Dictionary{ { 1, 2 } }, - }; - - /* Expected MST - * (0) (4) - * |\ / - * | 3 2 - * | \ / - * 4 (1) - * | \ - * | 6 - * | \ - * (2) (3) - */ - var expected = new[] - { - new Dictionary{ { 1, 3 }, { 2, 4 } }, - new Dictionary{ { 0, 3 }, { 3, 6 }, { 4, 2 } }, - new Dictionary{ { 0, 4 } }, - new Dictionary{ { 1, 6 } }, - new Dictionary{ { 1, 2 } }, - }; - - var res = Kruskal.Solve(adj); - for (var i = 0; i < adj.Length; i++) - { - res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); - } + [Test] + public void Solve_ListGraph2_CorrectAnswer() + { + /* Graph + * (0) (4) + * |\ / + * | 3 2 + * | \ / + * 4 (1) + * | / \ + * | 5 6 + * |/ \ + * (2) (3) + */ + var adj = new[] + { + new Dictionary{ { 1, 3 }, { 2, 4 } }, + new Dictionary{ { 0, 3 }, { 2, 5 }, { 3, 6 }, { 4, 2 } }, + new Dictionary{ { 0, 4 }, { 1, 5 } }, + new Dictionary{ { 1, 6 } }, + new Dictionary{ { 1, 2 } }, + }; + + /* Expected MST + * (0) (4) + * |\ / + * | 3 2 + * | \ / + * 4 (1) + * | \ + * | 6 + * | \ + * (2) (3) + */ + var expected = new[] + { + new Dictionary{ { 1, 3 }, { 2, 4 } }, + new Dictionary{ { 0, 3 }, { 3, 6 }, { 4, 2 } }, + new Dictionary{ { 0, 4 } }, + new Dictionary{ { 1, 6 } }, + new Dictionary{ { 1, 2 } }, + }; + + var res = Kruskal.Solve(adj); + for (var i = 0; i < adj.Length; i++) + { + res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); } + } - [Test] - public void Solve_ListGraph3_CorrectAnswer() - { - /* Graph - * (0)--3--(2) (4)--2--(5) - * \ / \ / - * 4 1 4 6 - * \ / \ / - * (1)--2--(3) - */ - var adj = new[] - { - new Dictionary{ { 1, 4 }, { 2, 3 } }, - new Dictionary{ { 0, 4 }, { 2, 1 }, { 3, 2 } }, - new Dictionary{ { 0, 3 }, { 1, 1 }, { 3, 4 } }, - new Dictionary{ { 1, 2 }, { 2, 4 }, { 4, 6 } }, - new Dictionary{ { 3, 6 }, { 5, 2 } }, - new Dictionary{ { 4, 2 } }, - }; - - /* Graph - * (0)--3--(2) (4)--2--(5) - * / / - * 1 6 - * / / - * (1)--2--(3) - */ - var expected = new[] - { - new Dictionary{ { 2, 3 } }, - new Dictionary{ { 2, 1 }, { 3, 2 } }, - new Dictionary{ { 0, 3 }, { 1, 1 } }, - new Dictionary{ { 1, 2 }, { 4, 6 } }, - new Dictionary{ { 3, 6 }, { 5, 2 } }, - new Dictionary{ { 4, 2 } }, - }; - - var res = Kruskal.Solve(adj); - for (var i = 0; i < adj.Length; i++) - { - res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); - } + [Test] + public void Solve_ListGraph3_CorrectAnswer() + { + /* Graph + * (0)--3--(2) (4)--2--(5) + * \ / \ / + * 4 1 4 6 + * \ / \ / + * (1)--2--(3) + */ + var adj = new[] + { + new Dictionary{ { 1, 4 }, { 2, 3 } }, + new Dictionary{ { 0, 4 }, { 2, 1 }, { 3, 2 } }, + new Dictionary{ { 0, 3 }, { 1, 1 }, { 3, 4 } }, + new Dictionary{ { 1, 2 }, { 2, 4 }, { 4, 6 } }, + new Dictionary{ { 3, 6 }, { 5, 2 } }, + new Dictionary{ { 4, 2 } }, + }; + + /* Graph + * (0)--3--(2) (4)--2--(5) + * / / + * 1 6 + * / / + * (1)--2--(3) + */ + var expected = new[] + { + new Dictionary{ { 2, 3 } }, + new Dictionary{ { 2, 1 }, { 3, 2 } }, + new Dictionary{ { 0, 3 }, { 1, 1 } }, + new Dictionary{ { 1, 2 }, { 4, 6 } }, + new Dictionary{ { 3, 6 }, { 5, 2 } }, + new Dictionary{ { 4, 2 } }, + }; + + var res = Kruskal.Solve(adj); + for (var i = 0; i < adj.Length; i++) + { + res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); } + } - [Test] - public void Solve_ListGraph4_CorrectAnswer() - { - /* Graph - * (0)--7--(1)--8--(2) - * \ / \ / - * 5 9 7 5 - * \ / \ / - * (3)--15-(4) - * \ / \ - * 6 8 9 - * \ / \ - * (5)--11-(6) - */ - var adj = new[] - { - new Dictionary{ { 1, 7 }, { 3, 5 } }, - new Dictionary{ { 0, 7 }, { 2, 8 }, { 3, 9 }, { 4, 7 } }, - new Dictionary{ { 1, 8 }, { 4, 5 } }, - new Dictionary{ { 0, 5 }, { 1, 9 }, { 4, 15 }, { 5, 6 } }, - new Dictionary{ { 1, 7 }, { 2, 5 }, { 3, 15 }, { 5, 8 }, { 6, 9 } }, - new Dictionary{ { 3, 6 }, { 4, 8 }, { 6, 11 } }, - new Dictionary{ { 4, 9 }, { 5, 11 } }, - }; - - /* Expected MST - * (0)--7--(1) (2) - * \ \ / - * 5 7 5 - * \ \ / - * (3) (4) - * \ \ - * 6 9 - * \ \ - * (5) (6) - */ - var expected = new[] - { - new Dictionary{ { 1, 7 }, { 3, 5 } }, - new Dictionary{ { 0, 7 }, { 4, 7 } }, - new Dictionary{ { 4, 5 } }, - new Dictionary{ { 0, 5 }, { 5, 6 } }, - new Dictionary{ { 1, 7 }, { 2, 5 }, { 6, 9 } }, - new Dictionary{ { 3, 6 } }, - new Dictionary{ { 4, 9 } }, - }; - - var res = Kruskal.Solve(adj); - for (var i = 0; i < adj.Length; i++) - { - res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); - } + [Test] + public void Solve_ListGraph4_CorrectAnswer() + { + /* Graph + * (0)--7--(1)--8--(2) + * \ / \ / + * 5 9 7 5 + * \ / \ / + * (3)--15-(4) + * \ / \ + * 6 8 9 + * \ / \ + * (5)--11-(6) + */ + var adj = new[] + { + new Dictionary{ { 1, 7 }, { 3, 5 } }, + new Dictionary{ { 0, 7 }, { 2, 8 }, { 3, 9 }, { 4, 7 } }, + new Dictionary{ { 1, 8 }, { 4, 5 } }, + new Dictionary{ { 0, 5 }, { 1, 9 }, { 4, 15 }, { 5, 6 } }, + new Dictionary{ { 1, 7 }, { 2, 5 }, { 3, 15 }, { 5, 8 }, { 6, 9 } }, + new Dictionary{ { 3, 6 }, { 4, 8 }, { 6, 11 } }, + new Dictionary{ { 4, 9 }, { 5, 11 } }, + }; + + /* Expected MST + * (0)--7--(1) (2) + * \ \ / + * 5 7 5 + * \ \ / + * (3) (4) + * \ \ + * 6 9 + * \ \ + * (5) (6) + */ + var expected = new[] + { + new Dictionary{ { 1, 7 }, { 3, 5 } }, + new Dictionary{ { 0, 7 }, { 4, 7 } }, + new Dictionary{ { 4, 5 } }, + new Dictionary{ { 0, 5 }, { 5, 6 } }, + new Dictionary{ { 1, 7 }, { 2, 5 }, { 6, 9 } }, + new Dictionary{ { 3, 6 } }, + new Dictionary{ { 4, 9 } }, + }; + + var res = Kruskal.Solve(adj); + for (var i = 0; i < adj.Length; i++) + { + res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); } + } - [Test] - public void Solve_ListGraph5_CorrectAnswer() - { - /* Graph - * (0)--8--(1)--15-(2) - * |\ / __/|\ - * | 4 5 __25 13 12 - * | \ /__/ | \ - * 10 (3)----14---(4) (5) - * | / \ _/| / - * | 9 6 __16 18 30 - * |/ \ / |/ - * (6)--18-(7)--20-(8) - */ - var adj = new[] - { - new Dictionary{ { 1, 8 }, { 3, 4 }, { 6, 10 } }, - new Dictionary{ { 0, 8 }, { 2, 15 }, { 3, 5 } }, - new Dictionary{ { 1, 15 }, { 3, 25 }, { 4, 13 }, { 5, 12 } }, - new Dictionary{ { 0, 4 }, { 1, 5 }, { 2, 25 }, { 4, 14 }, { 6, 9 }, { 7, 6 } }, - new Dictionary{ { 2, 13 }, { 3, 14 }, { 7, 16 }, { 8, 18 } }, - new Dictionary{ { 2, 12 }, { 8, 30 } }, - new Dictionary{ { 0, 10 }, { 3, 9 }, { 7, 18 } }, - new Dictionary{ { 3, 6 }, { 4, 16 }, { 6, 18 }, { 8, 20 } }, - new Dictionary{ { 4, 18 }, { 5, 30 }, { 7, 20 } }, - }; - - /* Expected MST - * (0) (1) (2) - * \ / |\ - * 4 5 13 12 - * \ / | \ - * (3)----14---(4) (5) - * / \ | - * 9 6 18 - * / \ | - * (6) (7) (8) - */ - var expected = new[] - { - new Dictionary{ { 3, 4 } }, - new Dictionary{ { 3, 5 } }, - new Dictionary{ { 4, 13 }, { 5, 12 } }, - new Dictionary{ { 0, 4 }, { 1, 5 }, { 4, 14 }, { 6, 9 }, { 7, 6 } }, - new Dictionary{ { 2, 13 }, { 3, 14 }, { 8, 18 } }, - new Dictionary{ { 2, 12 } }, - new Dictionary{ { 3, 9 } }, - new Dictionary{ { 3, 6 } }, - new Dictionary{ { 4, 18 } }, - }; - - var res = Kruskal.Solve(adj); - for (var i = 0; i < adj.Length; i++) - { - res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); - } + [Test] + public void Solve_ListGraph5_CorrectAnswer() + { + /* Graph + * (0)--8--(1)--15-(2) + * |\ / __/|\ + * | 4 5 __25 13 12 + * | \ /__/ | \ + * 10 (3)----14---(4) (5) + * | / \ _/| / + * | 9 6 __16 18 30 + * |/ \ / |/ + * (6)--18-(7)--20-(8) + */ + var adj = new[] + { + new Dictionary{ { 1, 8 }, { 3, 4 }, { 6, 10 } }, + new Dictionary{ { 0, 8 }, { 2, 15 }, { 3, 5 } }, + new Dictionary{ { 1, 15 }, { 3, 25 }, { 4, 13 }, { 5, 12 } }, + new Dictionary{ { 0, 4 }, { 1, 5 }, { 2, 25 }, { 4, 14 }, { 6, 9 }, { 7, 6 } }, + new Dictionary{ { 2, 13 }, { 3, 14 }, { 7, 16 }, { 8, 18 } }, + new Dictionary{ { 2, 12 }, { 8, 30 } }, + new Dictionary{ { 0, 10 }, { 3, 9 }, { 7, 18 } }, + new Dictionary{ { 3, 6 }, { 4, 16 }, { 6, 18 }, { 8, 20 } }, + new Dictionary{ { 4, 18 }, { 5, 30 }, { 7, 20 } }, + }; + + /* Expected MST + * (0) (1) (2) + * \ / |\ + * 4 5 13 12 + * \ / | \ + * (3)----14---(4) (5) + * / \ | + * 9 6 18 + * / \ | + * (6) (7) (8) + */ + var expected = new[] + { + new Dictionary{ { 3, 4 } }, + new Dictionary{ { 3, 5 } }, + new Dictionary{ { 4, 13 }, { 5, 12 } }, + new Dictionary{ { 0, 4 }, { 1, 5 }, { 4, 14 }, { 6, 9 }, { 7, 6 } }, + new Dictionary{ { 2, 13 }, { 3, 14 }, { 8, 18 } }, + new Dictionary{ { 2, 12 } }, + new Dictionary{ { 3, 9 } }, + new Dictionary{ { 3, 6 } }, + new Dictionary{ { 4, 18 } }, + }; + + var res = Kruskal.Solve(adj); + for (var i = 0; i < adj.Length; i++) + { + res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); } + } - [Test] - public void Solve_ListGraph6_CorrectAnswer() - { - /* Graph - * (0)--7--(1) (2) - * \ / /| - * 5 9 5 | - * \ / / | - * (3) (4) 2 - * / \ | - * 8 9 | - * / \| - * (5)--11-(6) - */ - var adj = new[] - { - new Dictionary{ { 1, 7 }, { 3, 5 } }, - new Dictionary{ { 0, 7 }, { 3, 9 } }, - new Dictionary{ { 4, 5 }, { 6, 2 } }, - new Dictionary{ { 0, 5 }, { 1, 9 } }, - new Dictionary{ { 2, 5 }, { 5, 8 }, { 6, 9 } }, - new Dictionary{ { 4, 8 }, { 6, 11 } }, - new Dictionary{ { 2, 2 }, { 4, 9 }, { 5, 11 } }, - }; - - /* Expected MST - * (0)--7--(1) (2) - * \ /| - * 5 5 | - * \ / | - * (3) (4) 2 - * / | - * 8 | - * / | - * (5) (6) - */ - var expected = new[] - { - new Dictionary{ { 1, 7 }, { 3, 5 } }, - new Dictionary{ { 0, 7 } }, - new Dictionary{ { 4, 5 }, { 6, 2 } }, - new Dictionary{ { 0, 5 } }, - new Dictionary{ { 2, 5 }, { 5, 8 } }, - new Dictionary{ { 4, 8 } }, - new Dictionary{ { 2, 2 } }, - }; - - var res = Kruskal.Solve(adj); - for (var i = 0; i < adj.Length; i++) - { - res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); - } + [Test] + public void Solve_ListGraph6_CorrectAnswer() + { + /* Graph + * (0)--7--(1) (2) + * \ / /| + * 5 9 5 | + * \ / / | + * (3) (4) 2 + * / \ | + * 8 9 | + * / \| + * (5)--11-(6) + */ + var adj = new[] + { + new Dictionary{ { 1, 7 }, { 3, 5 } }, + new Dictionary{ { 0, 7 }, { 3, 9 } }, + new Dictionary{ { 4, 5 }, { 6, 2 } }, + new Dictionary{ { 0, 5 }, { 1, 9 } }, + new Dictionary{ { 2, 5 }, { 5, 8 }, { 6, 9 } }, + new Dictionary{ { 4, 8 }, { 6, 11 } }, + new Dictionary{ { 2, 2 }, { 4, 9 }, { 5, 11 } }, + }; + + /* Expected MST + * (0)--7--(1) (2) + * \ /| + * 5 5 | + * \ / | + * (3) (4) 2 + * / | + * 8 | + * / | + * (5) (6) + */ + var expected = new[] + { + new Dictionary{ { 1, 7 }, { 3, 5 } }, + new Dictionary{ { 0, 7 } }, + new Dictionary{ { 4, 5 }, { 6, 2 } }, + new Dictionary{ { 0, 5 } }, + new Dictionary{ { 2, 5 }, { 5, 8 } }, + new Dictionary{ { 4, 8 } }, + new Dictionary{ { 2, 2 } }, + }; + + var res = Kruskal.Solve(adj); + for (var i = 0; i < adj.Length; i++) + { + res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue(); } } } diff --git a/Algorithms.Tests/Graph/MinimumSpanningTree/PrimMatrixTests.cs b/Algorithms.Tests/Graph/MinimumSpanningTree/PrimMatrixTests.cs index 76056da9..c9b7521f 100644 --- a/Algorithms.Tests/Graph/MinimumSpanningTree/PrimMatrixTests.cs +++ b/Algorithms.Tests/Graph/MinimumSpanningTree/PrimMatrixTests.cs @@ -4,392 +4,391 @@ using System; using System.Linq; -namespace Algorithms.Tests.Graph.MinimumSpanningTree +namespace Algorithms.Tests.Graph.MinimumSpanningTree; + +internal class PrimTests { - internal class PrimTests + [Test] + public void ValidateMatrix_WrongSize_ThrowsException() { - [Test] - public void ValidateMatrix_WrongSize_ThrowsException() + // Wrong number of columns + var matrix = new[,] { - // Wrong number of columns - var matrix = new[,] - { - { 0, 3, 4, float.PositiveInfinity }, - { 3, 0, 5, 6 }, - { 4, 5, 0, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, 0 }, - { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity }, - }; - Assert.Throws(() => PrimMatrix.Solve(matrix, 0)); + { 0, 3, 4, float.PositiveInfinity }, + { 3, 0, 5, 6 }, + { 4, 5, 0, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, 0 }, + { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity }, + }; + Assert.Throws(() => PrimMatrix.Solve(matrix, 0)); - // Wrong number of rows - matrix = new[,] - { - { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 0, 5, 6, 2 }, - { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, - }; - Assert.Throws(() => PrimMatrix.Solve(matrix, 0)); - } + // Wrong number of rows + matrix = new[,] + { + { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 0, 5, 6, 2 }, + { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, + }; + Assert.Throws(() => PrimMatrix.Solve(matrix, 0)); + } - [Test] - public void ValidateMatrix_UnconnectedGraph_ThrowsException() + [Test] + public void ValidateMatrix_UnconnectedGraph_ThrowsException() + { + // Last node does not connect to any other nodes + var matrix = new[,] { - // Last node does not connect to any other nodes - var matrix = new[,] - { - { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 0, 5, 6, 2 }, - { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 0 }, - }; - Assert.Throws(() => PrimMatrix.Solve(matrix, 0)); - } + { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 0, 5, 6, 2 }, + { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 0 }, + }; + Assert.Throws(() => PrimMatrix.Solve(matrix, 0)); + } - [Test] - public void ValidateMatrix_DirectedGraph_ThrowsException() + [Test] + public void ValidateMatrix_DirectedGraph_ThrowsException() + { + // Nodes 1 and 2 have a directed edge + var matrix = new[,] { - // Nodes 1 and 2 have a directed edge - var matrix = new[,] - { - { 0, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 0, 5, 6, 2 }, - { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, - { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 }, - }; - Assert.Throws(() => PrimMatrix.Solve(matrix, 0)); - } + { 0, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 0, 5, 6, 2 }, + { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, + { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 }, + }; + Assert.Throws(() => PrimMatrix.Solve(matrix, 0)); + } - [Test] - public void SolveMatrix_Graph1_CorrectAnswer() + [Test] + public void SolveMatrix_Graph1_CorrectAnswer() + { + /* Graph + * (1) + * / \ + * 3 2 + * / \ + * (0)--2--(2) + */ + var matrix = new float[,] { - /* Graph - * (1) - * / \ - * 3 2 - * / \ - * (0)--2--(2) - */ - var matrix = new float[,] - { - { 0, 3, 2 }, - { 3, 0, 2 }, - { 2, 2, 0 }, - }; + { 0, 3, 2 }, + { 3, 0, 2 }, + { 2, 2, 0 }, + }; - /* Expected MST - * (1) - * \ - * 2 - * \ - * (0)--2--(2) - */ - var expected = new[,] - { - { float.PositiveInfinity, float.PositiveInfinity, 2 }, - { float.PositiveInfinity, float.PositiveInfinity, 2 }, - { 2, 2, float.PositiveInfinity }, - }; + /* Expected MST + * (1) + * \ + * 2 + * \ + * (0)--2--(2) + */ + var expected = new[,] + { + { float.PositiveInfinity, float.PositiveInfinity, 2 }, + { float.PositiveInfinity, float.PositiveInfinity, 2 }, + { 2, 2, float.PositiveInfinity }, + }; - for (var i = 0; i < matrix.GetLength(0); i++) - { - PrimMatrix.Solve(matrix, i).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + for (var i = 0; i < matrix.GetLength(0); i++) + { + PrimMatrix.Solve(matrix, i).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); } + } - [Test] - public void SolveMatrix_Graph2_CorrectAnswer() + [Test] + public void SolveMatrix_Graph2_CorrectAnswer() + { + /* Graph + * (0) (4) + * |\ / + * | 3 2 + * | \ / + * 4 (1) + * | / \ + * | 5 6 + * |/ \ + * (2) (3) + */ + var matrix = new[,] { - /* Graph - * (0) (4) - * |\ / - * | 3 2 - * | \ / - * 4 (1) - * | / \ - * | 5 6 - * |/ \ - * (2) (3) - */ - var matrix = new[,] - { - { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 0, 5, 6, 2 }, - { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, - { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 }, - }; + { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 0, 5, 6, 2 }, + { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity }, + { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 }, + }; - /* Expected MST - * (0) (4) - * |\ / - * | 3 2 - * | \ / - * 4 (1) - * | \ - * | 6 - * | \ - * (2) (3) - */ - var expected = new[,] - { - { float.PositiveInfinity, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, - { 3, float.PositiveInfinity, float.PositiveInfinity, 6, 2 }, - { 4, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - }; + /* Expected MST + * (0) (4) + * |\ / + * | 3 2 + * | \ / + * 4 (1) + * | \ + * | 6 + * | \ + * (2) (3) + */ + var expected = new[,] + { + { float.PositiveInfinity, 3, 4, float.PositiveInfinity, float.PositiveInfinity }, + { 3, float.PositiveInfinity, float.PositiveInfinity, 6, 2 }, + { 4, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + }; - for (var i = 0; i < matrix.GetLength(0); i++) - { - PrimMatrix.Solve(matrix, i).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + for (var i = 0; i < matrix.GetLength(0); i++) + { + PrimMatrix.Solve(matrix, i).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); } + } - [Test] - public void SolveMatrix_Graph3_CorrectAnswer() + [Test] + public void SolveMatrix_Graph3_CorrectAnswer() + { + /* Graph + * (0)--3--(2) (4)--2--(5) + * \ / \ / + * 4 1 4 6 + * \ / \ / + * (1)--2--(3) + */ + var matrix = new[,] { - /* Graph - * (0)--3--(2) (4)--2--(5) - * \ / \ / - * 4 1 4 6 - * \ / \ / - * (1)--2--(3) - */ - var matrix = new[,] - { - { 0, 4, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { 4, 0, 1, 2, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 1, 0, 4, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 2, 4, 0, 6, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 0, 2 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, 0 }, - }; + { 0, 4, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { 4, 0, 1, 2, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 1, 0, 4, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 2, 4, 0, 6, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 0, 2 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, 0 }, + }; - /* Graph - * (0)--3--(2) (4)--2--(5) - * / / - * 1 6 - * / / - * (1)--2--(3) - */ - var expected = new[,] - { - { float.PositiveInfinity, float.PositiveInfinity, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, 1, 2, float.PositiveInfinity, float.PositiveInfinity }, - { 3, 1, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, 2 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity }, - }; + /* Graph + * (0)--3--(2) (4)--2--(5) + * / / + * 1 6 + * / / + * (1)--2--(3) + */ + var expected = new[,] + { + { float.PositiveInfinity, float.PositiveInfinity, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, 1, 2, float.PositiveInfinity, float.PositiveInfinity }, + { 3, 1, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, 2 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity }, + }; - for (var i = 0; i < matrix.GetLength(0); i++) - { - PrimMatrix.Solve(matrix, i).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + for (var i = 0; i < matrix.GetLength(0); i++) + { + PrimMatrix.Solve(matrix, i).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); } + } - [Test] - public void SolveMatrix_Graph4_CorrectAnswer() + [Test] + public void SolveMatrix_Graph4_CorrectAnswer() + { + /* Graph + * (0)--7--(1)--8--(2) + * \ / \ / + * 5 9 7 5 + * \ / \ / + * (3)--15-(4) + * \ / \ + * 6 8 9 + * \ / \ + * (5)--11-(6) + */ + var matrix = new[,] { - /* Graph - * (0)--7--(1)--8--(2) - * \ / \ / - * 5 9 7 5 - * \ / \ / - * (3)--15-(4) - * \ / \ - * 6 8 9 - * \ / \ - * (5)--11-(6) - */ - var matrix = new[,] - { - { 0, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { 7, 0, 8, 9, 7, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 8, 0, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity }, - { 5, 9, float.PositiveInfinity, 0, 15, 6, float.PositiveInfinity }, - { float.PositiveInfinity, 7, 5, 15, 0, 8, 9 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 8, 0, 11 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, 11, 0 }, - }; + { 0, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { 7, 0, 8, 9, 7, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 8, 0, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity }, + { 5, 9, float.PositiveInfinity, 0, 15, 6, float.PositiveInfinity }, + { float.PositiveInfinity, 7, 5, 15, 0, 8, 9 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 8, 0, 11 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, 11, 0 }, + }; - /* Expected MST - * (0)--7--(1) (2) - * \ \ / - * 5 7 5 - * \ \ / - * (3) (4) - * \ \ - * 6 9 - * \ \ - * (5) (6) - */ - var expected = new[,] - { - { float.PositiveInfinity, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { 7, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 7, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity }, - { 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity }, - { float.PositiveInfinity, 7, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity }, - }; + /* Expected MST + * (0)--7--(1) (2) + * \ \ / + * 5 7 5 + * \ \ / + * (3) (4) + * \ \ + * 6 9 + * \ \ + * (5) (6) + */ + var expected = new[,] + { + { float.PositiveInfinity, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { 7, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 7, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity }, + { 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity }, + { float.PositiveInfinity, 7, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity }, + }; - for (var i = 0; i < matrix.GetLength(0); i++) - { - PrimMatrix.Solve(matrix, i).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + for (var i = 0; i < matrix.GetLength(0); i++) + { + PrimMatrix.Solve(matrix, i).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); } + } - [Test] - public void SolveMatrix_Graph5_CorrectAnswer() + [Test] + public void SolveMatrix_Graph5_CorrectAnswer() + { + /* Graph + * (0)--8--(1)--15-(2) + * |\ / __/|\ + * | 4 5 __25 13 12 + * | \ /__/ | \ + * 10 (3)----14---(4) (5) + * | / \ _/| / + * | 9 6 __16 18 30 + * |/ \ / |/ + * (6)--18-(7)--20-(8) + */ + var matrix = new[,] { - /* Graph - * (0)--8--(1)--15-(2) - * |\ / __/|\ - * | 4 5 __25 13 12 - * | \ /__/ | \ - * 10 (3)----14---(4) (5) - * | / \ _/| / - * | 9 6 __16 18 30 - * |/ \ / |/ - * (6)--18-(7)--20-(8) - */ - var matrix = new[,] - { - { 0, 8, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity, 10, float.PositiveInfinity, float.PositiveInfinity }, - { 8, 0, 15, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { float.PositiveInfinity, 15, 0, 25, 13, 12, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, - { 4, 5, 25, 0, 14, float.PositiveInfinity, 9, 6, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, 13, 14, 0, float.PositiveInfinity, float.PositiveInfinity, 16, 18 }, - { float.PositiveInfinity, float.PositiveInfinity, 12, float.PositiveInfinity, float.PositiveInfinity, 0, float.PositiveInfinity, float.PositiveInfinity, 30 }, - { 10, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity, 0, 18, float.PositiveInfinity }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 16, float.PositiveInfinity, 18, 0, 20 }, - { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 18, 30, float.PositiveInfinity, 20, 0 }, - }; + { 0, 8, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity, 10, float.PositiveInfinity, float.PositiveInfinity }, + { 8, 0, 15, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { float.PositiveInfinity, 15, 0, 25, 13, 12, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }, + { 4, 5, 25, 0, 14, float.PositiveInfinity, 9, 6, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, 13, 14, 0, float.PositiveInfinity, float.PositiveInfinity, 16, 18 }, + { float.PositiveInfinity, float.PositiveInfinity, 12, float.PositiveInfinity, float.PositiveInfinity, 0, float.PositiveInfinity, float.PositiveInfinity, 30 }, + { 10, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity, 0, 18, float.PositiveInfinity }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 16, float.PositiveInfinity, 18, 0, 20 }, + { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 18, 30, float.PositiveInfinity, 20, 0 }, + }; - /* Expected MST - * (0) (1) (2) - * \ / |\ - * 4 5 13 12 - * \ / | \ - * (3)----14---(4) (5) - * / \ | - * 9 6 18 - * / \ | - * (6) (7) (8) - */ - var expected = new[,] + /* Expected MST + * (0) (1) (2) + * \ / |\ + * 4 5 13 12 + * \ / | \ + * (3)----14---(4) (5) + * / \ | + * 9 6 18 + * / \ | + * (6) (7) (8) + */ + var expected = new[,] + { { - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 4, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 5, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 13, - 12, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - 4, - 5, - float.PositiveInfinity, - float.PositiveInfinity, - 14, - float.PositiveInfinity, - 9, - 6, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - 13, - 14, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 18, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - 12, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 9, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 6, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - { - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - 18, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - float.PositiveInfinity, - }, - }; - - for (var i = 0; i < matrix.GetLength(0); i++) + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 4, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 5, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 13, + 12, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + 4, + 5, + float.PositiveInfinity, + float.PositiveInfinity, + 14, + float.PositiveInfinity, + 9, + 6, + float.PositiveInfinity, + }, { - PrimMatrix.Solve(matrix, i).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); - } + float.PositiveInfinity, + float.PositiveInfinity, + 13, + 14, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 18, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + 12, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 9, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 6, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + { + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + 18, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + }, + }; + + for (var i = 0; i < matrix.GetLength(0); i++) + { + PrimMatrix.Solve(matrix, i).Cast().SequenceEqual(expected.Cast()).Should().BeTrue(); } } } diff --git a/Algorithms.Tests/Helpers/IntComparer.cs b/Algorithms.Tests/Helpers/IntComparer.cs index a156ec7b..cc7e3928 100644 --- a/Algorithms.Tests/Helpers/IntComparer.cs +++ b/Algorithms.Tests/Helpers/IntComparer.cs @@ -1,9 +1,8 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace Algorithms.Tests.Helpers +namespace Algorithms.Tests.Helpers; + +internal class IntComparer : IComparer { - internal class IntComparer : IComparer - { - public int Compare(int x, int y) => x.CompareTo(y); - } + public int Compare(int x, int y) => x.CompareTo(y); } diff --git a/Algorithms.Tests/Helpers/RandomHelper.cs b/Algorithms.Tests/Helpers/RandomHelper.cs index a4a02b4a..d55eddf9 100644 --- a/Algorithms.Tests/Helpers/RandomHelper.cs +++ b/Algorithms.Tests/Helpers/RandomHelper.cs @@ -1,52 +1,51 @@ -using NUnit.Framework; +using NUnit.Framework; -namespace Algorithms.Tests.Helpers +namespace Algorithms.Tests.Helpers; + +internal static class RandomHelper { - internal static class RandomHelper + public static (int[] correctArray, int[] testArray) GetArrays(int n) { - public static (int[] correctArray, int[] testArray) GetArrays(int n) + var testArr = new int[n]; + var correctArray = new int[n]; + + for (var i = 0; i < n; i++) { - var testArr = new int[n]; - var correctArray = new int[n]; + var t = TestContext.CurrentContext.Random.Next(1_000_000); + testArr[i] = t; + correctArray[i] = t; + } - for (var i = 0; i < n; i++) - { - var t = TestContext.CurrentContext.Random.Next(1_000_000); - testArr[i] = t; - correctArray[i] = t; - } + return (correctArray, testArr); + } - return (correctArray, testArr); - } + public static (string[] correctArray, string[] testArray) GetStringArrays( + int n, + int maxLength, + bool equalLength) + { + var testArr = new string[n]; + var correctArray = new string[n]; + var length = TestContext.CurrentContext.Random.Next(2, maxLength); - public static (string[] correctArray, string[] testArray) GetStringArrays( - int n, - int maxLength, - bool equalLength) + for (var i = 0; i < n; i++) { - var testArr = new string[n]; - var correctArray = new string[n]; - var length = TestContext.CurrentContext.Random.Next(2, maxLength); + if (!equalLength) + { + length = TestContext.CurrentContext.Random.Next(2, maxLength); + } - for (var i = 0; i < n; i++) + var chars = new char[length]; + for (var j = 0; j < length; j++) { - if (!equalLength) - { - length = TestContext.CurrentContext.Random.Next(2, maxLength); - } - - var chars = new char[length]; - for (var j = 0; j < length; j++) - { - chars[j] = (char)TestContext.CurrentContext.Random.Next(97, 123); - } - - var t = new string(chars); - testArr[i] = t; - correctArray[i] = t; + chars[j] = (char)TestContext.CurrentContext.Random.Next(97, 123); } - return (correctArray, testArr); + var t = new string(chars); + testArr[i] = t; + correctArray[i] = t; } + + return (correctArray, testArr); } } diff --git a/Algorithms.Tests/Knapsack/BranchAndBoundKnapsackSolverTests.cs b/Algorithms.Tests/Knapsack/BranchAndBoundKnapsackSolverTests.cs index af59ffe5..c50ef1bf 100644 --- a/Algorithms.Tests/Knapsack/BranchAndBoundKnapsackSolverTests.cs +++ b/Algorithms.Tests/Knapsack/BranchAndBoundKnapsackSolverTests.cs @@ -3,113 +3,112 @@ using NUnit.Framework; using FluentAssertions; -namespace Algorithms.Tests.Knapsack +namespace Algorithms.Tests.Knapsack; + +public static class BranchAndBoundKnapsackSolverTests { - public static class BranchAndBoundKnapsackSolverTests + [Test] + public static void BranchAndBoundTest_Example1_Success() { - [Test] - public static void BranchAndBoundTest_Example1_Success() - { - // Arrange - var items = new[] {'A', 'B', 'C', 'D'}; - var values = new[] {18, 20, 14, 18}; - var weights = new[] {2, 4, 6, 9}; - - var capacity = 15; - - Func weightSelector = x => weights[Array.IndexOf(items, x)]; - Func valueSelector = x => values[Array.IndexOf(items, x)]; - - // Act - var solver = new BranchAndBoundKnapsackSolver(); - var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); - - // Assert - actualResult.Should().BeEquivalentTo('A', 'B', 'D'); - } - - [Test] - public static void BranchAndBoundTest_Example2_Success() - { - // Arrange - var items = new[] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; - var values = new[] { 505, 352, 458, 220, 354, 414, 498, 545, 473, 543 }; - var weights = new[] {23, 26, 20, 18, 32, 27, 29, 26, 30, 27}; - - var capacity = 67; - - Func weightSelector = x => weights[Array.IndexOf(items, x)]; - Func valueSelector = x => values[Array.IndexOf(items, x)]; - - // Act - var solver = new BranchAndBoundKnapsackSolver(); - var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); - - // Assert - actualResult.Should().BeEquivalentTo('H', 'D', 'A'); - } - - [Test] - public static void BranchAndBoundTest_CapacityIsZero_NothingTaken() - { - // Arrange - var items = new[] {'A', 'B', 'C', 'D'}; - var values = new[] {18, 20, 14, 18}; - var weights = new[] {2, 4, 6, 9}; - - var capacity = 0; - - Func weightSelector = x => weights[Array.IndexOf(items, x)]; - Func valueSelector = x => values[Array.IndexOf(items, x)]; - - // Act - var solver = new BranchAndBoundKnapsackSolver(); - var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); - - // Assert - actualResult.Should().BeEmpty(); - } - - [Test] - public static void BranchAndBoundTest_PlentyCapacity_EverythingIsTaken() - { - // Arrange - var items = new[] {'A', 'B', 'C', 'D'}; - var values = new[] {18, 20, 14, 18}; - var weights = new[] {2, 4, 6, 9}; - - var capacity = 1000; - - Func weightSelector = x => weights[Array.IndexOf(items, x)]; - Func valueSelector = x => values[Array.IndexOf(items, x)]; - - // Act - var solver = new BranchAndBoundKnapsackSolver(); - var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); - - // Assert - actualResult.Should().BeEquivalentTo(items); - } - - [Test] - public static void BranchAndBoundTest_NoItems_NothingTaken() - { - // Arrange - var items = Array.Empty(); - var values = Array.Empty(); - var weights = Array.Empty(); - - var capacity = 15; - - Func weightSelector = x => weights[Array.IndexOf(items, x)]; - Func valueSelector = x => values[Array.IndexOf(items, x)]; - - // Act - var solver = new BranchAndBoundKnapsackSolver(); - var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); - - // Assert - actualResult.Should().BeEmpty(); - } + // Arrange + var items = new[] {'A', 'B', 'C', 'D'}; + var values = new[] {18, 20, 14, 18}; + var weights = new[] {2, 4, 6, 9}; + + var capacity = 15; + + Func weightSelector = x => weights[Array.IndexOf(items, x)]; + Func valueSelector = x => values[Array.IndexOf(items, x)]; + + // Act + var solver = new BranchAndBoundKnapsackSolver(); + var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); + + // Assert + actualResult.Should().BeEquivalentTo('A', 'B', 'D'); + } + + [Test] + public static void BranchAndBoundTest_Example2_Success() + { + // Arrange + var items = new[] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; + var values = new[] { 505, 352, 458, 220, 354, 414, 498, 545, 473, 543 }; + var weights = new[] {23, 26, 20, 18, 32, 27, 29, 26, 30, 27}; + + var capacity = 67; + + Func weightSelector = x => weights[Array.IndexOf(items, x)]; + Func valueSelector = x => values[Array.IndexOf(items, x)]; + + // Act + var solver = new BranchAndBoundKnapsackSolver(); + var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); + + // Assert + actualResult.Should().BeEquivalentTo('H', 'D', 'A'); + } + + [Test] + public static void BranchAndBoundTest_CapacityIsZero_NothingTaken() + { + // Arrange + var items = new[] {'A', 'B', 'C', 'D'}; + var values = new[] {18, 20, 14, 18}; + var weights = new[] {2, 4, 6, 9}; + + var capacity = 0; + + Func weightSelector = x => weights[Array.IndexOf(items, x)]; + Func valueSelector = x => values[Array.IndexOf(items, x)]; + + // Act + var solver = new BranchAndBoundKnapsackSolver(); + var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); + + // Assert + actualResult.Should().BeEmpty(); + } + + [Test] + public static void BranchAndBoundTest_PlentyCapacity_EverythingIsTaken() + { + // Arrange + var items = new[] {'A', 'B', 'C', 'D'}; + var values = new[] {18, 20, 14, 18}; + var weights = new[] {2, 4, 6, 9}; + + var capacity = 1000; + + Func weightSelector = x => weights[Array.IndexOf(items, x)]; + Func valueSelector = x => values[Array.IndexOf(items, x)]; + + // Act + var solver = new BranchAndBoundKnapsackSolver(); + var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); + + // Assert + actualResult.Should().BeEquivalentTo(items); + } + + [Test] + public static void BranchAndBoundTest_NoItems_NothingTaken() + { + // Arrange + var items = Array.Empty(); + var values = Array.Empty(); + var weights = Array.Empty(); + + var capacity = 15; + + Func weightSelector = x => weights[Array.IndexOf(items, x)]; + Func valueSelector = x => values[Array.IndexOf(items, x)]; + + // Act + var solver = new BranchAndBoundKnapsackSolver(); + var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); + + // Assert + actualResult.Should().BeEmpty(); } } diff --git a/Algorithms.Tests/Knapsack/DynamicProgrammingKnapsackSolverTests.cs b/Algorithms.Tests/Knapsack/DynamicProgrammingKnapsackSolverTests.cs index a54d912a..087f5a26 100644 --- a/Algorithms.Tests/Knapsack/DynamicProgrammingKnapsackSolverTests.cs +++ b/Algorithms.Tests/Knapsack/DynamicProgrammingKnapsackSolverTests.cs @@ -1,104 +1,103 @@ -using System; +using System; using System.Linq; using Algorithms.Knapsack; using NUnit.Framework; -namespace Algorithms.Tests.Knapsack +namespace Algorithms.Tests.Knapsack; + +public static class DynamicProgrammingKnapsackSolverTests { - public static class DynamicProgrammingKnapsackSolverTests + [Test] + public static void SmallSampleOfChar() { - [Test] - public static void SmallSampleOfChar() - { - //Arrange - var items = new[] { 'A', 'B', 'C' }; - var val = new[] { 50, 100, 130 }; - var wt = new[] { 10, 20, 40 }; + //Arrange + var items = new[] { 'A', 'B', 'C' }; + var val = new[] { 50, 100, 130 }; + var wt = new[] { 10, 20, 40 }; - var capacity = 50; + var capacity = 50; - Func weightSelector = x => wt[Array.IndexOf(items, x)]; - Func valueSelector = x => val[Array.IndexOf(items, x)]; + Func weightSelector = x => wt[Array.IndexOf(items, x)]; + Func valueSelector = x => val[Array.IndexOf(items, x)]; - var expected = new[] { 'A', 'C' }; + var expected = new[] { 'A', 'C' }; - //Act - var solver = new DynamicProgrammingKnapsackSolver(); - var actual = solver.Solve(items, capacity, weightSelector, valueSelector); + //Act + var solver = new DynamicProgrammingKnapsackSolver(); + var actual = solver.Solve(items, capacity, weightSelector, valueSelector); - //Assert - Assert.AreEqual(expected.OrderBy(x => x), actual.OrderBy(x => x)); - } + //Assert + Assert.AreEqual(expected.OrderBy(x => x), actual.OrderBy(x => x)); + } - [Test] - public static void FSU_P01() - { - // Data from https://people.sc.fsu.edu/~jburkardt/datasets/knapsack_01/knapsack_01.html + [Test] + public static void FSU_P01() + { + // Data from https://people.sc.fsu.edu/~jburkardt/datasets/knapsack_01/knapsack_01.html - //Arrange - var items = new[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' }; - var val = new[] { 92, 57, 49, 68, 60, 43, 67, 84, 87, 72 }; - var wt = new[] { 23, 31, 29, 44, 53, 38, 63, 85, 89, 82 }; + //Arrange + var items = new[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' }; + var val = new[] { 92, 57, 49, 68, 60, 43, 67, 84, 87, 72 }; + var wt = new[] { 23, 31, 29, 44, 53, 38, 63, 85, 89, 82 }; - var capacity = 165; + var capacity = 165; - Func weightSelector = x => wt[Array.IndexOf(items, x)]; - Func valueSelector = x => val[Array.IndexOf(items, x)]; + Func weightSelector = x => wt[Array.IndexOf(items, x)]; + Func valueSelector = x => val[Array.IndexOf(items, x)]; - var expected = new[] { 'A', 'B', 'C', 'D', 'F' }; + var expected = new[] { 'A', 'B', 'C', 'D', 'F' }; - //Act - var solver = new DynamicProgrammingKnapsackSolver(); - var actual = solver.Solve(items, capacity, weightSelector, valueSelector); + //Act + var solver = new DynamicProgrammingKnapsackSolver(); + var actual = solver.Solve(items, capacity, weightSelector, valueSelector); - //Assert - Assert.AreEqual(expected.OrderBy(x => x), actual.OrderBy(x => x)); - } + //Assert + Assert.AreEqual(expected.OrderBy(x => x), actual.OrderBy(x => x)); + } - [Test] - public static void FSU_P07_WithNonIntegralValues() - { - // Shows how to handle weights with 1 significant digit right of the decimal - // Data from https://people.sc.fsu.edu/~jburkardt/datasets/knapsack_01/knapsack_01.html + [Test] + public static void FSU_P07_WithNonIntegralValues() + { + // Shows how to handle weights with 1 significant digit right of the decimal + // Data from https://people.sc.fsu.edu/~jburkardt/datasets/knapsack_01/knapsack_01.html - //Arrange - var val = new[] { 135, 139, 149, 150, 156, 163, 173, 184, 192, 201, 210, 214, 221, 229, 240 }; - var wt = new[] { 7.0, 7.3, 7.7, 8.0, 8.2, 8.7, 9.0, 9.4, 9.8, 10.6, 11.0, 11.3, 11.5, 11.8, 12.0 }; - var items = Enumerable.Range(1, val.Count()).ToArray(); + //Arrange + var val = new[] { 135, 139, 149, 150, 156, 163, 173, 184, 192, 201, 210, 214, 221, 229, 240 }; + var wt = new[] { 7.0, 7.3, 7.7, 8.0, 8.2, 8.7, 9.0, 9.4, 9.8, 10.6, 11.0, 11.3, 11.5, 11.8, 12.0 }; + var items = Enumerable.Range(1, val.Count()).ToArray(); - var capacity = 75; + var capacity = 75; - Func weightSelector = x => (int)(wt[Array.IndexOf(items, x)] * 10); - Func valueSelector = x => val[Array.IndexOf(items, x)]; + Func weightSelector = x => (int)(wt[Array.IndexOf(items, x)] * 10); + Func valueSelector = x => val[Array.IndexOf(items, x)]; - var expected = new[] { 1, 3, 5, 7, 8, 9, 14, 15 }; + var expected = new[] { 1, 3, 5, 7, 8, 9, 14, 15 }; - //Act - var solver = new DynamicProgrammingKnapsackSolver(); - var actual = solver.Solve(items, capacity * 10, weightSelector, valueSelector); + //Act + var solver = new DynamicProgrammingKnapsackSolver(); + var actual = solver.Solve(items, capacity * 10, weightSelector, valueSelector); - //Assert - Assert.AreEqual(expected.OrderBy(x => x), actual.OrderBy(x => x)); - } + //Assert + Assert.AreEqual(expected.OrderBy(x => x), actual.OrderBy(x => x)); + } - [Test] - public static void TakesHalf( - [Random(0, 1000, 100, Distinct = true)] - int length) - { - //Arrange - var solver = new DynamicProgrammingKnapsackSolver(); - var items = Enumerable.Repeat(42, 2 * length).ToArray(); - var expectedResult = Enumerable.Repeat(42, length); + [Test] + public static void TakesHalf( + [Random(0, 1000, 100, Distinct = true)] + int length) + { + //Arrange + var solver = new DynamicProgrammingKnapsackSolver(); + var items = Enumerable.Repeat(42, 2 * length).ToArray(); + var expectedResult = Enumerable.Repeat(42, length); - //Act - var result = solver.Solve(items, length, _ => 1, _ => 1); + //Act + var result = solver.Solve(items, length, _ => 1, _ => 1); - //Assert - Assert.AreEqual(expectedResult, result); - } + //Assert + Assert.AreEqual(expectedResult, result); } } diff --git a/Algorithms.Tests/Knapsack/NaiveKnapsackSolverTests.cs b/Algorithms.Tests/Knapsack/NaiveKnapsackSolverTests.cs index 97211d76..52d8b2cf 100644 --- a/Algorithms.Tests/Knapsack/NaiveKnapsackSolverTests.cs +++ b/Algorithms.Tests/Knapsack/NaiveKnapsackSolverTests.cs @@ -1,26 +1,25 @@ -using System.Linq; +using System.Linq; using Algorithms.Knapsack; using NUnit.Framework; -namespace Algorithms.Tests.Knapsack +namespace Algorithms.Tests.Knapsack; + +public static class NaiveKnapsackSolverTests { - public static class NaiveKnapsackSolverTests + [Test] + public static void TakesHalf( + [Random(0, 1000, 100, Distinct = true)] + int length) { - [Test] - public static void TakesHalf( - [Random(0, 1000, 100, Distinct = true)] - int length) - { - //Arrange - var solver = new NaiveKnapsackSolver(); - var items = Enumerable.Repeat(42, 2 * length).ToArray(); - var expectedResult = Enumerable.Repeat(42, length); + //Arrange + var solver = new NaiveKnapsackSolver(); + var items = Enumerable.Repeat(42, 2 * length).ToArray(); + var expectedResult = Enumerable.Repeat(42, length); - //Act - var result = solver.Solve(items, length, _ => 1, _ => 1); + //Act + var result = solver.Solve(items, length, _ => 1, _ => 1); - //Assert - Assert.AreEqual(expectedResult, result); - } + //Assert + Assert.AreEqual(expectedResult, result); } } diff --git a/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs b/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs index 72e9b7f8..0c13c19d 100644 --- a/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs +++ b/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs @@ -3,36 +3,35 @@ using FluentAssertions; using System; -namespace Algorithms.Tests.LinearAlgebra.Distances +namespace Algorithms.Tests.LinearAlgebra.Distances; + +public static class EuclideanTests { - public static class EuclideanTests + /// + /// Test the result given by Euclidean distance function. + /// + /// Origin point. + /// Target point. + /// Expected result. + [Test] + [TestCase(new[] { 1.5 }, new[] { -1.0 }, 2.5)] + [TestCase(new[] { 7.0, 4.0, 3.0 }, new[] { 17.0, 6.0, 2.0 }, 10.247)] + public static void DistanceTest(double[] point1, double[] point2, double expectedResult) { - /// - /// Test the result given by Euclidean distance function. - /// - /// Origin point. - /// Target point. - /// Expected result. - [Test] - [TestCase(new[] { 1.5 }, new[] { -1.0 }, 2.5)] - [TestCase(new[] { 7.0, 4.0, 3.0 }, new[] { 17.0, 6.0, 2.0 }, 10.247)] - public static void DistanceTest(double[] point1, double[] point2, double expectedResult) - { - Euclidean.Distance(point1, point2).Should().BeApproximately(expectedResult, 0.01); - } + Euclidean.Distance(point1, point2).Should().BeApproximately(expectedResult, 0.01); + } - /// - /// Throws ArgumentException if two different dimension arrays are given. - /// - /// First point of N dimensions. - /// Second point of M dimensions, M != N. - [Test] - [TestCase(new[] { 7.0, 4.5 }, new[] { -3.0 })] - [TestCase(new[] { 12.0 }, new[] { 1.5, 7.0, 3.2 })] - public static void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2) - { - Action action = () => Euclidean.Distance(point1, point2); - action.Should().Throw(); - } + /// + /// Throws ArgumentException if two different dimension arrays are given. + /// + /// First point of N dimensions. + /// Second point of M dimensions, M != N. + [Test] + [TestCase(new[] { 7.0, 4.5 }, new[] { -3.0 })] + [TestCase(new[] { 12.0 }, new[] { 1.5, 7.0, 3.2 })] + public static void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2) + { + Action action = () => Euclidean.Distance(point1, point2); + action.Should().Throw(); } } diff --git a/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs b/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs index 29f106cb..ed123cc2 100644 --- a/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs +++ b/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs @@ -3,38 +3,37 @@ using FluentAssertions; using System; -namespace Algorithms.Tests.LinearAlgebra.Distances +namespace Algorithms.Tests.LinearAlgebra.Distances; + +public class ManhattanTests { - public class ManhattanTests + /// + /// Test the result given by Manhattan distance function. + /// + /// Origin point. + /// Target point. + /// Expected result. + [Test] + [TestCase(new[] { 1.5 }, new[] { -1.0 }, 2.5)] + [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0, 5.0 }, 5)] + [TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 1.0, 2.0, 3.0 }, 0)] + [TestCase(new[] { 1.0, 2.0, 3.0, 4.0 }, new[] { 1.75, 2.25, -3.0, 0.5 }, 10.5)] + public void DistanceTest(double[] point1, double[] point2, double expectedDistance) { - /// - /// Test the result given by Manhattan distance function. - /// - /// Origin point. - /// Target point. - /// Expected result. - [Test] - [TestCase(new[] { 1.5 }, new[] { -1.0 }, 2.5)] - [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0, 5.0 }, 5)] - [TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 1.0, 2.0, 3.0 }, 0)] - [TestCase(new[] { 1.0, 2.0, 3.0, 4.0 }, new[] { 1.75, 2.25, -3.0, 0.5 }, 10.5)] - public void DistanceTest(double[] point1, double[] point2, double expectedDistance) - { - Manhattan.Distance(point1, point2).Should().BeApproximately(expectedDistance, 0.01); - } + Manhattan.Distance(point1, point2).Should().BeApproximately(expectedDistance, 0.01); + } - /// - /// Test that it throws ArgumentException if two different dimension arrays are given. - /// - /// First point of N dimensions. - /// Second point of M dimensions, M != N. - [Test] - [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0 })] - [TestCase(new[] { 1.0 }, new[] { 1.0, 2.0, 3.0 })] - public void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2) - { - Action action = () => Manhattan.Distance(point1, point2); - action.Should().Throw(); - } + /// + /// Test that it throws ArgumentException if two different dimension arrays are given. + /// + /// First point of N dimensions. + /// Second point of M dimensions, M != N. + [Test] + [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0 })] + [TestCase(new[] { 1.0 }, new[] { 1.0, 2.0, 3.0 })] + public void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2) + { + Action action = () => Manhattan.Distance(point1, point2); + action.Should().Throw(); } } diff --git a/Algorithms.Tests/LinearAlgebra/Eigenvalue/PowerIterationTests.cs b/Algorithms.Tests/LinearAlgebra/Eigenvalue/PowerIterationTests.cs index 9f571eae..10bf79df 100644 --- a/Algorithms.Tests/LinearAlgebra/Eigenvalue/PowerIterationTests.cs +++ b/Algorithms.Tests/LinearAlgebra/Eigenvalue/PowerIterationTests.cs @@ -4,71 +4,70 @@ using NUnit.Framework; using Utilities.Extensions; -namespace Algorithms.Tests.LinearAlgebra.Eigenvalue +namespace Algorithms.Tests.LinearAlgebra.Eigenvalue; + +public class PowerIterationTests { - public class PowerIterationTests + private static readonly object[] DominantVectorTestCases = { - private static readonly object[] DominantVectorTestCases = + new object[] { - new object[] - { - 3.0, - new[] { 0.7071039, 0.70710966 }, - new[,] { { 2.0, 1.0 }, { 1.0, 2.0 } }, - }, - new object[] - { - 4.235889, - new[] { 0.91287093, 0.40824829 }, - new[,] { { 2.0, 5.0 }, { 1.0, 2.0 } }, - }, - }; - - private readonly double epsilon = Math.Pow(10, -5); - - [Test] - public void Dominant_ShouldThrowArgumentException_WhenSourceMatrixIsNotSquareShaped() + 3.0, + new[] { 0.7071039, 0.70710966 }, + new[,] { { 2.0, 1.0 }, { 1.0, 2.0 } }, + }, + new object[] { - // Arrange - var source = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0, 0, 0 } }; + 4.235889, + new[] { 0.91287093, 0.40824829 }, + new[,] { { 2.0, 5.0 }, { 1.0, 2.0 } }, + }, + }; - // Act - Action action = () => PowerIteration.Dominant(source, StartVector(source.GetLength(0)), epsilon); + private readonly double epsilon = Math.Pow(10, -5); - // Assert - action.Should().Throw().WithMessage("The source matrix is not square-shaped."); - } + [Test] + public void Dominant_ShouldThrowArgumentException_WhenSourceMatrixIsNotSquareShaped() + { + // Arrange + var source = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0, 0, 0 } }; - [Test] - public void Dominant_ShouldThrowArgumentException_WhenStartVectorIsNotSameSizeAsMatrix() - { - // Arrange - var source = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; - var startVector = new double[] { 1, 0, 0, 0 }; + // Act + Action action = () => PowerIteration.Dominant(source, StartVector(source.GetLength(0)), epsilon); + + // Assert + action.Should().Throw().WithMessage("The source matrix is not square-shaped."); + } - // Act - Action action = () => PowerIteration.Dominant(source, startVector, epsilon); + [Test] + public void Dominant_ShouldThrowArgumentException_WhenStartVectorIsNotSameSizeAsMatrix() + { + // Arrange + var source = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; + var startVector = new double[] { 1, 0, 0, 0 }; - // Assert - action.Should().Throw() - .WithMessage("The length of the start vector doesn't equal the size of the source matrix."); - } + // Act + Action action = () => PowerIteration.Dominant(source, startVector, epsilon); - [TestCaseSource(nameof(DominantVectorTestCases))] - public void Dominant_ShouldCalculateDominantEigenvalueAndEigenvector( - double eigenvalue, - double[] eigenvector, - double[,] source) - { - // Act - var (actualEigVal, actualEigVec) = - PowerIteration.Dominant(source, StartVector(source.GetLength(0)), epsilon); + // Assert + action.Should().Throw() + .WithMessage("The length of the start vector doesn't equal the size of the source matrix."); + } - // Assert - actualEigVal.Should().BeApproximately(eigenvalue, epsilon); - actualEigVec.Magnitude().Should().BeApproximately(eigenvector.Magnitude(), epsilon); - } + [TestCaseSource(nameof(DominantVectorTestCases))] + public void Dominant_ShouldCalculateDominantEigenvalueAndEigenvector( + double eigenvalue, + double[] eigenvector, + double[,] source) + { + // Act + var (actualEigVal, actualEigVec) = + PowerIteration.Dominant(source, StartVector(source.GetLength(0)), epsilon); - private double[] StartVector(int length) => new Random(111111).NextVector(length); + // Assert + actualEigVal.Should().BeApproximately(eigenvalue, epsilon); + actualEigVec.Magnitude().Should().BeApproximately(eigenvector.Magnitude(), epsilon); } + + private double[] StartVector(int length) => new Random(111111).NextVector(length); } diff --git a/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs b/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs index 06289e3a..4104ac46 100644 --- a/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs +++ b/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs @@ -4,190 +4,189 @@ using System.Collections.Generic; using System.Numerics; -namespace Algorithms.Tests.ModularArithmetic +namespace Algorithms.Tests.ModularArithmetic; + +public static class ChineseRemainderTheoremTest { - public static class ChineseRemainderTheoremTest + [Test] + public static void TestCompute1() { - [Test] - public static void TestCompute1() - { - var expected = 43L; + var expected = 43L; - // Act - var x = ChineseRemainderTheorem.Compute(new List { 1L, 1L, 3L, 1L }, new List { 2L, 3L, 5L, 7L }); + // Act + var x = ChineseRemainderTheorem.Compute(new List { 1L, 1L, 3L, 1L }, new List { 2L, 3L, 5L, 7L }); - // Assert - Assert.AreEqual(expected, x); - } + // Assert + Assert.AreEqual(expected, x); + } - [Test] - public static void TestCompute2() - { - var expected = 100L; + [Test] + public static void TestCompute2() + { + var expected = 100L; + // Act + var x = ChineseRemainderTheorem.Compute(new List { 0L, 0L, 2L, 1L, 1L }, new List { 2L, 5L, 7L, 9L, 11L }); + + // Assert + Assert.AreEqual(expected, x); + } + + [Test] + public static void TestCompute3() + { + var expected = 13L; + + // Act + var x = ChineseRemainderTheorem.Compute(new List { 1L, 4L, 13L }, new List { 4L, 9L, 25L }); + + // Assert + Assert.AreEqual(expected, x); + } + + [Test] + public static void TestCompute_RequirementsNotMet_ArgumentLengthDifferent() + { + // Act + void Act() => ChineseRemainderTheorem.Compute(new List(), new List { 5L }); + + // Assert + _ = Assert.Throws(Act); + } + + [Test] + public static void TestCompute_RequirementsNotMet_NTooSmall() + { + foreach (var n in new List { long.MinValue, -1L, 0L, 1L }) + { // Act - var x = ChineseRemainderTheorem.Compute(new List { 0L, 0L, 2L, 1L, 1L }, new List { 2L, 5L, 7L, 9L, 11L }); + void Act() => ChineseRemainderTheorem.Compute(new List { 1L }, new List { n }); // Assert - Assert.AreEqual(expected, x); + _ = Assert.Throws(Act); } + } - [Test] - public static void TestCompute3() + [Test] + public static void TestCompute_RequirementsNotMet_ATooSmall() + { + foreach (var a in new List { long.MinValue, -2L, -1L }) { - var expected = 13L; - // Act - var x = ChineseRemainderTheorem.Compute(new List { 1L, 4L, 13L }, new List { 4L, 9L, 25L }); + void Act() => ChineseRemainderTheorem.Compute(new List { a }, new List { 3L }); // Assert - Assert.AreEqual(expected, x); + _ = Assert.Throws(Act); } + } - [Test] - public static void TestCompute_RequirementsNotMet_ArgumentLengthDifferent() + [Test] + public static void TestCompute_RequirementsNotMet_NNotCoprime() + { + foreach (var n in new List { 3L, 9L, 15L, 27L }) { // Act - void Act() => ChineseRemainderTheorem.Compute(new List(), new List { 5L }); + void Act() => ChineseRemainderTheorem.Compute(new List { 1L, 1L, 1L, 1L, 1L }, new List { 2L, 3L, 5L, 7L, n }); // Assert _ = Assert.Throws(Act); } + } - [Test] - public static void TestCompute_RequirementsNotMet_NTooSmall() - { - foreach (var n in new List { long.MinValue, -1L, 0L, 1L }) - { - // Act - void Act() => ChineseRemainderTheorem.Compute(new List { 1L }, new List { n }); - - // Assert - _ = Assert.Throws(Act); - } - } + [Test] + public static void TestCompute_BigInteger_1() + { + var expected = new BigInteger(43); - [Test] - public static void TestCompute_RequirementsNotMet_ATooSmall() - { - foreach (var a in new List { long.MinValue, -2L, -1L }) - { - // Act - void Act() => ChineseRemainderTheorem.Compute(new List { a }, new List { 3L }); - - // Assert - _ = Assert.Throws(Act); - } - } + // Act + var x = ChineseRemainderTheorem.Compute( + new List { BigInteger.One, BigInteger.One, new BigInteger(3), BigInteger.One }, + new List { new BigInteger(2), new BigInteger(3), new BigInteger(5), new BigInteger(7) } + ); - [Test] - public static void TestCompute_RequirementsNotMet_NNotCoprime() - { - foreach (var n in new List { 3L, 9L, 15L, 27L }) - { - // Act - void Act() => ChineseRemainderTheorem.Compute(new List { 1L, 1L, 1L, 1L, 1L }, new List { 2L, 3L, 5L, 7L, n }); - - // Assert - _ = Assert.Throws(Act); - } - } + // Assert + Assert.AreEqual(expected, x); + } - [Test] - public static void TestCompute_BigInteger_1() - { - var expected = new BigInteger(43); + [Test] + public static void TestCompute_BigInteger_2() + { + var expected = new BigInteger(100); - // Act - var x = ChineseRemainderTheorem.Compute( - new List { BigInteger.One, BigInteger.One, new BigInteger(3), BigInteger.One }, - new List { new BigInteger(2), new BigInteger(3), new BigInteger(5), new BigInteger(7) } - ); + // Act + var x = ChineseRemainderTheorem.Compute( + new List { BigInteger.Zero, BigInteger.Zero, new BigInteger(2), BigInteger.One, BigInteger.One }, + new List { new BigInteger(2), new BigInteger(5), new BigInteger(7), new BigInteger(9), new BigInteger(11) } + ); - // Assert - Assert.AreEqual(expected, x); - } + // Assert + Assert.AreEqual(expected, x); + } - [Test] - public static void TestCompute_BigInteger_2() - { - var expected = new BigInteger(100); + [Test] + public static void TestCompute_BigInteger_3() + { + var expected = new BigInteger(13); - // Act - var x = ChineseRemainderTheorem.Compute( - new List { BigInteger.Zero, BigInteger.Zero, new BigInteger(2), BigInteger.One, BigInteger.One }, - new List { new BigInteger(2), new BigInteger(5), new BigInteger(7), new BigInteger(9), new BigInteger(11) } - ); + // Act + var x = ChineseRemainderTheorem.Compute( + new List { BigInteger.One, new BigInteger(4), new BigInteger(13) }, + new List { new BigInteger(4), new BigInteger(9), new BigInteger(25) } + ); - // Assert - Assert.AreEqual(expected, x); - } + // Assert + Assert.AreEqual(expected, x); + } - [Test] - public static void TestCompute_BigInteger_3() - { - var expected = new BigInteger(13); + [Test] + public static void TestCompute_BigInteger_RequirementsNotMet_ArgumentLengthDifferent() + { + // Act + void Act() => ChineseRemainderTheorem.Compute(new List(), new List { new BigInteger(5) }); + + // Assert + _ = Assert.Throws(Act); + } + [Test] + public static void TestCompute_BigInteger_RequirementsNotMet_NTooSmall() + { + foreach (var n in new List { new BigInteger(long.MinValue), BigInteger.MinusOne, BigInteger.Zero, BigInteger.One }) + { // Act - var x = ChineseRemainderTheorem.Compute( - new List { BigInteger.One, new BigInteger(4), new BigInteger(13) }, - new List { new BigInteger(4), new BigInteger(9), new BigInteger(25) } - ); + void Act() => ChineseRemainderTheorem.Compute(new List { BigInteger.One }, new List { n }); // Assert - Assert.AreEqual(expected, x); + _ = Assert.Throws(Act); } + } - [Test] - public static void TestCompute_BigInteger_RequirementsNotMet_ArgumentLengthDifferent() + [Test] + public static void TestCompute_BigInteger_RequirementsNotMet_ATooSmall() + { + foreach (var a in new List { new BigInteger(long.MinValue), new BigInteger(-2), BigInteger.MinusOne }) { // Act - void Act() => ChineseRemainderTheorem.Compute(new List(), new List { new BigInteger(5) }); + void Act() => ChineseRemainderTheorem.Compute(new List { a }, new List { new BigInteger(3) }); // Assert _ = Assert.Throws(Act); } + } - [Test] - public static void TestCompute_BigInteger_RequirementsNotMet_NTooSmall() - { - foreach (var n in new List { new BigInteger(long.MinValue), BigInteger.MinusOne, BigInteger.Zero, BigInteger.One }) - { - // Act - void Act() => ChineseRemainderTheorem.Compute(new List { BigInteger.One }, new List { n }); - - // Assert - _ = Assert.Throws(Act); - } - } - - [Test] - public static void TestCompute_BigInteger_RequirementsNotMet_ATooSmall() + [Test] + public static void TestCompute_BigInteger_RequirementsNotMet_NNotCoprime() + { + foreach (var n in new List { new BigInteger(3), new BigInteger(9), new BigInteger(15), new BigInteger(27) }) { - foreach (var a in new List { new BigInteger(long.MinValue), new BigInteger(-2), BigInteger.MinusOne }) - { - // Act - void Act() => ChineseRemainderTheorem.Compute(new List { a }, new List { new BigInteger(3) }); - - // Assert - _ = Assert.Throws(Act); - } - } + // Act + void Act() => ChineseRemainderTheorem.Compute( + new List { BigInteger.One, BigInteger.One, BigInteger.One, BigInteger.One, BigInteger.One }, + new List { new BigInteger(2), new BigInteger(3), new BigInteger(5), new BigInteger(7), n } + ); - [Test] - public static void TestCompute_BigInteger_RequirementsNotMet_NNotCoprime() - { - foreach (var n in new List { new BigInteger(3), new BigInteger(9), new BigInteger(15), new BigInteger(27) }) - { - // Act - void Act() => ChineseRemainderTheorem.Compute( - new List { BigInteger.One, BigInteger.One, BigInteger.One, BigInteger.One, BigInteger.One }, - new List { new BigInteger(2), new BigInteger(3), new BigInteger(5), new BigInteger(7), n } - ); - - // Assert - _ = Assert.Throws(Act); - } + // Assert + _ = Assert.Throws(Act); } } } diff --git a/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs b/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs index aa9eaa33..03d3723a 100644 --- a/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs +++ b/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs @@ -2,54 +2,53 @@ using NUnit.Framework; using System.Numerics; -namespace Algorithms.Tests.ModularArithmetic +namespace Algorithms.Tests.ModularArithmetic; + +public static class ExtendedEuclideanAlgorithmTest { - public static class ExtendedEuclideanAlgorithmTest + [Test] + [TestCase(240, 46, 2, -9, 47)] + [TestCase(46, 240, 2, 47, -9)] + [TestCase(2, 3, 1, -1, 1)] + [TestCase(1, 1, 1, 0, 1)] + [TestCase(13, 17, 1, 4, -3)] + [TestCase(0, 17, 17, 0, 1)] + [TestCase(17, 0, 17, 1, 0)] + [TestCase(17, 17, 17, 0, 1)] + [TestCase(2 * 17, 17, 17, 0, 1)] + [TestCase(0, 0, 0, 1, 0)] + [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13, -1, 1)] + public static void TestCompute(long a, long b, long expectedGCD, long expectedBezoutOfA, long expectedBezoutOfB) { - [Test] - [TestCase(240, 46, 2, -9, 47)] - [TestCase(46, 240, 2, 47, -9)] - [TestCase(2, 3, 1, -1, 1)] - [TestCase(1, 1, 1, 0, 1)] - [TestCase(13, 17, 1, 4, -3)] - [TestCase(0, 17, 17, 0, 1)] - [TestCase(17, 0, 17, 1, 0)] - [TestCase(17, 17, 17, 0, 1)] - [TestCase(2 * 17, 17, 17, 0, 1)] - [TestCase(0, 0, 0, 1, 0)] - [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13, -1, 1)] - public static void TestCompute(long a, long b, long expectedGCD, long expectedBezoutOfA, long expectedBezoutOfB) - { - // Act - var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, b); + // Act + var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, b); - // Assert - Assert.AreEqual(expectedGCD, eeaResult.gcd); - Assert.AreEqual(expectedBezoutOfA, eeaResult.bezoutA); - Assert.AreEqual(expectedBezoutOfB, eeaResult.bezoutB); - } + // Assert + Assert.AreEqual(expectedGCD, eeaResult.gcd); + Assert.AreEqual(expectedBezoutOfA, eeaResult.bezoutA); + Assert.AreEqual(expectedBezoutOfB, eeaResult.bezoutB); + } - [Test] - [TestCase(240, 46, 2, -9, 47)] - [TestCase(46, 240, 2, 47, -9)] - [TestCase(2, 3, 1, -1, 1)] - [TestCase(1, 1, 1, 0, 1)] - [TestCase(13, 17, 1, 4, -3)] - [TestCase(0, 17, 17, 0, 1)] - [TestCase(17, 0, 17, 1, 0)] - [TestCase(17, 17, 17, 0, 1)] - [TestCase(2 * 17, 17, 17, 0, 1)] - [TestCase(0, 0, 0, 1, 0)] - [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13, -1, 1)] - public static void TestCompute_BigInteger(long a, long b, long expectedGCD, long expectedBezoutOfA, long expectedBezoutOfB) - { - // Act - var eeaResult = ExtendedEuclideanAlgorithm.Compute(new BigInteger(a), new BigInteger(b)); + [Test] + [TestCase(240, 46, 2, -9, 47)] + [TestCase(46, 240, 2, 47, -9)] + [TestCase(2, 3, 1, -1, 1)] + [TestCase(1, 1, 1, 0, 1)] + [TestCase(13, 17, 1, 4, -3)] + [TestCase(0, 17, 17, 0, 1)] + [TestCase(17, 0, 17, 1, 0)] + [TestCase(17, 17, 17, 0, 1)] + [TestCase(2 * 17, 17, 17, 0, 1)] + [TestCase(0, 0, 0, 1, 0)] + [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13, -1, 1)] + public static void TestCompute_BigInteger(long a, long b, long expectedGCD, long expectedBezoutOfA, long expectedBezoutOfB) + { + // Act + var eeaResult = ExtendedEuclideanAlgorithm.Compute(new BigInteger(a), new BigInteger(b)); - // Assert - Assert.AreEqual(new BigInteger(expectedGCD), eeaResult.gcd); - Assert.AreEqual(new BigInteger(expectedBezoutOfA), eeaResult.bezoutA); - Assert.AreEqual(new BigInteger(expectedBezoutOfB), eeaResult.bezoutB); - } + // Assert + Assert.AreEqual(new BigInteger(expectedGCD), eeaResult.gcd); + Assert.AreEqual(new BigInteger(expectedBezoutOfA), eeaResult.bezoutA); + Assert.AreEqual(new BigInteger(expectedBezoutOfB), eeaResult.bezoutB); } } diff --git a/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs b/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs index 37d2de0a..0a7b4982 100644 --- a/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs +++ b/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs @@ -3,66 +3,65 @@ using System; using System.Numerics; -namespace Algorithms.Tests.ModularArithmetic +namespace Algorithms.Tests.ModularArithmetic; + +public static class ModularMultiplicativeInverseTest { - public static class ModularMultiplicativeInverseTest + [Test] + [TestCase(2, 3, 2)] + [TestCase(1, 1, 0)] + [TestCase(13, 17, 4)] + public static void TestCompute(long a, long n, long expected) { - [Test] - [TestCase(2, 3, 2)] - [TestCase(1, 1, 0)] - [TestCase(13, 17, 4)] - public static void TestCompute(long a, long n, long expected) - { - // Act - var inverse = ModularMultiplicativeInverse.Compute(a, n); + // Act + var inverse = ModularMultiplicativeInverse.Compute(a, n); - // Assert - Assert.AreEqual(expected, inverse); - } + // Assert + Assert.AreEqual(expected, inverse); + } - [Test] - [TestCase(46, 240)] - [TestCase(0, 17)] - [TestCase(17, 0)] - [TestCase(17, 17)] - [TestCase(0, 0)] - [TestCase(2 * 13 * 17, 4 * 9 * 13)] - public static void TestCompute_Irrevertible(long a, long n) - { - // Act - void Act() => ModularMultiplicativeInverse.Compute(a, n); + [Test] + [TestCase(46, 240)] + [TestCase(0, 17)] + [TestCase(17, 0)] + [TestCase(17, 17)] + [TestCase(0, 0)] + [TestCase(2 * 13 * 17, 4 * 9 * 13)] + public static void TestCompute_Irrevertible(long a, long n) + { + // Act + void Act() => ModularMultiplicativeInverse.Compute(a, n); - // Assert - _ = Assert.Throws(Act); - } + // Assert + _ = Assert.Throws(Act); + } - [Test] - [TestCase(2, 3, 2)] - [TestCase(1, 1, 0)] - [TestCase(13, 17, 4)] - public static void TestCompute_BigInteger(long a, long n, long expected) - { - // Act - var inverse = ModularMultiplicativeInverse.Compute(new BigInteger(a), new BigInteger(n)); + [Test] + [TestCase(2, 3, 2)] + [TestCase(1, 1, 0)] + [TestCase(13, 17, 4)] + public static void TestCompute_BigInteger(long a, long n, long expected) + { + // Act + var inverse = ModularMultiplicativeInverse.Compute(new BigInteger(a), new BigInteger(n)); - // Assert - Assert.AreEqual(new BigInteger(expected), inverse); - } + // Assert + Assert.AreEqual(new BigInteger(expected), inverse); + } - [Test] - [TestCase(46, 240)] - [TestCase(0, 17)] - [TestCase(17, 0)] - [TestCase(17, 17)] - [TestCase(0, 0)] - [TestCase(2 * 13 * 17, 4 * 9 * 13)] - public static void TestCompute_BigInteger_Irrevertible(long a, long n) - { - // Act - void Act() => ModularMultiplicativeInverse.Compute(new BigInteger(a), new BigInteger(n)); + [Test] + [TestCase(46, 240)] + [TestCase(0, 17)] + [TestCase(17, 0)] + [TestCase(17, 17)] + [TestCase(0, 0)] + [TestCase(2 * 13 * 17, 4 * 9 * 13)] + public static void TestCompute_BigInteger_Irrevertible(long a, long n) + { + // Act + void Act() => ModularMultiplicativeInverse.Compute(new BigInteger(a), new BigInteger(n)); - // Assert - _ = Assert.Throws(Act); - } + // Assert + _ = Assert.Throws(Act); } } diff --git a/Algorithms.Tests/Numeric/AliquotSumCalculatorTests.cs b/Algorithms.Tests/Numeric/AliquotSumCalculatorTests.cs index c60b2c51..87057811 100644 --- a/Algorithms.Tests/Numeric/AliquotSumCalculatorTests.cs +++ b/Algorithms.Tests/Numeric/AliquotSumCalculatorTests.cs @@ -1,37 +1,36 @@ -using System; +using System; using Algorithms.Numeric; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class AliquotSumCalculatorTests { - public static class AliquotSumCalculatorTests + [Test] + [TestCase(1, 0)] + [TestCase(3, 1)] + [TestCase(25, 6)] + [TestCase(99, 57)] + public static void CalculateSum_SumIsCorrect(int number, int expectedSum) { - [Test] - [TestCase(1, 0)] - [TestCase(3, 1)] - [TestCase(25, 6)] - [TestCase(99, 57)] - public static void CalculateSum_SumIsCorrect(int number, int expectedSum) - { - // Arrange + // Arrange - // Act - var result = AliquotSumCalculator.CalculateAliquotSum(number); + // Act + var result = AliquotSumCalculator.CalculateAliquotSum(number); - // Assert - result.Should().Be(expectedSum); - } + // Assert + result.Should().Be(expectedSum); + } - [Test] - [TestCase(-2)] - public static void CalculateSum_NegativeInput_ExceptionIsThrown(int number) - { - // Arrange - Action act = () => AliquotSumCalculator.CalculateAliquotSum(number); + [Test] + [TestCase(-2)] + public static void CalculateSum_NegativeInput_ExceptionIsThrown(int number) + { + // Arrange + Action act = () => AliquotSumCalculator.CalculateAliquotSum(number); - // Assert - act.Should().Throw(); - } + // Assert + act.Should().Throw(); } } diff --git a/Algorithms.Tests/Numeric/AmicableNumbersTest.cs b/Algorithms.Tests/Numeric/AmicableNumbersTest.cs index 1ece5f3d..8eb61f4f 100644 --- a/Algorithms.Tests/Numeric/AmicableNumbersTest.cs +++ b/Algorithms.Tests/Numeric/AmicableNumbersTest.cs @@ -1,29 +1,23 @@ using Algorithms.Numeric; using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class AmicableNumbersTest { - public static class AmicableNumbersTest + [Test] + [TestCase(220, 284)] + [TestCase(1184, 1210)] + [TestCase(2620, 2924)] + [TestCase(5020, 5564)] + public static void AmicableNumbersChecker_Test(int x, int y) { - [Test] - [TestCase(220, 284)] - [TestCase(1184, 1210)] - [TestCase(2620, 2924)] - [TestCase(5020, 5564)] - public static void AmicableNumbersChecker_Test(int x, int y) - { - // Arrange + // Arrange - // Act - var result = AmicableNumbersChecker.AreAmicableNumbers(x, y); + // Act + var result = AmicableNumbersChecker.AreAmicableNumbers(x, y); - // Assert - Assert.IsTrue(result); - } + // Assert + Assert.IsTrue(result); } } diff --git a/Algorithms.Tests/Numeric/AutomorphicNumberTests.cs b/Algorithms.Tests/Numeric/AutomorphicNumberTests.cs index e07274a2..443b8ea9 100644 --- a/Algorithms.Tests/Numeric/AutomorphicNumberTests.cs +++ b/Algorithms.Tests/Numeric/AutomorphicNumberTests.cs @@ -3,112 +3,111 @@ using System; using System.Collections.Generic; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public class AutomorphicNumberTests { - public class AutomorphicNumberTests + [TestCase(1)] + [TestCase(5)] + [TestCase(6)] + [TestCase(25)] + [TestCase(76)] + [TestCase(376)] + [TestCase(625)] + [TestCase(9376)] + [TestCase(90625)] + [TestCase(109376)] + + public void TestAutomorphicNumbers(int number) { - [TestCase(1)] - [TestCase(5)] - [TestCase(6)] - [TestCase(25)] - [TestCase(76)] - [TestCase(376)] - [TestCase(625)] - [TestCase(9376)] - [TestCase(90625)] - [TestCase(109376)] - - public void TestAutomorphicNumbers(int number) - { - Assert.That(AutomorphicNumber.IsAutomorphic(number), Is.True); - } + Assert.That(AutomorphicNumber.IsAutomorphic(number), Is.True); + } - [TestCase(2)] - [TestCase(3)] - [TestCase(7)] - [TestCase(18)] - [TestCase(79)] - [TestCase(356)] - [TestCase(623)] - [TestCase(9876)] - [TestCase(90635)] - [TestCase(119376)] - [TestCase(891625)] - [TestCase(2990625)] - [TestCase(7209376)] - [TestCase(12891625)] - [TestCase(87129396)] - public void TestNonAutomorphicNumbers(int number) - { - Assert.That(AutomorphicNumber.IsAutomorphic(number), Is.False); - } + [TestCase(2)] + [TestCase(3)] + [TestCase(7)] + [TestCase(18)] + [TestCase(79)] + [TestCase(356)] + [TestCase(623)] + [TestCase(9876)] + [TestCase(90635)] + [TestCase(119376)] + [TestCase(891625)] + [TestCase(2990625)] + [TestCase(7209376)] + [TestCase(12891625)] + [TestCase(87129396)] + public void TestNonAutomorphicNumbers(int number) + { + Assert.That(AutomorphicNumber.IsAutomorphic(number), Is.False); + } - [TestCase(0)] - [TestCase(-1)] - public void TestInvalidAutomorphicNumbers(int number) - { - Assert.Throws(Is.TypeOf() - .And.Message.EqualTo($"An automorphic number must always be positive."), - delegate - { - AutomorphicNumber.IsAutomorphic(number); - }); - } + [TestCase(0)] + [TestCase(-1)] + public void TestInvalidAutomorphicNumbers(int number) + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo($"An automorphic number must always be positive."), + delegate + { + AutomorphicNumber.IsAutomorphic(number); + }); + } - [TestCase(1, 100)] - public void TestAutomorphicNumberSequence(int lower, int upper) - { - List automorphicList = new() { 1, 5, 6, 25, 76 }; - Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList)); - } + [TestCase(1, 100)] + public void TestAutomorphicNumberSequence(int lower, int upper) + { + List automorphicList = new() { 1, 5, 6, 25, 76 }; + Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList)); + } - [TestCase(8, 12)] - public void TestNoAutomorphicNumberInTheSequence(int lower, int upper) - { - List automorphicList = new(); - Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList)); - } + [TestCase(8, 12)] + public void TestNoAutomorphicNumberInTheSequence(int lower, int upper) + { + List automorphicList = new(); + Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList)); + } - [TestCase(25,25)] - public void TestAutomorphicNumberSequenceSameBounds(int lower, int upper) - { - List automorphicList = new() { 25 }; - Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList)); - } + [TestCase(25,25)] + public void TestAutomorphicNumberSequenceSameBounds(int lower, int upper) + { + List automorphicList = new() { 25 }; + Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList)); + } - [TestCase(-1,1)] - [TestCase(0, 1)] - public void TestAutomorphicNumberSequenceInvalidLowerBound(int lower, int upper) - { - Assert.Throws(Is.TypeOf() - .And.Message.EqualTo($"Lower bound must be greater than 0."), - delegate - { - AutomorphicNumber.GetAutomorphicNumbers(lower, upper); - }); - } + [TestCase(-1,1)] + [TestCase(0, 1)] + public void TestAutomorphicNumberSequenceInvalidLowerBound(int lower, int upper) + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo($"Lower bound must be greater than 0."), + delegate + { + AutomorphicNumber.GetAutomorphicNumbers(lower, upper); + }); + } - [TestCase(1, -1)] - [TestCase(10, -1)] - public void TestAutomorphicNumberSequenceInvalidUpperBound(int lower, int upper) - { - Assert.Throws(Is.TypeOf() - .And.Message.EqualTo($"Upper bound must be greater than 0."), - delegate - { - AutomorphicNumber.GetAutomorphicNumbers(lower, upper); - }); - } + [TestCase(1, -1)] + [TestCase(10, -1)] + public void TestAutomorphicNumberSequenceInvalidUpperBound(int lower, int upper) + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo($"Upper bound must be greater than 0."), + delegate + { + AutomorphicNumber.GetAutomorphicNumbers(lower, upper); + }); + } - [TestCase(25, 2)] - public void TestAutomorphicNumberSequenceReversedBounds(int lower, int upper) - { - Assert.Throws(Is.TypeOf() - .And.Message.EqualTo($"The lower bound must be less than or equal to the upper bound."), - delegate - { - AutomorphicNumber.GetAutomorphicNumbers(lower, upper); - }); - } + [TestCase(25, 2)] + public void TestAutomorphicNumberSequenceReversedBounds(int lower, int upper) + { + Assert.Throws(Is.TypeOf() + .And.Message.EqualTo($"The lower bound must be less than or equal to the upper bound."), + delegate + { + AutomorphicNumber.GetAutomorphicNumbers(lower, upper); + }); } } diff --git a/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs b/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs index 01614dd5..a08a9204 100644 --- a/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs +++ b/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs @@ -3,33 +3,32 @@ using Algorithms.Numeric; using NUnit.Framework; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class BinomialCoefficientTests { - public static class BinomialCoefficientTests + [TestCase(4, 2, 6)] + [TestCase(7, 3, 35)] + public static void CalculateFromPairs(int n, int k, int expected) { - [TestCase(4, 2, 6)] - [TestCase(7, 3, 35)] - public static void CalculateFromPairs(int n, int k, int expected) - { - // Arrange + // Arrange - // Act - var result = BinomialCoefficient.Calculate(new BigInteger(n), new BigInteger(k)); + // Act + var result = BinomialCoefficient.Calculate(new BigInteger(n), new BigInteger(k)); - // Assert - Assert.AreEqual(new BigInteger(expected), result); - } + // Assert + Assert.AreEqual(new BigInteger(expected), result); + } - [Test] - [TestCase(3, 7)] - public static void TeoremCalculateThrowsException(int n, int k) - { - // Arrange + [Test] + [TestCase(3, 7)] + public static void TeoremCalculateThrowsException(int n, int k) + { + // Arrange - // Act + // Act - // Assert - _ = Assert.Throws(() => BinomialCoefficient.Calculate(new BigInteger(n), new BigInteger(k))); - } + // Assert + _ = Assert.Throws(() => BinomialCoefficient.Calculate(new BigInteger(n), new BigInteger(k))); } } diff --git a/Algorithms.Tests/Numeric/Decomposition/LUTests.cs b/Algorithms.Tests/Numeric/Decomposition/LUTests.cs index d119caac..2a34c484 100644 --- a/Algorithms.Tests/Numeric/Decomposition/LUTests.cs +++ b/Algorithms.Tests/Numeric/Decomposition/LUTests.cs @@ -4,143 +4,142 @@ using NUnit.Framework; using Utilities.Extensions; -namespace Algorithms.Tests.Numeric.Decomposition +namespace Algorithms.Tests.Numeric.Decomposition; + +public class LuTests { - public class LuTests + private readonly double epsilon = Math.Pow(10, -6); + + [Test] + public void DecomposeIdentityMatrix() { - private readonly double epsilon = Math.Pow(10, -6); + // Arrange + var identityMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; + var expectedLower = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; + var expectedUpper = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; + + // Act + (double[,] lower, double[,] upper) = Lu.Decompose(identityMatrix); + + // Assert + Assert.AreEqual(expectedLower, lower); + Assert.AreEqual(expectedUpper, upper); + Assert.AreEqual(lower.Multiply(upper), identityMatrix); + } - [Test] - public void DecomposeIdentityMatrix() - { - // Arrange - var identityMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; - var expectedLower = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; - var expectedUpper = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; - - // Act - (double[,] lower, double[,] upper) = Lu.Decompose(identityMatrix); - - // Assert - Assert.AreEqual(expectedLower, lower); - Assert.AreEqual(expectedUpper, upper); - Assert.AreEqual(lower.Multiply(upper), identityMatrix); - } - - [Test] - public void DecomposeMatrix_Case3X3() - { - // Arrange - var source = new double[,] { { 2, 1, 4 }, { 7, 1, 1 }, { 4, 2, 9 } }; - var expectedLower = new[,] { { 1, 0, 0 }, { 3.5, 1, 0 }, { 2, 0, 1 } }; - var expectedUpper = new[,] { { 2, 1, 4 }, { 0, -2.5, -13 }, { 0, 0, 1 } }; - - // Act - (double[,] lower, double[,] upper) = Lu.Decompose(source); - - // Assert - Assert.AreEqual(expectedLower, lower); - Assert.AreEqual(expectedUpper, upper); - Assert.AreEqual(lower.Multiply(upper), source); - } - - [Test] - public void DecomposeMatrix_Case4X4() - { - // Arrange - var source = new[,] { { 1, 2, 4.5, 7 }, { 3, 8, 0.5, 2 }, { 2, 6, 4, 1.5 }, { 4, 14, 2, 10.5 } }; - var expectedLower = new[,] { { 1, 0, 0, 0 }, { 3, 1, 0, 0 }, { 2, 1, 1, 0 }, { 4, 3, 2.875, 1 } }; - var expectedUpper = new[,] { { 1, 2, 4.5, 7 }, { 0, 2, -13, -19 }, { 0, 0, 8, 6.5 }, { 0, 0, 0, 20.8125 } }; - - // Act - (double[,] lower, double[,] upper) = Lu.Decompose(source); - - // Assert - Assert.AreEqual(expectedLower, lower); - Assert.AreEqual(expectedUpper, upper); - Assert.AreEqual(lower.Multiply(upper), source); - } - - [Test] - public void FailOnDecomposeNonSquareMatrix() - { - // Arrange - var nonSquareMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0, 0, 0 } }; + [Test] + public void DecomposeMatrix_Case3X3() + { + // Arrange + var source = new double[,] { { 2, 1, 4 }, { 7, 1, 1 }, { 4, 2, 9 } }; + var expectedLower = new[,] { { 1, 0, 0 }, { 3.5, 1, 0 }, { 2, 0, 1 } }; + var expectedUpper = new[,] { { 2, 1, 4 }, { 0, -2.5, -13 }, { 0, 0, 1 } }; + + // Act + (double[,] lower, double[,] upper) = Lu.Decompose(source); + + // Assert + Assert.AreEqual(expectedLower, lower); + Assert.AreEqual(expectedUpper, upper); + Assert.AreEqual(lower.Multiply(upper), source); + } - // Act - void Act(double[,] source) => Lu.Decompose(source); + [Test] + public void DecomposeMatrix_Case4X4() + { + // Arrange + var source = new[,] { { 1, 2, 4.5, 7 }, { 3, 8, 0.5, 2 }, { 2, 6, 4, 1.5 }, { 4, 14, 2, 10.5 } }; + var expectedLower = new[,] { { 1, 0, 0, 0 }, { 3, 1, 0, 0 }, { 2, 1, 1, 0 }, { 4, 3, 2.875, 1 } }; + var expectedUpper = new[,] { { 1, 2, 4.5, 7 }, { 0, 2, -13, -19 }, { 0, 0, 8, 6.5 }, { 0, 0, 0, 20.8125 } }; + + // Act + (double[,] lower, double[,] upper) = Lu.Decompose(source); + + // Assert + Assert.AreEqual(expectedLower, lower); + Assert.AreEqual(expectedUpper, upper); + Assert.AreEqual(lower.Multiply(upper), source); + } - // Assert - Assert.Throws(() => Act(nonSquareMatrix)); - } + [Test] + public void FailOnDecomposeNonSquareMatrix() + { + // Arrange + var nonSquareMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0, 0, 0 } }; - [Test] - public void EliminateIdentityEquation() - { - // Arrange - var identityMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; - var coefficients = new double[] { 1, 2, 3 }; + // Act + void Act(double[,] source) => Lu.Decompose(source); - // Act - var solution = Lu.Eliminate(identityMatrix, coefficients); + // Assert + Assert.Throws(() => Act(nonSquareMatrix)); + } - // Assert - Assert.AreEqual(coefficients, solution); - } + [Test] + public void EliminateIdentityEquation() + { + // Arrange + var identityMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; + var coefficients = new double[] { 1, 2, 3 }; - [Test] - public void EliminateEquation_Case3X3() - { - // Arrange - var source = new double[,] { { 2, 1, -1 }, { -3, -1, 2 }, { -2, 1, 2 } }; - var coefficients = new double[] { 8, -11, -3 }; - var expectedSolution = new double[] { 2, 3, -1 }; + // Act + var solution = Lu.Eliminate(identityMatrix, coefficients); - // Act - var solution = Lu.Eliminate(source, coefficients); + // Assert + Assert.AreEqual(coefficients, solution); + } - // Assert - Assert.IsTrue(VectorMembersAreEqual(expectedSolution, solution)); - } + [Test] + public void EliminateEquation_Case3X3() + { + // Arrange + var source = new double[,] { { 2, 1, -1 }, { -3, -1, 2 }, { -2, 1, 2 } }; + var coefficients = new double[] { 8, -11, -3 }; + var expectedSolution = new double[] { 2, 3, -1 }; - [Test] - public void EliminateEquation_Case4X4() - { - // Arrange - var source = new[,] - { - { 1.0, 2.0, -3.0, -1.0 }, - { 0.0, -3.0, 2.0, 6.0 }, - { 0.0, 5.0, -6.0, -2.0 }, - { 0.0, -1.0, 8.0, 1.0 }, - }; - var coefficients = new[] { 0.0, -8.0, 0.0, -8.0 }; - var expectedSolution = new[] { -1.0, -2.0, -1.0, -2.0 }; - - // Act - var solution = Lu.Eliminate(source, coefficients); - - // Assert - Assert.IsTrue(VectorMembersAreEqual(expectedSolution, solution)); - } - - [Test] - public void FailOnEliminateEquationWithNonSquareMatrix() + // Act + var solution = Lu.Eliminate(source, coefficients); + + // Assert + Assert.IsTrue(VectorMembersAreEqual(expectedSolution, solution)); + } + + [Test] + public void EliminateEquation_Case4X4() + { + // Arrange + var source = new[,] { - // Arrange - var nonSquareMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0, 0, 0 } }; - var coefficients = new double[] { 1, 2, 3, 4 }; + { 1.0, 2.0, -3.0, -1.0 }, + { 0.0, -3.0, 2.0, 6.0 }, + { 0.0, 5.0, -6.0, -2.0 }, + { 0.0, -1.0, 8.0, 1.0 }, + }; + var coefficients = new[] { 0.0, -8.0, 0.0, -8.0 }; + var expectedSolution = new[] { -1.0, -2.0, -1.0, -2.0 }; + + // Act + var solution = Lu.Eliminate(source, coefficients); + + // Assert + Assert.IsTrue(VectorMembersAreEqual(expectedSolution, solution)); + } - // Act - void Act(double[,] source, double[] c) => Lu.Eliminate(source, c); + [Test] + public void FailOnEliminateEquationWithNonSquareMatrix() + { + // Arrange + var nonSquareMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0, 0, 0 } }; + var coefficients = new double[] { 1, 2, 3, 4 }; - // Assert - Assert.Throws(() => Act(nonSquareMatrix, coefficients)); - } + // Act + void Act(double[,] source, double[] c) => Lu.Eliminate(source, c); - private bool VectorMembersAreEqual(double[] expected, double[] actual) => - expected - .Zip(actual, (e, a) => new { Expected = e, Actual = a }) - .All(pair => Math.Abs(pair.Expected - pair.Actual) < epsilon); + // Assert + Assert.Throws(() => Act(nonSquareMatrix, coefficients)); } + + private bool VectorMembersAreEqual(double[] expected, double[] actual) => + expected + .Zip(actual, (e, a) => new { Expected = e, Actual = a }) + .All(pair => Math.Abs(pair.Expected - pair.Actual) < epsilon); } diff --git a/Algorithms.Tests/Numeric/Decomposition/MaclaurinTests.cs b/Algorithms.Tests/Numeric/Decomposition/MaclaurinTests.cs index 990a8bf8..9a2f9935 100644 --- a/Algorithms.Tests/Numeric/Decomposition/MaclaurinTests.cs +++ b/Algorithms.Tests/Numeric/Decomposition/MaclaurinTests.cs @@ -2,130 +2,129 @@ using Algorithms.Numeric.Series; using NUnit.Framework; -namespace Algorithms.Tests.Numeric.Decomposition +namespace Algorithms.Tests.Numeric.Decomposition; + +public class MaclaurinTests { - public class MaclaurinTests + [TestCase(0.01, 3, 0.01)] + [TestCase(1, 7, 0.001)] + [TestCase(-1.2, 7, 0.001)] + public void Exp_TermsForm_ValidCases(double point, int terms, double expectedError) + { + // Arrange + var expected = Math.Exp(point); + + // Act + var actual = Maclaurin.Exp(point, terms); + + // Assert + Assert.IsTrue(Math.Abs(expected - actual) < expectedError); + } + + [Test] + public void Exp_TermsForm_InvalidCase() => + Assert.Throws(() => Maclaurin.Exp(0, -1)); + + [TestCase(0, 1, 0.001)] + [TestCase(1, 7, 0.001)] + [TestCase(1.57, 7, 0.001)] + [TestCase(3.14, 7, 0.001)] + public void Sin_TermsForm_ValidCases(double point, int terms, double expectedError) + { + // Arrange + var expected = Math.Sin(point); + + // Act + var actual = Maclaurin.Sin(point, terms); + + // Assert + Assert.IsTrue(Math.Abs(expected - actual) < expectedError); + } + + [Test] + public void Sin_TermsForm_InvalidCase() => + Assert.Throws(() => Maclaurin.Sin(0, -1)); + + [TestCase(0, 1, 0.001)] + [TestCase(1, 7, 0.001)] + [TestCase(1.57, 7, 0.001)] + [TestCase(3.14, 7, 0.001)] + public void Cos_TermsForm_ValidCases(double point, int terms, double expectedError) + { + // Arrange + var expected = Math.Cos(point); + + // Act + var actual = Maclaurin.Cos(point, terms); + + // Assert + Assert.IsTrue(Math.Abs(expected - actual) < expectedError); + } + + [Test] + public void Cos_TermsForm_InvalidCase() => + Assert.Throws(() => Maclaurin.Cos(0, -1)); + + [TestCase(0.1, 0.001)] + [TestCase(0.1, 0.00001)] + [TestCase(2.1, 0.001)] + [TestCase(-1.2, 0.001)] + public void Exp_ErrorForm_ValidCases(double point, double error) { - [TestCase(0.01, 3, 0.01)] - [TestCase(1, 7, 0.001)] - [TestCase(-1.2, 7, 0.001)] - public void Exp_TermsForm_ValidCases(double point, int terms, double expectedError) - { - // Arrange - var expected = Math.Exp(point); - - // Act - var actual = Maclaurin.Exp(point, terms); - - // Assert - Assert.IsTrue(Math.Abs(expected - actual) < expectedError); - } - - [Test] - public void Exp_TermsForm_InvalidCase() => - Assert.Throws(() => Maclaurin.Exp(0, -1)); - - [TestCase(0, 1, 0.001)] - [TestCase(1, 7, 0.001)] - [TestCase(1.57, 7, 0.001)] - [TestCase(3.14, 7, 0.001)] - public void Sin_TermsForm_ValidCases(double point, int terms, double expectedError) - { - // Arrange - var expected = Math.Sin(point); - - // Act - var actual = Maclaurin.Sin(point, terms); - - // Assert - Assert.IsTrue(Math.Abs(expected - actual) < expectedError); - } - - [Test] - public void Sin_TermsForm_InvalidCase() => - Assert.Throws(() => Maclaurin.Sin(0, -1)); - - [TestCase(0, 1, 0.001)] - [TestCase(1, 7, 0.001)] - [TestCase(1.57, 7, 0.001)] - [TestCase(3.14, 7, 0.001)] - public void Cos_TermsForm_ValidCases(double point, int terms, double expectedError) - { - // Arrange - var expected = Math.Cos(point); - - // Act - var actual = Maclaurin.Cos(point, terms); - - // Assert - Assert.IsTrue(Math.Abs(expected - actual) < expectedError); - } - - [Test] - public void Cos_TermsForm_InvalidCase() => - Assert.Throws(() => Maclaurin.Cos(0, -1)); - - [TestCase(0.1, 0.001)] - [TestCase(0.1, 0.00001)] - [TestCase(2.1, 0.001)] - [TestCase(-1.2, 0.001)] - public void Exp_ErrorForm_ValidCases(double point, double error) - { - // Arrange - var expected = Math.Exp(point); - - // Act - var actual = Maclaurin.Exp(point, error); - - // Assert - Assert.IsTrue(Math.Abs(expected - actual) < error); - } - - [TestCase(0.0)] - [TestCase(1.0)] - public void Exp_ErrorForm_InvalidCases(double error) => - Assert.Throws(() => Maclaurin.Exp(0.0, error)); - - [TestCase(0, 0.001)] - [TestCase(1, 0.00001)] - [TestCase(1.57, 0.0001)] - [TestCase(3.14, 0.0001)] - public void Sin_ErrorForm_ValidCases(double point, double error) - { - // Arrange - var expected = Math.Sin(point); - - // Act - var actual = Maclaurin.Sin(point, error); - - // Assert - Assert.IsTrue(Math.Abs(expected - actual) < error); - } - - [TestCase(0.0)] - [TestCase(1.0)] - public void Sin_ErrorForm_InvalidCases(double error) => - Assert.Throws(() => Maclaurin.Sin(0.0, error)); - - [TestCase(0, 0.001)] - [TestCase(1, 0.00001)] - [TestCase(1.57, 0.0001)] - [TestCase(3.14, 0.0001)] - public void Cos_ErrorForm_ValidCases(double point, double error) - { - // Arrange - var expected = Math.Cos(point); - - // Act - var actual = Maclaurin.Cos(point, error); - - // Assert - Assert.IsTrue(Math.Abs(expected - actual) < error); - } - - [TestCase(0.0)] - [TestCase(1.0)] - public void Cos_ErrorForm_InvalidCases(double error) => - Assert.Throws(() => Maclaurin.Cos(0.0, error)); + // Arrange + var expected = Math.Exp(point); + + // Act + var actual = Maclaurin.Exp(point, error); + + // Assert + Assert.IsTrue(Math.Abs(expected - actual) < error); } + + [TestCase(0.0)] + [TestCase(1.0)] + public void Exp_ErrorForm_InvalidCases(double error) => + Assert.Throws(() => Maclaurin.Exp(0.0, error)); + + [TestCase(0, 0.001)] + [TestCase(1, 0.00001)] + [TestCase(1.57, 0.0001)] + [TestCase(3.14, 0.0001)] + public void Sin_ErrorForm_ValidCases(double point, double error) + { + // Arrange + var expected = Math.Sin(point); + + // Act + var actual = Maclaurin.Sin(point, error); + + // Assert + Assert.IsTrue(Math.Abs(expected - actual) < error); + } + + [TestCase(0.0)] + [TestCase(1.0)] + public void Sin_ErrorForm_InvalidCases(double error) => + Assert.Throws(() => Maclaurin.Sin(0.0, error)); + + [TestCase(0, 0.001)] + [TestCase(1, 0.00001)] + [TestCase(1.57, 0.0001)] + [TestCase(3.14, 0.0001)] + public void Cos_ErrorForm_ValidCases(double point, double error) + { + // Arrange + var expected = Math.Cos(point); + + // Act + var actual = Maclaurin.Cos(point, error); + + // Assert + Assert.IsTrue(Math.Abs(expected - actual) < error); + } + + [TestCase(0.0)] + [TestCase(1.0)] + public void Cos_ErrorForm_InvalidCases(double error) => + Assert.Throws(() => Maclaurin.Cos(0.0, error)); } diff --git a/Algorithms.Tests/Numeric/Decomposition/SVDTests.cs b/Algorithms.Tests/Numeric/Decomposition/SVDTests.cs index 9ac78a50..46dc9223 100644 --- a/Algorithms.Tests/Numeric/Decomposition/SVDTests.cs +++ b/Algorithms.Tests/Numeric/Decomposition/SVDTests.cs @@ -6,133 +6,132 @@ using M = Utilities.Extensions.MatrixExtensions; using V = Utilities.Extensions.VectorExtensions; -namespace Algorithms.Tests.Numeric.Decomposition +namespace Algorithms.Tests.Numeric.Decomposition; + +public class SvdTests { - public class SvdTests + [Test] + public void RandomUnitVector() { - [Test] - public void RandomUnitVector() - { - var epsilon = 0.0001; - // unit vector should have length 1 - ThinSvd.RandomUnitVector(10).Magnitude().Should().BeApproximately(1, epsilon); - // unit vector with single element should be [-1] or [+1] - Math.Abs(ThinSvd.RandomUnitVector(1)[0]).Should().BeApproximately(1, epsilon); - // two randomly generated unit vectors should not be equal - ThinSvd.RandomUnitVector(10).Should().NotBeEquivalentTo(ThinSvd.RandomUnitVector(10)); - } + var epsilon = 0.0001; + // unit vector should have length 1 + ThinSvd.RandomUnitVector(10).Magnitude().Should().BeApproximately(1, epsilon); + // unit vector with single element should be [-1] or [+1] + Math.Abs(ThinSvd.RandomUnitVector(1)[0]).Should().BeApproximately(1, epsilon); + // two randomly generated unit vectors should not be equal + ThinSvd.RandomUnitVector(10).Should().NotBeEquivalentTo(ThinSvd.RandomUnitVector(10)); + } - [Test] - public void Svd_Decompose() - { - CheckSvd(new double[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }); - CheckSvd(new double[,] { { 1, 2, 3 }, { 4, 5, 6 } }); - CheckSvd(new double[,] { { 1, 0, 0, 0, 2 }, { 0, 3, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 2, 0, 0, 0 } }); - } + [Test] + public void Svd_Decompose() + { + CheckSvd(new double[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }); + CheckSvd(new double[,] { { 1, 2, 3 }, { 4, 5, 6 } }); + CheckSvd(new double[,] { { 1, 0, 0, 0, 2 }, { 0, 3, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 2, 0, 0, 0 } }); + } - [Test] - public void Svd_Random([Random(3, 10, 5)] int m, [Random(3, 10, 5)] int n) - { - double[,] matrix = GenerateRandomMatrix(m, n); - CheckSvd(matrix); - } + [Test] + public void Svd_Random([Random(3, 10, 5)] int m, [Random(3, 10, 5)] int n) + { + double[,] matrix = GenerateRandomMatrix(m, n); + CheckSvd(matrix); + } - private void AssertMatrixEqual(double[,] matrix1, double[,] matrix2, double epsilon) + private void AssertMatrixEqual(double[,] matrix1, double[,] matrix2, double epsilon) + { + matrix1.GetLength(0).Should().Be(matrix2.GetLength(0)); + matrix1.GetLength(1).Should().Be(matrix2.GetLength(1)); + for (var i = 0; i < matrix1.GetLength(0); i++) { - matrix1.GetLength(0).Should().Be(matrix2.GetLength(0)); - matrix1.GetLength(1).Should().Be(matrix2.GetLength(1)); - for (var i = 0; i < matrix1.GetLength(0); i++) + for (var j = 0; j < matrix1.GetLength(1); j++) { - for (var j = 0; j < matrix1.GetLength(1); j++) - { - Assert.AreEqual(matrix1[i, j], matrix2[i, j], epsilon, $"At index ({i}, {j})"); - } + Assert.AreEqual(matrix1[i, j], matrix2[i, j], epsilon, $"At index ({i}, {j})"); } } + } - private double[,] GenerateRandomMatrix(int m, int n) + private double[,] GenerateRandomMatrix(int m, int n) + { + double[,] result = new double[m, n]; + Random random = new(); + for (var i = 0; i < m; i++) { - double[,] result = new double[m, n]; - Random random = new(); - for (var i = 0; i < m; i++) + for (var j = 0; j < n; j++) { - for (var j = 0; j < n; j++) - { - result[i, j] = random.NextDouble() - 0.5; - } + result[i, j] = random.NextDouble() - 0.5; } - - return result; } - private void CheckSvd(double[,] testMatrix) + return result; + } + + private void CheckSvd(double[,] testMatrix) + { + var epsilon = 1E-6; + double[,] u; + double[,] v; + double[] s; + (u, s, v) = ThinSvd.Decompose(testMatrix, 1e-6 * epsilon, 1000); + + for (var i = 1; i < s.Length; i++) { - var epsilon = 1E-6; - double[,] u; - double[,] v; - double[] s; - (u, s, v) = ThinSvd.Decompose(testMatrix, 1e-6 * epsilon, 1000); + // singular values should be arranged from greatest to smallest + // but there are rounding errors + (s[i] - s[i - 1]).Should().BeLessThan(1); + } - for (var i = 1; i < s.Length; i++) + for (var i = 0; i < u.GetLength(1); i++) + { + double[] extracted = new double[u.GetLength(0)]; + // extract a column of u + for (var j = 0; j < extracted.Length; j++) { - // singular values should be arranged from greatest to smallest - // but there are rounding errors - (s[i] - s[i - 1]).Should().BeLessThan(1); + extracted[j] = u[j, i]; } - for (var i = 0; i < u.GetLength(1); i++) + if (s[i] > epsilon) { - double[] extracted = new double[u.GetLength(0)]; - // extract a column of u - for (var j = 0; j < extracted.Length; j++) - { - extracted[j] = u[j, i]; - } - - if (s[i] > epsilon) - { - // if the singular value is non-zero, then the basis vector in u should be a unit vector - extracted.Magnitude().Should().BeApproximately(1, epsilon); - } - else - { - // if the singular value is zero, then the basis vector in u should be zeroed out - extracted.Magnitude().Should().BeApproximately(0, epsilon); - } + // if the singular value is non-zero, then the basis vector in u should be a unit vector + extracted.Magnitude().Should().BeApproximately(1, epsilon); } - - for (var i = 0; i < v.GetLength(1); i++) + else { - double[] extracted = new double[v.GetLength(0)]; - // extract column of v - for (var j = 0; j < extracted.Length; j++) - { - extracted[j] = v[j, i]; - } - - if (s[i] > epsilon) - { - // if the singular value is non-zero, then the basis vector in v should be a unit vector - Assert.AreEqual(1, extracted.Magnitude(), epsilon); - } - else - { - // if the singular value is zero, then the basis vector in v should be zeroed out - Assert.AreEqual(0, extracted.Magnitude(), epsilon); - } + // if the singular value is zero, then the basis vector in u should be zeroed out + extracted.Magnitude().Should().BeApproximately(0, epsilon); } + } - // convert singular values to a diagonal matrix - double[,] expanded = new double[s.Length, s.Length]; - for (var i = 0; i < s.Length; i++) + for (var i = 0; i < v.GetLength(1); i++) + { + double[] extracted = new double[v.GetLength(0)]; + // extract column of v + for (var j = 0; j < extracted.Length; j++) { - expanded[i, i] = s[i]; + extracted[j] = v[j, i]; } + if (s[i] > epsilon) + { + // if the singular value is non-zero, then the basis vector in v should be a unit vector + Assert.AreEqual(1, extracted.Magnitude(), epsilon); + } + else + { + // if the singular value is zero, then the basis vector in v should be zeroed out + Assert.AreEqual(0, extracted.Magnitude(), epsilon); + } + } - // matrix = U * S * V^t, definition of Singular Vector Decomposition - AssertMatrixEqual(testMatrix, u.Multiply(expanded).Multiply(v.Transpose()), epsilon); - AssertMatrixEqual(testMatrix, u.Multiply(expanded.Multiply(v.Transpose())), epsilon); + // convert singular values to a diagonal matrix + double[,] expanded = new double[s.Length, s.Length]; + for (var i = 0; i < s.Length; i++) + { + expanded[i, i] = s[i]; } + + + // matrix = U * S * V^t, definition of Singular Vector Decomposition + AssertMatrixEqual(testMatrix, u.Multiply(expanded).Multiply(v.Transpose()), epsilon); + AssertMatrixEqual(testMatrix, u.Multiply(expanded.Multiply(v.Transpose())), epsilon); } } diff --git a/Algorithms.Tests/Numeric/EulerMethodTest.cs b/Algorithms.Tests/Numeric/EulerMethodTest.cs index e9a78604..eed0bb04 100644 --- a/Algorithms.Tests/Numeric/EulerMethodTest.cs +++ b/Algorithms.Tests/Numeric/EulerMethodTest.cs @@ -4,59 +4,58 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class EulerMethodTest { - public static class EulerMethodTest + [Test] + public static void TestLinearEquation() { - [Test] - public static void TestLinearEquation() - { - Func exampleEquation = (x, _) => x; - List points = EulerMethod.EulerFull(0, 4, 0.001, 0, exampleEquation); - var yEnd = points[^1][1]; - yEnd.Should().BeApproximately(8, 0.01); - } + Func exampleEquation = (x, _) => x; + List points = EulerMethod.EulerFull(0, 4, 0.001, 0, exampleEquation); + var yEnd = points[^1][1]; + yEnd.Should().BeApproximately(8, 0.01); + } - [Test] - public static void TestExampleWikipedia() - { - // example from https://en.wikipedia.org/wiki/Euler_method - Func exampleEquation = (_, y) => y; - List points = EulerMethod.EulerFull(0, 4, 0.0125, 1, exampleEquation); - var yEnd = points[^1][1]; - yEnd.Should().BeApproximately(53.26, 0.01); - } + [Test] + public static void TestExampleWikipedia() + { + // example from https://en.wikipedia.org/wiki/Euler_method + Func exampleEquation = (_, y) => y; + List points = EulerMethod.EulerFull(0, 4, 0.0125, 1, exampleEquation); + var yEnd = points[^1][1]; + yEnd.Should().BeApproximately(53.26, 0.01); + } - [Test] - public static void TestExampleGeeksForGeeks() - { - // example from https://www.geeksforgeeks.org/euler-method-solving-differential-equation/ - // Euler method: y_n+1 = y_n + stepSize * f(x_n, y_n) - // differential equation: f(x, y) = x + y + x * y - // initial conditions: x_0 = 0; y_0 = 1; stepSize = 0.025 - // solution: - // y_1 = 1 + 0.025 * (0 + 1 + 0 * 1) = 1.025 - // y_2 = 1.025 + 0.025 * (0.025 + 1.025 + 0.025 * 1.025) = 1.051890625 - Func exampleEquation = (x, y) => x + y + x * y; - List points = EulerMethod.EulerFull(0, 0.05, 0.025, 1, exampleEquation); - var y1 = points[1][1]; - var y2 = points[2][1]; - Assert.AreEqual(y1, 1.025); - Assert.AreEqual(y2, 1.051890625); - } + [Test] + public static void TestExampleGeeksForGeeks() + { + // example from https://www.geeksforgeeks.org/euler-method-solving-differential-equation/ + // Euler method: y_n+1 = y_n + stepSize * f(x_n, y_n) + // differential equation: f(x, y) = x + y + x * y + // initial conditions: x_0 = 0; y_0 = 1; stepSize = 0.025 + // solution: + // y_1 = 1 + 0.025 * (0 + 1 + 0 * 1) = 1.025 + // y_2 = 1.025 + 0.025 * (0.025 + 1.025 + 0.025 * 1.025) = 1.051890625 + Func exampleEquation = (x, y) => x + y + x * y; + List points = EulerMethod.EulerFull(0, 0.05, 0.025, 1, exampleEquation); + var y1 = points[1][1]; + var y2 = points[2][1]; + Assert.AreEqual(y1, 1.025); + Assert.AreEqual(y2, 1.051890625); + } - [Test] - public static void StepsizeIsZeroOrNegative_ThrowsArgumentOutOfRangeException() - { - Func exampleEquation = (x, _) => x; - Assert.Throws(() => EulerMethod.EulerFull(0, 4, 0, 0, exampleEquation)); - } + [Test] + public static void StepsizeIsZeroOrNegative_ThrowsArgumentOutOfRangeException() + { + Func exampleEquation = (x, _) => x; + Assert.Throws(() => EulerMethod.EulerFull(0, 4, 0, 0, exampleEquation)); + } - [Test] - public static void StartIsLargerThanEnd_ThrowsArgumentOutOfRangeException() - { - Func exampleEquation = (x, _) => x; - Assert.Throws(() => EulerMethod.EulerFull(0, -4, 0.1, 0, exampleEquation)); - } + [Test] + public static void StartIsLargerThanEnd_ThrowsArgumentOutOfRangeException() + { + Func exampleEquation = (x, _) => x; + Assert.Throws(() => EulerMethod.EulerFull(0, -4, 0.1, 0, exampleEquation)); } } diff --git a/Algorithms.Tests/Numeric/FactorialTests.cs b/Algorithms.Tests/Numeric/FactorialTests.cs index 1f03613f..bb81994b 100644 --- a/Algorithms.Tests/Numeric/FactorialTests.cs +++ b/Algorithms.Tests/Numeric/FactorialTests.cs @@ -1,40 +1,39 @@ -using System; +using System; using System.Numerics; using Algorithms.Numeric; using NUnit.Framework; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class FactorialTests { - public static class FactorialTests + [TestCase(0, "1")] + [TestCase(1, "1")] + [TestCase(4, "24")] + [TestCase(10, "3628800")] + [TestCase(18, "6402373705728000")] + public static void GetsFactorial(int input, string expected) { - [TestCase(0, "1")] - [TestCase(1, "1")] - [TestCase(4, "24")] - [TestCase(10, "3628800")] - [TestCase(18, "6402373705728000")] - public static void GetsFactorial(int input, string expected) - { - // Arrange - BigInteger expectedBigInt = BigInteger.Parse(expected); + // Arrange + BigInteger expectedBigInt = BigInteger.Parse(expected); - // Act - var result = Factorial.Calculate(input); + // Act + var result = Factorial.Calculate(input); - // Assert - Assert.AreEqual(expectedBigInt, result); - } + // Assert + Assert.AreEqual(expectedBigInt, result); + } - [TestCase(-5)] - [TestCase(-10)] - public static void GetsFactorialExceptionForNegativeNumbers(int num) - { - // Arrange + [TestCase(-5)] + [TestCase(-10)] + public static void GetsFactorialExceptionForNegativeNumbers(int num) + { + // Arrange - // Act - void Act() => Factorial.Calculate(num); + // Act + void Act() => Factorial.Calculate(num); - // Assert - _ = Assert.Throws(Act); - } + // Assert + _ = Assert.Throws(Act); } } diff --git a/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs b/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs index 11c927b0..f4e5298e 100755 --- a/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs +++ b/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs @@ -1,47 +1,46 @@ using Algorithms.Numeric.Factorization; using NUnit.Framework; -namespace Algorithms.Tests.Numeric.Factorization +namespace Algorithms.Tests.Numeric.Factorization; + +public static class TrialDivisionFactorizerTests { - public static class TrialDivisionFactorizerTests + [Test] + [TestCase(2)] + [TestCase(3)] + [TestCase(29)] + [TestCase(31)] + public static void PrimeNumberFactorizationFails(int p) { - [Test] - [TestCase(2)] - [TestCase(3)] - [TestCase(29)] - [TestCase(31)] - public static void PrimeNumberFactorizationFails(int p) - { - // Arrange - var factorizer = new TrialDivisionFactorizer(); + // Arrange + var factorizer = new TrialDivisionFactorizer(); - // Act - var success = factorizer.TryFactor(p, out _); + // Act + var success = factorizer.TryFactor(p, out _); - // Assert - Assert.IsFalse(success); - } + // Assert + Assert.IsFalse(success); + } - [Test] - [TestCase(4, 2)] - [TestCase(6, 2)] - [TestCase(8, 2)] - [TestCase(9, 3)] - [TestCase(15, 3)] - [TestCase(35, 5)] - [TestCase(49, 7)] - [TestCase(77, 7)] - public static void PrimeNumberFactorizationSucceeds(int n, int expected) - { - // Arrange - var factorizer = new TrialDivisionFactorizer(); + [Test] + [TestCase(4, 2)] + [TestCase(6, 2)] + [TestCase(8, 2)] + [TestCase(9, 3)] + [TestCase(15, 3)] + [TestCase(35, 5)] + [TestCase(49, 7)] + [TestCase(77, 7)] + public static void PrimeNumberFactorizationSucceeds(int n, int expected) + { + // Arrange + var factorizer = new TrialDivisionFactorizer(); - // Act - var success = factorizer.TryFactor(n, out var factor); + // Act + var success = factorizer.TryFactor(n, out var factor); - // Assert - Assert.IsTrue(success); - Assert.AreEqual(expected, factor); - } + // Assert + Assert.IsTrue(success); + Assert.AreEqual(expected, factor); } } diff --git a/Algorithms.Tests/Numeric/GaussJordanEliminationTests.cs b/Algorithms.Tests/Numeric/GaussJordanEliminationTests.cs index a492366e..8f7581f9 100644 --- a/Algorithms.Tests/Numeric/GaussJordanEliminationTests.cs +++ b/Algorithms.Tests/Numeric/GaussJordanEliminationTests.cs @@ -1,40 +1,39 @@ -using System; +using System; using Algorithms.Numeric; using NUnit.Framework; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +/// +/// Class for testing Gauss-Jordan Elimination Algorithm. +/// +public static class GaussJordanEliminationTests { - /// - /// Class for testing Gauss-Jordan Elimination Algorithm. - /// - public static class GaussJordanEliminationTests + [Test] + public static void NonSquaredMatrixThrowsException() { - [Test] - public static void NonSquaredMatrixThrowsException() - { - // Arrange - var solver = new GaussJordanElimination(); - var input = new double[,] { { 2, -1, 5 }, { 0, 2, 1 }, { 3, 17, 7 } }; + // Arrange + var solver = new GaussJordanElimination(); + var input = new double[,] { { 2, -1, 5 }, { 0, 2, 1 }, { 3, 17, 7 } }; - // Act - void Act() => solver.Solve(input); + // Act + void Act() => solver.Solve(input); - // Assert - _ = Assert.Throws(Act); - } + // Assert + _ = Assert.Throws(Act); + } - [Test] - public static void UnableToSolveSingularMatrix() - { - // Arrange - var solver = new GaussJordanElimination(); - var input = new double[,] { { 0, 0, 0 }, { 0, 0, 0 } }; + [Test] + public static void UnableToSolveSingularMatrix() + { + // Arrange + var solver = new GaussJordanElimination(); + var input = new double[,] { { 0, 0, 0 }, { 0, 0, 0 } }; - // Act - var result = solver.Solve(input); + // Act + var result = solver.Solve(input); - // Assert - Assert.IsFalse(result); - } + // Assert + Assert.IsFalse(result); } } diff --git a/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs b/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs index 51f836fe..84b40e14 100644 --- a/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs +++ b/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs @@ -1,30 +1,29 @@ -using Algorithms.Numeric.GreatestCommonDivisor; +using Algorithms.Numeric.GreatestCommonDivisor; using NUnit.Framework; -namespace Algorithms.Tests.Numeric.GreatestCommonDivisor +namespace Algorithms.Tests.Numeric.GreatestCommonDivisor; + +public static class BinaryGreatestCommonDivisorFinderTests { - public static class BinaryGreatestCommonDivisorFinderTests + [Test] + [TestCase(2, 3, 1)] + [TestCase(1, 1, 1)] + [TestCase(13, 17, 1)] + [TestCase(0, 17, 17)] + [TestCase(17, 0, 17)] + [TestCase(17, 17, 17)] + [TestCase(2 * 17, 17, 17)] + [TestCase(0, 0, 0)] + [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13)] + public static void GreatestCommonDivisorCorrect(int a, int b, int expectedGcd) { - [Test] - [TestCase(2, 3, 1)] - [TestCase(1, 1, 1)] - [TestCase(13, 17, 1)] - [TestCase(0, 17, 17)] - [TestCase(17, 0, 17)] - [TestCase(17, 17, 17)] - [TestCase(2 * 17, 17, 17)] - [TestCase(0, 0, 0)] - [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13)] - public static void GreatestCommonDivisorCorrect(int a, int b, int expectedGcd) - { - // Arrange - var gcdFinder = new BinaryGreatestCommonDivisorFinder(); + // Arrange + var gcdFinder = new BinaryGreatestCommonDivisorFinder(); - // Act - var actualGcd = gcdFinder.FindGcd(a, b); + // Act + var actualGcd = gcdFinder.FindGcd(a, b); - // Assert - Assert.AreEqual(expectedGcd, actualGcd); - } + // Assert + Assert.AreEqual(expectedGcd, actualGcd); } } diff --git a/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs b/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs index c253fb63..68335730 100644 --- a/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs +++ b/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs @@ -1,30 +1,29 @@ -using Algorithms.Numeric.GreatestCommonDivisor; +using Algorithms.Numeric.GreatestCommonDivisor; using NUnit.Framework; -namespace Algorithms.Tests.Numeric.GreatestCommonDivisor +namespace Algorithms.Tests.Numeric.GreatestCommonDivisor; + +public static class EuclideanGreatestCommonDivisorFinderTests { - public static class EuclideanGreatestCommonDivisorFinderTests + [Test] + [TestCase(2, 3, 1)] + [TestCase(1, 1, 1)] + [TestCase(13, 17, 1)] + [TestCase(0, 17, 17)] + [TestCase(17, 0, 17)] + [TestCase(17, 17, 17)] + [TestCase(2 * 17, 17, 17)] + [TestCase(0, 0, int.MaxValue)] + [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13)] + public static void GreatestCommonDivisorCorrect(int a, int b, int expectedGcd) { - [Test] - [TestCase(2, 3, 1)] - [TestCase(1, 1, 1)] - [TestCase(13, 17, 1)] - [TestCase(0, 17, 17)] - [TestCase(17, 0, 17)] - [TestCase(17, 17, 17)] - [TestCase(2 * 17, 17, 17)] - [TestCase(0, 0, int.MaxValue)] - [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13)] - public static void GreatestCommonDivisorCorrect(int a, int b, int expectedGcd) - { - // Arrange - var gcdFinder = new EuclideanGreatestCommonDivisorFinder(); + // Arrange + var gcdFinder = new EuclideanGreatestCommonDivisorFinder(); - // Act - var actualGcd = gcdFinder.FindGcd(a, b); + // Act + var actualGcd = gcdFinder.FindGcd(a, b); - // Assert - Assert.AreEqual(expectedGcd, actualGcd); - } + // Assert + Assert.AreEqual(expectedGcd, actualGcd); } } diff --git a/Algorithms.Tests/Numeric/KeithNumberTest.cs b/Algorithms.Tests/Numeric/KeithNumberTest.cs index 6a8b211d..9ec102f0 100644 --- a/Algorithms.Tests/Numeric/KeithNumberTest.cs +++ b/Algorithms.Tests/Numeric/KeithNumberTest.cs @@ -2,32 +2,31 @@ using NUnit.Framework; using System; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class KeithNumberTest { - public static class KeithNumberTest + [Test] + [TestCase(14)] + [TestCase(47)] + [TestCase(197)] + [TestCase(7909)] + public static void KeithNumberWork(int number) { - [Test] - [TestCase(14)] - [TestCase(47)] - [TestCase(197)] - [TestCase(7909)] - public static void KeithNumberWork(int number) - { - // Act - var result = KeithNumberChecker.IsKeithNumber(number); + // Act + var result = KeithNumberChecker.IsKeithNumber(number); - // Assert - Assert.IsTrue(result); - } + // Assert + Assert.IsTrue(result); + } - [Test] - [TestCase(-2)] - public static void KeithNumberShouldThrowEx(int number) - { - // Arrange + [Test] + [TestCase(-2)] + public static void KeithNumberShouldThrowEx(int number) + { + // Arrange - // Assert - Assert.Throws(() => KeithNumberChecker.IsKeithNumber(number)); - } + // Assert + Assert.Throws(() => KeithNumberChecker.IsKeithNumber(number)); } } diff --git a/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs b/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs index a2107668..ee75fffa 100644 --- a/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs +++ b/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs @@ -1,36 +1,35 @@ using Algorithms.Numeric; using NUnit.Framework; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public class KrishnamurthyNumberCheckerTests { - public class KrishnamurthyNumberCheckerTests + [TestCase(1)] + [TestCase(2)] + [TestCase(145)] + [TestCase(40585)] + public void KrishnamurthyNumberCheckerKnownNumbers(int number) { - [TestCase(1)] - [TestCase(2)] - [TestCase(145)] - [TestCase(40585)] - public void KrishnamurthyNumberCheckerKnownNumbers(int number) - { - var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); - Assert.IsTrue(result); - } + var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); + Assert.IsTrue(result); + } - [TestCase(3)] - [TestCase(4)] - [TestCase(239847)] - [TestCase(12374)] - public void KrishnamurthyNumberCheckerNotKMNumber(int number) - { - var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); - Assert.IsFalse(result); - } + [TestCase(3)] + [TestCase(4)] + [TestCase(239847)] + [TestCase(12374)] + public void KrishnamurthyNumberCheckerNotKMNumber(int number) + { + var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); + Assert.IsFalse(result); + } - [TestCase(0)] - [TestCase(-1)] - public void KrishnamurthyNumberCheckerNotPositiveNumber(int number) - { - var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); - Assert.IsFalse(result); - } + [TestCase(0)] + [TestCase(-1)] + public void KrishnamurthyNumberCheckerNotPositiveNumber(int number) + { + var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); + Assert.IsFalse(result); } } diff --git a/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs b/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs index bd9f9a32..acfae24b 100644 --- a/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs +++ b/Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs @@ -3,45 +3,44 @@ using Algorithms.Numeric; using NUnit.Framework; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class MillerRabinPrimalityTest { - public static class MillerRabinPrimalityTest + [TestCase("7", ExpectedResult = true)] // true + [TestCase("47", ExpectedResult = true)] // true + [TestCase("247894109041876714378152933343208766493", ExpectedResult = true)] // true + [TestCase("247894109041876714378152933343208766493", 1, ExpectedResult = true)] // true + [TestCase("315757551269487563269454472438030700351", ExpectedResult = true)] // true + [TestCase("2476099", 12445, ExpectedResult = false)] // false 19^5 + // false 247894109041876714378152933343208766493*315757551269487563269454472438030700351 + [TestCase("78274436845194327170519855212507883195883737501141260366253362532531612139043", ExpectedResult = false)] + [Retry(3)] + public static bool MillerRabinPrimalityWork(string testcase, int? seed = null) { - [TestCase("7", ExpectedResult = true)] // true - [TestCase("47", ExpectedResult = true)] // true - [TestCase("247894109041876714378152933343208766493", ExpectedResult = true)] // true - [TestCase("247894109041876714378152933343208766493", 1, ExpectedResult = true)] // true - [TestCase("315757551269487563269454472438030700351", ExpectedResult = true)] // true - [TestCase("2476099", 12445, ExpectedResult = false)] // false 19^5 - // false 247894109041876714378152933343208766493*315757551269487563269454472438030700351 - [TestCase("78274436845194327170519855212507883195883737501141260366253362532531612139043", ExpectedResult = false)] - [Retry(3)] - public static bool MillerRabinPrimalityWork(string testcase, int? seed = null) - { - // Arrange - BigInteger number = BigInteger.Parse(testcase); + // Arrange + BigInteger number = BigInteger.Parse(testcase); - // Recommended number of checks' rounds = Log2(number) as BigInteger has no Log2 function we need to convert Log10 - BigInteger rounds = (BigInteger)(BigInteger.Log10(number) / BigInteger.Log10(2)); + // Recommended number of checks' rounds = Log2(number) as BigInteger has no Log2 function we need to convert Log10 + BigInteger rounds = (BigInteger)(BigInteger.Log10(number) / BigInteger.Log10(2)); - // Act - var result = MillerRabinPrimalityChecker.IsProbablyPrimeNumber(number, rounds, seed); + // Act + var result = MillerRabinPrimalityChecker.IsProbablyPrimeNumber(number, rounds, seed); - // Assert - return result; - } + // Assert + return result; + } - [TestCase("-2")] - [TestCase("0")] - [TestCase("3")] - // By the algorithm definition the number which is checked should be more than 3 - public static void MillerRabinPrimalityShouldThrowEx(string testcase) - { - // Arrange - BigInteger number = BigInteger.Parse(testcase); - BigInteger rounds = 1; - // Assert - Assert.Throws(() => MillerRabinPrimalityChecker.IsProbablyPrimeNumber(number, rounds)); - } + [TestCase("-2")] + [TestCase("0")] + [TestCase("3")] + // By the algorithm definition the number which is checked should be more than 3 + public static void MillerRabinPrimalityShouldThrowEx(string testcase) + { + // Arrange + BigInteger number = BigInteger.Parse(testcase); + BigInteger rounds = 1; + // Assert + Assert.Throws(() => MillerRabinPrimalityChecker.IsProbablyPrimeNumber(number, rounds)); } } diff --git a/Algorithms.Tests/Numeric/ModularExponentiationTest.cs b/Algorithms.Tests/Numeric/ModularExponentiationTest.cs index 7abed965..355fa52b 100644 --- a/Algorithms.Tests/Numeric/ModularExponentiationTest.cs +++ b/Algorithms.Tests/Numeric/ModularExponentiationTest.cs @@ -3,34 +3,33 @@ using NUnit.Framework; using FluentAssertions; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public class ModularExponentiationTest { - public class ModularExponentiationTest + [Test] + [TestCase(3, 6, 11, 3)] + [TestCase(5, 3, 13, 8)] + [TestCase(2, 7, 17, 9)] + [TestCase(7, 4, 16, 1)] + [TestCase(7, 2, 11, 5)] + [TestCase(4, 13, 497, 445)] + [TestCase(13, 3, 1, 0)] + public void ModularExponentiationCorrect(int b, int e, int m, int expectedRes) { - [Test] - [TestCase(3, 6, 11, 3)] - [TestCase(5, 3, 13, 8)] - [TestCase(2, 7, 17, 9)] - [TestCase(7, 4, 16, 1)] - [TestCase(7, 2, 11, 5)] - [TestCase(4, 13, 497, 445)] - [TestCase(13, 3, 1, 0)] - public void ModularExponentiationCorrect(int b, int e, int m, int expectedRes) - { - var modularExponentiation = new ModularExponentiation(); - var actualRes = modularExponentiation.ModularPow(b, e, m); - actualRes.Should().Be(expectedRes); - } + var modularExponentiation = new ModularExponentiation(); + var actualRes = modularExponentiation.ModularPow(b, e, m); + actualRes.Should().Be(expectedRes); + } - [TestCase(17, 7, -3)] - [TestCase(11, 3, -5)] - [TestCase(14, 3, 0)] - public void ModularExponentiationNegativeMod(int b, int e, int m) - { - var modularExponentiation = new ModularExponentiation(); - Action res = () => modularExponentiation.ModularPow(b, e, m); - res.Should().Throw() - .WithMessage(String.Format("{0} is not a positive integer", m)); - } + [TestCase(17, 7, -3)] + [TestCase(11, 3, -5)] + [TestCase(14, 3, 0)] + public void ModularExponentiationNegativeMod(int b, int e, int m) + { + var modularExponentiation = new ModularExponentiation(); + Action res = () => modularExponentiation.ModularPow(b, e, m); + res.Should().Throw() + .WithMessage(String.Format("{0} is not a positive integer", m)); } } diff --git a/Algorithms.Tests/Numeric/NarcissisticNumberTest.cs b/Algorithms.Tests/Numeric/NarcissisticNumberTest.cs index 313d9338..65a8ca78 100644 --- a/Algorithms.Tests/Numeric/NarcissisticNumberTest.cs +++ b/Algorithms.Tests/Numeric/NarcissisticNumberTest.cs @@ -1,26 +1,25 @@ -using Algorithms.Numeric; +using Algorithms.Numeric; using NUnit.Framework; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class NarcissisticNumberTest { - public static class NarcissisticNumberTest + [Test] + [TestCase(2, ExpectedResult = true)] + [TestCase(3, ExpectedResult = true)] + [TestCase(28, ExpectedResult = false)] + [TestCase(153, ExpectedResult = true)] + [TestCase(170, ExpectedResult = false)] + [TestCase(371, ExpectedResult = true)] + public static bool NarcissisticNumberWork(int number) { - [Test] - [TestCase(2, ExpectedResult = true)] - [TestCase(3, ExpectedResult = true)] - [TestCase(28, ExpectedResult = false)] - [TestCase(153, ExpectedResult = true)] - [TestCase(170, ExpectedResult = false)] - [TestCase(371, ExpectedResult = true)] - public static bool NarcissisticNumberWork(int number) - { - // Arrange + // Arrange - // Act - var result = NarcissisticNumberChecker.IsNarcissistic(number); + // Act + var result = NarcissisticNumberChecker.IsNarcissistic(number); - // Assert - return result; - } + // Assert + return result; } } diff --git a/Algorithms.Tests/Numeric/PerfectNumberTest.cs b/Algorithms.Tests/Numeric/PerfectNumberTest.cs index 494a9205..4c8ee058 100644 --- a/Algorithms.Tests/Numeric/PerfectNumberTest.cs +++ b/Algorithms.Tests/Numeric/PerfectNumberTest.cs @@ -1,35 +1,34 @@ -using System; +using System; using Algorithms.Numeric; using NUnit.Framework; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class PerfectNumberTests { - public static class PerfectNumberTests + [Test] + [TestCase(6)] + [TestCase(28)] + [TestCase(496)] + [TestCase(8128)] + public static void PerfectNumberWork(int number) { - [Test] - [TestCase(6)] - [TestCase(28)] - [TestCase(496)] - [TestCase(8128)] - public static void PerfectNumberWork(int number) - { - // Arrange + // Arrange - // Act - var result = PerfectNumberChecker.IsPerfectNumber(number); + // Act + var result = PerfectNumberChecker.IsPerfectNumber(number); - // Assert - Assert.IsTrue(result); - } + // Assert + Assert.IsTrue(result); + } - [Test] - [TestCase(-2)] - public static void PerfectNumberShouldThrowEx(int number) - { - // Arrange + [Test] + [TestCase(-2)] + public static void PerfectNumberShouldThrowEx(int number) + { + // Arrange - // Assert - Assert.Throws(() => PerfectNumberChecker.IsPerfectNumber(number)); - } + // Assert + Assert.Throws(() => PerfectNumberChecker.IsPerfectNumber(number)); } } diff --git a/Algorithms.Tests/Numeric/PerfectSquareTest.cs b/Algorithms.Tests/Numeric/PerfectSquareTest.cs index 2f347f21..13437317 100644 --- a/Algorithms.Tests/Numeric/PerfectSquareTest.cs +++ b/Algorithms.Tests/Numeric/PerfectSquareTest.cs @@ -1,27 +1,26 @@ -using Algorithms.Numeric; +using Algorithms.Numeric; using NUnit.Framework; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class PerfectSquareTests { - public static class PerfectSquareTests + [Test] + [TestCase(-4, ExpectedResult = false)] + [TestCase(4, ExpectedResult = true)] + [TestCase(9, ExpectedResult = true)] + [TestCase(10, ExpectedResult = false)] + [TestCase(16, ExpectedResult = true)] + [TestCase(70, ExpectedResult = false)] + [TestCase(81, ExpectedResult = true)] + public static bool IsPerfectSquare_ResultIsCorrect(int number) { - [Test] - [TestCase(-4, ExpectedResult = false)] - [TestCase(4, ExpectedResult = true)] - [TestCase(9, ExpectedResult = true)] - [TestCase(10, ExpectedResult = false)] - [TestCase(16, ExpectedResult = true)] - [TestCase(70, ExpectedResult = false)] - [TestCase(81, ExpectedResult = true)] - public static bool IsPerfectSquare_ResultIsCorrect(int number) - { - // Arrange + // Arrange - // Act - var result = PerfectSquareChecker.IsPerfectSquare(number); + // Act + var result = PerfectSquareChecker.IsPerfectSquare(number); - // Assert - return result; - } + // Assert + return result; } } diff --git a/Algorithms.Tests/Numeric/PseudoInverse/PseudoInverseTests.cs b/Algorithms.Tests/Numeric/PseudoInverse/PseudoInverseTests.cs index 432fda65..bf95a4b9 100644 --- a/Algorithms.Tests/Numeric/PseudoInverse/PseudoInverseTests.cs +++ b/Algorithms.Tests/Numeric/PseudoInverse/PseudoInverseTests.cs @@ -1,45 +1,44 @@ -using NUnit.Framework; +using NUnit.Framework; using Utilities.Extensions; -namespace Algorithms.Tests.Numeric.PseudoInverse +namespace Algorithms.Tests.Numeric.PseudoInverse; + +public static class PseudoInverseTests { - public static class PseudoInverseTests + [Test] + public static void SquaredMatrixInverseWorks() { - [Test] - public static void SquaredMatrixInverseWorks() - { - // Arrange - var inMat = new double[,] { { 2, 4, 6 }, { 2, 0, 2 }, { 6, 8, 14 } }; - var inMatCopy = new double[,] { { 2, 4, 6 }, { 2, 0, 2 }, { 6, 8, 14 } }; - - // Act - // using AA+A = A - var result = Algorithms.Numeric.Pseudoinverse.PseudoInverse.PInv(inMat); - var aainva = inMatCopy.Multiply(result).Multiply(inMatCopy); - - var rounded = aainva.RoundToNextInt(); - var isequal = rounded.IsEqual(inMatCopy); - // Assert - Assert.IsTrue(isequal); - } - - [Test] - public static void NonSquaredMatrixPseudoInverseMatrixWorks() - { - // Arrange - var inMat = new double[,] { { 1, 2, 3, 4 }, { 0, 1, 4, 7 }, { 5, 6, 0, 1 } }; - var inMatCopy = new double[,] { { 1, 2, 3, 4 }, { 0, 1, 4, 7 }, { 5, 6, 0, 1 } }; - - // Act - // using (A+)+ = A - var result = Algorithms.Numeric.Pseudoinverse.PseudoInverse.PInv(inMat); - var result2 = Algorithms.Numeric.Pseudoinverse.PseudoInverse.PInv(result); - - var rounded = result2.RoundToNextInt(); - - var isequal = rounded.IsEqual(inMatCopy); - // Assert - Assert.IsTrue(isequal); - } + // Arrange + var inMat = new double[,] { { 2, 4, 6 }, { 2, 0, 2 }, { 6, 8, 14 } }; + var inMatCopy = new double[,] { { 2, 4, 6 }, { 2, 0, 2 }, { 6, 8, 14 } }; + + // Act + // using AA+A = A + var result = Algorithms.Numeric.Pseudoinverse.PseudoInverse.PInv(inMat); + var aainva = inMatCopy.Multiply(result).Multiply(inMatCopy); + + var rounded = aainva.RoundToNextInt(); + var isequal = rounded.IsEqual(inMatCopy); + // Assert + Assert.IsTrue(isequal); + } + + [Test] + public static void NonSquaredMatrixPseudoInverseMatrixWorks() + { + // Arrange + var inMat = new double[,] { { 1, 2, 3, 4 }, { 0, 1, 4, 7 }, { 5, 6, 0, 1 } }; + var inMatCopy = new double[,] { { 1, 2, 3, 4 }, { 0, 1, 4, 7 }, { 5, 6, 0, 1 } }; + + // Act + // using (A+)+ = A + var result = Algorithms.Numeric.Pseudoinverse.PseudoInverse.PInv(inMat); + var result2 = Algorithms.Numeric.Pseudoinverse.PseudoInverse.PInv(result); + + var rounded = result2.RoundToNextInt(); + + var isequal = rounded.IsEqual(inMatCopy); + // Assert + Assert.IsTrue(isequal); } } diff --git a/Algorithms.Tests/Numeric/RungeKuttaMethodTest.cs b/Algorithms.Tests/Numeric/RungeKuttaMethodTest.cs index d85d8abe..b4eaff87 100644 --- a/Algorithms.Tests/Numeric/RungeKuttaMethodTest.cs +++ b/Algorithms.Tests/Numeric/RungeKuttaMethodTest.cs @@ -4,40 +4,39 @@ using System; using System.Collections.Generic; -namespace Algorithms.Tests.Numeric +namespace Algorithms.Tests.Numeric; + +public static class RungeKuttaTest { - public static class RungeKuttaTest + [Test] + public static void TestLinearEquation() { - [Test] - public static void TestLinearEquation() - { - Func exampleEquation = (x, _) => x; - List points = RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0.001, 0, exampleEquation); - var yEnd = points[^1][1]; - yEnd.Should().BeApproximately(8, 0.01); - } + Func exampleEquation = (x, _) => x; + List points = RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0.001, 0, exampleEquation); + var yEnd = points[^1][1]; + yEnd.Should().BeApproximately(8, 0.01); + } - [Test] - public static void TestExampleFunciton() - { - Func exampleEquation = (_, y) => y; - List points = RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0.0125, 1, exampleEquation); - var yEnd = points[^1][1]; - yEnd.Should().BeApproximately(54.598, 0.0005); - } + [Test] + public static void TestExampleFunciton() + { + Func exampleEquation = (_, y) => y; + List points = RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0.0125, 1, exampleEquation); + var yEnd = points[^1][1]; + yEnd.Should().BeApproximately(54.598, 0.0005); + } - [Test] - public static void StepsizeIsZeroOrNegative_ThrowsArgumentOutOfRangeException() - { - Func exampleEquation = (x, _) => x; - Assert.Throws(() => RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0, 0, exampleEquation)); - } + [Test] + public static void StepsizeIsZeroOrNegative_ThrowsArgumentOutOfRangeException() + { + Func exampleEquation = (x, _) => x; + Assert.Throws(() => RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0, 0, exampleEquation)); + } - [Test] - public static void StartIsLargerThanEnd_ThrowsArgumentOutOfRangeException() - { - Func exampleEquation = (x, _) => x; - Assert.Throws(() => RungeKuttaMethod.ClassicRungeKuttaMethod(0, -4, 0.1, 0, exampleEquation)); - } + [Test] + public static void StartIsLargerThanEnd_ThrowsArgumentOutOfRangeException() + { + Func exampleEquation = (x, _) => x; + Assert.Throws(() => RungeKuttaMethod.ClassicRungeKuttaMethod(0, -4, 0.1, 0, exampleEquation)); } } diff --git a/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs b/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs index aa8c16c7..43b14c3f 100644 --- a/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs +++ b/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs @@ -1,65 +1,60 @@ using Algorithms.Other; using NUnit.Framework; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class DecisionsConvolutionsTest { - public static class DecisionsConvolutionsTest + [Test] + public static void Verify_Linear_Convolution() { - [Test] - public static void Verify_Linear_Convolution() + // Arrange + var matrix = new List> { - // Arrange - var matrix = new List> - { - new List { 7, 6, 5, 8, 5, 6 }, - new List { 4, 8, 4, 4, 5, 3 }, - new List { 3, 8, 1, 4, 5, 2 }, - new List { 5, 6, 3, 6, 4, 5 }, - new List { 1, 4, 8, 6, 3, 6 }, - new List { 5, 1, 8, 6, 5, 1 }, - new List { 6, 8, 3, 6, 3, 5 } - }; + new List { 7, 6, 5, 8, 5, 6 }, + new List { 4, 8, 4, 4, 5, 3 }, + new List { 3, 8, 1, 4, 5, 2 }, + new List { 5, 6, 3, 6, 4, 5 }, + new List { 1, 4, 8, 6, 3, 6 }, + new List { 5, 1, 8, 6, 5, 1 }, + new List { 6, 8, 3, 6, 3, 5 } + }; - var expectedMatrix = new List { 7, 6, 5, 8, 5, 6 }; + var expectedMatrix = new List { 7, 6, 5, 8, 5, 6 }; - var priorities = new List { 1, 1, 1, 1, 0.545m, 0.583m }; + var priorities = new List { 1, 1, 1, 1, 0.545m, 0.583m }; - // Act - var optimizedMatrix = DecisionsConvolutions.Linear(matrix, priorities); + // Act + var optimizedMatrix = DecisionsConvolutions.Linear(matrix, priorities); - // Assert - Assert.AreEqual(optimizedMatrix, expectedMatrix); - } + // Assert + Assert.AreEqual(optimizedMatrix, expectedMatrix); + } - [Test] - public static void Verify_MaxMin_Convolution() + [Test] + public static void Verify_MaxMin_Convolution() + { + // Arrange + var matrix = new List> { - // Arrange - var matrix = new List> - { - new List { 7, 6, 5, 8, 5, 6 }, - new List { 4, 8, 4, 4, 5, 3 }, - new List { 3, 8, 1, 4, 5, 2 }, - new List { 5, 6, 3, 6, 4, 5 }, - new List { 1, 4, 8, 6, 3, 6 }, - new List { 5, 1, 8, 6, 5, 1 }, - new List { 6, 8, 3, 6, 3, 5 } - }; + new List { 7, 6, 5, 8, 5, 6 }, + new List { 4, 8, 4, 4, 5, 3 }, + new List { 3, 8, 1, 4, 5, 2 }, + new List { 5, 6, 3, 6, 4, 5 }, + new List { 1, 4, 8, 6, 3, 6 }, + new List { 5, 1, 8, 6, 5, 1 }, + new List { 6, 8, 3, 6, 3, 5 } + }; - var expectedMatrix = new List { 7, 6, 5, 8, 5, 6 }; + var expectedMatrix = new List { 7, 6, 5, 8, 5, 6 }; - var priorities = new List { 1, 1, 1, 1, 0.545m, 0.583m }; + var priorities = new List { 1, 1, 1, 1, 0.545m, 0.583m }; - // Act - var optimizedMatrix = DecisionsConvolutions.MaxMin(matrix, priorities); + // Act + var optimizedMatrix = DecisionsConvolutions.MaxMin(matrix, priorities); - // Assert - Assert.AreEqual(optimizedMatrix, expectedMatrix); - } + // Assert + Assert.AreEqual(optimizedMatrix, expectedMatrix); } } diff --git a/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs b/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs index 941c9774..fd962180 100644 --- a/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs +++ b/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs @@ -1,28 +1,27 @@ -using Algorithms.Other; +using Algorithms.Other; using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class FermatPrimeCheckerTests { - public static class FermatPrimeCheckerTests + [Test] + [TestCase(5, true)] + [TestCase(2633, true)] + [TestCase(9439, true)] + [TestCase(1, false)] + [TestCase(8, false)] + public static void IsProbablePrime(int inputNum, bool expected) { - [Test] - [TestCase(5, true)] - [TestCase(2633, true)] - [TestCase(9439, true)] - [TestCase(1, false)] - [TestCase(8, false)] - public static void IsProbablePrime(int inputNum, bool expected) - { - // Arrange - var random = new Randomizer(); - var times = random.Next(1, 1000); + // Arrange + var random = new Randomizer(); + var times = random.Next(1, 1000); - // Act - var result = FermatPrimeChecker.IsPrime(inputNum, times); + // Act + var result = FermatPrimeChecker.IsPrime(inputNum, times); - // Assert - Assert.AreEqual(expected, result); - } + // Assert + Assert.AreEqual(expected, result); } } diff --git a/Algorithms.Tests/Other/FloodFillTest.cs b/Algorithms.Tests/Other/FloodFillTest.cs index fd691709..dfc1c807 100644 --- a/Algorithms.Tests/Other/FloodFillTest.cs +++ b/Algorithms.Tests/Other/FloodFillTest.cs @@ -3,103 +3,102 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class Tests { - public static class Tests + private static readonly Color Black = Color.FromArgb(255, 0, 0, 0); + private static readonly Color Green = Color.FromArgb(255, 0, 255, 0); + private static readonly Color Violet = Color.FromArgb(255, 255, 0, 255); + private static readonly Color White = Color.FromArgb(255, 255, 255, 255); + private static readonly Color Orange = Color.FromArgb(255, 255, 128, 0); + + [Test] + public static void BreadthFirstSearch_ThrowsArgumentOutOfRangeException() { - private static readonly Color Black = Color.FromArgb(255, 0, 0, 0); - private static readonly Color Green = Color.FromArgb(255, 0, 255, 0); - private static readonly Color Violet = Color.FromArgb(255, 255, 0, 255); - private static readonly Color White = Color.FromArgb(255, 255, 255, 255); - private static readonly Color Orange = Color.FromArgb(255, 255, 128, 0); + Action act = () => Algorithms.Other.FloodFill.BreadthFirstSearch(GenerateTestBitmap(), (10, 10), Black, White); + act.Should().Throw(); + } - [Test] - public static void BreadthFirstSearch_ThrowsArgumentOutOfRangeException() - { - Action act = () => Algorithms.Other.FloodFill.BreadthFirstSearch(GenerateTestBitmap(), (10, 10), Black, White); - act.Should().Throw(); - } + [Test] + public static void DepthFirstSearch_ThrowsArgumentOutOfRangeException() + { + Action act = () => Algorithms.Other.FloodFill.DepthFirstSearch(GenerateTestBitmap(), (-1, -1), Black, White); + act.Should().Throw(); + } - [Test] - public static void DepthFirstSearch_ThrowsArgumentOutOfRangeException() - { - Action act = () => Algorithms.Other.FloodFill.DepthFirstSearch(GenerateTestBitmap(), (-1, -1), Black, White); - act.Should().Throw(); - } + [Test] + public static void BreadthFirstSearch_Test1() + { + TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), Green, Orange, (1, 1), Orange); + } - [Test] - public static void BreadthFirstSearch_Test1() - { - TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), Green, Orange, (1, 1), Orange); - } + [Test] + public static void BreadthFirstSearch_Test2() + { + TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), Green, Orange, (0, 1), Violet); + } - [Test] - public static void BreadthFirstSearch_Test2() - { - TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), Green, Orange, (0, 1), Violet); - } + [Test] + public static void BreadthFirstSearch_Test3() + { + TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), Green, Orange, (6, 4), White); + } - [Test] - public static void BreadthFirstSearch_Test3() - { - TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), Green, Orange, (6, 4), White); - } + [Test] + public static void DepthFirstSearch_Test1() + { + TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), Green, Orange, (1, 1), Orange); + } - [Test] - public static void DepthFirstSearch_Test1() - { - TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), Green, Orange, (1, 1), Orange); - } + [Test] + public static void DepthFirstSearch_Test2() + { + TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), Green, Orange, (0, 1), Violet); + } - [Test] - public static void DepthFirstSearch_Test2() - { - TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), Green, Orange, (0, 1), Violet); - } + [Test] + public static void DepthFirstSearch_Test3() + { + TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), Green, Orange, (6, 4), White); + } - [Test] - public static void DepthFirstSearch_Test3() + private static Bitmap GenerateTestBitmap() + { + Color[,] layout = { - TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), Green, Orange, (6, 4), White); - } + {Violet, Violet, Green, Green, Black, Green, Green}, + {Violet, Green, Green, Black, Green, Green, Green}, + {Green, Green, Green, Black, Green, Green, Green}, + {Black, Black, Green, Black, White, White, Green}, + {Violet, Violet, Black, Violet, Violet, White, White}, + {Green, Green, Green, Violet, Violet, Violet, Violet}, + {Violet, Violet, Violet, Violet, Violet, Violet, Violet}, + }; - private static Bitmap GenerateTestBitmap() + Bitmap bitmap = new(7, 7); + for (int x = 0; x < layout.GetLength(0); x++) { - Color[,] layout = + for (int y = 0; y < layout.GetLength(1); y++) { - {Violet, Violet, Green, Green, Black, Green, Green}, - {Violet, Green, Green, Black, Green, Green, Green}, - {Green, Green, Green, Black, Green, Green, Green}, - {Black, Black, Green, Black, White, White, Green}, - {Violet, Violet, Black, Violet, Violet, White, White}, - {Green, Green, Green, Violet, Violet, Violet, Violet}, - {Violet, Violet, Violet, Violet, Violet, Violet, Violet}, - }; - - Bitmap bitmap = new(7, 7); - for (int x = 0; x < layout.GetLength(0); x++) - { - for (int y = 0; y < layout.GetLength(1); y++) - { - bitmap.SetPixel(x, y, layout[y, x]); - } + bitmap.SetPixel(x, y, layout[y, x]); } - - return bitmap; } - private static void TestAlgorithm( - Action, Color, Color> algorithm, - ValueTuple fillLocation, - Color targetColor, - Color replacementColor, - ValueTuple testLocation, - Color expectedColor) - { - Bitmap bitmap = GenerateTestBitmap(); - algorithm(bitmap, fillLocation, targetColor, replacementColor); - Color actualColor = bitmap.GetPixel(testLocation.Item1, testLocation.Item2); - actualColor.Should().Be(expectedColor); - } + return bitmap; + } + + private static void TestAlgorithm( + Action, Color, Color> algorithm, + ValueTuple fillLocation, + Color targetColor, + Color replacementColor, + ValueTuple testLocation, + Color expectedColor) + { + Bitmap bitmap = GenerateTestBitmap(); + algorithm(bitmap, fillLocation, targetColor, replacementColor); + Color actualColor = bitmap.GetPixel(testLocation.Item1, testLocation.Item2); + actualColor.Should().Be(expectedColor); } } diff --git a/Algorithms.Tests/Other/GaussOptimizationTest.cs b/Algorithms.Tests/Other/GaussOptimizationTest.cs index 338fafbd..137212f9 100644 --- a/Algorithms.Tests/Other/GaussOptimizationTest.cs +++ b/Algorithms.Tests/Other/GaussOptimizationTest.cs @@ -2,100 +2,96 @@ using NUnit.Framework; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class GaussOptimizationTest { - public static class GaussOptimizationTest + [Test] + public static void Verify_Gauss_Optimization_Positive() { - [Test] - public static void Verify_Gauss_Optimization_Positive() - { - // Arrange - var gaussOptimization = new GaussOptimization(); + // Arrange + var gaussOptimization = new GaussOptimization(); - // Declaration of the constants that are used in the function - var coefficients = new List { 0.3, 0.6, 2.6, 0.3, 0.2, 1.4 }; + // Declaration of the constants that are used in the function + var coefficients = new List { 0.3, 0.6, 2.6, 0.3, 0.2, 1.4 }; - // Description of the function - var func = (double x1, double x2) => + // Description of the function + var func = (double x1, double x2) => + { + if (x1 > 1 || x1 < 0 || x2 > 1 || x2 < 0) { - if (x1 > 1 || x1 < 0 || x2 > 1 || x2 < 0) - { - return 0; - } + return 0; + } - return coefficients[0] + coefficients[1] * x1 + coefficients[2] * x2 + coefficients[3] * x1 * x2 + - coefficients[4] * x1 * x1 + coefficients[5] * x2 * x2; - }; + return coefficients[0] + coefficients[1] * x1 + coefficients[2] * x2 + coefficients[3] * x1 * x2 + + coefficients[4] * x1 * x1 + coefficients[5] * x2 * x2; + }; - // The parameter that identifies how much step size will be decreased each iteration - double n = 2.4; + // The parameter that identifies how much step size will be decreased each iteration + double n = 2.4; - // Default values of x1 and x2. These values will be used for the calculation of the next - // coordinates by Gauss optimization method - double x1 = 0.5; - double x2 = 0.5; + // Default values of x1 and x2. These values will be used for the calculation of the next + // coordinates by Gauss optimization method + double x1 = 0.5; + double x2 = 0.5; - // Default optimization step - double step = 0.5; + // Default optimization step + double step = 0.5; - // This value is used to control the accuracy of the optimization. In case if the error is less - // than eps, optimization will be stopped - double eps = Math.Pow(0.1, 10); + // This value is used to control the accuracy of the optimization. In case if the error is less + // than eps, optimization will be stopped + double eps = Math.Pow(0.1, 10); - // Act - (x1, x2) = gaussOptimization.Optimize(func, n, step, eps, x1, x2); + // Act + (x1, x2) = gaussOptimization.Optimize(func, n, step, eps, x1, x2); - // Assert - Assert.AreEqual(x1, 1, 0.3); - Assert.AreEqual(x2, 1, 0.3); - } + // Assert + Assert.AreEqual(x1, 1, 0.3); + Assert.AreEqual(x2, 1, 0.3); + } - [Test] - public static void Verify_Gauss_Optimization_Negative() - { - // Arrange - var gaussOptimization = new GaussOptimization(); + [Test] + public static void Verify_Gauss_Optimization_Negative() + { + // Arrange + var gaussOptimization = new GaussOptimization(); - // Declaration of the constants that are used in the function - var coefficients = new List { -0.3, -0.6, -2.6, -0.3, -0.2, -1.4 }; + // Declaration of the constants that are used in the function + var coefficients = new List { -0.3, -0.6, -2.6, -0.3, -0.2, -1.4 }; - // Description of the function - var func = (double x1, double x2) => + // Description of the function + var func = (double x1, double x2) => + { + if (x1 > 0 || x1 < -1 || x2 > 0 || x2 < -1) { - if (x1 > 0 || x1 < -1 || x2 > 0 || x2 < -1) - { - return 0; - } + return 0; + } - return coefficients[0] + coefficients[1] * x1 + coefficients[2] * x2 + coefficients[3] * x1 * x2 + - coefficients[4] * x1 * x1 + coefficients[5] * x2 * x2; - }; + return coefficients[0] + coefficients[1] * x1 + coefficients[2] * x2 + coefficients[3] * x1 * x2 + + coefficients[4] * x1 * x1 + coefficients[5] * x2 * x2; + }; - // The parameter that identifies how much step size will be decreased each iteration - double n = 2.4; + // The parameter that identifies how much step size will be decreased each iteration + double n = 2.4; - // Default values of x1 and x2. These values will be used for the calculation of the next - // coordinates by Gauss optimization method - double x1 = -0.5; - double x2 = -0.5; + // Default values of x1 and x2. These values will be used for the calculation of the next + // coordinates by Gauss optimization method + double x1 = -0.5; + double x2 = -0.5; - // Default optimization step - double step = 0.5; + // Default optimization step + double step = 0.5; - // This value is used to control the accuracy of the optimization. In case if the error is less - // than eps, optimization will be stopped - double eps = Math.Pow(0.1, 10); + // This value is used to control the accuracy of the optimization. In case if the error is less + // than eps, optimization will be stopped + double eps = Math.Pow(0.1, 10); - // Act - (x1, x2) = gaussOptimization.Optimize(func, n, step, eps, x1, x2); + // Act + (x1, x2) = gaussOptimization.Optimize(func, n, step, eps, x1, x2); - // Assert - Assert.AreEqual(x1, -1, 0.3); - Assert.AreEqual(x2, -1, 0.3); - } + // Assert + Assert.AreEqual(x1, -1, 0.3); + Assert.AreEqual(x2, -1, 0.3); } } diff --git a/Algorithms.Tests/Other/GeoLocationTests.cs b/Algorithms.Tests/Other/GeoLocationTests.cs index 9593f9a4..a5d1ce68 100644 --- a/Algorithms.Tests/Other/GeoLocationTests.cs +++ b/Algorithms.Tests/Other/GeoLocationTests.cs @@ -1,26 +1,25 @@ -using System; +using System; using Algorithms.Other; using NUnit.Framework; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class GeoLocationTests { - public static class GeoLocationTests + [Test] + [TestCase(53.430488d, -2.96129d, 53.430488d, -2.96129d, 0d)] + [TestCase(53.430971d, -2.959806d, 53.430242d, -2.960830d, 105d)] + public static void CalculateDistanceFromLatLngTest( + double lat1, + double lng1, + double lat2, + double lng2, + double expectedValue) { - [Test] - [TestCase(53.430488d, -2.96129d, 53.430488d, -2.96129d, 0d)] - [TestCase(53.430971d, -2.959806d, 53.430242d, -2.960830d, 105d)] - public static void CalculateDistanceFromLatLngTest( - double lat1, - double lng1, - double lat2, - double lng2, - double expectedValue) - { - var result = GeoLocation.CalculateDistanceFromLatLng(lat1, lng1, lat2, lng2); - var actualValue = Convert.ToDouble(result); + var result = GeoLocation.CalculateDistanceFromLatLng(lat1, lng1, lat2, lng2); + var actualValue = Convert.ToDouble(result); - // Assert - Assert.AreEqual(expectedValue, actualValue, 1d); // Accept if distance diff is +/-1 meters. - } + // Assert + Assert.AreEqual(expectedValue, actualValue, 1d); // Accept if distance diff is +/-1 meters. } } diff --git a/Algorithms.Tests/Other/Int2BinaryTests.cs b/Algorithms.Tests/Other/Int2BinaryTests.cs index af917978..65794ae4 100644 --- a/Algorithms.Tests/Other/Int2BinaryTests.cs +++ b/Algorithms.Tests/Other/Int2BinaryTests.cs @@ -1,68 +1,67 @@ -using Algorithms.Other; +using Algorithms.Other; using NUnit.Framework; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class Int2BinaryTests { - public static class Int2BinaryTests + [Test] + [TestCase((ushort)0, "0000000000000000")] + [TestCase((ushort)0b1, "0000000000000001")] + [TestCase((ushort)0b0001010100111000, "0001010100111000")] + [TestCase((ushort)0b1110111100110010, "1110111100110010")] + [TestCase((ushort)(ushort.MaxValue - 1), "1111111111111110")] + [TestCase(ushort.MaxValue, "1111111111111111")] + public static void GetsBinary(ushort input, string expected) { - [Test] - [TestCase((ushort)0, "0000000000000000")] - [TestCase((ushort)0b1, "0000000000000001")] - [TestCase((ushort)0b0001010100111000, "0001010100111000")] - [TestCase((ushort)0b1110111100110010, "1110111100110010")] - [TestCase((ushort)(ushort.MaxValue - 1), "1111111111111110")] - [TestCase(ushort.MaxValue, "1111111111111111")] - public static void GetsBinary(ushort input, string expected) - { - // Arrange + // Arrange - // Act - var result = Int2Binary.Int2Bin(input); + // Act + var result = Int2Binary.Int2Bin(input); - // Assert - Assert.AreEqual(expected, result); - } + // Assert + Assert.AreEqual(expected, result); + } - [Test] - [TestCase((uint)0, "00000000000000000000000000000000")] - [TestCase((uint)0b1, "00000000000000000000000000000001")] - [TestCase((uint)0b0001010100111000, "00000000000000000001010100111000")] - [TestCase((uint)0b1110111100110010, "00000000000000001110111100110010")] - [TestCase(0b10101100001110101110111100110010, "10101100001110101110111100110010")] - [TestCase(uint.MaxValue - 1, "11111111111111111111111111111110")] - [TestCase(uint.MaxValue, "11111111111111111111111111111111")] - public static void GetsBinary(uint input, string expected) - { - // Arrange + [Test] + [TestCase((uint)0, "00000000000000000000000000000000")] + [TestCase((uint)0b1, "00000000000000000000000000000001")] + [TestCase((uint)0b0001010100111000, "00000000000000000001010100111000")] + [TestCase((uint)0b1110111100110010, "00000000000000001110111100110010")] + [TestCase(0b10101100001110101110111100110010, "10101100001110101110111100110010")] + [TestCase(uint.MaxValue - 1, "11111111111111111111111111111110")] + [TestCase(uint.MaxValue, "11111111111111111111111111111111")] + public static void GetsBinary(uint input, string expected) + { + // Arrange - // Act - var result = Int2Binary.Int2Bin(input); + // Act + var result = Int2Binary.Int2Bin(input); - // Assert - Assert.AreEqual(expected, result); - } + // Assert + Assert.AreEqual(expected, result); + } - [Test] - [TestCase((ulong)0, "0000000000000000000000000000000000000000000000000000000000000000")] - [TestCase((ulong)0b1, "0000000000000000000000000000000000000000000000000000000000000001")] - [TestCase((ulong)0b0001010100111000, "0000000000000000000000000000000000000000000000000001010100111000")] - [TestCase((ulong)0b1110111100110010, "0000000000000000000000000000000000000000000000001110111100110010")] - [TestCase((ulong)0b10101100001110101110111100110010, - "0000000000000000000000000000000010101100001110101110111100110010")] - [TestCase(0b1000101110100101000011010101110101010101110101001010000011111000, - "1000101110100101000011010101110101010101110101001010000011111000")] - [TestCase(ulong.MaxValue - 1, "1111111111111111111111111111111111111111111111111111111111111110")] - [TestCase(ulong.MaxValue, "1111111111111111111111111111111111111111111111111111111111111111")] - public static void GetsBinary(ulong input, string expected) - { - // Arrange + [Test] + [TestCase((ulong)0, "0000000000000000000000000000000000000000000000000000000000000000")] + [TestCase((ulong)0b1, "0000000000000000000000000000000000000000000000000000000000000001")] + [TestCase((ulong)0b0001010100111000, "0000000000000000000000000000000000000000000000000001010100111000")] + [TestCase((ulong)0b1110111100110010, "0000000000000000000000000000000000000000000000001110111100110010")] + [TestCase((ulong)0b10101100001110101110111100110010, + "0000000000000000000000000000000010101100001110101110111100110010")] + [TestCase(0b1000101110100101000011010101110101010101110101001010000011111000, + "1000101110100101000011010101110101010101110101001010000011111000")] + [TestCase(ulong.MaxValue - 1, "1111111111111111111111111111111111111111111111111111111111111110")] + [TestCase(ulong.MaxValue, "1111111111111111111111111111111111111111111111111111111111111111")] + public static void GetsBinary(ulong input, string expected) + { + // Arrange - // Act - var result = Int2Binary.Int2Bin(input); + // Act + var result = Int2Binary.Int2Bin(input); - // Assert - Assert.AreEqual(expected, result); - } + // Assert + Assert.AreEqual(expected, result); } } diff --git a/Algorithms.Tests/Other/JulianEasterTests.cs b/Algorithms.Tests/Other/JulianEasterTests.cs index ba103832..3c7a260a 100644 --- a/Algorithms.Tests/Other/JulianEasterTests.cs +++ b/Algorithms.Tests/Other/JulianEasterTests.cs @@ -3,30 +3,29 @@ using Algorithms.Other; using NUnit.Framework; -namespace Algorithms.Tests.Other -{ - /// - /// A class for testing the Meeus's Julian Easter algorithm. - /// - public static class JulianEasterTest - { - private static readonly JulianCalendar Calendar = new(); +namespace Algorithms.Tests.Other; - [TestCaseSource(nameof(CalculateCases))] - public static void CalculateTest(int year, DateTime expected) - { - var result = JulianEaster.Calculate(year); +/// +/// A class for testing the Meeus's Julian Easter algorithm. +/// +public static class JulianEasterTest +{ + private static readonly JulianCalendar Calendar = new(); - Assert.AreEqual(expected, result); - } + [TestCaseSource(nameof(CalculateCases))] + public static void CalculateTest(int year, DateTime expected) + { + var result = JulianEaster.Calculate(year); - private static readonly object[] CalculateCases = - { - new object[] { 1800, new DateTime(1800, 04, 08, Calendar) }, - new object[] { 1950, new DateTime(1950, 03, 27, Calendar) }, - new object[] { 1991, new DateTime(1991, 03, 25, Calendar) }, - new object[] { 2000, new DateTime(2000, 04, 17, Calendar) }, - new object[] { 2199, new DateTime(2199, 04, 07, Calendar) } - }; + Assert.AreEqual(expected, result); } + + private static readonly object[] CalculateCases = + { + new object[] { 1800, new DateTime(1800, 04, 08, Calendar) }, + new object[] { 1950, new DateTime(1950, 03, 27, Calendar) }, + new object[] { 1991, new DateTime(1991, 03, 25, Calendar) }, + new object[] { 2000, new DateTime(2000, 04, 17, Calendar) }, + new object[] { 2199, new DateTime(2199, 04, 07, Calendar) } + }; } diff --git a/Algorithms.Tests/Other/KochSnowflakeTest.cs b/Algorithms.Tests/Other/KochSnowflakeTest.cs index 3620eed0..9c132452 100644 --- a/Algorithms.Tests/Other/KochSnowflakeTest.cs +++ b/Algorithms.Tests/Other/KochSnowflakeTest.cs @@ -6,47 +6,46 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class KochSnowflakeTest { - public static class KochSnowflakeTest + [Test] + public static void TestIterateMethod() { - [Test] - public static void TestIterateMethod() - { - List vectors = new() { new Vector2(0, 0), new Vector2(1, 0) }; - List result = KochSnowflake.Iterate(vectors, 1); - result[0].Should().Be(new Vector2(0, 0)); - result[1].Should().Be(new Vector2((float)1 / 3, 0)); + List vectors = new() { new Vector2(0, 0), new Vector2(1, 0) }; + List result = KochSnowflake.Iterate(vectors, 1); + result[0].Should().Be(new Vector2(0, 0)); + result[1].Should().Be(new Vector2((float)1 / 3, 0)); - /* Should().BeApproximately() is not defined for Vector2 or float - so the x-y-components have to be tested separately and the y-component needs to be cast to double */ - result[2].X.Should().Be(0.5f); - ((double)result[2].Y).Should().BeApproximately(Math.Sin(Math.PI / 3) / 3, 0.0001); + /* Should().BeApproximately() is not defined for Vector2 or float + so the x-y-components have to be tested separately and the y-component needs to be cast to double */ + result[2].X.Should().Be(0.5f); + ((double)result[2].Y).Should().BeApproximately(Math.Sin(Math.PI / 3) / 3, 0.0001); - result[3].Should().Be(new Vector2((float)2 / 3, 0)); - result[4].Should().Be(new Vector2(1, 0)); - } + result[3].Should().Be(new Vector2((float)2 / 3, 0)); + result[4].Should().Be(new Vector2(1, 0)); + } - [Test] - public static void BitmapWidthIsZeroOrNegative_ThrowsArgumentOutOfRangeException() - { - Assert.Throws(() => KochSnowflake.GetKochSnowflake(-200)); - } + [Test] + public static void BitmapWidthIsZeroOrNegative_ThrowsArgumentOutOfRangeException() + { + Assert.Throws(() => KochSnowflake.GetKochSnowflake(-200)); + } - [Test] - public static void TestKochSnowflakeExample() - { - var bitmapWidth = 600; - var offsetX = bitmapWidth / 10f; - var offsetY = bitmapWidth / 3.7f; + [Test] + public static void TestKochSnowflakeExample() + { + var bitmapWidth = 600; + var offsetX = bitmapWidth / 10f; + var offsetY = bitmapWidth / 3.7f; - Bitmap bitmap = KochSnowflake.GetKochSnowflake(); - bitmap.GetPixel(0, 0) - .Should() - .Be(Color.FromArgb(255, 255, 255, 255), "because the background should be white"); - bitmap.GetPixel((int)offsetX, (int)offsetY) - .Should() - .Be(Color.FromArgb(255, 0, 0, 0), "because the snowflake is drawn in black and this is the position of the first vector"); - } + Bitmap bitmap = KochSnowflake.GetKochSnowflake(); + bitmap.GetPixel(0, 0) + .Should() + .Be(Color.FromArgb(255, 255, 255, 255), "because the background should be white"); + bitmap.GetPixel((int)offsetX, (int)offsetY) + .Should() + .Be(Color.FromArgb(255, 0, 0, 0), "because the snowflake is drawn in black and this is the position of the first vector"); } } diff --git a/Algorithms.Tests/Other/LuhnTests.cs b/Algorithms.Tests/Other/LuhnTests.cs index 5dc61cea..eaa60d97 100644 --- a/Algorithms.Tests/Other/LuhnTests.cs +++ b/Algorithms.Tests/Other/LuhnTests.cs @@ -1,64 +1,63 @@ -using Algorithms.Other; +using Algorithms.Other; using NUnit.Framework; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +/// +/// A class for testing the Luhn algorithm. +/// +public class LuhnTests { - /// - /// A class for testing the Luhn algorithm. - /// - public class LuhnTests + [Test] + [TestCase("89014103211118510720")] // ICCID + [TestCase("071052120")] // Social Security Code + [TestCase("449125546588769")] // IMEI + [TestCase("4417123456789113")] // Bank card + public void ValidateTrue(string number) { - [Test] - [TestCase("89014103211118510720")] // ICCID - [TestCase("071052120")] // Social Security Code - [TestCase("449125546588769")] // IMEI - [TestCase("4417123456789113")] // Bank card - public void ValidateTrue(string number) - { - // Arrange - bool validate; + // Arrange + bool validate; - // Act - validate = Luhn.Validate(number); + // Act + validate = Luhn.Validate(number); - // Assert - Assert.True(validate); - } + // Assert + Assert.True(validate); + } - [Test] - [TestCase("89012104211118510720")] // ICCID - [TestCase("021053120")] // Social Security Code - [TestCase("449145545588969")] // IMEI - [TestCase("4437113456749113")] // Bank card - public void ValidateFalse(string number) - { - // Arrange - bool validate; + [Test] + [TestCase("89012104211118510720")] // ICCID + [TestCase("021053120")] // Social Security Code + [TestCase("449145545588969")] // IMEI + [TestCase("4437113456749113")] // Bank card + public void ValidateFalse(string number) + { + // Arrange + bool validate; - // Act - validate = Luhn.Validate(number); + // Act + validate = Luhn.Validate(number); - // Assert - Assert.False(validate); - } + // Assert + Assert.False(validate); + } - [Test] - [TestCase("x9012104211118510720")] // ICCID - [TestCase("0210x3120")] // Social Security Code - [TestCase("44914554558896x")] // IMEI - [TestCase("4437113456x49113")] // Bank card - public void GetLostNum(string number) - { - // Arrange - int lostNum; - bool validate; + [Test] + [TestCase("x9012104211118510720")] // ICCID + [TestCase("0210x3120")] // Social Security Code + [TestCase("44914554558896x")] // IMEI + [TestCase("4437113456x49113")] // Bank card + public void GetLostNum(string number) + { + // Arrange + int lostNum; + bool validate; - // Act - lostNum = Luhn.GetLostNum(number); - validate = Luhn.Validate(number.Replace("x", lostNum.ToString())); + // Act + lostNum = Luhn.GetLostNum(number); + validate = Luhn.Validate(number.Replace("x", lostNum.ToString())); - // Assert - Assert.True(validate); - } + // Assert + Assert.True(validate); } } diff --git a/Algorithms.Tests/Other/MandelbrotTest.cs b/Algorithms.Tests/Other/MandelbrotTest.cs index 6e95ba42..c481a69f 100644 --- a/Algorithms.Tests/Other/MandelbrotTest.cs +++ b/Algorithms.Tests/Other/MandelbrotTest.cs @@ -3,48 +3,47 @@ using Algorithms.Other; using NUnit.Framework; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class MandelbrotTest { - public static class MandelbrotTest + [Test] + public static void BitmapWidthIsZeroOrNegative_ThrowsArgumentOutOfRangeException() + { + Assert.Throws(() => Mandelbrot.GetBitmap(-200)); + } + + [Test] + public static void BitmapHeightIsZeroOrNegative_ThrowsArgumentOutOfRangeException() { - [Test] - public static void BitmapWidthIsZeroOrNegative_ThrowsArgumentOutOfRangeException() - { - Assert.Throws(() => Mandelbrot.GetBitmap(-200)); - } - - [Test] - public static void BitmapHeightIsZeroOrNegative_ThrowsArgumentOutOfRangeException() - { - Assert.Throws(() => Mandelbrot.GetBitmap(bitmapHeight: 0)); - } - - [Test] - public static void MaxStepIsZeroOrNegative_ThrowsArgumentOutOfRangeException() - { - Assert.Throws(() => Mandelbrot.GetBitmap(maxStep: -1)); - } - - [Test] - public static void TestBlackAndWhite() - { - Bitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: false); - // Pixel outside the Mandelbrot set should be white. - Assert.AreEqual(bitmap.GetPixel(0, 0), Color.FromArgb(255, 255, 255, 255)); - - // Pixel inside the Mandelbrot set should be black. - Assert.AreEqual(bitmap.GetPixel(400, 300), Color.FromArgb(255, 0, 0, 0)); - } - - [Test] - public static void TestColorCoded() - { - Bitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: true); - // Pixel distant to the Mandelbrot set should be red. - Assert.AreEqual(bitmap.GetPixel(0, 0), Color.FromArgb(255, 255, 0, 0)); - - // Pixel inside the Mandelbrot set should be black. - Assert.AreEqual(bitmap.GetPixel(400, 300), Color.FromArgb(255, 0, 0, 0)); - } + Assert.Throws(() => Mandelbrot.GetBitmap(bitmapHeight: 0)); + } + + [Test] + public static void MaxStepIsZeroOrNegative_ThrowsArgumentOutOfRangeException() + { + Assert.Throws(() => Mandelbrot.GetBitmap(maxStep: -1)); + } + + [Test] + public static void TestBlackAndWhite() + { + Bitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: false); + // Pixel outside the Mandelbrot set should be white. + Assert.AreEqual(bitmap.GetPixel(0, 0), Color.FromArgb(255, 255, 255, 255)); + + // Pixel inside the Mandelbrot set should be black. + Assert.AreEqual(bitmap.GetPixel(400, 300), Color.FromArgb(255, 0, 0, 0)); + } + + [Test] + public static void TestColorCoded() + { + Bitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: true); + // Pixel distant to the Mandelbrot set should be red. + Assert.AreEqual(bitmap.GetPixel(0, 0), Color.FromArgb(255, 255, 0, 0)); + + // Pixel inside the Mandelbrot set should be black. + Assert.AreEqual(bitmap.GetPixel(400, 300), Color.FromArgb(255, 0, 0, 0)); } } diff --git a/Algorithms.Tests/Other/ParetoOptimizationTests.cs b/Algorithms.Tests/Other/ParetoOptimizationTests.cs index 51b581d5..f0bb6175 100644 --- a/Algorithms.Tests/Other/ParetoOptimizationTests.cs +++ b/Algorithms.Tests/Other/ParetoOptimizationTests.cs @@ -1,46 +1,41 @@ using Algorithms.Other; using NUnit.Framework; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class ParetoOptimizationTests { - public static class ParetoOptimizationTests + [Test] + public static void Verify_Pareto_Optimization() { - [Test] - public static void Verify_Pareto_Optimization() - { - // Arrange - var paretoOptimization = new ParetoOptimization(); + // Arrange + var paretoOptimization = new ParetoOptimization(); - var matrix = new List> - { - new List { 7, 6, 5, 8, 5, 6 }, - new List { 4, 8, 4, 4, 5, 3 }, - new List { 3, 8, 1, 4, 5, 2 }, - new List { 5, 6, 3, 6, 4, 5 }, - new List { 1, 4, 8, 6, 3, 6 }, - new List { 5, 1, 8, 6, 5, 1 }, - new List { 6, 8, 3, 6, 3, 5 } - }; + var matrix = new List> + { + new List { 7, 6, 5, 8, 5, 6 }, + new List { 4, 8, 4, 4, 5, 3 }, + new List { 3, 8, 1, 4, 5, 2 }, + new List { 5, 6, 3, 6, 4, 5 }, + new List { 1, 4, 8, 6, 3, 6 }, + new List { 5, 1, 8, 6, 5, 1 }, + new List { 6, 8, 3, 6, 3, 5 } + }; - var expectedMatrix = new List> - { - new List { 7, 6, 5, 8, 5, 6 }, - new List { 4, 8, 4, 4, 5, 3 }, - new List { 1, 4, 8, 6, 3, 6 }, - new List { 5, 1, 8, 6, 5, 1 }, - new List { 6, 8, 3, 6, 3, 5 } - }; + var expectedMatrix = new List> + { + new List { 7, 6, 5, 8, 5, 6 }, + new List { 4, 8, 4, 4, 5, 3 }, + new List { 1, 4, 8, 6, 3, 6 }, + new List { 5, 1, 8, 6, 5, 1 }, + new List { 6, 8, 3, 6, 3, 5 } + }; - // Act - var optimizedMatrix = paretoOptimization.Optimize(matrix); + // Act + var optimizedMatrix = paretoOptimization.Optimize(matrix); - // Assert - Assert.AreEqual(optimizedMatrix, expectedMatrix); - } + // Assert + Assert.AreEqual(optimizedMatrix, expectedMatrix); } } diff --git a/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs b/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs index 9375118f..7a3eb7fa 100644 --- a/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs +++ b/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs @@ -1,19 +1,18 @@ using Algorithms.Other; using NUnit.Framework; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public class PollardsRhoFactorizingTests { - public class PollardsRhoFactorizingTests + [TestCase(8051, 97)] + [TestCase(105, 21)] + [TestCase(253, 11)] + [TestCase(10403, 101)] + [TestCase(187, 11)] + public void SimpleTest(int number, int expectedResult) { - [TestCase(8051, 97)] - [TestCase(105, 21)] - [TestCase(253, 11)] - [TestCase(10403, 101)] - [TestCase(187, 11)] - public void SimpleTest(int number, int expectedResult) - { - var result = PollardsRhoFactorizing.Calculate(number); - Assert.AreEqual(expectedResult, result); - } + var result = PollardsRhoFactorizing.Calculate(number); + Assert.AreEqual(expectedResult, result); } } diff --git a/Algorithms.Tests/Other/RGBHSVConversionTest.cs b/Algorithms.Tests/Other/RGBHSVConversionTest.cs index 9b886186..de84ec2c 100644 --- a/Algorithms.Tests/Other/RGBHSVConversionTest.cs +++ b/Algorithms.Tests/Other/RGBHSVConversionTest.cs @@ -3,83 +3,82 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class RgbHsvConversionTest { - public static class RgbHsvConversionTest + [Test] + public static void HueOutOfRange_ThrowsArgumentOutOfRangeException() { - [Test] - public static void HueOutOfRange_ThrowsArgumentOutOfRangeException() - { - Action act = () => RgbHsvConversion.HsvToRgb(400, 0, 0); - act.Should().Throw(); - } + Action act = () => RgbHsvConversion.HsvToRgb(400, 0, 0); + act.Should().Throw(); + } - [Test] - public static void SaturationOutOfRange_ThrowsArgumentOutOfRangeException() - { - Action act = () => RgbHsvConversion.HsvToRgb(0, 2, 0); - act.Should().Throw(); - } + [Test] + public static void SaturationOutOfRange_ThrowsArgumentOutOfRangeException() + { + Action act = () => RgbHsvConversion.HsvToRgb(0, 2, 0); + act.Should().Throw(); + } - [Test] - public static void ValueOutOfRange_ThrowsArgumentOutOfRangeException() - { - Action act = () => RgbHsvConversion.HsvToRgb(0, 0, 2); - act.Should().Throw(); - } + [Test] + public static void ValueOutOfRange_ThrowsArgumentOutOfRangeException() + { + Action act = () => RgbHsvConversion.HsvToRgb(0, 0, 2); + act.Should().Throw(); + } - // expected RGB-values taken from https://www.rapidtables.com/convert/color/hsv-to-rgb.html - [Test] - [TestCase(0, 0, 0, 0, 0, 0)] - [TestCase(0, 0, 1, 255, 255, 255)] - [TestCase(0, 1, 1, 255, 0, 0)] - [TestCase(60, 1, 1, 255, 255, 0)] - [TestCase(120, 1, 1, 0, 255, 0)] - [TestCase(240, 1, 1, 0, 0, 255)] - [TestCase(300, 1, 1, 255, 0, 255)] - [TestCase(180, 0.5, 0.5, 64, 128, 128)] - [TestCase(234, 0.14, 0.88, 193, 196, 224)] - [TestCase(330, 0.75, 0.5, 128, 32, 80)] - public static void TestRgbOutput( - double hue, - double saturation, - double value, - byte expectedRed, - byte exptectedGreen, - byte exptectedBlue) - { - var rgb = RgbHsvConversion.HsvToRgb(hue, saturation, value); - rgb.Item1.Should().Be(expectedRed); - rgb.Item2.Should().Be(exptectedGreen); - rgb.Item3.Should().Be(exptectedBlue); - } + // expected RGB-values taken from https://www.rapidtables.com/convert/color/hsv-to-rgb.html + [Test] + [TestCase(0, 0, 0, 0, 0, 0)] + [TestCase(0, 0, 1, 255, 255, 255)] + [TestCase(0, 1, 1, 255, 0, 0)] + [TestCase(60, 1, 1, 255, 255, 0)] + [TestCase(120, 1, 1, 0, 255, 0)] + [TestCase(240, 1, 1, 0, 0, 255)] + [TestCase(300, 1, 1, 255, 0, 255)] + [TestCase(180, 0.5, 0.5, 64, 128, 128)] + [TestCase(234, 0.14, 0.88, 193, 196, 224)] + [TestCase(330, 0.75, 0.5, 128, 32, 80)] + public static void TestRgbOutput( + double hue, + double saturation, + double value, + byte expectedRed, + byte exptectedGreen, + byte exptectedBlue) + { + var rgb = RgbHsvConversion.HsvToRgb(hue, saturation, value); + rgb.Item1.Should().Be(expectedRed); + rgb.Item2.Should().Be(exptectedGreen); + rgb.Item3.Should().Be(exptectedBlue); + } - // Parameters of test-cases for TestRGBOutput reversed - [Test] - [TestCase(0, 0, 0, 0, 0, 0)] - [TestCase(255, 255, 255, 0, 0, 1)] - [TestCase(255, 0, 0, 0, 1, 1)] - [TestCase(255, 255, 0, 60, 1, 1)] - [TestCase(0, 255, 0, 120, 1, 1)] - [TestCase(0, 0, 255, 240, 1, 1)] - [TestCase(255, 0, 255, 300, 1, 1)] - [TestCase(64, 128, 128, 180, 0.5, 0.5)] - [TestCase(193, 196, 224, 234, 0.14, 0.88)] - [TestCase(128, 32, 80, 330, 0.75, 0.5)] - public static void TestHsvOutput( - byte red, - byte green, - byte blue, - double expectedHue, - double expectedSaturation, - double expectedValue) - { - var hsv = RgbHsvConversion.RgbToHsv(red, green, blue); + // Parameters of test-cases for TestRGBOutput reversed + [Test] + [TestCase(0, 0, 0, 0, 0, 0)] + [TestCase(255, 255, 255, 0, 0, 1)] + [TestCase(255, 0, 0, 0, 1, 1)] + [TestCase(255, 255, 0, 60, 1, 1)] + [TestCase(0, 255, 0, 120, 1, 1)] + [TestCase(0, 0, 255, 240, 1, 1)] + [TestCase(255, 0, 255, 300, 1, 1)] + [TestCase(64, 128, 128, 180, 0.5, 0.5)] + [TestCase(193, 196, 224, 234, 0.14, 0.88)] + [TestCase(128, 32, 80, 330, 0.75, 0.5)] + public static void TestHsvOutput( + byte red, + byte green, + byte blue, + double expectedHue, + double expectedSaturation, + double expectedValue) + { + var hsv = RgbHsvConversion.RgbToHsv(red, green, blue); - // approximate-assertions needed because of small deviations due to converting between byte-values and double-values. - hsv.Item1.Should().BeApproximately(expectedHue, 0.2); - hsv.Item2.Should().BeApproximately(expectedSaturation, 0.002); - hsv.Item3.Should().BeApproximately(expectedValue, 0.002); - } + // approximate-assertions needed because of small deviations due to converting between byte-values and double-values. + hsv.Item1.Should().BeApproximately(expectedHue, 0.2); + hsv.Item2.Should().BeApproximately(expectedSaturation, 0.002); + hsv.Item3.Should().BeApproximately(expectedValue, 0.002); } } diff --git a/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs b/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs index 21102bf2..ba837fcb 100644 --- a/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs +++ b/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs @@ -3,682 +3,681 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public static class SieveOfEratosthenesTests { - public static class SieveOfEratosthenesTests + private static readonly long[] First10000PrimeNumbers = { - private static readonly long[] First10000PrimeNumbers = - { - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, - 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, - 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, - 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, - 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, - 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, - 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, - 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, - 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, - 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, - 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, - 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, - 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, - 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, - 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, - 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, - 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, - 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, - 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, - 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, - 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, - 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, - 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, - 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, - 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, - 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, - 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, - 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, - 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, - 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, - 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, - 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, - 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, - 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, - 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, - 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, - 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, - 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, - 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, - 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, - 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, - 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, - 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, - 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, - 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, - 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, - 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, - 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, - 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, - 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, - 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, - 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, - 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, - 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, - 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, - 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, - 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, - 8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, - 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, - 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, - 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, - 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, - 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, - 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, - 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, - 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 9859, - 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, - 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, - 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, - 10313, 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, - 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589, 10597, 10601, 10607, - 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, - 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, - 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, - 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, - 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, - 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, - 11489, 11491, 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, - 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783, 11789, 11801, - 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, - 11933, 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, - 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, - 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, - 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, - 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, - 12601, 12611, 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, - 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889, 12893, - 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, - 13007, 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, - 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, - 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, - 13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, - 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, - 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, - 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011, - 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, - 14197, 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, - 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, - 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, - 14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, - 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, - 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, - 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, - 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, - 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, - 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, - 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, - 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, - 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, - 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, - 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, - 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, - 16481, 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, - 16649, 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, - 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, 16921, 16927, 16931, 16937, - 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, - 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, - 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, - 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, - 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, - 17669, 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, - 17837, 17839, 17851, 17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, - 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, 18061, 18077, 18089, 18097, - 18119, 18121, 18127, 18131, 18133, 18143, 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, - 18233, 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, 18353, 18367, - 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, - 18517, 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, - 18701, 18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, - 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, 19013, 19031, 19037, 19051, - 19069, 19073, 19079, 19081, 19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, - 19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, 19333, 19373, 19379, 19381, - 19387, 19391, 19403, 19417, 19421, 19423, 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, - 19477, 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, 19603, - 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, - 19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, - 19949, 19961, 19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, - 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, 20161, 20173, 20177, 20183, - 20201, 20219, 20231, 20233, 20249, 20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, - 20357, 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, 20479, 20483, 20507, - 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, - 20693, 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, - 20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, - 20983, 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, - 21139, 21143, 21149, 21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, - 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, 21391, 21397, 21401, 21407, - 21419, 21433, 21467, 21481, 21487, 21491, 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, - 21563, 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, 21673, 21683, - 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, - 21841, 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, - 22003, 22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, - 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, 22247, 22259, 22271, 22273, - 22277, 22279, 22283, 22291, 22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, - 22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, 22549, 22567, 22571, 22573, - 22613, 22619, 22621, 22637, 22639, 22643, 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, - 22727, 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, 22871, - 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, - 23029, 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, - 23167, 23173, 23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, - 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, 23459, 23473, 23497, 23509, - 23531, 23537, 23539, 23549, 23557, 23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, - 23629, 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, 23753, 23761, 23767, - 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, - 23909, 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, - 24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, - 24169, 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, - 24371, 24373, 24379, 24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, - 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, 24671, 24677, 24683, 24691, - 24697, 24709, 24733, 24749, 24763, 24767, 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, - 24877, 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, 25013, 25031, - 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, - 25183, 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, - 25343, 25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, - 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, 25609, 25621, 25633, 25639, - 25643, 25657, 25667, 25673, 25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, - 25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, 25919, 25931, 25933, 25939, - 25943, 25951, 25969, 25981, 25997, 25999, 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, - 26111, 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, 26249, - 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, - 26399, 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, - 26561, 26573, 26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, - 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, 26813, 26821, 26833, 26839, - 26849, 26861, 26863, 26879, 26881, 26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, - 26987, 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, 27103, 27107, 27109, - 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, - 27329, 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, - 27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, - 27691, 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, - 27799, 27803, 27809, 27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, - 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, 28057, 28069, 28081, 28087, - 28097, 28099, 28109, 28111, 28123, 28151, 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, - 28283, 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, 28429, 28433, - 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, - 28579, 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, - 28687, 28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, - 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, 28949, 28961, 28979, 29009, - 29017, 29021, 29023, 29027, 29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, - 29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, 29269, 29287, 29297, 29303, - 29311, 29327, 29333, 29339, 29347, 29363, 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, - 29443, 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, 29611, - 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, - 29819, 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, - 29989, 30011, 30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, - 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, 30253, 30259, 30269, 30271, - 30293, 30307, 30313, 30319, 30323, 30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, - 30469, 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, 30593, 30631, 30637, - 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, - 30803, 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, - 30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, - 31091, 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, - 31231, 31237, 31247, 31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, - 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, 31513, 31517, 31531, 31541, - 31543, 31547, 31567, 31573, 31583, 31601, 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, - 31721, 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, 31859, 31873, - 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, - 32063, 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, - 32203, 32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, - 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, 32429, 32441, 32443, 32467, - 32479, 32491, 32497, 32503, 32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, - 32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, 32719, 32749, 32771, 32779, - 32783, 32789, 32797, 32801, 32803, 32831, 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, - 32939, 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, 33053, - 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, - 33211, 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, - 33377, 33391, 33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, - 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, 33617, 33619, 33623, 33629, - 33637, 33641, 33647, 33679, 33703, 33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, - 33797, 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, 33923, 33931, 33937, - 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, - 34157, 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, - 34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, - 34457, 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, - 34591, 34603, 34607, 34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, - 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, 34849, 34871, 34877, 34883, - 34897, 34913, 34919, 34939, 34949, 34961, 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, - 35083, 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, 35221, 35227, - 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, - 35401, 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, - 35537, 35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, - 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, 35869, 35879, 35897, 35899, - 35911, 35923, 35933, 35951, 35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, - 36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, 36187, 36191, 36209, 36217, - 36229, 36241, 36251, 36263, 36269, 36277, 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, - 36383, 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, 36541, - 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, - 36691, 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, - 36821, 36833, 36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, - 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, 37061, 37087, 37097, 37117, - 37123, 37139, 37159, 37171, 37181, 37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, - 37309, 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, 37423, 37441, 37447, - 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, - 37573, 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, - 37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, - 37951, 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, - 38119, 38149, 38153, 38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, - 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, 38377, 38393, 38431, 38447, - 38449, 38453, 38459, 38461, 38501, 38543, 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, - 38639, 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, 38737, 38747, - 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, - 38921, 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, - 39097, 39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, - 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, 39341, 39343, 39359, 39367, - 39371, 39373, 39383, 39397, 39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, - 39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, 39671, 39679, 39703, 39709, - 39719, 39727, 39733, 39749, 39761, 39769, 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, - 39857, 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, 40009, - 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, - 40169, 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, - 40361, 40387, 40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, - 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, 40693, 40697, 40699, 40709, - 40739, 40751, 40759, 40763, 40771, 40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, - 40867, 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, 41011, 41017, 41023, - 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, - 41183, 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, - 41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, - 41507, 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, - 41627, 41641, 41647, 41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, - 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, 41903, 41911, 41927, 41941, - 41947, 41953, 41957, 41959, 41969, 41981, 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, - 42073, 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, 42209, 42221, - 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, - 42379, 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, - 42487, 42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, - 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, 42751, 42767, 42773, 42787, - 42793, 42797, 42821, 42829, 42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, - 42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, 43063, 43067, 43093, 43103, - 43117, 43133, 43151, 43159, 43177, 43189, 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, - 43319, 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, 43499, - 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, - 43661, 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, - 43853, 43867, 43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, - 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, 44111, 44119, 44123, 44129, - 44131, 44159, 44171, 44179, 44189, 44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, - 44279, 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, 44483, 44491, 44497, - 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, - 44641, 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, - 44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, - 44953, 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, - 45131, 45137, 45139, 45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, - 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, 45413, 45427, 45433, 45439, - 45481, 45491, 45497, 45503, 45523, 45533, 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, - 45641, 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, 45779, 45817, - 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, - 45979, 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, - 46153, 46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, - 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, 46451, 46457, 46471, 46477, - 46489, 46499, 46507, 46511, 46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, - 46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, 46751, 46757, 46769, 46771, - 46807, 46811, 46817, 46819, 46829, 46831, 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, - 46993, 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, 47143, - 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, - 47317, 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, - 47497, 47501, 47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, - 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, 47737, 47741, 47743, 47777, - 47779, 47791, 47797, 47807, 47809, 47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, - 47939, 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, 48079, 48091, 48109, - 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, - 48299, 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, - 48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, - 48611, 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, - 48779, 48781, 48787, 48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, - 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, 49037, 49043, 49057, 49069, - 49081, 49103, 49109, 49117, 49121, 49123, 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, - 49211, 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, 49369, 49391, - 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, - 49537, 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, - 49711, 49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, - 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, 49991, 49993, 49999, 50021, - 50023, 50033, 50047, 50051, 50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, - 50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, 50287, 50291, 50311, 50321, - 50329, 50333, 50341, 50359, 50363, 50377, 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, - 50503, 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, 50651, - 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, - 50867, 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, - 51043, 51047, 51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, - 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, 51341, 51343, 51347, 51349, - 51361, 51383, 51407, 51413, 51419, 51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, - 51487, 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, 51607, 51613, 51631, - 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, - 51803, 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, - 51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, - 52127, 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, - 52289, 52291, 52301, 52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, - 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, 52583, 52609, 52627, 52631, - 52639, 52667, 52673, 52691, 52697, 52709, 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, - 52813, 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, 52957, 52963, - 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, - 53117, 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, - 53279, 53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, - 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, 53597, 53609, 53611, 53617, - 53623, 53629, 53633, 53639, 53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, - 53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, 53897, 53899, 53917, 53923, - 53927, 53939, 53951, 53959, 53987, 53993, 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, - 54121, 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, 54311, - 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, - 54443, 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, - 54581, 54583, 54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, - 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, 54881, 54907, 54917, 54919, - 54941, 54949, 54959, 54973, 54979, 54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, - 55103, 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, 55229, 55243, 55249, - 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, - 55457, 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, - 55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, - 55793, 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, - 55903, 55921, 55927, 55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, - 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, 56197, 56207, 56209, 56237, - 56239, 56249, 56263, 56267, 56269, 56299, 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, - 56431, 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, 56527, 56531, - 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, - 56711, 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, - 56857, 56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, - 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, 57107, 57119, 57131, 57139, - 57143, 57149, 57163, 57173, 57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, - 57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, 57397, 57413, 57427, 57457, - 57467, 57487, 57493, 57503, 57527, 57529, 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, - 57653, 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, 57787, - 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, - 57947, 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, - 58111, 58129, 58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, - 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, 58391, 58393, 58403, 58411, - 58417, 58427, 58439, 58441, 58451, 58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, - 58601, 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, 58733, 58741, 58757, - 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, - 58967, 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, - 59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, - 59233, 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, - 59399, 59407, 59417, 59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, - 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, 59663, 59669, 59671, 59693, - 59699, 59707, 59723, 59729, 59743, 59747, 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, - 59887, 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, 60077, 60083, - 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, - 60251, 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, - 60427, 60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, - 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, 60727, 60733, 60737, 60757, - 60761, 60763, 60773, 60779, 60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, - 60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, 61051, 61057, 61091, 61099, - 61121, 61129, 61141, 61151, 61153, 61169, 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, - 61333, 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, 61483, - 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, - 61631, 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, - 61781, 61813, 61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, - 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, 62081, 62099, 62119, 62129, - 62131, 62137, 62141, 62143, 62171, 62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, - 62303, 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, 62473, 62477, 62483, - 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, - 62653, 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, - 62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, - 62989, 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, - 63199, 63211, 63241, 63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, - 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, 63467, 63473, 63487, 63493, - 63499, 63521, 63527, 63533, 63541, 63559, 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, - 63647, 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, 63743, 63761, - 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, - 63929, 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, - 64151, 64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, - 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, 64483, 64489, 64499, 64513, - 64553, 64567, 64577, 64579, 64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, - 64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, 64853, 64871, 64877, 64879, - 64891, 64901, 64919, 64921, 64927, 64937, 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, - 65063, 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, 65179, - 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, - 65381, 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, 65519, 65521, 65537, 65539, - 65543, 65551, 65557, 65563, 65579, 65581, 65587, 65599, 65609, 65617, 65629, 65633, 65647, 65651, 65657, - 65677, 65687, 65699, 65701, 65707, 65713, 65717, 65719, 65729, 65731, 65761, 65777, 65789, 65809, 65827, - 65831, 65837, 65839, 65843, 65851, 65867, 65881, 65899, 65921, 65927, 65929, 65951, 65957, 65963, 65981, - 65983, 65993, 66029, 66037, 66041, 66047, 66067, 66071, 66083, 66089, 66103, 66107, 66109, 66137, 66161, - 66169, 66173, 66179, 66191, 66221, 66239, 66271, 66293, 66301, 66337, 66343, 66347, 66359, 66361, 66373, - 66377, 66383, 66403, 66413, 66431, 66449, 66457, 66463, 66467, 66491, 66499, 66509, 66523, 66529, 66533, - 66541, 66553, 66569, 66571, 66587, 66593, 66601, 66617, 66629, 66643, 66653, 66683, 66697, 66701, 66713, - 66721, 66733, 66739, 66749, 66751, 66763, 66791, 66797, 66809, 66821, 66841, 66851, 66853, 66863, 66877, - 66883, 66889, 66919, 66923, 66931, 66943, 66947, 66949, 66959, 66973, 66977, 67003, 67021, 67033, 67043, - 67049, 67057, 67061, 67073, 67079, 67103, 67121, 67129, 67139, 67141, 67153, 67157, 67169, 67181, 67187, - 67189, 67211, 67213, 67217, 67219, 67231, 67247, 67261, 67271, 67273, 67289, 67307, 67339, 67343, 67349, - 67369, 67391, 67399, 67409, 67411, 67421, 67427, 67429, 67433, 67447, 67453, 67477, 67481, 67489, 67493, - 67499, 67511, 67523, 67531, 67537, 67547, 67559, 67567, 67577, 67579, 67589, 67601, 67607, 67619, 67631, - 67651, 67679, 67699, 67709, 67723, 67733, 67741, 67751, 67757, 67759, 67763, 67777, 67783, 67789, 67801, - 67807, 67819, 67829, 67843, 67853, 67867, 67883, 67891, 67901, 67927, 67931, 67933, 67939, 67943, 67957, - 67961, 67967, 67979, 67987, 67993, 68023, 68041, 68053, 68059, 68071, 68087, 68099, 68111, 68113, 68141, - 68147, 68161, 68171, 68207, 68209, 68213, 68219, 68227, 68239, 68261, 68279, 68281, 68311, 68329, 68351, - 68371, 68389, 68399, 68437, 68443, 68447, 68449, 68473, 68477, 68483, 68489, 68491, 68501, 68507, 68521, - 68531, 68539, 68543, 68567, 68581, 68597, 68611, 68633, 68639, 68659, 68669, 68683, 68687, 68699, 68711, - 68713, 68729, 68737, 68743, 68749, 68767, 68771, 68777, 68791, 68813, 68819, 68821, 68863, 68879, 68881, - 68891, 68897, 68899, 68903, 68909, 68917, 68927, 68947, 68963, 68993, 69001, 69011, 69019, 69029, 69031, - 69061, 69067, 69073, 69109, 69119, 69127, 69143, 69149, 69151, 69163, 69191, 69193, 69197, 69203, 69221, - 69233, 69239, 69247, 69257, 69259, 69263, 69313, 69317, 69337, 69341, 69371, 69379, 69383, 69389, 69401, - 69403, 69427, 69431, 69439, 69457, 69463, 69467, 69473, 69481, 69491, 69493, 69497, 69499, 69539, 69557, - 69593, 69623, 69653, 69661, 69677, 69691, 69697, 69709, 69737, 69739, 69761, 69763, 69767, 69779, 69809, - 69821, 69827, 69829, 69833, 69847, 69857, 69859, 69877, 69899, 69911, 69929, 69931, 69941, 69959, 69991, - 69997, 70001, 70003, 70009, 70019, 70039, 70051, 70061, 70067, 70079, 70099, 70111, 70117, 70121, 70123, - 70139, 70141, 70157, 70163, 70177, 70181, 70183, 70199, 70201, 70207, 70223, 70229, 70237, 70241, 70249, - 70271, 70289, 70297, 70309, 70313, 70321, 70327, 70351, 70373, 70379, 70381, 70393, 70423, 70429, 70439, - 70451, 70457, 70459, 70481, 70487, 70489, 70501, 70507, 70529, 70537, 70549, 70571, 70573, 70583, 70589, - 70607, 70619, 70621, 70627, 70639, 70657, 70663, 70667, 70687, 70709, 70717, 70729, 70753, 70769, 70783, - 70793, 70823, 70841, 70843, 70849, 70853, 70867, 70877, 70879, 70891, 70901, 70913, 70919, 70921, 70937, - 70949, 70951, 70957, 70969, 70979, 70981, 70991, 70997, 70999, 71011, 71023, 71039, 71059, 71069, 71081, - 71089, 71119, 71129, 71143, 71147, 71153, 71161, 71167, 71171, 71191, 71209, 71233, 71237, 71249, 71257, - 71261, 71263, 71287, 71293, 71317, 71327, 71329, 71333, 71339, 71341, 71347, 71353, 71359, 71363, 71387, - 71389, 71399, 71411, 71413, 71419, 71429, 71437, 71443, 71453, 71471, 71473, 71479, 71483, 71503, 71527, - 71537, 71549, 71551, 71563, 71569, 71593, 71597, 71633, 71647, 71663, 71671, 71693, 71699, 71707, 71711, - 71713, 71719, 71741, 71761, 71777, 71789, 71807, 71809, 71821, 71837, 71843, 71849, 71861, 71867, 71879, - 71881, 71887, 71899, 71909, 71917, 71933, 71941, 71947, 71963, 71971, 71983, 71987, 71993, 71999, 72019, - 72031, 72043, 72047, 72053, 72073, 72077, 72089, 72091, 72101, 72103, 72109, 72139, 72161, 72167, 72169, - 72173, 72211, 72221, 72223, 72227, 72229, 72251, 72253, 72269, 72271, 72277, 72287, 72307, 72313, 72337, - 72341, 72353, 72367, 72379, 72383, 72421, 72431, 72461, 72467, 72469, 72481, 72493, 72497, 72503, 72533, - 72547, 72551, 72559, 72577, 72613, 72617, 72623, 72643, 72647, 72649, 72661, 72671, 72673, 72679, 72689, - 72701, 72707, 72719, 72727, 72733, 72739, 72763, 72767, 72797, 72817, 72823, 72859, 72869, 72871, 72883, - 72889, 72893, 72901, 72907, 72911, 72923, 72931, 72937, 72949, 72953, 72959, 72973, 72977, 72997, 73009, - 73013, 73019, 73037, 73039, 73043, 73061, 73063, 73079, 73091, 73121, 73127, 73133, 73141, 73181, 73189, - 73237, 73243, 73259, 73277, 73291, 73303, 73309, 73327, 73331, 73351, 73361, 73363, 73369, 73379, 73387, - 73417, 73421, 73433, 73453, 73459, 73471, 73477, 73483, 73517, 73523, 73529, 73547, 73553, 73561, 73571, - 73583, 73589, 73597, 73607, 73609, 73613, 73637, 73643, 73651, 73673, 73679, 73681, 73693, 73699, 73709, - 73721, 73727, 73751, 73757, 73771, 73783, 73819, 73823, 73847, 73849, 73859, 73867, 73877, 73883, 73897, - 73907, 73939, 73943, 73951, 73961, 73973, 73999, 74017, 74021, 74027, 74047, 74051, 74071, 74077, 74093, - 74099, 74101, 74131, 74143, 74149, 74159, 74161, 74167, 74177, 74189, 74197, 74201, 74203, 74209, 74219, - 74231, 74257, 74279, 74287, 74293, 74297, 74311, 74317, 74323, 74353, 74357, 74363, 74377, 74381, 74383, - 74411, 74413, 74419, 74441, 74449, 74453, 74471, 74489, 74507, 74509, 74521, 74527, 74531, 74551, 74561, - 74567, 74573, 74587, 74597, 74609, 74611, 74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719, 74729, - 74731, 74747, 74759, 74761, 74771, 74779, 74797, 74821, 74827, 74831, 74843, 74857, 74861, 74869, 74873, - 74887, 74891, 74897, 74903, 74923, 74929, 74933, 74941, 74959, 75011, 75013, 75017, 75029, 75037, 75041, - 75079, 75083, 75109, 75133, 75149, 75161, 75167, 75169, 75181, 75193, 75209, 75211, 75217, 75223, 75227, - 75239, 75253, 75269, 75277, 75289, 75307, 75323, 75329, 75337, 75347, 75353, 75367, 75377, 75389, 75391, - 75401, 75403, 75407, 75431, 75437, 75479, 75503, 75511, 75521, 75527, 75533, 75539, 75541, 75553, 75557, - 75571, 75577, 75583, 75611, 75617, 75619, 75629, 75641, 75653, 75659, 75679, 75683, 75689, 75703, 75707, - 75709, 75721, 75731, 75743, 75767, 75773, 75781, 75787, 75793, 75797, 75821, 75833, 75853, 75869, 75883, - 75913, 75931, 75937, 75941, 75967, 75979, 75983, 75989, 75991, 75997, 76001, 76003, 76031, 76039, 76079, - 76081, 76091, 76099, 76103, 76123, 76129, 76147, 76157, 76159, 76163, 76207, 76213, 76231, 76243, 76249, - 76253, 76259, 76261, 76283, 76289, 76303, 76333, 76343, 76367, 76369, 76379, 76387, 76403, 76421, 76423, - 76441, 76463, 76471, 76481, 76487, 76493, 76507, 76511, 76519, 76537, 76541, 76543, 76561, 76579, 76597, - 76603, 76607, 76631, 76649, 76651, 76667, 76673, 76679, 76697, 76717, 76733, 76753, 76757, 76771, 76777, - 76781, 76801, 76819, 76829, 76831, 76837, 76847, 76871, 76873, 76883, 76907, 76913, 76919, 76943, 76949, - 76961, 76963, 76991, 77003, 77017, 77023, 77029, 77041, 77047, 77069, 77081, 77093, 77101, 77137, 77141, - 77153, 77167, 77171, 77191, 77201, 77213, 77237, 77239, 77243, 77249, 77261, 77263, 77267, 77269, 77279, - 77291, 77317, 77323, 77339, 77347, 77351, 77359, 77369, 77377, 77383, 77417, 77419, 77431, 77447, 77471, - 77477, 77479, 77489, 77491, 77509, 77513, 77521, 77527, 77543, 77549, 77551, 77557, 77563, 77569, 77573, - 77587, 77591, 77611, 77617, 77621, 77641, 77647, 77659, 77681, 77687, 77689, 77699, 77711, 77713, 77719, - 77723, 77731, 77743, 77747, 77761, 77773, 77783, 77797, 77801, 77813, 77839, 77849, 77863, 77867, 77893, - 77899, 77929, 77933, 77951, 77969, 77977, 77983, 77999, 78007, 78017, 78031, 78041, 78049, 78059, 78079, - 78101, 78121, 78137, 78139, 78157, 78163, 78167, 78173, 78179, 78191, 78193, 78203, 78229, 78233, 78241, - 78259, 78277, 78283, 78301, 78307, 78311, 78317, 78341, 78347, 78367, 78401, 78427, 78437, 78439, 78467, - 78479, 78487, 78497, 78509, 78511, 78517, 78539, 78541, 78553, 78569, 78571, 78577, 78583, 78593, 78607, - 78623, 78643, 78649, 78653, 78691, 78697, 78707, 78713, 78721, 78737, 78779, 78781, 78787, 78791, 78797, - 78803, 78809, 78823, 78839, 78853, 78857, 78877, 78887, 78889, 78893, 78901, 78919, 78929, 78941, 78977, - 78979, 78989, 79031, 79039, 79043, 79063, 79087, 79103, 79111, 79133, 79139, 79147, 79151, 79153, 79159, - 79181, 79187, 79193, 79201, 79229, 79231, 79241, 79259, 79273, 79279, 79283, 79301, 79309, 79319, 79333, - 79337, 79349, 79357, 79367, 79379, 79393, 79397, 79399, 79411, 79423, 79427, 79433, 79451, 79481, 79493, - 79531, 79537, 79549, 79559, 79561, 79579, 79589, 79601, 79609, 79613, 79621, 79627, 79631, 79633, 79657, - 79669, 79687, 79691, 79693, 79697, 79699, 79757, 79769, 79777, 79801, 79811, 79813, 79817, 79823, 79829, - 79841, 79843, 79847, 79861, 79867, 79873, 79889, 79901, 79903, 79907, 79939, 79943, 79967, 79973, 79979, - 79987, 79997, 79999, 80021, 80039, 80051, 80071, 80077, 80107, 80111, 80141, 80147, 80149, 80153, 80167, - 80173, 80177, 80191, 80207, 80209, 80221, 80231, 80233, 80239, 80251, 80263, 80273, 80279, 80287, 80309, - 80317, 80329, 80341, 80347, 80363, 80369, 80387, 80407, 80429, 80447, 80449, 80471, 80473, 80489, 80491, - 80513, 80527, 80537, 80557, 80567, 80599, 80603, 80611, 80621, 80627, 80629, 80651, 80657, 80669, 80671, - 80677, 80681, 80683, 80687, 80701, 80713, 80737, 80747, 80749, 80761, 80777, 80779, 80783, 80789, 80803, - 80809, 80819, 80831, 80833, 80849, 80863, 80897, 80909, 80911, 80917, 80923, 80929, 80933, 80953, 80963, - 80989, 81001, 81013, 81017, 81019, 81023, 81031, 81041, 81043, 81047, 81049, 81071, 81077, 81083, 81097, - 81101, 81119, 81131, 81157, 81163, 81173, 81181, 81197, 81199, 81203, 81223, 81233, 81239, 81281, 81283, - 81293, 81299, 81307, 81331, 81343, 81349, 81353, 81359, 81371, 81373, 81401, 81409, 81421, 81439, 81457, - 81463, 81509, 81517, 81527, 81533, 81547, 81551, 81553, 81559, 81563, 81569, 81611, 81619, 81629, 81637, - 81647, 81649, 81667, 81671, 81677, 81689, 81701, 81703, 81707, 81727, 81737, 81749, 81761, 81769, 81773, - 81799, 81817, 81839, 81847, 81853, 81869, 81883, 81899, 81901, 81919, 81929, 81931, 81937, 81943, 81953, - 81967, 81971, 81973, 82003, 82007, 82009, 82013, 82021, 82031, 82037, 82039, 82051, 82067, 82073, 82129, - 82139, 82141, 82153, 82163, 82171, 82183, 82189, 82193, 82207, 82217, 82219, 82223, 82231, 82237, 82241, - 82261, 82267, 82279, 82301, 82307, 82339, 82349, 82351, 82361, 82373, 82387, 82393, 82421, 82457, 82463, - 82469, 82471, 82483, 82487, 82493, 82499, 82507, 82529, 82531, 82549, 82559, 82561, 82567, 82571, 82591, - 82601, 82609, 82613, 82619, 82633, 82651, 82657, 82699, 82721, 82723, 82727, 82729, 82757, 82759, 82763, - 82781, 82787, 82793, 82799, 82811, 82813, 82837, 82847, 82883, 82889, 82891, 82903, 82913, 82939, 82963, - 82981, 82997, 83003, 83009, 83023, 83047, 83059, 83063, 83071, 83077, 83089, 83093, 83101, 83117, 83137, - 83177, 83203, 83207, 83219, 83221, 83227, 83231, 83233, 83243, 83257, 83267, 83269, 83273, 83299, 83311, - 83339, 83341, 83357, 83383, 83389, 83399, 83401, 83407, 83417, 83423, 83431, 83437, 83443, 83449, 83459, - 83471, 83477, 83497, 83537, 83557, 83561, 83563, 83579, 83591, 83597, 83609, 83617, 83621, 83639, 83641, - 83653, 83663, 83689, 83701, 83717, 83719, 83737, 83761, 83773, 83777, 83791, 83813, 83833, 83843, 83857, - 83869, 83873, 83891, 83903, 83911, 83921, 83933, 83939, 83969, 83983, 83987, 84011, 84017, 84047, 84053, - 84059, 84061, 84067, 84089, 84121, 84127, 84131, 84137, 84143, 84163, 84179, 84181, 84191, 84199, 84211, - 84221, 84223, 84229, 84239, 84247, 84263, 84299, 84307, 84313, 84317, 84319, 84347, 84349, 84377, 84389, - 84391, 84401, 84407, 84421, 84431, 84437, 84443, 84449, 84457, 84463, 84467, 84481, 84499, 84503, 84509, - 84521, 84523, 84533, 84551, 84559, 84589, 84629, 84631, 84649, 84653, 84659, 84673, 84691, 84697, 84701, - 84713, 84719, 84731, 84737, 84751, 84761, 84787, 84793, 84809, 84811, 84827, 84857, 84859, 84869, 84871, - 84913, 84919, 84947, 84961, 84967, 84977, 84979, 84991, 85009, 85021, 85027, 85037, 85049, 85061, 85081, - 85087, 85091, 85093, 85103, 85109, 85121, 85133, 85147, 85159, 85193, 85199, 85201, 85213, 85223, 85229, - 85237, 85243, 85247, 85259, 85297, 85303, 85313, 85331, 85333, 85361, 85363, 85369, 85381, 85411, 85427, - 85429, 85439, 85447, 85451, 85453, 85469, 85487, 85513, 85517, 85523, 85531, 85549, 85571, 85577, 85597, - 85601, 85607, 85619, 85621, 85627, 85639, 85643, 85661, 85667, 85669, 85691, 85703, 85711, 85717, 85733, - 85751, 85781, 85793, 85817, 85819, 85829, 85831, 85837, 85843, 85847, 85853, 85889, 85903, 85909, 85931, - 85933, 85991, 85999, 86011, 86017, 86027, 86029, 86069, 86077, 86083, 86111, 86113, 86117, 86131, 86137, - 86143, 86161, 86171, 86179, 86183, 86197, 86201, 86209, 86239, 86243, 86249, 86257, 86263, 86269, 86287, - 86291, 86293, 86297, 86311, 86323, 86341, 86351, 86353, 86357, 86369, 86371, 86381, 86389, 86399, 86413, - 86423, 86441, 86453, 86461, 86467, 86477, 86491, 86501, 86509, 86531, 86533, 86539, 86561, 86573, 86579, - 86587, 86599, 86627, 86629, 86677, 86689, 86693, 86711, 86719, 86729, 86743, 86753, 86767, 86771, 86783, - 86813, 86837, 86843, 86851, 86857, 86861, 86869, 86923, 86927, 86929, 86939, 86951, 86959, 86969, 86981, - 86993, 87011, 87013, 87037, 87041, 87049, 87071, 87083, 87103, 87107, 87119, 87121, 87133, 87149, 87151, - 87179, 87181, 87187, 87211, 87221, 87223, 87251, 87253, 87257, 87277, 87281, 87293, 87299, 87313, 87317, - 87323, 87337, 87359, 87383, 87403, 87407, 87421, 87427, 87433, 87443, 87473, 87481, 87491, 87509, 87511, - 87517, 87523, 87539, 87541, 87547, 87553, 87557, 87559, 87583, 87587, 87589, 87613, 87623, 87629, 87631, - 87641, 87643, 87649, 87671, 87679, 87683, 87691, 87697, 87701, 87719, 87721, 87739, 87743, 87751, 87767, - 87793, 87797, 87803, 87811, 87833, 87853, 87869, 87877, 87881, 87887, 87911, 87917, 87931, 87943, 87959, - 87961, 87973, 87977, 87991, 88001, 88003, 88007, 88019, 88037, 88069, 88079, 88093, 88117, 88129, 88169, - 88177, 88211, 88223, 88237, 88241, 88259, 88261, 88289, 88301, 88321, 88327, 88337, 88339, 88379, 88397, - 88411, 88423, 88427, 88463, 88469, 88471, 88493, 88499, 88513, 88523, 88547, 88589, 88591, 88607, 88609, - 88643, 88651, 88657, 88661, 88663, 88667, 88681, 88721, 88729, 88741, 88747, 88771, 88789, 88793, 88799, - 88801, 88807, 88811, 88813, 88817, 88819, 88843, 88853, 88861, 88867, 88873, 88883, 88897, 88903, 88919, - 88937, 88951, 88969, 88993, 88997, 89003, 89009, 89017, 89021, 89041, 89051, 89057, 89069, 89071, 89083, - 89087, 89101, 89107, 89113, 89119, 89123, 89137, 89153, 89189, 89203, 89209, 89213, 89227, 89231, 89237, - 89261, 89269, 89273, 89293, 89303, 89317, 89329, 89363, 89371, 89381, 89387, 89393, 89399, 89413, 89417, - 89431, 89443, 89449, 89459, 89477, 89491, 89501, 89513, 89519, 89521, 89527, 89533, 89561, 89563, 89567, - 89591, 89597, 89599, 89603, 89611, 89627, 89633, 89653, 89657, 89659, 89669, 89671, 89681, 89689, 89753, - 89759, 89767, 89779, 89783, 89797, 89809, 89819, 89821, 89833, 89839, 89849, 89867, 89891, 89897, 89899, - 89909, 89917, 89923, 89939, 89959, 89963, 89977, 89983, 89989, 90001, 90007, 90011, 90017, 90019, 90023, - 90031, 90053, 90059, 90067, 90071, 90073, 90089, 90107, 90121, 90127, 90149, 90163, 90173, 90187, 90191, - 90197, 90199, 90203, 90217, 90227, 90239, 90247, 90263, 90271, 90281, 90289, 90313, 90353, 90359, 90371, - 90373, 90379, 90397, 90401, 90403, 90407, 90437, 90439, 90469, 90473, 90481, 90499, 90511, 90523, 90527, - 90529, 90533, 90547, 90583, 90599, 90617, 90619, 90631, 90641, 90647, 90659, 90677, 90679, 90697, 90703, - 90709, 90731, 90749, 90787, 90793, 90803, 90821, 90823, 90833, 90841, 90847, 90863, 90887, 90901, 90907, - 90911, 90917, 90931, 90947, 90971, 90977, 90989, 90997, 91009, 91019, 91033, 91079, 91081, 91097, 91099, - 91121, 91127, 91129, 91139, 91141, 91151, 91153, 91159, 91163, 91183, 91193, 91199, 91229, 91237, 91243, - 91249, 91253, 91283, 91291, 91297, 91303, 91309, 91331, 91367, 91369, 91373, 91381, 91387, 91393, 91397, - 91411, 91423, 91433, 91453, 91457, 91459, 91463, 91493, 91499, 91513, 91529, 91541, 91571, 91573, 91577, - 91583, 91591, 91621, 91631, 91639, 91673, 91691, 91703, 91711, 91733, 91753, 91757, 91771, 91781, 91801, - 91807, 91811, 91813, 91823, 91837, 91841, 91867, 91873, 91909, 91921, 91939, 91943, 91951, 91957, 91961, - 91967, 91969, 91997, 92003, 92009, 92033, 92041, 92051, 92077, 92083, 92107, 92111, 92119, 92143, 92153, - 92173, 92177, 92179, 92189, 92203, 92219, 92221, 92227, 92233, 92237, 92243, 92251, 92269, 92297, 92311, - 92317, 92333, 92347, 92353, 92357, 92363, 92369, 92377, 92381, 92383, 92387, 92399, 92401, 92413, 92419, - 92431, 92459, 92461, 92467, 92479, 92489, 92503, 92507, 92551, 92557, 92567, 92569, 92581, 92593, 92623, - 92627, 92639, 92641, 92647, 92657, 92669, 92671, 92681, 92683, 92693, 92699, 92707, 92717, 92723, 92737, - 92753, 92761, 92767, 92779, 92789, 92791, 92801, 92809, 92821, 92831, 92849, 92857, 92861, 92863, 92867, - 92893, 92899, 92921, 92927, 92941, 92951, 92957, 92959, 92987, 92993, 93001, 93047, 93053, 93059, 93077, - 93083, 93089, 93097, 93103, 93113, 93131, 93133, 93139, 93151, 93169, 93179, 93187, 93199, 93229, 93239, - 93241, 93251, 93253, 93257, 93263, 93281, 93283, 93287, 93307, 93319, 93323, 93329, 93337, 93371, 93377, - 93383, 93407, 93419, 93427, 93463, 93479, 93481, 93487, 93491, 93493, 93497, 93503, 93523, 93529, 93553, - 93557, 93559, 93563, 93581, 93601, 93607, 93629, 93637, 93683, 93701, 93703, 93719, 93739, 93761, 93763, - 93787, 93809, 93811, 93827, 93851, 93871, 93887, 93889, 93893, 93901, 93911, 93913, 93923, 93937, 93941, - 93949, 93967, 93971, 93979, 93983, 93997, 94007, 94009, 94033, 94049, 94057, 94063, 94079, 94099, 94109, - 94111, 94117, 94121, 94151, 94153, 94169, 94201, 94207, 94219, 94229, 94253, 94261, 94273, 94291, 94307, - 94309, 94321, 94327, 94331, 94343, 94349, 94351, 94379, 94397, 94399, 94421, 94427, 94433, 94439, 94441, - 94447, 94463, 94477, 94483, 94513, 94529, 94531, 94541, 94543, 94547, 94559, 94561, 94573, 94583, 94597, - 94603, 94613, 94621, 94649, 94651, 94687, 94693, 94709, 94723, 94727, 94747, 94771, 94777, 94781, 94789, - 94793, 94811, 94819, 94823, 94837, 94841, 94847, 94849, 94873, 94889, 94903, 94907, 94933, 94949, 94951, - 94961, 94993, 94999, 95003, 95009, 95021, 95027, 95063, 95071, 95083, 95087, 95089, 95093, 95101, 95107, - 95111, 95131, 95143, 95153, 95177, 95189, 95191, 95203, 95213, 95219, 95231, 95233, 95239, 95257, 95261, - 95267, 95273, 95279, 95287, 95311, 95317, 95327, 95339, 95369, 95383, 95393, 95401, 95413, 95419, 95429, - 95441, 95443, 95461, 95467, 95471, 95479, 95483, 95507, 95527, 95531, 95539, 95549, 95561, 95569, 95581, - 95597, 95603, 95617, 95621, 95629, 95633, 95651, 95701, 95707, 95713, 95717, 95723, 95731, 95737, 95747, - 95773, 95783, 95789, 95791, 95801, 95803, 95813, 95819, 95857, 95869, 95873, 95881, 95891, 95911, 95917, - 95923, 95929, 95947, 95957, 95959, 95971, 95987, 95989, 96001, 96013, 96017, 96043, 96053, 96059, 96079, - 96097, 96137, 96149, 96157, 96167, 96179, 96181, 96199, 96211, 96221, 96223, 96233, 96259, 96263, 96269, - 96281, 96289, 96293, 96323, 96329, 96331, 96337, 96353, 96377, 96401, 96419, 96431, 96443, 96451, 96457, - 96461, 96469, 96479, 96487, 96493, 96497, 96517, 96527, 96553, 96557, 96581, 96587, 96589, 96601, 96643, - 96661, 96667, 96671, 96697, 96703, 96731, 96737, 96739, 96749, 96757, 96763, 96769, 96779, 96787, 96797, - 96799, 96821, 96823, 96827, 96847, 96851, 96857, 96893, 96907, 96911, 96931, 96953, 96959, 96973, 96979, - 96989, 96997, 97001, 97003, 97007, 97021, 97039, 97073, 97081, 97103, 97117, 97127, 97151, 97157, 97159, - 97169, 97171, 97177, 97187, 97213, 97231, 97241, 97259, 97283, 97301, 97303, 97327, 97367, 97369, 97373, - 97379, 97381, 97387, 97397, 97423, 97429, 97441, 97453, 97459, 97463, 97499, 97501, 97511, 97523, 97547, - 97549, 97553, 97561, 97571, 97577, 97579, 97583, 97607, 97609, 97613, 97649, 97651, 97673, 97687, 97711, - 97729, 97771, 97777, 97787, 97789, 97813, 97829, 97841, 97843, 97847, 97849, 97859, 97861, 97871, 97879, - 97883, 97919, 97927, 97931, 97943, 97961, 97967, 97973, 97987, 98009, 98011, 98017, 98041, 98047, 98057, - 98081, 98101, 98123, 98129, 98143, 98179, 98207, 98213, 98221, 98227, 98251, 98257, 98269, 98297, 98299, - 98317, 98321, 98323, 98327, 98347, 98369, 98377, 98387, 98389, 98407, 98411, 98419, 98429, 98443, 98453, - 98459, 98467, 98473, 98479, 98491, 98507, 98519, 98533, 98543, 98561, 98563, 98573, 98597, 98621, 98627, - 98639, 98641, 98663, 98669, 98689, 98711, 98713, 98717, 98729, 98731, 98737, 98773, 98779, 98801, 98807, - 98809, 98837, 98849, 98867, 98869, 98873, 98887, 98893, 98897, 98899, 98909, 98911, 98927, 98929, 98939, - 98947, 98953, 98963, 98981, 98993, 98999, 99013, 99017, 99023, 99041, 99053, 99079, 99083, 99089, 99103, - 99109, 99119, 99131, 99133, 99137, 99139, 99149, 99173, 99181, 99191, 99223, 99233, 99241, 99251, 99257, - 99259, 99277, 99289, 99317, 99347, 99349, 99367, 99371, 99377, 99391, 99397, 99401, 99409, 99431, 99439, - 99469, 99487, 99497, 99523, 99527, 99529, 99551, 99559, 99563, 99571, 99577, 99581, 99607, 99611, 99623, - 99643, 99661, 99667, 99679, 99689, 99707, 99709, 99713, 99719, 99721, 99733, 99761, 99767, 99787, 99793, - 99809, 99817, 99823, 99829, 99833, 99839, 99859, 99871, 99877, 99881, 99901, 99907, 99923, 99929, 99961, - 99971, 99989, 99991, 100003, 100019, 100043, 100049, 100057, 100069, 100103, 100109, 100129, 100151, 100153, - 100169, 100183, 100189, 100193, 100207, 100213, 100237, 100267, 100271, 100279, 100291, 100297, 100313, - 100333, 100343, 100357, 100361, 100363, 100379, 100391, 100393, 100403, 100411, 100417, 100447, 100459, - 100469, 100483, 100493, 100501, 100511, 100517, 100519, 100523, 100537, 100547, 100549, 100559, 100591, - 100609, 100613, 100621, 100649, 100669, 100673, 100693, 100699, 100703, 100733, 100741, 100747, 100769, - 100787, 100799, 100801, 100811, 100823, 100829, 100847, 100853, 100907, 100913, 100927, 100931, 100937, - 100943, 100957, 100981, 100987, 100999, 101009, 101021, 101027, 101051, 101063, 101081, 101089, 101107, - 101111, 101113, 101117, 101119, 101141, 101149, 101159, 101161, 101173, 101183, 101197, 101203, 101207, - 101209, 101221, 101267, 101273, 101279, 101281, 101287, 101293, 101323, 101333, 101341, 101347, 101359, - 101363, 101377, 101383, 101399, 101411, 101419, 101429, 101449, 101467, 101477, 101483, 101489, 101501, - 101503, 101513, 101527, 101531, 101533, 101537, 101561, 101573, 101581, 101599, 101603, 101611, 101627, - 101641, 101653, 101663, 101681, 101693, 101701, 101719, 101723, 101737, 101741, 101747, 101749, 101771, - 101789, 101797, 101807, 101833, 101837, 101839, 101863, 101869, 101873, 101879, 101891, 101917, 101921, - 101929, 101939, 101957, 101963, 101977, 101987, 101999, 102001, 102013, 102019, 102023, 102031, 102043, - 102059, 102061, 102071, 102077, 102079, 102101, 102103, 102107, 102121, 102139, 102149, 102161, 102181, - 102191, 102197, 102199, 102203, 102217, 102229, 102233, 102241, 102251, 102253, 102259, 102293, 102299, - 102301, 102317, 102329, 102337, 102359, 102367, 102397, 102407, 102409, 102433, 102437, 102451, 102461, - 102481, 102497, 102499, 102503, 102523, 102533, 102539, 102547, 102551, 102559, 102563, 102587, 102593, - 102607, 102611, 102643, 102647, 102653, 102667, 102673, 102677, 102679, 102701, 102761, 102763, 102769, - 102793, 102797, 102811, 102829, 102841, 102859, 102871, 102877, 102881, 102911, 102913, 102929, 102931, - 102953, 102967, 102983, 103001, 103007, 103043, 103049, 103067, 103069, 103079, 103087, 103091, 103093, - 103099, 103123, 103141, 103171, 103177, 103183, 103217, 103231, 103237, 103289, 103291, 103307, 103319, - 103333, 103349, 103357, 103387, 103391, 103393, 103399, 103409, 103421, 103423, 103451, 103457, 103471, - 103483, 103511, 103529, 103549, 103553, 103561, 103567, 103573, 103577, 103583, 103591, 103613, 103619, - 103643, 103651, 103657, 103669, 103681, 103687, 103699, 103703, 103723, 103769, 103787, 103801, 103811, - 103813, 103837, 103841, 103843, 103867, 103889, 103903, 103913, 103919, 103951, 103963, 103967, 103969, - 103979, 103981, 103991, 103993, 103997, 104003, 104009, 104021, 104033, 104047, 104053, 104059, 104087, - 104089, 104107, 104113, 104119, 104123, 104147, 104149, 104161, 104173, 104179, 104183, 104207, 104231, - 104233, 104239, 104243, 104281, 104287, 104297, 104309, 104311, 104323, 104327, 104347, 104369, 104381, - 104383, 104393, 104399, 104417, 104459, 104471, 104473, 104479, 104491, 104513, 104527, 104537, 104543, - 104549, 104551, 104561, 104579, 104593, 104597, 104623, 104639, 104651, 104659, 104677, 104681, 104683, - 104693, 104701, 104707, 104711, 104717, 104723, 104729, - }; + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, + 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, + 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, + 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, + 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, + 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, + 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, + 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, + 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, + 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, + 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, + 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, + 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, + 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, + 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, + 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, + 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, + 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, + 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, + 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, + 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, + 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, + 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, + 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, + 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, + 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, + 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, + 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, + 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, + 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, + 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, + 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, + 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, + 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, + 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, + 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, + 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, + 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, + 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, + 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, + 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, + 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, + 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, + 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, + 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, + 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, + 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, + 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, + 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, + 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, + 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, + 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, + 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, + 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, + 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, + 8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, + 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, + 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, + 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, + 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, + 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, + 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, + 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, + 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 9859, + 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, + 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, + 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, + 10313, 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, + 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589, 10597, 10601, 10607, + 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, + 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, + 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, + 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, + 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, + 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, + 11489, 11491, 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, + 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783, 11789, 11801, + 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, + 11933, 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, + 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, + 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, + 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, + 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, + 12601, 12611, 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, + 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889, 12893, + 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, + 13007, 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, + 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, + 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, + 13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, + 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, + 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, + 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011, + 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, + 14197, 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, + 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, + 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, + 14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, + 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, + 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, + 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, + 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, + 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, + 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, + 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, + 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, + 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, + 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, + 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, + 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, + 16481, 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, + 16649, 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, + 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, 16921, 16927, 16931, 16937, + 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, + 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, + 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, + 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, + 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, + 17669, 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, + 17837, 17839, 17851, 17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, + 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, 18061, 18077, 18089, 18097, + 18119, 18121, 18127, 18131, 18133, 18143, 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, + 18233, 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, 18353, 18367, + 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, + 18517, 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, + 18701, 18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, + 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, 19013, 19031, 19037, 19051, + 19069, 19073, 19079, 19081, 19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, + 19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, 19333, 19373, 19379, 19381, + 19387, 19391, 19403, 19417, 19421, 19423, 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, + 19477, 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, 19603, + 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, + 19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, + 19949, 19961, 19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, + 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, 20161, 20173, 20177, 20183, + 20201, 20219, 20231, 20233, 20249, 20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, + 20357, 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, 20479, 20483, 20507, + 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, + 20693, 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, + 20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, + 20983, 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, + 21139, 21143, 21149, 21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, + 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, 21391, 21397, 21401, 21407, + 21419, 21433, 21467, 21481, 21487, 21491, 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, + 21563, 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, 21673, 21683, + 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, + 21841, 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, + 22003, 22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, + 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, 22247, 22259, 22271, 22273, + 22277, 22279, 22283, 22291, 22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, + 22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, 22549, 22567, 22571, 22573, + 22613, 22619, 22621, 22637, 22639, 22643, 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, + 22727, 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, 22871, + 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, + 23029, 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, + 23167, 23173, 23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, + 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, 23459, 23473, 23497, 23509, + 23531, 23537, 23539, 23549, 23557, 23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, + 23629, 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, 23753, 23761, 23767, + 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, + 23909, 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, + 24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, + 24169, 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, + 24371, 24373, 24379, 24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, + 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, 24671, 24677, 24683, 24691, + 24697, 24709, 24733, 24749, 24763, 24767, 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, + 24877, 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, 25013, 25031, + 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, + 25183, 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, + 25343, 25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, + 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, 25609, 25621, 25633, 25639, + 25643, 25657, 25667, 25673, 25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, + 25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, 25919, 25931, 25933, 25939, + 25943, 25951, 25969, 25981, 25997, 25999, 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, + 26111, 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, 26249, + 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, + 26399, 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, + 26561, 26573, 26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, + 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, 26813, 26821, 26833, 26839, + 26849, 26861, 26863, 26879, 26881, 26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, + 26987, 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, 27103, 27107, 27109, + 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, + 27329, 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, + 27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, + 27691, 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, + 27799, 27803, 27809, 27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, + 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, 28057, 28069, 28081, 28087, + 28097, 28099, 28109, 28111, 28123, 28151, 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, + 28283, 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, 28429, 28433, + 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, + 28579, 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, + 28687, 28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, + 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, 28949, 28961, 28979, 29009, + 29017, 29021, 29023, 29027, 29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, + 29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, 29269, 29287, 29297, 29303, + 29311, 29327, 29333, 29339, 29347, 29363, 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, + 29443, 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, 29611, + 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, + 29819, 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, + 29989, 30011, 30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, + 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, 30253, 30259, 30269, 30271, + 30293, 30307, 30313, 30319, 30323, 30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, + 30469, 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, 30593, 30631, 30637, + 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, + 30803, 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, + 30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, + 31091, 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, + 31231, 31237, 31247, 31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, + 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, 31513, 31517, 31531, 31541, + 31543, 31547, 31567, 31573, 31583, 31601, 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, + 31721, 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, 31859, 31873, + 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, + 32063, 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, + 32203, 32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, + 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, 32429, 32441, 32443, 32467, + 32479, 32491, 32497, 32503, 32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, + 32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, 32719, 32749, 32771, 32779, + 32783, 32789, 32797, 32801, 32803, 32831, 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, + 32939, 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, 33053, + 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, + 33211, 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, + 33377, 33391, 33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, + 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, 33617, 33619, 33623, 33629, + 33637, 33641, 33647, 33679, 33703, 33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, + 33797, 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, 33923, 33931, 33937, + 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, + 34157, 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, + 34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, + 34457, 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, + 34591, 34603, 34607, 34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, + 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, 34849, 34871, 34877, 34883, + 34897, 34913, 34919, 34939, 34949, 34961, 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, + 35083, 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, 35221, 35227, + 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, + 35401, 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, + 35537, 35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, + 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, 35869, 35879, 35897, 35899, + 35911, 35923, 35933, 35951, 35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, + 36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, 36187, 36191, 36209, 36217, + 36229, 36241, 36251, 36263, 36269, 36277, 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, + 36383, 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, 36541, + 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, + 36691, 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, + 36821, 36833, 36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, + 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, 37061, 37087, 37097, 37117, + 37123, 37139, 37159, 37171, 37181, 37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, + 37309, 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, 37423, 37441, 37447, + 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, + 37573, 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, + 37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, + 37951, 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, + 38119, 38149, 38153, 38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, + 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, 38377, 38393, 38431, 38447, + 38449, 38453, 38459, 38461, 38501, 38543, 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, + 38639, 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, 38737, 38747, + 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, + 38921, 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, + 39097, 39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, + 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, 39341, 39343, 39359, 39367, + 39371, 39373, 39383, 39397, 39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, + 39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, 39671, 39679, 39703, 39709, + 39719, 39727, 39733, 39749, 39761, 39769, 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, + 39857, 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, 40009, + 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, + 40169, 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, + 40361, 40387, 40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, + 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, 40693, 40697, 40699, 40709, + 40739, 40751, 40759, 40763, 40771, 40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, + 40867, 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, 41011, 41017, 41023, + 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, + 41183, 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, + 41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, + 41507, 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, + 41627, 41641, 41647, 41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, + 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, 41903, 41911, 41927, 41941, + 41947, 41953, 41957, 41959, 41969, 41981, 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, + 42073, 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, 42209, 42221, + 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, + 42379, 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, + 42487, 42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, + 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, 42751, 42767, 42773, 42787, + 42793, 42797, 42821, 42829, 42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, + 42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, 43063, 43067, 43093, 43103, + 43117, 43133, 43151, 43159, 43177, 43189, 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, + 43319, 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, 43499, + 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, + 43661, 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, + 43853, 43867, 43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, + 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, 44111, 44119, 44123, 44129, + 44131, 44159, 44171, 44179, 44189, 44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, + 44279, 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, 44483, 44491, 44497, + 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, + 44641, 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, + 44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, + 44953, 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, + 45131, 45137, 45139, 45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, + 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, 45413, 45427, 45433, 45439, + 45481, 45491, 45497, 45503, 45523, 45533, 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, + 45641, 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, 45779, 45817, + 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, + 45979, 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, + 46153, 46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, + 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, 46451, 46457, 46471, 46477, + 46489, 46499, 46507, 46511, 46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, + 46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, 46751, 46757, 46769, 46771, + 46807, 46811, 46817, 46819, 46829, 46831, 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, + 46993, 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, 47143, + 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, + 47317, 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, + 47497, 47501, 47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, + 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, 47737, 47741, 47743, 47777, + 47779, 47791, 47797, 47807, 47809, 47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, + 47939, 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, 48079, 48091, 48109, + 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, + 48299, 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, + 48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, + 48611, 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, + 48779, 48781, 48787, 48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, + 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, 49037, 49043, 49057, 49069, + 49081, 49103, 49109, 49117, 49121, 49123, 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, + 49211, 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, 49369, 49391, + 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, + 49537, 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, + 49711, 49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, + 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, 49991, 49993, 49999, 50021, + 50023, 50033, 50047, 50051, 50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, + 50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, 50287, 50291, 50311, 50321, + 50329, 50333, 50341, 50359, 50363, 50377, 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, + 50503, 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, 50651, + 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, + 50867, 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, + 51043, 51047, 51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, + 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, 51341, 51343, 51347, 51349, + 51361, 51383, 51407, 51413, 51419, 51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, + 51487, 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, 51607, 51613, 51631, + 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, + 51803, 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, + 51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, + 52127, 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, + 52289, 52291, 52301, 52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, + 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, 52583, 52609, 52627, 52631, + 52639, 52667, 52673, 52691, 52697, 52709, 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, + 52813, 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, 52957, 52963, + 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, + 53117, 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, + 53279, 53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, + 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, 53597, 53609, 53611, 53617, + 53623, 53629, 53633, 53639, 53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, + 53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, 53897, 53899, 53917, 53923, + 53927, 53939, 53951, 53959, 53987, 53993, 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, + 54121, 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, 54311, + 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, + 54443, 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, + 54581, 54583, 54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, + 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, 54881, 54907, 54917, 54919, + 54941, 54949, 54959, 54973, 54979, 54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, + 55103, 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, 55229, 55243, 55249, + 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, + 55457, 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, + 55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, + 55793, 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, + 55903, 55921, 55927, 55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, + 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, 56197, 56207, 56209, 56237, + 56239, 56249, 56263, 56267, 56269, 56299, 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, + 56431, 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, 56527, 56531, + 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, + 56711, 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, + 56857, 56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, + 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, 57107, 57119, 57131, 57139, + 57143, 57149, 57163, 57173, 57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, + 57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, 57397, 57413, 57427, 57457, + 57467, 57487, 57493, 57503, 57527, 57529, 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, + 57653, 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, 57787, + 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, + 57947, 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, + 58111, 58129, 58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, + 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, 58391, 58393, 58403, 58411, + 58417, 58427, 58439, 58441, 58451, 58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, + 58601, 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, 58733, 58741, 58757, + 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, + 58967, 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, + 59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, + 59233, 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, + 59399, 59407, 59417, 59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, + 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, 59663, 59669, 59671, 59693, + 59699, 59707, 59723, 59729, 59743, 59747, 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, + 59887, 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, 60077, 60083, + 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, + 60251, 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, + 60427, 60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, + 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, 60727, 60733, 60737, 60757, + 60761, 60763, 60773, 60779, 60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, + 60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, 61051, 61057, 61091, 61099, + 61121, 61129, 61141, 61151, 61153, 61169, 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, + 61333, 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, 61483, + 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, + 61631, 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, + 61781, 61813, 61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, + 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, 62081, 62099, 62119, 62129, + 62131, 62137, 62141, 62143, 62171, 62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, + 62303, 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, 62473, 62477, 62483, + 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, + 62653, 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, + 62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, + 62989, 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, + 63199, 63211, 63241, 63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, + 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, 63467, 63473, 63487, 63493, + 63499, 63521, 63527, 63533, 63541, 63559, 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, + 63647, 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, 63743, 63761, + 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, + 63929, 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, + 64151, 64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, + 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, 64483, 64489, 64499, 64513, + 64553, 64567, 64577, 64579, 64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, + 64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, 64853, 64871, 64877, 64879, + 64891, 64901, 64919, 64921, 64927, 64937, 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, + 65063, 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, 65179, + 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, + 65381, 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, 65519, 65521, 65537, 65539, + 65543, 65551, 65557, 65563, 65579, 65581, 65587, 65599, 65609, 65617, 65629, 65633, 65647, 65651, 65657, + 65677, 65687, 65699, 65701, 65707, 65713, 65717, 65719, 65729, 65731, 65761, 65777, 65789, 65809, 65827, + 65831, 65837, 65839, 65843, 65851, 65867, 65881, 65899, 65921, 65927, 65929, 65951, 65957, 65963, 65981, + 65983, 65993, 66029, 66037, 66041, 66047, 66067, 66071, 66083, 66089, 66103, 66107, 66109, 66137, 66161, + 66169, 66173, 66179, 66191, 66221, 66239, 66271, 66293, 66301, 66337, 66343, 66347, 66359, 66361, 66373, + 66377, 66383, 66403, 66413, 66431, 66449, 66457, 66463, 66467, 66491, 66499, 66509, 66523, 66529, 66533, + 66541, 66553, 66569, 66571, 66587, 66593, 66601, 66617, 66629, 66643, 66653, 66683, 66697, 66701, 66713, + 66721, 66733, 66739, 66749, 66751, 66763, 66791, 66797, 66809, 66821, 66841, 66851, 66853, 66863, 66877, + 66883, 66889, 66919, 66923, 66931, 66943, 66947, 66949, 66959, 66973, 66977, 67003, 67021, 67033, 67043, + 67049, 67057, 67061, 67073, 67079, 67103, 67121, 67129, 67139, 67141, 67153, 67157, 67169, 67181, 67187, + 67189, 67211, 67213, 67217, 67219, 67231, 67247, 67261, 67271, 67273, 67289, 67307, 67339, 67343, 67349, + 67369, 67391, 67399, 67409, 67411, 67421, 67427, 67429, 67433, 67447, 67453, 67477, 67481, 67489, 67493, + 67499, 67511, 67523, 67531, 67537, 67547, 67559, 67567, 67577, 67579, 67589, 67601, 67607, 67619, 67631, + 67651, 67679, 67699, 67709, 67723, 67733, 67741, 67751, 67757, 67759, 67763, 67777, 67783, 67789, 67801, + 67807, 67819, 67829, 67843, 67853, 67867, 67883, 67891, 67901, 67927, 67931, 67933, 67939, 67943, 67957, + 67961, 67967, 67979, 67987, 67993, 68023, 68041, 68053, 68059, 68071, 68087, 68099, 68111, 68113, 68141, + 68147, 68161, 68171, 68207, 68209, 68213, 68219, 68227, 68239, 68261, 68279, 68281, 68311, 68329, 68351, + 68371, 68389, 68399, 68437, 68443, 68447, 68449, 68473, 68477, 68483, 68489, 68491, 68501, 68507, 68521, + 68531, 68539, 68543, 68567, 68581, 68597, 68611, 68633, 68639, 68659, 68669, 68683, 68687, 68699, 68711, + 68713, 68729, 68737, 68743, 68749, 68767, 68771, 68777, 68791, 68813, 68819, 68821, 68863, 68879, 68881, + 68891, 68897, 68899, 68903, 68909, 68917, 68927, 68947, 68963, 68993, 69001, 69011, 69019, 69029, 69031, + 69061, 69067, 69073, 69109, 69119, 69127, 69143, 69149, 69151, 69163, 69191, 69193, 69197, 69203, 69221, + 69233, 69239, 69247, 69257, 69259, 69263, 69313, 69317, 69337, 69341, 69371, 69379, 69383, 69389, 69401, + 69403, 69427, 69431, 69439, 69457, 69463, 69467, 69473, 69481, 69491, 69493, 69497, 69499, 69539, 69557, + 69593, 69623, 69653, 69661, 69677, 69691, 69697, 69709, 69737, 69739, 69761, 69763, 69767, 69779, 69809, + 69821, 69827, 69829, 69833, 69847, 69857, 69859, 69877, 69899, 69911, 69929, 69931, 69941, 69959, 69991, + 69997, 70001, 70003, 70009, 70019, 70039, 70051, 70061, 70067, 70079, 70099, 70111, 70117, 70121, 70123, + 70139, 70141, 70157, 70163, 70177, 70181, 70183, 70199, 70201, 70207, 70223, 70229, 70237, 70241, 70249, + 70271, 70289, 70297, 70309, 70313, 70321, 70327, 70351, 70373, 70379, 70381, 70393, 70423, 70429, 70439, + 70451, 70457, 70459, 70481, 70487, 70489, 70501, 70507, 70529, 70537, 70549, 70571, 70573, 70583, 70589, + 70607, 70619, 70621, 70627, 70639, 70657, 70663, 70667, 70687, 70709, 70717, 70729, 70753, 70769, 70783, + 70793, 70823, 70841, 70843, 70849, 70853, 70867, 70877, 70879, 70891, 70901, 70913, 70919, 70921, 70937, + 70949, 70951, 70957, 70969, 70979, 70981, 70991, 70997, 70999, 71011, 71023, 71039, 71059, 71069, 71081, + 71089, 71119, 71129, 71143, 71147, 71153, 71161, 71167, 71171, 71191, 71209, 71233, 71237, 71249, 71257, + 71261, 71263, 71287, 71293, 71317, 71327, 71329, 71333, 71339, 71341, 71347, 71353, 71359, 71363, 71387, + 71389, 71399, 71411, 71413, 71419, 71429, 71437, 71443, 71453, 71471, 71473, 71479, 71483, 71503, 71527, + 71537, 71549, 71551, 71563, 71569, 71593, 71597, 71633, 71647, 71663, 71671, 71693, 71699, 71707, 71711, + 71713, 71719, 71741, 71761, 71777, 71789, 71807, 71809, 71821, 71837, 71843, 71849, 71861, 71867, 71879, + 71881, 71887, 71899, 71909, 71917, 71933, 71941, 71947, 71963, 71971, 71983, 71987, 71993, 71999, 72019, + 72031, 72043, 72047, 72053, 72073, 72077, 72089, 72091, 72101, 72103, 72109, 72139, 72161, 72167, 72169, + 72173, 72211, 72221, 72223, 72227, 72229, 72251, 72253, 72269, 72271, 72277, 72287, 72307, 72313, 72337, + 72341, 72353, 72367, 72379, 72383, 72421, 72431, 72461, 72467, 72469, 72481, 72493, 72497, 72503, 72533, + 72547, 72551, 72559, 72577, 72613, 72617, 72623, 72643, 72647, 72649, 72661, 72671, 72673, 72679, 72689, + 72701, 72707, 72719, 72727, 72733, 72739, 72763, 72767, 72797, 72817, 72823, 72859, 72869, 72871, 72883, + 72889, 72893, 72901, 72907, 72911, 72923, 72931, 72937, 72949, 72953, 72959, 72973, 72977, 72997, 73009, + 73013, 73019, 73037, 73039, 73043, 73061, 73063, 73079, 73091, 73121, 73127, 73133, 73141, 73181, 73189, + 73237, 73243, 73259, 73277, 73291, 73303, 73309, 73327, 73331, 73351, 73361, 73363, 73369, 73379, 73387, + 73417, 73421, 73433, 73453, 73459, 73471, 73477, 73483, 73517, 73523, 73529, 73547, 73553, 73561, 73571, + 73583, 73589, 73597, 73607, 73609, 73613, 73637, 73643, 73651, 73673, 73679, 73681, 73693, 73699, 73709, + 73721, 73727, 73751, 73757, 73771, 73783, 73819, 73823, 73847, 73849, 73859, 73867, 73877, 73883, 73897, + 73907, 73939, 73943, 73951, 73961, 73973, 73999, 74017, 74021, 74027, 74047, 74051, 74071, 74077, 74093, + 74099, 74101, 74131, 74143, 74149, 74159, 74161, 74167, 74177, 74189, 74197, 74201, 74203, 74209, 74219, + 74231, 74257, 74279, 74287, 74293, 74297, 74311, 74317, 74323, 74353, 74357, 74363, 74377, 74381, 74383, + 74411, 74413, 74419, 74441, 74449, 74453, 74471, 74489, 74507, 74509, 74521, 74527, 74531, 74551, 74561, + 74567, 74573, 74587, 74597, 74609, 74611, 74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719, 74729, + 74731, 74747, 74759, 74761, 74771, 74779, 74797, 74821, 74827, 74831, 74843, 74857, 74861, 74869, 74873, + 74887, 74891, 74897, 74903, 74923, 74929, 74933, 74941, 74959, 75011, 75013, 75017, 75029, 75037, 75041, + 75079, 75083, 75109, 75133, 75149, 75161, 75167, 75169, 75181, 75193, 75209, 75211, 75217, 75223, 75227, + 75239, 75253, 75269, 75277, 75289, 75307, 75323, 75329, 75337, 75347, 75353, 75367, 75377, 75389, 75391, + 75401, 75403, 75407, 75431, 75437, 75479, 75503, 75511, 75521, 75527, 75533, 75539, 75541, 75553, 75557, + 75571, 75577, 75583, 75611, 75617, 75619, 75629, 75641, 75653, 75659, 75679, 75683, 75689, 75703, 75707, + 75709, 75721, 75731, 75743, 75767, 75773, 75781, 75787, 75793, 75797, 75821, 75833, 75853, 75869, 75883, + 75913, 75931, 75937, 75941, 75967, 75979, 75983, 75989, 75991, 75997, 76001, 76003, 76031, 76039, 76079, + 76081, 76091, 76099, 76103, 76123, 76129, 76147, 76157, 76159, 76163, 76207, 76213, 76231, 76243, 76249, + 76253, 76259, 76261, 76283, 76289, 76303, 76333, 76343, 76367, 76369, 76379, 76387, 76403, 76421, 76423, + 76441, 76463, 76471, 76481, 76487, 76493, 76507, 76511, 76519, 76537, 76541, 76543, 76561, 76579, 76597, + 76603, 76607, 76631, 76649, 76651, 76667, 76673, 76679, 76697, 76717, 76733, 76753, 76757, 76771, 76777, + 76781, 76801, 76819, 76829, 76831, 76837, 76847, 76871, 76873, 76883, 76907, 76913, 76919, 76943, 76949, + 76961, 76963, 76991, 77003, 77017, 77023, 77029, 77041, 77047, 77069, 77081, 77093, 77101, 77137, 77141, + 77153, 77167, 77171, 77191, 77201, 77213, 77237, 77239, 77243, 77249, 77261, 77263, 77267, 77269, 77279, + 77291, 77317, 77323, 77339, 77347, 77351, 77359, 77369, 77377, 77383, 77417, 77419, 77431, 77447, 77471, + 77477, 77479, 77489, 77491, 77509, 77513, 77521, 77527, 77543, 77549, 77551, 77557, 77563, 77569, 77573, + 77587, 77591, 77611, 77617, 77621, 77641, 77647, 77659, 77681, 77687, 77689, 77699, 77711, 77713, 77719, + 77723, 77731, 77743, 77747, 77761, 77773, 77783, 77797, 77801, 77813, 77839, 77849, 77863, 77867, 77893, + 77899, 77929, 77933, 77951, 77969, 77977, 77983, 77999, 78007, 78017, 78031, 78041, 78049, 78059, 78079, + 78101, 78121, 78137, 78139, 78157, 78163, 78167, 78173, 78179, 78191, 78193, 78203, 78229, 78233, 78241, + 78259, 78277, 78283, 78301, 78307, 78311, 78317, 78341, 78347, 78367, 78401, 78427, 78437, 78439, 78467, + 78479, 78487, 78497, 78509, 78511, 78517, 78539, 78541, 78553, 78569, 78571, 78577, 78583, 78593, 78607, + 78623, 78643, 78649, 78653, 78691, 78697, 78707, 78713, 78721, 78737, 78779, 78781, 78787, 78791, 78797, + 78803, 78809, 78823, 78839, 78853, 78857, 78877, 78887, 78889, 78893, 78901, 78919, 78929, 78941, 78977, + 78979, 78989, 79031, 79039, 79043, 79063, 79087, 79103, 79111, 79133, 79139, 79147, 79151, 79153, 79159, + 79181, 79187, 79193, 79201, 79229, 79231, 79241, 79259, 79273, 79279, 79283, 79301, 79309, 79319, 79333, + 79337, 79349, 79357, 79367, 79379, 79393, 79397, 79399, 79411, 79423, 79427, 79433, 79451, 79481, 79493, + 79531, 79537, 79549, 79559, 79561, 79579, 79589, 79601, 79609, 79613, 79621, 79627, 79631, 79633, 79657, + 79669, 79687, 79691, 79693, 79697, 79699, 79757, 79769, 79777, 79801, 79811, 79813, 79817, 79823, 79829, + 79841, 79843, 79847, 79861, 79867, 79873, 79889, 79901, 79903, 79907, 79939, 79943, 79967, 79973, 79979, + 79987, 79997, 79999, 80021, 80039, 80051, 80071, 80077, 80107, 80111, 80141, 80147, 80149, 80153, 80167, + 80173, 80177, 80191, 80207, 80209, 80221, 80231, 80233, 80239, 80251, 80263, 80273, 80279, 80287, 80309, + 80317, 80329, 80341, 80347, 80363, 80369, 80387, 80407, 80429, 80447, 80449, 80471, 80473, 80489, 80491, + 80513, 80527, 80537, 80557, 80567, 80599, 80603, 80611, 80621, 80627, 80629, 80651, 80657, 80669, 80671, + 80677, 80681, 80683, 80687, 80701, 80713, 80737, 80747, 80749, 80761, 80777, 80779, 80783, 80789, 80803, + 80809, 80819, 80831, 80833, 80849, 80863, 80897, 80909, 80911, 80917, 80923, 80929, 80933, 80953, 80963, + 80989, 81001, 81013, 81017, 81019, 81023, 81031, 81041, 81043, 81047, 81049, 81071, 81077, 81083, 81097, + 81101, 81119, 81131, 81157, 81163, 81173, 81181, 81197, 81199, 81203, 81223, 81233, 81239, 81281, 81283, + 81293, 81299, 81307, 81331, 81343, 81349, 81353, 81359, 81371, 81373, 81401, 81409, 81421, 81439, 81457, + 81463, 81509, 81517, 81527, 81533, 81547, 81551, 81553, 81559, 81563, 81569, 81611, 81619, 81629, 81637, + 81647, 81649, 81667, 81671, 81677, 81689, 81701, 81703, 81707, 81727, 81737, 81749, 81761, 81769, 81773, + 81799, 81817, 81839, 81847, 81853, 81869, 81883, 81899, 81901, 81919, 81929, 81931, 81937, 81943, 81953, + 81967, 81971, 81973, 82003, 82007, 82009, 82013, 82021, 82031, 82037, 82039, 82051, 82067, 82073, 82129, + 82139, 82141, 82153, 82163, 82171, 82183, 82189, 82193, 82207, 82217, 82219, 82223, 82231, 82237, 82241, + 82261, 82267, 82279, 82301, 82307, 82339, 82349, 82351, 82361, 82373, 82387, 82393, 82421, 82457, 82463, + 82469, 82471, 82483, 82487, 82493, 82499, 82507, 82529, 82531, 82549, 82559, 82561, 82567, 82571, 82591, + 82601, 82609, 82613, 82619, 82633, 82651, 82657, 82699, 82721, 82723, 82727, 82729, 82757, 82759, 82763, + 82781, 82787, 82793, 82799, 82811, 82813, 82837, 82847, 82883, 82889, 82891, 82903, 82913, 82939, 82963, + 82981, 82997, 83003, 83009, 83023, 83047, 83059, 83063, 83071, 83077, 83089, 83093, 83101, 83117, 83137, + 83177, 83203, 83207, 83219, 83221, 83227, 83231, 83233, 83243, 83257, 83267, 83269, 83273, 83299, 83311, + 83339, 83341, 83357, 83383, 83389, 83399, 83401, 83407, 83417, 83423, 83431, 83437, 83443, 83449, 83459, + 83471, 83477, 83497, 83537, 83557, 83561, 83563, 83579, 83591, 83597, 83609, 83617, 83621, 83639, 83641, + 83653, 83663, 83689, 83701, 83717, 83719, 83737, 83761, 83773, 83777, 83791, 83813, 83833, 83843, 83857, + 83869, 83873, 83891, 83903, 83911, 83921, 83933, 83939, 83969, 83983, 83987, 84011, 84017, 84047, 84053, + 84059, 84061, 84067, 84089, 84121, 84127, 84131, 84137, 84143, 84163, 84179, 84181, 84191, 84199, 84211, + 84221, 84223, 84229, 84239, 84247, 84263, 84299, 84307, 84313, 84317, 84319, 84347, 84349, 84377, 84389, + 84391, 84401, 84407, 84421, 84431, 84437, 84443, 84449, 84457, 84463, 84467, 84481, 84499, 84503, 84509, + 84521, 84523, 84533, 84551, 84559, 84589, 84629, 84631, 84649, 84653, 84659, 84673, 84691, 84697, 84701, + 84713, 84719, 84731, 84737, 84751, 84761, 84787, 84793, 84809, 84811, 84827, 84857, 84859, 84869, 84871, + 84913, 84919, 84947, 84961, 84967, 84977, 84979, 84991, 85009, 85021, 85027, 85037, 85049, 85061, 85081, + 85087, 85091, 85093, 85103, 85109, 85121, 85133, 85147, 85159, 85193, 85199, 85201, 85213, 85223, 85229, + 85237, 85243, 85247, 85259, 85297, 85303, 85313, 85331, 85333, 85361, 85363, 85369, 85381, 85411, 85427, + 85429, 85439, 85447, 85451, 85453, 85469, 85487, 85513, 85517, 85523, 85531, 85549, 85571, 85577, 85597, + 85601, 85607, 85619, 85621, 85627, 85639, 85643, 85661, 85667, 85669, 85691, 85703, 85711, 85717, 85733, + 85751, 85781, 85793, 85817, 85819, 85829, 85831, 85837, 85843, 85847, 85853, 85889, 85903, 85909, 85931, + 85933, 85991, 85999, 86011, 86017, 86027, 86029, 86069, 86077, 86083, 86111, 86113, 86117, 86131, 86137, + 86143, 86161, 86171, 86179, 86183, 86197, 86201, 86209, 86239, 86243, 86249, 86257, 86263, 86269, 86287, + 86291, 86293, 86297, 86311, 86323, 86341, 86351, 86353, 86357, 86369, 86371, 86381, 86389, 86399, 86413, + 86423, 86441, 86453, 86461, 86467, 86477, 86491, 86501, 86509, 86531, 86533, 86539, 86561, 86573, 86579, + 86587, 86599, 86627, 86629, 86677, 86689, 86693, 86711, 86719, 86729, 86743, 86753, 86767, 86771, 86783, + 86813, 86837, 86843, 86851, 86857, 86861, 86869, 86923, 86927, 86929, 86939, 86951, 86959, 86969, 86981, + 86993, 87011, 87013, 87037, 87041, 87049, 87071, 87083, 87103, 87107, 87119, 87121, 87133, 87149, 87151, + 87179, 87181, 87187, 87211, 87221, 87223, 87251, 87253, 87257, 87277, 87281, 87293, 87299, 87313, 87317, + 87323, 87337, 87359, 87383, 87403, 87407, 87421, 87427, 87433, 87443, 87473, 87481, 87491, 87509, 87511, + 87517, 87523, 87539, 87541, 87547, 87553, 87557, 87559, 87583, 87587, 87589, 87613, 87623, 87629, 87631, + 87641, 87643, 87649, 87671, 87679, 87683, 87691, 87697, 87701, 87719, 87721, 87739, 87743, 87751, 87767, + 87793, 87797, 87803, 87811, 87833, 87853, 87869, 87877, 87881, 87887, 87911, 87917, 87931, 87943, 87959, + 87961, 87973, 87977, 87991, 88001, 88003, 88007, 88019, 88037, 88069, 88079, 88093, 88117, 88129, 88169, + 88177, 88211, 88223, 88237, 88241, 88259, 88261, 88289, 88301, 88321, 88327, 88337, 88339, 88379, 88397, + 88411, 88423, 88427, 88463, 88469, 88471, 88493, 88499, 88513, 88523, 88547, 88589, 88591, 88607, 88609, + 88643, 88651, 88657, 88661, 88663, 88667, 88681, 88721, 88729, 88741, 88747, 88771, 88789, 88793, 88799, + 88801, 88807, 88811, 88813, 88817, 88819, 88843, 88853, 88861, 88867, 88873, 88883, 88897, 88903, 88919, + 88937, 88951, 88969, 88993, 88997, 89003, 89009, 89017, 89021, 89041, 89051, 89057, 89069, 89071, 89083, + 89087, 89101, 89107, 89113, 89119, 89123, 89137, 89153, 89189, 89203, 89209, 89213, 89227, 89231, 89237, + 89261, 89269, 89273, 89293, 89303, 89317, 89329, 89363, 89371, 89381, 89387, 89393, 89399, 89413, 89417, + 89431, 89443, 89449, 89459, 89477, 89491, 89501, 89513, 89519, 89521, 89527, 89533, 89561, 89563, 89567, + 89591, 89597, 89599, 89603, 89611, 89627, 89633, 89653, 89657, 89659, 89669, 89671, 89681, 89689, 89753, + 89759, 89767, 89779, 89783, 89797, 89809, 89819, 89821, 89833, 89839, 89849, 89867, 89891, 89897, 89899, + 89909, 89917, 89923, 89939, 89959, 89963, 89977, 89983, 89989, 90001, 90007, 90011, 90017, 90019, 90023, + 90031, 90053, 90059, 90067, 90071, 90073, 90089, 90107, 90121, 90127, 90149, 90163, 90173, 90187, 90191, + 90197, 90199, 90203, 90217, 90227, 90239, 90247, 90263, 90271, 90281, 90289, 90313, 90353, 90359, 90371, + 90373, 90379, 90397, 90401, 90403, 90407, 90437, 90439, 90469, 90473, 90481, 90499, 90511, 90523, 90527, + 90529, 90533, 90547, 90583, 90599, 90617, 90619, 90631, 90641, 90647, 90659, 90677, 90679, 90697, 90703, + 90709, 90731, 90749, 90787, 90793, 90803, 90821, 90823, 90833, 90841, 90847, 90863, 90887, 90901, 90907, + 90911, 90917, 90931, 90947, 90971, 90977, 90989, 90997, 91009, 91019, 91033, 91079, 91081, 91097, 91099, + 91121, 91127, 91129, 91139, 91141, 91151, 91153, 91159, 91163, 91183, 91193, 91199, 91229, 91237, 91243, + 91249, 91253, 91283, 91291, 91297, 91303, 91309, 91331, 91367, 91369, 91373, 91381, 91387, 91393, 91397, + 91411, 91423, 91433, 91453, 91457, 91459, 91463, 91493, 91499, 91513, 91529, 91541, 91571, 91573, 91577, + 91583, 91591, 91621, 91631, 91639, 91673, 91691, 91703, 91711, 91733, 91753, 91757, 91771, 91781, 91801, + 91807, 91811, 91813, 91823, 91837, 91841, 91867, 91873, 91909, 91921, 91939, 91943, 91951, 91957, 91961, + 91967, 91969, 91997, 92003, 92009, 92033, 92041, 92051, 92077, 92083, 92107, 92111, 92119, 92143, 92153, + 92173, 92177, 92179, 92189, 92203, 92219, 92221, 92227, 92233, 92237, 92243, 92251, 92269, 92297, 92311, + 92317, 92333, 92347, 92353, 92357, 92363, 92369, 92377, 92381, 92383, 92387, 92399, 92401, 92413, 92419, + 92431, 92459, 92461, 92467, 92479, 92489, 92503, 92507, 92551, 92557, 92567, 92569, 92581, 92593, 92623, + 92627, 92639, 92641, 92647, 92657, 92669, 92671, 92681, 92683, 92693, 92699, 92707, 92717, 92723, 92737, + 92753, 92761, 92767, 92779, 92789, 92791, 92801, 92809, 92821, 92831, 92849, 92857, 92861, 92863, 92867, + 92893, 92899, 92921, 92927, 92941, 92951, 92957, 92959, 92987, 92993, 93001, 93047, 93053, 93059, 93077, + 93083, 93089, 93097, 93103, 93113, 93131, 93133, 93139, 93151, 93169, 93179, 93187, 93199, 93229, 93239, + 93241, 93251, 93253, 93257, 93263, 93281, 93283, 93287, 93307, 93319, 93323, 93329, 93337, 93371, 93377, + 93383, 93407, 93419, 93427, 93463, 93479, 93481, 93487, 93491, 93493, 93497, 93503, 93523, 93529, 93553, + 93557, 93559, 93563, 93581, 93601, 93607, 93629, 93637, 93683, 93701, 93703, 93719, 93739, 93761, 93763, + 93787, 93809, 93811, 93827, 93851, 93871, 93887, 93889, 93893, 93901, 93911, 93913, 93923, 93937, 93941, + 93949, 93967, 93971, 93979, 93983, 93997, 94007, 94009, 94033, 94049, 94057, 94063, 94079, 94099, 94109, + 94111, 94117, 94121, 94151, 94153, 94169, 94201, 94207, 94219, 94229, 94253, 94261, 94273, 94291, 94307, + 94309, 94321, 94327, 94331, 94343, 94349, 94351, 94379, 94397, 94399, 94421, 94427, 94433, 94439, 94441, + 94447, 94463, 94477, 94483, 94513, 94529, 94531, 94541, 94543, 94547, 94559, 94561, 94573, 94583, 94597, + 94603, 94613, 94621, 94649, 94651, 94687, 94693, 94709, 94723, 94727, 94747, 94771, 94777, 94781, 94789, + 94793, 94811, 94819, 94823, 94837, 94841, 94847, 94849, 94873, 94889, 94903, 94907, 94933, 94949, 94951, + 94961, 94993, 94999, 95003, 95009, 95021, 95027, 95063, 95071, 95083, 95087, 95089, 95093, 95101, 95107, + 95111, 95131, 95143, 95153, 95177, 95189, 95191, 95203, 95213, 95219, 95231, 95233, 95239, 95257, 95261, + 95267, 95273, 95279, 95287, 95311, 95317, 95327, 95339, 95369, 95383, 95393, 95401, 95413, 95419, 95429, + 95441, 95443, 95461, 95467, 95471, 95479, 95483, 95507, 95527, 95531, 95539, 95549, 95561, 95569, 95581, + 95597, 95603, 95617, 95621, 95629, 95633, 95651, 95701, 95707, 95713, 95717, 95723, 95731, 95737, 95747, + 95773, 95783, 95789, 95791, 95801, 95803, 95813, 95819, 95857, 95869, 95873, 95881, 95891, 95911, 95917, + 95923, 95929, 95947, 95957, 95959, 95971, 95987, 95989, 96001, 96013, 96017, 96043, 96053, 96059, 96079, + 96097, 96137, 96149, 96157, 96167, 96179, 96181, 96199, 96211, 96221, 96223, 96233, 96259, 96263, 96269, + 96281, 96289, 96293, 96323, 96329, 96331, 96337, 96353, 96377, 96401, 96419, 96431, 96443, 96451, 96457, + 96461, 96469, 96479, 96487, 96493, 96497, 96517, 96527, 96553, 96557, 96581, 96587, 96589, 96601, 96643, + 96661, 96667, 96671, 96697, 96703, 96731, 96737, 96739, 96749, 96757, 96763, 96769, 96779, 96787, 96797, + 96799, 96821, 96823, 96827, 96847, 96851, 96857, 96893, 96907, 96911, 96931, 96953, 96959, 96973, 96979, + 96989, 96997, 97001, 97003, 97007, 97021, 97039, 97073, 97081, 97103, 97117, 97127, 97151, 97157, 97159, + 97169, 97171, 97177, 97187, 97213, 97231, 97241, 97259, 97283, 97301, 97303, 97327, 97367, 97369, 97373, + 97379, 97381, 97387, 97397, 97423, 97429, 97441, 97453, 97459, 97463, 97499, 97501, 97511, 97523, 97547, + 97549, 97553, 97561, 97571, 97577, 97579, 97583, 97607, 97609, 97613, 97649, 97651, 97673, 97687, 97711, + 97729, 97771, 97777, 97787, 97789, 97813, 97829, 97841, 97843, 97847, 97849, 97859, 97861, 97871, 97879, + 97883, 97919, 97927, 97931, 97943, 97961, 97967, 97973, 97987, 98009, 98011, 98017, 98041, 98047, 98057, + 98081, 98101, 98123, 98129, 98143, 98179, 98207, 98213, 98221, 98227, 98251, 98257, 98269, 98297, 98299, + 98317, 98321, 98323, 98327, 98347, 98369, 98377, 98387, 98389, 98407, 98411, 98419, 98429, 98443, 98453, + 98459, 98467, 98473, 98479, 98491, 98507, 98519, 98533, 98543, 98561, 98563, 98573, 98597, 98621, 98627, + 98639, 98641, 98663, 98669, 98689, 98711, 98713, 98717, 98729, 98731, 98737, 98773, 98779, 98801, 98807, + 98809, 98837, 98849, 98867, 98869, 98873, 98887, 98893, 98897, 98899, 98909, 98911, 98927, 98929, 98939, + 98947, 98953, 98963, 98981, 98993, 98999, 99013, 99017, 99023, 99041, 99053, 99079, 99083, 99089, 99103, + 99109, 99119, 99131, 99133, 99137, 99139, 99149, 99173, 99181, 99191, 99223, 99233, 99241, 99251, 99257, + 99259, 99277, 99289, 99317, 99347, 99349, 99367, 99371, 99377, 99391, 99397, 99401, 99409, 99431, 99439, + 99469, 99487, 99497, 99523, 99527, 99529, 99551, 99559, 99563, 99571, 99577, 99581, 99607, 99611, 99623, + 99643, 99661, 99667, 99679, 99689, 99707, 99709, 99713, 99719, 99721, 99733, 99761, 99767, 99787, 99793, + 99809, 99817, 99823, 99829, 99833, 99839, 99859, 99871, 99877, 99881, 99901, 99907, 99923, 99929, 99961, + 99971, 99989, 99991, 100003, 100019, 100043, 100049, 100057, 100069, 100103, 100109, 100129, 100151, 100153, + 100169, 100183, 100189, 100193, 100207, 100213, 100237, 100267, 100271, 100279, 100291, 100297, 100313, + 100333, 100343, 100357, 100361, 100363, 100379, 100391, 100393, 100403, 100411, 100417, 100447, 100459, + 100469, 100483, 100493, 100501, 100511, 100517, 100519, 100523, 100537, 100547, 100549, 100559, 100591, + 100609, 100613, 100621, 100649, 100669, 100673, 100693, 100699, 100703, 100733, 100741, 100747, 100769, + 100787, 100799, 100801, 100811, 100823, 100829, 100847, 100853, 100907, 100913, 100927, 100931, 100937, + 100943, 100957, 100981, 100987, 100999, 101009, 101021, 101027, 101051, 101063, 101081, 101089, 101107, + 101111, 101113, 101117, 101119, 101141, 101149, 101159, 101161, 101173, 101183, 101197, 101203, 101207, + 101209, 101221, 101267, 101273, 101279, 101281, 101287, 101293, 101323, 101333, 101341, 101347, 101359, + 101363, 101377, 101383, 101399, 101411, 101419, 101429, 101449, 101467, 101477, 101483, 101489, 101501, + 101503, 101513, 101527, 101531, 101533, 101537, 101561, 101573, 101581, 101599, 101603, 101611, 101627, + 101641, 101653, 101663, 101681, 101693, 101701, 101719, 101723, 101737, 101741, 101747, 101749, 101771, + 101789, 101797, 101807, 101833, 101837, 101839, 101863, 101869, 101873, 101879, 101891, 101917, 101921, + 101929, 101939, 101957, 101963, 101977, 101987, 101999, 102001, 102013, 102019, 102023, 102031, 102043, + 102059, 102061, 102071, 102077, 102079, 102101, 102103, 102107, 102121, 102139, 102149, 102161, 102181, + 102191, 102197, 102199, 102203, 102217, 102229, 102233, 102241, 102251, 102253, 102259, 102293, 102299, + 102301, 102317, 102329, 102337, 102359, 102367, 102397, 102407, 102409, 102433, 102437, 102451, 102461, + 102481, 102497, 102499, 102503, 102523, 102533, 102539, 102547, 102551, 102559, 102563, 102587, 102593, + 102607, 102611, 102643, 102647, 102653, 102667, 102673, 102677, 102679, 102701, 102761, 102763, 102769, + 102793, 102797, 102811, 102829, 102841, 102859, 102871, 102877, 102881, 102911, 102913, 102929, 102931, + 102953, 102967, 102983, 103001, 103007, 103043, 103049, 103067, 103069, 103079, 103087, 103091, 103093, + 103099, 103123, 103141, 103171, 103177, 103183, 103217, 103231, 103237, 103289, 103291, 103307, 103319, + 103333, 103349, 103357, 103387, 103391, 103393, 103399, 103409, 103421, 103423, 103451, 103457, 103471, + 103483, 103511, 103529, 103549, 103553, 103561, 103567, 103573, 103577, 103583, 103591, 103613, 103619, + 103643, 103651, 103657, 103669, 103681, 103687, 103699, 103703, 103723, 103769, 103787, 103801, 103811, + 103813, 103837, 103841, 103843, 103867, 103889, 103903, 103913, 103919, 103951, 103963, 103967, 103969, + 103979, 103981, 103991, 103993, 103997, 104003, 104009, 104021, 104033, 104047, 104053, 104059, 104087, + 104089, 104107, 104113, 104119, 104123, 104147, 104149, 104161, 104173, 104179, 104183, 104207, 104231, + 104233, 104239, 104243, 104281, 104287, 104297, 104309, 104311, 104323, 104327, 104347, 104369, 104381, + 104383, 104393, 104399, 104417, 104459, 104471, 104473, 104479, 104491, 104513, 104527, 104537, 104543, + 104549, 104551, 104561, 104579, 104593, 104597, 104623, 104639, 104651, 104659, 104677, 104681, 104683, + 104693, 104701, 104707, 104711, 104717, 104723, 104729, + }; - [Test] - public static void First10_000PrimesCorrect() => - Assert.AreEqual(First10000PrimeNumbers, new SieveOfEratosthenes(104729).GetPrimes()); + [Test] + public static void First10_000PrimesCorrect() => + Assert.AreEqual(First10000PrimeNumbers, new SieveOfEratosthenes(104729).GetPrimes()); - [Test] - public static void TestMaxNumber() => Assert.AreEqual(new SieveOfEratosthenes(69).MaximumNumber, 69); + [Test] + public static void TestMaxNumber() => Assert.AreEqual(new SieveOfEratosthenes(69).MaximumNumber, 69); - [TestCase(13, true)] - [TestCase(10, false)] - public static void TestIsPrime(int input, bool expected) - { - Assert.AreEqual(new SieveOfEratosthenes(100).IsPrime(input), expected); - } + [TestCase(13, true)] + [TestCase(10, false)] + public static void TestIsPrime(int input, bool expected) + { + Assert.AreEqual(new SieveOfEratosthenes(100).IsPrime(input), expected); } } diff --git a/Algorithms.Tests/Other/WelfordsVarianceTest.cs b/Algorithms.Tests/Other/WelfordsVarianceTest.cs index 502ac40c..f8378429 100644 --- a/Algorithms.Tests/Other/WelfordsVarianceTest.cs +++ b/Algorithms.Tests/Other/WelfordsVarianceTest.cs @@ -1,163 +1,162 @@ using Algorithms.Other; using NUnit.Framework; -namespace Algorithms.Tests.Other +namespace Algorithms.Tests.Other; + +public class WelfordsVarianceTest { - public class WelfordsVarianceTest + [Test] + public void WelfordVariance_Example1() { - [Test] - public void WelfordVariance_Example1() - { - var welfordsVariance = new WelfordsVariance(); - welfordsVariance.AddValue(4); - welfordsVariance.AddValue(7); - welfordsVariance.AddValue(13); - welfordsVariance.AddValue(16); + var welfordsVariance = new WelfordsVariance(); + welfordsVariance.AddValue(4); + welfordsVariance.AddValue(7); + welfordsVariance.AddValue(13); + welfordsVariance.AddValue(16); - Assert.AreEqual(4, welfordsVariance.Count); - Assert.AreEqual(10, welfordsVariance.Mean, 0.0000001); - Assert.AreEqual(22.5, welfordsVariance.Variance, 0.0000001); - Assert.AreEqual(30, welfordsVariance.SampleVariance, 0.0000001); - } + Assert.AreEqual(4, welfordsVariance.Count); + Assert.AreEqual(10, welfordsVariance.Mean, 0.0000001); + Assert.AreEqual(22.5, welfordsVariance.Variance, 0.0000001); + Assert.AreEqual(30, welfordsVariance.SampleVariance, 0.0000001); + } - [Test] - public void WelfordVariance_Example2() - { - var stats = new WelfordsVariance(); - stats.AddValue(100000004); - stats.AddValue(100000007); - stats.AddValue(100000013); - stats.AddValue(100000016); - Assert.AreEqual(4, stats.Count); - Assert.AreEqual(100000010, stats.Mean, 0.0000001); - Assert.AreEqual(22.5, stats.Variance, 0.0000001); - Assert.AreEqual(30, stats.SampleVariance, 0.0000001); - } + [Test] + public void WelfordVariance_Example2() + { + var stats = new WelfordsVariance(); + stats.AddValue(100000004); + stats.AddValue(100000007); + stats.AddValue(100000013); + stats.AddValue(100000016); + Assert.AreEqual(4, stats.Count); + Assert.AreEqual(100000010, stats.Mean, 0.0000001); + Assert.AreEqual(22.5, stats.Variance, 0.0000001); + Assert.AreEqual(30, stats.SampleVariance, 0.0000001); + } - [Test] - public void WelfordVariance_Example3() - { - var stats = new WelfordsVariance(); - stats.AddValue(1000000004); - stats.AddValue(1000000007); - stats.AddValue(1000000013); - stats.AddValue(1000000016); - Assert.AreEqual(4, stats.Count); - Assert.AreEqual(1000000010, stats.Mean, 0.0000001); - Assert.AreEqual(22.5, stats.Variance, 0.0000001); - Assert.AreEqual(30, stats.SampleVariance, 0.0000001); - } + [Test] + public void WelfordVariance_Example3() + { + var stats = new WelfordsVariance(); + stats.AddValue(1000000004); + stats.AddValue(1000000007); + stats.AddValue(1000000013); + stats.AddValue(1000000016); + Assert.AreEqual(4, stats.Count); + Assert.AreEqual(1000000010, stats.Mean, 0.0000001); + Assert.AreEqual(22.5, stats.Variance, 0.0000001); + Assert.AreEqual(30, stats.SampleVariance, 0.0000001); + } - [Test] - public void WelfordVariance_Example4() - { - var stats = new WelfordsVariance(); - stats.AddValue(6); - stats.AddValue(2); - stats.AddValue(3); - stats.AddValue(1); - Assert.AreEqual(4, stats.Count); - Assert.AreEqual(3, stats.Mean, 0.0000001); - Assert.AreEqual(3.5, stats.Variance, 0.0000001); - Assert.AreEqual(4.6666667, stats.SampleVariance, 0.0000001); - } + [Test] + public void WelfordVariance_Example4() + { + var stats = new WelfordsVariance(); + stats.AddValue(6); + stats.AddValue(2); + stats.AddValue(3); + stats.AddValue(1); + Assert.AreEqual(4, stats.Count); + Assert.AreEqual(3, stats.Mean, 0.0000001); + Assert.AreEqual(3.5, stats.Variance, 0.0000001); + Assert.AreEqual(4.6666667, stats.SampleVariance, 0.0000001); + } - [Test] - public void WelfordVariance_Example5() - { - var stats = new WelfordsVariance(new double[] { 2, 2, 5, 7 }); - Assert.AreEqual(4, stats.Count); - Assert.AreEqual(4, stats.Mean, 0.0000001); - Assert.AreEqual(4.5, stats.Variance, 0.0000001); - Assert.AreEqual(6, stats.SampleVariance, 0.0000001); - } + [Test] + public void WelfordVariance_Example5() + { + var stats = new WelfordsVariance(new double[] { 2, 2, 5, 7 }); + Assert.AreEqual(4, stats.Count); + Assert.AreEqual(4, stats.Mean, 0.0000001); + Assert.AreEqual(4.5, stats.Variance, 0.0000001); + Assert.AreEqual(6, stats.SampleVariance, 0.0000001); + } - [Test] - public void WelfordVariance_Example6() - { - var stats = new WelfordsVariance(); - stats.AddRange(new double[] { 2, 4, 4, 4, 5, 5, 7, 9 }); - Assert.AreEqual(8, stats.Count); - Assert.AreEqual(5, stats.Mean, 0.0000001); - Assert.AreEqual(4, stats.Variance, 0.0000001); - Assert.AreEqual(4.5714286, stats.SampleVariance, 0.0000001); - } + [Test] + public void WelfordVariance_Example6() + { + var stats = new WelfordsVariance(); + stats.AddRange(new double[] { 2, 4, 4, 4, 5, 5, 7, 9 }); + Assert.AreEqual(8, stats.Count); + Assert.AreEqual(5, stats.Mean, 0.0000001); + Assert.AreEqual(4, stats.Variance, 0.0000001); + Assert.AreEqual(4.5714286, stats.SampleVariance, 0.0000001); + } - [Test] - public void WelfordVariance_Example7() - { - var stats = new WelfordsVariance(); - stats.AddRange(new double[] { 9, 2, 5, 4, 12, 7, 8, 11, 9, 3, 7, 4, 12, 5, 4, 10, 9, 6, 9, 4 }); - Assert.AreEqual(20, stats.Count); - Assert.AreEqual(7, stats.Mean, 0.0000001); - Assert.AreEqual(8.9, stats.Variance, 0.0000001); - Assert.AreEqual(9.3684211, stats.SampleVariance, 0.0000001); - } + [Test] + public void WelfordVariance_Example7() + { + var stats = new WelfordsVariance(); + stats.AddRange(new double[] { 9, 2, 5, 4, 12, 7, 8, 11, 9, 3, 7, 4, 12, 5, 4, 10, 9, 6, 9, 4 }); + Assert.AreEqual(20, stats.Count); + Assert.AreEqual(7, stats.Mean, 0.0000001); + Assert.AreEqual(8.9, stats.Variance, 0.0000001); + Assert.AreEqual(9.3684211, stats.SampleVariance, 0.0000001); + } - [Test] - public void WelfordVariance_Example8() - { - var stats = new WelfordsVariance(); - stats.AddRange(new [] { 51.3, 55.6, 49.9, 52.0 }); - Assert.AreEqual(4, stats.Count); - Assert.AreEqual(52.2, stats.Mean, 0.0000001); - Assert.AreEqual(4.4250000, stats.Variance, 0.0000001); - Assert.AreEqual(5.9000000, stats.SampleVariance, 0.0000001); - } + [Test] + public void WelfordVariance_Example8() + { + var stats = new WelfordsVariance(); + stats.AddRange(new [] { 51.3, 55.6, 49.9, 52.0 }); + Assert.AreEqual(4, stats.Count); + Assert.AreEqual(52.2, stats.Mean, 0.0000001); + Assert.AreEqual(4.4250000, stats.Variance, 0.0000001); + Assert.AreEqual(5.9000000, stats.SampleVariance, 0.0000001); + } - [Test] - public void WelfordVariance_Example9() - { - var stats = new WelfordsVariance(); - stats.AddRange(new double[] { -5, -3, -1, 1, 3 }); - Assert.AreEqual(5, stats.Count); - Assert.AreEqual(-1, stats.Mean, 0.0000001); - Assert.AreEqual(8, stats.Variance, 0.0000001); - Assert.AreEqual(10, stats.SampleVariance, 0.0000001); - } + [Test] + public void WelfordVariance_Example9() + { + var stats = new WelfordsVariance(); + stats.AddRange(new double[] { -5, -3, -1, 1, 3 }); + Assert.AreEqual(5, stats.Count); + Assert.AreEqual(-1, stats.Mean, 0.0000001); + Assert.AreEqual(8, stats.Variance, 0.0000001); + Assert.AreEqual(10, stats.SampleVariance, 0.0000001); + } - [Test] - public void WelfordVariance_Example10() - { - var stats = new WelfordsVariance(); - stats.AddRange(new double[] { -1, 0, 1 }); - Assert.AreEqual(3, stats.Count); - Assert.AreEqual(0, stats.Mean, 0.0000001); - Assert.AreEqual(0.6666667, stats.Variance, 0.0000001); - Assert.AreEqual(1, stats.SampleVariance, 0.0000001); - } + [Test] + public void WelfordVariance_Example10() + { + var stats = new WelfordsVariance(); + stats.AddRange(new double[] { -1, 0, 1 }); + Assert.AreEqual(3, stats.Count); + Assert.AreEqual(0, stats.Mean, 0.0000001); + Assert.AreEqual(0.6666667, stats.Variance, 0.0000001); + Assert.AreEqual(1, stats.SampleVariance, 0.0000001); + } - [Test] - public void WelfordVariance_NoValue() - { - var stats = new WelfordsVariance(); - Assert.AreEqual(0, stats.Count); - Assert.AreEqual(double.NaN, stats.Mean); - Assert.AreEqual(double.NaN, stats.Variance); - Assert.AreEqual(double.NaN, stats.SampleVariance); - } + [Test] + public void WelfordVariance_NoValue() + { + var stats = new WelfordsVariance(); + Assert.AreEqual(0, stats.Count); + Assert.AreEqual(double.NaN, stats.Mean); + Assert.AreEqual(double.NaN, stats.Variance); + Assert.AreEqual(double.NaN, stats.SampleVariance); + } - [Test] - public void WelfordVariance_OneValue() - { - var stats = new WelfordsVariance(); - stats.AddValue(1); - Assert.AreEqual(1, stats.Count); - Assert.AreEqual(double.NaN, stats.Mean); - Assert.AreEqual(double.NaN, stats.Variance); - Assert.AreEqual(double.NaN, stats.SampleVariance); - } + [Test] + public void WelfordVariance_OneValue() + { + var stats = new WelfordsVariance(); + stats.AddValue(1); + Assert.AreEqual(1, stats.Count); + Assert.AreEqual(double.NaN, stats.Mean); + Assert.AreEqual(double.NaN, stats.Variance); + Assert.AreEqual(double.NaN, stats.SampleVariance); + } - [Test] - public void WelfordVariance_TwoValues() - { - var stats = new WelfordsVariance(); - stats.AddValue(1); - stats.AddValue(2); - Assert.AreEqual(2, stats.Count); - Assert.AreEqual(1.5, stats.Mean, 0.0000001); - Assert.AreEqual(0.25, stats.Variance, 0.0000001); - Assert.AreEqual(0.5, stats.SampleVariance, 0.0000001); - } + [Test] + public void WelfordVariance_TwoValues() + { + var stats = new WelfordsVariance(); + stats.AddValue(1); + stats.AddValue(2); + Assert.AreEqual(2, stats.Count); + Assert.AreEqual(1.5, stats.Mean, 0.0000001); + Assert.AreEqual(0.25, stats.Variance, 0.0000001); + Assert.AreEqual(0.5, stats.SampleVariance, 0.0000001); } } From 9b9c5b6afb859043feff8d0c5a15abbcd99c5dad Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Wed, 10 Jan 2024 22:44:10 +0200 Subject: [PATCH 090/138] Remove redundant attributes (#438) --- .../Compressors/BurrowsWheelerTransformTests.cs | 2 -- Algorithms.Tests/Compressors/HuffmanCompressorTests.cs | 1 - Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs | 1 - Algorithms.Tests/Encoders/FeistelCipherTest.cs | 1 - Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs | 1 - Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs | 4 +--- Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs | 4 +--- .../ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs | 2 -- .../ModularArithmetic/ModularMultiplicativeInverseTest.cs | 4 ---- Algorithms.Tests/Numeric/AliquotSumCalculatorTests.cs | 2 -- Algorithms.Tests/Numeric/AmicableNumbersTest.cs | 1 - Algorithms.Tests/Numeric/BinomialCoefficientTests.cs | 1 - .../Numeric/Factorization/TrialDivisionFactorizerTests.cs | 2 -- .../BinaryGreatestCommonDivisorFinderTests.cs | 1 - .../EuclideanGreatestCommonDivisorFinderTests.cs | 1 - Algorithms.Tests/Numeric/KeithNumberTest.cs | 2 -- Algorithms.Tests/Numeric/ModularExponentiationTest.cs | 1 - Algorithms.Tests/Numeric/NarcissisticNumberTest.cs | 1 - Algorithms.Tests/Numeric/PerfectNumberTest.cs | 2 -- Algorithms.Tests/Numeric/PerfectSquareTest.cs | 1 - Algorithms.Tests/Other/FermatPrimeCheckerTests.cs | 1 - Algorithms.Tests/Other/GeoLocationTests.cs | 1 - Algorithms.Tests/Other/Int2BinaryTests.cs | 3 --- Algorithms.Tests/Other/LuhnTests.cs | 3 --- Algorithms.Tests/Other/RGBHSVConversionTest.cs | 2 -- .../LevenshteinDistance/LevenshteinDistanceTests.cs | 1 - Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs | 1 - Algorithms.Tests/Strings/PalindromeTests.cs | 2 -- .../Strings/Similarity/HammingDistanceTests.cs | 1 - Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs | 1 - .../Strings/Similarity/JaroWinklerDistanceTests.cs | 1 - DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs | 2 -- .../Hashing/NumberTheory/PrimeNumberTests.cs | 2 -- DataStructures.Tests/Heap/MinMaxHeapTests.cs | 5 ----- .../ScapegoatTree/ScapegoatTreeNodeTests.cs | 7 ------- DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs | 6 ------ 36 files changed, 2 insertions(+), 72 deletions(-) diff --git a/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs b/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs index cd5f4ea1..d022c950 100644 --- a/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs +++ b/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs @@ -6,7 +6,6 @@ namespace Algorithms.Tests.Compressors; public class BurrowsWheelerTransformTests { - [Test] [TestCase("banana", "nnbaaa", 3)] [TestCase("SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES", "TEXYDST.E.IXIXIXXSSMPPS.B..E.S.EUSFXDIIOIIIT", 29)] [TestCase("", "", 0)] @@ -20,7 +19,6 @@ public void Encode(string input, string expectedString, int expectedIndex) Assert.AreEqual(expectedIndex, index); } - [Test] [TestCase("nnbaaa", 3, "banana")] [TestCase("TEXYDST.E.IXIXIXXSSMPPS.B..E.S.EUSFXDIIOIIIT", 29, "SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES")] [TestCase("", 0, "")] diff --git a/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs b/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs index 70540020..f6d04bb8 100644 --- a/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs +++ b/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs @@ -8,7 +8,6 @@ namespace Algorithms.Tests.Compressors; public static class HuffmanCompressorTests { - [Test] [TestCase("This is a string", "101010110111011101110111100011111010010010010011000")] [TestCase("Hello", "1101110010")] [TestCase("dddddddddd", "1111111111")] diff --git a/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs b/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs index ec847b2e..19bec5d5 100644 --- a/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs +++ b/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs @@ -7,7 +7,6 @@ namespace Algorithms.Tests.Compressors; public static class ShannonFanoCompressorTests { - [Test] [TestCase("dddddddddd", "1111111111")] [TestCase("a", "1")] [TestCase("", "")] diff --git a/Algorithms.Tests/Encoders/FeistelCipherTest.cs b/Algorithms.Tests/Encoders/FeistelCipherTest.cs index ea5763a9..54bad8a6 100644 --- a/Algorithms.Tests/Encoders/FeistelCipherTest.cs +++ b/Algorithms.Tests/Encoders/FeistelCipherTest.cs @@ -26,7 +26,6 @@ public static void DecodedStringIsTheSame([Random(100)] uint key) Assert.AreEqual(message, decoded); } - [Test] [TestCase("00001111", (uint)0x12345678)] [TestCase("00001111222233334444555566667", (uint)0x12345678)] [TestCase("000011112222333344445555666677", (uint)0x12345678)] diff --git a/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs b/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs index f6da0cb2..52937d93 100644 --- a/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs +++ b/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs @@ -39,7 +39,6 @@ public static void EmptyArrayForNullRoot() Assert.IsEmpty(levelOrder); } - [Test] [TestCase(new [] {7, 9, 5})] [TestCase(new [] { 7, 13, 11, 15, 14, 4, 5, 16, 2 })] public static void IncorrectLevelOrderTraversal(int[] insertion) diff --git a/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs b/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs index 0c13c19d..50ace3ad 100644 --- a/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs +++ b/Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs @@ -8,12 +8,11 @@ namespace Algorithms.Tests.LinearAlgebra.Distances; public static class EuclideanTests { /// - /// Test the result given by Euclidean distance function. + /// Test the result given by Euclidean distance function. /// /// Origin point. /// Target point. /// Expected result. - [Test] [TestCase(new[] { 1.5 }, new[] { -1.0 }, 2.5)] [TestCase(new[] { 7.0, 4.0, 3.0 }, new[] { 17.0, 6.0, 2.0 }, 10.247)] public static void DistanceTest(double[] point1, double[] point2, double expectedResult) @@ -26,7 +25,6 @@ public static void DistanceTest(double[] point1, double[] point2, double expecte ///
/// First point of N dimensions. /// Second point of M dimensions, M != N. - [Test] [TestCase(new[] { 7.0, 4.5 }, new[] { -3.0 })] [TestCase(new[] { 12.0 }, new[] { 1.5, 7.0, 3.2 })] public static void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2) diff --git a/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs b/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs index ed123cc2..d03758b8 100644 --- a/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs +++ b/Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs @@ -8,12 +8,11 @@ namespace Algorithms.Tests.LinearAlgebra.Distances; public class ManhattanTests { /// - /// Test the result given by Manhattan distance function. + /// Test the result given by Manhattan distance function. /// /// Origin point. /// Target point. /// Expected result. - [Test] [TestCase(new[] { 1.5 }, new[] { -1.0 }, 2.5)] [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0, 5.0 }, 5)] [TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 1.0, 2.0, 3.0 }, 0)] @@ -28,7 +27,6 @@ public void DistanceTest(double[] point1, double[] point2, double expectedDistan ///
/// First point of N dimensions. /// Second point of M dimensions, M != N. - [Test] [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0 })] [TestCase(new[] { 1.0 }, new[] { 1.0, 2.0, 3.0 })] public void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2) diff --git a/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs b/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs index 03d3723a..69d98fc1 100644 --- a/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs +++ b/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs @@ -6,7 +6,6 @@ namespace Algorithms.Tests.ModularArithmetic; public static class ExtendedEuclideanAlgorithmTest { - [Test] [TestCase(240, 46, 2, -9, 47)] [TestCase(46, 240, 2, 47, -9)] [TestCase(2, 3, 1, -1, 1)] @@ -29,7 +28,6 @@ public static void TestCompute(long a, long b, long expectedGCD, long expectedBe Assert.AreEqual(expectedBezoutOfB, eeaResult.bezoutB); } - [Test] [TestCase(240, 46, 2, -9, 47)] [TestCase(46, 240, 2, 47, -9)] [TestCase(2, 3, 1, -1, 1)] diff --git a/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs b/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs index 0a7b4982..f79ec79f 100644 --- a/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs +++ b/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs @@ -7,7 +7,6 @@ namespace Algorithms.Tests.ModularArithmetic; public static class ModularMultiplicativeInverseTest { - [Test] [TestCase(2, 3, 2)] [TestCase(1, 1, 0)] [TestCase(13, 17, 4)] @@ -20,7 +19,6 @@ public static void TestCompute(long a, long n, long expected) Assert.AreEqual(expected, inverse); } - [Test] [TestCase(46, 240)] [TestCase(0, 17)] [TestCase(17, 0)] @@ -36,7 +34,6 @@ public static void TestCompute_Irrevertible(long a, long n) _ = Assert.Throws(Act); } - [Test] [TestCase(2, 3, 2)] [TestCase(1, 1, 0)] [TestCase(13, 17, 4)] @@ -49,7 +46,6 @@ public static void TestCompute_BigInteger(long a, long n, long expected) Assert.AreEqual(new BigInteger(expected), inverse); } - [Test] [TestCase(46, 240)] [TestCase(0, 17)] [TestCase(17, 0)] diff --git a/Algorithms.Tests/Numeric/AliquotSumCalculatorTests.cs b/Algorithms.Tests/Numeric/AliquotSumCalculatorTests.cs index 87057811..2cf7af0d 100644 --- a/Algorithms.Tests/Numeric/AliquotSumCalculatorTests.cs +++ b/Algorithms.Tests/Numeric/AliquotSumCalculatorTests.cs @@ -7,7 +7,6 @@ namespace Algorithms.Tests.Numeric; public static class AliquotSumCalculatorTests { - [Test] [TestCase(1, 0)] [TestCase(3, 1)] [TestCase(25, 6)] @@ -23,7 +22,6 @@ public static void CalculateSum_SumIsCorrect(int number, int expectedSum) result.Should().Be(expectedSum); } - [Test] [TestCase(-2)] public static void CalculateSum_NegativeInput_ExceptionIsThrown(int number) { diff --git a/Algorithms.Tests/Numeric/AmicableNumbersTest.cs b/Algorithms.Tests/Numeric/AmicableNumbersTest.cs index 8eb61f4f..f04e94bf 100644 --- a/Algorithms.Tests/Numeric/AmicableNumbersTest.cs +++ b/Algorithms.Tests/Numeric/AmicableNumbersTest.cs @@ -5,7 +5,6 @@ namespace Algorithms.Tests.Numeric; public static class AmicableNumbersTest { - [Test] [TestCase(220, 284)] [TestCase(1184, 1210)] [TestCase(2620, 2924)] diff --git a/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs b/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs index a08a9204..5bc04c27 100644 --- a/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs +++ b/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs @@ -20,7 +20,6 @@ public static void CalculateFromPairs(int n, int k, int expected) Assert.AreEqual(new BigInteger(expected), result); } - [Test] [TestCase(3, 7)] public static void TeoremCalculateThrowsException(int n, int k) { diff --git a/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs b/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs index f4e5298e..13f7ab5f 100755 --- a/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs +++ b/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs @@ -5,7 +5,6 @@ namespace Algorithms.Tests.Numeric.Factorization; public static class TrialDivisionFactorizerTests { - [Test] [TestCase(2)] [TestCase(3)] [TestCase(29)] @@ -22,7 +21,6 @@ public static void PrimeNumberFactorizationFails(int p) Assert.IsFalse(success); } - [Test] [TestCase(4, 2)] [TestCase(6, 2)] [TestCase(8, 2)] diff --git a/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs b/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs index 84b40e14..78262811 100644 --- a/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs +++ b/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs @@ -5,7 +5,6 @@ namespace Algorithms.Tests.Numeric.GreatestCommonDivisor; public static class BinaryGreatestCommonDivisorFinderTests { - [Test] [TestCase(2, 3, 1)] [TestCase(1, 1, 1)] [TestCase(13, 17, 1)] diff --git a/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs b/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs index 68335730..ec9f5be2 100644 --- a/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs +++ b/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs @@ -5,7 +5,6 @@ namespace Algorithms.Tests.Numeric.GreatestCommonDivisor; public static class EuclideanGreatestCommonDivisorFinderTests { - [Test] [TestCase(2, 3, 1)] [TestCase(1, 1, 1)] [TestCase(13, 17, 1)] diff --git a/Algorithms.Tests/Numeric/KeithNumberTest.cs b/Algorithms.Tests/Numeric/KeithNumberTest.cs index 9ec102f0..eb8f510b 100644 --- a/Algorithms.Tests/Numeric/KeithNumberTest.cs +++ b/Algorithms.Tests/Numeric/KeithNumberTest.cs @@ -6,7 +6,6 @@ namespace Algorithms.Tests.Numeric; public static class KeithNumberTest { - [Test] [TestCase(14)] [TestCase(47)] [TestCase(197)] @@ -20,7 +19,6 @@ public static void KeithNumberWork(int number) Assert.IsTrue(result); } - [Test] [TestCase(-2)] public static void KeithNumberShouldThrowEx(int number) { diff --git a/Algorithms.Tests/Numeric/ModularExponentiationTest.cs b/Algorithms.Tests/Numeric/ModularExponentiationTest.cs index 355fa52b..414fb026 100644 --- a/Algorithms.Tests/Numeric/ModularExponentiationTest.cs +++ b/Algorithms.Tests/Numeric/ModularExponentiationTest.cs @@ -7,7 +7,6 @@ namespace Algorithms.Tests.Numeric; public class ModularExponentiationTest { - [Test] [TestCase(3, 6, 11, 3)] [TestCase(5, 3, 13, 8)] [TestCase(2, 7, 17, 9)] diff --git a/Algorithms.Tests/Numeric/NarcissisticNumberTest.cs b/Algorithms.Tests/Numeric/NarcissisticNumberTest.cs index 65a8ca78..4741fe8a 100644 --- a/Algorithms.Tests/Numeric/NarcissisticNumberTest.cs +++ b/Algorithms.Tests/Numeric/NarcissisticNumberTest.cs @@ -5,7 +5,6 @@ namespace Algorithms.Tests.Numeric; public static class NarcissisticNumberTest { - [Test] [TestCase(2, ExpectedResult = true)] [TestCase(3, ExpectedResult = true)] [TestCase(28, ExpectedResult = false)] diff --git a/Algorithms.Tests/Numeric/PerfectNumberTest.cs b/Algorithms.Tests/Numeric/PerfectNumberTest.cs index 4c8ee058..fba92763 100644 --- a/Algorithms.Tests/Numeric/PerfectNumberTest.cs +++ b/Algorithms.Tests/Numeric/PerfectNumberTest.cs @@ -6,7 +6,6 @@ namespace Algorithms.Tests.Numeric; public static class PerfectNumberTests { - [Test] [TestCase(6)] [TestCase(28)] [TestCase(496)] @@ -22,7 +21,6 @@ public static void PerfectNumberWork(int number) Assert.IsTrue(result); } - [Test] [TestCase(-2)] public static void PerfectNumberShouldThrowEx(int number) { diff --git a/Algorithms.Tests/Numeric/PerfectSquareTest.cs b/Algorithms.Tests/Numeric/PerfectSquareTest.cs index 13437317..494c12b7 100644 --- a/Algorithms.Tests/Numeric/PerfectSquareTest.cs +++ b/Algorithms.Tests/Numeric/PerfectSquareTest.cs @@ -5,7 +5,6 @@ namespace Algorithms.Tests.Numeric; public static class PerfectSquareTests { - [Test] [TestCase(-4, ExpectedResult = false)] [TestCase(4, ExpectedResult = true)] [TestCase(9, ExpectedResult = true)] diff --git a/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs b/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs index fd962180..5f916539 100644 --- a/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs +++ b/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs @@ -6,7 +6,6 @@ namespace Algorithms.Tests.Other; public static class FermatPrimeCheckerTests { - [Test] [TestCase(5, true)] [TestCase(2633, true)] [TestCase(9439, true)] diff --git a/Algorithms.Tests/Other/GeoLocationTests.cs b/Algorithms.Tests/Other/GeoLocationTests.cs index a5d1ce68..b3aa427b 100644 --- a/Algorithms.Tests/Other/GeoLocationTests.cs +++ b/Algorithms.Tests/Other/GeoLocationTests.cs @@ -6,7 +6,6 @@ namespace Algorithms.Tests.Other; public static class GeoLocationTests { - [Test] [TestCase(53.430488d, -2.96129d, 53.430488d, -2.96129d, 0d)] [TestCase(53.430971d, -2.959806d, 53.430242d, -2.960830d, 105d)] public static void CalculateDistanceFromLatLngTest( diff --git a/Algorithms.Tests/Other/Int2BinaryTests.cs b/Algorithms.Tests/Other/Int2BinaryTests.cs index 65794ae4..9280beba 100644 --- a/Algorithms.Tests/Other/Int2BinaryTests.cs +++ b/Algorithms.Tests/Other/Int2BinaryTests.cs @@ -5,7 +5,6 @@ namespace Algorithms.Tests.Other; public static class Int2BinaryTests { - [Test] [TestCase((ushort)0, "0000000000000000")] [TestCase((ushort)0b1, "0000000000000001")] [TestCase((ushort)0b0001010100111000, "0001010100111000")] @@ -24,7 +23,6 @@ public static void GetsBinary(ushort input, string expected) } - [Test] [TestCase((uint)0, "00000000000000000000000000000000")] [TestCase((uint)0b1, "00000000000000000000000000000001")] [TestCase((uint)0b0001010100111000, "00000000000000000001010100111000")] @@ -43,7 +41,6 @@ public static void GetsBinary(uint input, string expected) Assert.AreEqual(expected, result); } - [Test] [TestCase((ulong)0, "0000000000000000000000000000000000000000000000000000000000000000")] [TestCase((ulong)0b1, "0000000000000000000000000000000000000000000000000000000000000001")] [TestCase((ulong)0b0001010100111000, "0000000000000000000000000000000000000000000000000001010100111000")] diff --git a/Algorithms.Tests/Other/LuhnTests.cs b/Algorithms.Tests/Other/LuhnTests.cs index eaa60d97..3040fdc2 100644 --- a/Algorithms.Tests/Other/LuhnTests.cs +++ b/Algorithms.Tests/Other/LuhnTests.cs @@ -8,7 +8,6 @@ namespace Algorithms.Tests.Other; ///
public class LuhnTests { - [Test] [TestCase("89014103211118510720")] // ICCID [TestCase("071052120")] // Social Security Code [TestCase("449125546588769")] // IMEI @@ -25,7 +24,6 @@ public void ValidateTrue(string number) Assert.True(validate); } - [Test] [TestCase("89012104211118510720")] // ICCID [TestCase("021053120")] // Social Security Code [TestCase("449145545588969")] // IMEI @@ -42,7 +40,6 @@ public void ValidateFalse(string number) Assert.False(validate); } - [Test] [TestCase("x9012104211118510720")] // ICCID [TestCase("0210x3120")] // Social Security Code [TestCase("44914554558896x")] // IMEI diff --git a/Algorithms.Tests/Other/RGBHSVConversionTest.cs b/Algorithms.Tests/Other/RGBHSVConversionTest.cs index de84ec2c..8a577134 100644 --- a/Algorithms.Tests/Other/RGBHSVConversionTest.cs +++ b/Algorithms.Tests/Other/RGBHSVConversionTest.cs @@ -29,7 +29,6 @@ public static void ValueOutOfRange_ThrowsArgumentOutOfRangeException() } // expected RGB-values taken from https://www.rapidtables.com/convert/color/hsv-to-rgb.html - [Test] [TestCase(0, 0, 0, 0, 0, 0)] [TestCase(0, 0, 1, 255, 255, 255)] [TestCase(0, 1, 1, 255, 0, 0)] @@ -55,7 +54,6 @@ public static void TestRgbOutput( } // Parameters of test-cases for TestRGBOutput reversed - [Test] [TestCase(0, 0, 0, 0, 0, 0)] [TestCase(255, 255, 255, 0, 0, 1)] [TestCase(255, 0, 0, 0, 1, 1)] diff --git a/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs index b2ad0298..68a94306 100644 --- a/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs @@ -5,7 +5,6 @@ namespace Algorithms.Tests.DynamicProgramming { public class LevenshteinDistanceTests { - [Test] [TestCase("kitten", "sitting", 3)] [TestCase("bob", "bond", 2)] [TestCase("algorithm", "logarithm", 3)] diff --git a/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs b/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs index ce24ac39..4a92b9cd 100644 --- a/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs +++ b/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs @@ -6,7 +6,6 @@ namespace Algorithms.Tests.Strings { public static class GeneralStringAlgorithmsTests { - [Test] [TestCase("Griffith", 'f', 2)] [TestCase("Randomwoooord", 'o', 4)] [TestCase("Control", 'C', 1)] diff --git a/Algorithms.Tests/Strings/PalindromeTests.cs b/Algorithms.Tests/Strings/PalindromeTests.cs index 1b3a38e2..98c62692 100644 --- a/Algorithms.Tests/Strings/PalindromeTests.cs +++ b/Algorithms.Tests/Strings/PalindromeTests.cs @@ -5,7 +5,6 @@ namespace Algorithms.Tests.Strings { public static class PalindromeTests { - [Test] [TestCase("Anna")] [TestCase("A Santa at Nasa")] public static void TextIsPalindrome_TrueExpected(string text) @@ -18,7 +17,6 @@ public static void TextIsPalindrome_TrueExpected(string text) Assert.True(isPalindrome); } - [Test] [TestCase("hallo")] [TestCase("Once upon a time")] public static void TextNotPalindrome_FalseExpected(string text) diff --git a/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs b/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs index 2f21cf3a..addf80f2 100644 --- a/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs +++ b/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs @@ -7,7 +7,6 @@ namespace Algorithms.Tests.Strings { public class HammingDistanceTests { - [Test] [TestCase("equal", "equal", 0)] [TestCase("dog", "dig", 1)] [TestCase("12345", "abcde", 5)] diff --git a/Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs b/Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs index 48800e14..c786aff1 100644 --- a/Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs +++ b/Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs @@ -7,7 +7,6 @@ namespace Algorithms.Tests.Strings { public class JaroSimilarityTests { - [Test] [TestCase("equal", "equal", 1)] [TestCase("abc", "123", 0)] [TestCase("FAREMVIEL", "FARMVILLE", 0.88d)] diff --git a/Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs b/Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs index e3a07247..37a0af93 100644 --- a/Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs +++ b/Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs @@ -7,7 +7,6 @@ namespace Algorithms.Tests.Strings { public class JaroWinklerDistanceTests { - [Test] [TestCase("equal", "equal", 0)] [TestCase("abc", "123", 1)] [TestCase("Winkler", "Welfare", 0.33)] diff --git a/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs b/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs index 182c2d10..43373972 100644 --- a/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs +++ b/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs @@ -10,7 +10,6 @@ namespace DataStructures.Tests.Graph; [TestFixture] public class DirectedWeightedGraphTests { - [Test] [TestCase(-1)] [TestCase(-2)] [TestCase(-3)] @@ -22,7 +21,6 @@ public void GraphInitializationTest_ShouldThrowOverflow(int capacity) .WithMessage("Graph capacity should always be a non-negative integer."); } - [Test] [TestCase(1)] [TestCase(10)] [TestCase(20)] diff --git a/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs b/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs index d6e11c57..c2f32d88 100644 --- a/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs +++ b/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs @@ -93,7 +93,6 @@ public static class PrimeNumberTests new object[] { 10, 1, true, 7 } }; - [Test] [TestCaseSource("IsPrimeSource")] public static void IsPrimeTest(int number, bool expected) { @@ -101,7 +100,6 @@ public static void IsPrimeTest(int number, bool expected) Assert.AreEqual(expected, actual); } - [Test] [TestCaseSource("NextPrimeSource")] public static void NextPrimeTest(int number, int factor, bool desc, int expected) { diff --git a/DataStructures.Tests/Heap/MinMaxHeapTests.cs b/DataStructures.Tests/Heap/MinMaxHeapTests.cs index 7752681a..2a756d18 100644 --- a/DataStructures.Tests/Heap/MinMaxHeapTests.cs +++ b/DataStructures.Tests/Heap/MinMaxHeapTests.cs @@ -34,7 +34,6 @@ public static void CustomComparerTest() Assert.AreEqual("aaaa", mmh.GetMax()); } - [Test] [TestCaseSource("CollectionsSource")] public static void AddTest(IEnumerable collection) { @@ -52,7 +51,6 @@ public static void AddTest(IEnumerable collection) Assert.AreEqual(collection.Count(), mmh.Count); } - [Test] [TestCaseSource("CollectionsSource")] public static void ExtractMaxTest(IEnumerable collection) { @@ -69,7 +67,6 @@ public static void ExtractMaxTest(IEnumerable collection) Assert.AreEqual(collection.Count() - 1, mmh.Count); } - [Test] [TestCaseSource("CollectionsSource")] public static void ExtractMinTest(IEnumerable collection) { @@ -87,7 +84,6 @@ public static void ExtractMinTest(IEnumerable collection) } - [Test] [TestCaseSource("CollectionsSource")] public static void GetMaxTest(IEnumerable collection) { @@ -100,7 +96,6 @@ public static void GetMaxTest(IEnumerable collection) Assert.AreEqual(collection.Max(), maxValue); } - [Test] [TestCaseSource("CollectionsSource")] public static void GetMinTest(IEnumerable collection) { diff --git a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs index 39adf687..ca7611a8 100644 --- a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs +++ b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs @@ -7,7 +7,6 @@ namespace DataStructures.Tests.ScapegoatTree; [TestFixture] public class ScapegoatTreeNodeTests { - [Test] [TestCase(2,1)] [TestCase("B", "A")] public void RightSetter_OtherKeyPrecedesRightKey_ThrowsException(TKey a, TKey b) @@ -19,7 +18,6 @@ public void RightSetter_OtherKeyPrecedesRightKey_ThrowsException(TKey a, T Assert.Throws(() => instance.Right = other); } - [Test] [TestCase(1,2)] [TestCase("A","B")] public void RightSetter_OtherKeyFollowsRightKey_AddsChild(TKey a, TKey b) @@ -31,7 +29,6 @@ public void RightSetter_OtherKeyFollowsRightKey_AddsChild(TKey a, TKey b) Assert.DoesNotThrow(() => instance.Right = other); } - [Test] [TestCase(1,2)] [TestCase("A","B")] public void LeftSetter_OtherKeyFollowsLeftKey_ThrowsException(TKey a, TKey b) @@ -43,7 +40,6 @@ public void LeftSetter_OtherKeyFollowsLeftKey_ThrowsException(TKey a, TKey Assert.Throws(() => instance.Left = other); } - [Test] [TestCase(2,1)] [TestCase("B", "A")] public void LeftSetter_OtherKeyPrecedesLeftKey_AddsChild(TKey a, TKey b) @@ -55,7 +51,6 @@ public void LeftSetter_OtherKeyPrecedesLeftKey_AddsChild(TKey a, TKey b) Assert.DoesNotThrow(() => instance.Left = other); } - [Test] [TestCase(1,2)] [TestCase("A","B")] public void CompareTo_InstanceKeyPrecedesOtherKey_ReturnsMinusOne(TKey a, TKey b) @@ -69,7 +64,6 @@ public void CompareTo_InstanceKeyPrecedesOtherKey_ReturnsMinusOne(TKey a, Assert.AreEqual(result, -1); } - [Test] [TestCase(2, 1)] [TestCase("B","A")] public void CompareTo_InstanceKeyFollowsOtherKey_ReturnsOne(TKey a, TKey b) @@ -83,7 +77,6 @@ public void CompareTo_InstanceKeyFollowsOtherKey_ReturnsOne(TKey a, TKey b Assert.AreEqual(result, 1); } - [Test] [TestCase(1, 1)] [TestCase("A","A")] public void CompareTo_InstanceKeyEqualsOtherKey_ReturnsZero(TKey a, TKey b) diff --git a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs index 08733c94..77ea8095 100644 --- a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs +++ b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs @@ -31,7 +31,6 @@ public void Constructor_AlphaParameter_InstanceIsValid() Assert.AreEqual(expected, tree.Alpha); } - [Test] [TestCase(1.1)] [TestCase(0.4)] public void Constructor_AlphaParameterIsInvalid_ThrowsException(double alpha) @@ -113,7 +112,6 @@ public void Search_KeyIsPresent_ReturnsKey() Assert.AreEqual(1, result!.Key); } - [Test] [TestCase(-2)] [TestCase(3)] public void Search_KeyIsNotPresent_ReturnsNull(int key) @@ -262,7 +260,6 @@ public void Insert_KeyIsNotPresent_KeyIsInserted() Assert.AreEqual(2, tree.MaxSize); } - [Test] [TestCase(3, new[]{2,5,1,6}, -1, 0.5)] public void Insert_TreeIsUnbalanced_RebuildsTree(int root, int[] keys, int candidate, double alpha) { @@ -281,7 +278,6 @@ public void Insert_TreeIsUnbalanced_RebuildsTree(int root, int[] keys, int candi Assert.Throws(() => tree.Insert(candidate)); } - [Test] [TestCase(20, new[]{10,30,5,11,29,40,50, 1, 12}, new[]{50,40,30,29}, 0.7)] public void Delete_TreeIsUnbalanced_BalancesTree(int root, int[] keys, int[] candidates, double alpha) { @@ -306,7 +302,6 @@ public void Delete_TreeIsUnbalanced_BalancesTree(int root, int[] keys, int[] can }); } - [Test] [TestCase(20, new[]{10,30,5,11,29,40,50}, 10, 1)] public void Delete_TreeIsUnbalanced_MaxSizeEqualsSize(int root, int[] keys, int candidate, double alpha) { @@ -326,7 +321,6 @@ public void Delete_TreeIsUnbalanced_MaxSizeEqualsSize(int root, int[] keys, int Assert.AreEqual(tree.Size, tree.MaxSize); } - [Test] [TestCase(3, new[]{2,5,1,6}, -1, 0.5)] [TestCase(3, new[]{2,5,1,6}, 7, 0.5)] public void Insert_TreeIsUnbalanced_BalancesTree(int root, int[] keys, int candidate, double alpha) From 60a8513f28d7a7ea23da9cbcc71fccdf8d591475 Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Fri, 12 Jan 2024 22:55:36 +0000 Subject: [PATCH 091/138] Switch to file-scoped namespaces (#439) --- .../GenerateChangesDictionaryTests.cs | 33 ++-- .../GenerateSingleCoinChangesTests.cs | 173 +++++++++--------- .../CoinChange/GetMinimalNextCoinTests.cs | 23 ++- .../CoinChange/MakeCoinChangeDynamicTests.cs | 47 +++-- .../LevenshteinDistanceTests.cs | 25 ++- .../NQueens/BacktrackingNQueensSolverTests.cs | 167 +++++++++-------- .../StableMarriage/GaleShapleyTests.cs | 73 ++++---- .../Search/BinarySearcherTests.cs | 101 +++++----- Algorithms.Tests/Search/BoyerMooreTests.cs | 37 ++-- Algorithms.Tests/Search/FastSearcherTests.cs | 135 +++++++------- .../Search/FibonacciSearcherTests.cs | 101 +++++----- Algorithms.Tests/Search/Helper.cs | 41 ++--- .../Search/InterpolationSearchTests.cs | 95 +++++----- Algorithms.Tests/Search/JumpSearcherTests.cs | 95 +++++----- .../Search/LinearSearcherTests.cs | 103 ++++++----- .../Search/RecursiveBinarySearcherTests.cs | 107 ++++++----- .../BinaryPrimeConstantSequenceTests.cs | 19 +- .../Sequences/BinomialSequenceTests.cs | 19 +- .../Sequences/CatalanSequenceTest.cs | 23 ++- .../Sequences/CubesSequenceTests.cs | 19 +- .../Sequences/DivisorsCountSequenceTests.cs | 39 ++-- .../Sequences/EuclidNumbersSequenceTests.cs | 21 +-- .../Sequences/EulerTotientSequenceTests.cs | 79 ++++---- .../Sequences/FactorialSequenceTest.cs | 19 +- .../Sequences/FermatNumbersSequenceTests.cs | 19 +- .../Sequences/FermatPrimesSequenceTests.cs | 19 +- .../Sequences/FibonacciSequenceTests.cs | 19 +- .../Sequences/GolombsSequenceTests.cs | 29 ++- .../Sequences/KolakoskiSequenceTests.cs | 45 +++-- .../Sequences/KummerNumbersSequenceTests.cs | 21 +-- .../Sequences/MakeChangeSequenceTests.cs | 43 +++-- .../MatchstickTriangleSequenceTests.cs | 8 +- .../Sequences/NaturalSequenceTests.cs | 19 +- .../NegativeIntegersSequenceTests.cs | 19 +- .../NumberOfBooleanFunctionsSequenceTests.cs | 19 +- ...erOfPrimesByNumberOfDigitsSequenceTests.cs | 19 +- ...NumberOfPrimesByPowersOf10SequenceTests.cs | 19 +- .../Sequences/PowersOf10SequenceTests.cs | 21 +-- .../Sequences/PowersOf2SequenceTests.cs | 19 +- .../Sequences/PrimePiSequenceTests.cs | 19 +- .../Sequences/PrimesSequenceTests.cs | 19 +- .../PrimorialNumbersSequenceTests.cs | 21 +-- .../Sequences/RecamansSequenceTests.cs | 31 ++-- .../Sequences/SquaresSequenceTests.cs | 19 +- .../ThreeNPlusOneStepsSequenceTests.cs | 28 +-- .../Sequences/VanEcksSequenceTests.cs | 31 ++-- .../Sequences/ZeroSequenceTests.cs | 19 +- .../Shufflers/FisherYatesShufflerTests.cs | 125 +++++++------ .../Comparison/BinaryInsertionSorterTests.cs | 35 ++-- .../Sorters/Comparison/BogoSorterTests.cs | 31 ++-- .../Sorters/Comparison/BubbleSorterTests.cs | 35 ++-- .../Sorters/Comparison/CocktailSorterTests.cs | 35 ++-- .../Sorters/Comparison/CombSorterTests.cs | 65 ++++--- .../Sorters/Comparison/CycleSorterTests.cs | 35 ++-- .../Sorters/Comparison/ExchangeSorterTests.cs | 35 ++-- .../Sorters/Comparison/HeapSorterTests.cs | 35 ++-- .../Comparison/InsertionSorterTests.cs | 35 ++-- .../MedianOfThreeQuickSorterTests.cs | 35 ++-- .../Sorters/Comparison/MergeSorterTests.cs | 41 ++--- .../Comparison/MiddlePointQuickSorterTests.cs | 35 ++-- .../Sorters/Comparison/PancakeSorterTests.cs | 35 ++-- .../Comparison/RandomPivotQuickSorterTests.cs | 35 ++-- .../Comparison/SelectionSorterTests.cs | 35 ++-- .../Sorters/Comparison/ShellSorterTests.cs | 35 ++-- .../Sorters/Comparison/TimSorterTests.cs | 97 +++++----- .../External/ExternalMergeSorterTests.cs | 97 +++++----- .../Sorters/Integer/BucketSorterTests.cs | 33 ++-- .../Sorters/Integer/CountingSorterTests.cs | 43 +++-- .../Sorters/Integer/RadixSorterTests.cs | 33 ++-- .../String/MsdRadixStringSorterTests.cs | 37 ++-- .../Strings/GeneralStringAlgorithmsTests.cs | 29 ++- Algorithms.Tests/Strings/PalindromeTests.cs | 45 +++-- .../Strings/PatternMatching/BoyerMoreTests.cs | 21 +-- .../KnuthMorrisPrattSearcherTests.cs | 155 ++++++++-------- .../PatternMatching/NaiveStringSearchTests.cs | 97 +++++----- .../Strings/PatternMatching/RabinKarpTests.cs | 23 ++- .../ZblockSubstringSearchTest.cs | 31 ++-- Algorithms.Tests/Strings/PermutationTests.cs | 107 ++++++----- .../Similarity/HammingDistanceTests.cs | 29 ++- .../Strings/Similarity/JaroSimilarityTests.cs | 25 ++- .../Similarity/JaroWinklerDistanceTests.cs | 21 +-- 81 files changed, 1840 insertions(+), 1919 deletions(-) diff --git a/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateChangesDictionaryTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateChangesDictionaryTests.cs index 78ff100c..a9fc7840 100644 --- a/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateChangesDictionaryTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateChangesDictionaryTests.cs @@ -1,26 +1,25 @@ -using System.Linq; +using System.Linq; using Algorithms.Problems.DynamicProgramming.CoinChange; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange +namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange; + +[TestFixture] +public class GenerateChangesDictionaryTests { - [TestFixture] - public class GenerateChangesDictionaryTests + [Test] + public void GenerateChangesDictionaryTest_Success() { - [Test] - public void GenerateChangesDictionaryTest_Success() - { - const int coin = 6; - var coins = new[] { 1, 3, 4 }; - var changeDictionary = DynamicCoinChangeSolver.GenerateChangesDictionary(coin, coins); + const int coin = 6; + var coins = new[] { 1, 3, 4 }; + var changeDictionary = DynamicCoinChangeSolver.GenerateChangesDictionary(coin, coins); - changeDictionary[1].SequenceEqual(new[] { 0 }).Should().BeTrue(); - changeDictionary[2].SequenceEqual(new[] { 1 }).Should().BeTrue(); - changeDictionary[3].SequenceEqual(new[] { 0, 2 }).Should().BeTrue(); - changeDictionary[4].SequenceEqual(new[] { 0, 1, 3 }).Should().BeTrue(); - changeDictionary[5].SequenceEqual(new[] { 1, 2, 4 }).Should().BeTrue(); - changeDictionary[6].SequenceEqual(new[] { 2, 3, 5 }).Should().BeTrue(); - } + changeDictionary[1].SequenceEqual(new[] { 0 }).Should().BeTrue(); + changeDictionary[2].SequenceEqual(new[] { 1 }).Should().BeTrue(); + changeDictionary[3].SequenceEqual(new[] { 0, 2 }).Should().BeTrue(); + changeDictionary[4].SequenceEqual(new[] { 0, 1, 3 }).Should().BeTrue(); + changeDictionary[5].SequenceEqual(new[] { 1, 2, 4 }).Should().BeTrue(); + changeDictionary[6].SequenceEqual(new[] { 2, 3, 5 }).Should().BeTrue(); } } diff --git a/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateSingleCoinChangesTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateSingleCoinChangesTests.cs index e530e520..9c57c841 100644 --- a/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateSingleCoinChangesTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateSingleCoinChangesTests.cs @@ -1,96 +1,95 @@ -using System; +using System; using System.Linq; using Algorithms.Problems.DynamicProgramming.CoinChange; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange +namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange; + +[TestFixture] +public class GenerateSingleCoinChangesTests { - [TestFixture] - public class GenerateSingleCoinChangesTests + [Test] + public void GenerateSingleCoinChangesTests_Success() + { + DynamicCoinChangeSolver + .GenerateSingleCoinChanges(6, new[] { 1, 2, 3 }) + .SequenceEqual(new[] { 3, 4, 5 }) + .Should().BeTrue(); + + DynamicCoinChangeSolver + .GenerateSingleCoinChanges(10, new[] { 1, 2, 3, 7, 12, 15, 14 }) + .SequenceEqual(new[] { 3, 7, 8, 9 }) + .Should().BeTrue(); + + DynamicCoinChangeSolver + .GenerateSingleCoinChanges(1, new[] { 1, 2, 3, 7, 12, 15, 14 }) + .SequenceEqual(new[] { 0 }) + .Should().BeTrue(); + + DynamicCoinChangeSolver + .GenerateSingleCoinChanges(2, new[] { 1, 2, 3, 7, 12, 15, 14 }) + .SequenceEqual(new[] { 0, 1 }) + .Should().BeTrue(); + } + + [Test] + public void GenerateSingleCoinChangesTests_ShouldThrow_CoinCannotBeLesserOrEqualZero() + { + const int coin = 0; + var arr = new[] { 1, 2, 3 }; + + Func act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, arr); + + act.Should().Throw() + .WithMessage($"The coin cannot be lesser or equal to zero {nameof(coin)}."); + } + + [Test] + public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayCannotBeEmpty() + { + const int coin = 10; + var coinsAsArray = Array.Empty(); + + Func act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray); + + act.Should().Throw() + .WithMessage($"Coins array cannot be empty {nameof(coinsAsArray)}."); + } + + [Test] + public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayMustContainOne() { - [Test] - public void GenerateSingleCoinChangesTests_Success() - { - DynamicCoinChangeSolver - .GenerateSingleCoinChanges(6, new[] { 1, 2, 3 }) - .SequenceEqual(new[] { 3, 4, 5 }) - .Should().BeTrue(); - - DynamicCoinChangeSolver - .GenerateSingleCoinChanges(10, new[] { 1, 2, 3, 7, 12, 15, 14 }) - .SequenceEqual(new[] { 3, 7, 8, 9 }) - .Should().BeTrue(); - - DynamicCoinChangeSolver - .GenerateSingleCoinChanges(1, new[] { 1, 2, 3, 7, 12, 15, 14 }) - .SequenceEqual(new[] { 0 }) - .Should().BeTrue(); - - DynamicCoinChangeSolver - .GenerateSingleCoinChanges(2, new[] { 1, 2, 3, 7, 12, 15, 14 }) - .SequenceEqual(new[] { 0, 1 }) - .Should().BeTrue(); - } - - [Test] - public void GenerateSingleCoinChangesTests_ShouldThrow_CoinCannotBeLesserOrEqualZero() - { - const int coin = 0; - var arr = new[] { 1, 2, 3 }; - - Func act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, arr); - - act.Should().Throw() - .WithMessage($"The coin cannot be lesser or equal to zero {nameof(coin)}."); - } - - [Test] - public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayCannotBeEmpty() - { - const int coin = 10; - var coinsAsArray = Array.Empty(); - - Func act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray); - - act.Should().Throw() - .WithMessage($"Coins array cannot be empty {nameof(coinsAsArray)}."); - } - - [Test] - public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayMustContainOne() - { - const int coin = 10; - var coinsAsArray = new[] { 2, 3, 4 }; - - Func act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray); - - act.Should().Throw() - .WithMessage($"Coins array must contain coin 1 {nameof(coinsAsArray)}."); - } - - [Test] - public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayCannotContainNegativeValues() - { - const int coin = 10; - var coinsAsArray = new[] { 1, 2, -3, 4 }; - - Func act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray); - - act.Should().Throw() - .WithMessage($"{nameof(coinsAsArray)} cannot contain numbers less than or equal to zero"); - } - - [Test] - public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayCannotContainDuplicates() - { - const int coin = 10; - var coinsAsArray = new[] { 1, 2, 3, 3, 4 }; - - Func act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray); - - act.Should().Throw() - .WithMessage($"Coins array cannot contain duplicates {nameof(coinsAsArray)}."); - } + const int coin = 10; + var coinsAsArray = new[] { 2, 3, 4 }; + + Func act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray); + + act.Should().Throw() + .WithMessage($"Coins array must contain coin 1 {nameof(coinsAsArray)}."); + } + + [Test] + public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayCannotContainNegativeValues() + { + const int coin = 10; + var coinsAsArray = new[] { 1, 2, -3, 4 }; + + Func act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray); + + act.Should().Throw() + .WithMessage($"{nameof(coinsAsArray)} cannot contain numbers less than or equal to zero"); + } + + [Test] + public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayCannotContainDuplicates() + { + const int coin = 10; + var coinsAsArray = new[] { 1, 2, 3, 3, 4 }; + + Func act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray); + + act.Should().Throw() + .WithMessage($"Coins array cannot contain duplicates {nameof(coinsAsArray)}."); } } diff --git a/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GetMinimalNextCoinTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GetMinimalNextCoinTests.cs index ac4b5fb6..0c354b50 100644 --- a/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GetMinimalNextCoinTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GetMinimalNextCoinTests.cs @@ -1,20 +1,19 @@ -using Algorithms.Problems.DynamicProgramming.CoinChange; +using Algorithms.Problems.DynamicProgramming.CoinChange; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange +namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange; + +public class GetMinimalNextCoinTests { - public class GetMinimalNextCoinTests + [Test] + public void GetMinimalNextCoinTest_Success() { - [Test] - public void GetMinimalNextCoinTest_Success() - { - const int coin = 6; - var coins = new[] { 1, 3, 4 }; - var exchangeDict = DynamicCoinChangeSolver.GenerateChangesDictionary(coin, coins); - var nextCoin = DynamicCoinChangeSolver.GetMinimalNextCoin(6, exchangeDict); + const int coin = 6; + var coins = new[] { 1, 3, 4 }; + var exchangeDict = DynamicCoinChangeSolver.GenerateChangesDictionary(coin, coins); + var nextCoin = DynamicCoinChangeSolver.GetMinimalNextCoin(6, exchangeDict); - nextCoin.Should().Be(3); - } + nextCoin.Should().Be(3); } } diff --git a/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/MakeCoinChangeDynamicTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/MakeCoinChangeDynamicTests.cs index 11520867..19e19e61 100644 --- a/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/MakeCoinChangeDynamicTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/CoinChange/MakeCoinChangeDynamicTests.cs @@ -1,35 +1,34 @@ -using System.Linq; +using System.Linq; using Algorithms.Problems.DynamicProgramming.CoinChange; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange +namespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange; + +[TestFixture] +public class MakeCoinChangeDynamicTests { - [TestFixture] - public class MakeCoinChangeDynamicTests + [Test] + public void MakeCoinChangeDynamicTest_Success() { - [Test] - public void MakeCoinChangeDynamicTest_Success() - { - DynamicCoinChangeSolver - .MakeCoinChangeDynamic(6, new[] { 1, 3, 4 }) - .SequenceEqual(new[] { 3, 3 }) - .Should().BeTrue(); + DynamicCoinChangeSolver + .MakeCoinChangeDynamic(6, new[] { 1, 3, 4 }) + .SequenceEqual(new[] { 3, 3 }) + .Should().BeTrue(); - DynamicCoinChangeSolver - .MakeCoinChangeDynamic(8, new[] { 1, 3, 4 }) - .SequenceEqual(new[] { 4, 4 }) - .Should().BeTrue(); + DynamicCoinChangeSolver + .MakeCoinChangeDynamic(8, new[] { 1, 3, 4 }) + .SequenceEqual(new[] { 4, 4 }) + .Should().BeTrue(); - DynamicCoinChangeSolver - .MakeCoinChangeDynamic(25, new[] { 1, 3, 4, 12, 13, 14 }) - .SequenceEqual(new[] { 13, 12 }) - .Should().BeTrue(); + DynamicCoinChangeSolver + .MakeCoinChangeDynamic(25, new[] { 1, 3, 4, 12, 13, 14 }) + .SequenceEqual(new[] { 13, 12 }) + .Should().BeTrue(); - DynamicCoinChangeSolver - .MakeCoinChangeDynamic(26, new[] { 1, 3, 4, 12, 13, 14 }) - .SequenceEqual(new[] { 14, 12 }) - .Should().BeTrue(); - } + DynamicCoinChangeSolver + .MakeCoinChangeDynamic(26, new[] { 1, 3, 4, 12, 13, 14 }) + .SequenceEqual(new[] { 14, 12 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs index 68a94306..5aabebeb 100644 --- a/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs @@ -1,20 +1,19 @@ using NUnit.Framework; using Algorithms.Problems.DynamicProgramming; -namespace Algorithms.Tests.DynamicProgramming +namespace Algorithms.Tests.DynamicProgramming; + +public class LevenshteinDistanceTests { - public class LevenshteinDistanceTests + [TestCase("kitten", "sitting", 3)] + [TestCase("bob", "bond", 2)] + [TestCase("algorithm", "logarithm", 3)] + [TestCase("star", "", 4)] + [TestCase("", "star", 4)] + [TestCase("abcde", "12345", 5)] + public void Calculate_ReturnsCorrectLevenshteinDistance(string source, string destination, int expectedDistance) { - [TestCase("kitten", "sitting", 3)] - [TestCase("bob", "bond", 2)] - [TestCase("algorithm", "logarithm", 3)] - [TestCase("star", "", 4)] - [TestCase("", "star", 4)] - [TestCase("abcde", "12345", 5)] - public void Calculate_ReturnsCorrectLevenshteinDistance(string source, string destination, int expectedDistance) - { - var result = LevenshteinDistance.Calculate(source, destination); - Assert.AreEqual(expectedDistance, result); - } + var result = LevenshteinDistance.Calculate(source, destination); + Assert.AreEqual(expectedDistance, result); } } diff --git a/Algorithms.Tests/Problems/NQueens/BacktrackingNQueensSolverTests.cs b/Algorithms.Tests/Problems/NQueens/BacktrackingNQueensSolverTests.cs index bf95ecdb..a54e2756 100644 --- a/Algorithms.Tests/Problems/NQueens/BacktrackingNQueensSolverTests.cs +++ b/Algorithms.Tests/Problems/NQueens/BacktrackingNQueensSolverTests.cs @@ -1,127 +1,126 @@ -using System; +using System; using System.Linq; using Algorithms.Problems.NQueens; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Problems.NQueens +namespace Algorithms.Tests.Problems.NQueens; + +public static class BacktrackingNQueensSolverTests { - public static class BacktrackingNQueensSolverTests + [TestCase(0, 0)] + [TestCase(1, 1)] + [TestCase(2, 0)] + [TestCase(3, 0)] + [TestCase(4, 2)] + [TestCase(5, 10)] + [TestCase(6, 4)] + [TestCase(7, 40)] + [TestCase(8, 92)] + [TestCase(8, 92)] + [TestCase(9, 352)] + [TestCase(10, 724)] + [TestCase(11, 2680)] + public static void SolvesCorrectly(int n, int expectedNumberOfSolutions) { - [TestCase(0, 0)] - [TestCase(1, 1)] - [TestCase(2, 0)] - [TestCase(3, 0)] - [TestCase(4, 2)] - [TestCase(5, 10)] - [TestCase(6, 4)] - [TestCase(7, 40)] - [TestCase(8, 92)] - [TestCase(8, 92)] - [TestCase(9, 352)] - [TestCase(10, 724)] - [TestCase(11, 2680)] - public static void SolvesCorrectly(int n, int expectedNumberOfSolutions) - { - // Arrange - // Act - var result = new BacktrackingNQueensSolver().BacktrackSolve(n).ToList(); + // Arrange + // Act + var result = new BacktrackingNQueensSolver().BacktrackSolve(n).ToList(); - // Assert - result.Should().HaveCount(expectedNumberOfSolutions); - foreach (var solution in result) - { - ValidateOneQueenPerRow(solution); - ValidateOneQueenPerColumn(solution); - ValidateOneQueenPerTopLeftBottomRightDiagonalLine(solution); - ValidateOneQueenPerBottomLeftTopRightDiagonalLine(solution); - } + // Assert + result.Should().HaveCount(expectedNumberOfSolutions); + foreach (var solution in result) + { + ValidateOneQueenPerRow(solution); + ValidateOneQueenPerColumn(solution); + ValidateOneQueenPerTopLeftBottomRightDiagonalLine(solution); + ValidateOneQueenPerBottomLeftTopRightDiagonalLine(solution); } + } - [Test] - public static void NCannotBeNegative() - { - var n = -1; + [Test] + public static void NCannotBeNegative() + { + var n = -1; - Action act = () => new BacktrackingNQueensSolver().BacktrackSolve(n); + Action act = () => new BacktrackingNQueensSolver().BacktrackSolve(n); - act.Should().Throw(); - } + act.Should().Throw(); + } - private static void ValidateOneQueenPerRow(bool[,] solution) + private static void ValidateOneQueenPerRow(bool[,] solution) + { + for (var i = 0; i < solution.GetLength(1); i++) { - for (var i = 0; i < solution.GetLength(1); i++) + var foundQueen = false; + for (var j = 0; j < solution.GetLength(0); j++) { - var foundQueen = false; - for (var j = 0; j < solution.GetLength(0); j++) - { - foundQueen = ValidateCell(foundQueen, solution[j, i]); - } + foundQueen = ValidateCell(foundQueen, solution[j, i]); } } + } - private static void ValidateOneQueenPerColumn(bool[,] solution) + private static void ValidateOneQueenPerColumn(bool[,] solution) + { + for (var i = 0; i < solution.GetLength(0); i++) { - for (var i = 0; i < solution.GetLength(0); i++) + var foundQueen = false; + for (var j = 0; j < solution.GetLength(1); j++) { - var foundQueen = false; - for (var j = 0; j < solution.GetLength(1); j++) - { - foundQueen = ValidateCell(foundQueen, solution[i, j]); - } + foundQueen = ValidateCell(foundQueen, solution[i, j]); } } + } - private static void ValidateOneQueenPerTopLeftBottomRightDiagonalLine(bool[,] solution) + private static void ValidateOneQueenPerTopLeftBottomRightDiagonalLine(bool[,] solution) + { + for (var i = 0; i < solution.GetLength(0); i++) { - for (var i = 0; i < solution.GetLength(0); i++) - { - var foundQueen = false; - for (var j = 0; i + j < solution.GetLength(1); j++) - { - foundQueen = ValidateCell(foundQueen, solution[i + j, i]); - } - } - - for (var i = 0; i < solution.GetLength(1); i++) + var foundQueen = false; + for (var j = 0; i + j < solution.GetLength(1); j++) { - var foundQueen = false; - for (var j = 0; i + j < solution.GetLength(0); j++) - { - foundQueen = ValidateCell(foundQueen, solution[j, i + j]); - } + foundQueen = ValidateCell(foundQueen, solution[i + j, i]); } } - private static void ValidateOneQueenPerBottomLeftTopRightDiagonalLine(bool[,] solution) + for (var i = 0; i < solution.GetLength(1); i++) { - for (var i = 0; i < solution.GetLength(0); i++) + var foundQueen = false; + for (var j = 0; i + j < solution.GetLength(0); j++) { - var foundQueen = false; - for (var j = 0; i - j >= 0; j++) - { - foundQueen = ValidateCell(foundQueen, solution[i - j, i]); - } + foundQueen = ValidateCell(foundQueen, solution[j, i + j]); } + } + } - for (var i = 0; i < solution.GetLength(1); i++) + private static void ValidateOneQueenPerBottomLeftTopRightDiagonalLine(bool[,] solution) + { + for (var i = 0; i < solution.GetLength(0); i++) + { + var foundQueen = false; + for (var j = 0; i - j >= 0; j++) { - var foundQueen = false; - for (var j = 0; i - j >= 0 && solution.GetLength(0) - j > 0; j++) - { - foundQueen = ValidateCell(foundQueen, solution[solution.GetLength(0) - j - 1, i - j]); - } + foundQueen = ValidateCell(foundQueen, solution[i - j, i]); } } - private static bool ValidateCell(bool foundQueen, bool currentCell) + for (var i = 0; i < solution.GetLength(1); i++) { - if (foundQueen) + var foundQueen = false; + for (var j = 0; i - j >= 0 && solution.GetLength(0) - j > 0; j++) { - currentCell.Should().BeFalse(); + foundQueen = ValidateCell(foundQueen, solution[solution.GetLength(0) - j - 1, i - j]); } + } + } - return foundQueen || currentCell; + private static bool ValidateCell(bool foundQueen, bool currentCell) + { + if (foundQueen) + { + currentCell.Should().BeFalse(); } + + return foundQueen || currentCell; } } diff --git a/Algorithms.Tests/Problems/StableMarriage/GaleShapleyTests.cs b/Algorithms.Tests/Problems/StableMarriage/GaleShapleyTests.cs index 55f16f2e..86c894b9 100644 --- a/Algorithms.Tests/Problems/StableMarriage/GaleShapleyTests.cs +++ b/Algorithms.Tests/Problems/StableMarriage/GaleShapleyTests.cs @@ -1,53 +1,52 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Algorithms.Problems.StableMarriage; using NUnit.Framework; -namespace Algorithms.Tests.Problems.StableMarriage +namespace Algorithms.Tests.Problems.StableMarriage; + +/// +/// The stable marriage problem (also stable matching problem or SMP) +/// is the problem of finding a stable matching between two equally sized sets of elements given an ordering of +/// preferences for each element. +/// +public static class GaleShapleyTests { /// - /// The stable marriage problem (also stable matching problem or SMP) - /// is the problem of finding a stable matching between two equally sized sets of elements given an ordering of - /// preferences for each element. + /// Checks that all parties are engaged and stable. /// - public static class GaleShapleyTests + [Test] + public static void MatchingIsSuccessful() { - /// - /// Checks that all parties are engaged and stable. - /// - [Test] - public static void MatchingIsSuccessful() - { - var random = new Random(7); - var proposers = Enumerable.Range(1, 10).Select(_ => new Proposer()).ToArray(); - var acceptors = Enumerable.Range(1, 10).Select(_ => new Accepter()).ToArray(); - - foreach (var proposer in proposers) - { - proposer.PreferenceOrder = new LinkedList(acceptors.OrderBy(_ => random.Next())); - } + var random = new Random(7); + var proposers = Enumerable.Range(1, 10).Select(_ => new Proposer()).ToArray(); + var acceptors = Enumerable.Range(1, 10).Select(_ => new Accepter()).ToArray(); - foreach (var acceptor in acceptors) - { - acceptor.PreferenceOrder = proposers.OrderBy(_ => random.Next()).ToList(); - } - - GaleShapley.Match(proposers, acceptors); + foreach (var proposer in proposers) + { + proposer.PreferenceOrder = new LinkedList(acceptors.OrderBy(_ => random.Next())); + } - Assert.IsTrue(acceptors.All(x => x.EngagedTo is not null)); - Assert.IsTrue(proposers.All(x => x.EngagedTo is not null)); - Assert.IsTrue(AreMatchesStable(proposers, acceptors)); + foreach (var acceptor in acceptors) + { + acceptor.PreferenceOrder = proposers.OrderBy(_ => random.Next()).ToList(); } - private static bool AreMatchesStable(Proposer[] proposers, Accepter[] accepters) => - proposers.All(p => - p.EngagedTo is not null - && Score(p, p.EngagedTo) <= accepters - .Where(a => a.PrefersOverCurrent(p)) - .Min(a => Score(p, a))); + GaleShapley.Match(proposers, acceptors); - private static int Score(Proposer proposer, Accepter accepter) => - proposer.PreferenceOrder.ToList().IndexOf(accepter); + Assert.IsTrue(acceptors.All(x => x.EngagedTo is not null)); + Assert.IsTrue(proposers.All(x => x.EngagedTo is not null)); + Assert.IsTrue(AreMatchesStable(proposers, acceptors)); } + + private static bool AreMatchesStable(Proposer[] proposers, Accepter[] accepters) => + proposers.All(p => + p.EngagedTo is not null + && Score(p, p.EngagedTo) <= accepters + .Where(a => a.PrefersOverCurrent(p)) + .Min(a => Score(p, a))); + + private static int Score(Proposer proposer, Accepter accepter) => + proposer.PreferenceOrder.ToList().IndexOf(accepter); } diff --git a/Algorithms.Tests/Search/BinarySearcherTests.cs b/Algorithms.Tests/Search/BinarySearcherTests.cs index 71d38d2d..bacca00f 100644 --- a/Algorithms.Tests/Search/BinarySearcherTests.cs +++ b/Algorithms.Tests/Search/BinarySearcherTests.cs @@ -3,58 +3,57 @@ using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Search +namespace Algorithms.Tests.Search; + +public static class BinarySearcherTests { - public static class BinarySearcherTests + [Test] + public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int n) + { + // Arrange + var searcher = new BinarySearcher(); + var random = Randomizer.CreateRandomizer(); + var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).OrderBy(x => x).ToArray(); + var selectedIndex = random.Next(0, n); + + // Act + var actualIndex = searcher.FindIndex(arrayToSearch, arrayToSearch[selectedIndex]); + + // Assert + Assert.AreEqual(arrayToSearch[selectedIndex], arrayToSearch[actualIndex]); + } + + [Test] + public static void FindIndex_ItemMissing_MinusOneReturned( + [Random(0, 1000, 10)] int n, + [Random(-100, 1100, 10)] int missingItem) { - [Test] - public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int n) - { - // Arrange - var searcher = new BinarySearcher(); - var random = Randomizer.CreateRandomizer(); - var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).OrderBy(x => x).ToArray(); - var selectedIndex = random.Next(0, n); - - // Act - var actualIndex = searcher.FindIndex(arrayToSearch, arrayToSearch[selectedIndex]); - - // Assert - Assert.AreEqual(arrayToSearch[selectedIndex], arrayToSearch[actualIndex]); - } - - [Test] - public static void FindIndex_ItemMissing_MinusOneReturned( - [Random(0, 1000, 10)] int n, - [Random(-100, 1100, 10)] int missingItem) - { - // Arrange - var searcher = new BinarySearcher(); - var random = Randomizer.CreateRandomizer(); - var arrayToSearch = Enumerable.Range(0, n) - .Select(_ => random.Next(0, 1000)) - .Where(x => x != missingItem) - .OrderBy(x => x).ToArray(); - - // Act - var actualIndex = searcher.FindIndex(arrayToSearch, missingItem); - - // Assert - Assert.AreEqual(-1, actualIndex); - } - - [Test] - public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemToSearch) - { - // Arrange - var searcher = new BinarySearcher(); - var arrayToSearch = new int[0]; - - // Act - var actualIndex = searcher.FindIndex(arrayToSearch, itemToSearch); - - // Assert - Assert.AreEqual(-1, actualIndex); - } + // Arrange + var searcher = new BinarySearcher(); + var random = Randomizer.CreateRandomizer(); + var arrayToSearch = Enumerable.Range(0, n) + .Select(_ => random.Next(0, 1000)) + .Where(x => x != missingItem) + .OrderBy(x => x).ToArray(); + + // Act + var actualIndex = searcher.FindIndex(arrayToSearch, missingItem); + + // Assert + Assert.AreEqual(-1, actualIndex); + } + + [Test] + public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemToSearch) + { + // Arrange + var searcher = new BinarySearcher(); + var arrayToSearch = new int[0]; + + // Act + var actualIndex = searcher.FindIndex(arrayToSearch, itemToSearch); + + // Assert + Assert.AreEqual(-1, actualIndex); } } diff --git a/Algorithms.Tests/Search/BoyerMooreTests.cs b/Algorithms.Tests/Search/BoyerMooreTests.cs index 6e206c23..2364a9ac 100644 --- a/Algorithms.Tests/Search/BoyerMooreTests.cs +++ b/Algorithms.Tests/Search/BoyerMooreTests.cs @@ -5,32 +5,31 @@ using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Search +namespace Algorithms.Tests.Search; + +public class BoyerMoore_Tests { - public class BoyerMoore_Tests + [Test] + public void BoyerMoore_Majority_Finder_Test() { - [Test] - public void BoyerMoore_Majority_Finder_Test() - { - var elementCount = 1000; + var elementCount = 1000; - var rnd = new Random(); - var randomNumbers = new List(); + var rnd = new Random(); + var randomNumbers = new List(); - while (randomNumbers.Count < elementCount / 2) - { - randomNumbers.Add(rnd.Next(0, elementCount)); - } + while (randomNumbers.Count < elementCount / 2) + { + randomNumbers.Add(rnd.Next(0, elementCount)); + } - var majorityElement = rnd.Next(0, elementCount); + var majorityElement = rnd.Next(0, elementCount); - randomNumbers.AddRange(Enumerable.Repeat(majorityElement, elementCount / 2 + 1)); - randomNumbers = randomNumbers.OrderBy(x => rnd.Next()).ToList(); + randomNumbers.AddRange(Enumerable.Repeat(majorityElement, elementCount / 2 + 1)); + randomNumbers = randomNumbers.OrderBy(x => rnd.Next()).ToList(); - var expected = majorityElement; - var actual = BoyerMoore.FindMajority(randomNumbers); + var expected = majorityElement; + var actual = BoyerMoore.FindMajority(randomNumbers); - Assert.AreEqual(actual, expected); - } + Assert.AreEqual(actual, expected); } } diff --git a/Algorithms.Tests/Search/FastSearcherTests.cs b/Algorithms.Tests/Search/FastSearcherTests.cs index 2108a917..fbf4d69a 100644 --- a/Algorithms.Tests/Search/FastSearcherTests.cs +++ b/Algorithms.Tests/Search/FastSearcherTests.cs @@ -1,82 +1,81 @@ -using Algorithms.Search; +using Algorithms.Search; using NUnit.Framework; using Utilities.Exceptions; -namespace Algorithms.Tests.Search +namespace Algorithms.Tests.Search; + +public static class FastSearcherTests { - public static class FastSearcherTests + [Test] + public static void FindIndex_ItemPresent_IndexCorrect() { - [Test] - public static void FindIndex_ItemPresent_IndexCorrect() - { - var searcher = new FastSearcher(); - var arr = Helper.GetSortedArray(1000); - var present = Helper.GetItemIn(arr); - var index = searcher.FindIndex(arr, present); - Assert.AreEqual(present, arr[index]); - } + var searcher = new FastSearcher(); + var arr = Helper.GetSortedArray(1000); + var present = Helper.GetItemIn(arr); + var index = searcher.FindIndex(arr, present); + Assert.AreEqual(present, arr[index]); + } - [TestCase(new[] { 1, 2 }, 1)] - [TestCase(new[] { 1, 2 }, 2)] - [TestCase(new[] { 1, 2, 3, 3, 3 }, 2)] - public static void FindIndex_ItemPresentInSpecificCase_IndexCorrect(int[] arr, int present) - { - var searcher = new FastSearcher(); - var index = searcher.FindIndex(arr, present); - Assert.AreEqual(present, arr[index]); - } + [TestCase(new[] { 1, 2 }, 1)] + [TestCase(new[] { 1, 2 }, 2)] + [TestCase(new[] { 1, 2, 3, 3, 3 }, 2)] + public static void FindIndex_ItemPresentInSpecificCase_IndexCorrect(int[] arr, int present) + { + var searcher = new FastSearcher(); + var index = searcher.FindIndex(arr, present); + Assert.AreEqual(present, arr[index]); + } - [Test] - public static void FindIndex_ItemMissing_ItemNotFoundExceptionThrown() - { - var searcher = new FastSearcher(); - var arr = Helper.GetSortedArray(1000); - var missing = Helper.GetItemNotIn(arr); - _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); - } + [Test] + public static void FindIndex_ItemMissing_ItemNotFoundExceptionThrown() + { + var searcher = new FastSearcher(); + var arr = Helper.GetSortedArray(1000); + var missing = Helper.GetItemNotIn(arr); + _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); + } - [TestCase(new int[0], 2)] - public static void FindIndex_ItemMissingInSpecificCase_ItemNotFoundExceptionThrown(int[] arr, int missing) - { - var searcher = new FastSearcher(); - _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); - } + [TestCase(new int[0], 2)] + public static void FindIndex_ItemMissingInSpecificCase_ItemNotFoundExceptionThrown(int[] arr, int missing) + { + var searcher = new FastSearcher(); + _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); + } - [Test] - public static void FindIndex_ItemSmallerThanAllMissing_ItemNotFoundExceptionThrown() - { - var searcher = new FastSearcher(); - var arr = Helper.GetSortedArray(1000); - var missing = Helper.GetItemSmallerThanAllIn(arr); - _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); - } + [Test] + public static void FindIndex_ItemSmallerThanAllMissing_ItemNotFoundExceptionThrown() + { + var searcher = new FastSearcher(); + var arr = Helper.GetSortedArray(1000); + var missing = Helper.GetItemSmallerThanAllIn(arr); + _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); + } - [Test] - public static void FindIndex_ItemBiggerThanAllMissing_ItemNotFoundExceptionThrown() - { - var searcher = new FastSearcher(); - var arr = Helper.GetSortedArray(1000); - var missing = Helper.GetItemBiggerThanAllIn(arr); - _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); - } + [Test] + public static void FindIndex_ItemBiggerThanAllMissing_ItemNotFoundExceptionThrown() + { + var searcher = new FastSearcher(); + var arr = Helper.GetSortedArray(1000); + var missing = Helper.GetItemBiggerThanAllIn(arr); + _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); + } - [Test] - public static void FindIndex_ArrayOfDuplicatesItemPresent_IndexCorrect() - { - var searcher = new FastSearcher(); - var arr = new int[1000]; - var present = 0; - var index = searcher.FindIndex(arr, present); - Assert.AreEqual(0, arr[index]); - } + [Test] + public static void FindIndex_ArrayOfDuplicatesItemPresent_IndexCorrect() + { + var searcher = new FastSearcher(); + var arr = new int[1000]; + var present = 0; + var index = searcher.FindIndex(arr, present); + Assert.AreEqual(0, arr[index]); + } - [Test] - public static void FindIndex_ArrayOfDuplicatesItemMissing_ItemNotFoundExceptionThrown() - { - var searcher = new FastSearcher(); - var arr = new int[1000]; - var missing = 1; - _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); - } + [Test] + public static void FindIndex_ArrayOfDuplicatesItemMissing_ItemNotFoundExceptionThrown() + { + var searcher = new FastSearcher(); + var arr = new int[1000]; + var missing = 1; + _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); } } diff --git a/Algorithms.Tests/Search/FibonacciSearcherTests.cs b/Algorithms.Tests/Search/FibonacciSearcherTests.cs index 60bb049e..84d5da3c 100644 --- a/Algorithms.Tests/Search/FibonacciSearcherTests.cs +++ b/Algorithms.Tests/Search/FibonacciSearcherTests.cs @@ -3,69 +3,68 @@ using NUnit.Framework; using System; -namespace Algorithms.Tests.Search +namespace Algorithms.Tests.Search; + +public static class FibonacciSearcherTests { - public static class FibonacciSearcherTests + [Test] + public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 10)] int n) { - [Test] - public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 10)] int n) - { - // Arranges - var searcher = new FibonacciSearcher(); - var arrayToSearch = Helper.GetSortedArray(n); - var present = Helper.GetItemIn(arrayToSearch); + // Arranges + var searcher = new FibonacciSearcher(); + var arrayToSearch = Helper.GetSortedArray(n); + var present = Helper.GetItemIn(arrayToSearch); - // Act - var actualIndex = searcher.FindIndex(arrayToSearch, present); + // Act + var actualIndex = searcher.FindIndex(arrayToSearch, present); - // Assert - arrayToSearch[actualIndex].Should().Be(present); - } + // Assert + arrayToSearch[actualIndex].Should().Be(present); + } - [Test] - public static void FindIndex_ItemMissing_MinusOneReturned([Random(1, 1000, 10)] int n) - { - // Arranges - var searcher = new FibonacciSearcher(); - var arrayToSearch = Helper.GetSortedArray(n); - var present = Helper.GetItemNotIn(arrayToSearch); - var expectedIndex = -1; + [Test] + public static void FindIndex_ItemMissing_MinusOneReturned([Random(1, 1000, 10)] int n) + { + // Arranges + var searcher = new FibonacciSearcher(); + var arrayToSearch = Helper.GetSortedArray(n); + var present = Helper.GetItemNotIn(arrayToSearch); + var expectedIndex = -1; - // Act - var actualIndex = searcher.FindIndex(arrayToSearch, present); + // Act + var actualIndex = searcher.FindIndex(arrayToSearch, present); - // Assert - actualIndex.Should().Be(expectedIndex); - } + // Assert + actualIndex.Should().Be(expectedIndex); + } - [Test] - public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(1, 1000, 10)] int missingItem) - { - // Arrange - var searcher = new FibonacciSearcher(); - var sortedArray = Array.Empty(); - var expectedIndex = -1; + [Test] + public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(1, 1000, 10)] int missingItem) + { + // Arrange + var searcher = new FibonacciSearcher(); + var sortedArray = Array.Empty(); + var expectedIndex = -1; - // Act - var actualIndex = searcher.FindIndex(sortedArray, missingItem); + // Act + var actualIndex = searcher.FindIndex(sortedArray, missingItem); - // Assert - actualIndex.Should().Be(expectedIndex); - } + // Assert + actualIndex.Should().Be(expectedIndex); + } - [TestCase(null, "a")] - [TestCase(new[] { "a", "b", "c" }, null)] - [TestCase(null, null)] - public static void FindIndex_ArrayNull_ItemNull_ArgumentNullExceptionThrown(string[] sortedArray, string searchItem) - { - // Arranges - var searcher = new FibonacciSearcher(); + [TestCase(null, "a")] + [TestCase(new[] { "a", "b", "c" }, null)] + [TestCase(null, null)] + public static void FindIndex_ArrayNull_ItemNull_ArgumentNullExceptionThrown(string[] sortedArray, string searchItem) + { + // Arranges + var searcher = new FibonacciSearcher(); - // Act - Action action = () => searcher.FindIndex(sortedArray, searchItem); + // Act + Action action = () => searcher.FindIndex(sortedArray, searchItem); - // Assert - action.Should().Throw(); - } + // Assert + action.Should().Throw(); } } diff --git a/Algorithms.Tests/Search/Helper.cs b/Algorithms.Tests/Search/Helper.cs index b7f9ded7..ce1ab35d 100644 --- a/Algorithms.Tests/Search/Helper.cs +++ b/Algorithms.Tests/Search/Helper.cs @@ -1,32 +1,31 @@ using System.Linq; using NUnit.Framework; -namespace Algorithms.Tests.Search +namespace Algorithms.Tests.Search; + +public static class Helper { - public static class Helper - { - public static int[] GetSortedArray(int length) => - Enumerable.Range(0, length) - .Select(_ => TestContext.CurrentContext.Random.Next(1_000_000)) - .OrderBy(x => x) - .ToArray(); + public static int[] GetSortedArray(int length) => + Enumerable.Range(0, length) + .Select(_ => TestContext.CurrentContext.Random.Next(1_000_000)) + .OrderBy(x => x) + .ToArray(); - public static int GetItemIn(int[] arr) => arr[TestContext.CurrentContext.Random.Next(arr.Length)]; + public static int GetItemIn(int[] arr) => arr[TestContext.CurrentContext.Random.Next(arr.Length)]; - public static int GetItemNotIn(int[] arr) + public static int GetItemNotIn(int[] arr) + { + int item; + do { - int item; - do - { - item = TestContext.CurrentContext.Random.Next(arr.Min(), arr.Max() + 1); - } - while (arr.Contains(item)); - - return item; + item = TestContext.CurrentContext.Random.Next(arr.Min(), arr.Max() + 1); } + while (arr.Contains(item)); - public static int GetItemSmallerThanAllIn(int[] arr) => arr.Min() - 1; - - public static int GetItemBiggerThanAllIn(int[] arr) => arr.Max() + 1; + return item; } + + public static int GetItemSmallerThanAllIn(int[] arr) => arr.Min() - 1; + + public static int GetItemBiggerThanAllIn(int[] arr) => arr.Max() + 1; } diff --git a/Algorithms.Tests/Search/InterpolationSearchTests.cs b/Algorithms.Tests/Search/InterpolationSearchTests.cs index f32e7104..a993598f 100644 --- a/Algorithms.Tests/Search/InterpolationSearchTests.cs +++ b/Algorithms.Tests/Search/InterpolationSearchTests.cs @@ -4,55 +4,54 @@ using System; using System.Linq; -namespace Algorithms.Tests.Search +namespace Algorithms.Tests.Search; + +public static class InterpolationSearchTests { - public static class InterpolationSearchTests + [Test] + public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int n) + { + // Arrange + var random = Randomizer.CreateRandomizer(); + var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).OrderBy(x => x).ToArray(); + var selectedIndex = random.Next(0, n); + + // Act + var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, arrayToSearch[selectedIndex]); + + // Assert + Assert.AreEqual(arrayToSearch[selectedIndex], arrayToSearch[actualIndex]); + } + + [Test] + public static void FindIndex_ItemMissing_MinusOneReturned( + [Random(0, 1000, 10)] int n, + [Random(-100, 1100, 10)] int missingItem) { - [Test] - public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int n) - { - // Arrange - var random = Randomizer.CreateRandomizer(); - var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).OrderBy(x => x).ToArray(); - var selectedIndex = random.Next(0, n); - - // Act - var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, arrayToSearch[selectedIndex]); - - // Assert - Assert.AreEqual(arrayToSearch[selectedIndex], arrayToSearch[actualIndex]); - } - - [Test] - public static void FindIndex_ItemMissing_MinusOneReturned( - [Random(0, 1000, 10)] int n, - [Random(-100, 1100, 10)] int missingItem) - { - // Arrange - var random = Randomizer.CreateRandomizer(); - var arrayToSearch = Enumerable.Range(0, n) - .Select(_ => random.Next(0, 1000)) - .Where(x => x != missingItem) - .OrderBy(x => x).ToArray(); - - // Act - var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, missingItem); - - // Assert - Assert.AreEqual(-1, actualIndex); - } - - [Test] - public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemToSearch) - { - // Arrange - var arrayToSearch = new int[0]; - - // Act - var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, itemToSearch); - - // Assert - Assert.AreEqual(-1, actualIndex); - } + // Arrange + var random = Randomizer.CreateRandomizer(); + var arrayToSearch = Enumerable.Range(0, n) + .Select(_ => random.Next(0, 1000)) + .Where(x => x != missingItem) + .OrderBy(x => x).ToArray(); + + // Act + var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, missingItem); + + // Assert + Assert.AreEqual(-1, actualIndex); + } + + [Test] + public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemToSearch) + { + // Arrange + var arrayToSearch = new int[0]; + + // Act + var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, itemToSearch); + + // Assert + Assert.AreEqual(-1, actualIndex); } } diff --git a/Algorithms.Tests/Search/JumpSearcherTests.cs b/Algorithms.Tests/Search/JumpSearcherTests.cs index 34045060..3c8daa3e 100644 --- a/Algorithms.Tests/Search/JumpSearcherTests.cs +++ b/Algorithms.Tests/Search/JumpSearcherTests.cs @@ -4,65 +4,64 @@ using System.Linq; using FluentAssertions; -namespace Algorithms.Tests.Search +namespace Algorithms.Tests.Search; + +public class JumpSearcherTests { - public class JumpSearcherTests + [Test] + public void FindIndex_ItemPresent_ItemCorrect([Random(1, 1000, 100)] int n) { - [Test] - public void FindIndex_ItemPresent_ItemCorrect([Random(1, 1000, 100)] int n) - { - // Arrange - var searcher = new JumpSearcher(); - var sortedArray = Enumerable.Range(0, n).Select(_ => TestContext.CurrentContext.Random.Next(1_000_000)).OrderBy(x => x).ToArray(); - var expectedIndex = TestContext.CurrentContext.Random.Next(sortedArray.Length); + // Arrange + var searcher = new JumpSearcher(); + var sortedArray = Enumerable.Range(0, n).Select(_ => TestContext.CurrentContext.Random.Next(1_000_000)).OrderBy(x => x).ToArray(); + var expectedIndex = TestContext.CurrentContext.Random.Next(sortedArray.Length); - // Act - var actualIndex = searcher.FindIndex(sortedArray, sortedArray[expectedIndex]); + // Act + var actualIndex = searcher.FindIndex(sortedArray, sortedArray[expectedIndex]); - // Assert - sortedArray[actualIndex].Should().Be(sortedArray[expectedIndex]); - } + // Assert + sortedArray[actualIndex].Should().Be(sortedArray[expectedIndex]); + } - [Test] - public void FindIndex_ItemMissing_MinusOneReturned([Random(1, 1000, 10)] int n, [Random(-100, 1100, 10)] int missingItem) - { - // Arrange - var searcher = new JumpSearcher(); - var sortedArray = Enumerable.Range(0, n).Select(_ => TestContext.CurrentContext.Random.Next(1_000_000)).Where(x => x != missingItem).OrderBy(x => x).ToArray(); - var expectedIndex = -1; + [Test] + public void FindIndex_ItemMissing_MinusOneReturned([Random(1, 1000, 10)] int n, [Random(-100, 1100, 10)] int missingItem) + { + // Arrange + var searcher = new JumpSearcher(); + var sortedArray = Enumerable.Range(0, n).Select(_ => TestContext.CurrentContext.Random.Next(1_000_000)).Where(x => x != missingItem).OrderBy(x => x).ToArray(); + var expectedIndex = -1; - // Act - var actualIndex = searcher.FindIndex(sortedArray, missingItem); + // Act + var actualIndex = searcher.FindIndex(sortedArray, missingItem); - // Assert - Assert.AreEqual(expectedIndex, actualIndex); - } + // Assert + Assert.AreEqual(expectedIndex, actualIndex); + } - [Test] - public void FindIndex_ArrayEmpty_MinusOneReturned([Random(-100, 1100, 10)] int missingItem) - { - // Arrange - var searcher = new JumpSearcher(); - var sortedArray = Array.Empty(); - var expectedIndex = -1; + [Test] + public void FindIndex_ArrayEmpty_MinusOneReturned([Random(-100, 1100, 10)] int missingItem) + { + // Arrange + var searcher = new JumpSearcher(); + var sortedArray = Array.Empty(); + var expectedIndex = -1; - // Act - var actualIndex = searcher.FindIndex(sortedArray, missingItem); + // Act + var actualIndex = searcher.FindIndex(sortedArray, missingItem); - // Assert - Assert.AreEqual(expectedIndex, actualIndex); - } + // Assert + Assert.AreEqual(expectedIndex, actualIndex); + } - [TestCase(null, "abc")] - [TestCase(new[] { "abc", "def", "ghi" }, null)] - [TestCase(null, null)] - public void FindIndex_ArrayNull_ItemNull_ArgumentNullExceptionThrown(string[] sortedArray, string searchItem) - { - // Arrange - var searcher = new JumpSearcher(); + [TestCase(null, "abc")] + [TestCase(new[] { "abc", "def", "ghi" }, null)] + [TestCase(null, null)] + public void FindIndex_ArrayNull_ItemNull_ArgumentNullExceptionThrown(string[] sortedArray, string searchItem) + { + // Arrange + var searcher = new JumpSearcher(); - // Act, Assert - _ = Assert.Throws(() => searcher.FindIndex(sortedArray, searchItem)); - } + // Act, Assert + _ = Assert.Throws(() => searcher.FindIndex(sortedArray, searchItem)); } } diff --git a/Algorithms.Tests/Search/LinearSearcherTests.cs b/Algorithms.Tests/Search/LinearSearcherTests.cs index e83ab619..f8a90ad3 100644 --- a/Algorithms.Tests/Search/LinearSearcherTests.cs +++ b/Algorithms.Tests/Search/LinearSearcherTests.cs @@ -1,72 +1,71 @@ -using System; +using System; using System.Linq; using Algorithms.Search; using NUnit.Framework; using NUnit.Framework.Internal; using Utilities.Exceptions; -namespace Algorithms.Tests.Search +namespace Algorithms.Tests.Search; + +public static class LinearSearcherTests { - public static class LinearSearcherTests + [Test] + public static void Find_ItemPresent_ItemCorrect([Random(0, 1_000_000, 100)] int n) { - [Test] - public static void Find_ItemPresent_ItemCorrect([Random(0, 1_000_000, 100)] int n) - { - // Arrange - var searcher = new LinearSearcher(); - var random = Randomizer.CreateRandomizer(); - var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray(); + // Arrange + var searcher = new LinearSearcher(); + var random = Randomizer.CreateRandomizer(); + var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray(); - // Act - var expectedItem = Array.Find(arrayToSearch, x => x == arrayToSearch[n / 2]); - var actualItem = searcher.Find(arrayToSearch, x => x == arrayToSearch[n / 2]); + // Act + var expectedItem = Array.Find(arrayToSearch, x => x == arrayToSearch[n / 2]); + var actualItem = searcher.Find(arrayToSearch, x => x == arrayToSearch[n / 2]); - // Assert - Assert.AreEqual(expectedItem, actualItem); - } + // Assert + Assert.AreEqual(expectedItem, actualItem); + } - [Test] - public static void FindIndex_ItemPresent_IndexCorrect([Random(0, 1_000_000, 100)] int n) - { - // Arrange - var searcher = new LinearSearcher(); - var random = Randomizer.CreateRandomizer(); - var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray(); + [Test] + public static void FindIndex_ItemPresent_IndexCorrect([Random(0, 1_000_000, 100)] int n) + { + // Arrange + var searcher = new LinearSearcher(); + var random = Randomizer.CreateRandomizer(); + var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray(); - // Act - var expectedIndex = Array.FindIndex(arrayToSearch, x => x == arrayToSearch[n / 2]); - var actualIndex = searcher.FindIndex(arrayToSearch, x => x == arrayToSearch[n / 2]); + // Act + var expectedIndex = Array.FindIndex(arrayToSearch, x => x == arrayToSearch[n / 2]); + var actualIndex = searcher.FindIndex(arrayToSearch, x => x == arrayToSearch[n / 2]); - // Assert - Assert.AreEqual(expectedIndex, actualIndex); - } + // Assert + Assert.AreEqual(expectedIndex, actualIndex); + } - [Test] - public static void Find_ItemMissing_ItemNotFoundExceptionThrown([Random(0, 1_000_000, 100)] int n) - { - // Arrange - var searcher = new LinearSearcher(); - var random = Randomizer.CreateRandomizer(); - var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray(); + [Test] + public static void Find_ItemMissing_ItemNotFoundExceptionThrown([Random(0, 1_000_000, 100)] int n) + { + // Arrange + var searcher = new LinearSearcher(); + var random = Randomizer.CreateRandomizer(); + var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray(); - // Act - // Assert - _ = Assert.Throws(() => searcher.Find(arrayToSearch, _ => false)); - } + // Act + // Assert + _ = Assert.Throws(() => searcher.Find(arrayToSearch, _ => false)); + } - [Test] - public static void FindIndex_ItemMissing_MinusOneReturned([Random(0, 1_000_000, 100)] int n) - { - // Arrange - var searcher = new LinearSearcher(); - var random = Randomizer.CreateRandomizer(); - var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray(); + [Test] + public static void FindIndex_ItemMissing_MinusOneReturned([Random(0, 1_000_000, 100)] int n) + { + // Arrange + var searcher = new LinearSearcher(); + var random = Randomizer.CreateRandomizer(); + var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray(); - // Act - var actualIndex = searcher.FindIndex(arrayToSearch, _ => false); + // Act + var actualIndex = searcher.FindIndex(arrayToSearch, _ => false); - // Assert - Assert.AreEqual(-1, actualIndex); - } + // Assert + Assert.AreEqual(-1, actualIndex); } } diff --git a/Algorithms.Tests/Search/RecursiveBinarySearcherTests.cs b/Algorithms.Tests/Search/RecursiveBinarySearcherTests.cs index 2c161579..07990aa5 100644 --- a/Algorithms.Tests/Search/RecursiveBinarySearcherTests.cs +++ b/Algorithms.Tests/Search/RecursiveBinarySearcherTests.cs @@ -6,72 +6,71 @@ using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Search +namespace Algorithms.Tests.Search; + +public static class RecursiveBinarySearcherTests { - public static class RecursiveBinarySearcherTests + [Test] + public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int n) { - [Test] - public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int n) - { - // Arrange - var subject = new RecursiveBinarySearcher(); - var randomizer = Randomizer.CreateRandomizer(); - var selectedIndex = randomizer.Next(0, n); - var collection = Enumerable.Range(0, n).Select(_ => randomizer.Next(0, 1000)).OrderBy(x => x).ToList(); + // Arrange + var subject = new RecursiveBinarySearcher(); + var randomizer = Randomizer.CreateRandomizer(); + var selectedIndex = randomizer.Next(0, n); + var collection = Enumerable.Range(0, n).Select(_ => randomizer.Next(0, 1000)).OrderBy(x => x).ToList(); - // Act - var actualIndex = subject.FindIndex(collection, collection[selectedIndex]); + // Act + var actualIndex = subject.FindIndex(collection, collection[selectedIndex]); - // Assert - Assert.AreEqual(collection[selectedIndex], collection[actualIndex]); - } + // Assert + Assert.AreEqual(collection[selectedIndex], collection[actualIndex]); + } - [Test] - public static void FindIndex_ItemMissing_MinusOneReturned( - [Random(0, 1000, 10)] int n, - [Random(-100, 1100, 10)] int missingItem) - { - // Arrange - var subject = new RecursiveBinarySearcher(); - var random = Randomizer.CreateRandomizer(); - var collection = Enumerable.Range(0, n) - .Select(_ => random.Next(0, 1000)) - .Where(x => x != missingItem) - .OrderBy(x => x).ToList(); + [Test] + public static void FindIndex_ItemMissing_MinusOneReturned( + [Random(0, 1000, 10)] int n, + [Random(-100, 1100, 10)] int missingItem) + { + // Arrange + var subject = new RecursiveBinarySearcher(); + var random = Randomizer.CreateRandomizer(); + var collection = Enumerable.Range(0, n) + .Select(_ => random.Next(0, 1000)) + .Where(x => x != missingItem) + .OrderBy(x => x).ToList(); - // Act - var actualIndex = subject.FindIndex(collection, missingItem); + // Act + var actualIndex = subject.FindIndex(collection, missingItem); - // Assert - Assert.AreEqual(-1, actualIndex); - } + // Assert + Assert.AreEqual(-1, actualIndex); + } - [Test] - public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemToSearch) - { - // Arrange - var subject = new RecursiveBinarySearcher(); - var collection = new int[0]; + [Test] + public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemToSearch) + { + // Arrange + var subject = new RecursiveBinarySearcher(); + var collection = new int[0]; - // Act - var actualIndex = subject.FindIndex(collection, itemToSearch); + // Act + var actualIndex = subject.FindIndex(collection, itemToSearch); - // Assert - Assert.AreEqual(-1, actualIndex); - } + // Assert + Assert.AreEqual(-1, actualIndex); + } - [Test] - public static void FindIndex_NullCollection_Throws() - { - // Arrange - var subject = new RecursiveBinarySearcher(); - var collection = (IList?)null; + [Test] + public static void FindIndex_NullCollection_Throws() + { + // Arrange + var subject = new RecursiveBinarySearcher(); + var collection = (IList?)null; - // Act - Action act = () => subject.FindIndex(collection, 42); + // Act + Action act = () => subject.FindIndex(collection, 42); - // Assert - act.Should().Throw(); - } + // Assert + act.Should().Throw(); } } diff --git a/Algorithms.Tests/Sequences/BinaryPrimeConstantSequenceTests.cs b/Algorithms.Tests/Sequences/BinaryPrimeConstantSequenceTests.cs index 759fedae..8e595950 100644 --- a/Algorithms.Tests/Sequences/BinaryPrimeConstantSequenceTests.cs +++ b/Algorithms.Tests/Sequences/BinaryPrimeConstantSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class BinaryPrimeConstantSequenceTests { - public class BinaryPrimeConstantSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new BinaryPrimeConstantSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { 0, 1, 1, 0, 1, 0, 1, 0, 0, 0 }) - .Should().BeTrue(); - } + var sequence = new BinaryPrimeConstantSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 0, 1, 1, 0, 1, 0, 1, 0, 0, 0 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/BinomialSequenceTests.cs b/Algorithms.Tests/Sequences/BinomialSequenceTests.cs index 7adf4337..928fee2c 100644 --- a/Algorithms.Tests/Sequences/BinomialSequenceTests.cs +++ b/Algorithms.Tests/Sequences/BinomialSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class BinomialSequenceTests { - public class BinomialSequenceTests + [Test] + public void First4RowsCorrect() { - [Test] - public void First4RowsCorrect() - { - var sequence = new BinomialSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { 1, 1, 1, 1, 2, 1, 1, 3, 3, 1 }) - .Should().BeTrue(); - } + var sequence = new BinomialSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 1, 1, 1, 1, 2, 1, 1, 3, 3, 1 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/CatalanSequenceTest.cs b/Algorithms.Tests/Sequences/CatalanSequenceTest.cs index cf266252..69fbac80 100644 --- a/Algorithms.Tests/Sequences/CatalanSequenceTest.cs +++ b/Algorithms.Tests/Sequences/CatalanSequenceTest.cs @@ -4,19 +4,18 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class CatalanSequenceTest { - public class CatalanSequenceTest + [Test] + public void First30ItemsCorrect() { - [Test] - public void First30ItemsCorrect() - { - var sequence = new CatalanSequence().Sequence.Take(30); - sequence.SequenceEqual(new BigInteger[] { 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, - 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, - 91482563640, 343059613650, 1289904147324, 4861946401452, 18367353072152, - 69533550916004, 263747951750360, 1002242216651368}) - .Should().BeTrue(); - } + var sequence = new CatalanSequence().Sequence.Take(30); + sequence.SequenceEqual(new BigInteger[] { 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, + 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, + 91482563640, 343059613650, 1289904147324, 4861946401452, 18367353072152, + 69533550916004, 263747951750360, 1002242216651368}) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/CubesSequenceTests.cs b/Algorithms.Tests/Sequences/CubesSequenceTests.cs index 649c9732..2b440136 100644 --- a/Algorithms.Tests/Sequences/CubesSequenceTests.cs +++ b/Algorithms.Tests/Sequences/CubesSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class CubesSequenceTests { - public class CubesSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new CubesSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { 0, 1, 8, 27, 64, 125, 216, 343, 512, 729 }) - .Should().BeTrue(); - } + var sequence = new CubesSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 0, 1, 8, 27, 64, 125, 216, 343, 512, 729 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/DivisorsCountSequenceTests.cs b/Algorithms.Tests/Sequences/DivisorsCountSequenceTests.cs index b78e9647..bf2fa9c4 100644 --- a/Algorithms.Tests/Sequences/DivisorsCountSequenceTests.cs +++ b/Algorithms.Tests/Sequences/DivisorsCountSequenceTests.cs @@ -4,28 +4,27 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class DivisorsCountSequenceTests { - public class DivisorsCountSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - // These values are taken from https://oeis.org/A000005 for comparison. - var oeisSource = new BigInteger[] - { - 1, 2, 2, 3, 2, 4, 2, 4, 3, 4, 2, 6, 2, - 4, 4, 5, 2, 6, 2, 6, 4, 4, 2, 8, 3, 4, - 4, 6, 2, 8, 2, 6, 4, 4, 4, 9, 2, 4, 4, - 8, 2, 8, 2, 6, 6, 4, 2, 10, 3, 6, 4, 6, - 2, 8, 4, 8, 4, 4, 2, 12, 2, 4, 6, 7, 4, - 8, 2, 6, 4, 8, 2, 12, 2, 4, 6, 6, 4, 8, - 2, 10, 5, 4, 2, 12, 4, 4, 4, 8, 2, 12, 4, - 6, 4, 4, 4, 12, 2, 6, 6, 9, 2, 8, 2, 8, - }; + // These values are taken from https://oeis.org/A000005 for comparison. + var oeisSource = new BigInteger[] + { + 1, 2, 2, 3, 2, 4, 2, 4, 3, 4, 2, 6, 2, + 4, 4, 5, 2, 6, 2, 6, 4, 4, 2, 8, 3, 4, + 4, 6, 2, 8, 2, 6, 4, 4, 4, 9, 2, 4, 4, + 8, 2, 8, 2, 6, 6, 4, 2, 10, 3, 6, 4, 6, + 2, 8, 4, 8, 4, 4, 2, 12, 2, 4, 6, 7, 4, + 8, 2, 6, 4, 8, 2, 12, 2, 4, 6, 6, 4, 8, + 2, 10, 5, 4, 2, 12, 4, 4, 4, 8, 2, 12, 4, + 6, 4, 4, 4, 12, 2, 6, 6, 9, 2, 8, 2, 8, + }; - var sequence = new DivisorsCountSequence().Sequence.Take(oeisSource.Length); - sequence.SequenceEqual(oeisSource).Should().BeTrue(); - } + var sequence = new DivisorsCountSequence().Sequence.Take(oeisSource.Length); + sequence.SequenceEqual(oeisSource).Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/EuclidNumbersSequenceTests.cs b/Algorithms.Tests/Sequences/EuclidNumbersSequenceTests.cs index 249e66f4..46a3d212 100644 --- a/Algorithms.Tests/Sequences/EuclidNumbersSequenceTests.cs +++ b/Algorithms.Tests/Sequences/EuclidNumbersSequenceTests.cs @@ -1,20 +1,19 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class EuclidNumbersSequenceTests { - public class EuclidNumbersSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new EuclidNumbersSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] - { 2, 3, 7, 31, 211, 2311, 30031, 510511, 9699691, 223092871 }) - .Should().BeTrue(); - } + var sequence = new EuclidNumbersSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] + { 2, 3, 7, 31, 211, 2311, 30031, 510511, 9699691, 223092871 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/EulerTotientSequenceTests.cs b/Algorithms.Tests/Sequences/EulerTotientSequenceTests.cs index ed9391f1..178ee787 100644 --- a/Algorithms.Tests/Sequences/EulerTotientSequenceTests.cs +++ b/Algorithms.Tests/Sequences/EulerTotientSequenceTests.cs @@ -4,48 +4,47 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class EulerTotientSequenceTests { - public class EulerTotientSequenceTests + [Test] + public void FirstElementsCorrect() { - [Test] - public void FirstElementsCorrect() - { - // Let's be thorough. 500 phi values! - // Initial test of 69 number from table at https://oeis.org/A000010/list and passed test. - // Extended out to 500 values from https://primefan.tripod.com/Phi500.html and passed initial 69 - // along with remaining values. - var check = new BigInteger[] - { - 1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18, 8, - 12, 10, 22, 8, 20, 12, 18, 12, 28, 8, 30, 16, 20, 16, 24, 12, 36, 18, 24, 16, - 40, 12, 42, 20, 24, 22, 46, 16, 42, 20, 32, 24, 52, 18, 40, 24, 36, 28, 58, 16, - 60, 30, 36, 32, 48, 20, 66, 32, 44, 24, 70, 24, 72, 36, 40, 36, 60, 24, 78, 32, - 54, 40, 82, 24, 64, 42, 56, 40, 88, 24, 72, 44, 60, 46, 72, 32, 96, 42, 60, 40, - 100, 32, 102, 48, 48, 52, 106, 36, 108, 40, 72, 48, 112, 36, 88, 56, 72, 58, 96, 32, - 110, 60, 80, 60, 100, 36, 126, 64, 84, 48, 130, 40, 108, 66, 72, 64, 136, 44, 138, 48, - 92, 70, 120, 48, 112, 72, 84, 72, 148, 40, 150, 72, 96, 60, 120, 48, 156, 78, 104, 64, - 132, 54, 162, 80, 80, 82, 166, 48, 156, 64, 108, 84, 172, 56, 120, 80, 116, 88, 178, 48, - 180, 72, 120, 88, 144, 60, 160, 92, 108, 72, 190, 64, 192, 96, 96, 84, 196, 60, 198, 80, - 132, 100, 168, 64, 160, 102, 132, 96, 180, 48, 210, 104, 140, 106, 168, 72, 180, 108, 144, 80, - 192, 72, 222, 96, 120, 112, 226, 72, 228, 88, 120, 112, 232, 72, 184, 116, 156, 96, 238, 64, - 240, 110, 162, 120, 168, 80, 216, 120, 164, 100, 250, 72, 220, 126, 128, 128, 256, 84, 216, 96, - 168, 130, 262, 80, 208, 108, 176, 132, 268, 72, 270, 128, 144, 136, 200, 88, 276, 138, 180, 96, - 280, 92, 282, 140, 144, 120, 240, 96, 272, 112, 192, 144, 292, 84, 232, 144, 180, 148, 264, 80, - 252, 150, 200, 144, 240, 96, 306, 120, 204, 120, 310, 96, 312, 156, 144, 156, 316, 104, 280, 128, - 212, 132, 288, 108, 240, 162, 216, 160, 276, 80, 330, 164, 216, 166, 264, 96, 336, 156, 224, 128, - 300, 108, 294, 168, 176, 172, 346, 112, 348, 120, 216, 160, 352, 116, 280, 176, 192, 178, 358, 96, - 342, 180, 220, 144, 288, 120, 366, 176, 240, 144, 312, 120, 372, 160, 200, 184, 336, 108, 378, 144, - 252, 190, 382, 128, 240, 192, 252, 192, 388, 96, 352, 168, 260, 196, 312, 120, 396, 198, 216, 160, - 400, 132, 360, 200, 216, 168, 360, 128, 408, 160, 272, 204, 348, 132, 328, 192, 276, 180, 418, 96, - 420, 210, 276, 208, 320, 140, 360, 212, 240, 168, 430, 144, 432, 180, 224, 216, 396, 144, 438, 160, - 252, 192, 442, 144, 352, 222, 296, 192, 448, 120, 400, 224, 300, 226, 288, 144, 456, 228, 288, 176, - 460, 120, 462, 224, 240, 232, 466, 144, 396, 184, 312, 232, 420, 156, 360, 192, 312, 238, 478, 128, - 432, 240, 264, 220, 384, 162, 486, 240, 324, 168, 490, 160, 448, 216, 240, 240, 420, 164, 498, 200, - }; + // Let's be thorough. 500 phi values! + // Initial test of 69 number from table at https://oeis.org/A000010/list and passed test. + // Extended out to 500 values from https://primefan.tripod.com/Phi500.html and passed initial 69 + // along with remaining values. + var check = new BigInteger[] + { + 1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18, 8, + 12, 10, 22, 8, 20, 12, 18, 12, 28, 8, 30, 16, 20, 16, 24, 12, 36, 18, 24, 16, + 40, 12, 42, 20, 24, 22, 46, 16, 42, 20, 32, 24, 52, 18, 40, 24, 36, 28, 58, 16, + 60, 30, 36, 32, 48, 20, 66, 32, 44, 24, 70, 24, 72, 36, 40, 36, 60, 24, 78, 32, + 54, 40, 82, 24, 64, 42, 56, 40, 88, 24, 72, 44, 60, 46, 72, 32, 96, 42, 60, 40, + 100, 32, 102, 48, 48, 52, 106, 36, 108, 40, 72, 48, 112, 36, 88, 56, 72, 58, 96, 32, + 110, 60, 80, 60, 100, 36, 126, 64, 84, 48, 130, 40, 108, 66, 72, 64, 136, 44, 138, 48, + 92, 70, 120, 48, 112, 72, 84, 72, 148, 40, 150, 72, 96, 60, 120, 48, 156, 78, 104, 64, + 132, 54, 162, 80, 80, 82, 166, 48, 156, 64, 108, 84, 172, 56, 120, 80, 116, 88, 178, 48, + 180, 72, 120, 88, 144, 60, 160, 92, 108, 72, 190, 64, 192, 96, 96, 84, 196, 60, 198, 80, + 132, 100, 168, 64, 160, 102, 132, 96, 180, 48, 210, 104, 140, 106, 168, 72, 180, 108, 144, 80, + 192, 72, 222, 96, 120, 112, 226, 72, 228, 88, 120, 112, 232, 72, 184, 116, 156, 96, 238, 64, + 240, 110, 162, 120, 168, 80, 216, 120, 164, 100, 250, 72, 220, 126, 128, 128, 256, 84, 216, 96, + 168, 130, 262, 80, 208, 108, 176, 132, 268, 72, 270, 128, 144, 136, 200, 88, 276, 138, 180, 96, + 280, 92, 282, 140, 144, 120, 240, 96, 272, 112, 192, 144, 292, 84, 232, 144, 180, 148, 264, 80, + 252, 150, 200, 144, 240, 96, 306, 120, 204, 120, 310, 96, 312, 156, 144, 156, 316, 104, 280, 128, + 212, 132, 288, 108, 240, 162, 216, 160, 276, 80, 330, 164, 216, 166, 264, 96, 336, 156, 224, 128, + 300, 108, 294, 168, 176, 172, 346, 112, 348, 120, 216, 160, 352, 116, 280, 176, 192, 178, 358, 96, + 342, 180, 220, 144, 288, 120, 366, 176, 240, 144, 312, 120, 372, 160, 200, 184, 336, 108, 378, 144, + 252, 190, 382, 128, 240, 192, 252, 192, 388, 96, 352, 168, 260, 196, 312, 120, 396, 198, 216, 160, + 400, 132, 360, 200, 216, 168, 360, 128, 408, 160, 272, 204, 348, 132, 328, 192, 276, 180, 418, 96, + 420, 210, 276, 208, 320, 140, 360, 212, 240, 168, 430, 144, 432, 180, 224, 216, 396, 144, 438, 160, + 252, 192, 442, 144, 352, 222, 296, 192, 448, 120, 400, 224, 300, 226, 288, 144, 456, 228, 288, 176, + 460, 120, 462, 224, 240, 232, 466, 144, 396, 184, 312, 232, 420, 156, 360, 192, 312, 238, 478, 128, + 432, 240, 264, 220, 384, 162, 486, 240, 324, 168, 490, 160, 448, 216, 240, 240, 420, 164, 498, 200, + }; - var sequence = new EulerTotientSequence().Sequence.Take(check.Length); - sequence.SequenceEqual(check).Should().BeTrue(); - } + var sequence = new EulerTotientSequence().Sequence.Take(check.Length); + sequence.SequenceEqual(check).Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/FactorialSequenceTest.cs b/Algorithms.Tests/Sequences/FactorialSequenceTest.cs index 5841593c..ae98d986 100644 --- a/Algorithms.Tests/Sequences/FactorialSequenceTest.cs +++ b/Algorithms.Tests/Sequences/FactorialSequenceTest.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class FactorialSequenceTest { - public class FactorialSequenceTest + [Test] + public void First10ItemsCorrect() { - [Test] - public void First10ItemsCorrect() - { - var sequence = new FactorialSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 }) - .Should().BeTrue(); - } + var sequence = new FactorialSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/FermatNumbersSequenceTests.cs b/Algorithms.Tests/Sequences/FermatNumbersSequenceTests.cs index 0fe67e77..2c71f0bb 100644 --- a/Algorithms.Tests/Sequences/FermatNumbersSequenceTests.cs +++ b/Algorithms.Tests/Sequences/FermatNumbersSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class FermatNumbersSequenceTests { - public class FermatNumbersSequenceTests + [Test] + public void First5ElementsCorrect() { - [Test] - public void First5ElementsCorrect() - { - var sequence = new FermatNumbersSequence().Sequence.Take(5); - sequence.SequenceEqual(new BigInteger[] { 3, 5, 17, 257, 65537 }) - .Should().BeTrue(); - } + var sequence = new FermatNumbersSequence().Sequence.Take(5); + sequence.SequenceEqual(new BigInteger[] { 3, 5, 17, 257, 65537 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/FermatPrimesSequenceTests.cs b/Algorithms.Tests/Sequences/FermatPrimesSequenceTests.cs index 113469e6..caf1577a 100644 --- a/Algorithms.Tests/Sequences/FermatPrimesSequenceTests.cs +++ b/Algorithms.Tests/Sequences/FermatPrimesSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class FermatPrimesSequenceTests { - public class FermatPrimesSequenceTests + [Test] + public void All5ElementsCorrect() { - [Test] - public void All5ElementsCorrect() - { - var sequence = new FermatPrimesSequence().Sequence.Take(5); - sequence.SequenceEqual(new BigInteger[] { 3, 5, 17, 257, 65537 }) - .Should().BeTrue(); - } + var sequence = new FermatPrimesSequence().Sequence.Take(5); + sequence.SequenceEqual(new BigInteger[] { 3, 5, 17, 257, 65537 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/FibonacciSequenceTests.cs b/Algorithms.Tests/Sequences/FibonacciSequenceTests.cs index b8acc50f..feebfd95 100644 --- a/Algorithms.Tests/Sequences/FibonacciSequenceTests.cs +++ b/Algorithms.Tests/Sequences/FibonacciSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class FibonacciSequenceTests { - public class FibonacciSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new FibonacciSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 }) - .Should().BeTrue(); - } + var sequence = new FibonacciSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/GolombsSequenceTests.cs b/Algorithms.Tests/Sequences/GolombsSequenceTests.cs index 3ee91c21..be0f95d5 100644 --- a/Algorithms.Tests/Sequences/GolombsSequenceTests.cs +++ b/Algorithms.Tests/Sequences/GolombsSequenceTests.cs @@ -4,24 +4,23 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class GolombsSequenceTests { - public class GolombsSequenceTests + [Test] + public void First50ElementsCorrect() { - [Test] - public void First50ElementsCorrect() - { - // Taken from https://oeis.org/A001462 - var expected = new BigInteger[] { - 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, - 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, - 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, - 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, - 12, 12, 12, 12, 13, 13, 13, 13, 13, 13}; + // Taken from https://oeis.org/A001462 + var expected = new BigInteger[] { + 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, + 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, + 12, 12, 12, 12, 13, 13, 13, 13, 13, 13}; - var sequence = new GolombsSequence().Sequence.Take(50); + var sequence = new GolombsSequence().Sequence.Take(50); - sequence.SequenceEqual(expected).Should().BeTrue(); - } + sequence.SequenceEqual(expected).Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/KolakoskiSequenceTests.cs b/Algorithms.Tests/Sequences/KolakoskiSequenceTests.cs index d2cbd60d..255ce34c 100644 --- a/Algorithms.Tests/Sequences/KolakoskiSequenceTests.cs +++ b/Algorithms.Tests/Sequences/KolakoskiSequenceTests.cs @@ -4,33 +4,32 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class KolakoskiSequenceTests { - public class KolakoskiSequenceTests + [Test] + public void First100ElementsCorrect() { - [Test] - public void First100ElementsCorrect() + // Taken from https://oeis.org/A000002 + var expected = new BigInteger[] { - // Taken from https://oeis.org/A000002 - var expected = new BigInteger[] - { - 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, - 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, - 2, 1, 1, 2, 1, 2, 2, 1, 1, 2, - 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, - 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, - 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, - 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, - 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, - 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, - 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, - }; + 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, + 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, + 2, 1, 1, 2, 1, 2, 2, 1, 1, 2, + 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, + 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, + 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, + 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, + 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, + 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, + 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, + }; - var sequence = new KolakoskiSequence().Sequence.Take(100); - var sequence2 = new KolakoskiSequence2().Sequence.Take(100); + var sequence = new KolakoskiSequence().Sequence.Take(100); + var sequence2 = new KolakoskiSequence2().Sequence.Take(100); - sequence.Should().Equal(expected); - sequence2.Should().Equal(expected); - } + sequence.Should().Equal(expected); + sequence2.Should().Equal(expected); } } diff --git a/Algorithms.Tests/Sequences/KummerNumbersSequenceTests.cs b/Algorithms.Tests/Sequences/KummerNumbersSequenceTests.cs index 8040a41a..b916b363 100644 --- a/Algorithms.Tests/Sequences/KummerNumbersSequenceTests.cs +++ b/Algorithms.Tests/Sequences/KummerNumbersSequenceTests.cs @@ -1,20 +1,19 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class KummerNumbersSequenceTests { - public class KummerNumbersSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new KummerNumbersSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] - { 1, 5, 29, 209, 2309, 30029, 510509, 9699689, 223092869, 6469693229 }) - .Should().BeTrue(); - } + var sequence = new KummerNumbersSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] + { 1, 5, 29, 209, 2309, 30029, 510509, 9699689, 223092869, 6469693229 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/MakeChangeSequenceTests.cs b/Algorithms.Tests/Sequences/MakeChangeSequenceTests.cs index 707d7610..69a79aaa 100644 --- a/Algorithms.Tests/Sequences/MakeChangeSequenceTests.cs +++ b/Algorithms.Tests/Sequences/MakeChangeSequenceTests.cs @@ -4,30 +4,29 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class MakeChangeSequenceTests { - public class MakeChangeSequenceTests + [Test] + public void First100ElementsCorrect() { - [Test] - public void First100ElementsCorrect() - { - // Values from https://oeis.org/A000008/b000008.txt - var test = new BigInteger[] - { - 1, 1, 2, 2, 3, 4, 5, 6, 7, 8, - 11, 12, 15, 16, 19, 22, 25, 28, 31, 34, - 40, 43, 49, 52, 58, 64, 70, 76, 82, 88, - 98, 104, 114, 120, 130, 140, 150, 160, 170, 180, - 195, 205, 220, 230, 245, 260, 275, 290, 305, 320, - 341, 356, 377, 392, 413, 434, 455, 476, 497, 518, - 546, 567, 595, 616, 644, 672, 700, 728, 756, 784, - 820, 848, 884, 912, 948, 984, 1020, 1056, 1092, 1128, - 1173, 1209, 1254, 1290, 1335, 1380, 1425, 1470, 1515, 1560, - 1615, 1660, 1715, 1760, 1815, 1870, 1925, 1980, 2035, 2090, - }; + // Values from https://oeis.org/A000008/b000008.txt + var test = new BigInteger[] + { + 1, 1, 2, 2, 3, 4, 5, 6, 7, 8, + 11, 12, 15, 16, 19, 22, 25, 28, 31, 34, + 40, 43, 49, 52, 58, 64, 70, 76, 82, 88, + 98, 104, 114, 120, 130, 140, 150, 160, 170, 180, + 195, 205, 220, 230, 245, 260, 275, 290, 305, 320, + 341, 356, 377, 392, 413, 434, 455, 476, 497, 518, + 546, 567, 595, 616, 644, 672, 700, 728, 756, 784, + 820, 848, 884, 912, 948, 984, 1020, 1056, 1092, 1128, + 1173, 1209, 1254, 1290, 1335, 1380, 1425, 1470, 1515, 1560, + 1615, 1660, 1715, 1760, 1815, 1870, 1925, 1980, 2035, 2090, + }; - var sequence = new MakeChangeSequence().Sequence.Take(test.Length); - sequence.SequenceEqual(test).Should().BeTrue(); - } + var sequence = new MakeChangeSequence().Sequence.Take(test.Length); + sequence.SequenceEqual(test).Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/MatchstickTriangleSequenceTests.cs b/Algorithms.Tests/Sequences/MatchstickTriangleSequenceTests.cs index bf838dff..06b61be3 100644 --- a/Algorithms.Tests/Sequences/MatchstickTriangleSequenceTests.cs +++ b/Algorithms.Tests/Sequences/MatchstickTriangleSequenceTests.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; @@ -9,7 +9,7 @@ namespace Algorithms.Tests.Sequences; [TestFixture] public static class MatchstickTriangleSequenceTests { - private static BigInteger[] TestList = { + private static BigInteger[] _testList = { 0, 1, 5, 13, 27, 48, 78, 118, 170, 235, 315, 411, 525, 658, 812, 988, 1188, 1413, 1665, 1945, 2255, 2596, 2970, 3378, 3822, 4303, 4823, 5383, 5985, 6630, 7320, 8056, 8840, 9673, @@ -22,7 +22,7 @@ public static class MatchstickTriangleSequenceTests [Test] public static void TestOeisList() { - var sequence = new MatchstickTriangleSequence().Sequence.Take(TestList.Length); - sequence.SequenceEqual(TestList).Should().BeTrue(); + var sequence = new MatchstickTriangleSequence().Sequence.Take(_testList.Length); + sequence.SequenceEqual(_testList).Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/NaturalSequenceTests.cs b/Algorithms.Tests/Sequences/NaturalSequenceTests.cs index 581c5972..3855461d 100644 --- a/Algorithms.Tests/Sequences/NaturalSequenceTests.cs +++ b/Algorithms.Tests/Sequences/NaturalSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class NaturalSequenceTests { - public class NaturalSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new NaturalSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }) - .Should().BeTrue(); - } + var sequence = new NaturalSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/NegativeIntegersSequenceTests.cs b/Algorithms.Tests/Sequences/NegativeIntegersSequenceTests.cs index 3437bfab..1d70b85f 100644 --- a/Algorithms.Tests/Sequences/NegativeIntegersSequenceTests.cs +++ b/Algorithms.Tests/Sequences/NegativeIntegersSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class NegativeIntegersSequenceTests { - public class NegativeIntegersSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new NegativeIntegersSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { -1, -2, -3, -4, -5, -6, -7, -8, -9, -10 }) - .Should().BeTrue(); - } + var sequence = new NegativeIntegersSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { -1, -2, -3, -4, -5, -6, -7, -8, -9, -10 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/NumberOfBooleanFunctionsSequenceTests.cs b/Algorithms.Tests/Sequences/NumberOfBooleanFunctionsSequenceTests.cs index af9ea2fa..805129db 100644 --- a/Algorithms.Tests/Sequences/NumberOfBooleanFunctionsSequenceTests.cs +++ b/Algorithms.Tests/Sequences/NumberOfBooleanFunctionsSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class NumberOfBooleanFunctionsSequenceTests { - public class NumberOfBooleanFunctionsSequenceTests + [Test] + public void First5ElementsCorrect() { - [Test] - public void First5ElementsCorrect() - { - var sequence = new NumberOfBooleanFunctionsSequence().Sequence.Take(5); - sequence.SequenceEqual(new BigInteger[] { 2, 4, 16, 256, 65536 }) - .Should().BeTrue(); - } + var sequence = new NumberOfBooleanFunctionsSequence().Sequence.Take(5); + sequence.SequenceEqual(new BigInteger[] { 2, 4, 16, 256, 65536 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/NumberOfPrimesByNumberOfDigitsSequenceTests.cs b/Algorithms.Tests/Sequences/NumberOfPrimesByNumberOfDigitsSequenceTests.cs index f86f2b17..79de5310 100644 --- a/Algorithms.Tests/Sequences/NumberOfPrimesByNumberOfDigitsSequenceTests.cs +++ b/Algorithms.Tests/Sequences/NumberOfPrimesByNumberOfDigitsSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class NumberOfPrimesByNumberOfDigitsSequenceTests { - public class NumberOfPrimesByNumberOfDigitsSequenceTests + [Test] + public void First5ElementsCorrect() { - [Test] - public void First5ElementsCorrect() - { - var sequence = new NumberOfPrimesByNumberOfDigitsSequence().Sequence.Take(5); - sequence.SequenceEqual(new BigInteger[] { 0, 4, 21, 143, 1061 }) - .Should().BeTrue(); - } + var sequence = new NumberOfPrimesByNumberOfDigitsSequence().Sequence.Take(5); + sequence.SequenceEqual(new BigInteger[] { 0, 4, 21, 143, 1061 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/NumberOfPrimesByPowersOf10SequenceTests.cs b/Algorithms.Tests/Sequences/NumberOfPrimesByPowersOf10SequenceTests.cs index 13c68213..33bf3cd6 100644 --- a/Algorithms.Tests/Sequences/NumberOfPrimesByPowersOf10SequenceTests.cs +++ b/Algorithms.Tests/Sequences/NumberOfPrimesByPowersOf10SequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class NumberOfPrimesByPowersOf10SequenceTests { - public class NumberOfPrimesByPowersOf10SequenceTests + [Test] + public void First5ElementsCorrect() { - [Test] - public void First5ElementsCorrect() - { - var sequence = new NumberOfPrimesByPowersOf10Sequence().Sequence.Take(5); - sequence.SequenceEqual(new BigInteger[] { 0, 4, 25, 168, 1229 }) - .Should().BeTrue(); - } + var sequence = new NumberOfPrimesByPowersOf10Sequence().Sequence.Take(5); + sequence.SequenceEqual(new BigInteger[] { 0, 4, 25, 168, 1229 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/PowersOf10SequenceTests.cs b/Algorithms.Tests/Sequences/PowersOf10SequenceTests.cs index 20aa90d8..36935052 100644 --- a/Algorithms.Tests/Sequences/PowersOf10SequenceTests.cs +++ b/Algorithms.Tests/Sequences/PowersOf10SequenceTests.cs @@ -1,20 +1,19 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class PowersOf10SequenceTests { - public class PowersOf10SequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new PowersOf10Sequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] - { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }) - .Should().BeTrue(); - } + var sequence = new PowersOf10Sequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] + { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/PowersOf2SequenceTests.cs b/Algorithms.Tests/Sequences/PowersOf2SequenceTests.cs index 679ccc06..b3848f24 100644 --- a/Algorithms.Tests/Sequences/PowersOf2SequenceTests.cs +++ b/Algorithms.Tests/Sequences/PowersOf2SequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class PowersOf2SequenceTests { - public class PowersOf2SequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new PowersOf2Sequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }) - .Should().BeTrue(); - } + var sequence = new PowersOf2Sequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/PrimePiSequenceTests.cs b/Algorithms.Tests/Sequences/PrimePiSequenceTests.cs index f74e5c00..e7f67a8a 100644 --- a/Algorithms.Tests/Sequences/PrimePiSequenceTests.cs +++ b/Algorithms.Tests/Sequences/PrimePiSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class PrimePiSequenceTests { - public class PrimePiSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new PrimePiSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { 0, 1, 2, 2, 3, 3, 4, 4, 4, 4 }) - .Should().BeTrue(); - } + var sequence = new PrimePiSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 0, 1, 2, 2, 3, 3, 4, 4, 4, 4 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/PrimesSequenceTests.cs b/Algorithms.Tests/Sequences/PrimesSequenceTests.cs index 2ea4edf6..b88a58c6 100644 --- a/Algorithms.Tests/Sequences/PrimesSequenceTests.cs +++ b/Algorithms.Tests/Sequences/PrimesSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class PrimesSequenceTests { - public class PrimesSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new PrimesSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 }) - .Should().BeTrue(); - } + var sequence = new PrimesSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/PrimorialNumbersSequenceTests.cs b/Algorithms.Tests/Sequences/PrimorialNumbersSequenceTests.cs index 2940f440..d2de66b6 100644 --- a/Algorithms.Tests/Sequences/PrimorialNumbersSequenceTests.cs +++ b/Algorithms.Tests/Sequences/PrimorialNumbersSequenceTests.cs @@ -1,20 +1,19 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class PrimorialNumbersSequenceTests { - public class PrimorialNumbersSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new PrimorialNumbersSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] - { 1, 2, 6, 30, 210, 2310, 30030, 510510, 9699690, 223092870 }) - .Should().BeTrue(); - } + var sequence = new PrimorialNumbersSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] + { 1, 2, 6, 30, 210, 2310, 30030, 510510, 9699690, 223092870 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/RecamansSequenceTests.cs b/Algorithms.Tests/Sequences/RecamansSequenceTests.cs index 7cde4dbf..6f018cb7 100644 --- a/Algorithms.Tests/Sequences/RecamansSequenceTests.cs +++ b/Algorithms.Tests/Sequences/RecamansSequenceTests.cs @@ -4,26 +4,25 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class RecamansSequenceTests { - public class RecamansSequenceTests + [Test] + public void First50ElementsCorrect() { - [Test] - public void First50ElementsCorrect() + // Taken from http://oeis.org/A005132 + var expected = new BigInteger[] { - // Taken from http://oeis.org/A005132 - var expected = new BigInteger[] - { - 0, 1, 3, 6, 2, 7, 13, 20, 12, 21, - 11, 22, 10, 23, 9, 24, 8, 25, 43, 62, - 42, 63, 41, 18, 42, 17, 43, 16, 44, 15, - 45, 14, 46, 79, 113, 78, 114, 77, 39, 78, - 38, 79, 37, 80, 36, 81, 35, 82, 34, 83, - }; + 0, 1, 3, 6, 2, 7, 13, 20, 12, 21, + 11, 22, 10, 23, 9, 24, 8, 25, 43, 62, + 42, 63, 41, 18, 42, 17, 43, 16, 44, 15, + 45, 14, 46, 79, 113, 78, 114, 77, 39, 78, + 38, 79, 37, 80, 36, 81, 35, 82, 34, 83, + }; - var sequence = new RecamansSequence().Sequence.Take(50); + var sequence = new RecamansSequence().Sequence.Take(50); - sequence.Should().Equal(expected); - } + sequence.Should().Equal(expected); } } diff --git a/Algorithms.Tests/Sequences/SquaresSequenceTests.cs b/Algorithms.Tests/Sequences/SquaresSequenceTests.cs index d9899d30..7ed748e2 100644 --- a/Algorithms.Tests/Sequences/SquaresSequenceTests.cs +++ b/Algorithms.Tests/Sequences/SquaresSequenceTests.cs @@ -1,19 +1,18 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Algorithms.Sequences; using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class SquaresSequenceTests { - public class SquaresSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new SquaresSequence().Sequence.Take(10); - sequence.SequenceEqual(new BigInteger[] { 0, 1, 4, 9, 16, 25, 36, 49, 64, 81 }) - .Should().BeTrue(); - } + var sequence = new SquaresSequence().Sequence.Take(10); + sequence.SequenceEqual(new BigInteger[] { 0, 1, 4, 9, 16, 25, 36, 49, 64, 81 }) + .Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/ThreeNPlusOneStepsSequenceTests.cs b/Algorithms.Tests/Sequences/ThreeNPlusOneStepsSequenceTests.cs index 54c81c07..ab1bfb3f 100644 --- a/Algorithms.Tests/Sequences/ThreeNPlusOneStepsSequenceTests.cs +++ b/Algorithms.Tests/Sequences/ThreeNPlusOneStepsSequenceTests.cs @@ -4,19 +4,19 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences { - public class ThreeNPlusOneStepsSequenceTests { - [Test] - public void First50ElementsCorrect() { - var sequence = new ThreeNPlusOneStepsSequence().Sequence.Take(50); - var first50 = new BigInteger[] { - 0, 1, 7, 2, 5, 8, 16, 3, 19, 6, - 14, 9, 9, 17, 17, 4, 12, 20, 20, 7, - 7, 15, 15, 10, 23, 10, 111, 18, 18, 18, - 106, 5, 26, 13, 13, 21, 21, 21, 34, 8, - 109, 8, 29, 16, 16, 16, 104, 11, 24, 24 - }; - sequence.SequenceEqual(first50).Should().BeTrue(); - } +namespace Algorithms.Tests.Sequences; + +public class ThreeNPlusOneStepsSequenceTests { + [Test] + public void First50ElementsCorrect() { + var sequence = new ThreeNPlusOneStepsSequence().Sequence.Take(50); + var first50 = new BigInteger[] { + 0, 1, 7, 2, 5, 8, 16, 3, 19, 6, + 14, 9, 9, 17, 17, 4, 12, 20, 20, 7, + 7, 15, 15, 10, 23, 10, 111, 18, 18, 18, + 106, 5, 26, 13, 13, 21, 21, 21, 34, 8, + 109, 8, 29, 16, 16, 16, 104, 11, 24, 24 + }; + sequence.SequenceEqual(first50).Should().BeTrue(); } } diff --git a/Algorithms.Tests/Sequences/VanEcksSequenceTests.cs b/Algorithms.Tests/Sequences/VanEcksSequenceTests.cs index b8f3bddf..4ee2caaa 100644 --- a/Algorithms.Tests/Sequences/VanEcksSequenceTests.cs +++ b/Algorithms.Tests/Sequences/VanEcksSequenceTests.cs @@ -4,26 +4,25 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class VanEcksSequenceTests { - public class VanEcksSequenceTests + [Test] + public void First50ElementsCorrect() { - [Test] - public void First50ElementsCorrect() + // Taken from http://oeis.org/A181391 + var expected = new BigInteger[] { - // Taken from http://oeis.org/A181391 - var expected = new BigInteger[] - { - 0, 0, 1, 0, 2, 0, 2, 2, 1, 6, - 0, 5, 0, 2, 6, 5, 4, 0, 5, 3, - 0, 3, 2, 9, 0, 4, 9, 3, 6, 14, - 0, 6, 3, 5, 15, 0, 5, 3, 5, 2, - 17, 0, 6, 11, 0, 3, 8, 0, 3, 3, - }; + 0, 0, 1, 0, 2, 0, 2, 2, 1, 6, + 0, 5, 0, 2, 6, 5, 4, 0, 5, 3, + 0, 3, 2, 9, 0, 4, 9, 3, 6, 14, + 0, 6, 3, 5, 15, 0, 5, 3, 5, 2, + 17, 0, 6, 11, 0, 3, 8, 0, 3, 3, + }; - var sequence = new VanEcksSequence().Sequence.Take(50); + var sequence = new VanEcksSequence().Sequence.Take(50); - sequence.Should().Equal(expected); - } + sequence.Should().Equal(expected); } } diff --git a/Algorithms.Tests/Sequences/ZeroSequenceTests.cs b/Algorithms.Tests/Sequences/ZeroSequenceTests.cs index 5627ff28..0a337d0c 100644 --- a/Algorithms.Tests/Sequences/ZeroSequenceTests.cs +++ b/Algorithms.Tests/Sequences/ZeroSequenceTests.cs @@ -4,17 +4,16 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Sequences +namespace Algorithms.Tests.Sequences; + +public class ZeroSequenceTests { - public class ZeroSequenceTests + [Test] + public void First10ElementsCorrect() { - [Test] - public void First10ElementsCorrect() - { - var sequence = new ZeroSequence().Sequence.Take(10); - sequence.SequenceEqual(Enumerable.Repeat(BigInteger.Zero, 10)) - .Should().BeTrue(); - } - + var sequence = new ZeroSequence().Sequence.Take(10); + sequence.SequenceEqual(Enumerable.Repeat(BigInteger.Zero, 10)) + .Should().BeTrue(); } + } diff --git a/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs b/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs index 95efaeea..c9352e89 100644 --- a/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs +++ b/Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs @@ -4,84 +4,83 @@ using NUnit.Framework; using System; -namespace Algorithms.Tests.Shufflers +namespace Algorithms.Tests.Shufflers; + +public static class FisherYatesShufflerTests { - public static class FisherYatesShufflerTests + [Test] + public static void ArrayShuffled_NewArrayHasSameSize( + [Random(10, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArrayShuffled_NewArrayHasSameSize( - [Random(10, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var shuffler = new FisherYatesShuffler(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var shuffler = new FisherYatesShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - shuffler.Shuffle(testArray); + // Act + shuffler.Shuffle(testArray); - // Assert - testArray.Length.Should().Be(correctArray.Length); - } + // Assert + testArray.Length.Should().Be(correctArray.Length); + } - [Test] - public static void ArrayShuffled_NewArrayHasSameValues( - [Random(0, 100, 10, Distinct = true)] - int n) - { - // Arrange - var shuffler = new FisherYatesShuffler(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + [Test] + public static void ArrayShuffled_NewArrayHasSameValues( + [Random(0, 100, 10, Distinct = true)] + int n) + { + // Arrange + var shuffler = new FisherYatesShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - shuffler.Shuffle(testArray); + // Act + shuffler.Shuffle(testArray); - // Assert - testArray.Should().BeEquivalentTo(correctArray); - } + // Assert + testArray.Should().BeEquivalentTo(correctArray); + } - [Test] - public static void ArrayShuffled_SameShuffle( - [Random(0, 1000, 2, Distinct = true)] int n, - [Random(1000, 10000, 5, Distinct = true)] int seed) - { - // Arrange - var shuffler = new FisherYatesShuffler(); - var (array1, array2) = RandomHelper.GetArrays(n); + [Test] + public static void ArrayShuffled_SameShuffle( + [Random(0, 1000, 2, Distinct = true)] int n, + [Random(1000, 10000, 5, Distinct = true)] int seed) + { + // Arrange + var shuffler = new FisherYatesShuffler(); + var (array1, array2) = RandomHelper.GetArrays(n); - // Act - shuffler.Shuffle(array1, seed); - shuffler.Shuffle(array2, seed); + // Act + shuffler.Shuffle(array1, seed); + shuffler.Shuffle(array2, seed); - // Assert - array1.Should().BeEquivalentTo(array2, options => options.WithStrictOrdering()); - } + // Assert + array1.Should().BeEquivalentTo(array2, options => options.WithStrictOrdering()); + } - [Test] - public static void ArrayShuffled_DifferentSeedDifferentShuffle( - [Random(10, 100, 2, Distinct = true)] int n, - [Random(1000, 10000, 5, Distinct = true)] int seed) - { - // Arrange - var shuffler = new FisherYatesShuffler(); - var (array1, array2) = RandomHelper.GetArrays(n); + [Test] + public static void ArrayShuffled_DifferentSeedDifferentShuffle( + [Random(10, 100, 2, Distinct = true)] int n, + [Random(1000, 10000, 5, Distinct = true)] int seed) + { + // Arrange + var shuffler = new FisherYatesShuffler(); + var (array1, array2) = RandomHelper.GetArrays(n); - // Act - shuffler.Shuffle(array1, seed); - shuffler.Shuffle(array2, seed + 13); + // Act + shuffler.Shuffle(array1, seed); + shuffler.Shuffle(array2, seed + 13); - // It seems the actual version of FluentAssertion has no options in NotBeEquivalentTo. - // With default options, it does not check for order, but for the same elements in the collection. - // So until the library is updated check that not all the items have the same order. - int hits = 0; - for (int i = 0; i < n; i++) + // It seems the actual version of FluentAssertion has no options in NotBeEquivalentTo. + // With default options, it does not check for order, but for the same elements in the collection. + // So until the library is updated check that not all the items have the same order. + int hits = 0; + for (int i = 0; i < n; i++) + { + if (array1[i] == array2[i]) { - if (array1[i] == array2[i]) - { - hits++; - } + hits++; } - hits.Should().BeLessThan(array2.Length); } + hits.Should().BeLessThan(array2.Length); } } diff --git a/Algorithms.Tests/Sorters/Comparison/BinaryInsertionSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/BinaryInsertionSorterTests.cs index a73e1997..858f5fd9 100644 --- a/Algorithms.Tests/Sorters/Comparison/BinaryInsertionSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/BinaryInsertionSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class BinaryInsertionSorterTests { - public static class BinaryInsertionSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new BinaryInsertionSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new BinaryInsertionSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/BogoSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/BogoSorterTests.cs index 7a4ef202..536d5099 100644 --- a/Algorithms.Tests/Sorters/Comparison/BogoSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/BogoSorterTests.cs @@ -1,26 +1,25 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class BogoSorterTests { - public static class BogoSorterTests + [Test] + public static void ArraySorted([Random(0, 10, 10, Distinct = true)] int n) { - [Test] - public static void ArraySorted([Random(0, 10, 10, Distinct = true)] int n) - { - // Arrange - var sorter = new BogoSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new BogoSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/BubbleSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/BubbleSorterTests.cs index 44c949be..caee747d 100644 --- a/Algorithms.Tests/Sorters/Comparison/BubbleSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/BubbleSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class BubbleSorterTests { - public static class BubbleSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new BubbleSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new BubbleSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/CocktailSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/CocktailSorterTests.cs index b5974ef7..2a40c95b 100644 --- a/Algorithms.Tests/Sorters/Comparison/CocktailSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/CocktailSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class CocktailSorterTests { - public static class CocktailSorterTests + [Test] + public static void SortsArray( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void SortsArray( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new CocktailSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new CocktailSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray); - // Assert - Assert.AreEqual(correctArray, testArray); - } + // Assert + Assert.AreEqual(correctArray, testArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/CombSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/CombSorterTests.cs index e01e8689..4a365fe1 100644 --- a/Algorithms.Tests/Sorters/Comparison/CombSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/CombSorterTests.cs @@ -1,46 +1,45 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class CombSorterTests { - public static class CombSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new CombSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new CombSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); + } - [Test] - public static void ArraySorted_WithCustomShrinkFactor( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new CombSorter(1.5); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + [Test] + public static void ArraySorted_WithCustomShrinkFactor( + [Random(0, 1000, 100, Distinct = true)] + int n) + { + // Arrange + var sorter = new CombSorter(1.5); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/CycleSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/CycleSorterTests.cs index c5f2fa3c..055e607a 100644 --- a/Algorithms.Tests/Sorters/Comparison/CycleSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/CycleSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class CycleSorterTests { - public static class CycleSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new CycleSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new CycleSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray); - // Assert - Assert.AreEqual(correctArray, testArray); - } + // Assert + Assert.AreEqual(correctArray, testArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/ExchangeSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/ExchangeSorterTests.cs index c189b5d0..7237f5c0 100644 --- a/Algorithms.Tests/Sorters/Comparison/ExchangeSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/ExchangeSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class ExchangeSorterTests { - public static class ExchangeSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new ExchangeSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new ExchangeSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/HeapSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/HeapSorterTests.cs index 7181ff3f..d0c944cd 100644 --- a/Algorithms.Tests/Sorters/Comparison/HeapSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/HeapSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class HeapSorterTests { - public static class HeapSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new HeapSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new HeapSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray); - // Assert - Assert.AreEqual(correctArray, testArray); - } + // Assert + Assert.AreEqual(correctArray, testArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/InsertionSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/InsertionSorterTests.cs index cbb1ac97..280db9cb 100644 --- a/Algorithms.Tests/Sorters/Comparison/InsertionSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/InsertionSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class InsertionSorterTests { - public static class InsertionSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new InsertionSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new InsertionSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/MedianOfThreeQuickSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/MedianOfThreeQuickSorterTests.cs index e79ee2db..3ba9df04 100644 --- a/Algorithms.Tests/Sorters/Comparison/MedianOfThreeQuickSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/MedianOfThreeQuickSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class MedianOfThreeQuickSorterTests { - public static class MedianOfThreeQuickSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new MedianOfThreeQuickSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new MedianOfThreeQuickSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/MergeSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/MergeSorterTests.cs index bf483a27..6b7dbe5b 100644 --- a/Algorithms.Tests/Sorters/Comparison/MergeSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/MergeSorterTests.cs @@ -1,31 +1,30 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +/// +/// Class for testing merge sorter algorithm. +/// +public static class MergeSorterTests { - /// - /// Class for testing merge sorter algorithm. - /// - public static class MergeSorterTests + [Test] + public static void TestOnMergeSorter( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void TestOnMergeSorter( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new MergeSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new MergeSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray); - // Assert - Assert.AreEqual(correctArray, testArray); - } + // Assert + Assert.AreEqual(correctArray, testArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/MiddlePointQuickSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/MiddlePointQuickSorterTests.cs index 9abacfba..fc87a5b0 100644 --- a/Algorithms.Tests/Sorters/Comparison/MiddlePointQuickSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/MiddlePointQuickSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class MiddlePointQuickSorterTests { - public static class MiddlePointQuickSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new MiddlePointQuickSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new MiddlePointQuickSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/PancakeSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/PancakeSorterTests.cs index f25c19e3..f06fe1ae 100644 --- a/Algorithms.Tests/Sorters/Comparison/PancakeSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/PancakeSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class PancakeSorterTests { - public static class PancakeSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new PancakeSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new PancakeSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/RandomPivotQuickSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/RandomPivotQuickSorterTests.cs index a576a906..b634152a 100644 --- a/Algorithms.Tests/Sorters/Comparison/RandomPivotQuickSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/RandomPivotQuickSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class RandomPivotQuickSorterTests { - public static class RandomPivotQuickSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new RandomPivotQuickSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new RandomPivotQuickSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/SelectionSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/SelectionSorterTests.cs index 4c1ca503..6297889f 100644 --- a/Algorithms.Tests/Sorters/Comparison/SelectionSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/SelectionSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class SelectionSorterTests { - public static class SelectionSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new SelectionSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new SelectionSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/ShellSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/ShellSorterTests.cs index f290ae74..49c1632f 100644 --- a/Algorithms.Tests/Sorters/Comparison/ShellSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/ShellSorterTests.cs @@ -1,28 +1,27 @@ -using System; +using System; using Algorithms.Sorters.Comparison; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class ShellSorterTests { - public static class ShellSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new ShellSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new ShellSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, intComparer); - Array.Sort(correctArray, intComparer); + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs index 0015149d..c9b79caf 100755 --- a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs @@ -4,66 +4,65 @@ using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Comparison +namespace Algorithms.Tests.Sorters.Comparison; + +public static class TimSorterTests { - public static class TimSorterTests - { - private static readonly IntComparer IntComparer = new(); + private static readonly IntComparer IntComparer = new(); - [Test] - public static void ArraySorted( - [Random(0, 10_000, 2000)] int n) - { - // Arrange - var sorter = new TimSorter(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + [Test] + public static void ArraySorted( + [Random(0, 10_000, 2000)] int n) + { + // Arrange + var sorter = new TimSorter(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray, IntComparer); - Array.Sort(correctArray, IntComparer); + // Act + sorter.Sort(testArray, IntComparer); + Array.Sort(correctArray, IntComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); + } - [Test] - public static void TinyArray() - { - // Arrange - var sorter = new TimSorter(); - var tinyArray = new[] { 1 }; - var correctArray = new[] { 1 }; + [Test] + public static void TinyArray() + { + // Arrange + var sorter = new TimSorter(); + var tinyArray = new[] { 1 }; + var correctArray = new[] { 1 }; - // Act - sorter.Sort(tinyArray, IntComparer); + // Act + sorter.Sort(tinyArray, IntComparer); - // Assert - Assert.AreEqual(tinyArray, correctArray); - } + // Assert + Assert.AreEqual(tinyArray, correctArray); + } - [Test] - public static void SmallChunks() - { - // Arrange - var sorter = new TimSorter(); - var (correctArray, testArray) = RandomHelper.GetArrays(800); - Array.Sort(correctArray, IntComparer); - Array.Sort(testArray, IntComparer); + [Test] + public static void SmallChunks() + { + // Arrange + var sorter = new TimSorter(); + var (correctArray, testArray) = RandomHelper.GetArrays(800); + Array.Sort(correctArray, IntComparer); + Array.Sort(testArray, IntComparer); - var max = testArray.Max(); - var min = testArray.Min(); + var max = testArray.Max(); + var min = testArray.Min(); - correctArray[0] = max; - correctArray[800-1] = min; - testArray[0] = max; - testArray[800 - 1] = min; + correctArray[0] = max; + correctArray[800-1] = min; + testArray[0] = max; + testArray[800 - 1] = min; - // Act - sorter.Sort(testArray, IntComparer); - Array.Sort(correctArray, IntComparer); + // Act + sorter.Sort(testArray, IntComparer); + Array.Sort(correctArray, IntComparer); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Assert + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/External/ExternalMergeSorterTests.cs b/Algorithms.Tests/Sorters/External/ExternalMergeSorterTests.cs index e540f988..409bd2e6 100644 --- a/Algorithms.Tests/Sorters/External/ExternalMergeSorterTests.cs +++ b/Algorithms.Tests/Sorters/External/ExternalMergeSorterTests.cs @@ -1,67 +1,66 @@ -using System; +using System; using Algorithms.Sorters.External; using Algorithms.Sorters.External.Storages; using Algorithms.Tests.Helpers; using NUnit.Framework; using NUnit.Framework.Internal; -namespace Algorithms.Tests.Sorters.External +namespace Algorithms.Tests.Sorters.External; + +public static class ExternalMergeSorterTests { - public static class ExternalMergeSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new ExternalMergeSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); - var main = new IntInMemoryStorage(testArray); - var temp = new IntInMemoryStorage(new int[testArray.Length]); - - // Act - sorter.Sort(main, temp, intComparer); - Array.Sort(correctArray, intComparer); + // Arrange + var sorter = new ExternalMergeSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + var main = new IntInMemoryStorage(testArray); + var temp = new IntInMemoryStorage(new int[testArray.Length]); - // Assert - Assert.AreEqual(testArray, correctArray); - } + // Act + sorter.Sort(main, temp, intComparer); + Array.Sort(correctArray, intComparer); - [Test] - public static void ArraySorted_OnDisk( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new ExternalMergeSorter(); - var intComparer = new IntComparer(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); - var randomizer = Randomizer.CreateRandomizer(); - var main = new IntFileStorage($"sorted_{randomizer.GetString(100)}", n); - var temp = new IntFileStorage($"temp_{randomizer.GetString(100)}", n); + // Assert + Assert.AreEqual(testArray, correctArray); + } - var writer = main.GetWriter(); - for (var i = 0; i < n; i++) - { - writer.Write(correctArray[i]); - } + [Test] + public static void ArraySorted_OnDisk( + [Random(0, 1000, 100, Distinct = true)] + int n) + { + // Arrange + var sorter = new ExternalMergeSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + var randomizer = Randomizer.CreateRandomizer(); + var main = new IntFileStorage($"sorted_{randomizer.GetString(100)}", n); + var temp = new IntFileStorage($"temp_{randomizer.GetString(100)}", n); - writer.Dispose(); + var writer = main.GetWriter(); + for (var i = 0; i < n; i++) + { + writer.Write(correctArray[i]); + } - // Act - sorter.Sort(main, temp, intComparer); - Array.Sort(correctArray, intComparer); + writer.Dispose(); - // Assert - var reader = main.GetReader(); - for (var i = 0; i < n; i++) - { - testArray[i] = reader.Read(); - } + // Act + sorter.Sort(main, temp, intComparer); + Array.Sort(correctArray, intComparer); - Assert.AreEqual(testArray, correctArray); + // Assert + var reader = main.GetReader(); + for (var i = 0; i < n; i++) + { + testArray[i] = reader.Read(); } + + Assert.AreEqual(testArray, correctArray); } } diff --git a/Algorithms.Tests/Sorters/Integer/BucketSorterTests.cs b/Algorithms.Tests/Sorters/Integer/BucketSorterTests.cs index dbc014ff..31436da9 100644 --- a/Algorithms.Tests/Sorters/Integer/BucketSorterTests.cs +++ b/Algorithms.Tests/Sorters/Integer/BucketSorterTests.cs @@ -1,27 +1,26 @@ -using System; +using System; using Algorithms.Sorters.Integer; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Integer +namespace Algorithms.Tests.Sorters.Integer; + +public static class BucketSorterTests { - public static class BucketSorterTests + [Test] + public static void ArraySorted( + [Random(0, 1000, 1000, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(0, 1000, 1000, Distinct = true)] - int n) - { - // Arrange - var sorter = new BucketSorter(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new BucketSorter(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray); - Array.Sort(correctArray); + // Act + sorter.Sort(testArray); + Array.Sort(correctArray); - // Assert - Assert.AreEqual(correctArray, testArray); - } + // Assert + Assert.AreEqual(correctArray, testArray); } } diff --git a/Algorithms.Tests/Sorters/Integer/CountingSorterTests.cs b/Algorithms.Tests/Sorters/Integer/CountingSorterTests.cs index 30db4484..4ebe406a 100644 --- a/Algorithms.Tests/Sorters/Integer/CountingSorterTests.cs +++ b/Algorithms.Tests/Sorters/Integer/CountingSorterTests.cs @@ -3,32 +3,31 @@ using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Integer +namespace Algorithms.Tests.Sorters.Integer; + +public static class CountingSorterTests { - public static class CountingSorterTests + [Test] + public static void SortsNonEmptyArray( + [Random(1, 10000, 100, Distinct = true)] + int n) { - [Test] - public static void SortsNonEmptyArray( - [Random(1, 10000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new CountingSorter(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new CountingSorter(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray); - Array.Sort(correctArray); + // Act + sorter.Sort(testArray); + Array.Sort(correctArray); - // Assert - Assert.AreEqual(correctArray, testArray); - } + // Assert + Assert.AreEqual(correctArray, testArray); + } - [Test] - public static void SortsEmptyArray() - { - var sorter = new CountingSorter(); - sorter.Sort(Array.Empty()); - } + [Test] + public static void SortsEmptyArray() + { + var sorter = new CountingSorter(); + sorter.Sort(Array.Empty()); } } diff --git a/Algorithms.Tests/Sorters/Integer/RadixSorterTests.cs b/Algorithms.Tests/Sorters/Integer/RadixSorterTests.cs index 0f0c9098..838ebdbe 100644 --- a/Algorithms.Tests/Sorters/Integer/RadixSorterTests.cs +++ b/Algorithms.Tests/Sorters/Integer/RadixSorterTests.cs @@ -1,27 +1,26 @@ -using System; +using System; using Algorithms.Sorters.Integer; using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.Integer +namespace Algorithms.Tests.Sorters.Integer; + +public static class RadixSorterTests { - public static class RadixSorterTests + [Test] + public static void SortsArray( + [Random(0, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void SortsArray( - [Random(0, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new RadixSorter(); - var (correctArray, testArray) = RandomHelper.GetArrays(n); + // Arrange + var sorter = new RadixSorter(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); - // Act - sorter.Sort(testArray); - Array.Sort(correctArray); + // Act + sorter.Sort(testArray); + Array.Sort(correctArray); - // Assert - Assert.AreEqual(correctArray, testArray); - } + // Assert + Assert.AreEqual(correctArray, testArray); } } diff --git a/Algorithms.Tests/Sorters/String/MsdRadixStringSorterTests.cs b/Algorithms.Tests/Sorters/String/MsdRadixStringSorterTests.cs index 44a77d55..278029a1 100644 --- a/Algorithms.Tests/Sorters/String/MsdRadixStringSorterTests.cs +++ b/Algorithms.Tests/Sorters/String/MsdRadixStringSorterTests.cs @@ -3,28 +3,27 @@ using Algorithms.Tests.Helpers; using NUnit.Framework; -namespace Algorithms.Tests.Sorters.String +namespace Algorithms.Tests.Sorters.String; + +/// +/// Class for testing MSD radix sorter algorithm. +/// +public static class MsdRadixStringSorterTests { - /// - /// Class for testing MSD radix sorter algorithm. - /// - public static class MsdRadixStringSorterTests + [Test] + public static void ArraySorted( + [Random(2, 1000, 100, Distinct = true)] + int n) { - [Test] - public static void ArraySorted( - [Random(2, 1000, 100, Distinct = true)] - int n) - { - // Arrange - var sorter = new MsdRadixStringSorter(); - var (correctArray, testArray) = RandomHelper.GetStringArrays(n, 100, false); + // Arrange + var sorter = new MsdRadixStringSorter(); + var (correctArray, testArray) = RandomHelper.GetStringArrays(n, 100, false); - // Act - sorter.Sort(testArray); - Array.Sort(correctArray); + // Act + sorter.Sort(testArray); + Array.Sort(correctArray); - // Assert - Assert.AreEqual(correctArray, testArray); - } + // Assert + Assert.AreEqual(correctArray, testArray); } } diff --git a/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs b/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs index 4a92b9cd..6859f133 100644 --- a/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs +++ b/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs @@ -1,23 +1,22 @@ -using System; +using System; using Algorithms.Strings; using NUnit.Framework; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public static class GeneralStringAlgorithmsTests { - public static class GeneralStringAlgorithmsTests + [TestCase("Griffith", 'f', 2)] + [TestCase("Randomwoooord", 'o', 4)] + [TestCase("Control", 'C', 1)] + public static void MaxCountCharIsObtained(string text, char expectedSymbol, int expectedCount) { - [TestCase("Griffith", 'f', 2)] - [TestCase("Randomwoooord", 'o', 4)] - [TestCase("Control", 'C', 1)] - public static void MaxCountCharIsObtained(string text, char expectedSymbol, int expectedCount) - { - // Arrange - // Act - var (symbol, count) = GeneralStringAlgorithms.FindLongestConsecutiveCharacters(text); + // Arrange + // Act + var (symbol, count) = GeneralStringAlgorithms.FindLongestConsecutiveCharacters(text); - // Assert - Assert.AreEqual(expectedSymbol, symbol); - Assert.AreEqual(expectedCount, count); - } + // Assert + Assert.AreEqual(expectedSymbol, symbol); + Assert.AreEqual(expectedCount, count); } } diff --git a/Algorithms.Tests/Strings/PalindromeTests.cs b/Algorithms.Tests/Strings/PalindromeTests.cs index 98c62692..bcb91629 100644 --- a/Algorithms.Tests/Strings/PalindromeTests.cs +++ b/Algorithms.Tests/Strings/PalindromeTests.cs @@ -1,32 +1,31 @@ -using Algorithms.Strings; +using Algorithms.Strings; using NUnit.Framework; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public static class PalindromeTests { - public static class PalindromeTests + [TestCase("Anna")] + [TestCase("A Santa at Nasa")] + public static void TextIsPalindrome_TrueExpected(string text) { - [TestCase("Anna")] - [TestCase("A Santa at Nasa")] - public static void TextIsPalindrome_TrueExpected(string text) - { - // Arrange - // Act - var isPalindrome = Palindrome.IsStringPalindrome(text); + // Arrange + // Act + var isPalindrome = Palindrome.IsStringPalindrome(text); - // Assert - Assert.True(isPalindrome); - } + // Assert + Assert.True(isPalindrome); + } - [TestCase("hallo")] - [TestCase("Once upon a time")] - public static void TextNotPalindrome_FalseExpected(string text) - { - // Arrange - // Act - var isPalindrome = Palindrome.IsStringPalindrome(text); + [TestCase("hallo")] + [TestCase("Once upon a time")] + public static void TextNotPalindrome_FalseExpected(string text) + { + // Arrange + // Act + var isPalindrome = Palindrome.IsStringPalindrome(text); - // Assert - Assert.False(isPalindrome); - } + // Assert + Assert.False(isPalindrome); } } diff --git a/Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs b/Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs index 09247560..be752221 100644 --- a/Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs @@ -2,18 +2,17 @@ using Algorithms.Strings.PatternMatching; using NUnit.Framework; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public class BoyerMooreTests { - public class BoyerMooreTests + [TestCase("HelloImATestcaseAndIWillPass", "Testcase", 8)] + [TestCase("HelloImATestcaseAndImCaseSensitive", "TestCase", -1)] + [TestCase("Hello Im a testcase and I work with whitespaces", "testcase", 11)] + [TestCase("Hello Im a testcase and I work with numbers like 1 2 3 4", "testcase", 11)] + public void FindFirstOccurrence_IndexCheck(string t, string p, int expectedIndex) { - [TestCase("HelloImATestcaseAndIWillPass", "Testcase", 8)] - [TestCase("HelloImATestcaseAndImCaseSensitive", "TestCase", -1)] - [TestCase("Hello Im a testcase and I work with whitespaces", "testcase", 11)] - [TestCase("Hello Im a testcase and I work with numbers like 1 2 3 4", "testcase", 11)] - public void FindFirstOccurrence_IndexCheck(string t, string p, int expectedIndex) - { - var resultIndex = BoyerMoore.FindFirstOccurrence(t, p); - Assert.AreEqual(resultIndex, expectedIndex); - } + var resultIndex = BoyerMoore.FindFirstOccurrence(t, p); + Assert.AreEqual(resultIndex, expectedIndex); } } diff --git a/Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs b/Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs index e8744b8a..96b63eb7 100644 --- a/Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs @@ -1,85 +1,84 @@ -using Algorithms.Strings; +using Algorithms.Strings; using Algorithms.Strings.PatternMatching; using NUnit.Framework; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public static class KnuthMorrisPrattSearcherTests { - public static class KnuthMorrisPrattSearcherTests + [Test] + public static void FindIndexes_ItemsPresent_PassExpected() + { + // Arrange + var searcher = new KnuthMorrisPrattSearcher(); + var str = "ABABAcdeABA"; + var pat = "ABA"; + + // Act + var expectedItem = new[] { 0, 2, 8 }; + var actualItem = searcher.FindIndexes(str, pat); + + // Assert + CollectionAssert.AreEqual(expectedItem, actualItem); + } + + [Test] + public static void FindIndexes_ItemsMissing_NoIndexesReturned() { - [Test] - public static void FindIndexes_ItemsPresent_PassExpected() - { - // Arrange - var searcher = new KnuthMorrisPrattSearcher(); - var str = "ABABAcdeABA"; - var pat = "ABA"; - - // Act - var expectedItem = new[] { 0, 2, 8 }; - var actualItem = searcher.FindIndexes(str, pat); - - // Assert - CollectionAssert.AreEqual(expectedItem, actualItem); - } - - [Test] - public static void FindIndexes_ItemsMissing_NoIndexesReturned() - { - // Arrange - var searcher = new KnuthMorrisPrattSearcher(); - var str = "ABABA"; - var pat = "ABB"; - - // Act & Assert - var indexes = searcher.FindIndexes(str, pat); - - // Assert - Assert.IsEmpty(indexes); - } - - [Test] - public static void LongestPrefixSuffixArray_PrefixSuffixOfLength1_PassExpected() - { - // Arrange - var searcher = new KnuthMorrisPrattSearcher(); - var s = "ABA"; - - // Act - var expectedItem = new[] { 0, 0, 1 }; - var actualItem = searcher.FindLongestPrefixSuffixValues(s); - - // Assert - CollectionAssert.AreEqual(expectedItem, actualItem); - } - - [Test] - public static void LongestPrefixSuffixArray_PrefixSuffixOfLength5_PassExpected() - { - // Arrange - var searcher = new KnuthMorrisPrattSearcher(); - var s = "AABAACAABAA"; - - // Act - var expectedItem = new[] { 0, 1, 0, 1, 2, 0, 1, 2, 3, 4, 5 }; - var actualItem = searcher.FindLongestPrefixSuffixValues(s); - - // Assert - CollectionAssert.AreEqual(expectedItem, actualItem); - } - - [Test] - public static void LongestPrefixSuffixArray_PrefixSuffixOfLength0_PassExpected() - { - // Arrange - var searcher = new KnuthMorrisPrattSearcher(); - var s = "AB"; - - // Act - var expectedItem = new[] { 0, 0 }; - var actualItem = searcher.FindLongestPrefixSuffixValues(s); - - // Assert - CollectionAssert.AreEqual(expectedItem, actualItem); - } + // Arrange + var searcher = new KnuthMorrisPrattSearcher(); + var str = "ABABA"; + var pat = "ABB"; + + // Act & Assert + var indexes = searcher.FindIndexes(str, pat); + + // Assert + Assert.IsEmpty(indexes); + } + + [Test] + public static void LongestPrefixSuffixArray_PrefixSuffixOfLength1_PassExpected() + { + // Arrange + var searcher = new KnuthMorrisPrattSearcher(); + var s = "ABA"; + + // Act + var expectedItem = new[] { 0, 0, 1 }; + var actualItem = searcher.FindLongestPrefixSuffixValues(s); + + // Assert + CollectionAssert.AreEqual(expectedItem, actualItem); + } + + [Test] + public static void LongestPrefixSuffixArray_PrefixSuffixOfLength5_PassExpected() + { + // Arrange + var searcher = new KnuthMorrisPrattSearcher(); + var s = "AABAACAABAA"; + + // Act + var expectedItem = new[] { 0, 1, 0, 1, 2, 0, 1, 2, 3, 4, 5 }; + var actualItem = searcher.FindLongestPrefixSuffixValues(s); + + // Assert + CollectionAssert.AreEqual(expectedItem, actualItem); + } + + [Test] + public static void LongestPrefixSuffixArray_PrefixSuffixOfLength0_PassExpected() + { + // Arrange + var searcher = new KnuthMorrisPrattSearcher(); + var s = "AB"; + + // Act + var expectedItem = new[] { 0, 0 }; + var actualItem = searcher.FindLongestPrefixSuffixValues(s); + + // Assert + CollectionAssert.AreEqual(expectedItem, actualItem); } } diff --git a/Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs b/Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs index abeb0912..f2624c12 100644 --- a/Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs @@ -3,56 +3,55 @@ using Algorithms.Strings.PatternMatching; using NUnit.Framework; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public static class NaiveStringSearchTests { - public static class NaiveStringSearchTests + [Test] + public static void ThreeMatchesFound_PassExpected() { - [Test] - public static void ThreeMatchesFound_PassExpected() - { - // Arrange - var pattern = "ABB"; - var content = "ABBBAAABBAABBBBAB"; - - // Act - var expectedOccurrences = new[] { 0, 6, 10 }; - var actualOccurrences = NaiveStringSearch.NaiveSearch(content, pattern); - var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences); - - // Assert - Assert.IsTrue(sequencesAreEqual); - } - - [Test] - public static void OneMatchFound_PassExpected() - { - // Arrange - var pattern = "BAAB"; - var content = "ABBBAAABBAABBBBAB"; - - // Act - var expectedOccurrences = new[] { 8 }; - var actualOccurrences = NaiveStringSearch.NaiveSearch(content, pattern); - var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences); - - // Assert - Assert.IsTrue(sequencesAreEqual); - } - - [Test] - public static void NoMatchFound_PassExpected() - { - // Arrange - var pattern = "XYZ"; - var content = "ABBBAAABBAABBBBAB"; - - // Act - var expectedOccurrences = new int[0]; - var actualOccurrences = NaiveStringSearch.NaiveSearch(content, pattern); - var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences); - - // Assert - Assert.IsTrue(sequencesAreEqual); - } + // Arrange + var pattern = "ABB"; + var content = "ABBBAAABBAABBBBAB"; + + // Act + var expectedOccurrences = new[] { 0, 6, 10 }; + var actualOccurrences = NaiveStringSearch.NaiveSearch(content, pattern); + var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences); + + // Assert + Assert.IsTrue(sequencesAreEqual); + } + + [Test] + public static void OneMatchFound_PassExpected() + { + // Arrange + var pattern = "BAAB"; + var content = "ABBBAAABBAABBBBAB"; + + // Act + var expectedOccurrences = new[] { 8 }; + var actualOccurrences = NaiveStringSearch.NaiveSearch(content, pattern); + var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences); + + // Assert + Assert.IsTrue(sequencesAreEqual); + } + + [Test] + public static void NoMatchFound_PassExpected() + { + // Arrange + var pattern = "XYZ"; + var content = "ABBBAAABBAABBBBAB"; + + // Act + var expectedOccurrences = new int[0]; + var actualOccurrences = NaiveStringSearch.NaiveSearch(content, pattern); + var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences); + + // Assert + Assert.IsTrue(sequencesAreEqual); } } diff --git a/Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs b/Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs index 7c9fe7fe..7a2ee029 100644 --- a/Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs @@ -3,19 +3,18 @@ using Algorithms.Strings.PatternMatching; using NUnit.Framework; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public class RabinKarpTest { - public class RabinKarpTest + [TestCase("HelloImATestcaseAndIWillPass", "Testcase", new[] { 8 })] + [TestCase("HelloImATestcaseAndImCaseSensitive", "TestCase", new int[] { })] + [TestCase("Hello Im a testcase and you can use whitespaces", "testcase", new[] { 11 })] + [TestCase("Hello Im a testcase and you can use numbers like 1, 2, 3, etcetera", "etcetera", new[] { 58 })] + [TestCase("HelloImATestcaseAndIHaveTwoOccurrencesOfTestcase", "Testcase", new[] { 8, 40 })] + public void FindAllOccurrences_IndexCheck(string t, string p, int[] expectedIndices) { - [TestCase("HelloImATestcaseAndIWillPass", "Testcase", new[] { 8 })] - [TestCase("HelloImATestcaseAndImCaseSensitive", "TestCase", new int[] { })] - [TestCase("Hello Im a testcase and you can use whitespaces", "testcase", new[] { 11 })] - [TestCase("Hello Im a testcase and you can use numbers like 1, 2, 3, etcetera", "etcetera", new[] { 58 })] - [TestCase("HelloImATestcaseAndIHaveTwoOccurrencesOfTestcase", "Testcase", new[] { 8, 40 })] - public void FindAllOccurrences_IndexCheck(string t, string p, int[] expectedIndices) - { - List result = RabinKarp.FindAllOccurrences(t, p); - Assert.AreEqual(result, new List(expectedIndices)); - } + List result = RabinKarp.FindAllOccurrences(t, p); + Assert.AreEqual(result, new List(expectedIndices)); } } diff --git a/Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs b/Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs index de9cdf1f..8ff7dd4b 100644 --- a/Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs +++ b/Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs @@ -2,23 +2,22 @@ using Algorithms.Strings.PatternMatching; using NUnit.Framework; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public class ZblockSubstringSearchTest { - public class ZblockSubstringSearchTest + [TestCase("abc", "abcdef", 1)] + [TestCase("xxx", "abxxxcdexxxf", 2)] + [TestCase("aa", "waapaaxcdaalaabb", 4)] + [TestCase("ABC", "ABAAABCDBBABCDDEBCABC", 3)] + [TestCase("xxx", "abcdefghij", 0)] + [TestCase("aab", "caabxaaaz", 1)] + [TestCase("abc", "xababaxbabcdabx", 1)] + [TestCase("GEEK", "GEEKS FOR GEEKS", 2)] + [TestCase("ground", "Hello, playground!", 1)] + public void Test(string pattern, string text, int expectedOccurences) { - [TestCase("abc", "abcdef", 1)] - [TestCase("xxx", "abxxxcdexxxf", 2)] - [TestCase("aa", "waapaaxcdaalaabb", 4)] - [TestCase("ABC", "ABAAABCDBBABCDDEBCABC", 3)] - [TestCase("xxx", "abcdefghij", 0)] - [TestCase("aab", "caabxaaaz", 1)] - [TestCase("abc", "xababaxbabcdabx", 1)] - [TestCase("GEEK", "GEEKS FOR GEEKS", 2)] - [TestCase("ground", "Hello, playground!", 1)] - public void Test(string pattern, string text, int expectedOccurences) - { - var occurencesFound = ZblockSubstringSearch.FindSubstring(pattern, text); - Assert.AreEqual(expectedOccurences, occurencesFound); - } + var occurencesFound = ZblockSubstringSearch.FindSubstring(pattern, text); + Assert.AreEqual(expectedOccurences, occurencesFound); } } diff --git a/Algorithms.Tests/Strings/PermutationTests.cs b/Algorithms.Tests/Strings/PermutationTests.cs index 189d602f..b4be153a 100644 --- a/Algorithms.Tests/Strings/PermutationTests.cs +++ b/Algorithms.Tests/Strings/PermutationTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Numerics; @@ -6,70 +6,69 @@ using Algorithms.Strings; using NUnit.Framework; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public class PermutationTests { - public class PermutationTests + [TestCase("")] + [TestCase("A")] + [TestCase("abcd")] + [TestCase("aabcd")] + [TestCase("aabbbcd")] + [TestCase("aabbccccd")] + public void Test_GetEveryUniquePermutation(string word) { - [TestCase("")] - [TestCase("A")] - [TestCase("abcd")] - [TestCase("aabcd")] - [TestCase("aabbbcd")] - [TestCase("aabbccccd")] - public void Test_GetEveryUniquePermutation(string word) - { - var permutations = Permutation.GetEveryUniquePermutation(word); + var permutations = Permutation.GetEveryUniquePermutation(word); - // We need to make sure that - // 1. We have the right number of permutations - // 2. Every string in permutations List is a permutation of word - // 3. There are no repetitions + // We need to make sure that + // 1. We have the right number of permutations + // 2. Every string in permutations List is a permutation of word + // 3. There are no repetitions - // Start 1. - // The number of unique permutations is - // n!/(A1! * A2! * ... An!) - // where n is the length of word and Ai is the number of occurrences if ith char in the string - var charOccurrence = new Dictionary(); - foreach (var c in word) + // Start 1. + // The number of unique permutations is + // n!/(A1! * A2! * ... An!) + // where n is the length of word and Ai is the number of occurrences if ith char in the string + var charOccurrence = new Dictionary(); + foreach (var c in word) + { + if (charOccurrence.ContainsKey(c)) { - if (charOccurrence.ContainsKey(c)) - { - charOccurrence[c] += 1; - } - else - { - charOccurrence[c] = 1; - } + charOccurrence[c] += 1; } - // now we know the values of A1, A2, ..., An - // evaluate the above formula - var expectedNumberOfAnagrams = Factorial.Calculate(word.Length); - expectedNumberOfAnagrams = charOccurrence.Aggregate(expectedNumberOfAnagrams, (current, keyValuePair) => + else { - return current / Factorial.Calculate(keyValuePair.Value); - }); - Assert.AreEqual(expectedNumberOfAnagrams, new BigInteger(permutations.Count)); - // End 1. - - // Start 2 - // string A is a permutation of string B if and only if sorted(A) == sorted(b) - var wordSorted = SortString(word); - foreach (var permutation in permutations) - { - Assert.AreEqual(wordSorted, SortString(permutation)); + charOccurrence[c] = 1; } - // End 2 - - // Start 3 - Assert.AreEqual(permutations.Count, new HashSet(permutations).Count); - // End 3 } + // now we know the values of A1, A2, ..., An + // evaluate the above formula + var expectedNumberOfAnagrams = Factorial.Calculate(word.Length); + expectedNumberOfAnagrams = charOccurrence.Aggregate(expectedNumberOfAnagrams, (current, keyValuePair) => + { + return current / Factorial.Calculate(keyValuePair.Value); + }); + Assert.AreEqual(expectedNumberOfAnagrams, new BigInteger(permutations.Count)); + // End 1. - private static string SortString(string word) + // Start 2 + // string A is a permutation of string B if and only if sorted(A) == sorted(b) + var wordSorted = SortString(word); + foreach (var permutation in permutations) { - var asArray = word.ToArray(); - Array.Sort(asArray); - return new string(asArray); + Assert.AreEqual(wordSorted, SortString(permutation)); } + // End 2 + + // Start 3 + Assert.AreEqual(permutations.Count, new HashSet(permutations).Count); + // End 3 + } + + private static string SortString(string word) + { + var asArray = word.ToArray(); + Array.Sort(asArray); + return new string(asArray); } } diff --git a/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs b/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs index addf80f2..d2fe0b78 100644 --- a/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs +++ b/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs @@ -3,23 +3,22 @@ using System; using Algorithms.Strings.Similarity; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public class HammingDistanceTests { - public class HammingDistanceTests + [TestCase("equal", "equal", 0)] + [TestCase("dog", "dig", 1)] + [TestCase("12345", "abcde", 5)] + public void Calculate_ReturnsCorrectHammingDistance(string s1, string s2, int expectedDistance) { - [TestCase("equal", "equal", 0)] - [TestCase("dog", "dig", 1)] - [TestCase("12345", "abcde", 5)] - public void Calculate_ReturnsCorrectHammingDistance(string s1, string s2, int expectedDistance) - { - var result = HammingDistance.Calculate(s1, s2); - Assert.AreEqual(expectedDistance, result); - } + var result = HammingDistance.Calculate(s1, s2); + Assert.AreEqual(expectedDistance, result); + } - [Test] - public void Calculate_ThrowsArgumentExceptionWhenStringLengthsDiffer() - { - Assert.Throws(() => HammingDistance.Calculate("123", "12345")); - } + [Test] + public void Calculate_ThrowsArgumentExceptionWhenStringLengthsDiffer() + { + Assert.Throws(() => HammingDistance.Calculate("123", "12345")); } } diff --git a/Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs b/Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs index c786aff1..0329be44 100644 --- a/Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs +++ b/Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs @@ -3,20 +3,19 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public class JaroSimilarityTests { - public class JaroSimilarityTests + [TestCase("equal", "equal", 1)] + [TestCase("abc", "123", 0)] + [TestCase("FAREMVIEL", "FARMVILLE", 0.88d)] + [TestCase("CRATE", "TRACE", 0.73d)] + [TestCase("CRATE11111", "CRTAE11111", 0.96d)] + [TestCase("a", "a", 1)] + [TestCase("", "", 1)] + public void Calculate_ReturnsCorrectJaroSimilarity(string s1, string s2, double expected) { - [TestCase("equal", "equal", 1)] - [TestCase("abc", "123", 0)] - [TestCase("FAREMVIEL", "FARMVILLE", 0.88d)] - [TestCase("CRATE", "TRACE", 0.73d)] - [TestCase("CRATE11111", "CRTAE11111", 0.96d)] - [TestCase("a", "a", 1)] - [TestCase("", "", 1)] - public void Calculate_ReturnsCorrectJaroSimilarity(string s1, string s2, double expected) - { - JaroSimilarity.Calculate(s1, s2).Should().BeApproximately(expected, 0.01); - } + JaroSimilarity.Calculate(s1, s2).Should().BeApproximately(expected, 0.01); } } diff --git a/Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs b/Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs index 37a0af93..5f9c1cab 100644 --- a/Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs +++ b/Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs @@ -3,18 +3,17 @@ using FluentAssertions; using NUnit.Framework; -namespace Algorithms.Tests.Strings +namespace Algorithms.Tests.Strings; + +public class JaroWinklerDistanceTests { - public class JaroWinklerDistanceTests + [TestCase("equal", "equal", 0)] + [TestCase("abc", "123", 1)] + [TestCase("Winkler", "Welfare", 0.33)] + [TestCase("faremviel", "farmville", 0.08)] + [TestCase("", "", 0)] + public void Calculate_ReturnsCorrectJaroWinklerDistance(string s1, string s2, double expected) { - [TestCase("equal", "equal", 0)] - [TestCase("abc", "123", 1)] - [TestCase("Winkler", "Welfare", 0.33)] - [TestCase("faremviel", "farmville", 0.08)] - [TestCase("", "", 0)] - public void Calculate_ReturnsCorrectJaroWinklerDistance(string s1, string s2, double expected) - { - JaroWinklerDistance.Calculate(s1, s2).Should().BeApproximately(expected, 0.01); - } + JaroWinklerDistance.Calculate(s1, s2).Should().BeApproximately(expected, 0.01); } } From cd7d7fb741e44c7f497dc1e24ef1f15e70a34fde Mon Sep 17 00:00:00 2001 From: Suresh <124827411+SureshRepos@users.noreply.github.com> Date: Fri, 2 Feb 2024 16:50:14 -0500 Subject: [PATCH 092/138] Update coverlet.collector to 6.0.0 (#444) --- Algorithms.Tests/Algorithms.Tests.csproj | 2 +- DataStructures.Tests/DataStructures.Tests.csproj | 2 +- Utilities.Tests/Utilities.Tests.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Algorithms.Tests/Algorithms.Tests.csproj b/Algorithms.Tests/Algorithms.Tests.csproj index 05714b3a..88b52fb0 100644 --- a/Algorithms.Tests/Algorithms.Tests.csproj +++ b/Algorithms.Tests/Algorithms.Tests.csproj @@ -14,7 +14,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/DataStructures.Tests/DataStructures.Tests.csproj b/DataStructures.Tests/DataStructures.Tests.csproj index e4ad4d0c..23494993 100644 --- a/DataStructures.Tests/DataStructures.Tests.csproj +++ b/DataStructures.Tests/DataStructures.Tests.csproj @@ -14,7 +14,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Utilities.Tests/Utilities.Tests.csproj b/Utilities.Tests/Utilities.Tests.csproj index bb7f17db..ae947744 100644 --- a/Utilities.Tests/Utilities.Tests.csproj +++ b/Utilities.Tests/Utilities.Tests.csproj @@ -13,7 +13,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 4f10a49cdd3757fcd9a87aa493a232636f995cec Mon Sep 17 00:00:00 2001 From: Suresh <124827411+SureshRepos@users.noreply.github.com> Date: Mon, 5 Feb 2024 05:30:30 -0500 Subject: [PATCH 093/138] Update FluentAssertions to 6.12.0 (#446) --- Algorithms.Tests/Algorithms.Tests.csproj | 2 +- Algorithms.Tests/Graph/FloydWarshallTests.cs | 3 +-- .../BranchAndBoundKnapsackSolverTests.cs | 26 +++++++++---------- .../DataStructures.Tests.csproj | 2 +- .../Extensions/DictionaryExtensionsTests.cs | 6 ++--- Utilities.Tests/Utilities.Tests.csproj | 2 +- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Algorithms.Tests/Algorithms.Tests.csproj b/Algorithms.Tests/Algorithms.Tests.csproj index 88b52fb0..352bceb5 100644 --- a/Algorithms.Tests/Algorithms.Tests.csproj +++ b/Algorithms.Tests/Algorithms.Tests.csproj @@ -18,7 +18,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/Algorithms.Tests/Graph/FloydWarshallTests.cs b/Algorithms.Tests/Graph/FloydWarshallTests.cs index 7e391954..1440cd0f 100644 --- a/Algorithms.Tests/Graph/FloydWarshallTests.cs +++ b/Algorithms.Tests/Graph/FloydWarshallTests.cs @@ -50,7 +50,6 @@ public void CorrectMatrixTest() }; var floydWarshaller = new FloydWarshall(); - - floydWarshaller.Run(graph).Should().Equal(actualDistances); + floydWarshaller.Run(graph).Should().BeEquivalentTo(actualDistances); } } diff --git a/Algorithms.Tests/Knapsack/BranchAndBoundKnapsackSolverTests.cs b/Algorithms.Tests/Knapsack/BranchAndBoundKnapsackSolverTests.cs index c50ef1bf..a4159984 100644 --- a/Algorithms.Tests/Knapsack/BranchAndBoundKnapsackSolverTests.cs +++ b/Algorithms.Tests/Knapsack/BranchAndBoundKnapsackSolverTests.cs @@ -11,9 +11,9 @@ public static class BranchAndBoundKnapsackSolverTests public static void BranchAndBoundTest_Example1_Success() { // Arrange - var items = new[] {'A', 'B', 'C', 'D'}; - var values = new[] {18, 20, 14, 18}; - var weights = new[] {2, 4, 6, 9}; + var items = new[] { 'A', 'B', 'C', 'D' }; + var values = new[] { 18, 20, 14, 18 }; + var weights = new[] { 2, 4, 6, 9 }; var capacity = 15; @@ -25,16 +25,16 @@ public static void BranchAndBoundTest_Example1_Success() var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); // Assert - actualResult.Should().BeEquivalentTo('A', 'B', 'D'); + actualResult.Should().BeEquivalentTo(new[] { 'A', 'B', 'D' }); } [Test] public static void BranchAndBoundTest_Example2_Success() { // Arrange - var items = new[] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; + var items = new[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' }; var values = new[] { 505, 352, 458, 220, 354, 414, 498, 545, 473, 543 }; - var weights = new[] {23, 26, 20, 18, 32, 27, 29, 26, 30, 27}; + var weights = new[] { 23, 26, 20, 18, 32, 27, 29, 26, 30, 27 }; var capacity = 67; @@ -46,16 +46,16 @@ public static void BranchAndBoundTest_Example2_Success() var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector); // Assert - actualResult.Should().BeEquivalentTo('H', 'D', 'A'); + actualResult.Should().BeEquivalentTo(new[] { 'H', 'D', 'A' }); } [Test] public static void BranchAndBoundTest_CapacityIsZero_NothingTaken() { // Arrange - var items = new[] {'A', 'B', 'C', 'D'}; - var values = new[] {18, 20, 14, 18}; - var weights = new[] {2, 4, 6, 9}; + var items = new[] { 'A', 'B', 'C', 'D' }; + var values = new[] { 18, 20, 14, 18 }; + var weights = new[] { 2, 4, 6, 9 }; var capacity = 0; @@ -74,9 +74,9 @@ public static void BranchAndBoundTest_CapacityIsZero_NothingTaken() public static void BranchAndBoundTest_PlentyCapacity_EverythingIsTaken() { // Arrange - var items = new[] {'A', 'B', 'C', 'D'}; - var values = new[] {18, 20, 14, 18}; - var weights = new[] {2, 4, 6, 9}; + var items = new[] { 'A', 'B', 'C', 'D' }; + var values = new[] { 18, 20, 14, 18 }; + var weights = new[] { 2, 4, 6, 9 }; var capacity = 1000; diff --git a/DataStructures.Tests/DataStructures.Tests.csproj b/DataStructures.Tests/DataStructures.Tests.csproj index 23494993..2b6e9636 100644 --- a/DataStructures.Tests/DataStructures.Tests.csproj +++ b/DataStructures.Tests/DataStructures.Tests.csproj @@ -18,7 +18,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs b/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs index 059c454b..9f309832 100644 --- a/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs +++ b/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs @@ -29,8 +29,8 @@ public void AddMany_ShouldAddAllKeyValuePairs() dictionary.Should().HaveCount(3); - dictionary.Should().ContainKey("one").WhichValue.Should().Be(1); - dictionary.Should().ContainKey("two").WhichValue.Should().Be(2); - dictionary.Should().ContainKey("three").WhichValue.Should().Be(3); + dictionary.Should().ContainKey("one").WhoseValue.Should().Be(1); + dictionary.Should().ContainKey("two").WhoseValue.Should().Be(2); + dictionary.Should().ContainKey("three").WhoseValue.Should().Be(3); } } diff --git a/Utilities.Tests/Utilities.Tests.csproj b/Utilities.Tests/Utilities.Tests.csproj index ae947744..50111924 100644 --- a/Utilities.Tests/Utilities.Tests.csproj +++ b/Utilities.Tests/Utilities.Tests.csproj @@ -17,7 +17,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + From c7f0d62fd7f90e23b4f40316e7540c13a43312cd Mon Sep 17 00:00:00 2001 From: Suresh <124827411+SureshRepos@users.noreply.github.com> Date: Mon, 5 Feb 2024 17:46:56 -0500 Subject: [PATCH 094/138] Update Microsoft.NET.Test.Sdk to 17.8.0 (#447) --- Algorithms.Tests/Algorithms.Tests.csproj | 2 +- DataStructures.Tests/DataStructures.Tests.csproj | 2 +- Utilities.Tests/Utilities.Tests.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Algorithms.Tests/Algorithms.Tests.csproj b/Algorithms.Tests/Algorithms.Tests.csproj index 352bceb5..fd46da23 100644 --- a/Algorithms.Tests/Algorithms.Tests.csproj +++ b/Algorithms.Tests/Algorithms.Tests.csproj @@ -19,7 +19,7 @@ all - + diff --git a/DataStructures.Tests/DataStructures.Tests.csproj b/DataStructures.Tests/DataStructures.Tests.csproj index 2b6e9636..59e783c3 100644 --- a/DataStructures.Tests/DataStructures.Tests.csproj +++ b/DataStructures.Tests/DataStructures.Tests.csproj @@ -19,7 +19,7 @@ all - + diff --git a/Utilities.Tests/Utilities.Tests.csproj b/Utilities.Tests/Utilities.Tests.csproj index 50111924..97429e11 100644 --- a/Utilities.Tests/Utilities.Tests.csproj +++ b/Utilities.Tests/Utilities.Tests.csproj @@ -20,7 +20,7 @@ - + From c9e2fa1878e4037c54f6ebe5a83fddea0110eed7 Mon Sep 17 00:00:00 2001 From: Marcos Simoneli Souza <65091092+MarcosSimoneli@users.noreply.github.com> Date: Sun, 11 Feb 2024 05:12:46 -0300 Subject: [PATCH 095/138] Update NUnit to 4.0.1 (fixes #442) (#443) --- Algorithms.Tests/Algorithms.Tests.csproj | 4 +- .../BurrowsWheelerTransformTests.cs | 8 +- .../Compressors/HuffmanCompressorTests.cs | 6 +- .../Compressors/ShannonFanoCompressorTests.cs | 6 +- .../Compressors/TranslatorTests.cs | 2 +- .../Encoders/CaesarEncoderTests.cs | 2 +- .../Encoders/FeistelCipherTest.cs | 2 +- .../Encoders/HillEnconderTests.cs | 2 +- .../Encoders/NysiisEncoderTests.cs | 2 +- .../Encoders/SoundexEncoderTest.cs | 2 +- .../Encoders/VigenereEncoderTests.cs | 4 +- .../Graph/BreadthFirstSearchTests.cs | 8 +- .../Graph/BreadthFirstTreeTraversalTests.cs | 17 +- .../Graph/DepthFirstSearchTests.cs | 8 +- .../DynamicProgrammingKnapsackSolverTests.cs | 8 +- .../Knapsack/NaiveKnapsackSolverTests.cs | 2 +- .../ChineseRemainderTheoremTest.cs | 12 +- .../ExtendedEuclideanAlgorithmTest.cs | 12 +- .../ModularMultiplicativeInverseTest.cs | 4 +- .../Numeric/AmicableNumbersTest.cs | 2 +- .../Numeric/BinomialCoefficientTests.cs | 2 +- .../Numeric/Decomposition/LUTests.cs | 24 +-- .../Numeric/Decomposition/MaclaurinTests.cs | 12 +- .../Numeric/Decomposition/SVDTests.cs | 6 +- Algorithms.Tests/Numeric/EulerMethodTest.cs | 4 +- Algorithms.Tests/Numeric/FactorialTests.cs | 2 +- .../TrialDivisionFactorizerTests.cs | 6 +- .../Numeric/GaussJordanEliminationTests.cs | 2 +- .../BinaryGreatestCommonDivisorFinderTests.cs | 2 +- ...clideanGreatestCommonDivisorFinderTests.cs | 2 +- Algorithms.Tests/Numeric/KeithNumberTest.cs | 2 +- .../KrishnamurthyNumberCheckerTests.cs | 12 +- Algorithms.Tests/Numeric/PerfectNumberTest.cs | 2 +- .../PseudoInverse/PseudoInverseTests.cs | 4 +- .../Other/DecisionsConvolutionsTest.cs | 4 +- .../Other/FermatPrimeCheckerTests.cs | 2 +- .../Other/GaussOptimizationTest.cs | 8 +- Algorithms.Tests/Other/GeoLocationTests.cs | 2 +- Algorithms.Tests/Other/Int2BinaryTests.cs | 6 +- Algorithms.Tests/Other/JulianEasterTests.cs | 15 +- Algorithms.Tests/Other/LuhnTests.cs | 6 +- Algorithms.Tests/Other/MandelbrotTest.cs | 8 +- .../Other/ParetoOptimizationTests.cs | 2 +- .../Other/PollardsRhoFactorizingTests.cs | 2 +- .../Other/SieveOfEratosthenesTests.cs | 6 +- .../Other/WelfordsVarianceTest.cs | 104 +++++------ .../LevenshteinDistanceTests.cs | 2 +- .../StableMarriage/GaleShapleyTests.cs | 8 +- .../Search/BinarySearcherTests.cs | 6 +- Algorithms.Tests/Search/BoyerMooreTests.cs | 2 +- Algorithms.Tests/Search/FastSearcherTests.cs | 6 +- .../Search/InterpolationSearchTests.cs | 6 +- Algorithms.Tests/Search/JumpSearcherTests.cs | 4 +- .../Search/LinearSearcherTests.cs | 6 +- .../Search/RecursiveBinarySearcherTests.cs | 6 +- .../Comparison/BinaryInsertionSorterTests.cs | 2 +- .../Sorters/Comparison/BogoSorterTests.cs | 2 +- .../Sorters/Comparison/BubbleSorterTests.cs | 2 +- .../Sorters/Comparison/CocktailSorterTests.cs | 2 +- .../Sorters/Comparison/CombSorterTests.cs | 4 +- .../Sorters/Comparison/CycleSorterTests.cs | 2 +- .../Sorters/Comparison/ExchangeSorterTests.cs | 2 +- .../Sorters/Comparison/HeapSorterTests.cs | 2 +- .../Comparison/InsertionSorterTests.cs | 2 +- .../MedianOfThreeQuickSorterTests.cs | 2 +- .../Sorters/Comparison/MergeSorterTests.cs | 2 +- .../Comparison/MiddlePointQuickSorterTests.cs | 2 +- .../Sorters/Comparison/PancakeSorterTests.cs | 2 +- .../Comparison/RandomPivotQuickSorterTests.cs | 2 +- .../Comparison/SelectionSorterTests.cs | 2 +- .../Sorters/Comparison/ShellSorterTests.cs | 2 +- .../Sorters/Comparison/TimSorterTests.cs | 6 +- .../External/ExternalMergeSorterTests.cs | 4 +- .../Sorters/Integer/BucketSorterTests.cs | 2 +- .../Sorters/Integer/CountingSorterTests.cs | 12 +- .../Sorters/Integer/RadixSorterTests.cs | 2 +- .../String/MsdRadixStringSorterTests.cs | 2 +- .../Strings/GeneralStringAlgorithmsTests.cs | 4 +- Algorithms.Tests/Strings/PalindromeTests.cs | 4 +- .../Strings/PatternMatching/BoyerMoreTests.cs | 2 +- .../KnuthMorrisPrattSearcherTests.cs | 10 +- .../PatternMatching/NaiveStringSearchTests.cs | 6 +- .../Strings/PatternMatching/RabinKarpTests.cs | 2 +- .../ZblockSubstringSearchTest.cs | 2 +- Algorithms.Tests/Strings/PermutationTests.cs | 6 +- .../Similarity/HammingDistanceTests.cs | 2 +- Algorithms/Other/JulianEaster.cs | 2 +- DataStructures.Tests/BinarySearchTreeTests.cs | 167 +++++++++--------- DataStructures.Tests/BitArrayTests.cs | 64 +++---- .../DataStructures.Tests.csproj | 4 +- .../Hashing/HashTableTests.cs | 46 ++--- .../Hashing/NumberTheory/PrimeNumberTests.cs | 8 +- DataStructures.Tests/Heap/BinaryHeapTests.cs | 70 ++++---- .../Heap/FibonacciHeaps/FibonacciHeapTests.cs | 56 +++--- DataStructures.Tests/Heap/MinMaxHeapTests.cs | 56 +++--- .../Heap/PairingHeap/PairingHeapTests.cs | 16 +- .../LinkedList/DoublyLinkedListTests.cs | 40 ++--- .../LinkedList/LinkedListTests.cs | 24 +-- .../Probabilistic/BloomFilterTests.cs | 16 +- .../Queue/ArrayBasedQueueTests.cs | 22 +-- .../Queue/ListBasedQueueTests.cs | 20 +-- .../Queue/StackBasedQueueTests.cs | 20 +-- .../ScapegoatTree/ExtensionsTests.cs | 24 +-- .../ScapegoatTree/ScapegoatTreeNodeTests.cs | 22 +-- .../ScapegoatTree/ScapegoatTreeTests.cs | 142 +++++++-------- .../SegmentTrees/SegmentTreeApplyTests.cs | 6 +- .../SegmentTrees/SegmentTreeTests.cs | 4 +- .../SegmentTrees/SegmentTreeUpdateTest.cs | 2 +- DataStructures.Tests/SortedListTests.cs | 14 +- .../Stack/QueueBasedStackTests.cs | 6 +- DataStructures.Tests/Tries/TrieTests.cs | 51 +++--- .../Extensions/MatrixExtensionsTests.cs | 6 +- Utilities.Tests/Utilities.Tests.csproj | 4 +- 113 files changed, 710 insertions(+), 708 deletions(-) diff --git a/Algorithms.Tests/Algorithms.Tests.csproj b/Algorithms.Tests/Algorithms.Tests.csproj index fd46da23..893564d8 100644 --- a/Algorithms.Tests/Algorithms.Tests.csproj +++ b/Algorithms.Tests/Algorithms.Tests.csproj @@ -20,7 +20,7 @@ - - + + diff --git a/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs b/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs index d022c950..96d4fdcc 100644 --- a/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs +++ b/Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs @@ -15,8 +15,8 @@ public void Encode(string input, string expectedString, int expectedIndex) var (encoded, index) = bwt.Encode(input); - Assert.AreEqual(expectedString, encoded); - Assert.AreEqual(expectedIndex, index); + Assert.That(encoded, Is.EqualTo(expectedString)); + Assert.That(index, Is.EqualTo(expectedIndex)); } [TestCase("nnbaaa", 3, "banana")] @@ -28,7 +28,7 @@ public void Decode(string encoded, int index, string expected) var result = bwt.Decode(encoded, index); - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } [Test] @@ -42,6 +42,6 @@ public void RandomEncodeDecode() var (encoded, index) = bwt.Encode(inputString); var result = bwt.Decode(encoded, index); - Assert.AreEqual(inputString, result); + Assert.That(result, Is.EqualTo(inputString)); } } diff --git a/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs b/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs index f6d04bb8..58a45a28 100644 --- a/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs +++ b/Algorithms.Tests/Compressors/HuffmanCompressorTests.cs @@ -25,8 +25,8 @@ public static void CompressingPhrase(string uncompressedText, string expectedCom var decompressedText = translator.Translate(compressedText, decompressionKeys); //Assert - Assert.AreEqual(expectedCompressedText, compressedText); - Assert.AreEqual(uncompressedText, decompressedText); + Assert.That(compressedText, Is.EqualTo(expectedCompressedText)); + Assert.That(decompressedText, Is.EqualTo(uncompressedText)); } [Test] @@ -45,7 +45,7 @@ public static void DecompressedTextTheSameAsOriginal( var decompressedText = translator.Translate(compressedText, decompressionKeys); //Assert - Assert.AreEqual(text, decompressedText); + Assert.That(decompressedText, Is.EqualTo(text)); } [Test] diff --git a/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs b/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs index 19bec5d5..837dbefa 100644 --- a/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs +++ b/Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs @@ -22,8 +22,8 @@ public static void CompressingPhrase(string uncompressedText, string expectedCom var decompressedText = translator.Translate(compressedText, decompressionKeys); //Assert - Assert.AreEqual(expectedCompressedText, compressedText); - Assert.AreEqual(uncompressedText, decompressedText); + Assert.That(compressedText, Is.EqualTo(expectedCompressedText)); + Assert.That(decompressedText, Is.EqualTo(uncompressedText)); } [Test] @@ -40,6 +40,6 @@ public static void DecompressedTextTheSameAsOriginal([Random(0, 1000, 100)] int var decompressedText = translator.Translate(compressedText, decompressionKeys); //Assert - Assert.AreEqual(text, decompressedText); + Assert.That(decompressedText, Is.EqualTo(text)); } } diff --git a/Algorithms.Tests/Compressors/TranslatorTests.cs b/Algorithms.Tests/Compressors/TranslatorTests.cs index 487629fd..c2653a2a 100644 --- a/Algorithms.Tests/Compressors/TranslatorTests.cs +++ b/Algorithms.Tests/Compressors/TranslatorTests.cs @@ -23,6 +23,6 @@ public static void TranslateCorrectly() var translatedText = translator.Translate("Hey man!", dict); // Assert - Assert.AreEqual("Good day sir.", translatedText); + Assert.That(translatedText, Is.EqualTo("Good day sir.")); } } diff --git a/Algorithms.Tests/Encoders/CaesarEncoderTests.cs b/Algorithms.Tests/Encoders/CaesarEncoderTests.cs index 6db9421d..d6564d35 100644 --- a/Algorithms.Tests/Encoders/CaesarEncoderTests.cs +++ b/Algorithms.Tests/Encoders/CaesarEncoderTests.cs @@ -19,6 +19,6 @@ public static void DecodedStringIsTheSame([Random(100)] int key) var decoded = encoder.Decode(encoded, key); // Assert - Assert.AreEqual(message, decoded); + Assert.That(decoded, Is.EqualTo(message)); } } diff --git a/Algorithms.Tests/Encoders/FeistelCipherTest.cs b/Algorithms.Tests/Encoders/FeistelCipherTest.cs index 54bad8a6..e5199093 100644 --- a/Algorithms.Tests/Encoders/FeistelCipherTest.cs +++ b/Algorithms.Tests/Encoders/FeistelCipherTest.cs @@ -23,7 +23,7 @@ public static void DecodedStringIsTheSame([Random(100)] uint key) var decoded = encoder.Decode(encoded, key); // Assert - Assert.AreEqual(message, decoded); + Assert.That(decoded, Is.EqualTo(message)); } [TestCase("00001111", (uint)0x12345678)] diff --git a/Algorithms.Tests/Encoders/HillEnconderTests.cs b/Algorithms.Tests/Encoders/HillEnconderTests.cs index 87709605..359a4cb4 100644 --- a/Algorithms.Tests/Encoders/HillEnconderTests.cs +++ b/Algorithms.Tests/Encoders/HillEnconderTests.cs @@ -22,6 +22,6 @@ public static void DecodedStringIsTheSame() var decodeText = encoder.Decode(encodedText, key); // Assert - Assert.AreEqual(message, decodeText); + Assert.That(decodeText, Is.EqualTo(message)); } } diff --git a/Algorithms.Tests/Encoders/NysiisEncoderTests.cs b/Algorithms.Tests/Encoders/NysiisEncoderTests.cs index fdffcde1..b8f8ddcc 100644 --- a/Algorithms.Tests/Encoders/NysiisEncoderTests.cs +++ b/Algorithms.Tests/Encoders/NysiisEncoderTests.cs @@ -26,6 +26,6 @@ public void AttemptNysiis(string source, string expected) { var enc = new NysiisEncoder(); var nysiis = enc.Encode(source); - Assert.AreEqual(expected, nysiis); + Assert.That(nysiis, Is.EqualTo(expected)); } } diff --git a/Algorithms.Tests/Encoders/SoundexEncoderTest.cs b/Algorithms.Tests/Encoders/SoundexEncoderTest.cs index 1c9a8206..8bb7fde4 100644 --- a/Algorithms.Tests/Encoders/SoundexEncoderTest.cs +++ b/Algorithms.Tests/Encoders/SoundexEncoderTest.cs @@ -21,6 +21,6 @@ public static void AttemptSoundex(string source, string encoded) { SoundexEncoder enc = new(); var nysiis = enc.Encode(source); - Assert.AreEqual(nysiis, encoded); + Assert.That(encoded, Is.EqualTo(nysiis)); } } diff --git a/Algorithms.Tests/Encoders/VigenereEncoderTests.cs b/Algorithms.Tests/Encoders/VigenereEncoderTests.cs index 2d32703a..4765ec23 100644 --- a/Algorithms.Tests/Encoders/VigenereEncoderTests.cs +++ b/Algorithms.Tests/Encoders/VigenereEncoderTests.cs @@ -22,7 +22,7 @@ public static void DecodedStringIsTheSame() var decoded = encoder.Decode(encoded, key); // Assert - Assert.AreEqual(message, decoded); + Assert.That(decoded, Is.EqualTo(message)); } [Test] @@ -38,7 +38,7 @@ public static void Encode_KeyIsTooShort_KeyIsAppended() var decoded = encoder.Decode(encoded, key); // Assert - Assert.AreEqual(message, decoded); + Assert.That(decoded, Is.EqualTo(message)); } [Test] diff --git a/Algorithms.Tests/Graph/BreadthFirstSearchTests.cs b/Algorithms.Tests/Graph/BreadthFirstSearchTests.cs index 253b49a6..136104c7 100644 --- a/Algorithms.Tests/Graph/BreadthFirstSearchTests.cs +++ b/Algorithms.Tests/Graph/BreadthFirstSearchTests.cs @@ -37,7 +37,7 @@ public void VisitAll_ShouldCountNumberOfVisitedVertix_ResultShouldBeTheSameAsNum dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVertices++); //Assert - Assert.AreEqual(countOfVisitedVertices, graph.Count); + Assert.That(graph.Count, Is.EqualTo(countOfVisitedVertices)); } [Test] @@ -78,9 +78,9 @@ public void VisitAll_ShouldCountNumberOfVisitedVerices_TwoSeparatedGraphInOne() dfsSearcher.VisitAll(graph, vertex4, _ => countOfVisitedVerticesPerSecondGraph++); //Assert - Assert.AreEqual(countOfVisitedVerticesPerFirstGraph, 3); + Assert.That(countOfVisitedVerticesPerFirstGraph, Is.EqualTo(3)); - Assert.AreEqual(countOfVisitedVerticesPerSecondGraph, 3); + Assert.That(countOfVisitedVerticesPerSecondGraph, Is.EqualTo(3)); } [Test] @@ -126,6 +126,6 @@ public void VisitAll_ReturnTheSuqenceOfVertices_ShouldBeTheSameAsExpected() dfsSearcher.VisitAll(graph, vertex1, vertex => sequenceOfVisitedVertices.Add(vertex)); //Assert - CollectionAssert.AreEqual(expectedSequenceOfVisitedVertices, sequenceOfVisitedVertices); + Assert.That(sequenceOfVisitedVertices, Is.EqualTo(expectedSequenceOfVisitedVertices)); } } diff --git a/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs b/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs index 52937d93..9cfcc80e 100644 --- a/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs +++ b/Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs @@ -1,7 +1,6 @@ using Algorithms.Graph; -using NUnit.Framework; using DataStructures.BinarySearchTree; -using System; +using NUnit.Framework; namespace Algorithms.Tests.Graph; @@ -23,7 +22,7 @@ public static void CorrectLevelOrderTraversal() int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); // Assert - Assert.AreEqual(levelOrder, correctPath); + Assert.That(correctPath, Is.EqualTo(levelOrder)); } [Test] @@ -36,11 +35,11 @@ public static void EmptyArrayForNullRoot() int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); // Assert - Assert.IsEmpty(levelOrder); + Assert.That(levelOrder, Is.Empty); } - [TestCase(new [] {7, 9, 5})] - [TestCase(new [] { 7, 13, 11, 15, 14, 4, 5, 16, 2 })] + [TestCase(new[] { 7, 9, 5 })] + [TestCase(new[] { 7, 13, 11, 15, 14, 4, 5, 16, 2 })] public static void IncorrectLevelOrderTraversal(int[] insertion) { // Arrange @@ -54,7 +53,7 @@ public static void IncorrectLevelOrderTraversal(int[] insertion) int[] levelOrder = BreadthFirstTreeTraversal.LevelOrderTraversal(testTree); // Assert - Assert.AreNotEqual(levelOrder, insertion); + Assert.That(insertion, Is.Not.EqualTo(levelOrder)); } [Test] @@ -72,7 +71,7 @@ public static void DeepestNodeInTree() int deepest = BreadthFirstTreeTraversal.DeepestNode(testTree); // Assert - Assert.AreEqual(12, deepest); + Assert.That(deepest, Is.EqualTo(12)); } [Test] @@ -85,7 +84,7 @@ public static void DeepestNodeOfEmptyTree() int? deepest = BreadthFirstTreeTraversal.DeepestNode(testTree); // Assert - Assert.IsNull(deepest); + Assert.That(deepest, Is.Null); } } diff --git a/Algorithms.Tests/Graph/DepthFirstSearchTests.cs b/Algorithms.Tests/Graph/DepthFirstSearchTests.cs index 446403ba..fe48adb3 100644 --- a/Algorithms.Tests/Graph/DepthFirstSearchTests.cs +++ b/Algorithms.Tests/Graph/DepthFirstSearchTests.cs @@ -37,7 +37,7 @@ public void VisitAll_ShouldCountNumberOfVisitedVertix_ResultShouldBeTheSameAsNum dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVertices++); //Assert - Assert.AreEqual(countOfVisitedVertices, graph.Count); + Assert.That(graph.Count, Is.EqualTo(countOfVisitedVertices)); } [Test] @@ -78,9 +78,9 @@ public void VisitAll_ShouldCountNumberOfVisitedVertices_TwoSeparatedGraphInOne() dfsSearcher.VisitAll(graph, vertex4, _ => countOfVisitedVerticesPerSecondGraph++); //Assert - Assert.AreEqual(countOfVisitedVerticesPerFirstGraph, 3); + Assert.That(3, Is.EqualTo(countOfVisitedVerticesPerFirstGraph)); - Assert.AreEqual(countOfVisitedVerticesPerSecondGraph, 3); + Assert.That(3, Is.EqualTo(countOfVisitedVerticesPerSecondGraph)); } [Test] @@ -124,6 +124,6 @@ public void VisitAll_ReturnTheSuqenceOfVertices_ShouldBeTheSameAsExpected() dfsSearcher.VisitAll(graph, vertex1, vertex => sequenceOfVisitedVertices.Add(vertex)); //Assert - CollectionAssert.AreEqual(expectedSequenceOfVisitedVertices, sequenceOfVisitedVertices); + Assert.That(sequenceOfVisitedVertices, Is.EqualTo(expectedSequenceOfVisitedVertices)); } } diff --git a/Algorithms.Tests/Knapsack/DynamicProgrammingKnapsackSolverTests.cs b/Algorithms.Tests/Knapsack/DynamicProgrammingKnapsackSolverTests.cs index 087f5a26..a2b69f31 100644 --- a/Algorithms.Tests/Knapsack/DynamicProgrammingKnapsackSolverTests.cs +++ b/Algorithms.Tests/Knapsack/DynamicProgrammingKnapsackSolverTests.cs @@ -28,7 +28,7 @@ public static void SmallSampleOfChar() var actual = solver.Solve(items, capacity, weightSelector, valueSelector); //Assert - Assert.AreEqual(expected.OrderBy(x => x), actual.OrderBy(x => x)); + Assert.That(actual.OrderBy(x => x), Is.EqualTo(expected.OrderBy(x => x))); } [Test] @@ -53,7 +53,7 @@ public static void FSU_P01() var actual = solver.Solve(items, capacity, weightSelector, valueSelector); //Assert - Assert.AreEqual(expected.OrderBy(x => x), actual.OrderBy(x => x)); + Assert.That(actual.OrderBy(x => x), Is.EqualTo(expected.OrderBy(x => x))); } [Test] @@ -80,7 +80,7 @@ public static void FSU_P07_WithNonIntegralValues() var actual = solver.Solve(items, capacity * 10, weightSelector, valueSelector); //Assert - Assert.AreEqual(expected.OrderBy(x => x), actual.OrderBy(x => x)); + Assert.That(actual.OrderBy(x => x), Is.EqualTo(expected.OrderBy(x => x))); } @@ -98,6 +98,6 @@ public static void TakesHalf( var result = solver.Solve(items, length, _ => 1, _ => 1); //Assert - Assert.AreEqual(expectedResult, result); + Assert.That(result, Is.EqualTo(expectedResult)); } } diff --git a/Algorithms.Tests/Knapsack/NaiveKnapsackSolverTests.cs b/Algorithms.Tests/Knapsack/NaiveKnapsackSolverTests.cs index 52d8b2cf..d67ae0bb 100644 --- a/Algorithms.Tests/Knapsack/NaiveKnapsackSolverTests.cs +++ b/Algorithms.Tests/Knapsack/NaiveKnapsackSolverTests.cs @@ -20,6 +20,6 @@ public static void TakesHalf( var result = solver.Solve(items, length, _ => 1, _ => 1); //Assert - Assert.AreEqual(expectedResult, result); + Assert.That(result, Is.EqualTo(expectedResult)); } } diff --git a/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs b/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs index 4104ac46..d282ff91 100644 --- a/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs +++ b/Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs @@ -17,7 +17,7 @@ public static void TestCompute1() var x = ChineseRemainderTheorem.Compute(new List { 1L, 1L, 3L, 1L }, new List { 2L, 3L, 5L, 7L }); // Assert - Assert.AreEqual(expected, x); + Assert.That(x, Is.EqualTo(expected)); } [Test] @@ -29,7 +29,7 @@ public static void TestCompute2() var x = ChineseRemainderTheorem.Compute(new List { 0L, 0L, 2L, 1L, 1L }, new List { 2L, 5L, 7L, 9L, 11L }); // Assert - Assert.AreEqual(expected, x); + Assert.That(x, Is.EqualTo(expected)); } [Test] @@ -41,7 +41,7 @@ public static void TestCompute3() var x = ChineseRemainderTheorem.Compute(new List { 1L, 4L, 13L }, new List { 4L, 9L, 25L }); // Assert - Assert.AreEqual(expected, x); + Assert.That(x, Is.EqualTo(expected)); } [Test] @@ -105,7 +105,7 @@ public static void TestCompute_BigInteger_1() ); // Assert - Assert.AreEqual(expected, x); + Assert.That(x, Is.EqualTo(expected)); } [Test] @@ -120,7 +120,7 @@ public static void TestCompute_BigInteger_2() ); // Assert - Assert.AreEqual(expected, x); + Assert.That(x, Is.EqualTo(expected)); } [Test] @@ -135,7 +135,7 @@ public static void TestCompute_BigInteger_3() ); // Assert - Assert.AreEqual(expected, x); + Assert.That(x, Is.EqualTo(expected)); } [Test] diff --git a/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs b/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs index 69d98fc1..ea3e7792 100644 --- a/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs +++ b/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs @@ -23,9 +23,9 @@ public static void TestCompute(long a, long b, long expectedGCD, long expectedBe var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, b); // Assert - Assert.AreEqual(expectedGCD, eeaResult.gcd); - Assert.AreEqual(expectedBezoutOfA, eeaResult.bezoutA); - Assert.AreEqual(expectedBezoutOfB, eeaResult.bezoutB); + Assert.That(eeaResult.gcd, Is.EqualTo(expectedGCD)); + Assert.That(eeaResult.bezoutA, Is.EqualTo(expectedBezoutOfA)); + Assert.That(eeaResult.bezoutB, Is.EqualTo(expectedBezoutOfB)); } [TestCase(240, 46, 2, -9, 47)] @@ -45,8 +45,8 @@ public static void TestCompute_BigInteger(long a, long b, long expectedGCD, long var eeaResult = ExtendedEuclideanAlgorithm.Compute(new BigInteger(a), new BigInteger(b)); // Assert - Assert.AreEqual(new BigInteger(expectedGCD), eeaResult.gcd); - Assert.AreEqual(new BigInteger(expectedBezoutOfA), eeaResult.bezoutA); - Assert.AreEqual(new BigInteger(expectedBezoutOfB), eeaResult.bezoutB); + Assert.That(eeaResult.gcd, Is.EqualTo(new BigInteger(expectedGCD))); + Assert.That(eeaResult.bezoutA, Is.EqualTo(new BigInteger(expectedBezoutOfA))); + Assert.That(eeaResult.bezoutB, Is.EqualTo(new BigInteger(expectedBezoutOfB))); } } diff --git a/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs b/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs index f79ec79f..fef6a304 100644 --- a/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs +++ b/Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs @@ -16,7 +16,7 @@ public static void TestCompute(long a, long n, long expected) var inverse = ModularMultiplicativeInverse.Compute(a, n); // Assert - Assert.AreEqual(expected, inverse); + Assert.That(inverse, Is.EqualTo(expected)); } [TestCase(46, 240)] @@ -43,7 +43,7 @@ public static void TestCompute_BigInteger(long a, long n, long expected) var inverse = ModularMultiplicativeInverse.Compute(new BigInteger(a), new BigInteger(n)); // Assert - Assert.AreEqual(new BigInteger(expected), inverse); + Assert.That(inverse, Is.EqualTo(new BigInteger(expected))); } [TestCase(46, 240)] diff --git a/Algorithms.Tests/Numeric/AmicableNumbersTest.cs b/Algorithms.Tests/Numeric/AmicableNumbersTest.cs index f04e94bf..59932646 100644 --- a/Algorithms.Tests/Numeric/AmicableNumbersTest.cs +++ b/Algorithms.Tests/Numeric/AmicableNumbersTest.cs @@ -17,6 +17,6 @@ public static void AmicableNumbersChecker_Test(int x, int y) var result = AmicableNumbersChecker.AreAmicableNumbers(x, y); // Assert - Assert.IsTrue(result); + Assert.That(result, Is.True); } } diff --git a/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs b/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs index 5bc04c27..98b10222 100644 --- a/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs +++ b/Algorithms.Tests/Numeric/BinomialCoefficientTests.cs @@ -17,7 +17,7 @@ public static void CalculateFromPairs(int n, int k, int expected) var result = BinomialCoefficient.Calculate(new BigInteger(n), new BigInteger(k)); // Assert - Assert.AreEqual(new BigInteger(expected), result); + Assert.That(result, Is.EqualTo(new BigInteger(expected))); } [TestCase(3, 7)] diff --git a/Algorithms.Tests/Numeric/Decomposition/LUTests.cs b/Algorithms.Tests/Numeric/Decomposition/LUTests.cs index 2a34c484..105c1cf3 100644 --- a/Algorithms.Tests/Numeric/Decomposition/LUTests.cs +++ b/Algorithms.Tests/Numeric/Decomposition/LUTests.cs @@ -22,9 +22,9 @@ public void DecomposeIdentityMatrix() (double[,] lower, double[,] upper) = Lu.Decompose(identityMatrix); // Assert - Assert.AreEqual(expectedLower, lower); - Assert.AreEqual(expectedUpper, upper); - Assert.AreEqual(lower.Multiply(upper), identityMatrix); + Assert.That(lower, Is.EqualTo(expectedLower)); + Assert.That(upper, Is.EqualTo(expectedUpper)); + Assert.That(identityMatrix, Is.EqualTo(lower.Multiply(upper))); } [Test] @@ -39,9 +39,9 @@ public void DecomposeMatrix_Case3X3() (double[,] lower, double[,] upper) = Lu.Decompose(source); // Assert - Assert.AreEqual(expectedLower, lower); - Assert.AreEqual(expectedUpper, upper); - Assert.AreEqual(lower.Multiply(upper), source); + Assert.That(lower, Is.EqualTo(expectedLower)); + Assert.That(upper, Is.EqualTo(expectedUpper)); + Assert.That(source, Is.EqualTo(lower.Multiply(upper))); } [Test] @@ -56,9 +56,9 @@ public void DecomposeMatrix_Case4X4() (double[,] lower, double[,] upper) = Lu.Decompose(source); // Assert - Assert.AreEqual(expectedLower, lower); - Assert.AreEqual(expectedUpper, upper); - Assert.AreEqual(lower.Multiply(upper), source); + Assert.That(lower, Is.EqualTo(expectedLower)); + Assert.That(upper, Is.EqualTo(expectedUpper)); + Assert.That(source, Is.EqualTo(lower.Multiply(upper))); } [Test] @@ -85,7 +85,7 @@ public void EliminateIdentityEquation() var solution = Lu.Eliminate(identityMatrix, coefficients); // Assert - Assert.AreEqual(coefficients, solution); + Assert.That(solution, Is.EqualTo(coefficients)); } [Test] @@ -100,7 +100,7 @@ public void EliminateEquation_Case3X3() var solution = Lu.Eliminate(source, coefficients); // Assert - Assert.IsTrue(VectorMembersAreEqual(expectedSolution, solution)); + Assert.That(VectorMembersAreEqual(expectedSolution, solution), Is.True); } [Test] @@ -121,7 +121,7 @@ public void EliminateEquation_Case4X4() var solution = Lu.Eliminate(source, coefficients); // Assert - Assert.IsTrue(VectorMembersAreEqual(expectedSolution, solution)); + Assert.That(VectorMembersAreEqual(expectedSolution, solution), Is.True); } [Test] diff --git a/Algorithms.Tests/Numeric/Decomposition/MaclaurinTests.cs b/Algorithms.Tests/Numeric/Decomposition/MaclaurinTests.cs index 9a2f9935..cedd5120 100644 --- a/Algorithms.Tests/Numeric/Decomposition/MaclaurinTests.cs +++ b/Algorithms.Tests/Numeric/Decomposition/MaclaurinTests.cs @@ -18,7 +18,7 @@ public void Exp_TermsForm_ValidCases(double point, int terms, double expectedErr var actual = Maclaurin.Exp(point, terms); // Assert - Assert.IsTrue(Math.Abs(expected - actual) < expectedError); + Assert.That(Math.Abs(expected - actual) < expectedError, Is.True); } [Test] @@ -38,7 +38,7 @@ public void Sin_TermsForm_ValidCases(double point, int terms, double expectedErr var actual = Maclaurin.Sin(point, terms); // Assert - Assert.IsTrue(Math.Abs(expected - actual) < expectedError); + Assert.That(Math.Abs(expected - actual) < expectedError, Is.True); } [Test] @@ -58,7 +58,7 @@ public void Cos_TermsForm_ValidCases(double point, int terms, double expectedErr var actual = Maclaurin.Cos(point, terms); // Assert - Assert.IsTrue(Math.Abs(expected - actual) < expectedError); + Assert.That(Math.Abs(expected - actual) < expectedError, Is.True); } [Test] @@ -78,7 +78,7 @@ public void Exp_ErrorForm_ValidCases(double point, double error) var actual = Maclaurin.Exp(point, error); // Assert - Assert.IsTrue(Math.Abs(expected - actual) < error); + Assert.That(Math.Abs(expected - actual) < error, Is.True); } [TestCase(0.0)] @@ -99,7 +99,7 @@ public void Sin_ErrorForm_ValidCases(double point, double error) var actual = Maclaurin.Sin(point, error); // Assert - Assert.IsTrue(Math.Abs(expected - actual) < error); + Assert.That(Math.Abs(expected - actual) < error, Is.True); } [TestCase(0.0)] @@ -120,7 +120,7 @@ public void Cos_ErrorForm_ValidCases(double point, double error) var actual = Maclaurin.Cos(point, error); // Assert - Assert.IsTrue(Math.Abs(expected - actual) < error); + Assert.That(Math.Abs(expected - actual) < error, Is.True); } [TestCase(0.0)] diff --git a/Algorithms.Tests/Numeric/Decomposition/SVDTests.cs b/Algorithms.Tests/Numeric/Decomposition/SVDTests.cs index 46dc9223..88ac87ee 100644 --- a/Algorithms.Tests/Numeric/Decomposition/SVDTests.cs +++ b/Algorithms.Tests/Numeric/Decomposition/SVDTests.cs @@ -45,7 +45,7 @@ private void AssertMatrixEqual(double[,] matrix1, double[,] matrix2, double epsi { for (var j = 0; j < matrix1.GetLength(1); j++) { - Assert.AreEqual(matrix1[i, j], matrix2[i, j], epsilon, $"At index ({i}, {j})"); + Assert.That(matrix1[i, j], Is.EqualTo(matrix2[i, j]).Within(epsilon), $"At index ({i}, {j})"); } } } @@ -113,12 +113,12 @@ private void CheckSvd(double[,] testMatrix) if (s[i] > epsilon) { // if the singular value is non-zero, then the basis vector in v should be a unit vector - Assert.AreEqual(1, extracted.Magnitude(), epsilon); + Assert.That(extracted.Magnitude(), Is.EqualTo(1).Within(epsilon)); } else { // if the singular value is zero, then the basis vector in v should be zeroed out - Assert.AreEqual(0, extracted.Magnitude(), epsilon); + Assert.That(extracted.Magnitude(), Is.EqualTo(0).Within(epsilon)); } } diff --git a/Algorithms.Tests/Numeric/EulerMethodTest.cs b/Algorithms.Tests/Numeric/EulerMethodTest.cs index eed0bb04..f022662b 100644 --- a/Algorithms.Tests/Numeric/EulerMethodTest.cs +++ b/Algorithms.Tests/Numeric/EulerMethodTest.cs @@ -41,8 +41,8 @@ public static void TestExampleGeeksForGeeks() List points = EulerMethod.EulerFull(0, 0.05, 0.025, 1, exampleEquation); var y1 = points[1][1]; var y2 = points[2][1]; - Assert.AreEqual(y1, 1.025); - Assert.AreEqual(y2, 1.051890625); + Assert.That(1.025, Is.EqualTo(y1)); + Assert.That(1.051890625, Is.EqualTo(y2)); } [Test] diff --git a/Algorithms.Tests/Numeric/FactorialTests.cs b/Algorithms.Tests/Numeric/FactorialTests.cs index bb81994b..7a2ab058 100644 --- a/Algorithms.Tests/Numeric/FactorialTests.cs +++ b/Algorithms.Tests/Numeric/FactorialTests.cs @@ -21,7 +21,7 @@ public static void GetsFactorial(int input, string expected) var result = Factorial.Calculate(input); // Assert - Assert.AreEqual(expectedBigInt, result); + Assert.That(result, Is.EqualTo(expectedBigInt)); } [TestCase(-5)] diff --git a/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs b/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs index 13f7ab5f..9144ce17 100755 --- a/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs +++ b/Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs @@ -18,7 +18,7 @@ public static void PrimeNumberFactorizationFails(int p) var success = factorizer.TryFactor(p, out _); // Assert - Assert.IsFalse(success); + Assert.That(success, Is.False); } [TestCase(4, 2)] @@ -38,7 +38,7 @@ public static void PrimeNumberFactorizationSucceeds(int n, int expected) var success = factorizer.TryFactor(n, out var factor); // Assert - Assert.IsTrue(success); - Assert.AreEqual(expected, factor); + Assert.That(success, Is.True); + Assert.That(factor, Is.EqualTo(expected)); } } diff --git a/Algorithms.Tests/Numeric/GaussJordanEliminationTests.cs b/Algorithms.Tests/Numeric/GaussJordanEliminationTests.cs index 8f7581f9..8d4bb9df 100644 --- a/Algorithms.Tests/Numeric/GaussJordanEliminationTests.cs +++ b/Algorithms.Tests/Numeric/GaussJordanEliminationTests.cs @@ -34,6 +34,6 @@ public static void UnableToSolveSingularMatrix() var result = solver.Solve(input); // Assert - Assert.IsFalse(result); + Assert.That(result, Is.False); } } diff --git a/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs b/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs index 78262811..12218628 100644 --- a/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs +++ b/Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs @@ -23,6 +23,6 @@ public static void GreatestCommonDivisorCorrect(int a, int b, int expectedGcd) var actualGcd = gcdFinder.FindGcd(a, b); // Assert - Assert.AreEqual(expectedGcd, actualGcd); + Assert.That(actualGcd, Is.EqualTo(expectedGcd)); } } diff --git a/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs b/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs index ec9f5be2..22ab7a21 100644 --- a/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs +++ b/Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs @@ -23,6 +23,6 @@ public static void GreatestCommonDivisorCorrect(int a, int b, int expectedGcd) var actualGcd = gcdFinder.FindGcd(a, b); // Assert - Assert.AreEqual(expectedGcd, actualGcd); + Assert.That(actualGcd, Is.EqualTo(expectedGcd)); } } diff --git a/Algorithms.Tests/Numeric/KeithNumberTest.cs b/Algorithms.Tests/Numeric/KeithNumberTest.cs index eb8f510b..9a3a9cd5 100644 --- a/Algorithms.Tests/Numeric/KeithNumberTest.cs +++ b/Algorithms.Tests/Numeric/KeithNumberTest.cs @@ -16,7 +16,7 @@ public static void KeithNumberWork(int number) var result = KeithNumberChecker.IsKeithNumber(number); // Assert - Assert.IsTrue(result); + Assert.That(result, Is.True); } [TestCase(-2)] diff --git a/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs b/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs index ee75fffa..e8e150cc 100644 --- a/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs +++ b/Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs @@ -12,24 +12,18 @@ public class KrishnamurthyNumberCheckerTests public void KrishnamurthyNumberCheckerKnownNumbers(int number) { var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); - Assert.IsTrue(result); + Assert.That(result, Is.True); } [TestCase(3)] [TestCase(4)] [TestCase(239847)] [TestCase(12374)] - public void KrishnamurthyNumberCheckerNotKMNumber(int number) - { - var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); - Assert.IsFalse(result); - } - [TestCase(0)] [TestCase(-1)] - public void KrishnamurthyNumberCheckerNotPositiveNumber(int number) + public void KrishnamurthyNumberCheckerNotKMNumber(int number) { var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number); - Assert.IsFalse(result); + Assert.That(result, Is.False); } } diff --git a/Algorithms.Tests/Numeric/PerfectNumberTest.cs b/Algorithms.Tests/Numeric/PerfectNumberTest.cs index fba92763..8863fb01 100644 --- a/Algorithms.Tests/Numeric/PerfectNumberTest.cs +++ b/Algorithms.Tests/Numeric/PerfectNumberTest.cs @@ -18,7 +18,7 @@ public static void PerfectNumberWork(int number) var result = PerfectNumberChecker.IsPerfectNumber(number); // Assert - Assert.IsTrue(result); + Assert.That(result, Is.True); } [TestCase(-2)] diff --git a/Algorithms.Tests/Numeric/PseudoInverse/PseudoInverseTests.cs b/Algorithms.Tests/Numeric/PseudoInverse/PseudoInverseTests.cs index bf95a4b9..10138ffc 100644 --- a/Algorithms.Tests/Numeric/PseudoInverse/PseudoInverseTests.cs +++ b/Algorithms.Tests/Numeric/PseudoInverse/PseudoInverseTests.cs @@ -20,7 +20,7 @@ public static void SquaredMatrixInverseWorks() var rounded = aainva.RoundToNextInt(); var isequal = rounded.IsEqual(inMatCopy); // Assert - Assert.IsTrue(isequal); + Assert.That(isequal, Is.True); } [Test] @@ -39,6 +39,6 @@ public static void NonSquaredMatrixPseudoInverseMatrixWorks() var isequal = rounded.IsEqual(inMatCopy); // Assert - Assert.IsTrue(isequal); + Assert.That(isequal, Is.True); } } diff --git a/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs b/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs index 43b14c3f..53772d07 100644 --- a/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs +++ b/Algorithms.Tests/Other/DecisionsConvolutionsTest.cs @@ -29,7 +29,7 @@ public static void Verify_Linear_Convolution() var optimizedMatrix = DecisionsConvolutions.Linear(matrix, priorities); // Assert - Assert.AreEqual(optimizedMatrix, expectedMatrix); + Assert.That(expectedMatrix, Is.EqualTo(optimizedMatrix)); } [Test] @@ -55,6 +55,6 @@ public static void Verify_MaxMin_Convolution() var optimizedMatrix = DecisionsConvolutions.MaxMin(matrix, priorities); // Assert - Assert.AreEqual(optimizedMatrix, expectedMatrix); + Assert.That(expectedMatrix, Is.EqualTo(optimizedMatrix)); } } diff --git a/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs b/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs index 5f916539..eb8bedce 100644 --- a/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs +++ b/Algorithms.Tests/Other/FermatPrimeCheckerTests.cs @@ -21,6 +21,6 @@ public static void IsProbablePrime(int inputNum, bool expected) var result = FermatPrimeChecker.IsPrime(inputNum, times); // Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } } diff --git a/Algorithms.Tests/Other/GaussOptimizationTest.cs b/Algorithms.Tests/Other/GaussOptimizationTest.cs index 137212f9..76f824a3 100644 --- a/Algorithms.Tests/Other/GaussOptimizationTest.cs +++ b/Algorithms.Tests/Other/GaussOptimizationTest.cs @@ -47,8 +47,8 @@ public static void Verify_Gauss_Optimization_Positive() (x1, x2) = gaussOptimization.Optimize(func, n, step, eps, x1, x2); // Assert - Assert.AreEqual(x1, 1, 0.3); - Assert.AreEqual(x2, 1, 0.3); + Assert.That(x1, Is.EqualTo(1).Within(0.3)); + Assert.That(x2, Is.EqualTo(1).Within(0.3)); } [Test] @@ -91,7 +91,7 @@ public static void Verify_Gauss_Optimization_Negative() (x1, x2) = gaussOptimization.Optimize(func, n, step, eps, x1, x2); // Assert - Assert.AreEqual(x1, -1, 0.3); - Assert.AreEqual(x2, -1, 0.3); + Assert.That(x1, Is.EqualTo(-1).Within(0.3)); + Assert.That(x2, Is.EqualTo(-1).Within(0.3)); } } diff --git a/Algorithms.Tests/Other/GeoLocationTests.cs b/Algorithms.Tests/Other/GeoLocationTests.cs index b3aa427b..5ba12c27 100644 --- a/Algorithms.Tests/Other/GeoLocationTests.cs +++ b/Algorithms.Tests/Other/GeoLocationTests.cs @@ -19,6 +19,6 @@ public static void CalculateDistanceFromLatLngTest( var actualValue = Convert.ToDouble(result); // Assert - Assert.AreEqual(expectedValue, actualValue, 1d); // Accept if distance diff is +/-1 meters. + Assert.That(actualValue, Is.EqualTo(expectedValue).Within(1d)); // Accept if distance diff is +/-1 meters. } } diff --git a/Algorithms.Tests/Other/Int2BinaryTests.cs b/Algorithms.Tests/Other/Int2BinaryTests.cs index 9280beba..0b9cf1c5 100644 --- a/Algorithms.Tests/Other/Int2BinaryTests.cs +++ b/Algorithms.Tests/Other/Int2BinaryTests.cs @@ -19,7 +19,7 @@ public static void GetsBinary(ushort input, string expected) var result = Int2Binary.Int2Bin(input); // Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } @@ -38,7 +38,7 @@ public static void GetsBinary(uint input, string expected) var result = Int2Binary.Int2Bin(input); // Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } [TestCase((ulong)0, "0000000000000000000000000000000000000000000000000000000000000000")] @@ -59,6 +59,6 @@ public static void GetsBinary(ulong input, string expected) var result = Int2Binary.Int2Bin(input); // Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } } diff --git a/Algorithms.Tests/Other/JulianEasterTests.cs b/Algorithms.Tests/Other/JulianEasterTests.cs index 3c7a260a..214ec970 100644 --- a/Algorithms.Tests/Other/JulianEasterTests.cs +++ b/Algorithms.Tests/Other/JulianEasterTests.cs @@ -10,22 +10,21 @@ namespace Algorithms.Tests.Other; ///
public static class JulianEasterTest { - private static readonly JulianCalendar Calendar = new(); - [TestCaseSource(nameof(CalculateCases))] public static void CalculateTest(int year, DateTime expected) { var result = JulianEaster.Calculate(year); - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } private static readonly object[] CalculateCases = { - new object[] { 1800, new DateTime(1800, 04, 08, Calendar) }, - new object[] { 1950, new DateTime(1950, 03, 27, Calendar) }, - new object[] { 1991, new DateTime(1991, 03, 25, Calendar) }, - new object[] { 2000, new DateTime(2000, 04, 17, Calendar) }, - new object[] { 2199, new DateTime(2199, 04, 07, Calendar) } + new object[] { 1800, new DateTime(1800, 04, 08, 00, 00, 00, DateTimeKind.Utc) }, + new object[] { 1950, new DateTime(1950, 03, 27, 00, 00, 00, DateTimeKind.Utc) }, + new object[] { 1991, new DateTime(1991, 03, 25, 00, 00, 00, DateTimeKind.Utc) }, + new object[] { 2000, new DateTime(2000, 04, 17, 00, 00, 00, DateTimeKind.Utc) }, + new object[] { 2199, new DateTime(2199, 04, 07, 00, 00, 00, DateTimeKind.Utc) } }; + } diff --git a/Algorithms.Tests/Other/LuhnTests.cs b/Algorithms.Tests/Other/LuhnTests.cs index 3040fdc2..7bd32a47 100644 --- a/Algorithms.Tests/Other/LuhnTests.cs +++ b/Algorithms.Tests/Other/LuhnTests.cs @@ -21,7 +21,7 @@ public void ValidateTrue(string number) validate = Luhn.Validate(number); // Assert - Assert.True(validate); + Assert.That(validate, Is.True); } [TestCase("89012104211118510720")] // ICCID @@ -37,7 +37,7 @@ public void ValidateFalse(string number) validate = Luhn.Validate(number); // Assert - Assert.False(validate); + Assert.That(validate, Is.False); } [TestCase("x9012104211118510720")] // ICCID @@ -55,6 +55,6 @@ public void GetLostNum(string number) validate = Luhn.Validate(number.Replace("x", lostNum.ToString())); // Assert - Assert.True(validate); + Assert.That(validate, Is.True); } } diff --git a/Algorithms.Tests/Other/MandelbrotTest.cs b/Algorithms.Tests/Other/MandelbrotTest.cs index c481a69f..9d72de54 100644 --- a/Algorithms.Tests/Other/MandelbrotTest.cs +++ b/Algorithms.Tests/Other/MandelbrotTest.cs @@ -30,10 +30,10 @@ public static void TestBlackAndWhite() { Bitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: false); // Pixel outside the Mandelbrot set should be white. - Assert.AreEqual(bitmap.GetPixel(0, 0), Color.FromArgb(255, 255, 255, 255)); + Assert.That(Color.FromArgb(255, 255, 255, 255), Is.EqualTo(bitmap.GetPixel(0, 0))); // Pixel inside the Mandelbrot set should be black. - Assert.AreEqual(bitmap.GetPixel(400, 300), Color.FromArgb(255, 0, 0, 0)); + Assert.That(Color.FromArgb(255, 0, 0, 0), Is.EqualTo(bitmap.GetPixel(400, 300))); } [Test] @@ -41,9 +41,9 @@ public static void TestColorCoded() { Bitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: true); // Pixel distant to the Mandelbrot set should be red. - Assert.AreEqual(bitmap.GetPixel(0, 0), Color.FromArgb(255, 255, 0, 0)); + Assert.That(Color.FromArgb(255, 255, 0, 0), Is.EqualTo(bitmap.GetPixel(0, 0))); // Pixel inside the Mandelbrot set should be black. - Assert.AreEqual(bitmap.GetPixel(400, 300), Color.FromArgb(255, 0, 0, 0)); + Assert.That(Color.FromArgb(255, 0, 0, 0), Is.EqualTo(bitmap.GetPixel(400, 300))); } } diff --git a/Algorithms.Tests/Other/ParetoOptimizationTests.cs b/Algorithms.Tests/Other/ParetoOptimizationTests.cs index f0bb6175..9daf1113 100644 --- a/Algorithms.Tests/Other/ParetoOptimizationTests.cs +++ b/Algorithms.Tests/Other/ParetoOptimizationTests.cs @@ -36,6 +36,6 @@ public static void Verify_Pareto_Optimization() var optimizedMatrix = paretoOptimization.Optimize(matrix); // Assert - Assert.AreEqual(optimizedMatrix, expectedMatrix); + Assert.That(expectedMatrix, Is.EqualTo(optimizedMatrix)); } } diff --git a/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs b/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs index 7a3eb7fa..d3aa8b62 100644 --- a/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs +++ b/Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs @@ -13,6 +13,6 @@ public class PollardsRhoFactorizingTests public void SimpleTest(int number, int expectedResult) { var result = PollardsRhoFactorizing.Calculate(number); - Assert.AreEqual(expectedResult, result); + Assert.That(result, Is.EqualTo(expectedResult)); } } diff --git a/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs b/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs index ba837fcb..3f3f5eae 100644 --- a/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs +++ b/Algorithms.Tests/Other/SieveOfEratosthenesTests.cs @@ -669,15 +669,15 @@ public static class SieveOfEratosthenesTests [Test] public static void First10_000PrimesCorrect() => - Assert.AreEqual(First10000PrimeNumbers, new SieveOfEratosthenes(104729).GetPrimes()); + Assert.That(new SieveOfEratosthenes(104729).GetPrimes(), Is.EqualTo(First10000PrimeNumbers)); [Test] - public static void TestMaxNumber() => Assert.AreEqual(new SieveOfEratosthenes(69).MaximumNumber, 69); + public static void TestMaxNumber() => Assert.That(new SieveOfEratosthenes(69).MaximumNumber, Is.EqualTo(69)); [TestCase(13, true)] [TestCase(10, false)] public static void TestIsPrime(int input, bool expected) { - Assert.AreEqual(new SieveOfEratosthenes(100).IsPrime(input), expected); + Assert.That(expected, Is.EqualTo(new SieveOfEratosthenes(100).IsPrime(input))); } } diff --git a/Algorithms.Tests/Other/WelfordsVarianceTest.cs b/Algorithms.Tests/Other/WelfordsVarianceTest.cs index f8378429..8b25b54a 100644 --- a/Algorithms.Tests/Other/WelfordsVarianceTest.cs +++ b/Algorithms.Tests/Other/WelfordsVarianceTest.cs @@ -14,10 +14,10 @@ public void WelfordVariance_Example1() welfordsVariance.AddValue(13); welfordsVariance.AddValue(16); - Assert.AreEqual(4, welfordsVariance.Count); - Assert.AreEqual(10, welfordsVariance.Mean, 0.0000001); - Assert.AreEqual(22.5, welfordsVariance.Variance, 0.0000001); - Assert.AreEqual(30, welfordsVariance.SampleVariance, 0.0000001); + Assert.That(welfordsVariance.Count, Is.EqualTo(4)); + Assert.That(welfordsVariance.Mean, Is.EqualTo(10).Within(0.0000001)); + Assert.That(welfordsVariance.Variance, Is.EqualTo(22.5).Within(0.0000001)); + Assert.That(welfordsVariance.SampleVariance, Is.EqualTo(30).Within(0.0000001)); } [Test] @@ -28,10 +28,10 @@ public void WelfordVariance_Example2() stats.AddValue(100000007); stats.AddValue(100000013); stats.AddValue(100000016); - Assert.AreEqual(4, stats.Count); - Assert.AreEqual(100000010, stats.Mean, 0.0000001); - Assert.AreEqual(22.5, stats.Variance, 0.0000001); - Assert.AreEqual(30, stats.SampleVariance, 0.0000001); + Assert.That(stats.Count, Is.EqualTo(4)); + Assert.That(stats.Mean, Is.EqualTo(100000010).Within(0.0000001)); + Assert.That(stats.Variance, Is.EqualTo(22.5).Within(0.0000001)); + Assert.That(stats.SampleVariance, Is.EqualTo(30).Within(0.0000001)); } [Test] @@ -42,10 +42,10 @@ public void WelfordVariance_Example3() stats.AddValue(1000000007); stats.AddValue(1000000013); stats.AddValue(1000000016); - Assert.AreEqual(4, stats.Count); - Assert.AreEqual(1000000010, stats.Mean, 0.0000001); - Assert.AreEqual(22.5, stats.Variance, 0.0000001); - Assert.AreEqual(30, stats.SampleVariance, 0.0000001); + Assert.That(stats.Count, Is.EqualTo(4)); + Assert.That(stats.Mean, Is.EqualTo(1000000010).Within(0.0000001)); + Assert.That(stats.Variance, Is.EqualTo(22.5).Within(0.0000001)); + Assert.That(stats.SampleVariance, Is.EqualTo(30).Within(0.0000001)); } [Test] @@ -56,20 +56,20 @@ public void WelfordVariance_Example4() stats.AddValue(2); stats.AddValue(3); stats.AddValue(1); - Assert.AreEqual(4, stats.Count); - Assert.AreEqual(3, stats.Mean, 0.0000001); - Assert.AreEqual(3.5, stats.Variance, 0.0000001); - Assert.AreEqual(4.6666667, stats.SampleVariance, 0.0000001); + Assert.That(stats.Count, Is.EqualTo(4)); + Assert.That(stats.Mean, Is.EqualTo(3).Within(0.0000001)); + Assert.That(stats.Variance, Is.EqualTo(3.5).Within(0.0000001)); + Assert.That(stats.SampleVariance, Is.EqualTo(4.6666667).Within(0.0000001)); } [Test] public void WelfordVariance_Example5() { var stats = new WelfordsVariance(new double[] { 2, 2, 5, 7 }); - Assert.AreEqual(4, stats.Count); - Assert.AreEqual(4, stats.Mean, 0.0000001); - Assert.AreEqual(4.5, stats.Variance, 0.0000001); - Assert.AreEqual(6, stats.SampleVariance, 0.0000001); + Assert.That(stats.Count, Is.EqualTo(4)); + Assert.That(stats.Mean, Is.EqualTo(4).Within(0.0000001)); + Assert.That(stats.Variance, Is.EqualTo(4.5).Within(0.0000001)); + Assert.That(stats.SampleVariance, Is.EqualTo(6).Within(0.0000001)); } [Test] @@ -77,10 +77,10 @@ public void WelfordVariance_Example6() { var stats = new WelfordsVariance(); stats.AddRange(new double[] { 2, 4, 4, 4, 5, 5, 7, 9 }); - Assert.AreEqual(8, stats.Count); - Assert.AreEqual(5, stats.Mean, 0.0000001); - Assert.AreEqual(4, stats.Variance, 0.0000001); - Assert.AreEqual(4.5714286, stats.SampleVariance, 0.0000001); + Assert.That(stats.Count, Is.EqualTo(8)); + Assert.That(stats.Mean, Is.EqualTo(5).Within(0.0000001)); + Assert.That(stats.Variance, Is.EqualTo(4).Within(0.0000001)); + Assert.That(stats.SampleVariance, Is.EqualTo(4.5714286).Within(0.0000001)); } [Test] @@ -88,10 +88,10 @@ public void WelfordVariance_Example7() { var stats = new WelfordsVariance(); stats.AddRange(new double[] { 9, 2, 5, 4, 12, 7, 8, 11, 9, 3, 7, 4, 12, 5, 4, 10, 9, 6, 9, 4 }); - Assert.AreEqual(20, stats.Count); - Assert.AreEqual(7, stats.Mean, 0.0000001); - Assert.AreEqual(8.9, stats.Variance, 0.0000001); - Assert.AreEqual(9.3684211, stats.SampleVariance, 0.0000001); + Assert.That(stats.Count, Is.EqualTo(20)); + Assert.That(stats.Mean, Is.EqualTo(7).Within(0.0000001)); + Assert.That(stats.Variance, Is.EqualTo(8.9).Within(0.0000001)); + Assert.That(stats.SampleVariance, Is.EqualTo(9.3684211).Within(0.0000001)); } [Test] @@ -99,10 +99,10 @@ public void WelfordVariance_Example8() { var stats = new WelfordsVariance(); stats.AddRange(new [] { 51.3, 55.6, 49.9, 52.0 }); - Assert.AreEqual(4, stats.Count); - Assert.AreEqual(52.2, stats.Mean, 0.0000001); - Assert.AreEqual(4.4250000, stats.Variance, 0.0000001); - Assert.AreEqual(5.9000000, stats.SampleVariance, 0.0000001); + Assert.That(stats.Count, Is.EqualTo(4)); + Assert.That(stats.Mean, Is.EqualTo(52.2).Within(0.0000001)); + Assert.That(stats.Variance, Is.EqualTo(4.4250000).Within(0.0000001)); + Assert.That(stats.SampleVariance, Is.EqualTo(5.9000000).Within(0.0000001)); } [Test] @@ -110,10 +110,10 @@ public void WelfordVariance_Example9() { var stats = new WelfordsVariance(); stats.AddRange(new double[] { -5, -3, -1, 1, 3 }); - Assert.AreEqual(5, stats.Count); - Assert.AreEqual(-1, stats.Mean, 0.0000001); - Assert.AreEqual(8, stats.Variance, 0.0000001); - Assert.AreEqual(10, stats.SampleVariance, 0.0000001); + Assert.That(stats.Count, Is.EqualTo(5)); + Assert.That(stats.Mean, Is.EqualTo(-1).Within(0.0000001)); + Assert.That(stats.Variance, Is.EqualTo(8).Within(0.0000001)); + Assert.That(stats.SampleVariance, Is.EqualTo(10).Within(0.0000001)); } [Test] @@ -121,20 +121,20 @@ public void WelfordVariance_Example10() { var stats = new WelfordsVariance(); stats.AddRange(new double[] { -1, 0, 1 }); - Assert.AreEqual(3, stats.Count); - Assert.AreEqual(0, stats.Mean, 0.0000001); - Assert.AreEqual(0.6666667, stats.Variance, 0.0000001); - Assert.AreEqual(1, stats.SampleVariance, 0.0000001); + Assert.That(stats.Count, Is.EqualTo(3)); + Assert.That(stats.Mean, Is.EqualTo(0).Within(0.0000001)); + Assert.That(stats.Variance, Is.EqualTo(0.6666667).Within(0.0000001)); + Assert.That(stats.SampleVariance, Is.EqualTo(1).Within(0.0000001)); } [Test] public void WelfordVariance_NoValue() { var stats = new WelfordsVariance(); - Assert.AreEqual(0, stats.Count); - Assert.AreEqual(double.NaN, stats.Mean); - Assert.AreEqual(double.NaN, stats.Variance); - Assert.AreEqual(double.NaN, stats.SampleVariance); + Assert.That(stats.Count, Is.EqualTo(0)); + Assert.That(stats.Mean, Is.EqualTo(double.NaN)); + Assert.That(stats.Variance, Is.EqualTo(double.NaN)); + Assert.That(stats.SampleVariance, Is.EqualTo(double.NaN)); } [Test] @@ -142,10 +142,10 @@ public void WelfordVariance_OneValue() { var stats = new WelfordsVariance(); stats.AddValue(1); - Assert.AreEqual(1, stats.Count); - Assert.AreEqual(double.NaN, stats.Mean); - Assert.AreEqual(double.NaN, stats.Variance); - Assert.AreEqual(double.NaN, stats.SampleVariance); + Assert.That(stats.Count, Is.EqualTo(1)); + Assert.That(stats.Mean, Is.EqualTo(double.NaN)); + Assert.That(stats.Variance, Is.EqualTo(double.NaN)); + Assert.That(stats.SampleVariance, Is.EqualTo(double.NaN)); } [Test] @@ -154,9 +154,9 @@ public void WelfordVariance_TwoValues() var stats = new WelfordsVariance(); stats.AddValue(1); stats.AddValue(2); - Assert.AreEqual(2, stats.Count); - Assert.AreEqual(1.5, stats.Mean, 0.0000001); - Assert.AreEqual(0.25, stats.Variance, 0.0000001); - Assert.AreEqual(0.5, stats.SampleVariance, 0.0000001); + Assert.That(stats.Count, Is.EqualTo(2)); + Assert.That(stats.Mean, Is.EqualTo(1.5).Within(0.0000001)); + Assert.That(stats.Variance, Is.EqualTo(0.25).Within(0.0000001)); + Assert.That(stats.SampleVariance, Is.EqualTo(0.5).Within(0.0000001)); } } diff --git a/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs b/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs index 5aabebeb..13005638 100644 --- a/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs +++ b/Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs @@ -14,6 +14,6 @@ public class LevenshteinDistanceTests public void Calculate_ReturnsCorrectLevenshteinDistance(string source, string destination, int expectedDistance) { var result = LevenshteinDistance.Calculate(source, destination); - Assert.AreEqual(expectedDistance, result); + Assert.That(result, Is.EqualTo(expectedDistance)); } } diff --git a/Algorithms.Tests/Problems/StableMarriage/GaleShapleyTests.cs b/Algorithms.Tests/Problems/StableMarriage/GaleShapleyTests.cs index 86c894b9..d8318762 100644 --- a/Algorithms.Tests/Problems/StableMarriage/GaleShapleyTests.cs +++ b/Algorithms.Tests/Problems/StableMarriage/GaleShapleyTests.cs @@ -35,13 +35,13 @@ public static void MatchingIsSuccessful() GaleShapley.Match(proposers, acceptors); - Assert.IsTrue(acceptors.All(x => x.EngagedTo is not null)); - Assert.IsTrue(proposers.All(x => x.EngagedTo is not null)); - Assert.IsTrue(AreMatchesStable(proposers, acceptors)); + Assert.That(acceptors.ToList().TrueForAll(x => x.EngagedTo is not null)); + Assert.That(proposers.ToList().TrueForAll(x => x.EngagedTo is not null)); + Assert.That(AreMatchesStable(proposers, acceptors), Is.True); } private static bool AreMatchesStable(Proposer[] proposers, Accepter[] accepters) => - proposers.All(p => + proposers.ToList().TrueForAll(p => p.EngagedTo is not null && Score(p, p.EngagedTo) <= accepters .Where(a => a.PrefersOverCurrent(p)) diff --git a/Algorithms.Tests/Search/BinarySearcherTests.cs b/Algorithms.Tests/Search/BinarySearcherTests.cs index bacca00f..5d1669a1 100644 --- a/Algorithms.Tests/Search/BinarySearcherTests.cs +++ b/Algorithms.Tests/Search/BinarySearcherTests.cs @@ -20,7 +20,7 @@ public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int var actualIndex = searcher.FindIndex(arrayToSearch, arrayToSearch[selectedIndex]); // Assert - Assert.AreEqual(arrayToSearch[selectedIndex], arrayToSearch[actualIndex]); + Assert.That(arrayToSearch[actualIndex], Is.EqualTo(arrayToSearch[selectedIndex])); } [Test] @@ -40,7 +40,7 @@ public static void FindIndex_ItemMissing_MinusOneReturned( var actualIndex = searcher.FindIndex(arrayToSearch, missingItem); // Assert - Assert.AreEqual(-1, actualIndex); + Assert.That(actualIndex, Is.EqualTo(-1)); } [Test] @@ -54,6 +54,6 @@ public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemT var actualIndex = searcher.FindIndex(arrayToSearch, itemToSearch); // Assert - Assert.AreEqual(-1, actualIndex); + Assert.That(actualIndex, Is.EqualTo(-1)); } } diff --git a/Algorithms.Tests/Search/BoyerMooreTests.cs b/Algorithms.Tests/Search/BoyerMooreTests.cs index 2364a9ac..4ad891fc 100644 --- a/Algorithms.Tests/Search/BoyerMooreTests.cs +++ b/Algorithms.Tests/Search/BoyerMooreTests.cs @@ -30,6 +30,6 @@ public void BoyerMoore_Majority_Finder_Test() var expected = majorityElement; var actual = BoyerMoore.FindMajority(randomNumbers); - Assert.AreEqual(actual, expected); + Assert.That(expected, Is.EqualTo(actual)); } } diff --git a/Algorithms.Tests/Search/FastSearcherTests.cs b/Algorithms.Tests/Search/FastSearcherTests.cs index fbf4d69a..2bc95bf3 100644 --- a/Algorithms.Tests/Search/FastSearcherTests.cs +++ b/Algorithms.Tests/Search/FastSearcherTests.cs @@ -13,7 +13,7 @@ public static void FindIndex_ItemPresent_IndexCorrect() var arr = Helper.GetSortedArray(1000); var present = Helper.GetItemIn(arr); var index = searcher.FindIndex(arr, present); - Assert.AreEqual(present, arr[index]); + Assert.That(arr[index], Is.EqualTo(present)); } [TestCase(new[] { 1, 2 }, 1)] @@ -23,7 +23,7 @@ public static void FindIndex_ItemPresentInSpecificCase_IndexCorrect(int[] arr, i { var searcher = new FastSearcher(); var index = searcher.FindIndex(arr, present); - Assert.AreEqual(present, arr[index]); + Assert.That(arr[index], Is.EqualTo(present)); } [Test] @@ -67,7 +67,7 @@ public static void FindIndex_ArrayOfDuplicatesItemPresent_IndexCorrect() var arr = new int[1000]; var present = 0; var index = searcher.FindIndex(arr, present); - Assert.AreEqual(0, arr[index]); + Assert.That(arr[index], Is.EqualTo(0)); } [Test] diff --git a/Algorithms.Tests/Search/InterpolationSearchTests.cs b/Algorithms.Tests/Search/InterpolationSearchTests.cs index a993598f..098e803a 100644 --- a/Algorithms.Tests/Search/InterpolationSearchTests.cs +++ b/Algorithms.Tests/Search/InterpolationSearchTests.cs @@ -20,7 +20,7 @@ public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, arrayToSearch[selectedIndex]); // Assert - Assert.AreEqual(arrayToSearch[selectedIndex], arrayToSearch[actualIndex]); + Assert.That(arrayToSearch[actualIndex], Is.EqualTo(arrayToSearch[selectedIndex])); } [Test] @@ -39,7 +39,7 @@ public static void FindIndex_ItemMissing_MinusOneReturned( var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, missingItem); // Assert - Assert.AreEqual(-1, actualIndex); + Assert.That(actualIndex, Is.EqualTo(-1)); } [Test] @@ -52,6 +52,6 @@ public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemT var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, itemToSearch); // Assert - Assert.AreEqual(-1, actualIndex); + Assert.That(actualIndex, Is.EqualTo(-1)); } } diff --git a/Algorithms.Tests/Search/JumpSearcherTests.cs b/Algorithms.Tests/Search/JumpSearcherTests.cs index 3c8daa3e..b58ccb7b 100644 --- a/Algorithms.Tests/Search/JumpSearcherTests.cs +++ b/Algorithms.Tests/Search/JumpSearcherTests.cs @@ -35,7 +35,7 @@ public void FindIndex_ItemMissing_MinusOneReturned([Random(1, 1000, 10)] int n, var actualIndex = searcher.FindIndex(sortedArray, missingItem); // Assert - Assert.AreEqual(expectedIndex, actualIndex); + Assert.That(actualIndex, Is.EqualTo(expectedIndex)); } [Test] @@ -50,7 +50,7 @@ public void FindIndex_ArrayEmpty_MinusOneReturned([Random(-100, 1100, 10)] int m var actualIndex = searcher.FindIndex(sortedArray, missingItem); // Assert - Assert.AreEqual(expectedIndex, actualIndex); + Assert.That(actualIndex, Is.EqualTo(expectedIndex)); } [TestCase(null, "abc")] diff --git a/Algorithms.Tests/Search/LinearSearcherTests.cs b/Algorithms.Tests/Search/LinearSearcherTests.cs index f8a90ad3..44c6128a 100644 --- a/Algorithms.Tests/Search/LinearSearcherTests.cs +++ b/Algorithms.Tests/Search/LinearSearcherTests.cs @@ -22,7 +22,7 @@ public static void Find_ItemPresent_ItemCorrect([Random(0, 1_000_000, 100)] int var actualItem = searcher.Find(arrayToSearch, x => x == arrayToSearch[n / 2]); // Assert - Assert.AreEqual(expectedItem, actualItem); + Assert.That(actualItem, Is.EqualTo(expectedItem)); } [Test] @@ -38,7 +38,7 @@ public static void FindIndex_ItemPresent_IndexCorrect([Random(0, 1_000_000, 100) var actualIndex = searcher.FindIndex(arrayToSearch, x => x == arrayToSearch[n / 2]); // Assert - Assert.AreEqual(expectedIndex, actualIndex); + Assert.That(actualIndex, Is.EqualTo(expectedIndex)); } [Test] @@ -66,6 +66,6 @@ public static void FindIndex_ItemMissing_MinusOneReturned([Random(0, 1_000_000, var actualIndex = searcher.FindIndex(arrayToSearch, _ => false); // Assert - Assert.AreEqual(-1, actualIndex); + Assert.That(actualIndex, Is.EqualTo(-1)); } } diff --git a/Algorithms.Tests/Search/RecursiveBinarySearcherTests.cs b/Algorithms.Tests/Search/RecursiveBinarySearcherTests.cs index 07990aa5..1b35d079 100644 --- a/Algorithms.Tests/Search/RecursiveBinarySearcherTests.cs +++ b/Algorithms.Tests/Search/RecursiveBinarySearcherTests.cs @@ -23,7 +23,7 @@ public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int var actualIndex = subject.FindIndex(collection, collection[selectedIndex]); // Assert - Assert.AreEqual(collection[selectedIndex], collection[actualIndex]); + Assert.That(collection[actualIndex], Is.EqualTo(collection[selectedIndex])); } [Test] @@ -43,7 +43,7 @@ public static void FindIndex_ItemMissing_MinusOneReturned( var actualIndex = subject.FindIndex(collection, missingItem); // Assert - Assert.AreEqual(-1, actualIndex); + Assert.That(actualIndex, Is.EqualTo(-1)); } [Test] @@ -57,7 +57,7 @@ public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemT var actualIndex = subject.FindIndex(collection, itemToSearch); // Assert - Assert.AreEqual(-1, actualIndex); + Assert.That(actualIndex, Is.EqualTo(-1)); } [Test] diff --git a/Algorithms.Tests/Sorters/Comparison/BinaryInsertionSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/BinaryInsertionSorterTests.cs index 858f5fd9..3c1f75dd 100644 --- a/Algorithms.Tests/Sorters/Comparison/BinaryInsertionSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/BinaryInsertionSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/BogoSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/BogoSorterTests.cs index 536d5099..e25ab47f 100644 --- a/Algorithms.Tests/Sorters/Comparison/BogoSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/BogoSorterTests.cs @@ -20,6 +20,6 @@ public static void ArraySorted([Random(0, 10, 10, Distinct = true)] int n) Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/BubbleSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/BubbleSorterTests.cs index caee747d..4ba41d7f 100644 --- a/Algorithms.Tests/Sorters/Comparison/BubbleSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/BubbleSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/CocktailSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/CocktailSorterTests.cs index 2a40c95b..2329a1a9 100644 --- a/Algorithms.Tests/Sorters/Comparison/CocktailSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/CocktailSorterTests.cs @@ -22,6 +22,6 @@ public static void SortsArray( Array.Sort(correctArray); // Assert - Assert.AreEqual(correctArray, testArray); + Assert.That(testArray, Is.EqualTo(correctArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/CombSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/CombSorterTests.cs index 4a365fe1..a708271f 100644 --- a/Algorithms.Tests/Sorters/Comparison/CombSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/CombSorterTests.cs @@ -22,7 +22,7 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } [Test] @@ -40,6 +40,6 @@ public static void ArraySorted_WithCustomShrinkFactor( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/CycleSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/CycleSorterTests.cs index 055e607a..1fda91d9 100644 --- a/Algorithms.Tests/Sorters/Comparison/CycleSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/CycleSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray); // Assert - Assert.AreEqual(correctArray, testArray); + Assert.That(testArray, Is.EqualTo(correctArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/ExchangeSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/ExchangeSorterTests.cs index 7237f5c0..7b672399 100644 --- a/Algorithms.Tests/Sorters/Comparison/ExchangeSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/ExchangeSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/HeapSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/HeapSorterTests.cs index d0c944cd..44decc30 100644 --- a/Algorithms.Tests/Sorters/Comparison/HeapSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/HeapSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray); // Assert - Assert.AreEqual(correctArray, testArray); + Assert.That(testArray, Is.EqualTo(correctArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/InsertionSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/InsertionSorterTests.cs index 280db9cb..1ad383e5 100644 --- a/Algorithms.Tests/Sorters/Comparison/InsertionSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/InsertionSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/MedianOfThreeQuickSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/MedianOfThreeQuickSorterTests.cs index 3ba9df04..a3440fd5 100644 --- a/Algorithms.Tests/Sorters/Comparison/MedianOfThreeQuickSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/MedianOfThreeQuickSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/MergeSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/MergeSorterTests.cs index 6b7dbe5b..7019b3fb 100644 --- a/Algorithms.Tests/Sorters/Comparison/MergeSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/MergeSorterTests.cs @@ -25,6 +25,6 @@ public static void TestOnMergeSorter( Array.Sort(correctArray); // Assert - Assert.AreEqual(correctArray, testArray); + Assert.That(testArray, Is.EqualTo(correctArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/MiddlePointQuickSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/MiddlePointQuickSorterTests.cs index fc87a5b0..69dc19ba 100644 --- a/Algorithms.Tests/Sorters/Comparison/MiddlePointQuickSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/MiddlePointQuickSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/PancakeSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/PancakeSorterTests.cs index f06fe1ae..a47cdef6 100644 --- a/Algorithms.Tests/Sorters/Comparison/PancakeSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/PancakeSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/RandomPivotQuickSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/RandomPivotQuickSorterTests.cs index b634152a..1954e040 100644 --- a/Algorithms.Tests/Sorters/Comparison/RandomPivotQuickSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/RandomPivotQuickSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/SelectionSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/SelectionSorterTests.cs index 6297889f..0af23844 100644 --- a/Algorithms.Tests/Sorters/Comparison/SelectionSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/SelectionSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/ShellSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/ShellSorterTests.cs index 49c1632f..cac73054 100644 --- a/Algorithms.Tests/Sorters/Comparison/ShellSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/ShellSorterTests.cs @@ -22,6 +22,6 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs index c9b79caf..c02a13b1 100755 --- a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs @@ -23,7 +23,7 @@ public static void ArraySorted( Array.Sort(correctArray, IntComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } [Test] @@ -38,7 +38,7 @@ public static void TinyArray() sorter.Sort(tinyArray, IntComparer); // Assert - Assert.AreEqual(tinyArray, correctArray); + Assert.That(correctArray, Is.EqualTo(tinyArray)); } [Test] @@ -63,6 +63,6 @@ public static void SmallChunks() Array.Sort(correctArray, IntComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/External/ExternalMergeSorterTests.cs b/Algorithms.Tests/Sorters/External/ExternalMergeSorterTests.cs index 409bd2e6..06d9a8d2 100644 --- a/Algorithms.Tests/Sorters/External/ExternalMergeSorterTests.cs +++ b/Algorithms.Tests/Sorters/External/ExternalMergeSorterTests.cs @@ -26,7 +26,7 @@ public static void ArraySorted( Array.Sort(correctArray, intComparer); // Assert - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } [Test] @@ -61,6 +61,6 @@ public static void ArraySorted_OnDisk( testArray[i] = reader.Read(); } - Assert.AreEqual(testArray, correctArray); + Assert.That(correctArray, Is.EqualTo(testArray)); } } diff --git a/Algorithms.Tests/Sorters/Integer/BucketSorterTests.cs b/Algorithms.Tests/Sorters/Integer/BucketSorterTests.cs index 31436da9..4506b480 100644 --- a/Algorithms.Tests/Sorters/Integer/BucketSorterTests.cs +++ b/Algorithms.Tests/Sorters/Integer/BucketSorterTests.cs @@ -21,6 +21,6 @@ public static void ArraySorted( Array.Sort(correctArray); // Assert - Assert.AreEqual(correctArray, testArray); + Assert.That(testArray, Is.EqualTo(correctArray)); } } diff --git a/Algorithms.Tests/Sorters/Integer/CountingSorterTests.cs b/Algorithms.Tests/Sorters/Integer/CountingSorterTests.cs index 4ebe406a..c436ae1b 100644 --- a/Algorithms.Tests/Sorters/Integer/CountingSorterTests.cs +++ b/Algorithms.Tests/Sorters/Integer/CountingSorterTests.cs @@ -21,13 +21,21 @@ public static void SortsNonEmptyArray( Array.Sort(correctArray); // Assert - Assert.AreEqual(correctArray, testArray); + Assert.That(testArray, Is.EqualTo(correctArray)); } [Test] public static void SortsEmptyArray() { + // Arrange var sorter = new CountingSorter(); - sorter.Sort(Array.Empty()); + var (correctArray, testArray) = RandomHelper.GetArrays(0); + + // Act + sorter.Sort(testArray); + Array.Sort(correctArray); + + // Assert + Assert.That(testArray, Is.Empty); } } diff --git a/Algorithms.Tests/Sorters/Integer/RadixSorterTests.cs b/Algorithms.Tests/Sorters/Integer/RadixSorterTests.cs index 838ebdbe..7866613a 100644 --- a/Algorithms.Tests/Sorters/Integer/RadixSorterTests.cs +++ b/Algorithms.Tests/Sorters/Integer/RadixSorterTests.cs @@ -21,6 +21,6 @@ public static void SortsArray( Array.Sort(correctArray); // Assert - Assert.AreEqual(correctArray, testArray); + Assert.That(testArray, Is.EqualTo(correctArray)); } } diff --git a/Algorithms.Tests/Sorters/String/MsdRadixStringSorterTests.cs b/Algorithms.Tests/Sorters/String/MsdRadixStringSorterTests.cs index 278029a1..301e633c 100644 --- a/Algorithms.Tests/Sorters/String/MsdRadixStringSorterTests.cs +++ b/Algorithms.Tests/Sorters/String/MsdRadixStringSorterTests.cs @@ -24,6 +24,6 @@ public static void ArraySorted( Array.Sort(correctArray); // Assert - Assert.AreEqual(correctArray, testArray); + Assert.That(testArray, Is.EqualTo(correctArray)); } } diff --git a/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs b/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs index 6859f133..7c4849ba 100644 --- a/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs +++ b/Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs @@ -16,7 +16,7 @@ public static void MaxCountCharIsObtained(string text, char expectedSymbol, int var (symbol, count) = GeneralStringAlgorithms.FindLongestConsecutiveCharacters(text); // Assert - Assert.AreEqual(expectedSymbol, symbol); - Assert.AreEqual(expectedCount, count); + Assert.That(symbol, Is.EqualTo(expectedSymbol)); + Assert.That(count, Is.EqualTo(expectedCount)); } } diff --git a/Algorithms.Tests/Strings/PalindromeTests.cs b/Algorithms.Tests/Strings/PalindromeTests.cs index bcb91629..aa573a15 100644 --- a/Algorithms.Tests/Strings/PalindromeTests.cs +++ b/Algorithms.Tests/Strings/PalindromeTests.cs @@ -14,7 +14,7 @@ public static void TextIsPalindrome_TrueExpected(string text) var isPalindrome = Palindrome.IsStringPalindrome(text); // Assert - Assert.True(isPalindrome); + Assert.That(isPalindrome, Is.True); } [TestCase("hallo")] @@ -26,6 +26,6 @@ public static void TextNotPalindrome_FalseExpected(string text) var isPalindrome = Palindrome.IsStringPalindrome(text); // Assert - Assert.False(isPalindrome); + Assert.That(isPalindrome, Is.False); } } diff --git a/Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs b/Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs index be752221..8aaee455 100644 --- a/Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs @@ -13,6 +13,6 @@ public class BoyerMooreTests public void FindFirstOccurrence_IndexCheck(string t, string p, int expectedIndex) { var resultIndex = BoyerMoore.FindFirstOccurrence(t, p); - Assert.AreEqual(resultIndex, expectedIndex); + Assert.That(expectedIndex, Is.EqualTo(resultIndex)); } } diff --git a/Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs b/Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs index 96b63eb7..3271ea65 100644 --- a/Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs @@ -19,7 +19,7 @@ public static void FindIndexes_ItemsPresent_PassExpected() var actualItem = searcher.FindIndexes(str, pat); // Assert - CollectionAssert.AreEqual(expectedItem, actualItem); + Assert.That(actualItem, Is.EqualTo(expectedItem)); } [Test] @@ -34,7 +34,7 @@ public static void FindIndexes_ItemsMissing_NoIndexesReturned() var indexes = searcher.FindIndexes(str, pat); // Assert - Assert.IsEmpty(indexes); + Assert.That(indexes, Is.Empty); } [Test] @@ -49,7 +49,7 @@ public static void LongestPrefixSuffixArray_PrefixSuffixOfLength1_PassExpected() var actualItem = searcher.FindLongestPrefixSuffixValues(s); // Assert - CollectionAssert.AreEqual(expectedItem, actualItem); + Assert.That(actualItem, Is.EqualTo(expectedItem)); } [Test] @@ -64,7 +64,7 @@ public static void LongestPrefixSuffixArray_PrefixSuffixOfLength5_PassExpected() var actualItem = searcher.FindLongestPrefixSuffixValues(s); // Assert - CollectionAssert.AreEqual(expectedItem, actualItem); + Assert.That(actualItem, Is.EqualTo(expectedItem)); } [Test] @@ -79,6 +79,6 @@ public static void LongestPrefixSuffixArray_PrefixSuffixOfLength0_PassExpected() var actualItem = searcher.FindLongestPrefixSuffixValues(s); // Assert - CollectionAssert.AreEqual(expectedItem, actualItem); + Assert.That(actualItem, Is.EqualTo(expectedItem)); } } diff --git a/Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs b/Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs index f2624c12..954aca50 100644 --- a/Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs @@ -20,7 +20,7 @@ public static void ThreeMatchesFound_PassExpected() var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences); // Assert - Assert.IsTrue(sequencesAreEqual); + Assert.That(sequencesAreEqual, Is.True); } [Test] @@ -36,7 +36,7 @@ public static void OneMatchFound_PassExpected() var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences); // Assert - Assert.IsTrue(sequencesAreEqual); + Assert.That(sequencesAreEqual, Is.True); } [Test] @@ -52,6 +52,6 @@ public static void NoMatchFound_PassExpected() var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences); // Assert - Assert.IsTrue(sequencesAreEqual); + Assert.That(sequencesAreEqual, Is.True); } } diff --git a/Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs b/Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs index 7a2ee029..71c6b8d2 100644 --- a/Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs +++ b/Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs @@ -15,6 +15,6 @@ public class RabinKarpTest public void FindAllOccurrences_IndexCheck(string t, string p, int[] expectedIndices) { List result = RabinKarp.FindAllOccurrences(t, p); - Assert.AreEqual(result, new List(expectedIndices)); + Assert.That(result, Is.EqualTo(new List(expectedIndices))); } } diff --git a/Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs b/Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs index 8ff7dd4b..b76766d6 100644 --- a/Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs +++ b/Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs @@ -18,6 +18,6 @@ public class ZblockSubstringSearchTest public void Test(string pattern, string text, int expectedOccurences) { var occurencesFound = ZblockSubstringSearch.FindSubstring(pattern, text); - Assert.AreEqual(expectedOccurences, occurencesFound); + Assert.That(occurencesFound, Is.EqualTo(expectedOccurences)); } } diff --git a/Algorithms.Tests/Strings/PermutationTests.cs b/Algorithms.Tests/Strings/PermutationTests.cs index b4be153a..db160fc3 100644 --- a/Algorithms.Tests/Strings/PermutationTests.cs +++ b/Algorithms.Tests/Strings/PermutationTests.cs @@ -48,7 +48,7 @@ public void Test_GetEveryUniquePermutation(string word) { return current / Factorial.Calculate(keyValuePair.Value); }); - Assert.AreEqual(expectedNumberOfAnagrams, new BigInteger(permutations.Count)); + Assert.That(new BigInteger(permutations.Count), Is.EqualTo(expectedNumberOfAnagrams)); // End 1. // Start 2 @@ -56,12 +56,12 @@ public void Test_GetEveryUniquePermutation(string word) var wordSorted = SortString(word); foreach (var permutation in permutations) { - Assert.AreEqual(wordSorted, SortString(permutation)); + Assert.That(SortString(permutation), Is.EqualTo(wordSorted)); } // End 2 // Start 3 - Assert.AreEqual(permutations.Count, new HashSet(permutations).Count); + Assert.That(new HashSet(permutations).Count, Is.EqualTo(permutations.Count)); // End 3 } diff --git a/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs b/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs index d2fe0b78..4970ae03 100644 --- a/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs +++ b/Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs @@ -13,7 +13,7 @@ public class HammingDistanceTests public void Calculate_ReturnsCorrectHammingDistance(string s1, string s2, int expectedDistance) { var result = HammingDistance.Calculate(s1, s2); - Assert.AreEqual(expectedDistance, result); + Assert.That(result, Is.EqualTo(expectedDistance)); } [Test] diff --git a/Algorithms/Other/JulianEaster.cs b/Algorithms/Other/JulianEaster.cs index 0717a11a..a8649c26 100644 --- a/Algorithms/Other/JulianEaster.cs +++ b/Algorithms/Other/JulianEaster.cs @@ -24,7 +24,7 @@ public static DateTime Calculate(int year) var month = (int)Math.Floor((d + e + 114) / 31M); var day = ((d + e + 114) % 31) + 1; - DateTime easter = new(year, month, day, new JulianCalendar()); + DateTime easter = new(year, month, day, 00, 00, 00, DateTimeKind.Utc); return easter; } diff --git a/DataStructures.Tests/BinarySearchTreeTests.cs b/DataStructures.Tests/BinarySearchTreeTests.cs index 52870283..56aa2ccb 100644 --- a/DataStructures.Tests/BinarySearchTreeTests.cs +++ b/DataStructures.Tests/BinarySearchTreeTests.cs @@ -16,8 +16,9 @@ public static void Constructor_UseCustomComparer_FormsCorrectTree() var elems = new[] { "z", "yy", "vvv", "bbbb", "fffff", "pppppp" }; tree.AddRange(elems); - Assert.IsNotNull(tree.Search("vvv")); - Assert.AreEqual("bbbb", tree.Search("vvv")!.Right!.Key); + Assert.That(tree.Search("vvv"), Is.Not.Null); + Assert.That(tree.Search("vvv")!.Right, Is.Not.Null); + Assert.That(tree.Search("vvv")!.Right!.Key, Is.EqualTo("bbbb")); } [Test] @@ -26,34 +27,34 @@ public static void Add_MultipleKeys_FormsCorrectBST() var tree = new BinarySearchTree(); tree.Add(5); - Assert.AreEqual(1, tree.Count); + Assert.That(tree.Count, Is.EqualTo(1)); tree.Add(3); - Assert.AreEqual(2, tree.Count); + Assert.That(tree.Count, Is.EqualTo(2)); tree.Add(4); - Assert.AreEqual(3, tree.Count); + Assert.That(tree.Count, Is.EqualTo(3)); tree.Add(2); - Assert.AreEqual(4, tree.Count); + Assert.That(tree.Count, Is.EqualTo(4)); var rootNode = tree.Search(5); - Assert.AreEqual(5, rootNode!.Key); - Assert.AreEqual(3, rootNode!.Left!.Key); - Assert.IsNull(rootNode!.Right); + Assert.That(rootNode!.Key, Is.EqualTo(5)); + Assert.That(rootNode!.Left!.Key, Is.EqualTo(3)); + Assert.That(rootNode!.Right, Is.Null); var threeNode = tree.Search(3); - Assert.AreEqual(3, threeNode!.Key); - Assert.AreEqual(2, threeNode!.Left!.Key); - Assert.AreEqual(4, threeNode!.Right!.Key); + Assert.That(threeNode!.Key, Is.EqualTo(3)); + Assert.That(threeNode!.Left!.Key, Is.EqualTo(2)); + Assert.That(threeNode!.Right!.Key, Is.EqualTo(4)); var twoNode = tree.Search(2); - Assert.IsNull(twoNode!.Left); - Assert.IsNull(twoNode!.Right); + Assert.That(twoNode!.Left, Is.Null); + Assert.That(twoNode!.Right, Is.Null); var fourNode = tree.Search(4); - Assert.IsNull(fourNode!.Left); - Assert.IsNull(fourNode!.Right); + Assert.That(fourNode!.Left, Is.Null); + Assert.That(fourNode!.Right, Is.Null); } [Test] @@ -72,22 +73,22 @@ public static void AddRange_MultipleKeys_FormsCorrectBST() tree.AddRange(new List { 5, 3, 4, 2 }); var rootNode = tree.Search(5); - Assert.AreEqual(5, rootNode!.Key); - Assert.AreEqual(3, rootNode!.Left!.Key); - Assert.IsNull(rootNode!.Right); + Assert.That(rootNode!.Key, Is.EqualTo(5)); + Assert.That(rootNode!.Left!.Key, Is.EqualTo(3)); + Assert.That(rootNode!.Right, Is.Null); var threeNode = tree.Search(3); - Assert.AreEqual(3, threeNode!.Key); - Assert.AreEqual(2, threeNode!.Left!.Key); - Assert.AreEqual(4, threeNode!.Right!.Key); + Assert.That(threeNode!.Key, Is.EqualTo(3)); + Assert.That(threeNode!.Left!.Key, Is.EqualTo(2)); + Assert.That(threeNode!.Right!.Key, Is.EqualTo(4)); var twoNode = tree.Search(2); - Assert.IsNull(twoNode!.Left); - Assert.IsNull(twoNode!.Right); + Assert.That(twoNode!.Left, Is.Null); + Assert.That(twoNode!.Right, Is.Null); var fourNode = tree.Search(4); - Assert.IsNull(fourNode!.Left); - Assert.IsNull(fourNode!.Right); + Assert.That(fourNode!.Left, Is.Null); + Assert.That(fourNode!.Right, Is.Null); } [Test] @@ -96,13 +97,13 @@ public static void Search_MultipleKeys_FindsAllKeys() var tree = new BinarySearchTree(); tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - Assert.AreEqual(2, tree.Search(2)!.Key); - Assert.AreEqual(3, tree.Search(3)!.Key); - Assert.AreEqual(4, tree.Search(4)!.Key); - Assert.AreEqual(5, tree.Search(5)!.Key); - Assert.AreEqual(6, tree.Search(6)!.Key); - Assert.AreEqual(7, tree.Search(7)!.Key); - Assert.AreEqual(8, tree.Search(8)!.Key); + Assert.That(tree.Search(2)!.Key, Is.EqualTo(2)); + Assert.That(tree.Search(3)!.Key, Is.EqualTo(3)); + Assert.That(tree.Search(4)!.Key, Is.EqualTo(4)); + Assert.That(tree.Search(5)!.Key, Is.EqualTo(5)); + Assert.That(tree.Search(6)!.Key, Is.EqualTo(6)); + Assert.That(tree.Search(7)!.Key, Is.EqualTo(7)); + Assert.That(tree.Search(8)!.Key, Is.EqualTo(8)); } [Test] @@ -111,13 +112,13 @@ public static void Contains_MultipleKeys_FindsAllKeys() var tree = new BinarySearchTree(); tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - Assert.IsTrue(tree.Contains(2)); - Assert.IsTrue(tree.Contains(3)); - Assert.IsTrue(tree.Contains(4)); - Assert.IsTrue(tree.Contains(5)); - Assert.IsTrue(tree.Contains(6)); - Assert.IsTrue(tree.Contains(7)); - Assert.IsTrue(tree.Contains(8)); + Assert.That(tree.Contains(2), Is.True); + Assert.That(tree.Contains(3), Is.True); + Assert.That(tree.Contains(4), Is.True); + Assert.That(tree.Contains(5), Is.True); + Assert.That(tree.Contains(6), Is.True); + Assert.That(tree.Contains(7), Is.True); + Assert.That(tree.Contains(8), Is.True); } [Test] @@ -127,18 +128,18 @@ public static void Remove_LeafNodes_CorrectlyRemovesNodes() tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); var twoRemoveResult = tree.Remove(2); - Assert.IsTrue(twoRemoveResult); - Assert.IsNull(tree.Search(2)); - Assert.IsNull(tree.Search(3)!.Left); - Assert.IsNotNull(tree.Search(3)!.Right); - Assert.AreEqual(6, tree.Count); + Assert.That(twoRemoveResult, Is.True); + Assert.That(tree.Search(2), Is.Null); + Assert.That(tree.Search(3)!.Left, Is.Null); + Assert.That(tree.Search(3)!.Right, Is.Not.Null); + Assert.That(tree.Count, Is.EqualTo(6)); var fourRemoveResult = tree.Remove(4); - Assert.IsTrue(fourRemoveResult); - Assert.IsNull(tree.Search(4)); - Assert.IsNull(tree.Search(3)!.Left); - Assert.IsNull(tree.Search(3)!.Right); - Assert.AreEqual(5, tree.Count); + Assert.That(fourRemoveResult, Is.True); + Assert.That(tree.Search(4), Is.Null); + Assert.That(tree.Search(3)!.Left, Is.Null); + Assert.That(tree.Search(3)!.Right, Is.Null); + Assert.That(tree.Count, Is.EqualTo(5)); } [Test] @@ -149,19 +150,19 @@ public static void Remove_NodesWithOneChild_CorrectlyRemovesNodes() tree.Remove(4); var threeRemoveResult = tree.Remove(3); - Assert.IsTrue(threeRemoveResult); - Assert.IsNull(tree.Search(3)); - Assert.IsNull(tree.Search(2)!.Left); - Assert.IsNull(tree.Search(2)!.Right); - Assert.AreEqual(5, tree.Count); + Assert.That(threeRemoveResult, Is.True); + Assert.That(tree.Search(3), Is.Null); + Assert.That(tree.Search(2)!.Left, Is.Null); + Assert.That(tree.Search(2)!.Right, Is.Null); + Assert.That(tree.Count, Is.EqualTo(5)); tree.Remove(6); var sevenRemoveResult = tree.Remove(7); - Assert.IsTrue(sevenRemoveResult); - Assert.IsNull(tree.Search(7)); - Assert.IsNull(tree.Search(8)!.Left); - Assert.IsNull(tree.Search(8)!.Right); - Assert.AreEqual(3, tree.Count); + Assert.That(sevenRemoveResult, Is.True); + Assert.That(tree.Search(7), Is.Null); + Assert.That(tree.Search(8)!.Left, Is.Null); + Assert.That(tree.Search(8)!.Right, Is.Null); + Assert.That(tree.Count, Is.EqualTo(3)); } [Test] @@ -171,11 +172,11 @@ public static void Remove_NodesWithTwoChildren_CorrectlyRemovesNodes() tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); var sevenRemoveResult = tree.Remove(7); - Assert.IsTrue(sevenRemoveResult); - Assert.IsNull(tree.Search(7)); - Assert.IsNull(tree.Search(6)!.Left); - Assert.IsNotNull(tree.Search(6)!.Right); - Assert.AreEqual(6, tree.Count); + Assert.That(sevenRemoveResult, Is.True); + Assert.That(tree.Search(7), Is.Null); + Assert.That(tree.Search(6)!.Left, Is.Null); + Assert.That(tree.Search(6)!.Right, Is.Not.Null); + Assert.That(tree.Count, Is.EqualTo(6)); } [Test] @@ -184,16 +185,16 @@ public static void Remove_NonExistentElement_ReturnsFalse() var tree = new BinarySearchTree(); tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - Assert.IsFalse(tree.Remove(999)); - Assert.AreEqual(7, tree.Count); + Assert.That(tree.Remove(999), Is.False); + Assert.That(tree.Count, Is.EqualTo(7)); } [Test] public static void Remove_EmptyTree_ReturnsFalse() { var tree = new BinarySearchTree(); - Assert.IsFalse(tree.Remove(8)); - Assert.AreEqual(0, tree.Count); + Assert.That(tree.Remove(8), Is.False); + Assert.That(tree.Count, Is.EqualTo(0)); } [Test] @@ -203,17 +204,17 @@ public static void Remove_RemoveRoot_CorrectlyRemovesRoot() tree.Add(5); tree.Remove(5); - Assert.AreEqual(0, tree.Count); - Assert.IsNull(tree.Search(5)); + Assert.That(tree.Count, Is.EqualTo(0)); + Assert.That(tree.Search(5), Is.Null); tree.AddRange(new List { 5, 4, 6 }); tree.Remove(5); - Assert.AreEqual(2, tree.Count); - Assert.IsNull(tree.Search(5)); - Assert.IsNotNull(tree.Search(4)); - Assert.IsNotNull(tree.Search(6)); - Assert.AreEqual(6, tree.Search(4)!.Right!.Key); + Assert.That(tree.Count, Is.EqualTo(2)); + Assert.That(tree.Search(5), Is.Null); + Assert.That(tree.Search(4), Is.Not.Null); + Assert.That(tree.Search(6), Is.Not.Null); + Assert.That(tree.Search(4)!.Right!.Key, Is.EqualTo(6)); } [Test] @@ -222,14 +223,14 @@ public static void GetMax_NonEmptyTree_ReturnsCorrectValue() var tree = new BinarySearchTree(); tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - Assert.AreEqual(8, tree.GetMax()!.Key); + Assert.That(tree.GetMax()!.Key, Is.EqualTo(8)); } [Test] public static void GetMax_EmptyTree_ReturnsDefaultValue() { var tree = new BinarySearchTree(); - Assert.IsNull(tree.GetMax()); + Assert.That(tree.GetMax(), Is.Null); } [Test] @@ -238,14 +239,14 @@ public static void GetMin_NonEmptyTree_ReturnsCorrectValue() var tree = new BinarySearchTree(); tree.AddRange(new List { 5, 3, 4, 2, 7, 6, 8 }); - Assert.AreEqual(2, tree.GetMin()!.Key); + Assert.That(tree.GetMin()!.Key, Is.EqualTo(2)); } [Test] public static void GetMin_EmptyTree_ReturnsDefaultValue() { var tree = new BinarySearchTree(); - Assert.IsNull(tree.GetMin()); + Assert.That(tree.GetMin(), Is.Null); } [Test] @@ -256,7 +257,7 @@ public static void GetKeysInOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder() var keys = tree.GetKeysInOrder(); var expected = new List { 2, 3, 4, 5, 6, 7, 8 }; - Assert.IsTrue(keys.SequenceEqual(expected)); + Assert.That(keys.SequenceEqual(expected), Is.True); } [Test] @@ -267,7 +268,7 @@ public static void GetKeysPreOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder() var keys = tree.GetKeysPreOrder(); var expected = new List { 5, 3, 2, 4, 7, 6, 8 }; - Assert.IsTrue(keys.SequenceEqual(expected)); + Assert.That(keys.SequenceEqual(expected), Is.True); } [Test] @@ -278,6 +279,6 @@ public static void GetKeysPostOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder() var keys = tree.GetKeysPostOrder(); var expected = new List { 2, 4, 3, 6, 8, 7, 5 }; - Assert.IsTrue(keys.SequenceEqual(expected)); + Assert.That(keys.SequenceEqual(expected), Is.True); } } diff --git a/DataStructures.Tests/BitArrayTests.cs b/DataStructures.Tests/BitArrayTests.cs index d99f8b8b..e4555dd1 100644 --- a/DataStructures.Tests/BitArrayTests.cs +++ b/DataStructures.Tests/BitArrayTests.cs @@ -19,9 +19,9 @@ public static void TestIndexer() testObj.Compile(24); // Assert - Assert.IsTrue(testObj[0]); - Assert.IsTrue(testObj[1]); - Assert.IsFalse(testObj[3]); + Assert.That(testObj[0], Is.True); + Assert.That(testObj[1], Is.True); + Assert.That(testObj[3], Is.False); } [TestCase(19, 3)] @@ -34,7 +34,7 @@ public static void TestNumberOfOneBits(int number, int expected) testObj.Compile(number); // Assert - Assert.AreEqual(expected, testObj.NumberOfOneBits()); + Assert.That(expected, Is.EqualTo(testObj.NumberOfOneBits())); } [TestCase(26, 2)] @@ -47,7 +47,7 @@ public static void TestNumberOfZeroBits(int number, int expected) testObj.Compile(number); // Assert - Assert.AreEqual(expected, testObj.NumberOfZeroBits()); + Assert.That(expected, Is.EqualTo(testObj.NumberOfZeroBits())); } [TestCase(33, 33)] @@ -60,7 +60,7 @@ public static void TestToInt64(int number, int expected) testObj.Compile(number); // Assert - Assert.AreEqual(expected, testObj.ToInt64()); + Assert.That(expected, Is.EqualTo(testObj.ToInt64())); } [Test] @@ -97,7 +97,7 @@ public static void TestResetField(string sequence) testObj.ResetField(); // Assert - Assert.AreEqual(0, testObj.ToInt64()); + Assert.That(0, Is.EqualTo(testObj.ToInt64())); } [TestCase("101001", 63)] @@ -110,7 +110,7 @@ public static void TestSetAll(string sequence, int expected) testObj.SetAll(true); // Assert - Assert.AreEqual(expected, testObj.ToInt64()); + Assert.That(expected, Is.EqualTo(testObj.ToInt64())); } [Test] @@ -123,7 +123,7 @@ public static void TestCloneEquals() var testObj2 = (BitArray)testObj1.Clone(); // Assert - Assert.IsTrue(testObj1.Equals(testObj2)); + Assert.That(testObj1.Equals(testObj2), Is.True); } [Test] @@ -154,8 +154,8 @@ public static void TestHasCode() var result = testObj.GetHashCode(); // Assert - Assert.NotNull(result); - Assert.AreEqual(5, result); + Assert.That(result, Is.Not.Null); + Assert.That(5, Is.EqualTo(result)); } [Test] @@ -178,8 +178,8 @@ public static void TestMoveNextCurrent() } } - Assert.AreEqual(counterOnes, 5); - Assert.AreEqual(counterZeros, 2); + Assert.That(counterOnes, Is.EqualTo(5)); + Assert.That(counterZeros, Is.EqualTo(2)); } [Test] @@ -216,7 +216,7 @@ public static void TestCompileToString(string sequence, string expectedSequence) testObj.Compile(sequence); // Assert - Assert.AreEqual(expectedSequence, testObj.ToString()); + Assert.That(expectedSequence, Is.EqualTo(testObj.ToString())); } [TestCase("klgml", 5)] @@ -245,7 +245,7 @@ public static void TestCompileLong(int number, string expected) testObj.Compile((long)number); // Assert - Assert.AreEqual(expected, testObj.ToString()); + Assert.That(expected, Is.EqualTo(testObj.ToString())); } [TestCase(46, 3)] @@ -274,7 +274,7 @@ public static void TestCompileInteger(int number, string expected) testObj.Compile(number); // Assert - Assert.AreEqual(expected, testObj.ToString()); + Assert.That(expected, Is.EqualTo(testObj.ToString())); } [TestCase(-8, 5)] @@ -304,7 +304,7 @@ public static void TestConstructor(string sequence, int expected) // Act // Assert - Assert.AreEqual(expected, testObj1.ToInt64()); + Assert.That(expected, Is.EqualTo(testObj1.ToInt64())); } [TestCase(new[] { true, false, true }, 5)] @@ -316,7 +316,7 @@ public static void TestConstructorBoolArray(bool[] sequence, int expected) // Act // Assert - Assert.AreEqual(expected, testObj3.ToInt64()); + Assert.That(expected, Is.EqualTo(testObj3.ToInt64())); } [TestCase("000120")] @@ -351,7 +351,7 @@ public static void TestOperatorAnd(int tObj1, int tObj2, string expected) var result = testObj1 & testObj2; // Assert - Assert.AreEqual(expected, result.ToString()); + Assert.That(expected, Is.EqualTo(result.ToString())); } [TestCase(1, 1, 1, 1, "0")] @@ -369,7 +369,7 @@ public static void TestOperatorXorAndDiffSizes(int t1, int s1, int t2, int s2, s var result = testObj1 ^ testObj2; // Assert - Assert.AreEqual(expected, result.ToString()); + Assert.That(expected, Is.EqualTo(result.ToString())); } [TestCase(9, 4, 4, 3, "1101")] @@ -387,7 +387,7 @@ public static void TestOperatorOrAndDiffSizes(int t1, int s1, int t2, int s2, st var result = testObj1 | testObj2; // Assert - Assert.AreEqual(expected, result.ToString()); + Assert.That(expected, Is.EqualTo(result.ToString())); } [TestCase(1, 1, 1, 1, "1")] @@ -405,7 +405,7 @@ public static void TestOperatorAndAndDiffSizes(int t1, int s1, int t2, int s2, s var result = testObj1 & testObj2; // Assert - Assert.AreEqual(expected, result.ToString()); + Assert.That(expected, Is.EqualTo(result.ToString())); } [TestCase(25, 30, "11111")] @@ -422,7 +422,7 @@ public static void TestOperatorOr(int tObj1, int tObj2, string expected) var result = testObj1 | testObj2; // Assert - Assert.AreEqual(expected, result.ToString()); + Assert.That(expected, Is.EqualTo(result.ToString())); } [TestCase(16, "01111")] @@ -436,7 +436,7 @@ public static void TestOperatorNot(int number, string expected) testObj = ~testObj; // Assert - Assert.AreEqual(expected, testObj.ToString()); + Assert.That(expected, Is.EqualTo(testObj.ToString())); } [TestCase(25, 30, 7)] @@ -453,7 +453,7 @@ public static void TestOperatorXor(int testNum, int testNum2, int expected) var result = testObj1 ^ testObj2; // Assert - Assert.AreEqual(expected, result.ToInt32()); + Assert.That(expected, Is.EqualTo(result.ToInt32())); } [TestCase(16, "10000000")] @@ -467,7 +467,7 @@ public static void TestOperatorShiftLeft(int number, string expected) testObj <<= 3; // Assert - Assert.AreEqual(expected, testObj.ToString()); + Assert.That(expected, Is.EqualTo(testObj.ToString())); } [TestCase(24, "110")] @@ -481,7 +481,7 @@ public static void TestOperatorShiftRight(int number, string expected) testObj >>= 2; // Assert - Assert.AreEqual(expected, testObj.ToString()); + Assert.That(expected, Is.EqualTo(testObj.ToString())); } #endregion OPERATOR TESTS @@ -498,8 +498,8 @@ public static void TestParity() testObj.Compile(26); // Assert - Assert.IsFalse(testObj.EvenParity()); - Assert.IsTrue(testObj.OddParity()); + Assert.That(testObj.EvenParity(), Is.False); + Assert.That(testObj.OddParity(), Is.True); } [Test] @@ -513,8 +513,8 @@ public static void TestCompare() // Act // Assert - Assert.IsTrue(testObj1 == testObj2); - Assert.IsTrue(testObj1 != testObj3); + Assert.That(testObj1 == testObj2, Is.True); + Assert.That(testObj1 != testObj3, Is.True); } [Test] @@ -527,7 +527,7 @@ public static void ArraysOfDifferentLengthsAreNotEqual() // Act // Assert - Assert.False(testObj1 == testObj2); + Assert.That(testObj1 == testObj2, Is.False); } #endregion COMPARE TESTS diff --git a/DataStructures.Tests/DataStructures.Tests.csproj b/DataStructures.Tests/DataStructures.Tests.csproj index 59e783c3..67e2d0a2 100644 --- a/DataStructures.Tests/DataStructures.Tests.csproj +++ b/DataStructures.Tests/DataStructures.Tests.csproj @@ -20,8 +20,8 @@ - - + + diff --git a/DataStructures.Tests/Hashing/HashTableTests.cs b/DataStructures.Tests/Hashing/HashTableTests.cs index 786d2770..bf0658ea 100644 --- a/DataStructures.Tests/Hashing/HashTableTests.cs +++ b/DataStructures.Tests/Hashing/HashTableTests.cs @@ -33,7 +33,7 @@ public void Add_IncreasesCount_WhenKeyDoesNotExist() hashTable.Add("a", 1); - Assert.AreEqual(1, hashTable.Count); + Assert.That(hashTable.Count, Is.EqualTo(1)); } [Test] @@ -50,7 +50,7 @@ public void Add_DoesNotIncreaseCount_WhenKeyAlreadyExists() { Console.WriteLine("ArgumentException"); } - Assert.AreEqual(1, hashTable.Count); + Assert.That(hashTable.Count, Is.EqualTo(1)); } [Test] @@ -66,9 +66,9 @@ public void Add_IncreasesCount_WhenValueDoesNotExist() { var hashTable = new HashTable(); - hashTable.Add("a", 1); + hashTable.Add("b", 1); - Assert.AreEqual(1, hashTable.Count); + Assert.That(hashTable.Count, Is.EqualTo(1)); } [Test] @@ -87,7 +87,7 @@ public void Add_DoesNotIncreaseCount_WhenValueAlreadyExists() Console.WriteLine("ArgumentException"); } - Assert.AreEqual(2, hashTable.Count); + Assert.That(hashTable.Count, Is.EqualTo(2)); } [Test] @@ -103,7 +103,7 @@ public void Add_IncreasesCount_WhenValueIsNull() { Console.WriteLine("ArgumentNullException"); } - Assert.AreEqual(0, hashTable.Count); + Assert.That(hashTable.Count, Is.EqualTo(0)); } [Test] @@ -113,7 +113,7 @@ public void Add_IncreasesCount_WhenValueAlreadyExists() hashTable.Add("a", 1); hashTable.Add("b", 1); - Assert.AreEqual(2, hashTable.Count); + Assert.That(hashTable.Count, Is.EqualTo(2)); } [Test] @@ -129,7 +129,7 @@ public void Remove_ReturnsFalse_WhenKeyDoesNotExist() { var hashTable = new HashTable(); - Assert.IsFalse(hashTable.Remove("a")); + Assert.That(hashTable.Remove("a"), Is.False); } [Test] @@ -139,7 +139,7 @@ public void Remove_ReturnsTrue_WhenKeyExists() hashTable.Add("a", 1); - Assert.IsTrue(hashTable.Remove("a")); + Assert.That(hashTable.Remove("a"), Is.True); } [Test] @@ -150,7 +150,7 @@ public void Remove_DecreasesCount_WhenKeyExists() hashTable.Add("a", 1); hashTable.Remove("a"); - Assert.AreEqual(0, hashTable.Count); + Assert.That(hashTable.Count, Is.EqualTo(0)); } [Test] @@ -160,7 +160,7 @@ public void Remove_DoesNotDecreaseCount_WhenKeyDoesNotExist() hashTable.Remove("a"); - Assert.AreEqual(0, hashTable.Count); + Assert.That(hashTable.Count, Is.EqualTo(0)); } [Test] @@ -168,7 +168,7 @@ public void ContainsValue_ReturnsFalse_WhenValueDoesNotExist() { var hashTable = new HashTable(); - Assert.IsFalse(hashTable.ContainsValue(1)); + Assert.That(hashTable.ContainsValue(1), Is.False); } [Test] @@ -178,7 +178,7 @@ public void ContainsValue_ReturnsTrue_WhenValueExists() hashTable.Add("a", 1); - Assert.IsTrue(hashTable.ContainsValue(1)); + Assert.That(hashTable.ContainsValue(1), Is.True); } [Test] @@ -194,7 +194,7 @@ public void ContainsKey_ReturnsFalse_WhenKeyDoesNotExist() { var hashTable = new HashTable(); - Assert.IsFalse(hashTable.ContainsKey("a")); + Assert.That(hashTable.ContainsKey("a"), Is.False); } [Test] @@ -204,7 +204,7 @@ public void ContainsKey_ReturnsTrue_WhenKeyExists() hashTable.Add("a", 1); - Assert.IsTrue(hashTable.ContainsKey("a")); + Assert.That(hashTable.ContainsKey("a"), Is.True); } [Test] @@ -223,7 +223,7 @@ public void Clear_SetsCountToZero() hashTable.Add("a", 1); hashTable.Clear(); - Assert.AreEqual(0, hashTable.Count); + Assert.That(hashTable.Count, Is.EqualTo(0)); } [Test] @@ -234,7 +234,7 @@ public void Clear_RemovesAllElements() hashTable.Add("a", 1); hashTable.Clear(); - Assert.IsFalse(hashTable.ContainsKey("a")); + Assert.That(hashTable.ContainsKey("a"), Is.False); } [Test] @@ -251,7 +251,7 @@ public void Resize_IncreasesCapacity() /// Next Prime number after 4 is 5 /// Capacity should be 5 /// After resizing, the capacity should be 10 - Assert.AreEqual(10, hashTable.Capacity); + Assert.That(hashTable.Capacity, Is.EqualTo(10)); } [Test] public void LoadFactor_ReturnsCorrectValue() @@ -263,7 +263,7 @@ public void LoadFactor_ReturnsCorrectValue() hashTable.Add("three", 3); hashTable.Add("four", 4); hashTable.Add("humour", 5); - Assert.AreEqual(0.75f, hashTable.LoadFactor); + Assert.That(hashTable.LoadFactor, Is.EqualTo(0.75f)); } [Test] @@ -276,7 +276,7 @@ public void Keys_ReturnsCorrectKeys() var keys = new List { 1,2,3 }; - CollectionAssert.AreEquivalent(keys, hashTable.Keys); + Assert.That(keys, Is.EquivalentTo(hashTable.Keys)); } [Test] @@ -289,7 +289,7 @@ public void Values_ReturnsCorrectValues() var values = new List { "one", "two", "three" }; - CollectionAssert.AreEquivalent(values, hashTable?.Values); + Assert.That(values, Is.EquivalentTo(hashTable.Values)); } [Test] @@ -353,7 +353,7 @@ public void This_Get_ReturnsCorrectValue() { var hashTable = new HashTable(4); hashTable.Add("one", 1); - Assert.AreEqual(1, hashTable["one"]); + Assert.That(hashTable["one"], Is.EqualTo(1)); } [Test] @@ -362,7 +362,7 @@ public void This_Set_UpdatesValue() var hashTable = new HashTable(4); hashTable.Add("one", 1); hashTable["one"] = 2; - Assert.AreEqual(2, hashTable["one"]); + Assert.That(hashTable["one"], Is.EqualTo(2)); } [Test] diff --git a/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs b/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs index c2f32d88..c446a31f 100644 --- a/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs +++ b/DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs @@ -93,17 +93,17 @@ public static class PrimeNumberTests new object[] { 10, 1, true, 7 } }; - [TestCaseSource("IsPrimeSource")] + [TestCaseSource(nameof(IsPrimeSource))] public static void IsPrimeTest(int number, bool expected) { var actual = PrimeNumber.IsPrime(number); - Assert.AreEqual(expected, actual); + Assert.That(expected, Is.EqualTo(actual)); } - [TestCaseSource("NextPrimeSource")] + [TestCaseSource(nameof(NextPrimeSource))] public static void NextPrimeTest(int number, int factor, bool desc, int expected) { var actual = PrimeNumber.NextPrime(number, factor, desc); - Assert.AreEqual(expected, actual); + Assert.That(expected, Is.EqualTo(actual)); } } diff --git a/DataStructures.Tests/Heap/BinaryHeapTests.cs b/DataStructures.Tests/Heap/BinaryHeapTests.cs index 3ebdf9c6..b348eb1b 100644 --- a/DataStructures.Tests/Heap/BinaryHeapTests.cs +++ b/DataStructures.Tests/Heap/BinaryHeapTests.cs @@ -28,10 +28,10 @@ public static void Constructor_UseCustomComparer_BuildCorrectHeap() revHeap.Push(i); } - Assert.AreEqual(10, revHeap.Count); - Assert.AreEqual(1, revHeap.Peek()); - Assert.AreEqual(1, revHeap.Pop()); - Assert.AreEqual(2, revHeap.Peek()); + Assert.That(revHeap.Count, Is.EqualTo(10)); + Assert.That(revHeap.Peek(), Is.EqualTo(1)); + Assert.That(revHeap.Pop(), Is.EqualTo(1)); + Assert.That(revHeap.Peek(), Is.EqualTo(2)); } [Test] @@ -39,24 +39,24 @@ public static void Push_AddElements_BuildCorrectHeap() { var heap = BuildTestHeap(); - Assert.AreEqual(10, heap.Peek()); - Assert.AreEqual(10, heap.Count); + Assert.That(heap.Peek(), Is.EqualTo(10)); + Assert.That(heap.Count, Is.EqualTo(10)); } public static void Pop_RemoveElements_HeapStillValid() { var heap = BuildTestHeap(); - Assert.AreEqual(10, heap.Peek()); - Assert.AreEqual(10, heap.Count); + Assert.That(heap.Peek(), Is.EqualTo(10)); + Assert.That(heap.Count, Is.EqualTo(10)); - Assert.AreEqual(10, heap.Pop()); - Assert.AreEqual(9, heap.Count); - Assert.IsFalse(heap.Contains(10)); + Assert.That(heap.Pop(), Is.EqualTo(10)); + Assert.That(heap.Count, Is.EqualTo(9)); + Assert.That(heap.Contains(10),Is.False); - Assert.AreEqual(9, heap.Pop()); - Assert.AreEqual(8, heap.Count); - Assert.IsFalse(heap.Contains(9)); + Assert.That(heap.Pop(), Is.EqualTo(9)); + Assert.That(heap.Count, Is.EqualTo(8)); + Assert.That(heap.Contains(9), Is.False); } [Test] @@ -72,7 +72,7 @@ public static void Peek_NonEmptyHeap_ReturnsCorrectAnswer() { var heap = BuildTestHeap(); - Assert.AreEqual(10, heap.Peek()); + Assert.That(heap.Peek(), Is.EqualTo(10)); } [Test] @@ -88,7 +88,7 @@ public static void PushPop_EmptyHeap_ReturnsCorrectAnswer() { var heap = new BinaryHeap(); - Assert.AreEqual(10, heap.PushPop(10)); + Assert.That(heap.PushPop(10), Is.EqualTo(10)); } [Test] @@ -96,8 +96,8 @@ public static void PushPop_NonEmptyHeap_ReturnsCorrectAnswer() { var heap = BuildTestHeap(); - Assert.AreEqual(20, heap.PushPop(20)); - Assert.AreEqual(10, heap.PushPop(-10)); + Assert.That(heap.PushPop(20), Is.EqualTo(20)); + Assert.That(heap.PushPop(-10), Is.EqualTo(10)); } [Test] @@ -105,10 +105,10 @@ public static void Contains_NonEmptyHeap_ReturnsCorrectAnswer() { var heap = BuildTestHeap(); - Assert.IsTrue(heap.Contains(1)); - Assert.IsTrue(heap.Contains(5)); - Assert.IsTrue(heap.Contains(10)); - Assert.IsFalse(heap.Contains(11)); + Assert.That(heap.Contains(1), Is.True); + Assert.That(heap.Contains(5), Is.True); + Assert.That(heap.Contains(10), Is.True); + Assert.That(heap.Contains(11), Is.False); } [Test] @@ -116,10 +116,10 @@ public static void Contains_EmptyHeap_ReturnsCorrectAnswer() { var heap = new BinaryHeap(); - Assert.IsFalse(heap.Contains(1)); - Assert.IsFalse(heap.Contains(5)); - Assert.IsFalse(heap.Contains(10)); - Assert.IsFalse(heap.Contains(11)); + Assert.That(heap.Contains(1), Is.False); + Assert.That(heap.Contains(5), Is.False); + Assert.That(heap.Contains(10), Is.False); + Assert.That(heap.Contains(11), Is.False); } [Test] @@ -128,19 +128,19 @@ public static void Remove_NonEmptyHeap_HeapStillValid() var heap = BuildTestHeap(); heap.Remove(2); - Assert.IsFalse(heap.Contains(2)); - Assert.AreEqual(10, heap.Peek()); - Assert.AreEqual(9, heap.Count); + Assert.That(heap.Contains(2), Is.False); + Assert.That(heap.Peek(), Is.EqualTo(10)); + Assert.That(heap.Count, Is.EqualTo(9)); heap.Remove(8); - Assert.IsFalse(heap.Contains(8)); - Assert.AreEqual(10, heap.Peek()); - Assert.AreEqual(8, heap.Count); + Assert.That(heap.Contains(8), Is.False); + Assert.That(heap.Peek(), Is.EqualTo(10)); + Assert.That(heap.Count, Is.EqualTo(8)); heap.Remove(5); - Assert.IsFalse(heap.Contains(5)); - Assert.AreEqual(10, heap.Peek()); - Assert.AreEqual(7, heap.Count); + Assert.That(heap.Contains(5), Is.False); + Assert.That(heap.Peek(), Is.EqualTo(10)); + Assert.That(heap.Count, Is.EqualTo(7)); Assert.Throws(() => heap.Remove(11)); } diff --git a/DataStructures.Tests/Heap/FibonacciHeaps/FibonacciHeapTests.cs b/DataStructures.Tests/Heap/FibonacciHeaps/FibonacciHeapTests.cs index 300a340f..2a996393 100644 --- a/DataStructures.Tests/Heap/FibonacciHeaps/FibonacciHeapTests.cs +++ b/DataStructures.Tests/Heap/FibonacciHeaps/FibonacciHeapTests.cs @@ -41,22 +41,22 @@ public static void Push_AddElements_BuildCorrectHeap() { var heap = BuildTestHeap(); - Assert.AreEqual(1, heap.Peek()); - Assert.AreEqual(10, heap.Count); + Assert.That(heap.Peek(),Is.EqualTo(1)); + Assert.That(heap.Count, Is.EqualTo(10)); } public static void Pop_RemoveElements_HeapStillValid() { var heap = BuildTestHeap(); - Assert.AreEqual(1, heap.Peek()); - Assert.AreEqual(10, heap.Count); + Assert.That(heap.Peek(), Is.EqualTo(1)); + Assert.That(heap.Count, Is.EqualTo(10)); - Assert.AreEqual(1, heap.Pop()); - Assert.AreEqual(9, heap.Count); + Assert.That(heap.Pop(), Is.EqualTo(1)); + Assert.That(heap.Count, Is.EqualTo(9)); - Assert.AreEqual(2, heap.Pop()); - Assert.AreEqual(8, heap.Count); + Assert.That(heap.Pop(), Is.EqualTo(2)); + Assert.That(heap.Count, Is.EqualTo(8)); } [Test] @@ -85,11 +85,11 @@ public static void Pop_NonEmptyHeap_ReturnsInSortedOrder() for (var i = 0; i < heapSize - 1; i++) { var newElement = heap.Pop(); - Assert.LessOrEqual(element, newElement); + Assert.That(element, Is.LessThanOrEqualTo(newElement)); element = newElement; } - Assert.Zero(heap.Count); + Assert.That(heap.Count, Is.Zero); } [Test] @@ -108,15 +108,15 @@ public static void DecreaseKey_NonEmptyHeap_ReturnsCorrectAnswer() var node = heap.Push(11); heap.DecreaseKey(node, -1); - Assert.AreEqual(heap.Pop(), -1); - Assert.AreEqual(heap.Pop(), 1); + Assert.That(heap.Pop(), Is.EqualTo(-1)); + Assert.That(heap.Pop(), Is.EqualTo(1)); node = heap.Push(5); heap.DecreaseKey(node, 1); - Assert.AreEqual(heap.Pop(), 1); + Assert.That(heap.Pop(), Is.EqualTo(1)); - Assert.AreEqual(heap.Pop(), 2); - Assert.AreEqual(heap.Pop(), 3); + Assert.That(heap.Pop(), Is.EqualTo(2)); + Assert.That(heap.Pop(), Is.EqualTo(3)); } [Test] @@ -140,11 +140,11 @@ public static void Union_NonEmptyHeap_ReturnsSortedOrder() for (var i = 0; i < 10; i++) { - Assert.AreEqual(i, oddHeap.Pop()); + Assert.That(oddHeap.Pop(), Is.EqualTo(i)); } - Assert.Zero(oddHeap.Count); - Assert.Zero(evenHeap.Count); + Assert.That(oddHeap.Count, Is.Zero); + Assert.That(evenHeap.Count, Is.Zero); } [Test] @@ -156,15 +156,15 @@ public static void Union_EmptyHeap_BecomesOtherHeap() var minNode = otherHeap.Peek(); var otherCount = otherHeap.Count; - Assert.Zero(thisHeap.Count); + Assert.That(thisHeap.Count, Is.Zero); thisHeap.Union(otherHeap); - Assert.Zero(otherHeap.Count); - Assert.AreEqual(thisHeap.Peek(), minNode); + Assert.That(otherHeap.Count, Is.Zero); + Assert.That(minNode, Is.EqualTo(thisHeap.Peek())); Assert.Throws(() => otherHeap.Peek()); - Assert.AreEqual(otherCount, thisHeap.Count); + Assert.That(thisHeap.Count, Is.EqualTo(otherCount)); } [Test] @@ -178,8 +178,8 @@ public static void Union_FullHeapWithEmptyHeap_Unchanged() thisHeap.Union(otherHeap); - Assert.AreEqual(thisHeap.Count, previousCount); - Assert.AreEqual(thisHeap.Peek(), previousMin); + Assert.That(previousCount, Is.EqualTo(thisHeap.Count)); + Assert.That(previousMin, Is.EqualTo(thisHeap.Peek())); } [Test] @@ -220,25 +220,25 @@ public static void DecreaseKey_NonEmptyHeap_PreservesHeapStructure() var bigItem = heap.Push(20); heap.DecreaseKey(item, -1); - Assert.AreEqual(heap.Pop(), -1); + Assert.That(-1, Is.EqualTo(heap.Pop())); var currentVal = -1; for (var i = 0; i < 10; i++) { var newVal = heap.Pop(); - Assert.True(currentVal < newVal); + Assert.That(currentVal < newVal, Is.True); currentVal = newVal; } heap.DecreaseKey(bigItem, -1); - Assert.AreEqual(heap.Pop(), -1); + Assert.That(-1, Is.EqualTo(heap.Pop())); currentVal = -1; for (var i = 0; i < 9; i++) { var newVal = heap.Pop(); - Assert.True(currentVal < newVal); + Assert.That(currentVal < newVal, Is.True); currentVal = newVal; } diff --git a/DataStructures.Tests/Heap/MinMaxHeapTests.cs b/DataStructures.Tests/Heap/MinMaxHeapTests.cs index 2a756d18..06d749f0 100644 --- a/DataStructures.Tests/Heap/MinMaxHeapTests.cs +++ b/DataStructures.Tests/Heap/MinMaxHeapTests.cs @@ -16,7 +16,6 @@ public static class MinMaxHeapTests new[] { "abc", "abc", "xyz", "bcd", "klm", "opq", "ijk" }, }; - [Test] public static void CustomComparerTest() { @@ -29,12 +28,12 @@ public static void CustomComparerTest() mmh.Add(s); } - Assert.AreEqual(comparer, mmh.Comparer); - Assert.AreEqual("c", mmh.GetMin()); - Assert.AreEqual("aaaa", mmh.GetMax()); + Assert.That(comparer, Is.EqualTo(mmh.Comparer)); + Assert.That("c", Is.EqualTo(mmh.GetMin())); + Assert.That("aaaa", Is.EqualTo(mmh.GetMax())); } - [TestCaseSource("CollectionsSource")] + [TestCaseSource(nameof(CollectionsSource))] public static void AddTest(IEnumerable collection) { var mmh = new MinMaxHeap(); @@ -46,71 +45,70 @@ public static void AddTest(IEnumerable collection) var minValue = mmh.GetMin(); var maxValue = mmh.GetMax(); - Assert.AreEqual(collection.Min(), minValue); - Assert.AreEqual(collection.Max(), maxValue); - Assert.AreEqual(collection.Count(), mmh.Count); + Assert.That(collection.Min(), Is.EqualTo(minValue)); + Assert.That(collection.Max(), Is.EqualTo(maxValue)); + Assert.That(collection.Count(), Is.EqualTo(mmh.Count)); } - [TestCaseSource("CollectionsSource")] + [TestCaseSource(nameof(CollectionsSource))] public static void ExtractMaxTest(IEnumerable collection) { var ordered = collection.OrderByDescending(x => x); var mmh = new MinMaxHeap(collection); - var emptyHeap = new MinMaxHeap(); + var emptyHeap = new MinMaxHeap(); var first = mmh.ExtractMax(); var second = mmh.GetMax(); Assert.Throws(() => emptyHeap.ExtractMax()); - Assert.AreEqual(ordered.ElementAt(0), first); - Assert.AreEqual(ordered.ElementAt(1), second); - Assert.AreEqual(collection.Count() - 1, mmh.Count); + Assert.That(ordered.ElementAt(0), Is.EqualTo(first)); + Assert.That(ordered.ElementAt(1), Is.EqualTo(second)); + Assert.That(collection.Count() - 1, Is.EqualTo(mmh.Count)); } - [TestCaseSource("CollectionsSource")] + [TestCaseSource(nameof(CollectionsSource))] public static void ExtractMinTest(IEnumerable collection) { var ordered = collection.OrderBy(x => x); var mmh = new MinMaxHeap(collection); - var emptyHeap = new MinMaxHeap(); + var emptyHeap = new MinMaxHeap(); var first = mmh.ExtractMin(); var second = mmh.GetMin(); Assert.Throws(() => emptyHeap.ExtractMin()); - Assert.AreEqual(ordered.ElementAt(0), first); - Assert.AreEqual(ordered.ElementAt(1), second); - Assert.AreEqual(collection.Count() - 1, mmh.Count); + Assert.That(ordered.ElementAt(0), Is.EqualTo(first)); + Assert.That(ordered.ElementAt(1), Is.EqualTo(second)); + Assert.That(collection.Count() - 1, Is.EqualTo(mmh.Count)); } - - [TestCaseSource("CollectionsSource")] + [TestCaseSource(nameof(CollectionsSource))] public static void GetMaxTest(IEnumerable collection) { - var emptyHeap = new MinMaxHeap(); + var emptyHeap = new MinMaxHeap(); var mmh = new MinMaxHeap(collection); var maxValue = mmh.GetMax(); Assert.Throws(() => emptyHeap.GetMax()); - Assert.AreEqual(collection.Max(), maxValue); + Assert.That(collection.Max(), Is.EqualTo(maxValue)); } - [TestCaseSource("CollectionsSource")] + [TestCaseSource(nameof(CollectionsSource))] public static void GetMinTest(IEnumerable collection) { - var emptyHeap = new MinMaxHeap(); + var emptyHeap = new MinMaxHeap(); var mmh = new MinMaxHeap(collection); var minValue = mmh.GetMin(); Assert.Throws(() => emptyHeap.GetMin()); - Assert.AreEqual(collection.Min(), minValue); + Assert.That(collection.Min(), Is.EqualTo(minValue)); } [Test] public static void HeapSortUsingGet( - [ValueSource("CollectionsSource")] IEnumerable collection, + [ValueSource(nameof(CollectionsSource))] IEnumerable collection, [Values] bool ascending) { var ordered = ascending ? collection.OrderBy(x => x) : collection.OrderByDescending(x => x); @@ -134,12 +132,12 @@ public static void HeapSortUsingGet( extracted.Add(value); } - Assert.IsTrue(ordered.SequenceEqual(extracted)); + Assert.That(ordered.SequenceEqual(extracted), Is.True); } [Test] public static void HeapSortUsingExtract( - [ValueSource("CollectionsSource")] IEnumerable collection, + [ValueSource(nameof(CollectionsSource))] IEnumerable collection, [Values] bool ascending) { var ordered = ascending ? collection.OrderBy(x => x) : collection.OrderByDescending(x => x); @@ -152,6 +150,6 @@ public static void HeapSortUsingExtract( extracted.Add(value); } - Assert.IsTrue(ordered.SequenceEqual(extracted)); + Assert.That(ordered.SequenceEqual(extracted), Is.True); } } diff --git a/DataStructures.Tests/Heap/PairingHeap/PairingHeapTests.cs b/DataStructures.Tests/Heap/PairingHeap/PairingHeapTests.cs index c2a9630d..e295714e 100644 --- a/DataStructures.Tests/Heap/PairingHeap/PairingHeapTests.cs +++ b/DataStructures.Tests/Heap/PairingHeap/PairingHeapTests.cs @@ -74,10 +74,10 @@ public void BuildMinHeap_CreateHeap_HeapIsCheked() for (var i = 0; i <= nodeCount; i++) { min = minHeap.Extract(); - Assert.AreEqual(min, i - 1); + Assert.That(min, Is.EqualTo(i - 1)); } - Assert.AreEqual(minHeap.Count, minHeap.Count); + Assert.That(minHeap.Count, Is.EqualTo(minHeap.Count)); var rnd = new Random(); var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(_ => rnd.Next()).ToList(); @@ -99,10 +99,10 @@ public void BuildMinHeap_CreateHeap_HeapIsCheked() for (var i = 0; i < nodeCount - 2; i++) { min = minHeap.Extract(); - Assert.AreEqual(testSeries[i], min); + Assert.That(testSeries[i], Is.EqualTo(min)); } - Assert.AreEqual(minHeap.Count, minHeap.Count); + Assert.That(minHeap.Count, Is.EqualTo(minHeap.Count)); } [Test] @@ -120,13 +120,13 @@ public void BuildMaxHeap_CreateHeap_HeapIsCheked() maxHeap.UpdateKey(i, i + 1); } - Assert.AreEqual(maxHeap.Count, maxHeap.Count); + Assert.That(maxHeap.Count, Is.EqualTo(maxHeap.Count)); var max = 0; for (var i = nodeCount; i >= 0; i--) { max = maxHeap.Extract(); - Assert.AreEqual(max, i + 1); + Assert.That(max, Is.EqualTo(i + 1)); } var rnd = new Random(); @@ -148,9 +148,9 @@ public void BuildMaxHeap_CreateHeap_HeapIsCheked() for (var i = 0; i < nodeCount - 2; i++) { max = maxHeap.Extract(); - Assert.AreEqual(testSeries[i], max); + Assert.That(testSeries[i], Is.EqualTo(max)); } - Assert.AreEqual(maxHeap.Count, maxHeap.Count); + Assert.That(maxHeap.Count, Is.EqualTo(maxHeap.Count)); } } diff --git a/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs b/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs index d8629ddb..9ea060c8 100644 --- a/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs +++ b/DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs @@ -13,8 +13,8 @@ public static void TestGetData() var dll = new DoublyLinkedList(new[] { 0, 1, 2, 3, 4 }); var arr = dll.GetData().ToArray(); - Assert.AreEqual(dll.Count, 5); - Assert.AreEqual(new[] { 0, 1, 2, 3, 4 }, arr); + Assert.That(dll.Count, Is.EqualTo(5)); + Assert.That(new[] { 0, 1, 2, 3, 4 }, Is.EqualTo(arr)); } [Test] @@ -25,8 +25,8 @@ public static void TestGetAt() var one = dll.GetAt(1); var three = dll.GetAt(3); - Assert.AreEqual(one.Data, 1); - Assert.AreEqual(three.Data, 3); + Assert.That(one.Data, Is.EqualTo(1)); + Assert.That(three.Data, Is.EqualTo(3)); Assert.Throws( () => dll.GetAt(-1) ); @@ -48,9 +48,9 @@ public static void TestAddtion() var arr = dll.GetData().ToArray(); var reversedArr = dll.GetDataReversed().ToArray(); - Assert.AreEqual(dll.Count, 5); - Assert.AreEqual(new[] { 0, 1, 2, 3, 4 }, arr); - Assert.AreEqual(new[] { 4, 3, 2, 1, 0 }, reversedArr); + Assert.That(dll.Count, Is.EqualTo(5)); + Assert.That(new[] { 0, 1, 2, 3, 4 }, Is.EqualTo(arr)); + Assert.That(new[] { 4, 3, 2, 1, 0 }, Is.EqualTo(reversedArr)); } [Test] @@ -65,9 +65,9 @@ public static void TestRemove() var arr = dll.GetData().ToArray(); var reversedArr = dll.GetDataReversed().ToArray(); - Assert.AreEqual(dll.Count, 2); - Assert.AreEqual(new[] { 1, 3 }, arr); - Assert.AreEqual(new[] { 3, 1 }, reversedArr); + Assert.That(dll.Count, Is.EqualTo(2) ); + Assert.That(new[] { 1, 3 }, Is.EqualTo(arr)); + Assert.That(new[] { 3, 1 }, Is.EqualTo(reversedArr)); } [Test] @@ -78,8 +78,8 @@ public static void TestFind() var one = dll.Find(1); var three = dll.Find(3); - Assert.AreEqual(one.Data, 1); - Assert.AreEqual(three.Data, 3); + Assert.That(one.Data, Is.EqualTo(1)); + Assert.That(three.Data, Is.EqualTo(3)); } [Test] @@ -90,8 +90,8 @@ public static void TestIndexOf() var one = dll.IndexOf(1); var three = dll.IndexOf(3); - Assert.AreEqual(one, 1); - Assert.AreEqual(three, 3); + Assert.That(one, Is.EqualTo(1)); + Assert.That(three, Is.EqualTo(3)); } [Test] @@ -102,8 +102,8 @@ public static void TestContains() var one = dll.Contains(1); var six = dll.Contains(6); - Assert.IsTrue(one); - Assert.IsFalse(six); + Assert.That(one, Is.True); + Assert.That(six, Is.False); } [Test] @@ -117,8 +117,8 @@ public static void TestReverse() empty.Reverse(); var emptyArr = empty.GetData().ToArray(); - Assert.AreEqual(arr, new[] { 4, 3, 2, 1, 0 }); - Assert.AreEqual(emptyArr, new int[] { }); + Assert.That(arr, Is.EqualTo(new[] { 4, 3, 2, 1, 0 })); + Assert.That(emptyArr, Is.EqualTo(new int[] { })); } [Test] @@ -128,7 +128,7 @@ public static void TestGetDataReversed() var arr = dll.GetData().ToArray(); var reversedArr = dll.GetDataReversed().ToArray(); - Assert.AreEqual(arr, new[] { 0, 1, 2, 3, 4 }); - Assert.AreEqual(reversedArr, new[] { 4, 3, 2, 1, 0 }); + Assert.That(arr, Is.EqualTo(new[] { 0, 1, 2, 3, 4 })); + Assert.That(reversedArr, Is.EqualTo(new[] { 4, 3, 2, 1, 0 })); } } diff --git a/DataStructures.Tests/LinkedList/LinkedListTests.cs b/DataStructures.Tests/LinkedList/LinkedListTests.cs index 7cc79db1..60a09c19 100644 --- a/DataStructures.Tests/LinkedList/LinkedListTests.cs +++ b/DataStructures.Tests/LinkedList/LinkedListTests.cs @@ -21,7 +21,7 @@ public static void LengthWorksCorrectly([Random(0, 1000, 100)] int quantity) } // Assert - Assert.AreEqual(quantity, a.Length()); + Assert.That(quantity, Is.EqualTo(a.Length())); } [Test] @@ -33,7 +33,7 @@ public static void LengthOnEmptyListIsZero() // Act // Assert - Assert.AreEqual(0, a.Length()); + Assert.That(0, Is.EqualTo(a.Length())); } [Test] @@ -51,8 +51,8 @@ public static void GetItemsFromLinkedList() var items = testObj.GetListData(); // Assert - Assert.AreEqual(5, items.Count()); - Assert.AreEqual("O", testObj.GetElementByIndex(4)); + Assert.That(5, Is.EqualTo(items.Count())); + Assert.That("O", Is.EqualTo(testObj.GetElementByIndex(4))); } [Test] @@ -97,13 +97,13 @@ public static void RemoveItemsFromList() var resultString = testObj.GetElementByIndex(0) + testObj.GetElementByIndex(1); // Assert - Assert.AreEqual("HI", resultString); - Assert.IsTrue(xRemoveSucess); - Assert.IsTrue(oRemoveSucess); - Assert.IsTrue(eRemoveSucess); - Assert.IsTrue(lRemoveSucess); - Assert.IsTrue(l2RemoveSucess); - Assert.IsFalse(l3RemoveSucess); - Assert.IsFalse(nonExistantRemoveSucess); + Assert.That("HI", Is.EqualTo(resultString)); + Assert.That(xRemoveSucess, Is.True); + Assert.That(oRemoveSucess, Is.True); + Assert.That(eRemoveSucess, Is.True); + Assert.That(lRemoveSucess, Is.True); + Assert.That(l2RemoveSucess, Is.True); + Assert.That(l3RemoveSucess, Is.False); + Assert.That(nonExistantRemoveSucess, Is.False); } } diff --git a/DataStructures.Tests/Probabilistic/BloomFilterTests.cs b/DataStructures.Tests/Probabilistic/BloomFilterTests.cs index c72d5640..1c9fba89 100644 --- a/DataStructures.Tests/Probabilistic/BloomFilterTests.cs +++ b/DataStructures.Tests/Probabilistic/BloomFilterTests.cs @@ -71,10 +71,10 @@ public void TestBloomFilterInsertOptimalSize() } filter.Insert(k); set.Add(k); - Assert.IsTrue(filter.Search(k)); + Assert.That(filter.Search(k), Is.True); } - Assert.True(.05 > falsePositives / 1000.0); // be a bit generous in our fault tolerance here + Assert.That(.05 > falsePositives / 1000.0, Is.True); // be a bit generous in our fault tolerance here } [Test] @@ -86,7 +86,7 @@ public void TestBloomFilterInsert() { var simpleObject = new SimpleObject(TestNames[rand.Next(TestNames.Length)], rand.Next(15)); filter.Insert(simpleObject); - Assert.IsTrue(filter.Search(simpleObject)); + Assert.That(filter.Search(simpleObject), Is.True); } } @@ -98,9 +98,9 @@ public void TestBloomFilterSearchOverridenHash() var simpleObjectInserted2 = new SimpleObjectOverridenHash("foo", 1); var simpleObjectNotInserted = new SimpleObjectOverridenHash("bar", 2); filter.Insert(simpleObjectInserted); - Assert.IsTrue(filter.Search(simpleObjectInserted)); - Assert.IsTrue(filter.Search(simpleObjectInserted2)); - Assert.IsFalse(filter.Search(simpleObjectNotInserted)); + Assert.That(filter.Search(simpleObjectInserted), Is.True); + Assert.That(filter.Search(simpleObjectInserted2), Is.True); + Assert.That(filter.Search(simpleObjectNotInserted), Is.False); } [Test] @@ -110,8 +110,8 @@ public void TestBloomFilterSearch() var simpleObjectInserted = new SimpleObject("foo", 1); var simpleObjectNotInserted = new SimpleObject("foo", 1); filter.Insert(simpleObjectInserted); - Assert.False(filter.Search(simpleObjectNotInserted)); - Assert.True(filter.Search(simpleObjectInserted)); + Assert.That(filter.Search(simpleObjectNotInserted), Is.False); + Assert.That(filter.Search(simpleObjectInserted), Is.True); } } diff --git a/DataStructures.Tests/Queue/ArrayBasedQueueTests.cs b/DataStructures.Tests/Queue/ArrayBasedQueueTests.cs index f980e041..0f94c1ff 100644 --- a/DataStructures.Tests/Queue/ArrayBasedQueueTests.cs +++ b/DataStructures.Tests/Queue/ArrayBasedQueueTests.cs @@ -24,9 +24,9 @@ public static void DequeueWorksCorrectly() } // Assert - Assert.AreEqual("ABC", result.ToString()); - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + Assert.That("ABC", Is.EqualTo(result.ToString())); + Assert.That(q.IsEmpty(), Is.True, "Queue is empty"); + Assert.That(q.IsFull(), Is.False, "Queue is full"); } [Test] @@ -45,9 +45,9 @@ public static void PeekWorksCorrectly() } // Assert - Assert.AreEqual(1, peeked); - Assert.IsFalse(q.IsEmpty(), "Queue is empty"); - Assert.IsTrue(q.IsFull(), "Queue is full"); + Assert.That(1, Is.EqualTo(peeked)); + Assert.That(q.IsEmpty(), Is.False, "Queue is empty"); + Assert.That(q.IsFull(), Is.True, "Queue is full"); } [Test] @@ -68,7 +68,7 @@ public static void DequeueEmptyQueueThrowsInvalidOperationException() } // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType())); } [Test] @@ -90,7 +90,7 @@ public static void EnqueueFullQueueThrowsInvalidOperationException() } // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType())); } [Test] @@ -111,7 +111,7 @@ public static void PeekEmptyQueueThrowsInvalidOperationException() } // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType())); } [Test] @@ -126,7 +126,7 @@ public static void ClearWorksCorrectly() q.Clear(); // Assert - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + Assert.That(q.IsEmpty(), Is.True, "Queue is empty"); + Assert.That(q.IsFull(), Is.False, "Queue is full"); } } diff --git a/DataStructures.Tests/Queue/ListBasedQueueTests.cs b/DataStructures.Tests/Queue/ListBasedQueueTests.cs index a3477d50..34afa5b8 100644 --- a/DataStructures.Tests/Queue/ListBasedQueueTests.cs +++ b/DataStructures.Tests/Queue/ListBasedQueueTests.cs @@ -24,9 +24,9 @@ public static void DequeueWorksCorrectly() } // Assert - Assert.AreEqual("ABC", result.ToString()); - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + Assert.That("ABC", Is.EqualTo(result.ToString())); + Assert.That(q.IsEmpty(), Is.True, "Queue is empty"); + Assert.That(q.IsFull(), Is.False, "Queue is full"); } [Test] @@ -45,9 +45,9 @@ public static void PeekWorksCorrectly() } // Assert - Assert.AreEqual(1, peeked); - Assert.IsFalse(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + Assert.That(1, Is.EqualTo(peeked)); + Assert.That(q.IsEmpty(), Is.False, "Queue is empty"); + Assert.That(q.IsFull(), Is.False, "Queue is full"); } [Test] @@ -68,7 +68,7 @@ public static void DequeueEmptyQueueThrowsInvalidOperationException() } // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType())); } [Test] @@ -89,7 +89,7 @@ public static void PeekEmptyQueueThrowsInvalidOperationException() } // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType())); } [Test] @@ -104,7 +104,7 @@ public static void ClearWorksCorrectly() q.Clear(); // Assert - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + Assert.That(q.IsEmpty(), Is.True, "Queue is empty"); + Assert.That(q.IsFull(), Is.False, "Queue is full"); } } diff --git a/DataStructures.Tests/Queue/StackBasedQueueTests.cs b/DataStructures.Tests/Queue/StackBasedQueueTests.cs index 7d322bad..a88d9630 100644 --- a/DataStructures.Tests/Queue/StackBasedQueueTests.cs +++ b/DataStructures.Tests/Queue/StackBasedQueueTests.cs @@ -24,9 +24,9 @@ public static void DequeueWorksCorrectly() } // Assert - Assert.AreEqual("ABC", result.ToString()); - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + Assert.That("ABC", Is.EqualTo(result.ToString())); + Assert.That(q.IsEmpty(), Is.True, "Queue is empty"); + Assert.That(q.IsFull(), Is.False, "Queue is full"); } [Test] @@ -45,9 +45,9 @@ public static void PeekWorksCorrectly() } // Assert - Assert.AreEqual(1, peeked); - Assert.IsFalse(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + Assert.That(1, Is.EqualTo(peeked)); + Assert.That(q.IsEmpty(), Is.False, "Queue is empty"); + Assert.That(q.IsFull(), Is.False, "Queue is full"); } [Test] @@ -68,7 +68,7 @@ public static void DequeueEmptyQueueThrowsInvalidOperationException() } // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType())); } [Test] @@ -89,7 +89,7 @@ public static void PeekEmptyQueueThrowsInvalidOperationException() } // Assert - Assert.AreEqual(typeof(InvalidOperationException), exception?.GetType()); + Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType())); } [Test] @@ -104,7 +104,7 @@ public static void ClearWorksCorrectly() q.Clear(); // Assert - Assert.IsTrue(q.IsEmpty(), "Queue is empty"); - Assert.IsFalse(q.IsFull(), "Queue is full"); + Assert.That(q.IsEmpty(), Is.True, "Queue is empty"); + Assert.That(q.IsFull(), Is.False, "Queue is full"); } } diff --git a/DataStructures.Tests/ScapegoatTree/ExtensionsTests.cs b/DataStructures.Tests/ScapegoatTree/ExtensionsTests.cs index d81ca973..e9e237a1 100644 --- a/DataStructures.Tests/ScapegoatTree/ExtensionsTests.cs +++ b/DataStructures.Tests/ScapegoatTree/ExtensionsTests.cs @@ -36,18 +36,18 @@ public void RebuildFlatTree_ValidFlatTree_RebuildsTree() var tree = Extensions.RebuildFromList(list, 0, list.Count - 1); - Assert.AreEqual(list.Count, tree.GetSize()); - Assert.AreEqual(expected.Key, tree.Key); - Assert.IsNotNull(tree.Left); - Assert.IsNotNull(tree.Right); - Assert.AreEqual(expected.Left.Key, tree.Left!.Key); - Assert.AreEqual(expected.Right.Key, tree.Right!.Key); - Assert.IsNotNull(tree.Left.Left); - Assert.IsNotNull(tree.Left.Right); - Assert.AreEqual(expected.Left.Left.Key, tree.Left!.Left!.Key); - Assert.AreEqual(expected.Left.Right.Key, tree.Left!.Right!.Key); - Assert.IsNotNull(tree.Right.Left); - Assert.AreEqual(expected.Right.Left.Key, tree.Right!.Left!.Key); + Assert.That(list.Count, Is.EqualTo(tree.GetSize())); + Assert.That(expected.Key, Is.EqualTo(tree.Key)); + Assert.That(tree.Left, Is.Not.Null); + Assert.That(tree.Right, Is.Not.Null); + Assert.That(expected.Left.Key, Is.EqualTo(tree.Left!.Key)); + Assert.That(expected.Right.Key, Is.EqualTo(tree.Right!.Key)); + Assert.That(tree.Left.Left, Is.Not.Null); + Assert.That(tree.Left.Right, Is.Not.Null); + Assert.That(expected.Left.Left.Key, Is.EqualTo(tree.Left!.Left!.Key)); + Assert.That(expected.Left.Right.Key, Is.EqualTo(tree.Left!.Right!.Key)); + Assert.That(tree.Right.Left, Is.Not.Null); + Assert.That(expected.Right.Left.Key, Is.EqualTo(tree.Right!.Left!.Key)); } [Test] diff --git a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs index ca7611a8..57ad9d8c 100644 --- a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs +++ b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs @@ -61,7 +61,7 @@ public void CompareTo_InstanceKeyPrecedesOtherKey_ReturnsMinusOne(TKey a, var result = instance.Key.CompareTo(other.Key); - Assert.AreEqual(result, -1); + Assert.That(result, Is.EqualTo(-1)); } [TestCase(2, 1)] @@ -74,7 +74,7 @@ public void CompareTo_InstanceKeyFollowsOtherKey_ReturnsOne(TKey a, TKey b var result = instance.Key.CompareTo(other.Key); - Assert.AreEqual(result, 1); + Assert.That(1, Is.EqualTo(result)); } [TestCase(1, 1)] @@ -87,7 +87,7 @@ public void CompareTo_InstanceKeyEqualsOtherKey_ReturnsZero(TKey a, TKey b var result = instance.Key.CompareTo(other.Key); - Assert.AreEqual(result, 0); + Assert.That(0, Is.EqualTo(result)); } [Test] @@ -95,7 +95,7 @@ public void GetSize_NodeHasNoChildren_ReturnsOne() { var node = new Node(1); - Assert.AreEqual(node.GetSize(), 1); + Assert.That(1, Is.EqualTo(node.GetSize())); } [Test] @@ -103,7 +103,7 @@ public void GetSize_NodeHasChildren_ReturnsCorrectSize() { var node = new Node(1, new Node(2), new Node(0)); - Assert.AreEqual(node.GetSize(), 3); + Assert.That(3, Is.EqualTo(node.GetSize())); } [Test] @@ -111,7 +111,7 @@ public void GetSmallestKeyNode_NodeHasNoLeftChildren_ReturnsNode() { var node = new Node(1); - Assert.AreEqual(node.GetSmallestKeyNode(), node); + Assert.That(node, Is.EqualTo(node.GetSmallestKeyNode())); } [Test] @@ -123,7 +123,7 @@ public void GetSmallestKeyNode_NodeHasSmallestChild_ReturnsChild() node.Left = smaller; smaller.Left = smallest; - Assert.AreEqual(node.GetSmallestKeyNode(), smallest); + Assert.That(smallest, Is.EqualTo(node.GetSmallestKeyNode())); } [Test] @@ -131,7 +131,7 @@ public void GetLargestKeyNode_NodeHasNoRightChildren_ReturnsNode() { var node = new Node(1); - Assert.AreEqual(node.GetLargestKeyNode(), node); + Assert.That(node, Is.EqualTo(node.GetLargestKeyNode())); } [Test] @@ -143,7 +143,7 @@ public void GetLargestKeyNode_NodeHasLargestChild_ReturnsChild() node.Right = larger; larger.Right = largest; - Assert.AreEqual(node.GetLargestKeyNode(), largest); + Assert.That(largest, Is.EqualTo(node.GetLargestKeyNode())); } [Test] @@ -160,7 +160,7 @@ public void IsAlphaWeightBalanced_TreeIsUnbalanced_ReturnsFalse() b.Left = c; root.Right = d; - Assert.IsFalse(root.IsAlphaWeightBalanced(0.5)); + Assert.That(root.IsAlphaWeightBalanced(0.5), Is.False); } [Test] @@ -175,6 +175,6 @@ public void IsAlphaWeightBalanced_TreeIsBalanced_ReturnsTrue() a.Left = b; root.Right = d; - Assert.IsTrue(root.IsAlphaWeightBalanced(0.5)); + Assert.That(root.IsAlphaWeightBalanced(0.5), Is.True); } } diff --git a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs index 77ea8095..89e02920 100644 --- a/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs +++ b/DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs @@ -12,10 +12,10 @@ public void Constructor_NoParameters_InstanceIsValid() { var tree = new ScapegoatTree(); - Assert.IsNull(tree.Root); - Assert.IsTrue(tree.Size == 0); - Assert.IsTrue(tree.MaxSize == 0); - Assert.AreEqual(0.5, tree.Alpha); + Assert.That(tree.Root, Is.Null); + Assert.That(tree.Size == 0, Is.True); + Assert.That(tree.MaxSize == 0, Is.True); + Assert.That(tree.Alpha, Is.EqualTo(0.5)); } [Test] @@ -25,10 +25,10 @@ public void Constructor_AlphaParameter_InstanceIsValid() var tree = new ScapegoatTree(expected); - Assert.IsNull(tree.Root); - Assert.IsTrue(tree.Size == 0); - Assert.IsTrue(tree.MaxSize == 0); - Assert.AreEqual(expected, tree.Alpha); + Assert.That(tree.Root, Is.Null); + Assert.That(tree.Size == 0, Is.True); + Assert.That(tree.MaxSize == 0, Is.True); + Assert.That(tree.Alpha, Is.EqualTo(expected)); } [TestCase(1.1)] @@ -46,11 +46,11 @@ public void Constructor_KeyParameter_InstanceIsValid() var tree = new ScapegoatTree(expected); - Assert.IsNotNull(tree.Root); - Assert.IsTrue(tree.Root!.Key == expected); - Assert.IsTrue(tree.Size == 1); - Assert.IsTrue(tree.MaxSize == 1); - Assert.AreEqual(0.5, tree.Alpha); + Assert.That(tree.Root, Is.Not.Null); + Assert.That(tree.Root!.Key == expected, Is.True); + Assert.That(tree.Size == 1, Is.True); + Assert.That(tree.MaxSize == 1, Is.True); + Assert.That(tree.Alpha, Is.EqualTo(0.5)); } [Test] @@ -61,10 +61,10 @@ public void Constructor_KeyAndAlphaParameters_InstanceIsValid() var tree = new ScapegoatTree(key, alpha); - Assert.IsNotNull(tree.Root); - Assert.IsTrue(tree.Size == 1); - Assert.IsTrue(tree.MaxSize == 1); - Assert.AreEqual(alpha, tree.Alpha); + Assert.That(tree.Root, Is.Not.Null); + Assert.That(tree.Size == 1, Is.True); + Assert.That(tree.MaxSize == 1, Is.True); + Assert.That(tree.Alpha, Is.EqualTo(alpha)); } [Test] @@ -75,10 +75,10 @@ public void Constructor_NodeAndAlphaParameters_InstanceIsValid() var tree = new ScapegoatTree(node, alpha); - Assert.IsNotNull(tree.Root); - Assert.IsTrue(tree.Size == 3); - Assert.IsTrue(tree.MaxSize == 3); - Assert.AreEqual(alpha, tree.Alpha); + Assert.That(tree.Root, Is.Not.Null); + Assert.That(tree.Size == 3, Is.True); + Assert.That(tree.MaxSize == 3, Is.True); + Assert.That(tree.Alpha, Is.EqualTo(alpha)); } [Test] @@ -88,7 +88,7 @@ public void IsAlphaWeightBalanced_RootIsNull_ReturnsTrue() var result = tree.IsAlphaWeightBalanced(); - Assert.IsTrue(result); + Assert.That(result, Is.True); } [Test] @@ -98,7 +98,7 @@ public void Search_RootIsNull_ReturnsNull() var result = tree.Search(1); - Assert.IsNull(result); + Assert.That(result, Is.Null); } [Test] @@ -108,8 +108,8 @@ public void Search_KeyIsPresent_ReturnsKey() var result = tree.Search(1); - Assert.IsNotNull(result); - Assert.AreEqual(1, result!.Key); + Assert.That(result, Is.Not.Null); + Assert.That(result!.Key, Is.EqualTo(1)); } [TestCase(-2)] @@ -122,7 +122,7 @@ public void Search_KeyIsNotPresent_ReturnsNull(int key) var result = tree.Search(key); - Assert.IsNull(result); + Assert.That(result, Is.Null); } [Test] @@ -132,11 +132,11 @@ public void Insert_RootIsNull_InsertsRoot() var inserted = tree.Insert(1); - Assert.IsTrue(inserted); - Assert.IsNotNull(tree.Root); - Assert.AreEqual(1, tree.Root!.Key); - Assert.AreEqual(1, tree.Size); - Assert.AreEqual(1, tree.MaxSize); + Assert.That(inserted, Is.True); + Assert.That(tree.Root, Is.Not.Null); + Assert.That(tree.Root!.Key, Is.EqualTo(1)); + Assert.That(tree.Size, Is.EqualTo(1)); + Assert.That(tree.MaxSize, Is.EqualTo(1)); } [Test] @@ -146,7 +146,7 @@ public void Delete_RootIsNull_ReturnsFalse() var deleted = tree.Delete(1); - Assert.IsFalse(deleted); + Assert.That(deleted, Is.False); } [Test] @@ -156,8 +156,8 @@ public void Delete_KeyIsNotPresent_ReturnsFalse() var deleted = tree.Delete(2); - Assert.IsFalse(deleted); - Assert.AreEqual(1, tree.Size); + Assert.That(deleted, Is.False); + Assert.That(tree.Size, Is.EqualTo(1)); } [Test] @@ -167,9 +167,9 @@ public void Insert_KeyIsPresent_ReturnsFalse() var inserted = tree.Insert(1); - Assert.IsFalse(inserted); - Assert.AreEqual(1, tree.Size); - Assert.AreEqual(1, tree.MaxSize); + Assert.That(inserted, Is.False); + Assert.That(tree.Size, Is.EqualTo(1)); + Assert.That(tree.MaxSize, Is.EqualTo(1)); } [Test] @@ -179,12 +179,12 @@ public void Remove_KeyIsPresent_RemovesKey() var inserted = tree.Insert(2); - Assert.IsTrue(inserted); + Assert.That(inserted, Is.True); var deleted = tree.Delete(2); - Assert.IsTrue(deleted); - Assert.AreEqual(1, tree.Size); + Assert.That(deleted, Is.True); + Assert.That(tree.Size, Is.EqualTo(1)); } [Test] @@ -194,9 +194,9 @@ public void Remove_KeyIsRootWithNoChildren_RemovesKey() var deleted = tree.Delete(1); - Assert.IsTrue(deleted); - Assert.IsNull(tree.Root); - Assert.AreEqual(0, tree.Size); + Assert.That(deleted, Is.True); + Assert.That(tree.Root, Is.Null); + Assert.That(tree.Size, Is.EqualTo(0)); } [Test] @@ -206,12 +206,12 @@ public void Remove_KeyIsRootWithOneLeftChild_RemovesKey() var inserted = tree.Insert(-1); - Assert.IsTrue(inserted); + Assert.That(inserted, Is.True); var deleted = tree.Delete(1); - Assert.IsTrue(deleted); - Assert.AreEqual(1, tree.Size); + Assert.That(deleted, Is.True); + Assert.That(tree.Size, Is.EqualTo(1)); } [Test] @@ -221,12 +221,12 @@ public void Remove_KeyIsRootWithOneRightChild_RemovesKey() var inserted = tree.Insert(2); - Assert.IsTrue(inserted); + Assert.That(inserted, Is.True); var deleted = tree.Delete(1); - Assert.IsTrue(deleted); - Assert.AreEqual(1, tree.Size); + Assert.That(deleted, Is.True); + Assert.That(tree.Size, Is.EqualTo(1)); } [Test] @@ -236,16 +236,16 @@ public void Remove_KeyIsRootWithTwoChildren_RemovesKey() var inserted = tree.Insert(-1); - Assert.IsTrue(inserted); + Assert.That(inserted, Is.True); inserted = tree.Insert(2); - Assert.IsTrue(inserted); + Assert.That(inserted, Is.True); var deleted = tree.Delete(1); - Assert.IsTrue(deleted); - Assert.AreEqual(2, tree.Size); + Assert.That(deleted, Is.True); + Assert.That(tree.Size, Is.EqualTo(2)); } [Test] @@ -255,9 +255,9 @@ public void Insert_KeyIsNotPresent_KeyIsInserted() var inserted = tree.Insert(2); - Assert.IsTrue(inserted); - Assert.AreEqual(2, tree.Size); - Assert.AreEqual(2, tree.MaxSize); + Assert.That(inserted, Is.True); + Assert.That(tree.Size, Is.EqualTo(2)); + Assert.That(tree.MaxSize, Is.EqualTo(2)); } [TestCase(3, new[]{2,5,1,6}, -1, 0.5)] @@ -318,7 +318,7 @@ public void Delete_TreeIsUnbalanced_MaxSizeEqualsSize(int root, int[] keys, int tree.Delete(candidate); - Assert.AreEqual(tree.Size, tree.MaxSize); + Assert.That(tree.MaxSize, Is.EqualTo(tree.Size)); } [TestCase(3, new[]{2,5,1,6}, -1, 0.5)] @@ -338,9 +338,9 @@ public void Insert_TreeIsUnbalanced_BalancesTree(int root, int[] keys, int candi var inserted = tree.Insert(candidate); - Assert.True(inserted); - Assert.True(tree.Size == 6); - Assert.True(tree.IsAlphaWeightBalanced()); + Assert.That(inserted, Is.True); + Assert.That(tree.Size == 6, Is.True); + Assert.That(tree.IsAlphaWeightBalanced(), Is.True); } [TestCase(3, 5, 0.5)] @@ -350,9 +350,9 @@ public void Insert_TreeIsUnbalanced_BalancesTree2(int root, int candidate, doubl var inserted = tree.Insert(candidate); - Assert.True(inserted); - Assert.True(tree.Size == 2); - Assert.True(tree.IsAlphaWeightBalanced()); + Assert.That(inserted, Is.True); + Assert.That(tree.Size == 2, Is.True); + Assert.That(tree.IsAlphaWeightBalanced(), Is.True); } [Test] @@ -360,7 +360,7 @@ public void Contains_RootIsNull_ReturnsFalse() { var tree = new ScapegoatTree(); - Assert.IsFalse(tree.Contains(1)); + Assert.That(tree.Contains(1), Is.False); } [Test] @@ -368,7 +368,7 @@ public void Contains_RootHasKey_ReturnsTrue() { var tree = new ScapegoatTree(1); - Assert.IsTrue(tree.Contains(1)); + Assert.That(tree.Contains(1), Is.True); } [Test] @@ -378,7 +378,7 @@ public void Contains_TreeHasKey_ReturnsTrue() tree.Insert(2); - Assert.IsTrue(tree.Contains(2)); + Assert.That(tree.Contains(2), Is.True); } [Test] @@ -388,7 +388,7 @@ public void Contains_TreeDoesNotContainKey_ReturnsFalse() tree.Insert(2); - Assert.IsFalse(tree.Contains(-1)); + Assert.That(tree.Contains(-1), Is.False); } [Test] @@ -398,9 +398,9 @@ public void Clear_TreeHasKeys_ClearsTree() tree.Clear(); - Assert.IsTrue(tree.Size == 0); - Assert.IsTrue(tree.MaxSize == 0); - Assert.IsNull(tree.Root); + Assert.That(tree.Size == 0, Is.True); + Assert.That(tree.MaxSize == 0, Is.True); + Assert.That(tree.Root, Is.Null); } [Test] @@ -412,7 +412,7 @@ public void Tune_AlphaIsValid_ChangesAlpha() tree.Tune(expected); - Assert.AreEqual(expected, tree.Alpha); + Assert.That(tree.Alpha, Is.EqualTo(expected)); } [Test] diff --git a/DataStructures.Tests/SegmentTrees/SegmentTreeApplyTests.cs b/DataStructures.Tests/SegmentTrees/SegmentTreeApplyTests.cs index 675c3a11..307d884d 100644 --- a/DataStructures.Tests/SegmentTrees/SegmentTreeApplyTests.cs +++ b/DataStructures.Tests/SegmentTrees/SegmentTreeApplyTests.cs @@ -11,9 +11,9 @@ public class SegmentTreeApplyTests [Test] public void Apply_Query_Update_Query_Test() { - Assert.AreEqual(22, testTree.Query(1, 4)); + Assert.That(testTree.Query(1, 4), Is.EqualTo(22)); testTree.Apply(0, 3, 2); - Assert.AreEqual(new[] { 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, testTree.Operand); - Assert.AreEqual(36, testTree.Query(1, 4)); + Assert.That(testTree.Operand, Is.EqualTo(new[] { 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 })); + Assert.That(testTree.Query(1, 4), Is.EqualTo(36)); } } diff --git a/DataStructures.Tests/SegmentTrees/SegmentTreeTests.cs b/DataStructures.Tests/SegmentTrees/SegmentTreeTests.cs index 07a57713..2a139662 100644 --- a/DataStructures.Tests/SegmentTrees/SegmentTreeTests.cs +++ b/DataStructures.Tests/SegmentTrees/SegmentTreeTests.cs @@ -12,13 +12,13 @@ public class SegmentTreeTests public void TreeArray_Test() { int[] expectedArray = { 0, 39, 22, 17, 17, 5, 15, 2, 8, 9, 1, 4, 8, 7, 2, 0 }; - Assert.AreEqual(expectedArray, testTree.Tree); + Assert.That(testTree.Tree, Is.EqualTo(expectedArray)); } [TestCase(1, 4, 22)] [TestCase(2, 2, 1)] public void Query_Test(int left, int right, int expectedValue) { - Assert.AreEqual(expectedValue, testTree.Query(left, right)); + Assert.That(testTree.Query(left, right), Is.EqualTo(expectedValue)); } } diff --git a/DataStructures.Tests/SegmentTrees/SegmentTreeUpdateTest.cs b/DataStructures.Tests/SegmentTrees/SegmentTreeUpdateTest.cs index 8bf1dd6b..50598906 100644 --- a/DataStructures.Tests/SegmentTrees/SegmentTreeUpdateTest.cs +++ b/DataStructures.Tests/SegmentTrees/SegmentTreeUpdateTest.cs @@ -19,6 +19,6 @@ public void Init() public void Update_Test(int node, int value, int left, int right, int aftQuery) { testTree.Update(node, value); - Assert.AreEqual(aftQuery, testTree.Query(left, right)); + Assert.That(aftQuery, Is.EqualTo(testTree.Query(left, right))); } } diff --git a/DataStructures.Tests/SortedListTests.cs b/DataStructures.Tests/SortedListTests.cs index b3ca7f6e..b2896dec 100644 --- a/DataStructures.Tests/SortedListTests.cs +++ b/DataStructures.Tests/SortedListTests.cs @@ -20,7 +20,7 @@ public void Add_AddMultipleValues_SortingCorrectly( list.Add(value); } - CollectionAssert.AreEqual(values.OrderBy(i => i), list); + Assert.That(list, Is.EqualTo(values.OrderBy(i => i))); } [Test] @@ -37,7 +37,7 @@ public void Contains_PositiveArrayAdded_NegativeNumberAsked_FalseReturned( list.Add(i); } - Assert.IsFalse(list.Contains(value)); + Assert.That(list.Contains(value), Is.False); } [Test] @@ -54,7 +54,7 @@ public void Contains_PositiveArrayAdded_ContainingValueAsked_TrueReturned( list.Add(i); } - Assert.IsTrue(list.Contains(value)); + Assert.That(list.Contains(value), Is.True); } @@ -72,7 +72,7 @@ public void Remove_PositiveArrayAdded_NegativeNumberAsked_FalseReturned( list.Add(i); } - Assert.IsFalse(list.TryRemove(value)); + Assert.That(list.TryRemove(value), Is.False); } [Test] @@ -95,8 +95,8 @@ public void Remove_PositiveArrayAdded_ContainingValueAsked_TrueReturned( expectingValues.Remove(value); - Assert.IsTrue(list.TryRemove(value)); - CollectionAssert.AreEqual(expectingValues, list); + Assert.That(list.TryRemove(value), Is.True); + Assert.That(list, Is.EqualTo(expectingValues)); } [Test] @@ -114,7 +114,7 @@ public void Clear_ArrayAdded_ListCleaned_ListIsEmpty( list.Clear(); - CollectionAssert.IsEmpty(list); + Assert.That(list, Is.Empty); } private static List GetValues(int count) diff --git a/DataStructures.Tests/Stack/QueueBasedStackTests.cs b/DataStructures.Tests/Stack/QueueBasedStackTests.cs index a95c451c..5dc2aefb 100644 --- a/DataStructures.Tests/Stack/QueueBasedStackTests.cs +++ b/DataStructures.Tests/Stack/QueueBasedStackTests.cs @@ -26,7 +26,7 @@ public static void PopWorksCorrectly() //Assert Assert.That("CBA", Is.EqualTo(result.ToString())); - Assert.IsTrue(s.IsEmpty(), "Stack is Empty"); + Assert.That(s.IsEmpty(), Is.True, "Stack is Empty"); } [Test] public static void PeekWorksCorrectly() @@ -47,7 +47,7 @@ public static void PeekWorksCorrectly() //Assert Assert.That(3, Is.EqualTo(peeked)); - Assert.IsFalse(s.IsEmpty(), "Stack is Empty"); + Assert.That(s.IsEmpty(), Is.False, "Stack is Empty"); } [Test] public static void PopEmptyStackThrowsInvalidOperationException() @@ -101,7 +101,7 @@ public static void ClearWorksCorrectly() s.Clear(); // Assert - Assert.IsTrue(s.IsEmpty(), "Queue is empty"); + Assert.That(s.IsEmpty(), Is.True, "Queue is empty"); } [Test] diff --git a/DataStructures.Tests/Tries/TrieTests.cs b/DataStructures.Tests/Tries/TrieTests.cs index 8b84356d..2b005281 100644 --- a/DataStructures.Tests/Tries/TrieTests.cs +++ b/DataStructures.Tests/Tries/TrieTests.cs @@ -1,4 +1,3 @@ -using System; using DataStructures.Tries; using NUnit.Framework; @@ -7,7 +6,8 @@ namespace DataStructures.Tests.Tries; public static class TrieTests { [Test] - public static void FindWordInTrie(){ + public static void FindWordInTrie() + { // Arrange string[] words = { "trie", @@ -20,18 +20,19 @@ public static void FindWordInTrie(){ Trie trie = new(words); // Assert - Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); - Assert.IsTrue(trie.Find("node"), "The word 'node' isn't in Trie structure"); - Assert.IsTrue(trie.Find("none"), "The word 'none' isn't in Trie structure"); - Assert.IsTrue(trie.Find("treatment"), "The word 'treatment' isn't in Trie structure"); - - Assert.IsFalse(trie.Find("nodes"), "The word 'nodes' is in Trie sturcture"); - Assert.IsFalse(trie.Find(""), "The word empty is in Trie structure"); - Assert.IsFalse(trie.Find("tri"), "The word 'tri' is in Trie structure"); + Assert.That(trie.Find("trie"), Is.True, "The word 'trie' isn't in Trie structure"); + Assert.That(trie.Find("node"), Is.True, "The word 'node' isn't in Trie structure"); + Assert.That(trie.Find("none"), Is.True, "The word 'none' isn't in Trie structure"); + Assert.That(trie.Find("treatment"), Is.True, "The word 'treatment' isn't in Trie structure"); + + Assert.That(trie.Find("nodes"), Is.False, "The word 'nodes' is in Trie sturcture"); + Assert.That(trie.Find(""), Is.False, "The word empty is in Trie structure"); + Assert.That(trie.Find("tri"), Is.False, "The word 'tri' is in Trie structure"); } [Test] - public static void InsertInTrie(){ + public static void InsertInTrie() + { // Arrange string[] words = { "trie", @@ -49,14 +50,15 @@ public static void InsertInTrie(){ } // Assert - Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); - Assert.IsTrue(trie.Find("node"), "The word 'node' isn't in Trie structure"); - Assert.IsTrue(trie.Find("none"), "The word 'none' isn't in Trie structure"); - Assert.IsTrue(trie.Find("treatment"), "The word 'treatment' isn't in Trie structure"); + Assert.That(trie.Find("trie"), Is.True, "The word 'trie' isn't in Trie structure"); + Assert.That(trie.Find("node"), Is.True, "The word 'node' isn't in Trie structure"); + Assert.That(trie.Find("none"), Is.True, "The word 'none' isn't in Trie structure"); + Assert.That(trie.Find("treatment"), Is.True, "The word 'treatment' isn't in Trie structure"); } [Test] - public static void RemoveFromTrie(){ + public static void RemoveFromTrie() + { // Arrange string[] words = { "trie", @@ -75,10 +77,10 @@ public static void RemoveFromTrie(){ trie.Remove("trie"); // Assert - Assert.IsFalse(trie.Find("trie"), "The word 'trie' is in Trie structure"); - Assert.IsTrue(trie.Find("treatment"), "The word 'treament' isn't in Trie structure"); - Assert.IsTrue(trie.Find("node"), "The word 'node' isn't in Trie structure"); - Assert.IsTrue(trie.Find("none"), "The word 'none' isn't in Trie structure"); + Assert.That(trie.Find("trie"), Is.False, "The word 'trie' is in Trie structure"); + Assert.That(trie.Find("treatment"), Is.True, "The word 'treament' isn't in Trie structure"); + Assert.That(trie.Find("node"), Is.True, "The word 'node' isn't in Trie structure"); + Assert.That(trie.Find("none"), Is.True, "The word 'none' isn't in Trie structure"); } [Test] @@ -93,12 +95,13 @@ public static void MultipleInsert() trie.Insert(w); // Assert - Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); - Assert.IsFalse(trie.Find("nodes"), "The word 'nodes' is in Trie sturcture"); + Assert.That(trie.Find("trie"), Is.True, "The word 'trie' isn't in Trie structure"); + Assert.That(trie.Find("nodes"), Is.False, "The word 'nodes' is in Trie sturcture"); } [Test] - public static void RemoveAWordThatIsNtInTrie(){ + public static void RemoveAWordThatIsNtInTrie() + { // Arrange const string w = "trie"; Trie trie = new(); @@ -109,6 +112,6 @@ public static void RemoveAWordThatIsNtInTrie(){ trie.Remove("none"); // Assert - Assert.IsTrue(trie.Find("trie"), "The word 'trie' isn't in Trie structure"); + Assert.That(trie.Find("trie"), Is.True, "The word 'trie' isn't in Trie structure"); } } diff --git a/Utilities.Tests/Extensions/MatrixExtensionsTests.cs b/Utilities.Tests/Extensions/MatrixExtensionsTests.cs index 8d99f4d3..a079299e 100644 --- a/Utilities.Tests/Extensions/MatrixExtensionsTests.cs +++ b/Utilities.Tests/Extensions/MatrixExtensionsTests.cs @@ -142,7 +142,7 @@ public static void EqualMatricesShouldReturnTrue() var result = a.IsEqual(b); // Assert - Assert.True(result); + Assert.That(result, Is.True); } [Test] @@ -156,7 +156,7 @@ public static void NonEqualMatricesShouldReturnFalse() var result = a.IsEqual(b); // Assert - Assert.False(result); + Assert.That(result, Is.False); } [Test] @@ -170,7 +170,7 @@ public static void DifferentSizeMatricesShouldReturnFalse() var result = a.IsEqual(b); // Assert - Assert.False(result); + Assert.That(result, Is.False); } [TestCaseSource(nameof(MatrixSubtractTestCases))] diff --git a/Utilities.Tests/Utilities.Tests.csproj b/Utilities.Tests/Utilities.Tests.csproj index 97429e11..ef6c6056 100644 --- a/Utilities.Tests/Utilities.Tests.csproj +++ b/Utilities.Tests/Utilities.Tests.csproj @@ -18,8 +18,8 @@ all - - + + From f32c0436ccbddaa82faf6b760b38c76d128fb506 Mon Sep 17 00:00:00 2001 From: OZZY Date: Fri, 19 Apr 2024 23:44:41 +0200 Subject: [PATCH 096/138] Add DeleteFirst and DeleteLast to SinglyLinkedList (#450) --- .../LinkedList/LinkedListTests.cs | 67 +++++++++++++++++++ .../SinglyLinkedList/SinglyLinkedList.cs | 47 +++++++++++++ 2 files changed, 114 insertions(+) diff --git a/DataStructures.Tests/LinkedList/LinkedListTests.cs b/DataStructures.Tests/LinkedList/LinkedListTests.cs index 60a09c19..731306b9 100644 --- a/DataStructures.Tests/LinkedList/LinkedListTests.cs +++ b/DataStructures.Tests/LinkedList/LinkedListTests.cs @@ -106,4 +106,71 @@ public static void RemoveItemsFromList() Assert.That(l3RemoveSucess, Is.False); Assert.That(nonExistantRemoveSucess, Is.False); } + + [Test] + public static void DeleteFirstFromList() + { + // Arrange + var testObj = new SinglyLinkedList(); + _ = testObj.AddLast("H"); + _ = testObj.AddLast("E"); + _ = testObj.AddLast("L"); + _ = testObj.AddLast("L"); + _ = testObj.AddLast("O"); + + // Act + var deleteSuccess = testObj.DeleteFirst(); + + // Assert + Assert.That(deleteSuccess, Is.True); + Assert.That(4, Is.EqualTo(testObj.Length())); + Assert.That("E", Is.EqualTo(testObj.GetElementByIndex(0))); + } + + [Test] + public static void DeleteFirstFromEmptyList() + { + // Arrange + var testObj = new SinglyLinkedList(); + + // Act + var deleteSuccess = testObj.DeleteFirst(); + + // Assert + Assert.That(deleteSuccess, Is.False); + } + + [Test] + public static void DeleteLastFromList() + { + // Arrange + var testObj = new SinglyLinkedList(); + _ = testObj.AddLast("H"); + _ = testObj.AddLast("E"); + _ = testObj.AddLast("L"); + _ = testObj.AddLast("L"); + _ = testObj.AddLast("O"); + + // Act + var deleteSuccess = testObj.DeleteLast(); + + // Assert + Assert.That(deleteSuccess, Is.True); + Assert.That(4, Is.EqualTo(testObj.Length())); + Assert.That("L", Is.EqualTo(testObj.GetElementByIndex(testObj.Length() - 1))); + } + + [Test] + public static void DeleteLastFromEmptyList() + { + // Arrange + var testObj = new SinglyLinkedList(); + + // Act + var deleteSuccess = testObj.DeleteLast(); + + // Assert + Assert.That(deleteSuccess, Is.False); + } + } diff --git a/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs b/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs index 12f6ff75..5de05d45 100644 --- a/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs +++ b/DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs @@ -153,4 +153,51 @@ public bool DeleteElement(T element) return false; } + + /// + /// Deletes the first element of the list. + /// + /// true if the operation is successul. + public bool DeleteFirst() + { + // checks if the List is empty + if(Head is null) + { + return false; + } + + // if not, the head is overwritten with the next element and the old head is deleted + Head = Head.Next; + return true; + } + + /// + /// Deletes the last element of the list. + /// + /// returns true if the operation is successful. + public bool DeleteLast() + { + // checks if the List is empty + if(Head is null) + { + return false; + } + + // checks if the List has only one element + if(Head.Next is null) + { + Head = null; + return true; + } + + // if not, iterates through the list to the second last element and deletes the last one + SinglyLinkedListNode? secondlast = Head; + while(secondlast.Next?.Next is not null) + { + secondlast = secondlast.Next; + } + + secondlast.Next = null; + return true; + } } From d28baa34d93577f73b1ed74f71cb72c8ddee98fd Mon Sep 17 00:00:00 2001 From: Ang <63333314+AngLv@users.noreply.github.com> Date: Sun, 5 May 2024 12:46:37 -0700 Subject: [PATCH 097/138] Fix inconsistent index and count when removing vertex from Graph (#451) --- .../Graph/DirectedWeightedGraphTests.cs | 101 ++++++++++++++++++ DataStructures/Graph/DirectedWeightedGraph.cs | 44 +++++++- DataStructures/Graph/Vertex.cs | 2 +- 3 files changed, 142 insertions(+), 5 deletions(-) diff --git a/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs b/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs index 43373972..d63d80f6 100644 --- a/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs +++ b/DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs @@ -83,6 +83,107 @@ public void GraphRemoveVertexTest_Success() graph.GetNeighbors(vertexC).Should().HaveCount(0); } + [Test] + public void GraphRemoveAndAddVertexTest_Success() + { + double weight_A_B = 1; + double weight_A_C = 2; + double weight_A_D = 3; + double weight_B_A = 4; + double weight_B_C = 5; + double weight_C_A = 6; + double weight_C_B = 7; + double weight_C_D = 8; + double weight_D_A = 9; + double weight_D_C = 10; + + var graph = new DirectedWeightedGraph(10); + var vertexA = graph.AddVertex('A'); + var vertexB = graph.AddVertex('B'); + var vertexC = graph.AddVertex('C'); + graph.AddEdge(vertexA, vertexB, weight_A_B); + graph.AddEdge(vertexA, vertexC, weight_A_C); + graph.AddEdge(vertexB, vertexA, weight_B_A); + graph.AddEdge(vertexB, vertexC, weight_B_C); + graph.AddEdge(vertexC, vertexA, weight_C_A); + graph.AddEdge(vertexC, vertexB, weight_C_B); + + var vertexA_Index_BeforeUpdate = vertexA.Index; + vertexA_Index_BeforeUpdate.Should().Be(0); + var neighborsA_BeforeUpdate = graph.GetNeighbors(vertexA).ToList(); + neighborsA_BeforeUpdate.Should().HaveCount(2); + neighborsA_BeforeUpdate[0].Should().Be(vertexB); + neighborsA_BeforeUpdate[1].Should().Be(vertexC); + + var vertexB_Index_BeforeUpdate = vertexB.Index; + vertexB_Index_BeforeUpdate.Should().Be(1); + var neighborsB_BeforeUpdate = graph.GetNeighbors(vertexB).ToList(); + neighborsB_BeforeUpdate.Should().HaveCount(2); + neighborsB_BeforeUpdate[0].Should().Be(vertexA); + neighborsB_BeforeUpdate[1].Should().Be(vertexC); + + var vertexC_Index_BeforeUpdate = vertexC.Index; + vertexC_Index_BeforeUpdate.Should().Be(2); + var neighborsC_BeforeUpdate = graph.GetNeighbors(vertexC).ToList(); + neighborsC_BeforeUpdate.Should().HaveCount(2); + neighborsC_BeforeUpdate[0].Should().Be(vertexA); + neighborsC_BeforeUpdate[1].Should().Be(vertexB); + + var weight_A_B_BeforeUpdate = graph.AdjacentDistance(vertexA, vertexB); + var weight_A_C_BeforeUpdate = graph.AdjacentDistance(vertexA, vertexC); + var weight_B_A_BeforeUpdate = graph.AdjacentDistance(vertexB, vertexA); + var weight_B_C_BeforeUpdate = graph.AdjacentDistance(vertexB, vertexC); + var weight_C_A_BeforeUpdate = graph.AdjacentDistance(vertexC, vertexA); + var weight_C_B_BeforeUpdate = graph.AdjacentDistance(vertexC, vertexB); + weight_A_B_BeforeUpdate.Should().Be(weight_A_B); + weight_A_C_BeforeUpdate.Should().Be(weight_A_C); + weight_B_A_BeforeUpdate.Should().Be(weight_B_A); + weight_B_C_BeforeUpdate.Should().Be(weight_B_C); + weight_C_A_BeforeUpdate.Should().Be(weight_C_A); + weight_C_B_BeforeUpdate.Should().Be(weight_C_B); + + graph.RemoveVertex(vertexB); + var vertexD = graph.AddVertex('D'); + graph.AddEdge(vertexA, vertexD, weight_A_D); + graph.AddEdge(vertexC, vertexD, weight_C_D); + graph.AddEdge(vertexD, vertexA, weight_D_A); + graph.AddEdge(vertexD, vertexC, weight_D_C); + + var vertexA_Index_AfterUpdate = vertexA.Index; + vertexA_Index_AfterUpdate.Should().Be(0); + var neighborsA_AfterUpdate = graph.GetNeighbors(vertexA).ToList(); + neighborsA_AfterUpdate.Should().HaveCount(2); + neighborsA_AfterUpdate[0].Should().Be(vertexC); + neighborsA_AfterUpdate[1].Should().Be(vertexD); + + var vertexC_Index_AfterUpdate = vertexC.Index; + vertexC_Index_AfterUpdate.Should().Be(1); + var neighborsC_AfterUpdate = graph.GetNeighbors(vertexC).ToList(); + neighborsC_AfterUpdate.Should().HaveCount(2); + neighborsC_AfterUpdate[0].Should().Be(vertexA); + neighborsC_AfterUpdate[1].Should().Be(vertexD); + + var vertexD_Index_AfterUpdate = vertexD.Index; + vertexD_Index_AfterUpdate.Should().Be(2); + var neighborsD_AfterUpdate = graph.GetNeighbors(vertexD).ToList(); + neighborsD_AfterUpdate.Should().HaveCount(2); + neighborsD_AfterUpdate[0].Should().Be(vertexA); + neighborsD_AfterUpdate[1].Should().Be(vertexC); + + var weight_A_C_AfterUpdate = graph.AdjacentDistance(vertexA, vertexC); + var weight_A_D_AfterUpdate = graph.AdjacentDistance(vertexA, vertexD); + var weight_C_A_AfterUpdate = graph.AdjacentDistance(vertexC, vertexA); + var weight_C_D_AfterUpdate = graph.AdjacentDistance(vertexC, vertexD); + var weight_D_A_AfterUpdate = graph.AdjacentDistance(vertexD, vertexA); + var weight_D_C_AfterUpdate = graph.AdjacentDistance(vertexD, vertexC); + weight_A_D_AfterUpdate.Should().Be(weight_A_D); + weight_A_C_AfterUpdate.Should().Be(weight_A_C); + weight_D_A_AfterUpdate.Should().Be(weight_D_A); + weight_D_C_AfterUpdate.Should().Be(weight_D_C); + weight_C_A_AfterUpdate.Should().Be(weight_C_A); + weight_C_D_AfterUpdate.Should().Be(weight_C_D); + } + [Test] public void GraphRemoveVertexTest_ShouldThrowVertexNotInGraph() { diff --git a/DataStructures/Graph/DirectedWeightedGraph.cs b/DataStructures/Graph/DirectedWeightedGraph.cs index 7385e03f..15e0a336 100644 --- a/DataStructures/Graph/DirectedWeightedGraph.cs +++ b/DataStructures/Graph/DirectedWeightedGraph.cs @@ -86,13 +86,49 @@ public void RemoveVertex(Vertex vertex) { ThrowIfVertexNotInGraph(vertex); - Vertices[vertex.Index] = null; + int indexToRemove = vertex.Index; + vertex.Index = -1; vertex.SetGraphNull(); - for (var i = 0; i < Count; i++) + // Update the vertex array and the index of vertices. + for (int i = indexToRemove; i < Count - 1; i++) { - adjacencyMatrix[i, vertex.Index] = 0; - adjacencyMatrix[vertex.Index, i] = 0; + Vertices[i] = Vertices[i + 1]; + Vertices[i] !.Index = i; + } + + Vertices[Count - 1] = null; + + // Update adjacency matrix to remove the row and column of the removed vertex. + for (int i = 0; i < Count; i++) + { + for (int j = 0; j < Count; j++) + { + if (i < indexToRemove && j < indexToRemove) + { + continue; + } + else if (i < indexToRemove && j >= indexToRemove && j < Count - 1) + { + adjacencyMatrix[i, j] = adjacencyMatrix[i, j + 1]; + } + else if (i >= indexToRemove && i < Count - 1 && j < indexToRemove) + { + adjacencyMatrix[i, j] = adjacencyMatrix[i + 1, j]; + } + else if (i >= indexToRemove && i < Count - 1 && j >= indexToRemove && j < Count - 1) + { + adjacencyMatrix[i, j] = adjacencyMatrix[i + 1, j + 1]; + } + else if (i == Count - 1 || j == Count - 1) + { + adjacencyMatrix[i, j] = 0; + } + else + { + throw new InvalidOperationException(); + } + } } Count--; diff --git a/DataStructures/Graph/Vertex.cs b/DataStructures/Graph/Vertex.cs index 072366d8..bc5353b1 100644 --- a/DataStructures/Graph/Vertex.cs +++ b/DataStructures/Graph/Vertex.cs @@ -14,7 +14,7 @@ public class Vertex /// /// Gets an index of the vertex in graph adjacency matrix. /// - public int Index { get; } + public int Index { get; internal set; } /// /// Gets reference to the graph this vertex belongs to. From 7a61d94f23105c8c46a296b0c475772e529398ee Mon Sep 17 00:00:00 2001 From: Philipp Meier Date: Thu, 9 May 2024 19:38:09 +0200 Subject: [PATCH 098/138] Fix broken links in README.md (#452) --- README.md | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 43ac9a56..febc021e 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ find more than one implementation for the same objective but using different alg * [Algorithms](./Algorithms) * [Crypto](./Algorithms/Crypto/) * [Paddings](./Algorithms/Crypto/Paddings/) - * [ISO 10125-2 Padding](./Algorithms/Crypto/Paddings/ISO10126d2Padding.cs) - * [ISO 7816-4 Padding](./Algorithms/Crypto/Paddings/ISO7816d4Padding.cs) + * [ISO 10125-2 Padding](./Algorithms/Crypto/Paddings/Iso10126D2Padding.cs) + * [ISO 7816-4 Padding](./Algorithms/Crypto/Paddings/Iso7816D4Padding.cs) * [X9.32 Padding](./Algorithms/Crypto/Paddings/X932Padding.cs) * [TBC Padding](./Algorithms/Crypto/Paddings/TbcPadding.cs) - * [PKCS7 Padding](./Algorithms/Crypto/Paddings/PKCS7Padding.cs) + * [PKCS7 Padding](./Algorithms/Crypto/Paddings/Pkcs7Padding.cs) * [Digests](./Algorithms/Crypto/Digests/) * [MD2 Digest](./Algorithms/Crypto/Digests/Md2Digest.cs) * [Data Compression](./Algorithms/DataCompression) @@ -54,7 +54,7 @@ find more than one implementation for the same objective but using different alg * [Naive solver](./Algorithms/Knapsack/NaiveKnapsackSolver.cs) * [Dynamic Programming solver](./Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs) * [Branch and bound solver](./Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs) - * [IHeuristicSolver](./Algorithms/Knapsack/IHeuristicSolver.cs) + * [IHeuristicKnapsackSolver](./Algorithms/Knapsack/IHeuristicKnapsackSolver.cs) * [Linear Algebra](./Algorithms/LinearAlgebra) * [Distances](./Algorithms/LinearAlgebra/Distances) * [Euclidean](./Algorithms/LinearAlgebra/Distances/Euclidean.cs) @@ -132,7 +132,6 @@ find more than one implementation for the same objective but using different alg * [Radix Sort](./Algorithms/Sorters/Integer/RadixSorter.cs) * [String](./Algorithms/Sorters/String) * [MSD Radix Sort](./Algorithms/Sorters/String/MsdRadixStringSorter.cs) - * [Knuth–Morris–Pratt Search](./Algorithms/Strings/KnuthMorrisPrattSearcher.cs) * [Shufflers](./Algorithms/Shufflers) * [Fisher-Yates Shuffler](./Algorithms/Shufflers/FisherYatesShuffler.cs) * [Sequences](./Algorithms/Sequences) @@ -177,20 +176,20 @@ find more than one implementation for the same objective but using different alg * [A057588 Kummer Numbers](./Algorithms/Sequences/KummerNumbersSequence.cs) * [A019434 Fermat Primes](./Algorithms/Sequences/FermatPrimesSequence.cs) * [A181391 Van Eck's](./Algorithms/Sequences/VanEcksSequence.cs) - * [String](./Algorithms/Strings) + * [String](./Algorithms/Strings) * [Similarity](./Algorithms/Strings/Similarity/) - * [Hamming Distance](./Algorithms/Strings/HammingDistance.cs) - * [Jaro Similarity](./Algorithms/Strings/JaroSimilarity.cs) - * [Jaro-Winkler Distance](./Algorithms/Strings/JaroWinklerDistance.cs) - * [Pattern Matching](./Algorithms/Strings/PatternMatching/) - * [Longest Consecutive Character](./Algorithms/Strings/PatternMatching/GeneralStringAlgorithms.cs) + * [Hamming Distance](./Algorithms/Strings/Similarity/HammingDistance.cs) + * [Jaro Similarity](./Algorithms/Strings/Similarity/JaroSimilarity.cs) + * [Jaro-Winkler Distance](./Algorithms/Strings/Similarity/JaroWinklerDistance.cs) + * [Pattern Matching](./Algorithms/Strings/PatternMatching/) * [Naive String Search](./Algorithms/Strings/PatternMatching/NaiveStringSearch.cs) * [Rabin Karp](./Algorithms/Strings/PatternMatching/RabinKarp.cs) * [Boyer Moore](./Algorithms/Strings/PatternMatching/BoyerMoore.cs) + * [Knuth–Morris–Pratt Search](./Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs) + * [Z-block substring search](./Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs) + * [Longest Consecutive Character](./Algorithms/Strings/GeneralStringAlgorithms.cs) * [Palindrome Checker](./Algorithms/Strings/Palindrome.cs) * [Get all permutations of a string](./Algorithms/Strings/Permutation.cs) - - * [Z-block substring search](./Algorithms/Strings/ZblockSubstringSearch.cs) * [Other](./Algorithms/Other) * [Fermat Prime Checker](./Algorithms/Other/FermatPrimeChecker.cs) * [Sieve of Eratosthenes](./Algorithms/Other/SieveOfEratosthenes.cs) @@ -227,7 +226,7 @@ find more than one implementation for the same objective but using different alg * [Segment Tree Update](./DataStructures/SegmentTrees/SegmentTreeUpdate.cs) * [Binary Search Tree](./DataStructures/BinarySearchTree) * [Scapegoat Tree](./DataStructures/ScapegoatTree) - * [Fenwick tree (or Binary Indexed Tree)](./DataStructures/BinaryIndexedTree) + * [Fenwick tree (or Binary Indexed Tree)](./DataStructures/Fenwick/BinaryIndexedTree.cs) * [AA Tree](./DataStructures/AATree) * [AVL Tree](./DataStructures/AVLTree) * [Red-Black Tree](./DataStructures/RedBlackTree) From 50829eaec756ddfe3caaa525b03f0d9b64bcef02 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Mon, 20 May 2024 22:26:37 +0200 Subject: [PATCH 099/138] Upload coverage report using `CODECOV_TOKEN` (#454) --- .github/workflows/ci.yml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26f7b3d8..531eace4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,5 +19,19 @@ jobs: run: dotnet build --no-restore - name: Test run: dotnet test --no-restore --collect "XPlat Code Coverage" - - name: Upload code coverage to Codecov - run: bash <(curl -s https://codecov.io/bash) + - name: Upload coverage to codecov (tokenless) + if: >- + github.event_name == 'pull_request' && + github.event.pull_request.head.repo.full_name != github.repository + uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: true + - name: Upload coverage to codecov (with token) + if: > + github.repository == 'TheAlgorithms/C-Sharp' && + (github.event_name != 'pull_request' || + github.event.pull_request.head.repo.full_name == github.repository) + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true From 327af3d29b56f9964d5ade422bb8cf87022177be Mon Sep 17 00:00:00 2001 From: ZLoo Date: Sat, 13 Jul 2024 21:21:58 +0300 Subject: [PATCH 100/138] Replace System.Drawing.Common with SkiaSharp (#455) --- Algorithms.Tests/Other/FloodFillTest.cs | 33 ++++++++------- Algorithms.Tests/Other/KochSnowflakeTest.cs | 15 +++---- Algorithms.Tests/Other/MandelbrotTest.cs | 14 +++--- Algorithms/Algorithms.csproj | 3 +- Algorithms/Other/FloodFill.cs | 10 ++--- Algorithms/Other/KochSnowflake.cs | 47 ++++++++++++--------- Algorithms/Other/Mandelbrot.cs | 38 +++++++++-------- 7 files changed, 84 insertions(+), 76 deletions(-) diff --git a/Algorithms.Tests/Other/FloodFillTest.cs b/Algorithms.Tests/Other/FloodFillTest.cs index dfc1c807..e24dc1da 100644 --- a/Algorithms.Tests/Other/FloodFillTest.cs +++ b/Algorithms.Tests/Other/FloodFillTest.cs @@ -1,17 +1,18 @@ -using System; -using System.Drawing; using FluentAssertions; using NUnit.Framework; +using SkiaSharp; +using System; namespace Algorithms.Tests.Other; public static class Tests { - private static readonly Color Black = Color.FromArgb(255, 0, 0, 0); - private static readonly Color Green = Color.FromArgb(255, 0, 255, 0); - private static readonly Color Violet = Color.FromArgb(255, 255, 0, 255); - private static readonly Color White = Color.FromArgb(255, 255, 255, 255); - private static readonly Color Orange = Color.FromArgb(255, 255, 128, 0); + private const byte Alpha = 255; + private static readonly SKColor Black = new(0, 0, 0, Alpha); + private static readonly SKColor Green = new(0, 255, 0, Alpha); + private static readonly SKColor Violet = new(255, 0, 255, Alpha); + private static readonly SKColor White = new(255, 255, 255, Alpha); + private static readonly SKColor Orange = new(255, 128, 0, Alpha); [Test] public static void BreadthFirstSearch_ThrowsArgumentOutOfRangeException() @@ -63,9 +64,9 @@ public static void DepthFirstSearch_Test3() TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), Green, Orange, (6, 4), White); } - private static Bitmap GenerateTestBitmap() + private static SKBitmap GenerateTestBitmap() { - Color[,] layout = + SKColor[,] layout = { {Violet, Violet, Green, Green, Black, Green, Green}, {Violet, Green, Green, Black, Green, Green, Green}, @@ -76,7 +77,7 @@ private static Bitmap GenerateTestBitmap() {Violet, Violet, Violet, Violet, Violet, Violet, Violet}, }; - Bitmap bitmap = new(7, 7); + SKBitmap bitmap = new(7, 7); for (int x = 0; x < layout.GetLength(0); x++) { for (int y = 0; y < layout.GetLength(1); y++) @@ -89,16 +90,16 @@ private static Bitmap GenerateTestBitmap() } private static void TestAlgorithm( - Action, Color, Color> algorithm, + Action, SKColor, SKColor> algorithm, ValueTuple fillLocation, - Color targetColor, - Color replacementColor, + SKColor targetColor, + SKColor replacementColor, ValueTuple testLocation, - Color expectedColor) + SKColor expectedColor) { - Bitmap bitmap = GenerateTestBitmap(); + SKBitmap bitmap = GenerateTestBitmap(); algorithm(bitmap, fillLocation, targetColor, replacementColor); - Color actualColor = bitmap.GetPixel(testLocation.Item1, testLocation.Item2); + SKColor actualColor = bitmap.GetPixel(testLocation.Item1, testLocation.Item2); actualColor.Should().Be(expectedColor); } } diff --git a/Algorithms.Tests/Other/KochSnowflakeTest.cs b/Algorithms.Tests/Other/KochSnowflakeTest.cs index 9c132452..432a6975 100644 --- a/Algorithms.Tests/Other/KochSnowflakeTest.cs +++ b/Algorithms.Tests/Other/KochSnowflakeTest.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Numerics; using Algorithms.Other; using FluentAssertions; using NUnit.Framework; +using SkiaSharp; +using System; +using System.Collections.Generic; +using System.Numerics; namespace Algorithms.Tests.Other; @@ -39,13 +39,12 @@ public static void TestKochSnowflakeExample() var bitmapWidth = 600; var offsetX = bitmapWidth / 10f; var offsetY = bitmapWidth / 3.7f; - - Bitmap bitmap = KochSnowflake.GetKochSnowflake(); + SKBitmap bitmap = KochSnowflake.GetKochSnowflake(); bitmap.GetPixel(0, 0) .Should() - .Be(Color.FromArgb(255, 255, 255, 255), "because the background should be white"); + .Be(new SKColor(255, 255, 255, 255), "because the background should be white"); bitmap.GetPixel((int)offsetX, (int)offsetY) .Should() - .Be(Color.FromArgb(255, 0, 0, 0), "because the snowflake is drawn in black and this is the position of the first vector"); + .Be(new SKColor(0, 0, 0, 255), "because the snowflake is drawn in black and this is the position of the first vector"); } } diff --git a/Algorithms.Tests/Other/MandelbrotTest.cs b/Algorithms.Tests/Other/MandelbrotTest.cs index 9d72de54..6588160d 100644 --- a/Algorithms.Tests/Other/MandelbrotTest.cs +++ b/Algorithms.Tests/Other/MandelbrotTest.cs @@ -1,7 +1,7 @@ using System; -using System.Drawing; using Algorithms.Other; using NUnit.Framework; +using SkiaSharp; namespace Algorithms.Tests.Other; @@ -28,22 +28,22 @@ public static void MaxStepIsZeroOrNegative_ThrowsArgumentOutOfRangeException() [Test] public static void TestBlackAndWhite() { - Bitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: false); + SKBitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: false); // Pixel outside the Mandelbrot set should be white. - Assert.That(Color.FromArgb(255, 255, 255, 255), Is.EqualTo(bitmap.GetPixel(0, 0))); + Assert.That(new SKColor(255, 255, 255, 255), Is.EqualTo(bitmap.GetPixel(0, 0))); // Pixel inside the Mandelbrot set should be black. - Assert.That(Color.FromArgb(255, 0, 0, 0), Is.EqualTo(bitmap.GetPixel(400, 300))); + Assert.That(new SKColor(0, 0, 0, 255), Is.EqualTo(bitmap.GetPixel(400, 300))); } [Test] public static void TestColorCoded() { - Bitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: true); + SKBitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: true); // Pixel distant to the Mandelbrot set should be red. - Assert.That(Color.FromArgb(255, 255, 0, 0), Is.EqualTo(bitmap.GetPixel(0, 0))); + Assert.That(new SKColor(255, 0, 0, 255), Is.EqualTo(bitmap.GetPixel(0, 0))); // Pixel inside the Mandelbrot set should be black. - Assert.That(Color.FromArgb(255, 0, 0, 0), Is.EqualTo(bitmap.GetPixel(400, 300))); + Assert.That(new SKColor(0, 0, 0, 255), Is.EqualTo(bitmap.GetPixel(400, 300))); } } diff --git a/Algorithms/Algorithms.csproj b/Algorithms/Algorithms.csproj index 01c73e2a..84283140 100644 --- a/Algorithms/Algorithms.csproj +++ b/Algorithms/Algorithms.csproj @@ -16,11 +16,12 @@ + + all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/Algorithms/Other/FloodFill.cs b/Algorithms/Other/FloodFill.cs index 0904e9c9..22cc94e1 100644 --- a/Algorithms/Other/FloodFill.cs +++ b/Algorithms/Other/FloodFill.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Drawing; +using SkiaSharp; namespace Algorithms.Other; @@ -23,7 +23,7 @@ public static class FloodFill /// The start location on the bitmap. /// The old color to be replaced. /// The new color to replace the old one. - public static void BreadthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) + public static void BreadthFirstSearch(SKBitmap bitmap, (int x, int y) location, SKColor targetColor, SKColor replacementColor) { if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) { @@ -46,7 +46,7 @@ public static void BreadthFirstSearch(Bitmap bitmap, (int x, int y) location, Co /// The start location on the bitmap. /// The old color to be replaced. /// The new color to replace the old one. - public static void DepthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) + public static void DepthFirstSearch(SKBitmap bitmap, (int x, int y) location, SKColor targetColor, SKColor replacementColor) { if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) { @@ -56,7 +56,7 @@ public static void DepthFirstSearch(Bitmap bitmap, (int x, int y) location, Colo DepthFirstFill(bitmap, location, targetColor, replacementColor); } - private static void BreadthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor, List<(int x, int y)> queue) + private static void BreadthFirstFill(SKBitmap bitmap, (int x, int y) location, SKColor targetColor, SKColor replacementColor, List<(int x, int y)> queue) { (int x, int y) currentLocation = queue[0]; queue.RemoveAt(0); @@ -77,7 +77,7 @@ private static void BreadthFirstFill(Bitmap bitmap, (int x, int y) location, Col } } - private static void DepthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) + private static void DepthFirstFill(SKBitmap bitmap, (int x, int y) location, SKColor targetColor, SKColor replacementColor) { if (bitmap.GetPixel(location.x, location.y) == targetColor) { diff --git a/Algorithms/Other/KochSnowflake.cs b/Algorithms/Other/KochSnowflake.cs index 6ad5d6e4..739bffd4 100644 --- a/Algorithms/Other/KochSnowflake.cs +++ b/Algorithms/Other/KochSnowflake.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.Numerics; +using SkiaSharp; namespace Algorithms.Other; @@ -52,7 +52,7 @@ public static List Iterate(List initialVectors, int steps = 5) /// The width of the rendered bitmap. /// The number of iterations. /// The bitmap of the rendered Koch snowflake. - public static Bitmap GetKochSnowflake( + public static SKBitmap GetKochSnowflake( int bitmapWidth = 600, int steps = 5) { @@ -124,31 +124,36 @@ private static Vector2 Rotate(Vector2 vector, float angleInDegrees) /// The width of the rendered bitmap. /// The height of the rendered bitmap. /// The bitmap of the rendered edges. - private static Bitmap GetBitmap( + private static SKBitmap GetBitmap( List vectors, int bitmapWidth, int bitmapHeight) { - Bitmap bitmap = new(bitmapWidth, bitmapHeight); + SKBitmap bitmap = new(bitmapWidth, bitmapHeight); + var canvas = new SKCanvas(bitmap); - using (Graphics graphics = Graphics.FromImage(bitmap)) + // Set the background white + var rect = SKRect.Create(0, 0, bitmapWidth, bitmapHeight); + + var paint = new SKPaint { - // Set the background white - var imageSize = new Rectangle(0, 0, bitmapWidth, bitmapHeight); - graphics.FillRectangle(Brushes.White, imageSize); - - // Draw the edges - for (var i = 0; i < vectors.Count - 1; i++) - { - Pen blackPen = new(Color.Black, 1); - - var x1 = vectors[i].X; - var y1 = vectors[i].Y; - var x2 = vectors[i + 1].X; - var y2 = vectors[i + 1].Y; - - graphics.DrawLine(blackPen, x1, y1, x2, y2); - } + Style = SKPaintStyle.Fill, + Color = SKColors.White, + }; + + canvas.DrawRect(rect, paint); + + paint.Color = SKColors.Black; + + // Draw the edges + for (var i = 0; i < vectors.Count - 1; i++) + { + var x1 = vectors[i].X; + var y1 = vectors[i].Y; + var x2 = vectors[i + 1].X; + var y2 = vectors[i + 1].Y; + + canvas.DrawLine(new SKPoint(x1, y1), new SKPoint(x2, y2), paint); } return bitmap; diff --git a/Algorithms/Other/Mandelbrot.cs b/Algorithms/Other/Mandelbrot.cs index 777bca2f..c93d3acf 100644 --- a/Algorithms/Other/Mandelbrot.cs +++ b/Algorithms/Other/Mandelbrot.cs @@ -1,5 +1,5 @@ using System; -using System.Drawing; +using SkiaSharp; namespace Algorithms.Other; @@ -22,6 +22,8 @@ namespace Algorithms.Other; /// public static class Mandelbrot { + private const byte Alpha = 255; + /// /// Method to generate the bitmap of the Mandelbrot set. Two types of coordinates /// are used: bitmap-coordinates that refer to the pixels and figure-coordinates @@ -39,7 +41,7 @@ public static class Mandelbrot /// Maximum number of steps to check for divergent behavior. /// Render in color or black and white. /// The bitmap of the rendered Mandelbrot set. - public static Bitmap GetBitmap( + public static SKBitmap GetBitmap( int bitmapWidth = 800, int bitmapHeight = 600, double figureCenterX = -0.6, @@ -69,7 +71,7 @@ public static Bitmap GetBitmap( $"{nameof(maxStep)} should be greater than zero"); } - var bitmap = new Bitmap(bitmapWidth, bitmapHeight); + var bitmap = new SKBitmap(bitmapWidth, bitmapHeight); var figureHeight = figureWidth / bitmapWidth * bitmapHeight; // loop through the bitmap-coordinates @@ -100,10 +102,10 @@ public static Bitmap GetBitmap( /// /// Distance until divergence threshold. /// The color corresponding to the distance. - private static Color BlackAndWhiteColorMap(double distance) => + private static SKColor BlackAndWhiteColorMap(double distance) => distance >= 1 - ? Color.FromArgb(255, 0, 0, 0) - : Color.FromArgb(255, 255, 255, 255); + ? new SKColor(0, 0, 0, Alpha) + : new SKColor(255, 255, 255, Alpha); /// /// Color-coding taking the relative distance into account. The Mandelbrot set @@ -111,11 +113,11 @@ private static Color BlackAndWhiteColorMap(double distance) => /// /// Distance until divergence threshold. /// The color corresponding to the distance. - private static Color ColorCodedColorMap(double distance) + private static SKColor ColorCodedColorMap(double distance) { if (distance >= 1) { - return Color.FromArgb(255, 0, 0, 0); + return new SKColor(0, 0, 0, Alpha); } // simplified transformation of HSV to RGB @@ -126,19 +128,19 @@ private static Color ColorCodedColorMap(double distance) var hi = (int)Math.Floor(hue / 60) % 6; var f = hue / 60 - Math.Floor(hue / 60); - var v = (int)val; - var p = 0; - var q = (int)(val * (1 - f * saturation)); - var t = (int)(val * (1 - (1 - f) * saturation)); + var v = (byte)val; + const byte p = 0; + var q = (byte)(val * (1 - f * saturation)); + var t = (byte)(val * (1 - (1 - f) * saturation)); switch (hi) { - case 0: return Color.FromArgb(255, v, t, p); - case 1: return Color.FromArgb(255, q, v, p); - case 2: return Color.FromArgb(255, p, v, t); - case 3: return Color.FromArgb(255, p, q, v); - case 4: return Color.FromArgb(255, t, p, v); - default: return Color.FromArgb(255, v, p, q); + case 0: return new SKColor(v, t, p, Alpha); + case 1: return new SKColor(q, v, p, Alpha); + case 2: return new SKColor(p, v, t, Alpha); + case 3: return new SKColor(p, q, v, Alpha); + case 4: return new SKColor(t, p, v, Alpha); + default: return new SKColor(v, p, q, Alpha); } } From b0838cbb3296d99bb8feade676460e6d08b38460 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Thu, 25 Jul 2024 23:19:28 +0300 Subject: [PATCH 101/138] Add Bitap pattern matching (#458) --- .../Strings/PatternMatching/BitapTests.cs | 119 +++++++++ Algorithms/Strings/PatternMatching/Bitap.cs | 243 ++++++++++++++++++ README.md | 1 + 3 files changed, 363 insertions(+) create mode 100644 Algorithms.Tests/Strings/PatternMatching/BitapTests.cs create mode 100644 Algorithms/Strings/PatternMatching/Bitap.cs diff --git a/Algorithms.Tests/Strings/PatternMatching/BitapTests.cs b/Algorithms.Tests/Strings/PatternMatching/BitapTests.cs new file mode 100644 index 00000000..133d63f0 --- /dev/null +++ b/Algorithms.Tests/Strings/PatternMatching/BitapTests.cs @@ -0,0 +1,119 @@ +using System; +using Algorithms.Strings.PatternMatching; +using NUnit.Framework; + +namespace Algorithms.Tests.Strings.PatternMatching; + +[TestFixture] +public class BitapTests +{ + [Test] + public void FindExactPattern_EmptyTextReturnsError() + { + Assert.That(Bitap.FindExactPattern("", "abc"), Is.EqualTo(-1)); + } + + [Test] + public void FindExactPattern_EmptyPatternReturnsZero() + { + Assert.That(Bitap.FindExactPattern("abc", ""), Is.EqualTo(0)); + } + + [Test] + public void FindExactPattern_PatternFoundAtBeginning() + { + Assert.That(Bitap.FindExactPattern("hello world", "hello"), Is.EqualTo(0)); + } + + [Test] + public void FindExactPattern_PatternFoundInTheMiddle() + { + Assert.That(Bitap.FindExactPattern("abcabc", "cab"), Is.EqualTo(2)); + } + + [Test] + public void FindExactPattern_PatternFoundAtEnd() + { + Assert.That(Bitap.FindExactPattern("the end", "end"), Is.EqualTo(4)); + } + + [Test] + public void FindExactPattern_PatternNotFound() + { + Assert.That(Bitap.FindExactPattern("abcdefg", "xyz"), Is.EqualTo(-1)); + } + + [Test] + public void FindExactPattern_PatternLongerThanText() + { + Assert.That(Bitap.FindExactPattern("short", "longerpattern"), Is.EqualTo(-1)); + } + + [Test] + public void FindExactPattern_OverlappingPatterns() + { + Assert.That(Bitap.FindExactPattern("ababab", "abab"), Is.EqualTo(0)); + } + + [Test] + public void FindExactPattern_PatternTooLongThrowsException() + { + var longPattern = new string('a', 32); + Assert.Throws(() => Bitap.FindExactPattern("some text", longPattern)); + } + + [Test] + public void FindExactPattern_SpecialCharactersInPattern() + { + Assert.That(Bitap.FindExactPattern("hello, world!", ", wo"), Is.EqualTo(5)); + } + + [Test] + public void FindFuzzyPattern_EmptyTextReturnsZero() + { + Assert.That(Bitap.FindFuzzyPattern("", "abc", 1), Is.EqualTo(0)); + } + + [Test] + public void FindFuzzyPattern_EmptyPatternReturnsZero() + { + Assert.That(Bitap.FindFuzzyPattern("def", "", 1), Is.EqualTo(0)); + } + + [Test] + public void FindFuzzyPattern_ExactMatchFound() + { + Assert.That(Bitap.FindFuzzyPattern("hello world", "hello", 0), Is.EqualTo(0)); + } + + [Test] + public void FindFuzzyPattern_FuzzyMatchWithOneMismatch() + { + Assert.That(Bitap.FindFuzzyPattern("hello world", "hellp", 1), Is.EqualTo(0)); + } + + [Test] + public void FindFuzzyPattern_FuzzyMatchWithMultipleMismatches() + { + Assert.That(Bitap.FindFuzzyPattern("abcde", "xbcdz", 2), Is.EqualTo(0)); + } + + [Test] + public void FindFuzzyPattern_FuzzyMatchAtEnd() + { + Assert.That(Bitap.FindFuzzyPattern("abcdefg", "efx", 1), Is.EqualTo(4)); + } + + [Test] + public void FindFuzzyPattern_FuzzyMatchNotFound() + { + Assert.That(Bitap.FindFuzzyPattern("abcdefg", "xyz", 2), Is.EqualTo(-1)); + } + + [Test] + public void FindFuzzyPattern_PatternTooLongReturnsNegativeOne() + { + var longPattern = new string('a', 32); + Assert.That(Bitap.FindFuzzyPattern("some text", longPattern, 1), Is.EqualTo(-1)); + } +} diff --git a/Algorithms/Strings/PatternMatching/Bitap.cs b/Algorithms/Strings/PatternMatching/Bitap.cs new file mode 100644 index 00000000..0ca5975a --- /dev/null +++ b/Algorithms/Strings/PatternMatching/Bitap.cs @@ -0,0 +1,243 @@ +using System; + +namespace Algorithms.Strings.PatternMatching; + +/// +/// The Bitap algorithm is a fuzzy string matching technique. It ains to find approximate matches of a pattern within a +/// text, allowing for a certain degree of mismatch (e.g., mistypes, minor variations etc.). It's knowd for its efficiency, +/// using bitwise operations for fast comparisons. +/// +/// +/// How it works: +/// +/// +/// Initialization +/// +/// Bitmasks are created for each character in the pattern. These bitmasks are essentially binary numbers where each bit +/// represents a specific character's position within the pattern. An initial state variable R is set to all 1s, +/// indicating that all characters in the pattern are initially unmatched. +/// +/// +/// +/// Iteration +/// +/// The algorithm iterates through each character in the text. For each character, the state R is updated using +/// bitwise operations (shifts and logical ORs). This update reflects whether the current character in the text matches +/// the corresponding character in the pattern. +/// +/// +/// +/// Matching +/// +/// After each iteration, the algorithm checks if the least significant bit of R is set to 1. +/// If it is, it means there's a potential match at that position, with a mismatch distance that's within the allowed +/// threshold. +/// +/// +/// +/// +/// +/// Finding Matches +/// +/// +/// If the least significant bit of R is 1, it means a potential match is found. +/// The number of leading zeros in R indicates the mismatch distance. +/// If this distance is within the allowed threshold, it's considered a valid match. +/// +/// +public static class Bitap +{ + /// + /// + /// This function implements the Bitap algorithm for finding exact matches of a pattern within a text. + /// It aims to find the first occurrence of the pattern in the text, allowing for no mismatches. + /// + /// + /// The algorithm iterates through each character in the text. For each character, the state R is updated using + /// bitwise operations (shifts and logical ORs). This update reflects whether the current character in the text matches + /// the corresponding character in the pattern. + /// + /// + /// After each iteration, the algorithm checks if the least significant bit of R is set to 1. + /// If it is, it means there's a potential match at that position, with a mismatch distance of 0. + /// The function returns the index of the first occurrence of the pattern in the text, or -1 if not found. + /// + /// + /// The function throws an if the pattern is longer than 31 characters. + /// This is because the maximum length of the pattern is 31, because if it's longer than that, + /// we won't be able to represent the pattern mask in an int. + /// + /// + /// The text to search in. + /// The pattern to search for. + /// The index of the first occurrence of the pattern in the text, or -1 if not found. + /// The pattern is longer than 31 characters. + public static int FindExactPattern(string text, string pattern) + { + // The length of the pattern. + var len = pattern.Length; + + // An array of integers that will be used to mask the pattern. + // The pattern mask is a bitmask that we will use to search for the pattern characters + // in the text. We'll set the bit corresponding to the character in the pattern + // to 0, and then use bitwise operations to check for the pattern. + var patternMask = new int[128]; + int index; + + // Check if the pattern is empty. + if (string.IsNullOrEmpty(pattern)) + { + return 0; + } + + // Check if the pattern is longer than 31 characters. + if (len > 31) + { + throw new ArgumentException("The pattern is longer than 31 characters."); + } + + // Initialize the register R to all 1s. + var r = ~1; + + // Initialize the pattern mask to all 1s. + for (index = 0; index <= 127; ++index) + { + patternMask[index] = ~0; + } + + // Set the bits corresponding to the characters in the pattern to 0 in the pattern mask. + for (index = 0; index < len; ++index) + { + patternMask[pattern[index]] &= ~(1 << index); + } + + // Iterate through each character in the text. + for (index = 0; index < text.Length; ++index) + { + // Update the state R by ORing the pattern mask with the character in the text, + // and then shift it to the left by 1. + r |= patternMask[text[index]]; + r <<= 1; + + // Check if the least significant bit of R is set to 1. + // If there's a potential match at that position, with a mismatch distance of 0, + // return the index of the first occurrence of the pattern in the text. + if ((r & 1 << len) == 0) + { + return index - len + 1; + } + } + + // If no match is found, return -1. + return -1; + } + + /// + /// Finds the first occurrence of a pattern in a given text with a given threshold for mismatches. + /// + /// The text to search in. + /// The pattern to search for. + /// The maximum number of mismatches allowed. + /// The index of the first occurrence of the pattern in the text, or -1 if not found. + public static int FindFuzzyPattern(string text, string pattern, int threshold) + { + // Create a pattern mask for each character in the pattern. + // The pattern mask is a bitmask that we will use to search for the pattern characters + // in the text. We'll set the bit corresponding to the character in the pattern + // to 0, and then use bitwise operations to check for the pattern. + var patternMask = new int[128]; + + // Create a register array. + // The register array is used to keep track of the pattern mask as we search for the pattern. + // We'll start with a register that has all bits set to 1, because all bits in the pattern mask + // will be set to 1 initially. + var r = new int[(threshold + 1) * sizeof(int)]; + + var len = pattern.Length; + + // Check for empty strings. + // If the text is empty, return 0. + // If the pattern is empty, return 0. + if (string.IsNullOrEmpty(text)) + { + return 0; + } + + if (string.IsNullOrEmpty(pattern)) + { + return 0; + } + + // Check for a pattern that is too long. + // If the pattern is longer than 31 characters, return -1. + // The maximum length of the pattern is 31, because if it's longer than that, + // we won't be able to represent the pattern mask in an int. + if (len > 31) + { + return -1; + } + + // Initialize the register. + // Set the least significant bit in the register to 0 or 1 + // depending on whether the current character in the text matches the pattern. + // This will make it easier to check for the pattern later. + for (var i = 0; i <= threshold; ++i) + { + r[i] = ~1; + } + + // Initialize the pattern mask. + // Set the bit corresponding to each character in the pattern to 0 in the pattern mask. + // This will make it easier to check for the pattern later. + for (var i = 0; i <= 127; i++) + { + patternMask[i] = ~0; + } + + // Set the pattern mask for each character in the pattern. + // Use bitwise AND to clear the bit corresponding to the current character. + for (var i = 0; i < len; ++i) + { + patternMask[pattern[i]] &= ~(1 << i); + } + + // Search for the pattern in the text. + // Loop through each character in the text. + for (var i = 0; i < text.Length; ++i) + { + // Update the register. + // Set the least significant bit in the register to 0 or 1 + // depending on whether the current character in the text matches the pattern. + // This will make it easier to check for the pattern later. + var oldR = r[0]; + + r[0] |= patternMask[text[i]]; + r[0] <<= 1; + + // Update the other registers. + // Set the least significant bit in each register to 0 or 1 + // depending on whether the current character in the text matches the pattern. + // This will make it easier to check for the pattern later. + for (var j = 1; j <= threshold; ++j) + { + var tmp = r[j]; + + r[j] = (oldR & (r[j] | patternMask[text[i]])) << 1; + oldR = tmp; + } + + // If the pattern has been found, return the index. + // Check the most significant bit in the register. + // If it's 0, then the pattern has been found. + if ((r[threshold] & 1 << len) == 0) + { + // The pattern has been found. + // Return the index of the first character in the pattern. + return i - len + 1; + } + } + + // The pattern has not been found. + return -1; + } +} diff --git a/README.md b/README.md index febc021e..f5d26fd8 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,7 @@ find more than one implementation for the same objective but using different alg * [Jaro Similarity](./Algorithms/Strings/Similarity/JaroSimilarity.cs) * [Jaro-Winkler Distance](./Algorithms/Strings/Similarity/JaroWinklerDistance.cs) * [Pattern Matching](./Algorithms/Strings/PatternMatching/) + * [Bitop Pattern Matching](./Algorithms/Strings/PatternMatching/Bitap.cs) * [Naive String Search](./Algorithms/Strings/PatternMatching/NaiveStringSearch.cs) * [Rabin Karp](./Algorithms/Strings/PatternMatching/RabinKarp.cs) * [Boyer Moore](./Algorithms/Strings/PatternMatching/BoyerMoore.cs) From 9eb21968c96812bd32c5b07841e8a1bbc193c469 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Thu, 1 Aug 2024 09:34:14 +0300 Subject: [PATCH 102/138] Add Cosine Similarity Algorithm for Strings (#459) --- .../Similarity/CosineSimilarityTests.cs | 84 +++++++++++ .../Strings/Similarity/CosineSimilarity.cs | 136 ++++++++++++++++++ README.md | 1 + 3 files changed, 221 insertions(+) create mode 100644 Algorithms.Tests/Strings/Similarity/CosineSimilarityTests.cs create mode 100644 Algorithms/Strings/Similarity/CosineSimilarity.cs diff --git a/Algorithms.Tests/Strings/Similarity/CosineSimilarityTests.cs b/Algorithms.Tests/Strings/Similarity/CosineSimilarityTests.cs new file mode 100644 index 00000000..0770e913 --- /dev/null +++ b/Algorithms.Tests/Strings/Similarity/CosineSimilarityTests.cs @@ -0,0 +1,84 @@ +using System; +using Algorithms.Strings.Similarity; +using NUnit.Framework; + +namespace Algorithms.Tests.Strings.Similarity; + +[TestFixture] +public class CosineSimilarityTests +{ + [Test] + public void Calculate_IdenticalStrings_ReturnsOne() + { + var str1 = "test"; + var str2 = "test"; + var result = CosineSimilarity.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(1.0).Within(1e-6), "Identical strings should have a cosine similarity of 1."); + } + + [Test] + public void Calculate_CompletelyDifferentStrings_ReturnsZero() + { + var str1 = "abc"; + var str2 = "xyz"; + var result = CosineSimilarity.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(0.0).Within(1e-6), "Completely different strings should have a cosine similarity of 0."); + } + + [Test] + public void Calculate_EmptyStrings_ReturnsZero() + { + var str1 = ""; + var str2 = ""; + var result = CosineSimilarity.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(0.0).Within(1e-6), "Empty strings should have a cosine similarity of 0."); + } + + [Test] + public void Calculate_OneEmptyString_ReturnsZero() + { + var str1 = "test"; + var str2 = ""; + var result = CosineSimilarity.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(0.0).Within(1e-6), "Empty string should have a cosine similarity of 0."); + } + + [Test] + public void Calculate_SameCharactersDifferentCases_ReturnsOne() + { + var str1 = "Test"; + var str2 = "test"; + var result = CosineSimilarity.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(1.0).Within(1e-6), "The method should be case-insensitive."); + } + + [Test] + public void Calculate_SpecialCharacters_ReturnsCorrectValue() + { + var str1 = "hello!"; + var str2 = "hello!"; + var result = CosineSimilarity.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(1.0).Within(1e-6), "Strings with special characters should have a cosine similarity of 1."); + } + + [Test] + public void Calculate_DifferentLengthWithCommonCharacters_ReturnsCorrectValue() + { + var str1 = "hello"; + var str2 = "hello world"; + var result = CosineSimilarity.Calculate(str1, str2); + var expected = 10 / (Math.Sqrt(7) * Math.Sqrt(19)); // calculated manually + Assert.That(result, Is.EqualTo(expected).Within(1e-6), "Strings with different lengths but some common characters should have the correct cosine similarity."); + } + + [Test] + public void Calculate_PartiallyMatchingStrings_ReturnsCorrectValue() + { + var str1 = "night"; + var str2 = "nacht"; + var result = CosineSimilarity.Calculate(str1, str2); + // Assuming the correct calculation gives an expected value + var expected = 3.0 / 5.0; + Assert.That(result, Is.EqualTo(expected).Within(1e-6), "Partially matching strings should have the correct cosine similarity."); + } +} diff --git a/Algorithms/Strings/Similarity/CosineSimilarity.cs b/Algorithms/Strings/Similarity/CosineSimilarity.cs new file mode 100644 index 00000000..d05ee8c9 --- /dev/null +++ b/Algorithms/Strings/Similarity/CosineSimilarity.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; + +namespace Algorithms.Strings.Similarity; + +public static class CosineSimilarity +{ + /// + /// Calculates the Cosine Similarity between two strings. + /// Cosine Similarity is a measure of similarity between two non-zero vectors of an inner product space. + /// It measures the cosine of the angle between the two vectors. + /// + /// The first string. + /// The second string. + /// + /// A double value between 0 and 1 that represents the similarity + /// of the two strings. + /// + public static double Calculate(string left, string right) + { + // Step 1: Get the vectors for the two strings + // Each vector represents the frequency of each character in the string. + var vectors = GetVectors(left.ToLowerInvariant(), right.ToLowerInvariant()); + var leftVector = vectors.leftVector; + var rightVector = vectors.rightVector; + + // Step 2: Calculate the intersection of the two vectors + // The intersection is the set of characters that appear in both strings. + var intersection = GetIntersection(leftVector, rightVector); + + // Step 3: Calculate the dot product of the two vectors + // The dot product is the sum of the products of the corresponding values of the characters in the intersection. + var dotProduct = DotProduct(leftVector, rightVector, intersection); + + // Step 4: Calculate the square magnitude of each vector + // The magnitude is the square root of the sum of the squares of the values in the vector. + var mLeft = 0.0; + foreach (var value in leftVector.Values) + { + mLeft += value * value; + } + + var mRight = 0.0; + foreach (var value in rightVector.Values) + { + mRight += value * value; + } + + // Step 5: Check if either vector is zero + // If either vector is zero (i.e., all characters are unique), the Cosine Similarity is 0. + if (mLeft <= 0 || mRight <= 0) + { + return 0.0; + } + + // Step 6: Calculate and return the Cosine Similarity + // The Cosine Similarity is the dot product divided by the product of the magnitudes. + return dotProduct / (Math.Sqrt(mLeft) * Math.Sqrt(mRight)); + } + + /// + /// Calculates the vectors for the given strings. + /// + /// The first string. + /// The second string. + /// A tuple containing the vectors for the two strings. + private static (Dictionary leftVector, Dictionary rightVector) GetVectors(string left, string right) + { + var leftVector = new Dictionary(); + var rightVector = new Dictionary(); + + // Calculate the frequency of each character in the left string + foreach (var character in left) + { + leftVector.TryGetValue(character, out var frequency); + leftVector[character] = ++frequency; + } + + // Calculate the frequency of each character in the right string + foreach (var character in right) + { + rightVector.TryGetValue(character, out var frequency); + rightVector[character] = ++frequency; + } + + return (leftVector, rightVector); + } + + /// + /// Calculates the dot product between two vectors represented as dictionaries of character frequencies. + /// The dot product is the sum of the products of the corresponding values of the characters in the intersection of the two vectors. + /// + /// The vector of the left string. + /// The vector of the right string. + /// The intersection of the two vectors, represented as a set of characters. + /// The dot product of the two vectors. + private static double DotProduct(Dictionary leftVector, Dictionary rightVector, HashSet intersection) + { + // Initialize the dot product to 0 + double dotProduct = 0; + + // Iterate over each character in the intersection of the two vectors + foreach (var character in intersection) + { + // Calculate the product of the corresponding values of the characters in the left and right vectors + dotProduct += leftVector[character] * rightVector[character]; + } + + // Return the dot product + return dotProduct; + } + + /// + /// Calculates the intersection of two vectors, represented as dictionaries of character frequencies. + /// + /// The vector of the left string. + /// The vector of the right string. + /// A HashSet containing the characters that appear in both vectors. + private static HashSet GetIntersection(Dictionary leftVector, Dictionary rightVector) + { + // Initialize a HashSet to store the intersection of the two vectors. + var intersection = new HashSet(); + + // Iterate over each key-value pair in the left vector. + foreach (var kvp in leftVector) + { + // If the right vector contains the same key, add it to the intersection. + if (rightVector.ContainsKey(kvp.Key)) + { + intersection.Add(kvp.Key); + } + } + + return intersection; + } +} diff --git a/README.md b/README.md index f5d26fd8..c66e20eb 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,7 @@ find more than one implementation for the same objective but using different alg * [A181391 Van Eck's](./Algorithms/Sequences/VanEcksSequence.cs) * [String](./Algorithms/Strings) * [Similarity](./Algorithms/Strings/Similarity/) + * [Cosine Similarity](./Algorithms/Strings/Similarity/CosineSimilarity.cs) * [Hamming Distance](./Algorithms/Strings/Similarity/HammingDistance.cs) * [Jaro Similarity](./Algorithms/Strings/Similarity/JaroSimilarity.cs) * [Jaro-Winkler Distance](./Algorithms/Strings/Similarity/JaroWinklerDistance.cs) From 351b95b2dc71ff10e81b5704249863817e07b9d7 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Thu, 1 Aug 2024 22:55:28 +0300 Subject: [PATCH 103/138] Add Damerau-Levenshtein Distance (#460) --- .../DamerauLevenshteinDistanceTests.cs | 116 ++++++++++++++++++ .../Similarity/DamerauLevenshteinDistance.cs | 104 ++++++++++++++++ README.md | 1 + 3 files changed, 221 insertions(+) create mode 100644 Algorithms.Tests/Strings/Similarity/DamerauLevenshteinDistanceTests.cs create mode 100644 Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs diff --git a/Algorithms.Tests/Strings/Similarity/DamerauLevenshteinDistanceTests.cs b/Algorithms.Tests/Strings/Similarity/DamerauLevenshteinDistanceTests.cs new file mode 100644 index 00000000..5f522aff --- /dev/null +++ b/Algorithms.Tests/Strings/Similarity/DamerauLevenshteinDistanceTests.cs @@ -0,0 +1,116 @@ +using Algorithms.Strings.Similarity; +using NUnit.Framework; + +namespace Algorithms.Tests.Strings.Similarity; + +[TestFixture] +public class DamerauLevenshteinDistanceTests +{ + [Test] + public void Calculate_IdenticalStrings_ReturnsZero() + { + var str1 = "test"; + var str2 = "test"; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(0), "Identical strings should have a Damerau-Levenshtein distance of 0."); + } + + [Test] + public void Calculate_CompletelyDifferentStrings_ReturnsLengthOfLongestString() + { + var str1 = "abc"; + var str2 = "xyz"; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(3),"Completely different strings should have a Damerau-Levenshtein distance equal to the length of the longest string."); + } + + [Test] + public void Calculate_OneEmptyString_ReturnsLengthOfOtherString() + { + var str1 = "test"; + var str2 = ""; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(4),"One empty string should have a Damerau-Levenshtein distance equal to the length of the other string."); + } + + [Test] + public void Calculate_BothEmptyStrings_ReturnsZero() + { + var str1 = ""; + var str2 = ""; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(0), "Both empty strings should have a Damerau-Levenshtein distance of 0."); + } + + [Test] + public void Calculate_DifferentLengths_ReturnsCorrectValue() + { + var str1 = "short"; + var str2 = "longer"; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(6), "Strings of different lengths should return the correct Damerau-Levenshtein distance."); + } + + [Test] + public void Calculate_SpecialCharacters_ReturnsCorrectValue() + { + var str1 = "hello!"; + var str2 = "hello?"; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(1), "Strings with special characters should return the correct Damerau-Levenshtein distance."); + } + + [Test] + public void Calculate_DifferentCases_ReturnsCorrectValue() + { + var str1 = "Hello"; + var str2 = "hello"; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(1), "Strings with different cases should return the correct Damerau-Levenshtein distance."); + } + + [Test] + public void Calculate_CommonPrefixes_ReturnsCorrectValue() + { + var str1 = "prefix"; + var str2 = "pre"; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(3), "Strings with common prefixes should return the correct Damerau-Levenshtein distance."); + } + + [Test] + public void Calculate_CommonSuffixes_ReturnsCorrectValue() + { + var str1 = "suffix"; + var str2 = "fix"; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(3), "Strings with common suffixes should return the correct Damerau-Levenshtein distance."); + } + + [Test] + public void Calculate_Transpositions_ReturnsCorrectValue() + { + var str1 = "abcd"; + var str2 = "acbd"; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(1), "Strings with transpositions should return the correct Damerau-Levenshtein distance."); + } + + [Test] + public void Calculate_RepeatedCharacters_ReturnsCorrectValue() + { + var str1 = "aaa"; + var str2 = "aaaaa"; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(2), "Strings with repeated characters should return the correct Damerau-Levenshtein distance."); + } + + [Test] + public void Calculate_UnicodeCharacters_ReturnsCorrectValue() + { + var str1 = "こんにちは"; + var str2 = "こんばんは"; + var result = DamerauLevenshteinDistance.Calculate(str1, str2); + Assert.That(result, Is.EqualTo(2), "Strings with Unicode characters should return the correct Damerau-Levenshtein distance."); + } +} diff --git a/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs b/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs new file mode 100644 index 00000000..a00bdae6 --- /dev/null +++ b/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs @@ -0,0 +1,104 @@ +using System; + +namespace Algorithms.Strings.Similarity; + +public static class DamerauLevenshteinDistance +{ + /// + /// Calculates the Damerau-Levenshtein distance between two strings. + /// The Damerau-Levenshtein distance is a string metric for measuring the difference between two sequences. + /// It is calculated as the minimum number of operations needed to transform one sequence into the other. + /// The possible operations are insertion, deletion, substitution, and transposition. + /// + /// The first string. + /// The second string. + /// The Damerau-Levenshtein distance between the two strings. + public static int Calculate(string left, string right) + { + // Get the lengths of the input strings. + var leftSize = left.Length; + var rightSize = right.Length; + + // Initialize a matrix of distances between the two strings. + var distances = InitializeDistanceArray(leftSize, rightSize); + + // Iterate over each character in the left string. + for (var i = 1; i < leftSize + 1; i++) + { + // Iterate over each character in the right string. + for (var j = 1; j < rightSize + 1; j++) + { + // Calculate the cost of the current operation. + // If the characters at the current positions are the same, the cost is 0. + // Otherwise, the cost is 1. + var cost = left[i - 1] == right[j - 1] ? 0 : 1; + + // Calculate the minimum distance by considering three possible operations: + // deletion, insertion, and substitution. + distances[i, j] = Math.Min( + Math.Min( // deletion + distances[i - 1, j] + 1, // delete the character from the left string + distances[i, j - 1] + 1), // insert the character into the right string + distances[i - 1, j - 1] + cost); // substitute the character in the left string with the character in the right string + + // If the current character in the left string is the same as the character + // two positions to the left in the right string and the current character + // in the right string is the same as the character one position to the right + // in the left string, then we can also consider a transposition operation. + if (i > 1 && j > 1 && left[i - 1] == right[j - 2] && left[i - 2] == right[j - 1]) + { + distances[i, j] = Math.Min( + distances[i, j], // current minimum distance + distances[i - 2, j - 2] + cost); // transpose the last two characters + } + } + } + + // Return the distance between the two strings. + return distances[leftSize, rightSize]; + } + + /// + /// Initializes a matrix of distances between two string representations. + /// + /// This method creates a matrix of distances where the dimensions are one larger + /// than the input strings. The first row of the matrix represents the distances + /// when the left string is empty, and the first column represents the distances + /// when the right string is empty. The values in the first row and first column + /// are the lengths of the corresponding strings. + /// + /// The matrix is used by the Damerau-Levenshtein algorithm to calculate the + /// minimum number of single-character edits (insertions, deletions, or substitutions) + /// required to change one word into the other. + /// The matrix is initialized with dimensions one larger than the input strings. + /// The first row of the matrix represents the distances when the left string is empty. + /// The first column of the matrix represents the distances when the right string is empty. + /// The values in the first row and first column are the lengths of the corresponding strings. + /// Initializes a matrix of distances between two strings representations. + /// + /// The size of the left string. + /// The size of the right string. + /// A matrix of distances. + private static int[,] InitializeDistanceArray(int leftSize, int rightSize) + { + // Initialize a matrix of distances with dimensions one larger than the input strings. + var matrix = new int[leftSize + 1, rightSize + 1]; + + // Set the values in the first row to the lengths of the left string. + // This represents the distance when the left string is empty. + for (var i = 1; i < leftSize + 1; i++) + { + matrix[i, 0] = i; + } + + // Set the values in the first column to the lengths of the right string. + // This represents the distance when the right string is empty. + for (var i = 1; i < rightSize + 1; i++) + { + matrix[0, i] = i; + } + + // Return the initialized matrix of distances. + return matrix; + } +} diff --git a/README.md b/README.md index c66e20eb..8ed99dc9 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,7 @@ find more than one implementation for the same objective but using different alg * [String](./Algorithms/Strings) * [Similarity](./Algorithms/Strings/Similarity/) * [Cosine Similarity](./Algorithms/Strings/Similarity/CosineSimilarity.cs) + * [Damerau-Levenshtein Distance](./Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs) * [Hamming Distance](./Algorithms/Strings/Similarity/HammingDistance.cs) * [Jaro Similarity](./Algorithms/Strings/Similarity/JaroSimilarity.cs) * [Jaro-Winkler Distance](./Algorithms/Strings/Similarity/JaroWinklerDistance.cs) From 6fce1f5b28eaac5142d4d6d321e8eb1bacf41d37 Mon Sep 17 00:00:00 2001 From: Ricardo Ribeiro Rodrigues <72521349+RicardoRibeiroRodrigues@users.noreply.github.com> Date: Sun, 25 Aug 2024 16:43:36 -0300 Subject: [PATCH 104/138] Update DOTNET version in CONTRIBUTING.md (#467) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52ab3d89..14daae30 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ this repository. We welcome adding new algorithms and data structures that were mentioned in books or other reputable sources. We also welcome fixing bugs in code, clarifying documentation and adding new test cases to check existing code. -The framework targeted by our code is **dotnet 6**. The corresponding SDK can be found [here](https://dotnet.microsoft.com/download/dotnet/6.0). +The framework targeted by our code is **dotnet 8**. The corresponding SDK can be found [here](https://dotnet.microsoft.com/download/dotnet/8.0). Please note that we have a code of conduct, please follow it in all your interactions with the project. From cb45f4a41dcc88401a5f91a182192b76f073e20e Mon Sep 17 00:00:00 2001 From: Ricardo Ribeiro Rodrigues <72521349+RicardoRibeiroRodrigues@users.noreply.github.com> Date: Sun, 25 Aug 2024 17:02:37 -0300 Subject: [PATCH 105/138] Add absolute value algorithm (#462) --- Algorithms.Tests/Numeric/AbsTests.cs | 67 +++++++++++++++++++++++++ Algorithms/Numeric/Abs.cs | 73 ++++++++++++++++++++++++++++ README.md | 1 + 3 files changed, 141 insertions(+) create mode 100644 Algorithms.Tests/Numeric/AbsTests.cs create mode 100644 Algorithms/Numeric/Abs.cs diff --git a/Algorithms.Tests/Numeric/AbsTests.cs b/Algorithms.Tests/Numeric/AbsTests.cs new file mode 100644 index 00000000..8e45bf9b --- /dev/null +++ b/Algorithms.Tests/Numeric/AbsTests.cs @@ -0,0 +1,67 @@ +using System; +using System.Numerics; +using Algorithms.Numeric; +using NUnit.Framework; + +namespace Algorithms.Tests.Numeric; + +public static class AbsTests +{ + [TestCase(0, 0)] + [TestCase(34, 34)] + [TestCase(-100000000000.0d, 100000000000.0d)] + [TestCase(-3, 3)] + [TestCase(-3.1443123d, 3.1443123d)] + public static void GetsAbsVal(T inputNum, T expected) where T : INumber + { + // Act + var result = Abs.AbsVal(inputNum); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } + + [TestCase(new[] { -3, -1, 2, -11 }, -11)] + [TestCase(new[] { 0, 5, 1, 11 }, 11)] + [TestCase(new[] { 3.0, -10.0, -2.0 }, -10.0d)] + public static void GetAbsMax(T[] inputNums, T expected) where T : INumber + { + // Act + var result = Abs.AbsMax(inputNums); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public static void AbsMaxThrowsArgumentException() + { + // Arrange + var inputNums = Array.Empty(); + + // Assert + Assert.Throws(() => Abs.AbsMax(inputNums)); + } + + [TestCase(new[] { -3, -1, 2, -11 }, -1)] + [TestCase(new[] { -3, -5, 1, -11 }, 1)] + [TestCase(new[] { 0, 5, 1, 11 }, 0)] + public static void GetAbsMin(T[] inputNums, T expected) where T : INumber + { + // Act + var result = Abs.AbsMin(inputNums); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public static void AbsMinThrowsArgumentException() + { + // Arrange + var inputNums = Array.Empty(); + + // Assert + Assert.Throws(() => Abs.AbsMin(inputNums)); + } +} \ No newline at end of file diff --git a/Algorithms/Numeric/Abs.cs b/Algorithms/Numeric/Abs.cs new file mode 100644 index 00000000..763b6402 --- /dev/null +++ b/Algorithms/Numeric/Abs.cs @@ -0,0 +1,73 @@ +using System; +using System.Numerics; + +namespace Algorithms.Numeric; + +/// +/// Find the absolute value of a number. +/// +public static class Abs +{ + /// + /// Returns the absolute value of a number. + /// + /// Type of number. + /// Number to find the absolute value of. + /// Absolute value of the number. + public static T AbsVal(T inputNum) where T : INumber + { + return T.IsNegative(inputNum) ? -inputNum : inputNum; + } + + /// + /// Returns the number with the smallest absolute value on the input array. + /// + /// Type of number. + /// Array of numbers to find the smallest absolute. + /// Smallest absolute number. + public static T AbsMin(T[] inputNums) where T : INumber + { + if (inputNums.Length == 0) + { + throw new ArgumentException("Array is empty."); + } + + var min = inputNums[0]; + for (var index = 1; index < inputNums.Length; index++) + { + var current = inputNums[index]; + if (AbsVal(current).CompareTo(AbsVal(min)) < 0) + { + min = current; + } + } + + return min; + } + + /// + /// Returns the number with the largest absolute value on the input array. + /// + /// Type of number. + /// Array of numbers to find the largest absolute. + /// Largest absolute number. + public static T AbsMax(T[] inputNums) where T : INumber + { + if (inputNums.Length == 0) + { + throw new ArgumentException("Array is empty."); + } + + var max = inputNums[0]; + for (var index = 1; index < inputNums.Length; index++) + { + var current = inputNums[index]; + if (AbsVal(current).CompareTo(AbsVal(max)) > 0) + { + max = current; + } + } + + return max; + } +} diff --git a/README.md b/README.md index 8ed99dc9..6ad84ea3 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ find more than one implementation for the same objective but using different alg * [Extended Euclidean Algorithm](./Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs) * [Modular Multiplicative Inverse](./Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs) * [Numeric](./Algorithms/Numeric) + * [Absolute](./Algorithms/Numeric/Abs.cs) * [Aliquot Sum Calculator](./Algorithms/Numeric/AliquotSumCalculator.cs) * [Amicable Numbers Checker](./Algorithms/Numeric/AmicableNumbersChecker.cs) * [Decomposition](./Algorithms/Numeric/Decomposition) From 5c09c0e0959886130c6a67e5e658373848520420 Mon Sep 17 00:00:00 2001 From: Ricardo Ribeiro Rodrigues <72521349+RicardoRibeiroRodrigues@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:56:00 -0300 Subject: [PATCH 106/138] Add SoftMax Function (#469) --- Algorithms.Tests/Numeric/SoftMaxTests.cs | 48 ++++++++++++++++++++++++ Algorithms/Numeric/SoftMax.cs | 45 ++++++++++++++++++++++ README.md | 1 + 3 files changed, 94 insertions(+) create mode 100644 Algorithms.Tests/Numeric/SoftMaxTests.cs create mode 100644 Algorithms/Numeric/SoftMax.cs diff --git a/Algorithms.Tests/Numeric/SoftMaxTests.cs b/Algorithms.Tests/Numeric/SoftMaxTests.cs new file mode 100644 index 00000000..d44925e0 --- /dev/null +++ b/Algorithms.Tests/Numeric/SoftMaxTests.cs @@ -0,0 +1,48 @@ +using System; +using Algorithms.Numeric; +using NUnit.Framework; + +namespace Algorithms.Tests.Numeric; + +public static class SoftMaxTests +{ + [TestCase(new[] {5.0, 5.0}, new[] {0.5, 0.5})] + [TestCase(new[] {1.0, 2.0, 3.0}, new[] {0.09003057317038046, 0.24472847105479767, 0.6652409557748219})] + [TestCase(new[] {0.0}, new[] {1.0})] + public static void SoftMaxFunction(double[] input, double[] expected) + { + // Act + var result = SoftMax.Compute(input); + + // Assert + Assert.That(result, Is.EqualTo(expected).Within(1e-9)); + } + + [Test] + public static void SoftMaxFunctionThrowsArgumentException() + { + // Arrange + var input = Array.Empty(); + + // Assert + Assert.Throws(() => SoftMax.Compute(input)); + } + + [TestCase(new[] {1.0, 2.0, 3.0, 4.0, 5.0})] + [TestCase(new[] {0.0, 0.0, 0.0, 0.0, 0.0})] + [TestCase(new[] {5.0})] + public static void SoftMaxFunctionSumsToOne(double[] input) + { + // Act + var result = SoftMax.Compute(input); + + var sum = 0.0; + foreach (var value in result) + { + sum += value; + } + + // Assert + Assert.That(sum, Is.EqualTo(1.0).Within(1e-9)); + } +} \ No newline at end of file diff --git a/Algorithms/Numeric/SoftMax.cs b/Algorithms/Numeric/SoftMax.cs new file mode 100644 index 00000000..c20a54b5 --- /dev/null +++ b/Algorithms/Numeric/SoftMax.cs @@ -0,0 +1,45 @@ +using System; + +namespace Algorithms.Numeric; + +/// +/// Implementation of the SoftMax function. +/// Its a function that takes as input a vector of K real numbers, and normalizes +/// it into a probability distribution consisting of K probabilities proportional +/// to the exponentials of the input numbers. After softmax, the elements of the vector always sum up to 1. +/// https://en.wikipedia.org/wiki/Softmax_function. +/// +public static class SoftMax +{ + /// + /// Compute the SoftMax function. + /// The SoftMax function is defined as: + /// softmax(x_i) = exp(x_i) / sum(exp(x_j)) for j = 1 to n + /// where x_i is the i-th element of the input vector. + /// The elements of the output vector are the probabilities of the input vector, the output sums up to 1. + /// + /// The input vector of real numbers. + /// The output vector of real numbers. + public static double[] Compute(double[] input) + { + if (input.Length == 0) + { + throw new ArgumentException("Array is empty."); + } + + var exponentVector = new double[input.Length]; + var sum = 0.0; + for (var index = 0; index < input.Length; index++) + { + exponentVector[index] = Math.Exp(input[index]); + sum += exponentVector[index]; + } + + for (var index = 0; index < input.Length; index++) + { + exponentVector[index] /= sum; + } + + return exponentVector; + } +} diff --git a/README.md b/README.md index 6ad84ea3..fd4f1942 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,7 @@ find more than one implementation for the same objective but using different alg * [Automorphic Number](./Algorithms/Numeric/AutomorphicNumber.cs) * [Josephus Problem](./Algorithms/Numeric/JosephusProblem.cs) * [Newton's Square Root Calculation](./Algorithms/NewtonSquareRoot.cs) + * [SoftMax Function](./Algorithms/Numeric/SoftMax.cs) * [Searches](./Algorithms/Search) * [A-Star](./Algorithms/Search/AStar/) * [Binary Search](./Algorithms/Search/BinarySearcher.cs) From 6b37d04938493ee9071a6e1446271105ed053fd6 Mon Sep 17 00:00:00 2001 From: Ricardo Ribeiro Rodrigues <72521349+RicardoRibeiroRodrigues@users.noreply.github.com> Date: Tue, 3 Sep 2024 08:45:06 -0300 Subject: [PATCH 107/138] Add Wildcard Pattern Matching (#470) --- .../PatternMatching/WildCardMatcherTests.cs | 36 +++++++ .../PatternMatching/WildCardMatcher.cs | 97 +++++++++++++++++++ README.md | 1 + 3 files changed, 134 insertions(+) create mode 100644 Algorithms.Tests/Strings/PatternMatching/WildCardMatcherTests.cs create mode 100644 Algorithms/Strings/PatternMatching/WildCardMatcher.cs diff --git a/Algorithms.Tests/Strings/PatternMatching/WildCardMatcherTests.cs b/Algorithms.Tests/Strings/PatternMatching/WildCardMatcherTests.cs new file mode 100644 index 00000000..5361557a --- /dev/null +++ b/Algorithms.Tests/Strings/PatternMatching/WildCardMatcherTests.cs @@ -0,0 +1,36 @@ +using Algorithms.Strings.PatternMatching; +using NUnit.Framework; + +namespace Algorithms.Tests.Strings.PatternMatching; + +public static class WildCardMatcherTests +{ + [TestCase("aab", "c*a*b", true)] + [TestCase("aaa", "aa", false)] + [TestCase("aaa", "a.a", true)] + [TestCase("aaab", "aa*", false)] + [TestCase("aaab", ".*", true)] + [TestCase("a", "bbbb", false)] + [TestCase("", "bbbb", false)] + [TestCase("a", "", false)] + [TestCase("", "", true)] + public static void MatchPattern(string inputString, string pattern, bool expected) + { + // Act + var result = WildCardMatcher.MatchPattern(inputString, pattern); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public static void MatchPatternThrowsArgumentException() + { + // Arrange + var inputString = "abc"; + var pattern = "*abc"; + + // Assert + Assert.Throws(() => WildCardMatcher.MatchPattern(inputString, pattern)); + } +} diff --git a/Algorithms/Strings/PatternMatching/WildCardMatcher.cs b/Algorithms/Strings/PatternMatching/WildCardMatcher.cs new file mode 100644 index 00000000..cf15ce21 --- /dev/null +++ b/Algorithms/Strings/PatternMatching/WildCardMatcher.cs @@ -0,0 +1,97 @@ +using System; + +namespace Algorithms.Strings.PatternMatching; + +/// +/// Implentation of regular expression matching with support for '.' and '*'. +/// '.' Matches any single character. +/// '*' Matches zero or more of the preceding element. +/// The matching should cover the entire input string (not partial). +/// +public static class WildCardMatcher +{ + /// + /// Using bottom-up dynamic programming for matching the input string with the pattern. + /// + /// Time complexity: O(n*m), where n is the length of the input string and m is the length of the pattern. + /// + /// Constrain: The pattern cannot start with '*'. + /// + /// The input string to match. + /// The pattern to match. + /// True if the input string matches the pattern, false otherwise. + /// Thrown when the pattern starts with '*'. + public static bool MatchPattern(string inputString, string pattern) + { + if (pattern.Length > 0 && pattern[0] == '*') + { + throw new ArgumentException("Pattern cannot start with *"); + } + + var inputLength = inputString.Length + 1; + var patternLength = pattern.Length + 1; + + // DP 2d matrix, where dp[i, j] is true if the first i characters in the input string match the first j characters in the pattern + // This DP is initialized to all falses, as it is the default value for a boolean. + var dp = new bool[inputLength, patternLength]; + + // Empty string and empty pattern are a match + dp[0, 0] = true; + + // Since the empty string can only match a pattern that has a * in it, we need to initialize the first row of the DP matrix + for (var j = 1; j < patternLength; j++) + { + if (pattern[j - 1] == '*') + { + dp[0, j] = dp[0, j - 2]; + } + } + + // Now using bottom-up approach to find for all remaining lenghts of input and pattern + for (var i = 1; i < inputLength; i++) + { + for (var j = 1; j < patternLength; j++) + { + MatchRemainingLenghts(inputString, pattern, dp, i, j); + } + } + + return dp[inputLength - 1, patternLength - 1]; + } + + // Helper method to match the remaining lengths of the input string and the pattern + // This method is called for all i and j where i > 0 and j > 0 + private static void MatchRemainingLenghts(string inputString, string pattern, bool[,] dp, int i, int j) + { + // If the characters match or the pattern has a ., then the result is the same as the previous positions. + if (inputString[i - 1] == pattern[j - 1] || pattern[j - 1] == '.') + { + dp[i, j] = dp[i - 1, j - 1]; + } + else if (pattern[j - 1] == '*') + { + MatchForZeroOrMore(inputString, pattern, dp, i, j); + } + else + { + // If the characters do not match, then the result is false, which is the default value. + } + } + + // Helper method to match for the "*" pattern. + private static void MatchForZeroOrMore(string inputString, string pattern, bool[,] dp, int i, int j) + { + if (dp[i, j - 2]) + { + dp[i, j] = true; + } + else if (inputString[i - 1] == pattern[j - 2] || pattern[j - 2] == '.') + { + dp[i, j] = dp[i - 1, j]; + } + else + { + // Leave the default value of false + } + } +} diff --git a/README.md b/README.md index fd4f1942..ef5a1cfd 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,7 @@ find more than one implementation for the same objective but using different alg * [Rabin Karp](./Algorithms/Strings/PatternMatching/RabinKarp.cs) * [Boyer Moore](./Algorithms/Strings/PatternMatching/BoyerMoore.cs) * [Knuth–Morris–Pratt Search](./Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs) + * [WildCard Pattern Matching](./Algorithms/Strings/PatternMatching/WildCardMatcher.cs) * [Z-block substring search](./Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs) * [Longest Consecutive Character](./Algorithms/Strings/GeneralStringAlgorithms.cs) * [Palindrome Checker](./Algorithms/Strings/Palindrome.cs) From 5eb02545c5113366af5a2951c2974489e61045ca Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Sat, 21 Sep 2024 11:49:42 +0300 Subject: [PATCH 108/138] Add Optimal String Alignment (OSA) Distance Algorithm (#464) --- .../Similarity/OptimalStringAlignmentTests.cs | 74 +++++++++ .../Similarity/OptimalStringAlignment.cs | 157 ++++++++++++++++++ README.md | 1 + 3 files changed, 232 insertions(+) create mode 100644 Algorithms.Tests/Strings/Similarity/OptimalStringAlignmentTests.cs create mode 100644 Algorithms/Strings/Similarity/OptimalStringAlignment.cs diff --git a/Algorithms.Tests/Strings/Similarity/OptimalStringAlignmentTests.cs b/Algorithms.Tests/Strings/Similarity/OptimalStringAlignmentTests.cs new file mode 100644 index 00000000..48199013 --- /dev/null +++ b/Algorithms.Tests/Strings/Similarity/OptimalStringAlignmentTests.cs @@ -0,0 +1,74 @@ +using Algorithms.Strings.Similarity; +using FluentAssertions; +using NUnit.Framework; +using System; + +namespace Algorithms.Tests.Strings.Similarity +{ + [TestFixture] + public class OptimalStringAlignmentTests + { + [Test] + public void Calculate_IdenticalStrings_ReturnsZero() + { + var result = OptimalStringAlignment.Calculate("example", "example"); + result.Should().Be(0.0); + } + + [Test] + public void Calculate_FirstStringEmpty_ReturnsLengthOfSecondString() + { + var result = OptimalStringAlignment.Calculate("", "example"); + result.Should().Be("example".Length); + } + + [Test] + public void Calculate_SecondStringEmpty_ReturnsLengthOfFirstString() + { + var result = OptimalStringAlignment.Calculate("example", ""); + result.Should().Be("example".Length); + } + + [Test] + public void Calculate_BothStringsEmpty_ReturnsZero() + { + var result = OptimalStringAlignment.Calculate("", ""); + result.Should().Be(0.0); + } + + [Test] + public void Calculate_OneInsertion_ReturnsOne() + { + var result = OptimalStringAlignment.Calculate("example", "examples"); + result.Should().Be(1.0); + } + + [Test] + public void Calculate_OneDeletion_ReturnsOne() + { + var result = OptimalStringAlignment.Calculate("examples", "example"); + result.Should().Be(1.0); + } + + [Test] + public void Calculate_OneSubstitution_ReturnsOne() + { + var result = OptimalStringAlignment.Calculate("example", "exbmple"); + result.Should().Be(1.0); + } + + [Test] + public void Calculate_OneTransposition_ReturnsOne() + { + var result = OptimalStringAlignment.Calculate("example", "exmaple"); + result.Should().Be(1.0); + } + + [Test] + public void Calculate_MultipleOperations_ReturnsCorrectDistance() + { + var result = OptimalStringAlignment.Calculate("kitten", "sitting"); + result.Should().Be(3.0); + } + } +} diff --git a/Algorithms/Strings/Similarity/OptimalStringAlignment.cs b/Algorithms/Strings/Similarity/OptimalStringAlignment.cs new file mode 100644 index 00000000..743c4ce1 --- /dev/null +++ b/Algorithms/Strings/Similarity/OptimalStringAlignment.cs @@ -0,0 +1,157 @@ +using System; + +namespace Algorithms.Strings.Similarity +{ + /// + /// Provides methods to calculate the Optimal String Alignment distance between two strings. + /// + /// The Optimal String Alignment distance, also known as the restricted Damerau-Levenshtein distance, + /// is a string metric used to measure the difference between two sequences. It is similar to the + /// Levenshtein distance, but it also considers transpositions (swapping of two adjacent characters) + /// as a single operation. This metric is particularly useful when adjacent characters are commonly + /// transposed, such as in typographical errors. + /// + /// The OSA distance between two strings is defined as the minimum number of operations required to + /// transform one string into the other, where the operations include: + /// + /// 1. Insertion: Adding a single character. + /// 2. Deletion: Removing a single character. + /// 3. Substitution: Replacing one character with another. + /// 4. Transposition: Swapping two adjacent characters (this is what distinguishes OSA from the + /// traditional Levenshtein distance). + /// + /// The OSA distance algorithm ensures that no operation is applied more than once to the same + /// character in the same position. This is the main difference between the OSA and the more general + /// Damerau-Levenshtein distance, which does not have this restriction. + /// + /// + /// Example Usage: + /// + /// int distance = OptimalStringAlignmentDistance("example", "exmaple"); + /// Console.WriteLine(distance); // Output: 1 + /// + /// In this example, the strings "example" and "exmaple" differ by one transposition of adjacent characters ('a' and 'm'), + /// so the OSA distance is 1. + /// + /// + /// int distance = OptimalStringAlignmentDistance("kitten", "sitting"); + /// Console.WriteLine(distance); // Output: 3 + /// + /// Here, the strings "kitten" and "sitting" have three differences (substitutions 'k' to 's', 'e' to 'i', and insertion of 'g'), + /// resulting in an OSA distance of 3. + /// + /// + /// + /// This algorithm has a time complexity of O(n * m), where n and m are the lengths of the two input strings. + /// It is efficient for moderate-sized strings but may become computationally expensive for very long strings. + /// + public static class OptimalStringAlignment + { + /// + /// Calculates the Optimal String Alignment distance between two strings. + /// + /// The first string. + /// The second string. + /// The Optimal String Alignment distance between the two strings. + /// Thrown when either of the input strings is null. + public static double Calculate(string firstString, string secondString) + { + ArgumentNullException.ThrowIfNull(nameof(firstString)); + ArgumentNullException.ThrowIfNull(nameof(secondString)); + + if (firstString == secondString) + { + return 0.0; + } + + if (firstString.Length == 0) + { + return secondString.Length; + } + + if (secondString.Length == 0) + { + return firstString.Length; + } + + var distanceMatrix = GenerateDistanceMatrix(firstString.Length, secondString.Length); + distanceMatrix = CalculateDistance(firstString, secondString, distanceMatrix); + + return distanceMatrix[firstString.Length, secondString.Length]; + } + + /// + /// Generates the initial distance matrix for the given lengths of the two strings. + /// + /// The length of the first string. + /// The length of the second string. + /// The initialized distance matrix. + private static int[,] GenerateDistanceMatrix(int firstLength, int secondLength) + { + var distanceMatrix = new int[firstLength + 2, secondLength + 2]; + + for (var i = 0; i <= firstLength; i++) + { + distanceMatrix[i, 0] = i; + } + + for (var j = 0; j <= secondLength; j++) + { + distanceMatrix[0, j] = j; + } + + return distanceMatrix; + } + + /// + /// Calculates the distance matrix for the given strings using the Optimal String Alignment algorithm. + /// + /// The first string. + /// The second string. + /// The initial distance matrix. + /// The calculated distance matrix. + private static int[,] CalculateDistance(string firstString, string secondString, int[,] distanceMatrix) + { + for (var i = 1; i <= firstString.Length; i++) + { + for (var j = 1; j <= secondString.Length; j++) + { + var cost = 1; + + if (firstString[i - 1] == secondString[j - 1]) + { + cost = 0; + } + + distanceMatrix[i, j] = Minimum( + distanceMatrix[i - 1, j - 1] + cost, // substitution + distanceMatrix[i, j - 1] + 1, // insertion + distanceMatrix[i - 1, j] + 1); // deletion + + if (i > 1 && j > 1 + && firstString[i - 1] == secondString[j - 2] + && firstString[i - 2] == secondString[j - 1]) + { + distanceMatrix[i, j] = Math.Min( + distanceMatrix[i, j], + distanceMatrix[i - 2, j - 2] + cost); // transposition + } + } + } + + return distanceMatrix; + } + + /// + /// Returns the minimum of three integers. + /// + /// The first integer. + /// The second integer. + /// The third integer. + /// The minimum of the three integers. + private static int Minimum(int a, int b, int c) + { + return Math.Min(a, Math.Min(b, c)); + } + } +} diff --git a/README.md b/README.md index ef5a1cfd..23ae8a18 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,7 @@ find more than one implementation for the same objective but using different alg * [Hamming Distance](./Algorithms/Strings/Similarity/HammingDistance.cs) * [Jaro Similarity](./Algorithms/Strings/Similarity/JaroSimilarity.cs) * [Jaro-Winkler Distance](./Algorithms/Strings/Similarity/JaroWinklerDistance.cs) + * [Optimal String Alignment](./Algorithms/Strings/Similarity/OptimalStringAlignment.cs) * [Pattern Matching](./Algorithms/Strings/PatternMatching/) * [Bitop Pattern Matching](./Algorithms/Strings/PatternMatching/Bitap.cs) * [Naive String Search](./Algorithms/Strings/PatternMatching/NaiveStringSearch.cs) From ab2b5ccff52908ea6f985d9a523ae125aeba45c5 Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Sun, 22 Sep 2024 15:40:30 +0300 Subject: [PATCH 109/138] Increase unit test coverage of HashTable and TimSort (#466) --- .../Sorters/Comparison/TimSorterTests.cs | 7 +- .../Sorters/Utils/GallopingStrategyTests.cs | 120 +++++++++++++++ Algorithms/Sorters/Comparison/TimSorter.cs | 143 ++++-------------- Algorithms/Sorters/Utils/GallopingStrategy.cs | 106 +++++++++++++ .../Hashing/HashTableTests.cs | 33 ++++ 5 files changed, 291 insertions(+), 118 deletions(-) create mode 100644 Algorithms.Tests/Sorters/Utils/GallopingStrategyTests.cs create mode 100644 Algorithms/Sorters/Utils/GallopingStrategy.cs diff --git a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs index c02a13b1..822ac789 100755 --- a/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs +++ b/Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs @@ -9,13 +9,14 @@ namespace Algorithms.Tests.Sorters.Comparison; public static class TimSorterTests { private static readonly IntComparer IntComparer = new(); + private static readonly TimSorterSettings Settings = new(); [Test] public static void ArraySorted( [Random(0, 10_000, 2000)] int n) { // Arrange - var sorter = new TimSorter(); + var sorter = new TimSorter(Settings, IntComparer); var (correctArray, testArray) = RandomHelper.GetArrays(n); // Act @@ -30,7 +31,7 @@ public static void ArraySorted( public static void TinyArray() { // Arrange - var sorter = new TimSorter(); + var sorter = new TimSorter(Settings, IntComparer); var tinyArray = new[] { 1 }; var correctArray = new[] { 1 }; @@ -45,7 +46,7 @@ public static void TinyArray() public static void SmallChunks() { // Arrange - var sorter = new TimSorter(); + var sorter = new TimSorter(Settings, IntComparer); var (correctArray, testArray) = RandomHelper.GetArrays(800); Array.Sort(correctArray, IntComparer); Array.Sort(testArray, IntComparer); diff --git a/Algorithms.Tests/Sorters/Utils/GallopingStrategyTests.cs b/Algorithms.Tests/Sorters/Utils/GallopingStrategyTests.cs new file mode 100644 index 00000000..2c7e6050 --- /dev/null +++ b/Algorithms.Tests/Sorters/Utils/GallopingStrategyTests.cs @@ -0,0 +1,120 @@ +using Algorithms.Sorters.Utils; +using NUnit.Framework; +using System.Collections.Generic; + +namespace Algorithms.Tests.Sorters.Utils +{ + [TestFixture] + public class GallopingStrategyTests + { + private readonly IComparer comparer = Comparer.Default; + +[Test] + public void GallopLeft_KeyPresent_ReturnsCorrectIndex() + { + var array = new[] { 1, 2, 3, 4, 5 }; + var index = GallopingStrategy.GallopLeft(array, 3, 0, array.Length, comparer); + Assert.That(index, Is.EqualTo(2)); + } + + [Test] + public void GallopLeft_KeyNotPresent_ReturnsCorrectIndex() + { + var array = new[] { 1, 2, 4, 5 }; + var index = GallopingStrategy.GallopLeft(array, 3, 0, array.Length, comparer); + Assert.That(index, Is.EqualTo(2)); + } + + [Test] + public void GallopLeft_KeyLessThanAll_ReturnsZero() + { + var array = new[] { 2, 3, 4, 5 }; + var index = GallopingStrategy.GallopLeft(array, 1, 0, array.Length, comparer); + Assert.That(index, Is.EqualTo(0)); + } + + [Test] + public void GallopLeft_KeyGreaterThanAll_ReturnsLength() + { + var array = new[] { 1, 2, 3, 4 }; + var index = GallopingStrategy.GallopLeft(array, 5, 0, array.Length, comparer); + Assert.That(index, Is.EqualTo(array.Length)); + } + + [Test] + public void GallopRight_KeyPresent_ReturnsCorrectIndex() + { + var array = new[] { 1, 2, 3, 4, 5 }; + var index = GallopingStrategy.GallopRight(array, 3, 0, array.Length, comparer); + Assert.That(index, Is.EqualTo(3)); + } + + [Test] + public void GallopRight_KeyNotPresent_ReturnsCorrectIndex() + { + var array = new[] { 1, 2, 4, 5 }; + var index = GallopingStrategy.GallopRight(array, 3, 0, array.Length, comparer); + Assert.That(index, Is.EqualTo(2)); + } + + [Test] + public void GallopRight_KeyLessThanAll_ReturnsZero() + { + var array = new[] { 2, 3, 4, 5 }; + var index = GallopingStrategy.GallopRight(array, 1, 0, array.Length, comparer); + Assert.That(index, Is.EqualTo(0)); + } + + [Test] + public void GallopRight_KeyGreaterThanAll_ReturnsLength() + { + var array = new[] { 1, 2, 3, 4 }; + var index = GallopingStrategy.GallopRight(array, 5, 0, array.Length, comparer); + Assert.That(index, Is.EqualTo(array.Length)); + } + + [Test] + public void GallopLeft_EmptyArray_ReturnsZero() + { + var array = new int[] { }; + var index = GallopingStrategy.GallopLeft(array, 1, 0, array.Length, comparer); + Assert.That(index, Is.EqualTo(0)); + } + + [Test] + public void GallopRight_EmptyArray_ReturnsZero() + { + var array = new int[] { }; + var index = GallopingStrategy.GallopRight(array, 1, 0, array.Length, comparer); + Assert.That(index, Is.EqualTo(0)); + } + + // Test when (shiftable << 1) < 0 is true + [Test] + public void TestBoundLeftShift_WhenShiftableCausesNegativeShift_ReturnsShiftedValuePlusOne() + { + // Arrange + int shiftable = int.MaxValue; // This should cause a negative result after left shift + + // Act + int result = GallopingStrategy.BoundLeftShift(shiftable); + + // Assert + Assert.That((shiftable << 1) + 1, Is.EqualTo(result)); // True branch + } + + // Test when (shiftable << 1) < 0 is false + [Test] + public void TestBoundLeftShift_WhenShiftableDoesNotCauseNegativeShift_ReturnsMaxValue() + { + // Arrange + int shiftable = 1; // This will not cause a negative result after left shift + + // Act + int result = GallopingStrategy.BoundLeftShift(shiftable); + + // Assert + Assert.That(int.MaxValue, Is.EqualTo(result)); // False branch + } + } +} diff --git a/Algorithms/Sorters/Comparison/TimSorter.cs b/Algorithms/Sorters/Comparison/TimSorter.cs index df2220ac..0115e560 100755 --- a/Algorithms/Sorters/Comparison/TimSorter.cs +++ b/Algorithms/Sorters/Comparison/TimSorter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Algorithms.Sorters.Utils; namespace Algorithms.Sorters.Comparison; @@ -27,6 +28,10 @@ public class TimSorter : IComparisonSorter { private readonly int minMerge; private readonly int initMinGallop; + + // Pool of reusable TimChunk objects for memory efficiency. + private readonly TimChunk[] chunkPool = new TimChunk[2]; + private readonly int[] runBase; private readonly int[] runLengths; @@ -50,15 +55,18 @@ private class TimChunk public int Wins { get; set; } } - public TimSorter(int minMerge = 32, int minGallop = 7) + public TimSorter(TimSorterSettings settings, IComparer comparer) { initMinGallop = minGallop; - this.minMerge = minMerge; runBase = new int[85]; runLengths = new int[85]; stackSize = 0; - this.minGallop = minGallop; + + minGallop = settings.MinGallop; + minMerge = settings.MinMerge; + + this.comparer = comparer ?? Comparer.Default; } /// @@ -158,15 +166,6 @@ private static void ReverseRange(T[] array, int start, int end) } } - /// - /// Left shift a value, preventing a roll over to negative numbers. - /// - /// int value to left shift. - /// Left shifted value, bound to 2,147,483,647. - private static int BoundLeftShift(int shiftable) => (shiftable << 1) < 0 - ? (shiftable << 1) + 1 - : int.MaxValue; - /// /// Check the chunks before getting in to a merge to make sure there's something to actually do. /// @@ -265,105 +264,6 @@ private int CountRunAndMakeAscending(T[] array, int start) return runHi - start; } - /// - /// Find the position in the array that a key should fit to the left of where it currently sits. - /// - /// Array to search. - /// Key to place in the array. - /// Base index for the key. - /// Length of the chunk to run through. - /// Initial starting position to start from. - /// Offset for the key's location. - private int GallopLeft(T[] array, T key, int i, int len, int hint) - { - var (offset, lastOfs) = comparer.Compare(key, array[i + hint]) > 0 - ? RightRun(array, key, i, len, hint, 0) - : LeftRun(array, key, i, hint, 1); - - return FinalOffset(array, key, i, offset, lastOfs, 1); - } - - /// - /// Find the position in the array that a key should fit to the right of where it currently sits. - /// - /// Array to search. - /// Key to place in the array. - /// Base index for the key. - /// Length of the chunk to run through. - /// Initial starting position to start from. - /// Offset for the key's location. - private int GallopRight(T[] array, T key, int i, int len, int hint) - { - var (offset, lastOfs) = comparer.Compare(key, array[i + hint]) < 0 - ? LeftRun(array, key, i, hint, 0) - : RightRun(array, key, i, len, hint, -1); - - return FinalOffset(array, key, i, offset, lastOfs, 0); - } - - private (int offset, int lastOfs) LeftRun(T[] array, T key, int i, int hint, int lt) - { - var maxOfs = hint + 1; - var (offset, tmp) = (1, 0); - - while (offset < maxOfs && comparer.Compare(key, array[i + hint - offset]) < lt) - { - tmp = offset; - offset = BoundLeftShift(offset); - } - - if (offset > maxOfs) - { - offset = maxOfs; - } - - var lastOfs = hint - offset; - offset = hint - tmp; - - return (offset, lastOfs); - } - - private (int offset, int lastOfs) RightRun(T[] array, T key, int i, int len, int hint, int gt) - { - var (offset, lastOfs) = (1, 0); - var maxOfs = len - hint; - while (offset < maxOfs && comparer.Compare(key, array[i + hint + offset]) > gt) - { - lastOfs = offset; - offset = BoundLeftShift(offset); - } - - if (offset > maxOfs) - { - offset = maxOfs; - } - - offset += hint; - lastOfs += hint; - - return (offset, lastOfs); - } - - private int FinalOffset(T[] array, T key, int i, int offset, int lastOfs, int lt) - { - lastOfs++; - while (lastOfs < offset) - { - var m = lastOfs + (int)((uint)(offset - lastOfs) >> 1); - - if (comparer.Compare(key, array[i + m]) < lt) - { - offset = m; - } - else - { - lastOfs = m + 1; - } - } - - return offset; - } - /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. It requires O(n log n) compares, but O(n^2) data movement. @@ -465,7 +365,7 @@ private void MergeAt(T[] array, int index) stackSize--; - var k = GallopRight(array, array[baseB], baseA, lenA, 0); + var k = GallopingStrategy.GallopRight(array, array[baseB], baseA, lenA, comparer); baseA += k; lenA -= k; @@ -475,7 +375,7 @@ private void MergeAt(T[] array, int index) return; } - lenB = GallopLeft(array, array[baseA + lenA - 1], baseB, lenB, lenB - 1); + lenB = GallopingStrategy.GallopLeft(array, array[baseA + lenA - 1], baseB, lenB, comparer); if (lenB <= 0) { @@ -590,7 +490,7 @@ private bool StableMerge(TimChunk left, TimChunk right, ref int dest, int private bool GallopMerge(TimChunk left, TimChunk right, ref int dest) { - left.Wins = GallopRight(left.Array, right.Array[right.Index], left.Index, left.Remaining, 0); + left.Wins = GallopingStrategy.GallopRight(left.Array, right.Array[right.Index], left.Index, left.Remaining, comparer); if (left.Wins != 0) { Array.Copy(left.Array, left.Index, right.Array, dest, left.Wins); @@ -609,7 +509,7 @@ private bool GallopMerge(TimChunk left, TimChunk right, ref int dest) return true; } - right.Wins = GallopLeft(right.Array, left.Array[left.Index], right.Index, right.Remaining, 0); + right.Wins = GallopingStrategy.GallopLeft(right.Array, left.Array[left.Index], right.Index, right.Remaining, comparer); if (right.Wins != 0) { Array.Copy(right.Array, right.Index, right.Array, dest, right.Wins); @@ -631,3 +531,16 @@ private bool GallopMerge(TimChunk left, TimChunk right, ref int dest) return false; } } + +public class TimSorterSettings +{ + public int MinMerge { get; } + + public int MinGallop { get; } + + public TimSorterSettings(int minMerge = 32, int minGallop = 7) + { + MinMerge = minMerge; + MinGallop = minGallop; + } +} diff --git a/Algorithms/Sorters/Utils/GallopingStrategy.cs b/Algorithms/Sorters/Utils/GallopingStrategy.cs new file mode 100644 index 00000000..2226064b --- /dev/null +++ b/Algorithms/Sorters/Utils/GallopingStrategy.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Sorters.Utils +{ + public static class GallopingStrategy + { + public static int GallopLeft(T[] array, T key, int baseIndex, int length, IComparer comparer) + { + if (array.Length == 0) + { + return 0; + } + + var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) > 0 + ? RightRun(array, key, baseIndex, length, 0, comparer) + : LeftRun(array, key, baseIndex, 0, comparer); + + return FinalOffset(array, key, baseIndex, offset, lastOfs, 1, comparer); + } + + public static int GallopRight(T[] array, T key, int baseIndex, int length, IComparer comparer) + { + if (array.Length == 0) + { + return 0; + } + + var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) < 0 + ? LeftRun(array, key, baseIndex, length, comparer) + : RightRun(array, key, baseIndex, length, 0, comparer); + + return FinalOffset(array, key, baseIndex, offset, lastOfs, 0, comparer); + } + + public static int BoundLeftShift(int shiftable) => (shiftable << 1) < 0 + ? (shiftable << 1) + 1 + : int.MaxValue; + + private static (int offset, int lastOfs) LeftRun(T[] array, T key, int baseIndex, int hint, IComparer comparer) + { + var maxOfs = hint + 1; + var (offset, tmp) = (1, 0); + + while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint - offset]) < 0) + { + tmp = offset; + offset = BoundLeftShift(offset); + } + + if (offset > maxOfs) + { + offset = maxOfs; + } + + var lastOfs = hint - offset; + offset = hint - tmp; + + return (offset, lastOfs); + } + + private static (int offset, int lastOfs) RightRun(T[] array, T key, int baseIndex, int len, int hint, IComparer comparer) + { + var (offset, lastOfs) = (1, 0); + var maxOfs = len - hint; + while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint + offset]) > 0) + { + lastOfs = offset; + offset = BoundLeftShift(offset); + } + + if (offset > maxOfs) + { + offset = maxOfs; + } + + offset += hint; + lastOfs += hint; + + return (offset, lastOfs); + } + + private static int FinalOffset(T[] array, T key, int baseIndex, int offset, int lastOfs, int lt, IComparer comparer) + { + lastOfs++; + while (lastOfs < offset) + { + var m = lastOfs + (int)((uint)(offset - lastOfs) >> 1); + + if (comparer.Compare(key, array[baseIndex + m]) < lt) + { + offset = m; + } + else + { + lastOfs = m + 1; + } + } + + return offset; + } + } +} diff --git a/DataStructures.Tests/Hashing/HashTableTests.cs b/DataStructures.Tests/Hashing/HashTableTests.cs index bf0658ea..10ee6d7d 100644 --- a/DataStructures.Tests/Hashing/HashTableTests.cs +++ b/DataStructures.Tests/Hashing/HashTableTests.cs @@ -381,4 +381,37 @@ public void This_Get_KeyNotFoundException_WhenKeyDoesNotExist() Console.WriteLine(value); }); } + + [Test] + public void Test_NegativeHashKey_ReturnsCorrectValue() + { + var hashTable = new HashTable(4); + hashTable.Add(new NegativeHashKey(1), 1); + Assert.That(hashTable[new NegativeHashKey(1)], Is.EqualTo(1)); + } +} + +public class NegativeHashKey +{ + private readonly int id; + + public NegativeHashKey(int id) + { + this.id = id; + } + + public override int GetHashCode() + { + // Return a negative hash code + return -id; + } + + public override bool Equals(object? obj) + { + if (obj is NegativeHashKey other) + { + return id == other.id; + } + return false; + } } From cf193527738d2d5c6d30dffad0211f8c81740c0b Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Tue, 24 Sep 2024 14:53:39 +0300 Subject: [PATCH 110/138] Add Basic TimSorter (#471) --- .../Comparison/BasicTeamSorterTests.cs | 87 +++++++++++++ .../Sorters/Comparison/BasicTimSorter.cs | 120 ++++++++++++++++++ README.md | 1 + 3 files changed, 208 insertions(+) create mode 100644 Algorithms.Tests/Sorters/Comparison/BasicTeamSorterTests.cs create mode 100644 Algorithms/Sorters/Comparison/BasicTimSorter.cs diff --git a/Algorithms.Tests/Sorters/Comparison/BasicTeamSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/BasicTeamSorterTests.cs new file mode 100644 index 00000000..f699202d --- /dev/null +++ b/Algorithms.Tests/Sorters/Comparison/BasicTeamSorterTests.cs @@ -0,0 +1,87 @@ +using Algorithms.Sorters.Comparison; +using FluentAssertions; +using NUnit.Framework; +using System; +using System.Collections.Generic; + +namespace Algorithms.Tests.Sorters.Comparison +{ + [TestFixture] + public class BasicTimSorterTests + { + private readonly BasicTimSorter sorter = new(Comparer.Default); + + [Test] + public void Sort_EmptyArray_DoesNotThrow() + { + var array = Array.Empty(); + Assert.DoesNotThrow(() => sorter.Sort(array)); + Assert.That(array, Is.Empty); + } + + [Test] + public void Sort_SingleElementArray_DoesNotChangeArray() + { + var array = new[] { 1 }; + sorter.Sort(array); + Assert.That(array, Is.EqualTo(new[] { 1 })); + } + + [Test] + public void Sort_AlreadySortedArray_DoesNotChangeArray() + { + var array = new[] { 1, 2, 3, 4, 5 }; + sorter.Sort(array); + Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 })); + } + + [Test] + public void Sort_UnsortedArray_SortsCorrectly() + { + var array = new[] { 5, 3, 1, 4, 2 }; + sorter.Sort(array); + Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 })); + } + + [Test] + public void Sort_ReverseSortedArray_SortsCorrectly() + { + var array = new[] { 5, 4, 3, 2, 1 }; + sorter.Sort(array); + Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 })); + } + + [Test] + public void Sort_ArrayWithDuplicates_SortsCorrectly() + { + var array = new[] { 3, 1, 2, 3, 1, 2 }; + sorter.Sort(array); + Assert.That(array, Is.EqualTo(new[] { 1, 1, 2, 2, 3, 3 })); + } + + [Test] + public void Sort_LargeArray_SortsCorrectly() + { + var array = new int[1000]; + for (var i = 0; i < 1000; i++) + { + array[i] = 1000 - i; + } + sorter.Sort(array); + array.Should().BeInAscendingOrder(); + } + + [Test] + public void Sort_LargeRandomArray_SortsCorrectly() + { + var array = new int[1000]; + var random = new Random(); + for (var i = 0; i < 1000; i++) + { + array[i] = random.Next(1, 1001); + } + sorter.Sort(array); + array.Should().BeInAscendingOrder(); + } + } +} diff --git a/Algorithms/Sorters/Comparison/BasicTimSorter.cs b/Algorithms/Sorters/Comparison/BasicTimSorter.cs new file mode 100644 index 00000000..2ca6fb33 --- /dev/null +++ b/Algorithms/Sorters/Comparison/BasicTimSorter.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Algorithms.Sorters.Comparison +{ + /// + /// A basic implementation of the TimSort algorithm for sorting arrays. + /// + /// The type of elements in the array. + public class BasicTimSorter + { + private readonly int minRuns = 32; + private readonly IComparer comparer; + + /// + /// Initializes a new instance of the class. + /// + /// The comparer to use for comparing elements. + public BasicTimSorter(IComparer comparer) + { + this.comparer = comparer ?? Comparer.Default; + } + + /// + /// Sorts the specified array using the TimSort algorithm. + /// + /// The array to sort. + public void Sort(T[] array) + { + var n = array.Length; + + // Step 1: Sort small pieces of the array using Insertion Sort + for (var i = 0; i < n; i += minRuns) + { + InsertionSort(array, i, Math.Min(i + minRuns - 1, n - 1)); + } + + // Step 2: Merge sorted runs using Merge Sort + for (var size = minRuns; size < n; size *= 2) + { + for (var left = 0; left < n; left += 2 * size) + { + var mid = left + size - 1; + var right = Math.Min(left + 2 * size - 1, n - 1); + + if (mid < right) + { + Merge(array, left, mid, right); + } + } + } + } + + /// + /// Sorts a portion of the array using the Insertion Sort algorithm. + /// + /// The array to sort. + /// The starting index of the portion to sort. + /// The ending index of the portion to sort. + private void InsertionSort(T[] array, int left, int right) + { + for (var i = left + 1; i <= right; i++) + { + var key = array[i]; + var j = i - 1; + + // Move elements of array[0..i-1], that are greater than key, + // to one position ahead of their current position + while (j >= left && comparer.Compare(array[j], key) > 0) + { + array[j + 1] = array[j]; + j--; + } + + array[j + 1] = key; + } + } + + /// + /// Merges two sorted subarrays into a single sorted subarray. + /// + /// The array containing the subarrays to merge. + /// The starting index of the first subarray. + /// The ending index of the first subarray. + /// The ending index of the second subarray. + private void Merge(T[] array, int left, int mid, int right) + { + // Create segments for left and right subarrays + var leftSegment = new ArraySegment(array, left, mid - left + 1); + var rightSegment = new ArraySegment(array, mid + 1, right - mid); + + // Convert segments to arrays + var leftArray = leftSegment.ToArray(); + var rightArray = rightSegment.ToArray(); + + var i = 0; + var j = 0; + var k = left; + + // Merge the two subarrays back into the main array + while (i < leftArray.Length && j < rightArray.Length) + { + array[k++] = comparer.Compare(leftArray[i], rightArray[j]) <= 0 ? leftArray[i++] : rightArray[j++]; + } + + // Copy remaining elements from leftArray, if any + while (i < leftArray.Length) + { + array[k++] = leftArray[i++]; + } + + // Copy remaining elements from rightArray, if any + while (j < rightArray.Length) + { + array[k++] = rightArray[j++]; + } + } + } +} diff --git a/README.md b/README.md index 23ae8a18..13c2542b 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,7 @@ find more than one implementation for the same objective but using different alg * [Selection Sort](./Algorithms/Sorters/Comparison/SelectionSorter.cs) * [Shell Sort](./Algorithms/Sorters/Comparison/ShellSorter.cs) * [Tim Sort](./Algorithms/Sorters/Comparison/TimSorter.cs) + * [Simplified Tim Sort](./Algorithms/Sorters/Comparison/BasicTimSorter.cs) * [External](./Algorithms/Sorters/External) * [Merge Sort](./Algorithms/Sorters/External/ExternalMergeSorter.cs) * [Integer](./Algorithms/Sorters/Integer) From 36a7dd66f654a8c00c8c1550204b71e21946bf03 Mon Sep 17 00:00:00 2001 From: Mohit Singh <168663521+mohit-gogitter@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:52:15 +0530 Subject: [PATCH 111/138] Add BalancedParenthesesChecker, NextGreaterElement, and ReverseStack (#473) --- .../Stack/BalancedParenthesesCheckerTests.cs | 124 ++++++++++++++++++ .../Stack/NextGreaterElementTests.cs | 100 ++++++++++++++ Algorithms.Tests/Stack/ReverseStackTests.cs | 84 ++++++++++++ .../Stack/BalancedParenthesesChecker.cs | 90 +++++++++++++ Algorithms/Stack/NextGreaterElement.cs | 47 +++++++ Algorithms/Stack/ReverseStack.cs | 44 +++++++ README.md | 4 + 7 files changed, 493 insertions(+) create mode 100644 Algorithms.Tests/Stack/BalancedParenthesesCheckerTests.cs create mode 100644 Algorithms.Tests/Stack/NextGreaterElementTests.cs create mode 100644 Algorithms.Tests/Stack/ReverseStackTests.cs create mode 100644 Algorithms/Stack/BalancedParenthesesChecker.cs create mode 100644 Algorithms/Stack/NextGreaterElement.cs create mode 100644 Algorithms/Stack/ReverseStack.cs diff --git a/Algorithms.Tests/Stack/BalancedParenthesesCheckerTests.cs b/Algorithms.Tests/Stack/BalancedParenthesesCheckerTests.cs new file mode 100644 index 00000000..64c3876d --- /dev/null +++ b/Algorithms.Tests/Stack/BalancedParenthesesCheckerTests.cs @@ -0,0 +1,124 @@ +using System; +using Algorithms.Stack; +using NUnit.Framework; + +namespace Algorithms.Tests.Stack +{ + [TestFixture] + public class BalancedParenthesesCheckerTests + { + public static bool IsBalanced(string expression) + { + var checker = new BalancedParenthesesChecker(); + return checker.IsBalanced(expression); + } + + [Test] + public void IsBalanced_EmptyString_ThrowsArgumentException() + { + // Arrange + var expression = string.Empty; + + // Act & Assert + var ex = Assert.Throws(() => IsBalanced(expression)); + + if(ex!=null) + { + Assert.That(ex.Message, Is.EqualTo("The input expression cannot be null or empty.")); + } + + } + + [Test] + public void IsBalanced_ValidBalancedExpression_ReturnsTrue() + { + // Arrange + var expression = "{[()]}"; + + // Act + var result = IsBalanced(expression); + + // Assert + Assert.That(result, Is.EqualTo(true)); + } + + [Test] + public void IsBalanced_ValidUnbalancedExpression_ReturnsFalse() + { + // Arrange + var expression = "{[(])}"; + + // Act + var result = IsBalanced(expression); + + // Assert + Assert.That(result, Is.EqualTo(false)); + } + + [Test] + public void IsBalanced_UnbalancedWithExtraClosingBracket_ReturnsFalse() + { + // Arrange + var expression = "{[()]}]"; + + // Act + var result = IsBalanced(expression); + + // Assert + Assert.That(result, Is.EqualTo(false)); + } + + [Test] + public void IsBalanced_ExpressionWithInvalidCharacters_ThrowsArgumentException() + { + // Arrange + var expression = "{[a]}"; + + // Act & Assert + var ex = Assert.Throws(() => IsBalanced(expression)); + if (ex != null) + { + Assert.That(ex.Message, Is.EqualTo("Invalid character 'a' found in the expression.")); + } + } + + [Test] + public void IsBalanced_SingleOpeningBracket_ReturnsFalse() + { + // Arrange + var expression = "("; + + // Act + var result = IsBalanced(expression); + + // Assert + Assert.That(result, Is.EqualTo(false)); + } + + [Test] + public void IsBalanced_SingleClosingBracket_ReturnsFalse() + { + // Arrange + var expression = ")"; + + // Act + var result = IsBalanced(expression); + + // Assert + Assert.That(result, Is.EqualTo(false)); + } + + [Test] + public void IsBalanced_ExpressionWithMultipleBalancedBrackets_ReturnsTrue() + { + // Arrange + var expression = "[{()}]()"; + + // Act + var result = IsBalanced(expression); + + // Assert + Assert.That(result, Is.EqualTo(true)); + } + } +} diff --git a/Algorithms.Tests/Stack/NextGreaterElementTests.cs b/Algorithms.Tests/Stack/NextGreaterElementTests.cs new file mode 100644 index 00000000..09df3649 --- /dev/null +++ b/Algorithms.Tests/Stack/NextGreaterElementTests.cs @@ -0,0 +1,100 @@ +using System; +using Algorithms.Stack; +using NUnit.Framework; + +namespace Algorithms.Tests.Stack +{ + [TestFixture] + public class NextGreaterElementTests + { + private static int[] FindNextGreaterElement(int[] input) + { + var obj = new NextGreaterElement(); + return obj.FindNextGreaterElement(input); + } + + [Test] + public void FindNextGreaterElement_InputIsEmpty_ReturnsEmptyArray() + { + // Arrange + int[] input = Array.Empty(); + int[] expected = Array.Empty(); + + // Act + var result = FindNextGreaterElement(input); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void FindNextGreaterElement_BasicScenario_ReturnsCorrectResult() + { + // Arrange + int[] input = { 4, 5, 2, 25 }; + int[] expected = { 5, 25, 25, -1 }; + + // Act + var result = FindNextGreaterElement(input); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void FindNextGreaterElement_NoNextGreaterElement_ReturnsCorrectResult() + { + // Arrange + int[] input = { 13, 7, 6, 12 }; + int[] expected = { -1, 12, 12, -1 }; + + // Act + var result = FindNextGreaterElement(input); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void FindNextGreaterElement_AllElementsHaveNoGreaterElement_ReturnsAllNegativeOnes() + { + // Arrange + int[] input = { 5, 4, 3, 2, 1 }; + int[] expected = { -1, -1, -1, -1, -1 }; + + // Act + var result = FindNextGreaterElement(input); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void FindNextGreaterElement_InputWithDuplicates_ReturnsCorrectResult() + { + // Arrange + int[] input = { 4, 4, 3, 2, 4 }; + int[] expected = { -1, -1, 4, 4, -1 }; + + // Act + var result = FindNextGreaterElement(input); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void FindNextGreaterElement_SingleElementArray_ReturnsNegativeOne() + { + // Arrange + int[] input = { 10 }; + int[] expected = { -1 }; + + // Act + var result = FindNextGreaterElement(input); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } + } +} diff --git a/Algorithms.Tests/Stack/ReverseStackTests.cs b/Algorithms.Tests/Stack/ReverseStackTests.cs new file mode 100644 index 00000000..8312efac --- /dev/null +++ b/Algorithms.Tests/Stack/ReverseStackTests.cs @@ -0,0 +1,84 @@ +using Algorithms.Stack; +using NUnit.Framework; +using System.Collections.Generic; + + +namespace Algorithms.Tests.Stack +{ + public class ReverseStackTests + { + public static void Reverse(Stack stack) + { + var obj = new ReverseStack(); + obj.Reverse(stack); + } + + [Test] + public void Reverse_EmptyStack_DoesNotChangeStack() + { + // Arrange + Stack stack = new Stack(); + + // Act + Reverse(stack); + + // Assert + Assert.That(stack.Count, Is.EqualTo(0)); + } + + [Test] + public void Reverse_SingleElementStack_DoesNotChangeStack() + { + // Arrange + Stack stack = new Stack(); + stack.Push(1); + + // Act + Reverse(stack); + + // Assert + Assert.That(stack.Count, Is.EqualTo(1)); + Assert.That(stack.Peek(), Is.EqualTo(1)); + } + + [Test] + public void Reverse_MultipleElementStack_ReturnsCorrectOrder() + { + // Arrange + Stack stack = new Stack(); + stack.Push(1); + stack.Push(2); + stack.Push(3); + // The stack is now [3, 2, 1] (top to bottom) + + // Act + Reverse(stack); + + // Assert + Assert.That(stack.Count, Is.EqualTo(3)); + Assert.That(stack.Pop(), Is.EqualTo(1)); // Should return 1 + Assert.That(stack.Pop(), Is.EqualTo(2)); // Should return 2 + Assert.That(stack.Pop(), Is.EqualTo(3)); // Should return 3 + } + + [Test] + public void Reverse_StackWithDuplicates_ReturnsCorrectOrder() + { + // Arrange + Stack stack = new Stack(); + stack.Push(1); + stack.Push(2); + stack.Push(1); + // The stack is now [1, 2, 1] (top to bottom) + + // Act + Reverse(stack); + + // Assert + Assert.That(stack.Count, Is.EqualTo(3)); + Assert.That(stack.Pop(), Is.EqualTo(1)); // Should return 1 + Assert.That(stack.Pop(), Is.EqualTo(2)); // Should return 2 + Assert.That(stack.Pop(), Is.EqualTo(1)); // Should return 1 + } + } +} diff --git a/Algorithms/Stack/BalancedParenthesesChecker.cs b/Algorithms/Stack/BalancedParenthesesChecker.cs new file mode 100644 index 00000000..2f2b8311 --- /dev/null +++ b/Algorithms/Stack/BalancedParenthesesChecker.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; + +namespace Algorithms.Stack +{ + /// + /// It checks if an expression has matching and balanced parentheses. + /// @author Mohit Singh. mohit-gogitter + /// + public class BalancedParenthesesChecker + { + private static readonly Dictionary ParenthesesMap = new Dictionary + { + { '(', ')' }, + { '{', '}' }, + { '[', ']' }, + }; + + /// + /// Determines if a given string expression containing brackets is balanced. + /// A string is considered balanced if all opening brackets have corresponding closing brackets + /// in the correct order. The supported brackets are '()', '{}', and '[]'. + /// + /// + /// The input string expression containing the brackets to check for balance. + /// + /// + /// true if the brackets in the expression are balanced; otherwise, false. + /// + /// + /// Thrown when the input expression contains invalid characters or is null/empty. + /// Only '(', ')', '{', '}', '[', ']' characters are allowed. + /// + public bool IsBalanced(string expression) + { + if (string.IsNullOrEmpty(expression)) + { + throw new ArgumentException("The input expression cannot be null or empty."); + } + + Stack stack = new Stack(); + foreach (char c in expression) + { + if (IsOpeningParenthesis(c)) + { + stack.Push(c); + } + else if (IsClosingParenthesis(c)) + { + if (!IsBalancedClosing(stack, c)) + { + return false; + } + } + else + { + throw new ArgumentException($"Invalid character '{c}' found in the expression."); + } + } + + return stack.Count == 0; + } + + private static bool IsOpeningParenthesis(char c) + { + return c == '(' || c == '{' || c == '['; + } + + private static bool IsClosingParenthesis(char c) + { + return c == ')' || c == '}' || c == ']'; + } + + private static bool IsBalancedClosing(Stack stack, char close) + { + if (stack.Count == 0) + { + return false; + } + + char open = stack.Pop(); + return IsMatchingPair(open, close); + } + + private static bool IsMatchingPair(char open, char close) + { + return ParenthesesMap.ContainsKey(open) && ParenthesesMap[open] == close; + } + } +} diff --git a/Algorithms/Stack/NextGreaterElement.cs b/Algorithms/Stack/NextGreaterElement.cs new file mode 100644 index 00000000..0e5bbecb --- /dev/null +++ b/Algorithms/Stack/NextGreaterElement.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +namespace Algorithms.Stack +{ + /// + /// For each element in an array, the utility finds the next greater element on the right side using a stack. + /// @author Mohit Singh. mohit-gogitter + /// + public class NextGreaterElement + { + /// + /// Finds the next greater element for each element in the input array. + /// The next greater element for an element x is the first element greater than x to its right. + /// If there is no greater element, -1 is returned for that element. + /// + /// The array of integers to find the next greater elements for. + /// An array where each index contains the next greater element of the corresponding element in the input array, or -1 if no such element exists. + /// Thrown when the input array is null. + public int[] FindNextGreaterElement(int[] nums) + { + int[] result = new int[nums.Length]; + Stack stack = new Stack(); + + // Initialize all elements in the result array to -1 + for (int i = 0; i < nums.Length; i++) + { + result[i] = -1; + } + + for (int i = 0; i < nums.Length; i++) + { + // While the stack is not empty and the current element is greater than the element + // corresponding to the index stored at the top of the stack + while (stack.Count > 0 && nums[i] > nums[stack.Peek()]) + { + int index = stack.Pop(); + result[index] = nums[i]; // Set the next greater element + } + + stack.Push(i); // Push current index to stack + } + + return result; + } + } +} diff --git a/Algorithms/Stack/ReverseStack.cs b/Algorithms/Stack/ReverseStack.cs new file mode 100644 index 00000000..af2f4e26 --- /dev/null +++ b/Algorithms/Stack/ReverseStack.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; + +namespace Algorithms.Stack +{ + /// + /// Reverses the elements in a stack using recursion. + /// @author Mohit Singh. mohit-gogitter + /// + public class ReverseStack + { + /// + /// Recursively reverses the elements of the specified stack. + /// + /// The type of elements in the stack. + /// The stack to be reversed. This parameter cannot be null. + /// Thrown when the stack parameter is null. + public void Reverse(Stack stack) + { + if (stack.Count == 0) + { + return; + } + + T temp = stack.Pop(); + Reverse(stack); + InsertAtBottom(stack, temp); + } + + private void InsertAtBottom(Stack stack, T value) + { + if (stack.Count == 0) + { + stack.Push(value); + } + else + { + T temp = stack.Pop(); + InsertAtBottom(stack, value); + stack.Push(temp); + } + } + } +} diff --git a/README.md b/README.md index 13c2542b..f13516de 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,10 @@ find more than one implementation for the same objective but using different alg * [A057588 Kummer Numbers](./Algorithms/Sequences/KummerNumbersSequence.cs) * [A019434 Fermat Primes](./Algorithms/Sequences/FermatPrimesSequence.cs) * [A181391 Van Eck's](./Algorithms/Sequences/VanEcksSequence.cs) + * [Stack](./Algorithms/Stack) + * [Next Greater Element](./Algorithms/Stack/NextGreaterElement.cs) + * [Balanced Parentheses Checker](./Algorithms/Stack/BalancedParenthesesChecker.cs) + * [Reverse Stack](./Algorithms/Stack/ReverseStack.cs) * [String](./Algorithms/Strings) * [Similarity](./Algorithms/Strings/Similarity/) * [Cosine Similarity](./Algorithms/Strings/Similarity/CosineSimilarity.cs) From 833a0fb123786901988a3c18165369d3fc138fad Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Mon, 21 Oct 2024 21:53:18 +0300 Subject: [PATCH 112/138] Update StyleCop (#480) --- .../ExtendedEuclideanAlgorithmTest.cs | 12 +- Algorithms/Algorithms.csproj | 2 +- .../BurrowsWheelerTransform.cs | 2 +- .../DataCompression/HuffmanCompressor.cs | 4 +- .../DataCompression/ShannonFanoCompressor.cs | 18 +- Algorithms/Encoders/NysiisEncoder.cs | 16 +- Algorithms/Graph/FloydWarshall.cs | 2 +- .../Eigenvalue/PowerIteration.cs | 6 +- .../ChineseRemainderTheorem.cs | 8 +- .../ExtendedEuclideanAlgorithm.cs | 20 +- .../ModularMultiplicativeInverse.cs | 8 +- Algorithms/Other/FloodFill.cs | 34 +-- Algorithms/Other/GaussOptimization.cs | 2 +- Algorithms/Other/RGBHSVConversion.cs | 6 +- Algorithms/Search/FastSearcher.cs | 4 +- Algorithms/Sorters/Comparison/MergeSorter.cs | 2 +- Algorithms/Sorters/Comparison/TimSorter.cs | 247 +++++++++--------- .../Sorters/Comparison/TimSorterSettings.cs | 14 + Algorithms/Sorters/Utils/GallopingStrategy.cs | 4 +- .../Strings/Similarity/CosineSimilarity.cs | 6 +- .../Similarity/DamerauLevenshteinDistance.cs | 2 +- DataStructures/AATree/AATree.cs | 2 +- DataStructures/DataStructures.csproj | 2 +- DataStructures/Graph/DirectedWeightedGraph.cs | 2 +- DataStructures/Hashing/HashTable.cs | 2 +- .../RedBlackTree/RedBlackTreeNode.cs | 4 +- DataStructures/ScapegoatTree/ScapegoatTree.cs | 2 +- Utilities/Extensions/DictionaryExtensions.cs | 2 +- Utilities/Utilities.csproj | 2 +- 29 files changed, 219 insertions(+), 218 deletions(-) create mode 100644 Algorithms/Sorters/Comparison/TimSorterSettings.cs diff --git a/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs b/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs index ea3e7792..83ab1caf 100644 --- a/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs +++ b/Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs @@ -23,9 +23,9 @@ public static void TestCompute(long a, long b, long expectedGCD, long expectedBe var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, b); // Assert - Assert.That(eeaResult.gcd, Is.EqualTo(expectedGCD)); - Assert.That(eeaResult.bezoutA, Is.EqualTo(expectedBezoutOfA)); - Assert.That(eeaResult.bezoutB, Is.EqualTo(expectedBezoutOfB)); + Assert.That(eeaResult.Gcd, Is.EqualTo(expectedGCD)); + Assert.That(eeaResult.BezoutA, Is.EqualTo(expectedBezoutOfA)); + Assert.That(eeaResult.BezoutB, Is.EqualTo(expectedBezoutOfB)); } [TestCase(240, 46, 2, -9, 47)] @@ -45,8 +45,8 @@ public static void TestCompute_BigInteger(long a, long b, long expectedGCD, long var eeaResult = ExtendedEuclideanAlgorithm.Compute(new BigInteger(a), new BigInteger(b)); // Assert - Assert.That(eeaResult.gcd, Is.EqualTo(new BigInteger(expectedGCD))); - Assert.That(eeaResult.bezoutA, Is.EqualTo(new BigInteger(expectedBezoutOfA))); - Assert.That(eeaResult.bezoutB, Is.EqualTo(new BigInteger(expectedBezoutOfB))); + Assert.That(eeaResult.Gcd, Is.EqualTo(new BigInteger(expectedGCD))); + Assert.That(eeaResult.BezoutA, Is.EqualTo(new BigInteger(expectedBezoutOfA))); + Assert.That(eeaResult.BezoutB, Is.EqualTo(new BigInteger(expectedBezoutOfB))); } } diff --git a/Algorithms/Algorithms.csproj b/Algorithms/Algorithms.csproj index 84283140..671d3e70 100644 --- a/Algorithms/Algorithms.csproj +++ b/Algorithms/Algorithms.csproj @@ -18,7 +18,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Algorithms/DataCompression/BurrowsWheelerTransform.cs b/Algorithms/DataCompression/BurrowsWheelerTransform.cs index e84aab8d..6ec19387 100644 --- a/Algorithms/DataCompression/BurrowsWheelerTransform.cs +++ b/Algorithms/DataCompression/BurrowsWheelerTransform.cs @@ -16,7 +16,7 @@ public class BurrowsWheelerTransform /// rotation matrix. /// /// Input string. - public (string encoded, int index) Encode(string s) + public (string Encoded, int Index) Encode(string s) { if (s.Length == 0) { diff --git a/Algorithms/DataCompression/HuffmanCompressor.cs b/Algorithms/DataCompression/HuffmanCompressor.cs index a9d3f689..368f0704 100644 --- a/Algorithms/DataCompression/HuffmanCompressor.cs +++ b/Algorithms/DataCompression/HuffmanCompressor.cs @@ -27,7 +27,7 @@ public HuffmanCompressor(IComparisonSorter sorter, Translator translat /// /// Text message to compress. /// Compressed string and keys to decompress it. - public (string compressedText, Dictionary decompressionKeys) Compress(string uncompressedText) + public (string CompressedText, Dictionary DecompressionKeys) Compress(string uncompressedText) { if (string.IsNullOrEmpty(uncompressedText)) { @@ -70,7 +70,7 @@ private static ListNode[] GetListNodesFromText(string text) return occurenceCounts.Select(kvp => new ListNode(kvp.Key, 1d * kvp.Value / text.Length)).ToArray(); } - private (Dictionary compressionKeys, Dictionary decompressionKeys) GetKeys( + private (Dictionary CompressionKeys, Dictionary DecompressionKeys) GetKeys( ListNode tree) { var compressionKeys = new Dictionary(); diff --git a/Algorithms/DataCompression/ShannonFanoCompressor.cs b/Algorithms/DataCompression/ShannonFanoCompressor.cs index 6a48e7b4..3aba6761 100644 --- a/Algorithms/DataCompression/ShannonFanoCompressor.cs +++ b/Algorithms/DataCompression/ShannonFanoCompressor.cs @@ -10,11 +10,11 @@ namespace Algorithms.DataCompression; ///
public class ShannonFanoCompressor { - private readonly IHeuristicKnapsackSolver<(char symbol, double frequency)> splitter; + private readonly IHeuristicKnapsackSolver<(char Symbol, double Frequency)> splitter; private readonly Translator translator; public ShannonFanoCompressor( - IHeuristicKnapsackSolver<(char symbol, double frequency)> splitter, + IHeuristicKnapsackSolver<(char Symbol, double Frequency)> splitter, Translator translator) { this.splitter = splitter; @@ -27,7 +27,7 @@ public ShannonFanoCompressor( ///
/// Text message to compress. /// Compressed string and keys to decompress it. - public (string compressedText, Dictionary decompressionKeys) Compress(string uncompressedText) + public (string CompressedText, Dictionary DecompressionKeys) Compress(string uncompressedText) { if (string.IsNullOrEmpty(uncompressedText)) { @@ -49,7 +49,7 @@ public ShannonFanoCompressor( return (translator.Translate(uncompressedText, compressionKeys), decompressionKeys); } - private (Dictionary compressionKeys, Dictionary decompressionKeys) GetKeys( + private (Dictionary CompressionKeys, Dictionary DecompressionKeys) GetKeys( ListNode tree) { var compressionKeys = new Dictionary(); @@ -57,8 +57,8 @@ public ShannonFanoCompressor( if (tree.Data.Length == 1) { - compressionKeys.Add(tree.Data[0].symbol.ToString(), string.Empty); - decompressionKeys.Add(string.Empty, tree.Data[0].symbol.ToString()); + compressionKeys.Add(tree.Data[0].Symbol.ToString(), string.Empty); + decompressionKeys.Add(string.Empty, tree.Data[0].Symbol.ToString()); return (compressionKeys, decompressionKeys); } @@ -86,7 +86,7 @@ private ListNode GenerateShannonFanoTree(ListNode node) return node; } - var left = splitter.Solve(node.Data, 0.5 * node.Data.Sum(x => x.frequency), x => x.frequency, _ => 1); + var left = splitter.Solve(node.Data, 0.5 * node.Data.Sum(x => x.Frequency), x => x.Frequency, _ => 1); var right = node.Data.Except(left).ToArray(); node.LeftChild = GenerateShannonFanoTree(new ListNode(left)); @@ -122,9 +122,9 @@ private ListNode GetListNodeFromText(string text) ///
public class ListNode { - public ListNode((char symbol, double frequency)[] data) => Data = data; + public ListNode((char Symbol, double Frequency)[] data) => Data = data; - public (char symbol, double frequency)[] Data { get; } + public (char Symbol, double Frequency)[] Data { get; } public ListNode? RightChild { get; set; } diff --git a/Algorithms/Encoders/NysiisEncoder.cs b/Algorithms/Encoders/NysiisEncoder.cs index a5e98747..10810af3 100644 --- a/Algorithms/Encoders/NysiisEncoder.cs +++ b/Algorithms/Encoders/NysiisEncoder.cs @@ -51,13 +51,13 @@ private string RemoveDuplicates(string text) private string TrimEnd(string text) { - var checks = new (string from, string to)?[] + var checks = new (string From, string To)?[] { ("S", string.Empty), ("AY", "Y"), ("A", string.Empty), }; - var replacement = checks.FirstOrDefault(t => text.EndsWith(t!.Value.from)); + var replacement = checks.FirstOrDefault(t => text.EndsWith(t!.Value.From)); if (replacement is { }) { var (from, to) = replacement!.Value; @@ -69,7 +69,7 @@ private string TrimEnd(string text) private string ReplaceStep(string text, int i) { - (string from, string to)[] replacements = + (string From, string To)[] replacements = { ("EV", "AF"), ("E", "A"), @@ -134,7 +134,7 @@ private bool TryReplace(string text, int index, (string, string)[] opts, out str private string StartReplace(string start) { - var checks = new (string from, string to)?[] + var checks = new (string From, string To)?[] { ("MAC", "MCC"), ("KN", "NN"), @@ -143,7 +143,7 @@ private string StartReplace(string start) ("PF", "FF"), ("SCH", "SSS"), }; - var replacement = checks.FirstOrDefault(t => start.StartsWith(t!.Value.from)); + var replacement = checks.FirstOrDefault(t => start.StartsWith(t!.Value.From)); if (replacement is { }) { var (from, to) = replacement!.Value; @@ -155,7 +155,7 @@ private string StartReplace(string start) private string EndReplace(string end) { - var checks = new (string from, string to)?[] + var checks = new (string From, string To)?[] { ("EE", "Y"), ("IE", "Y"), @@ -164,7 +164,7 @@ private string EndReplace(string end) ("NT", "D"), ("ND", "D"), }; - var replacement = checks.FirstOrDefault(t => end.EndsWith(t!.Value.from)); + var replacement = checks.FirstOrDefault(t => end.EndsWith(t!.Value.From)); if (replacement is { }) { var (from, to) = replacement!.Value; @@ -175,5 +175,5 @@ private string EndReplace(string end) } private string Replace(string text, int index, int length, string substitute) => - text[..index] + substitute + text[(index + length) ..]; + text[..index] + substitute + text[(index + length)..]; } diff --git a/Algorithms/Graph/FloydWarshall.cs b/Algorithms/Graph/FloydWarshall.cs index 7bb9d707..8c7fc466 100644 --- a/Algorithms/Graph/FloydWarshall.cs +++ b/Algorithms/Graph/FloydWarshall.cs @@ -49,7 +49,7 @@ public class FloydWarshall { for (var j = 0; j < distances.GetLength(0); j++) { - var dist = graph.AdjacentDistance(graph.Vertices[i] !, graph.Vertices[j] !); + var dist = graph.AdjacentDistance(graph.Vertices[i]!, graph.Vertices[j]!); distances[i, j] = dist != 0 ? dist : double.PositiveInfinity; } } diff --git a/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs b/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs index 8e503992..df225723 100644 --- a/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs +++ b/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs @@ -27,7 +27,7 @@ public static class PowerIteration /// Dominant eigenvalue and eigenvector pair. /// The matrix is not square-shaped. /// The length of the start vector doesn't equal the size of the source matrix. - public static (double eigenvalue, double[] eigenvector) Dominant( + public static (double Eigenvalue, double[] Eigenvector) Dominant( double[,] source, double[] startVector, double error = 0.00001) @@ -61,7 +61,7 @@ public static (double eigenvalue, double[] eigenvector) Dominant( var eigenvalue = source.Multiply(currentEigenVector.ToColumnVector()).ToRowVector().Magnitude(); - return (eigenvalue, eigenvector: currentEigenVector); + return (eigenvalue, Eigenvector: currentEigenVector); } /// @@ -81,6 +81,6 @@ public static (double eigenvalue, double[] eigenvector) Dominant( /// Dominant eigenvalue and eigenvector pair. /// The matrix is not square-shaped. /// The length of the start vector doesn't equal the size of the source matrix. - public static (double eigenvalue, double[] eigenvector) Dominant(double[,] source, double error = 0.00001) => + public static (double Eigenvalue, double[] Eigenvector) Dominant(double[,] source, double error = 0.00001) => Dominant(source, new Random().NextVector(source.GetLength(1)), error); } diff --git a/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs b/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs index 1eeaef76..9f7d88cb 100644 --- a/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs +++ b/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs @@ -49,7 +49,7 @@ public static long Compute(List listOfAs, List listOfNs) var n_i = listOfNs[i]; var modulus_i = prodN / n_i; - var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).bezoutB; + var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).BezoutB; result += a_i * bezout_modulus_i * modulus_i; } @@ -102,7 +102,7 @@ public static BigInteger Compute(List listOfAs, List lis var n_i = listOfNs[i]; var modulus_i = prodN / n_i; - var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).bezoutB; + var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).BezoutB; result += a_i * bezout_modulus_i * modulus_i; } @@ -145,7 +145,7 @@ private static void CheckRequirements(List listOfAs, List listOfNs) for (var j = i + 1; j < listOfNs.Count; j++) { long gcd; - if ((gcd = ExtendedEuclideanAlgorithm.Compute(listOfNs[i], listOfNs[j]).gcd) != 1L) + if ((gcd = ExtendedEuclideanAlgorithm.Compute(listOfNs[i], listOfNs[j]).Gcd) != 1L) { throw new ArgumentException($"The GCD of n_{i} = {listOfNs[i]} and n_{j} = {listOfNs[j]} equals {gcd} and thus these values aren't coprime."); } @@ -182,7 +182,7 @@ private static void CheckRequirements(List listOfAs, List - /// Computes the greatest common divisor (gcd) of integers a and b, also the coefficients of Bézout's identity, - /// which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = gcd(a, b). + /// Computes the greatest common divisor (Gcd) of integers a and b, also the coefficients of Bézout's identity, + /// which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = Gcd(a, b). /// /// Input number. /// Second input number. - /// A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the gcd(a,b). + /// A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the Gcd(a,b). public static ExtendedEuclideanAlgorithmResult Compute(long a, long b) { long quotient; @@ -46,12 +46,12 @@ public static ExtendedEuclideanAlgorithmResult Compute(long a, long b) } /// - /// Computes the greatest common divisor (gcd) of integers a and b, also the coefficients of Bézout's identity, - /// which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = gcd(a, b). + /// Computes the greatest common divisor (Gcd) of integers a and b, also the coefficients of Bézout's identity, + /// which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = Gcd(a, b). /// /// Input number. /// Second input number. - /// A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the gcd(a,b). + /// A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the Gcd(a,b). public static ExtendedEuclideanAlgorithmResult Compute(BigInteger a, BigInteger b) { BigInteger quotient; @@ -87,8 +87,8 @@ public static ExtendedEuclideanAlgorithmResult Compute(BigInteger a, /// The result type for the computation of the Extended Euclidean Algorithm. ///
/// The data type of the computation (i.e. long or BigInteger). - /// The bezout coefficient of the parameter a to the computation. - /// The bezout coefficient of the parameter b to the computation. - /// The greatest common divisor of the parameters a and b to the computation. - public record ExtendedEuclideanAlgorithmResult(T bezoutA, T bezoutB, T gcd); + /// The bezout coefficient of the parameter a to the computation. + /// The bezout coefficient of the parameter b to the computation. + /// The greatest common divisor of the parameters a and b to the computation. + public record ExtendedEuclideanAlgorithmResult(T BezoutA, T BezoutB, T Gcd); } diff --git a/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs b/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs index 0e42cd68..9a3c5ce0 100644 --- a/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs +++ b/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs @@ -20,13 +20,13 @@ public static long Compute(long a, long n) var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, n); // Check if there is an inverse: - if (eeaResult.gcd != 1) + if (eeaResult.Gcd != 1) { throw new ArithmeticException($"{a} is not invertible in Z/{n}Z."); } // Make sure, inverseOfA (i.e. the bezout coefficient of a) is in the interval [0, n). - var inverseOfA = eeaResult.bezoutA; + var inverseOfA = eeaResult.BezoutA; if (inverseOfA < 0) { inverseOfA += n; @@ -47,13 +47,13 @@ public static BigInteger Compute(BigInteger a, BigInteger n) var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, n); // Check if there is an inverse: - if (eeaResult.gcd != 1) + if (eeaResult.Gcd != 1) { throw new ArithmeticException($"{a} is not invertible in Z/{n}Z."); } // Make sure, inverseOfA (i.e. the bezout coefficient of a) is in the interval [0, n). - var inverseOfA = eeaResult.bezoutA; + var inverseOfA = eeaResult.BezoutA; if (inverseOfA < 0) { inverseOfA += n; diff --git a/Algorithms/Other/FloodFill.cs b/Algorithms/Other/FloodFill.cs index 22cc94e1..ac881d5f 100644 --- a/Algorithms/Other/FloodFill.cs +++ b/Algorithms/Other/FloodFill.cs @@ -14,7 +14,7 @@ namespace Algorithms.Other; ///
public static class FloodFill { - private static readonly List<(int xOffset, int yOffset)> Neighbors = new() { (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1) }; + private static readonly List<(int XOffset, int YOffset)> Neighbors = new() { (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1) }; /// /// Implements the flood fill algorithm through a breadth-first approach using a queue. @@ -23,14 +23,14 @@ public static class FloodFill /// The start location on the bitmap. /// The old color to be replaced. /// The new color to replace the old one. - public static void BreadthFirstSearch(SKBitmap bitmap, (int x, int y) location, SKColor targetColor, SKColor replacementColor) + public static void BreadthFirstSearch(SKBitmap bitmap, (int X, int Y) location, SKColor targetColor, SKColor replacementColor) { - if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) + if (location.X < 0 || location.X >= bitmap.Width || location.Y < 0 || location.Y >= bitmap.Height) { throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap"); } - var queue = new List<(int x, int y)>(); + var queue = new List<(int X, int Y)>(); queue.Add(location); while (queue.Count > 0) @@ -46,9 +46,9 @@ public static void BreadthFirstSearch(SKBitmap bitmap, (int x, int y) location, /// The start location on the bitmap. /// The old color to be replaced. /// The new color to replace the old one. - public static void DepthFirstSearch(SKBitmap bitmap, (int x, int y) location, SKColor targetColor, SKColor replacementColor) + public static void DepthFirstSearch(SKBitmap bitmap, (int X, int Y) location, SKColor targetColor, SKColor replacementColor) { - if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) + if (location.X < 0 || location.X >= bitmap.Width || location.Y < 0 || location.Y >= bitmap.Height) { throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap"); } @@ -56,19 +56,19 @@ public static void DepthFirstSearch(SKBitmap bitmap, (int x, int y) location, SK DepthFirstFill(bitmap, location, targetColor, replacementColor); } - private static void BreadthFirstFill(SKBitmap bitmap, (int x, int y) location, SKColor targetColor, SKColor replacementColor, List<(int x, int y)> queue) + private static void BreadthFirstFill(SKBitmap bitmap, (int X, int Y) location, SKColor targetColor, SKColor replacementColor, List<(int X, int Y)> queue) { - (int x, int y) currentLocation = queue[0]; + (int X, int Y) currentLocation = queue[0]; queue.RemoveAt(0); - if (bitmap.GetPixel(currentLocation.x, currentLocation.y) == targetColor) + if (bitmap.GetPixel(currentLocation.X, currentLocation.Y) == targetColor) { - bitmap.SetPixel(currentLocation.x, currentLocation.y, replacementColor); + bitmap.SetPixel(currentLocation.X, currentLocation.Y, replacementColor); for (int i = 0; i < Neighbors.Count; i++) { - int x = currentLocation.x + Neighbors[i].xOffset; - int y = currentLocation.y + Neighbors[i].yOffset; + int x = currentLocation.X + Neighbors[i].XOffset; + int y = currentLocation.Y + Neighbors[i].YOffset; if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height) { queue.Add((x, y)); @@ -77,16 +77,16 @@ private static void BreadthFirstFill(SKBitmap bitmap, (int x, int y) location, S } } - private static void DepthFirstFill(SKBitmap bitmap, (int x, int y) location, SKColor targetColor, SKColor replacementColor) + private static void DepthFirstFill(SKBitmap bitmap, (int X, int Y) location, SKColor targetColor, SKColor replacementColor) { - if (bitmap.GetPixel(location.x, location.y) == targetColor) + if (bitmap.GetPixel(location.X, location.Y) == targetColor) { - bitmap.SetPixel(location.x, location.y, replacementColor); + bitmap.SetPixel(location.X, location.Y, replacementColor); for (int i = 0; i < Neighbors.Count; i++) { - int x = location.x + Neighbors[i].xOffset; - int y = location.y + Neighbors[i].yOffset; + int x = location.X + Neighbors[i].XOffset; + int y = location.Y + Neighbors[i].YOffset; if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height) { DepthFirstFill(bitmap, (x, y), targetColor, replacementColor); diff --git a/Algorithms/Other/GaussOptimization.cs b/Algorithms/Other/GaussOptimization.cs index 3387a1e1..a8c50fdb 100644 --- a/Algorithms/Other/GaussOptimization.cs +++ b/Algorithms/Other/GaussOptimization.cs @@ -24,7 +24,7 @@ public class GaussOptimization /// The first function parameter. /// The second function parameter. /// A tuple of coordinates of function extremum. - public (double, double) Optimize( + public (double X1, double X2) Optimize( Func func, double n, double step, diff --git a/Algorithms/Other/RGBHSVConversion.cs b/Algorithms/Other/RGBHSVConversion.cs index ecad76d3..9e1f2f97 100644 --- a/Algorithms/Other/RGBHSVConversion.cs +++ b/Algorithms/Other/RGBHSVConversion.cs @@ -22,7 +22,7 @@ public static class RgbHsvConversion /// Saturation of the color. /// Brightness-value of the color. /// The tuple of RGB-components. - public static (byte red, byte green, byte blue) HsvToRgb( + public static (byte Red, byte Green, byte Blue) HsvToRgb( double hue, double saturation, double value) @@ -59,7 +59,7 @@ public static (byte red, byte green, byte blue) HsvToRgb( /// Green-component of the color. /// Blue-component of the color. /// The tuple of HSV-components. - public static (double hue, double saturation, double value) RgbToHsv( + public static (double Hue, double Saturation, double Value) RgbToHsv( byte red, byte green, byte blue) @@ -94,7 +94,7 @@ public static (double hue, double saturation, double value) RgbToHsv( return (hue, saturation, value); } - private static (byte red, byte green, byte blue) GetRgbBySection( + private static (byte Red, byte Green, byte Blue) GetRgbBySection( double hueSection, double chroma, double matchValue, diff --git a/Algorithms/Search/FastSearcher.cs b/Algorithms/Search/FastSearcher.cs index b11989df..42b2cf3a 100644 --- a/Algorithms/Search/FastSearcher.cs +++ b/Algorithms/Search/FastSearcher.cs @@ -44,7 +44,7 @@ public int FindIndex(Span array, int item) return from + FindIndex(array.Slice(from, to - from + 1), item); } - private (int left, int right) ComputeIndices(Span array, int item) + private (int Left, int Right) ComputeIndices(Span array, int item) { var indexBinary = array.Length / 2; @@ -62,7 +62,7 @@ public int FindIndex(Span array, int item) : (indexInterpolation, indexBinary); } - private (int from, int to) SelectSegment(Span array, int left, int right, int item) + private (int From, int To) SelectSegment(Span array, int left, int right, int item) { if (item < array[left]) { diff --git a/Algorithms/Sorters/Comparison/MergeSorter.cs b/Algorithms/Sorters/Comparison/MergeSorter.cs index b86af4b6..13a888ad 100644 --- a/Algorithms/Sorters/Comparison/MergeSorter.cs +++ b/Algorithms/Sorters/Comparison/MergeSorter.cs @@ -57,7 +57,7 @@ private static void Merge(T[] array, T[] left, T[] right, IComparer comparer) } } - private static (T[] left, T[] right) Split(T[] array) + private static (T[] Left, T[] Right) Split(T[] array) { var mid = array.Length / 2; return (array.Take(mid).ToArray(), array.Skip(mid).ToArray()); diff --git a/Algorithms/Sorters/Comparison/TimSorter.cs b/Algorithms/Sorters/Comparison/TimSorter.cs index 0115e560..d098d340 100755 --- a/Algorithms/Sorters/Comparison/TimSorter.cs +++ b/Algorithms/Sorters/Comparison/TimSorter.cs @@ -9,18 +9,18 @@ namespace Algorithms.Sorters.Comparison; /// It was originally implemented by Tim Peters in 2002 for use in the Python programming language. /// /// This class is based on a Java interpretation of Tim Peter's original work. -/// Java class is viewable here: +/// Java class is viewable here: /// http://cr.openjdk.java.net/~martin/webrevs/openjdk7/timsort/raw_files/new/src/share/classes/java/util/TimSort.java /// -/// Tim Peters's list sort for Python, is described in detail here: -/// http://svn.python.org/projects/python/trunk/Objects/listsort.txt +/// Tim Peters's list sort for Python, is described in detail here: +/// http://svn.python.org/projects/python/trunk/Objects/listsort.txt /// /// Tim's C code may be found here: http://svn.python.org/projects/python/trunk/Objects/listobject.c /// -/// The underlying techniques are described in this paper (and may have even earlier origins): -/// "Optimistic Sorting and Information Theoretic Complexity" -/// Peter McIlroy -/// SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), +/// The underlying techniques are described in this paper (and may have even earlier origins): +/// "Optimistic Sorting and Information Theoretic Complexity" +/// Peter McIlroy +/// SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), /// pp 467-474, Austin, Texas, 25-27 January 1993. /// /// Type of array element. @@ -34,31 +34,31 @@ public class TimSorter : IComparisonSorter private readonly int[] runBase; private readonly int[] runLengths; - + private int minGallop; private int stackSize; private IComparer comparer = default!; - /// - /// Private class for handling gallop merges, allows for tracking array indexes and wins. - /// - /// Type of array element. - private class TimChunk - { - public Tc[] Array { get; set; } = default!; - - public int Index { get; set; } - - public int Remaining { get; set; } - - public int Wins { get; set; } + /// + /// Private class for handling gallop merges, allows for tracking array indexes and wins. + /// + /// Type of array element. + private class TimChunk + { + public Tc[] Array { get; set; } = default!; + + public int Index { get; set; } + + public int Remaining { get; set; } + + public int Wins { get; set; } } public TimSorter(TimSorterSettings settings, IComparer comparer) { initMinGallop = minGallop; - runBase = new int[85]; + runBase = new int[85]; runLengths = new int[85]; stackSize = 0; @@ -149,21 +149,21 @@ private static int MinRunLength(int total, int minRun) return total + r; } - /// - /// Reverse the specified range of the specified array. - /// - /// the array in which a range is to be reversed. - /// the index of the first element in the range to be reversed. - /// the index after the last element in the range to be reversed. - private static void ReverseRange(T[] array, int start, int end) - { - end--; - while (start < end) - { - var t = array[start]; - array[start++] = array[end]; - array[end--] = t; - } + /// + /// Reverse the specified range of the specified array. + /// + /// the array in which a range is to be reversed. + /// the index of the first element in the range to be reversed. + /// the index after the last element in the range to be reversed. + private static void ReverseRange(T[] array, int start, int end) + { + end--; + while (start < end) + { + var t = array[start]; + array[start++] = array[end]; + array[end--] = t; + } } /// @@ -175,18 +175,18 @@ private static void ReverseRange(T[] array, int start, int end) /// If a merge is required. private static bool NeedsMerge(TimChunk left, TimChunk right, ref int dest) { - right.Array[dest++] = right.Array[right.Index++]; + right.Array[dest++] = right.Array[right.Index++]; if (--right.Remaining == 0) - { - Array.Copy(left.Array, left.Index, right.Array, dest, left.Remaining); - return false; + { + Array.Copy(left.Array, left.Index, right.Array, dest, left.Remaining); + return false; } - + if (left.Remaining == 1) - { - Array.Copy(right.Array, right.Index, right.Array, dest, right.Remaining); - right.Array[dest + right.Remaining] = left.Array[left.Index]; - return false; + { + Array.Copy(right.Array, right.Index, right.Array, dest, right.Remaining); + right.Array[dest + right.Remaining] = left.Array[left.Index]; + return false; } return true; @@ -201,71 +201,71 @@ private static bool NeedsMerge(TimChunk left, TimChunk right, ref int dest private static void FinalizeMerge(TimChunk left, TimChunk right, int dest) { if (left.Remaining == 1) - { - Array.Copy(right.Array, right.Index, right.Array, dest, right.Remaining); - right.Array[dest + right.Remaining] = left.Array[left.Index]; + { + Array.Copy(right.Array, right.Index, right.Array, dest, right.Remaining); + right.Array[dest + right.Remaining] = left.Array[left.Index]; } else if (left.Remaining == 0) - { - throw new ArgumentException("Comparison method violates its general contract!"); + { + throw new ArgumentException("Comparison method violates its general contract!"); } else - { - Array.Copy(left.Array, left.Index, right.Array, dest, left.Remaining); + { + Array.Copy(left.Array, left.Index, right.Array, dest, left.Remaining); } } - /// - /// Returns the length of the run beginning at the specified position in - /// the specified array and reverses the run if it is descending (ensuring - /// that the run will always be ascending when the method returns). + /// + /// Returns the length of the run beginning at the specified position in + /// the specified array and reverses the run if it is descending (ensuring + /// that the run will always be ascending when the method returns). /// - /// A run is the longest ascending sequence with: + /// A run is the longest ascending sequence with: /// - /// + /// /// - /// or the longest descending sequence with: + /// or the longest descending sequence with: /// - /// a[lo + 1] > a[lo + 2] > ...]]> + /// a[lo + 1] > a[lo + 2] > ...]]> /// - /// For its intended use in a stable mergesort, the strictness of the - /// definition of "descending" is needed so that the call can safely - /// reverse a descending sequence without violating stability. - /// - /// the array in which a run is to be counted and possibly reversed. - /// index of the first element in the run. - /// the length of the run beginning at the specified position in the specified array. + /// For its intended use in a stable mergesort, the strictness of the + /// definition of "descending" is needed so that the call can safely + /// reverse a descending sequence without violating stability. + /// + /// the array in which a run is to be counted and possibly reversed. + /// index of the first element in the run. + /// the length of the run beginning at the specified position in the specified array. private int CountRunAndMakeAscending(T[] array, int start) - { - var runHi = start + 1; + { + var runHi = start + 1; if (runHi == array.Length) - { + { return 1; - } - - // Find end of run, and reverse range if descending + } + + // Find end of run, and reverse range if descending if (comparer.Compare(array[runHi++], array[start]) < 0) - { // Descending + { // Descending while (runHi < array.Length && comparer.Compare(array[runHi], array[runHi - 1]) < 0) - { + { runHi++; } - + ReverseRange(array, start, runHi); } else - { // Ascending + { // Ascending while (runHi < array.Length && comparer.Compare(array[runHi], array[runHi - 1]) >= 0) - { + { runHi++; - } - } - - return runHi - start; + } + } + + return runHi - start; } /// - /// Sorts the specified portion of the specified array using a binary + /// Sorts the specified portion of the specified array using a binary /// insertion sort. It requires O(n log n) compares, but O(n^2) data movement. /// /// Array to sort. @@ -334,25 +334,25 @@ private void MergeCollapse(T[] array) } } - private void MergeForceCollapse(T[] array) - { - while (stackSize > 1) - { - var n = stackSize - 2; + private void MergeForceCollapse(T[] array) + { + while (stackSize > 1) + { + var n = stackSize - 2; if (n > 0 && runLengths[n - 1] < runLengths[n + 1]) { n--; } - - MergeAt(array, n); - } + + MergeAt(array, n); + } } private void MergeAt(T[] array, int index) { - var baseA = runBase[index]; - var lenA = runLengths[index]; - var baseB = runBase[index + 1]; + var baseA = runBase[index]; + var lenA = runLengths[index]; + var baseB = runBase[index + 1]; var lenB = runLengths[index + 1]; runLengths[index] = lenA + lenB; @@ -386,45 +386,45 @@ private void MergeAt(T[] array, int index) } private void Merge(T[] array, int baseA, int lenA, int baseB, int lenB) - { - var endA = baseA + lenA; + { + var endA = baseA + lenA; var dest = baseA; - TimChunk left = new() - { - Array = array[baseA..endA], - Remaining = lenA, - }; - - TimChunk right = new() - { - Array = array, - Index = baseB, - Remaining = lenB, - }; - - // Move first element of the right chunk and deal with degenerate cases. + TimChunk left = new() + { + Array = array[baseA..endA], + Remaining = lenA, + }; + + TimChunk right = new() + { + Array = array, + Index = baseB, + Remaining = lenB, + }; + + // Move first element of the right chunk and deal with degenerate cases. if (!TimSorter.NeedsMerge(left, right, ref dest)) { // One of the chunks had 0-1 items in it, so no need to merge anything. return; } - + var gallop = minGallop; - + while (RunMerge(left, right, ref dest, ref gallop)) { // Penalize for leaving gallop mode gallop = gallop > 0 ? gallop + 2 - : 2; + : 2; } minGallop = gallop >= 1 ? gallop - : 1; - - FinalizeMerge(left, right, dest); + : 1; + + FinalizeMerge(left, right, dest); } private bool RunMerge(TimChunk left, TimChunk right, ref int dest, ref int gallop) @@ -531,16 +531,3 @@ private bool GallopMerge(TimChunk left, TimChunk right, ref int dest) return false; } } - -public class TimSorterSettings -{ - public int MinMerge { get; } - - public int MinGallop { get; } - - public TimSorterSettings(int minMerge = 32, int minGallop = 7) - { - MinMerge = minMerge; - MinGallop = minGallop; - } -} diff --git a/Algorithms/Sorters/Comparison/TimSorterSettings.cs b/Algorithms/Sorters/Comparison/TimSorterSettings.cs new file mode 100644 index 00000000..0f804fbd --- /dev/null +++ b/Algorithms/Sorters/Comparison/TimSorterSettings.cs @@ -0,0 +1,14 @@ +namespace Algorithms.Sorters.Comparison; + +public class TimSorterSettings +{ + public int MinMerge { get; } + + public int MinGallop { get; } + + public TimSorterSettings(int minMerge = 32, int minGallop = 7) + { + MinMerge = minMerge; + MinGallop = minGallop; + } +} diff --git a/Algorithms/Sorters/Utils/GallopingStrategy.cs b/Algorithms/Sorters/Utils/GallopingStrategy.cs index 2226064b..4c4ddc02 100644 --- a/Algorithms/Sorters/Utils/GallopingStrategy.cs +++ b/Algorithms/Sorters/Utils/GallopingStrategy.cs @@ -40,7 +40,7 @@ public static int BoundLeftShift(int shiftable) => (shiftable << 1) < 0 ? (shiftable << 1) + 1 : int.MaxValue; - private static (int offset, int lastOfs) LeftRun(T[] array, T key, int baseIndex, int hint, IComparer comparer) + private static (int Offset, int LastOfs) LeftRun(T[] array, T key, int baseIndex, int hint, IComparer comparer) { var maxOfs = hint + 1; var (offset, tmp) = (1, 0); @@ -62,7 +62,7 @@ private static (int offset, int lastOfs) LeftRun(T[] array, T key, int baseIndex return (offset, lastOfs); } - private static (int offset, int lastOfs) RightRun(T[] array, T key, int baseIndex, int len, int hint, IComparer comparer) + private static (int Offset, int LastOfs) RightRun(T[] array, T key, int baseIndex, int len, int hint, IComparer comparer) { var (offset, lastOfs) = (1, 0); var maxOfs = len - hint; diff --git a/Algorithms/Strings/Similarity/CosineSimilarity.cs b/Algorithms/Strings/Similarity/CosineSimilarity.cs index d05ee8c9..2975f793 100644 --- a/Algorithms/Strings/Similarity/CosineSimilarity.cs +++ b/Algorithms/Strings/Similarity/CosineSimilarity.cs @@ -21,8 +21,8 @@ public static double Calculate(string left, string right) // Step 1: Get the vectors for the two strings // Each vector represents the frequency of each character in the string. var vectors = GetVectors(left.ToLowerInvariant(), right.ToLowerInvariant()); - var leftVector = vectors.leftVector; - var rightVector = vectors.rightVector; + var leftVector = vectors.LeftVector; + var rightVector = vectors.RightVector; // Step 2: Calculate the intersection of the two vectors // The intersection is the set of characters that appear in both strings. @@ -64,7 +64,7 @@ public static double Calculate(string left, string right) /// The first string. /// The second string. /// A tuple containing the vectors for the two strings. - private static (Dictionary leftVector, Dictionary rightVector) GetVectors(string left, string right) + private static (Dictionary LeftVector, Dictionary RightVector) GetVectors(string left, string right) { var leftVector = new Dictionary(); var rightVector = new Dictionary(); diff --git a/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs b/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs index a00bdae6..4d699658 100644 --- a/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs +++ b/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs @@ -36,7 +36,7 @@ public static int Calculate(string left, string right) // Calculate the minimum distance by considering three possible operations: // deletion, insertion, and substitution. distances[i, j] = Math.Min( - Math.Min( // deletion + Math.Min(// deletion distances[i - 1, j] + 1, // delete the character from the left string distances[i, j - 1] + 1), // insert the character into the right string distances[i - 1, j - 1] + cost); // substitute the character in the left string with the character in the right string diff --git a/DataStructures/AATree/AATree.cs b/DataStructures/AATree/AATree.cs index f4322cbf..c2f2eeae 100644 --- a/DataStructures/AATree/AATree.cs +++ b/DataStructures/AATree/AATree.cs @@ -216,7 +216,7 @@ private AaTreeNode Add(TKey key, AaTreeNode? node) throw new ArgumentException($"Key \"{key}\" already in tree!", nameof(key)); } - return Split(Skew(node)) !; + return Split(Skew(node))!; } /// diff --git a/DataStructures/DataStructures.csproj b/DataStructures/DataStructures.csproj index 06f645a3..445adbf9 100644 --- a/DataStructures/DataStructures.csproj +++ b/DataStructures/DataStructures.csproj @@ -16,7 +16,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/DataStructures/Graph/DirectedWeightedGraph.cs b/DataStructures/Graph/DirectedWeightedGraph.cs index 15e0a336..666b9e48 100644 --- a/DataStructures/Graph/DirectedWeightedGraph.cs +++ b/DataStructures/Graph/DirectedWeightedGraph.cs @@ -94,7 +94,7 @@ public void RemoveVertex(Vertex vertex) for (int i = indexToRemove; i < Count - 1; i++) { Vertices[i] = Vertices[i + 1]; - Vertices[i] !.Index = i; + Vertices[i]!.Index = i; } Vertices[Count - 1] = null; diff --git a/DataStructures/Hashing/HashTable.cs b/DataStructures/Hashing/HashTable.cs index 05dde26a..8f6aac78 100644 --- a/DataStructures/Hashing/HashTable.cs +++ b/DataStructures/Hashing/HashTable.cs @@ -150,7 +150,7 @@ public void Add(TKey? key, TValue? value) var index = GetIndex(key); if ( entries[index] != null && - EqualityComparer.Default.Equals(entries[index] !.Key!, key)) + EqualityComparer.Default.Equals(entries[index]!.Key!, key)) { throw new ArgumentException("Key already exists"); } diff --git a/DataStructures/RedBlackTree/RedBlackTreeNode.cs b/DataStructures/RedBlackTree/RedBlackTreeNode.cs index 5c888b38..91f42df0 100644 --- a/DataStructures/RedBlackTree/RedBlackTreeNode.cs +++ b/DataStructures/RedBlackTree/RedBlackTreeNode.cs @@ -6,12 +6,12 @@ namespace DataStructures.RedBlackTree; public enum NodeColor : byte { /// - /// Represents red node + /// Represents red node. /// Red, /// - /// Represents black node + /// Represents black node. /// Black, } diff --git a/DataStructures/ScapegoatTree/ScapegoatTree.cs b/DataStructures/ScapegoatTree/ScapegoatTree.cs index a5262152..8f0a1b55 100644 --- a/DataStructures/ScapegoatTree/ScapegoatTree.cs +++ b/DataStructures/ScapegoatTree/ScapegoatTree.cs @@ -247,7 +247,7 @@ public void Tune(double value) /// Scapegoat node with its parent node. Parent can be null if scapegoat node is root node. /// Thrown if path stack is empty. /// Thrown if scapegoat wasn't found. - public (Node? parent, Node scapegoat) FindScapegoatInPath(Stack> path) + public (Node? Parent, Node Scapegoat) FindScapegoatInPath(Stack> path) { if (path.Count == 0) { diff --git a/Utilities/Extensions/DictionaryExtensions.cs b/Utilities/Extensions/DictionaryExtensions.cs index 03638290..3d040554 100644 --- a/Utilities/Extensions/DictionaryExtensions.cs +++ b/Utilities/Extensions/DictionaryExtensions.cs @@ -17,7 +17,7 @@ public static class DictionaryExtensions /// public static void AddMany( this Dictionary keys, - IEnumerable<(TKey, TValue)> enumerable) where TKey : notnull + IEnumerable<(TKey Key, TValue Value)> enumerable) where TKey : notnull { foreach (var (key, value) in enumerable) { diff --git a/Utilities/Utilities.csproj b/Utilities/Utilities.csproj index 8c289a07..01944c82 100644 --- a/Utilities/Utilities.csproj +++ b/Utilities/Utilities.csproj @@ -16,7 +16,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 7f6eed475e56867c76a4287d92c546bd659bb17d Mon Sep 17 00:00:00 2001 From: Kalafatis Kwstas Date: Mon, 21 Oct 2024 22:05:31 +0300 Subject: [PATCH 113/138] Add Ascon Hash Algorithm (#479) --- .../Crypto/Digests/AsconDigestTests.cs | 266 +++++++++ .../Crypto/Exceptions/CryptoExceptionTests.cs | 69 +++ .../Exceptions/DataLengthExceptionTests.cs | 67 +++ .../Exceptions/OutputLengthExceptionTests.cs | 67 +++ .../Crypto/Utils/ByteEncodingUtils.cs | 81 +++ .../Crypto/Utils/LongUtilsTests.cs | 98 ++++ .../Crypto/Utils/ValidationUtilsTests.cs | 124 ++++ Algorithms/Crypto/Digests/AsconDigest.cs | 538 ++++++++++++++++++ Algorithms/Crypto/Digests/IDigest.cs | 70 +++ .../Crypto/Exceptions/CryptoException.cs | 36 ++ .../Crypto/Exceptions/DataLengthException.cs | 36 ++ .../Exceptions/OutputLengthException.cs | 57 ++ Algorithms/Crypto/Utils/ByteEncodingUtils.cs | 63 ++ Algorithms/Crypto/Utils/LongUtils.cs | 78 +++ Algorithms/Crypto/Utils/ValidationUtils.cs | 95 ++++ README.md | 3 +- 16 files changed, 1747 insertions(+), 1 deletion(-) create mode 100644 Algorithms.Tests/Crypto/Digests/AsconDigestTests.cs create mode 100644 Algorithms.Tests/Crypto/Exceptions/CryptoExceptionTests.cs create mode 100644 Algorithms.Tests/Crypto/Exceptions/DataLengthExceptionTests.cs create mode 100644 Algorithms.Tests/Crypto/Exceptions/OutputLengthExceptionTests.cs create mode 100644 Algorithms.Tests/Crypto/Utils/ByteEncodingUtils.cs create mode 100644 Algorithms.Tests/Crypto/Utils/LongUtilsTests.cs create mode 100644 Algorithms.Tests/Crypto/Utils/ValidationUtilsTests.cs create mode 100644 Algorithms/Crypto/Digests/AsconDigest.cs create mode 100644 Algorithms/Crypto/Digests/IDigest.cs create mode 100644 Algorithms/Crypto/Exceptions/CryptoException.cs create mode 100644 Algorithms/Crypto/Exceptions/DataLengthException.cs create mode 100644 Algorithms/Crypto/Exceptions/OutputLengthException.cs create mode 100644 Algorithms/Crypto/Utils/ByteEncodingUtils.cs create mode 100644 Algorithms/Crypto/Utils/LongUtils.cs create mode 100644 Algorithms/Crypto/Utils/ValidationUtils.cs diff --git a/Algorithms.Tests/Crypto/Digests/AsconDigestTests.cs b/Algorithms.Tests/Crypto/Digests/AsconDigestTests.cs new file mode 100644 index 00000000..bd83f2dd --- /dev/null +++ b/Algorithms.Tests/Crypto/Digests/AsconDigestTests.cs @@ -0,0 +1,266 @@ +using System; +using System.Text; +using Algorithms.Crypto.Digests; +using Algorithms.Crypto.Exceptions; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Crypto.Digests; + +[NonParallelizable] +public class AsconDigestTests +{ + private readonly AsconDigest asconHash = new AsconDigest(AsconDigest.AsconParameters.AsconHash); + private readonly AsconDigest asconHashA = new AsconDigest(AsconDigest.AsconParameters.AsconHashA); + + [TestCase("a", "02a9d471afab12914197af7090f00d16c41b6e30be0a63bbfd00bc13064de548")] + [TestCase("abc", "d37fe9f1d10dbcfad8408a6804dbe91124a8912693322bb23ec1701e19e3fd51")] + [TestCase("Hello", "d80f38d94ad72bd18718879f753a44870e8446925ff64bd7441db5fe020b6c0c")] + [TestCase("message digest", "e8848979c5adfd21bfcf29e54be1dd085ee523d251e8e6876f2654d6368da0ca")] + [TestCase("abcdefghijklmnopqrstuvwxyz", "c62368674e1b2301f19f46c50bb7f87a988a3e41205d68ab9d7882d2a15e917b")] + [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "4ff71928d740524735b5ab12bb1598463054f88089f3c5f9760b6bdcd23f897b")] + [TestCase("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "2dae8b553b93841120e88ee77b9ccb8b512a32318db6012025f3f1c482b1def8")] + public void AsconHash_ReturnsCorrectValue(string input, string expected) + { + var inputBytes = Encoding.ASCII.GetBytes(input); + var result = asconHash.Digest(inputBytes); + + result.Should().Be(expected); + } + + [TestCase("a", "062bb0346671da00da4f460308b4d2c4d9877c3e2827d6229ff5361332d36527")] + [TestCase("abc", "836a5ddba0142b011ce3425ea9789fd6a21628d619195a48c1540f847667a84e")] + [TestCase("Hello", "15f245df8af697dc540e86083822809ab7299575d8ad6c2e17ecc603a7ab79dd")] + [TestCase("message digest", "3f18a1f398a40a77e0e9477aa6cb50e9e1abecff651c1874f9717c02c8a165ba")] + [TestCase("abcdefghijklmnopqrstuvwxyz", "406b809260f361e12dcf0bf924bfe1ffd2f987fc18d90b94fc544ff80dc2946b")] + [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "5c6c69ff3ee83361391b7236c8eb6718f52df43de5a61a4f4d2819d40430dc19")] + [TestCase("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "d8e38fc50d682550cd176decda61adb7fd1c793cdafa825f17f3a002d65847be")] + public void AsconHashA_ReturnsCorrectValue(string input, string expected) + { + var inputBytes = Encoding.ASCII.GetBytes(input); + var result = asconHashA.Digest(inputBytes); + + result.Should().Be(expected); + } + + [Test] + public void BlockUpdate_WithValidOffsetAndLength_ShouldProcessCorrectly() + { + // Arrange + var input = new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 }; + var offset = 2; + var length = 6; // Picking 6 bytes starting from offset 2 + + // Act + var act = () => asconHash.BlockUpdate(input, offset, length); + + // Assert + act.Should().NotThrow(); // Ensure no exceptions are thrown during processing + + // Finalize the hash and check the output size + var output = new byte[asconHash.GetDigestSize()]; + asconHash.DoFinal(output, 0); + output.Should().HaveCount(32); // Ascon hash size is 32 bytes + } + + [Test] + public void BlockUpdate_WithInvalidOffset_ShouldThrowDataLengthException() + { + // Arrange + var input = new byte[] { 0x00, 0x11, 0x22, 0x33 }; + var offset = 3; // Offset goes too close to the end + var length = 3; // Length would exceed buffer size + + // Act + var act = () => asconHash.BlockUpdate(input, offset, length); + + // Assert + act.Should().Throw() + .WithMessage("input buffer too short"); + } + + [Test] + public void BlockUpdate_WithInvalidLength_ShouldThrowDataLengthException() + { + // Arrange + var input = new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; + var offset = 1; // Valid offset + var length = 10; // Invalid length (exceeds buffer) + + // Act + var act = () => asconHash.BlockUpdate(input, offset, length); + + // Assert + act.Should().Throw() + .WithMessage("input buffer too short"); + } + + [Test] + public void BlockUpdate_WithPartialBlock_ShouldProcessCorrectly() + { + // Arrange + var input = new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44 }; + var offset = 0; + var length = 5; // Less than 8 bytes, partial block + + // Act + asconHash.BlockUpdate(input, offset, length); + + // Assert + var output = new byte[asconHash.GetDigestSize()]; + asconHash.DoFinal(output, 0); + output.Should().HaveCount(32); // Ensure valid hash output + } + + [Test] + public void BlockUpdate_WithFullBlock_ShouldProcessCorrectly() + { + // Arrange + var input = new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; + var offset = 0; + var length = 8; // Full block + + // Act + asconHash.BlockUpdate(input, offset, length); + + // Assert + var output = new byte[asconHash.GetDigestSize()]; + asconHash.DoFinal(output, 0); + output.Should().HaveCount(32); // Ensure valid hash output + } + + [Test] + public void BlockUpdate_MultipleCalls_ShouldProcessCorrectly() + { + // Arrange + var input1 = new byte[] { 0x00, 0x11, 0x22 }; + var input2 = new byte[] { 0x33, 0x44, 0x55, 0x66, 0x77 }; + + // Act + asconHash.BlockUpdate(input1, 0, input1.Length); + asconHash.BlockUpdate(input2, 0, input2.Length); + + // Assert + var output = new byte[asconHash.GetDigestSize()]; + asconHash.DoFinal(output, 0); + output.Should().HaveCount(32); // Ensure valid hash output + } + + [Test] + public void AsconHash_WhenGetNameIsCalled_ReturnsCorrectValue() + { + asconHash.AlgorithmName.Should().Be("Ascon-Hash"); + asconHashA.AlgorithmName.Should().Be("Ascon-HashA"); + } + + [Test] + public void AsconHash_WhenGetByteLengthIsCalled_ReturnsCorrectValue() + { + asconHash.GetByteLength().Should().Be(8); + } + + [Test] + public void Update_ShouldProcessByte_WhenBufferIsFull() + { + // Arrange + byte[] inputBytes = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; // 8 bytes to fill the buffer + + // Act + foreach (var input in inputBytes) + { + asconHashA.Update(input); + } + + // Assert + // Since the buffer is full after 8 updates, we expect the state to have been processed. + var output = new byte[asconHashA.GetDigestSize()]; + asconHashA.DoFinal(output, 0); + output.Should().HaveCount(32); // Ascon hash size is 32 bytes + } + + [Test] + public void Update_ShouldNotProcess_WhenBufferIsNotFull() + { + // Arrange + byte[] inputBytes = { 0x00, 0x11, 0x22, 0x33 }; // Only 4 bytes (buffer is not full) + + // Act + foreach (var input in inputBytes) + { + asconHashA.Update(input); + } + + // Assert + // Even though the buffer has received input, it should not process until it is full (8 bytes). + // We can check that DoFinal still completes, but the buffer has not been processed yet. + var output = new byte[asconHashA.GetDigestSize()]; + asconHashA.DoFinal(output, 0); + output.Should().HaveCount(32); // Ensure valid hash output + } + + [Test] + public void Update_ShouldProcessMultipleBlocks() + { + // Arrange + var inputBytes = new byte[16]; // Enough to fill two full blocks (16 bytes) + + // Act + foreach (var input in inputBytes) + { + asconHashA.Update(input); + } + + // Assert + // Ensure that the state is processed twice since 16 bytes were passed (2 blocks of 8 bytes). + var output = new byte[asconHashA.GetDigestSize()]; + asconHashA.DoFinal(output, 0); + output.Should().HaveCount(32); // Ensure valid hash output + } + + [Test] + public void Update_ShouldHandleSingleByteCorrectly() + { + // Arrange + byte input = 0xFF; // Single byte input + + // Act + asconHashA.Update(input); + + // Assert + // Even though one byte is provided, it should not process the state (waiting for 8 bytes). + var output = new byte[asconHashA.GetDigestSize()]; + asconHashA.DoFinal(output, 0); + output.Should().HaveCount(32); // Ensure valid hash output + } + + [Test] + public void Update_ShouldAccumulateStateWithMultipleUpdates() + { + // Arrange + byte[] inputBytes = { 0x00, 0x11, 0x22 }; // Partial input + + // Act + foreach (var input in inputBytes) + { + asconHashA.Update(input); + } + + // Add more data to fill the buffer. + byte[] additionalBytes = { 0x33, 0x44, 0x55, 0x66, 0x77 }; + foreach (var input in additionalBytes) + { + asconHashA.Update(input); + } + + // Assert + // Ensure that the state is correctly updated after multiple partial updates. + var output = new byte[asconHashA.GetDigestSize()]; + asconHashA.DoFinal(output, 0); + output.Should().HaveCount(32); // Ensure valid hash output + } + + private static string ToHexString(byte[] bytes) + { + return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant(); + } +} diff --git a/Algorithms.Tests/Crypto/Exceptions/CryptoExceptionTests.cs b/Algorithms.Tests/Crypto/Exceptions/CryptoExceptionTests.cs new file mode 100644 index 00000000..dc43c741 --- /dev/null +++ b/Algorithms.Tests/Crypto/Exceptions/CryptoExceptionTests.cs @@ -0,0 +1,69 @@ +using Algorithms.Crypto.Exceptions; +using NUnit.Framework; +using FluentAssertions; +using System; + + +namespace Algorithms.Tests.Crypto.Exceptions +{ + [TestFixture] + public class CryptoExceptionTests + { + [Test] + public void CryptoException_ShouldBeCreatedWithoutMessageOrInnerException() + { + // Act + var exception = new CryptoException(); + + // Assert + exception.Should().BeOfType() + .And.Subject.As() + .Message.Should().NotBeNullOrEmpty(); + exception.InnerException.Should().BeNull(); + } + + [Test] + public void CryptoException_ShouldSetMessage() + { + // Arrange + var expectedMessage = "This is a custom cryptographic error."; + + // Act + var exception = new CryptoException(expectedMessage); + + // Assert + exception.Should().BeOfType() + .And.Subject.As() + .Message.Should().Be(expectedMessage); + exception.InnerException.Should().BeNull(); + } + + [Test] + public void CryptoException_ShouldSetMessageAndInnerException() + { + // Arrange + var expectedMessage = "An error occurred during encryption."; + var innerException = new InvalidOperationException("Invalid operation"); + + // Act + var exception = new CryptoException(expectedMessage, innerException); + + // Assert + exception.Should().BeOfType() + .And.Subject.As() + .Message.Should().Be(expectedMessage); + exception.InnerException.Should().Be(innerException); + } + + [Test] + public void CryptoException_MessageShouldNotBeNullWhenUsingDefaultConstructor() + { + // Act + var exception = new CryptoException(); + + // Assert + exception.Message.Should().NotBeNullOrEmpty(); // Even the default Exception message is not null or empty. + } + } +} + diff --git a/Algorithms.Tests/Crypto/Exceptions/DataLengthExceptionTests.cs b/Algorithms.Tests/Crypto/Exceptions/DataLengthExceptionTests.cs new file mode 100644 index 00000000..e792d4cb --- /dev/null +++ b/Algorithms.Tests/Crypto/Exceptions/DataLengthExceptionTests.cs @@ -0,0 +1,67 @@ +using NUnit.Framework; +using FluentAssertions; +using System; +using Algorithms.Crypto.Exceptions; + +namespace Algorithms.Tests.Crypto.Exceptions +{ + [TestFixture] + public class DataLengthExceptionTests + { + [Test] + public void DataLengthException_ShouldBeCreatedWithoutMessageOrInnerException() + { + // Act + var exception = new DataLengthException(); + + // Assert + exception.Should().BeOfType() + .And.Subject.As() + .Message.Should().NotBeNullOrEmpty(); + exception.InnerException.Should().BeNull(); + } + + [Test] + public void DataLengthException_ShouldSetMessage() + { + // Arrange + var expectedMessage = "Data length is invalid."; + + // Act + var exception = new DataLengthException(expectedMessage); + + // Assert + exception.Should().BeOfType() + .And.Subject.As() + .Message.Should().Be(expectedMessage); + exception.InnerException.Should().BeNull(); + } + + [Test] + public void DataLengthException_ShouldSetMessageAndInnerException() + { + // Arrange + var expectedMessage = "An error occurred due to incorrect data length."; + var innerException = new ArgumentException("Invalid argument"); + + // Act + var exception = new DataLengthException(expectedMessage, innerException); + + // Assert + exception.Should().BeOfType() + .And.Subject.As() + .Message.Should().Be(expectedMessage); + exception.InnerException.Should().Be(innerException); + } + + [Test] + public void DataLengthException_MessageShouldNotBeNullWhenUsingDefaultConstructor() + { + // Act + var exception = new DataLengthException(); + + // Assert + exception.Message.Should().NotBeNullOrEmpty(); // Even the default Exception message is not null or empty. + } + } +} diff --git a/Algorithms.Tests/Crypto/Exceptions/OutputLengthExceptionTests.cs b/Algorithms.Tests/Crypto/Exceptions/OutputLengthExceptionTests.cs new file mode 100644 index 00000000..313b95ad --- /dev/null +++ b/Algorithms.Tests/Crypto/Exceptions/OutputLengthExceptionTests.cs @@ -0,0 +1,67 @@ +using NUnit.Framework; +using FluentAssertions; +using System; +using Algorithms.Crypto.Exceptions; + +namespace Algorithms.Tests.Crypto.Exceptions +{ + [TestFixture] + public class OutputLengthExceptionTests + { + [Test] + public void OutputLengthException_ShouldBeCreatedWithoutMessageOrInnerException() + { + // Act + var exception = new OutputLengthException(); + + // Assert + exception.Should().BeOfType() + .And.Subject.As() + .Message.Should().NotBeNullOrEmpty(); + exception.InnerException.Should().BeNull(); + } + + [Test] + public void OutputLengthException_ShouldSetMessage() + { + // Arrange + var expectedMessage = "Output buffer is too short."; + + // Act + var exception = new OutputLengthException(expectedMessage); + + // Assert + exception.Should().BeOfType() + .And.Subject.As() + .Message.Should().Be(expectedMessage); + exception.InnerException.Should().BeNull(); + } + + [Test] + public void OutputLengthException_ShouldSetMessageAndInnerException() + { + // Arrange + var expectedMessage = "Output length error."; + var innerException = new ArgumentException("Invalid argument"); + + // Act + var exception = new OutputLengthException(expectedMessage, innerException); + + // Assert + exception.Should().BeOfType() + .And.Subject.As() + .Message.Should().Be(expectedMessage); + exception.InnerException.Should().Be(innerException); + } + + [Test] + public void OutputLengthException_MessageShouldNotBeNullWhenUsingDefaultConstructor() + { + // Act + var exception = new OutputLengthException(); + + // Assert + exception.Message.Should().NotBeNullOrEmpty(); // Even the default Exception message is not null or empty. + } + } +} diff --git a/Algorithms.Tests/Crypto/Utils/ByteEncodingUtils.cs b/Algorithms.Tests/Crypto/Utils/ByteEncodingUtils.cs new file mode 100644 index 00000000..ef04168d --- /dev/null +++ b/Algorithms.Tests/Crypto/Utils/ByteEncodingUtils.cs @@ -0,0 +1,81 @@ +using NUnit.Framework; +using FluentAssertions; +using System; +using Algorithms.Crypto.Utils; + +namespace Algorithms.Tests.Crypto.Utils +{ + [TestFixture] + public class ByteEncodingUtilsTests + { + [Test] + public void BigEndianToUint64_ByteArray_ShouldConvertCorrectly() + { + // Arrange + byte[] input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; + var expected = 0x0123456789ABCDEFUL; + + // Act + var result = ByteEncodingUtils.BigEndianToUint64(input, 0); + + // Assert + result.Should().Be(expected); + } + + [Test] + public void BigEndianToUint64_ByteArray_WithOffset_ShouldConvertCorrectly() + { + // Arrange + byte[] input = { 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; + var expected = 0x0123456789ABCDEFUL; + + // Act + var result = ByteEncodingUtils.BigEndianToUint64(input, 2); + + // Assert + result.Should().Be(expected); + } + + [Test] + public void BigEndianToUint64_Span_ShouldConvertCorrectly() + { + // Arrange + Span input = stackalloc byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; + var expected = 0x0123456789ABCDEFUL; + + // Act + var result = ByteEncodingUtils.BigEndianToUint64(input); + + // Assert + result.Should().Be(expected); + } + + [Test] + public void UInt64ToBigEndian_ShouldWriteCorrectly() + { + // Arrange + var value = 0x0123456789ABCDEFUL; + Span output = stackalloc byte[8]; + byte[] expected = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; + + // Act + ByteEncodingUtils.UInt64ToBigEndian(value, output); + + // Assert + output.ToArray().Should().Equal(expected); + } + + [Test] + public void BigEndianToUint64_InvalidOffset_ShouldThrowException() + { + // Arrange + byte[] input = { 0x01, 0x23 }; + + // Act + Action act = () => ByteEncodingUtils.BigEndianToUint64(input, 1); + + // Assert + act.Should().Throw(); + } + } +} diff --git a/Algorithms.Tests/Crypto/Utils/LongUtilsTests.cs b/Algorithms.Tests/Crypto/Utils/LongUtilsTests.cs new file mode 100644 index 00000000..cc2029bc --- /dev/null +++ b/Algorithms.Tests/Crypto/Utils/LongUtilsTests.cs @@ -0,0 +1,98 @@ +using NUnit.Framework; +using FluentAssertions; +using Algorithms.Crypto.Utils; + +namespace Algorithms.Tests.Crypto.Utils +{ + [TestFixture] + public class LongUtilsTests + { + [Test] + public void RotateLeft_Long_ShouldRotateCorrectly() + { + // Arrange + var input = 0x0123456789ABCDEF; + var distance = 8; + var expected = 0x23456789ABCDEF01L; // The expected result is a signed long value. + + // Act + var result = LongUtils.RotateLeft(input, distance); + + // Assert + result.Should().Be(expected); + } + + [Test] + public void RotateLeft_Ulong_ShouldRotateCorrectly() + { + // Arrange + var input = 0x0123456789ABCDEFUL; + var distance = 8; + var expected = 0x23456789ABCDEF01UL; // The expected result is an unsigned ulong value. + + // Act + var result = LongUtils.RotateLeft(input, distance); + + // Assert + result.Should().Be(expected); + } + + [Test] + public void RotateRight_Long_ShouldRotateCorrectly() + { + // Arrange + var input = 0x0123456789ABCDEF; + var distance = 8; + var expected = unchecked((long)0xEF0123456789ABCD); // Using unchecked to correctly represent signed long. + + // Act + var result = LongUtils.RotateRight(input, distance); + + // Assert + result.Should().Be(expected); + } + + [Test] + public void RotateRight_Ulong_ShouldRotateCorrectly() + { + // Arrange + var input = 0x0123456789ABCDEFUL; + var distance = 8; + var expected = 0xEF0123456789ABCDUL; // The expected result is an unsigned ulong value. + + // Act + var result = LongUtils.RotateRight(input, distance); + + // Assert + result.Should().Be(expected); + } + + [Test] + public void RotateLeft_Long_ShouldHandleZeroRotation() + { + // Arrange + var input = 0x0123456789ABCDEF; + var distance = 0; + + // Act + var result = LongUtils.RotateLeft(input, distance); + + // Assert + result.Should().Be(input); // No rotation, result should be the same as input. + } + + [Test] + public void RotateRight_Ulong_ShouldHandleFullRotation() + { + // Arrange + var input = 0x0123456789ABCDEFUL; + var distance = 64; + + // Act + var result = LongUtils.RotateRight(input, distance); + + // Assert + result.Should().Be(input); // Full 64-bit rotation should result in the same value. + } + } +} diff --git a/Algorithms.Tests/Crypto/Utils/ValidationUtilsTests.cs b/Algorithms.Tests/Crypto/Utils/ValidationUtilsTests.cs new file mode 100644 index 00000000..f109fcda --- /dev/null +++ b/Algorithms.Tests/Crypto/Utils/ValidationUtilsTests.cs @@ -0,0 +1,124 @@ +using NUnit.Framework; +using FluentAssertions; +using System; +using Algorithms.Crypto.Utils; +using Algorithms.Crypto.Exceptions; + +namespace Algorithms.Tests.Crypto.Utils +{ + [TestFixture] + public class ValidationUtilsTests + { + [Test] + public void CheckDataLength_WithBufferOutOfBounds_ShouldThrowDataLengthException() + { + // Arrange + var buffer = new byte[5]; // A byte array of length 5 + var offset = 3; // Starting at index 3 + var length = 4; // Expecting to read 4 bytes (which will exceed the buffer size) + var errorMessage = "Buffer is too short"; + + // Act + var act = () => ValidationUtils.CheckDataLength(buffer, offset, length, errorMessage); + + // Assert + act.Should().Throw() + .WithMessage(errorMessage); + } + + [Test] + public void CheckOutputLength_WithCondition_ShouldThrowOutputLengthException() + { + // Arrange + var condition = true; + var errorMessage = "Output length is invalid"; + + // Act + var act = () => ValidationUtils.CheckOutputLength(condition, errorMessage); + + // Assert + act.Should().Throw() + .WithMessage(errorMessage); + } + + [Test] + public void CheckOutputLength_WithCondition_ShouldNotThrowOutputLengthException() + { + // Arrange + var condition = false; + var errorMessage = "Output length is invalid"; + + // Act + var act = () => ValidationUtils.CheckOutputLength(condition, errorMessage); + + // Assert + act.Should().NotThrow(); + } + + [Test] + public void CheckOutputLength_WithBufferOutOfBounds_ShouldThrowOutputLengthException() + { + // Arrange + var buffer = new byte[5]; + var offset = 3; + var length = 4; + var errorMessage = "Output buffer is too short"; + + // Act + var act = () => ValidationUtils.CheckOutputLength(buffer, offset, length, errorMessage); + + // Assert + act.Should().Throw() + .WithMessage(errorMessage); + } + + [Test] + public void CheckOutputLength_WithBProperBufferSize_ShouldThrowOutputLengthException() + { + // Arrange + var buffer = new byte[5]; + var offset = 0; + var length = 4; + var errorMessage = "Output buffer is too short"; + + // Act + var act = () => ValidationUtils.CheckOutputLength(buffer, offset, length, errorMessage); + + // Assert + act.Should().NotThrow(); + } + + [Test] + public void CheckOutputLength_SpanExceedsLimit_ShouldThrowOutputLengthException() + { + // Arrange + Span output = new byte[10]; + var outputLength = output.Length; + var maxLength = 5; + var errorMessage = "Output exceeds maximum length"; + + // Act + var act = () => ValidationUtils.CheckOutputLength(outputLength > maxLength, errorMessage); // Capture the length + + // Assert + act.Should().Throw() + .WithMessage(errorMessage); + } + + [Test] + public void CheckOutputLength_SpanDoesNotExceedLimit_ShouldThrowOutputLengthException() + { + // Arrange + Span output = new byte[10]; + var outputLength = output.Length; + var maxLength = 15; + var errorMessage = "Output exceeds maximum length"; + + // Act + var act = () => ValidationUtils.CheckOutputLength(outputLength > maxLength, errorMessage); // Capture the length + + // Assert + act.Should().NotThrow(); + } + } +} diff --git a/Algorithms/Crypto/Digests/AsconDigest.cs b/Algorithms/Crypto/Digests/AsconDigest.cs new file mode 100644 index 00000000..d6ec3c97 --- /dev/null +++ b/Algorithms/Crypto/Digests/AsconDigest.cs @@ -0,0 +1,538 @@ +using System; +using System.Runtime.CompilerServices; +using Algorithms.Crypto.Utils; + +namespace Algorithms.Crypto.Digests; + +/// +/// Implements the Ascon cryptographic hash algorithm, providing both the standard Ascon-Hash and the Ascon-HashA variants. +/// +/// +/// The class implements the Ascon hash function, a lightweight cryptographic algorithm designed for +/// resource-constrained environments such as IoT devices. It provides two variants: +/// +/// +/// +/// : The standard Ascon-Hash variant with 12 rounds of the permutation function for enhanced security. +/// +/// +/// +/// +/// : A performance-optimized variant with 8 rounds of the permutation function, offering a trade-off between security and performance. +/// +/// +/// +///
+/// The AsconDigest processes data in 8-byte blocks, accumulating input until a block is complete, at which point it applies +/// the permutation function to update the internal state. After all data has been processed, the hash value can be finalized +/// and retrieved. +///
+/// Ascon was designed to meet the requirements of lightweight cryptography, making it ideal for devices with limited computational power. +///
+public class AsconDigest : IDigest +{ + public enum AsconParameters + { + /// + /// Represents the Ascon Hash variant, the standard cryptographic hashing function of the Ascon family. + /// + /// + /// AsconHash is the primary hashing algorithm in the Ascon family. It is designed for efficiency and security + /// in resource-constrained environments, such as IoT devices, and provides high resistance to cryptanalytic attacks. + /// This variant uses 12 rounds of the permutation function for increased security. + /// + AsconHash, + + /// + /// Represents the Ascon HashA variant, an alternative variant of the Ascon hashing function with fewer permutation rounds. + /// + /// + /// AsconHashA is a variant of the Ascon hashing function that uses fewer rounds (8 rounds) of the permutation function, + /// trading off some security for improved performance in specific scenarios. It is still designed to be secure for many + /// applications, but it operates faster in environments where computational resources are limited. + /// + AsconHashA, + } + + /// + /// Specifies the Ascon variant being used (either Ascon-Hash or Ascon-HashA). This defines the cryptographic algorithm's behavior. + /// + private readonly AsconParameters asconParameters; + + /// + /// The number of permutation rounds applied in the Ascon cryptographic process. This is determined by the selected Ascon variant. + /// + private readonly int asconPbRounds; + + /// + /// Internal buffer that temporarily stores input data before it is processed in 8-byte blocks. The buffer is cleared after each block is processed. + /// + private readonly byte[] buffer = new byte[8]; + + /// + /// Internal state variable x0 used in the cryptographic permutation function. This is updated continuously as input data is processed. + /// + private ulong x0; + + /// + /// Internal state variable x1 used in the cryptographic permutation function. This, along with other state variables, is updated during each round. + /// + private ulong x1; + + /// + /// Internal state variable x2 used in the cryptographic permutation function. It helps track the evolving state of the digest. + /// + private ulong x2; + + /// + /// Internal state variable x3 used in the cryptographic permutation function, contributing to the mixing and non-linearity of the state. + /// + private ulong x3; + + /// + /// Internal state variable x4 used in the cryptographic permutation function. This, along with x0 to x3, ensures cryptographic security. + /// + private ulong x4; + + /// + /// Tracks the current position within the buffer array. When bufferPosition reaches 8, the buffer is processed and reset. + /// + private int bufferPosition; + + /// + /// Initializes a new instance of the class with the specified Ascon parameters. + /// + /// The Ascon variant to use, either or . + /// + /// This constructor sets up the digest by selecting the appropriate number of permutation rounds based on the Ascon variant. + /// + /// For , 12 permutation rounds are used. + /// For , 8 permutation rounds are used. + /// + /// If an unsupported parameter is provided, the constructor throws an to indicate that the parameter is invalid. + /// The internal state of the digest is then reset to prepare for processing input data. + /// + /// Thrown when an invalid parameter setting is provided for Ascon Hash. + public AsconDigest(AsconParameters parameters) + { + // Set the Ascon parameter (AsconHash or AsconHashA) for this instance. + asconParameters = parameters; + + // Determine the number of permutation rounds based on the Ascon variant. + asconPbRounds = parameters switch + { + AsconParameters.AsconHash => 12, // 12 rounds for Ascon-Hash variant. + AsconParameters.AsconHashA => 8, // 8 rounds for Ascon-HashA variant. + _ => throw new ArgumentException("Invalid parameter settings for Ascon Hash"), // Throw exception for invalid parameter. + }; + + // Reset the internal state to prepare for new input. + Reset(); + } + + /// + /// Gets the name of the cryptographic algorithm based on the selected Ascon parameter. + /// + /// + /// A string representing the name of the algorithm variant, either "Ascon-Hash" or "Ascon-HashA". + /// + /// + /// This property determines the algorithm name based on the selected Ascon variant when the instance was initialized. + /// It supports two variants: + /// + /// "Ascon-Hash" for the variant. + /// "Ascon-HashA" for the variant. + /// + /// If an unsupported or unknown parameter is used, the property throws an . + /// + /// Thrown if an unknown Ascon parameter is encountered. + public string AlgorithmName + { + get + { + return asconParameters switch + { + AsconParameters.AsconHash => "Ascon-Hash", // Return "Ascon-Hash" for AsconHash variant. + AsconParameters.AsconHashA => "Ascon-HashA", // Return "Ascon-HashA" for AsconHashA variant. + _ => throw new InvalidOperationException(), // Throw an exception for unknown Ascon parameters. + }; + } + } + + /// + /// Gets the size of the resulting hash produced by the digest, in bytes. + /// + /// The size of the hash, which is 32 bytes (256 bits) for this digest implementation. + /// + /// This method returns the fixed size of the hash output produced by the digest algorithm. In this implementation, + /// the digest produces a 256-bit hash, which corresponds to 32 bytes. This is typical for cryptographic hash functions + /// that aim to provide a high level of security by generating a large output size. + /// + public int GetDigestSize() => 32; + + /// + /// Gets the internal block size of the digest in bytes. + /// + /// The internal block size of the digest, which is 8 bytes (64 bits). + /// + /// This method returns the block size that the digest algorithm uses when processing input data. The input is processed + /// in chunks (blocks) of 8 bytes at a time. This block size determines how the input data is split and processed in multiple + /// steps before producing the final hash. + /// + public int GetByteLength() => 8; + + /// + /// Updates the cryptographic state by processing a single byte of input and adding it to the internal buffer. + /// + /// The byte to be added to the internal buffer and processed. + /// + /// This method collects input bytes in an internal buffer. Once the buffer is filled (reaching 8 bytes), the buffer is processed + /// by converting it into a 64-bit unsigned integer in big-endian format and XORing it with the internal state variable x0. + /// After processing the buffer, the permutation function is applied to mix the internal state, and the buffer position is reset to zero. + ///

+ /// If the buffer has not yet reached 8 bytes, the method simply adds the input byte to the buffer and waits for further input. + ///
+ public void Update(byte input) + { + // Add the input byte to the buffer. + buffer[bufferPosition] = input; + + // If the buffer is not full (less than 8 bytes), increment the buffer position and return early. + if (++bufferPosition != 8) + { + return; // Wait for more input to fill the buffer before processing. + } + + // Once the buffer is full (8 bytes), convert the buffer to a 64-bit integer (big-endian) and XOR it with the state. + x0 ^= ByteEncodingUtils.BigEndianToUint64(buffer, 0); + + // Apply the permutation function to mix the state. + P(asconPbRounds); + + // Reset the buffer position for the next block of input. + bufferPosition = 0; + } + + /// + /// Updates the cryptographic state by processing a segment of input data from a byte array, starting at a specified offset and length. + /// + /// The byte array containing the input data to be processed. + /// The offset in the input array where processing should begin. + /// The number of bytes from the input array to process. + /// + /// This method ensures that the input data is valid by checking the array length, starting from the provided offset, + /// and making sure it is long enough to accommodate the specified length. It then processes the data by converting + /// the relevant section of the byte array to a and delegating the actual block update to + /// the method for further processing. + /// + /// + /// Thrown if the input data is too short, starting from and for the length . + /// + public void BlockUpdate(byte[] input, int inOff, int inLen) + { + // Validate the input data to ensure there is enough data to process from the specified offset and length. + ValidationUtils.CheckDataLength(input, inOff, inLen, "input buffer too short"); + + // Convert the input byte array into a ReadOnlySpan and delegate the processing to the span-based method. + BlockUpdate(input.AsSpan(inOff, inLen)); + } + + /// + /// Processes the input data by updating the internal cryptographic state, handling both partial and full blocks. + /// + /// A read-only span of bytes representing the input data to be processed. + /// + /// This method processes the input data in chunks of 8 bytes. It manages the internal buffer to accumulate data + /// until there are enough bytes to process a full 8-byte block. When the buffer is full or enough input is provided, + /// it XORs the buffered data with the internal state variable x0 and applies the permutation function + /// to update the cryptographic state. + ///

+ /// If the input contains more than 8 bytes, the method continues to process full 8-byte blocks in a loop until + /// the input is exhausted. Any remaining bytes (less than 8) are stored in the internal buffer for future processing. + ///
+ public void BlockUpdate(ReadOnlySpan input) + { + // Calculate the number of available bytes left in the buffer before it reaches 8 bytes. + var available = 8 - bufferPosition; + + // If the input length is smaller than the remaining space in the buffer, copy the input into the buffer. + if (input.Length < available) + { + input.CopyTo(buffer.AsSpan(bufferPosition)); // Copy the small input into the buffer. + bufferPosition += input.Length; // Update the buffer position. + return; // Return early since we don't have enough data to process a full block. + } + + // If there is data in the buffer, but it isn't full, fill it and process the full 8-byte block. + if (bufferPosition > 0) + { + // Copy enough bytes from the input to complete the buffer. + input[..available].CopyTo(buffer.AsSpan(bufferPosition)); + + // XOR the full buffer with the internal state (x0) and apply the permutation. + x0 ^= ByteEncodingUtils.BigEndianToUint64(buffer); + P(asconPbRounds); // Apply the permutation rounds. + + // Update the input to exclude the bytes we've already processed from the buffer. + input = input[available..]; + } + + // Process full 8-byte blocks directly from the input. + while (input.Length >= 8) + { + // XOR the next 8-byte block from the input with the internal state and apply the permutation. + x0 ^= ByteEncodingUtils.BigEndianToUint64(input); + P(asconPbRounds); + + // Move to the next 8-byte chunk in the input. + input = input[8..]; + } + + // Copy any remaining bytes (less than 8) into the buffer to store for future processing. + input.CopyTo(buffer); + bufferPosition = input.Length; // Update the buffer position to reflect the remaining unprocessed data. + } + + /// + /// Finalizes the cryptographic hash computation, absorbing any remaining data, applying the final permutation, + /// and writing the resulting hash to the specified position in the provided output byte array. + /// + /// The byte array where the final 32-byte hash will be written. + /// The offset in the output array at which to start writing the hash. + /// The size of the hash (32 bytes). + /// + /// This method finalizes the hash computation by converting the output array to a and + /// calling the method. It provides flexibility in placing the result in an + /// existing byte array with a specified offset. + /// + /// Thrown if the output buffer is too small to hold the resulting hash. + public int DoFinal(byte[] output, int outOff) + { + // Call the Span-based DoFinal method with the output byte array and offset. + return DoFinal(output.AsSpan(outOff)); + } + + /// + /// Finalizes the cryptographic hash computation, absorbing any remaining data, applying the final permutation, and + /// writing the resulting hash to the provided output buffer. + /// + /// A span of bytes where the final 32-byte hash will be written. + /// The size of the hash (32 bytes). + /// + /// This method completes the hash computation by absorbing any remaining input data, applying the final permutation, + /// and extracting the state variables to produce the final hash. The method processes the state in 8-byte chunks, + /// writing the result into the output buffer in big-endian format. After the final permutation is applied, the internal + /// state is reset to prepare for a new hashing session. + /// + /// Thrown if the output buffer is too small to hold the resulting hash. + public int DoFinal(Span output) + { + // Validate that the output buffer is at least 32 bytes in length. + ValidationUtils.CheckOutputLength(output, 32, "output buffer too short"); + + // Absorb any remaining input and apply the final permutation. + AbsorbAndFinish(); + + // Convert the first part of the state (x0) to big-endian format and write it to the output. + ByteEncodingUtils.UInt64ToBigEndian(x0, output); + + // Loop to process the remaining parts of the internal state (x1, x2, etc.). + for (var i = 0; i < 3; ++i) + { + // Move to the next 8-byte segment in the output buffer. + output = output[8..]; + + // Apply the permutation rounds to mix the state. + P(asconPbRounds); + + // Convert the updated state variable (x0) to big-endian format and write it to the output. + ByteEncodingUtils.UInt64ToBigEndian(x0, output); + } + + // Reset the internal state for the next hash computation. + Reset(); + + // Return the size of the hash (32 bytes). + return 32; + } + + /// + /// Computes the cryptographic hash of the input byte array and returns the result as a lowercase hexadecimal string. + /// + /// The input byte array to be hashed. + /// A string containing the computed hash in lowercase hexadecimal format. + /// + /// This method takes a byte array as input, processes it to compute the Ascon hash, and returns the result as a hexadecimal string. + /// It internally converts the byte array to a and delegates the actual hashing to the + /// method. + /// + public string Digest(byte[] input) + { + return Digest(input.AsSpan()); + } + + /// + /// Computes the cryptographic hash of the input span of bytes and returns the result as a lowercase hexadecimal string. + /// + /// A span of bytes representing the input data to be hashed. + /// A string containing the computed hash in lowercase hexadecimal format. + /// + /// This method processes the input span using the Ascon cryptographic algorithm to compute the hash. It accumulates + /// the input, applies the necessary permutations and internal state updates, and finally produces a hash in the form + /// of a 32-byte array. The result is then converted into a lowercase hexadecimal string using . + /// + public string Digest(Span input) + { + // Update the internal state with the input data. + BlockUpdate(input); + + // Create an array to hold the final hash output (32 bytes). + var output = new byte[GetDigestSize()]; + + // Finalize the hash computation and store the result in the output array. + DoFinal(output, 0); + + // Convert the hash (byte array) to a lowercase hexadecimal string. + return BitConverter.ToString(output).Replace("-", string.Empty).ToLowerInvariant(); + } + + /// + /// Resets the internal state of the Ascon cryptographic hash algorithm to its initial state based on the selected variant. + /// + /// + /// This method clears the internal buffer and resets the buffer position to zero. Depending on the specified + /// Ascon variant ( or ), it also reinitializes + /// the internal state variables (x0, x1, x2, x3, x4) to their starting values. + ///

+ /// The reset is necessary to prepare the hash function for a new message. It ensures that previous messages do not + /// affect the new one and that the internal state is consistent with the algorithm’s specification for the selected variant. + ///
+ public void Reset() + { + // Clear the buffer to remove any leftover data from previous operations. + Array.Clear(buffer, 0, buffer.Length); + + // Reset the buffer position to zero to start processing fresh input. + bufferPosition = 0; + + // Initialize the internal state variables (x0, x1, x2, x3, x4) based on the selected Ascon variant. + switch (asconParameters) + { + // If using the AsconHashA variant, set the specific initial state values for x0 through x4. + case AsconParameters.AsconHashA: + x0 = 92044056785660070UL; + x1 = 8326807761760157607UL; + x2 = 3371194088139667532UL; + x3 = 15489749720654559101UL; + x4 = 11618234402860862855UL; + break; + + // If using the AsconHash variant, set the specific initial state values for x0 through x4. + case AsconParameters.AsconHash: + x0 = 17191252062196199485UL; + x1 = 10066134719181819906UL; + x2 = 13009371945472744034UL; + x3 = 4834782570098516968UL; + x4 = 3787428097924915520UL; + break; + + // If an unknown Ascon variant is encountered, throw an exception. + default: + throw new InvalidOperationException(); + } + } + + /// + /// Finalizes the absorption phase of the cryptographic hash by padding the buffer and applying the final permutation round. + /// + /// + /// This method is called when the input data has been fully absorbed into the internal state, and it needs to be finalized. + /// The buffer is padded with a specific value (0x80) to signify the end of the data, and the remaining portion of the buffer is + /// XORed with the internal state variable x0. After padding, the final permutation round is applied using 12 rounds of + /// the permutation function . This ensures the internal state is fully mixed and the cryptographic hash + /// is securely finalized. + /// + private void AbsorbAndFinish() + { + // Pad the buffer with 0x80 to indicate the end of the data. + buffer[bufferPosition] = 0x80; + + // XOR the buffer (after padding) with the internal state x0, but only the relevant portion of the buffer is considered. + // The (56 - (bufferPosition << 3)) shifts ensure that only the unprocessed part of the buffer is XORed into x0. + x0 ^= ByteEncodingUtils.BigEndianToUint64(buffer, 0) & (ulong.MaxValue << (56 - (bufferPosition << 3))); + + // Apply 12 rounds of the permutation function to fully mix and finalize the internal state. + P(12); + } + + /// + /// Executes the cryptographic permutation function by applying a sequence of rounds that transform the internal state variables. + /// + /// + /// The number of rounds to execute. If set to 12, additional rounds are performed with specific constants to enhance the security of the transformation. + /// + /// + /// In the Ascon cryptographic algorithm, the permutation function P transforms the internal state over multiple rounds. + /// This method applies a set of round constants, each of which alters the state variables (x0, x1, x2, x3, x4) differently, + /// ensuring that the transformation introduces non-linearity and diffusion, which are essential for cryptographic security. + ///

+ /// When is set to 12, the method first applies four unique round constants. + /// Afterward, it applies a fixed set of six additional constants regardless of the number of rounds. + ///
+ private void P(int numberOfRounds) + { + if (numberOfRounds == 12) + { + Round(0xf0UL); + Round(0xe1UL); + Round(0xd2UL); + Round(0xc3UL); + } + + Round(0xb4UL); + Round(0xa5UL); + + Round(0x96UL); + Round(0x87UL); + Round(0x78UL); + Round(0x69UL); + Round(0x5aUL); + Round(0x4bUL); + } + + /// + /// Executes a single round of the cryptographic permutation function, transforming the internal state + /// variables x0, x1, x2, x3, and x4 using XOR, AND, and NOT operations, along with circular bit rotations. + /// This function is designed to introduce diffusion and non-linearity into the state for cryptographic security. + /// + /// + /// A 64-bit unsigned integer constant that influences the round's transformation. Each round uses a unique value of this constant + /// to ensure that the transformation applied to the state differs for each round. + /// + /// + /// The Round function uses a series of bitwise operations (XOR, AND, NOT) and circular bit rotations to mix + /// the internal state. Each transformation step introduces non-linearity and ensures that small changes in the input or state + /// variables propagate widely across the internal state, enhancing the security of the cryptographic process. + ///

+ /// The round constant () plays a crucial role in altering the state at each round, ensuring + /// that each round contributes uniquely to the overall cryptographic transformation. Circular rotations are applied using + /// to spread bits throughout the 64-bit word. + ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Round(ulong circles) + { + // Step 1: Perform XOR and AND operations to mix inputs and state variables + var t0 = x0 ^ x1 ^ x2 ^ x3 ^ circles ^ (x1 & (x0 ^ x2 ^ x4 ^ circles)); + var t1 = x0 ^ x2 ^ x3 ^ x4 ^ circles ^ ((x1 ^ x2 ^ circles) & (x1 ^ x3)); + var t2 = x1 ^ x2 ^ x4 ^ circles ^ (x3 & x4); + var t3 = x0 ^ x1 ^ x2 ^ circles ^ (~x0 & (x3 ^ x4)); + var t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1); + + // Step 2: Apply circular right shifts and update the internal state variables + x0 = t0 ^ LongUtils.RotateRight(t0, 19) ^ LongUtils.RotateRight(t0, 28); + x1 = t1 ^ LongUtils.RotateRight(t1, 39) ^ LongUtils.RotateRight(t1, 61); + x2 = ~(t2 ^ LongUtils.RotateRight(t2, 1) ^ LongUtils.RotateRight(t2, 6)); + x3 = t3 ^ LongUtils.RotateRight(t3, 10) ^ LongUtils.RotateRight(t3, 17); + x4 = t4 ^ LongUtils.RotateRight(t4, 7) ^ LongUtils.RotateRight(t4, 41); + } +} diff --git a/Algorithms/Crypto/Digests/IDigest.cs b/Algorithms/Crypto/Digests/IDigest.cs new file mode 100644 index 00000000..0800f176 --- /dev/null +++ b/Algorithms/Crypto/Digests/IDigest.cs @@ -0,0 +1,70 @@ +using System; + +namespace Algorithms.Crypto.Digests; + +/// +/// Interface for message digest algorithms, providing methods to update, finalize, and reset the digest state. +/// +public interface IDigest +{ + /// + /// Gets the name of the digest algorithm (e.g., "SHA-256"). + /// + string AlgorithmName { get; } + + /// + /// Gets the size of the digest in bytes (e.g., 32 bytes for SHA-256). + /// + /// The size of the digest in bytes. + int GetDigestSize(); + + /// + /// Gets the byte length of the internal buffer used by the digest. + /// + /// The byte length of the internal buffer. + int GetByteLength(); + + /// + /// Updates the digest with a single byte of input data. + /// + /// The byte to add to the digest. + void Update(byte input); + + /// + /// Updates the digest with a portion of a byte array. + /// + /// The byte array containing the input data. + /// The offset within the array to start reading from. + /// The length of data to read from the array. + void BlockUpdate(byte[] input, int inOff, int inLen); + + /// + /// Updates the digest with a portion of input data from a of bytes. + /// + /// The containing the input data. + void BlockUpdate(ReadOnlySpan input); + + /// + /// Completes the digest calculation and stores the result in the specified byte array. + /// + /// The byte array to store the final digest. + /// The offset within the array to start writing the digest. + /// The number of bytes written to the output array. + int DoFinal(byte[] output, int outOff); + + /// + /// Completes the digest calculation and stores the result in the specified of bytes. + /// + /// The to store the final digest. + /// The number of bytes written to the output span. + int DoFinal(Span output); + + string Digest(byte[] input); + + string Digest(Span input); + + /// + /// Resets the digest to its initial state, clearing all data accumulated so far. + /// + void Reset(); +} diff --git a/Algorithms/Crypto/Exceptions/CryptoException.cs b/Algorithms/Crypto/Exceptions/CryptoException.cs new file mode 100644 index 00000000..44b3bbd7 --- /dev/null +++ b/Algorithms/Crypto/Exceptions/CryptoException.cs @@ -0,0 +1,36 @@ +using System; + +namespace Algorithms.Crypto.Exceptions; + +/// +/// Represents errors that occur during cryptographic operations. +/// +public class CryptoException : Exception +{ + /// + /// Initializes a new instance of the class. + /// + public CryptoException() + { + } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The message that describes the error. + public CryptoException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with a specified error message + /// and a reference to the inner exception that is the cause of this exception. + /// + /// The message that describes the error. + /// The exception that is the cause of the current exception. + public CryptoException(string message, Exception inner) + : base(message, inner) + { + } +} diff --git a/Algorithms/Crypto/Exceptions/DataLengthException.cs b/Algorithms/Crypto/Exceptions/DataLengthException.cs new file mode 100644 index 00000000..f96e2a7f --- /dev/null +++ b/Algorithms/Crypto/Exceptions/DataLengthException.cs @@ -0,0 +1,36 @@ +using System; + +namespace Algorithms.Crypto.Exceptions; + +/// +/// Represents errors that occur when the length of data in a cryptographic operation is invalid or incorrect. +/// +public class DataLengthException : CryptoException +{ + /// + /// Initializes a new instance of the class. + /// + public DataLengthException() + { + } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The message that describes the error. + public DataLengthException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with a specified error message + /// and a reference to the inner exception that is the cause of this exception. + /// + /// The message that describes the error. + /// The exception that is the cause of the current exception. + public DataLengthException(string message, Exception inner) + : base(message, inner) + { + } +} diff --git a/Algorithms/Crypto/Exceptions/OutputLengthException.cs b/Algorithms/Crypto/Exceptions/OutputLengthException.cs new file mode 100644 index 00000000..1e295fc4 --- /dev/null +++ b/Algorithms/Crypto/Exceptions/OutputLengthException.cs @@ -0,0 +1,57 @@ +using System; + +namespace Algorithms.Crypto.Exceptions; + +/// +/// Represents an exception that is thrown when the output buffer length is insufficient for a cryptographic operation. +/// +/// +/// The is a specific subclass of . It is used in cryptographic +/// operations to signal that the provided output buffer does not have enough space to store the required output. This exception is +/// typically thrown when encryption, hashing, or other cryptographic operations require more space than what has been allocated in +/// the output buffer. +///
+/// This exception provides constructors for creating the exception with a custom message, an inner exception, or both. By inheriting +/// from , it can be handled similarly in cases where both input and output length issues may arise. +///
+public class OutputLengthException : DataLengthException +{ + /// + /// Initializes a new instance of the class. + /// + /// + /// This constructor initializes a new instance of the class without any additional message or inner exception. + /// It is commonly used when a generic output length issue needs to be raised without specific details. + /// + public OutputLengthException() + { + } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The message that describes the error. + /// + /// This constructor allows for a custom error message to be provided, giving more detail about the specific issue with the output length. + /// + public OutputLengthException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with a specified error message + /// and a reference to the inner exception that is the cause of this exception. + /// + /// The message that describes the error. + /// The exception that is the cause of the current exception. + /// + /// This constructor allows for both a custom message and an inner exception, which can be useful for propagating + /// the underlying cause of the error. For example, if the output buffer length is too short due to incorrect calculations, + /// the root cause (e.g., an ) can be passed in as the inner exception. + /// + public OutputLengthException(string message, Exception inner) + : base(message, inner) + { + } +} diff --git a/Algorithms/Crypto/Utils/ByteEncodingUtils.cs b/Algorithms/Crypto/Utils/ByteEncodingUtils.cs new file mode 100644 index 00000000..479d2508 --- /dev/null +++ b/Algorithms/Crypto/Utils/ByteEncodingUtils.cs @@ -0,0 +1,63 @@ +using System; +using System.Buffers.Binary; +using System.Runtime.CompilerServices; + +namespace Algorithms.Crypto.Utils; + +/// +/// Provides utility methods for converting between byte arrays and 64-bit unsigned integers using big-endian byte order. +/// +/// +/// The class contains static methods that assist in reading and writing 64-bit unsigned integers +/// from and to byte arrays or spans in big-endian format. These methods are optimized for cryptographic operations where byte +/// encoding is critical for consistency and security. +/// +public static class ByteEncodingUtils +{ + /// + /// Converts an 8-byte segment from a byte array (starting at the specified offset) into a 64-bit unsigned integer using big-endian format. + /// + /// The byte array containing the input data. + /// The offset within the byte array to start reading from. + /// A 64-bit unsigned integer representing the big-endian interpretation of the byte array segment. + /// Thrown if the specified offset is out of range of the byte array. + /// + /// This method reads 8 bytes from the specified offset within the byte array and converts them to a 64-bit unsigned integer + /// in big-endian format. Big-endian format stores the most significant byte first, followed by the less significant bytes. + /// + public static ulong BigEndianToUint64(byte[] byteStream, int offset) + { + return BinaryPrimitives.ReadUInt64BigEndian(byteStream.AsSpan(offset)); + } + + /// + /// Converts a read-only span of bytes into a 64-bit unsigned integer using big-endian format. + /// + /// A read-only span containing the input data. + /// A 64-bit unsigned integer representing the big-endian interpretation of the span of bytes. + /// + /// This method is optimized for performance using the attribute to encourage + /// inlining by the compiler. It reads exactly 8 bytes from the input span and converts them into a 64-bit unsigned integer. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong BigEndianToUint64(ReadOnlySpan byteStream) + { + return BinaryPrimitives.ReadUInt64BigEndian(byteStream); + } + + /// + /// Writes a 64-bit unsigned integer to a span of bytes using big-endian format. + /// + /// The 64-bit unsigned integer to write. + /// The span of bytes where the value will be written. + /// + /// This method writes the 64-bit unsigned integer into the span in big-endian format, where the most significant byte is written first. + /// The method is optimized using the attribute to improve performance in scenarios + /// where frequent byte-to-integer conversions are required, such as cryptographic algorithms. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void UInt64ToBigEndian(ulong value, Span byteStream) + { + BinaryPrimitives.WriteUInt64BigEndian(byteStream, value); + } +} diff --git a/Algorithms/Crypto/Utils/LongUtils.cs b/Algorithms/Crypto/Utils/LongUtils.cs new file mode 100644 index 00000000..60f266f8 --- /dev/null +++ b/Algorithms/Crypto/Utils/LongUtils.cs @@ -0,0 +1,78 @@ +using System.Numerics; + +namespace Algorithms.Crypto.Utils; + +/// +/// Provides utility methods for performing bitwise rotation operations (left and right) on 64-bit integers. +/// +/// +/// The class contains methods to rotate 64-bit signed and unsigned integers to the left or right. +/// These rotations are crucial in various cryptographic algorithms, where circular shifts are used to mix data and +/// introduce non-linearity. The methods use the underlying for efficient, +/// hardware-supported bitwise rotations. +/// +public static class LongUtils +{ + /// + /// Rotates the bits of a 64-bit signed integer to the left by a specified number of bits. + /// + /// The 64-bit signed integer to rotate. + /// The number of bits to rotate the integer to the left. + /// The result of rotating the integer to the left by the specified distance. + /// + /// This method uses the underlying method, converting the signed integer to an unsigned integer + /// for the rotation, then casting it back to a signed integer. The rotation is performed in a circular manner, where bits shifted + /// out of the most significant bit are reintroduced into the least significant bit. + /// + public static long RotateLeft(long i, int distance) + { + return (long)BitOperations.RotateLeft((ulong)i, distance); + } + + /// + /// Rotates the bits of a 64-bit unsigned integer to the left by a specified number of bits. + /// + /// The 64-bit unsigned integer to rotate. + /// The number of bits to rotate the integer to the left. + /// The result of rotating the integer to the left by the specified distance. + /// + /// The rotation is performed circularly, meaning bits shifted out of the most significant bit are reintroduced into + /// the least significant bit. This method is optimized for performance using hardware-supported operations through + /// . + /// + public static ulong RotateLeft(ulong i, int distance) + { + return BitOperations.RotateLeft(i, distance); + } + + /// + /// Rotates the bits of a 64-bit signed integer to the right by a specified number of bits. + /// + /// The 64-bit signed integer to rotate. + /// The number of bits to rotate the integer to the right. + /// The result of rotating the integer to the right by the specified distance. + /// + /// Similar to the left rotation, this method uses to perform the rotation. + /// The signed integer is cast to an unsigned integer for the operation and cast back to a signed integer afterward. + /// The rotation wraps bits shifted out of the least significant bit into the most significant bit. + /// + public static long RotateRight(long i, int distance) + { + return (long)BitOperations.RotateRight((ulong)i, distance); + } + + /// + /// Rotates the bits of a 64-bit unsigned integer to the right by a specified number of bits. + /// + /// The 64-bit unsigned integer to rotate. + /// The number of bits to rotate the integer to the right. + /// The result of rotating the integer to the right by the specified distance. + /// + /// This method performs the rotation circularly, where bits shifted out of the least significant bit are reintroduced + /// into the most significant bit. The operation uses hardware-supported instructions via . + /// + public static ulong RotateRight(ulong i, int distance) + { + return BitOperations.RotateRight(i, distance); + } +} diff --git a/Algorithms/Crypto/Utils/ValidationUtils.cs b/Algorithms/Crypto/Utils/ValidationUtils.cs new file mode 100644 index 00000000..88931dfa --- /dev/null +++ b/Algorithms/Crypto/Utils/ValidationUtils.cs @@ -0,0 +1,95 @@ +using System; +using System.Diagnostics; +using Algorithms.Crypto.Exceptions; + +namespace Algorithms.Crypto.Utils; + +/// +/// Provides utility methods for validating the lengths of input and output data in cryptographic operations. +/// +/// +/// The class contains static methods to validate the length and position of data buffers used in +/// cryptographic operations. These methods throw appropriate exceptions such as or +/// when the validation fails. These are critical for ensuring that cryptographic computations +/// do not run into buffer overflows, underflows, or incorrect input/output buffer lengths. +/// +public static class ValidationUtils +{ + /// + /// Validates that the specified offset and length fit within the bounds of the given buffer. + /// + /// The byte array to validate. + /// The offset into the byte array where validation should start. + /// The number of bytes to validate from the specified offset. + /// The message that describes the error if the exception is thrown. + /// Thrown if the offset and length exceed the bounds of the buffer. + /// + /// This method ensures that the specified offset and length fit within the bounds of the buffer. If the offset and length + /// go out of bounds, a is thrown with the provided error message. + /// + public static void CheckDataLength(byte[] buffer, int offset, int length, string message) + { + if (offset > (buffer.Length - length)) + { + throw new DataLengthException(message); + } + } + + /// + /// Throws an if the specified condition is true. + /// + /// A boolean condition indicating whether the exception should be thrown. + /// The message that describes the error if the exception is thrown. + /// Thrown if the condition is true. + /// + /// This method performs a simple conditional check for output length validation. If the condition is true, an + /// is thrown with the provided message. + /// + public static void CheckOutputLength(bool condition, string message) + { + if (condition) + { + throw new OutputLengthException(message); + } + } + + /// + /// Validates that the specified offset and length fit within the bounds of the output buffer. + /// + /// The byte array to validate. + /// The offset into the byte array where validation should start. + /// The number of bytes to validate from the specified offset. + /// The message that describes the error if the exception is thrown. + /// Thrown if the offset and length exceed the bounds of the buffer. + /// + /// This method ensures that the specified offset and length do not exceed the bounds of the output buffer. If the + /// validation fails, an is thrown with the provided message. + /// + public static void CheckOutputLength(byte[] buffer, int offset, int length, string message) + { + if (offset > (buffer.Length - length)) + { + throw new OutputLengthException(message); + } + } + + /// + /// Validates that the length of the output span does not exceed the specified length. + /// + /// The type of elements in the span. + /// The span to validate. + /// The maximum allowed length for the output span. + /// The message that describes the error if the exception is thrown. + /// Thrown if the length of the output span exceeds the specified length. + /// + /// This method checks that the span does not exceed the specified length. If the span length exceeds the allowed length, + /// an is thrown with the provided error message. + /// + public static void CheckOutputLength(Span output, int length, string message) + { + if (output.Length > length) + { + throw new OutputLengthException(message); + } + } +} diff --git a/README.md b/README.md index f13516de..93e048d2 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ find more than one implementation for the same objective but using different alg * [TBC Padding](./Algorithms/Crypto/Paddings/TbcPadding.cs) * [PKCS7 Padding](./Algorithms/Crypto/Paddings/Pkcs7Padding.cs) * [Digests](./Algorithms/Crypto/Digests/) + * [Ascon Hash Digest](./Algorithms/Crypto/Digests/AsconDigest.cs) * [MD2 Digest](./Algorithms/Crypto/Digests/Md2Digest.cs) * [Data Compression](./Algorithms/DataCompression) * [Burrows-Wheeler transform](./Algorithms/DataCompression/BurrowsWheelerTransform.cs) @@ -66,7 +67,7 @@ find more than one implementation for the same objective but using different alg * [Extended Euclidean Algorithm](./Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs) * [Modular Multiplicative Inverse](./Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs) * [Numeric](./Algorithms/Numeric) - * [Absolute](./Algorithms/Numeric/Abs.cs) + * [Absolute](./Algorithms/Numeric/Abs.cs) * [Aliquot Sum Calculator](./Algorithms/Numeric/AliquotSumCalculator.cs) * [Amicable Numbers Checker](./Algorithms/Numeric/AmicableNumbersChecker.cs) * [Decomposition](./Algorithms/Numeric/Decomposition) From fe93f5767d094f408cf4b0b7606fa83ef17f8392 Mon Sep 17 00:00:00 2001 From: Duc Nguyen Thanh <58723762+ngtduc693@users.noreply.github.com> Date: Wed, 23 Oct 2024 12:42:39 +0700 Subject: [PATCH 114/138] Add User-Based Collaborative Filtering (#483) --- Algorithms.Tests/Algorithms.Tests.csproj | 1 + .../CollaborativeFilteringTests.cs | 95 +++++++++++++++++++ .../CollaborativeFiltering.cs | 89 +++++++++++++++++ .../ISimilarityCalculator.cs | 13 +++ README.md | 2 + 5 files changed, 200 insertions(+) create mode 100644 Algorithms.Tests/RecommenderSystem/CollaborativeFilteringTests.cs create mode 100644 Algorithms/RecommenderSystem/CollaborativeFiltering.cs create mode 100644 Algorithms/RecommenderSystem/ISimilarityCalculator.cs diff --git a/Algorithms.Tests/Algorithms.Tests.csproj b/Algorithms.Tests/Algorithms.Tests.csproj index 893564d8..d6d63755 100644 --- a/Algorithms.Tests/Algorithms.Tests.csproj +++ b/Algorithms.Tests/Algorithms.Tests.csproj @@ -20,6 +20,7 @@
+
diff --git a/Algorithms.Tests/RecommenderSystem/CollaborativeFilteringTests.cs b/Algorithms.Tests/RecommenderSystem/CollaborativeFilteringTests.cs new file mode 100644 index 00000000..208de6fb --- /dev/null +++ b/Algorithms.Tests/RecommenderSystem/CollaborativeFilteringTests.cs @@ -0,0 +1,95 @@ +using Algorithms.RecommenderSystem; +using Moq; +using NUnit.Framework; +using System.Collections.Generic; + +namespace Algorithms.Tests.RecommenderSystem +{ + [TestFixture] + public class CollaborativeFilteringTests + { + private Mock? mockSimilarityCalculator; + private CollaborativeFiltering? recommender; + private Dictionary> testRatings = null!; + + [SetUp] + public void Setup() + { + mockSimilarityCalculator = new Mock(); + recommender = new CollaborativeFiltering(mockSimilarityCalculator.Object); + + testRatings = new Dictionary> + { + ["user1"] = new() + { + ["item1"] = 5.0, + ["item2"] = 3.0, + ["item3"] = 4.0 + }, + ["user2"] = new() + { + ["item1"] = 4.0, + ["item2"] = 2.0, + ["item3"] = 5.0 + }, + ["user3"] = new() + { + ["item1"] = 3.0, + ["item2"] = 4.0, + ["item4"] = 3.0 + } + }; + } + + [Test] + [TestCase("item1", 4.0, 5.0)] + [TestCase("item2", 2.0, 4.0)] + public void CalculateSimilarity_WithValidInputs_ReturnsExpectedResults( + string commonItem, + double rating1, + double rating2) + { + var user1Ratings = new Dictionary { [commonItem] = rating1 }; + var user2Ratings = new Dictionary { [commonItem] = rating2 }; + + var similarity = recommender?.CalculateSimilarity(user1Ratings, user2Ratings); + + Assert.That(similarity, Is.InRange(-1.0, 1.0)); + } + + [Test] + public void CalculateSimilarity_WithNoCommonItems_ReturnsZero() + { + var user1Ratings = new Dictionary { ["item1"] = 5.0 }; + var user2Ratings = new Dictionary { ["item2"] = 4.0 }; + + var similarity = recommender?.CalculateSimilarity(user1Ratings, user2Ratings); + + Assert.That(similarity, Is.EqualTo(0)); + } + + [Test] + public void PredictRating_WithNonexistentItem_ReturnsZero() + { + var predictedRating = recommender?.PredictRating("nonexistentItem", "user1", testRatings); + + Assert.That(predictedRating, Is.EqualTo(0)); + } + + [Test] + public void PredictRating_WithOtherUserHavingRatedTargetItem_ShouldCalculateSimilarityAndWeightedSum() + { + var targetItem = "item1"; + var targetUser = "user1"; + + mockSimilarityCalculator? + .Setup(s => s.CalculateSimilarity(It.IsAny>(), It.IsAny>())) + .Returns(0.8); + + var predictedRating = recommender?.PredictRating(targetItem, targetUser, testRatings); + + Assert.That(predictedRating, Is.Not.EqualTo(0.0d)); + Assert.That(predictedRating, Is.EqualTo(3.5d).Within(0.01)); + } + } +} diff --git a/Algorithms/RecommenderSystem/CollaborativeFiltering.cs b/Algorithms/RecommenderSystem/CollaborativeFiltering.cs new file mode 100644 index 00000000..8da58b8a --- /dev/null +++ b/Algorithms/RecommenderSystem/CollaborativeFiltering.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Algorithms.RecommenderSystem +{ + public class CollaborativeFiltering + { + private readonly ISimilarityCalculator similarityCalculator; + + public CollaborativeFiltering(ISimilarityCalculator similarityCalculator) + { + this.similarityCalculator = similarityCalculator; + } + + /// + /// Method to calculate similarity between two users using Pearson correlation. + /// + /// Rating of User 1. + /// Rating of User 2. + /// double value to reflect the index of similarity between two users. + public double CalculateSimilarity(Dictionary user1Ratings, Dictionary user2Ratings) + { + var commonItems = user1Ratings.Keys.Intersect(user2Ratings.Keys).ToList(); + if (commonItems.Count == 0) + { + return 0; + } + + var user1Scores = commonItems.Select(item => user1Ratings[item]).ToArray(); + var user2Scores = commonItems.Select(item => user2Ratings[item]).ToArray(); + + var avgUser1 = user1Scores.Average(); + var avgUser2 = user2Scores.Average(); + + double numerator = 0; + double sumSquare1 = 0; + double sumSquare2 = 0; + double epsilon = 1e-10; + + for (var i = 0; i < commonItems.Count; i++) + { + var diff1 = user1Scores[i] - avgUser1; + var diff2 = user2Scores[i] - avgUser2; + + numerator += diff1 * diff2; + sumSquare1 += diff1 * diff1; + sumSquare2 += diff2 * diff2; + } + + var denominator = Math.Sqrt(sumSquare1 * sumSquare2); + return Math.Abs(denominator) < epsilon ? 0 : numerator / denominator; + } + + /// + /// Predict a rating for a specific item by a target user. + /// + /// The item for which the rating needs to be predicted. + /// The user for whom the rating is being predicted. + /// + /// A dictionary containing user ratings where: + /// - The key is the user's identifier (string). + /// - The value is another dictionary where the key is the item identifier (string), and the value is the rating given by the user (double). + /// + /// The predicted rating for the target item by the target user. + /// If there is insufficient data to predict a rating, the method returns 0. + /// + public double PredictRating(string targetItem, string targetUser, Dictionary> ratings) + { + var targetUserRatings = ratings[targetUser]; + double totalSimilarity = 0; + double weightedSum = 0; + double epsilon = 1e-10; + + foreach (var otherUser in ratings.Keys.Where(u => u != targetUser)) + { + var otherUserRatings = ratings[otherUser]; + if (otherUserRatings.ContainsKey(targetItem)) + { + var similarity = similarityCalculator.CalculateSimilarity(targetUserRatings, otherUserRatings); + totalSimilarity += Math.Abs(similarity); + weightedSum += similarity * otherUserRatings[targetItem]; + } + } + + return Math.Abs(totalSimilarity) < epsilon ? 0 : weightedSum / totalSimilarity; + } + } +} diff --git a/Algorithms/RecommenderSystem/ISimilarityCalculator.cs b/Algorithms/RecommenderSystem/ISimilarityCalculator.cs new file mode 100644 index 00000000..e055a3c7 --- /dev/null +++ b/Algorithms/RecommenderSystem/ISimilarityCalculator.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.RecommenderSystem +{ + public interface ISimilarityCalculator + { + double CalculateSimilarity(Dictionary user1Ratings, Dictionary user2Ratings); + } +} diff --git a/README.md b/README.md index 93e048d2..f67c4356 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,8 @@ find more than one implementation for the same objective but using different alg * [Josephus Problem](./Algorithms/Numeric/JosephusProblem.cs) * [Newton's Square Root Calculation](./Algorithms/NewtonSquareRoot.cs) * [SoftMax Function](./Algorithms/Numeric/SoftMax.cs) + * [RecommenderSystem](./Algorithms/RecommenderSystem) + * [CollaborativeFiltering](./Algorithms/RecommenderSystem/CollaborativeFiltering) * [Searches](./Algorithms/Search) * [A-Star](./Algorithms/Search/AStar/) * [Binary Search](./Algorithms/Search/BinarySearcher.cs) From bd2d09d1b7078883a901890e3387c689eb4340e2 Mon Sep 17 00:00:00 2001 From: Thiago Rocha <62914339+thiagohpr@users.noreply.github.com> Date: Wed, 23 Oct 2024 08:12:21 -0300 Subject: [PATCH 115/138] Add addition without + operator(#482) --- .../AdditionWithoutArithmeticsTests.cs | 23 +++++++++++++++ .../Numeric/AdditionWithoutArithmetic.cs | 28 +++++++++++++++++++ README.md | 3 +- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 Algorithms.Tests/Numeric/AdditionWithoutArithmeticsTests.cs create mode 100644 Algorithms/Numeric/AdditionWithoutArithmetic.cs diff --git a/Algorithms.Tests/Numeric/AdditionWithoutArithmeticsTests.cs b/Algorithms.Tests/Numeric/AdditionWithoutArithmeticsTests.cs new file mode 100644 index 00000000..a9eec6b1 --- /dev/null +++ b/Algorithms.Tests/Numeric/AdditionWithoutArithmeticsTests.cs @@ -0,0 +1,23 @@ +using System; +using System.Numerics; +using Algorithms.Numeric; +using NUnit.Framework; + +namespace Algorithms.Tests.Numeric; + +public static class AdditionWithoutArithmeticTests +{ + [TestCase(3, 5, 8)] + [TestCase(13, 5, 18)] + [TestCase(-7, 2, -5)] + [TestCase(0, -7, -7)] + [TestCase(-321, 0, -321)] + public static void CalculateAdditionWithoutArithmetic_Test(int first, int second, int expectedResult) + { + // Act + var result = AdditionWithoutArithmetic.CalculateAdditionWithoutArithmetic(first, second); + + // Assert + Assert.That(result, Is.EqualTo(expectedResult)); + } +} diff --git a/Algorithms/Numeric/AdditionWithoutArithmetic.cs b/Algorithms/Numeric/AdditionWithoutArithmetic.cs new file mode 100644 index 00000000..7ec294b7 --- /dev/null +++ b/Algorithms/Numeric/AdditionWithoutArithmetic.cs @@ -0,0 +1,28 @@ +using System; +using System.Numerics; + +namespace Algorithms.Numeric; + +/// +/// Add the integers without arithmetic operation. +/// +public static class AdditionWithoutArithmetic +{ + /// + /// Returns the sum of two integers. + /// + /// First number to add. + /// Second number to add. + /// Sum of the two numbers. + public static int CalculateAdditionWithoutArithmetic(int first, int second) + { + while (second != 0) + { + int c = first & second; // Carry + first ^= second; // Sum without carry + second = c << 1; // Carry shifted left + } + + return first; + } +} diff --git a/README.md b/README.md index f67c4356..64896aac 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,8 @@ find more than one implementation for the same objective but using different alg * [Extended Euclidean Algorithm](./Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs) * [Modular Multiplicative Inverse](./Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs) * [Numeric](./Algorithms/Numeric) - * [Absolute](./Algorithms/Numeric/Abs.cs) + * [Absolute](./Algorithms/Numeric/Abs.cs) + * [Addition Without Arithmetic](./Algorithms/Numeric/AdditionWithoutArithmetic.cs) * [Aliquot Sum Calculator](./Algorithms/Numeric/AliquotSumCalculator.cs) * [Amicable Numbers Checker](./Algorithms/Numeric/AmicableNumbersChecker.cs) * [Decomposition](./Algorithms/Numeric/Decomposition) From 56ca7195bd1dbe2cf844a3e7fe5728104a0f5994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Falc=C3=A3o?= <72179636+Paulofalcao2002@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:04:02 -0300 Subject: [PATCH 116/138] Add devcontainer support (#485) --- .devcontainer/devcontainer.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..2185d100 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,15 @@ +{ + "name": "The Algorithms C#", + "image": "mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm", + "customizations": { + "vscode": { + "extensions": [ + "ms-dotnettools.csharp", + "ms-dotnettools.csdevkit", + "nunit.nunit-adapter", + "fluentassertions.fluentassertions" + ] + } + }, + "postCreateCommand": "sudo chown -R $(whoami) /workspaces" +} \ No newline at end of file From 013a6b92fc48d6486ca6f6bca080273c408888cb Mon Sep 17 00:00:00 2001 From: Duc Nguyen Thanh <58723762+ngtduc693@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:29:00 +0700 Subject: [PATCH 117/138] Add Geohashing (#486) --- Algorithms.Tests/Other/GeohashTests.cs | 59 ++++++++++++++++++ Algorithms/Other/Geohash.cs | 84 ++++++++++++++++++++++++++ README.md | 1 + 3 files changed, 144 insertions(+) create mode 100644 Algorithms.Tests/Other/GeohashTests.cs create mode 100644 Algorithms/Other/Geohash.cs diff --git a/Algorithms.Tests/Other/GeohashTests.cs b/Algorithms.Tests/Other/GeohashTests.cs new file mode 100644 index 00000000..bf2cced4 --- /dev/null +++ b/Algorithms.Tests/Other/GeohashTests.cs @@ -0,0 +1,59 @@ +using Algorithms.Other; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Tests.Other +{ + [TestFixture] + public class GeohashTests + { + [Test] + public void Encode_ShouldReturnCorrectGeohash_ForHoChiMinhCity() + { + double latitude = 10.8231; + double longitude = 106.6297; + string result = Geohash.Encode(latitude, longitude); + Assert.That(result, Is.EqualTo("w3gvd6m3hh54")); + } + + [Test] + public void Encode_ShouldReturnCorrectGeohash_ForHanoi() + { + double latitude = 21.0285; + double longitude = 105.8542; + string result = Geohash.Encode(latitude, longitude); + Assert.That(result, Is.EqualTo("w7er8u0evss2")); + } + + [Test] + public void Encode_ShouldReturnCorrectGeohash_ForDaNang() + { + double latitude = 16.0544; + double longitude = 108.2022; + string result = Geohash.Encode(latitude, longitude); + Assert.That(result, Is.EqualTo("w6ugq4w7wj04")); + } + + [Test] + public void Encode_ShouldReturnCorrectGeohash_ForNhaTrang() + { + double latitude = 12.2388; + double longitude = 109.1967; + string result = Geohash.Encode(latitude, longitude); + Assert.That(result, Is.EqualTo("w6jtsu485t8v")); + } + + [Test] + public void Encode_ShouldReturnCorrectGeohash_ForVungTau() + { + double latitude = 10.3460; + double longitude = 107.0843; + string result = Geohash.Encode(latitude, longitude); + Assert.That(result, Is.EqualTo("w3u4ug2mv41m")); + } + } +} diff --git a/Algorithms/Other/Geohash.cs b/Algorithms/Other/Geohash.cs new file mode 100644 index 00000000..53507f85 --- /dev/null +++ b/Algorithms/Other/Geohash.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Other +{ + public static class Geohash + { + private const string Base32Characters = "0123456789bcdefghjkmnpqrstuvwxyz"; // Convert latitude and longitude coordinates into a concise string + private const int GeohashLength = 12; // ± 1.86 cm + + /// + /// Encodes the provided latitude and longitude coordinates into a Geohash string. + /// Geohashing is a method to encode geographic coordinates (latitude, longitude). + /// into a short string of letters and digits. Each character in the resulting Geohash . + /// string adds more precision to the location. The longer the Geohash, the smaller the area. + /// + /// The latitude of the location to encode. It must be a value between -90 and 90. + /// The longitude of the location to encode. It must be a value between -180 and 180. + /// + /// A Geohash string of length 12 representing the location with high precision. + /// A longer Geohash provides higher precision in terms of geographic area. + /// and a 12-character Geohash can be accurate down to around 1.86 cm. + /// + public static string Encode(double latitude, double longitude) + { + double[] latitudeRange = new[] { -90.0, 90.0 }; + double[] longitudeRange = new[] { -180.0, 180.0 }; + bool isEncodingLongitude = true; + int currentBit = 0; + int base32Index = 0; + StringBuilder geohashResult = new StringBuilder(); + + while (geohashResult.Length < GeohashLength) + { + double midpoint; + + if (isEncodingLongitude) + { + midpoint = (longitudeRange[0] + longitudeRange[1]) / 2; + if (longitude > midpoint) + { + base32Index |= 1 << (4 - currentBit); + longitudeRange[0] = midpoint; + } + else + { + longitudeRange[1] = midpoint; + } + } + else + { + midpoint = (latitudeRange[0] + latitudeRange[1]) / 2; + if (latitude > midpoint) + { + base32Index |= 1 << (4 - currentBit); + latitudeRange[0] = midpoint; + } + else + { + latitudeRange[1] = midpoint; + } + } + + isEncodingLongitude = !isEncodingLongitude; + + if (currentBit < 4) + { + currentBit++; + } + else + { + geohashResult.Append(Base32Characters[base32Index]); + currentBit = 0; + base32Index = 0; + } + } + + return geohashResult.ToString(); + } + } +} diff --git a/README.md b/README.md index 64896aac..ddf2c1cc 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,7 @@ find more than one implementation for the same objective but using different alg * [Welford's Variance](./Algorithms/Other/WelfordsVariance.cs) * [Julian Easter](./Algorithms/Other/JulianEaster.cs) * [Pollard's Rho](./Algorithms/Other/PollardsRhoFactorizing.cs) + * [GeoLocation Hash](./Algorithms/Other/Geohash.cs) * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) * [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs) From b19d093d8149af73837273446b76c8e8eaa21bf4 Mon Sep 17 00:00:00 2001 From: Duc Nguyen Thanh <58723762+ngtduc693@users.noreply.github.com> Date: Fri, 25 Oct 2024 22:18:49 +0700 Subject: [PATCH 118/138] Add Triangulation algorithm (#489) --- Algorithms.Tests/Other/TriangulatorTests.cs | 62 +++++++++++++++++++++ Algorithms/Other/Triangulator.cs | 55 ++++++++++++++++++ README.md | 1 + 3 files changed, 118 insertions(+) create mode 100644 Algorithms.Tests/Other/TriangulatorTests.cs create mode 100644 Algorithms/Other/Triangulator.cs diff --git a/Algorithms.Tests/Other/TriangulatorTests.cs b/Algorithms.Tests/Other/TriangulatorTests.cs new file mode 100644 index 00000000..39014684 --- /dev/null +++ b/Algorithms.Tests/Other/TriangulatorTests.cs @@ -0,0 +1,62 @@ +using Algorithms.Other; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Tests.Other +{ + [TestFixture] + public class TriangulatorTests + { + [Test] + public void CalculatePosition_ValidCoordinatesAndDistances_ReturnsExpectedPosition() + { + var triangulator = new Triangulator(); + var baseLocations = new List<(double Latitude, double Longitude)> + { + (16.054407, 108.202167), + (16.049807, 108.218991), + (16.063597, 108.215553) + }; + + var distances = new List { 0.5, 0.7, 0.6 }; + + var expectedPosition = (Latitude: 16.054, Longitude: 108.210); + var result = triangulator.CalculatePosition(baseLocations, distances); + + Assert.That(result.Latitude, Is.EqualTo(expectedPosition.Latitude).Within(0.01)); + Assert.That(result.Longitude, Is.EqualTo(expectedPosition.Longitude).Within(0.01)); + } + + [Test] + public void CalculatePosition_InvalidBaseLocations_ThrowsArgumentException() + { + var triangulator = new Triangulator(); + var baseLocations = new List<(double Latitude, double Longitude)> + { + (10.762622, 106.660172) + }; + var distances = new List { 1.0 }; + + Assert.That(() => triangulator.CalculatePosition(baseLocations, distances), Throws.ArgumentException); + } + + [Test] + public void CalculatePosition_InvalidDistances_ThrowsArgumentException() + { + var triangulator = new Triangulator(); + var baseLocations = new List<(double Latitude, double Longitude)> + { + (10.762622, 106.660172), + (10.774981, 106.665504), + (10.771817, 106.681179) + }; + var distances = new List { 1.0 }; + + Assert.That(() => triangulator.CalculatePosition(baseLocations, distances), Throws.ArgumentException); + } + } +} diff --git a/Algorithms/Other/Triangulator.cs b/Algorithms/Other/Triangulator.cs new file mode 100644 index 00000000..a9cd27fc --- /dev/null +++ b/Algorithms/Other/Triangulator.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Other +{ + public class Triangulator + { + public (double Latitude, double Longitude) CalculatePosition(List<(double Latitude, double Longitude)> baseLocations, List distances) + { + if (baseLocations.Count < 3 || distances.Count < 3) + { + throw new ArgumentException("At least three points and corresponding distances are required."); + } + + // Get the coordinates of the three base stations + double lat1 = baseLocations[0].Latitude; + double lon1 = baseLocations[0].Longitude; + double lat2 = baseLocations[1].Latitude; + double lon2 = baseLocations[1].Longitude; + double lat3 = baseLocations[2].Latitude; + double lon3 = baseLocations[2].Longitude; + + // Convert coordinates to radians + lat1 = ToRadians(lat1); + lon1 = ToRadians(lon1); + lat2 = ToRadians(lat2); + lon2 = ToRadians(lon2); + lat3 = ToRadians(lat3); + lon3 = ToRadians(lon3); + + // Calculate the center point + double centerLat = (lat1 + lat2 + lat3) / 3; + double centerLon = (lon1 + lon2 + lon3) / 3; + + // Convert back to degrees + centerLat = ToDegrees(centerLat); + centerLon = ToDegrees(centerLon); + + return (centerLat, centerLon); + } + + private double ToRadians(double degrees) + { + return degrees * Math.PI / 180; + } + + private double ToDegrees(double radians) + { + return radians * 180 / Math.PI; + } + } +} diff --git a/README.md b/README.md index ddf2c1cc..a4d4663f 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,7 @@ find more than one implementation for the same objective but using different alg * [Julian Easter](./Algorithms/Other/JulianEaster.cs) * [Pollard's Rho](./Algorithms/Other/PollardsRhoFactorizing.cs) * [GeoLocation Hash](./Algorithms/Other/Geohash.cs) + * [Triangulation Algorithm](./Algorithms/Other/Triangulator.cs) * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) * [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs) From 93febae9b1746ef70ab58e5ffaec20b439034dff Mon Sep 17 00:00:00 2001 From: Duc Nguyen Thanh <58723762+ngtduc693@users.noreply.github.com> Date: Sat, 26 Oct 2024 03:21:26 +0700 Subject: [PATCH 119/138] Add Geofencing (#487) --- Algorithms.Tests/Other/GeofenceTests.cs | 66 +++++++++++++++++++++++++ Algorithms/Other/Geofence.cs | 37 ++++++++++++++ README.md | 1 + 3 files changed, 104 insertions(+) create mode 100644 Algorithms.Tests/Other/GeofenceTests.cs create mode 100644 Algorithms/Other/Geofence.cs diff --git a/Algorithms.Tests/Other/GeofenceTests.cs b/Algorithms.Tests/Other/GeofenceTests.cs new file mode 100644 index 00000000..30dcfff4 --- /dev/null +++ b/Algorithms.Tests/Other/GeofenceTests.cs @@ -0,0 +1,66 @@ +using Algorithms.Other; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Tests.Other +{ + [TestFixture] + public class GeofenceTests + { + private Geofence? geofence; + + [SetUp] + public void Setup() + { + geofence = new Geofence(10.8231, 106.6297, 500); + } + + [Test] + public void IsInside_ShouldReturnTrue_WhenUserIsInsideGeofence() + { + double userLat = 10.8221; + double userLon = 106.6289; + + bool? result = geofence?.IsInside(userLat, userLon); + + Assert.That(result, Is.True); + } + + [Test] + public void IsInside_ShouldReturnFalse_WhenUserIsOutsideGeofence() + { + double userLat = 10.8300; + double userLon = 106.6400; + + bool? result = geofence?.IsInside(userLat, userLon); + + Assert.That(result, Is.False); + } + + [Test] + public void IsInside_ShouldReturnTrue_WhenUserIsExactlyOnGeofenceBoundary() + { + double userLat = 10.8231; + double userLon = 106.6297; + + bool? result = geofence?.IsInside(userLat, userLon); + + Assert.That(result, Is.True); + } + + [Test] + public void IsInside_ShouldReturnFalse_WhenUserIsFarFromGeofence() + { + double userLat = 20.0000; + double userLon = 100.0000; + + bool? result = geofence?.IsInside(userLat, userLon); + + Assert.That(result, Is.False); + } + } +} diff --git a/Algorithms/Other/Geofence.cs b/Algorithms/Other/Geofence.cs new file mode 100644 index 00000000..90fb9626 --- /dev/null +++ b/Algorithms/Other/Geofence.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Other +{ + public class Geofence + { + public double Latitude { get; set; } + + public double Longitude { get; set; } + + public double RadiusInMeters { get; set; } + + public Geofence(double latitude, double longitude, double radiusInMeters) + { + Latitude = latitude; + Longitude = longitude; + RadiusInMeters = radiusInMeters; + } + + /// + /// Checks whether the provided user location (latitude and longitude) is within the geofence boundary. + /// The geofence is defined by a center point (latitude, longitude) and a radius in meters. + /// + /// The latitude of the user's current location. + /// The longitude of the user's current location. + /// Returns true if the user is inside the geofence, otherwise returns false. + public bool IsInside(double userLatitude, double userLongitude) + { + double distance = GeoLocation.CalculateDistanceFromLatLng(Latitude, Longitude, userLatitude, userLongitude); + return distance <= RadiusInMeters; + } + } +} diff --git a/README.md b/README.md index a4d4663f..8085ccab 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,7 @@ find more than one implementation for the same objective but using different alg * [Julian Easter](./Algorithms/Other/JulianEaster.cs) * [Pollard's Rho](./Algorithms/Other/PollardsRhoFactorizing.cs) * [GeoLocation Hash](./Algorithms/Other/Geohash.cs) + * [Geofencing](./Algorithms/Other/Geofence.cs) * [Triangulation Algorithm](./Algorithms/Other/Triangulator.cs) * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) From f9f450c0cf84a43c02d116f79ac1dc475369755a Mon Sep 17 00:00:00 2001 From: Mohit Singh <168663521+mohit-gogitter@users.noreply.github.com> Date: Sat, 26 Oct 2024 11:27:34 +0530 Subject: [PATCH 120/138] Add Circular Linked List Data Structure (#476) --- .../LinkedList/CircularLinkedListTests.cs | 180 ++++++++++++++++++ .../CircularLinkedList/CircularLinkedList.cs | 155 +++++++++++++++ .../CircularLinkedListNode.cs | 24 +++ README.md | 1 + 4 files changed, 360 insertions(+) create mode 100644 DataStructures.Tests/LinkedList/CircularLinkedListTests.cs create mode 100644 DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs create mode 100644 DataStructures/LinkedList/CircularLinkedList/CircularLinkedListNode.cs diff --git a/DataStructures.Tests/LinkedList/CircularLinkedListTests.cs b/DataStructures.Tests/LinkedList/CircularLinkedListTests.cs new file mode 100644 index 00000000..12b86b09 --- /dev/null +++ b/DataStructures.Tests/LinkedList/CircularLinkedListTests.cs @@ -0,0 +1,180 @@ +using System; +using DataStructures.LinkedList.CircularLinkedList; +using NUnit.Framework; + +namespace DataStructures.Tests.LinkedList; + +[TestFixture] +public static class CircularLinkedListTests +{ + [Test] + public static void TestInsertAtBeginning() + { + var cll = new CircularLinkedList(); + cll.InsertAtBeginning(10); + cll.InsertAtBeginning(20); + cll.InsertAtBeginning(30); + + Assert.That("30 20 10", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + [Test] + public static void TestInsertAtEnd() + { + var cll = new CircularLinkedList(); + cll.InsertAtEnd(10); + cll.InsertAtEnd(20); + cll.InsertAtEnd(30); + + Assert.That("10 20 30", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + [Test] + public static void TestInsertAfter() + { + var cll = new CircularLinkedList(); + cll.InsertAtEnd(10); + cll.InsertAtEnd(20); + cll.InsertAtEnd(30); + cll.InsertAfter(20, 25); + + Assert.That("10 20 25 30", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + [Test] + public static void TestInsertAtBeginningInEmptyList() + { + var cll = new CircularLinkedList(); + cll.InsertAtBeginning(10); + + Assert.That("10", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + [Test] + public static void TestInsertAtEndInEmptyList() + { + var cll = new CircularLinkedList(); + cll.InsertAtEnd(10); + + Assert.That("10", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + [Test] + public static void TestInsertAfterInEmptyList() + { + var cll = new CircularLinkedList(); + var ex = Assert.Throws(() => cll.InsertAfter(10, 20)); + + Assert.That(ex!.Message, Is.EqualTo("List is empty.")); + } + + [Test] + public static void TestInsertAfterSpecificNode() + { + var cll = new CircularLinkedList(); + cll.InsertAtEnd(10); + cll.InsertAtEnd(20); + cll.InsertAtEnd(30); + cll.InsertAfter(20, 25); // Insert after node with value 20 + + Assert.That("10 20 25 30", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + [Test] + public static void TestInsertAfterOnNonExistingValue() + { + var cll = new CircularLinkedList(); + cll.InsertAtEnd(10); + cll.InsertAfter(99, 25); // 99 does not exist + + Assert.That("10", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + [Test] + public static void TestDeleteNode() + { + var cll = new CircularLinkedList(); + cll.InsertAtEnd(10); + cll.InsertAtEnd(20); + cll.InsertAtEnd(30); + cll.DeleteNode(20); + + Assert.That("10 30", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + [Test] + public static void TestDeleteOnlyNode() + { + var cll = new CircularLinkedList(); + cll.InsertAtBeginning(10); + cll.DeleteNode(10); + + Assert.That(cll.IsEmpty(), Is.EqualTo(true)); + } + + [Test] + public static void TestDeleteHeadNode() + { + var cll = new CircularLinkedList(); + cll.InsertAtEnd(10); + cll.InsertAtEnd(20); + cll.InsertAtEnd(30); + cll.DeleteNode(10); + + Assert.That("20 30", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + [Test] + public static void TestDeleteTailNode() + { + var cll = new CircularLinkedList(); + cll.InsertAtEnd(10); + cll.InsertAtEnd(20); + cll.InsertAtEnd(30); + cll.DeleteNode(30); + + Assert.That("10 20", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + [Test] + public static void TestDeleteFromEmptyList() + { + var cll = new CircularLinkedList(); + var ex = Assert.Throws(() => cll.DeleteNode(10)); + + Assert.That(ex!.Message, Is.EqualTo("List is empty.")); + } + + [Test] + public static void TestDeleteNonExistentNode() + { + var cll = new CircularLinkedList(); + cll.InsertAtEnd(10); + cll.InsertAtEnd(20); + cll.InsertAtEnd(30); + cll.DeleteNode(40); // Attempting to delete a node that doesn't exist + + Assert.That("10 20 30", Is.EqualTo(GetDisplayOutput(cll).Trim())); + } + + private static string GetDisplayOutput(CircularLinkedList list) + { + var head = list.GetHead(); + if (head == null) + { + return string.Empty; + } + + var current = head; + var result = new System.Text.StringBuilder(); + + do + { + result.Append(current!.Data + " "); + current = current.Next; + } + while (current != head); + + return result.ToString().Trim(); + } +} diff --git a/DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs b/DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs new file mode 100644 index 00000000..18c5148d --- /dev/null +++ b/DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs @@ -0,0 +1,155 @@ +using System; + +namespace DataStructures.LinkedList.CircularLinkedList +{ + /// + /// CircularLinkedList. + /// @author Mohit Singh. mohit-gogitter + /// + /// The generic type parameter. + public class CircularLinkedList + { + /// + /// Points to the last node in the Circular Linked List. + /// + private CircularLinkedListNode? tail; + + /// + /// Initializes a new instance of the class. + /// + public CircularLinkedList() + { + tail = null; + } + + /// + /// Gets the head node (tail.Next) of the Circular Linked List. + /// + public CircularLinkedListNode? GetHead() + { + return tail?.Next; + } + + /// + /// Determines whether the Circular Linked List is empty. + /// + /// True if the list is empty; otherwise, false. + public bool IsEmpty() + { + return tail == null; + } + + /// + /// Inserts a new node at the beginning of the Circular Linked List. + /// + /// The data to insert into the new node. + public void InsertAtBeginning(T data) + { + var newNode = new CircularLinkedListNode(data); + if (IsEmpty()) + { + tail = newNode; + tail.Next = tail; + } + else + { + newNode.Next = tail!.Next; + tail.Next = newNode; + } + } + + /// + /// Inserts a new node at the end of the Circular Linked List. + /// + /// The data to insert into the new node. + public void InsertAtEnd(T data) + { + var newNode = new CircularLinkedListNode(data); + if (IsEmpty()) + { + tail = newNode; + tail.Next = tail; + } + else + { + newNode.Next = tail!.Next; + tail.Next = newNode; + tail = newNode; + } + } + + /// + /// Inserts a new node after a specific value in the list. + /// + /// The value to insert the node after. + /// The data to insert into the new node. + public void InsertAfter(T value, T data) + { + if (IsEmpty()) + { + throw new InvalidOperationException("List is empty."); + } + + var current = tail!.Next; + do + { + if (current!.Data!.Equals(value)) + { + var newNode = new CircularLinkedListNode(data); + newNode.Next = current.Next; + current.Next = newNode; + + return; + } + + current = current.Next; + } + while (current != tail.Next); + } + + /// + /// Deletes a node with a specific value from the list. + /// + /// The value of the node to delete. + public void DeleteNode(T value) + { + if (IsEmpty()) + { + throw new InvalidOperationException("List is empty."); + } + + var current = tail!.Next; + var previous = tail; + + do + { + if (current!.Data!.Equals(value)) + { + if (current == tail && current.Next == tail) + { + tail = null; + } + else if (current == tail) + { + previous!.Next = tail.Next; + tail = previous; + } + else if (current == tail.Next) + { + tail.Next = current.Next; + } + else + { + previous!.Next = current.Next; + } + + return; + } + + previous = current; + current = current.Next; + } + while (current != tail!.Next); + } + } +} diff --git a/DataStructures/LinkedList/CircularLinkedList/CircularLinkedListNode.cs b/DataStructures/LinkedList/CircularLinkedList/CircularLinkedListNode.cs new file mode 100644 index 00000000..40f416f7 --- /dev/null +++ b/DataStructures/LinkedList/CircularLinkedList/CircularLinkedListNode.cs @@ -0,0 +1,24 @@ +namespace DataStructures.LinkedList.CircularLinkedList +{ + /// + /// Represents a node in the Circular Linked List. + /// Each node contains generic data and a reference to the next node. + /// + /// The type of the data stored in the node. + /// + /// Initializes a new instance of the class. + /// + /// The data to be stored in the node. + public class CircularLinkedListNode(T data) + { + /// + /// Gets or sets the data for the node. + /// + public T Data { get; set; } = data; + + /// + /// Gets or sets the reference to the next node in the list. + /// + public CircularLinkedListNode? Next { get; set; } + } +} diff --git a/README.md b/README.md index 8085ccab..8a1308e2 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,7 @@ find more than one implementation for the same objective but using different alg * [Singly Linked List](./DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs) * [Doubly Linked List](./DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs) * [Skip List](./DataStructures/LinkedList/SkipList/SkipList.cs) + * [Circular Linked List](./DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs) * [Graph](./DataStructures/Graph) * [Directed Weighted Graph Via Adjacency Matrix](./DataStructures/Graph/DirectedWeightedGraph.cs) * [Disjoint Set](./DataStructures/DisjointSet) From 5239e7118085069e17487b7e30570e6c9b60df0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Falc=C3=A3o?= <72179636+Paulofalcao2002@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:41:05 -0300 Subject: [PATCH 121/138] Add Ceil numeric algorithm (#490) --- Algorithms.Tests/Numeric/CeilTests.cs | 27 +++++++++++++++++++++++++++ Algorithms/Numeric/Ceil.cs | 23 +++++++++++++++++++++++ README.md | 1 + 3 files changed, 51 insertions(+) create mode 100644 Algorithms.Tests/Numeric/CeilTests.cs create mode 100644 Algorithms/Numeric/Ceil.cs diff --git a/Algorithms.Tests/Numeric/CeilTests.cs b/Algorithms.Tests/Numeric/CeilTests.cs new file mode 100644 index 00000000..a43904fa --- /dev/null +++ b/Algorithms.Tests/Numeric/CeilTests.cs @@ -0,0 +1,27 @@ +using System; +using System.Numerics; +using Algorithms.Numeric; +using NUnit.Framework; + +namespace Algorithms.Tests.Numeric; + +public static class CeilTests +{ + [TestCase(0.0, 0)] + [TestCase(1.1, 2)] + [TestCase(1.9, 2)] + [TestCase(1.0, 1)] + [TestCase(-1.1, -1)] + [TestCase(-1.9, -1)] + [TestCase(-1.0, -1)] + [TestCase(1000000000.1, 1000000001)] + [TestCase(1, 1)] + public static void GetsCeilVal(T inputNum, T expected) where T : INumber + { + // Act + var result = Ceil.CeilVal(inputNum); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } +} \ No newline at end of file diff --git a/Algorithms/Numeric/Ceil.cs b/Algorithms/Numeric/Ceil.cs new file mode 100644 index 00000000..26b718b7 --- /dev/null +++ b/Algorithms/Numeric/Ceil.cs @@ -0,0 +1,23 @@ +using System; +using System.Numerics; + +namespace Algorithms.Numeric; + +/// +/// Perform ceiling operation on a number. +/// +public static class Ceil +{ + /// + /// Returns the smallest integer greater than or equal to the number. + /// + /// Type of number. + /// Number to find the ceiling of. + /// Ceiling value of the number. + public static T CeilVal(T inputNum) where T : INumber + { + T intPart = T.CreateChecked(Convert.ToInt32(inputNum)); + + return inputNum > intPart ? intPart + T.One : intPart; + } +} diff --git a/README.md b/README.md index 8a1308e2..d64f7803 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ find more than one implementation for the same objective but using different alg * [Addition Without Arithmetic](./Algorithms/Numeric/AdditionWithoutArithmetic.cs) * [Aliquot Sum Calculator](./Algorithms/Numeric/AliquotSumCalculator.cs) * [Amicable Numbers Checker](./Algorithms/Numeric/AmicableNumbersChecker.cs) + * [Ceil](./Algorithms/Numeric/Ceil.cs) * [Decomposition](./Algorithms/Numeric/Decomposition) * [LU Decomposition](./Algorithms/Numeric/Decomposition/LU.cs) * [Thin Singular Vector Decomposition](./Algorithms/Numeric/Decomposition/ThinSVD.cs) From d59c28a6afef68efdb92771b5444ba3868aae808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Falc=C3=A3o?= <72179636+Paulofalcao2002@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:28:46 -0300 Subject: [PATCH 122/138] Add Floor numeric algorithm (#493) --- Algorithms.Tests/Numeric/FloorTests.cs | 27 ++++++++++++++++++++++++++ Algorithms/Numeric/Floor.cs | 23 ++++++++++++++++++++++ README.md | 1 + 3 files changed, 51 insertions(+) create mode 100644 Algorithms.Tests/Numeric/FloorTests.cs create mode 100644 Algorithms/Numeric/Floor.cs diff --git a/Algorithms.Tests/Numeric/FloorTests.cs b/Algorithms.Tests/Numeric/FloorTests.cs new file mode 100644 index 00000000..9221c0d2 --- /dev/null +++ b/Algorithms.Tests/Numeric/FloorTests.cs @@ -0,0 +1,27 @@ +using System; +using System.Numerics; +using Algorithms.Numeric; +using NUnit.Framework; + +namespace Algorithms.Tests.Numeric; + +public static class FloorTests +{ + [TestCase(0.0, 0)] + [TestCase(1.1, 1)] + [TestCase(1.9, 1)] + [TestCase(1.0, 1)] + [TestCase(-1.1, -2)] + [TestCase(-1.9, -2)] + [TestCase(-1.0, -1)] + [TestCase(1000000000.1, 1000000000)] + [TestCase(1, 1)] + public static void GetsFloorVal(T inputNum, T expected) where T : INumber + { + // Act + var result = Floor.FloorVal(inputNum); + + // Assert + Assert.That(result, Is.EqualTo(expected)); + } +} \ No newline at end of file diff --git a/Algorithms/Numeric/Floor.cs b/Algorithms/Numeric/Floor.cs new file mode 100644 index 00000000..b59131df --- /dev/null +++ b/Algorithms/Numeric/Floor.cs @@ -0,0 +1,23 @@ +using System; +using System.Numerics; + +namespace Algorithms.Numeric; + +/// +/// Perform floor operation on a number. +/// +public static class Floor +{ + /// + /// Returns the largest integer less than or equal to the number. + /// + /// Type of number. + /// Number to find the floor of. + /// Floor value of the number. + public static T FloorVal(T inputNum) where T : INumber + { + T intPart = T.CreateChecked(Convert.ToInt32(inputNum)); + + return inputNum < intPart ? intPart - T.One : intPart; + } +} diff --git a/README.md b/README.md index d64f7803..8cce7949 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ find more than one implementation for the same objective but using different alg * [Decomposition](./Algorithms/Numeric/Decomposition) * [LU Decomposition](./Algorithms/Numeric/Decomposition/LU.cs) * [Thin Singular Vector Decomposition](./Algorithms/Numeric/Decomposition/ThinSVD.cs) + * [Floor](./Algorithms/Floor.cs) * [Greatest Common Divisor](./Algorithms/Numeric/GreatestCommonDivisor) * [Euclidean GCD](./Algorithms/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinder.cs) * [Binary GCD](./Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs) From cb4760c36a66cbaf3c81e5d167d429b3872eb1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Falc=C3=A3o?= <72179636+Paulofalcao2002@users.noreply.github.com> Date: Thu, 31 Oct 2024 18:58:17 -0300 Subject: [PATCH 123/138] Add perfect cube numeric algorithm (#494) --- Algorithms.Tests/Numeric/PerfectCubeTests.cs | 41 +++++++++++++ Algorithms/Numeric/PerfectCubeChecker.cs | 60 ++++++++++++++++++++ README.md | 1 + 3 files changed, 102 insertions(+) create mode 100644 Algorithms.Tests/Numeric/PerfectCubeTests.cs create mode 100644 Algorithms/Numeric/PerfectCubeChecker.cs diff --git a/Algorithms.Tests/Numeric/PerfectCubeTests.cs b/Algorithms.Tests/Numeric/PerfectCubeTests.cs new file mode 100644 index 00000000..9bf03aea --- /dev/null +++ b/Algorithms.Tests/Numeric/PerfectCubeTests.cs @@ -0,0 +1,41 @@ +using Algorithms.Numeric; +using NUnit.Framework; + +namespace Algorithms.Tests.Numeric; + +public static class PerfectCubeTests +{ + [TestCase(-27, ExpectedResult = true)] + [TestCase(27, ExpectedResult = true)] + [TestCase(4, ExpectedResult = false)] + [TestCase(64, ExpectedResult = true)] + [TestCase(0, ExpectedResult = true)] + [TestCase(1, ExpectedResult = true)] + [TestCase(8, ExpectedResult = true)] + [TestCase(9, ExpectedResult = false)] + public static bool IsPerfectCube_ResultIsCorrect(int number) + { + // Act + var result = PerfectCubeChecker.IsPerfectCube(number); + + // Assert + return result; + } + + [TestCase(-27, ExpectedResult = true)] + [TestCase(27, ExpectedResult = true)] + [TestCase(4, ExpectedResult = false)] + [TestCase(64, ExpectedResult = true)] + [TestCase(0, ExpectedResult = true)] + [TestCase(1, ExpectedResult = true)] + [TestCase(8, ExpectedResult = true)] + [TestCase(9, ExpectedResult = false)] + public static bool IsPerfectCubeBinarySearch_ResultIsCorrect(int number) + { + // Act + var result = PerfectCubeChecker.IsPerfectCubeBinarySearch(number); + + // Assert + return result; + } +} diff --git a/Algorithms/Numeric/PerfectCubeChecker.cs b/Algorithms/Numeric/PerfectCubeChecker.cs new file mode 100644 index 00000000..cf3eebd6 --- /dev/null +++ b/Algorithms/Numeric/PerfectCubeChecker.cs @@ -0,0 +1,60 @@ +using System; + +namespace Algorithms.Numeric; + +/// +/// A perfect cube is an element of algebraic structure that is equal to the cube of another element. +/// +public static class PerfectCubeChecker +{ + /// + /// Checks if a number is a perfect cube or not. + /// + /// Number to check. + /// True if is a perfect cube; False otherwise. + public static bool IsPerfectCube(int number) + { + if (number < 0) + { + number = -number; + } + + var cubeRoot = Math.Round(Math.Pow(number, 1.0 / 3.0)); + return Math.Abs(cubeRoot * cubeRoot * cubeRoot - number) < 1e-6; + } + + /// + /// Checks if a number is a perfect cube or not using binary search. + /// + /// Number to check. + /// True if is a perfect cube; False otherwise. + public static bool IsPerfectCubeBinarySearch(int number) + { + if (number < 0) + { + number = -number; + } + + int left = 0; + int right = number; + while (left <= right) + { + int mid = left + (right - left) / 2; + int midCubed = mid * mid * mid; + if (midCubed == number) + { + return true; + } + else if (midCubed < number) + { + left = mid + 1; + } + else + { + right = mid - 1; + } + } + + return false; + } +} diff --git a/README.md b/README.md index 8cce7949..bfd6df40 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ find more than one implementation for the same objective but using different alg * [Keith Number Checker](./Algorithms/Numeric/KeithNumberChecker.cs) * [Pseudo-Inverse](./Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs) * [Narcissistic Number Checker](./Algorithms/Numeric/NarcissisticNumberChecker.cs) + * [Perfect Cube Checker](./Algorithms/Numeric/PerfectCubeChecker.cs) * [Perfect Number Checker](./Algorithms/Numeric/PerfectNumberChecker.cs) * [Perfect Square Checker](./Algorithms/Numeric/PerfectSquareChecker.cs) * [Euler Method](./Algorithms/Numeric/EulerMethod.cs) From 02f2ecba893c2b8fa12ed298a0aca57d43c82c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Falc=C3=A3o?= <72179636+Paulofalcao2002@users.noreply.github.com> Date: Thu, 14 Nov 2024 18:00:26 -0300 Subject: [PATCH 124/138] Add Chebyshev distance algorithm (#496) --- .../LinearAlgebra/Distances/ChebyshevTests.cs | 26 ++++++++++++++++ .../LinearAlgebra/Distances/Chebyshev.cs | 31 +++++++++++++++++++ README.md | 1 + 3 files changed, 58 insertions(+) create mode 100644 Algorithms.Tests/LinearAlgebra/Distances/ChebyshevTests.cs create mode 100644 Algorithms/LinearAlgebra/Distances/Chebyshev.cs diff --git a/Algorithms.Tests/LinearAlgebra/Distances/ChebyshevTests.cs b/Algorithms.Tests/LinearAlgebra/Distances/ChebyshevTests.cs new file mode 100644 index 00000000..2a5ca6e9 --- /dev/null +++ b/Algorithms.Tests/LinearAlgebra/Distances/ChebyshevTests.cs @@ -0,0 +1,26 @@ +using NUnit.Framework; +using Algorithms.LinearAlgebra.Distances; +using FluentAssertions; +using System; + +namespace Algorithms.Tests.LinearAlgebra.Distances; + +public class ChebyshevTests +{ + [TestCase(new[] { 1.0, 1.0 }, new[] { 2.0, 2.0 }, 1.0)] + [TestCase(new[] { 1.0, 1.0, 9.0 }, new[] { 2.0, 2.0, -5.2 }, 14.2)] + [TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 1.0, 2.0, 3.0 }, 0.0)] + [TestCase(new[] { 1.0, 2.0, 3.0, 4.0 }, new[] { 1.75, 2.25, -3.0, 0.5 }, 6.0)] + public void DistanceTest(double[] point1, double[] point2, double expectedDistance) + { + Chebyshev.Distance(point1, point2).Should().BeApproximately(expectedDistance, 0.01); + } + + [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0 })] + [TestCase(new[] { 1.0 }, new[] { 1.0, 2.0, 3.0 })] + public void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2) + { + Action action = () => Chebyshev.Distance(point1, point2); + action.Should().Throw(); + } +} \ No newline at end of file diff --git a/Algorithms/LinearAlgebra/Distances/Chebyshev.cs b/Algorithms/LinearAlgebra/Distances/Chebyshev.cs new file mode 100644 index 00000000..b710fb1d --- /dev/null +++ b/Algorithms/LinearAlgebra/Distances/Chebyshev.cs @@ -0,0 +1,31 @@ +using System; +using System.Linq; + +namespace Algorithms.LinearAlgebra.Distances; + +/// +/// Implementation of Chebyshev distance. +/// It is the maximum absolute difference between the measures in all dimensions of two points. +/// In other words, it is the maximum distance one has to travel along any coordinate axis to get from one point to another. +/// +/// It is commonly used in various fields such as chess, warehouse logistics, and more. +/// +public static class Chebyshev +{ + /// + /// Calculate Chebyshev distance for two N-Dimensional points. + /// + /// First N-Dimensional point. + /// Second N-Dimensional point. + /// Calculated Chebyshev distance. + public static double Distance(double[] point1, double[] point2) + { + if (point1.Length != point2.Length) + { + throw new ArgumentException("Both points should have the same dimensionality"); + } + + // distance = max(|x1-y1|, |x2-y2|, ..., |xn-yn|) + return point1.Zip(point2, (x1, x2) => Math.Abs(x1 - x2)).Max(); + } +} diff --git a/README.md b/README.md index bfd6df40..6d4e1e93 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ find more than one implementation for the same objective but using different alg * [IHeuristicKnapsackSolver](./Algorithms/Knapsack/IHeuristicKnapsackSolver.cs) * [Linear Algebra](./Algorithms/LinearAlgebra) * [Distances](./Algorithms/LinearAlgebra/Distances) + * [Chebyshev](./Algorithms/LinearAlgebra/Distances/Chebyshev.cs) * [Euclidean](./Algorithms/LinearAlgebra/Distances/Euclidean.cs) * [Manhattan](./Algorithms/LinearAlgebra/Distances/Manhattan.cs) * [Eigenvalue](./Algorithms/LinearAlgebra/Eigenvalue) From 87776ee39d9d648cf5a8738b19d5cc171effa75e Mon Sep 17 00:00:00 2001 From: Alireza Sariri <131848129+alirezasariri78@users.noreply.github.com> Date: Fri, 15 Nov 2024 10:44:34 +0330 Subject: [PATCH 125/138] Create present value module (#495) --- .../Financial/PresentValueTests.cs | 29 +++++++++++++++++++ Algorithms/Financial/PresentValue.cs | 28 ++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 Algorithms.Tests/Financial/PresentValueTests.cs create mode 100644 Algorithms/Financial/PresentValue.cs diff --git a/Algorithms.Tests/Financial/PresentValueTests.cs b/Algorithms.Tests/Financial/PresentValueTests.cs new file mode 100644 index 00000000..bf2dcaea --- /dev/null +++ b/Algorithms.Tests/Financial/PresentValueTests.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Algorithms.Financial; +using FluentAssertions; +using NUnit.Framework; + +namespace Algorithms.Tests.Financial; + +public static class PresentValueTests +{ + [TestCase(0.13,new[] { 10.0, 20.70, -293.0, 297.0 },4.69)] + [TestCase(0.07,new[] { -109129.39, 30923.23, 15098.93, 29734.0, 39.0 }, -42739.63)] + [TestCase(0.07, new[] { 109129.39, 30923.23, 15098.93, 29734.0, 39.0 }, 175519.15)] + [TestCase(0.0, new[] { 109129.39, 30923.23, 15098.93, 29734.0, 39.0 }, 184924.55)] + + public static void Present_Value_General_Tests(double discountRate,double[] cashFlow ,double expected) + => + PresentValue.Calculate(discountRate, cashFlow.ToList()) + .Should() + .Be(expected); + + + [TestCase(-1.0, new[] { 10.0, 20.70, -293.0, 297.0 })] + [TestCase(1.0,new double[] {})] + + public static void Present_Value_Exception_Tests(double discountRate, double[] cashFlow) + => Assert.Throws(() => PresentValue.Calculate(discountRate, cashFlow.ToList())); +} diff --git a/Algorithms/Financial/PresentValue.cs b/Algorithms/Financial/PresentValue.cs new file mode 100644 index 00000000..805bcd14 --- /dev/null +++ b/Algorithms/Financial/PresentValue.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Algorithms.Financial; + +/// +/// PresentValue is the value of an expected income stream determined as of the date of valuation. +/// +public static class PresentValue +{ + public static double Calculate(double discountRate, List cashFlows) + { + if (discountRate < 0) + { + throw new ArgumentException("Discount rate cannot be negative"); + } + + if (cashFlows.Count == 0) + { + throw new ArgumentException("Cash flows list cannot be empty"); + } + + double presentValue = cashFlows.Select((t, i) => t / Math.Pow(1 + discountRate, i)).Sum(); + + return Math.Round(presentValue, 2); + } +} From c4091c7e0a9163c1b04e38ae2a22022bff1690c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Falc=C3=A3o?= <72179636+Paulofalcao2002@users.noreply.github.com> Date: Sat, 16 Nov 2024 19:16:58 -0300 Subject: [PATCH 126/138] Add Minkowski distance algorithm (#497) --- .../LinearAlgebra/Distances/MinkowskiTests.cs | 28 ++++++++++++++ .../LinearAlgebra/Distances/Minkowski.cs | 37 +++++++++++++++++++ README.md | 1 + 3 files changed, 66 insertions(+) create mode 100644 Algorithms.Tests/LinearAlgebra/Distances/MinkowskiTests.cs create mode 100644 Algorithms/LinearAlgebra/Distances/Minkowski.cs diff --git a/Algorithms.Tests/LinearAlgebra/Distances/MinkowskiTests.cs b/Algorithms.Tests/LinearAlgebra/Distances/MinkowskiTests.cs new file mode 100644 index 00000000..193677b7 --- /dev/null +++ b/Algorithms.Tests/LinearAlgebra/Distances/MinkowskiTests.cs @@ -0,0 +1,28 @@ +using NUnit.Framework; +using Algorithms.LinearAlgebra.Distances; +using FluentAssertions; +using System; + +namespace Algorithms.Tests.LinearAlgebra.Distances; + +public class MinkowskiTests +{ + [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0, 5.0 }, 1, 5.0)] // Simulate Manhattan condition + [TestCase(new[] { 7.0, 4.0, 3.0 }, new[] { 17.0, 6.0, 2.0 }, 2, 10.247)] // Simulate Euclidean condition + [TestCase(new[] { 1.0, 2.0, 3.0, 4.0 }, new[] { 1.75, 2.25, -3.0, 0.5 }, 20, 6.0)] // Simulate Chebyshev condition + [TestCase(new[] { 1.0, 1.0, 9.0 }, new[] { 2.0, 2.0, -5.2 }, 3, 14.2)] + [TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 1.0, 2.0, 3.0 }, 5, 0.0)] + public void DistanceTest(double[] point1, double[] point2, int order, double expectedDistance) + { + Minkowski.Distance(point1, point2, order).Should().BeApproximately(expectedDistance, 0.01); + } + + [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0 }, 2)] + [TestCase(new[] { 1.0 }, new[] { 1.0, 2.0, 3.0 }, 1)] + [TestCase(new[] { 1.0, 1.0 }, new[] { 2.0, 2.0 }, 0)] + public void DistanceThrowsArgumentExceptionOnInvalidInput(double[] point1, double[] point2, int order) + { + Action action = () => Minkowski.Distance(point1, point2, order); + action.Should().Throw(); + } +} \ No newline at end of file diff --git a/Algorithms/LinearAlgebra/Distances/Minkowski.cs b/Algorithms/LinearAlgebra/Distances/Minkowski.cs new file mode 100644 index 00000000..9b3080f3 --- /dev/null +++ b/Algorithms/LinearAlgebra/Distances/Minkowski.cs @@ -0,0 +1,37 @@ +using System; +using System.Linq; + +namespace Algorithms.LinearAlgebra.Distances; + +/// +/// Implementation of Minkowski distance. +/// It is the sum of the lengths of the projections of the line segment between the points onto the +/// coordinate axes, raised to the power of the order and then taking the p-th root. +/// For the case of order = 1, the Minkowski distance degenerates to the Manhattan distance, +/// for order = 2, the usual Euclidean distance is obtained and for order = infinity, the Chebyshev distance is obtained. +/// +public static class Minkowski +{ + /// + /// Calculate Minkowski distance for two N-Dimensional points. + /// + /// First N-Dimensional point. + /// Second N-Dimensional point. + /// Order of the Minkowski distance. + /// Calculated Minkowski distance. + public static double Distance(double[] point1, double[] point2, int order) + { + if (order < 1) + { + throw new ArgumentException("The order must be greater than or equal to 1."); + } + + if (point1.Length != point2.Length) + { + throw new ArgumentException("Both points should have the same dimensionality"); + } + + // distance = (|x1-y1|^p + |x2-y2|^p + ... + |xn-yn|^p)^(1/p) + return Math.Pow(point1.Zip(point2, (x1, x2) => Math.Pow(Math.Abs(x1 - x2), order)).Sum(), 1.0 / order); + } +} diff --git a/README.md b/README.md index 6d4e1e93..c9fd190e 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ find more than one implementation for the same objective but using different alg * [Chebyshev](./Algorithms/LinearAlgebra/Distances/Chebyshev.cs) * [Euclidean](./Algorithms/LinearAlgebra/Distances/Euclidean.cs) * [Manhattan](./Algorithms/LinearAlgebra/Distances/Manhattan.cs) + * [Minkowski](./Algorithms/LinearAlgebra/Distances/Minkowski.cs) * [Eigenvalue](./Algorithms/LinearAlgebra/Eigenvalue) * [Power Iteration](./Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs) * [Modular Arithmetic](./Algorithms/ModularArithmetic) From 0184c377fdcc1f1f80961b0e901859f1f44d2d7c Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Tue, 26 Nov 2024 05:18:45 -0300 Subject: [PATCH 127/138] Add tests for null key handling in DictionaryExtensions (#498) --- .../Extensions/DictionaryExtensionsTests.cs | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs b/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs index 9f309832..73964a29 100644 --- a/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs +++ b/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs @@ -33,4 +33,101 @@ public void AddMany_ShouldAddAllKeyValuePairs() dictionary.Should().ContainKey("two").WhoseValue.Should().Be(2); dictionary.Should().ContainKey("three").WhoseValue.Should().Be(3); } + + [Test] + public void AddMany_ShouldNotChangeDictionary_WhenEnumerableIsEmpty() + { + var dictionary = new Dictionary { ["one"] = 1 }; + var enumerable = Array.Empty<(string, int)>(); + + dictionary.AddMany(enumerable); + + dictionary.Should().HaveCount(1); + dictionary.Should().ContainKey("one").WhoseValue.Should().Be(1); + } + + [Test] + public void AddMany_ShouldThrowArgumentNullException_WhenDictionaryIsNull() + { + Dictionary dictionary = null!; + var enumerable = new[] { ("one", 1) }; + + var action = () => dictionary.AddMany(enumerable); + + action.Should().Throw(); + } + + [Test] + public void AddMany_ShouldThrowArgumentNullException_WhenEnumerableIsNull() + { + var dictionary = new Dictionary { ["one"] = 1 }; + IEnumerable<(string, int)> enumerable = null!; + + var action = () => dictionary.AddMany(enumerable); + + action.Should().Throw(); + } + + [Test] + public void AddMany_ShouldAllowNullValues_WhenValueTypeIsNullable() + { + var dictionary = new Dictionary { ["one"] = 1 }; + var enumerable = new[] { ("two", (int?)null) }; + + dictionary.AddMany(enumerable); + + dictionary.Should().HaveCount(2); + dictionary.Should().ContainKey("two").WhoseValue.Should().Be(null); + } + + + [Test] + public void AddMany_ShouldAllowNullValue_WhenValueIsNullable() + { + var dictionary = new Dictionary(); // Key type is int, value type is nullable string + var enumerable = new[] + { + (1, null), // null value + (2, "banana") + }; + + dictionary.AddMany(enumerable); + + dictionary.Should().ContainKey(1).WhoseValue.Should().BeNull(); + dictionary.Should().ContainKey(2).WhoseValue.Should().Be("banana"); + } + + [Test] + public void AddMany_ShouldThrowArgumentException_WhenAddingDuplicateKey() + { + var dictionary = new Dictionary(); // Key type is int, value type is nullable string + var enumerable = new[] + { + (1, "Things"), // First entry + (2, "Stuff"), + (1, "That Thing") // Duplicate key (should throw exception) + }; + + var action = () => dictionary.AddMany(enumerable); + + action.Should().Throw(); // Adding a duplicate key should throw ArgumentException + } + + [Test] + public void AddMany_ShouldAddManyKeyValuePairs_WhenAddingLargeEnumerable() + { + var dictionary = new Dictionary(); + var enumerable = new List<(int, string)>(); + + // Create a large enumerable + for (int i = 0; i < 10000; i++) + { + enumerable.Add((i, "Value" + i)); + } + + dictionary.AddMany(enumerable); + + dictionary.Should().HaveCount(10000); + dictionary[9999].Should().Be("Value9999"); + } } From 0ef98497fa2b41b3d078b50972296b4c9784e1e9 Mon Sep 17 00:00:00 2001 From: William Lin <44896209+wm55414@users.noreply.github.com> Date: Thu, 28 Nov 2024 06:17:08 +0800 Subject: [PATCH 128/138] Fix Dijkstra algorithm (#499) --- .../Graph/Dijkstra/DijkstraTests.cs | 134 +++++++++++++++++- .../Graph/Dijkstra/DijkstraAlgorithm.cs | 67 +++------ 2 files changed, 151 insertions(+), 50 deletions(-) diff --git a/Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs b/Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs index 5f450e08..e61778bb 100644 --- a/Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs +++ b/Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs @@ -190,10 +190,136 @@ public void DijkstraTest4_Success() shortestPathList[2].ToString().Should() .Be($"Vertex: {c} - Distance: {3} - Previous: {a}"); - // Vertex D won't be visited in this dijkstra implementation which is valid only for cyclic graphs, - // since it is necessary to backtrack all unvisited vertices and place them - // to the priority queue, which is not implemented yet in this repository. - // If algo goes to the next vertex with minimal distance and this vertex is leaf -- algorithm stops. + shortestPathList[3].Vertex.Should().Be(d); + shortestPathList[3].Distance.Should().Be(8); + shortestPathList[3].PreviousVertex.Should().Be(c); + shortestPathList[3].ToString().Should() + .Be($"Vertex: {d} - Distance: {8} - Previous: {c}"); + } + + [Test] + public void DijkstraTest5_Success() + { + // here test case is from https://www.youtube.com/watch?v=pVfj6mxhdMw + + var graph = new DirectedWeightedGraph(7); + var a = graph.AddVertex('A'); + var b = graph.AddVertex('B'); + var c = graph.AddVertex('C'); + var d = graph.AddVertex('D'); + var e = graph.AddVertex('E'); + var w = graph.AddVertex('W'); + var z = graph.AddVertex('Z'); + + graph.AddEdge(a, b, 6); + graph.AddEdge(b, a, 6); + + graph.AddEdge(a, d, 1); + graph.AddEdge(d, a, 1); + + graph.AddEdge(d, e, 1); + graph.AddEdge(e, d, 1); + + graph.AddEdge(d, b, 2); + graph.AddEdge(b, d, 2); + + graph.AddEdge(e, b, 2); + graph.AddEdge(b, e, 2); + + graph.AddEdge(e, c, 5); + graph.AddEdge(c, e, 5); + + graph.AddEdge(c, b, 5); + graph.AddEdge(b, c, 5); + + graph.AddEdge(a, w, 50); + graph.AddEdge(w, a, 50); + + graph.AddEdge(w, z, 1); + graph.AddEdge(z, w, 1); + + var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); + shortestPathList.Length.Should().Be(7); + + shortestPathList[0].Vertex.Should().Be(a); + shortestPathList[0].Distance.Should().Be(0); + shortestPathList[0].PreviousVertex.Should().Be(a); + shortestPathList[0].ToString().Should() + .Be($"Vertex: {a} - Distance: {0} - Previous: {a}"); + + shortestPathList[1].Vertex.Should().Be(b); + shortestPathList[1].Distance.Should().Be(3); + shortestPathList[1].PreviousVertex.Should().Be(d); + shortestPathList[1].ToString().Should() + .Be($"Vertex: {b} - Distance: {3} - Previous: {d}"); + + shortestPathList[2].Vertex.Should().Be(c); + shortestPathList[2].Distance.Should().Be(7); + shortestPathList[2].PreviousVertex.Should().Be(e); + shortestPathList[2].ToString().Should() + .Be($"Vertex: {c} - Distance: {7} - Previous: {e}"); + + shortestPathList[3].Vertex.Should().Be(d); + shortestPathList[3].Distance.Should().Be(1); + shortestPathList[3].PreviousVertex.Should().Be(a); + shortestPathList[3].ToString().Should() + .Be($"Vertex: {d} - Distance: {1} - Previous: {a}"); + + shortestPathList[4].Vertex.Should().Be(e); + shortestPathList[4].Distance.Should().Be(2); + shortestPathList[4].PreviousVertex.Should().Be(d); + shortestPathList[4].ToString().Should() + .Be($"Vertex: {e} - Distance: {2} - Previous: {d}"); + + shortestPathList[5].Vertex.Should().Be(w); + shortestPathList[5].Distance.Should().Be(50); + shortestPathList[5].PreviousVertex.Should().Be(a); + shortestPathList[5].ToString().Should() + .Be($"Vertex: {w} - Distance: {50} - Previous: {a}"); + + shortestPathList[6].Vertex.Should().Be(z); + shortestPathList[6].Distance.Should().Be(51); + shortestPathList[6].PreviousVertex.Should().Be(w); + shortestPathList[6].ToString().Should() + .Be($"Vertex: {z} - Distance: {51} - Previous: {w}"); + } + + [Test] + public void DijkstraTest6_Success() + { + var graph = new DirectedWeightedGraph(5); + var a = graph.AddVertex('A'); + var b = graph.AddVertex('B'); + var c = graph.AddVertex('C'); + var d = graph.AddVertex('D'); + + graph.AddEdge(a, b, 1); + graph.AddEdge(b, a, 1); + + graph.AddEdge(c, d, 5); + graph.AddEdge(d, c, 5); + + var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); + + shortestPathList.Length.Should().Be(4); + shortestPathList[0].Vertex.Should().Be(a); + shortestPathList[0].Distance.Should().Be(0); + shortestPathList[0].PreviousVertex.Should().Be(a); + shortestPathList[0].ToString().Should() + .Be($"Vertex: {a} - Distance: {0} - Previous: {a}"); + + shortestPathList[1].Vertex.Should().Be(b); + shortestPathList[1].Distance.Should().Be(1); + shortestPathList[1].PreviousVertex.Should().Be(a); + shortestPathList[1].ToString().Should() + .Be($"Vertex: {b} - Distance: {1} - Previous: {a}"); + + shortestPathList[2].Vertex.Should().Be(c); + shortestPathList[2].Distance.Should().Be(double.MaxValue); + shortestPathList[2].PreviousVertex.Should().BeNull(); + shortestPathList[2].ToString().Should() + .Be($"Vertex: {c} - Distance: {double.MaxValue} - Previous: {null}"); + shortestPathList[3].Vertex.Should().Be(d); shortestPathList[3].Distance.Should().Be(double.MaxValue); shortestPathList[3].PreviousVertex.Should().BeNull(); diff --git a/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs b/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs index 113b1ece..8aee1f0f 100644 --- a/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs +++ b/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs @@ -25,44 +25,43 @@ public static DistanceModel[] GenerateShortestPath(DirectedWeightedGraph, double>(); - var currentPath = 0d; + distanceRecord.Enqueue(distanceArray[0], distanceArray[0].Distance); - while (true) + while (visitedVertices.Count != distanceArray.Length && distanceRecord.Count != 0) { - visitedVertices.Add(currentVertex); + while(visitedVertices.Contains(distanceRecord.Peek().Vertex!)) + { + distanceRecord.Dequeue(); + } + + var minDistance = distanceRecord.Dequeue(); + + var currentPath = minDistance.Distance; + + visitedVertices.Add(minDistance.Vertex!); var neighborVertices = graph - .GetNeighbors(currentVertex) + .GetNeighbors(minDistance.Vertex!) .Where(x => x != null && !visitedVertices.Contains(x)) .ToList(); foreach (var vertex in neighborVertices) { - var adjacentDistance = graph.AdjacentDistance(currentVertex, vertex!); + var adjacentDistance = graph.AdjacentDistance(minDistance.Vertex!, vertex!); var distance = distanceArray[vertex!.Index]; - if (distance.Distance <= currentPath + adjacentDistance) + var fullDistance = currentPath + adjacentDistance; + + if (distance.Distance > fullDistance) { - continue; + distance.Distance = fullDistance; + distance.PreviousVertex = minDistance.Vertex; + distanceRecord.Enqueue(distance, fullDistance); } - - distance.Distance = currentPath + adjacentDistance; - distance.PreviousVertex = currentVertex; } - - var minimalAdjacentVertex = GetMinimalUnvisitedAdjacentVertex(graph, currentVertex, neighborVertices); - - if (neighborVertices.Count == 0 || minimalAdjacentVertex is null) - { - break; - } - - currentPath += graph.AdjacentDistance(currentVertex, minimalAdjacentVertex); - - currentVertex = minimalAdjacentVertex; } return distanceArray; @@ -96,28 +95,4 @@ private static void ValidateGraphAndStartVertex(DirectedWeightedGraph grap throw new ArgumentNullException(nameof(graph)); } } - - private static Vertex? GetMinimalUnvisitedAdjacentVertex( - IDirectedWeightedGraph graph, - Vertex startVertex, - IEnumerable?> adjacentVertices) - { - var minDistance = double.MaxValue; - Vertex? minVertex = default; - - foreach (var vertex in adjacentVertices) - { - var currentDistance = graph.AdjacentDistance(startVertex, vertex!); - - if (minDistance <= currentDistance) - { - continue; - } - - minDistance = currentDistance; - minVertex = vertex; - } - - return minVertex; - } } From 046f26e0e3fecfbd6e89866d060410e0f9fc11a1 Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:52:04 -0300 Subject: [PATCH 129/138] Improve coverage for hash table (#500) --- .../Hashing/HashTableTests.cs | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/DataStructures.Tests/Hashing/HashTableTests.cs b/DataStructures.Tests/Hashing/HashTableTests.cs index 10ee6d7d..ce1e0476 100644 --- a/DataStructures.Tests/Hashing/HashTableTests.cs +++ b/DataStructures.Tests/Hashing/HashTableTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using DataStructures.Hashing; +using FluentAssertions; using NUnit.Framework; namespace DataStructures.Tests.Hashing; @@ -389,6 +390,99 @@ public void Test_NegativeHashKey_ReturnsCorrectValue() hashTable.Add(new NegativeHashKey(1), 1); Assert.That(hashTable[new NegativeHashKey(1)], Is.EqualTo(1)); } + + [Test] + public void Add_ShouldTriggerResize_WhenThresholdExceeded() + { + // Arrange + var initialCapacity = 4; + var hashTable = new HashTable(initialCapacity); + + // Act + for (int i = 1; i <= 4; i++) // Start keys from 1 to avoid default(TKey) = 0 issue + { + hashTable.Add(i, $"Value{i}"); + } + + // Assert + hashTable.Capacity.Should().BeGreaterThan(initialCapacity); // Ensure resizing occurred + hashTable.Count.Should().Be(4); // Verify count reflects number of added items + } + + + [Test] + public void Add_ThrowsException_WhenKeyIsDefault() + { + // Arrange + var hashTable = new HashTable(); + + // Act & Assert + Action act = () => hashTable.Add(default, "Value"); + act.Should().Throw().WithMessage("*key*"); + } + + [Test] + public void Add_ThrowsException_WhenValueIsDefault() + { + // Arrange + var hashTable = new HashTable(); + + // Act & Assert + Action act = () => hashTable.Add(1, default); + act.Should().Throw().WithMessage("*value*"); + } + + [Test] + public void Add_StoresValueCorrectly() + { + // Arrange + var hashTable = new HashTable(); + + // Act + hashTable.Add(1, "Value1"); + + // Assert + hashTable[1].Should().Be("Value1"); + } + + [Test] + public void Get_ReturnsCorrectValue_ForExistingKey() + { + // Arrange + var hashTable = new HashTable(); + hashTable.Add("key", 42); + + // Act + var value = hashTable["key"]; + + // Assert + value.Should().Be(42); + } + + [Test] + public void Get_ThrowsException_WhenKeyDoesNotExist() + { + // Arrange + var hashTable = new HashTable(); + + // Act & Assert + Action act = () => _ = hashTable["nonexistent"]; + act.Should().Throw(); + } + + [Test] + public void Capacity_Increases_WhenResizeOccurs() + { + var initialCapacity = 4; + var hashTable = new HashTable(initialCapacity); + + for (int i = 1; i <= 5; i++) + { + hashTable.Add(i, $"Value{i}"); + } + + hashTable.Capacity.Should().BeGreaterThan(initialCapacity); + } } public class NegativeHashKey From 2ed7a7bce29a990bfc0e283ef7735a1b9f6e8229 Mon Sep 17 00:00:00 2001 From: Gerson Jr <57489438+gmottajr@users.noreply.github.com> Date: Fri, 6 Dec 2024 05:16:06 -0300 Subject: [PATCH 130/138] Enhance FastSearcherTests with additional test cases and improved assertions using FluentAssertions. (#501) --- Algorithms.Tests/Search/FastSearcherTests.cs | 89 +++++++++++++------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/Algorithms.Tests/Search/FastSearcherTests.cs b/Algorithms.Tests/Search/FastSearcherTests.cs index 2bc95bf3..224c244d 100644 --- a/Algorithms.Tests/Search/FastSearcherTests.cs +++ b/Algorithms.Tests/Search/FastSearcherTests.cs @@ -1,5 +1,7 @@ using Algorithms.Search; +using FluentAssertions; using NUnit.Framework; +using System; using Utilities.Exceptions; namespace Algorithms.Tests.Search; @@ -9,11 +11,16 @@ public static class FastSearcherTests [Test] public static void FindIndex_ItemPresent_IndexCorrect() { + // Arrange var searcher = new FastSearcher(); var arr = Helper.GetSortedArray(1000); var present = Helper.GetItemIn(arr); + + // Act var index = searcher.FindIndex(arr, present); - Assert.That(arr[index], Is.EqualTo(present)); + + // Assert + arr[index].Should().Be(present); } [TestCase(new[] { 1, 2 }, 1)] @@ -21,61 +28,81 @@ public static void FindIndex_ItemPresent_IndexCorrect() [TestCase(new[] { 1, 2, 3, 3, 3 }, 2)] public static void FindIndex_ItemPresentInSpecificCase_IndexCorrect(int[] arr, int present) { + // Arrange var searcher = new FastSearcher(); + + // Act var index = searcher.FindIndex(arr, present); - Assert.That(arr[index], Is.EqualTo(present)); + + // Assert + arr[index].Should().Be(present); } [Test] - public static void FindIndex_ItemMissing_ItemNotFoundExceptionThrown() + public static void FindIndex_ItemPresentInArrayOfDuplicates_IndexCorrect() { + // Arrange var searcher = new FastSearcher(); - var arr = Helper.GetSortedArray(1000); - var missing = Helper.GetItemNotIn(arr); - _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); + var arr = CreateArrayOfDuplicates(1000, 0); // Helper for large duplicate arrays + var present = 0; + + // Act + var index = searcher.FindIndex(arr, present); + + // Assert + arr[index].Should().Be(0); } - [TestCase(new int[0], 2)] - public static void FindIndex_ItemMissingInSpecificCase_ItemNotFoundExceptionThrown(int[] arr, int missing) + [TestCase(new int[0], 2)] // Empty array + [TestCase(new[] { 1, 2, 3 }, 4)] // Item missing in array + public static void FindIndex_ItemMissing_ItemNotFoundExceptionThrown(int[] arr, int missing) { + // Arrange var searcher = new FastSearcher(); - _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); + + // Act + Action act = () => searcher.FindIndex(arr, missing); + + // Assert + act.Should().Throw(); } [Test] - public static void FindIndex_ItemSmallerThanAllMissing_ItemNotFoundExceptionThrown() + public static void FindIndex_ItemMissingInArrayOfDuplicates_ItemNotFoundExceptionThrown() { + // Arrange var searcher = new FastSearcher(); - var arr = Helper.GetSortedArray(1000); - var missing = Helper.GetItemSmallerThanAllIn(arr); - _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); + var arr = CreateArrayOfDuplicates(1000, 0); // Helper for large duplicate arrays + var missing = 1; + + // Act + Action act = () => searcher.FindIndex(arr, missing); + + // Assert + act.Should().Throw(); } [Test] - public static void FindIndex_ItemBiggerThanAllMissing_ItemNotFoundExceptionThrown() + public static void FindIndex_ItemOutOfRange_ItemNotFoundExceptionThrown() { + // Arrange var searcher = new FastSearcher(); var arr = Helper.GetSortedArray(1000); - var missing = Helper.GetItemBiggerThanAllIn(arr); - _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); - } + var smaller = Helper.GetItemSmallerThanAllIn(arr); + var bigger = Helper.GetItemBiggerThanAllIn(arr); - [Test] - public static void FindIndex_ArrayOfDuplicatesItemPresent_IndexCorrect() - { - var searcher = new FastSearcher(); - var arr = new int[1000]; - var present = 0; - var index = searcher.FindIndex(arr, present); - Assert.That(arr[index], Is.EqualTo(0)); + // Act & Assert + Action act1 = () => searcher.FindIndex(arr, smaller); + Action act2 = () => searcher.FindIndex(arr, bigger); + + act1.Should().Throw(); + act2.Should().Throw(); } - [Test] - public static void FindIndex_ArrayOfDuplicatesItemMissing_ItemNotFoundExceptionThrown() + private static int[] CreateArrayOfDuplicates(int length, int value) { - var searcher = new FastSearcher(); - var arr = new int[1000]; - var missing = 1; - _ = Assert.Throws(() => searcher.FindIndex(arr, missing)); + var arr = new int[length]; + Array.Fill(arr, value); + return arr; } } From 329fc507e6068b43335a6decc8c05b721326dab4 Mon Sep 17 00:00:00 2001 From: Jc Calayag <138150245+Jccqt@users.noreply.github.com> Date: Fri, 11 Jul 2025 18:36:47 +0800 Subject: [PATCH 131/138] Add Gnome sort algorithm (#507) --- .../Sorters/Comparison/GnomeSorterTests.cs | 27 ++++++++++++ Algorithms/Sorters/Comparison/GnomeSorter.cs | 42 +++++++++++++++++++ README.md | 1 + 3 files changed, 70 insertions(+) create mode 100644 Algorithms.Tests/Sorters/Comparison/GnomeSorterTests.cs create mode 100644 Algorithms/Sorters/Comparison/GnomeSorter.cs diff --git a/Algorithms.Tests/Sorters/Comparison/GnomeSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/GnomeSorterTests.cs new file mode 100644 index 00000000..fc9cb5a8 --- /dev/null +++ b/Algorithms.Tests/Sorters/Comparison/GnomeSorterTests.cs @@ -0,0 +1,27 @@ +using System; +using Algorithms.Sorters.Comparison; +using Algorithms.Tests.Helpers; +using NUnit.Framework; + +namespace Algorithms.Tests.Sorters.Comparison; + +public static class GnomeSorterTests +{ + [Test] + public static void ArraySorted( + [Random(0, 1000, 100, Distinct = true)] + int n) + { + // Arrange + var sorter = new GnomeSorter(); + var intComparer = new IntComparer(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + sorter.Sort(testArray, intComparer); + Array.Sort(correctArray, intComparer); + + // Assert + Assert.That(correctArray, Is.EqualTo(testArray)); + } +} diff --git a/Algorithms/Sorters/Comparison/GnomeSorter.cs b/Algorithms/Sorters/Comparison/GnomeSorter.cs new file mode 100644 index 00000000..28bfeeb2 --- /dev/null +++ b/Algorithms/Sorters/Comparison/GnomeSorter.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; + +namespace Algorithms.Sorters.Comparison; + +/// +/// Class that implements gnome sort algorithm. +/// +/// Type of array element. +public class GnomeSorter : IComparisonSorter +{ + /// + /// Moves forward through the array until it founds two elements out of order, + /// then swaps them and move back one position, + /// internal, in-place, stable, + /// time complexity: O(n2), + /// space complexity: O(1). + /// + /// Array to sort. + /// Compares elements. + public void Sort(T[] array, IComparer comparer) + { + int index = 0; + + while (index < array.Length) + { + if (index == 0 || comparer.Compare(array[index], array[index - 1]) >= 0) + { + index++; + } + else + { + Swap(array, index, index - 1); + index--; + } + } + } + + public void Swap(T[] array, int index1, int index2) + { + (array[index1], array[index2]) = (array[index2], array[index1]); + } +} diff --git a/README.md b/README.md index c9fd190e..198d2bd7 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ find more than one implementation for the same objective but using different alg * [Comb Sort](./Algorithms/Sorters/Comparison/CombSorter.cs) * [Cycle Sort](./Algorithms/Sorters/Comparison/CycleSorter.cs) * [Exchange Sort](./Algorithms/Sorters/Comparison/ExchangeSorter.cs) + * [Gnome Sort](./Algorithms/Sorters/Comparison/GnomeSorter.cs) * [Heap Sort](./Algorithms/Sorters/Comparison/HeapSorter.cs) * [Insertion Sort](./Algorithms/Sorters/Comparison/InsertionSorter.cs) * [Merge Sort](./Algorithms/Sorters/Comparison/MergeSorter.cs) From 8fec0422cc740e016c211f8ccaced83738f063c1 Mon Sep 17 00:00:00 2001 From: Jc Calayag <138150245+Jccqt@users.noreply.github.com> Date: Sat, 12 Jul 2025 01:54:16 +0800 Subject: [PATCH 132/138] Add Autokey encoder (#509) --- .../Encoders/AutokeyEncoderTests.cs | 26 +++++++ Algorithms/Encoders/AutokeyEncorder.cs | 69 +++++++++++++++++++ README.md | 1 + 3 files changed, 96 insertions(+) create mode 100644 Algorithms.Tests/Encoders/AutokeyEncoderTests.cs create mode 100644 Algorithms/Encoders/AutokeyEncorder.cs diff --git a/Algorithms.Tests/Encoders/AutokeyEncoderTests.cs b/Algorithms.Tests/Encoders/AutokeyEncoderTests.cs new file mode 100644 index 00000000..0613e1c6 --- /dev/null +++ b/Algorithms.Tests/Encoders/AutokeyEncoderTests.cs @@ -0,0 +1,26 @@ +using System; +using Algorithms.Encoders; +using NUnit.Framework; +using NUnit.Framework.Internal; + +namespace Algorithms.Tests.Encoders +{ + public static class AutokeyEncoderTests + { + [Test] + public static void DecodedStringIsTheSame() + { + // Arrange + var plainText = "PLAINTEXT"; + var keyword = "KEYWORD"; + var encoder = new AutokeyEncorder(); + + // Act + var encoded = encoder.Encode(plainText, keyword); + var decoded = encoder.Decode(encoded, keyword); + + // Assert + Assert.That(decoded, Is.EqualTo(plainText)); + } + } +} diff --git a/Algorithms/Encoders/AutokeyEncorder.cs b/Algorithms/Encoders/AutokeyEncorder.cs new file mode 100644 index 00000000..8dc13d37 --- /dev/null +++ b/Algorithms/Encoders/AutokeyEncorder.cs @@ -0,0 +1,69 @@ +using System; +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; + +namespace Algorithms.Encoders +{ + /// + /// Class for AutoKey encoding strings. + /// + public class AutokeyEncorder + { + /// + /// Autokey Cipher is a type of polyalphabetic cipher. + /// This works by choosing a key (a word or short phrase), + /// then you append the plaintext to itself to form a longer key. + /// + /// The string to be appended to the key. + /// The string to be appended to the plaintext. + /// The Autokey encoded string (All Uppercase). + public string Encode(string plainText, string keyword) + { + plainText = Regex.Replace(plainText.ToUpper(CultureInfo.InvariantCulture), "[^A-Z]", string.Empty); + keyword = keyword.ToUpper(CultureInfo.InvariantCulture); + + keyword += plainText; + + StringBuilder cipherText = new StringBuilder(); + + for(int i = 0; i < plainText.Length; i++) + { + char plainCharacter = plainText[i]; + char keyCharacter = keyword[i]; + + int encryptedCharacter = (plainCharacter - 'A' + keyCharacter - 'A') % 26 + 'A'; + cipherText.Append((char)encryptedCharacter); + } + + return cipherText.ToString(); + } + + /// + /// Removed the key from the encoded string. + /// + /// The encoded string. + /// The key to be removed from the encoded string. + /// The plaintext (All Uppercase). + public string Decode(string cipherText, string keyword) + { + cipherText = Regex.Replace(cipherText.ToUpper(CultureInfo.InvariantCulture), "[^A-Z]", string.Empty); + keyword = keyword.ToUpper(CultureInfo.InvariantCulture); + + StringBuilder plainText = new StringBuilder(); + StringBuilder extendedKeyword = new StringBuilder(keyword); + + for(int i = 0; i < cipherText.Length; i++) + { + char cipherCharacter = cipherText[i]; + char keywordCharacter = extendedKeyword[i]; + + int decryptedCharacter = (cipherCharacter - 'A' - (keywordCharacter - 'A') + 26) % 26 + 'A'; + plainText.Append((char)decryptedCharacter); + extendedKeyword.Append((char)decryptedCharacter); + } + + return plainText.ToString(); + } + } +} diff --git a/README.md b/README.md index 198d2bd7..b9933f9f 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ find more than one implementation for the same objective but using different alg * [Soundex](./Algorithms/Encoders/SoundexEncoder.cs) * [Feistel](./Algorithms/Encoders/FeistelCipher.cs) * [Blowfish](./Algorithms/Encoders/BlowfishEncoder.cs) + * [Autokey](./Algorithms/Encoders/AutokeyEncoder.cs) * [Graph](./Algorithms/Graph) * [Minimum Spanning Tree](./Algorithms/Graph/MinimumSpanningTree) * [Prim's Algorithm (Adjacency Matrix)](./Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs) From b0244999ab3f655add6da6c8550e3c186b43e9f9 Mon Sep 17 00:00:00 2001 From: Jc Calayag <138150245+Jccqt@users.noreply.github.com> Date: Wed, 16 Jul 2025 04:44:25 +0800 Subject: [PATCH 133/138] Add LINQ shuffling algorithm (#515) --- .../Shufflers/LINQShufflerTests.cs | 60 +++++++++++++++++++ Algorithms/Shufflers/LINQShuffler.cs | 30 ++++++++++ README.md | 1 + 3 files changed, 91 insertions(+) create mode 100644 Algorithms.Tests/Shufflers/LINQShufflerTests.cs create mode 100644 Algorithms/Shufflers/LINQShuffler.cs diff --git a/Algorithms.Tests/Shufflers/LINQShufflerTests.cs b/Algorithms.Tests/Shufflers/LINQShufflerTests.cs new file mode 100644 index 00000000..5894ca88 --- /dev/null +++ b/Algorithms.Tests/Shufflers/LINQShufflerTests.cs @@ -0,0 +1,60 @@ +using Algorithms.Shufflers; +using Algorithms.Tests.Helpers; +using FluentAssertions; +using NUnit.Framework; +using System; + +namespace Algorithms.Tests.Shufflers +{ + public static class LinqShufflerTests + { + [Test] + public static void ArrayShuffled_NewArraySameSize( + [Random(10, 1000, 100, Distinct = true)] + int n) + { + // Arrange + var shuffler = new LinqShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(testArray); + + // Assert + testArray.Length.Should().Be(correctArray.Length); + } + + [Test] + public static void ArrayShuffled_NewArraySameValues( + [Random(10, 1000, 100, Distinct = true)] + int n) + { + // Arrange + var shuffler = new LinqShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(testArray); + + // Assert + testArray.Should().BeEquivalentTo(correctArray); + } + + [Test] + public static void ArrayShuffled_NewArraySameShuffle( + [Random(0, 1000, 2, Distinct = true)] int n, + [Random(1000, 10000, 5, Distinct = true)] int seed) + { + // Arrange + var shuffle = new LinqShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffle.Shuffle(testArray, seed); + shuffle.Shuffle(correctArray, seed); + + // Assert + correctArray.Should().BeEquivalentTo(testArray, options => options.WithStrictOrdering()); + } + } +} diff --git a/Algorithms/Shufflers/LINQShuffler.cs b/Algorithms/Shufflers/LINQShuffler.cs new file mode 100644 index 00000000..a3eb6b39 --- /dev/null +++ b/Algorithms/Shufflers/LINQShuffler.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Shufflers +{ + /// + /// LINQ Shuffle is a simple shuffling algorithm, + /// where the elements within a collection are shuffled using + /// LINQ queries and lambda expressions in C#. + /// + /// Type array input. + public class LinqShuffler + { + /// + /// First, it will generate a random value for each element. + /// Next, it will sort the elements based on these generated + /// random numbers using OrderBy. + /// + /// Array to shuffle. + /// Random generator seed. Used to repeat the shuffle. + public T[] Shuffle(T[] array, int? seed = null) + { + var random = seed is null ? new Random() : new Random(seed.Value); + return array.OrderBy(x => random.Next()).ToArray(); + } + } +} diff --git a/README.md b/README.md index b9933f9f..9f1fef06 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ find more than one implementation for the same objective but using different alg * [MSD Radix Sort](./Algorithms/Sorters/String/MsdRadixStringSorter.cs) * [Shufflers](./Algorithms/Shufflers) * [Fisher-Yates Shuffler](./Algorithms/Shufflers/FisherYatesShuffler.cs) + * [LINQ Shuffler](./Algorithms/Shufflers/LinqShuffler.cs) * [Sequences](./Algorithms/Sequences) * [A000002 Kolakoski](./Algorithms/Sequences/KolakoskiSequence.cs) * [A000004 Zero](./Algorithms/Sequences/ZeroSequence.cs) From 99bc144318c8dbb5a266146e57ae970228c00c39 Mon Sep 17 00:00:00 2001 From: Jc Calayag <138150245+Jccqt@users.noreply.github.com> Date: Fri, 18 Jul 2025 01:04:49 +0800 Subject: [PATCH 134/138] Add Naive shuffling algorithm (#517) --- .../Shufflers/NaiveShufflerTests.cs | 60 +++++++++++++++++++ Algorithms/Shufflers/NaiveShuffler.cs | 31 ++++++++++ README.md | 1 + 3 files changed, 92 insertions(+) create mode 100644 Algorithms.Tests/Shufflers/NaiveShufflerTests.cs create mode 100644 Algorithms/Shufflers/NaiveShuffler.cs diff --git a/Algorithms.Tests/Shufflers/NaiveShufflerTests.cs b/Algorithms.Tests/Shufflers/NaiveShufflerTests.cs new file mode 100644 index 00000000..111b718a --- /dev/null +++ b/Algorithms.Tests/Shufflers/NaiveShufflerTests.cs @@ -0,0 +1,60 @@ +using Algorithms.Shufflers; +using Algorithms.Tests.Helpers; +using FluentAssertions; +using NUnit.Framework; +using System; + +namespace Algorithms.Tests.Shufflers +{ + public static class NaiveShufflerTests + { + [Test] + public static void ArrayShuffled_NewArraySameSize( + [Random(10, 1000, 100, Distinct = true)] + int n) + { + // Arrange + var shuffler = new NaiveShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(testArray); + + // Assert + testArray.Length.Should().Be(correctArray.Length); + } + + [Test] + public static void ArrayShuffled_NewArraySameValues( + [Random(10, 1000, 100, Distinct = true)] + int n) + { + // Arrange + var shuffler = new NaiveShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(testArray); + + // Assert + testArray.Should().BeEquivalentTo(correctArray); + } + + [Test] + public static void ArrayShuffled_NewArraySameShuffle( + [Random(0, 1000, 2, Distinct = true)] int n, + [Random(1000, 10000, 5, Distinct = true)] int seed) + { + // Arrange + var shuffle = new NaiveShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffle.Shuffle(testArray, seed); + shuffle.Shuffle(correctArray, seed); + + // Assert + correctArray.Should().BeEquivalentTo(testArray, options => options.WithStrictOrdering()); + } + } +} diff --git a/Algorithms/Shufflers/NaiveShuffler.cs b/Algorithms/Shufflers/NaiveShuffler.cs new file mode 100644 index 00000000..94e10d18 --- /dev/null +++ b/Algorithms/Shufflers/NaiveShuffler.cs @@ -0,0 +1,31 @@ +using System; + +namespace Algorithms.Shufflers +{ + /// + /// Naive Shuffle is a simple and incorrect shuffling algorithm + /// that randomly swaps every element with any other element in the array. + /// + /// Type array input. + public class NaiveShuffler : IShuffler + { + /// + /// First, it loop from 0 to n - 1. + /// Next, it will randomly pick any j in the array. + /// Lastly, it will swap array[i] with array[j]. + /// + /// Array to shuffle. + /// Random generator seed. Used to repeat the shuffle. + public void Shuffle(T[] array, int? seed = null) + { + var random = seed is null ? new Random() : new Random(seed.Value); + for(int i = 0; i < array.Length; i++) + { + int j = random.Next(array.Length); + T temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + } + } +} diff --git a/README.md b/README.md index 9f1fef06..bd8490d3 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,7 @@ find more than one implementation for the same objective but using different alg * [Shufflers](./Algorithms/Shufflers) * [Fisher-Yates Shuffler](./Algorithms/Shufflers/FisherYatesShuffler.cs) * [LINQ Shuffler](./Algorithms/Shufflers/LinqShuffler.cs) + * [Naive Shuffler](./Algorithms/Shufflers/NaiveShuffler.cs) * [Sequences](./Algorithms/Sequences) * [A000002 Kolakoski](./Algorithms/Sequences/KolakoskiSequence.cs) * [A000004 Zero](./Algorithms/Sequences/ZeroSequence.cs) From 00e9bc4c1644c2f264843804e0ccd58e0459e02e Mon Sep 17 00:00:00 2001 From: Jc Calayag <138150245+Jccqt@users.noreply.github.com> Date: Tue, 22 Jul 2025 03:05:30 +0800 Subject: [PATCH 135/138] Add recursive shuffling algorithm (#519) --- .../Shufflers/RecursiveShufflerTests.cs | 60 +++++++++++++++++++ Algorithms/Shufflers/RecursiveShuffler.cs | 46 ++++++++++++++ README.md | 1 + 3 files changed, 107 insertions(+) create mode 100644 Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs create mode 100644 Algorithms/Shufflers/RecursiveShuffler.cs diff --git a/Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs b/Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs new file mode 100644 index 00000000..0559e401 --- /dev/null +++ b/Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs @@ -0,0 +1,60 @@ +using Algorithms.Shufflers; +using Algorithms.Tests.Helpers; +using FluentAssertions; +using NUnit.Framework; +using System; + +namespace Algorithms.Tests.Shufflers +{ + public static class RecursiveShufflerTests + { + [Test] + public static void ArrayShuffled_NewArraySameSize( + [Random(10, 1000, 100, Distinct = true)] + int n) + { + // Arrange + var shuffler = new RecursiveShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(testArray); + + // Assert + testArray.Length.Should().Be(correctArray.Length); + } + + [Test] + public static void ArrayShuffled_NewArraySameValues( + [Random(10, 1000, 100, Distinct = true)] + int n) + { + // Arrange + var shuffler = new RecursiveShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(testArray); + + // Assert + testArray.Should().BeEquivalentTo(correctArray); + } + + [Test] + public static void ArrayShuffled_NewArraySameShuffle( + [Random(0, 1000, 2, Distinct = true)] int n, + [Random(1000, 10000, 5, Distinct = true)] int seed) + { + // Arrange + var shuffler = new RecursiveShuffler(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(testArray, seed); + shuffler.Shuffle(correctArray, seed); + + // Assert + correctArray.Should().BeEquivalentTo(testArray, options => options.WithStrictOrdering()); + } + } +} diff --git a/Algorithms/Shufflers/RecursiveShuffler.cs b/Algorithms/Shufflers/RecursiveShuffler.cs new file mode 100644 index 00000000..4a367e1b --- /dev/null +++ b/Algorithms/Shufflers/RecursiveShuffler.cs @@ -0,0 +1,46 @@ +using System; + +namespace Algorithms.Shufflers +{ + /// + /// Recursive Shuffler is a recursive version of + /// Fisher-Yates shuffle algorithm. This can only be used + /// for educational purposes due to stack depth limits. + /// + /// Type array input. + public class RecursiveShuffler : IShuffler + { + /// + /// This is the public overload method that calls the private overload method. + /// + /// Array to shuffle. + /// Random generator seed. Used to repeat the shuffle. + public void Shuffle(T[] array, int? seed = null) + { + Shuffle(array, array.Length - 1, seed); + } + + /// + /// First, it will check the length of the array on the base case. + /// Next, if there's still items left, it will shuffle the sub-array. + /// Lastly, it will randomly select index from 0 to number of items of the array + /// then swap the elements array[items] and array[index]. + /// + /// Array to shuffle. + /// Number of items in the array. + /// Random generator seed. Used to repeat the shuffle. + private void Shuffle(T[] array, int items, int? seed) + { + if (items <= 0) + { + return; + } + + Shuffle(array, items - 1, seed); + var random = seed is null ? new Random() : new Random(seed.Value); + int index = random.Next(items + 1); + (array[items], array[index]) = (array[index], array[items]); + (array[items], array[index]) = (array[index], array[items]); + } + } +} diff --git a/README.md b/README.md index bd8490d3..ff928316 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,7 @@ find more than one implementation for the same objective but using different alg * [Fisher-Yates Shuffler](./Algorithms/Shufflers/FisherYatesShuffler.cs) * [LINQ Shuffler](./Algorithms/Shufflers/LinqShuffler.cs) * [Naive Shuffler](./Algorithms/Shufflers/NaiveShuffler.cs) + * [Recursive Shuffler](./Algorithms/Shufflers/RecursiveShuffler.cs) * [Sequences](./Algorithms/Sequences) * [A000002 Kolakoski](./Algorithms/Sequences/KolakoskiSequence.cs) * [A000004 Zero](./Algorithms/Sequences/ZeroSequence.cs) From 1b9aa7e90660b187dae7edc1624d74fc34d2beb0 Mon Sep 17 00:00:00 2001 From: Karan Chadha <72665232+KaranChadha10@users.noreply.github.com> Date: Sun, 7 Sep 2025 14:08:34 +0530 Subject: [PATCH 136/138] Migrate to file-scoped namespaces and remove unused global usings (#521) --- .../Numeric/AdditionWithoutArithmetic.cs | 3 - .../Numeric/KrishnamurthyNumberChecker.cs | 2 - Algorithms/Other/Geofence.cs | 51 +++-- Algorithms/Other/Geohash.cs | 117 ++++++------ Algorithms/Other/JulianEaster.cs | 1 - Algorithms/Other/Triangulator.cs | 84 ++++----- .../ISimilarityCalculator.cs | 4 - Algorithms/Shufflers/LINQShuffler.cs | 38 ++-- Algorithms/Shufflers/NaiveShuffler.cs | 41 ++-- Algorithms/Shufflers/RecursiveShuffler.cs | 69 ++++--- .../Sorters/Comparison/BasicTimSorter.cs | 176 +++++++++--------- Algorithms/Sorters/Utils/GallopingStrategy.cs | 147 +++++++-------- .../Stack/BalancedParenthesesChecker.cs | 127 +++++++------ Algorithms/Stack/NextGreaterElement.cs | 63 +++---- Algorithms/Stack/ReverseStack.cs | 59 +++--- DataStructures/Cache/LfuCache.cs | 1 - DataStructures/Cache/LruCache.cs | 1 - DataStructures/DisjointSet/DisjointSet.cs | 2 - DataStructures/Hashing/Entry.cs | 5 - .../Hashing/NumberTheory/PrimeNumber.cs | 4 - 20 files changed, 470 insertions(+), 525 deletions(-) diff --git a/Algorithms/Numeric/AdditionWithoutArithmetic.cs b/Algorithms/Numeric/AdditionWithoutArithmetic.cs index 7ec294b7..f85ea52d 100644 --- a/Algorithms/Numeric/AdditionWithoutArithmetic.cs +++ b/Algorithms/Numeric/AdditionWithoutArithmetic.cs @@ -1,6 +1,3 @@ -using System; -using System.Numerics; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/KrishnamurthyNumberChecker.cs b/Algorithms/Numeric/KrishnamurthyNumberChecker.cs index c4d245a0..a1e40991 100644 --- a/Algorithms/Numeric/KrishnamurthyNumberChecker.cs +++ b/Algorithms/Numeric/KrishnamurthyNumberChecker.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Other/Geofence.cs b/Algorithms/Other/Geofence.cs index 90fb9626..59afab77 100644 --- a/Algorithms/Other/Geofence.cs +++ b/Algorithms/Other/Geofence.cs @@ -1,37 +1,30 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Algorithms.Other; -namespace Algorithms.Other +public class Geofence { - public class Geofence - { - public double Latitude { get; set; } + public double Latitude { get; set; } - public double Longitude { get; set; } + public double Longitude { get; set; } - public double RadiusInMeters { get; set; } + public double RadiusInMeters { get; set; } - public Geofence(double latitude, double longitude, double radiusInMeters) - { - Latitude = latitude; - Longitude = longitude; - RadiusInMeters = radiusInMeters; - } + public Geofence(double latitude, double longitude, double radiusInMeters) + { + Latitude = latitude; + Longitude = longitude; + RadiusInMeters = radiusInMeters; + } - /// - /// Checks whether the provided user location (latitude and longitude) is within the geofence boundary. - /// The geofence is defined by a center point (latitude, longitude) and a radius in meters. - /// - /// The latitude of the user's current location. - /// The longitude of the user's current location. - /// Returns true if the user is inside the geofence, otherwise returns false. - public bool IsInside(double userLatitude, double userLongitude) - { - double distance = GeoLocation.CalculateDistanceFromLatLng(Latitude, Longitude, userLatitude, userLongitude); - return distance <= RadiusInMeters; - } + /// + /// Checks whether the provided user location (latitude and longitude) is within the geofence boundary. + /// The geofence is defined by a center point (latitude, longitude) and a radius in meters. + /// + /// The latitude of the user's current location. + /// The longitude of the user's current location. + /// Returns true if the user is inside the geofence, otherwise returns false. + public bool IsInside(double userLatitude, double userLongitude) + { + double distance = GeoLocation.CalculateDistanceFromLatLng(Latitude, Longitude, userLatitude, userLongitude); + return distance <= RadiusInMeters; } } diff --git a/Algorithms/Other/Geohash.cs b/Algorithms/Other/Geohash.cs index 53507f85..bde2a759 100644 --- a/Algorithms/Other/Geohash.cs +++ b/Algorithms/Other/Geohash.cs @@ -1,84 +1,79 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Other +namespace Algorithms.Other; + +public static class Geohash { - public static class Geohash + private const string Base32Characters = "0123456789bcdefghjkmnpqrstuvwxyz"; // Convert latitude and longitude coordinates into a concise string + private const int GeohashLength = 12; // ± 1.86 cm + + /// + /// Encodes the provided latitude and longitude coordinates into a Geohash string. + /// Geohashing is a method to encode geographic coordinates (latitude, longitude). + /// into a short string of letters and digits. Each character in the resulting Geohash . + /// string adds more precision to the location. The longer the Geohash, the smaller the area. + /// + /// The latitude of the location to encode. It must be a value between -90 and 90. + /// The longitude of the location to encode. It must be a value between -180 and 180. + /// + /// A Geohash string of length 12 representing the location with high precision. + /// A longer Geohash provides higher precision in terms of geographic area. + /// and a 12-character Geohash can be accurate down to around 1.86 cm. + /// + public static string Encode(double latitude, double longitude) { - private const string Base32Characters = "0123456789bcdefghjkmnpqrstuvwxyz"; // Convert latitude and longitude coordinates into a concise string - private const int GeohashLength = 12; // ± 1.86 cm + double[] latitudeRange = new[] { -90.0, 90.0 }; + double[] longitudeRange = new[] { -180.0, 180.0 }; + bool isEncodingLongitude = true; + int currentBit = 0; + int base32Index = 0; + StringBuilder geohashResult = new StringBuilder(); - /// - /// Encodes the provided latitude and longitude coordinates into a Geohash string. - /// Geohashing is a method to encode geographic coordinates (latitude, longitude). - /// into a short string of letters and digits. Each character in the resulting Geohash . - /// string adds more precision to the location. The longer the Geohash, the smaller the area. - /// - /// The latitude of the location to encode. It must be a value between -90 and 90. - /// The longitude of the location to encode. It must be a value between -180 and 180. - /// - /// A Geohash string of length 12 representing the location with high precision. - /// A longer Geohash provides higher precision in terms of geographic area. - /// and a 12-character Geohash can be accurate down to around 1.86 cm. - /// - public static string Encode(double latitude, double longitude) + while (geohashResult.Length < GeohashLength) { - double[] latitudeRange = new[] { -90.0, 90.0 }; - double[] longitudeRange = new[] { -180.0, 180.0 }; - bool isEncodingLongitude = true; - int currentBit = 0; - int base32Index = 0; - StringBuilder geohashResult = new StringBuilder(); + double midpoint; - while (geohashResult.Length < GeohashLength) + if (isEncodingLongitude) { - double midpoint; - - if (isEncodingLongitude) + midpoint = (longitudeRange[0] + longitudeRange[1]) / 2; + if (longitude > midpoint) { - midpoint = (longitudeRange[0] + longitudeRange[1]) / 2; - if (longitude > midpoint) - { - base32Index |= 1 << (4 - currentBit); - longitudeRange[0] = midpoint; - } - else - { - longitudeRange[1] = midpoint; - } + base32Index |= 1 << (4 - currentBit); + longitudeRange[0] = midpoint; } else { - midpoint = (latitudeRange[0] + latitudeRange[1]) / 2; - if (latitude > midpoint) - { - base32Index |= 1 << (4 - currentBit); - latitudeRange[0] = midpoint; - } - else - { - latitudeRange[1] = midpoint; - } + longitudeRange[1] = midpoint; } - - isEncodingLongitude = !isEncodingLongitude; - - if (currentBit < 4) + } + else + { + midpoint = (latitudeRange[0] + latitudeRange[1]) / 2; + if (latitude > midpoint) { - currentBit++; + base32Index |= 1 << (4 - currentBit); + latitudeRange[0] = midpoint; } else { - geohashResult.Append(Base32Characters[base32Index]); - currentBit = 0; - base32Index = 0; + latitudeRange[1] = midpoint; } } - return geohashResult.ToString(); + isEncodingLongitude = !isEncodingLongitude; + + if (currentBit < 4) + { + currentBit++; + } + else + { + geohashResult.Append(Base32Characters[base32Index]); + currentBit = 0; + base32Index = 0; + } } + + return geohashResult.ToString(); } } diff --git a/Algorithms/Other/JulianEaster.cs b/Algorithms/Other/JulianEaster.cs index a8649c26..7785f080 100644 --- a/Algorithms/Other/JulianEaster.cs +++ b/Algorithms/Other/JulianEaster.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; namespace Algorithms.Other; diff --git a/Algorithms/Other/Triangulator.cs b/Algorithms/Other/Triangulator.cs index a9cd27fc..dc7f9af0 100644 --- a/Algorithms/Other/Triangulator.cs +++ b/Algorithms/Other/Triangulator.cs @@ -1,55 +1,51 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Other +namespace Algorithms.Other; + +public class Triangulator { - public class Triangulator + public (double Latitude, double Longitude) CalculatePosition(List<(double Latitude, double Longitude)> baseLocations, List distances) { - public (double Latitude, double Longitude) CalculatePosition(List<(double Latitude, double Longitude)> baseLocations, List distances) + if (baseLocations.Count < 3 || distances.Count < 3) { - if (baseLocations.Count < 3 || distances.Count < 3) - { - throw new ArgumentException("At least three points and corresponding distances are required."); - } - - // Get the coordinates of the three base stations - double lat1 = baseLocations[0].Latitude; - double lon1 = baseLocations[0].Longitude; - double lat2 = baseLocations[1].Latitude; - double lon2 = baseLocations[1].Longitude; - double lat3 = baseLocations[2].Latitude; - double lon3 = baseLocations[2].Longitude; - - // Convert coordinates to radians - lat1 = ToRadians(lat1); - lon1 = ToRadians(lon1); - lat2 = ToRadians(lat2); - lon2 = ToRadians(lon2); - lat3 = ToRadians(lat3); - lon3 = ToRadians(lon3); - - // Calculate the center point - double centerLat = (lat1 + lat2 + lat3) / 3; - double centerLon = (lon1 + lon2 + lon3) / 3; - - // Convert back to degrees - centerLat = ToDegrees(centerLat); - centerLon = ToDegrees(centerLon); - - return (centerLat, centerLon); + throw new ArgumentException("At least three points and corresponding distances are required."); } - private double ToRadians(double degrees) - { - return degrees * Math.PI / 180; - } + // Get the coordinates of the three base stations + double lat1 = baseLocations[0].Latitude; + double lon1 = baseLocations[0].Longitude; + double lat2 = baseLocations[1].Latitude; + double lon2 = baseLocations[1].Longitude; + double lat3 = baseLocations[2].Latitude; + double lon3 = baseLocations[2].Longitude; + + // Convert coordinates to radians + lat1 = ToRadians(lat1); + lon1 = ToRadians(lon1); + lat2 = ToRadians(lat2); + lon2 = ToRadians(lon2); + lat3 = ToRadians(lat3); + lon3 = ToRadians(lon3); + + // Calculate the center point + double centerLat = (lat1 + lat2 + lat3) / 3; + double centerLon = (lon1 + lon2 + lon3) / 3; + + // Convert back to degrees + centerLat = ToDegrees(centerLat); + centerLon = ToDegrees(centerLon); + + return (centerLat, centerLon); + } - private double ToDegrees(double radians) - { - return radians * 180 / Math.PI; - } + private double ToRadians(double degrees) + { + return degrees * Math.PI / 180; + } + + private double ToDegrees(double radians) + { + return radians * 180 / Math.PI; } } diff --git a/Algorithms/RecommenderSystem/ISimilarityCalculator.cs b/Algorithms/RecommenderSystem/ISimilarityCalculator.cs index e055a3c7..5add6c9d 100644 --- a/Algorithms/RecommenderSystem/ISimilarityCalculator.cs +++ b/Algorithms/RecommenderSystem/ISimilarityCalculator.cs @@ -1,8 +1,4 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Algorithms.RecommenderSystem { diff --git a/Algorithms/Shufflers/LINQShuffler.cs b/Algorithms/Shufflers/LINQShuffler.cs index a3eb6b39..542c0101 100644 --- a/Algorithms/Shufflers/LINQShuffler.cs +++ b/Algorithms/Shufflers/LINQShuffler.cs @@ -1,30 +1,26 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Shufflers +namespace Algorithms.Shufflers; + +/// +/// LINQ Shuffle is a simple shuffling algorithm, +/// where the elements within a collection are shuffled using +/// LINQ queries and lambda expressions in C#. +/// +/// Type array input. +public class LinqShuffler { /// - /// LINQ Shuffle is a simple shuffling algorithm, - /// where the elements within a collection are shuffled using - /// LINQ queries and lambda expressions in C#. + /// First, it will generate a random value for each element. + /// Next, it will sort the elements based on these generated + /// random numbers using OrderBy. /// - /// Type array input. - public class LinqShuffler + /// Array to shuffle. + /// Random generator seed. Used to repeat the shuffle. + public T[] Shuffle(T[] array, int? seed = null) { - /// - /// First, it will generate a random value for each element. - /// Next, it will sort the elements based on these generated - /// random numbers using OrderBy. - /// - /// Array to shuffle. - /// Random generator seed. Used to repeat the shuffle. - public T[] Shuffle(T[] array, int? seed = null) - { - var random = seed is null ? new Random() : new Random(seed.Value); - return array.OrderBy(x => random.Next()).ToArray(); - } + var random = seed is null ? new Random() : new Random(seed.Value); + return array.OrderBy(x => random.Next()).ToArray(); } } diff --git a/Algorithms/Shufflers/NaiveShuffler.cs b/Algorithms/Shufflers/NaiveShuffler.cs index 94e10d18..c50f56f6 100644 --- a/Algorithms/Shufflers/NaiveShuffler.cs +++ b/Algorithms/Shufflers/NaiveShuffler.cs @@ -1,31 +1,30 @@ using System; -namespace Algorithms.Shufflers +namespace Algorithms.Shufflers; + +/// +/// Naive Shuffle is a simple and incorrect shuffling algorithm +/// that randomly swaps every element with any other element in the array. +/// +/// Type array input. +public class NaiveShuffler : IShuffler { /// - /// Naive Shuffle is a simple and incorrect shuffling algorithm - /// that randomly swaps every element with any other element in the array. + /// First, it loop from 0 to n - 1. + /// Next, it will randomly pick any j in the array. + /// Lastly, it will swap array[i] with array[j]. /// - /// Type array input. - public class NaiveShuffler : IShuffler + /// Array to shuffle. + /// Random generator seed. Used to repeat the shuffle. + public void Shuffle(T[] array, int? seed = null) { - /// - /// First, it loop from 0 to n - 1. - /// Next, it will randomly pick any j in the array. - /// Lastly, it will swap array[i] with array[j]. - /// - /// Array to shuffle. - /// Random generator seed. Used to repeat the shuffle. - public void Shuffle(T[] array, int? seed = null) + var random = seed is null ? new Random() : new Random(seed.Value); + for (int i = 0; i < array.Length; i++) { - var random = seed is null ? new Random() : new Random(seed.Value); - for(int i = 0; i < array.Length; i++) - { - int j = random.Next(array.Length); - T temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } + int j = random.Next(array.Length); + T temp = array[i]; + array[i] = array[j]; + array[j] = temp; } } } diff --git a/Algorithms/Shufflers/RecursiveShuffler.cs b/Algorithms/Shufflers/RecursiveShuffler.cs index 4a367e1b..6ff315ca 100644 --- a/Algorithms/Shufflers/RecursiveShuffler.cs +++ b/Algorithms/Shufflers/RecursiveShuffler.cs @@ -1,46 +1,45 @@ using System; -namespace Algorithms.Shufflers +namespace Algorithms.Shufflers; + +/// +/// Recursive Shuffler is a recursive version of +/// Fisher-Yates shuffle algorithm. This can only be used +/// for educational purposes due to stack depth limits. +/// +/// Type array input. +public class RecursiveShuffler : IShuffler { /// - /// Recursive Shuffler is a recursive version of - /// Fisher-Yates shuffle algorithm. This can only be used - /// for educational purposes due to stack depth limits. + /// This is the public overload method that calls the private overload method. /// - /// Type array input. - public class RecursiveShuffler : IShuffler + /// Array to shuffle. + /// Random generator seed. Used to repeat the shuffle. + public void Shuffle(T[] array, int? seed = null) { - /// - /// This is the public overload method that calls the private overload method. - /// - /// Array to shuffle. - /// Random generator seed. Used to repeat the shuffle. - public void Shuffle(T[] array, int? seed = null) - { - Shuffle(array, array.Length - 1, seed); - } + Shuffle(array, array.Length - 1, seed); + } - /// - /// First, it will check the length of the array on the base case. - /// Next, if there's still items left, it will shuffle the sub-array. - /// Lastly, it will randomly select index from 0 to number of items of the array - /// then swap the elements array[items] and array[index]. - /// - /// Array to shuffle. - /// Number of items in the array. - /// Random generator seed. Used to repeat the shuffle. - private void Shuffle(T[] array, int items, int? seed) + /// + /// First, it will check the length of the array on the base case. + /// Next, if there's still items left, it will shuffle the sub-array. + /// Lastly, it will randomly select index from 0 to number of items of the array + /// then swap the elements array[items] and array[index]. + /// + /// Array to shuffle. + /// Number of items in the array. + /// Random generator seed. Used to repeat the shuffle. + private void Shuffle(T[] array, int items, int? seed) + { + if (items <= 0) { - if (items <= 0) - { - return; - } - - Shuffle(array, items - 1, seed); - var random = seed is null ? new Random() : new Random(seed.Value); - int index = random.Next(items + 1); - (array[items], array[index]) = (array[index], array[items]); - (array[items], array[index]) = (array[index], array[items]); + return; } + + Shuffle(array, items - 1, seed); + var random = seed is null ? new Random() : new Random(seed.Value); + int index = random.Next(items + 1); + (array[items], array[index]) = (array[index], array[items]); + (array[items], array[index]) = (array[index], array[items]); } } diff --git a/Algorithms/Sorters/Comparison/BasicTimSorter.cs b/Algorithms/Sorters/Comparison/BasicTimSorter.cs index 2ca6fb33..c278dcd5 100644 --- a/Algorithms/Sorters/Comparison/BasicTimSorter.cs +++ b/Algorithms/Sorters/Comparison/BasicTimSorter.cs @@ -1,120 +1,118 @@ using System; -using System.Collections; using System.Collections.Generic; -namespace Algorithms.Sorters.Comparison +namespace Algorithms.Sorters.Comparison; + +/// +/// A basic implementation of the TimSort algorithm for sorting arrays. +/// +/// The type of elements in the array. +public class BasicTimSorter { + private readonly int minRuns = 32; + private readonly IComparer comparer; + + /// + /// Initializes a new instance of the class. + /// + /// The comparer to use for comparing elements. + public BasicTimSorter(IComparer comparer) + { + this.comparer = comparer ?? Comparer.Default; + } + /// - /// A basic implementation of the TimSort algorithm for sorting arrays. + /// Sorts the specified array using the TimSort algorithm. /// - /// The type of elements in the array. - public class BasicTimSorter + /// The array to sort. + public void Sort(T[] array) { - private readonly int minRuns = 32; - private readonly IComparer comparer; - - /// - /// Initializes a new instance of the class. - /// - /// The comparer to use for comparing elements. - public BasicTimSorter(IComparer comparer) + var n = array.Length; + + // Step 1: Sort small pieces of the array using Insertion Sort + for (var i = 0; i < n; i += minRuns) { - this.comparer = comparer ?? Comparer.Default; + InsertionSort(array, i, Math.Min(i + minRuns - 1, n - 1)); } - /// - /// Sorts the specified array using the TimSort algorithm. - /// - /// The array to sort. - public void Sort(T[] array) + // Step 2: Merge sorted runs using Merge Sort + for (var size = minRuns; size < n; size *= 2) { - var n = array.Length; - - // Step 1: Sort small pieces of the array using Insertion Sort - for (var i = 0; i < n; i += minRuns) + for (var left = 0; left < n; left += 2 * size) { - InsertionSort(array, i, Math.Min(i + minRuns - 1, n - 1)); - } + var mid = left + size - 1; + var right = Math.Min(left + 2 * size - 1, n - 1); - // Step 2: Merge sorted runs using Merge Sort - for (var size = minRuns; size < n; size *= 2) - { - for (var left = 0; left < n; left += 2 * size) + if (mid < right) { - var mid = left + size - 1; - var right = Math.Min(left + 2 * size - 1, n - 1); - - if (mid < right) - { - Merge(array, left, mid, right); - } + Merge(array, left, mid, right); } } } + } - /// - /// Sorts a portion of the array using the Insertion Sort algorithm. - /// - /// The array to sort. - /// The starting index of the portion to sort. - /// The ending index of the portion to sort. - private void InsertionSort(T[] array, int left, int right) + /// + /// Sorts a portion of the array using the Insertion Sort algorithm. + /// + /// The array to sort. + /// The starting index of the portion to sort. + /// The ending index of the portion to sort. + private void InsertionSort(T[] array, int left, int right) + { + for (var i = left + 1; i <= right; i++) { - for (var i = left + 1; i <= right; i++) - { - var key = array[i]; - var j = i - 1; - - // Move elements of array[0..i-1], that are greater than key, - // to one position ahead of their current position - while (j >= left && comparer.Compare(array[j], key) > 0) - { - array[j + 1] = array[j]; - j--; - } + var key = array[i]; + var j = i - 1; - array[j + 1] = key; + // Move elements of array[0..i-1], that are greater than key, + // to one position ahead of their current position + while (j >= left && comparer.Compare(array[j], key) > 0) + { + array[j + 1] = array[j]; + j--; } + + array[j + 1] = key; } + } - /// - /// Merges two sorted subarrays into a single sorted subarray. - /// - /// The array containing the subarrays to merge. - /// The starting index of the first subarray. - /// The ending index of the first subarray. - /// The ending index of the second subarray. - private void Merge(T[] array, int left, int mid, int right) - { - // Create segments for left and right subarrays - var leftSegment = new ArraySegment(array, left, mid - left + 1); - var rightSegment = new ArraySegment(array, mid + 1, right - mid); + /// + /// Merges two sorted subarrays into a single sorted subarray. + /// + /// The array containing the subarrays to merge. + /// The starting index of the first subarray. + /// The ending index of the first subarray. + /// The ending index of the second subarray. + private void Merge(T[] array, int left, int mid, int right) + { + // Create segments for left and right subarrays + var leftSegment = new ArraySegment(array, left, mid - left + 1); + var rightSegment = new ArraySegment(array, mid + 1, right - mid); - // Convert segments to arrays - var leftArray = leftSegment.ToArray(); - var rightArray = rightSegment.ToArray(); + // Convert segments to arrays + var leftArray = leftSegment.ToArray(); + var rightArray = rightSegment.ToArray(); - var i = 0; - var j = 0; - var k = left; + var i = 0; + var j = 0; + var k = left; - // Merge the two subarrays back into the main array - while (i < leftArray.Length && j < rightArray.Length) - { - array[k++] = comparer.Compare(leftArray[i], rightArray[j]) <= 0 ? leftArray[i++] : rightArray[j++]; - } + // Merge the two subarrays back into the main array + while (i < leftArray.Length && j < rightArray.Length) + { + array[k++] = comparer.Compare(leftArray[i], rightArray[j]) <= 0 ? leftArray[i++] : rightArray[j++]; + } - // Copy remaining elements from leftArray, if any - while (i < leftArray.Length) - { - array[k++] = leftArray[i++]; - } + // Copy remaining elements from leftArray, if any + while (i < leftArray.Length) + { + array[k++] = leftArray[i++]; + } - // Copy remaining elements from rightArray, if any - while (j < rightArray.Length) - { - array[k++] = rightArray[j++]; - } + // Copy remaining elements from rightArray, if any + while (j < rightArray.Length) + { + array[k++] = rightArray[j++]; } } } diff --git a/Algorithms/Sorters/Utils/GallopingStrategy.cs b/Algorithms/Sorters/Utils/GallopingStrategy.cs index 4c4ddc02..05f22272 100644 --- a/Algorithms/Sorters/Utils/GallopingStrategy.cs +++ b/Algorithms/Sorters/Utils/GallopingStrategy.cs @@ -1,106 +1,101 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Algorithms.Sorters.Utils +namespace Algorithms.Sorters.Utils; + +public static class GallopingStrategy { - public static class GallopingStrategy + public static int GallopLeft(T[] array, T key, int baseIndex, int length, IComparer comparer) { - public static int GallopLeft(T[] array, T key, int baseIndex, int length, IComparer comparer) + if (array.Length == 0) { - if (array.Length == 0) - { - return 0; - } + return 0; + } - var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) > 0 - ? RightRun(array, key, baseIndex, length, 0, comparer) - : LeftRun(array, key, baseIndex, 0, comparer); + var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) > 0 + ? RightRun(array, key, baseIndex, length, 0, comparer) + : LeftRun(array, key, baseIndex, 0, comparer); - return FinalOffset(array, key, baseIndex, offset, lastOfs, 1, comparer); - } + return FinalOffset(array, key, baseIndex, offset, lastOfs, 1, comparer); + } - public static int GallopRight(T[] array, T key, int baseIndex, int length, IComparer comparer) + public static int GallopRight(T[] array, T key, int baseIndex, int length, IComparer comparer) + { + if (array.Length == 0) { - if (array.Length == 0) - { - return 0; - } + return 0; + } - var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) < 0 - ? LeftRun(array, key, baseIndex, length, comparer) - : RightRun(array, key, baseIndex, length, 0, comparer); + var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) < 0 + ? LeftRun(array, key, baseIndex, length, comparer) + : RightRun(array, key, baseIndex, length, 0, comparer); - return FinalOffset(array, key, baseIndex, offset, lastOfs, 0, comparer); - } + return FinalOffset(array, key, baseIndex, offset, lastOfs, 0, comparer); + } - public static int BoundLeftShift(int shiftable) => (shiftable << 1) < 0 - ? (shiftable << 1) + 1 - : int.MaxValue; + public static int BoundLeftShift(int shiftable) => (shiftable << 1) < 0 + ? (shiftable << 1) + 1 + : int.MaxValue; - private static (int Offset, int LastOfs) LeftRun(T[] array, T key, int baseIndex, int hint, IComparer comparer) + private static (int Offset, int LastOfs) LeftRun(T[] array, T key, int baseIndex, int hint, IComparer comparer) + { + var maxOfs = hint + 1; + var (offset, tmp) = (1, 0); + + while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint - offset]) < 0) { - var maxOfs = hint + 1; - var (offset, tmp) = (1, 0); + tmp = offset; + offset = BoundLeftShift(offset); + } - while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint - offset]) < 0) - { - tmp = offset; - offset = BoundLeftShift(offset); - } + if (offset > maxOfs) + { + offset = maxOfs; + } - if (offset > maxOfs) - { - offset = maxOfs; - } + var lastOfs = hint - offset; + offset = hint - tmp; - var lastOfs = hint - offset; - offset = hint - tmp; + return (offset, lastOfs); + } - return (offset, lastOfs); + private static (int Offset, int LastOfs) RightRun(T[] array, T key, int baseIndex, int len, int hint, IComparer comparer) + { + var (offset, lastOfs) = (1, 0); + var maxOfs = len - hint; + while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint + offset]) > 0) + { + lastOfs = offset; + offset = BoundLeftShift(offset); } - private static (int Offset, int LastOfs) RightRun(T[] array, T key, int baseIndex, int len, int hint, IComparer comparer) + if (offset > maxOfs) { - var (offset, lastOfs) = (1, 0); - var maxOfs = len - hint; - while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint + offset]) > 0) - { - lastOfs = offset; - offset = BoundLeftShift(offset); - } - - if (offset > maxOfs) - { - offset = maxOfs; - } + offset = maxOfs; + } - offset += hint; - lastOfs += hint; + offset += hint; + lastOfs += hint; - return (offset, lastOfs); - } + return (offset, lastOfs); + } - private static int FinalOffset(T[] array, T key, int baseIndex, int offset, int lastOfs, int lt, IComparer comparer) + private static int FinalOffset(T[] array, T key, int baseIndex, int offset, int lastOfs, int lt, IComparer comparer) + { + lastOfs++; + while (lastOfs < offset) { - lastOfs++; - while (lastOfs < offset) + var m = lastOfs + (int)((uint)(offset - lastOfs) >> 1); + + if (comparer.Compare(key, array[baseIndex + m]) < lt) { - var m = lastOfs + (int)((uint)(offset - lastOfs) >> 1); - - if (comparer.Compare(key, array[baseIndex + m]) < lt) - { - offset = m; - } - else - { - lastOfs = m + 1; - } + offset = m; + } + else + { + lastOfs = m + 1; } - - return offset; } + + return offset; } } diff --git a/Algorithms/Stack/BalancedParenthesesChecker.cs b/Algorithms/Stack/BalancedParenthesesChecker.cs index 2f2b8311..0b889933 100644 --- a/Algorithms/Stack/BalancedParenthesesChecker.cs +++ b/Algorithms/Stack/BalancedParenthesesChecker.cs @@ -1,90 +1,89 @@ using System; using System.Collections.Generic; -namespace Algorithms.Stack +namespace Algorithms.Stack; + +/// +/// It checks if an expression has matching and balanced parentheses. +/// @author Mohit Singh. mohit-gogitter +/// +public class BalancedParenthesesChecker { - /// - /// It checks if an expression has matching and balanced parentheses. - /// @author Mohit Singh. mohit-gogitter - /// - public class BalancedParenthesesChecker - { - private static readonly Dictionary ParenthesesMap = new Dictionary + private static readonly Dictionary ParenthesesMap = new Dictionary { { '(', ')' }, { '{', '}' }, { '[', ']' }, }; - /// - /// Determines if a given string expression containing brackets is balanced. - /// A string is considered balanced if all opening brackets have corresponding closing brackets - /// in the correct order. The supported brackets are '()', '{}', and '[]'. - /// - /// - /// The input string expression containing the brackets to check for balance. - /// - /// - /// true if the brackets in the expression are balanced; otherwise, false. - /// - /// - /// Thrown when the input expression contains invalid characters or is null/empty. - /// Only '(', ')', '{', '}', '[', ']' characters are allowed. - /// - public bool IsBalanced(string expression) + /// + /// Determines if a given string expression containing brackets is balanced. + /// A string is considered balanced if all opening brackets have corresponding closing brackets + /// in the correct order. The supported brackets are '()', '{}', and '[]'. + /// + /// + /// The input string expression containing the brackets to check for balance. + /// + /// + /// true if the brackets in the expression are balanced; otherwise, false. + /// + /// + /// Thrown when the input expression contains invalid characters or is null/empty. + /// Only '(', ')', '{', '}', '[', ']' characters are allowed. + /// + public bool IsBalanced(string expression) + { + if (string.IsNullOrEmpty(expression)) + { + throw new ArgumentException("The input expression cannot be null or empty."); + } + + Stack stack = new Stack(); + foreach (char c in expression) { - if (string.IsNullOrEmpty(expression)) + if (IsOpeningParenthesis(c)) { - throw new ArgumentException("The input expression cannot be null or empty."); + stack.Push(c); } - - Stack stack = new Stack(); - foreach (char c in expression) + else if (IsClosingParenthesis(c)) { - if (IsOpeningParenthesis(c)) - { - stack.Push(c); - } - else if (IsClosingParenthesis(c)) - { - if (!IsBalancedClosing(stack, c)) - { - return false; - } - } - else + if (!IsBalancedClosing(stack, c)) { - throw new ArgumentException($"Invalid character '{c}' found in the expression."); + return false; } } - - return stack.Count == 0; - } - - private static bool IsOpeningParenthesis(char c) - { - return c == '(' || c == '{' || c == '['; + else + { + throw new ArgumentException($"Invalid character '{c}' found in the expression."); + } } - private static bool IsClosingParenthesis(char c) - { - return c == ')' || c == '}' || c == ']'; - } + return stack.Count == 0; + } - private static bool IsBalancedClosing(Stack stack, char close) - { - if (stack.Count == 0) - { - return false; - } + private static bool IsOpeningParenthesis(char c) + { + return c == '(' || c == '{' || c == '['; + } - char open = stack.Pop(); - return IsMatchingPair(open, close); - } + private static bool IsClosingParenthesis(char c) + { + return c == ')' || c == '}' || c == ']'; + } - private static bool IsMatchingPair(char open, char close) + private static bool IsBalancedClosing(Stack stack, char close) + { + if (stack.Count == 0) { - return ParenthesesMap.ContainsKey(open) && ParenthesesMap[open] == close; + return false; } + + char open = stack.Pop(); + return IsMatchingPair(open, close); + } + + private static bool IsMatchingPair(char open, char close) + { + return ParenthesesMap.ContainsKey(open) && ParenthesesMap[open] == close; } } diff --git a/Algorithms/Stack/NextGreaterElement.cs b/Algorithms/Stack/NextGreaterElement.cs index 0e5bbecb..c2d728a7 100644 --- a/Algorithms/Stack/NextGreaterElement.cs +++ b/Algorithms/Stack/NextGreaterElement.cs @@ -1,47 +1,46 @@ using System; using System.Collections.Generic; -namespace Algorithms.Stack +namespace Algorithms.Stack; + +/// +/// For each element in an array, the utility finds the next greater element on the right side using a stack. +/// @author Mohit Singh. mohit-gogitter +/// +public class NextGreaterElement { /// - /// For each element in an array, the utility finds the next greater element on the right side using a stack. - /// @author Mohit Singh. mohit-gogitter + /// Finds the next greater element for each element in the input array. + /// The next greater element for an element x is the first element greater than x to its right. + /// If there is no greater element, -1 is returned for that element. /// - public class NextGreaterElement + /// The array of integers to find the next greater elements for. + /// An array where each index contains the next greater element of the corresponding element in the input array, or -1 if no such element exists. + /// Thrown when the input array is null. + public int[] FindNextGreaterElement(int[] nums) { - /// - /// Finds the next greater element for each element in the input array. - /// The next greater element for an element x is the first element greater than x to its right. - /// If there is no greater element, -1 is returned for that element. - /// - /// The array of integers to find the next greater elements for. - /// An array where each index contains the next greater element of the corresponding element in the input array, or -1 if no such element exists. - /// Thrown when the input array is null. - public int[] FindNextGreaterElement(int[] nums) - { - int[] result = new int[nums.Length]; - Stack stack = new Stack(); + int[] result = new int[nums.Length]; + Stack stack = new Stack(); - // Initialize all elements in the result array to -1 - for (int i = 0; i < nums.Length; i++) - { - result[i] = -1; - } + // Initialize all elements in the result array to -1 + for (int i = 0; i < nums.Length; i++) + { + result[i] = -1; + } - for (int i = 0; i < nums.Length; i++) + for (int i = 0; i < nums.Length; i++) + { + // While the stack is not empty and the current element is greater than the element + // corresponding to the index stored at the top of the stack + while (stack.Count > 0 && nums[i] > nums[stack.Peek()]) { - // While the stack is not empty and the current element is greater than the element - // corresponding to the index stored at the top of the stack - while (stack.Count > 0 && nums[i] > nums[stack.Peek()]) - { - int index = stack.Pop(); - result[index] = nums[i]; // Set the next greater element - } - - stack.Push(i); // Push current index to stack + int index = stack.Pop(); + result[index] = nums[i]; // Set the next greater element } - return result; + stack.Push(i); // Push current index to stack } + + return result; } } diff --git a/Algorithms/Stack/ReverseStack.cs b/Algorithms/Stack/ReverseStack.cs index af2f4e26..081f8aec 100644 --- a/Algorithms/Stack/ReverseStack.cs +++ b/Algorithms/Stack/ReverseStack.cs @@ -1,44 +1,43 @@ using System; using System.Collections.Generic; -namespace Algorithms.Stack +namespace Algorithms.Stack; + +/// +/// Reverses the elements in a stack using recursion. +/// @author Mohit Singh. mohit-gogitter +/// +public class ReverseStack { /// - /// Reverses the elements in a stack using recursion. - /// @author Mohit Singh. mohit-gogitter + /// Recursively reverses the elements of the specified stack. /// - public class ReverseStack + /// The type of elements in the stack. + /// The stack to be reversed. This parameter cannot be null. + /// Thrown when the stack parameter is null. + public void Reverse(Stack stack) { - /// - /// Recursively reverses the elements of the specified stack. - /// - /// The type of elements in the stack. - /// The stack to be reversed. This parameter cannot be null. - /// Thrown when the stack parameter is null. - public void Reverse(Stack stack) + if (stack.Count == 0) { - if (stack.Count == 0) - { - return; - } - - T temp = stack.Pop(); - Reverse(stack); - InsertAtBottom(stack, temp); + return; } - private void InsertAtBottom(Stack stack, T value) + T temp = stack.Pop(); + Reverse(stack); + InsertAtBottom(stack, temp); + } + + private void InsertAtBottom(Stack stack, T value) + { + if (stack.Count == 0) + { + stack.Push(value); + } + else { - if (stack.Count == 0) - { - stack.Push(value); - } - else - { - T temp = stack.Pop(); - InsertAtBottom(stack, value); - stack.Push(temp); - } + T temp = stack.Pop(); + InsertAtBottom(stack, value); + stack.Push(temp); } } } diff --git a/DataStructures/Cache/LfuCache.cs b/DataStructures/Cache/LfuCache.cs index 93f9ffd0..546fcc1b 100644 --- a/DataStructures/Cache/LfuCache.cs +++ b/DataStructures/Cache/LfuCache.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; namespace DataStructures.Cache; diff --git a/DataStructures/Cache/LruCache.cs b/DataStructures/Cache/LruCache.cs index 9bbbbce3..185eaf3a 100644 --- a/DataStructures/Cache/LruCache.cs +++ b/DataStructures/Cache/LruCache.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; namespace DataStructures.Cache; diff --git a/DataStructures/DisjointSet/DisjointSet.cs b/DataStructures/DisjointSet/DisjointSet.cs index 1f7b6618..2b03b134 100644 --- a/DataStructures/DisjointSet/DisjointSet.cs +++ b/DataStructures/DisjointSet/DisjointSet.cs @@ -1,5 +1,3 @@ -using System.Collections; - namespace DataStructures.DisjointSet; /// diff --git a/DataStructures/Hashing/Entry.cs b/DataStructures/Hashing/Entry.cs index e7afe8f4..745e4aa7 100644 --- a/DataStructures/Hashing/Entry.cs +++ b/DataStructures/Hashing/Entry.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using DataStructures.Hashing.NumberTheory; - namespace DataStructures.Hashing; /// diff --git a/DataStructures/Hashing/NumberTheory/PrimeNumber.cs b/DataStructures/Hashing/NumberTheory/PrimeNumber.cs index 3dc55e26..412ff022 100644 --- a/DataStructures/Hashing/NumberTheory/PrimeNumber.cs +++ b/DataStructures/Hashing/NumberTheory/PrimeNumber.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; - namespace DataStructures.Hashing.NumberTheory; /// From 767c45a3e5fec99a4621fd99da9ea8d4877a2a4c Mon Sep 17 00:00:00 2001 From: Karan Chadha <72665232+KaranChadha10@users.noreply.github.com> Date: Mon, 8 Sep 2025 16:17:39 +0530 Subject: [PATCH 137/138] Add GlobalUsings.cs with project-wide using directives for Algorithms folder (#522) --- Algorithms/Crypto/Digests/AsconDigest.cs | 1 - Algorithms/Crypto/Digests/IDigest.cs | 2 -- Algorithms/Crypto/Digests/Md2Digest.cs | 4 +--- .../Crypto/Exceptions/CryptoException.cs | 2 -- .../Crypto/Exceptions/DataLengthException.cs | 2 -- .../Exceptions/OutputLengthException.cs | 2 -- .../Crypto/Paddings/IBlockCipherPadding.cs | 4 +--- .../Crypto/Paddings/Iso10126D2Padding.cs | 5 +---- .../Crypto/Paddings/Iso7816D4Padding.cs | 4 +--- Algorithms/Crypto/Paddings/Pkcs7Padding.cs | 4 +--- Algorithms/Crypto/Paddings/TbcPadding.cs | 4 +--- Algorithms/Crypto/Paddings/X932Padding.cs | 5 +---- Algorithms/Crypto/Utils/ByteEncodingUtils.cs | 1 - Algorithms/Crypto/Utils/LongUtils.cs | 2 -- Algorithms/Crypto/Utils/ValidationUtils.cs | 2 -- .../BurrowsWheelerTransform.cs | 3 --- .../DataCompression/HuffmanCompressor.cs | 4 ---- .../DataCompression/ShannonFanoCompressor.cs | 3 --- Algorithms/DataCompression/Translator.cs | 3 --- Algorithms/Encoders/AutokeyEncorder.cs | 9 ++------ Algorithms/Encoders/BlowfishEncoder.cs | 6 +----- Algorithms/Encoders/CaesarEncoder.cs | 2 -- Algorithms/Encoders/FeistelCipher.cs | 10 +++------ Algorithms/Encoders/HillEncoder.cs | 2 -- Algorithms/Encoders/NysiisEncoder.cs | 4 ---- Algorithms/Encoders/SoundexEncoder.cs | 3 --- Algorithms/Encoders/VigenereEncoder.cs | 3 --- Algorithms/Financial/PresentValue.cs | 4 ---- Algorithms/GlobalUsings.cs | 21 +++++++++++++++++++ Algorithms/Graph/BellmanFord.cs | 2 -- Algorithms/Graph/BreadthFirstSearch.cs | 2 -- Algorithms/Graph/BreadthFirstTreeTraversal.cs | 2 -- Algorithms/Graph/DepthFirstSearch.cs | 2 -- .../Graph/Dijkstra/DijkstraAlgorithm.cs | 5 +---- Algorithms/Graph/FloydWarshall.cs | 1 - Algorithms/Graph/IGraphSearch.cs | 1 - Algorithms/Graph/Kosaraju.cs | 2 -- .../Graph/MinimumSpanningTree/Kruskal.cs | 4 +--- .../Graph/MinimumSpanningTree/PrimMatrix.cs | 2 -- .../Knapsack/BranchAndBoundKnapsackSolver.cs | 6 +----- .../DynamicProgrammingKnapsackSolver.cs | 3 --- .../Knapsack/IHeuristicKnapsackSolver.cs | 2 -- Algorithms/Knapsack/NaiveKnapsackSolver.cs | 3 --- .../LinearAlgebra/Distances/Chebyshev.cs | 3 --- .../LinearAlgebra/Distances/Euclidean.cs | 3 --- .../LinearAlgebra/Distances/Manhattan.cs | 3 --- .../LinearAlgebra/Distances/Minkowski.cs | 3 --- .../Eigenvalue/PowerIteration.cs | 4 ---- .../ChineseRemainderTheorem.cs | 5 ----- .../ExtendedEuclideanAlgorithm.cs | 2 -- .../ModularMultiplicativeInverse.cs | 3 --- Algorithms/NewtonSquareRoot.cs | 5 +---- Algorithms/Numeric/Abs.cs | 3 --- Algorithms/Numeric/AliquotSumCalculator.cs | 2 -- Algorithms/Numeric/AutomorphicNumber.cs | 5 ----- Algorithms/Numeric/BinomialCoefficient.cs | 3 --- Algorithms/Numeric/Ceil.cs | 3 --- Algorithms/Numeric/Decomposition/LU.cs | 2 -- Algorithms/Numeric/Decomposition/ThinSVD.cs | 3 --- Algorithms/Numeric/EulerMethod.cs | 3 --- Algorithms/Numeric/Factorial.cs | 3 --- .../Factorization/TrialDivisionFactorizer.cs | 3 --- Algorithms/Numeric/Floor.cs | 3 --- Algorithms/Numeric/GaussJordanElimination.cs | 2 -- .../BinaryGreatestCommonDivisorFinder.cs | 2 -- Algorithms/Numeric/JosephusProblem.cs | 4 +--- Algorithms/Numeric/KeithNumberChecker.cs | 2 -- .../Numeric/MillerRabinPrimalityChecker.cs | 3 --- Algorithms/Numeric/ModularExponentiation.cs | 2 -- .../Numeric/NarcissisticNumberChecker.cs | 2 -- Algorithms/Numeric/PerfectCubeChecker.cs | 2 -- Algorithms/Numeric/PerfectNumberChecker.cs | 2 -- Algorithms/Numeric/PerfectSquareChecker.cs | 2 -- .../Numeric/Pseudoinverse/PseudoInverse.cs | 2 -- Algorithms/Numeric/RungeKuttaMethod.cs | 3 --- Algorithms/Numeric/Series/Maclaurin.cs | 3 --- Algorithms/Numeric/SoftMax.cs | 2 -- Algorithms/Other/DecisionsConvolutions.cs | 3 --- Algorithms/Other/FermatPrimeChecker.cs | 3 --- Algorithms/Other/FloodFill.cs | 2 -- Algorithms/Other/GaussOptimization.cs | 4 ---- Algorithms/Other/GeoLocation.cs | 2 -- Algorithms/Other/Geohash.cs | 2 -- Algorithms/Other/Int2Binary.cs | 2 -- Algorithms/Other/JulianEaster.cs | 2 -- Algorithms/Other/KochSnowflake.cs | 3 --- Algorithms/Other/Luhn.cs | 2 -- Algorithms/Other/Mandelbrot.cs | 1 - Algorithms/Other/ParetoOptimization.cs | 3 --- Algorithms/Other/PollardsRhoFactorizing.cs | 1 - Algorithms/Other/RGBHSVConversion.cs | 2 -- Algorithms/Other/SieveOfEratosthenes.cs | 9 +++----- Algorithms/Other/Triangulator.cs | 3 --- .../CoinChange/DynamicCoinChangeSolver.cs | 4 ---- .../LevenshteinDistance.cs | 4 +--- .../NQueens/BacktrackingNQueensSolver.cs | 3 --- .../Problems/StableMarriage/Accepter.cs | 2 -- .../Problems/StableMarriage/GaleShapley.cs | 4 ---- .../Problems/StableMarriage/Proposer.cs | 2 -- .../CollaborativeFiltering.cs | 4 ---- .../ISimilarityCalculator.cs | 2 -- Algorithms/Search/AStar/AStar.cs | 2 -- Algorithms/Search/AStar/Node.cs | 2 -- .../Search/AStar/PathfindingException.cs | 2 -- Algorithms/Search/AStar/PriorityQueue.cs | 3 --- Algorithms/Search/AStar/VecN.cs | 2 -- Algorithms/Search/BinarySearcher.cs | 2 -- Algorithms/Search/BoyerMoore.cs | 4 ---- Algorithms/Search/FastSearcher.cs | 1 - Algorithms/Search/FibonacciSearcher.cs | 2 -- Algorithms/Search/JumpSearcher.cs | 2 -- Algorithms/Search/LinearSearcher.cs | 1 - Algorithms/Search/RecursiveBinarySearcher.cs | 3 --- Algorithms/Sequences/AllOnesSequence.cs | 3 --- Algorithms/Sequences/AllThreesSequence.cs | 3 --- Algorithms/Sequences/AllTwosSequence.cs | 3 --- .../Sequences/BinaryPrimeConstantSequence.cs | 3 --- Algorithms/Sequences/BinomialSequence.cs | 3 --- Algorithms/Sequences/CakeNumbersSequence.cs | 3 --- Algorithms/Sequences/CatalanSequence.cs | 3 --- .../CentralPolygonalNumbersSequence.cs | 3 --- Algorithms/Sequences/CubesSequence.cs | 3 --- Algorithms/Sequences/DivisorsCountSequence.cs | 3 --- Algorithms/Sequences/EuclidNumbersSequence.cs | 3 --- Algorithms/Sequences/EulerTotientSequence.cs | 4 ---- Algorithms/Sequences/FactorialSequence.cs | 3 --- Algorithms/Sequences/FermatNumbersSequence.cs | 3 --- Algorithms/Sequences/FermatPrimesSequence.cs | 4 ---- Algorithms/Sequences/FibonacciSequence.cs | 3 --- Algorithms/Sequences/GolombsSequence.cs | 3 --- Algorithms/Sequences/ISequence.cs | 3 --- Algorithms/Sequences/KolakoskiSequence.cs | 3 --- Algorithms/Sequences/KolakoskiSequence2.cs | 4 ---- Algorithms/Sequences/KummerNumbersSequence.cs | 4 ---- .../LucasNumbersBeginningAt2Sequence.cs | 3 --- Algorithms/Sequences/MakeChangeSequence.cs | 5 +---- .../Sequences/MatchstickTriangleSequence.cs | 3 --- Algorithms/Sequences/NaturalSequence.cs | 3 --- .../Sequences/NegativeIntegersSequence.cs | 3 --- .../NumberOfBooleanFunctionsSequence.cs | 3 --- .../NumberOfPrimesByNumberOfDigitsSequence.cs | 3 --- .../NumberOfPrimesByPowersOf10Sequence.cs | 3 --- Algorithms/Sequences/OnesCountingSequence.cs | 5 +---- Algorithms/Sequences/PowersOf10Sequence.cs | 3 --- Algorithms/Sequences/PowersOf2Sequence.cs | 3 --- Algorithms/Sequences/PrimePiSequence.cs | 3 --- Algorithms/Sequences/PrimesSequence.cs | 4 ---- .../Sequences/PrimorialNumbersSequence.cs | 3 --- Algorithms/Sequences/RecamansSequence.cs | 3 --- Algorithms/Sequences/SquaresSequence.cs | 3 --- Algorithms/Sequences/TetrahedralSequence.cs | 5 +---- .../Sequences/TetranacciNumbersSequence.cs | 4 ---- .../Sequences/ThreeNPlusOneStepsSequence.cs | 3 --- .../Sequences/TribonacciNumbersSequence.cs | 4 ---- Algorithms/Sequences/VanEcksSequence.cs | 3 --- Algorithms/Sequences/ZeroSequence.cs | 3 --- Algorithms/Shufflers/FisherYatesShuffler.cs | 2 -- Algorithms/Shufflers/LINQShuffler.cs | 3 --- Algorithms/Shufflers/NaiveShuffler.cs | 2 -- Algorithms/Shufflers/RecursiveShuffler.cs | 2 -- .../Sorters/Comparison/BasicTimSorter.cs | 3 --- .../Comparison/BinaryInsertionSorter.cs | 3 --- Algorithms/Sorters/Comparison/BogoSorter.cs | 3 --- Algorithms/Sorters/Comparison/BubbleSorter.cs | 2 -- .../Sorters/Comparison/CocktailSorter.cs | 2 -- Algorithms/Sorters/Comparison/CombSorter.cs | 3 --- Algorithms/Sorters/Comparison/CycleSorter.cs | 2 -- .../Sorters/Comparison/ExchangeSorter.cs | 2 -- Algorithms/Sorters/Comparison/GnomeSorter.cs | 2 -- Algorithms/Sorters/Comparison/HeapSorter.cs | 2 -- .../Sorters/Comparison/IComparisonSorter.cs | 2 -- .../Sorters/Comparison/InsertionSorter.cs | 2 -- .../Comparison/MedianOfThreeQuickSorter.cs | 2 -- Algorithms/Sorters/Comparison/MergeSorter.cs | 3 --- .../Comparison/MiddlePointQuickSorter.cs | 2 -- .../Sorters/Comparison/PancakeSorter.cs | 2 -- Algorithms/Sorters/Comparison/QuickSorter.cs | 2 -- .../Comparison/RandomPivotQuickSorter.cs | 3 --- .../Sorters/Comparison/SelectionSorter.cs | 2 -- Algorithms/Sorters/Comparison/ShellSorter.cs | 2 -- Algorithms/Sorters/Comparison/TimSorter.cs | 2 -- .../Sorters/External/ExternalMergeSorter.cs | 3 --- .../Sorters/External/IExternalSorter.cs | 2 -- .../External/ISequentialStorageReader.cs | 2 -- .../External/ISequentialStorageWriter.cs | 2 -- Algorithms/Sorters/Integer/BucketSorter.cs | 4 ---- Algorithms/Sorters/Integer/CountingSorter.cs | 3 --- Algorithms/Sorters/Utils/GallopingStrategy.cs | 2 -- .../Stack/BalancedParenthesesChecker.cs | 3 --- Algorithms/Stack/NextGreaterElement.cs | 3 --- Algorithms/Stack/ReverseStack.cs | 3 --- Algorithms/Strings/GeneralStringAlgorithms.cs | 2 -- Algorithms/Strings/Palindrome.cs | 3 --- Algorithms/Strings/PatternMatching/Bitap.cs | 4 +--- .../Strings/PatternMatching/BoyerMoore.cs | 2 -- .../KnuthMorrisPrattSearcher.cs | 2 -- .../PatternMatching/NaiveStringSearch.cs | 2 -- .../Strings/PatternMatching/RabinKarp.cs | 3 --- .../PatternMatching/WildCardMatcher.cs | 2 -- Algorithms/Strings/Permutation.cs | 3 --- .../Strings/Similarity/CosineSimilarity.cs | 5 +---- .../Similarity/DamerauLevenshteinDistance.cs | 4 +--- .../Strings/Similarity/HammingDistance.cs | 4 +--- .../Strings/Similarity/JaccardSimilarity.cs | 5 +---- .../Strings/Similarity/JaroSimilarity.cs | 2 -- .../Strings/Similarity/JaroWinklerDistance.cs | 2 -- .../Similarity/OptimalStringAlignment.cs | 2 -- 207 files changed, 51 insertions(+), 572 deletions(-) create mode 100644 Algorithms/GlobalUsings.cs diff --git a/Algorithms/Crypto/Digests/AsconDigest.cs b/Algorithms/Crypto/Digests/AsconDigest.cs index d6ec3c97..92b8349a 100644 --- a/Algorithms/Crypto/Digests/AsconDigest.cs +++ b/Algorithms/Crypto/Digests/AsconDigest.cs @@ -1,4 +1,3 @@ -using System; using System.Runtime.CompilerServices; using Algorithms.Crypto.Utils; diff --git a/Algorithms/Crypto/Digests/IDigest.cs b/Algorithms/Crypto/Digests/IDigest.cs index 0800f176..c9dcb8c9 100644 --- a/Algorithms/Crypto/Digests/IDigest.cs +++ b/Algorithms/Crypto/Digests/IDigest.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Crypto.Digests; /// diff --git a/Algorithms/Crypto/Digests/Md2Digest.cs b/Algorithms/Crypto/Digests/Md2Digest.cs index e29e976a..294f74d8 100644 --- a/Algorithms/Crypto/Digests/Md2Digest.cs +++ b/Algorithms/Crypto/Digests/Md2Digest.cs @@ -1,6 +1,4 @@ -using System; - -namespace Algorithms.Crypto.Digests; +namespace Algorithms.Crypto.Digests; /// /// MD2 is a cryptographic hash function that takes an input message and produces a 128-bit output, also called a message diff --git a/Algorithms/Crypto/Exceptions/CryptoException.cs b/Algorithms/Crypto/Exceptions/CryptoException.cs index 44b3bbd7..27523e2c 100644 --- a/Algorithms/Crypto/Exceptions/CryptoException.cs +++ b/Algorithms/Crypto/Exceptions/CryptoException.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Crypto.Exceptions; /// diff --git a/Algorithms/Crypto/Exceptions/DataLengthException.cs b/Algorithms/Crypto/Exceptions/DataLengthException.cs index f96e2a7f..3c77be1f 100644 --- a/Algorithms/Crypto/Exceptions/DataLengthException.cs +++ b/Algorithms/Crypto/Exceptions/DataLengthException.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Crypto.Exceptions; /// diff --git a/Algorithms/Crypto/Exceptions/OutputLengthException.cs b/Algorithms/Crypto/Exceptions/OutputLengthException.cs index 1e295fc4..cd3000d9 100644 --- a/Algorithms/Crypto/Exceptions/OutputLengthException.cs +++ b/Algorithms/Crypto/Exceptions/OutputLengthException.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Crypto.Exceptions; /// diff --git a/Algorithms/Crypto/Paddings/IBlockCipherPadding.cs b/Algorithms/Crypto/Paddings/IBlockCipherPadding.cs index e451f377..19122261 100644 --- a/Algorithms/Crypto/Paddings/IBlockCipherPadding.cs +++ b/Algorithms/Crypto/Paddings/IBlockCipherPadding.cs @@ -1,6 +1,4 @@ -using System; - -namespace Algorithms.Crypto.Paddings; +namespace Algorithms.Crypto.Paddings; /// /// A common interface that all block cipher padding schemes should follow. diff --git a/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs b/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs index 51bfca39..e7751b42 100644 --- a/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs +++ b/Algorithms/Crypto/Paddings/Iso10126D2Padding.cs @@ -1,7 +1,4 @@ -using System; -using System.Security.Cryptography; - -namespace Algorithms.Crypto.Paddings; +namespace Algorithms.Crypto.Paddings; /// /// diff --git a/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs b/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs index df12c5da..b6c6e41d 100644 --- a/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs +++ b/Algorithms/Crypto/Paddings/Iso7816D4Padding.cs @@ -1,6 +1,4 @@ -using System; - -namespace Algorithms.Crypto.Paddings; +namespace Algorithms.Crypto.Paddings; /// /// diff --git a/Algorithms/Crypto/Paddings/Pkcs7Padding.cs b/Algorithms/Crypto/Paddings/Pkcs7Padding.cs index ef2cdc07..bcfbc304 100644 --- a/Algorithms/Crypto/Paddings/Pkcs7Padding.cs +++ b/Algorithms/Crypto/Paddings/Pkcs7Padding.cs @@ -1,6 +1,4 @@ -using System; - -namespace Algorithms.Crypto.Paddings; +namespace Algorithms.Crypto.Paddings; /// /// diff --git a/Algorithms/Crypto/Paddings/TbcPadding.cs b/Algorithms/Crypto/Paddings/TbcPadding.cs index d9386dc6..a3735792 100644 --- a/Algorithms/Crypto/Paddings/TbcPadding.cs +++ b/Algorithms/Crypto/Paddings/TbcPadding.cs @@ -1,6 +1,4 @@ -using System; - -namespace Algorithms.Crypto.Paddings; +namespace Algorithms.Crypto.Paddings; /// /// diff --git a/Algorithms/Crypto/Paddings/X932Padding.cs b/Algorithms/Crypto/Paddings/X932Padding.cs index 6a4f5f45..2e552c38 100644 --- a/Algorithms/Crypto/Paddings/X932Padding.cs +++ b/Algorithms/Crypto/Paddings/X932Padding.cs @@ -1,7 +1,4 @@ -using System; -using System.Security.Cryptography; - -namespace Algorithms.Crypto.Paddings; +namespace Algorithms.Crypto.Paddings; /// /// diff --git a/Algorithms/Crypto/Utils/ByteEncodingUtils.cs b/Algorithms/Crypto/Utils/ByteEncodingUtils.cs index 479d2508..0d2c9a27 100644 --- a/Algorithms/Crypto/Utils/ByteEncodingUtils.cs +++ b/Algorithms/Crypto/Utils/ByteEncodingUtils.cs @@ -1,4 +1,3 @@ -using System; using System.Buffers.Binary; using System.Runtime.CompilerServices; diff --git a/Algorithms/Crypto/Utils/LongUtils.cs b/Algorithms/Crypto/Utils/LongUtils.cs index 60f266f8..28cbacc2 100644 --- a/Algorithms/Crypto/Utils/LongUtils.cs +++ b/Algorithms/Crypto/Utils/LongUtils.cs @@ -1,5 +1,3 @@ -using System.Numerics; - namespace Algorithms.Crypto.Utils; /// diff --git a/Algorithms/Crypto/Utils/ValidationUtils.cs b/Algorithms/Crypto/Utils/ValidationUtils.cs index 88931dfa..f770ad2c 100644 --- a/Algorithms/Crypto/Utils/ValidationUtils.cs +++ b/Algorithms/Crypto/Utils/ValidationUtils.cs @@ -1,5 +1,3 @@ -using System; -using System.Diagnostics; using Algorithms.Crypto.Exceptions; namespace Algorithms.Crypto.Utils; diff --git a/Algorithms/DataCompression/BurrowsWheelerTransform.cs b/Algorithms/DataCompression/BurrowsWheelerTransform.cs index 6ec19387..86b90501 100644 --- a/Algorithms/DataCompression/BurrowsWheelerTransform.cs +++ b/Algorithms/DataCompression/BurrowsWheelerTransform.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Algorithms.DataCompression; /// diff --git a/Algorithms/DataCompression/HuffmanCompressor.cs b/Algorithms/DataCompression/HuffmanCompressor.cs index 368f0704..41a49702 100644 --- a/Algorithms/DataCompression/HuffmanCompressor.cs +++ b/Algorithms/DataCompression/HuffmanCompressor.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; using Algorithms.Sorters.Comparison; -using Utilities.Extensions; namespace Algorithms.DataCompression; diff --git a/Algorithms/DataCompression/ShannonFanoCompressor.cs b/Algorithms/DataCompression/ShannonFanoCompressor.cs index 3aba6761..c9b62a5f 100644 --- a/Algorithms/DataCompression/ShannonFanoCompressor.cs +++ b/Algorithms/DataCompression/ShannonFanoCompressor.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Linq; using Algorithms.Knapsack; -using Utilities.Extensions; namespace Algorithms.DataCompression; diff --git a/Algorithms/DataCompression/Translator.cs b/Algorithms/DataCompression/Translator.cs index 3bf0106a..c5f361d3 100644 --- a/Algorithms/DataCompression/Translator.cs +++ b/Algorithms/DataCompression/Translator.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Text; - namespace Algorithms.DataCompression; /// diff --git a/Algorithms/Encoders/AutokeyEncorder.cs b/Algorithms/Encoders/AutokeyEncorder.cs index 8dc13d37..bdaa7e54 100644 --- a/Algorithms/Encoders/AutokeyEncorder.cs +++ b/Algorithms/Encoders/AutokeyEncorder.cs @@ -1,8 +1,3 @@ -using System; -using System.Globalization; -using System.Text; -using System.Text.RegularExpressions; - namespace Algorithms.Encoders { /// @@ -27,7 +22,7 @@ public string Encode(string plainText, string keyword) StringBuilder cipherText = new StringBuilder(); - for(int i = 0; i < plainText.Length; i++) + for (int i = 0; i < plainText.Length; i++) { char plainCharacter = plainText[i]; char keyCharacter = keyword[i]; @@ -53,7 +48,7 @@ public string Decode(string cipherText, string keyword) StringBuilder plainText = new StringBuilder(); StringBuilder extendedKeyword = new StringBuilder(keyword); - for(int i = 0; i < cipherText.Length; i++) + for (int i = 0; i < cipherText.Length; i++) { char cipherCharacter = cipherText[i]; char keywordCharacter = extendedKeyword[i]; diff --git a/Algorithms/Encoders/BlowfishEncoder.cs b/Algorithms/Encoders/BlowfishEncoder.cs index 558542c5..33582aed 100644 --- a/Algorithms/Encoders/BlowfishEncoder.cs +++ b/Algorithms/Encoders/BlowfishEncoder.cs @@ -1,8 +1,4 @@ -using System; -using System.Linq; -using System.Text; - -namespace Algorithms.Encoders; +namespace Algorithms.Encoders; /// /// diff --git a/Algorithms/Encoders/CaesarEncoder.cs b/Algorithms/Encoders/CaesarEncoder.cs index 8efb2a25..33bd6c6d 100644 --- a/Algorithms/Encoders/CaesarEncoder.cs +++ b/Algorithms/Encoders/CaesarEncoder.cs @@ -1,5 +1,3 @@ -using System.Text; - namespace Algorithms.Encoders; /// diff --git a/Algorithms/Encoders/FeistelCipher.cs b/Algorithms/Encoders/FeistelCipher.cs index 99b50e4b..fb26b6e6 100644 --- a/Algorithms/Encoders/FeistelCipher.cs +++ b/Algorithms/Encoders/FeistelCipher.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace Algorithms.Encoders; /// @@ -101,7 +97,7 @@ public string Decode(string text, uint key) ulong decodedBlock = leftSubblock; decodedBlock = (decodedBlock << 32) | rightSubblock; - for(int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { ulong a = (decodedBlock & 0xFF00000000000000) >> 56; @@ -125,7 +121,7 @@ private static List SplitTextToBlocks(string text) List blocksListPlain = new(); byte[] textArray = Encoding.ASCII.GetBytes(text); int offset = 8; - for(int i = 0; i < text.Length; i += 8) + for (int i = 0; i < text.Length; i += 8) { // text not always has len%16 == 0, that's why the offset should be adjusted for the last part of the text if (i > text.Length - 8) @@ -144,7 +140,7 @@ private static List SplitTextToBlocks(string text) private static List GetBlocksFromEncodedText(string text) { List blocksListPlain = new(); - for(int i = 0; i < text.Length; i += 16) + for (int i = 0; i < text.Length; i += 16) { ulong block = Convert.ToUInt64(text.Substring(i, 16), 16); blocksListPlain.Add(block); diff --git a/Algorithms/Encoders/HillEncoder.cs b/Algorithms/Encoders/HillEncoder.cs index c6a84e7c..6fbb6ca0 100644 --- a/Algorithms/Encoders/HillEncoder.cs +++ b/Algorithms/Encoders/HillEncoder.cs @@ -1,5 +1,3 @@ -using System; -using System.Linq; using Algorithms.Numeric; namespace Algorithms.Encoders; diff --git a/Algorithms/Encoders/NysiisEncoder.cs b/Algorithms/Encoders/NysiisEncoder.cs index 10810af3..503c8585 100644 --- a/Algorithms/Encoders/NysiisEncoder.cs +++ b/Algorithms/Encoders/NysiisEncoder.cs @@ -1,7 +1,3 @@ -using System.Globalization; -using System.Linq; -using System.Text; - namespace Algorithms.Encoders; /// diff --git a/Algorithms/Encoders/SoundexEncoder.cs b/Algorithms/Encoders/SoundexEncoder.cs index bebcf002..ce0d51e1 100644 --- a/Algorithms/Encoders/SoundexEncoder.cs +++ b/Algorithms/Encoders/SoundexEncoder.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Encoders; /// diff --git a/Algorithms/Encoders/VigenereEncoder.cs b/Algorithms/Encoders/VigenereEncoder.cs index f4fe9036..514cb236 100644 --- a/Algorithms/Encoders/VigenereEncoder.cs +++ b/Algorithms/Encoders/VigenereEncoder.cs @@ -1,6 +1,3 @@ -using System; -using System.Text; - namespace Algorithms.Encoders; /// diff --git a/Algorithms/Financial/PresentValue.cs b/Algorithms/Financial/PresentValue.cs index 805bcd14..db6c8a12 100644 --- a/Algorithms/Financial/PresentValue.cs +++ b/Algorithms/Financial/PresentValue.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Financial; /// diff --git a/Algorithms/GlobalUsings.cs b/Algorithms/GlobalUsings.cs new file mode 100644 index 00000000..c7f122bf --- /dev/null +++ b/Algorithms/GlobalUsings.cs @@ -0,0 +1,21 @@ +// ----------------------------------------------------------------------------- +// Global using directives for the C-Sharp solution. +// These namespaces are imported globally so they don’t need to be repeatedly declared +// in individual files, improving readability and reducing boilerplate. +// +// Guidelines: +// - Keep only the most commonly used namespaces here. +// - Add project-specific namespaces (e.g., Utilities.Extensions) only if they are +// required across the majority of files in the project. +// - Avoid placing rarely used namespaces here to maintain clarity. +// ----------------------------------------------------------------------------- + +global using System; // Core base classes and fundamental types +global using System.Collections.Generic; // Generic collection types (List, Dictionary, etc.) +global using System.Globalization; // Culture-related information (dates, numbers, formatting) +global using System.Linq; // LINQ query operators for collections +global using System.Numerics; // Numeric types such as BigInteger and Complex +global using System.Security.Cryptography; // Cryptographic services (hashing, encryption, random numbers) +global using System.Text; // Text encoding, StringBuilder, etc. +global using System.Text.RegularExpressions; // Regular expression support +global using Utilities.Extensions; // Common extension methods used across the solution diff --git a/Algorithms/Graph/BellmanFord.cs b/Algorithms/Graph/BellmanFord.cs index cec67ae0..075a3ecb 100644 --- a/Algorithms/Graph/BellmanFord.cs +++ b/Algorithms/Graph/BellmanFord.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using DataStructures.Graph; namespace Algorithms.Graph; diff --git a/Algorithms/Graph/BreadthFirstSearch.cs b/Algorithms/Graph/BreadthFirstSearch.cs index 187c1ff9..1802d1e6 100644 --- a/Algorithms/Graph/BreadthFirstSearch.cs +++ b/Algorithms/Graph/BreadthFirstSearch.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using DataStructures.Graph; namespace Algorithms.Graph; diff --git a/Algorithms/Graph/BreadthFirstTreeTraversal.cs b/Algorithms/Graph/BreadthFirstTreeTraversal.cs index 76f16b72..6240729a 100644 --- a/Algorithms/Graph/BreadthFirstTreeTraversal.cs +++ b/Algorithms/Graph/BreadthFirstTreeTraversal.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using DataStructures.BinarySearchTree; namespace Algorithms.Graph; diff --git a/Algorithms/Graph/DepthFirstSearch.cs b/Algorithms/Graph/DepthFirstSearch.cs index 805a067f..d24f07b9 100644 --- a/Algorithms/Graph/DepthFirstSearch.cs +++ b/Algorithms/Graph/DepthFirstSearch.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using DataStructures.Graph; namespace Algorithms.Graph; diff --git a/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs b/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs index 8aee1f0f..c4258aec 100644 --- a/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs +++ b/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; using DataStructures.Graph; namespace Algorithms.Graph.Dijkstra; @@ -31,7 +28,7 @@ public static DistanceModel[] GenerateShortestPath(DirectedWeightedGraph[] Solve(Dictionary[] adjacencyL { nodes[i] = set.MakeSet(i); - foreach(var (node, weight) in adjacencyList[i]) + foreach (var (node, weight) in adjacencyList[i]) { edgeWeightList.Add(weight); nodeConnectList.Add((i, node)); diff --git a/Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs b/Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs index 55b6a2d5..c3bbed68 100644 --- a/Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs +++ b/Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Graph.MinimumSpanningTree; /// diff --git a/Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs b/Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs index c3f5b27d..9056c579 100644 --- a/Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs +++ b/Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Knapsack; /// @@ -111,7 +107,7 @@ private static T[] GetItemsFromPath(T[] items, BranchAndBoundNode lastNodeOfPath // only bogus initial node has no parent for (var current = lastNodeOfPath; current.Parent is not null; current = current.Parent) { - if(current.IsTaken) + if (current.IsTaken) { takenItems.Add(items[current.Level]); } diff --git a/Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs b/Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs index db60b55d..1e8d25e2 100644 --- a/Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs +++ b/Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Knapsack; /// diff --git a/Algorithms/Knapsack/IHeuristicKnapsackSolver.cs b/Algorithms/Knapsack/IHeuristicKnapsackSolver.cs index e73bcdd1..78ae7a76 100644 --- a/Algorithms/Knapsack/IHeuristicKnapsackSolver.cs +++ b/Algorithms/Knapsack/IHeuristicKnapsackSolver.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Knapsack; /// diff --git a/Algorithms/Knapsack/NaiveKnapsackSolver.cs b/Algorithms/Knapsack/NaiveKnapsackSolver.cs index 841b8750..38a4f93d 100644 --- a/Algorithms/Knapsack/NaiveKnapsackSolver.cs +++ b/Algorithms/Knapsack/NaiveKnapsackSolver.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Knapsack; /// diff --git a/Algorithms/LinearAlgebra/Distances/Chebyshev.cs b/Algorithms/LinearAlgebra/Distances/Chebyshev.cs index b710fb1d..753f95f1 100644 --- a/Algorithms/LinearAlgebra/Distances/Chebyshev.cs +++ b/Algorithms/LinearAlgebra/Distances/Chebyshev.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Algorithms.LinearAlgebra.Distances; /// diff --git a/Algorithms/LinearAlgebra/Distances/Euclidean.cs b/Algorithms/LinearAlgebra/Distances/Euclidean.cs index 67fd4129..db4bf63b 100644 --- a/Algorithms/LinearAlgebra/Distances/Euclidean.cs +++ b/Algorithms/LinearAlgebra/Distances/Euclidean.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Algorithms.LinearAlgebra.Distances; /// diff --git a/Algorithms/LinearAlgebra/Distances/Manhattan.cs b/Algorithms/LinearAlgebra/Distances/Manhattan.cs index ea0dd96f..7c7387cd 100644 --- a/Algorithms/LinearAlgebra/Distances/Manhattan.cs +++ b/Algorithms/LinearAlgebra/Distances/Manhattan.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Algorithms.LinearAlgebra.Distances; /// diff --git a/Algorithms/LinearAlgebra/Distances/Minkowski.cs b/Algorithms/LinearAlgebra/Distances/Minkowski.cs index 9b3080f3..5f9bcb04 100644 --- a/Algorithms/LinearAlgebra/Distances/Minkowski.cs +++ b/Algorithms/LinearAlgebra/Distances/Minkowski.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Algorithms.LinearAlgebra.Distances; /// diff --git a/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs b/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs index df225723..51579be3 100644 --- a/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs +++ b/Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs @@ -1,7 +1,3 @@ -using System; -using System.Linq; -using Utilities.Extensions; - namespace Algorithms.LinearAlgebra.Eigenvalue; /// diff --git a/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs b/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs index 9f7d88cb..582e7cf4 100644 --- a/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs +++ b/Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - namespace Algorithms.ModularArithmetic; /// diff --git a/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs b/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs index 8037049d..ef1e08c5 100644 --- a/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs +++ b/Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs @@ -1,5 +1,3 @@ -using System.Numerics; - namespace Algorithms.ModularArithmetic; /// diff --git a/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs b/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs index 9a3c5ce0..9f09da82 100644 --- a/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs +++ b/Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs @@ -1,6 +1,3 @@ -using System; -using System.Numerics; - namespace Algorithms.ModularArithmetic; /// diff --git a/Algorithms/NewtonSquareRoot.cs b/Algorithms/NewtonSquareRoot.cs index 4e8935a8..6dc6d40e 100644 --- a/Algorithms/NewtonSquareRoot.cs +++ b/Algorithms/NewtonSquareRoot.cs @@ -1,7 +1,4 @@ -using System; -using System.Numerics; - -namespace Algorithms; +namespace Algorithms; public static class NewtonSquareRoot { diff --git a/Algorithms/Numeric/Abs.cs b/Algorithms/Numeric/Abs.cs index 763b6402..c7eed397 100644 --- a/Algorithms/Numeric/Abs.cs +++ b/Algorithms/Numeric/Abs.cs @@ -1,6 +1,3 @@ -using System; -using System.Numerics; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/AliquotSumCalculator.cs b/Algorithms/Numeric/AliquotSumCalculator.cs index b74b550f..938ab9c7 100644 --- a/Algorithms/Numeric/AliquotSumCalculator.cs +++ b/Algorithms/Numeric/AliquotSumCalculator.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/AutomorphicNumber.cs b/Algorithms/Numeric/AutomorphicNumber.cs index 159f4988..fe576e1e 100644 --- a/Algorithms/Numeric/AutomorphicNumber.cs +++ b/Algorithms/Numeric/AutomorphicNumber.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/BinomialCoefficient.cs b/Algorithms/Numeric/BinomialCoefficient.cs index e2fe6fed..6af6ba20 100644 --- a/Algorithms/Numeric/BinomialCoefficient.cs +++ b/Algorithms/Numeric/BinomialCoefficient.cs @@ -1,6 +1,3 @@ -using System; -using System.Numerics; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/Ceil.cs b/Algorithms/Numeric/Ceil.cs index 26b718b7..a9c03c8c 100644 --- a/Algorithms/Numeric/Ceil.cs +++ b/Algorithms/Numeric/Ceil.cs @@ -1,6 +1,3 @@ -using System; -using System.Numerics; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/Decomposition/LU.cs b/Algorithms/Numeric/Decomposition/LU.cs index 8b4ccc6f..2e8fa5d8 100644 --- a/Algorithms/Numeric/Decomposition/LU.cs +++ b/Algorithms/Numeric/Decomposition/LU.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric.Decomposition; /// diff --git a/Algorithms/Numeric/Decomposition/ThinSVD.cs b/Algorithms/Numeric/Decomposition/ThinSVD.cs index 8c07f2e6..930efa8f 100644 --- a/Algorithms/Numeric/Decomposition/ThinSVD.cs +++ b/Algorithms/Numeric/Decomposition/ThinSVD.cs @@ -1,6 +1,3 @@ -using System; -using Utilities.Extensions; - namespace Algorithms.Numeric.Decomposition; /// diff --git a/Algorithms/Numeric/EulerMethod.cs b/Algorithms/Numeric/EulerMethod.cs index 20112c2b..770417d1 100644 --- a/Algorithms/Numeric/EulerMethod.cs +++ b/Algorithms/Numeric/EulerMethod.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/Factorial.cs b/Algorithms/Numeric/Factorial.cs index 6c30f50e..2a4d60df 100644 --- a/Algorithms/Numeric/Factorial.cs +++ b/Algorithms/Numeric/Factorial.cs @@ -1,6 +1,3 @@ -using System; -using System.Numerics; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs b/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs index f105fd6d..8ad1c4c9 100755 --- a/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs +++ b/Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Algorithms.Numeric.Factorization; /// diff --git a/Algorithms/Numeric/Floor.cs b/Algorithms/Numeric/Floor.cs index b59131df..4c5c9a04 100644 --- a/Algorithms/Numeric/Floor.cs +++ b/Algorithms/Numeric/Floor.cs @@ -1,6 +1,3 @@ -using System; -using System.Numerics; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/GaussJordanElimination.cs b/Algorithms/Numeric/GaussJordanElimination.cs index 3ef7969b..bf1f6c2f 100644 --- a/Algorithms/Numeric/GaussJordanElimination.cs +++ b/Algorithms/Numeric/GaussJordanElimination.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs b/Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs index 691a855a..78bfe97a 100644 --- a/Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs +++ b/Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric.GreatestCommonDivisor; /// diff --git a/Algorithms/Numeric/JosephusProblem.cs b/Algorithms/Numeric/JosephusProblem.cs index 0aac5ace..2bc0ffe8 100644 --- a/Algorithms/Numeric/JosephusProblem.cs +++ b/Algorithms/Numeric/JosephusProblem.cs @@ -1,6 +1,4 @@ -using System; - -namespace Algorithms.Numeric; +namespace Algorithms.Numeric; public static class JosephusProblem { diff --git a/Algorithms/Numeric/KeithNumberChecker.cs b/Algorithms/Numeric/KeithNumberChecker.cs index e1a91f93..d6439fb4 100644 --- a/Algorithms/Numeric/KeithNumberChecker.cs +++ b/Algorithms/Numeric/KeithNumberChecker.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/MillerRabinPrimalityChecker.cs b/Algorithms/Numeric/MillerRabinPrimalityChecker.cs index 0850a43c..fe5a81c8 100644 --- a/Algorithms/Numeric/MillerRabinPrimalityChecker.cs +++ b/Algorithms/Numeric/MillerRabinPrimalityChecker.cs @@ -1,6 +1,3 @@ -using System; -using System.Numerics; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/ModularExponentiation.cs b/Algorithms/Numeric/ModularExponentiation.cs index c7f4f2e9..312dfce1 100644 --- a/Algorithms/Numeric/ModularExponentiation.cs +++ b/Algorithms/Numeric/ModularExponentiation.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/NarcissisticNumberChecker.cs b/Algorithms/Numeric/NarcissisticNumberChecker.cs index 4e6283d8..79b1d3e7 100644 --- a/Algorithms/Numeric/NarcissisticNumberChecker.cs +++ b/Algorithms/Numeric/NarcissisticNumberChecker.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/PerfectCubeChecker.cs b/Algorithms/Numeric/PerfectCubeChecker.cs index cf3eebd6..320d0fb0 100644 --- a/Algorithms/Numeric/PerfectCubeChecker.cs +++ b/Algorithms/Numeric/PerfectCubeChecker.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/PerfectNumberChecker.cs b/Algorithms/Numeric/PerfectNumberChecker.cs index 4abd55f8..c7a3b8f0 100644 --- a/Algorithms/Numeric/PerfectNumberChecker.cs +++ b/Algorithms/Numeric/PerfectNumberChecker.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/PerfectSquareChecker.cs b/Algorithms/Numeric/PerfectSquareChecker.cs index 6465c3b6..5bc0765e 100644 --- a/Algorithms/Numeric/PerfectSquareChecker.cs +++ b/Algorithms/Numeric/PerfectSquareChecker.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs b/Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs index 0e9317aa..f85f63c0 100644 --- a/Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs +++ b/Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs @@ -1,6 +1,4 @@ -using System; using Algorithms.Numeric.Decomposition; -using Utilities.Extensions; namespace Algorithms.Numeric.Pseudoinverse; diff --git a/Algorithms/Numeric/RungeKuttaMethod.cs b/Algorithms/Numeric/RungeKuttaMethod.cs index 2ef987bd..494ef969 100644 --- a/Algorithms/Numeric/RungeKuttaMethod.cs +++ b/Algorithms/Numeric/RungeKuttaMethod.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Numeric/Series/Maclaurin.cs b/Algorithms/Numeric/Series/Maclaurin.cs index 75924a50..421349ad 100644 --- a/Algorithms/Numeric/Series/Maclaurin.cs +++ b/Algorithms/Numeric/Series/Maclaurin.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Algorithms.Numeric.Series; /// diff --git a/Algorithms/Numeric/SoftMax.cs b/Algorithms/Numeric/SoftMax.cs index c20a54b5..be1f88d2 100644 --- a/Algorithms/Numeric/SoftMax.cs +++ b/Algorithms/Numeric/SoftMax.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Numeric; /// diff --git a/Algorithms/Other/DecisionsConvolutions.cs b/Algorithms/Other/DecisionsConvolutions.cs index cb0eedbd..5da22ba5 100644 --- a/Algorithms/Other/DecisionsConvolutions.cs +++ b/Algorithms/Other/DecisionsConvolutions.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Other; /// diff --git a/Algorithms/Other/FermatPrimeChecker.cs b/Algorithms/Other/FermatPrimeChecker.cs index 9f277d2c..3d491192 100644 --- a/Algorithms/Other/FermatPrimeChecker.cs +++ b/Algorithms/Other/FermatPrimeChecker.cs @@ -1,6 +1,3 @@ -using System; -using System.Numerics; - namespace Algorithms.Other; /// diff --git a/Algorithms/Other/FloodFill.cs b/Algorithms/Other/FloodFill.cs index ac881d5f..28ddfd16 100644 --- a/Algorithms/Other/FloodFill.cs +++ b/Algorithms/Other/FloodFill.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using SkiaSharp; namespace Algorithms.Other; diff --git a/Algorithms/Other/GaussOptimization.cs b/Algorithms/Other/GaussOptimization.cs index a8c50fdb..b8206005 100644 --- a/Algorithms/Other/GaussOptimization.cs +++ b/Algorithms/Other/GaussOptimization.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Other; /// diff --git a/Algorithms/Other/GeoLocation.cs b/Algorithms/Other/GeoLocation.cs index 1cc39adb..39822c9b 100644 --- a/Algorithms/Other/GeoLocation.cs +++ b/Algorithms/Other/GeoLocation.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Other; public static class GeoLocation diff --git a/Algorithms/Other/Geohash.cs b/Algorithms/Other/Geohash.cs index bde2a759..f66f9919 100644 --- a/Algorithms/Other/Geohash.cs +++ b/Algorithms/Other/Geohash.cs @@ -1,5 +1,3 @@ -using System.Text; - namespace Algorithms.Other; public static class Geohash diff --git a/Algorithms/Other/Int2Binary.cs b/Algorithms/Other/Int2Binary.cs index 07cd57ff..7021bdfe 100644 --- a/Algorithms/Other/Int2Binary.cs +++ b/Algorithms/Other/Int2Binary.cs @@ -1,5 +1,3 @@ -using System.Text; - namespace Algorithms.Other; /// diff --git a/Algorithms/Other/JulianEaster.cs b/Algorithms/Other/JulianEaster.cs index 7785f080..1c92ba13 100644 --- a/Algorithms/Other/JulianEaster.cs +++ b/Algorithms/Other/JulianEaster.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Other; /// diff --git a/Algorithms/Other/KochSnowflake.cs b/Algorithms/Other/KochSnowflake.cs index 739bffd4..29803788 100644 --- a/Algorithms/Other/KochSnowflake.cs +++ b/Algorithms/Other/KochSnowflake.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Numerics; using SkiaSharp; namespace Algorithms.Other; diff --git a/Algorithms/Other/Luhn.cs b/Algorithms/Other/Luhn.cs index e9b1e54e..b6d873c9 100644 --- a/Algorithms/Other/Luhn.cs +++ b/Algorithms/Other/Luhn.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Other; /// diff --git a/Algorithms/Other/Mandelbrot.cs b/Algorithms/Other/Mandelbrot.cs index c93d3acf..0decd3cf 100644 --- a/Algorithms/Other/Mandelbrot.cs +++ b/Algorithms/Other/Mandelbrot.cs @@ -1,4 +1,3 @@ -using System; using SkiaSharp; namespace Algorithms.Other; diff --git a/Algorithms/Other/ParetoOptimization.cs b/Algorithms/Other/ParetoOptimization.cs index 1f5d198d..4e6037d8 100644 --- a/Algorithms/Other/ParetoOptimization.cs +++ b/Algorithms/Other/ParetoOptimization.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Other; /// diff --git a/Algorithms/Other/PollardsRhoFactorizing.cs b/Algorithms/Other/PollardsRhoFactorizing.cs index ceef6a8e..3ac4bf4b 100644 --- a/Algorithms/Other/PollardsRhoFactorizing.cs +++ b/Algorithms/Other/PollardsRhoFactorizing.cs @@ -1,4 +1,3 @@ -using System; using Algorithms.Numeric.GreatestCommonDivisor; namespace Algorithms.Other; diff --git a/Algorithms/Other/RGBHSVConversion.cs b/Algorithms/Other/RGBHSVConversion.cs index 9e1f2f97..480bff8e 100644 --- a/Algorithms/Other/RGBHSVConversion.cs +++ b/Algorithms/Other/RGBHSVConversion.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Other; /// diff --git a/Algorithms/Other/SieveOfEratosthenes.cs b/Algorithms/Other/SieveOfEratosthenes.cs index 72943fa0..ce28b2c7 100644 --- a/Algorithms/Other/SieveOfEratosthenes.cs +++ b/Algorithms/Other/SieveOfEratosthenes.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Other; /// @@ -24,14 +21,14 @@ public SieveOfEratosthenes(long maximumNumberToCheck) // initialize primes array Array.Fill(this.primes, true, 2, primes.Length - 2); - for(long i = 2; i * i <= maximumNumberToCheck; i++) + for (long i = 2; i * i <= maximumNumberToCheck; i++) { if (!primes[i]) { continue; } - for(long composite = i * i; composite <= maximumNumberToCheck; composite += i) + for (long composite = i * i; composite <= maximumNumberToCheck; composite += i) { primes[composite] = false; } @@ -56,7 +53,7 @@ public SieveOfEratosthenes(long maximumNumberToCheck) /// Primes in ascending order. public IEnumerable GetPrimes() { - for(long i = 2; i < primes.Length; i++) + for (long i = 2; i < primes.Length; i++) { if (primes[i]) { diff --git a/Algorithms/Other/Triangulator.cs b/Algorithms/Other/Triangulator.cs index dc7f9af0..566fffc3 100644 --- a/Algorithms/Other/Triangulator.cs +++ b/Algorithms/Other/Triangulator.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Other; public class Triangulator diff --git a/Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs b/Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs index b6faeb8d..465901f6 100644 --- a/Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs +++ b/Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Problems.DynamicProgramming.CoinChange; public static class DynamicCoinChangeSolver diff --git a/Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs b/Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs index 4adb3e27..07f00b15 100644 --- a/Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs +++ b/Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Problems.DynamicProgramming; /// @@ -23,7 +21,7 @@ public static int Calculate(string source, string target) { var distances = new int[source.Length + 1, target.Length + 1]; - for(var i = 0; i <= source.Length; i++) + for (var i = 0; i <= source.Length; i++) { distances[i, 0] = i; } diff --git a/Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs b/Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs index 744c6214..a7d6e29d 100644 --- a/Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs +++ b/Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Problems.NQueens; public class BacktrackingNQueensSolver diff --git a/Algorithms/Problems/StableMarriage/Accepter.cs b/Algorithms/Problems/StableMarriage/Accepter.cs index 430e2cd2..317824af 100644 --- a/Algorithms/Problems/StableMarriage/Accepter.cs +++ b/Algorithms/Problems/StableMarriage/Accepter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Problems.StableMarriage; public class Accepter diff --git a/Algorithms/Problems/StableMarriage/GaleShapley.cs b/Algorithms/Problems/StableMarriage/GaleShapley.cs index 521e2be0..344a8ce0 100644 --- a/Algorithms/Problems/StableMarriage/GaleShapley.cs +++ b/Algorithms/Problems/StableMarriage/GaleShapley.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Problems.StableMarriage; public static class GaleShapley diff --git a/Algorithms/Problems/StableMarriage/Proposer.cs b/Algorithms/Problems/StableMarriage/Proposer.cs index bb05f26a..c4ffc5b2 100644 --- a/Algorithms/Problems/StableMarriage/Proposer.cs +++ b/Algorithms/Problems/StableMarriage/Proposer.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Problems.StableMarriage; public class Proposer diff --git a/Algorithms/RecommenderSystem/CollaborativeFiltering.cs b/Algorithms/RecommenderSystem/CollaborativeFiltering.cs index 8da58b8a..1a3c87cc 100644 --- a/Algorithms/RecommenderSystem/CollaborativeFiltering.cs +++ b/Algorithms/RecommenderSystem/CollaborativeFiltering.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.RecommenderSystem { public class CollaborativeFiltering diff --git a/Algorithms/RecommenderSystem/ISimilarityCalculator.cs b/Algorithms/RecommenderSystem/ISimilarityCalculator.cs index 5add6c9d..c31f0b4c 100644 --- a/Algorithms/RecommenderSystem/ISimilarityCalculator.cs +++ b/Algorithms/RecommenderSystem/ISimilarityCalculator.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.RecommenderSystem { public interface ISimilarityCalculator diff --git a/Algorithms/Search/AStar/AStar.cs b/Algorithms/Search/AStar/AStar.cs index d5e86eaa..2c50fc88 100644 --- a/Algorithms/Search/AStar/AStar.cs +++ b/Algorithms/Search/AStar/AStar.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Search.AStar; /// diff --git a/Algorithms/Search/AStar/Node.cs b/Algorithms/Search/AStar/Node.cs index fbc353ce..69b98a1b 100644 --- a/Algorithms/Search/AStar/Node.cs +++ b/Algorithms/Search/AStar/Node.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Search.AStar; /// diff --git a/Algorithms/Search/AStar/PathfindingException.cs b/Algorithms/Search/AStar/PathfindingException.cs index 62559c01..2987c935 100644 --- a/Algorithms/Search/AStar/PathfindingException.cs +++ b/Algorithms/Search/AStar/PathfindingException.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Search.AStar; /// diff --git a/Algorithms/Search/AStar/PriorityQueue.cs b/Algorithms/Search/AStar/PriorityQueue.cs index bb63950d..20554463 100644 --- a/Algorithms/Search/AStar/PriorityQueue.cs +++ b/Algorithms/Search/AStar/PriorityQueue.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - // todo: extract to data structures namespace Algorithms.Search.AStar; diff --git a/Algorithms/Search/AStar/VecN.cs b/Algorithms/Search/AStar/VecN.cs index 4f28072c..63fab94b 100644 --- a/Algorithms/Search/AStar/VecN.cs +++ b/Algorithms/Search/AStar/VecN.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Search.AStar; /// diff --git a/Algorithms/Search/BinarySearcher.cs b/Algorithms/Search/BinarySearcher.cs index 4146be49..01b128f9 100644 --- a/Algorithms/Search/BinarySearcher.cs +++ b/Algorithms/Search/BinarySearcher.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Search; /// diff --git a/Algorithms/Search/BoyerMoore.cs b/Algorithms/Search/BoyerMoore.cs index dcbd1966..ab62470e 100644 --- a/Algorithms/Search/BoyerMoore.cs +++ b/Algorithms/Search/BoyerMoore.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Search; /// diff --git a/Algorithms/Search/FastSearcher.cs b/Algorithms/Search/FastSearcher.cs index 42b2cf3a..08081d67 100644 --- a/Algorithms/Search/FastSearcher.cs +++ b/Algorithms/Search/FastSearcher.cs @@ -1,4 +1,3 @@ -using System; using Utilities.Exceptions; namespace Algorithms.Search; diff --git a/Algorithms/Search/FibonacciSearcher.cs b/Algorithms/Search/FibonacciSearcher.cs index c58ef979..e5adb790 100644 --- a/Algorithms/Search/FibonacciSearcher.cs +++ b/Algorithms/Search/FibonacciSearcher.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Search; /// diff --git a/Algorithms/Search/JumpSearcher.cs b/Algorithms/Search/JumpSearcher.cs index cb379e31..24a51ccb 100644 --- a/Algorithms/Search/JumpSearcher.cs +++ b/Algorithms/Search/JumpSearcher.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Search; /// diff --git a/Algorithms/Search/LinearSearcher.cs b/Algorithms/Search/LinearSearcher.cs index 9361dcfd..cb6ef78a 100644 --- a/Algorithms/Search/LinearSearcher.cs +++ b/Algorithms/Search/LinearSearcher.cs @@ -1,4 +1,3 @@ -using System; using Utilities.Exceptions; namespace Algorithms.Search; diff --git a/Algorithms/Search/RecursiveBinarySearcher.cs b/Algorithms/Search/RecursiveBinarySearcher.cs index daf36cad..55ad57ce 100644 --- a/Algorithms/Search/RecursiveBinarySearcher.cs +++ b/Algorithms/Search/RecursiveBinarySearcher.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Search; /// diff --git a/Algorithms/Sequences/AllOnesSequence.cs b/Algorithms/Sequences/AllOnesSequence.cs index 86645e65..4ac6c4c0 100644 --- a/Algorithms/Sequences/AllOnesSequence.cs +++ b/Algorithms/Sequences/AllOnesSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/AllThreesSequence.cs b/Algorithms/Sequences/AllThreesSequence.cs index 956c0f0a..ca3d3a0a 100644 --- a/Algorithms/Sequences/AllThreesSequence.cs +++ b/Algorithms/Sequences/AllThreesSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/AllTwosSequence.cs b/Algorithms/Sequences/AllTwosSequence.cs index 2213c4a4..cd3b61a6 100644 --- a/Algorithms/Sequences/AllTwosSequence.cs +++ b/Algorithms/Sequences/AllTwosSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/BinaryPrimeConstantSequence.cs b/Algorithms/Sequences/BinaryPrimeConstantSequence.cs index d09097c4..b6cdf4bc 100644 --- a/Algorithms/Sequences/BinaryPrimeConstantSequence.cs +++ b/Algorithms/Sequences/BinaryPrimeConstantSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/BinomialSequence.cs b/Algorithms/Sequences/BinomialSequence.cs index 6e20f3f0..a920ef57 100644 --- a/Algorithms/Sequences/BinomialSequence.cs +++ b/Algorithms/Sequences/BinomialSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/CakeNumbersSequence.cs b/Algorithms/Sequences/CakeNumbersSequence.cs index ac186107..94dbcc5e 100644 --- a/Algorithms/Sequences/CakeNumbersSequence.cs +++ b/Algorithms/Sequences/CakeNumbersSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/CatalanSequence.cs b/Algorithms/Sequences/CatalanSequence.cs index 0ed4f6b0..52ac3a05 100644 --- a/Algorithms/Sequences/CatalanSequence.cs +++ b/Algorithms/Sequences/CatalanSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/CentralPolygonalNumbersSequence.cs b/Algorithms/Sequences/CentralPolygonalNumbersSequence.cs index 1f84aaa1..582a18e6 100644 --- a/Algorithms/Sequences/CentralPolygonalNumbersSequence.cs +++ b/Algorithms/Sequences/CentralPolygonalNumbersSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/CubesSequence.cs b/Algorithms/Sequences/CubesSequence.cs index 287d0b8a..99e222d9 100644 --- a/Algorithms/Sequences/CubesSequence.cs +++ b/Algorithms/Sequences/CubesSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/DivisorsCountSequence.cs b/Algorithms/Sequences/DivisorsCountSequence.cs index da80737b..5412f823 100644 --- a/Algorithms/Sequences/DivisorsCountSequence.cs +++ b/Algorithms/Sequences/DivisorsCountSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/EuclidNumbersSequence.cs b/Algorithms/Sequences/EuclidNumbersSequence.cs index 36d703d9..05425276 100644 --- a/Algorithms/Sequences/EuclidNumbersSequence.cs +++ b/Algorithms/Sequences/EuclidNumbersSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/EulerTotientSequence.cs b/Algorithms/Sequences/EulerTotientSequence.cs index 9921a5cb..c6f5ef19 100644 --- a/Algorithms/Sequences/EulerTotientSequence.cs +++ b/Algorithms/Sequences/EulerTotientSequence.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/FactorialSequence.cs b/Algorithms/Sequences/FactorialSequence.cs index 8bbd6fbc..d340fe0a 100644 --- a/Algorithms/Sequences/FactorialSequence.cs +++ b/Algorithms/Sequences/FactorialSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/FermatNumbersSequence.cs b/Algorithms/Sequences/FermatNumbersSequence.cs index 308e4379..f939e643 100644 --- a/Algorithms/Sequences/FermatNumbersSequence.cs +++ b/Algorithms/Sequences/FermatNumbersSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/FermatPrimesSequence.cs b/Algorithms/Sequences/FermatPrimesSequence.cs index b7a13984..644a623b 100644 --- a/Algorithms/Sequences/FermatPrimesSequence.cs +++ b/Algorithms/Sequences/FermatPrimesSequence.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/FibonacciSequence.cs b/Algorithms/Sequences/FibonacciSequence.cs index 47546ad7..f4e81568 100644 --- a/Algorithms/Sequences/FibonacciSequence.cs +++ b/Algorithms/Sequences/FibonacciSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/GolombsSequence.cs b/Algorithms/Sequences/GolombsSequence.cs index b60d5415..b41f17cd 100644 --- a/Algorithms/Sequences/GolombsSequence.cs +++ b/Algorithms/Sequences/GolombsSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/ISequence.cs b/Algorithms/Sequences/ISequence.cs index 6de87764..c7152945 100644 --- a/Algorithms/Sequences/ISequence.cs +++ b/Algorithms/Sequences/ISequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/KolakoskiSequence.cs b/Algorithms/Sequences/KolakoskiSequence.cs index d791027d..6d32b791 100644 --- a/Algorithms/Sequences/KolakoskiSequence.cs +++ b/Algorithms/Sequences/KolakoskiSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/KolakoskiSequence2.cs b/Algorithms/Sequences/KolakoskiSequence2.cs index 22bbc7ae..ae394a00 100644 --- a/Algorithms/Sequences/KolakoskiSequence2.cs +++ b/Algorithms/Sequences/KolakoskiSequence2.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/KummerNumbersSequence.cs b/Algorithms/Sequences/KummerNumbersSequence.cs index 3f94b7b7..5b6e3210 100644 --- a/Algorithms/Sequences/KummerNumbersSequence.cs +++ b/Algorithms/Sequences/KummerNumbersSequence.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs b/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs index 269035eb..54afa9d6 100644 --- a/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs +++ b/Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/MakeChangeSequence.cs b/Algorithms/Sequences/MakeChangeSequence.cs index 1574f133..0f4ecce8 100644 --- a/Algorithms/Sequences/MakeChangeSequence.cs +++ b/Algorithms/Sequences/MakeChangeSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// @@ -41,7 +38,7 @@ public IEnumerable Sequence yield return value; } - for(var index = 17; ; index++) + for (var index = 17; ; index++) { BigInteger newValue = seed[index - 2] + seed[index - 5] - seed[index - 7] + seed[index - 10] - seed[index - 12] - seed[index - 15] diff --git a/Algorithms/Sequences/MatchstickTriangleSequence.cs b/Algorithms/Sequences/MatchstickTriangleSequence.cs index d2dd075b..a281f263 100644 --- a/Algorithms/Sequences/MatchstickTriangleSequence.cs +++ b/Algorithms/Sequences/MatchstickTriangleSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/NaturalSequence.cs b/Algorithms/Sequences/NaturalSequence.cs index a7115119..3f2d928a 100644 --- a/Algorithms/Sequences/NaturalSequence.cs +++ b/Algorithms/Sequences/NaturalSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/NegativeIntegersSequence.cs b/Algorithms/Sequences/NegativeIntegersSequence.cs index 826999d5..c7fd78f5 100644 --- a/Algorithms/Sequences/NegativeIntegersSequence.cs +++ b/Algorithms/Sequences/NegativeIntegersSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs b/Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs index 5d6c8b2a..a8c48ec1 100644 --- a/Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs +++ b/Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs b/Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs index edee1c62..aa51641b 100644 --- a/Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs +++ b/Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs b/Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs index 9873d566..41e6c88f 100644 --- a/Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs +++ b/Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/OnesCountingSequence.cs b/Algorithms/Sequences/OnesCountingSequence.cs index 2836e7b4..5b215abd 100644 --- a/Algorithms/Sequences/OnesCountingSequence.cs +++ b/Algorithms/Sequences/OnesCountingSequence.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Numerics; - -namespace Algorithms.Sequences; +namespace Algorithms.Sequences; /// /// diff --git a/Algorithms/Sequences/PowersOf10Sequence.cs b/Algorithms/Sequences/PowersOf10Sequence.cs index 5fdd1a64..d564130f 100644 --- a/Algorithms/Sequences/PowersOf10Sequence.cs +++ b/Algorithms/Sequences/PowersOf10Sequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/PowersOf2Sequence.cs b/Algorithms/Sequences/PowersOf2Sequence.cs index 80d20c74..7df26085 100644 --- a/Algorithms/Sequences/PowersOf2Sequence.cs +++ b/Algorithms/Sequences/PowersOf2Sequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/PrimePiSequence.cs b/Algorithms/Sequences/PrimePiSequence.cs index 84c19076..718cd164 100644 --- a/Algorithms/Sequences/PrimePiSequence.cs +++ b/Algorithms/Sequences/PrimePiSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/PrimesSequence.cs b/Algorithms/Sequences/PrimesSequence.cs index ad4d9e1d..e5c6a709 100644 --- a/Algorithms/Sequences/PrimesSequence.cs +++ b/Algorithms/Sequences/PrimesSequence.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/PrimorialNumbersSequence.cs b/Algorithms/Sequences/PrimorialNumbersSequence.cs index dc5a3a14..205a77eb 100644 --- a/Algorithms/Sequences/PrimorialNumbersSequence.cs +++ b/Algorithms/Sequences/PrimorialNumbersSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/RecamansSequence.cs b/Algorithms/Sequences/RecamansSequence.cs index 5e749bc7..a18e1e55 100644 --- a/Algorithms/Sequences/RecamansSequence.cs +++ b/Algorithms/Sequences/RecamansSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/SquaresSequence.cs b/Algorithms/Sequences/SquaresSequence.cs index 4e910191..6b47fabd 100644 --- a/Algorithms/Sequences/SquaresSequence.cs +++ b/Algorithms/Sequences/SquaresSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/TetrahedralSequence.cs b/Algorithms/Sequences/TetrahedralSequence.cs index e0a298d2..c559ab46 100644 --- a/Algorithms/Sequences/TetrahedralSequence.cs +++ b/Algorithms/Sequences/TetrahedralSequence.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Numerics; - -namespace Algorithms.Sequences; +namespace Algorithms.Sequences; /// /// diff --git a/Algorithms/Sequences/TetranacciNumbersSequence.cs b/Algorithms/Sequences/TetranacciNumbersSequence.cs index 34220808..30ea24d5 100644 --- a/Algorithms/Sequences/TetranacciNumbersSequence.cs +++ b/Algorithms/Sequences/TetranacciNumbersSequence.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs b/Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs index ce690a13..a28a1999 100644 --- a/Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs +++ b/Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/TribonacciNumbersSequence.cs b/Algorithms/Sequences/TribonacciNumbersSequence.cs index bf8bdcdd..be229cef 100644 --- a/Algorithms/Sequences/TribonacciNumbersSequence.cs +++ b/Algorithms/Sequences/TribonacciNumbersSequence.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/VanEcksSequence.cs b/Algorithms/Sequences/VanEcksSequence.cs index 9fbf8d84..79d8228c 100644 --- a/Algorithms/Sequences/VanEcksSequence.cs +++ b/Algorithms/Sequences/VanEcksSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Sequences/ZeroSequence.cs b/Algorithms/Sequences/ZeroSequence.cs index 0bdf7abf..cbb2c2d9 100644 --- a/Algorithms/Sequences/ZeroSequence.cs +++ b/Algorithms/Sequences/ZeroSequence.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Numerics; - namespace Algorithms.Sequences; /// diff --git a/Algorithms/Shufflers/FisherYatesShuffler.cs b/Algorithms/Shufflers/FisherYatesShuffler.cs index 53f457f8..06bf6f50 100644 --- a/Algorithms/Shufflers/FisherYatesShuffler.cs +++ b/Algorithms/Shufflers/FisherYatesShuffler.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Shufflers; /// diff --git a/Algorithms/Shufflers/LINQShuffler.cs b/Algorithms/Shufflers/LINQShuffler.cs index 542c0101..8538417d 100644 --- a/Algorithms/Shufflers/LINQShuffler.cs +++ b/Algorithms/Shufflers/LINQShuffler.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Algorithms.Shufflers; /// diff --git a/Algorithms/Shufflers/NaiveShuffler.cs b/Algorithms/Shufflers/NaiveShuffler.cs index c50f56f6..8c0fbeae 100644 --- a/Algorithms/Shufflers/NaiveShuffler.cs +++ b/Algorithms/Shufflers/NaiveShuffler.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Shufflers; /// diff --git a/Algorithms/Shufflers/RecursiveShuffler.cs b/Algorithms/Shufflers/RecursiveShuffler.cs index 6ff315ca..46a9cbcb 100644 --- a/Algorithms/Shufflers/RecursiveShuffler.cs +++ b/Algorithms/Shufflers/RecursiveShuffler.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Shufflers; /// diff --git a/Algorithms/Sorters/Comparison/BasicTimSorter.cs b/Algorithms/Sorters/Comparison/BasicTimSorter.cs index c278dcd5..0e5135ee 100644 --- a/Algorithms/Sorters/Comparison/BasicTimSorter.cs +++ b/Algorithms/Sorters/Comparison/BasicTimSorter.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs b/Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs index 1b089bf8..e6380673 100644 --- a/Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs +++ b/Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/BogoSorter.cs b/Algorithms/Sorters/Comparison/BogoSorter.cs index 9a25cd08..f419a331 100644 --- a/Algorithms/Sorters/Comparison/BogoSorter.cs +++ b/Algorithms/Sorters/Comparison/BogoSorter.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/BubbleSorter.cs b/Algorithms/Sorters/Comparison/BubbleSorter.cs index 0a3e707e..9caf45aa 100644 --- a/Algorithms/Sorters/Comparison/BubbleSorter.cs +++ b/Algorithms/Sorters/Comparison/BubbleSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/CocktailSorter.cs b/Algorithms/Sorters/Comparison/CocktailSorter.cs index d73576ad..d90d72f9 100644 --- a/Algorithms/Sorters/Comparison/CocktailSorter.cs +++ b/Algorithms/Sorters/Comparison/CocktailSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/CombSorter.cs b/Algorithms/Sorters/Comparison/CombSorter.cs index ac6e2a19..8ef67faa 100644 --- a/Algorithms/Sorters/Comparison/CombSorter.cs +++ b/Algorithms/Sorters/Comparison/CombSorter.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/CycleSorter.cs b/Algorithms/Sorters/Comparison/CycleSorter.cs index fd81320d..dd8109c9 100644 --- a/Algorithms/Sorters/Comparison/CycleSorter.cs +++ b/Algorithms/Sorters/Comparison/CycleSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/ExchangeSorter.cs b/Algorithms/Sorters/Comparison/ExchangeSorter.cs index c109b91c..f2721527 100644 --- a/Algorithms/Sorters/Comparison/ExchangeSorter.cs +++ b/Algorithms/Sorters/Comparison/ExchangeSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/GnomeSorter.cs b/Algorithms/Sorters/Comparison/GnomeSorter.cs index 28bfeeb2..60ba54cf 100644 --- a/Algorithms/Sorters/Comparison/GnomeSorter.cs +++ b/Algorithms/Sorters/Comparison/GnomeSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/HeapSorter.cs b/Algorithms/Sorters/Comparison/HeapSorter.cs index c2dbf5b5..496815be 100644 --- a/Algorithms/Sorters/Comparison/HeapSorter.cs +++ b/Algorithms/Sorters/Comparison/HeapSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/IComparisonSorter.cs b/Algorithms/Sorters/Comparison/IComparisonSorter.cs index 7d6fa798..74e7a481 100644 --- a/Algorithms/Sorters/Comparison/IComparisonSorter.cs +++ b/Algorithms/Sorters/Comparison/IComparisonSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/InsertionSorter.cs b/Algorithms/Sorters/Comparison/InsertionSorter.cs index 755f422b..734815f6 100644 --- a/Algorithms/Sorters/Comparison/InsertionSorter.cs +++ b/Algorithms/Sorters/Comparison/InsertionSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/MedianOfThreeQuickSorter.cs b/Algorithms/Sorters/Comparison/MedianOfThreeQuickSorter.cs index abede8f5..63330a18 100644 --- a/Algorithms/Sorters/Comparison/MedianOfThreeQuickSorter.cs +++ b/Algorithms/Sorters/Comparison/MedianOfThreeQuickSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/MergeSorter.cs b/Algorithms/Sorters/Comparison/MergeSorter.cs index 13a888ad..fda8d4fb 100644 --- a/Algorithms/Sorters/Comparison/MergeSorter.cs +++ b/Algorithms/Sorters/Comparison/MergeSorter.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/MiddlePointQuickSorter.cs b/Algorithms/Sorters/Comparison/MiddlePointQuickSorter.cs index 25806e4a..3d07416f 100644 --- a/Algorithms/Sorters/Comparison/MiddlePointQuickSorter.cs +++ b/Algorithms/Sorters/Comparison/MiddlePointQuickSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/PancakeSorter.cs b/Algorithms/Sorters/Comparison/PancakeSorter.cs index 478ae926..9dc783ed 100644 --- a/Algorithms/Sorters/Comparison/PancakeSorter.cs +++ b/Algorithms/Sorters/Comparison/PancakeSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/QuickSorter.cs b/Algorithms/Sorters/Comparison/QuickSorter.cs index e4615577..67072fac 100644 --- a/Algorithms/Sorters/Comparison/QuickSorter.cs +++ b/Algorithms/Sorters/Comparison/QuickSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/RandomPivotQuickSorter.cs b/Algorithms/Sorters/Comparison/RandomPivotQuickSorter.cs index a9515ed4..83511b63 100644 --- a/Algorithms/Sorters/Comparison/RandomPivotQuickSorter.cs +++ b/Algorithms/Sorters/Comparison/RandomPivotQuickSorter.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/SelectionSorter.cs b/Algorithms/Sorters/Comparison/SelectionSorter.cs index 167bf454..2a238c0e 100644 --- a/Algorithms/Sorters/Comparison/SelectionSorter.cs +++ b/Algorithms/Sorters/Comparison/SelectionSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/ShellSorter.cs b/Algorithms/Sorters/Comparison/ShellSorter.cs index f00c1155..046069b1 100644 --- a/Algorithms/Sorters/Comparison/ShellSorter.cs +++ b/Algorithms/Sorters/Comparison/ShellSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Comparison; /// diff --git a/Algorithms/Sorters/Comparison/TimSorter.cs b/Algorithms/Sorters/Comparison/TimSorter.cs index d098d340..40254962 100755 --- a/Algorithms/Sorters/Comparison/TimSorter.cs +++ b/Algorithms/Sorters/Comparison/TimSorter.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using Algorithms.Sorters.Utils; namespace Algorithms.Sorters.Comparison; diff --git a/Algorithms/Sorters/External/ExternalMergeSorter.cs b/Algorithms/Sorters/External/ExternalMergeSorter.cs index 5b45aef3..eb8c2980 100644 --- a/Algorithms/Sorters/External/ExternalMergeSorter.cs +++ b/Algorithms/Sorters/External/ExternalMergeSorter.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Sorters.External; public class ExternalMergeSorter : IExternalSorter diff --git a/Algorithms/Sorters/External/IExternalSorter.cs b/Algorithms/Sorters/External/IExternalSorter.cs index f6929656..0068c0a9 100644 --- a/Algorithms/Sorters/External/IExternalSorter.cs +++ b/Algorithms/Sorters/External/IExternalSorter.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.External; public interface IExternalSorter diff --git a/Algorithms/Sorters/External/ISequentialStorageReader.cs b/Algorithms/Sorters/External/ISequentialStorageReader.cs index 1158362a..18446d03 100644 --- a/Algorithms/Sorters/External/ISequentialStorageReader.cs +++ b/Algorithms/Sorters/External/ISequentialStorageReader.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Sorters.External; public interface ISequentialStorageReader : IDisposable diff --git a/Algorithms/Sorters/External/ISequentialStorageWriter.cs b/Algorithms/Sorters/External/ISequentialStorageWriter.cs index 6b48dfb6..7c7a2dc8 100644 --- a/Algorithms/Sorters/External/ISequentialStorageWriter.cs +++ b/Algorithms/Sorters/External/ISequentialStorageWriter.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Sorters.External; public interface ISequentialStorageWriter : IDisposable diff --git a/Algorithms/Sorters/Integer/BucketSorter.cs b/Algorithms/Sorters/Integer/BucketSorter.cs index 843d7c80..f665ec7c 100644 --- a/Algorithms/Sorters/Integer/BucketSorter.cs +++ b/Algorithms/Sorters/Integer/BucketSorter.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Sorters.Integer; /// diff --git a/Algorithms/Sorters/Integer/CountingSorter.cs b/Algorithms/Sorters/Integer/CountingSorter.cs index fc43b153..31fca188 100644 --- a/Algorithms/Sorters/Integer/CountingSorter.cs +++ b/Algorithms/Sorters/Integer/CountingSorter.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Algorithms.Sorters.Integer; /// diff --git a/Algorithms/Sorters/Utils/GallopingStrategy.cs b/Algorithms/Sorters/Utils/GallopingStrategy.cs index 05f22272..2e15ce1b 100644 --- a/Algorithms/Sorters/Utils/GallopingStrategy.cs +++ b/Algorithms/Sorters/Utils/GallopingStrategy.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Sorters.Utils; public static class GallopingStrategy diff --git a/Algorithms/Stack/BalancedParenthesesChecker.cs b/Algorithms/Stack/BalancedParenthesesChecker.cs index 0b889933..0b738609 100644 --- a/Algorithms/Stack/BalancedParenthesesChecker.cs +++ b/Algorithms/Stack/BalancedParenthesesChecker.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Stack; /// diff --git a/Algorithms/Stack/NextGreaterElement.cs b/Algorithms/Stack/NextGreaterElement.cs index c2d728a7..eb2b2ed4 100644 --- a/Algorithms/Stack/NextGreaterElement.cs +++ b/Algorithms/Stack/NextGreaterElement.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Stack; /// diff --git a/Algorithms/Stack/ReverseStack.cs b/Algorithms/Stack/ReverseStack.cs index 081f8aec..8a6b264c 100644 --- a/Algorithms/Stack/ReverseStack.cs +++ b/Algorithms/Stack/ReverseStack.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Stack; /// diff --git a/Algorithms/Strings/GeneralStringAlgorithms.cs b/Algorithms/Strings/GeneralStringAlgorithms.cs index 6e1822c6..85722720 100644 --- a/Algorithms/Strings/GeneralStringAlgorithms.cs +++ b/Algorithms/Strings/GeneralStringAlgorithms.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Strings; /// diff --git a/Algorithms/Strings/Palindrome.cs b/Algorithms/Strings/Palindrome.cs index 21be50a5..a28c82a4 100644 --- a/Algorithms/Strings/Palindrome.cs +++ b/Algorithms/Strings/Palindrome.cs @@ -1,6 +1,3 @@ -using System; -using System.Text.RegularExpressions; - namespace Algorithms.Strings; /// diff --git a/Algorithms/Strings/PatternMatching/Bitap.cs b/Algorithms/Strings/PatternMatching/Bitap.cs index 0ca5975a..be8b93fc 100644 --- a/Algorithms/Strings/PatternMatching/Bitap.cs +++ b/Algorithms/Strings/PatternMatching/Bitap.cs @@ -1,6 +1,4 @@ -using System; - -namespace Algorithms.Strings.PatternMatching; +namespace Algorithms.Strings.PatternMatching; /// /// The Bitap algorithm is a fuzzy string matching technique. It ains to find approximate matches of a pattern within a diff --git a/Algorithms/Strings/PatternMatching/BoyerMoore.cs b/Algorithms/Strings/PatternMatching/BoyerMoore.cs index a00e93c4..dadf0c0a 100644 --- a/Algorithms/Strings/PatternMatching/BoyerMoore.cs +++ b/Algorithms/Strings/PatternMatching/BoyerMoore.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Strings.PatternMatching; /// diff --git a/Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs b/Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs index 3b31e614..aba670b3 100644 --- a/Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs +++ b/Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Algorithms.Strings.PatternMatching; public class KnuthMorrisPrattSearcher diff --git a/Algorithms/Strings/PatternMatching/NaiveStringSearch.cs b/Algorithms/Strings/PatternMatching/NaiveStringSearch.cs index 184c8067..ed29c45a 100644 --- a/Algorithms/Strings/PatternMatching/NaiveStringSearch.cs +++ b/Algorithms/Strings/PatternMatching/NaiveStringSearch.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - // Implements the traditional naive string matching algorithm in C# for TheAlgorithms/C-Sharp. namespace Algorithms.Strings.PatternMatching; diff --git a/Algorithms/Strings/PatternMatching/RabinKarp.cs b/Algorithms/Strings/PatternMatching/RabinKarp.cs index 3dc19321..a36f3fce 100644 --- a/Algorithms/Strings/PatternMatching/RabinKarp.cs +++ b/Algorithms/Strings/PatternMatching/RabinKarp.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Algorithms.Strings.PatternMatching; /// diff --git a/Algorithms/Strings/PatternMatching/WildCardMatcher.cs b/Algorithms/Strings/PatternMatching/WildCardMatcher.cs index cf15ce21..bc4219f4 100644 --- a/Algorithms/Strings/PatternMatching/WildCardMatcher.cs +++ b/Algorithms/Strings/PatternMatching/WildCardMatcher.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Strings.PatternMatching; /// diff --git a/Algorithms/Strings/Permutation.cs b/Algorithms/Strings/Permutation.cs index 201d5583..970e3ec0 100644 --- a/Algorithms/Strings/Permutation.cs +++ b/Algorithms/Strings/Permutation.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Linq; - namespace Algorithms.Strings; public static class Permutation diff --git a/Algorithms/Strings/Similarity/CosineSimilarity.cs b/Algorithms/Strings/Similarity/CosineSimilarity.cs index 2975f793..db2db6dd 100644 --- a/Algorithms/Strings/Similarity/CosineSimilarity.cs +++ b/Algorithms/Strings/Similarity/CosineSimilarity.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -namespace Algorithms.Strings.Similarity; +namespace Algorithms.Strings.Similarity; public static class CosineSimilarity { diff --git a/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs b/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs index 4d699658..222dbd1e 100644 --- a/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs +++ b/Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs @@ -1,6 +1,4 @@ -using System; - -namespace Algorithms.Strings.Similarity; +namespace Algorithms.Strings.Similarity; public static class DamerauLevenshteinDistance { diff --git a/Algorithms/Strings/Similarity/HammingDistance.cs b/Algorithms/Strings/Similarity/HammingDistance.cs index 9b061e6a..e85ff31d 100644 --- a/Algorithms/Strings/Similarity/HammingDistance.cs +++ b/Algorithms/Strings/Similarity/HammingDistance.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Strings.Similarity; /// @@ -21,7 +19,7 @@ public static class HammingDistance /// Levenshtein distance between source and target strings. public static int Calculate(string s1, string s2) { - if(s1.Length != s2.Length) + if (s1.Length != s2.Length) { throw new ArgumentException("Strings must be equal length."); } diff --git a/Algorithms/Strings/Similarity/JaccardSimilarity.cs b/Algorithms/Strings/Similarity/JaccardSimilarity.cs index 63fe23cc..4207b2af 100644 --- a/Algorithms/Strings/Similarity/JaccardSimilarity.cs +++ b/Algorithms/Strings/Similarity/JaccardSimilarity.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -namespace Algorithms.Strings.Similarity; +namespace Algorithms.Strings.Similarity; /// /// diff --git a/Algorithms/Strings/Similarity/JaroSimilarity.cs b/Algorithms/Strings/Similarity/JaroSimilarity.cs index 35741b66..33253c41 100644 --- a/Algorithms/Strings/Similarity/JaroSimilarity.cs +++ b/Algorithms/Strings/Similarity/JaroSimilarity.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Strings.Similarity; /// diff --git a/Algorithms/Strings/Similarity/JaroWinklerDistance.cs b/Algorithms/Strings/Similarity/JaroWinklerDistance.cs index 481f5ba9..02bcdc88 100644 --- a/Algorithms/Strings/Similarity/JaroWinklerDistance.cs +++ b/Algorithms/Strings/Similarity/JaroWinklerDistance.cs @@ -1,5 +1,3 @@ -using System.Linq; - namespace Algorithms.Strings.Similarity; /// diff --git a/Algorithms/Strings/Similarity/OptimalStringAlignment.cs b/Algorithms/Strings/Similarity/OptimalStringAlignment.cs index 743c4ce1..f6784ab1 100644 --- a/Algorithms/Strings/Similarity/OptimalStringAlignment.cs +++ b/Algorithms/Strings/Similarity/OptimalStringAlignment.cs @@ -1,5 +1,3 @@ -using System; - namespace Algorithms.Strings.Similarity { /// From d6c05535f337911842dd06adc012303bf3e6e912 Mon Sep 17 00:00:00 2001 From: Karan Chadha <72665232+KaranChadha10@users.noreply.github.com> Date: Wed, 17 Sep 2025 02:41:29 +0530 Subject: [PATCH 138/138] chore: add GlobalUsings.cs with project-wide using directives in utilities folder (#523) --- .../Extensions/DictionaryExtensionsTests.cs | 6 ------ .../Extensions/MatrixExtensionsTests.cs | 5 ----- .../Extensions/RandomExtensionsTests.cs | 5 ----- .../Extensions/VectorExtensionsTests.cs | 5 ----- Utilities.Tests/GlobalUsings.cs | 17 +++++++++++++++++ Utilities/Exceptions/ItemNotFoundException.cs | 2 -- Utilities/Extensions/DictionaryExtensions.cs | 3 --- Utilities/Extensions/MatrixExtensions.cs | 2 -- Utilities/Extensions/RandomExtensions.cs | 3 --- Utilities/Extensions/VectorExtensions.cs | 2 -- Utilities/GlobalUsings.cs | 15 +++++++++++++++ 11 files changed, 32 insertions(+), 33 deletions(-) create mode 100644 Utilities.Tests/GlobalUsings.cs create mode 100644 Utilities/GlobalUsings.cs diff --git a/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs b/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs index 73964a29..d4f44865 100644 --- a/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs +++ b/Utilities.Tests/Extensions/DictionaryExtensionsTests.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using FluentAssertions; -using NUnit.Framework; -using Utilities.Extensions; - namespace Utilities.Tests.Extensions; public class DictionaryExtensionsTests diff --git a/Utilities.Tests/Extensions/MatrixExtensionsTests.cs b/Utilities.Tests/Extensions/MatrixExtensionsTests.cs index a079299e..83793a54 100644 --- a/Utilities.Tests/Extensions/MatrixExtensionsTests.cs +++ b/Utilities.Tests/Extensions/MatrixExtensionsTests.cs @@ -1,8 +1,3 @@ -using System; -using FluentAssertions; -using NUnit.Framework; -using Utilities.Extensions; - namespace Utilities.Tests.Extensions; public class MatrixExtensionsTests diff --git a/Utilities.Tests/Extensions/RandomExtensionsTests.cs b/Utilities.Tests/Extensions/RandomExtensionsTests.cs index a26922f6..2ca6d346 100644 --- a/Utilities.Tests/Extensions/RandomExtensionsTests.cs +++ b/Utilities.Tests/Extensions/RandomExtensionsTests.cs @@ -1,8 +1,3 @@ -using System; -using FluentAssertions; -using NUnit.Framework; -using Utilities.Extensions; - namespace Utilities.Tests.Extensions; public class RandomExtensionsTests diff --git a/Utilities.Tests/Extensions/VectorExtensionsTests.cs b/Utilities.Tests/Extensions/VectorExtensionsTests.cs index e4c5320f..974cba33 100644 --- a/Utilities.Tests/Extensions/VectorExtensionsTests.cs +++ b/Utilities.Tests/Extensions/VectorExtensionsTests.cs @@ -1,8 +1,3 @@ -using System; -using FluentAssertions; -using NUnit.Framework; -using Utilities.Extensions; - namespace Utilities.Tests.Extensions; public class VectorExtensionsTests diff --git a/Utilities.Tests/GlobalUsings.cs b/Utilities.Tests/GlobalUsings.cs new file mode 100644 index 00000000..c85dacaf --- /dev/null +++ b/Utilities.Tests/GlobalUsings.cs @@ -0,0 +1,17 @@ +// ----------------------------------------------------------------------------- +// Global using directives for the C-Sharp solution. +// These namespaces are imported globally so they don’t need to be repeatedly declared +// in individual files, improving readability and reducing boilerplate. +// +// Guidelines: +// - Keep only the most commonly used namespaces here. +// - Add project-specific namespaces (e.g., Utilities.Extensions) only if they are +// required across the majority of files in the project. +// - Avoid placing rarely used namespaces here to maintain clarity. +// ----------------------------------------------------------------------------- + +global using System; // Core base classes and fundamental types +global using System.Collections.Generic; // Generic collection types (List, Dictionary, etc.) +global using FluentAssertions; // Assertion library for more readable and expressive unit tests +global using NUnit.Framework; // Testing framework providing attributes and assertions for test cases +global using Utilities.Extensions; // Common project-specific extension methods reused across multiple files diff --git a/Utilities/Exceptions/ItemNotFoundException.cs b/Utilities/Exceptions/ItemNotFoundException.cs index 580fc691..c9cc38f8 100644 --- a/Utilities/Exceptions/ItemNotFoundException.cs +++ b/Utilities/Exceptions/ItemNotFoundException.cs @@ -1,5 +1,3 @@ -using System; - namespace Utilities.Exceptions; /// diff --git a/Utilities/Extensions/DictionaryExtensions.cs b/Utilities/Extensions/DictionaryExtensions.cs index 3d040554..ca917348 100644 --- a/Utilities/Extensions/DictionaryExtensions.cs +++ b/Utilities/Extensions/DictionaryExtensions.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace Utilities.Extensions; public static class DictionaryExtensions diff --git a/Utilities/Extensions/MatrixExtensions.cs b/Utilities/Extensions/MatrixExtensions.cs index 780f6e73..96b63d0c 100644 --- a/Utilities/Extensions/MatrixExtensions.cs +++ b/Utilities/Extensions/MatrixExtensions.cs @@ -1,5 +1,3 @@ -using System; - namespace Utilities.Extensions; public static class MatrixExtensions diff --git a/Utilities/Extensions/RandomExtensions.cs b/Utilities/Extensions/RandomExtensions.cs index eb7f7f47..a4bab3c2 100644 --- a/Utilities/Extensions/RandomExtensions.cs +++ b/Utilities/Extensions/RandomExtensions.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Utilities.Extensions; public static class RandomExtensions diff --git a/Utilities/Extensions/VectorExtensions.cs b/Utilities/Extensions/VectorExtensions.cs index bfb807f0..7241bb17 100644 --- a/Utilities/Extensions/VectorExtensions.cs +++ b/Utilities/Extensions/VectorExtensions.cs @@ -1,5 +1,3 @@ -using System; - namespace Utilities.Extensions; public static class VectorExtensions diff --git a/Utilities/GlobalUsings.cs b/Utilities/GlobalUsings.cs new file mode 100644 index 00000000..25845bd1 --- /dev/null +++ b/Utilities/GlobalUsings.cs @@ -0,0 +1,15 @@ +// ----------------------------------------------------------------------------- +// Global using directives for the C-Sharp solution. +// These namespaces are imported globally so they don’t need to be repeatedly declared +// in individual files, improving readability and reducing boilerplate. +// +// Guidelines: +// - Keep only the most commonly used namespaces here. +// - Add project-specific namespaces (e.g., Utilities.Extensions) only if they are +// required across the majority of files in the project. +// - Avoid placing rarely used namespaces here to maintain clarity. +// ----------------------------------------------------------------------------- + +global using System; // Core base classes and fundamental types +global using System.Collections.Generic; // Generic collection types (List, Dictionary, etc.) +global using System.Linq; // LINQ query operators for collections