From 66474d67908be547361a58c328f7e4a0a520da4f Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Sat, 6 Jan 2018 21:31:19 -0500 Subject: [PATCH 01/10] include selection option(r) in permutation --- .../Combinatorics/Permutation_Tests.cs | 79 ++++++++----------- .../Combinatorics/Permutation.cs | 56 ++----------- 2 files changed, 38 insertions(+), 97 deletions(-) diff --git a/Advanced.Algorithms.Tests/Combinatorics/Permutation_Tests.cs b/Advanced.Algorithms.Tests/Combinatorics/Permutation_Tests.cs index 5e066128..d3cdd420 100644 --- a/Advanced.Algorithms.Tests/Combinatorics/Permutation_Tests.cs +++ b/Advanced.Algorithms.Tests/Combinatorics/Permutation_Tests.cs @@ -12,77 +12,64 @@ namespace Advanced.Algorithms.Tests.Combinatorics public class Permutation_Tests { //for verification - readonly Func factorial = n => n == 0 ? 1 : + static readonly Func factorial = n => n == 0 ? 1 : Enumerable.Range(1, n).Aggregate((acc, x) => acc * x); - - [TestMethod] - public void Permutation_Without_Repetitions_Smoke_Test() - { - var input = "".ToCharArray().ToList(); - var permuations = Permutation.Find(input); - Assert.AreEqual(factorial(input.Count), permuations.Count); - - input = "cookie".ToCharArray().ToList(); - permuations = Permutation.Find(input); - Assert.AreEqual(factorial(input.Count), permuations.Count); - - input = "monster".ToCharArray().ToList(); - permuations = Permutation.Find(input); - Assert.AreEqual(factorial(input.Count), permuations.Count); - } - + //for verification + static readonly Func permutation = (int n, int r) + => n == 0 || r == 0 ? 1 : factorial(n) / factorial(n - r); [TestMethod] public void Permutation_With_Repetition_Smoke_Test() { var input = "".ToCharArray().ToList(); - var permuations = Permutation.Find(input, true); + var permuations = Permutation.Find(input, input.Count, true); Assert.AreEqual(Math.Pow(input.Count, input.Count), permuations.Count); input = "pen".ToCharArray().ToList(); - permuations = Permutation.Find(input, true); + permuations = Permutation.Find(input, input.Count, true); Assert.AreEqual(Math.Pow(input.Count, input.Count), permuations.Count); input = "scan".ToCharArray().ToList(); - permuations = Permutation.Find(input, true); + permuations = Permutation.Find(input, input.Count, true); Assert.AreEqual(Math.Pow(input.Count, input.Count), permuations.Count); - } - [TestMethod] - public void Permutation_Without_Repetition_Without_Inversions_Smoke_Test() - { - var input = "".ToCharArray().ToList(); - var permuations = Permutation.Find(input, false, false); - Assert.AreEqual(factorial(input.Count) / 2, permuations.Count); + input = "scan".ToCharArray().ToList(); + permuations = Permutation.Find(input, 2, true); + Assert.AreEqual(Math.Pow(input.Count, 2), permuations.Count); - input = "abc".ToCharArray().ToList(); - permuations = Permutation.Find(input, false, false); - Assert.AreEqual(factorial(input.Count) / 2, permuations.Count); + input = "scan".ToCharArray().ToList(); + permuations = Permutation.Find(input, 3, true); + Assert.AreEqual(Math.Pow(input.Count, 3), permuations.Count); - input = "acde".ToCharArray().ToList(); - permuations = Permutation.Find(input, false, false); - Assert.AreEqual(factorial(input.Count) / 2, permuations.Count); + input = "scaner".ToCharArray().ToList(); + permuations = Permutation.Find(input, 4, true); + Assert.AreEqual(Math.Pow(input.Count, 4), permuations.Count); } [TestMethod] - public void Permutation_With_Repetition_Without_Inversions_Smoke_Test() + public void Permutation_Without_Repetitions_Smoke_Test() { - var input = "".ToCharArray().ToList(); - var permuations = Permutation.Find(input, true, false); - Assert.AreEqual(0, permuations.Count); + var permuations = Permutation.Find(input, input.Count); + Assert.AreEqual(permutation(input.Count, input.Count), permuations.Count); - input = "pen".ToCharArray().ToList(); - permuations = Permutation.Find(input, true, false); - Assert.AreEqual(9, permuations.Count); + input = "cookie".ToCharArray().ToList(); + permuations = Permutation.Find(input, input.Count); + Assert.AreEqual(permutation(input.Count, input.Count), permuations.Count); - input = "cool".ToCharArray().ToList(); - permuations = Permutation.Find(input, true, false); - Assert.AreEqual(80, permuations.Count); - } + input = "monster".ToCharArray().ToList(); + permuations = Permutation.Find(input, input.Count); + Assert.AreEqual(permutation(input.Count, input.Count), permuations.Count); - + input = "cookie".ToCharArray().ToList(); + permuations = Permutation.Find(input, 2); + Assert.AreEqual(permutation(input.Count, 2), permuations.Count); + + input = "monster".ToCharArray().ToList(); + permuations = Permutation.Find(input, 3); + Assert.AreEqual(permutation(input.Count, 3), permuations.Count); + } } } diff --git a/Advanced.Algorithms/Combinatorics/Permutation.cs b/Advanced.Algorithms/Combinatorics/Permutation.cs index 48626411..7bf79288 100644 --- a/Advanced.Algorithms/Combinatorics/Permutation.cs +++ b/Advanced.Algorithms/Combinatorics/Permutation.cs @@ -8,20 +8,20 @@ namespace Advanced.Algorithms.Combinatorics { public class Permutation { - public static List> Find(List input, bool withRepetition = false) + public static List> Find(List input, int r, bool withRepetition = false) { var result = new List>(); - Recurse(input, withRepetition, new List(), new HashSet(), result); + Recurse(input, r, withRepetition, new List(), new HashSet(), result); return result; } - private static void Recurse(List input, bool withRepetition, + private static void Recurse(List input, int r, bool withRepetition, List prefix, HashSet prefixIndices, List> result) { - if (prefix.Count == input.Count) + if (prefix.Count == r) { result.Add(new List(prefix)); return; @@ -37,53 +37,7 @@ private static void Recurse(List input, bool withRepetition, prefix.Add(input[j]); prefixIndices.Add(j); - Recurse(input, withRepetition, prefix, prefixIndices, result); - - prefix.RemoveAt(prefix.Count - 1); - prefixIndices.Remove(j); - } - } - - public static List> Find(List input, bool withRepetition, - bool withInversions) where T : IComparable - { - var result = new List>(); - - Recurse(input, withRepetition, withInversions, - new List(), new HashSet(), result); - - return result; - } - - private static void Recurse(List input, - bool withRepetition, bool withInversions, - List prefix, HashSet prefixIndices, - List> result) where T : IComparable - { - if (prefix.Count == input.Count - && (withInversions || - (prefix.Count > 0 && prefix[0].CompareTo(prefix[prefix.Count - 1]) < 0))) - { - result.Add(new List(prefix)); - return; - } - - if (prefix.Count == input.Count) - { - return; - } - - for (int j = 0; j < input.Count; j++) - { - if (prefixIndices.Contains(j) && !withRepetition) - { - continue; - } - - prefix.Add(input[j]); - prefixIndices.Add(j); - - Recurse(input, withRepetition, withInversions, prefix, prefixIndices, result); + Recurse(input, r, withRepetition, prefix, prefixIndices, result); prefix.RemoveAt(prefix.Count - 1); prefixIndices.Remove(j); From d49939f9c0267e9614d75693fda5e2cb9e21fe2e Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Sun, 7 Jan 2018 19:39:19 -0500 Subject: [PATCH 02/10] Fix variations --- .../Combinatorics/Variation_Tests.cs | 4 +- .../Combinatorics/Variation.cs | 40 +++++-------------- 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/Advanced.Algorithms.Tests/Combinatorics/Variation_Tests.cs b/Advanced.Algorithms.Tests/Combinatorics/Variation_Tests.cs index f0d3604b..ba898b81 100644 --- a/Advanced.Algorithms.Tests/Combinatorics/Variation_Tests.cs +++ b/Advanced.Algorithms.Tests/Combinatorics/Variation_Tests.cs @@ -41,11 +41,11 @@ public void Variation_With_Repetitions_Smoke_Test() { var input = "abcd".ToCharArray().ToList(); var variations = Variation.Find(input, 2, true); - Assert.AreEqual(Math.Pow(input.Count, 2), variations.Count); + Assert.AreEqual(combination(input.Count + 2 - 1, 2) * factorial(2), variations.Count); input = "scan".ToCharArray().ToList(); variations = Variation.Find(input, 3, true); - Assert.AreEqual(Math.Pow(input.Count, 3), variations.Count); + Assert.AreEqual(combination(input.Count + 3 - 1, 3) * factorial(3), variations.Count); input = "".ToCharArray().ToList(); variations = Variation.Find(input, 3, true); diff --git a/Advanced.Algorithms/Combinatorics/Variation.cs b/Advanced.Algorithms/Combinatorics/Variation.cs index 987ad636..303056c5 100644 --- a/Advanced.Algorithms/Combinatorics/Variation.cs +++ b/Advanced.Algorithms/Combinatorics/Variation.cs @@ -9,49 +9,31 @@ namespace Advanced.Algorithms.Combinatorics public class Variation { /*Variations are arrangements of selections of objects, where the order of the selected objects matters. - To count k-element variations of n objects, we first need to choose a k-element combination and then + To count r-element variations of n objects, we first need to choose a r-element combination and then a permutation of the selected objects*/ //Without repetition - /* It is also the number of ways of putting r distinct balls into input.Count distinct boxes such that each box + /* It is also the number of ways of putting n distinct balls into r distinct boxes such that each box receives at most one element. */ //With repetition - /* It is the number of all ways of putting r distinct balls into input.Count distinct boxes */ + /* It is the number of all ways of putting n distinct balls into r distinct boxes */ public static List> Find(List input, int r, bool withRepetition) { - var result = new List>(); + var combinations = new List>(); - Recurse(input, r, withRepetition, new List(), new HashSet(), result); + combinations.AddRange(Combination.Find(input, r, withRepetition)); - return result; - } + var variations = new List>(); - private static void Recurse(List input, int r, bool withRepetition, - List prefix, HashSet prefixIndices, - List> result) - { - if (prefix.Count == r) + foreach (var combination in combinations) { - result.Add(new List(prefix)); - return; + variations.AddRange(Permutation.Find(combination, combination.Count)); } - for (int j = 0; j < input.Count; j++) - { - if (prefixIndices.Contains(j) && !withRepetition) - { - continue; - } - - prefix.Add(input[j]); - prefixIndices.Add(j); - - Recurse(input, r, withRepetition, prefix, prefixIndices, result); - - prefix.RemoveAt(prefix.Count - 1); - prefixIndices.Remove(j); - } + return variations; } + + } } From ab3e826f4916a517a89568d9457065e452406898 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Tue, 16 Jan 2018 22:21:22 -0500 Subject: [PATCH 03/10] Support buld operations for ring buffer --- .../Queues/CircularQueue_Tests.cs | 26 +-- .../DataStructures/Queues/CircularQueue.cs | 173 +++++++++++------- 2 files changed, 124 insertions(+), 75 deletions(-) diff --git a/Advanced.Algorithms.Tests/DataStructures/Queues/CircularQueue_Tests.cs b/Advanced.Algorithms.Tests/DataStructures/Queues/CircularQueue_Tests.cs index eecd152d..324c69b4 100644 --- a/Advanced.Algorithms.Tests/DataStructures/Queues/CircularQueue_Tests.cs +++ b/Advanced.Algorithms.Tests/DataStructures/Queues/CircularQueue_Tests.cs @@ -13,16 +13,16 @@ public void CircularQueue_Test() { var Queue = new CircularQueue(7); - Queue.Enqueue(1); - Queue.Enqueue(2); + Assert.AreEqual(0, Queue.Enqueue(1)); + Assert.AreEqual(0, Queue.Enqueue(2)); - Queue.Enqueue(3); - Queue.Enqueue(4); - Queue.Enqueue(5); - Queue.Enqueue(6); - Queue.Enqueue(7); - Queue.Enqueue(8); - Queue.Enqueue(9); + Assert.AreEqual(0, Queue.Enqueue(3)); + Assert.AreEqual(0, Queue.Enqueue(4)); + Assert.AreEqual(0, Queue.Enqueue(5)); + Assert.AreEqual(0, Queue.Enqueue(6)); + Assert.AreEqual(0, Queue.Enqueue(7)); + Assert.AreEqual(1, Queue.Enqueue(8)); + Assert.AreEqual(2, Queue.Enqueue(9)); Assert.AreEqual(Queue.Count, 7); Assert.AreEqual(3, Queue.Dequeue()); @@ -47,8 +47,8 @@ public void CircularQueue_Test() Assert.AreEqual(Queue.Count, 0); - Queue.Enqueue(1); - Queue.Enqueue(2); + Assert.AreEqual(0, Queue.Enqueue(1)); + Assert.AreEqual(0, Queue.Enqueue(2)); Assert.AreEqual(Queue.Count, 2); Assert.AreEqual(1, Queue.Dequeue()); @@ -57,6 +57,6 @@ public void CircularQueue_Test() Assert.AreEqual(Queue.Dequeue(), 2); } - + } -} +} \ No newline at end of file diff --git a/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs b/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs index 513c3ffe..972ba7ad 100644 --- a/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs +++ b/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs @@ -1,99 +1,148 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace Advanced.Algorithms.DataStructures.Queues +/// +/// Cicular queue aka Ring Buffer using fixed size array +/// +/// +public class CircularQueue { + private T[] queue; + + //points to the index of next element to be deleted + private int start = 0; + + //points to the index new element should be inserted + private int end = 0; + + public int Count { get; private set; } + + public CircularQueue(int size) + { + queue = new T[size]; + } + /// - /// Cicular queue aka Ring Buffer using fixed size array + /// Note: When buffer overflows oldest data will be erased + /// O(1) time complexity /// - /// - public class CircularQueue + /// + public T Enqueue(T data) { - private T[] queue; - - //points to the index of next element to be deleted - private int start = 0; + T deleted = default(T); - //points to the index new element should be inserted - private int end = 0; + //wrap around removing oldest element + if (end > queue.Length - 1) + { + end = 0; - public int Count { get; private set; } + if (start == 0) + { + deleted = queue[start]; + start++; + } + } - public CircularQueue(int size) + //when end meets start after wraping around + if (end == start && Count > 1) { - queue = new T[size]; + deleted = queue[start]; + start++; } - /// - /// Note: When buffer overflows oldest data will be erased - /// - /// - public void Enqueue(T data) + queue[end] = data; + end++; + + if (Count < queue.Length) { - //wrap around removing oldest element - if (end > queue.Length - 1) - { - end = 0; + Count++; + } - if(start == 0) - { - start++; - } - } + return deleted; + } - //when end meets start after wraping around - if (end == start && Count > 1) - { - start++; - } + /// + /// O(bulk.Length) time complexity + /// + /// + /// + public IEnumerable Enqueue(T[] bulk) + { + var deletedList = new List(); - queue[end] = data; - end++; + foreach (var item in bulk) + { + var deleted = Enqueue(item); - if (Count < queue.Length) + if (!deleted.Equals(default(T))) { - Count++; + deletedList.Add(deleted); } } + return deletedList; + } + + /// + /// O(1) time complexity + /// + /// + public T Dequeue() + { + if (Count == 0) + { + throw new Exception("Empty queue."); + } + + var element = queue[start]; + start++; - public T Dequeue() + //wrap around + if (start > queue.Length - 1) { - if (Count == 0) + start = 0; + + if (end == 0) { - throw new Exception("Empty queue."); + end++; } + } - var element = queue[start]; - start++; + Count--; - //wrap around - if (start > queue.Length - 1) - { - start = 0; + if (start == end && Count > 1) + { + end++; + } - if (end == 0) - { - end++; - } - } + //reset + if (Count == 0) + { + start = end = 0; + } - Count--; + return element; + } - if (start == end && Count > 1) - { - end++; - } + /// + /// O(bulkNumber) time complexity + /// + /// + public IEnumerable Dequeue(int bulkNumber) + { + var deletedList = new List(); + while (bulkNumber > 0 && Count > 0) + { + var deleted = Dequeue(); - //reset - if (Count == 0) + if (!deleted.Equals(default(T))) { - start = end = 0; + deletedList.Add(deleted); } - - return element; } + + return deletedList; } + } + From e4d738ad68512852c8c0fe9193572c40d659b2c1 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Tue, 16 Jan 2018 22:40:40 -0500 Subject: [PATCH 04/10] fix bug in buld delete for circular queue --- Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs b/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs index 972ba7ad..c94d76da 100644 --- a/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs +++ b/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs @@ -139,6 +139,8 @@ public IEnumerable Dequeue(int bulkNumber) { deletedList.Add(deleted); } + + bulkNumber--; } return deletedList; From 4f12076d253e22bf0ff2985244647614c0943aab Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Wed, 17 Jan 2018 14:32:48 -0500 Subject: [PATCH 05/10] Travelling Salesman problem --- .../Advanced.Algorithms.Tests.csproj | 1 + .../ShortestPath/TravellingSalesman_Tests.cs | 43 +++++++++++ .../ShortestPath/TravellingSalesman.cs | 75 +++++++++++++++++++ README.md | 1 + 4 files changed, 120 insertions(+) create mode 100644 Advanced.Algorithms.Tests/GraphAlgorithms/ShortestPath/TravellingSalesman_Tests.cs create mode 100644 Advanced.Algorithms/GraphAlgorithms/ShortestPath/TravellingSalesman.cs diff --git a/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj b/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj index 2d35c843..b37edf5a 100644 --- a/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj +++ b/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj @@ -127,6 +127,7 @@ + diff --git a/Advanced.Algorithms.Tests/GraphAlgorithms/ShortestPath/TravellingSalesman_Tests.cs b/Advanced.Algorithms.Tests/GraphAlgorithms/ShortestPath/TravellingSalesman_Tests.cs new file mode 100644 index 00000000..0012e79f --- /dev/null +++ b/Advanced.Algorithms.Tests/GraphAlgorithms/ShortestPath/TravellingSalesman_Tests.cs @@ -0,0 +1,43 @@ +using Advanced.Algorithms.DataStructures.Graph.AdjacencyList; +using Advanced.Algorithms.GraphAlgorithms; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Advanced.Algorithms.Tests.GraphAlgorithms.ShortestPath +{ + /// + /// Problem details below + /// https://en.wikipedia.org/wiki/Travelling_salesman_problem + /// + [TestClass] + public class TravellingSalesman_Tests + { + [TestMethod] + public void TravellingSalesman_Smoke_Test() + { + var graph = new WeightedDiGraph(); + + graph.AddVertex(0); + graph.AddVertex(1); + graph.AddVertex(2); + graph.AddVertex(3); + + graph.AddEdge(0, 1, 1); + graph.AddEdge(0, 2, 15); + graph.AddEdge(0, 3, 6); + + graph.AddEdge(1, 0, 2); + graph.AddEdge(1, 2, 7); + graph.AddEdge(1, 3, 3); + + graph.AddEdge(2, 0, 9); + graph.AddEdge(2, 1, 6); + graph.AddEdge(2, 3, 12); + + graph.AddEdge(3, 0, 10); + graph.AddEdge(3, 1, 4); + graph.AddEdge(3, 2, 8); + + Assert.AreEqual(21, TravellingSalesman.GetMinWeight(graph)); + } + } +} diff --git a/Advanced.Algorithms/GraphAlgorithms/ShortestPath/TravellingSalesman.cs b/Advanced.Algorithms/GraphAlgorithms/ShortestPath/TravellingSalesman.cs new file mode 100644 index 00000000..aeccace0 --- /dev/null +++ b/Advanced.Algorithms/GraphAlgorithms/ShortestPath/TravellingSalesman.cs @@ -0,0 +1,75 @@ + +using Advanced.Algorithms.DataStructures.Graph.AdjacencyList; +using System.Collections.Generic; +using System.Linq; + +namespace Advanced.Algorithms.GraphAlgorithms +{ + /// + /// Problem details below + /// https://en.wikipedia.org/wiki/Travelling_salesman_problem + /// Uses dynamic programming and have + /// psuedo-polynomial time runtime complexity for this NP hard problem + /// + public class TravellingSalesman + { + public static int GetMinWeight(WeightedDiGraph graph) + { + return GetMinWeight(graph.ReferenceVertex, graph.ReferenceVertex, + graph.VerticesCount, + new HashSet>(), + new Dictionary()); + } + + public static int GetMinWeight(WeightedDiGraphVertex currentVertex, + WeightedDiGraphVertex tgtVertex, + int remainingVertexCount, + HashSet> visited, + Dictionary cache) + { + var cacheKey = $"{currentVertex.Value}-{remainingVertexCount}"; + + if (cache.ContainsKey(cacheKey)) + { + return cache[cacheKey]; + } + + visited.Add(currentVertex); + + var results = new List(); + + foreach (var vertex in currentVertex.OutEdges) + { + //base case + if (vertex.Key == tgtVertex + && remainingVertexCount == 1) + { + results.Add(vertex.Value); + break; + } + + if (!visited.Contains(vertex.Key)) + { + var result = GetMinWeight(vertex.Key, tgtVertex, remainingVertexCount - 1, visited, cache); + + if (result != int.MaxValue) + { + results.Add(result + vertex.Value); + } + + } + } + + visited.Remove(currentVertex); + + if (results.Count == 0) + { + return int.MaxValue; + } + + var min = results.Min(); + cache.Add(cacheKey, min); + return min; + } + } +} diff --git a/README.md b/README.md index 7a22cd22..e080f888 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,7 @@ Note: It is observed that among the implementations here in practice, with the e - [X] Dijikstra's algorithm ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Dijikstra.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/GraphAlgorithms/ShortestPath/Dijikstras_Tests.cs)) using Fibornacci Heap. - [X] Floyd-Warshall algorithm ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Floyd-Warshall.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/GraphAlgorithms/ShortestPath/FloydWarshall_Tests.cs)) - [X] Johnson's algorithm ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Johnsons.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/GraphAlgorithms/ShortestPath/Johnson_Tests.cs)) +- [X] Travelling Salesman Problem ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/GraphAlgorithms/ShortestPath/TravellingSalesman.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/GraphAlgorithms/ShortestPath/TravellingSalesman_Tests.cs)) ### Matching From 54b5546a786b57cdf4458be4a4e0d83b5e86422b Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Sun, 21 Jan 2018 20:53:56 -0500 Subject: [PATCH 06/10] New section --- .../Advanced.Algorithms.Tests.csproj | 3 +- .../Combinatorics/Variation_Tests.cs | 56 ------- .../CircularQueue_Tests.cs | 5 +- .../Combinatorics/Variation.cs | 39 ----- .../DataStructures/Queues/CircularQueue.cs | 150 ----------------- .../DistributedSystems/CircularQueue.cs | 153 ++++++++++++++++++ README.md | 6 +- 7 files changed, 160 insertions(+), 252 deletions(-) delete mode 100644 Advanced.Algorithms.Tests/Combinatorics/Variation_Tests.cs rename Advanced.Algorithms.Tests/{DataStructures/Queues => DistributedSystems}/CircularQueue_Tests.cs (91%) delete mode 100644 Advanced.Algorithms/Combinatorics/Variation.cs delete mode 100644 Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs create mode 100644 Advanced.Algorithms/DistributedSystems/CircularQueue.cs diff --git a/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj b/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj index b37edf5a..34a2bdd7 100644 --- a/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj +++ b/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj @@ -67,7 +67,6 @@ - @@ -99,7 +98,7 @@ - + diff --git a/Advanced.Algorithms.Tests/Combinatorics/Variation_Tests.cs b/Advanced.Algorithms.Tests/Combinatorics/Variation_Tests.cs deleted file mode 100644 index ba898b81..00000000 --- a/Advanced.Algorithms.Tests/Combinatorics/Variation_Tests.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Advanced.Algorithms.Combinatorics; - -namespace Advanced.Algorithms.Tests.Combinatorics -{ - [TestClass] - public class Variation_Tests - { - //for verification - static readonly Func factorial = n => n == 0 ? 1 : - Enumerable.Range(1, n).Aggregate((acc, x) => acc * x); - - //for verification - static readonly Func combination = (int n, int r) - => n == 0 || r == 0 ? 0 : factorial(n) / (factorial(r) * factorial(n - r)); - - [TestMethod] - public void Variation_Without_Repetitions_Smoke_Test() - { - var input = "".ToCharArray().ToList(); - var variations = Variation.Find(input, 2, false); - Assert.AreEqual(combination(input.Count, 2) * factorial(2), variations.Count); - - input = "cookie".ToCharArray().ToList(); - variations = Variation.Find(input, 3, false); - Assert.AreEqual(combination(input.Count, 3) * factorial(3), variations.Count); - - input = "monsters".ToCharArray().ToList(); - variations = Variation.Find(input, 3, false); - Assert.AreEqual(combination(input.Count, 3) * factorial(3), variations.Count); - } - - - [TestMethod] - public void Variation_With_Repetitions_Smoke_Test() - { - var input = "abcd".ToCharArray().ToList(); - var variations = Variation.Find(input, 2, true); - Assert.AreEqual(combination(input.Count + 2 - 1, 2) * factorial(2), variations.Count); - - input = "scan".ToCharArray().ToList(); - variations = Variation.Find(input, 3, true); - Assert.AreEqual(combination(input.Count + 3 - 1, 3) * factorial(3), variations.Count); - - input = "".ToCharArray().ToList(); - variations = Variation.Find(input, 3, true); - Assert.AreEqual(0, variations.Count); - } - - } -} diff --git a/Advanced.Algorithms.Tests/DataStructures/Queues/CircularQueue_Tests.cs b/Advanced.Algorithms.Tests/DistributedSystems/CircularQueue_Tests.cs similarity index 91% rename from Advanced.Algorithms.Tests/DataStructures/Queues/CircularQueue_Tests.cs rename to Advanced.Algorithms.Tests/DistributedSystems/CircularQueue_Tests.cs index 324c69b4..d68a3411 100644 --- a/Advanced.Algorithms.Tests/DataStructures/Queues/CircularQueue_Tests.cs +++ b/Advanced.Algorithms.Tests/DistributedSystems/CircularQueue_Tests.cs @@ -1,8 +1,7 @@ -using Advanced.Algorithms.DataStructures; -using Advanced.Algorithms.DataStructures.Queues; +using Advanced.Algorithms.DataStructures.DistributedSystems; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Advanced.Algorithms.Tests.DataStructures.Queues +namespace Advanced.Algorithms.Tests.DataStructures.DistributedSystems { [TestClass] public class CircularQueue_Tests diff --git a/Advanced.Algorithms/Combinatorics/Variation.cs b/Advanced.Algorithms/Combinatorics/Variation.cs deleted file mode 100644 index 303056c5..00000000 --- a/Advanced.Algorithms/Combinatorics/Variation.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Advanced.Algorithms.Combinatorics -{ - public class Variation - { - /*Variations are arrangements of selections of objects, where the order of the selected objects matters. - To count r-element variations of n objects, we first need to choose a r-element combination and then - a permutation of the selected objects*/ - - //Without repetition - /* It is also the number of ways of putting n distinct balls into r distinct boxes such that each box - receives at most one element. */ - - //With repetition - /* It is the number of all ways of putting n distinct balls into r distinct boxes */ - public static List> Find(List input, int r, bool withRepetition) - { - var combinations = new List>(); - - combinations.AddRange(Combination.Find(input, r, withRepetition)); - - var variations = new List>(); - - foreach (var combination in combinations) - { - variations.AddRange(Permutation.Find(combination, combination.Count)); - } - - return variations; - } - - - } -} diff --git a/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs b/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs deleted file mode 100644 index c94d76da..00000000 --- a/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using System.Collections.Generic; - -/// -/// Cicular queue aka Ring Buffer using fixed size array -/// -/// -public class CircularQueue -{ - private T[] queue; - - //points to the index of next element to be deleted - private int start = 0; - - //points to the index new element should be inserted - private int end = 0; - - public int Count { get; private set; } - - public CircularQueue(int size) - { - queue = new T[size]; - } - - /// - /// Note: When buffer overflows oldest data will be erased - /// O(1) time complexity - /// - /// - public T Enqueue(T data) - { - T deleted = default(T); - - //wrap around removing oldest element - if (end > queue.Length - 1) - { - end = 0; - - if (start == 0) - { - deleted = queue[start]; - start++; - } - } - - //when end meets start after wraping around - if (end == start && Count > 1) - { - deleted = queue[start]; - start++; - } - - queue[end] = data; - end++; - - if (Count < queue.Length) - { - Count++; - } - - return deleted; - } - - /// - /// O(bulk.Length) time complexity - /// - /// - /// - public IEnumerable Enqueue(T[] bulk) - { - var deletedList = new List(); - - foreach (var item in bulk) - { - var deleted = Enqueue(item); - - if (!deleted.Equals(default(T))) - { - deletedList.Add(deleted); - } - } - - return deletedList; - } - - /// - /// O(1) time complexity - /// - /// - public T Dequeue() - { - if (Count == 0) - { - throw new Exception("Empty queue."); - } - - var element = queue[start]; - start++; - - //wrap around - if (start > queue.Length - 1) - { - start = 0; - - if (end == 0) - { - end++; - } - } - - Count--; - - if (start == end && Count > 1) - { - end++; - } - - //reset - if (Count == 0) - { - start = end = 0; - } - - return element; - } - - /// - /// O(bulkNumber) time complexity - /// - /// - public IEnumerable Dequeue(int bulkNumber) - { - var deletedList = new List(); - while (bulkNumber > 0 && Count > 0) - { - var deleted = Dequeue(); - - if (!deleted.Equals(default(T))) - { - deletedList.Add(deleted); - } - - bulkNumber--; - } - - return deletedList; - } - -} - diff --git a/Advanced.Algorithms/DistributedSystems/CircularQueue.cs b/Advanced.Algorithms/DistributedSystems/CircularQueue.cs new file mode 100644 index 00000000..fdebcc63 --- /dev/null +++ b/Advanced.Algorithms/DistributedSystems/CircularQueue.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; + +namespace Advanced.Algorithms.DataStructures.DistributedSystems +{ + /// + /// Cicular queue aka Ring Buffer using fixed size array + /// + /// + public class CircularQueue + { + private T[] queue; + + //points to the index of next element to be deleted + private int start = 0; + + //points to the index new element should be inserted + private int end = 0; + + public int Count { get; private set; } + + public CircularQueue(int size) + { + queue = new T[size]; + } + + /// + /// Note: When buffer overflows oldest data will be erased + /// O(1) time complexity + /// + /// + public T Enqueue(T data) + { + T deleted = default(T); + + //wrap around removing oldest element + if (end > queue.Length - 1) + { + end = 0; + + if (start == 0) + { + deleted = queue[start]; + start++; + } + } + + //when end meets start after wraping around + if (end == start && Count > 1) + { + deleted = queue[start]; + start++; + } + + queue[end] = data; + end++; + + if (Count < queue.Length) + { + Count++; + } + + return deleted; + } + + /// + /// O(bulk.Length) time complexity + /// + /// + /// + public IEnumerable Enqueue(T[] bulk) + { + var deletedList = new List(); + + foreach (var item in bulk) + { + var deleted = Enqueue(item); + + if (!deleted.Equals(default(T))) + { + deletedList.Add(deleted); + } + } + + return deletedList; + } + + /// + /// O(1) time complexity + /// + /// + public T Dequeue() + { + if (Count == 0) + { + throw new Exception("Empty queue."); + } + + var element = queue[start]; + start++; + + //wrap around + if (start > queue.Length - 1) + { + start = 0; + + if (end == 0) + { + end++; + } + } + + Count--; + + if (start == end && Count > 1) + { + end++; + } + + //reset + if (Count == 0) + { + start = end = 0; + } + + return element; + } + + /// + /// O(bulkNumber) time complexity + /// + /// + public IEnumerable Dequeue(int bulkNumber) + { + var deletedList = new List(); + while (bulkNumber > 0 && Count > 0) + { + var deleted = Dequeue(); + + if (!deleted.Equals(default(T))) + { + deletedList.Add(deleted); + } + + bulkNumber--; + } + + return deletedList; + } + + } + +} \ No newline at end of file diff --git a/README.md b/README.md index e080f888..c1b88790 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,6 @@ Supports ### Queue - [X] Queue (using [Dynamic Array](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/DataStructures/Queues/ArrayQueue.cs) and optionally using [Doubly Linked List](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/DataStructures/Queues/LinkedListQueue.cs)) ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/DataStructures/Queues/Queue.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/DataStructures/Queues/Queue_Tests.cs)) -- [X] Circular Queue (Ring Buffer) ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/DataStructures/Queues/CircularQueue_Tests.cs)) #### Priority Queue @@ -240,9 +239,12 @@ Note: On a decent desktop, in given implementations here for +ive random input i - [X] Permutations ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/Combinatorics/Permutation.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/Combinatorics/Permutation_Tests.cs)) - [X] Combinations ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/Combinatorics/Combination.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/Combinatorics/Combination_Tests.cs)) -- [X] Variations ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/Combinatorics/Variation.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/Combinatorics/Variation_Tests.cs)) - [X] Subsets ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/Combinatorics/Subset.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/Combinatorics/Subset_Tests.cs)) +## Distributed Systems + +- [X] Circular Queue (Ring Buffer) ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/DistributedSystems/CircularQueue.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/DistributedSystems/CircularQueue_Tests.cs)) + ## Numerical Methods - [X] kth Smallest ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/NumericalMethods/KthSmallest.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/NumericalMethods/KthSmallest_Tests.cs)) From 00ffe76037c699edec28b5a24f588bf2f37467b1 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 22 Jan 2018 20:10:05 -0500 Subject: [PATCH 07/10] Consistant hash & LRU Cache --- .../Advanced.Algorithms.Tests.csproj | 2 + .../ConsistentHash_Tests.cs | 43 ++++ .../DistributedSystems/LRUCache_Tests.cs | 30 +++ .../DistributedSystems/ConsistentHash.cs | 192 ++++++++++++++++++ .../DistributedSystems/LRUCache.cs | 67 ++++++ README.md | 2 + 6 files changed, 336 insertions(+) create mode 100644 Advanced.Algorithms.Tests/DistributedSystems/ConsistentHash_Tests.cs create mode 100644 Advanced.Algorithms.Tests/DistributedSystems/LRUCache_Tests.cs create mode 100644 Advanced.Algorithms/DistributedSystems/ConsistentHash.cs create mode 100644 Advanced.Algorithms/DistributedSystems/LRUCache.cs diff --git a/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj b/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj index 34a2bdd7..1efa7396 100644 --- a/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj +++ b/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj @@ -125,6 +125,8 @@ + + diff --git a/Advanced.Algorithms.Tests/DistributedSystems/ConsistentHash_Tests.cs b/Advanced.Algorithms.Tests/DistributedSystems/ConsistentHash_Tests.cs new file mode 100644 index 00000000..fabd438a --- /dev/null +++ b/Advanced.Algorithms.Tests/DistributedSystems/ConsistentHash_Tests.cs @@ -0,0 +1,43 @@ +using Advanced.Algorithms.DistributedSystems; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +namespace Advanced.Algorithms.Tests.DistributedSystems +{ + [TestClass] + public class ConsistentHash_Tests + { + + [TestMethod] + public void ConsistantHash_Smoke_Test() + { + var hash = new ConsistentHash(); + + hash.AddNode(15); + hash.AddNode(25); + hash.AddNode(172); + + for (int i = 200; i < 300; i++) + { + hash.AddNode(i); + } + + hash.RemoveNode(15); + hash.RemoveNode(172); + hash.RemoveNode(25); + + var rnd = new Random(); + for (int i = 0; i < 1000; i++) + { + Assert.AreNotEqual(15, hash.GetNode(rnd.Next().ToString())); + Assert.AreNotEqual(25, hash.GetNode(rnd.Next().ToString())); + Assert.AreNotEqual(172, hash.GetNode(rnd.Next().ToString())); + + var t = hash.GetNode(rnd.Next().ToString()); + Assert.IsTrue(t >= 200 && t < 300); + } + + } + + } +} \ No newline at end of file diff --git a/Advanced.Algorithms.Tests/DistributedSystems/LRUCache_Tests.cs b/Advanced.Algorithms.Tests/DistributedSystems/LRUCache_Tests.cs new file mode 100644 index 00000000..f692d7b3 --- /dev/null +++ b/Advanced.Algorithms.Tests/DistributedSystems/LRUCache_Tests.cs @@ -0,0 +1,30 @@ +using Advanced.Algorithms.DistributedSystems; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +namespace Advanced.Algorithms.Tests.DistributedSystems +{ + [TestClass] + public class LRUCache_Tests + { + + [TestMethod] + public void LRUCache_Smoke_Test() + { + var cache = new LRUCache(2); + + cache.Put(1, 1); + cache.Put(2, 2); + Assert.AreEqual(1, cache.Get(1)); + + cache.Put(3, 3); + Assert.AreEqual(0, cache.Get(2)); + + cache.Put(4, 4); + Assert.AreEqual(0, cache.Get(1)); + Assert.AreEqual(3, cache.Get(3)); + Assert.AreEqual(4, cache.Get(4)); + } + + } +} \ No newline at end of file diff --git a/Advanced.Algorithms/DistributedSystems/ConsistentHash.cs b/Advanced.Algorithms/DistributedSystems/ConsistentHash.cs new file mode 100644 index 00000000..95078397 --- /dev/null +++ b/Advanced.Algorithms/DistributedSystems/ConsistentHash.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace Advanced.Algorithms.DistributedSystems +{ + + /// + /// A consistant hash implementation with MurmurHash + /// Adapted from https://github.com/wsq003/consistent-hash/blob/master/ConsistentHash.cs + /// + /// + public class ConsistentHash + { + SortedDictionary circle = new SortedDictionary(); + int[] circleKeys; + int replicas; + + public ConsistentHash() + : this(new List(), 100) { } + + public ConsistentHash(IEnumerable nodes, int replicas) + { + this.replicas = replicas; + foreach (T node in nodes) + { + AddNode(node); + } + } + + /// + /// Add a new bucket + /// + /// + public void AddNode(T node) + { + for (int i = 0; i < replicas; i++) + { + int hash = getHashCode(node.GetHashCode().ToString() + i); + circle[hash] = node; + } + + circleKeys = circle.Keys.ToArray(); + } + + /// + /// Get the bucket for the given Key + /// + /// + /// + public T GetNode(string key) + { + int hash = getHashCode(key); + int first = Next_ClockWise(circleKeys, hash); + return circle[circleKeys[first]]; + } + + /// + /// Remove a bucket from lookUp + /// + /// + public void RemoveNode(T node) + { + for (int i = 0; i < replicas; i++) + { + int hash = getHashCode(node.GetHashCode().ToString() + i); + if (!circle.Remove(hash)) + { + throw new Exception("Cannot remove a node that was never added."); + } + } + + circleKeys = circle.Keys.ToArray(); + } + + + /// + /// Move clockwise until we find a bucket with Key >= hashCode + /// + /// + /// + /// Returns the index of bucket + int Next_ClockWise(int[] keys, int hashCode) + { + int begin = 0; + int end = keys.Length - 1; + + if (keys[end] < hashCode || keys[0] > hashCode) + { + return 0; + } + + //do a binary search + int mid = begin; + while (end - begin > 1) + { + mid = (end + begin) / 2; + if (keys[mid] >= hashCode) + { + end = mid; + } + else + { + begin = mid; + } + } + + return end; + } + + + private static int getHashCode(string key) + { + return (int)MurmurHash2.Hash(Encoding.Unicode.GetBytes(key)); + } + + } + + internal class MurmurHash2 + { + internal static UInt32 Hash(Byte[] data) + { + return Hash(data, 0xc58f1a7b); + } + const UInt32 m = 0x5bd1e995; + const Int32 r = 24; + + [StructLayout(LayoutKind.Explicit)] + struct BytetoUInt32Converter + { + [FieldOffset(0)] + public Byte[] Bytes; + + [FieldOffset(0)] + public UInt32[] UInts; + } + + internal static UInt32 Hash(Byte[] data, UInt32 seed) + { + Int32 length = data.Length; + if (length == 0) + return 0; + UInt32 h = seed ^ (UInt32)length; + Int32 currentIndex = 0; + // array will be length of Bytes but contains Uints + // therefore the currentIndex will jump with +1 while length will jump with +4 + UInt32[] hackArray = new BytetoUInt32Converter { Bytes = data }.UInts; + while (length >= 4) + { + UInt32 k = hackArray[currentIndex++]; + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + length -= 4; + } + currentIndex *= 4; // fix the length + switch (length) + { + case 3: + h ^= (UInt16)(data[currentIndex++] | data[currentIndex++] << 8); + h ^= (UInt32)data[currentIndex] << 16; + h *= m; + break; + case 2: + h ^= (UInt16)(data[currentIndex++] | data[currentIndex] << 8); + h *= m; + break; + case 1: + h ^= data[currentIndex]; + h *= m; + break; + default: + break; + } + + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; + } + } +} + diff --git a/Advanced.Algorithms/DistributedSystems/LRUCache.cs b/Advanced.Algorithms/DistributedSystems/LRUCache.cs new file mode 100644 index 00000000..e6815e4d --- /dev/null +++ b/Advanced.Algorithms/DistributedSystems/LRUCache.cs @@ -0,0 +1,67 @@ +using Advanced.Algorithms.DataStructures; +using System; +using System.Collections.Generic; +using System.Linq; + + +namespace Advanced.Algorithms.DistributedSystems +{ + public class LRUCache + { + private int capacity; + + private Dictionary>> lookUp + = new Dictionary>>(); + + private DoublyLinkedList> dll = new DoublyLinkedList>(); + + public LRUCache(int capacity) + { + if (capacity <= 0) + { + throw new Exception("Capacity must be a positive integer."); + } + this.capacity = capacity; + } + + /// + /// O(1) time complexity + /// + /// + /// + public V Get(K key) + { + if (!lookUp.ContainsKey(key)) + return default(V); + + var node = lookUp[key]; + + //move lately used node to beginning of ddl + dll.Delete(node); + var newNode = dll.InsertFirst(node.Data); + lookUp[key] = newNode; + + return node.Data.Item2; + } + + /// + /// O(1) time complexity + /// + /// + /// + public void Put(K key, V value) + { + //evict last node of ddl if capacity overflows + if (lookUp.Count == capacity) + { + var nodeToEvict = dll.Last(); + lookUp.Remove(nodeToEvict.Item1); + dll.DeleteLast(); + } + + //insert + var newNode = dll.InsertFirst(new Tuple(key, value)); + lookUp.Add(key, newNode); + } + } +} diff --git a/README.md b/README.md index c1b88790..d4084d66 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,8 @@ Note: On a decent desktop, in given implementations here for +ive random input i ## Distributed Systems - [X] Circular Queue (Ring Buffer) ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/DistributedSystems/CircularQueue.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/DistributedSystems/CircularQueue_Tests.cs)) +- [X] Consistant Hash ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/DistributedSystems/ConsistantHash.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/DistributedSystems/ConsistantHash_Tests.cs)) +- [X] LRU Cache ([Implementation](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms/DistributedSystems/LRUCache.cs) | [Tests](https://github.com/justcoding121/Advanced-Algorithms/tree/develop/Advanced.Algorithms.Tests/DistributedSystems/LRUCache_Tests.cs)) ## Numerical Methods From 6dd9fd98a9a5fe9d1675f143bd5d72818adcfbb9 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 22 Jan 2018 20:15:59 -0500 Subject: [PATCH 08/10] remove unwarranted salt --- .../Dictionary/OpenAddressDictionary.cs | 16 ++++++++-------- .../DataStructures/HashSet/OpenAddressHashSet.cs | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Advanced.Algorithms/DataStructures/Dictionary/OpenAddressDictionary.cs b/Advanced.Algorithms/DataStructures/Dictionary/OpenAddressDictionary.cs index 3fe70631..cd6b029d 100644 --- a/Advanced.Algorithms/DataStructures/Dictionary/OpenAddressDictionary.cs +++ b/Advanced.Algorithms/DataStructures/Dictionary/OpenAddressDictionary.cs @@ -37,7 +37,7 @@ public V this[K key] //O(1) time complexity; worst case O(n) public bool ContainsKey(K key) { - var hashCode = SaltHash(Math.Abs(key.GetHashCode())); + var hashCode = getHash(key); var index = hashCode % bucketSize; if (hashArray[index] == null) @@ -84,7 +84,7 @@ public void Add(K key, V value) Grow(); - var hashCode = SaltHash(Math.Abs(key.GetHashCode())); + var hashCode = getHash(key); var index = hashCode % bucketSize; @@ -130,7 +130,7 @@ public void Add(K key, V value) //O(1) time complexity; worst case O(n) public void Remove(K key) { - var hashCode = SaltHash(Math.Abs(key.GetHashCode())); + var hashCode = getHash(key); var curIndex = hashCode % bucketSize; if (hashArray[curIndex] == null) @@ -228,7 +228,7 @@ public void Clear() private void SetValue(K key, V value) { - var index = (SaltHash(Math.Abs(key.GetHashCode()))) % bucketSize; + var index = getHash(key) % bucketSize; if (hashArray[index] == null) { @@ -269,7 +269,7 @@ private void SetValue(K key, V value) private V GetValue(K key) { - var index = (SaltHash(Math.Abs(key.GetHashCode()))) % bucketSize; + var index = getHash(key) % bucketSize; if (hashArray[index] == null) { @@ -363,13 +363,13 @@ private void Shrink() } /// - /// salt the hash with a random number + /// get hash /// /// /// - private int SaltHash(int key) + private int getHash(K key) { - return key * 3; + return Math.Abs(key.GetHashCode()); } //Implementation for the GetEnumerator method. diff --git a/Advanced.Algorithms/DataStructures/HashSet/OpenAddressHashSet.cs b/Advanced.Algorithms/DataStructures/HashSet/OpenAddressHashSet.cs index 4c6ea4bd..f3bc2170 100644 --- a/Advanced.Algorithms/DataStructures/HashSet/OpenAddressHashSet.cs +++ b/Advanced.Algorithms/DataStructures/HashSet/OpenAddressHashSet.cs @@ -31,7 +31,7 @@ public OpenAddressHashSet(int initialBucketSize = 2) //O(1) time complexity; worst case O(n) public bool Contains(V value) { - var hashCode = SaltHash(Math.Abs(value.GetHashCode())); + var hashCode = getHash(value); var index = hashCode % bucketSize; if (hashArray[index] == null) @@ -78,7 +78,7 @@ public void Add(V value) Grow(); - var hashCode = SaltHash(Math.Abs(value.GetHashCode())); + var hashCode = getHash(value); var index = hashCode % bucketSize; @@ -124,7 +124,7 @@ public void Add(V value) //O(1) time complexity; worst case O(n) public void Remove(V value) { - var hashCode = SaltHash(Math.Abs(value.GetHashCode())); + var hashCode = getHash(value); var curIndex = hashCode % bucketSize; if (hashArray[curIndex] == null) @@ -222,7 +222,7 @@ public void Clear() private void SetValue(V value) { - var index = (SaltHash(Math.Abs(value.GetHashCode()))) % bucketSize; + var index = getHash(value) % bucketSize; if (hashArray[index] == null) { @@ -263,7 +263,7 @@ private void SetValue(V value) private V GetValue(V value) { - var index = (SaltHash(Math.Abs(value.GetHashCode()))) % bucketSize; + var index = getHash(value) % bucketSize; if (hashArray[index] == null) { @@ -357,13 +357,13 @@ private void Shrink() } /// - /// salt the hash with a random number + /// get hash /// /// /// - private int SaltHash(int value) + private int getHash(V value) { - return value * 3; + return Math.Abs(value.GetHashCode()); } //Implementation for the GetEnumerator method. From 93f1c6f190bd1dbda6ae70b02574959eea21d019 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 22 Jan 2018 20:22:00 -0500 Subject: [PATCH 09/10] issue #5 Fix --- .../GraphAlgorithms/ShortestPath/Bellman-Ford.cs | 2 +- Advanced.Algorithms/GraphAlgorithms/ShortestPath/Dijikstra.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Bellman-Ford.cs b/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Bellman-Ford.cs index fd65b226..aaa4b0b6 100644 --- a/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Bellman-Ford.cs +++ b/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Bellman-Ford.cs @@ -100,7 +100,7 @@ private ShortestPathResult tracePath(WeightedDiGraph graph, pathStack.Push(destination); var currentV = destination; - while (!currentV.Equals(default(T)) && !parentMap[currentV].Equals(default(T))) + while (!Equals(currentV, default(T)) && !parentMap[currentV].Equals(default(T))) { pathStack.Push(parentMap[currentV]); currentV = parentMap[currentV]; diff --git a/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Dijikstra.cs b/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Dijikstra.cs index 8e03f382..b29d0736 100644 --- a/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Dijikstra.cs +++ b/Advanced.Algorithms/GraphAlgorithms/ShortestPath/Dijikstra.cs @@ -178,7 +178,7 @@ private ShortestPathResult tracePath(WeightedDiGraph graph, pathStack.Push(destination); var currentV = destination; - while (!currentV.Equals(default(T)) && !parentMap[currentV].Equals(default(T))) + while (!Equals(currentV,default(T)) && !parentMap[currentV].Equals(default(T))) { pathStack.Push(parentMap[currentV]); currentV = parentMap[currentV]; From 907041d8f7265400e825bca903e4d62003ae219f Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 22 Jan 2018 20:26:30 -0500 Subject: [PATCH 10/10] fix build failing silently --- .build/Bootstrap.ps1 | 2 +- .build/Common.psm1 | 2 +- .build/default.ps1 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.build/Bootstrap.ps1 b/.build/Bootstrap.ps1 index 37b49cbe..4d77d2bd 100644 --- a/.build/Bootstrap.ps1 +++ b/.build/Bootstrap.ps1 @@ -14,7 +14,7 @@ Install-Psake $psakeDirectory = (Resolve-Path $env:ChocolateyInstall\lib\Psake*) -Import-Module (Join-Path $psakeDirectory "tools\Psake.psm1") +Import-Module (Join-Path $psakeDirectory "tools\Psake\Psake.psm1") if($Help) { diff --git a/.build/Common.psm1 b/.build/Common.psm1 index b73c1d9d..1a19d515 100644 --- a/.build/Common.psm1 +++ b/.build/Common.psm1 @@ -24,7 +24,7 @@ function Install-Chocolatey() function Install-Psake() { - if(!(Test-Path $env:ChocolateyInstall\lib\Psake*)) + if(!(Test-Path $env:ChocolateyInstall\lib\Psake\tools\Psake*)) { choco install psake -y } diff --git a/.build/default.ps1 b/.build/default.ps1 index 2507709d..46263cf3 100644 --- a/.build/default.ps1 +++ b/.build/default.ps1 @@ -54,7 +54,7 @@ Task Restore-Packages { } Task Install-MSBuild { - if(!(Test-Path $MSBuild14)) + if(!(Test-Path $MSBuild)) { cinst microsoft-build-tools -y }