#pragma once
template <class T>
class LinkedList
{
private:
//номер ячейки Refs, указывающей на первый элемент списка
static const int c_nullElem = 0;
//номер ячейки Refs, указывающей на первый элемент из "свободного места"
static const int c_nullFreeSpace = 1;
//Массив для хранения элементов списка
T* m_elems;
// Массив для хранения ссылок
int* m_refs;
// Указатель предыдущего элемента
int m_before;
// Указатель следующего элемента
int m_after;
// длинна масива
int m_arrayLength;
// Количество элементов в списке
int m_count;
private:
// Присваивание виртуальному индексу virtualIndex значения realIndex
void Link(int virtualIndex, int realIndex)
{
m_refs[virtualIndex] = realIndex;
}
// Выделение места для новых элементов
int GetSpace()
{
int i, oldLength;
if (IsListFull())
{
oldLength = m_arrayLength;
IncreaseArrays();
// добавляемые элементы помечаются как свободное место
for (int j = oldLength; j < m_arrayLength; ++j)
{
m_refs[j] = j + 1;
}
m_refs[c_nullFreeSpace] = oldLength;
m_refs[m_arrayLength] = c_nullFreeSpace;
}
i = m_refs[c_nullFreeSpace];
Link(c_nullFreeSpace, m_refs[i]);
return i;
}
// освобождение места при удалении элемента из списка
void PutSpace(int i)
{
Link(i, m_refs[c_nullFreeSpace]);
Link(c_nullFreeSpace, i);
}
// увеличить массивы в 2 раза
void IncreaseArrays()
{
T* tmpElems = new T[m_arrayLength * 2];
int* tmpRefs = new int[m_arrayLength * 2];
memset(tmpElems, 0, m_arrayLength * 2);
memset(tmpRefs, 0, m_arrayLength * 2);
for (int i = 0; i < m_arrayLength; ++i)
{
tmpElems[i] = m_elems[i];
tmpRefs[i] = m_refs[i];
}
// очищаем память
delete [] m_elems;
delete [] m_refs;
// назначаем новые массивы
m_elems = tmpElems;
m_refs = tmpRefs;
m_arrayLength *= 2;
}
public:
// Создание списка для хранения capacity элементов
// 1-я ячейка Refs указывает на первый элемент списка
// 2-я ячейка Refs указывает на 1-й элемент Х из "свободного места"
// capacity - максимально допустимое количество элементов в списке.
LinkedList(int capacity)
{
m_elems = new T[capacity];
m_refs = new int[capacity];
m_arrayLength = capacity;
ClearList();
}
// Очистка списка
void ClearList()
{
// конец списка указывает сам на себя
m_refs[c_nullElem] = c_nullElem;
// Поскольку список пуст, то все ячейки массива помечаются
// как "свободное место".
for (int i = c_nullFreeSpace; i < m_arrayLength; ++i)
{
m_refs[i] = i + 1;
}
// Закольцовываем "свободное место".
m_refs[m_arrayLength - 1] = c_nullFreeSpace;
m_after = 0;
m_before = 0;
m_count = 0;
}
// добавить element в список
void AddItem(T element)
{
// получаем свободное место
int i = GetSpace();
// устанавливаем его в нужном месте списка устанавливаем
// указатель добавляем элемент element в список
Link(m_after, i);
Link(i, m_before);
m_before = i;
m_elems[i] = element;
MoveNext();
// увеличиваем счетчик количества элементов
++m_count;
}
// удалить элемент из списка
void RemoveItem()
{
if (m_count != 0)
{
int i = m_before;
m_before = m_refs[i];
Link(m_after, m_before);
PutSpace(i);
--m_count;
}
}
// прочитать значение элемента из списка
// если параметр Index отсутствует или
// не является порядковым номером эелемента списка
// то возвращается значение элемента перед указателем
// в противном случае возвращается значение элемента
// с порядковым номером Index
T ReadItem(int index = -1)
{
if (!(index >= 0 && index < m_count))
{
if (IsEndOfList())
{
return m_elems[m_after];
}
else
{
return m_elems[m_before];
}
}
else
{
int k = c_nullElem;
for (int i = 0; i <= index; ++i)
{
k = m_refs[k];
}
return m_elems[k];
}
}
// вернуть количество элементов в списке
int GetCount()
{
return m_count;
}
// определить, есть ли свободное место в списке
bool IsListFull()
{
return m_refs[c_nullFreeSpace] == c_nullFreeSpace;
}
// передвинуть указатель на один элемент списка
void MoveNext()
{
m_after = m_before;
m_before = m_refs[m_before];
}
// передвинуть указатель в начало списка
void MoveFront()
{
m_after = 0;
m_before = m_refs[c_nullElem];
}
// определить, находится ли указатель в конце списка
bool IsEndOfList()
{
return m_refs[m_after] == c_nullElem;
}
};