359 lines
9.1 KiB
C#
359 lines
9.1 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Prac8
|
|
{
|
|
public class MyList<T> : IEnumerable<T>
|
|
{
|
|
private const int DefaultCapacity = 4;
|
|
private T[] _items;
|
|
private int _count;
|
|
|
|
public MyList(int capacity = DefaultCapacity)
|
|
{
|
|
if (capacity < 1)
|
|
{
|
|
capacity = DefaultCapacity;
|
|
}
|
|
|
|
_items = new T[capacity];
|
|
_count = 0;
|
|
}
|
|
|
|
public int Count => _count;
|
|
|
|
public T this[int index]
|
|
{
|
|
get => Get(index);
|
|
set
|
|
{
|
|
ValidateIndex(index);
|
|
_items[index] = value;
|
|
}
|
|
}
|
|
|
|
public void Add(T item)
|
|
{
|
|
EnsureCapacity();
|
|
_items[_count] = item;
|
|
_count++;
|
|
}
|
|
|
|
public void Insert(int index, T item)
|
|
{
|
|
ValidateInsertIndex(index);
|
|
EnsureCapacity();
|
|
|
|
for (int i = _count; i > index; i--)
|
|
{
|
|
_items[i] = _items[i - 1];
|
|
}
|
|
|
|
_items[index] = item;
|
|
_count++;
|
|
}
|
|
|
|
public void AddRange(MyList<T> otherList)
|
|
{
|
|
if (otherList == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(otherList), "Другой список не должен быть null.");
|
|
}
|
|
|
|
MyList<T> source = CreateSafeCopy(otherList);
|
|
EnsureCapacityFor(source.Count);
|
|
|
|
foreach (T item in source)
|
|
{
|
|
Add(item);
|
|
}
|
|
}
|
|
|
|
public void InsertRange(int index, MyList<T> otherList)
|
|
{
|
|
ValidateInsertIndex(index);
|
|
|
|
if (otherList == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(otherList), "Другой список не должен быть null.");
|
|
}
|
|
|
|
if (otherList.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
MyList<T> source = CreateSafeCopy(otherList);
|
|
EnsureCapacityFor(source.Count);
|
|
|
|
for (int i = _count - 1; i >= index; i--)
|
|
{
|
|
_items[i + source.Count] = _items[i];
|
|
}
|
|
|
|
int insertPosition = index;
|
|
foreach (T item in source)
|
|
{
|
|
_items[insertPosition] = item;
|
|
insertPosition++;
|
|
}
|
|
|
|
_count += source.Count;
|
|
}
|
|
|
|
public void RemoveAt(int index)
|
|
{
|
|
ValidateIndex(index);
|
|
|
|
for (int i = index; i < _count - 1; i++)
|
|
{
|
|
_items[i] = _items[i + 1];
|
|
}
|
|
|
|
_count--;
|
|
_items[_count] = default(T);
|
|
}
|
|
|
|
public void RemoveLast()
|
|
{
|
|
if (_count == 0)
|
|
{
|
|
throw new InvalidOperationException("Нельзя удалить последний элемент из пустого списка.");
|
|
}
|
|
|
|
_count--;
|
|
_items[_count] = default(T);
|
|
}
|
|
|
|
public void RemoveRange(int firstIndex, int secondIndex)
|
|
{
|
|
if (_count == 0)
|
|
{
|
|
throw new InvalidOperationException("Список пуст.");
|
|
}
|
|
|
|
ValidateIndex(firstIndex);
|
|
ValidateIndex(secondIndex);
|
|
|
|
if (firstIndex > secondIndex)
|
|
{
|
|
throw new ArgumentException("Первый индекс не может быть больше второго.");
|
|
}
|
|
|
|
int removeCount = secondIndex - firstIndex + 1;
|
|
|
|
for (int i = firstIndex; i < _count - removeCount; i++)
|
|
{
|
|
_items[i] = _items[i + removeCount];
|
|
}
|
|
|
|
for (int i = _count - removeCount; i < _count; i++)
|
|
{
|
|
_items[i] = default(T);
|
|
}
|
|
|
|
_count -= removeCount;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
for (int i = 0; i < _count; i++)
|
|
{
|
|
_items[i] = default(T);
|
|
}
|
|
|
|
_count = 0;
|
|
}
|
|
|
|
public T Get(int index)
|
|
{
|
|
ValidateIndex(index);
|
|
return _items[index];
|
|
}
|
|
|
|
public void Print()
|
|
{
|
|
if (_count == 0)
|
|
{
|
|
Console.WriteLine("Список пуст.");
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < _count; i++)
|
|
{
|
|
Console.WriteLine($"[{i}] {_items[i]}");
|
|
}
|
|
}
|
|
|
|
public T Find(Predicate<T> match)
|
|
{
|
|
if (match == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(match), "Предикат не должен быть null.");
|
|
}
|
|
|
|
for (int i = 0; i < _count; i++)
|
|
{
|
|
if (match(_items[i]))
|
|
{
|
|
return _items[i];
|
|
}
|
|
}
|
|
|
|
return default(T);
|
|
}
|
|
|
|
public void EnsureCapacity()
|
|
{
|
|
if (_count < _items.Length)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int newCapacity = _items.Length == 0 ? DefaultCapacity : _items.Length * 2;
|
|
Array.Resize(ref _items, newCapacity);
|
|
}
|
|
|
|
public void Sort(int index)
|
|
{
|
|
if (index != 0 && index != 1)
|
|
{
|
|
throw new ArgumentException("Для сортировки используйте 1 - по возрастанию или 0 - по убыванию.");
|
|
}
|
|
|
|
if (_count < 2)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Comparer<T> comparer = Comparer<T>.Default;
|
|
bool ascending = index == 1;
|
|
|
|
for (int i = 0; i < _count - 1; i++)
|
|
{
|
|
int selectedIndex = i;
|
|
|
|
for (int j = i + 1; j < _count; j++)
|
|
{
|
|
int compareResult = comparer.Compare(_items[j], _items[selectedIndex]);
|
|
|
|
if ((ascending && compareResult < 0) || (!ascending && compareResult > 0))
|
|
{
|
|
selectedIndex = j;
|
|
}
|
|
}
|
|
|
|
if (selectedIndex != i)
|
|
{
|
|
T temp = _items[i];
|
|
_items[i] = _items[selectedIndex];
|
|
_items[selectedIndex] = temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Reverse()
|
|
{
|
|
int left = 0;
|
|
int right = _count - 1;
|
|
|
|
while (left < right)
|
|
{
|
|
T temp = _items[left];
|
|
_items[left] = _items[right];
|
|
_items[right] = temp;
|
|
left++;
|
|
right--;
|
|
}
|
|
}
|
|
|
|
public void Distinct()
|
|
{
|
|
if (_count < 2)
|
|
{
|
|
return;
|
|
}
|
|
|
|
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
|
|
T[] uniqueItems = new T[Math.Max(DefaultCapacity, _count)];
|
|
int uniqueCount = 0;
|
|
|
|
for (int i = 0; i < _count; i++)
|
|
{
|
|
bool exists = false;
|
|
|
|
for (int j = 0; j < uniqueCount; j++)
|
|
{
|
|
if (comparer.Equals(_items[i], uniqueItems[j]))
|
|
{
|
|
exists = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!exists)
|
|
{
|
|
uniqueItems[uniqueCount] = _items[i];
|
|
uniqueCount++;
|
|
}
|
|
}
|
|
|
|
_items = uniqueItems;
|
|
_count = uniqueCount;
|
|
}
|
|
|
|
public IEnumerator<T> GetEnumerator()
|
|
{
|
|
for (int i = 0; i < _count; i++)
|
|
{
|
|
yield return _items[i];
|
|
}
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
|
|
private void ValidateIndex(int index)
|
|
{
|
|
if (index < 0 || index >= _count)
|
|
{
|
|
throw new IndexOutOfRangeException("Индекс находится вне границ списка.");
|
|
}
|
|
}
|
|
|
|
private void ValidateInsertIndex(int index)
|
|
{
|
|
if (index < 0 || index > _count)
|
|
{
|
|
throw new IndexOutOfRangeException("Индекс для вставки находится вне границ списка.");
|
|
}
|
|
}
|
|
|
|
private void EnsureCapacityFor(int additionalItems)
|
|
{
|
|
while (_count + additionalItems > _items.Length)
|
|
{
|
|
int newCapacity = _items.Length == 0 ? DefaultCapacity : _items.Length * 2;
|
|
Array.Resize(ref _items, newCapacity);
|
|
}
|
|
}
|
|
|
|
private static MyList<T> CreateSafeCopy(MyList<T> source)
|
|
{
|
|
MyList<T> copy = new MyList<T>(Math.Max(DefaultCapacity, source.Count));
|
|
foreach (T item in source)
|
|
{
|
|
copy.Add(item);
|
|
}
|
|
|
|
return copy;
|
|
}
|
|
}
|
|
}
|