Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Есть ли find_if для std::set, как указать свою функцию сравнения? 
V
    Опции темы
zim22
Дата 23.11.2009, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Здравствуйте.
Нужно в контейнере set произвести поиск объектов. 
Но встроенный std::set::find не устраивает, т.к. он ищет точное соответствие по ключу, а мне нужно определённое мной сравнение.
У меня при поиске два объекта будут равны друг другу, если поля double d  обоих объектов отличаются друг от друга не более, чем на 50%.
Как это сделать? Заранее спасибо.
***
В принципе я могу использовать find_if из algorithm, но тогда я потеряю логарифмическое время поиска в сравнении с std::set::find, чего не хотелось бы...

Код

#include <set>
#include <string>

struct CompoundObject {
  friend bool operator<(const CompoundObject &lhs, const CompoundObject &rhs);
  int i;
  double d;
  std::string s;  
};

bool operator<(const CompoundObject &lhs, const CompoundObject &rhs) {
  // сортировать объекты сначала по целой части
  if (lhs.i != rhs.i)
    return lhs.i < rhs.i;
  // затем по вещественной
  if (lhs.d != rhs.d)
        return lhs.d < rhs.d;
  // и в конце по строке
  if (lhs.s != rhs.s)
    return lhs.s < rhs.s;

  return false; // объекты равны между собой
  
}

int main()
{
  std::set<CompoundObject> objectSet;
  CompoundObject first = {10, 20.33, "yo"};
  objectSet.insert(first);

  CompoundObject search = {10, 17.35, "yo"};
  std::set<CompoundObject>::iterator it = objectSet.find(search); // !!! должен вернуть итератор на объект first

  return 0;
}


Это сообщение отредактировал(а) zim22 - 23.11.2009, 13:13


--------------------
PM MAIL   Вверх
xvr
Дата 23.11.2009, 14:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



  •  Переделываешь bool operator<(const CompoundObject &lhs, const CompoundObject &rhs)  что бы сравнение по вещественной части было в конце
  •  Вычисляешь диапазон CompoundObject :: d для поиска
  •  С помощью lower_bound ищешь начало объектов в set
  •  Далее линейный перебором шагаешь до конца диапазона


Это сообщение отредактировал(а) xvr - 23.11.2009, 14:20
PM MAIL   Вверх
baldina
Дата 23.11.2009, 14:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата
логарифмическое время поиска
достигается за счет того, что элементы в set уже упорядочены по определенному (заданному Вами!) закону. для использования другого способа упорядочения c сохранением эффективного поиска потребуется построить новую структуру данных.
если задача поиска по разным критериям имеет систематический характер, можно использовать boost::multi_index.

если в данном случае сравнение с 50% точностью должно производиться всегда, то достаточно модифицировать 
Код

  // затем по вещественной
  if (lhs.d != rhs.d)
        return lhs.d < rhs.d;

на 
Код

  // затем по вещественной
  if (fabs (lhs.d - rhs.d)/max (fabs(lhs.d), fabs(rhs.d)) < 0.5)
        return lhs.d < rhs.d;



Это сообщение отредактировал(а) baldina - 23.11.2009, 14:22
PM MAIL   Вверх
xvr
Дата 23.11.2009, 14:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(baldina @ 23.11.2009,  14:19)
если в данном случае сравнение с 50% точностью должно производиться всегда, то достаточно модифицировать 
Код

  // затем по вещественной
  if (lhs.d != rhs.d)
        return lhs.d < rhs.d;

на 
Код

  // затем по вещественной
  if (fabs (lhs.d - rhs.d)/max (fabs(lhs.d), fabs(rhs.d)) >= 0.5)
        return lhs.d < rhs.d;

В таком случае придется set заменить на multiset, т.к. ключи начнут дублироваться

PM MAIL   Вверх
baldina
Дата 23.11.2009, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата

В таком случае придется set заменить на multiset, т.к. ключи начнут дублироваться

согласен, начнут. но по определению zim22 это означает что ключи одинаковы, а если нет разницы, зачем хранить больше?  smile 
кстати, алгоритм с поиском lower_bound имеет трудоемкость O(n); худший случай, когда все ключи отличаются не более чем на 50%. 

если знать задачу поподробней, можно было бы подумать как лучше организовать
PM MAIL   Вверх
zim22
Дата 23.11.2009, 14:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(baldina @  23.11.2009,  13:27 Найти цитируемый пост)
но по определению zim22 это означает что ключи одинаковы,

они эквивалентны при выборе подходящих вариантов обмена квартир. однако в самом set дубликаты не допускаются.
Цитата(baldina @  23.11.2009,  13:27 Найти цитируемый пост)
если знать задачу поподробней, можно было бы подумать как лучше организовать

без проблем smile 

Цитата

Написать программу учета заявок на обмен квартир и поиска вариантов обмена.

