📜  C++ STL-algorithm.lower_bound()函数(1)

📅  最后修改于: 2023-12-03 14:39:50.610000             🧑  作者: Mango

C++ STL-algorithm.lower_bound()函数

lower_bound()函数是C++ STL中的一个非常有用的函数,它可用于在有序的容器中查找某个元素的位置,或者用于查找第一个大于等于给定值的元素的位置。本文将介绍lower_bound()函数的用法和其实现原理,希望能帮助读者更好地理解这个函数的作用和使用方法。

lower_bound()函数的定义和用法

lower_bound()函数的定义如下所示:

template<class ForwardIt, class T>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value);

lower_bound()函数的参数说明如下:

  • firstlast分别是容器迭代器的起始位置和结束位置。函数将在[first, last)区间内查找。
  • value是要查找的值。该值必须与容器元素的类型兼容,并且容器中的元素必须是有序的。

lower_bound()函数的返回值是一个迭代器,它指向容器中第一个大于等于给定值的元素的位置。如果容器中没有大于等于给定值的元素,则返回一个指向last的迭代器。

下面是lower_bound()函数的一个简单例子:

#include <vector>
#include <algorithm>
#include <iostream>

int main()
{
    std::vector<int> vec = {1, 2, 3, 4, 4, 5, 6};

    auto it = std::lower_bound(vec.begin(), vec.end(), 4);

    if (it == vec.end()) {
        std::cout << "4 is not found in vec\n";
    } else {
        std::cout << "4 is found at index " << std::distance(vec.begin(), it) << '\n';
    }

    return 0;
}

输出如下:

4 is found at index 3
lower_bound()函数的实现原理

lower_bound()函数的实现原理是利用了二分查找算法,因为容器是有序的,所以可以通过不断地折半查找,最终找到第一个大于等于给定值的元素的位置。下面是lower_bound()函数的一个简化版实现,用于查找整数数组中是否存在某个值:

int lower_bound(int arr[], int n, int x)
{
    int l = 0, r = n - 1;

    while (l < r) {
        int mid = l + (r - l) / 2;

        if (arr[mid] < x)
            l = mid + 1;
        else
            r = mid;
    }

    if (arr[l] >= x)
        return l;
    else
        return -1;
}

这里的arr是整数数组,n是数组的元素个数,x是要查找的值。该函数的返回值是第一个大于等于x的元素的位置,如果不存在,则返回-1

实际上,C++ STL中的lower_bound()函数实现要更加复杂,它不仅支持随机访问迭代器,还支持双向迭代器和随机访问迭代器,具体如下:

template<class ForwardIt, class T>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value)
{
    using category = typename std::iterator_traits<ForwardIt>::iterator_category;
    return __lower_bound(first, last, value, category());
}

// 辅助函数,用于随机访问迭代器
template<class RandomIt, class T>
RandomIt __lower_bound(RandomIt first, RandomIt last, const T& value, std::random_access_iterator_tag)
{
    auto len = last - first;
    auto half = len;
    RandomIt middle;

    while (len > 0) {
        half = len >> 1;
        middle = first + half;

        if (*middle < value) {
            first = middle + 1;
            len = len - half - 1;
        } else {
            len = half;
        }
    }

    return first;
}

// 辅助函数,用于双向迭代器
template<class BidirIt, class T>
BidirIt __lower_bound(BidirIt first, BidirIt last, const T& value, std::bidirectional_iterator_tag)
{
    using rev_iter = std::reverse_iterator<BidirIt>;
    return std::reverse_iterator<BidirIt>(
               std::upper_bound(rev_iter(last), rev_iter(first), value)).base();
}

lower_bound()函数的实现分为两个辅助函数,分别用于随机访问迭代器和双向迭代器。这里仅展示随机访问迭代器的实现方式,具体如下:

  • 首先计算区间长度len,然后利用二分查找算法,将区间折半查找。
  • 如果中间元素小于value,则将左端点first移动到中间元素的下一个位置,同时将剩余区间的长度减去一半。
  • 如果中间元素大于等于value,则将右端点last移动到中间元素的位置。
  • 最终返回左端点first的值。

对于双向迭代器,由于没有随机访问的特性,因此不能像随机访问迭代器那样直接折半查找。另外,lower_bound()函数仍然需要保证二分查找的正确性,因此可以利用upper_bound()函数来实现。具体实现方式如下:

  • 首先将last反向迭代器转换为reverse_iterator<BidirIt>类型的迭代器,将first转换为相应的类型。然后调用upper_bound()函数。
  • upper_bound()函数可以在一个有序区间中查找第一个大于给定值的元素的位置。因此,我们可以将last作为起始位置,first作为结束位置进行查找,得到第一个大于value的元素的位置。
  • 将这个位置用base()函数转换为正向迭代器的形式,并返回。
总结

lower_bound()函数是一个非常有用的函数,它可以用于在有序的容器中快速查找元素的位置。借助二分查找算法,lower_bound()函数可以高效地查找第一个大于等于给定值的元素的位置,具有较高的时间复杂度和空间复杂度。同时,C++ STL中的lower_bound()函数支持多种迭代器类型,具有很好的通用性和适应性。因此,在实际编程中,开发者可以充分利用lower_bound()函数的特性,提高代码的效率和质量。