/// <summary> /// Checks various properties to determine if the tree is a valid AA Tree. /// Throws exceptions if properties are violated. /// Useful for debugging. /// </summary> /// <remarks> /// The properties that are checked are: /// <list type="number"> /// <item>The level of every leaf node is one.</item> /// <item>The level of every left child is exactly one less than that of its parent.</item> /// <item>The level of every right child is equal to or one less than that of its parent.</item> /// <item>The level of every right grandchild is strictly less than that of its grandparent.</item> /// <item>Every node of level greater than one has two children.</item> /// </list> /// More information: https://en.wikipedia.org/wiki/AA_tree . /// </remarks> /// <param name="node">The node to check from.</param> /// <returns>true if node passes all checks, false otherwise.</returns> private static bool Validate <T>(AATreeNode <T>?node) { if (node == null) { return(true); } // Check level == 1 if node if a leaf node. var leafNodeCheck = CheckLeafNode(node); // Check level of left child is exactly one less than parent. var leftCheck = CheckLeftSubtree(node); // Check level of right child is equal or one less than parent. var rightCheck = CheckRightSubtree(node); // Check right grandchild level is less than node. var grandchildCheck = CheckRightGrandChild(node); // Check if node has two children if not leaf. var nonLeafChildrenCheck = CheckNonLeafChildren(node); var thisNodeResult = leafNodeCheck && leftCheck && rightCheck; thisNodeResult = thisNodeResult && grandchildCheck && nonLeafChildrenCheck; return(thisNodeResult && Validate(node.Left) && Validate(node.Right)); }
// Tree Balancing After Adding an item private void BalanceTreeAfterAdd(Stack <AATreeNode> parentNodes) { AATreeNode parentNode = null; while (parentNodes.Count > 0) { var node = parentNodes.Pop(); if (parentNodes.Count > 0) { parentNode = parentNodes.Peek(); } else { parentNode = null; } // maintain two properties // 1. if a node and its left child have same level then rotate right. // 2. if a node, its right child and right node's right child have same level then rotate left. if (parentNode != null) { bool isLeftNode = parentNode.Left == node; RotateRight(parentNode, isLeftNode ? parentNode.Left : parentNode.Right); RotateLeft(parentNode, isLeftNode ? parentNode.Left : parentNode.Right); } else { // check root node. RotateRight(null, this.root); RotateLeft(null, this.root); } } }
// PreOrder Traversal implementation. private static IEnumerable <T> PreOrderTraversal(AATreeNode node) { if (node == AATree <T> .NullNode) { yield break; } Stack <AATreeNode> stack = new Stack <AATreeNode>(); stack.Push(node); AATreeNode currentNode = AATree <T> .NullNode; while (stack.Count > 0) { currentNode = stack.Pop(); if (currentNode.Right != AATree <T> .NullNode) { stack.Push(currentNode.Right); } if (currentNode.Left != AATree <T> .NullNode) { stack.Push(currentNode.Left); } yield return(currentNode.Value); } }
// InOrder Traversal implementation. private static IEnumerable <T> InOrderTraversal(AATreeNode node) { if (node == AATree <T> .NullNode) { yield break; } Stack <AATreeNode> nodes = new Stack <AATreeNode>(); AATreeNode currentNode = node; while (nodes.Count > 0 || currentNode != AATree <T> .NullNode) { if (currentNode != AATree <T> .NullNode) { nodes.Push(currentNode); currentNode = currentNode.Left; } else { currentNode = nodes.Pop(); yield return(currentNode.Value); currentNode = currentNode.Right; } } }
/// <summary> /// Searches for the specified value in the AATree. /// If found returns the node containing the value in node out param, else this param contains NullNode. /// </summary> /// <param name="value">Value to search.</param> /// <param name="node">AATree node.</param> /// <returns>Returns true if the value is found, else returns false.</returns> internal bool TrySearch(T value, out AATreeNode node) { bool result = false; node = AATree <T> .NullNode; var currentNode = this.root; while (currentNode != AATree <T> .NullNode) { int compResult = this.Comparer.Compare(value, currentNode.Value); if (compResult == 0) { node = currentNode; result = true; break; } if (compResult < 0) { //goto left currentNode = currentNode.Left; } else { //goto right currentNode = currentNode.Right; } } return(result); }
public AATreeNode(T value, AATreeNode nullNode) { this.Value = value; this.Left = nullNode; this.Right = nullNode; this.Level = 1; }
// Tree Balancing After remving an item private void BalanceTreeAfterRemove(Stack <AATreeNode> parentNodes) { AATreeNode parentNode = null; // balance the tree. while (parentNodes.Count > 0) { var node = parentNodes.Pop(); if ((node.Level - node.Left.Level) > 1 || (node.Level - node.Right.Level) > 1) { node.Level--; if (node.Right.Level > node.Level) { node.Right.Level = node.Level; } if (parentNodes.Count > 0) { parentNode = parentNodes.Peek(); } else { parentNode = null; } if (parentNode != null) { bool isLeftNode = parentNode.Left == node; if (RotateRight(parentNode, node)) { // get the new child from parent. node = isLeftNode ? parentNode.Left : parentNode.Right; } if (RotateRight(node, node.Right)) { if (RotateRight(node.Right, node.Right.Right)) { if (RotateLeft(parentNode, node)) { node = isLeftNode ? parentNode.Left : parentNode.Right; } } } RotateLeft(node, node.Right); } else { RotateRight(null, this.root); RotateRight(this.root, this.root.Right); RotateRight(this.root.Right, this.root.Right.Right); RotateLeft(null, this.root); RotateLeft(this.root, this.root.Right); } } } }
/// <summary> /// Checks if right grandchild's (right node's right node) level is less than node. /// </summary> /// <param name="node">The node to check.</param> /// <returns>true if node passes check, false otherwise.</returns> private bool CheckRightGrandChild <T>(AATreeNode <T> node) { var condition = node.Right != null && node.Right.Right != null && node.Right.Level < node.Right.Right.Level; return(!condition); }
/// <summary> /// Checks if right node's level is either equal to or one less than node's level. /// </summary> /// <param name="node">The node to check.</param> /// <returns>true if node passes check, false otherwise.</returns> private static bool CheckRightSubtree <T>(AATreeNode <T> node) { var condition = node.Right != null && node.Level - node.Right.Level != 1 && node.Level != node.Right.Level; return(!condition); }
// PostOrder Traversal implementation. private static IEnumerable <T> PostOrderTraversal(AATreeNode node) { if (node == AATree <T> .NullNode) { yield break; } Stack <AATreeNode> nodes = new Stack <AATreeNode>(); AATreeNode currentNode = node; while (true) { if (currentNode != AATree <T> .NullNode) { if (currentNode.Right != AATree <T> .NullNode) { nodes.Push(currentNode.Right); } nodes.Push(currentNode); currentNode = currentNode.Left; } else { if (nodes.Count == 0) { break; } currentNode = nodes.Pop(); if (currentNode.Right != AATree <T> .NullNode && nodes.Count > 0 && nodes.Peek() == currentNode.Right) { nodes.Pop(); // remove right; nodes.Push(currentNode); // push current currentNode = currentNode.Right; } else { yield return(currentNode.Value); currentNode = AATree <T> .NullNode; } } } }
/// <summary> /// Split or Rotate left. /// </summary> /// <param name="parentNode"></param> /// <param name="node"></param> /// <returns></returns> private bool RotateLeft(AATreeNode parentNode, AATreeNode node) { bool result = false; if (node == AATree <T> .NullNode) { return(result); } if (node.Level == node.Right.Level && node.Right.Level == node.Right.Right.Level) { // rotate left. var nodeToMoveUp = node.Right; node.Right = nodeToMoveUp.Left; nodeToMoveUp.Left = node; if (parentNode != null) { if (parentNode.Left == node) { parentNode.Left = nodeToMoveUp; parentNode.Left.Level++; } else { parentNode.Right = nodeToMoveUp; parentNode.Right.Level++; } } else { this.root = nodeToMoveUp; this.root.Level++; } result = true; } return(result); }
/// <summary> /// Checks if node is a leaf, and if so if its level is 1. /// </summary> /// <param name="node">The node to check.</param> /// <returns>true if node passes check, false otherwise.</returns> private static bool CheckLeafNode <T>(AATreeNode <T> node) { var condition = node.Left == null && node.Right == null && node.Level != 1; return(!condition); }
/// <summary> /// Checks if left node's level is exactly one less than node's level. /// </summary> /// <param name="node">The node to check.</param> /// <returns>true if node passes check, false otherwise.</returns> private bool CheckLeftSubtree <T>(AATreeNode <T> node) { var condition = node.Left != null && node.Level - node.Left.Level != 1; return(!condition); }
/// <summary> /// Initializes an instance of AATree class with specified comparer. /// </summary> /// <param name="comparer">Comparer to compare values.</param> public AATree(IComparer <T> comparer) { this.Comparer = comparer; this.root = AATree <T> .NullNode; this.DefaultValue = default(T); }
/// <summary> /// Tries to remove specified value from the AATree. /// </summary> /// <param name="value">Value to remove.</param> /// <returns>Returns true if the value is found and removed successfully, else returns false.</returns> public bool Remove(T value) { // Step1. Serach for the value in the tree // Step2. if not found return false, if found then go to step3. // Step3. if the node is a leaf node then delete the node, else if the node has only one child then delete // the node and assign its child to parent, // else if the node has two child then find a node which can be replaced by the node to be deleted // (use LeftmostRight or RightmostLeft node) //Step4. balance the tree. bool result = false; Stack <AATreeNode> parentNodes = new Stack <AATreeNode>(); AATreeNode node = this.root; while (node != AATree <T> .NullNode) { int keyCompResult = this.Comparer.Compare(value, node.Value); if (keyCompResult == 0) { result = true; break; } else if (keyCompResult < 0) { //if key is lessthan the node.Key goto left parentNodes.Push(node); node = node.Left; } else { //if key is greaterthan the node.Key goto right parentNodes.Push(node); node = node.Right; } } if (!result) { return(result); } AATreeNode nodeToDelete = node; if (nodeToDelete.Left != AATree <T> .NullNode && nodeToDelete.Right != AATree <T> .NullNode) { parentNodes.Push(node); // using right most of left sub tree. node = nodeToDelete.Left; while (node.Right != AATree <T> .NullNode) { parentNodes.Push(node); node = node.Right; } var tval = nodeToDelete.Value; nodeToDelete.Value = node.Value; node.Value = tval; nodeToDelete = node; } AATreeNode parentNode = null; if (nodeToDelete.Left == AATree <T> .NullNode || nodeToDelete.Right == AATree <T> .NullNode) { AATreeNode childNode = nodeToDelete.Left == AATree <T> .NullNode ? nodeToDelete.Right : nodeToDelete.Left; if (parentNodes.Count > 0) { parentNode = parentNodes.Peek(); } if (parentNode != null) { if (parentNode.Left == nodeToDelete) { parentNode.Left = childNode; } else { parentNode.Right = childNode; } } else { this.root = childNode; } } BalanceTreeAfterRemove(parentNodes); if (result) { this.Count--; } return(result); }
/// <summary> /// Checks if node is not a leaf, and if so if it has two children. /// </summary> /// <param name="node">The node to check.</param> /// <returns>true if node passes check, false otherwise.</returns> private static bool CheckNonLeafChildren <T>(AATreeNode <T> node) { var condition = node.Level > 1 && (node.Left == null || node.Right == null); return(!condition); }
/// <summary> /// Tries to add specified value to the AATree. /// If the value is already present in the tree then this method returns without adding. /// </summary> /// <param name="value">Value to add.</param> /// <returns>Returns true if value is added successfully, else returns false.</returns> public bool Add(T value) { bool result = false; if (this.root == AATree <T> .NullNode) { this.root = new AATreeNode(value, AATree <T> .NullNode); result = true; } if (!result) { AATreeNode node = this.root; Stack <AATreeNode> parentNodes = new Stack <AATreeNode>(); while (true) { int keyCompResult = Comparer.Compare(value, node.Value); if (keyCompResult == 0) { // key already exists. result = false; break; } else if (keyCompResult < 0) { // go to left. if (node.Left == AATree <T> .NullNode) { node.Left = new AATreeNode(value, AATree <T> .NullNode); result = true; break; } else { parentNodes.Push(node); node = node.Left; } } else { // go to right. if (node.Right == AATree <T> .NullNode) { node.Right = new AATreeNode(value, AATree <T> .NullNode); result = true; break; } else { parentNodes.Push(node); node = node.Right; } } } if (result) { parentNodes.Push(node); BalanceTreeAfterAdd(parentNodes); } } if (result) { Count++; } return(result); }