C++ 算法 查找元素

一 概述
  • C++ 标准库中提供了很多算法,定义于头文件 < algorithm >。本文主要探究以下用于 查找元素 的算法:
    • std::find 查找第一个匹配元素
    • std::find_if 查找第一个匹配元素
    • std::find_if_not(C++11) 查找第一个不匹配元素
    • std::search_n 查找前n个连续匹配值
    • std::search 查找第一个子区间
    • std::find_end 查找最后一个子区间
    • std::find_first_of 查找某些元素第一次出现位置
    • std::adjacent_find 查找两个连续且相等的元素
二 辅助函数
  • 为了举例说明各算法,Demo中定义了如下一些辅助函数:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
#include <list>
#include <functional>

template <typename C>
void fill(C& container, int begin, int end) {
  for (auto i = begin; i <= end; i++) {
    container.emplace_back(i);
  }
}

template <typename C>
void print(const std::string& pre, C container) {
  std::cout << pre;
  std::copy(container.begin(), container.end(),
            std::ostream_iterator<int>(std::cout, " "));
  std::cout << std::endl;
}

bool even(int a) {
  return a % 2 == 0;
}

bool my_equal(int a, int b) {
  return a == b;
}
二 std::find
std::vector<int> vc;
vc.emplace_back(1);
fill(vc, 1, 9);
print("vc: ", vc);

auto it = std::find(vc.begin(), vc.end(), 1);
std::cout << "the first element equals 1 is No."
                << std::distance(vc.begin(), it) << std::endl;
auto it1 = std::find(vc.begin(), vc.end(), 10);
if (it1 != vc.end()) {
  std::cout << "the first element equals 10 is No."
            << std::distance(vc.begin(), it1) << std::endl;
} else {
  std::cout << "no element equals 10 in vc." << std::endl;
}
  • 结果
vc: 1 1 2 3 4 5 6 7 8 9
the first element equals 1 is No.0
no element equals 10 in vc.
  • 说明
    • std::find 选择容器中第一个匹配元素,若找到则返回指向该元素的迭代器,否则,返回容器 end()。
    • std::find 注意其中一个构造函数中 模板参数 ExecutionPolicy, 定义于C++17, 例子请参考此前文章 std::find std::execution
    • std::distance 请参考此前文章 C++ iterator(1) 几个辅助函数
三 std::find_if
  • 定义
template< class InputIt, class UnaryPredicate >
InputIt find_if( InputIt first, InputIt last, UnaryPredicate p );(1)(C++20)
template< class InputIt, class UnaryPredicate >
constexpr InputIt find_if( InputIt first, InputIt last, UnaryPredicate p );(2)(C++20)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
ForwardIt find_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, 
                   UnaryPredicate p );(3)(C++17)
  • 功能
    • 查找第一个 使 UnaryPredicate p 返回 true 的元素
  • Demo
print("vc: ", vc);
auto it = std::find_if(vc.begin(), vc.end(), even);
std::cout << "the first even element is No."
          << std::distance(vc.begin(), it) << std::endl;
  • 结果
vc: 1 1 2 3 4 5 6 7 8 9
the first even element is No.2
四 std::find_if_not
  • 定义
template< class InputIt, class UnaryPredicate >
InputIt find_if_not( InputIt first, InputIt last, UnaryPredicate q );(1)(C++11)(C++20)
template< class InputIt, class UnaryPredicate >
constexpr InputIt find_if_not( InputIt first, InputIt last, UnaryPredicate q );(2)(C++20)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
ForwardIt find_if_not( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, 
                       UnaryPredicate q );(3)(C++17)
  • 功能
    • 查找第一个 使 UnaryPredicate p 返回 false 的元素
  • Demo
print("vc: ", vc);
auto it = std::find_if_not(vc.begin(), vc.end(), even);
std::cout << "the first odd element is No."
          << std::distance(vc.begin(), it) << std::endl;
  • 结果
vc: 1 1 2 3 4 5 6 7 8 9
the first odd element is No.0
五 std::search_n
  • 定义
