Skip to content

Instantly share code, notes, and snippets.

@amantix
Last active April 5, 2023 13:20
Show Gist options
  • Save amantix/2a1a00282199d2de3a8d3ac6164e3c52 to your computer and use it in GitHub Desktop.
Save amantix/2a1a00282199d2de3a8d3ac6164e3c52 to your computer and use it in GitHub Desktop.
Реализация абстрактного типа данных список на основе динамического (расширяющегося) массива. Является упрощенным аналогом System.Collections.Generic.List<T>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Vector
{
/// <summary>
/// Представляет строго типизированный список объектов, доступных по индексу.
/// </summary>
/// <typeparam name="T"></typeparam>
public class Vector<T>: IList<T>
{
/// <summary>
/// Итератор списка элементов типа T, представленных объектом Vector
/// </summary>
private class VectorEnumerator : IEnumerator<T>
{
/// <summary>
/// Текущий индекс итератора в массиве элементов
/// </summary>
private int _idx;
/// <summary>
/// Итерируемый массив элементов
/// </summary>
private T[] _array;
public void Dispose()
{
}
public VectorEnumerator(T[] array)
{
_idx = -1;
_array = array;
}
public VectorEnumerator(Vector<T> v)
{
_idx = -1;
_array = v._array;
}
/// <summary>
/// Продвижение итератора вперёд.
/// </summary>
/// <returns></returns>
public bool MoveNext()
{
return ++_idx < _array.Length;
}
/// <summary>
/// Сброс итератора и возврат в позицию перед первым элементом.
/// </summary>
public void Reset()
{
_idx = -1;
}
/// <summary>
/// Получение текущего элемента.
/// </summary>
public T Current
{
get
{
try
{
return _array[_idx];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
/// <summary>
/// Неуниверсальное свойство получения текущего элемента.
/// </summary>
object IEnumerator.Current => Current;
}
/// <summary>
/// Массив - хранилище элементов списка
/// </summary>
private T[] _array;
/// <summary>
/// Конструктор списка Vector по умолчанию, создающий пустой список.
/// </summary>
public Vector()
{
_array = Array.Empty<T>();
Capacity = 0;
Count = 0;
}
/// <summary>
/// Конструктор списка Vector с указанным значением ёмкости.
/// </summary>
/// <param name="capacity"></param>
public Vector(int capacity)
{
_array = new T[Capacity = capacity];
}
/// <summary>
/// Конструктор списка Vector по указанной коллекции.
/// </summary>
/// <param name="collection"></param>
public Vector(IEnumerable<T> collection)
{
var enumerable = collection as T[] ?? collection.ToArray();
Capacity = Count = enumerable.Length;
for(var i=0; i<Count; ++i)
_array[i] = enumerable[i];
}
/// <summary>
/// Метод получения строго типизированного итератора Vector
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
return new VectorEnumerator(_array);
}
/// <summary>
/// Метод получения итератора неуниверсальной коллекции для Vector
/// </summary>
/// <returns></returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Внутренний метод расширения массива элементов.
/// Если массив пустой - расширяем до 4.
/// В противном случае увеличиваем ёмкость вдвое.
/// </summary>
private void Extend()
{
if (Capacity == 0)
_array = new T[Capacity = 4];
else
{
Capacity *= 2;
var tmp = new T[Capacity];
Array.Copy(_array, tmp, _array.Length);
_array = tmp;
}
}
/// <summary>
/// Метод добавления элемента в список Vector.
/// </summary>
/// <param name="item"></param>
public void Add(T item)
{
if (Count == Capacity)
Extend();
_array[Count++] = item;
}
/// <summary>
/// Метод очищения списка Vector
/// </summary>
public void Clear()
{
Count = 0;
}
/// <summary>
/// Метод проверки наличия указанного элемента в списке Vector
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Contains(T item)
{
for (var i = 0; i < Count; ++i)
if (_array[i].Equals(item))
return true;
return false;
}
/// <summary>
/// Метод копирования содержимого списка Vector в массив,
/// начиная с заданного индекса
/// </summary>
/// <param name="array"></param>
/// <param name="arrayIndex"></param>
public void CopyTo(T[] array, int arrayIndex)
{
_array.CopyTo(array, arrayIndex);
}
/// <summary>
/// Метод удаления указанного элемента из списка Vector
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Remove(T item)
{
int found = IndexOf(item);
if (found < 0)
return false;
RemoveAt(found);
return true;
}
/// <summary>
/// Метод сокращения ёмкости списка Vector до фактического количества элементов.
/// </summary>
public void TrimExcess()
{
if (Count >= Capacity) return;
var tmp = new T[Count];
if(Count>0)
_array.CopyTo(tmp, 0);
_array = tmp;
Capacity = 0;
}
/// <summary>
/// Свойство получения ёмкости списка Vector
/// </summary>
public int Capacity { get; private set; }
/// <summary>
/// Свойство получения фактического количества элементов в списке Vector
/// </summary>
public int Count { get; private set; }
/// <summary>
///
/// </summary>
public bool IsReadOnly => false;
/// <summary>
/// Получение индекса элемента в списке Vector
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int IndexOf(T item)
{
int i = 0;
int found = -1;
while (i < _array.Length)
{
if (_array[i].Equals(item))
{
found = i;
break;
}
++i;
}
return found;
}
/// <summary>
/// Вставка элемента в список Vector по заданному индексу.
/// </summary>
/// <param name="index"></param>
/// <param name="item"></param>
public void Insert(int index, T item)
{
if (index < 0 || index > Count)
throw new ArgumentOutOfRangeException(nameof(index));
if (Count == Capacity)
Extend();
for (int i = Count; i < index; --i)
_array[i] = _array[i - 1];
_array[index] = item;
++Count;
}
/// <summary>
/// Удаление элемента из списка Vector, находящегося по заданному индексу.
/// </summary>
/// <param name="index"></param>
public void RemoveAt(int index)
{
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException(nameof(index));
for (int i = index; i < Count - 1; i++)
_array[i] = _array[i + 1];
--Count;
}
/// <summary>
/// Доступ к элементу списка Vector по индексу.
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T this[int index]
{
get
{
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException(nameof(index));
return _array[index];
}
set
{
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException(nameof(index));
_array[index] = value;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment