286 lines
8.8 KiB
C#
286 lines
8.8 KiB
C#
using C_.Datastructures.LinkedList;
|
|
using C_.Datastructures.Stack;
|
|
using C_.Datastructures.Queue;
|
|
using System;
|
|
|
|
namespace C_.Datastructures.BinaryTree
|
|
{
|
|
internal class Tree<T> where T:IComparable
|
|
{
|
|
public TreeNode<T>? Root { get; set; }
|
|
public int Count { get; set; }
|
|
|
|
public static Tree<T> Create(){
|
|
//Create a new Tree with no Head
|
|
return new Tree<T>{
|
|
Root = null,
|
|
Count = 0
|
|
};
|
|
}
|
|
|
|
public static Tree<T> Create(T value){
|
|
//Create a new Tree with Head
|
|
return new Tree<T>{
|
|
Root = TreeNode<T>.Create(value)
|
|
};
|
|
}
|
|
|
|
public void Add(T value)
|
|
{//Add item to the correct position in the tree (Input cannot be null)
|
|
Count++;
|
|
|
|
if (Root == default)
|
|
{//If new node should become the root
|
|
Root = TreeNode<T>.Create(value);
|
|
return;
|
|
}
|
|
|
|
//Find position to insert
|
|
TreeNode<T> node = Root;
|
|
node = Descend(value, node)!;
|
|
|
|
if (value.CompareTo(node.Value) < 0)
|
|
{//Insert to left
|
|
node.Left = TreeNode<T>.Create(value);
|
|
return;
|
|
}
|
|
//Insert to right
|
|
node.Right = TreeNode<T>.Create(value);
|
|
return;
|
|
}
|
|
|
|
public bool Delete(T value)
|
|
{
|
|
//Check if root of tree is null
|
|
if (Count == 0)
|
|
return false;
|
|
|
|
//Check if the only value is the root
|
|
if (Count == 1)
|
|
{
|
|
if (Root!.Value!.Equals(value))
|
|
{//If the only item is the one we are trying to delete
|
|
Count = 0;
|
|
Root = default;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//Stack to store the items leading up to and including the one we are trying to delete
|
|
Stack<TreeNode<T>>? deletionStack;
|
|
|
|
//Search for item being deleted + Parents
|
|
deletionStack = Find(value);
|
|
|
|
if (deletionStack == default)
|
|
return false; //Item was not found
|
|
|
|
//Delete Item (replace) and replace pointers to retain integrity of tree
|
|
|
|
TreeNode<T>? node = deletionStack.Pop();
|
|
|
|
//stack to store the items leading up to the value that we will use to replace the node
|
|
Stack<TreeNode<T>>? replacementStack = Min(node!.Right);
|
|
|
|
if (replacementStack == default)
|
|
{//Nothing to the right of the value we are deleting
|
|
if (deletionStack.Peek() != default)
|
|
{//Parent adopts left hand side of node if present
|
|
deletionStack.Pop()!.Left = node.Left;
|
|
}
|
|
|
|
if (node.Left != default)
|
|
{//Node adopts left value if no lower value to the right
|
|
node.Value = node.Left!.Value;
|
|
node.Left = node.Left.Left;
|
|
}
|
|
}
|
|
else
|
|
{//Replace the value + reorder nodes
|
|
node.Value = replacementStack.Peek()!.Value;
|
|
TreeNode<T>? replacementNode = replacementStack.Pop();
|
|
|
|
switch (replacementStack.GetCount())
|
|
{//Determine what to do based on number of items in replacement stack
|
|
case 1:
|
|
node.Right = replacementNode!.Right;
|
|
break;
|
|
case >=2:
|
|
replacementStack.Peek()!.Left = replacementNode!.Right;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
Count--;
|
|
return true;
|
|
}
|
|
|
|
public LinkedList<T>? Traverse(TraversalType traversalType)
|
|
{
|
|
if (Root == default)
|
|
return default;
|
|
|
|
LinkedList<T> list = LinkedList<T>.Create();
|
|
|
|
switch (traversalType)
|
|
{//Select which type of traversal to do
|
|
case TraversalType.Inorder:
|
|
Inorder(list, Root);
|
|
break;
|
|
case TraversalType.Preorder:
|
|
Preorder(list, Root);
|
|
break;
|
|
case TraversalType.Postorder:
|
|
Postorder(list, Root);
|
|
break;
|
|
case TraversalType.Breadth:
|
|
Queue<TreeNode<T>> queue = Queue<TreeNode<T>>.Create();
|
|
BreadthFirst(list, queue, Root);
|
|
break;
|
|
default:
|
|
return default;
|
|
}
|
|
|
|
return list;
|
|
}
|
|
private void Inorder(LinkedList<T> list, TreeNode<T> node)
|
|
{//Inorder Traversal
|
|
if (node.Left != default)
|
|
Inorder(list, node.Left);
|
|
|
|
list.Append(node.Value);
|
|
|
|
if (node.Right != default)
|
|
Inorder(list, node.Right);
|
|
}
|
|
|
|
private void Preorder(LinkedList<T> list, TreeNode<T> node)
|
|
{//Preorder Traversal
|
|
list.Append(node.Value);
|
|
|
|
if (node.Left != default)
|
|
Preorder(list, node.Left);
|
|
|
|
if (node.Right != default)
|
|
Preorder(list, node.Right);
|
|
}
|
|
|
|
private void Postorder(LinkedList<T> list, TreeNode<T> node)
|
|
{//Postorder Traversal
|
|
if (node.Left != default)
|
|
Postorder(list, node.Left);
|
|
|
|
if (node.Right != default)
|
|
Postorder(list, node.Right);
|
|
|
|
list.Append(node.Value);
|
|
}
|
|
|
|
private void BreadthFirst(LinkedList<T> list, Queue<TreeNode<T>> queue, TreeNode<T> node)
|
|
{//Breadth First Traversal
|
|
list.Append(node.Value);
|
|
|
|
if (node.Left != default)
|
|
queue.Push(node.Left);
|
|
|
|
if (node.Right != default)
|
|
queue.Push(node.Right);
|
|
|
|
//Only continue to traverse if there are no mode nodes to process
|
|
if (queue.Peek() != default)
|
|
BreadthFirst(list, queue, queue.Pop()!);
|
|
}
|
|
|
|
|
|
|
|
|
|
private static TreeNode<T>? GetNext(T value, TreeNode<T>? node)
|
|
{//T is comparable so use methods to determine which way to traverse
|
|
if(node == default)
|
|
return default;
|
|
|
|
if (value.CompareTo(node.Value) < 0)
|
|
{//Traverse Left
|
|
return node.Left;
|
|
}
|
|
//Traverse Right
|
|
return node.Right;
|
|
}
|
|
|
|
private Stack<TreeNode<T>>? Find(T value)
|
|
{//Return true if the item can be found within the tree
|
|
if (Root == default || Root.Value!.Equals(default))
|
|
return default;
|
|
|
|
Stack<TreeNode<T>>? stack = Stack<TreeNode<T>>.Create(Root);
|
|
|
|
while (stack.Peek() != default)
|
|
{
|
|
//Compare value at node to see if we are looking for the root item
|
|
if (stack.Peek()!.Value!.Equals(value))
|
|
return stack;
|
|
|
|
stack.Push(GetNext(value, stack.Peek()));
|
|
}
|
|
return default;
|
|
}
|
|
|
|
private static Stack<TreeNode<T>>? Min(TreeNode<T>? node)
|
|
{//Returns a Stack with the value on top being the minimum of the subtree
|
|
|
|
if(node == default)
|
|
return default;
|
|
|
|
//Stack to store and be able to get the parent values
|
|
Stack<TreeNode<T>> stack = Stack<TreeNode<T>>.Create(node);
|
|
|
|
while(true){
|
|
if (stack.Peek()!.Left == default)
|
|
return stack;
|
|
|
|
stack.Push(stack.Peek()!.Left);
|
|
}
|
|
}
|
|
|
|
private static Stack<TreeNode<T>>? Max(TreeNode<T>? node)
|
|
{///Returns a Stack with the value on top being the maximum of the subtree
|
|
if(node == default)
|
|
return default;
|
|
|
|
//Stack to store and be able to get the parent values
|
|
Stack<TreeNode<T>> stack = Stack<TreeNode<T>>.Create(node);
|
|
|
|
while(true){
|
|
if (stack.Peek()!.Right == default)
|
|
return stack;
|
|
|
|
stack.Push(stack.Peek()!.Right);
|
|
}
|
|
}
|
|
|
|
private TreeNode<T>? Descend(T value, TreeNode<T>? current)
|
|
{//Keep trying to determine whether to go left or right until null node is found that can be appended to
|
|
if (current == default)
|
|
return default;
|
|
|
|
TreeNode<T>? node;
|
|
|
|
node = Descend(value, GetNext(value, current));
|
|
if (node == null)
|
|
{
|
|
return current;
|
|
}
|
|
return node;
|
|
}
|
|
}
|
|
|
|
public enum TraversalType
|
|
{//Enum to allow for Traversal selection
|
|
Inorder,
|
|
Preorder,
|
|
Postorder,
|
|
Breadth
|
|
}
|
|
} |