private static void HandleBlackUncle(IBinarySearchTreeNode <T> newNode, IBinarySearchTreeNode <T> parent, IBinarySearchTreeNode <T> uncle, IBinarySearchTreeNode <T> grandparent) { if (IsLeft(newNode)) { if (IsLeft(parent)) { // Case A: the new node and its parent are left children IBinarySearchTreeNode <T> tmp = parent.Right; parent.Parent = grandparent.Parent; parent.Right = grandparent; grandparent.Parent = parent; grandparent.Left = tmp; grandparent.Left.Parent = grandparent; parent.IsBlack = true; grandparent.IsBlack = false; } else { } } else { } }
private static bool UnoptimizedValidateSearchTree(IBinarySearchTreeNode <T> rootNode) { // Base case - no children if (rootNode.Degree == 0) { return(true); } // Binary search tree - all values in nodes left of the // current node must be smaller or equal. if (rootNode.Left?.FindMax().CompareTo(rootNode.Data) > 0) { return(false); } // Binary search tree - all values in nodes right of the // current node must be greater. if (rootNode.Right?.FindMin().CompareTo(rootNode.Data) < 1) { return(false); } // Else, check children sub-trees. var leftState = rootNode.Left == null || rootNode.Left.IsValidSearchTree; var rightState = rootNode.Right == null || rootNode.Right.IsValidSearchTree; return(leftState && rightState); }
private void NonRecursiveInsert(IBinarySearchTreeNode <TKey, TValue> root, IBinarySearchTreeNode <TKey, TValue> newNode) { while (true) { if (root.Key.CompareTo(newNode.Key) > 0) { if (root.LeftChild == null) { root.LeftChild = newNode; return; } else { root = root.LeftChild; } } else { if (root.RightChild == null) { root.RightChild = newNode; return; } else { root = root.RightChild; } } } }
private static void Balance(IBinarySearchTreeNode <T> newNode) { IBinarySearchTreeNode <T> parent = newNode.Parent; if (parent != null) { if (!parent.IsBlack) // We have a red violation { IBinarySearchTreeNode <T> uncle = GetSibling(parent); IBinarySearchTreeNode <T> grandparent = parent.Parent; // Since we know that the parent is red and that the tree was previously balances the grandparent must exist if (uncle == null || uncle.IsBlack) { HandleBlackUncle(newNode, parent, uncle, grandparent); } else { HandleRedUncle(parent, uncle, grandparent); } } // else the parent node of the new node is black and the tree is already balanced } else { // this must be the root node, ensure it is black newNode.IsBlack = true; } }
/// <summary> /// Find a node /// </summary> /// <param name="Value"></param> /// <returns></returns> IBinarySearchTreeNode <T> IBinarySearchTree <T> .FindNode(T Value) { //Root itself is null if (_root == null) { return(null); } IBinarySearchTreeNode <T> current = _root; while (current != null) { if (current.Data.CompareTo(Value) == 0) { break; } else if (current.Data.CompareTo(Value) > 0) { current = current.LeftChild; } else { current = current.RightChild; } } return(current); }
private void Insert(IBinarySearchTreeNode <TKey, TValue> root, IBinarySearchTreeNode <TKey, TValue> newNode) { if (root.Key.CompareTo(newNode.Key) > 0) { if (root.LeftChild == null) { root.LeftChild = newNode; } else { Insert(root.LeftChild, newNode); } } else { if (root.RightChild == null) { root.RightChild = newNode; } else { Insert(root.RightChild, newNode); } } }
private bool Remove(IBinarySearchTreeNode <TKey, TValue> parent, TKey key) { if (parent == null) { return(false); } if (parent.Key.CompareTo(key) > 0) { if (parent.LeftChild != null && parent.LeftChild.Key.CompareTo(key) == 0) { parent.LeftChild = GetNewChildAfterRemoving(parent.LeftChild); return(true); } else { return(Remove(parent.LeftChild, key)); } } else { // if (parent.Key.CompareTo(key) < 0) // we exclude case where parent.Key.CompareTo(key) == 0 in the public Remove(key) method if (parent.RightChild != null && parent.RightChild.Key.CompareTo(key) == 0) { parent.RightChild = GetNewChildAfterRemoving(parent.RightChild); return(true); } else { return(Remove(parent.RightChild, key)); } } }
public void Add(T value) { if (Count == Int32.MaxValue) { throw new CollectionFullException(); } if (_root == null) { _root = new BinarySearchTreeNode <T>(value); _root.IsBlack = true; // ensure root node is still black } else { _root.AddChild(value); // We need to make sure that _root is still the root while (_root.Parent != null) { _root = _root.Parent; } } Count++; }
public void BinarySearchTreeTests_SearchTest() { IBinarySearchTree <int, int> tree = new BinarySearchTree <int, int>(); IBinarySearchTreeNode <int, int> actual = tree.Search(100); Assert.IsNull(actual); }
private static void HandleRedUncle(IBinarySearchTreeNode <T> parent, IBinarySearchTreeNode <T> uncle, IBinarySearchTreeNode <T> grandparent) { parent.IsBlack = true; uncle.IsBlack = true; grandparent.IsBlack = false; Balance(grandparent); }
/// <summary> /// Find some data in a binary search tree using binary search. /// </summary> /// <param name="data"> /// The data to search for. /// </param> /// <param name="lastNodeVisited"> /// Will be filled with the last node visited. If the return value /// is "true" than this is the matching node or result. /// In case of "false" this is the last node investigated before /// stopping the search. Having this reference is essential /// for node insertion and removal scenarios. /// </param> /// <param name="safetyCheck"> /// Check whether the (sub-)tree is a valid binary search tree /// at all before searching. Throws <see cref="InvalidOperationException"/> /// if invalid. This is a costly operation of O(n) /// for valid trees but spares you an extra check of /// "IsValidSearchTree" if you had done so anyway. /// </param> /// <returns> /// True if the data was found otherwise false. /// </returns> /// <exception cref="InvalidOperationException"> /// Thrown if the (sub-)tree is not a valid binary search tree by /// definition AND "safetyCheck" was set to "true". /// </exception> public bool Find(T data, out IBinarySearchTreeNode <T> lastNodeVisited, bool safetyCheck = false) { lastNodeVisited = this; Debug.WriteLine($"BST {nameof(Find)}: Searching for '{data}' from '{this}' ..."); // Safety check requested - won't search an invalid BST if (safetyCheck) { if (!IsValidSearchTree) { throw new InvalidOperationException( $"{nameof(IBinarySearchTreeNode<T>)}.{nameof(Find)}: " + $"This is an invalid binary search tree and {nameof(safetyCheck)} was set to {true}. " + "Search aborted."); } } // Data found if (data.CompareTo(Data) == 0) { Debug.WriteLine($"BST {nameof(Find)}: Data ({data}) match found!"); return(true); } // Supplied data is lesser than current node's data if (data.CompareTo(Data) < 0) { Debug.WriteLine($"BST {nameof(Find)}: {(this.Left == null ? "No left child." : "Search left sub-tree ...")}"); // Lesser means we have to go left // If there isn't a left node the data could not be found. return (this.Left == null ? false : this.Left.Find(data, out lastNodeVisited)); } // Supplied data is greater than current node's data if (data.CompareTo(Data) > 0) { Debug.WriteLine($"BST {nameof(Find)}: {(this.Right == null ? "No right child." : "Search right sub-tree ...")}"); // Greater means we have to go right // If there isn't a right node the data could not be found. return (this.Right == null ? false : this.Right.Find(data, out lastNodeVisited)); } Debug.WriteLine($"BST {nameof(Find)}: Search for '{data}' unsuccessful."); return(false); }
private int GetHeight(IBinarySearchTreeNode <TKey, TValue> root) { if (root == null) { return(0); } return(Math.Max( root.LeftChild != null ? 1 + GetHeight(root.LeftChild) : 0, root.RightChild != null ? 1 + GetHeight(root.RightChild) : 0)); }
private void TraverseInOrder(IBinarySearchTreeNode <TKey, TValue> root, Action <IBinarySearchTreeNode <TKey, TValue> > yielder) { if (root == null) { return; } TraverseInOrder(root.LeftChild, yielder); yielder(root); TraverseInOrder(root.RightChild, yielder); }
private static bool CheckNodeArgument <T>(IBinarySearchTreeNode <T> node) where T : IComparable <T> { if (node == null) { throw new ArgumentNullException(nameof(node)); } else { return(true); } }
/// <summary> /// Simple binary search tree demos examining various BSTs. /// </summary> private static void SampleBinarySearchTreeDemos() { IBinarySearchTreeNode <int> resultNode = null; var result = false; WriteLine("SAMPLE BINARY SEARCH TREE DEMOS"); WriteLine(); var invalidTree = CreateBookSampleBinarySearchTree(); WriteLine(invalidTree); WriteLine($"Is valid BST? {invalidTree.Root.IsValidSearchTree}"); WriteLine(); WriteLine(); var validTree1 = CreateValidBinarySearchTree1(); WriteLine(validTree1); WriteLine($"Is valid BST? {validTree1.Root.IsValidSearchTree}"); var v1data1 = 47; var v1data2 = 43; result = validTree1.Root.Find(v1data1, out resultNode); WriteLine($"Search for {v1data1}: Found = {result}, Node = '{resultNode}'."); result = validTree1.Root.Find(v1data2, out resultNode); WriteLine($"Search for {v1data2}: Found = {result}, Node = '{resultNode}'."); WriteLine(); WriteLine(); var validTree2 = CreateValidBinarySearchTree2(); WriteLine(validTree2); WriteLine($"Is valid BST? {validTree2.Root.IsValidSearchTree}"); var v2data1 = 60; var v2data2 = 73; result = validTree2.Root.Find(v2data1, out resultNode); WriteLine($"Search for {v2data1}: Found = {result}, Node = '{resultNode}'."); result = validTree2.Root.Find(v2data2, out resultNode); WriteLine($"Search for {v2data2}: Found = {result}, Node = '{resultNode}'."); WriteLine(); }
public void BinarySearchTreeTests_LCA3() { IBinarySearchTree <int, string> tree = new BinarySearchTree <int, string>(); IBinarySearchTreeNode <int, string> john = tree.Insert(10, "John"); IBinarySearchTreeNode <int, string> clark = tree.Insert(5, "Clark"); IBinarySearchTreeNode <int, string> pitty = tree.Insert(13, "Pitty"); IBinarySearchTreeNode <int, string> ancestor = tree.LCA(john, john); Assert.IsNotNull(ancestor); Assert.AreEqual(john, ancestor); }
public IBinarySearchTreeNode <TKey, TValue> LCA(IBinarySearchTreeNode <TKey, TValue> node1, IBinarySearchTreeNode <TKey, TValue> node2) { // we assume that node1 and node2 have already placed in the tree if (node1.Key.CompareTo(node2.Key) > 0) { IBinarySearchTreeNode <TKey, TValue> tmp = node1; node1 = node2; node2 = tmp; } return(LCA(root, node1, node2)); }
public bool Remove(TKey key) { if (root == null) { return(false); } if (root.Key.CompareTo(key) == 0) { root = GetNewChildAfterRemoving(root); return(true); } return(Remove(root, key)); }
/// <summary> /// Find the maximum value below this node /// </summary> /// <param name="Node"></param> /// <returns></returns> public IBinarySearchTreeNode <T> FindMaxNode(IBinarySearchTreeNode <T> Node) { if (Node == null) { return(null); } IBinarySearchTreeNode <T> current = Node; while (current.HasRightChild) { current = current.RightChild; } return(current); }
public void AddFirstNodeTest() { ITree <int> tree = new BinarySearchTree <int>(); tree.Add(1); Assert.Equal(1, tree.Count); Assert.Equal(1, tree.Root.Value); IBinarySearchTreeNode <int> rootNode = (IBinarySearchTreeNode <int>)tree.Root; Assert.True(rootNode.IsBlack); Assert.Null(rootNode.Left); Assert.Null(rootNode.Right); }
/// <summary> /// Find the smallest data value in a binary search (sub)-tree. /// </summary> /// <typeparam name="T"> /// The type of data contained in the node. /// </typeparam> /// <param name="node"> /// The start node to search recursively. /// </param> /// <returns> /// The smallest object by comparison. /// </returns> public static T FindMin <T>(this IBinarySearchTreeNode <T> node) where T : IComparable <T> { CheckNodeArgument(node); // In-order traversal of a binary search tree yields a list // of sorted values. // This could also enable checks in alternate ways. var nodes = node.Traverse(TreeTraversalMode.InOrder); // We could take the first item in the list for min but just // to be sure, it might be an invalid BST, take it explicitly. return(nodes .Select(n => n.Data) .Min()); }
public virtual IBinarySearchTreeNode <TKey, TValue> Insert(TKey key, TValue value) { IBinarySearchTreeNode <TKey, TValue> newNode = new BinarySearchTreeNode <TKey, TValue>(key, value); if (root == null) { root = newNode; } else { // Insert(root, newNode); NonRecursiveInsert(root, newNode); } return(newNode); }
private void Mirror(IBinarySearchTreeNode <TKey, TValue> root) { if (root == null) { return; } Mirror(root.LeftChild); Mirror(root.RightChild); // swap left and right subtree IBinarySearchTreeNode <TKey, TValue> tmp = root.LeftChild; root.LeftChild = root.RightChild; root.RightChild = tmp; }
public void RedViolationTest_BlackUncle_LeftNode_LeftParent() { // Test for Case A: the new node and its parent are left children ITree <int> tree = new BinarySearchTree <int>(); // In order to easily simulate this case we are going to manually create the tree // so it is in the correct state. tree.Add(4); IBinarySearchTreeNode <int> rootNode = (IBinarySearchTreeNode <int>)tree.Root; rootNode.IsBlack = true; rootNode.Right = new BinarySearchTreeNode <int>(5); rootNode.Right.IsBlack = true; rootNode.Right.Parent = rootNode; rootNode.Left = new BinarySearchTreeNode <int>(2); rootNode.Left.Parent = rootNode; rootNode.Left.Right = new BinarySearchTreeNode <int>(3); rootNode.Left.Right.IsBlack = true; rootNode.Left.Right.Parent = rootNode.Left; tree.Add(1); rootNode = (IBinarySearchTreeNode <int>)tree.Root; Assert.Null(rootNode.Parent); Assert.Equal(2, rootNode.Value); Assert.True(rootNode.IsBlack); Assert.Equal(1, rootNode.Left.Value); Assert.False(rootNode.Left.IsBlack); Assert.Null(rootNode.Left.Left); Assert.Null(rootNode.Left.Right); Assert.Equal(4, rootNode.Right.Value); Assert.False(rootNode.Left.IsBlack); Assert.Equal(3, rootNode.Right.Left.Value); Assert.True(rootNode.Right.Left.IsBlack); Assert.Null(rootNode.Right.Left.Left); Assert.Null(rootNode.Right.Left.Right); Assert.Equal(5, rootNode.Right.Right.Value); Assert.True(rootNode.Right.Right.IsBlack); Assert.Null(rootNode.Right.Right.Left); Assert.Null(rootNode.Right.Right.Right); }
private static IBinarySearchTreeNode <T> GetSibling(IBinarySearchTreeNode <T> node) { IBinarySearchTreeNode <T> sibling = null; if (node.Parent != null) { if (IsLeft(node)) { sibling = node.Parent.Right; } else { sibling = node.Parent.Left; } } return(sibling); }
public void BinarySearchTreeTests_SimpleTree_SearchTest() { IBinarySearchTree <int, string> tree = new BinarySearchTree <int, string>(); tree.Insert(10, "John"); tree.Insert(5, "Clark"); tree.Insert(13, "Pitty"); IBinarySearchTreeNode <int, string> actual = tree.Search(5); IBinarySearchTreeNode <int, string> actual2 = tree.Search(13); IBinarySearchTreeNode <int, string> actual3 = tree.Search(10); IBinarySearchTreeNode <int, string> actual4 = tree.Search(0); Assert.IsTrue(actual.Key == 5 && actual.Value == "Clark"); Assert.IsTrue(actual2.Key == 13 && actual2.Value == "Pitty"); Assert.IsTrue(actual3.Key == 10 && actual3.Value == "John"); Assert.IsNull(actual4); }
public void BinarySearchTreeTests_LCA5() { IBinarySearchTree <int, string> tree = new BinarySearchTree <int, string>(); IBinarySearchTreeNode <int, string> lui = tree.Insert(3, "Lui"); IBinarySearchTreeNode <int, string> clark = tree.Insert(5, "Clark"); IBinarySearchTreeNode <int, string> joney = tree.Insert(1, "Joney"); IBinarySearchTreeNode <int, string> jack = tree.Insert(8, "Jack"); IBinarySearchTreeNode <int, string> john = tree.Insert(10, "John"); IBinarySearchTreeNode <int, string> ben = tree.Insert(6, "Ben"); IBinarySearchTreeNode <int, string> lulu = tree.Insert(7, "Lu-lu"); IBinarySearchTreeNode <int, string> cris = tree.Insert(2, "Cris"); IBinarySearchTreeNode <int, string> lenon = tree.Insert(0, "Lenon"); IBinarySearchTreeNode <int, string> ancestor = tree.LCA(lulu, john); Assert.IsNotNull(ancestor); Assert.AreEqual(jack, ancestor); }
protected virtual IBinarySearchTreeNode <TKey, TValue> Search(IBinarySearchTreeNode <TKey, TValue> root, TKey key) { if (root == null) { return(null); } int compareResult = root.Key.CompareTo(key); if (compareResult > 0) { return(Search(root.LeftChild, key)); } else if (compareResult < 0) { return(Search(root.RightChild, key)); } return(root); }
/// <summary> /// Remove a node from the Binary search tree /// </summary> /// <param name="Value"></param> /// <returns></returns> IBinarySearchTreeNode <T> IBinarySearchTree <T> .RemoveNode(T Value) { IBinarySearchTreeNode <T> CurrentNode = (this as IBinarySearchTree <T>).FindNode(Value); if (CurrentNode == null) { return(null); } IBinarySearchTreeNode <T> Parent = CurrentNode.Parent; if (CurrentNode.ChildrenCount == 2) // Has both left and right children { IBinarySearchTreeNode <T> temp = this.FindMinNode(CurrentNode.RightChild); //find minimum in right subtree CurrentNode.Data = temp.Data; //copy the value in the minimum to current CurrentNode.RightChild = temp.RightChild; //delete the node with single child } else if (CurrentNode.HasLeftChild) //Only has left child { CurrentNode.Parent.LeftChild = CurrentNode.LeftChild; CurrentNode.LeftChild.Parent = CurrentNode.Parent; } else if (CurrentNode.HasRightChild) //Only has right child { CurrentNode.Parent.RightChild = CurrentNode.RightChild; CurrentNode.RightChild.Parent = CurrentNode.Parent; } else //No children { if (CurrentNode.Parent.LeftChild == CurrentNode) { CurrentNode.Parent.LeftChild = null; } else if (CurrentNode.Parent.RightChild == CurrentNode) { CurrentNode.Parent.RightChild = null; } } return(CurrentNode); }
private IBinarySearchTreeNode <TKey, TValue> GetNewChildAfterRemoving(IBinarySearchTreeNode <TKey, TValue> removedNode) { if (!removedNode.HasChildren) { return(null); } else { if (removedNode.LeftChild == null) { return(removedNode.RightChild); } else if (removedNode.RightChild == null) { return(removedNode.LeftChild); } else // has two children { IBinarySearchTreeNode <TKey, TValue> parent = removedNode; IBinarySearchTreeNode <TKey, TValue> leftmostNodeInTheRightSubtree = removedNode.RightChild; while (leftmostNodeInTheRightSubtree.LeftChild != null) { parent = leftmostNodeInTheRightSubtree; leftmostNodeInTheRightSubtree = leftmostNodeInTheRightSubtree.LeftChild; } if (parent != removedNode) { // leftmostNodeInTheRightSubtree may has ONLY a right child // we was moving to the left all the time, // thus we have to set a new left child for parent of leftmostNodeInTheRightSubtree parent.LeftChild = leftmostNodeInTheRightSubtree.RightChild; leftmostNodeInTheRightSubtree.RightChild = removedNode.RightChild; } leftmostNodeInTheRightSubtree.LeftChild = removedNode.LeftChild; return(leftmostNodeInTheRightSubtree); } } }