private static bool IsBst2Inner(Node t, out double min, out double max) { if (t == null) { min = double.MaxValue; max = double.MinValue; return true; } if (!IsBst2Inner(t.Left, out min, out max) || t.Value < max) { return false; // we don't care min, max in this case } double min_copy = min; if (!IsBst2Inner(t.Right, out min, out max) || t.Value > min) { return false; // we don't care min, max in this case } double max_copy = max; min = Math.Min(min_copy, t.Value); max = Math.Max(max_copy, t.Value); return true; }
/// <summary> /// Test for BST using in order traversal characteristic /// </summary> /// <remarks> /// It is sufficient and necessary that if a tree is BST, then /// its in order travesal yields a non-decreasing series. /// /// This approach in-order traverse the tree and check for each /// node that its value is greater or equal to its previous node's /// value. /// /// O(N) in time. O(log(N)) in space. /// </remarks> private static bool IsBstCheckInOrderInner(Node tree, ref double? prev) { if (tree == null) return true; if (!IsBstCheckInOrderInner(tree.Left, ref prev) || (prev != null && (double)prev > tree.Value)) return false; prev = tree.Value; return IsBstCheckInOrderInner(tree.Right, ref prev); }
/// <summary> /// Wrapper for IsBstCheckInOrder /// </summary> static bool IsBstCheckInOrder(Node tree) { double? prev = null; return IsBstCheckInOrderInner(tree, ref prev); }
static bool IsBst2(Node t) { double min = 0, max = 0; return IsBst2Inner(t, out min, out max); }
/// <summary> /// Wrapper of IsBstInner /// </summary> static bool IsBst(Node tree) { double min = 0, max = 0; return IsBstInner(tree, ref min, ref max); }
/// <summary> /// Test cases /// </summary> static void Main(string[] args) { Node n3 = new Node(3); Node n4 = new Node(4); Node n5 = new Node(5); Node n6 = new Node(6); Node n8 = new Node(8); Node n9 = new Node(9); Node n5b = new Node(5); // Test case 1: valid BST n3.Right = n4; n8.Left = n6; n8.Right = n9; n5.Left = n3; n5.Right = n8; n6.Left = n5b; Debug.Assert(IsBst(n5)); Debug.Assert(IsBst2(n5)); Debug.Assert(IsBstCheckRange(n5)); Debug.Assert(IsBstCheckInOrder(n5)); // Test case 2: invalid BST // Move n9 to the right child of n5b to invalidate the BST n8.Right = null; n5b.Right = n9; Debug.Assert(IsBst(n5) == false); Debug.Assert(IsBst2(n5) == false); Debug.Assert(IsBstCheckRange(n5) == false); Debug.Assert(IsBstCheckInOrder(n5) == false); // Test case 3: single node valid BST. var n0 = new Node(0); Debug.Assert(IsBst(n0)); Debug.Assert(IsBst2(n0)); Debug.Assert(IsBstCheckRange(n0)); Debug.Assert(IsBstCheckInOrder(n0)); }
/// <summary> /// Test for BST /// </summary> /// <remarks> /// Test for BST using the BST definition: /// 1. The root's value should be larger/smaller or equal to all its left/right subtree's nodes /// 2. The root's left and right subtrees need to be BST too. /// /// O(N) in time. O(log(N)) in space. /// </remarks> private static bool IsBstInner(Node tree, ref double min, ref double max) { if (tree == null) { throw new ArgumentNullException(); } if (tree.Left == null && tree.Right == null) { min = tree.Value; max = tree.Value; return true; } if (tree.Left != null && (!IsBstInner(tree.Left, ref min, ref max) || tree.Value < max )) { return false; } double min_ret = tree.Left == null ? tree.Value : min; if (tree.Right != null && (!IsBstInner(tree.Right, ref min, ref max) || tree.Value > min)) { return false; } max = tree.Right == null ? tree.Value : max; min = min_ret; return true; }
/// <summary> /// Test for BST by checking tree's range recursively /// </summary> /// <remarks> /// Using BST's characteristic that any node from the /// root's left/right subtree is smaller/larger or equal /// to the root node. This approach checks for this property /// recursively, for every node in the tree. /// /// O(N) in time. O(log(N)) in space. /// </remarks> private static bool IsBstCheckRangeInner(Node tree, double min, double max) { if (tree == null) return true; return tree.Value >= min && tree.Value <= max && IsBstCheckRangeInner(tree.Left, min, tree.Value) && IsBstCheckRangeInner(tree.Right, tree.Value, max); }
/// <summary> /// Wrapper for IsBstCheckRange /// </summary> static bool IsBstCheckRange(Node tree) { return IsBstCheckRangeInner(tree, double.MinValue, double.MaxValue); }