所以我有这个相对简单的问题,并且想知道它的解决方案是否已经存在。
我必须将一个值从一个范围转换为另一个范围。如果只有一个范围,像这样:
{-30.0, 30.0} -> {25.0, 50.0}
本来很容易。 但我有一组范围:
{-30.0, -20.0} -> {25.0, 30.0}
{-20.0, 0.0} -> {30.0, 40.0}
{ 0.0, 30.0} -> {40.0, 50.0}
一种解决方案是对每次访问进行线性搜索。 另一种解决方案是使范围具有相等的长度,以便可以直接映射输入值。
有谁知道比线性搜索解决方案更好?或者,如果已经存在执行此类转换的容器?
非常感谢。
答案 0 :(得分:0)
我认为范围不能重叠。 (域名和范围)
我建议对范围进行排序
这样,您就可以使用O(log n)
来查询范围。
在某些输入模式中,这种方法可能是合适的: -
转换它: -
{-30.0, -20.0} -> {25.0, 30.0}
{-20.0, 0.0} -> {30.0, 40.0}
{ 0.0, 30.0} -> {40.0, 50.0}
更多制服: -
float [] inputRange = {-30,-20, -10,0 ,10 ,20 ,30};
float [] outputRange = {25 ,30 ,*35*,40,*43.3333*,*43.6667*,50};
//* is a pre-calculated
然后,您只能使用O(1)
进行查询。
缺点: -
答案 1 :(得分:0)
当@javaLover回复时,而不是线性 - O(n)操作,
当n个范围时,你可以找到合适的范围O(log n)
操作,例如使用std::map
:
#include <utility>
#include <map>
#include <algorithm>
#include <iostream>
int main()
{
using Range = std::pair<double, double>;
struct RangeLess {
bool operator()(const Range &a, const Range &b) const {
return a.first < b.first && a.second < b.second;
}
};
using RangeMap = std::map<Range, Range, RangeLess>;
const RangeMap ranges_map = {
{{-30.0, -20.0}, {25.0, 30.0}},
{{-20.0, 0.0}, {30.0, 40.0}},
{ {1.0, 30.0}, {40.0, 50.0}},
};
auto map_point = [&ranges_map](double x) -> double {
const Range x_range = {x, x};
auto it = ranges_map.find(x_range);
if (it == ranges_map.end()) {
return x;
} else {
const Range &in = it->first;
const Range &out = it->second;
return (x - in.first) / (in.second - in.first) * (out.second - out.first) + out.first;
}
};
const double patterns[] = {-40, -30, -25, -20, 0.5, 5, 40};
for (auto &&x : patterns) {
std::cout << x << " -> " << map_point(x) << "\n";
}
}
答案 2 :(得分:0)
这是对user1034749提出的解决方案的详细说明。它使用std::set和一个包含两对值的类。
template<class SRC, class DST>
class Range {
public:
std::pair<SRC, SRC> src_range;
std::pair<DST, DST> dst_range;
bool operator<(const Range& rhs) const {
return (src_range.first < rhs.src_range.first) && (src_range.second < rhs.src_range.second);
}
Range(SRC src_first, SRC src_second,
DST dst_first, DST dst_second)
: src_range(src_first, src_second),
dst_range(dst_first, dst_second) {}
Range()
: src_range(0, 0),
dst_range(0, 0) {}
Range(SRC value)
: src_range(value, value),
dst_range(value, value) {}
};
bool mapping_test() {
// Mapping
std::set<Range<double,double>>
z = {{-30.0, -20.0, -10.0, -5.0},
{-20.0, 0, -5.0, 5.0},
{0, 10.0, 5.0, 8.0}};
// Find range that contains this value
Range<double,double> f{8.0};
auto d = z.find(f);
if(d != z.end()) {
std::cout << "Found {" << (*d).dst_range.first
<< ","
<< (*d).dst_range.second
<< "}\n";
}
return true;
}
在这种情况下,可以找到相关值的范围,包括源范围和目标。 std::set容器中的查找是log(n)复杂度。