Recursive Search Binary Tree C# - c#

Iam trying to Findout if this program can check if a binary tree is BST or not,
Following is the Code:
public static bool isValidBST(Node root)
{
return isValid(root, root.Left.Value,
root.Right.Value);
}
private static bool isValid(Node node, int MIN, int MAX)
{
// tree with no childres is BST
if (node == null)
return true;
if (node.Value <= MIN || node.Value >= MAX)
return false;
return isValid(node.Left, MIN, node.Value) && isValid(node.Right, node.Value, MAX);
}
I Think there is somthing missing in my code for example i dont think this code would work on a tree with one root and just two nodes. can you guys help me to fix my implementation?
I also found this solution on stackoverflow
private static bool isValid(Node node, int MIN, int MAX)
{
// tree with no childres is BST
if (node == null)
return true;
if (node.Value > MIN && node.Value < MAX
&& isValid(node.Left, MIN, Math.Min(node.Value, MAX))
&& isValid(node.Right, Math.Max(node.Value, MIN), MAX))
return true;
else
return false;
}
But this won't work for me eather!
this is how i tried the Code:
public static void Main(string[] args)
{
Node n1 = new Node(1, null, null);
Node n3 = new Node(3, null, null);
Node n2 = new Node(2, n1, n3);
Console.WriteLine(isValidBST(n2));
Console.ReadLine();
}
The result is False,while it should be True.

You have the error in the starting point of your solution:
public static bool isValidBST(Node root)
{
return isValid(root, root.Left.Value,
root.Right.Value);
}
Instead of passing root.Left.Value and root.Right.Value in the recursive function, send int.MaxValue and int.MinValue. There are at least two good reasons for doing so:
if root node does not have left or right child, your approach will cause NullReferenceException
by passing int.MaxValue and int.MinValue, you require from the left and right child only to be less than / greater than its parent, without the other boundary. For example, you shouldn't care whether the first left child is greater than some specific value, it just have to be less than the root value! By sending int.MinValue you make sure that it is always greater than that value, so you are just checking the upper bound.

Related

SortedSet with element duplication - can't remove element

