Здравствуйте, Кодт, Вы писали:
К>1) unordered_* и hash_* есть в STL?
hash_ это расширение некоторых STL. unordered_ будут в STL и есть в Boost.
К>2) какая временная сложность у unordered_multiset?
Amortized constant.
На практике multimap ощутимо быстрее map.
К>3) как по заданному предикату сравнения (равенства или порядка, неважно) сделать хеш-функцию?
Никак, но часто проблем с тем чтобы сделать хеш-фукнцию для ключа нет.
К>Например, есть функция strcoll, сравнивающая строки в соответствие с текущей (или заданной) локалью. К>Я надеюсь, что она корректно обрабатывает лигатуры, умляуты и т.п. К>То есть, немецкие слова Roentgen и Röntgen попадут в одну корзину.
Нет тут проблемы. Достаточно привести к виду, где Roentgen и Röntgen будут одинаковы.
strxfrm делает это.
К>Хеш-функция, читающая строку посимвольно, даст разные значения для слитного и раздельного написания умляута. Получится более сильный предикат, чем искомый — а должен быть более слабый. К>Значит, нам нужна хеш-функция, читающая строку порциями, да ещё в зависимости от локали. К>Давайте попросим разработчиков ОС и компиляторов, чтоб они включили эти хеш-функции в соответствующие системные библиотеки? Дело-то хорошее...
Хеширование результата strxfrm уже долшно работать.
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, jazzer, Вы писали:
J>>очередь сообщений, упорядоченная по таймстемпу с плохим разрешением
AG>Это priority_queue, нет ?
Если я не ошибаюсь, priority_queue постоянно двигает объекты (естественно, как же иначе их в массиве располагать), в отличие от дерева.
А сложность и там и там — логарифм (правда, в дереве еще есть такая хорошая вещь как hinted insertion)
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Alexander G, Вы писали:
AG>>В любом случае, если у слов есть значения, нужен multimap, а не multiset.
I>Чем multiset хуже?
Тем, что в его find, upper_bound, и другие нужно передавать то же, что хранится в нём, т.е. слово со значением.
В multimap поиск по слову находит слово и значение.
Здравствуйте, Roman Odaisky, Вы писали:
Z>>Задача: У Маши в корзине 4 яблока. Мама положила ей в корзинку еще 3 груши. Сколько фруктов в корзинке у Маши?
RO>Здесь нужен std::map<Fruit, std::size_t>, а не multiset.
size() может иметь сложность O(1), а сумма по std::map<Fruit, std::size_t> — O(n)
Здравствуйте, Zigmar, Вы писали:
Z>Здравствуйте, Alexander G, Вы писали: AG>>Зачем может пригодиться multiset — не понимаю.
Z>Задача: У Маши в корзине 4 яблока. Мама положила ей в корзинку еще 3 груши. Сколько фруктов в корзинке у Маши? Z>Решение: Z>
AG>Кто-нибудь можеть привести пример разумного применения?
Пример: есть заказ и его составляющие, т.е. отношение один ко многим.
Можно хранить составляющие в multiset, причем ключем будет ссылка на заказ (ID заказа), тогда по ID заказа можно эффективно выбрать все его составляющие.
Здравствуйте, Кодт, Вы писали:
К>Значит, нам нужна хеш-функция, читающая строку порциями, да ещё в зависимости от локали.
Обычно это решается нормализацией строк в хэш-функции.
Здравствуйте, Alexander G, Вы писали:
AG>Кто-нибудь можеть привести пример разумного применения?
имххо, set и multiset это примерно тожесамое что map и multimap, только без значений value.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>имххо, set и multiset это примерно тожесамое что map и multimap, только без значений value.
Для multimap вижу применение: привязывать к структурам числовые ключи и работать с диапазомами этих ключей методами lower_bound, upper_bound, equal_range. Просто связать ключи и значения — это скорее hash_map чем multimap.
"To protect people you must slay people. To let people live you must let people die. This is the true teaching of the sword."
-Seijuro Hiko, "Rurouni Kensin"
Здравствуйте, Zigmar, Вы писали:
Z>Здравствуйте, Alexander G, Вы писали: AG>>Зачем может пригодиться multiset — не понимаю.
Z>Задача: У Маши в корзине 4 яблока. Мама положила ей в корзинку еще 3 груши. Сколько фруктов в корзинке у Маши? Z>Решение:
Не очень убедительно. Для данной задачи будет лучше vector. Для оптимальой работы при большом количестве фруктов и малом количестве типов фуктов — вариант Roman Odaisky. При большом числе типов фуктов — unordered_multiset.
Здравствуйте, Alexander G, Вы писали: Z>>Задача: У Маши в корзине 4 яблока. Мама положила ей в корзинку еще 3 груши. Сколько фруктов в корзинке у Маши? Z>>Решение: AG>Не очень убедительно. Для данной задачи будет лучше vector. Для оптимальой работы при большом количестве фруктов и малом количестве типов фуктов — вариант Roman Odaisky. При большом числе типов фуктов — unordered_multiset.
Эты была скорее шутка На практике, я не разу не сталкивался с задачей, где мне пришлось пользоваться multiset. Но мне кажется, что такие случае вполне могут быть, как пример выше, когда предикат сравнения не гарантирует тождественности самих объектов.
"To protect people you must slay people. To let people live you must let people die. This is the true teaching of the sword."
-Seijuro Hiko, "Rurouni Kensin"
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, R.K., Вы писали:
RK>>Возможно, для хранения частично упорядоченного множества. Например: AG>2. Тут лучше подходит unordered_mulitset/hash_multiset, а не multiset.
Интересно, как unordered_mulitset может подойти лучше в задаче, в которой требуется упорядочение.
Здравствуйте, Zigmar, Вы писали:
Z>Здравствуйте, Alexander G, Вы писали: Z>>>Задача: У Маши в корзине 4 яблока. Мама положила ей в корзинку еще 3 груши. Сколько фруктов в корзинке у Маши? Z>>>Решение: AG>>Не очень убедительно. Для данной задачи будет лучше vector. Для оптимальой работы при большом количестве фруктов и малом количестве типов фуктов — вариант Roman Odaisky. При большом числе типов фуктов — unordered_multiset. Z>Эты была скорее шутка На практике, я не разу не сталкивался с задачей, где мне пришлось пользоваться multiset. Но мне кажется, что такие случае вполне могут быть, как пример выше, когда предикат сравнения не гарантирует тождественности самих объектов.
Вообще-то предикаты, не гарантирующие тождественности, встречаются сплошь и рядом, а именно — когда ты упорядочиваешь структуры по одному полю и значения этого поля не являются уникальными (например, фамилия).
Здравствуйте, Alexander G, Вы писали:
AG>Кто-нибудь можеть привести пример разумного применения?
Да запросто. Например, у тебя у человека есть набор отработаных смен, и нужно их распределить по датам. std::map<date, shift> не пойдёт, так как могут быть две (или три) смены в один день. Тут-то std::multimap/multiset и помогает.
Здравствуйте, Alexander G, Вы писали:
AG>Кто-нибудь можеть привести пример разумного применения?
например, над множеством объектов требуется построить различные индексы по каким любо ключам.
как вариант, индексы можно делать в виде set или multiset из указателей с соответсвующими компараторами — multisetset<T*, T_compare>
Здравствуйте, jazzer, Вы писали:
RK>>>Возможно, для хранения частично упорядоченного множества. Например: AG>>2. Тут лучше подходит unordered_mulitset/hash_multiset, а не multiset. J>Интересно, как unordered_mulitset может подойти лучше в задаче, в которой требуется упорядочение.
Интересно как в случае multiset (не multimap) извлечь пользу из упорядочения.
Здравствуйте, maq, Вы писали:
maq>Пример: есть заказ и его составляющие, т.е. отношение один ко многим.
maq>Можно хранить составляющие в multiset, причем ключем будет ссылка на заказ (ID заказа), тогда по ID заказа можно эффективно выбрать все его составляющие.
Это multimap, а не multiset, причём скорее даже unordered_multimap
Здравствуйте, sokel, Вы писали:
S>например, над множеством объектов требуется построить различные индексы по каким любо ключам. S>как вариант, индексы можно делать в виде set или multiset из указателей с соответсвующими компараторами — multisetset<T*, T_compare>
Допустим имеем такой multiset (пишу прямо сюда, может не скомпилиться, но думаю код понятен):
struct T { int a, b, c, d, e };
strunct T_compare
: public std::binary_function<T*, T*, bool>
{
T_compare(void) : f_(boost::bind(T::d, _1) < boost::bind(T::d, _2)) {}
bool operator()(T* lhs, T*, rhs) { return f_(lhs, rhs); }
private:
boost::function<bool (T*, T*)> f_;
}
multisetset<T*, T_compare>
Ну вот он упорядочен по d. Дальше что ? Чтобы работать теперь с диапазонами, нужны не ключи, а сами T*. Вряд ли это полезно.
Здравствуйте, Cyberax, Вы писали:
C>Да запросто. Например, у тебя у человека есть набор отработаных смен, и нужно их распределить по датам. std::map<date, shift> не пойдёт, так как могут быть две (или три) смены в один день. Тут-то std::multimap/multiset и помогает.
multimap — да, насколько я понимаю, именно для этого. но multiset — ?
Здравствуйте, maq, Вы писали:
maq>Ну не обязательно, ведь ID это значение поля класса, который будет лежать в multiset, зачем его еще как ключ выносить в map.
Затем, чтобы значение ID можно было передать в eqaul_range.
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, jazzer, Вы писали:
RK>>>>Возможно, для хранения частично упорядоченного множества. Например: AG>>>2. Тут лучше подходит unordered_mulitset/hash_multiset, а не multiset. J>>Интересно, как unordered_mulitset может подойти лучше в задаче, в которой требуется упорядочение.
AG>Интересно как в случае multiset (не multimap) извлечь пользу из упорядочения.
очередь сообщений, упорядоченная по таймстемпу с плохим разрешением
Здравствуйте, Alexander G, Вы писали:
AG>2. Тут лучше подходит unordered_mulitset/hash_multiset, а не multiset.
1) unordered_* и hash_* есть в STL?
2) какая временная сложность у unordered_multiset?
3) как по заданному предикату сравнения (равенства или порядка, неважно) сделать хеш-функцию?
Например, есть функция strcoll, сравнивающая строки в соответствие с текущей (или заданной) локалью.
Я надеюсь, что она корректно обрабатывает лигатуры, умляуты и т.п.
То есть, немецкие слова Roentgen и Röntgen попадут в одну корзину.
Хеш-функция, читающая строку посимвольно, даст разные значения для слитного и раздельного написания умляута. Получится более сильный предикат, чем искомый — а должен быть более слабый.
Значит, нам нужна хеш-функция, читающая строку порциями, да ещё в зависимости от локали.
Давайте попросим разработчиков ОС и компиляторов, чтоб они включили эти хеш-функции в соответствующие системные библиотеки? Дело-то хорошее...
Здравствуйте, igna, Вы писали:
I>Чтобы имитировать привычный пользователю просмотр книжного словаря.
Для пользователя нам надо отображать не всё — всё на экране не поместится.
Значит нужен random access iterator, к которому прибавляется положение скроллбара. Это сортированный vector.
Здравствуйте, Alexander G, Вы писали:
AG>Для пользователя нам надо отображать не всё — всё на экране не поместится. AG>Значит нужен random access iterator, к которому прибавляется положение скроллбара. Это сортированный vector.
Я видел такой скроллбар для просмотра словаря из более чем ста тысяч слов. Использовать его двигая вверх-вниз мышью было довольно неудобно и бессмысленно, все равно не знаешь куда попадешь (хуже чем в книжном словаре). Реально пользователям это было не нужно, они просто хотели видеть слова предшествующие или последующие найденному поиском слову. Для такой функциональности сортированный вектор не нужен, но сортировка все-таки нужна.
Здравствуйте, igna, Вы писали:
I>Я видел такой скроллбар для просмотра словаря из более чем ста тысяч слов. Использовать его двигая вверх-вниз мышью было довольно неудобно и бессмысленно, все равно не знаешь куда попадешь (хуже чем в книжном словаре). Реально пользователям это было не нужно, они просто хотели видеть слова предшествующие или последующие найденному поиском слову. Для такой функциональности сортированный вектор не нужен, но сортировка все-таки нужна.
Хорошо, без скролбара. Хотя скролбаром нужно просто уметь пользоваться — двигать ползунок, затем кликать мжду ползунком и стрелкой, затем кликать по стрелке — вот в такой последовательности точность будет повышаться. А ещё есть клавиши управления курсором.
Всё равно, если пользователь не добавляет слова то лучше вектор.
А если даже взять словарь, где пользователь добавляет слова, нужен mulitmap, а не multiset, потому что у слов есть значения.
Здравствуйте, Alexander G, Вы писали:
AG>Хорошо, без скролбара. Хотя скролбаром нужно просто уметь пользоваться — двигать ползунок, затем кликать мжду ползунком и стрелкой, затем кликать по стрелке — вот в такой последовательности точность будет повышаться. А ещё есть клавиши управления курсором.
Вот если убрать практически бесполезную в данном случае операцию "двигать ползунок" и заменить скроллбар четырьмя кнопками: "кликать между ползунком и стрелкой вверх", "кликать между ползунком и стрелкой вниз", "кликать по стрелке вверх" и "кликать по стрелке вниз", то вектор просто будет не нужен.
AG>Всё равно, если пользователь не добавляет слова то лучше вектор.
Здравствуйте, Alexander G, Вы писали:
AG>А чем multiset::equal_range лучше std::equal_range ?
Теоритически может быть быстрее, если реализована не дословно как 'make_pair(a.lower_bound(k), a.upper_bound(k))', а с использованием некоторых деталей реализации.
AG>std::vector — дефолтный контейнер, это использование других вместо него нужно обосновывать.
+1
Здравствуйте, Alexander G, Вы писали:
AG>Ну вот он упорядочен по d. Дальше что ? Чтобы работать теперь с диапазонами, нужны не ключи, а сами T*. Вряд ли это полезно.
И всё-таки, может быть полезно. Если, например, в сравнении участвует множество полей структуры. Плюс в разных индексах сравниваемые наборы полей могут пересекаться. И в отдельную структуры-ключи выносить не хочется. Для поиска создаем объект на стеке, в нем заполняем нужные для компаратора поля и вперед — получать диапазоны.
P.S. эти проблемы решаются с помощью multiindex вроде, но для себя все вопросы с ассоциативными контейнерами давно решил велосипедом. самодельное дерево + стратегия доступа к линкам в объектах (объекты сами по себе являются нодами). а для порядка — отдельная стратегия (нужна в insert-erase). деревья с фиксированными стратегиями порядка — аналоги stl деревьев. ну и по сути все деревья тогда представляются как своеобразный set или multiset. разница только в стратегиях порядка, определяющих варианты сравнения объектов с ключами (и/или с самим собой) и возможность множественной вставки. это могут быть стратегии упорядовачивания по member-ключу, типа member_order (кстати, можно даже мутить стратегии, которые будут принимать на вход тип ключа, вообще не имеющий отношения к объектам, например поиск по паре типа std::pair а порядок при вставке просто по паре членов структуры, просто чуть сложней стратегия (реализовать сравнение во всех вариантах типа объекта и типа ключа, соответственно стратегии вроде pair-triple-quad-member_order). различные варианты self_order стратегий (как для set). довольно часто попадаются стратегии навроде cast_member_order — по члену предка или потомка при возможности static_cast.
Здравствуйте, igna, Вы писали:
I>Я видел такой скроллбар для просмотра словаря из более чем ста тысяч слов. Использовать его двигая вверх-вниз мышью было довольно неудобно и бессмысленно, все равно не знаешь куда попадешь (хуже чем в книжном словаре). Реально пользователям это было не нужно, они просто хотели видеть слова предшествующие или последующие найденному поиском слову. Для такой функциональности сортированный вектор не нужен, но сортировка все-таки нужна.
1) Советую посмотреть, например, как работает скроллер в лингво.
2) Жизнь такова, что обычно словарей много, а пользователю надо показывать их слияние...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Alexander G, Вы писали:
AG>std::vector — дефолтный контейнер, это использование других вместо него нужно обосновывать.
Хорошо, согласен.
AG>А если даже взять словарь, где пользователь добавляет слова, нужен mulitmap, а не multiset, потому что у слов есть значения.
А вот этот аргумент не понял. У слов есть значения? Можно и под этим углом посмотреть, но зачем? Например пользователь создает новую статью, и часть программы отвечающая за создание объекта Статья знает, что две части этого объекта будут храниться отдельно? Или она этого не знает, и созданный ей объект преобразуется затем к виду подходящему для хранения в multimap?
Здравствуйте, igna, Вы писали:
I>Спасибо за совет, а на что обратить внимание?
Ну подёргай его, понажимай в разные места и посмотри куда попадаешь. Узнаешь много нового. Так же, кстати, и другие словари читят.
Например, популярная темя -- попадать по движению очень длинного скроллера не в любую точку, а в границу логического контекста.
E>>2) Жизнь такова, что обычно словарей много, а пользователю надо показывать их слияние... I>Можно поподробнее? Это аргумент за или против multiset?
Ну не годятся стандартные контейнеры в электронных словарях. Так как тебе надо не вычитывая весь словарь с диска достать из него толкьо кусок, идущий подряд. При этом надо не из одного словаря, а из коллекции и всё это смёржить.
Посомтри, как какой-нибудь e-словарь (например Лингво) работает?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>А вот этот аргумент не понял. У слов есть значения? Можно и под этим углом посмотреть, но зачем? Например пользователь создает новую статью, и часть программы отвечающая за создание объекта Статья знает, что две части этого объекта будут храниться отдельно? Или она этого не знает, и созданный ей объект преобразуется затем к виду подходящему для хранения в multimap?
В любом случае, если у слов есть значения, нужен multimap, а не multiset. Что будет значением multimap это уже другой вопрос.
Если значений нет (орфографический словарь) то нужен set.
Здравствуйте, Erop, Вы писали:
E>Ну не годятся стандартные контейнеры в электронных словарях.
Словарь-то не обязательно должен быть огромным. Представь изначально пустой словарь, заполняемый школьником изучающим иностранный язык. В нем будет максимум несколько тысяч слов.
Здравствуйте, igna, Вы писали:
I>Чем multiset хуже?
Вот кстати этим
multiset: The key value of an element in a multiset may not be changed directly.
multimap: The value of an element in a multimap, but not its associated key value, may be changed directly.
Здравствуйте, Alexander G, Вы писали:
AG>Тем, что в его find, upper_bound, и другие нужно передавать то же, что хранится в нём, т.е. слово со значением.
Строго говоря, это неверно, поскольку можно передавать dummy-значение (а не то значение, "что хранится"), но понятно, что имеется ввиду. Аргумент принят.
Здравствуйте, Alexander G, Вы писали:
AG>Ну вот он упорядочен по d. Дальше что ? Чтобы работать теперь с диапазонами, нужны не ключи, а сами T*. Вряд ли это полезно.
такой вот несколько надуманный пример структуры с поиском по паре ключей:
Здравствуйте, igna, Вы писали:
I>Словарь-то не обязательно должен быть огромным. Представь изначально пустой словарь, заполняемый школьником изучающим иностранный язык. В нем будет максимум несколько тысяч слов.
Известные мне электронные словари расчитаны на возможноть подключения очень больших словарей.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Зачем существует std::multiset
От:
Аноним
Дата:
19.06.08 07:49
Оценка:
Здравствуйте, Alexander G, Вы писали:
AG>Кто-нибудь можеть привести пример разумного применения?
//Все очень просто
//multiset может хотябы пригодится для случаев когда он хранит класс
//для которого перегружен оператор меньше таким образом что сравнивается одно поле
//а второе поле игнорируется но при этом вторые поля у сравниваемых объектов могут отличаться
//здесь собсвтенно мультисет и может пригодится
//как пример #include <iostream>
#include <string>
#include <set>
#include <iterator>
struct asc{
int key;
std::string value;
asc( int k, std::string v ) : key(k),value(v) { }
asc( ) {}
bool operator < ( const asc &object ) const {
return key < object.key;
}
};
int main() {
std::set< asc > so;
std::multiset< asc > sm;
so.insert( asc( 1, "before" ) );
so.insert( asc( 1, "after" ) );
sm.insert( asc( 1, "before" ) );
sm.insert( asc( 1, "after" ) );
std::cout << "so size = " << so.size() << std::endl; //здесь мы потеряем значение
std::cout << "sm size = " << sm.size() << std::endl; //здесь все в порядке
}
А>//Все очень просто
А>//multiset может хотябы пригодится для случаев когда он хранит класс
А>//для которого перегружен оператор меньше таким образом что сравнивается одно поле
А>//а второе поле игнорируется но при этом вторые поля у сравниваемых объектов могут отличаться
А>//здесь собсвтенно мультисет и может пригодится
А>
Я понимаю что это будет работать, но это хуже multimap, т.к. :
Стандартном не предусмотрено изменение value здесь, в отличии от multimap.
Не предусмотрен поиск по отдельно key.
Не забывайте также, что для просто key-value лучше подходят хеш-таблицы. Упорядоченное по ключу множество нужно тогда, когда требуется порядок элементов.
Всё это вместе приводит к тому, что я не могу придумать случая, когда multiset был бы правильным выбором контейнера.