用O(logn)计算C ++中元素的底限

时间:2015-03-22 17:15:14

标签: c++ arrays algorithm

所以,我必须在O(logn)中计算排序数组中数字的最低值,其中floor表示数组中小于给定数字的最大数字。

For example, let the input array be {1, 2, 8, 10, 10, 12, 19}
For x = 0:    floor doesn't exist in array
For x = 1:    floor  = 1
For x = 5:    floor  = 2
For x = 20:   floor  = 19

我做了以下功能:

int bina (int arr[], int low, int high, int num)
{
    if ( arr[low] > num )
        return -1;
    else if (arr[high] <= num )
        return high;
    int mid = (low+high)/2;
    if ( arr[mid] == num )
        return mid;
    // floor of num lies from low to (mid-1)
    else if (arr[mid] > num)  
    {
        if ( (mid-1) >= low && arr[mid-1] < num )
            return mid-1;
        else
            bina(arr, low, mid-1, num);
    }
    // floor of num lies between (mid+1) to high
    else if ( arr[mid] < num )
    {
        if ( (mid+1) <= high && arr[mid+1] > num )
            return mid;
        else
            bina(arr, low, mid+1, num);
    }
 }

主要通过呼叫bina(arr,0,k-1,n)调用此方法。但是,在设置这些值时(在上面的示例中),它总是返回1.我不知道问题是什么。我交叉检查了我的逻辑3次,似乎是正确的。有人可以帮我吗?谢谢!

2 个答案:

答案 0 :(得分:3)

最终案例中的代码看起来很可疑。

尝试更改:

bina(arr, low, mid+1, num);

return bina(arr, mid+1, high, num);

您可能还需要在行bina(arr, low, mid-1, num);中添加一个返回值。

答案 1 :(得分:0)

通过稍微不同地查看作业,可以简化此任务的代码。就目前而言,循环的每次迭代基本上都有一个5向条件。

然而,当你开始讨论它时,如果我们保持在循环中,实际上只有两种可能的行动方式:我们继续搜索输入的左半部分,或者我们继续搜索右半部分。同样,退出循环时只需要一个条件:左侧和右侧缩小到一个点。

因为我已经用这种方式编写了代码,所以这里有一些通用形式的代码:

template <class Iter>
Iter lower_bound(Iter left, 
                 Iter right, 
                 typename std::iterator_traits<Iter>::value_type val) 
{
    while (left < right) {
        Iter middle = left + (right - left) / 2;
        if (*middle < val)
            left = middle + 1;
        else
            right = middle;
    }
    return left;
}

...这里有一小段测试代码:

#include <iterator>

using std::end;
using std::begin;   

int main() {
    int a[] = {12, 20, 20, 20, 32, 40, 52};
    int targets[] = {10, 19, 20, 22, 40, 60};

    for (auto i : targets) {
        std::cout << "Target: " << i 
                  << ", position: " << lower_bound(begin(a), end(a), i) - a << "\n";

    }
}

另请注意,使用这种方式编写的代码,我们需要进行的唯一更改是获取upper_bound而不是lower_bound正在改变:

    if (*middle < val)
        left = middle + 1;
    else
        right = middle;

...为:

    if (val < *middle)
        right = middle;
    else
        left = middle + 1;

此代码在迭代器方面有效,因此它将迭代器返回到您可以插入指定值的位置,并且值将保持有序,并且它将是具有该值的第一个项目。如果它小于集合中的任何值,它将把迭代器返回到第一个项目。如果它大于集合中的任何项目,它将返回collection.end()(它刚刚超过最后一项)。