Название: [Решено][STL] Найти ближайшее меньшее или большее значение.
Отправлено: kuzulis от Сентябрь 16, 2013, 20:53
Доброго всем времени. Задача: Есть отсортированный вектор целых значений. Необходимо вернуть ближайшее больше или ближайшее меньшее значение относительно заданного, т.е.: C++ (Qt) int main(int argc, char *argv[]) { int myints[] = {16,32,64,128,256,512,1024,2048}; std::vector<int> v(myints,myints + 8); std::vector<int>::iterator low, up; low = std::near_lower(v.begin(), v.end(), 230); // up = std::near_upper(v.begin(), v.end(), 230); // std::cout << "near lower " << (*low) << '\n'; std::cout << "near upper" << (*up) << '\n'; return 0; }
Должно вывести: near lower 128 near upper 256
Есть ли в STL готовое решение (что-то типа near_lower(), near_upper())? Интересует стандарт C++98.. Или нужно самому городить огород? :)
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: m_ax от Сентябрь 16, 2013, 21:36
Есть find_if C++ (Qt) int myints[] = {16,32,64,128,256,512,1024,2048}; std::vector<int> v(myints,myints + 8); std::vector<int>::iterator low; int val = 230; if ((low = std::find_if(v.begin(), v.end(), std::bind1st(std::less_equal<int>(), val))) != v.end()) { if (low != v.begin()) --low; std::cout << *low << std::endl; }
Аналогично и для near_upper
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: m_ax от Сентябрь 16, 2013, 22:02
Нет, лучше так не делать..
Наверное проще свою функцию написать.. Не намного больше кода получится..
Edit: (Это будет корректно работать, только если список отсортирован!)
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: _OLEGator_ от Сентябрь 16, 2013, 22:08
Например, методом деления пополам искать.
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: m_ax от Сентябрь 16, 2013, 22:19
Например, методом деления пополам искать.
Только вот не для всех контейнеров это прокатит.. ( Точнее сказать, не для всех это будет эффективно..
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: kuzulis от Сентябрь 16, 2013, 22:22
Да, спасибо, парни. > Например, методом деления пополам искать. Дело в том, что функция то уже есть, но она Си-шная и там тупо перебор каждого значения. Я хотел бы портировать ее на C++ с использованием шаблонов. > Наверное проще свою функцию написать.. Не намного больше кода получится.. А если делать шаблонными near_lower() и near_upper() - То как будет выглядеть код? А то я в шаблонах не очень то.. :) Переписал на шаблонах: C++ (Qt) template<class InputIterator, class T> InputIterator near_lower(InputIterator first, InputIterator last, const T& val) { InputIterator lower; if ((lower = std::find_if(first, last, std::bind1st(std::less_equal<T>(), val))) != last) { if (lower != first) --lower; } return lower; } int main(int argc, char *argv[]) { int myints[] = {16,32,64,128,256,512,1024,2048}; std::vector<int> v(myints,myints + 8); std::vector<int>::iterator low; int val = 230; low = near_lower(v.begin(), v.end(), val); std::cout << "lower " << (*low); return 0; }
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: m_ax от Сентябрь 16, 2013, 22:30
А если делать шаблонными near_lower() и near_upper() - То как будет выглядеть код? А то я в шаблонах не очень то.. :)
Не, всё нормально.. Если вы гарантируете, что список будет отсортирован.. И ещё, конечно, нужно проверять: не вернула ли near_lower end: C++ (Qt) if ((low = near_lower(v.begin(), v.end(), val) != v.end()) { std::cout << *low << std::endl; }
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: kuzulis от Сентябрь 16, 2013, 22:55
Блин, что-то тяжко с шаблонами у меня. Нужно например так реализовать, чтобы при:
val = 1 -> low=-xxxx, up=-xxxx // выход за границы, it::end val = 16 -> low=16, up=16 val = 17 -> low=16, up=32 val = 31 -> low=16, up=32 val = 2048 -> low=2048, up=2048 val = 2049 -> low=-xxxx, up=-xxxx // выход за границы, it::end
Такое возможно? :)
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: m_ax от Сентябрь 17, 2013, 00:59
Вот для произвольной последовательности: C++ (Qt) template<class InputIterator, class T> InputIterator near_lower(InputIterator first, InputIterator last, const T& val) { InputIterator lower = first; while (first != last) { if ((val - *first >= 0) && (val - *first <= fabs(val - *lower))) lower = first; ++first; } return lower; } int main() { std::vector<int> v = {161,-32,64,128,-256,512,1024,2048}; int val = 0; std::vector<int>::iterator low; if ((low = near_lower(v.begin(), v.end(), val)) != v.end()) std::cout << *low << std::endl; return 0; }
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: m_ax от Сентябрь 17, 2013, 01:59
Кстати, есть же стандартные std::lower_bound и std::upper_bound ;D Работают только для отсортированных последовательностей.. C++ (Qt) template<class InputIterator, class T> InputIterator near_lower_s(InputIterator first, InputIterator last, const T& val) { if ((val < *first) || (first == last)) return last; InputIterator lower = std::lower_bound(first, last, val); return (lower == last) ? --lower : lower; }
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: Igors от Сентябрь 17, 2013, 10:10
C++ (Qt) int main(int argc, char *argv[]) { int myints[] = {16,32,64,128,256,512,1024,2048}; std::vector<int> v(myints, myints + sizeof(myints) / sizeof(myints[0])); int resLo, resHi, match = 230; int * bound = std::lower_bound(v.begin(), v.end(), match); if (bound == v.end()) resLo = resHi = v.back(); else { if (*bound == match) resLo = resHi = match; else { resHi = *bound; resLo = (bound == v.begin()) ? resHi : *(bound - 1); } } std::cout << "near lower " << resLo << '\n'; std::cout << "near upper" << resHi << '\n'; return 0; }
lower_bound (upper_bound) - одни из немногих действительно нужных std ф-ций.
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: kuzulis от Сентябрь 17, 2013, 11:07
Спасибо парни, в итоге наваял это: C++ (Qt) #include "stdafx.h" #include <iostream> #include <algorithm> #include <vector> template<class InputIterator, class T> T near_lower(const InputIterator first, const InputIterator last, const T& val) { InputIterator lower = std::lower_bound(first, last, val); if ((val <= *first) || (lower == last) || (first == last)) return val; if (val != *lower) --lower; return (*lower); } template<class InputIterator, class T> T near_upper(const InputIterator first, const InputIterator last, const T& val) { InputIterator upper = std::lower_bound(first, last, val); return ((val <= *first) || (upper == last) || (first == last)) ? val : (*upper); } void tst_lower(std::vector<int>::const_iterator &first, std::vector<int>::const_iterator &last) { int test_sequence[] = {1,16,17,230,256,2000,2048,2049,60000}; std::vector<int> tst(test_sequence, test_sequence + 9); std::vector<int>::const_iterator it = tst.begin(); std::vector<int>::const_iterator end = tst.end(); std::cout << std::endl << "Lower test: " << std::endl; for (it; it != end; ++it) { int low = near_lower(first, last, *it); std::cout << "val " << (*it) << ", lower " << low << std::endl; } } void tst_upper(std::vector<int>::const_iterator &first, std::vector<int>::const_iterator &last) { int test_sequence[] = {1,16,17,230,256,2000,2048,2049,60000}; std::vector<int> tst(test_sequence, test_sequence + 9); std::vector<int>::const_iterator it = tst.begin(); std::vector<int>::const_iterator end = tst.end(); std::cout << std::endl << "Upper test: " << std::endl; for (it; it != end; ++it) { int low = near_upper(first, last, *it); std::cout << "val " << (*it) << ", upper " << low << std::endl; } } int _tmain(int argc, _TCHAR* argv[]) { int myints[] = {16,32,64,128,256,512,1024,2048}; std::vector<int> v(myints, myints + 8); tst_lower(v.begin(), v.end()); tst_upper(v.begin(), v.end()); return 0; }
Вывод: Lower test: val 1, lower 1 val 16, lower 16 val 17, lower 16 val 230, lower 128 val 256, lower 256 val 2000, lower 1024 val 2048, lower 2048 val 2049, lower 2049 val 60000, lower 60000
Upper test: val 1, upper 1 val 16, upper 16 val 17, upper 32 val 230, upper 256 val 256, upper 256 val 2000, upper 2048 val 2048, upper 2048 val 2049, upper 2049 val 60000, upper 60000
Вроде то что нужно, правда немного изменил алгоритм при выходе за границы.. :)
Название: Re: [STL] Найти ближайшее меньшее или большее значение.
Отправлено: Igors от Сентябрь 17, 2013, 11:28
Засовывать в вектор необязвтельно, можно просто для массива. И обычно C++ (Qt) typedef std::vector<int>::const_iterator TIter;
а то сопля длинная получается :)
Название: Re: [Решено][STL] Найти ближайшее меньшее или большее значение.
Отправлено: kuzulis от Сентябрь 17, 2013, 15:17
Спасибки :)
|