您将获得std::vector<T>
个不同的项目。已经排序了。
类型T
仅支持少于 <
运算符进行比较。这是一个很重要的功能。所以你必须尽可能少地使用它。
有没有比二分查找更好的解决方案? 如果没有,有没有比这更好的解决方案,使用少于运营商的次数?
template<typename T>
int FindKey(const std::vector<T>& list, const T& key)
{
if( list.empty() )
return -1;
int left = 0;
int right = list.size() - 1;
int mid;
while( left < right )
{
mid = (right + left) / 2;
if( list[mid] < key )
left = mid + 1;
else
right = mid;
}
if( !(key < list[left]) && !(list[left] < key) )
return left;
return -1;
}
这不是一个现实世界的情况,只是一个编码测试。
答案 0 :(得分:1)
您可以使用hash table(例如unordered_map
来折算额外的 O(n)预处理时间,以便分摊 O(1)查询时间3}})创建lookup table。
散列表计算密钥的hash functions,不要比较密钥本身。
两个键可能具有相同的哈希值,导致冲突,这解释了为什么不保证每个单独的操作都是恒定时间。 Amortized常量时间意味着如果执行总计花费时间 t 的 k 操作,则商 t / k = O(1) ,对于足够大的 k 。
#include <vector>
#include <unordered_map>
template<typename T>
class lookup {
std::unordered_map<T, int> position;
public:
lookup(const std::vector<T>& a) {
for(int i = 0; i < a.size(); ++i) position.emplace(a[i], i);
}
int operator()(const T& key) const {
auto pos = position.find(key);
return pos == position.end() ? -1 : pos->second;
}
};
这也需要额外的内存。
如果值可以映射到整数并且在a reasonable range范围内(即 max-min = O(n)),则只需使用vector
作为查找表而不是unordered_map
。具有保证常量查询时间的好处。
有关更详细的讨论,请参阅此answer to "C++ get index of element of array by value",包括线性,二进制和哈希索引查找的经验比较。
如果T
类型的接口不支持除bool operator<(L, R)
之外的其他操作,那么使用decision tree model可以证明lower bound for comparison-based search algorithms为Ω(log n)。< / p>
答案 1 :(得分:0)
您可以使用std::lower_bound
。它通过log(n)+1
比较来实现,这是您问题的最佳复杂性。
template<typename T>
int FindKey(const std::vector<T>& list, const T& key)
{
if(list.empty())
return -1;
typename std::vector<T>::const_iterator lb =
std::lower_bound(list.begin(), list.end(), key);
// now lb is an iterator to the first element
// which is greater or equal to key
if(key < *lb)
return -1;
else
return std::distance(list.begin(), lb);
}
通过额外检查相等性,您可以使用log(n)+2
比较。
答案 2 :(得分:0)
如果您的号码是正态分布的,您可以在日志日志中使用插值搜索。如果他们有其他分发,您可以修改它以考虑您的分发,但我不知道哪些分发产生日志日志时间。