- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Эффективное использование STL - Скотт Мейерс
Шрифт:
Интервал:
Закладка:
В действительности я несколько оптимистично подошел к ассоциативным контейнерам — приведенное описание предполагает, что узлы бинарных деревьев сгруппированы в относительно малом наборе страниц памяти. В большинстве реализаций STL подобная группировка достигается при помощи нестандартных диспетчеров памяти, работающих поверх распределителей памяти контейнеров (см. советы 10 и И), но если реализация не следит за локализованностью ссылок, узлы могут оказаться разбросанными по всему адресному пространству. Это приведет к росту числа подгрузок страниц. Даже при использовании группирующих диспетчеров памяти в ассоциативных контейнерах обычно чаще возникают проблемы с подгрузкой страниц, поскольку узловым контейнерам, в отличие от блоковых (таких как vector), труднее обеспечить близкое расположение соседних элементов контейнера в физической памяти. Однако именно эта организация памяти сводит к минимуму подгрузку страниц при выполнении бинарного поиска.
Мораль: данные, хранящиеся в сортированном векторе, обычно занимают меньше памяти, чем те же данные в стандартном ассоциативном контейнере; бинарный поиск в сортированном векторе обычно происходит быстрее, чем поиск в стандартном ассоциативном контейнере (с учетом подгрузки страниц).
Конечно, сортированный vector обладает серьезным недостатком — он должен постоянно сохранять порядок сортировки! При вставке нового элемента все последующие элементы сдвигаются на одну позицию. Операция сдвига обходится довольно дорого и становится еще дороже при перераспределении памяти (см. совет 14), поскольку после этого обычно приходится копировать всеэлементы вектора. С другой стороны, при удалении элемента из вектора все последующие элементы сдвигаются на одну позицию к началу. Операции вставки-удаления дорого обходятся для контейнеров vector, но относительно дешевы для ассоциативных контейнеров. По этой причине сортированные контейнеры vector используются вместо ассоциативных контейнеров лишь в том случае, если вы знаете, что при использовании структуры данных операции поиска почти не смешиваются со вставкой и удалением.
В этом совете было много текста, но катастрофически не хватало примеров. Давайте рассмотрим базовый код использования сортированного vector вместо set:
vector<Widget> vw; // Альтернатива для set<Widget>
… // Подготовительная фаза: много вставок,
// мало операций поиска
sort(vw.begin(), vw.end()); // Конец подготовительной фазы (при эмуляции
// multiset можно воспользоваться
// алгоритмом stable_sort - см. совет 31).
Widget w;// Объект с искомым значением
… // Начало фазы поиска
if (binary_search(vw.begin(), vw.end(), w))… // Поиск с применением
// binary_search
vector<Widget>::iterator i =
lower_bound(vw.begin(), vw.end(), w); // Поиск с применением
if (i != vw.end() && !(*i < w))… // lower_bound: конструкция
// !(*i<w)) описана в совете 45
pair<vector<Widget>::iterator, vector<Widget>::iterator> range =
equal_range(vw.begin(), vw.end(), w); // Поиск с применением
if (range.first != range.second)… // equal_range
… // Конец фазы поиска,
// начало фазы реорганизации
sort(vw.begin(), vw.end()); // Начало новой фазы поиска…
Как видите, все реализуется достаточно прямолинейно. Основные затруднения связаны с выбором алгоритма поиска (binary_search, lower_bound и т. д.), но в этом вам поможет совет 45.
При переходе от map/multimap к контейнеру vector ситуация становится более интересной, поскольку vector должен содержать объекты pair, входящие в map/multimap. Но при объявлении объекта типа map<K, V> (или его multimap-аналога) элементы, хранящиеся в контейнере, в действительности относятся к типу pair<const K, V>. Чтобы эмулировать map или multimap на базе vector, признак константности необходимо устранить, поскольку в процессе сортировки элементы вектора перемещаются посредством присваивания, а это означает, что оба компонента пары должны допускать присваивание. Следовательно, при эмуляции map<K, V> на базе vector данные, хранящиеся в векторе, должны относиться к типу pair<K, V>, а не pair<const K, V>.
Содержимое map/multimap хранится в отсортированном виде, но при сортировке учитывается только ключевая составляющая элемента (первый компонент пары), поэтому при сортировке vector должно происходить то же самое. Нам придется написать собственную функцию сравнения для пар, поскольку оператор < типа pair сравнивает обесоставляющие пары.
Интересно заметить, что для выполнения поиска требуется вторая функция сравнения. Функция сравнения, используемая при сортировке, получает два объекта pair, но поиск выполняется только по значению ключа. С другой стороны, функция сравнения, используемая при поиске, должна получать два разнотипных объекта — объект с типом ключа (искомое значение) и pair (одна из пар, хранящихся в векторе). Но это еще не все: мы не знаем, что передается в первом аргументе — ключ или pair, поэтому в действительности для поиска необходимы две функции: одна получает ключ, а другая — объект pair. В следующем примере объединено все сказанное ранее:
typedef pair<string, int> Data; // Тип, хранимый в "map" в данном примере
class DataCompare{ // Класс для функций сравнения
public:
bool operator()(constData& lhs, // Функция сравнения
constData& rhs) const // для сортировки
{
return keyLess(lhs.first, rhs.first); // Определение keyLess
} // приведено ниже
bool operator()(const Data& lhs, // Функция сравнения
const Data::first_type& k) const // для поиска (форма 1)
{
return keyLess(lhs.first, rhs.first);
}
bool operator()(const Data::first_type& k, // Функция сравнения
const Data& rhs) const; // для поиска (форма 2)
{
return keyLess(k.rhs.first);
}
private: // "Настоящая" функция
bool keyLess(const Data::first_type& k1, // сравнения
const Data::first_type& k2) const {
return k1 < k2;
}
}
В данном примере предполагается, что сортированный вектор эмулирует map<string, int>. Перед нами практически буквальное переложение комментариев, приведенных ранее, если не считать присутствия функции keyLess, предназначенной для согласования функций operator(). Каждая функция просто сравнивает два ключа, поэтому, чтобы не программировать одни и те же действия дважды, мы производим проверку в keyLess, а функция operator() возвращает полученный результат. Конечно, этот прием упрощает сопровождение DataCompare, однако у него есть один недостаток: наличие функций operator() с разными типами параметров исключает адаптацию объектов функций (см. совет 40). С этим ничего не поделаешь.
Контейнер map эмулируется на базе сортированного вектора практически так же, как и контейнер set. Единственное принципиальное отличие заключается в том, что в качестве функций сравнения используются объекты DataCompare:
vector<Widget> vd; // Альтернатива для map<string, int>
… // Подготовительная фаза: много вставок,
// мало операций поиска
sort(vd.begin(), vd.end(), DataCompare()); // Конец подготовительной фазы
// (при эмуляции multiset можно
// воспользоваться алгоритмом
// stable_sort - см. совет 31)
string s; // Объект с искомым значением
… // Начало фазы поиска
if (binary_search(vd.begin(), vd.end(), s, DataCompare()))… // Поиск
// с применением binary_search
vector<Data>::iterator i = lower_bound(vd.begin(), vd.end().s,
DataCompare()); // Поиск с применением
if (i != vd.end() && !(i->first < s))… // lower_bound: конструкция
//!(i->first<s)) описана
//в совете 45
pair<vector<Data>::iterator, vector<Data>::iterator> range =
equal_range(vd.begin(), vd.end(), s, DataCompare()); // Поиск с применением
if (range.first != range.second)… // equal_range
… // Конец фазы поиска,