mirror of
https://github.com/AlexMacocian/SystemExtensions.git
synced 2026-07-21 00:29:29 +00:00
Improve IHttpClient factories (#20)
Codestyle fixes Setup CODEOWNERS Setup dependabot
This commit is contained in:
@@ -1,393 +1,402 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// AVL tree implementation.
|
||||
/// Thanks to Karim Oumghar for the implementation example.
|
||||
/// Read on https://simpledevcode.wordpress.com/2014/09/16/avl-tree-in-c/
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class AVLTree<T> : ICollection<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
[Serializable]
|
||||
private class AVLNode<TKey>
|
||||
{
|
||||
public TKey Value;
|
||||
public AVLNode<TKey> Left;
|
||||
public AVLNode<TKey> Right;
|
||||
public AVLNode(TKey value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
}
|
||||
AVLNode<T> root;
|
||||
private int count = 0;
|
||||
private readonly bool isReadOnly = false;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of items currently stored in the tree.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// True if the collection is readonly. False otherwise.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => isReadOnly;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an AVLTree collection.
|
||||
/// </summary>
|
||||
public AVLTree()
|
||||
{
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds the value to the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the tree.</param>
|
||||
public void Add(T value)
|
||||
/// <summary>
|
||||
/// AVL tree implementation.
|
||||
/// Thanks to Karim Oumghar for the implementation example.
|
||||
/// Read on https://simpledevcode.wordpress.com/2014/09/16/avl-tree-in-c/
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class AVLTree<T> : ICollection<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
[Serializable]
|
||||
private class AVLNode<TKey>
|
||||
{
|
||||
public TKey Value;
|
||||
public AVLNode<TKey> Left;
|
||||
public AVLNode<TKey> Right;
|
||||
public AVLNode(TKey value)
|
||||
{
|
||||
count++;
|
||||
var newItem = new AVLNode<T>(value);
|
||||
if (root == null)
|
||||
{
|
||||
root = newItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
root = RecursiveInsertion(root, newItem);
|
||||
}
|
||||
this.Value = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if the key is contained into the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be checked if present in the tree.</param>
|
||||
/// <returns>True if the value is in the tree.</returns>
|
||||
public bool Contains(T value)
|
||||
}
|
||||
AVLNode<T> root;
|
||||
private int count = 0;
|
||||
private readonly bool isReadOnly = false;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of items currently stored in the tree.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
var node = Find(value, root);
|
||||
if (node == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (node.Value.CompareTo(value) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this.count;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the specified value from the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be deleted.</param>
|
||||
public bool Remove(T value)
|
||||
}
|
||||
/// <summary>
|
||||
/// True if the collection is readonly. False otherwise.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => this.isReadOnly;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an AVLTree collection.
|
||||
/// </summary>
|
||||
public AVLTree()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds the value to the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the tree.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
this.count++;
|
||||
var newItem = new AVLNode<T>(value);
|
||||
if (this.root == null)
|
||||
{
|
||||
this.root = newItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.root = this.RecursiveInsertion(this.root, newItem);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if the key is contained into the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be checked if present in the tree.</param>
|
||||
/// <returns>True if the value is in the tree.</returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
var node = this.Find(value, this.root);
|
||||
if (node == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.Value.CompareTo(value) == 0)
|
||||
{
|
||||
root = Delete(root, value);
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the tree.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
else
|
||||
{
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(root);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the specified value from the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be deleted.</param>
|
||||
public bool Remove(T value)
|
||||
{
|
||||
this.root = this.Delete(this.root, value);
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the tree.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(this.root);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var currentNode = queue.Dequeue();
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
currentNode.Left = null;
|
||||
count--;
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
currentNode.Right = null;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
root = null;
|
||||
count--;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the tree onto the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to store the values in the tree.</param>
|
||||
/// <param name="arrayIndex">Starting index of the provided array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(root);
|
||||
while (queue.Count > 0)
|
||||
var currentNode = queue.Dequeue();
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
var currentNode = queue.Dequeue();
|
||||
array[arrayIndex++] = currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
queue.Enqueue(currentNode.Left);
|
||||
currentNode.Left = null;
|
||||
this.count--;
|
||||
}
|
||||
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
currentNode.Right = null;
|
||||
this.count--;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the tree.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
|
||||
this.root = null;
|
||||
this.count--;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the tree onto the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to store the values in the tree.</param>
|
||||
/// <param name="arrayIndex">Starting index of the provided array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(this.root);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
return GetEnumerator(root);
|
||||
var currentNode = queue.Dequeue();
|
||||
array[arrayIndex++] = currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the tree structure into an array.
|
||||
/// </summary>
|
||||
/// <returns>Array containing the values contained in the tree.</returns>
|
||||
public T[] ToArray()
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the tree.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator(this.root);
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the tree structure into an array.
|
||||
/// </summary>
|
||||
/// <returns>Array containing the values contained in the tree.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
var array = new T[this.count];
|
||||
this.CopyTo(array, 0);
|
||||
return array;
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private AVLNode<T> RecursiveInsertion(AVLNode<T> current, AVLNode<T> n)
|
||||
{
|
||||
if (current == null)
|
||||
{
|
||||
var array = new T[count];
|
||||
CopyTo(array, 0);
|
||||
return array;
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private AVLNode<T> RecursiveInsertion(AVLNode<T> current, AVLNode<T> n)
|
||||
{
|
||||
if (current == null)
|
||||
{
|
||||
current = n;
|
||||
return current;
|
||||
}
|
||||
else if (n.Value.CompareTo(current.Value) < 0)
|
||||
{
|
||||
current.Left = RecursiveInsertion(current.Left, n);
|
||||
current = BalanceTree(current);
|
||||
}
|
||||
else if (n.Value.CompareTo(current.Value) > 0)
|
||||
{
|
||||
current.Right = RecursiveInsertion(current.Right, n);
|
||||
current = BalanceTree(current);
|
||||
}
|
||||
current = n;
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> BalanceTree(AVLNode<T> current)
|
||||
else if (n.Value.CompareTo(current.Value) < 0)
|
||||
{
|
||||
var b_factor = BalanceFactor(current);
|
||||
if (b_factor > 1)
|
||||
{
|
||||
if (BalanceFactor(current.Left) > 0)
|
||||
{
|
||||
current = RotateLL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateLR(current);
|
||||
}
|
||||
}
|
||||
else if (b_factor < -1)
|
||||
{
|
||||
if (BalanceFactor(current.Right) > 0)
|
||||
{
|
||||
current = RotateRL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateRR(current);
|
||||
}
|
||||
}
|
||||
return current;
|
||||
current.Left = this.RecursiveInsertion(current.Left, n);
|
||||
current = this.BalanceTree(current);
|
||||
}
|
||||
private AVLNode<T> Delete(AVLNode<T> current, T target)
|
||||
else if (n.Value.CompareTo(current.Value) > 0)
|
||||
{
|
||||
AVLNode<T> parent;
|
||||
if (current == null)
|
||||
{ return null; }
|
||||
current.Right = this.RecursiveInsertion(current.Right, n);
|
||||
current = this.BalanceTree(current);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> BalanceTree(AVLNode<T> current)
|
||||
{
|
||||
var b_factor = this.BalanceFactor(current);
|
||||
if (b_factor > 1)
|
||||
{
|
||||
if (this.BalanceFactor(current.Left) > 0)
|
||||
{
|
||||
current = this.RotateLL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
//left subtree
|
||||
if (target.CompareTo(current.Value) < 0)
|
||||
{
|
||||
current.Left = Delete(current.Left, target);
|
||||
if (BalanceFactor(current) == -2)//here
|
||||
{
|
||||
if (BalanceFactor(current.Right) <= 0)
|
||||
{
|
||||
current = RotateRR(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateRL(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
//right subtree
|
||||
else if (target.CompareTo(current.Value) > 0)
|
||||
{
|
||||
current.Right = Delete(current.Right, target);
|
||||
if (BalanceFactor(current) == 2)
|
||||
{
|
||||
if (BalanceFactor(current.Left) >= 0)
|
||||
{
|
||||
current = RotateLL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateLR(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
//if target is found
|
||||
else
|
||||
{
|
||||
count--;
|
||||
if (current.Right != null)
|
||||
{
|
||||
//delete its inorder successor
|
||||
parent = current.Right;
|
||||
while (parent.Left != null)
|
||||
{
|
||||
parent = parent.Left;
|
||||
}
|
||||
current.Value = parent.Value;
|
||||
current.Right = Delete(current.Right, parent.Value);
|
||||
if (BalanceFactor(current) == 2)//rebalancing
|
||||
{
|
||||
if (BalanceFactor(current.Left) >= 0)
|
||||
{
|
||||
current = RotateLL(current);
|
||||
}
|
||||
else { current = RotateLR(current); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //if current.left != null
|
||||
return current.Left;
|
||||
}
|
||||
}
|
||||
current = this.RotateLR(current);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> Find(T target, AVLNode<T> current)
|
||||
else if (b_factor < -1)
|
||||
{
|
||||
if (current == null)
|
||||
if (this.BalanceFactor(current.Right) > 0)
|
||||
{
|
||||
return null;
|
||||
current = this.RotateRL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = this.RotateRR(current);
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> Delete(AVLNode<T> current, T target)
|
||||
{
|
||||
AVLNode<T> parent;
|
||||
if (current == null)
|
||||
{ return null; }
|
||||
else
|
||||
{
|
||||
//left subtree
|
||||
if (target.CompareTo(current.Value) < 0)
|
||||
{
|
||||
if (target.CompareTo(current.Value) == 0)
|
||||
current.Left = this.Delete(current.Left, target);
|
||||
if (this.BalanceFactor(current) == -2)//here
|
||||
{
|
||||
return current;
|
||||
if (this.BalanceFactor(current.Right) <= 0)
|
||||
{
|
||||
current = this.RotateRR(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = this.RotateRL(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
//right subtree
|
||||
else if (target.CompareTo(current.Value) > 0)
|
||||
{
|
||||
current.Right = this.Delete(current.Right, target);
|
||||
if (this.BalanceFactor(current) == 2)
|
||||
{
|
||||
if (this.BalanceFactor(current.Left) >= 0)
|
||||
{
|
||||
current = this.RotateLL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = this.RotateLR(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
//if target is found
|
||||
else
|
||||
{
|
||||
this.count--;
|
||||
if (current.Right != null)
|
||||
{
|
||||
//delete its inorder successor
|
||||
parent = current.Right;
|
||||
while (parent.Left != null)
|
||||
{
|
||||
parent = parent.Left;
|
||||
}
|
||||
|
||||
current.Value = parent.Value;
|
||||
current.Right = this.Delete(current.Right, parent.Value);
|
||||
if (this.BalanceFactor(current) == 2)//rebalancing
|
||||
{
|
||||
if (this.BalanceFactor(current.Left) >= 0)
|
||||
{
|
||||
current = this.RotateLL(current);
|
||||
}
|
||||
else { current = this.RotateLR(current); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return Find(target, current.Left);
|
||||
{ //if current.left != null
|
||||
return current.Left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> Find(T target, AVLNode<T> current)
|
||||
{
|
||||
if (current == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (target.CompareTo(current.Value) < 0)
|
||||
{
|
||||
if (target.CompareTo(current.Value) == 0)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target.CompareTo(current.Value) == 0)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Find(target, current.Right);
|
||||
}
|
||||
return this.Find(target, current.Left);
|
||||
}
|
||||
|
||||
}
|
||||
private int Max(int l, int r)
|
||||
else
|
||||
{
|
||||
return l > r ? l : r;
|
||||
}
|
||||
private int GetHeight(AVLNode<T> current)
|
||||
{
|
||||
var height = 0;
|
||||
if (current != null)
|
||||
if (target.CompareTo(current.Value) == 0)
|
||||
{
|
||||
var l = GetHeight(current.Left);
|
||||
var r = GetHeight(current.Right);
|
||||
var m = Max(l, r);
|
||||
height = m + 1;
|
||||
return current;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
private int BalanceFactor(AVLNode<T> current)
|
||||
{
|
||||
var l = GetHeight(current.Left);
|
||||
var r = GetHeight(current.Right);
|
||||
var b_factor = l - r;
|
||||
return b_factor;
|
||||
}
|
||||
private AVLNode<T> RotateRR(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Right;
|
||||
parent.Right = pivot.Left;
|
||||
pivot.Left = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLL(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Left;
|
||||
parent.Left = pivot.Right;
|
||||
pivot.Right = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLR(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Left;
|
||||
parent.Left = RotateRR(pivot);
|
||||
return RotateLL(parent);
|
||||
}
|
||||
private AVLNode<T> RotateRL(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Right;
|
||||
parent.Right = RotateLL(pivot);
|
||||
return RotateRR(parent);
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(AVLNode<T> rootNode)
|
||||
{
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(rootNode);
|
||||
|
||||
while (queue.Count > 0)
|
||||
else
|
||||
{
|
||||
var currentNode = queue.Dequeue();
|
||||
yield return currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
return this.Find(target, current.Right);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
private int Max(int l, int r)
|
||||
{
|
||||
return l > r ? l : r;
|
||||
}
|
||||
private int GetHeight(AVLNode<T> current)
|
||||
{
|
||||
var height = 0;
|
||||
if (current != null)
|
||||
{
|
||||
var l = this.GetHeight(current.Left);
|
||||
var r = this.GetHeight(current.Right);
|
||||
var m = this.Max(l, r);
|
||||
height = m + 1;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
private int BalanceFactor(AVLNode<T> current)
|
||||
{
|
||||
var l = this.GetHeight(current.Left);
|
||||
var r = this.GetHeight(current.Right);
|
||||
var b_factor = l - r;
|
||||
return b_factor;
|
||||
}
|
||||
private AVLNode<T> RotateRR(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Right;
|
||||
parent.Right = pivot.Left;
|
||||
pivot.Left = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLL(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Left;
|
||||
parent.Left = pivot.Right;
|
||||
pivot.Right = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLR(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Left;
|
||||
parent.Left = this.RotateRR(pivot);
|
||||
return this.RotateLL(parent);
|
||||
}
|
||||
private AVLNode<T> RotateRL(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Right;
|
||||
parent.Right = this.RotateLL(pivot);
|
||||
return this.RotateRR(parent);
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(AVLNode<T> rootNode)
|
||||
{
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(rootNode);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var currentNode = queue.Dequeue();
|
||||
yield return currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,214 +1,219 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Binary heap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class BinaryHeap<T> : IEnumerable<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
T[] items;
|
||||
private int capacity;
|
||||
private int count;
|
||||
private readonly int initialCapacity;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Binary heap implementation.
|
||||
/// Minimum value from the heap.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class BinaryHeap<T> : IEnumerable<T> where T : IComparable<T>
|
||||
public T Min
|
||||
{
|
||||
#region Fields
|
||||
T[] items;
|
||||
private int capacity;
|
||||
private int count;
|
||||
private readonly int initialCapacity;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Minimum value from the heap.
|
||||
/// </summary>
|
||||
public T Min
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
return items[1];
|
||||
}
|
||||
return this.items[1];
|
||||
}
|
||||
/// <summary>
|
||||
/// Maximum value from the heap.
|
||||
/// </summary>
|
||||
public T Max
|
||||
{
|
||||
get
|
||||
{
|
||||
return items[count];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Capacity of the heap.
|
||||
/// </summary>
|
||||
public int Capacity
|
||||
{
|
||||
get => capacity;
|
||||
set
|
||||
{
|
||||
if (value > capacity)
|
||||
{
|
||||
Array.Resize(ref items, value);
|
||||
capacity = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Number of elements in the heap.
|
||||
/// </summary>
|
||||
public int Count { get => count; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
public BinaryHeap()
|
||||
{
|
||||
capacity = 10;
|
||||
initialCapacity = capacity;
|
||||
items = new T[capacity];
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Initial capacity of the heap. Used for initial alocation of the array.</param>
|
||||
public BinaryHeap(int capacity)
|
||||
{
|
||||
this.capacity = capacity;
|
||||
initialCapacity = capacity;
|
||||
items = new T[capacity];
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
if (count == Capacity - 1)
|
||||
{
|
||||
Capacity = 2 * Capacity;
|
||||
}
|
||||
var position = ++count;
|
||||
for (; position > 1 && value.CompareTo(items[position / 2]) < 0; position /= 2)
|
||||
{
|
||||
items[position] = items[position / 2];
|
||||
}
|
||||
items[position] = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the item at the root. Throws exception if there are no items in the heap.
|
||||
/// </summary>
|
||||
/// <returns>Value removed.</returns>
|
||||
public T Remove()
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
var min = items[1];
|
||||
items[1] = items[count--];
|
||||
BubbleDown(1);
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Peeks at the item at the root. Throws exception if there are no items in the heap.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T Peek()
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
var min = items[1];
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Return the heap structure as an array
|
||||
/// </summary>
|
||||
/// <returns>Array with values sorted as in heap</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
var newArray = new T[count];
|
||||
Array.Copy(items, 1, newArray, 0, count);
|
||||
return newArray;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the heap contains specified value
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the heap</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return items.Contains(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap.
|
||||
/// </summary>
|
||||
/// <param name="completeClear">Specifies if the underlying array should be cleared as well</param>
|
||||
public void Clear(bool completeClear)
|
||||
{
|
||||
count = 0;
|
||||
if (completeClear)
|
||||
{
|
||||
capacity = initialCapacity;
|
||||
items = new T[initialCapacity];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the heap.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the heap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
yield return items[i + 1];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Bubble the specified element to its position
|
||||
/// </summary>
|
||||
/// <param name="index">Index of element to bubble</param>
|
||||
private void BubbleDown(int index)
|
||||
{
|
||||
var temp = items[index];
|
||||
int childIndex;
|
||||
for (; 2 * index <= count; index = childIndex)
|
||||
{
|
||||
childIndex = 2 * index;
|
||||
if (childIndex != Count && items[childIndex].CompareTo(items[childIndex + 1]) > 0)
|
||||
{
|
||||
childIndex++;
|
||||
}
|
||||
if (temp.CompareTo(items[childIndex]) > 0)
|
||||
{
|
||||
items[index] = items[childIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
items[index] = temp;
|
||||
}
|
||||
/// <summary>
|
||||
/// Implementation of IEnumerator.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator over the array.</returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
/// <summary>
|
||||
/// Maximum value from the heap.
|
||||
/// </summary>
|
||||
public T Max
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.items[this.count];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Capacity of the heap.
|
||||
/// </summary>
|
||||
public int Capacity
|
||||
{
|
||||
get => this.capacity;
|
||||
set
|
||||
{
|
||||
if (value > this.capacity)
|
||||
{
|
||||
Array.Resize(ref this.items, value);
|
||||
this.capacity = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Number of elements in the heap.
|
||||
/// </summary>
|
||||
public int Count { get => this.count; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
public BinaryHeap()
|
||||
{
|
||||
this.capacity = 10;
|
||||
this.initialCapacity = this.capacity;
|
||||
this.items = new T[this.capacity];
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Initial capacity of the heap. Used for initial alocation of the array.</param>
|
||||
public BinaryHeap(int capacity)
|
||||
{
|
||||
this.capacity = capacity;
|
||||
this.initialCapacity = capacity;
|
||||
this.items = new T[capacity];
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
if (this.count == this.Capacity - 1)
|
||||
{
|
||||
this.Capacity = 2 * this.Capacity;
|
||||
}
|
||||
|
||||
var position = ++this.count;
|
||||
for (; position > 1 && value.CompareTo(this.items[position / 2]) < 0; position /= 2)
|
||||
{
|
||||
this.items[position] = this.items[position / 2];
|
||||
}
|
||||
|
||||
this.items[position] = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the item at the root. Throws exception if there are no items in the heap.
|
||||
/// </summary>
|
||||
/// <returns>Value removed.</returns>
|
||||
public T Remove()
|
||||
{
|
||||
if (this.count == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
|
||||
var min = this.items[1];
|
||||
this.items[1] = this.items[this.count--];
|
||||
this.BubbleDown(1);
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Peeks at the item at the root. Throws exception if there are no items in the heap.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T Peek()
|
||||
{
|
||||
if (this.count == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
|
||||
var min = this.items[1];
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Return the heap structure as an array
|
||||
/// </summary>
|
||||
/// <returns>Array with values sorted as in heap</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
var newArray = new T[this.count];
|
||||
Array.Copy(this.items, 1, newArray, 0, this.count);
|
||||
return newArray;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the heap contains specified value
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the heap</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return this.items.Contains(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
this.count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap.
|
||||
/// </summary>
|
||||
/// <param name="completeClear">Specifies if the underlying array should be cleared as well</param>
|
||||
public void Clear(bool completeClear)
|
||||
{
|
||||
this.count = 0;
|
||||
if (completeClear)
|
||||
{
|
||||
this.capacity = this.initialCapacity;
|
||||
this.items = new T[this.initialCapacity];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the heap.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the heap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < this.count; i++)
|
||||
{
|
||||
yield return this.items[i + 1];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Bubble the specified element to its position
|
||||
/// </summary>
|
||||
/// <param name="index">Index of element to bubble</param>
|
||||
private void BubbleDown(int index)
|
||||
{
|
||||
var temp = this.items[index];
|
||||
int childIndex;
|
||||
for (; 2 * index <= this.count; index = childIndex)
|
||||
{
|
||||
childIndex = 2 * index;
|
||||
if (childIndex != this.Count && this.items[childIndex].CompareTo(this.items[childIndex + 1]) > 0)
|
||||
{
|
||||
childIndex++;
|
||||
}
|
||||
|
||||
if (temp.CompareTo(this.items[childIndex]) > 0)
|
||||
{
|
||||
this.items[index] = this.items[childIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.items[index] = temp;
|
||||
}
|
||||
/// <summary>
|
||||
/// Implementation of IEnumerator.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator over the array.</returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,39 +1,38 @@
|
||||
namespace System.Collections.Generic
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for queue implementations.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
public interface IQueue<T> : IEnumerable<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for queue implementations.
|
||||
/// Returns the number of items in the queue.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
public interface IQueue<T> : IEnumerable<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the number of items in the queue.
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
/// <summary>
|
||||
/// Inserts item into the queue.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be inserted.</param>
|
||||
void Enqueue(T item);
|
||||
/// <summary>
|
||||
/// Remove the first item in the queue.
|
||||
/// </summary>
|
||||
/// <returns>First item in the queue.</returns>
|
||||
T Dequeue();
|
||||
/// <summary>
|
||||
/// Looks up the first item from the queue without removing it.
|
||||
/// </summary>
|
||||
/// <returns>First item from the queue.</returns>
|
||||
T Peek();
|
||||
/// <summary>
|
||||
/// Clears the contents of the queue.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
/// <summary>
|
||||
/// Checks if queue contains an item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if queue contains provided item. False otherwise.</returns>
|
||||
bool Contains(T item);
|
||||
}
|
||||
int Count { get; }
|
||||
/// <summary>
|
||||
/// Inserts item into the queue.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be inserted.</param>
|
||||
void Enqueue(T item);
|
||||
/// <summary>
|
||||
/// Remove the first item in the queue.
|
||||
/// </summary>
|
||||
/// <returns>First item in the queue.</returns>
|
||||
T Dequeue();
|
||||
/// <summary>
|
||||
/// Looks up the first item from the queue without removing it.
|
||||
/// </summary>
|
||||
/// <returns>First item from the queue.</returns>
|
||||
T Peek();
|
||||
/// <summary>
|
||||
/// Clears the contents of the queue.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
/// <summary>
|
||||
/// Checks if queue contains an item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if queue contains provided item. False otherwise.</returns>
|
||||
bool Contains(T item);
|
||||
}
|
||||
|
||||
@@ -1,103 +1,102 @@
|
||||
namespace System.Collections.Generic
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Priority Queue data structure. The implementation is based on an array-based implementation of Binary Heap.
|
||||
/// Exposes some of the functionality of the Binary Heap as a queue.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class PriorityQueue<T> : IQueue<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
private readonly BinaryHeap<T> binaryHeap;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Priority Queue data structure. The implementation is based on an array-based implementation of Binary Heap.
|
||||
/// Exposes some of the functionality of the Binary Heap as a queue.
|
||||
/// Returns the number of elements stored into the queue.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class PriorityQueue<T> : IQueue<T> where T : IComparable<T>
|
||||
public int Count
|
||||
{
|
||||
#region Fields
|
||||
private readonly BinaryHeap<T> binaryHeap;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Returns the number of elements stored into the queue.
|
||||
/// </summary>
|
||||
public int Count
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
return binaryHeap.Count;
|
||||
}
|
||||
return this.binaryHeap.Count;
|
||||
}
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for priority queue data structure.
|
||||
/// </summary>
|
||||
public PriorityQueue()
|
||||
{
|
||||
binaryHeap = new BinaryHeap<T>();
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Add provided value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the queue.</param>
|
||||
public void Enqueue(T value)
|
||||
{
|
||||
binaryHeap.Add(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Pops the queue and removes the highest priority value from the queue.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue</returns>
|
||||
public T Dequeue()
|
||||
{
|
||||
if (Count > 0)
|
||||
{
|
||||
return binaryHeap.Remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IndexOutOfRangeException("Queue is empty!");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Looks up the highest priority value from the queue. Doesn't alter the queue in any way.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue.</returns>
|
||||
public T Peek()
|
||||
{
|
||||
return binaryHeap.Min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the queue contents, removing any value stored into the queue.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
binaryHeap.Clear();
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if queue contains provided item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if queue contains the provided item. False otherwise.</returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return binaryHeap.Contains(item);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the queue.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the queue.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return binaryHeap.GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Necesarry for the implementatio of IQueue.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for priority queue data structure.
|
||||
/// </summary>
|
||||
public PriorityQueue()
|
||||
{
|
||||
this.binaryHeap = new BinaryHeap<T>();
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Add provided value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the queue.</param>
|
||||
public void Enqueue(T value)
|
||||
{
|
||||
this.binaryHeap.Add(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Pops the queue and removes the highest priority value from the queue.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue</returns>
|
||||
public T Dequeue()
|
||||
{
|
||||
if (this.Count > 0)
|
||||
{
|
||||
return this.binaryHeap.Remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IndexOutOfRangeException("Queue is empty!");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Looks up the highest priority value from the queue. Doesn't alter the queue in any way.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue.</returns>
|
||||
public T Peek()
|
||||
{
|
||||
return this.binaryHeap.Min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the queue contents, removing any value stored into the queue.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
this.binaryHeap.Clear();
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if queue contains provided item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if queue contains the provided item. False otherwise.</returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return this.binaryHeap.Contains(item);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the queue.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the queue.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return this.binaryHeap.GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Necesarry for the implementatio of IQueue.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,236 +1,248 @@
|
||||
namespace System.Collections.Generic
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Skip list implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class SkipList<T> : ICollection<T> where T : IComparable<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Skip list implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
#region Fields
|
||||
[Serializable]
|
||||
public sealed class SkipList<T> : ICollection<T> where T : IComparable<T>
|
||||
private class NodeSet<TKey>
|
||||
{
|
||||
#region Fields
|
||||
[Serializable]
|
||||
private class NodeSet<TKey>
|
||||
{
|
||||
public TKey Key;
|
||||
public int Level;
|
||||
public NodeSet<TKey>[] Next;
|
||||
public TKey Key;
|
||||
public int Level;
|
||||
public NodeSet<TKey>[] Next;
|
||||
|
||||
public NodeSet(TKey key, int level)
|
||||
{
|
||||
this.Key = key;
|
||||
this.Level = level;
|
||||
Next = new NodeSet<TKey>[level + 1];
|
||||
}
|
||||
}
|
||||
private int count;
|
||||
private readonly Random random;
|
||||
private readonly NodeSet<T> head;
|
||||
private readonly NodeSet<T> end;
|
||||
private readonly int maxLevel = 10;
|
||||
private int level;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Number of elements in the list.
|
||||
/// </summary>
|
||||
public int Count { get => count; }
|
||||
/// <summary>
|
||||
/// Specifies if the collection can be modified.
|
||||
/// </summary>
|
||||
public bool IsReadOnly { get; set; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new instance of SkipList collection.
|
||||
/// </summary>
|
||||
/// <param name="maxLevel">Maximum level of the skip list.</param>
|
||||
public SkipList(int maxLevel = 10)
|
||||
public NodeSet(TKey key, int level)
|
||||
{
|
||||
this.maxLevel = maxLevel;
|
||||
random = new Random();
|
||||
head = new NodeSet<T>(default, maxLevel);
|
||||
end = head;
|
||||
for (var i = 0; i <= maxLevel; i++)
|
||||
{
|
||||
head.Next[i] = end;
|
||||
}
|
||||
this.Key = key;
|
||||
this.Level = level;
|
||||
this.Next = new NodeSet<TKey>[level + 1];
|
||||
}
|
||||
}
|
||||
private int count;
|
||||
private readonly Random random;
|
||||
private readonly NodeSet<T> head;
|
||||
private readonly NodeSet<T> end;
|
||||
private readonly int maxLevel = 10;
|
||||
private int level;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Number of elements in the list.
|
||||
/// </summary>
|
||||
public int Count { get => this.count; }
|
||||
/// <summary>
|
||||
/// Specifies if the collection can be modified.
|
||||
/// </summary>
|
||||
public bool IsReadOnly { get; set; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new instance of SkipList collection.
|
||||
/// </summary>
|
||||
/// <param name="maxLevel">Maximum level of the skip list.</param>
|
||||
public SkipList(int maxLevel = 10)
|
||||
{
|
||||
this.maxLevel = maxLevel;
|
||||
this.random = new Random();
|
||||
this.head = new NodeSet<T>(default, maxLevel);
|
||||
this.end = this.head;
|
||||
for (var i = 0; i <= maxLevel; i++)
|
||||
{
|
||||
this.head.Next[i] = this.end;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds an item to the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be added.</param>
|
||||
public void Add(T item)
|
||||
{
|
||||
var curNode = this.head;
|
||||
var newLevel = 0;
|
||||
while (this.random.Next(0, 2) > 0 && newLevel < this.maxLevel)
|
||||
{
|
||||
newLevel++;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds an item to the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be added.</param>
|
||||
public void Add(T item)
|
||||
if (newLevel > this.level)
|
||||
{
|
||||
var curNode = head;
|
||||
var newLevel = 0;
|
||||
while (random.Next(0, 2) > 0 && newLevel < maxLevel)
|
||||
{
|
||||
newLevel++;
|
||||
}
|
||||
if (newLevel > level)
|
||||
{
|
||||
level = newLevel;
|
||||
}
|
||||
var newNode = new NodeSet<T>(item, newLevel);
|
||||
for (var i = 0; i <= newLevel; i++)
|
||||
{
|
||||
if (i > curNode.Level)
|
||||
{
|
||||
curNode = head;
|
||||
}
|
||||
while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0)
|
||||
{
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
newNode.Next[i] = curNode.Next[i];
|
||||
curNode.Next[i] = newNode;
|
||||
}
|
||||
count++;
|
||||
this.level = newLevel;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes provided item from the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be removed.</param>
|
||||
/// <returns>True if removal was successful.</returns>
|
||||
public bool Remove(T item)
|
||||
|
||||
var newNode = new NodeSet<T>(item, newLevel);
|
||||
for (var i = 0; i <= newLevel; i++)
|
||||
{
|
||||
var removed = false;
|
||||
var curNode = head;
|
||||
for (var i = 0; i <= maxLevel; i++)
|
||||
if (i > curNode.Level)
|
||||
{
|
||||
if (i > curNode.Level)
|
||||
{
|
||||
curNode = head;
|
||||
}
|
||||
while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0)
|
||||
{
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
if (curNode.Next[i].Key.CompareTo(item) == 0) //Item is present on this level
|
||||
{
|
||||
curNode.Next[i] = curNode.Next[i].Next[i];
|
||||
removed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
curNode = this.head;
|
||||
}
|
||||
if (removed)
|
||||
|
||||
while (curNode.Next[i] != this.end && curNode.Next[i].Key.CompareTo(item) < 0)
|
||||
{
|
||||
count--;
|
||||
return true;
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
|
||||
newNode.Next[i] = curNode.Next[i];
|
||||
curNode.Next[i] = newNode;
|
||||
}
|
||||
|
||||
this.count++;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes provided item from the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be removed.</param>
|
||||
/// <returns>True if removal was successful.</returns>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
var removed = false;
|
||||
var curNode = this.head;
|
||||
for (var i = 0; i <= this.maxLevel; i++)
|
||||
{
|
||||
if (i > curNode.Level)
|
||||
{
|
||||
curNode = this.head;
|
||||
}
|
||||
|
||||
while (curNode.Next[i] != this.end && curNode.Next[i].Key.CompareTo(item) < 0)
|
||||
{
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
|
||||
if (curNode.Next[i].Key.CompareTo(item) == 0) //Item is present on this level
|
||||
{
|
||||
curNode.Next[i] = curNode.Next[i].Next[i];
|
||||
removed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the collection.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
|
||||
if (removed)
|
||||
{
|
||||
for (var i = 0; i < maxLevel; i++)
|
||||
{
|
||||
head.Next[i] = end;
|
||||
}
|
||||
count = 0;
|
||||
this.count--;
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if item is present in the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if item is present in the collection.</returns>
|
||||
public bool Contains(T item)
|
||||
else
|
||||
{
|
||||
if (Find(item) != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the skip list contents onto the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to hold the values from the list.</param>
|
||||
/// <param name="arrayIndex">Index to start insertion in the array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
var node = head.Next[0];
|
||||
while (node != end)
|
||||
{
|
||||
array[arrayIndex] = node.Key;
|
||||
arrayIndex++;
|
||||
node = node.Next[0];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the elements from the collection into an array.
|
||||
/// </summary>
|
||||
/// <returns>Array filled with elements from the collection.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
var array = new T[count];
|
||||
var index = 0;
|
||||
var curNode = head.Next[0];
|
||||
while (curNode != end)
|
||||
{
|
||||
array[index] = curNode.Key;
|
||||
index++;
|
||||
curNode = curNode.Next[0];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
var curNode = head.Next[0];
|
||||
while (curNode != end)
|
||||
{
|
||||
yield return curNode.Key;
|
||||
curNode = curNode.Next[0];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private NodeSet<T> Find(T key)
|
||||
{
|
||||
var curNode = head;
|
||||
|
||||
for (var i = level; i >= 0; i--)
|
||||
{
|
||||
while (curNode.Next[i] != end)
|
||||
{
|
||||
if (curNode.Next[i].Key.CompareTo(key) > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (curNode.Next[i].Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode.Next[i];
|
||||
}
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
}
|
||||
|
||||
curNode = curNode.Next[0];
|
||||
if (curNode != end && curNode.Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the collection.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
for (var i = 0; i < this.maxLevel; i++)
|
||||
{
|
||||
this.head.Next[i] = this.end;
|
||||
}
|
||||
|
||||
this.count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if item is present in the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if item is present in the collection.</returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
if (this.Find(item) != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the skip list contents onto the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to hold the values from the list.</param>
|
||||
/// <param name="arrayIndex">Index to start insertion in the array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
var node = this.head.Next[0];
|
||||
while (node != this.end)
|
||||
{
|
||||
array[arrayIndex] = node.Key;
|
||||
arrayIndex++;
|
||||
node = node.Next[0];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the elements from the collection into an array.
|
||||
/// </summary>
|
||||
/// <returns>Array filled with elements from the collection.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
var array = new T[this.count];
|
||||
var index = 0;
|
||||
var curNode = this.head.Next[0];
|
||||
while (curNode != this.end)
|
||||
{
|
||||
array[index] = curNode.Key;
|
||||
index++;
|
||||
curNode = curNode.Next[0];
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
var curNode = this.head.Next[0];
|
||||
while (curNode != this.end)
|
||||
{
|
||||
yield return curNode.Key;
|
||||
curNode = curNode.Next[0];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private NodeSet<T> Find(T key)
|
||||
{
|
||||
var curNode = this.head;
|
||||
|
||||
for (var i = this.level; i >= 0; i--)
|
||||
{
|
||||
while (curNode.Next[i] != this.end)
|
||||
{
|
||||
if (curNode.Next[i].Key.CompareTo(key) > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (curNode.Next[i].Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode.Next[i];
|
||||
}
|
||||
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
}
|
||||
|
||||
curNode = curNode.Next[0];
|
||||
if (curNode != this.end && curNode.Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,280 +1,287 @@
|
||||
namespace System.Collections.Generic
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Treap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class Treap<T> : ICollection<T> where T : IComparable<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Treap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
#region Fields
|
||||
[Serializable]
|
||||
public sealed class Treap<T> : ICollection<T> where T : IComparable<T>
|
||||
private class Node<TKey>
|
||||
{
|
||||
#region Fields
|
||||
[Serializable]
|
||||
private class Node<TKey>
|
||||
public TKey Key;
|
||||
public int Priority;
|
||||
public Node<TKey> Left, Right;
|
||||
public Node(TKey key, int priority)
|
||||
{
|
||||
public TKey Key;
|
||||
public int Priority;
|
||||
public Node<TKey> Left, Right;
|
||||
public Node(TKey key, int priority)
|
||||
{
|
||||
Key = key;
|
||||
Priority = priority;
|
||||
Left = null;
|
||||
Right = null;
|
||||
}
|
||||
this.Key = key;
|
||||
this.Priority = priority;
|
||||
this.Left = null;
|
||||
this.Right = null;
|
||||
}
|
||||
private readonly Random randomGen;
|
||||
private Node<T> root;
|
||||
private int count;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of values in the treap.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Not implemented.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => false;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for treap.
|
||||
/// </summary>
|
||||
public Treap()
|
||||
{
|
||||
randomGen = new Random();
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
root = InsertNode(root, value);
|
||||
count++;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes value from treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be removed.</param>
|
||||
public bool Remove(T value)
|
||||
{
|
||||
root = RemoveNode(root, value);
|
||||
count--;
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the treap.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
Clear(root);
|
||||
root = null;
|
||||
count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the treap contains the specified value.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the treap.</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return Find(root, value) != null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the treap structure as an ordered array.
|
||||
/// </summary>
|
||||
/// <returns>Ordered array containing the values stored in the treap.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
if (root != null)
|
||||
{
|
||||
var array = new T[count];
|
||||
var index = 0;
|
||||
ToArray(root, ref array, ref index);
|
||||
return array;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copy the treap into the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to be populated with the values contained in the array.</param>
|
||||
/// <param name="arrayIndex">Starting index of the array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
ToArray(root, ref array, ref arrayIndex);
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the treap. Note that the values are not guaranteed to be sorted.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the treap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetEnumerator(root);
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private Node<T> InsertNode(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
node = new Node<T>(key, randomGen.Next(0, 100));
|
||||
return node;
|
||||
}
|
||||
else if (key.CompareTo(node.Key) <= 0)
|
||||
{
|
||||
node.Left = InsertNode(node.Left, key);
|
||||
if (node.Left.Priority > node.Priority)
|
||||
{
|
||||
node = RotateRight(node);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Right = InsertNode(node.Right, key);
|
||||
if (node.Right.Priority > node.Priority)
|
||||
{
|
||||
node = RotateLeft(node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
private Node<T> RemoveNode(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
if (key.CompareTo(node.Key) < 0)
|
||||
{
|
||||
node.Left = RemoveNode(node.Left, key);
|
||||
}
|
||||
else if (key.CompareTo(node.Key) > 0)
|
||||
{
|
||||
node.Right = RemoveNode(node.Right, key);
|
||||
}
|
||||
else if (node.Left == null)
|
||||
{
|
||||
node = node.Right;
|
||||
}
|
||||
else if (node.Right == null)
|
||||
{
|
||||
node = node.Left;
|
||||
}
|
||||
else if (node.Left.Priority < node.Right.Priority)
|
||||
{
|
||||
node = RotateLeft(node);
|
||||
node.Left = RemoveNode(node.Left, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = RotateRight(node);
|
||||
node.Right = RemoveNode(node.Right, key);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
private Node<T> RotateRight(Node<T> node)
|
||||
{
|
||||
Node<T> temp = node.Left, temp2 = temp.Right;
|
||||
temp.Right = node;
|
||||
node.Left = temp2;
|
||||
return temp;
|
||||
}
|
||||
private Node<T> RotateLeft(Node<T> node)
|
||||
{
|
||||
Node<T> temp = node.Right, temp2 = temp.Left;
|
||||
temp.Left = node;
|
||||
node.Right = temp2;
|
||||
return temp;
|
||||
}
|
||||
private void Clear(Node<T> node)
|
||||
{
|
||||
if (node.Left != null)
|
||||
{
|
||||
Clear(node.Left);
|
||||
}
|
||||
if (node.Right != null)
|
||||
{
|
||||
Clear(node.Right);
|
||||
}
|
||||
node.Left = node.Right = null;
|
||||
}
|
||||
private Node<T> Find(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.Key.CompareTo(key) < 0)
|
||||
{
|
||||
var found = Find(node.Left, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = Find(node.Right, key);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else if (node.Key.CompareTo(key) > 0)
|
||||
{
|
||||
var found = Find(node.Right, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = Find(node.Left, key);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else
|
||||
{
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void ToArray(Node<T> node, ref T[] array, ref int index)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
ToArray(node.Left, ref array, ref index);
|
||||
array[index] = node.Key;
|
||||
index++;
|
||||
ToArray(node.Right, ref array, ref index);
|
||||
}
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(Node<T> currentNode)
|
||||
{
|
||||
var queue = new Queue<Node<T>>();
|
||||
queue.Enqueue(currentNode);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
currentNode = queue.Dequeue();
|
||||
yield return currentNode.Key;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
private readonly Random randomGen;
|
||||
private Node<T> root;
|
||||
private int count;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of values in the treap.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Not implemented.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => false;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for treap.
|
||||
/// </summary>
|
||||
public Treap()
|
||||
{
|
||||
this.randomGen = new Random();
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
this.root = this.InsertNode(this.root, value);
|
||||
this.count++;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes value from treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be removed.</param>
|
||||
public bool Remove(T value)
|
||||
{
|
||||
this.root = this.RemoveNode(this.root, value);
|
||||
this.count--;
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the treap.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
this.Clear(this.root);
|
||||
this.root = null;
|
||||
this.count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the treap contains the specified value.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the treap.</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return this.Find(this.root, value) != null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the treap structure as an ordered array.
|
||||
/// </summary>
|
||||
/// <returns>Ordered array containing the values stored in the treap.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
if (this.root != null)
|
||||
{
|
||||
var array = new T[this.count];
|
||||
var index = 0;
|
||||
this.ToArray(this.root, ref array, ref index);
|
||||
return array;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copy the treap into the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to be populated with the values contained in the array.</param>
|
||||
/// <param name="arrayIndex">Starting index of the array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
this.ToArray(this.root, ref array, ref arrayIndex);
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the treap. Note that the values are not guaranteed to be sorted.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the treap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator(this.root);
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private Node<T> InsertNode(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
node = new Node<T>(key, this.randomGen.Next(0, 100));
|
||||
return node;
|
||||
}
|
||||
else if (key.CompareTo(node.Key) <= 0)
|
||||
{
|
||||
node.Left = this.InsertNode(node.Left, key);
|
||||
if (node.Left.Priority > node.Priority)
|
||||
{
|
||||
node = this.RotateRight(node);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Right = this.InsertNode(node.Right, key);
|
||||
if (node.Right.Priority > node.Priority)
|
||||
{
|
||||
node = this.RotateLeft(node);
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
private Node<T> RemoveNode(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
if (key.CompareTo(node.Key) < 0)
|
||||
{
|
||||
node.Left = this.RemoveNode(node.Left, key);
|
||||
}
|
||||
else if (key.CompareTo(node.Key) > 0)
|
||||
{
|
||||
node.Right = this.RemoveNode(node.Right, key);
|
||||
}
|
||||
else if (node.Left == null)
|
||||
{
|
||||
node = node.Right;
|
||||
}
|
||||
else if (node.Right == null)
|
||||
{
|
||||
node = node.Left;
|
||||
}
|
||||
else if (node.Left.Priority < node.Right.Priority)
|
||||
{
|
||||
node = this.RotateLeft(node);
|
||||
node.Left = this.RemoveNode(node.Left, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = this.RotateRight(node);
|
||||
node.Right = this.RemoveNode(node.Right, key);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
private Node<T> RotateRight(Node<T> node)
|
||||
{
|
||||
Node<T> temp = node.Left, temp2 = temp.Right;
|
||||
temp.Right = node;
|
||||
node.Left = temp2;
|
||||
return temp;
|
||||
}
|
||||
private Node<T> RotateLeft(Node<T> node)
|
||||
{
|
||||
Node<T> temp = node.Right, temp2 = temp.Left;
|
||||
temp.Left = node;
|
||||
node.Right = temp2;
|
||||
return temp;
|
||||
}
|
||||
private void Clear(Node<T> node)
|
||||
{
|
||||
if (node.Left != null)
|
||||
{
|
||||
this.Clear(node.Left);
|
||||
}
|
||||
|
||||
if (node.Right != null)
|
||||
{
|
||||
this.Clear(node.Right);
|
||||
}
|
||||
|
||||
node.Left = node.Right = null;
|
||||
}
|
||||
private Node<T> Find(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.Key.CompareTo(key) < 0)
|
||||
{
|
||||
var found = this.Find(node.Left, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = this.Find(node.Right, key);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
else if (node.Key.CompareTo(key) > 0)
|
||||
{
|
||||
var found = this.Find(node.Right, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = this.Find(node.Left, key);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
else
|
||||
{
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void ToArray(Node<T> node, ref T[] array, ref int index)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
this.ToArray(node.Left, ref array, ref index);
|
||||
array[index] = node.Key;
|
||||
index++;
|
||||
this.ToArray(node.Right, ref array, ref index);
|
||||
}
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(Node<T> currentNode)
|
||||
{
|
||||
var queue = new Queue<Node<T>>();
|
||||
queue.Enqueue(currentNode);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
currentNode = queue.Dequeue();
|
||||
yield return currentNode.Key;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user