Каждая заявка содержит фамилию и инициалы заявителя, а также сведения о двух квартирах: требуемой (искомой) и имеющейся. Сведения о каждой квартире содержат: количество комнат, площадь, этаж, район.

Программа должна обеспечивать выбор с помощью меню и выполнение следующих функций:

1) ввод заявки на обмен;
2) поиск в картотеке подходящего варианта: при совпадении требований и предложений по количеству комнат и этажности и различии по показателю «площадь» в пределах 10% выводится соответствующая карточка и удаляется из списка, в противном случае поступившая заявка включается в картотеку;
3) вывод всей картотеки.

Хранение данных организовать с применением контейнерного класса set.




Это сообщение отредактировал(а) zim22 - 23.11.2009, 14:43


--------------------
PM MAIL   Вверх
baldina
Дата 23.11.2009, 14:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



ну, дык, оно самое. 
Цитата
совпадении требований и предложений по количеству комнат и этажности и различии по показателю «площадь» в пределах 10%
 и есть ключ. дубликатов не будет: карточка либо добавляется, либо выводится и удаляется.
т.е. оператор сравнения должен сравнивать количество комнат и этажность точно, а площадь с 10% точностью.

Добавлено через 1 минуту и 15 секунд
zim22, где такие программы заставляют писать? прост любопытно

Добавлено через 5 минут и 29 секунд
вообще-то задание либо не полно, либо противоречиво. дело в том, что при вводе (by design, ввиду требования использовать set) производится поиск карточки; при совпадении ключей добавления не будет. с другой стороны при поиске выводится единственный вариант.
это скорее всего означает, что поиск варианта и ввод суть одна операция.
PM MAIL   Вверх
zim22
Дата 23.11.2009, 15:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(baldina @  23.11.2009,  13:49 Найти цитируемый пост)
что поиск варианта и ввод суть одна операция.

это похожие операции. но они не равнозначны.
ввод - это сохранение в set новой, уникальной заявки. в которой хоть одно поле отличается от уже имеющихся в set (иначе set::insert не пройдёт).
поиск варианта - это вывод всех заявок, в которых количество комнат и этажей совпадает и 10% отклонение по площади. т.е. найдена может быть больше, чем одна заявка.
Цитата(baldina @  23.11.2009,  13:49 Найти цитируемый пост)
zim22, где такие программы заставляют писать? прост любопытно

никто не заставляет. это я нашёл на просторах интернета лабораторную из института. мне она понравилась - я решил реализовать smile
я таким способом проверяю свой прогресс в С++ - спустя пару месяцев потом посмотрю на эту лабу и если захочется плеваться от кода - значит всё нормально, иначе - это плохо, т.к. ничего нового я за это время не узнал.


Это сообщение отредактировал(а) zim22 - 23.11.2009, 15:07


--------------------
PM MAIL   Вверх
xvr
Дата 23.11.2009, 15:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(baldina @ 23.11.2009,  14:27)
кстати, алгоритм с поиском lower_bound имеет трудоемкость O(n); худший случай, когда все ключи отличаются не более чем на 50%. 

Это означает, что поиск вернет ВСЕ ключи. Так что тут O(n) скорее всего не применимо. В общем случае все же будет log(n)

PM MAIL   Вверх
baldina
Дата 23.11.2009, 15:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата

вывод всех заявок

в задании не сказано... 
ну тогда искать стандартным find-ом или, как предложил xvr, слегка оптимизировать процесс, в среднем поиск будет эффективнее, чем линейный.

2xvr
Цитата

Это означает, что поиск вернет ВСЕ ключи. Так что тут O(n) скорее всего не применимо. В общем случае все же будет log(n)

если поиск вернет все ключи, то алгоритм затратит линейное время: алгоритм не может иметь зависимость времени работы меньше, чем объем обрабатываемых данных. если требуется вывести n ключей, то алгоритм не может затратить времени меньше, чем с*n.
что такое "в общем"? есть понятия в лучшем, худшем и среднем случае. в среднем, возможно (и так кажется интуитивно), будет порядок роста log(N), однако это требует доказательства.
PM MAIL   Вверх
bsa
Дата 23.11.2009, 15:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196




M
bsa
zim22, вопросы тебе, думаю, следует задавать в другом разделе, а то тебе ответить могут только форумчане со статусом не ниже "опытный". А новички так вообще не поймут.


Это сообщение отредактировал(а) bsa - 23.11.2009, 15:50
PM   Вверх
baldina
Дата 23.11.2009, 15:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата

искать стандартным find-ом

некрасиво. если действительно в результате получается диапазон, то lower_bound/upper_bound дают результат наиболее эффективно, это простое и красивое решение.

PM MAIL   Вверх
zim22
Дата 23.11.2009, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(bsa @  23.11.2009,  14:48 Найти цитируемый пост)
zim22, вопросы тебе, думаю, следует задавать в другом разделе,

хорошо. буду перебираться в "С++ общие вопросы" smile


