Название: Множества (std::set, QSet) Отправлено: __Heaven__ от Сентябрь 03, 2017, 00:30 Привет друзья!
Прошу помочь найти решение, ибо не хотелось бы велосипедить. Я выделяю для себя положительные стороны контейнеров: std::set - возможность конструирования по месту с подсказкой (emplace_hint, почему этого нет в 5,7+ реализациях QSet, ведь, объявляли о переходе на c++11??) QSet - наличие простых методов и операторов для вычисления пересечений, сложений и вычитаний. Используя std::set я не имею возможности выполнить вычитание без создания контейнера для результата. Я говорю про std::set_difference. Меня же интересует аналог QSet<T> &QSet::operator-=(const T &value). Не хотелось бы выделять дополнительной памяти. Быть может есть какой-нибудь обобщенный erase_iterator? Так можно было бы освобождать память из-под обработанных элементов. Название: Re: Множества (std::set, QSet) Отправлено: Igors от Сентябрь 03, 2017, 10:32 Это принципиально разные ассоциативные контейнеры, и выбор определяется соображением "нужна ли упорядоченность". Напр если данные нужно рисовать по точкам, одна за другой, то QSet (на базе QHash) просто не годится.
Если такой необходимости нет, то выбор обычно в пользу более быстрого QSet. Правда если хеш-ключ получается слишком замороченный, то ну его нафиг, лучше set. И третье: в любом случае ключ - сами данные, т.е. менять их будет нельзя, в этом нужно сразу точно убедиться Меня же интересует аналог QSet<T> &QSet::operator-=(const T &value). Не хотелось бы выделять дополнительной памяти. Быть может есть какой-нибудь обобщенный erase_iterator? Так можно было бы освобождать память из-под обработанных элементов. Была подобная задача с интенсивным вычитанием. Как ни странно, оптимально получается.. на векторах (т.е. вообще без ассоциативных контейнеров). Ну а если выжимать не надо, то делов 5 минут - проходитесь итераторм по первому делая erase для тех что есть во втором (ах это уже велосипед :)). Оптимизировать память - см squeeze() Название: Re: Множества (std::set, QSet) Отправлено: __Heaven__ от Сентябрь 03, 2017, 11:17 Да, нужна упорядоченность и меньшее потребление памяти.
Ключ менять нет необходимости. На векторах делать точно не хочу. Имеется много операций вставки и удаления. Название: Re: Множества (std::set, QSet) Отправлено: Igors от Сентябрь 03, 2017, 12:08 Да, нужна упорядоченность и меньшее потребление памяти. Ну тогда QSet пролетает. Когда-то (давно) мерял, помещение в std::set обходится примерно +20 байт на элемент (в 64бит может больше)Ключ менять нет необходимости. На векторах делать точно не хочу. Имеется много операций вставки и удаления. Всем известно что вставка/удаление в set/map намного (или несравненно) быстрее чем вставка в вектор (там же массу данных надо сдвигать). Однако для "множественных" операций это может оказаться не так. Напр надо вставить тысячу вертексов. Для set это будет тысяча операций, время просто умножится на тысячу. А вот для вектора это можно сделать одной операцией. Поэтому начиная с какой-то интенсивности вектор догонит, а затем и перегонит set. Это заманчиво если финальные данные нужны как вектор. Правда нужна такая задача :)Название: Re: Множества (std::set, QSet) Отправлено: __Heaven__ от Сентябрь 03, 2017, 12:26 Как производился замер потребления? Очень странно, ведь QSet хранит и хэшданные.
В std::set можно и кусками вставлять через insert(container.cbegin(), container.cend()). Также есть замечательная emplace_hint, которая позволит сэкономить на поиске места вставки. Название: Re: Множества (std::set, QSet) Отправлено: kambala от Сентябрь 03, 2017, 15:09 может линейный список подойдет?
Название: Re: Множества (std::set, QSet) Отправлено: Igors от Сентябрь 03, 2017, 15:25 Как производился замер потребления? Я мерял std::set, просто шагал в отладчике пока не дотопал до new а там посмотрел. В std::set можно и кусками вставлять через insert(container.cbegin(), container.cend()). Это не делает вставки быстрееРасскажите чего хотите добиться, тогда может и "матчасть" присмотрим подходящую Название: Re: Множества (std::set, QSet) Отправлено: __Heaven__ от Сентябрь 03, 2017, 16:21 Кажется линейный список не подходит. Недопустимы дубликаты и предпочтительно упорядочивание.
В std::set можно и кусками вставлять через insert(container.cbegin(), container.cend()). Это не делает вставки быстрееКод
Цитировать Insert: 1065 clang на моём пк:EmplaceHint: 256 InsertHint: 281 InsertIterators: 273 Цитировать Insert: 3820 EmplaceHint: 684 InsertHint: 659 InsertIterators: 615 Расскажите чего хотите добиться, тогда может и "матчасть" присмотрим подходящую Ушли от темы к замерам... Добиться хочу отсечения из текущего std::set другого std::set без дополнительного выделения памяти.Нужен невелосипедный аналог QSet::operator-=. Название: Re: Множества (std::set, QSet) Отправлено: Igors от Сентябрь 03, 2017, 18:21 Добиться хочу отсечения из текущего std::set другого std::set без дополнительного выделения памяти. Такое отсечение (ис каропки или нет) скорее всего не вернет распределенную память (как это водится в std). А фокус со swap (как для вектора) здесь вряд ли прокатит. Лучше это сразу проверить.Нужен невелосипедный аналог QSet::operator-=. Доп выделение неизбежно так или иначе почти для всех контейнеров. Надо выделить память для новых данных, переписать и удалить оригинал. Поэтому не видно смысла упорно искать фирменный оператор -=, он делает то же самое :) Код
Название: Re: Множества (std::set, QSet) Отправлено: __Heaven__ от Сентябрь 03, 2017, 22:57 Написал функцию без потребления доп памяти.
Хотел найти подобную реализацию от профессионалов. Код
Название: Re: Множества (std::set, QSet) Отправлено: __Heaven__ от Сентябрь 03, 2017, 23:21 https://ideone.com/emlYr7
Код
Цитировать Stl + destructor: 917 Heaven: 183 Sets are equal: true Название: Re: Множества (std::set, QSet) Отправлено: Igors от Сентябрь 04, 2017, 09:34 Этв реализация никакого отношения к std::set не имеет, она столь же подходит для напр сортированных массивов/векторов (только надо чуть переделать erase). Когда удаляемых эл-тов много - в этом есть смысл (о чем говорилось выше), иначе быстрее и проще так
Код
Название: Re: Множества (std::set, QSet) Отправлено: __Heaven__ от Сентябрь 04, 2017, 10:47 Этв реализация никакого отношения к std::set не имеет Да имеет она всё.Я бы посмотрел, как вы применяете её к вектору с "чуть переделанным erase" Сложно пишете. Существует size_type erase( const key_type& key ). Название: Re: Множества (std::set, QSet) Отправлено: Igors от Сентябрь 04, 2017, 11:23 Да имеет она всё. Предположим вычитаемое (второй set) содержит всего 1 эл-т - а Вы все равно молотите весь первый set который может быть огромен. Зачем так делать если set умеет быстро искать?Я бы посмотрел, как вы применяете её к вектору с "чуть переделанным erase" Напишем велик для удаления эл-тов из вектораКод Теперь вместо IsElementDeleted подставляете что написали выше. Если "ис каропки" - дело чести, то можно remove_if (хотя он чуть хуже). Да, это долгая операция, НО она практически не зависит от числа удаляемых эл-тов, поэтому для "массовых" удалений она может оказаться быстрее. Название: Re: Множества (std::set, QSet) Отправлено: __Heaven__ от Сентябрь 04, 2017, 12:33 Да имеет она всё. Предположим вычитаемое (второй set) содержит всего 1 эл-т - а Вы все равно молотите весь первый set который может быть огромен. Зачем так делать если set умеет быстро искать?В моей программе чаще встречается вычитание ~ из 10млн элементов 10тыс - 8млн элементов. Если 10 млн на 10 млн случится, то будет долго искать. Думаю, что пробег ради 1 элемента - скромная плата за скорость на больших множествах. Хотя, можно и ветвление алгоритма сделать в зависимости от отношения размеров. Вашего примера я не понял. Название: Re: Множества (std::set, QSet) Отправлено: Igors от Сентябрь 05, 2017, 05:28 В моей программе чаще встречается вычитание ~ из 10млн элементов 10тыс - 8млн элементов. Если 10 млн на 10 млн случится, то будет долго искать. Думаю, что пробег ради 1 элемента - скромная плата за скорость на больших множествах. Ну как сказать, если удаляется 1/1000, то простецкое удаление find/erase окажется намного быстрее. Но обычно в подобных задачах важнее другое - а стоит ли вообще заводить ассоциативный контейнер который выжрет немало памяти? Напр если только в целях "быстрого вычитания", то может и нетВашего примера я не понял. Что в своем примере Вы делаете первым в главном цикле? Находите вычитаемый эл-т с которым надо сравнивать (кстати в общем случае lower_bound). Для массивов все то же самое, только вместо erase - сдвиг (поэлементный) |