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 } diff --git a/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj b/Advanced.Algorithms.Tests/Advanced.Algorithms.Tests.csproj index 2d35c843..1efa7396 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 @@ - + @@ -126,7 +125,10 @@ + + + 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.Tests/Combinatorics/Variation_Tests.cs b/Advanced.Algorithms.Tests/Combinatorics/Variation_Tests.cs deleted file mode 100644 index f0d3604b..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(Math.Pow(input.Count, 2), variations.Count); - - input = "scan".ToCharArray().ToList(); - variations = Variation.Find(input, 3, true); - Assert.AreEqual(Math.Pow(input.Count, 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 62% rename from Advanced.Algorithms.Tests/DataStructures/Queues/CircularQueue_Tests.cs rename to Advanced.Algorithms.Tests/DistributedSystems/CircularQueue_Tests.cs index eecd152d..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 @@ -13,16 +12,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 +46,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 +56,6 @@ public void CircularQueue_Test() Assert.AreEqual(Queue.Dequeue(), 2); } - + } -} +} \ No newline at end of file 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.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/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); diff --git a/Advanced.Algorithms/Combinatorics/Variation.cs b/Advanced.Algorithms/Combinatorics/Variation.cs deleted file mode 100644 index 987ad636..00000000 --- a/Advanced.Algorithms/Combinatorics/Variation.cs +++ /dev/null @@ -1,57 +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 k-element variations of n objects, we first need to choose a k-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 - receives at most one element. */ - - //With repetition - /* It is the number of all ways of putting r distinct balls into input.Count distinct boxes */ - public static List> Find(List input, int r, bool withRepetition) - { - var result = new List>(); - - Recurse(input, r, withRepetition, new List(), new HashSet(), result); - - return result; - } - - private static void Recurse(List input, int r, bool withRepetition, - List prefix, HashSet prefixIndices, - List> result) - { - if (prefix.Count == r) - { - result.Add(new List(prefix)); - return; - } - - 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); - } - } - } -} 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. diff --git a/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs b/Advanced.Algorithms/DistributedSystems/CircularQueue.cs similarity index 56% rename from Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs rename to Advanced.Algorithms/DistributedSystems/CircularQueue.cs index 513c3ffe..fdebcc63 100644 --- a/Advanced.Algorithms/DataStructures/Queues/CircularQueue.cs +++ b/Advanced.Algorithms/DistributedSystems/CircularQueue.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace Advanced.Algorithms.DataStructures.Queues +namespace Advanced.Algorithms.DataStructures.DistributedSystems { /// /// Cicular queue aka Ring Buffer using fixed size array @@ -28,17 +26,21 @@ public CircularQueue(int size) /// /// Note: When buffer overflows oldest data will be erased + /// O(1) time complexity /// /// - public void Enqueue(T data) + public T Enqueue(T data) { + T deleted = default(T); + //wrap around removing oldest element if (end > queue.Length - 1) { end = 0; - if(start == 0) + if (start == 0) { + deleted = queue[start]; start++; } } @@ -46,6 +48,7 @@ public void Enqueue(T data) //when end meets start after wraping around if (end == start && Count > 1) { + deleted = queue[start]; start++; } @@ -56,9 +59,36 @@ public void Enqueue(T data) { 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) @@ -95,5 +125,29 @@ public T Dequeue() 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/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/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]; 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..d4084d66 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 @@ -172,6 +171,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 @@ -239,9 +239,14 @@ 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)) +- [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 - [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))