--------------------
PM MAIL   Вверх
xvr
Дата 23.11.2009, 19:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(baldina @ 23.11.2009,  15:32)
2xvr
Цитата

Это означает, что поиск вернет ВСЕ ключи. Так что тут O(n) скорее всего не применимо. В общем случае все же будет log(n)

если поиск вернет все ключи, то алгоритм затратит линейное время: алгоритм не может иметь зависимость времени работы меньше, чем объем обрабатываемых данных. 

Алгоритм должен ВЕРНУТЬ все ключи. А это значит, что каким бы он не был, ему придется их перебрать все. Т.е. данный случай - вырожденный. При ЛЮБОМ алгоритме поиска будет затрачено O(n) времени для ВОЗВРАТА ключей.

Можно разделить процедуру на 2 части: поиск начала возвращаемых данных и перебор для собственно возврата данных. Первая часть делается за log(n) (для lower_bound) и зависит от алгоритма поиска, вторая не зависит от алгоритма поиска а целиком зависит от данных.

Цитата

если требуется вывести n ключей, то алгоритм не может затратить времени меньше, чем с*n.
Угу, поиск начала - log(n), а выдача значений от алгоритма не зависит (хотя она и O(n))

Цитата

что такое "в общем"? есть понятия в лучшем, худшем и среднем случае.
Я имел в виду эффективность поиска, это приблизительно 'в среднем случае'

PM MAIL   Вверх
zim22
Дата 23.11.2009, 20:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(xvr @  23.11.2009,  18:51 Найти цитируемый пост)
 поиск начала возвращаемых данных и перебор для собственно возврата данных

хороший вариант. мне нравится.

только как я понял, все рассуждения базируются на этом:
Цитата(xvr @  23.11.2009,  13:19 Найти цитируемый пост)
 Переделываешь bool operator<(const CompoundObject &lhs, const CompoundObject &rhs)  что бы сравнение по вещественной части было в конце

но мне не хотелось бы сравнение по вещественной части ограничивать каким-то расположением.
в идеале пользователь класса должен был с лёгкостью менять порядок сортировки.
первоначально я организовал эту лёгкость с помощью макросов:
Код

#define SORTING_IN_THIS_ORDER_OF_PRIORITY(FIRST, SECOND, THIRD, FOURTH, FIFTH) \
  FIRST SECOND THIRD FOURTH FIFTH

#define GENERATE_BODY_OF_IF_FUNCTION(FUNCTION_NAME, CATEGORY_OF_FLAT) \
  if (lhs.CATEGORY_OF_FLAT.FUNCTION_NAME() != rhs.CATEGORY_OF_FLAT.FUNCTION_NAME()) \
    return lhs.CATEGORY_OF_FLAT.FUNCTION_NAME() < rhs.CATEGORY_OF_FLAT.FUNCTION_NAME();

#define M_AREA(X) GENERATE_BODY_OF_IF_FUNCTION(getArea, X)  
#define M_FLOOR(X) GENERATE_BODY_OF_IF_FUNCTION(getFloor, X)    
#define M_ROOMS_NUMBER(X) GENERATE_BODY_OF_IF_FUNCTION(getRooms, X)      
#define M_DISTRICT(X) GENERATE_BODY_OF_IF_FUNCTION(getDistrict, X)        
#define M_APPLICANT_NAME(X) \
  if (lhs.X.applicantName_ != rhs.X.applicantName_) \
    return lhs.X.applicantName_ < rhs.X.applicantName_;

#define OWNED owned_
#define SEARCHED searched_


bool operator<(const Application &lhs, const Application &rhs) {
  
  SORTING_IN_THIS_ORDER_OF_PRIORITY(    
    M_AREA(OWNED), M_FLOOR(OWNED), M_ROOMS_NUMBER(OWNED), 
    M_DISTRICT(OWNED), M_APPLICANT_NAME(OWNED)
  )

  SORTING_IN_THIS_ORDER_OF_PRIORITY(
    M_AREA(SEARCHED), M_FLOOR(SEARCHED), M_ROOMS_NUMBER(SEARCHED), 
    M_DISTRICT(SEARCHED), M_APPLICANT_NAME(SEARCHED)
  )  
  return false;
}

но код мне показался слишком громоздким и я от них отказался в пользу этого:
Код

// сортировка квартир
bool operator<(const Flat &lhs, const Flat &rhs) {
  // сортировать по площади (сравнение по вещественной части)
  if (lhs.area_ != rhs.area_)
    return lhs.area_ < rhs.area_;

  // сортировать по номеру этажа
  if (lhs.floor_ != rhs.floor_)
    return lhs.floor_ < rhs.floor_;

  // сортировать по количеству комнат
  if (lhs.roomsNumber_ != rhs.roomsNumber_)
    return lhs.roomsNumber_ < rhs.roomsNumber_;

  // сортировать по району
  if (lhs.district_ != rhs.district_)
    return lhs.district_ < rhs.district_;

  return false; // // объекты равны между собой
}



--------------------
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1369 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.