Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Март 10, 2012, 15:25



Название: Lookup
Отправлено: Igors от Март 10, 2012, 15:25
Добрый день

Есть контейнер элементы которого имеют какой-то атрибут, пусть цвет. Значение атрибута не уникально, напр в исходном контейнере 4 элемента с красным цветом, 2 с синим и.т.п.

Нужно: имея элемент быстро найти все с тем же цветом.  напр элемент красный - пробежаться по всем остальным красным. Исходный контейнер сортировать/изменять нельзя, создавать любые доп данные - можно.

Спасибо


Название: Re: Lookup
Отправлено: kambala от Март 10, 2012, 15:46
можно сразу завести словарь, ключами которого будут атрибуты, а значениями - векторы/множества указателей на элементы с данным атрибутом


Название: Re: Lookup
Отправлено: qt_user от Март 10, 2012, 16:33
std::multimap
+
pair<const_iterator,const_iterator>
   equal_range ( const key_type& x ) const;


Название: Re: Lookup
Отправлено: Igors от Март 10, 2012, 19:26
Рекомендации понятны, спасибо. А нельзя это сделать без всякого STL и/или Qt, просто на массивах/new? Или так будет сложно/громоздко?


Название: Re: Lookup
Отправлено: kambala от Март 11, 2012, 01:14
а как тогда сопоставлять массив нужному атрибуту (т.е. задать однозначное отображение)? если множество допустимых значений атрибута известно заранее, тогда просто массивами можно конечно.


Название: Re: Lookup
Отправлено: Bepec от Март 11, 2012, 07:01
Можно конечно создать кучу массивов с названиями атрибутов, и в них запихивать элементы.

Конечно это будет жутким костылём, ибо мультимап уже это реализует и вполне сносно.

PS напиши свой собственный мультимап.


Название: Re: Lookup
Отправлено: Disa от Март 11, 2012, 10:47
Вопрос почти по теме, если контейнер не модифицировать после инициализации и если элементы уникальные - что предпочтительнее: set <pair> или все же map?



Название: Re: Lookup
Отправлено: Igors от Март 11, 2012, 10:56
Нельзя модифицировать исходный контейнер, но снабдить элемент доп данными - можно


Название: Re: Lookup
Отправлено: Bepec от Март 11, 2012, 12:02
уникальные - map.
повторяющиеся - pair или мультимап.


Название: Re: Lookup
Отправлено: qt_user от Март 11, 2012, 13:14
Вопрос почти по теме, если контейнер не модифицировать после инициализации и если элементы уникальные - что предпочтительнее: set <pair> или все же map?


я думаю если ключи допустим строка, оператор сравнения для std::string будет работать намного быстрее,
чем для std::pair<std::string, std::string>

хотя это больше зависит от задачи: если можно выделить один ключ - тогда это std::map,
если два значения равноправны и нельзя сказать что из них является ключом - тогда лучше
std::set<std::pair<...> >


Название: Re: Lookup
Отправлено: Disa от Март 11, 2012, 15:00
Ну хотя получается, что грубо у всех множест nlogn для поиска, но и все себя перестраивают при добавлении эллемента.
И еще, как я понимаю в зависимости от константы перед nlogn будет сильно зависеть как контейней будет вести себя при разном количестве эллементов. Не смог обнаружить какие-то тесты по сравнению скорости работы алгоритмов и операторов, мб кому-то попадались на глаза?


Название: Re: Lookup
Отправлено: Igors от Март 11, 2012, 16:13
И еще, как я понимаю в зависимости от константы перед nlogn будет сильно зависеть как контейней будет вести себя при разном количестве эллементов. Не смог обнаружить какие-то тесты по сравнению скорости работы алгоритмов и операторов, мб кому-то попадались на глаза?
Это катастрофически зависит от конкретной реализации, часто также от опций компилятора. Напр (не к ночи будь сказано) у MS это может отличаться на порядки debug/release

На мой взгляд лучшее средство - тщательно продумывать организацию данных, а не ляпать контейнерами абы как. О чем, кстати, и данная тема  :)


Название: Re: Lookup
Отправлено: Igors от Март 12, 2012, 16:18
Можно конечно создать кучу массивов с названиями атрибутов, и в них запихивать элементы.

Конечно это будет жутким костылём, ибо мультимап уже это реализует и вполне сносно.

PS напиши свой собственный мультимап.
Написал  :)

Код
C++ (Qt)
struct CDataLookup {
QList <CElement> mData;    // исходный контейнер
QList <CElement *> mLookup; // указатели отсортированы по атрибуту (цвету)
};
 
// использование
void CDataLookup::ScanByColor( CElement & elem )
{
 for (int i = elem.mLookupIndex; i < mLookup.size(); ++i) {
   if (mLookup[i]->mColor != elem.mColor) break;
   DoSomething(mLookup[i]);  // указатель на элемент с тем же цветом что и elem
 }
}
 

Edit: а можно и вообще не хранить сортированный массив


Название: Re: Lookup
Отправлено: qt_user от Март 13, 2012, 00:53
Можно конечно создать кучу массивов с названиями атрибутов, и в них запихивать элементы.

Конечно это будет жутким костылём, ибо мультимап уже это реализует и вполне сносно.

PS напиши свой собственный мультимап.
Написал  :)

Код
C++ (Qt)
struct CDataLookup {
QList <CElement> mData;
QList <CElement *> mLookup;
};
 
void CDataLookup::ScanByColor( CElement & elem )
{
   for (int i = elem.mLookupIndex; i < mLookup.size(); ++i) {
     if (mLookup[i]->mColor != elem.mColor) break;
   DoSomething(mLookup[i]);
 }
}
 