template< class ForwardIt, class Size, class T >
ForwardIt search_n( ForwardIt first, ForwardIt last, Size count, const T& value );(C++20)
template< class ForwardIt, class Size, class T >
constexpr ForwardIt search_n( ForwardIt first, ForwardIt last, Size count, const T& value );(C++20)
template< class ExecutionPolicy, class ForwardIt, class Size, class T >
ForwardIt search_n( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, Size count, const T& value );(C++17)	
template< class ForwardIt, class Size, class T, class BinaryPredicate >
ForwardIt search_n( ForwardIt first, ForwardIt last, Size count, const T& value, BinaryPredicate p );(C++20)
template< class ForwardIt, class Size, class T, class BinaryPredicate >
constexpr ForwardIt search_n( ForwardIt first, ForwardIt last, Size count, const T& value,
                               BinaryPredicate p );(C++20)
template< class ExecutionPolicy, class ForwardIt, class Size, class T, class BinaryPredicate >
ForwardIt search_n( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, Size count, const T& value,
                     BinaryPredicate p );(C++17)
  • 功能
    • 查找前n个连续匹配值
  • Demo
print("vc: ", vc);
auto it = std::search_n(vc.begin(), vc.end(), 2, 1);
std::cout << "2  consecutive element equal 1 start at No."
          << std::distance(vc.begin(), it) << std::endl;

// 由于不在早期的STL规范中,所以是binary predicate 而不是unary predicate
auto it1 = std::search_n(vc.begin(), vc.end(), 2, 1, my_equal);
std::cout << "2  consecutive element equal 1 start at No."
          << std::distance(vc.begin(), it1) << std::endl;
  • 结果
2  consecutive element equal 1 start at No.0
2  consecutive element equal 1 start at No.0
六 std::search
  • 定义
template< class ForwardIt1, class ForwardIt2 >
ForwardIt1 search( ForwardIt1 first, ForwardIt1 last, ForwardIt2 s_first, ForwardIt2 s_last );(C++20)
template< class ForwardIt1, class ForwardIt2 >
constexpr ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,
                             ForwardIt2 s_first, ForwardIt2 s_last );(C++20)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >
ForwardIt1 search( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                   ForwardIt2 s_first, ForwardIt2 s_last );(C++17)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,
                   ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );(C++20)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
constexpr ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,
                             ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );(C++20)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryPredicate >
ForwardIt1 search( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                   ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );(C++17)
template<class ForwardIt, class Searcher>
ForwardIt search( ForwardIt first, ForwardIt last, const Searcher& searcher );(C++17)(C++20)
template<class ForwardIt, class Searcher>
constexpr ForwardIt search( ForwardIt first, ForwardIt last, const Searcher& searcher );(C++20)
  • 功能
    • 查找第一个子区间
  • Demo
print("vc: ", vc);
std::list<int> l;
fill(l, 3, 6);
print("list: ", l);
auto it = std::search(vc.begin(), vc.end(), l.begin(), l.end());
std::cout << "the first 3 4 5 6 position in vc is No."
          << std::distance(vc.begin(), it) << std::endl;
          
// 注意构造函数参数 searcher
//  auto it1 = std::search(vc.begin(), vc.end(),
//                        std::boyer_moore_searcher(l.begin(), l.end()) );
//  std::cout << "the 3 4 5 6 position in vc is No."
//            << std::distance(vc.begin(), it1) << std::endl;
  • 结果:
vc: 1 1 2 3 4 5 6 7 8 9
list: 3 4 5 6
the first 3 4 5 6 position in vc is No.3
  • 说明
    • 模板参数 Searcher (C++17) , 标准库提供以下搜索器
      • default_searcher (C++17) 标准 C++ 库搜索算法实现(类模板)
      • boyer_moore_searcher(C++17) Boyer-Moore 搜索算法实现(类模板)
      • boyer_moore_horspool_searcher(C++17) Boyer-Moore-Horspool 搜索算法实现(类模板)
七 std::find_end
  • 定义
