#c #algorithm
#c #алгоритм
Вопрос:
Я использую std::unique
для объединения кластеров в вектор с плавающей точкой, используя метод equals с большим эпсилоном. Проблема в том, что он выполняет запуски, подобные 1, и превращает их в 2.
Хотя я хочу, чтобы он объединял их, как при использовании среднего значения по «равным» точкам, превратите их в 3.
(1) ... . .... .....
(2) . . . .
(3) . . . .
Как я могу это сделать, используя стандартную библиотеку C ?
Комментарии:
1. Каков формат данных? Это не может быть просто
std::vector<float>
так, иначе вы потеряете позиционирование. Если я вас не неправильно понял.2. @MooingDuck: так и есть, значение — это позиция. первый из них похож на 1,2,3,20,25,26,27,28,35,36,37,38,39.
3. Всегда ли «запуски» являются последовательными?
4. Я считаю, что было бы проще просто написать алгоритм самостоятельно, а не создавать какой-то супер предикат, который будет усреднять вещи для вас.
5. «метод equals с большим эпсилоном» не является отношением эквивалентности, поэтому его
std::unique
вообще нельзя использовать.
Ответ №1:
Нет, нет стандартного алгоритма, который может делать то, что вы хотите. Тем не менее, это не невероятно сложно. Я попытался сделать минимальные предположения об итераторах, поэтому это должно работать с любым итератором прямого ввода.
#include <iostream>
template<class initer, class outiter, class predicate>
outiter average_runs(initer begin, initer end, outiter out, predicate pred) {
//quit if no range
if (begin == end)
return out;
initer endrun = begin;
do {
//find end of run
while(endrun 1 != end amp;amp; pred(*endrun,*(endrun 1)))
endrun;
//move "begin" to the middle
std::advance(begin, std::distance(begin,endrun)/2);
//output the result
*out = *begin;
//start next run
begin = endrun;
} while(endrun != end);
return out;
}
bool intclose(int l, int r)
{ return r-l <= 1;}
int main() {
int array[13] = {1,2,3,20,25,26,27,28,35,36,37,38,39};
int output[13] = {};
int* end = average_runs((int*)array, array 13, (int*)output, amp;intclose);
for(int* c = output; c<end; c)
std::cout << *c << ' ';
return 0;
}
//displays: 2 20 26 37
Комментарии:
1. Выражение
(endrun-begin)
не гарантируется для прямого итератора.2. Также я не могу найти гарантии, что если
fwditer a=b; b ; a ;
этоa
иb
«указать» на одно и то же «местоположение». Это означает, что итераторы istream, вероятно, с треском провалятся в этом и подобных алгоритмах.3. Было бы поистине чудесно, если бы вы могли найти середину ряда, даже не зная, каким будет следующее число, не так ли? 😉
4. Если бы желания были лошадьми, у меня были бы крылья! (или что-то в этом роде)