// O(KN) running median computation (can be improved to O(log K * N) // with a min-heap and max-heap. inline void runmed(vector<double> &x, vector<double> &m) { double n = x.size(); long k = (long)min( ( n - 1 ) / 2, ceil(0.1*n) ); // Automatically estimate K for runs. m.resize(x.size()); long k2 = k / 2; vector<double> x2(k); // Advance along vector. for(long i = 0; i < (long)x.size(); i++) { long start = max(0L, i - k2); long end = min((long)x.size(), i + k2 + 1); x2.resize(end - start); // Copy run into another vector (becaused _median modifies // original order). int j = 0; while(start < end) { x2[j] = x[start]; j++; start++; } // Compute median using that vector. m[i] = _median(x2.begin(), x2.end()); } }
boundary_t<Itr> _partition(Itr begin, Itr end) { Itr median = _median(begin, --end); std::swap(*begin, *median); Itr pivot = begin++, next = begin; while (next != end) { if (*next < *pivot) std::swap(*(begin++), *(next++)); else if (*next > *pivot) std::swap(*next, *(end--)); else ++next; } std::swap(*pivot, *(--begin)); return {begin, end}; }
// This version of median will change the order of elements. inline double median_unsafe(vector<double> &data) { if(data.size() == 0) { std::cerr << "no data for median()" << std::endl; exit(1); } return _median(data.begin(), data.end()); }