template< class ForwardIt1, class ForwardIt2 >
ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,
                     ForwardIt2 s_first, ForwardIt2 s_last );(C++20)
template< class ForwardIt1, class ForwardIt2 >
constexpr ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,
                               ForwardIt2 s_first, ForwardIt2 s_last );(C++20)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >
ForwardIt1 find_end( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                     ForwardIt2 s_first, ForwardIt2 s_last );(C++17)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,
                     ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );(C++20)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
constexpr ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,
                               ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );(C++20)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryPredicate >
ForwardIt1 find_end( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                     ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );(C++17)
  • 功能
    • 查找最后一个子区间
  • Demo
// find_end 查找最后一个子区间 (叫做search_end更合适)
fill(vc, 3, 6);
std::list<int> l;
fill(l, 3, 6);
print("vc: ", vc);
print("list: ", l);
auto it = std::find_end(vc.begin(), vc.end(), l.begin(), l.end());
std::cout << "the last 3 4 5 6 position in vc is No."
          << std::distance(vc.begin(), it) << std::endl;
  • 结果
vc: 1 1 2 3 4 5 6 7 8 9 3 4 5 6
list: 3 4 5 6
the last 3 4 5 6 position in vc is No.10
  • 说明
    • 由于该算法不是早期STL的一部分,被命名为了find_end, 叫做search_end更合适(search 查找第一个子区间)
八 std::find_first_of
  • 定义
    • 与 find_end 形式类似
  • 功能
    • 查找某些元素第一次出现位置, 与search 功能类似。可将 find_end 与之对应。
  • Demo
std::list<int> l;
fill(l, 3, 6);
print("vc: ", vc);
print("list: ", l);
auto it = std::find_first_of(vc.begin(), vc.end(), l.begin(), l.end());
std::cout << "the first 3 4 5 6 position in vc is No."
          << std::distance(vc.begin(), it) << std::endl;
  • 结果
vc: 1 1 2 3 4 5 6 7 8 9 3 4 5 6
list: 3 4 5 6
the first 3 4 5 6 position in vc is No.3
九 std::adjacent_find
  • 定义
template< class ForwardIt >
ForwardIt adjacent_find( ForwardIt first, ForwardIt last );(1)(C++20)
template< class ForwardIt >
constexpr ForwardIt adjacent_find( ForwardIt first, ForwardIt last );(1)(C++20)
template< class ExecutionPolicy, class ForwardIt >
ForwardIt adjacent_find( ExecutionPolicy&& policy,
                         ForwardIt first, ForwardIt last );(2)(C++17)	
template< class ForwardIt, class BinaryPredicate>
ForwardIt adjacent_find( ForwardIt first, ForwardIt last, BinaryPredicate p );(3)(C++20)
template< class ForwardIt, class BinaryPredicate>
constexpr ForwardIt adjacent_find( ForwardIt first, ForwardIt last, BinaryPredicate p );(3)(C++20)
template< class ExecutionPolicy, class ForwardIt, class BinaryPredicate>
ForwardIt adjacent_find( ExecutionPolicy&& policy,
                         ForwardIt first, ForwardIt last, BinaryPredicate p );(4)(C++17)
  • 功能
    • 查找两个连续且相等的元素
  • Demo
std::list<int> l;
fill(l, 3, 6);
fill(l, 6, 7);
fill(l, 7, 8);
print("list: ", l);
auto it = std::adjacent_find(l.begin(), l.end());
std::cout
    << "the first two same consecutive element position in list is No."
    << std::distance(l.begin(), it) << std::endl;
  • 结果
list: 3 4 5 6 6 7 7 8
the first two same consecutive element position in list is No.3
十 说明
  • 由于一些算法早期不在标准库中,一些命名和参数类型并不符合通用规范, 例如
    • search_n 使用 binary predicate 而不是 unary predicate。
    • find_end 使用 forward_iterator 而不是 input_iterator等。
  • C++17 增加一些新的算法的构造函数模板参数,例如
    • std::find ExecutionPolicy模板参数
    • std::search Searcher模板参数
  • 参考
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值