我需要创建一个查找表,它将长度链接到一个时间间隔(两者都是数据类型为double)。键在插入时线性增加,因此它已经被排序(也许unordered_map会更好?)。
我正在寻找的方法是找到一个最符合当前长度的键来获取时间值,或者更好地找到围绕长度的两个键(给定键位于它们之间)所以我可以找到两个时间值之间的插值。
我还需要尽可能最佳的性能,因为它会实时调用。
编辑:我宁愿以下是对下面第一个答案的评论,但格式很难阅读。
我尝试执行以下操作,但它似乎返回相同的迭代器(5.6):
std::map<double, double> map;
map.insert(std::pair<double, double>(0.123, 0.1));
map.insert(std::pair<double, double>(2.5, 0.4));
map.insert(std::pair<double, double>(5.6, 0.8));
std::map<double, double>::iterator low, high;
double pos = 3.0;
low = map.lower_bound(pos);
high = map.upper_bound(pos);
我如何得到“低”&#39;指向最后一个元素&lt;比用于搜索的密钥?
编辑2: 傻我,低......如果它不是第一个元素,它会做到这一点。
到达那里:)
答案 0 :(得分:17)
为此,您可以使用std::map::lower_bound
返回指向第一个不小于key的元素的迭代器。
返回一个范围,其中包含容器中具有给定键的所有元素。
在您的情况下,如果您想要最近的条目,则需要检查返回的条目和之前的条目并比较差异。像这样的东西可能会起作用
std::map<double, double>::iterator low, prev;
double pos = 3.0;
low = map.lower_bound(pos);
if (low == map.end()) {
// nothing found, maybe use rbegin()
} else if (low == map.begin()) {
std::cout << "low=" << low->first << '\n';
} else {
prev = std::prev(low);
if ((pos - prev->first) < (low->first - pos))
std::cout << "prev=" << prev->first << '\n';
else
std::cout << "low=" << low->first << '\n';
}
答案 1 :(得分:5)
&#34;可能获得最佳效果&#34; - 如果您按递增顺序插入元素,则可以push_back
/ emplace_back
将它们转换为std::vector
然后使用std::lower_bound
- 您将获得更好的缓存利用率,因为数据将被打包到连续的地址空间中。
答案 2 :(得分:3)
您当然可以使用lower_bound和upper_bound,它们在运行时是对数的。他们应该做你想做的事。
std::map<double,double>::iterator close_low;
//... your_map ...
close_low=your_map.lower_bound (current_length);
这应该给你一个迭代器,它的第一个map元素的键是&lt;当前长度。同样使用upper_bound并且你有时间被包围。
答案 3 :(得分:2)
这里的函数std::lower_bound()
和std::upper_bound()
非常有用。
lower_bound()
为您正在寻找的值提供>=
的第一个元素; upper_bound()
提供的第一个元素是>
而不是值。
例如,在以下列表中搜索值5
:{1,3,5,5,6}
1 使用lower_bound()
返回第三个元素,而upper_bound()
会返回第五个元素。
如果这两个函数返回相同的内容x
,那么您要查找的值不会出现在列表中。
它之前的值为x-1
,紧随其后的值为x
。
1 正如Tony D在评论中指出的那样,问题是地图,通常不包含重复的元素。 我保留这个例子来说明这两个函数。
答案 4 :(得分:0)
完整的通用解决方案(来自Olaf Dietsche的answer的原始思想):
#include <map>
#include <iostream>
#include <cstdint>
template <typename T1, typename T2>
T1 findClosestKey(const std::map<T1, T2> & data, T1 key)
{
if (data.size() == 0) {
throw std::out_of_range("Received empty map.");
}
auto lower = data.lower_bound(key);
if (lower == data.end()) // If none found, return the last one.
return std::prev(lower)->first;
if (lower == data.begin())
return lower->first;
// Check which one is closest.
auto previous = std::prev(lower);
if ((key - previous->first) < (lower->first - key))
return previous->first;
return lower->first;
}
int main () {
double key = 3.3;
std::map<double, int> data = {{-10, 1000}, {0, 2000}, {10, 3000}};
std::cout << "Provided key: " << key << ", closest key: " << findClosestKey(data, key) << std::endl;
return 0;
}
答案 5 :(得分:0)
#include <map>
template <typename T1, typename T2>
std::map<T1, T2>::iterator nearest_key(const std::map<T1, T2>& map, T1 key) {
auto lower_bound = map.lower_bound(key);
auto upper_bound = lower_bound; upper_bound++;
if (lower_bound == map.end()) return upper_bound;
if (upper_bound == map.end()) return lower_bound;
unsigned int dist_to_lower = std::abs((int)lower_bound->first - (int)key);
unsigned int dist_to_upper = std::abs((int)upper_bound->first - (int)key);
return (dist_to_upper < dist_to_lower) ? upper_bound : lower_bound;
}
答案 6 :(得分:0)
以上是错误的。应该是这样的 模板
typename std::map<T1, T2>::const_iterator nearest_key(const std::map<T1, T2>& map, T1 key)
{
auto lower_bound = map.lower_bound(key);
if (lower_bound == map.end()) return --lower_bound;
auto upper_bound = lower_bound; upper_bound++;
if (upper_bound == map.end()) return lower_bound;
auto dist_to_lower = lower_bound->first - key;
auto dist_to_upper = upper_bound->first - key;
return (dist_to_upper < dist_to_lower) ? upper_bound : lower_bound;
}