Qwertiy » 15.04.2013 (Пн) 15:05
Представим массив неограниченного размера. Недостатком работы с ним является то, что при вставке куда-нибудь между имеющимися данными требуется перемещать весь хвост массива. Кроме того, реальный массив имеет ограниченный размер, поэтому при необходимости добавить элемент, весь массив надо пересоздать заново. Эта проблема решается при помощи предварительного резервирования памяти и хранения реальной длины массива. Сответствующий класс в Си++ называется vector<smth>. При своём создании он резервирует 16 элементов и заново выделяет память только когда появися 17-й - размер буфера составит 32 элемента, затем 64 и т. д. Но проблема перемещения хвоста при вставке в произвольную позицию сохраняется.
Теперь список, точнее, двунаправленный список. Каждый его узел кроме данных содержит указатель на предыдущий и следующий элемент. Это позволяет, имея указатель на узел списка, мгновенно выполнять операции вставки и удаления элемента. Однако, при этом теряется возможность определить положение элемента по номеру, поэтому для получения i-го элемента требуется пройти все i первых элементов. В Си++ этот класс называется list<smth>.
Есть другие способы хранения данных, которые позволяют выполнять операции вставки и выбора по индексу за одинаковое время, например, декартово дерево, но это к делу не относится.
То, что у тебя названо блоковым списком позволяет занять некоторую промежуточную позицию между массивом и списком. В идеальных условиях, он способен сделать нечто типа sqrt-декомпозиции, что даст существенно более быстрый доступ и немного более медленную вставку по сравнению со списком. Идея заключается в том, что каждый элемент списка содержит в себе вектор, размер которого не может превышать заданного числа. Если при вставке мы пытаемся его превысить, то создаётся новый узел списка и последний элемент массива текущего узла вытесняется в него. Так написану у тебя, но мне это не нравится, т. к. постоянное добавление в заполнеенй узел будет создавать новый. Также, у тебя упоминается альтернативный вариант, но он мне не нравится, т. к. он портит ассимптотику вставки смещением элементов. Если бы я писал реализацию, то я бы перекидывал половину элементов с целью уравновесить размеры узлов. Таким образом получается нечто вроде list<vector<smth>>.
Но есть небольшое отличие в реализации итератора. Теоретически, вектор позволяет в качестве итератора использовать указатель на элемент с данными, а список - указатель на узел. Однако, во варианте со списком векторов, итератором является лишь пара из указателя на узел списка и индекса элемета в нём. Да, ещё одним недостатком такой структуры является то, что операция вставки может разрушать итераторы, сохранённые до неё.
* smth - something - некий тип, в соответствии с тем, что мы держим в коллекции.
Да, забыл про удаление элемента. Собственно, ничего особенного в неём нет, достаточно просто удалить элемент из соответствующего массива. Даже если узел с пустым массивом останется в списке, то ничего страшного не произойдёт.
Какие вопросы остались?