我需要查看整数列表中的整数。我对它们进行排序并使用lower_bound来查找给定整数所在的范围。这需要O(lgn)。有什么方法可以比这更好吗?
以下是要改进的提示。
一种方法是在数组中创建一个数组和索引。这可能不是空间有效的。 我可以使用unordered_map吗?我应该定义什么哈希函数?
// Sort in reverse order to aid the lookup process
vector<unsigned int> sortedByRange;
//... sortedByRange.push_back(..)
sort(sortedByRange.begin(), sortedByRange.end(), greater);
Range = (sortedByAddress_.begin() - sortedByRange.end();
std::cout<<"Range :"<<Range<<std::endl; //prints 3330203948
std::pair<unsigned int, unsigned int> lookup(unsigned int addr){
pair<unsigned int, unsigned int> result;
vector<unsigned int>::iterator it = lower_bound(sortedByRange.begin(),
sortedByRange.end(), addr);
result.first = *it;
result.second = *(it++);
return result;
}
答案 0 :(得分:1)
如果总范围不是很大,你可以构建一个任何方便大小的采样索引数组(你想要多少RAM?)
因此,例如,如果数据的总范围是256M,并且您有一个备用兆字节,则存储数据范围的每1K间隔的位置。然后,对于任何给定的数据点,您对索引数组执行O(1)(实际上是O(2):))探测以找到该数据点的最低和最高似是合理的范围,然后您可以在该数据点上执行lower_bound范围。如果你的范围在大小上没有大的变化,那么应该给你平均的恒定时间查找。
如果你不想在问题上留下那么多记忆,你可以根据平均范围大小和模糊因子尝试一对线性估计。如果事实证明不包含特定数据点,则可以回退到完整的二进制搜索;否则,限制范围内的二分搜索应该是平均线性时间。
这是第一个建议,如果手工操作不够清楚的话。完全未经测试的代码,甚至没有尝试编译它,并且整数类型的使用至少可以说是马虎。如果你使用它,试着让它更美丽。此外,我应该(但没有)将索引范围的开始限制为* begin_;如果它明显大于0,你应该修复它。
// The provided range must be sorted, and value_type must be arithmetic.
template<type RandomIterator, unsigned long size>
class IndexedLookup {
public:
using value_type = typename RandomIterator::value_type;
IndexedLookup(RandomIterator begin, RandomIterator end)
: begin_(begin),
end_(end),
delta_(*(end_ - 1) / size) {
for (unsigned long i = 0; i < size; ++i)
index_[i] = std::lower_bound(begin_, end_, i * delta_) - begin_;
// The above expression cannot be out of range
index_[size] = end_ - begin_;
}
RandomIterator lookup(value_type needle) {
int low = needle / delta_;
return std::lower_bound(index_[begin_ + low],
index_[begin_ + low + 1],
needle);
}
private:
RandomIterator begin_, end_;
value_type delta_;
std::array<int, size + 1> index_;
}
答案 1 :(得分:0)
方法1:如果您只需要知道列表中是否有给定的数字,并且最大值不是太大,您可以考虑使用位字段。查找将是O(1)操作。
方法2:如果值的范围很大(其中包含小整数和大整数),但列表大小不大(例如成千上万),您可以尝试(以编程方式)制作
的哈希函数0
... N + m
的值m
足够小; 然后可以将常量列表的值放入由哈希值索引的数组中,以便快速检查给定输入值的包含。如果列表中存在漏洞(m
非零),则应使用特殊值(例如-1
)表示漏洞。
包含测试:针对给定的输入 1.计算哈希值; 2.如果哈希值的值超出范围,则输入不在列表中; 3.当且仅当由哈希值索引的生成数组中的值与输入值相同时,输入才属于列表。
如何制作哈希函数值得在SO中提出另一个问题(对于字符串值,存在用于为此目的生成工具的工具)。 : - )
限制:如果列表不是在编译时创建的,而是在程序的运行时计算或接收,则此方法不适用。此外,如果此列表频繁更改,则生成散列函数和代码所需的计算时间可能会使此方法不适用。