SortedList

G
using System.Collections;
using System.Collections.Generic;

namespace DataStructures;

/// <summary>
///     Implementation of SortedList using binary search.
/// </summary>
/// <typeparam name="T">Generic Type.</typeparam>
public class SortedList<T> : IEnumerable<T>
{
    private readonly IComparer<T> comparer;
    private readonly List<T> memory;

    /// <summary>
    ///     Initializes a new instance of the <see cref="SortedList{T}" /> class. Uses a Comparer.Default for type T.
    /// </summary>
    public SortedList()
        : this(Comparer<T>.Default)
    {
    }

    /// <summary>
    ///     Gets the number of elements containing in <see cref="SortedList{T}" />.
    /// </summary>
    public int Count => memory.Count;

    /// <summary>
    ///     Initializes a new instance of the <see cref="SortedList{T}" /> class.
    /// </summary>
    /// <param name="comparer">Comparer user for binary search.</param>
    public SortedList(IComparer<T> comparer)
    {
        memory = new List<T>();
        this.comparer = comparer;
    }

    /// <summary>
    ///     Adds new item to <see cref="SortedList{T}" /> instance, maintaining the order.
    /// </summary>
    /// <param name="item">An element to insert.</param>
    public void Add(T item)
    {
        var index = IndexFor(item, out _);
        memory.Insert(index, item);
    }

    /// <summary>
    ///     Gets an element of <see cref="SortedList{T}" /> at specified index.
    /// </summary>
    /// <param name="i">Index.</param>
    public T this[int i] => memory[i];

    /// <summary>
    /// Removes all elements from <see cref="SortedList{T}" />.
    /// </summary>
    public void Clear()
        => memory.Clear();

    /// <summary>
    /// Indicates whether a <see cref="SortedList{T}" /> contains a certain element.
    /// </summary>
    /// <param name="item">An element to search.</param>
    /// <returns>true - <see cref="SortedList{T}" /> contains an element, otherwise - false.</returns>
    public bool Contains(T item)
    {
        _ = IndexFor(item, out var found);
        return found;
    }

    /// <summary>
    /// Removes a certain element from <see cref="SortedList{T}" />.
    /// </summary>
    /// <param name="item">An element to remove.</param>
    /// <returns>true - element is found and removed, otherwise false.</returns>
    public bool TryRemove(T item)
    {
        var index = IndexFor(item, out var found);

        if (found)
        {
            memory.RemoveAt(index);
        }

        return found;
    }

    /// <summary>
    /// Returns an enumerator that iterates through the <see cref="SortedList{T}" />.
    /// </summary>
    /// <returns>A Enumerator for the <see cref="SortedList{T}" />.</returns>
    public IEnumerator<T> GetEnumerator()
        => memory.GetEnumerator();

    /// <inheritdoc cref="IEnumerable.GetEnumerator"/>
    IEnumerator IEnumerable.GetEnumerator()
        => GetEnumerator();

    /// <summary>
    /// Binary search algorithm for finding element index in <see cref="SortedList{T}" />.
    /// </summary>
    /// <param name="item">Element.</param>
    /// <param name="found">Indicates whether the equal value was found in <see cref="SortedList{T}" />.</param>
    /// <returns>Index for the Element.</returns>
    private int IndexFor(T item, out bool found)
    {
        var left = 0;
        var right = memory.Count;

        while (right - left > 0)
        {
            var mid = (left + right) / 2;

            switch (comparer.Compare(item, memory[mid]))
            {
                case > 0:
                    left = mid + 1;
                    break;
                case < 0:
                    right = mid;
                    break;
                default:
                    found = true;
                    return mid;
            }
        }

        found = false;
        return left;
    }
}