I am trying to search through a binary search tree using a recursive method in C#.
So far I am able to successfully execute this method using two parameters:
public bool Search(int value, Node start)
{
if(start == null) {
return false;
}
else if(value == start.value) {
return true;
}
else {
if(value < start.value) {
Search(value, start.LeftChild.value);
}
else {
Search(value, start.RightChild.value);
}
}
}
However I would like to see if there's a way to use only one parameter such as using the following method signature:
public bool Search(int value){}
I also have the following that I can use to access the tree:
public class BinarySearchTree
{
private Node<int> root;
public Node<int> Root { get => root; set => root = value; }
public BinarySearchTree()
{
this.root = null;
}
}
public bool Search(int value)
{
return SearchTree(value, root);
bool SearchTree(int value, Node<int> start)
{
if(start == null)
return false;
else if(value == start.Value)
return true;
else
{
if(value < start.Value)
return SearchTree(value, start.LeftChild);
else
return SearchTree(value, start.RightChild);
}
}
}
if there's a way to use only one parameter such as using the following method signature:
sure. make it a method in Node class.
public class Node
{
public Node LeftChild, RightChild;
public int value;
public bool Search(int value)
{
if (value == this.value)
{
return true;
}
else
{
if (value < this.value)
{
return this.LeftChild?.Search(value) ?? false;
}
else
{
return this.RightChild?.Search(value) ?? false;
}
}
}
}
then for tree call it as tree.Root.Search(0);
Related
To check the validity of a Binary Search Tree, I use a method. But the method always returns false, when tested against a valid Binary Search Tree.
Online Demo Here
The code
public class Program
{
public static void Main()
{
BinarySearchTree<int> tree = new BinarySearchTree<int>();
tree.Insert(2);
tree.Insert(1);
tree.Insert(3);
Console.WriteLine(tree.IsValidBinarySearchTreeRecursive(tree.root).ToString()); // this is supposed to return true when tested against the simple tree above
}
}
public class Node<T> where T : IComparable
{
public Node<T> left;
public Node<T> right;
public T data;
public Node(T data)
{
this.left = null;
this.right = null;
this.data = data;
}
}
public class BinarySearchTree<T> where T : IComparable
{
public Node<T> root;
public BinarySearchTree()
{
this.root = null;
}
public bool Insert(T data)
{
Node<T> before = null;
Node<T> after = this.root;
while(after != null)
{
before = after;
if(data.CompareTo(after.data) < 0)
after = after.left;
else if(data.CompareTo(after.data) > 0)
after = after.right;
else
return false;
}
Node<T> newNode = new Node<T>(data);
if (this.root == null)
{
this.root = newNode;
}
else
{
if(data.CompareTo(before.data) < 0)
before.left = newNode;
else
before.right = newNode;
}
return true;
}
private bool _HelperForIsValidBinarySearchTreeRecursive(Node<T> node, T lower, T upper)
{
if (node == null)
return true;
T val = node.data;
Type nodeType = typeof(T);
if(nodeType.IsNumeric())
{
if(val.CompareTo(lower) <= 0)
return false;
if(val.CompareTo(upper) >= 0)
return false;
}
else
{
if(lower != null && val.CompareTo(lower) <= 0)
return false;
if(upper != null && val.CompareTo(upper) >= 0)
return false;
}
if(!_HelperForIsValidBinarySearchTreeRecursive(node.right, val, upper))
return false;
if(!_HelperForIsValidBinarySearchTreeRecursive(node.left, lower, val))
return false;
return true;
}
public bool IsValidBinarySearchTreeRecursive(Node<T> root)
{
Type nodeType = typeof(T);
if(nodeType.IsNumeric())
return _HelperForIsValidBinarySearchTreeRecursive(root, root.data, root.data);
return _HelperForIsValidBinarySearchTreeRecursive(root, default(T), default(T));
}
}
public static class StaticUtilities
{
private static readonly HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int), typeof(double), typeof(decimal),
typeof(long), typeof(short), typeof(sbyte),
typeof(byte), typeof(ulong), typeof(ushort),
typeof(uint), typeof(float)
};
public static bool IsNumeric(this Type myType)
{
return NumericTypes.Contains(Nullable.GetUnderlyingType(myType) ?? myType);
}
}
Your problem is here:
if(val.CompareTo(lower) <= 0)
return false; // you are always hitting this line
if(val.CompareTo(upper) >= 0)
return false;
Because your T val = node.data; and your lower and even your upper are node.data from your first call.
So most probably the line to fix is
return _HelperForIsValidBinarySearchTreeRecursive(root, root.data, root.data);
as I guess your original intention was to compare the left and right with the root?
Based on this: https://www.geeksforgeeks.org/a-program-to-check-if-a-binary-tree-is-bst-or-not/
for your numeric approach, your solution should be:
/* false if this node violates the min/max constraints */
if (node.data < min || node.data > max)
{
return false;
}
So your code becomes:
if(val.CompareTo(lower) < 0)
return false; // you are always hitting this line
if(val.CompareTo(upper) > 0)
return false;
Then you will hit the next obstacle down the line. My suggestion for a solution, would be to change this:
private bool _HelperForIsValidBinarySearchTreeRecursive(Node<T> node, T lower, T upper)
To
private bool _HelperForIsValidBinarySearchTreeRecursive(Node<T> node, Node<T> leftNode<T> right)
and call like this:
_HelperForIsValidBinarySearchTreeRecursive(root, root.Left, root.Right)
My C# Solution
public bool IsBST()
{
return CheckBST(Root, default(T), default(T));
}
private bool CheckBST(TreeNode<T> root, T Min, T Max)
{
if (root == null)
{
return true;
}
if (!(root.Value.CompareTo(Min) <= 0 || root.Value.CompareTo(Max) >= 1))
{
return false;
}
return CheckBST(root.Left, Min, root.Value) && CheckBST(root.Right, root.Value, Max);
}
Ive starting learning C# with a background of c/c++. I am creating a simple BST but my insert function wont work. Any help would greatly be appreciated.
I get this kind of error when not passing by reference in c/c++. Since I created a two classes Node and BST, shouldn't they be passed by reference? Ive worked on this problem for a couple of hours and tried to change my code but with no luck.
public Node(int data)
{
this.data = data;
this.right = null;
this.left = null;
}
public Node Left
{
get { return left; }
set { left = value; }
}
public Node Right
{
get { return right; }
set { right = value; }
}
public int Data
{
get { return data; }
set { data = value; }
}
}
class BST
{
private Node root;
public BST()
{
root = null;
}
public Node Root
{
get { return root; }
set { root = value; }
}
public void Insert(int data)
{
if (root == null)
{
root = new Node(data);
}
else
{
InsertHelper(root, data);
}
}
public void InsertHelper( Node root, int data)
{
if (root == null)
{
root = new Node(data);
//return root;
}
if (root.Data > data)
{
InsertHelper(root.Left, data);
}
if (root.Data < data)
{
InsertHelper(root.Right, data);
}
}
You are assigning a new node to the argument pointer instead of original one. Insert should be:
public void Insert(int data)
{
if (root == null)
{
root = new Node(data);
}
else
{
root = InsertHelper(root, data);
}
}
and InsertHelper should be:
public Node InsertHelper( Node root, int data)
{
if (root == null)
return new Node(data);
if (root.Data > data)
{
root.Left = InsertHelper(root.Left, data);
}
if (root.Data < data)
{
root.Right = InsertHelper(root.Right, data);
}
return root;
}
In fact you don't even need Insert since InsertHelper already deals with root being null
Main method for testing:
public static void Main()
{
BST bst = new BST();
bst.Insert(5);
bst.Insert(6);
bst.Insert(4);
bst.Insert(7);
bst.Insert(3);
Console.WriteLine(bst.Root.Data + " ");
Console.WriteLine(bst.Root.Left.Data + " ");
Console.WriteLine(bst.Root.Right.Data + " ");
Console.WriteLine(bst.Root.Left.Left.Data + " ");
Console.WriteLine(bst.Root.Right.Right.Data + " ");
}
I have these two functions, used to search for a folder within a hierarchy:
public Folder<T> Find (string Path)
{
Folder<T> Result = null;
if (this.Path != Path &&
ChildrenDict != null)
{
foreach (KeyValuePair<long, Folder<T>> Child in ChildrenDict)
{
Result = Child.Value.Find (Path);
}
}
else
{
Result = this;
}
return Result;
}
public Folder<T> Find (long ID)
{
Folder<T> Result = null;
if (this.ID != ID &&
ChildrenDict != null)
{
foreach (KeyValuePair<long, Folder<T>> Child in ChildrenDict)
{
Result = Child.Value.Find (ID);
}
}
else
{
Result = this;
}
return Result;
}
As you can see, they are very similar to one another. How can I re-structure them so I don't have essentially the same code several times, one per each property I might want to use to find them?
Create a method with a condition parameter which does the logic:
protected Folder<T> Find(Func<Folder<T>, bool> condition) {
Folder<T> Result = null;
if(!condition(this) && ChildrenDict != null) {
foreach(var Child in ChildrenDict) {
Result = Child.Value.Find(condition);
}
} else {
Result = this;
}
return Result;
}
Rewrite your public Find methods as:
public Folder<T> Find(string path) {
return Find(f => f.Path == path);
}
First off, this is a school assignment, so there. I wouldn't be posting if it weren't for the fact that I'm really hurting for help.
Now we have this binary search tree we are supposed to implement. Basically, this class below is complete, I am given to understand.
public class BinarySearchTree<T> where T : IComparable<T>
{
BinarySearchTreeNode<T> _root;
public BinarySearchTreeNode<T> Root
{
get { return _root; }
}
public BinarySearchTree()
{
}
public BinarySearchTree(BinarySearchTreeNode<T> root)
{
_root = root;
}
public void Insert(T value)
{
if (_root != null)
_root.Insert(value);
else
_root = new BinarySearchTreeNode<T>(value);
}
public void Remove(T value)
{
if (_root == null)
return;
if (_root.LeftChild != null || _root.RightChild != null)
{
_root.Remove(value);
}
else if (_root.Value.CompareTo(value) == 0)
{
_root = null;
}
}
public bool Find(T value)
{
if (_root != null)
return _root.Find(value);
else
return false;
}
}
And here the class I am supposed to implement, or at least as far as I have gotten.
public class BinarySearchTreeNode<T> where T : IComparable<T>
{
private T _value;
public T Value
{
get { return _value; }
}
public BinarySearchTreeNode<T> LeftChild
{
get { return _leftChild; }
set { _leftChild = value; }
}
private BinarySearchTreeNode<T> _leftChild, _parent, _rightChild;
public BinarySearchTreeNode<T> RightChild
{
get { return _rightChild; }
set { _rightChild = value; }
}
public BinarySearchTreeNode<T> Parent
{
get { return _parent; }
set { _parent = value; }
}
public BinarySearchTreeNode(T value)
{
_value = value;
Parent = this;
}
public void Insert(T value)
{
if (value.CompareTo(Parent.Value) < 0)
{
if (LeftChild != null)
{
LeftChild.Insert(value);
}
else
{
LeftChild = new BinarySearchTreeNode<T>(value);
LeftChild.Parent = this;
}
}
else if (Value.CompareTo(Parent.Value) >= 0)
{
if (RightChild != null)
RightChild.Insert(value);
else{
RightChild = new BinarySearchTreeNode<T>(value);
Righthild.Parent = this;
}
}
}
public void Remove(T value)
{
if (LeftChild != null)
if (value.CompareTo(Parent.Value) < 0)
LeftChild.Remove(value);
else if (RightChild != null)
if (value.CompareTo(Parent.Value) >= 0)
RightChild.Remove(value);
}
public bool Find(T value)
{
if (value.Equals(Parent.Value))
return true;
else if (value.CompareTo(Parent.Value) < 0)
{
if (LeftChild != null)
return LeftChild.Find(value);
}
else if (value.CompareTo(Parent.Value) > 0)
{
if (RightChild != null)
return RightChild.Find(value);
}
return false;
}
}
The issue is that I can't quite seem to get my head around just how I am supposed to properly implement remove, so that I can remove a node simply by pointing towards the parents, for instance. Any help or hints is appreciated.
Edit(!)
So I got almost everything in order, baring one thing which is case 2 for the remove method.
//Case 2: If node has only one child, copy the value of the child to your node, and assign LeftChild or RightChild to null (as is the case)
if (RightChild != null && LeftChild == null)
{
if (value.CompareTo(this.Parent._value) > 0)
{
Parent.RightChild = RightChild;
RightChild = null;
}
}
if (RightChild == null && LeftChild != null)
{
if (value.CompareTo(Parent._value) < 0)
{
Parent.LeftChild = LeftChild;
LeftChild = null;
}
}
Basically, I am completely unable to replace the original node. If I have have
4 - 3 - 2 ( preorder ) and I want to remove 3 then I can do that and get 4 - 2.
However, if I want to remove 4 , it won't do anything, though it only got one child. I am think thats because it doesn't have a parent, but I am unsure of how to get around that. Any ideas?
Binary Search Tree
There are three possible cases to consider:
Deleting a leaf (node with no children): Deleting a leaf is easy, as we can simply remove it from the tree.
Deleting a node with one child: Remove the node and replace it with its child.
Deleting a node with two children: Call the node to be deleted N. Do not delete N. Instead, choose either its in-order successor node or its in-order predecessor node, R. Replace the value of N with the value of R, then delete R.
Add one more condition to your remove method whose pseudo-code is:
if (value.CompareTo(Parent.Value) == 0){
//Case 1: If node has no children, then make Parent = null
// Case 2: If node has only one child, copy the value of the child to your node, and assign LeftChild or RightChild to null (as is the case)
//Case 3: Find the in-order successor, copy its value to the current node and delete the in-order successor.
}
Hi I don't understand why this code doesn't work - it don't remove key; I still get "2" on output.
Bencode.BencodeDict d = new myTorrent.Bencode.BencodeDict();
d.Dict.Add(new Bencode.BencodeString("info"), new Bencode.BencodeString("1"));
d.Dict.Add(new Bencode.BencodeString("info2"), new Bencode.BencodeString("2"));
d.Dict.Add(new Bencode.BencodeString("info3"), new Bencode.BencodeString("3"));
d.Remove(new Bencode.BencodeString("info2"));
Bencode.BencodeVariable s1;
s1 = d[new Bencode.BencodeString("info2")];
if (s1 != null)
Console.WriteLine(System.Text.UTF8Encoding.UTF8.GetString(s1.Encode()));
My BencodeDict and BencodeString
namespace myTorrent.Bencode
{
class BencodeDict : BencodeVariable, IDictionary<BencodeString, BencodeVariable>
{
private Dictionary<BencodeString, BencodeVariable> dict;
public BencodeDict() {
this.dict = new Dictionary<BencodeString,BencodeVariable>();
}
protected override void InternalDecode(BinaryReader data) { /*...*/ }
public override long ByteLength() { /*...*/ }
public override byte[] Encode() { /*...*/ }
//#region Overridden Methods
public override bool Equals(object ob)
{
if (ob == null)
return false;
BencodeDict y = ob as BencodeDict;
if (this.dict.Count != y.dict.Count)
return false;
BencodeVariable val;
foreach (KeyValuePair<BencodeString, BencodeVariable> keypair in this.dict)
{
if (!y.TryGetValue(keypair.Key, out val))
return false;
if (!keypair.Value.Equals(val))
return false;
}
return true;
}
public override int GetHashCode()
{
int result = 0;
foreach (KeyValuePair<BencodeString, BencodeVariable> keypair in this.dict)
{
result ^= keypair.Key.GetHashCode();
result ^= keypair.Value.GetHashCode();
}
return result;
}
#region IDictionary and IList methods
public void Add(BencodeString key, BencodeVariable value)
{
this.dict.Add(key, value);
}
public void Add(KeyValuePair<BencodeString, BencodeVariable> item)
{
this.dict.Add(item.Key, item.Value);
}
public void Clear()
{
this.dict.Clear();
}
public bool Contains(KeyValuePair<BencodeString, BencodeVariable> item)
{
if (!this.dict.ContainsKey(item.Key))
return false;
return this.dict[item.Key].Equals(item.Value);
}
public bool ContainsKey(BencodeString key)
{
foreach(KeyValuePair<BencodeString, BencodeVariable> pair in this.dict) {
if (pair.Key.Equals(key))
return true;
}
return false;
}
public void CopyTo(KeyValuePair<BencodeString, BencodeVariable>[] array, int arrayIndex) { /*...*/ }
public int Count
{
get { return this.dict.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(BencodeString key)
{
return this.dict.Remove(key);
}
public bool Remove(KeyValuePair<BencodeString, BencodeVariable> item)
{
return this.dict.Remove(item.Key);
}
public bool TryGetValue(BencodeString key, out BencodeVariable value)
{
foreach(KeyValuePair<BencodeString, BencodeVariable> pair in this.dict)
if ( pair.Key.Equals(key) ) {
value = pair.Value;
return true;
}
value = null;
return false;
}
public BencodeVariable this[BencodeString key]
{
get {
foreach(KeyValuePair<BencodeString, BencodeVariable> pair in this.dict)
if ( pair.Key.Equals(key) )
return pair.Value;
return null;
}
set { this.dict[key] = value; }
}
public ICollection<BencodeString> Keys
{
get { return this.dict.Keys; }
}
public ICollection<BencodeVariable> Values
{
get { return this.dict.Values; }
}
public IEnumerator<KeyValuePair<BencodeString, BencodeVariable>> GetEnumerator()
{
return this.dict.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.dict.GetEnumerator();
}
#endregion
}
}
class BencodeString : BencodeVariable
{
private byte[] str;
public BencodeString() {
this.str = null;
}
public BencodeString(string str) {
this.str = encoding.GetBytes(str);
}
public override bool Equals(object ob)
{
if (ob == null)
return false;
BencodeString y = ob as BencodeString;
return (encoding.GetString(this.str) == encoding.GetString(y.str));
}
public override int GetHashCode()
{
return this.str.GetHashCode();
}
}
You're relying on byte[].GetHashCode() doing something desirable. It won't. Arrays don't implement equality or hash operations - you'll get the default (identity) behaviour.
Rewrite your GetHashCode method as something like this:
public override int GetHashCode()
{
int result = 17;
foreach (byte b in str)
{
result = result * 31 + b;
}
return result;
}
(Also it's not clear what encoding is, but that's a different matter.)
Note that your Equals override will also throw a NullReferenceException if ob is a non-null reference, but not to a BencodeString.
EDIT: Assuming you're actually wanting to check for the byte arrays being the same, I wouldn't call Encoding.GetString in your equality check. There's no point. Just check the byte array contents directly. Something like this is a reasonable byte array equality check - although I'd generally prefer to write a generic equivalent:
private static bool ArraysEqual(byte[] x, byte[] y)
{
if (x == y)
{
return true;
}
if (x == null || y == null)
{
return false;
}
if (x.Length != y.Length)
{
return false;
}
for (int i = 0; i < x.Length; i++)
{
if (x[i] != y[i])
{
return false;
}
}
return true;
}
If you do want to check whether two byte arrays are decoded to equal strings, then you should use Encoding.GetString in both places... but that would rarely be an appropriate thing to do, IMO.
Mind you, it's not clear why you've got your own string-like class to start with. There are all kinds of potential problems here... unequal encodings, null references etc.
It is very important that values that are Equal also produce the same hash code. An obvious (but not necessarily efficient) workaround is this:
public override int GetHashCode()
{
return encoding.GetString(this.str).GetHashCode();
}
Making strings not behave as Unicode strings internally is a a code smell but possibly intentional here. It is normally applied at the outer interface. Your implementation would allow for the encoding to change after the string is read. But a really serious problem with that is that the dictionary is no longer valid when that happens. You won't be able to find keys back.