// Constructor to create a single node public TTreeNode(K k, V v) { key = k; value = v; left = null; right = null; }
// Searches for a node with name key, name. If found it returns a reference // to the node and to thenodes parent. Else returns null. private TTreeNode <K, V> findParent(K key, ref TTreeNode <K, V> parent) { TTreeNode <K, V> np = root; parent = null; CompareResult cmp; while (np != null) { cmp = comparator(key, np.key); if (cmp == CompareResult.Equal) // found ! { return(np); } if (cmp == CompareResult.Less) { parent = np; np = np.left; } else { parent = np; np = np.right; } } return(null); // Return null to indicate failure to find name }
// Recursively locates an empty slot in the binary tree and inserts the node private void add(TTreeNode <K, V> node, ref TTreeNode <K, V> tree) { if (tree == null) { tree = node; } else { // If we find a node with the same name then it's // a duplicate and we can't continue CompareResult comparison = comparator(node.key, tree.key); if (comparison == CompareResult.Equal) { throw new Exception(); } if (comparison == CompareResult.Less) { add(node, ref tree.left); } else { add(node, ref tree.right); } } }
// Recursive destruction of binary search tree, called by method clear // and destroy. Can be used to kill a sub-tree of a larger tree. // This is a hanger on from its Delphi origins, it might be dispensable // given the garbage collection abilities of .NET private void killTree(ref TTreeNode <K, V> p) { if (p != null) { killTree(ref p.left); killTree(ref p.right); p = null; } }
/// <summary> /// Find the next ordinal node starting at node startNode. /// Due to the structure of a binary search tree, the /// successor node is simply the left most node on the right branch. /// </summary> /// <param name="startNode">Name key to use for searching</param> /// <param name="parent">Returns the parent node if search successful</param> /// <returns>Returns a reference to the node if successful, else null</returns> public TTreeNode <K, V> findSuccessor(TTreeNode <K, V> startNode, ref TTreeNode <K, V> parent) { parent = startNode; // Look for the left-most node on the right side startNode = startNode.right; while (startNode.left != null) { parent = startNode; startNode = startNode.left; } return(startNode); }
/// <summary> /// Add a symbol to the tree if it's a new one. Returns reference to the new /// node if a new node inserted, else returns null to indicate node already present. /// </summary> /// <param name="name">Name of node to add to tree</param> /// <param name="d">Value of node</param> /// <returns> Returns reference to the new node is the node was inserted. /// If a duplicate node (same name was located then returns null</returns> public TTreeNode <K, V> insert(K key, V value) { TTreeNode <K, V> node = new TTreeNode <K, V>(key, value); try { if (root == null) { root = node; } else { add(node, ref root); } _count++; return(node); } catch (Exception) { return(null); } }
/// <summary> /// Find name in tree. Return a reference to the node /// if symbol found else return null to indicate failure. /// </summary> /// <param name="name">Name of node to locate</param> /// <returns>Returns null if it fails to find the node, else returns reference to node</returns> public TTreeNode <K, V> find(K key) { TTreeNode <K, V> np = root; CompareResult cmp; while (np != null) { cmp = comparator(key, np.key); if (cmp == CompareResult.Equal) // found ! { return(np); } if (cmp == CompareResult.Less) { np = np.left; } else { np = np.right; } } return(null); // Return null to indicate failure to find name }
private List <V> find(CompareType compare, K key, ref int readedNondes, TTreeNode <K, V> node) { List <V> ret = new List <V>(); if (node == null) { return(ret); } readedNondes++; CompareResult compareResult = comparator(node.key, key); switch (compare) { case CompareType.equal: case CompareType.like: if (compareResult == CompareResult.Equal) { ret.Add(node.value); } else if (compareResult == CompareResult.Less) { ret.AddRange(find(compare, key, ref readedNondes, node.right)); } else { ret.AddRange(find(compare, key, ref readedNondes, node.left)); } break; case CompareType.notEqual: case CompareType.notLike: if (compareResult != CompareResult.Equal) { ret.Add(node.value); } ret.AddRange(find(compare, key, ref readedNondes, node.left)); ret.AddRange(find(compare, key, ref readedNondes, node.right)); break; case CompareType.greater: if (compareResult == CompareResult.Greater) { ret.Add(node.value); ret.AddRange(find(compare, key, ref readedNondes, node.left)); ret.AddRange(find(compare, key, ref readedNondes, node.right)); } else { ret.AddRange(find(compare, key, ref readedNondes, node.right)); } break; case CompareType.greaterOrEqual: if (compareResult == CompareResult.Equal) { ret.Add(node.value); ret.AddRange(find(compare, key, ref readedNondes, node.right)); } else if (compareResult == CompareResult.Greater) { ret.Add(node.value); ret.AddRange(find(compare, key, ref readedNondes, node.left)); ret.AddRange(find(compare, key, ref readedNondes, node.right)); } else { ret.AddRange(find(compare, key, ref readedNondes, node.right)); } break; case CompareType.less: if (compareResult == CompareResult.Less) { ret.Add(node.value); ret.AddRange(find(compare, key, ref readedNondes, node.left)); ret.AddRange(find(compare, key, ref readedNondes, node.right)); } else { ret.AddRange(find(compare, key, ref readedNondes, node.left)); } break; case CompareType.lessOrEqual: if (compareResult == CompareResult.Equal) { ret.Add(node.value); ret.AddRange(find(compare, key, ref readedNondes, node.left)); } else if (compareResult == CompareResult.Less) { ret.Add(node.value); ret.AddRange(find(compare, key, ref readedNondes, node.left)); ret.AddRange(find(compare, key, ref readedNondes, node.right)); } else { ret.AddRange(find(compare, key, ref readedNondes, node.left)); } break; } return(ret); }
/// <summary> /// Delete a given node. This is the more complex method in the binary search /// class. The method considers three senarios, 1) the deleted node has no /// children; 2) the deleted node as one child; 3) the deleted node has two /// children. Case one and two are relatively simple to handle, the only /// unusual considerations are when the node is the root node. Case 3) is /// much more complicated. It requires the location of the successor node. /// The node to be deleted is then replaced by the sucessor node and the /// successor node itself deleted. Throws an exception if the method fails /// to locate the node for deletion. /// </summary> /// <param name="key">Name key of node to delete</param> public void delete(K key) { TTreeNode <K, V> parent = null; // First find the node to delete and its parent TTreeNode <K, V> nodeToDelete = findParent(key, ref parent); if (nodeToDelete == null) { throw new Exception("Unable to delete node: " + key.ToString()); // can't find node, then say so } // Three cases to consider, leaf, one child, two children // If it is a simple leaf then just null what the parent is pointing to if ((nodeToDelete.left == null) && (nodeToDelete.right == null)) { if (parent == null) { root = null; return; } // find out whether left or right is associated // with the parent and null as appropriate if (parent.left == nodeToDelete) { parent.left = null; } else { parent.right = null; } _count--; return; } // One of the children is null, in this case // delete the node and move child up if (nodeToDelete.left == null) { // Special case if we're at the root if (parent == null) { root = nodeToDelete.right; return; } // Identify the child and point the parent at the child if (parent.left == nodeToDelete) { parent.right = nodeToDelete.right; } else { parent.left = nodeToDelete.right; } nodeToDelete = null; // Clean up the deleted node _count--; return; } // One of the children is null, in this case // delete the node and move child up if (nodeToDelete.right == null) { // Special case if we're at the root if (parent == null) { root = nodeToDelete.left; return; } // Identify the child and point the parent at the child if (parent.left == nodeToDelete) { parent.left = nodeToDelete.left; } else { parent.right = nodeToDelete.left; } nodeToDelete = null; // Clean up the deleted node _count--; return; } // Both children have nodes, therefore find the successor, // replace deleted node with successor and remove successor // The parent argument becomes the parent of the successor TTreeNode <K, V> successor = findSuccessor(nodeToDelete, ref parent); // Make a copy of the successor node TTreeNode <K, V> tmp = new TTreeNode <K, V>(successor.key, successor.value); // Find out which side the successor parent is pointing to the // successor and remove the successor if (parent.left == successor) { parent.left = null; } else { parent.right = null; } // Copy over the successor values to the deleted node position nodeToDelete.value = tmp.value; nodeToDelete.key = tmp.key; _count--; }
public TBinarySTree(CompareMethod <K> compareMethod) { comparator = compareMethod; root = null; _count = 0; }