I'm working on an implementation of the A-star algorithm in C# in Unity.
I need to evaluate a collection of Node :
class Node
{
public Cell cell;
public Node previous;
public int f;
public int h;
public Node(Cell cell, Node previous = null, int f = 0, int h = 0)
{
this.cell = cell;
this.previous = previous;
this.f = f;
this.h = h;
}
}
I have a SortedSet which allows me to store several Node, sorted by h property. Though, I need to be able to store two nodes with the same h property. So I've implemented a specific IComparer, in a way that allow me sorting by h property, and triggerring equality only when two nodes are representing the exact same cell.
class ByHCost : IComparer<Node>
{
public int Compare(Node n1, Node n2)
{
int result = n1.h.CompareTo(n2.h);
result = (result == 0) ? 1 : result;
result = (n1.cell == n2.cell) ? 0 : result;
return result;
}
}
My problem : I have a hard time to remove things from my SortedSet (I named it openSet).Here is an example:
At some point in the algorithm, I need to remove a node from the list based on some criteria (NB: I use isCell127 variable to focus my debug on an unique cell)
int removedNodesNb = openSet.RemoveWhere((Node n) => {
bool isSame = n.cell == candidateNode.cell;
bool hasWorseCost = n.f > candidateNode.f;
if(isCell127)
{
Debug.Log(isSame && hasWorseCost); // the predicate match exactly one time and debug.log return true
}
return isSame && hasWorseCost;
});
if(isCell127)
{
Debug.Log($"removed {removedNodesNb}"); // 0 nodes where removed
}
Here, the removeWhere method seems to find a match, but doesn't remove the node.
I tried another way :
Node worseNode = openSet.SingleOrDefault(n => {
bool isSame = n.cell == candidateNode.cell;
bool hasWorseCost = n.f > candidateNode.f;
return isSame && hasWorseCost;
});
if(isCell127)
{
Debug.Log($"does worseNode exists ? {worseNode != null}"); // Debug returns true, it does exist.
}
if(worseNode != null)
{
if(isCell127)
{
Debug.Log($"openSet length {openSet.Count}"); // 10
}
openSet.Remove(worseNode);
if(isCell127)
{
Debug.Log($"openSet length {openSet.Count}"); // 10 - It should have been 9.
}
}
I think the problem is related to my pretty unusual IComparer, but I can't figure whats exatcly the problem.
Also, I would like to know if there is a significative performance improvment about using an auto SortedSet instead of a manually sorted List, especially in the A-star algorithm use case.
If i write your test you do:
n1.h < n2.h
n1.cell = n2.cell -> final result = 0
n1.h > n2.h
n1.cell = n2.cell -> final result = 0
n1.h = n2.h
n1.cell != n2.cell -> final result = 1
n1.h < n2.h
n1.cell != n2.cell -> final result = -1
n1.h > n2.h
n1.cell != n2.cell -> final result = 1
when you have equality on h value (test number 3) you choose to have always the same result -> 1. so its no good you have to have another test on cell to clarify the position bacause there is a confusion with other test which gives the same result (test number 5)
So i could test with sample, but i am pretty sure you break the Sort.
So if you clarify the test, i suggest you to use Linq with a list...its best performance.
I'll answer my own topic because I've a pretty complete one.
Comparison
The comparison of the IComparer interface needs to follow some rules. Like #frenchy said, my own comparison was broken. Here are math fundamentals of a comparison I totally forgot (I found them here):
1) A.CompareTo(A) must return zero.
2) If A.CompareTo(B) returns zero, then B.CompareTo(A) must return zero.
3) If A.CompareTo(B) returns zero and B.CompareTo(C) returns zero, then A.CompareTo(C) must return zero.
4) If A.CompareTo(B) returns a value other than zero, then B.CompareTo(A) must return a value of the opposite sign.
5) If A.CompareTo(B) returns a value x not equal to zero, and B.CompareTo(C) returns a value y of the same sign as x, then A.CompareTo(C) must return a value of the same sign as x and y.
6) By definition, any object compares greater than (or follows) null, and two null references compare equal to each other.
In my case, rule 4) - symetry - was broken.
I needed to store multiple node with the same h property, but also to sort by that h property. So, I needed to avoid equality when h property are the same.
What I decided to do, instead of a default value when h comparison lead to 0 (which broke 4th rule), is refine the comparison in a way that never lead to 0 with a unique value foreach node instance. Well, this implementation is probably not the best, maybe there is something better to do for a unique value, but here is what I did.
private class Node
{
private static int globalIncrement = 0;
public Cell cell;
public Node previous;
public int f;
public int h;
public int uid;
public Node(Cell cell, Node previous = null, int f = 0, int h = 0)
{
Node.globalIncrement++;
this.cell = cell;
this.previous = previous;
this.f = f;
this.h = h;
this.uid = Node.globalIncrement;
}
}
private class ByHCost : IComparer<Node>
{
public int Compare(Node n1, Node n2)
{
if(n1.cell == n2.cell)
{
return 0;
}
int result = n1.h.CompareTo(n2.h);
result = (result == 0) ? n1.uid.CompareTo(n2.uid) : result; // Here is the additional comparison which never lead to 0. Depending on use case and number of object, it would be better to use another system of unique values.
return result;
}
}
RemoveWhere method
RemoveWhere use a predicate to look into the collection so I didn't think it cares about comparison. But RemoveWhere use internally Remove method, which do care about the comparison. So, even if the RemoveWhere have found one element, if your comparison is inconstent, it will silently pass its way. That's a pretty weird implementation, no ?

How to determine if Binary Tree is BST

