12.6. Когда нельзя использовать обобщенные алгоритмы
12.6. Когда нельзя использовать обобщенные алгоритмы
Ассоциативные контейнеры (отображения и множества) поддерживают определенный порядок элементов для быстрого поиска и извлечения. Поэтому к ним не разрешается применять обобщенные алгоритмы, меняющие порядок, такие, как sort() и partition(). Если в ассоциативном контейнере требуется переставить элементы, то необходимо сначала скопировать их в последовательный контейнер, например в вектор или список. Контейнер list (список) реализован в виде двусвязного списка: в каждом элементе, помимо собственно данных, хранятся два члена-указателя – на следующий и на предыдущий элементы. Основное преимущество списка – это эффективная вставка и удаление одного элемента или целого диапазона в произвольное место списка, а недостаток – невозможность произвольного доступа. Например, можно написать:
vectorstring::iterator vec_iter = vec.begin() + 7;
Такая форма вполне допустима и инициализирует vec_iter адресом восьмого элемента вектора, но запись
// ошибка: арифметические операции над итераторами
// не поддерживаются списком
liststring::iterator list_iter = slist.begin() + 7;
некорректна, так как элементы списка не занимают непрерывную область памяти. Для того чтобы добраться до восьмого элемента, необходимо посетить все промежуточные.
Поскольку список не поддерживает произвольного доступа, то алгоритмы merge(), remove(), reverse(), sort() и unique() лучше к таким контейнерам не применять, хотя ни один из них явно не требует наличия соответствующего итератора. Вместо этого для списка определены специализированные версии названных операций в виде функций-членов, а также операция splice():
list::merge() объединяет два отсортированных списка list::remove() удаляет элементы с заданным значением list::remove_if()удаляет элементы, удовлетворяющие некоторому условию list::reverse() переставляет элементы списка в обратном порядке list::sort() сортирует элементы списка list::splice() перемещает элементы из одного списка в другой list::unique() оставляет один элемент из каждой цепочки одинаковых смежных элементов
void list::merge( list rhs );
template class Compare
12.6.1. Операция list_merge()
void list::merge( list rhs, Compare comp );
Элементы двух упорядоченных списков объединяются либо на основе оператора "меньше", определенного для типа элементов в контейнере, либо на основе указанной пользователем операции сравнения. (Заметьте, что элементы списка rhs перемещаются в список, для которого вызвана функция-член merge(); по завершении операции список rhs будет пуст.) Например:
int array1[ 10 ] = { 34, 0, 8, 3, 1, 13, 2, 5, 21, 1 };
int array2[ 5 ] = { 377, 89, 233, 55, 144 };
list ilist1( array1, array1 + 10 );
list ilist2( array2, array2 + 5 );
// для объединения требуется, чтобы оба списка были упорядочены
ilist1.sort(); ilist2.sort();
ilist1.merge( ilist2 );
После выполнения операции merge() список ilist2 пуст, а ilist1 содержит первые 15 чисел Фибоначчи в порядке возрастания.