diff --git a/src/Advanced.Algorithms/DataStructures/Tree/AvlTree.cs b/src/Advanced.Algorithms/DataStructures/Tree/AvlTree.cs index 8d1dea92..82b9546c 100644 --- a/src/Advanced.Algorithms/DataStructures/Tree/AvlTree.cs +++ b/src/Advanced.Algorithms/DataStructures/Tree/AvlTree.cs @@ -34,13 +34,17 @@ public AVLTree(bool enableNodeLookUp = false) /// Enabling lookup will fasten deletion/insertion/exists operations /// at the cost of additional space. public AVLTree(IEnumerable sortedCollection, bool enableNodeLookUp = false) - : this(enableNodeLookUp) { ValidateSortedCollection(sortedCollection); var nodes = sortedCollection.Select(x => new AVLTreeNode(null, x)).ToArray(); Root = (AVLTreeNode)ToBST(nodes); recomputeHeight(Root); assignCount(Root); + + if (enableNodeLookUp) + { + nodeLookUp = nodes.ToDictionary(x => x.Value, x => x as BSTNodeBase); + } } diff --git a/src/Advanced.Algorithms/DataStructures/Tree/RedBlackTree.cs b/src/Advanced.Algorithms/DataStructures/Tree/RedBlackTree.cs index 36121b51..c7f1126b 100644 --- a/src/Advanced.Algorithms/DataStructures/Tree/RedBlackTree.cs +++ b/src/Advanced.Algorithms/DataStructures/Tree/RedBlackTree.cs @@ -131,7 +131,9 @@ internal bool Exists(T value) { if (nodeLookUp != null) { - return (nodeLookUp[value] as RedBlackTreeNode, Root.Position(value)); + //since node look up is only used by Bentley-Ottmann algorithm internally + //and it does'nt need the position we can return defualt(int). + return (nodeLookUp[value] as RedBlackTreeNode, default(int)); } var result = Root.Find(value); @@ -831,6 +833,7 @@ public T NextHigher(T value) return next != null ? next.Value : default(T); } + ///Special (internal only) method for Bentley-Ottmann sweep line algorithm. internal void Swap(T value1, T value2) { var node1 = find(value1).Item1; diff --git a/tests/Advanced.Algorithms.Tests/DataStructures/Tree/AVLTree_Tests.cs b/tests/Advanced.Algorithms.Tests/DataStructures/Tree/AVLTree_Tests.cs index 7cdcf106..b5f44a74 100644 --- a/tests/Advanced.Algorithms.Tests/DataStructures/Tree/AVLTree_Tests.cs +++ b/tests/Advanced.Algorithms.Tests/DataStructures/Tree/AVLTree_Tests.cs @@ -98,6 +98,77 @@ public void AVLTree_Accuracy_Test() { var nodeCount = 1000; + var rnd = new Random(); + var sorted = Enumerable.Range(1, nodeCount).ToList(); + var randomNumbers = sorted + .OrderBy(x => rnd.Next()) + .ToList(); + + var tree = new AVLTree(); + + for (int i = 0; i < nodeCount; i++) + { + tree.Insert(randomNumbers[i]); + + Assert.IsTrue(tree.HasItem(randomNumbers[i])); + Assert.IsTrue(tree.Root.IsBinarySearchTree(int.MinValue, int.MaxValue)); + tree.Root.VerifyCount(); + + var actualHeight = tree.GetHeight(); + + //http://stackoverflow.com/questions/30769383/finding-the-minimum-and-maximum-height-in-a-avl-tree-given-a-number-of-nodes + var maxHeight = 1.44 * Math.Log(nodeCount + 2, 2) - 0.328; + + Assert.IsTrue(actualHeight < maxHeight); + Assert.IsTrue(tree.Count == i + 1); + } + + for (int i = 0; i < sorted.Count; i++) + { + Assert.AreEqual(sorted[i], tree.ElementAt(i)); + Assert.AreEqual(i, tree.IndexOf(sorted[i])); + } + + randomNumbers = Enumerable.Range(1, nodeCount) + .OrderBy(x => rnd.Next()) + .ToList(); + + //IEnumerable test using linq + Assert.AreEqual(tree.Count, tree.Count()); + Assert.AreEqual(tree.Count, tree.AsEnumerableDesc().Count()); + + for (int i = 0; i < nodeCount; i++) + { + if (rnd.NextDouble() >= 0.5) + { + tree.Delete(randomNumbers[i]); + } + else + { + var index = tree.IndexOf(randomNumbers[i]); + Assert.AreEqual(tree.ElementAt(index), randomNumbers[i]); + tree.RemoveAt(index); + } + + Assert.IsTrue(tree.Root.IsBinarySearchTree(int.MinValue, int.MaxValue)); + tree.Root.VerifyCount(); + + var actualHeight = tree.GetHeight(); + + //http://stackoverflow.com/questions/30769383/finding-the-minimum-and-maximum-height-in-a-avl-tree-given-a-number-of-nodes + var maxHeight = 1.44 * Math.Log(nodeCount + 2, 2) - 0.328; + + Assert.IsTrue(actualHeight < maxHeight); + } + + Assert.IsTrue(tree.Count == 0); + } + + [TestMethod] + public void AVLTree_Accuracy_Test_With_Node_LookUp() + { + var nodeCount = 1000; + var rnd = new Random(); var sorted = Enumerable.Range(1, nodeCount).ToList(); var randomNumbers = sorted @@ -165,7 +236,7 @@ public void AVLTree_Accuracy_Test() } [TestMethod] - public void AVLTree_BulkInit_Test() + public void AVLTree_BulkInit_Test_With_Node_LookUp() { var nodeCount = 1000; @@ -199,6 +270,41 @@ public void AVLTree_BulkInit_Test() Assert.IsTrue(tree.Count == 0); } + [TestMethod] + public void AVLTree_BulkInit_Test() + { + var nodeCount = 1000; + + var rnd = new Random(); + var randomNumbers = Enumerable.Range(1, nodeCount).ToList(); + + var tree = new AVLTree(randomNumbers, true); + + Assert.IsTrue(tree.Root.IsBinarySearchTree(int.MinValue, int.MaxValue)); + Assert.AreEqual(tree.Count, tree.Count()); + + tree.Root.VerifyCount(); + + for (int i = 0; i < nodeCount; i++) + { + tree.Delete(randomNumbers[i]); + + tree.Root.VerifyCount(); + Assert.IsTrue(tree.Root.IsBinarySearchTree(int.MinValue, int.MaxValue)); + + var actualHeight = tree.GetHeight(); + + //http://stackoverflow.com/questions/30769383/finding-the-minimum-and-maximum-height-in-a-avl-tree-given-a-number-of-nodes + var maxHeight = 1.44 * Math.Log(nodeCount + 2, 2) - 0.328; + + Assert.IsTrue(actualHeight < maxHeight); + + Assert.IsTrue(tree.Count == nodeCount - 1 - i); + } + + Assert.IsTrue(tree.Count == 0); + } + [TestMethod] public void AVLTree_Stress_Test() {