给定一个带有多个值的排序向量,如下例所示:
std::vector<double> f;
f.pushback(10);
f.pushback(100);
f.pushback(1000);
f.pushback(10000);
我正在寻找最优雅的方法来检索任何双d紧邻它的两个值。例如,给定值“45”,我希望返回“10”和“100”。
我在查看lower_bound和upper_bound,但他们并没有按我的意愿行事。你能帮忙吗?
编辑:我已经决定发布我自己的anser,因为它有点是我在这个帖子中得到的所有有用答案的组合。我已经投了那些我认为最有帮助的答案。谢谢大家,
戴夫
答案 0 :(得分:8)
您可以使用STL的lower_bound在几行代码中获得您想要的功能。 lower_bound在底层使用二进制搜索,因此您的运行时为O(log n)。
double val = 45;
double lower, upper;
std::vector<double>::iterator it;
it = lower_bound(f.begin(), f.end(), val);
if (it == f.begin()) upper = *it; // no smaller value than val in vector
else if (it == f.end()) lower = *(it-1); // no bigger value than val in vector
else {
lower = *(it-1);
upper = *it;
}
答案 1 :(得分:8)
您可以使用equal_range()在一次调用中获取这两个值(如果存在)。它返回一个std ::对迭代器,第一个是第一个位置,第二个是你可以在不违反排序的情况下插入传递值的最后一个位置。为了严格满足您的标准,在验证它不等于向量的begin()之后,您必须首先递减迭代器。
答案 2 :(得分:6)
您可以简单地使用binary search,它将在O(log(n))中运行。
这是一个Lua片段(我没有时间在C ++中做,对不起),它可以做你想要的,除了极限条件(你还没有定义):
function search(value, list, first, last)
if not first then first = 1; last = #list end
if last - first < 2 then
return list[first], list[last]
end
local median = math.ceil(first + (last - first)/2)
if list[median] > value then
return search(value, list, first, median)
else
return search(value, list, median, last)
end
end
local list = {1,10,100,1000}
print(search(arg[1] + 0, list))
从命令行搜索值:
$ lua search.lua 10 # didn't know what to do in this case
10 100
$ lua search.lua 101
100 1000
$ lua search.lua 99
10 100
答案 3 :(得分:4)
我将发布我自己的anser,并投票给任何帮助我达到它的人,因为这是我最终会使用的,你们都帮助我得出了这个结论。欢迎提出意见。
std::pair<value_type, value_type> GetDivisions(const value_type& from) const
{
if (m_divisions.empty())
throw 0; // Can't help you if we're empty.
std::vector<value_type>::const_iterator it =
std::lower_bound(m_divisions.begin(), m_divisions.end(), from);
if (it == m_divisions.end())
return std::make_pair(m_divisions.back(), m_divisions.back());
else if (it == m_divisions.begin())
return std::make_pair(m_divisions.front(), m_divisions.front());
else
return std::make_pair(*(it - 1), *(it));
}
答案 4 :(得分:1)
如果(在您的情况下)d小于第一个元素或者大于最后一个元素,该怎么办?以及如何处理负值?顺便说一句:保证你的“d”生活在你的矢量的第一个和最后一个值之间你可以这样做:
// Your initializations
std::vector<double>::const_iterator sit = f.begin();
double upper, lower;
以下是其余部分:
while ( *sit < d ) // if the element is still less than your d
++sit; // increase your iterator
upper = *sit; // here you get the upper value
lower = *(--sit); // and here your lower
够优雅吗? :/
答案 5 :(得分:0)
您可以在向量中搜索您的值(如果它在向量中,它将告诉您值的位置),然后返回该位置之前和之后的值。所以搜索45会告诉你它应该在index = 1然后你会返回0和1(取决于你的搜索实现,你要么得到较小值的索引或较大值的索引,但这很容易检查几个边界条件)。这应该能够在O(log n)中运行,其中n是向量中元素的数量。
答案 6 :(得分:0)
我会写这样的东西,没有测试是否编译,但你明白了:
template <typename Iterator>
std::pair<Iterator, Iterator> find_best_pair(Iterator first, Iterator last, const typename Iterator::value_type & val)
{
std::pair<Iterator, Iterator> result(last, last);
typename Iterator::difference_type size = std::distance(first, last);
if (size == 2)
{
// if the container is of size 2, the answer is the two elements
result.first = first;
result.first = first;
++result.first;
}
else
{
// must be of at lease size 3
if (size > 2)
{
Iterator second = first;
++second;
Iterator prev_last = last;
--prev_last;
Iterator it(std::lower_bound(second, last, val));
if (it != last)
{
result.first = it;
result.second = it;
if (it != prev_last)
{
// if this is not the previous last
// then the answer is (it, it + 1)
++result.second;
}
else
{
// if this the previous last
// then the answer is (it - 1, it)
--result.first;
}
}
}
}
return result;
}
答案 7 :(得分:0)
我写了这个小函数,它似乎适合你想要的更普遍的情况。我还没有完全测试过,但我确实写了一些测试代码(包括在内)。
#include <algorithm>
#include <iostream>
#include <vector>
template <class RandomAccessIt, class Container, class T>
std::pair<RandomAccessIt, RandomAccessIt> bracket_range(RandomAccessIt begin, RandomAccessIt end, Container& c, T val)
{
typename Container::iterator first;
typename Container::iterator second;
first = std::find(begin, end, val);
//Find the first value after this by iteration
second = first;
if (first == begin){ // Found the first element, so set this to end to indicate no lower values
first = end;
}
else if (first != end && first != begin) --first; //Set this to the first value before the found one, if the value was found
while (second != end && *second == val) ++second;
return std::make_pair(first,second);
}
int main(int argc, _TCHAR* argv[])
{
std::vector<int> values;
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> vals;
for (int i = 1; i < 9; ++i) values.push_back(i);
for (int i = 0; i < 10; ++i){
vals = bracket_range(values.begin(), values.end(),values, i);
if (vals.first == values.end() && vals.second == values.end()){ // Not found at all
std::cout << i << " is not in the container." << std::endl;
}
else if (vals.first == values.end()){ // No value lower
std::cout << i << ": " << "None Lower," << *(vals.second) << std::endl;
}
else if (vals.second == values.end()) { // No value higher
std::cout << i << ": " << *(vals.first) << ", None Higher" << std::endl;
}
else{
std::cout << i << ": " << *(vals.first) << "," << *(vals.second) << std::endl;
}
}
return 0;
}
答案 8 :(得分:0)
根据tunnuz发布的代码,这里有一些关于绑定检查的改进:
template<typename T>
void find_enclosing_values(const std::vector<T> &vec, const T &value, T &lower, T &upper, const T &invalid_value)
{
std::vector<T>::const_iterator it = vec.begin();
while (it != vec.end() && *it < value)
++it;
if(it != vec.end())
upper = *it;
else
upper = invalid_value;
if(it == vec.begin())
lower = invalid_value;
else
lower = *(--it);
}
使用示例:
std::vector<int> v;
v.push_back(3);
v.push_back(7);
v.push_back(10);
int lower, upper;
find_enclosing_values(v, 4, lower, upper, -1);
std::cout<<"lower "<<lower<<" upper "<<upper<<std::endl;
答案 9 :(得分:-1)
如果你有能力使用其他数据结构(不是矢量),我建议B-tree。如果您的数据不变,我相信您可以在恒定时间内检索结果(最差的对数时间)。