Edit: а можно и вообще не хранить сортированный массив
это конечно все хорошо, но зачем нужен подобный велосипед если есть тот же
мультимап?
void CDataLookup::ScanByColor( CElement & elem ) - я так понимаю перед каждым вызовом
этой ф-ции нужно заново сортировать QList <CElement *> mLookup; ?


Название: Re: Lookup
Отправлено: Igors от Март 13, 2012, 11:08
это конечно все хорошо, но зачем нужен подобный велосипед если есть тот же
мультимап?
void CDataLookup::ScanByColor( CElement & elem ) - я так понимаю перед каждым вызовом
этой ф-ции нужно заново сортировать QList <CElement *> mLookup; ?
Нет, достаточно один раз отсортировать и вписать в каждый элемент индекс указателя на первый с тем же цветом в сортированном массиве. Хотя есть ходы и получше.

Небольшая разница между "имея элемент" и "имея (значение) цвета" позволяет обойтись без поиска вообще. А от мультимапы я балдею :) Ну ладно, допустим даже "искать по цвету" - но тогда почему не lower_bound? На худой конец С-шный bsearch. Тот же логарифм но сортированный массив указателей куда дешевле чем любой ассоциативный контейнер.


Название: Re: Lookup
Отправлено: qt_user от Март 13, 2012, 22:17
Небольшая разница между "имея элемент" и "имея (значение) цвета" позволяет обойтись без поиска вообще. А от мультимапы я балдею :) Ну ладно, допустим даже "искать по цвету" - но тогда почему не lower_bound? На худой конец С-шный bsearch. Тот же логарифм но сортированный массив указателей куда дешевле чем любой ассоциативный контейнер.
мультимап как и мап реализованы на основе красно-черного бинарного дерева, которое само балансируется
по высоте, и исключается случай вырождения дерева в список, поэтому гарантировано логарифм при основе 2


Название: Re: Lookup
Отправлено: twp от Март 13, 2012, 23:23
мультимап как и мап реализованы на основе красно-черного бинарного дерева, которое само балансируется
по высоте, и исключается случай вырождения дерева в список, поэтому гарантировано логарифм при основе 2

Цитата: Assistant
The QMap class is a template class that provides a skip-list-based dictionary.


Название: Re: Lookup
Отправлено: V1KT0P от Март 13, 2012, 23:38
Добрый день

Есть контейнер элементы которого имеют какой-то атрибут, пусть цвет. Значение атрибута не уникально, напр в исходном контейнере 4 элемента с красным цветом, 2 с синим и.т.п.

Нужно: имея элемент быстро найти все с тем же цветом.  напр элемент красный - пробежаться по всем остальным красным. Исходный контейнер сортировать/изменять нельзя, создавать любые доп данные - можно.

Спасибо
Ну у меня в голове родился такой интересный костыль. Если тебе надо быстро пройтись по всем элементам но не критична скорость добавления/удаления новых элементов и не жалко продублировать данные то вот как можно замутить через-жопу:
QList<Элемент> - Список элементов.
QMap<Атрибут,*QList<Элемент> > - Вот здесь будем хранить дублированные данные.

Вот у нас есть элемент и нам надо пройтись по всем таким же элементам с таким же атрибутом. Типа псевдокод:
QList<Элемент> *список = QMap.value(Элемент.Атрибут);
Ну и дальше foreach список с проверкой на то что элемент не равняется первоначальному.

Ну и при вставке и удалении надо будет синхронизовать с QMap<Атрибут,*QList<Элемент> > но если этот контейнер и дополнительный вынести в отдельный класс то можно там все так красиво в обертку завернуть =).


Название: Re: Lookup
Отправлено: qt_user от Март 14, 2012, 10:40
The QMap class is a template class that provides a skip-list-based dictionary.

не очень понял что значит "skip-list-based dictionary", но вот что говорит вики:
Associative containers are designed to be especially efficient in accessing its elements by their key, as opposed to sequence containers which are more efficient in accessing elements by their position.[1] Associative containers are guaranteed to perform operations of insertion, deletion, and testing whether an element is in it, in logarithmic time - O(log n). As such, they are typically implemented using self-balancing binary search trees and support bidirectional iteration. Iterators and references are not invalidated by insert and erase operations, except for iterators and references to erased elements.
http://en.wikipedia.org/wiki/Associative_containers_(C%2B%2B)

self-balancing binary search tree - это и есть самобалансируещее красно-черное дерево


Название: Re: Lookup
Отправлено: twp от Март 14, 2012, 10:53
не очень понял что значит "skip-list-based dictionary", но вот что говорит вики:
На вики есть и про Skip list (Список с пропусками) (http://ru.wikipedia.org/wiki/Список_с_пропусками)


Название: Re: Lookup
Отправлено: Igors от Март 14, 2012, 12:53
Желание вооружиться знаниями вполне нормально, но Вы можете думать сами?  :)

Для задачи изложенной в теме - вообще не нужны никакие мапы и/или др ассоциативные контейнеры, проход вообще выполняется без поиска, за счет того что нужные данные просчитываются один раз и сохраняются в элементы. Это можно с тем же успехом делать и С массивами.

Если же рассматривать др, более общую задачу - уметь находить все "по цвету" при условии что в исходный контейнер добавляются/удаляются элементы - то и здесь можно найти ходы намного лучше шаблонов STL, как по скорости, так и по расходу памяти. Правда они не будут такими общими/универсальными/очевидными.