I've written a binary-tree using .NET Core 3.0
. What can I do to improve my coding style?
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace BinaryTree
{
/// <summary>
/// Represents a binary tree <seealso href="https://en.wikipedia.org/wiki/Binary_tree"/>.
/// </summary>
/// <typeparam name="T">The type which this tree should contain.</typeparam>
[Serializable]
[DataContract]
public class BinaryTree<T> where T : IComparable, new()
{
#if DEBUG
/// <summary>
/// Determines whether or not to log actions in the console.
/// </summary>
public static bool Log = true;
#endif
[DataMember]
private Node<T> _parentNode;
public BinaryTree()
{
#if DEBUG
if (Log)
Console.WriteLine("Initializing binary-tree..");
#endif
_parentNode = new Node<T>();
}
/// <summary>
/// Adds the specific item inside the binary-tree using binary-tree logic.
/// </summary>
/// <param name="item">The item that will be added.</param>
public void Add(T item)
{
#if DEBUG
if (Log)
Console.WriteLine("Initializing binary-tree..");
#endif
_parentNode.Add(item);
}
/// <summary>
/// Removes the specific item inside the binary-tree using binary-tree logic. The root node cannot be removed.
/// </summary>
/// <param name="item">The item that will be removed.</param>
public void Remove(T item)
{
_parentNode.Remove(item);
}
/// <summary>
/// Searches for a specific item inside this binary-tree using binary-tree logic.
/// </summary>
/// <param name="item"></param>
/// <returns>Returns the count of said item if existing - 0 if otherwise.</returns>
public int Contains(T item)
{
return _parentNode.Contains(item);
}
/// <summary>
/// Clears everything out of this binary-tree.
/// </summary>
public void Clear()
{
_parentNode = new Node<T>();
}
public override bool Equals(object obj)
{
return obj is BinaryTree<T> tree && tree._parentNode.Equals(_parentNode);
}
public void Serialize(string file)
{
using (var writer = new StreamWriter(file))
{
var bf = new BinaryFormatter();
bf.Serialize(writer.BaseStream, this);
}
}
public static BinaryTree<T> Deserialize(string file)
{
using (var reader = new StreamReader(file))
{
var bf = new BinaryFormatter();
return (BinaryTree<T>)bf.Deserialize(reader.BaseStream);
}
}
/// <summary>
/// Represents a node of a binary-tree. This may be either a simple node, a parent, or a leaf.
/// </summary>
/// <typeparam name="T">The type which this node should contain.</typeparam>
[Serializable]
[DataContract]
private class Node<T> where T : IComparable, new()
{
/// <summary>
/// Right "lower" arm of current node - this is where everything bigger than this node is getting redirect towards.
/// </summary>
[DataMember]
private Node<T> _bigger;
/// <summary>
/// Saved data and count of data - inside this specific node.
/// </summary>
[DataMember]
private (T data, int count) _item;
/// <summary>
/// Root node, if existing.
/// </summary>
[DataMember]
private Node<T> _parent;
/// <summary>
/// Left "lower" arm of current node - this is where everything smaller than this node is getting redirect towards.
/// </summary>
[DataMember]
private Node<T> _smaller;
private Node(T item)
{
_item = (item, 1);
}
public Node()
{
}
public override bool Equals(object obj)
{
return obj is Node<T> node &&
(node._bigger?.Equals(_bigger) ?? _bigger == null) &&
(node._item.data?.Equals(_item.data) ?? _item.data == null) &&
(node._item.count.Equals(_item.count)) &&
(node._parent?.Equals(_parent) ?? _parent==null) &&
(node._smaller?.Equals(_smaller) ?? _smaller == null);
}
private void Set(T data)
{
if (_item.data.Equals(default(T)))
{
_item = (data, 1);
return;
}
if (data.Equals(_item.data))
_item.count++;
else
Add(data);
}
public void Remove(T data)
{
if (data.Equals(_item.data))
{
if (_item.count > 1)
{
_item.count--;
}
else
{
if (_parent == null) return;
var replacement = new Node<T>(data)
{
_smaller = _smaller,
_bigger = _bigger,
_parent = _parent
};
if (_parent._item.data.CompareTo(_item.data) == 1)
_parent._smaller = replacement;
else
_parent._bigger = replacement;
}
}
else
{
if (data.CompareTo(_item.data) == 1)
{
_bigger?.Remove(data);
if (_bigger != null) _bigger._parent = this;
}
else
{
_smaller?.Remove(data);
if (_smaller != null) _smaller._parent = this;
}
}
}
public void Add(T item)
{
if (_item.data.Equals(default(T)))
{
Set(item);
return;
}
if (item.CompareTo(_item.data) == 1)
{
#if DEBUG
if (Log)
Console.WriteLine($"{item} > {_item.data} → move to right lower node..");
#endif
(_bigger = CreateOrReturnNode(_bigger)).Set(item);
}
else
{
#if DEBUG
if (Log)
Console.WriteLine($"{item} < {_item.data} → move to left lower node..");
#endif
(_smaller = CreateOrReturnNode(_smaller)).Set(item);
}
}
public int Contains(T value)
{
if (_item.data.Equals(value))
{
#if DEBUG
if (Log)
Console.WriteLine("Item was found!");
#endif
return _item.count;
}
if (value.CompareTo(_item.data).Equals(1))
{
#if DEBUG
if (Log)
Console.WriteLine($"{value} > {_item.data} → search in right lower node..");
#endif
return _bigger?.Contains(value) ?? 0;
}
#if DEBUG
if (Log)
Console.WriteLine($"{value} < {_item.data} → search in left lower node..");
#endif
return _smaller?.Contains(value) ?? 0;
}
/// <summary>
/// Either creates a new node, or returns the existing one.
/// </summary>
/// <param name="node">The node which is getting checked whether it is set or not.</param>
/// <returns>Either a new node, or the already existing one.</returns>
private static Node<T> CreateOrReturnNode(Node<T> node = null)
{
return node ?? new Node<T>();
}
}
}
}
Updated Version: https://github.com/TheRealVira/binary-tree/blob/master/BinaryTree/BinaryTree.cs
_parent
doesn't seem to be touched outsideRemove
, so it looks like you were half-way through a refactor to either add or remove the field. \$\endgroup\$ – Peter Taylor Feb 12 '19 at 9:07