I have this binary search tree with Node class and I need to write mapping and filtering method for it but I have no clue how can I go through the whole tree. My every attempt to go through it skipped almost half of the tree.
public class BST<T> where T:IComparable<T>
{
public class Node
{
public T value { get; }
public Node left;
public Node right;
public Node(T element)
{
this.value = element;
left = null;
right = null;
}
}
private Node root;
private void add(T element)
{
if (root == null)
root = new Node(element);
else
{
add(element, root);
}
}
public void add(T element, Node leaf)
{
if(element.CompareTo(leaf.value) > 0)
{
if (leaf.right == null)
leaf.right = new Node(element);
else
add(element,leaf.right);
}
else
{
if (leaf.left == null)
leaf.left = new Node(element);
else
add(element, leaf.left);
}
}
}
I have no clue how can I go through the whole tree
There are many ways to do that. One is to make your class iterable.
For that you can define the following method on your Node class:
public IEnumerator<T> GetEnumerator()
{
if (left != null) {
foreach (var node in left) {
yield return node;
}
}
yield return value;
if (right != null) {
foreach (var node in right) {
yield return node;
}
}
}
And delegate to it from a similar method on your BST class:
public IEnumerator<T> GetEnumerator()
{
if (root != null) {
foreach (var node in root) {
yield return node;
}
}
}
Now you can write code like this:
var tree = new BST<int>();
tree.add(4);
tree.add(2);
tree.add(3);
tree.add(6);
tree.add(5);
foreach (var value in tree) {
Console.WriteLine(value);
}
I need to write mapping and filtering method for it
It depends on what you want the result of a mapping/filtering function to be. If it is just a sequence of values, the above should be simple to adapt. If a new tree should be created with the mapped/filtered values, then feed these values back into a new tree (calling its add), or (in case of mapping) use the same recursive pattern of the above methods to create a new method that does not do yield, but creates a new tree while iterating the existing nodes, so the new tree has the same shape, but with mapped values.
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);
Suppose there is a LinkedList, type of its nodes that are bound to numeric up/down toolboxs, is integer. Each node value should be between values of the next and previous nodes.
class node {
private _v;
public v {
get {return _v};
set {
if (value != _v &&
value > previousnode.v &&
value < nextnode.v){
_v = value;
OnPropertyChanged(nameof(node));
}
}
}
}
LinkedList<node> LL;
Please guide me how to access previousenode.v and nextnode.v from inside node class. (No WPF solution!)
You can use the LinkedList.Find method to get the LinkedListNode containing your node object and then get the previous and next node objects:
class node {
private int _v;
public int v
{
get { return _v; }
set {
var lln = LL.Find(this);
var previousnode = lln.Previous.Value;
var nextnode = lln.Next.Value;
if (value != _v &&
value > previousnode.v &&
value < nextnode.v) {
_v = value;
OnPropertyChanged(nameof(node));
}
}
}
}
I am learning data structures, lately I've been trying to create a BST. Here is the code for that:
class Program
{
static void Main(string[] args)
{
BST tree = new BST();
tree.Insert(3);
tree.Insert(6);
tree.Insert(12);
tree.Insert(2);
tree.Insert(8);
tree.InOrder(tree.root);
// output: 2 3 6 8 12
tree.Delete(12);
tree.InOrder(tree.root);
// output: 2 3 6
}
}
class Node
{
public Node lc;
public int value;
public Node rc;
}
class BST
{
public Node root;
public BST()
{
root = null;
}
public void Insert(int value)
{
Node temp = new Node();
temp.value = value;
if (root == null)
{
root = temp;
}
else
{
Node parent = null;
Node current = root;
while (current != null)
{
parent = current;
if (value <= current.value)
{
current = current.lc;
}
else
{
current = current.rc;
}
}
if (value <= parent.value)
{
parent.lc = temp;
}
else
{
parent.rc = temp;
}
}
}
public void Delete(int value)
{
Node current = root;
Node parent = null;
while (current != null)
{
parent = current;
if (value <= current.value)
{
current = current.lc;
if (current.value == value)
{
parent.lc = null;
break;
}
}
else
{
current = current.rc;
if (value == current.value)
{
parent.rc = null;
break;
}
}
}
}
public void InOrder(Node root)
{
if (root != null)
{
InOrder(root.lc);
Console.WriteLine(root.value);
InOrder(root.rc);
}
}
}
However, I am encountering an issue with deleting the Node identified, as of now I am writing the code for deleting a node which doesn't have any children.
For some reason when I try to delete the Node with which holds the value 12, the Node with the value 8 gets deleted too....I tried to dry run, but still can't understand why I am loosing connection with that other Node which holds 8.
All right, so it turned out as Sasha pointed, I was drawing the tree incorrectly and was loosing the connection to the Node that holds the value of 8 because it was connected to the left of the Node that was deleted.
I know that SortedDictionary is a binary search tree (and it can almost do what I need to do!) but I can't figure out how to do everything I need in the correct complexity.
So here are the constraints (and the data structure which I know has it)
Inserting and Deletion in O(log n) (SortedDictionary)
Search in O(log n) (SortedDictionary & SortedList)
Iteration from one searched element to another in O(log n) + O(m) (where m is the number of elements in between) (SortedList)
As you can see, I don't know how to get SortedDictionary to do number 3. Basically what I need to do is get all the elements with a range without iterating the set.
Please tell me if my question isn't clear.
This seems to describe a B+ tree perfectly: http://en.wikipedia.org/wiki/B%2B_tree :
Inserting a record requires O(log(n)) operations in the worst case
Finding a record requires O(log(n)) operations in the worst case
Performing a range query with k elements occurring within the range requires O(log(n) + k) operations in the worst case.
A C# implementation seems to exist here: http://bplusdotnet.sourceforge.net/
I don't think there is a collection in the framework that does what you describe, although I could be wrong.
What you are looking for is a linked list that is indexed with a binary tree. This would provide you O(log n) insertion, deletion and search using the binary tree, with O(m) traversal using the linked list.
You might want to have a look at the C5 Generic Collections Library. Although there doesn't appear to be a collection that fits your description there, you might be able to marry together their TreeSet<T> and LinkedList<T> objects, creating a new SortedLinkedList<T> object.
Some of the suggestions were pretty good, but I decided to implement the collection myself (it sounded fun). I started with the .NET implementation of SortedDictionary, and heavily modified it to do what I needed it to do
Just so other people can benefit from my work, here is the class:
internal delegate void TreeWalkAction<Key, Value>(BinaryTreeSearch<Key, Value>.Node node);
internal delegate bool TreeWalkTerminationPredicate<Key, Value>(BinaryTreeSearch<Key, Value>.Node node);
internal class BinaryTreeSearch<Key, Value>
{
// Fields
private IComparer<Key> comparer;
private int count;
private Node root;
private int version;
// Methods
public BinaryTreeSearch(IComparer<Key> comparer)
{
if (comparer == null)
{
this.comparer = Comparer<Key>.Default;
}
else
{
this.comparer = comparer;
}
}
private Node First
{
get
{
if (root == null) return null;
Node n = root;
while (n.Left != null)
{
n = n.Left;
}
return n;
}
}
public Key Min
{
get
{
Node first = First;
return first == null ? default(Key) : first.Key;
}
}
public Key Max
{
get
{
if (root == null) return default(Key);
Node n = root;
while (n.Right != null)
{
n = n.Right;
}
return n.Key;
}
}
public List<Value> this[Key key]
{
get
{
Node n = FindNode(key);
return n == null ? new List<Value>() : n.Values;
}
}
public List<Value> GetRange(Key start, Key end)
{
Node node = FindNextNode(start);
List<Value> ret = new List<Value>();
InOrderTreeWalk(node,
aNode => ret.AddRange(aNode.Values),
aNode => comparer.Compare(end, aNode.Key) < 0);
return ret;
}
public void Add(Key key, Value value)
{
if (this.root == null)
{
this.root = new Node(null, key, value, false);
this.count = 1;
}
else
{
Node root = this.root;
Node node = null;
Node grandParent = null;
Node greatGrandParent = null;
int num = 0;
while (root != null)
{
num = this.comparer.Compare(key, root.Key);
if (num == 0)
{
root.Values.Add(value);
count++;
return;
}
if (Is4Node(root))
{
Split4Node(root);
if (IsRed(node))
{
this.InsertionBalance(root, ref node, grandParent, greatGrandParent);
}
}
greatGrandParent = grandParent;
grandParent = node;
node = root;
root = (num < 0) ? root.Left : root.Right;
}
Node current = new Node(node, key, value);
if (num > 0)
{
node.Right = current;
}
else
{
node.Left = current;
}
if (node.IsRed)
{
this.InsertionBalance(current, ref node, grandParent, greatGrandParent);
}
this.root.IsRed = false;
this.count++;
this.version++;
}
}
public void Clear()
{
this.root = null;
this.count = 0;
this.version++;
}
public bool Contains(Key key)
{
return (this.FindNode(key) != null);
}
internal Node FindNode(Key item)
{
int num;
for (Node node = this.root; node != null; node = (num < 0) ? node.Left : node.Right)
{
num = this.comparer.Compare(item, node.Key);
if (num == 0)
{
return node;
}
}
return null;
}
internal Node FindNextNode(Key key)
{
int num;
Node node = root;
while (true)
{
num = comparer.Compare(key, node.Key);
if (num == 0)
{
return node;
}
else if (num < 0)
{
if (node.Left == null) return node;
node = node.Left;
}
else
{
node = node.Right;
}
}
}
private static Node GetSibling(Node node, Node parent)
{
if (parent.Left == node)
{
return parent.Right;
}
return parent.Left;
}
internal void InOrderTreeWalk(Node start, TreeWalkAction<Key, Value> action, TreeWalkTerminationPredicate<Key, Value> terminationPredicate)
{
Node node = start;
while (node != null && !terminationPredicate(node))
{
action(node);
node = node.Next;
}
}
private void InsertionBalance(Node current, ref Node parent, Node grandParent, Node greatGrandParent)
{
Node node;
bool flag = grandParent.Right == parent;
bool flag2 = parent.Right == current;
if (flag == flag2)
{
node = flag2 ? RotateLeft(grandParent) : RotateRight(grandParent);
}
else
{
node = flag2 ? RotateLeftRight(grandParent) : RotateRightLeft(grandParent);
parent = greatGrandParent;
}
grandParent.IsRed = true;
node.IsRed = false;
this.ReplaceChildOfNodeOrRoot(greatGrandParent, grandParent, node);
}
private static bool Is2Node(Node node)
{
return ((IsBlack(node) && IsNullOrBlack(node.Left)) && IsNullOrBlack(node.Right));
}
private static bool Is4Node(Node node)
{
return (IsRed(node.Left) && IsRed(node.Right));
}
private static bool IsBlack(Node node)
{
return ((node != null) && !node.IsRed);
}
private static bool IsNullOrBlack(Node node)
{
if (node != null)
{
return !node.IsRed;
}
return true;
}
private static bool IsRed(Node node)
{
return ((node != null) && node.IsRed);
}
private static void Merge2Nodes(Node parent, Node child1, Node child2)
{
parent.IsRed = false;
child1.IsRed = true;
child2.IsRed = true;
}
public bool Remove(Key key, Value value)
{
if (this.root == null)
{
return false;
}
Node root = this.root;
Node parent = null;
Node node3 = null;
Node match = null;
Node parentOfMatch = null;
bool flag = false;
while (root != null)
{
if (Is2Node(root))
{
if (parent == null)
{
root.IsRed = true;
}
else
{
Node sibling = GetSibling(root, parent);
if (sibling.IsRed)
{
if (parent.Right == sibling)
{
RotateLeft(parent);
}
else
{
RotateRight(parent);
}
parent.IsRed = true;
sibling.IsRed = false;
this.ReplaceChildOfNodeOrRoot(node3, parent, sibling);
node3 = sibling;
if (parent == match)
{
parentOfMatch = sibling;
}
sibling = (parent.Left == root) ? parent.Right : parent.Left;
}
if (Is2Node(sibling))
{
Merge2Nodes(parent, root, sibling);
}
else
{
TreeRotation rotation = RotationNeeded(parent, root, sibling);
Node newChild = null;
switch (rotation)
{
case TreeRotation.LeftRotation:
sibling.Right.IsRed = false;
newChild = RotateLeft(parent);
break;
case TreeRotation.RightRotation:
sibling.Left.IsRed = false;
newChild = RotateRight(parent);
break;
case TreeRotation.RightLeftRotation:
newChild = RotateRightLeft(parent);
break;
case TreeRotation.LeftRightRotation:
newChild = RotateLeftRight(parent);
break;
}
newChild.IsRed = parent.IsRed;
parent.IsRed = false;
root.IsRed = true;
this.ReplaceChildOfNodeOrRoot(node3, parent, newChild);
if (parent == match)
{
parentOfMatch = newChild;
}
node3 = newChild;
}
}
}
int num = flag ? -1 : this.comparer.Compare(key, root.Key);
if (num == 0)
{
flag = true;
match = root;
parentOfMatch = parent;
}
node3 = parent;
parent = root;
if (num < 0)
{
root = root.Left;
}
else
{
root = root.Right;
}
}
if (match != null)
{
if (match.Values.Remove(value))
{
this.count--;
}
if (match.Values.Count == 0)
{
this.ReplaceNode(match, parentOfMatch, parent, node3);
}
}
if (this.root != null)
{
this.root.IsRed = false;
}
this.version++;
return flag;
}
private void ReplaceChildOfNodeOrRoot(Node parent, Node child, Node newChild)
{
if (parent != null)
{
if (parent.Left == child)
{
parent.Left = newChild;
}
else
{
parent.Right = newChild;
}
if (newChild != null) newChild.Parent = parent;
}
else
{
this.root = newChild;
}
}
private void ReplaceNode(Node match, Node parentOfMatch, Node succesor, Node parentOfSuccesor)
{
if (succesor == match)
{
succesor = match.Left;
}
else
{
if (succesor.Right != null)
{
succesor.Right.IsRed = false;
}
if (parentOfSuccesor != match)
{
parentOfSuccesor.Left = succesor.Right; if (succesor.Right != null) succesor.Right.Parent = parentOfSuccesor;
succesor.Right = match.Right; if (match.Right != null) match.Right.Parent = succesor;
}
succesor.Left = match.Left; if (match.Left != null) match.Left.Parent = succesor;
}
if (succesor != null)
{
succesor.IsRed = match.IsRed;
}
this.ReplaceChildOfNodeOrRoot(parentOfMatch, match, succesor);
}
private static Node RotateLeft(Node node)
{
Node right = node.Right;
node.Right = right.Left; if (right.Left != null) right.Left.Parent = node;
right.Left = node; if (node != null) node.Parent = right;
return right;
}
private static Node RotateLeftRight(Node node)
{
Node left = node.Left;
Node right = left.Right;
node.Left = right.Right; if (right.Right != null) right.Right.Parent = node;
right.Right = node; if (node != null) node.Parent = right;
left.Right = right.Left; if (right.Left != null) right.Left.Parent = left;
right.Left = left; if (left != null) left.Parent = right;
return right;
}
private static Node RotateRight(Node node)
{
Node left = node.Left;
node.Left = left.Right; if (left.Right != null) left.Right.Parent = node;
left.Right = node; if (node != null) node.Parent = left;
return left;
}
private static Node RotateRightLeft(Node node)
{
Node right = node.Right;
Node left = right.Left;
node.Right = left.Left; if (left.Left != null) left.Left.Parent = node;
left.Left = node; if (node != null) node.Parent = left;
right.Left = left.Right; if (left.Right != null) left.Right.Parent = right;
left.Right = right; if (right != null) right.Parent = left;
return left;
}
private static TreeRotation RotationNeeded(Node parent, Node current, Node sibling)
{
if (IsRed(sibling.Left))
{
if (parent.Left == current)
{
return TreeRotation.RightLeftRotation;
}
return TreeRotation.RightRotation;
}
if (parent.Left == current)
{
return TreeRotation.LeftRotation;
}
return TreeRotation.LeftRightRotation;
}
private static void Split4Node(Node node)
{
node.IsRed = true;
node.Left.IsRed = false;
node.Right.IsRed = false;
}
// Properties
public IComparer<Key> Comparer
{
get
{
return this.comparer;
}
}
public int Count
{
get
{
return this.count;
}
}
internal class Node
{
// Fields
private bool isRed;
private Node left, right, parent;
private Key key;
private List<Value> values;
// Methods
public Node(Node parent, Key item, Value value) : this(parent, item, value, true)
{
}
public Node(Node parent, Key key, Value value, bool isRed)
{
this.key = key;
this.parent = parent;
this.values = new List<Value>(new Value[] { value });
this.isRed = isRed;
}
// Properties
public bool IsRed
{
get
{
return this.isRed;
}
set
{
this.isRed = value;
}
}
public Key Key
{
get
{
return this.key;
}
set
{
this.key = value;
}
}
public List<Value> Values { get { return values; } }
public Node Left
{
get
{
return this.left;
}
set
{
this.left = value;
}
}
public Node Right
{
get
{
return this.right;
}
set
{
this.right = value;
}
}
public Node Parent
{
get
{
return this.parent;
}
set
{
this.parent = value;
}
}
public Node Next
{
get
{
if (right == null)
{
if (parent == null)
{
return null; // this puppy must be lonely
}
else if (parent.Left == this) // this is a left child
{
return parent;
}
else
{
//this is a right child, we need to go up the tree
//until we find a left child. Then the parent will be the next
Node n = this;
do
{
n = n.parent;
if (n.parent == null)
{
return null; // this must have been a node along the right edge of the tree
}
} while (n.parent.right == n);
return n.parent;
}
}
else // there is a right child.
{
Node go = right;
while (go.left != null)
{
go = go.left;
}
return go;
}
}
}
public override string ToString()
{
return key.ToString() + " - [" + string.Join(", ", new List<string>(values.Select<Value, string>(o => o.ToString())).ToArray()) + "]";
}
}
internal enum TreeRotation
{
LeftRightRotation = 4,
LeftRotation = 1,
RightLeftRotation = 3,
RightRotation = 2
}
}
and a quick unit test (which doesn't actually cover all the code, so there might still be some bugs):
[TestFixture]
public class BTSTest
{
private class iC : IComparer<int>{public int Compare(int x, int y){return x.CompareTo(y);}}
[Test]
public void Test()
{
BinaryTreeSearch<int, int> bts = new BinaryTreeSearch<int, int>(new iC());
bts.Add(5, 1);
bts.Add(5, 2);
bts.Add(6, 2);
bts.Add(2, 3);
bts.Add(8, 2);
bts.Add(10, 11);
bts.Add(9, 4);
bts.Add(3, 32);
bts.Add(12, 32);
bts.Add(8, 32);
bts.Add(9, 32);
Assert.AreEqual(11, bts.Count);
Assert.AreEqual(2, bts.Min);
Assert.AreEqual(12, bts.Max);
List<int> val = bts[5];
Assert.AreEqual(2, val.Count);
Assert.IsTrue(val.Contains(1));
Assert.IsTrue(val.Contains(2));
val = bts[6];
Assert.AreEqual(1, val.Count);
Assert.IsTrue(val.Contains(2));
Assert.IsTrue(bts.Contains(5));
Assert.IsFalse(bts.Contains(-1));
val = bts.GetRange(5, 8);
Assert.AreEqual(5, val.Count);
Assert.IsTrue(val.Contains(1));
Assert.IsTrue(val.Contains(32));
Assert.AreEqual(3, val.Count<int>(num => num == 2));
bts.Remove(8, 32);
bts.Remove(5, 2);
Assert.AreEqual(9, bts.Count);
val = bts.GetRange(5, 8);
Assert.AreEqual(3, val.Count);
Assert.IsTrue(val.Contains(1));
Assert.AreEqual(2, val.Count<int>(num => num == 2));
bts.Remove(2, 3);
Assert.IsNull(bts.FindNode(2));
bts.Remove(12, 32);
Assert.IsNull(bts.FindNode(12));
Assert.AreEqual(3, bts.Min);
Assert.AreEqual(10, bts.Max);
bts.Remove(9, 4);
bts.Remove(5, 1);
bts.Remove(6, 2);
}
}
Check out System.Collections.ObjectModel.KeyedCollection<TKey, TItem> - it might not suit your requirements but it seems like a good fit, as it provides an internal lookup dictionary that enables O(1) retrieval of items by index and approaching O(1) by key.
The caveat is that it is intended to store objects where the key is defined as a property on the object, so unless you can mash your input data to fit, it won't be appropriate.
I would include some more information on what data you are intending to store and the volume, as this might help provide alternatives.