我有一个从x到y的int的排序数组(元素的值是随机的,但是使用qsort()以升序排序).该程序接收各种间隔,例如< 10; 50>或< 50; 100>.我有以下简单的for循环来确定数组中的值是否在设置的时间间隔内,如果是,则向计数器添加一个.
for(int i = 0; i < arraySize ;i++ ) {
if (points[i] >= interval1 && points[i] <= interval2){
counter++;
}
}
我需要一种比O(n)更快的方法来搜索数组,并确定points [i]中的值是否在设置的间隔内.价值可以达到数百万,因此显着放缓.
数组中的元素范围为0到1000000000(1e9).间隔分别.
最佳答案 使用二进制搜索 – 对于输入间隔[i,j],找到大于i的最小整数的索引,找到小于j的最大整数的索引,然后返回它们之间的距离.
ssize_t bin_search_first_larger(int arr[], size_t arr_sz, int val) {
ssize_t l = -1;
ssize_t r = arr_sz;
/* invariant: arr[l] < val && val <= arr[r] */
while (l+1 != r) {
ssize_t m = l+(r-l)/2;
if (arr[m] < val) {
l = m;
} else {
r = m;
}
}
/* l+1 == r && arr[l] < val && val <= arr[r] */
return r;
}
ssize_t bin_search_last_smaller(int arr[], size_t arr_sz, int val) {
ssize_t l = -1;
ssize_t r = arr_sz;
/* invariant: arr[l] <= val && val < arr[r] */
while (l+1 != r) {
ssize_t m = l+(r-l)/2;
if (arr[m] <= val) {
l = m;
} else {
r = m;
}
}
/* l+1 == r && arr[l] <= val && val < arr[r] */
return l;
}
ssize_t values_in(int arr[], size_t arr_sz, int x, int y) {
ssize_t i = bin_search_first_larger(arr, arr_sz, x);
ssize_t j = bin_search_last_smaller(arr, arr_sz, y);
return j-i+1;
}
二进制搜索代码改编自Jon Bentley的Programming Pearls(非常值得一读),其中显示了如何修改二进制搜索以返回具有重复项的已排序数组中值的第一次出现或最后一次出现(而不是返回任意出现的重复值).这个过程与您的用例类似,区别很微妙.
注意,从概念上讲,假设arr [-1]是负无穷大,而arr [N]是正无穷大(其中N是数组的大小),但显然,代码从不试图访问这些元素.
时间复杂度是O(log(N)),其中N是数组的大小,很难(不可能?)得到更好的数据.
我运行了一些测试,它似乎适用于一般情况和边缘情况(范围中没有元素,或者y大于每个元素,或x小于每个元素,或者x都小于每个元素和y更大)而不是每个元素),但你可能知道这并不能证明没有错误.