I am trying to figure out a logic to determine if Binary Tree is BST. I want to use the inorder approach and I don't want to use an extra array to store all incoming values as we know that Inorder should be in sorted order. I want to check the incoming value w/o having to store it in an array. Below is my attempt which is not working.
public bool CheckBST(BstNode root)
{
BstNode prev = new BstNode(Int32.MinValue);
if (root == null)
return true;
if (root.left != null)
{
return CheckBST(root.left);
}
if (prev != null && prev.data >= root.data) // means data is not sorted hence NOT BST
return false;
prev = root;
if(root.right!=null)
{
return CheckBST(root.right);
}
return true;
}
Given a binary tree, following determines if it is a valid binary search tree (BST).
The left subtree of a node contains only nodes with keys less than
the node's key.
The right subtree of a node contains only nodes with keys greater
than the node's key.
Both the left and right subtrees must also be binary search trees.
Let's see below example:
If you see the above Binary Tree is a BST.
Now let's see another example :
The root node's value is 5 but its right child's value is 4 which does not satisfy the condition mentioned above. So the given tree is not a BST.
Solution Code:
Given that the TreeNode is defined as
public class TreeNode
{
public int Val { get; set; }
public TreeNode Left { get; set; }
public TreeNode Right { get; set; }
public TreeNode(int x) { this.Val = x; }
}
The code to check the validation is
public bool IsValidBST(TreeNode root)
{
return IsValidBST(root, int.MinValue, int.MaxValue);
}
private bool IsValidBST(TreeNode root, int minValue, int maxValue)
{
if (root == null)
{
return true;
}
int nodeValue = root.Val;
if (nodeValue < minValue || nodeValue > maxValue)
{
return false;
}
return IsValidBST(root.Left, minValue, nodeValue - 1) && IsValidBST(root.Right, nodeValue + 1, maxValue);
}
Now the IsValidBST can be invoked with root node
bool isValidBST = IsValidBST(rootNode);
So usually in a BST there are three things in each node. That is the data, and the two pointers left and right. If there are more than two pointers available in any node then it is not a BST. It is probably best to determine at the level of the node if it there are more pointers than there should be. You would be wasting time and resources by searching the tree.
Here is a good way to go about doing it https://www.geeksforgeeks.org/a-program-to-check-if-a-binary-tree-is-bst-or-not/
You can't initilaze the prev everytime in CheckBST. You can make the prev global. Also I have made the prev as type integer.
int prev = Int32.MinValue; //made this global and integer type
public bool CheckBST(BstNode root) {
if (root == null)
return true;
bool isLeftBST = CheckBST(root.left);
if (isLeftBST == false) return false;
if (prev != Int32.MinValue && prev >= root.data) // means data is not sorted hence NOT BST
return false;
prev = root.data; //mark the prev before traversing the right subtree
return isLeftBST && CheckBST(root.right);
}
Ignore the syntax problems, if any. I tried more of a pseudo code.
Ofcourse there are other ways to solve this problem as well. Like keeping track of min and max value so far (in #user1672994 answer).
If you could make CheckBST return the range (min, max) of the BST being checked, then the following recursive function shall do:
// Defines the return value that represents BST check failure.
const pair<int, int> kCheckFailed(Int32.MaxValue, Int32.MinValue);
pair<int, int> CheckBST(const BstNode& curr)
{
pair<int, int> left_ret(curr.value, curr.value);
pair<int, int> right_ret(curr.value, curr.value);
// Makes sure the left subtree, if any, is a BST, and its max
// (`left_ret.second`) is no greater than `curr.value`
if (curr.left) {
left_ret = CheckBST(*curr.left);
if (left_ret == kCheckFailed || left_ret.second > curr.value)
return kCheckFailed;
}
// Makes sure the right subtree, if any, is a BST, and its min
// (`right_ret.first`) is not less than `curr.value`.
if (curr.right) {
right_ret = CheckBST(*curr.right);
if (right_ret == kCheckFailed || right_ret.first < curr.value)
return kCheckFailed;
}
// Returns range by combining min of left subtree and max of right subtree.
return make_pair(left_ret.first, right_ret.second);
}
Note that CheckBST takes a (sub)tree root by reference to ensure the node (curr) is always valid. However, curr.left or curr.right may still be NULL, in which cases, the corresponding min or max values, respectively, are just curr.value, as initialized to both ret_left and ret_right.
Recursive with time complexity of O(1).
Remove the commented our lines to see how it gets called.
For the first call pass isBST(root, null, null).
public bool isBST(Node root, Node l, Node r)
{
// Console.WriteLine($"Processing: isBST({root?.data}, {l?.data}, {r?.data})");
if (root == null) return true;
if (l != null && root.data <= l.data) return false;
if (r != null && root.data >= r.data) return false;
// Console.WriteLine($"isBST({root?.left?.data}, {l}, {root?.data}) && isBST({root?.right?.data}, {root?.data}, {r?.data})");
return isBST(root.left, l, root) && isBST(root.right, root, r);
}
You dont need prev.
Check recursively that max(left) is less than or equal root.
Check recursively that min(right) if greater than root.
Check if the left is BST.
Check if the right is BST.
Of course, check on nulls where needed.

how to find two short numbers in between another short numbers in C#

I am having two short numbers 20101, 20141 if i pass 20121 and 20131 then it should return it is available with in the range. if i pass 20081 and 20091 then it should return false, same for 20142 to 20154.
how to find in between for two short numbers.
bool TestRange (int numberToCheck, int bottom, int top)
{
return (numberToCheck >= bottom && numberToCheck <= top);
}
tried the above but it is working as expected. because in my case i want to check two short numbers in another two short numbers. how to do it
Change the signature to bool TestRange (int[] numbersToCheck, int bottom, int top) and iterate numbersToCheck and return as required
Since I needed to use something like that way too often and I'm lazy, I've written an extension method, to check if any integer is between two values.
public static class IntExtensions
{
public static bool Between(this int value, int lowerBound, int upperBound)
{
return value >= lowerBound && value <= upperBound;
}
}
That way you can easily use it with LinQ as
return Array.All(x => x.Between(integer, integer)); // All numbers must be in range.
return Array.Any(x => x.Between(integer, integer)); // At least one number must be in range.
Or just return the numbers that match the constraint as a new array:
return Array.Where(x => x.Between(integer, integer)).ToArray();
In general case with many (arbitrary number) items to test, I suggest signature modification and Linq:
// If you want to pass many items, pass IEnumerable<T>
bool TestRange(IEnumerable<int> numbersToCheck, int bottom, int top) {
if (null == numberToCheck)
throw new ArgumentNullException("numbersToCheck"); // or return true or false...
return numbersToCheck.All(item => item >= bottom && top <= item);
}
...
if (TestRange(new int[] {20121, 20131}, 20101, 20141)) {...}

How would I return the lowest value from the list without using shortcuts?

I was given a list of numbers, { 1, 2, 3, 4, 5, 6, 7 }. I was asked to return the lowest value without using shortcuts, e.g. .Min() etc.
I am not going to give you the answer to your homework question for you directly, however to get you started just loop over the list and keep track of the smallest one you found. When you are done the smallest you found is the smallest in the list.
For your second part, it is just basic problem solving. Look at the problem, break it into smaller pieces. For example, for your problem you could break it in to:
How do I loop over a list
How do I remember a value between loops
How do i compare if the remembered value is smaller than the current loop value
How do I replace my remembered value if the current loop value is smaller
Then solve each piece individually.
You can do this in old-fashion imperative way. Works with all comparable types:
public static class MyEnumerableExtensions
{
public static T Min<T>(this IEnumerable<T> list) where T : IComparable<T>
{
if (list == null)
{
throw new ArgumentNullException("list");
}
T min = default (T);
bool initialized = false;
foreach (T elem in list)
{
if (!initialized)
{
min = elem;
initialized = true;
}
else if (min == null) // Do not compare with null, reset min
{
min = elem;
}
else if (elem != null && min.CompareTo(elem) > 0) // Compare only when elem is not null
{
min = elem;
}
}
if (!initialized)
{
throw new InvalidOperationException("list is empty");
}
return min;
}
}
Usage:
var min1 = list.Min();
var min2 = MyEnumerableExtensions.Min(list);
Also, is only Min method is restricted from Linq, additional tricks are possible. Works for numbers only:
var minViaMax = -list.Select(x => -x).Max();
var minViaAggregate = list.Aggregate(Math.Min);

How to get the closest item to my key from a SortedDictionary?

Currently I'm using a binary search over a SortedList<T,U> for a specific number, and if it doesn't exist I get the closest lower-bound key-item instead.
I saw that it was rather slow in inserting unsorted data which I'm doing a lot of.
Is there a way to do something similar with the SortedDictionary, or should I just stick to my SortedList?
SortedList<K, V> is really slow when inserting data as it shifts <=N elements in internal array each time a new element is added. The complexity of addition is O(N). Nevertheless it supports binary search which allows to find exact element or its neighbors in O(log N).
Balanced binary tree is the best data structure to solve your problem.
You'll be able to to do the following operations w/ logarithmic complexity:
Add item in O(log N) vs. O(N) in SortedList<K, V>
Remove item in O(log N)
Search item or its nearest in O(log N)
Looking for element or its nearest lower-bound in binary tree is simple:
Go vertically through the tree from root to child in order to find your key. If key < node, then go to left child, otherwise to the right one.
If you found the key, return
If key not found, nearest left parent will be the one you are looking for (nearest lower-bound)
If there is no left parents, just take the last visited node, it is minimal node in the tree.
There are many articles describing how to implement binary tree. Nevertheless I'm going to reuse .NET Framework collection using a kind of hack :)
Now, I'm gonna present to you SortedSet<T> which itself is red-black tree. It has one drawback, it has no ability to find nearest nodes quickly. But we know the algorithm of search in tree (it's described in 1.) and it is implemented in SortedSet<T>.Contains method (decompiled at the bottom*). Now we can capture all nodes from root to the last visited node during traversal using our custom comparer. After that we can find nearest lower-bound node using algorithm above:
public class LowerBoundSortedSet<T> : SortedSet<T> {
private ComparerDecorator<T> _comparerDecorator;
private class ComparerDecorator<T> : IComparer<T> {
private IComparer<T> _comparer;
public T LowerBound { get; private set; }
private bool _reset = true;
public void Reset()
{
_reset = true;
}
public ComparerDecorator(IComparer<T> comparer)
{
_comparer = comparer;
}
public int Compare(T x, T y)
{
int num = _comparer.Compare(x, y);
if (_reset)
{
LowerBound = y;
}
if (num >= 0)
{
LowerBound = y;
_reset = false;
}
return num;
}
}
public LowerBoundSortedSet()
: this(Comparer<T>.Default) {}
public LowerBoundSortedSet(IComparer<T> comparer)
: base(new ComparerDecorator<T>(comparer)) {
_comparerDecorator = (ComparerDecorator<T>)this.Comparer;
}
public T FindLowerBound(T key)
{
_comparerDecorator.Reset();
this.Contains<T>(key);
return _comparerDecorator.LowerBound;
}
}
You see that finding nearest node takes no more than usual search, i.e. O(log N). So, this is the fastest solution for your problem. This collection is as fast as SortedList<K, V> in finding nearest and is as fast as SortedSet<T> in addition.
What about SortedDictionary<K, V>? It is almost the same as SortedSet<T> except one thing: each key has a value. I hope you will be able to do the same with SortedDictionary<K, V>.
*Decompiled SortedSet<T>.Contains method:
public virtual bool Contains(T item)
{
return this.FindNode(item) != null;
}
internal virtual SortedSet<T>.Node FindNode(T item)
{
for (SortedSet<T>.Node node = this.root; node != null; {
int num;
node = num < 0 ? node.Left : node.Right;
}
)
{
num = this.comparer.Compare(item, node.Item);
if (num == 0)
return node;
}
return (SortedSet<T>.Node) null;
}

Categories