【C++之泛型算法】004查找元素

find()

在 C++ 中,std::find 是一个泛型算法,用于在序列(如数组、向量、列表等)中查找一个特定的值或满足特定条件的元素。该算法接受两个迭代器作为范围参数,以及要查找的值或条件,并返回一个指向找到的第一个匹配元素的迭代器。如果未找到匹配项,则返回尾后迭代器(end())。

下面是 std::find 的详细用法:
函数签名

template <class InputIt, class T>
InputIt find(InputIt first, InputIt last, const T& value);


示例:查找特定值

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

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int value_to_find = 5;

    // 使用 std::find 查找值
    auto it = std::find(numbers.begin(), numbers.end(), value_to_find);

    if (it != numbers.end()) {
        // 如果找到了值,输出它的位置和值
        std::cout << "Found " << value_to_find << " at position: "
                  << std::distance(numbers.begin(), it) << std::endl;
    } else {
        // 如果没有找到,输出消息
        std::cout << value_to_find << " not found." << std::endl;
    }

    return 0;
}

find_if()

template <class InputIt, class UnaryPredicate>
InputIt find_if(InputIt first, InputIt last, UnaryPredicate p);

示例:查找满足条件的元素

如果你需要根据特定条件来查找元素,而不是一个固定的值,你可以使用 std::find_if。这需要提供一个一元谓词(即一个接受单个参数并返回布尔值的函数或函数对象),用于定义查找条件。

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

// 自定义一元谓词,判断一个数是否是偶数
struct is_even {
    bool operator()(int num) const {
        return num % 2 == 0;
    }
};

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

    // 使用 std::find_if 和自定义谓词查找偶数
    auto it = std::find_if(numbers.begin(), numbers.end(), is_even());

    if (it != numbers.end()) {
        // 如果找到了满足条件的元素,输出它的位置和值
        std::cout << "Found the first even number: " << *it << " at position: "
                  << std::distance(numbers.begin(), it) << std::endl;
    } else {
        // 如果没有找到,输出消息
        std::cout << "No even numbers found." << std::endl;
    }

    return 0;
}

在这个例子中,is_even 是一个结构体,它重载了调用操作符 operator(),使其能够像函数一样被调用,并返回一个布尔值来表示一个数是否是偶数。然后,std::find_if 使用这个谓词来查找序列中的第一个偶数。
注意事项

  • std::find 和 std::find_if 返回的迭代器指向找到的元素或尾后迭代器(如果未找到)。
  • 如果序列是容器(如 std::vector、std::list 等),则可以直接使用容器的成员函数 begin() 和 end() 作为范围参数。
  • 谓词函数或函数对象必须能够接受序列中元素的类型作为参数,并返回一个布尔值。
  • 在使用返回的迭代器之前,始终检查它是否等于尾后迭代器,以避免解引用空指针。

find_if_not()

std::find_if_not 是 C++ 标准库中的一个泛型算法,它与 std::find_if 功能相反。std::find_if 用于查找满足特定条件的第一个元素,而 std::find_if_not 用于查找不满足特定条件的第一个元素。换句话说,它返回序列中第一个使给定谓词返回 false 的元素。

下面是 std::find_if_not 的基本用法示例:

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

// 自定义谓词,用于查找奇数
struct is_odd {
    bool operator()(int n) const {
        return n % 2 != 0;
    }
};

int main() {
    std::vector<int> numbers = {2, 4, 6, 8, 10, 1, 3, 5, 7, 9};

    // 使用自定义谓词查找第一个不是奇数的元素(即第一个偶数)
    auto it = std::find_if_not(numbers.begin(), numbers.end(), is_odd());

    if (it != numbers.end()) {
        std::cout << "Found the first even number: " << *it << std::endl;
    } else {
        std::cout << "No even numbers found." << std::endl;
    }

    return 0;
}

在这个例子中,我们定义了一个名为 is_odd 的结构体,它有一个重载的 operator(),用于判断一个整数是否是奇数。然后,我们将 is_odd() 对象作为第三个参数传递给 std::find_if_not 函数,以查找向量中的第一个偶数(即第一个不满足 is_odd 条件的元素)。

std::find_if_not 返回的迭代器将指向找到的第一个不满足谓词条件的元素。如果没有找到这样的元素(即序列中的所有元素都满足谓词条件),则 std::find_if_not 将返回尾后迭代器。

请注意,在使用返回的迭代器之前,你应该始终检查它是否等于尾后迭代器,以避免对空指针进行解引用。此外,谓词函数或函数对象必须能够接受序列中元素的类型作为参数,并返回一个布尔值。

search_n()

std::search_n 是 C++ 标准库中的一个泛型算法,用于在序列中查找由指定数量的元素组成的子序列。这个函数在 头文件中定义。std::search_n 接受两对迭代器(分别表示主序列和子序列的范围),并返回一个指向主序列中第一个匹配子序列的起始位置的迭代器。如果没有找到匹配项,它将返回主序列的尾后迭代器1。

以下是 std::search_n 的详细用法及示例:

用法:

template<class ForwardIterator, class Size, class T>
ForwardIterator search_n(ForwardIterator first, ForwardIterator last, Size count, const T& val);

template<class ForwardIterator, class Size, class T, class BinaryPredicate>
ForwardIterator search_n(ForwardIterator first, ForwardIterator last, Size count, const T& val, BinaryPredicate pred);

参数:

  • first:指向范围的第一个元素的前向迭代器,其中元素本身包含在范围内。
  • last:指向范围的最后一个元素之后的位置的前向迭代器。
  • count:要查找的子序列中元素的数量。
  • val:要查找的子序列中元素的值。
  • pred:一个二元谓词,用于定义如何比较序列中的元素(可选参数)。

示例:

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

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

    auto it = std::search_n(main_seq.begin(), main_seq.end(), sub_seq.size(), sub_seq.begin());

    if (it != main_seq.end()) {
        std::cout << "Found sub-sequence at position: " << std::distance(main_seq.begin(), it) << std::endl;
    } else {
        std::cout << "Sub-sequence not found." << std::endl;
    }

    return 0;
}

在这个例子中,我们在 main_seq 中查找由 sub_seq 指定的子序列。如果找到了子序列,it 将指向 main_seq 中子序列的起始位置;如果没有找到,it 将等于 main_seq.end()。我们使用 std::distance 来计算子序列在主序列中的位置1。

当然,std::search_n 的第二个定义允许你提供一个二元谓词(binary predicate),该谓词定义了如何比较主序列中的元素与子序列中的对应元素。这允许你在搜索时进行更复杂的匹配,而不仅仅是简单的相等比较。

下面是一个使用二元谓词作为 std::search_n 参数的例子:

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

// 自定义比较函数,用于比较两个整数是否相差不超过1
bool is_near(int a, int b) {
    return std::abs(a - b) <= 1;
}

int main() {
    // 主序列
    std::vector<int> main_sequence = {1, 2, 3, 5, 6, 7, 8, 9, 10};
    // 子序列(这里我们不直接使用一个向量,而是使用值和数量)
    int sub_sequence_value = 5;
    size_t sub_sequence_count = 3;

    // 使用自定义的比较函数搜索子序列
    auto it = std::search_n(main_sequence.begin(), main_sequence.end(),
                            sub_sequence_count, sub_sequence_value, is_near);

    if (it != main_sequence.end()) {
        // 如果找到了子序列,输出它的起始位置和长度
        std::cout << "Found sub-sequence starting at position: "
                  << std::distance(main_sequence.begin(), it) << std::endl;
    } else {
        // 如果没有找到子序列,输出消息
        std::cout << "Sub-sequence not found." << std::endl;
    }

    return 0;
}

在这个例子中,我们定义了一个名为 is_near 的二元谓词,它接受两个整数并检查它们是否相差不超过 1。然后,我们使用 std::search_n 在 main_sequence 中搜索一个由 3 个连续整数组成的子序列,这些整数与给定的 sub_sequence_value(即 5)相差不超过 1。

因此,如果 main_sequence 中存在这样的子序列(例如 {4, 5, 6} 或 {6, 7, 8}),std::search_n 将找到它并返回指向该子序列起始位置的迭代器。如果没有找到匹配的子序列,则返回 main_sequence.end()。

这个例子展示了 std::search_n 的灵活性,它允许你定义自己的匹配条件,而不仅仅是基于简单的相等性。

search()

在 C++ 标准库中,std::search 是一个泛型算法,用于在一个序列中查找另一个序列。它可以在任何支持迭代器的容器(如 std::vector、std::list、std::array 等)中使用。std::search 的基本用法是查找一个序列中是否包含另一个序列,并返回第一个匹配项的迭代器。

下面是 std::search 的基本用法和一些示例:

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

int main() {
    // 定义一个主序列
    std::vector<int> main_sequence = {1, 2, 3, 4, 5, 6, 7, 8, 9};

    // 定义要搜索的子序列
    std::vector<int> sub_sequence = {4, 5, 6};

    // 使用 std::search 查找子序列
    auto it = std::search(main_sequence.begin(), main_sequence.end(),
                          sub_sequence.begin(), sub_sequence.end());

    if (it != main_sequence.end()) {
        // 如果找到了子序列,输出匹配项的起始位置
        std::cout << "Found sub-sequence at position: "
                  << std::distance(main_sequence.begin(), it) << std::endl;
    } else {
        // 如果没有找到子序列,输出消息
        std::cout << "Sub-sequence not found." << std::endl;
    }

    // 示例:使用 std::search 查找单个值
    int value_to_find = 5;
    it = std::search(main_sequence.begin(), main_sequence.end(),
                     value_to_find);

    if (it != main_sequence.end()) {
        // 如果找到了值,输出匹配项的位置
        std::cout << "Found value " << value_to_find << " at position: "
                  << std::distance(main_sequence.begin(), it) << std::endl;
    } else {
        // 如果没有找到值,输出消息
        std::cout << "Value not found." << std::endl;
    }

    return 0;
}

std::search 的签名如下:

template< class InputIt1, class InputIt2 >
InputIt1 search( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2 );

template< class InputIt1, class InputIt2, class BinaryPredicate >
InputIt1 search( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate p );

第一个版本接受两对迭代器,分别表示主序列和子序列的范围。它使用 operator== 来比较元素。

第二个版本还接受一个二元谓词 p,该谓词用于自定义比较逻辑。这使得你可以定义自己的比较逻辑,而不仅仅是检查元素是否相等。

使用二元谓词的 std::search 示例:

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

// 自定义比较函数,检查两个整数是否相差不超过2
bool is_near(int a, int b) {
    return std::abs(a - b) <= 2;
}

int main() {
    std::vector<int> main_sequence = {1, 2, 4, 5, 6, 7, 9, 10};
    std::vector<int> sub_sequence = {4, 5, 6};

    // 使用自定义比较函数搜索子序列
    auto it = std::search(main_sequence.begin(), main_sequence.end(),
                          sub_sequence.begin(), sub_sequence.end(), is_near);

    if (it != main_sequence.end()) {
        std::cout << "Found sub-sequence using custom comparison." << std::endl;
    } else {
        std::cout << "Sub-sequence not found using custom comparison." << std::endl;
    }

    return 0;
}

在这个示例中,我们定义了一个名为 is_near 的二元谓词,它检查两个整数是否相差不超过 2。然后,我们将这个谓词作为 std::search 的第五个参数传递,以便在搜索时使用我们的自定义比较逻辑。

find_end()

std::find_end 是 C++ 标准库中的一个泛型算法,它在一个主序列中搜索最后一个与子序列相匹配的序列,并返回主序列中最后一个匹配序列的起始位置的迭代器。如果没有找到匹配项,则返回主序列的尾迭代器。

以下是 std::find_end 的详细用法和示例:

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

int main() {
    // 主序列
    std::vector<int> main_sequence = {1, 2, 3, 4, 1, 2, 3, 4, 5};
    // 子序列
    std::vector<int> sub_sequence = {1, 2, 3, 4};

    // 使用 std::find_end 查找子序列在主序列中的最后一个匹配项
    auto it = std::find_end(main_sequence.begin(), main_sequence.end(),
                            sub_sequence.begin(), sub_sequence.end());

    if (it != main_sequence.end()) {
        // 如果找到了子序列,输出匹配项的起始位置
        std::cout << "Found sub-sequence at the last position starting at: "
                  << std::distance(main_sequence.begin(), it) << std::endl;
    } else {
        // 如果没有找到子序列,输出消息
        std::cout << "Sub-sequence not found." << std::endl;
    }

    return 0;
}

在这个例子中,std::find_end 会在 main_sequence 中查找 sub_sequence 的最后一个出现位置。因为 sub_sequence 在 main_sequence 中出现了两次,std::find_end 会找到最后一次出现的位置并输出它的起始位置。

std::find_end 还有一个重载版本,它接受一个二元谓词(binary predicate)作为第五个参数,用于自定义比较逻辑:

template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
ForwardIt1 find_end( ForwardIt1 first1, ForwardIt1 last1,
                      ForwardIt2 first2, ForwardIt2 last2,
                      BinaryPredicate p );

二元谓词是一个返回布尔值的函数或函数对象,它接受两个参数并确定它们是否相等。这使得你可以在搜索时提供自定义的相等性判断。

例如,如果你想在一个字符串序列中查找另一个字符串序列,但忽略大小写,你可以这样做:

#include <iostream>
#include <vector>
#include <algorithm>
#include <cctype>
#include <string>

// 自定义比较函数对象,忽略大小写比较字符
struct ignore_case {
    bool operator()(char a, char b) const {
        return std::tolower(a) == std::tolower(b);
    }
};

int main() {
    // 主序列
    std::vector<std::string> main_sequence = {"apple", "Banana", "Cherry", "Date"};
    // 子序列
    std::vector<std::string> sub_sequence = {"banana", "cherry"};

    // 使用 std::find_end 和自定义比较函数对象查找子序列
    auto it = std::find_end(main_sequence.begin(), main_sequence.end(),
                            sub_sequence.begin(), sub_sequence.end(),
                            ignore_case());

    if (it != main_sequence.end()) {
        // 如果找到了子序列,输出匹配项的起始位置
        std::cout << "Found sub-sequence at the last position starting at: "
                  << std::distance(main_sequence.begin(), it) << std::endl;
    } else {
        // 如果没有找到子序列,输出消息
        std::cout << "Sub-sequence not found." << std::endl;
    }

    return 0;
}

在这个例子中,ignore_case 结构被用作 std::find_end 的二元谓词,以忽略大小写的方式比较字符串中的字符。

find_first_of()

std::find_first_of 是 C++ 标准库中的一个泛型算法,用于在一个序列(主序列)中查找另一个序列(搜索序列)中任意一个元素的第一个匹配项。这个算法返回主序列中第一个匹配元素的迭代器,如果没有找到匹配项,则返回主序列的尾迭代器。

下面是 std::find_first_of 的两个版本的详细用法,每个版本都附带一个例子:

  1. 基本版本
    用法:
template< class ForwardIt1, class ForwardIt2 >
ForwardIt1 find_first_of( ForwardIt1 first1, ForwardIt1 last1,
                           ForwardIt2 first2, ForwardIt2 last2 );

例子:

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

int main() {
    // 主序列
    std::vector<char> mainSequence = {'a', 'b', 'c', 'd', 'e', 'f'};
    // 搜索序列
    std::vector<char> searchSequence = {'c', 'd', 'z'};

    // 查找主序列中第一个匹配搜索序列中任意一个元素的位置
    auto it = std::find_first_of(mainSequence.begin(), mainSequence.end(),
                                 searchSequence.begin(), searchSequence.end());

    if (it != mainSequence.end()) {
        // 如果找到了匹配项,输出它的位置
        std::cout << "First element of searchSequence found at position: "
                  << std::distance(mainSequence.begin(), it) << std::endl;
    } else {
        // 如果没有找到匹配项,输出消息
        std::cout << "No element of searchSequence found." << std::endl;
    }

    return 0;
}

在这个例子中,std::find_first_of 会在 mainSequence 中查找 searchSequence 中任意一个元素的第一个匹配项。因为 ‘c’ 是 searchSequence 中的第一个元素,并且在 mainSequence 中也是第一个匹配的元素,所以 it 会指向 mainSequence 中的 ‘c’,并且程序会输出匹配元素的位置。
2. 带有二元谓词的版本
用法:

template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
ForwardIt1 find_first_of( ForwardIt1 first1, ForwardIt1 last1,
                           ForwardIt2 first2, ForwardIt2 last2,
                           BinaryPredicate p );

例子:

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

// 自定义比较函数对象,比较两个字符是否相等(不区分大小写)
struct is_equal_ignore_case {
    bool operator()(char a, char b) const {
        return std::tolower(a) == std::tolower(b);
    }
};

int main() {
    // 主序列
    std::vector<std::string> mainSequence = {"apple", "Banana", "Cherry", "Date"};
    // 搜索序列
    std::vector<std::string> searchSequence = {"banana", "cherry"};

    // 使用自定义的比较函数对象查找主序列中第一个匹配搜索序列中任意一个元素的位置
    auto it = std::find_first_of(mainSequence.begin(), mainSequence.end(),
                                 searchSequence.begin(), searchSequence.end(),
                                 is_equal_ignore_case());

    if (it != mainSequence.end()) {
        // 如果找到了匹配项,输出它的位置
        std::cout << "First element of searchSequence found at position: "
                  << std::distance(mainSequence.begin(), it) << std::endl;
    } else {
        // 如果没有找到匹配项,输出消息
        std::cout << "No element of searchSequence found." << std::endl;
    }

    return 0;
}

在这个例子中,std::find_first_of 使用 is_equal_ignore_case 函数对象作为二元谓词,来在主序列 mainSequence 中查找搜索序列 searchSequence 中第一个匹配的元素,而不考虑大小写。因为 “banana” 和 “cherry” 在忽略大小写的情况下,分别是 mainSequence 中的第二个和第三个元素,所以 it 会指向 mainSequence 中的 “Banana”,并且程序会输出匹配元素的位置。

adjacent_find()

std::adjacent_find 是 C++ 标准库中的一个泛型算法,用于在一个序列中查找相邻的重复元素。该算法会返回指向第一对相邻重复元素的迭代器,如果没有找到任何相邻的重复元素,则返回序列的尾迭代器。

以下是 std::adjacent_find 的基本语法:

template< class ForwardIt >
ForwardIt adjacent_find( ForwardIt first, ForwardIt last );

template< class ForwardIt, class BinaryPredicate >
ForwardIt adjacent_find( ForwardIt first, ForwardIt last, BinaryPredicate p );

第一个版本接受两个迭代器,表示序列的范围([first, last))。它使用 operator== 来比较相邻的元素是否相同。

第二个版本与第一个类似,但还接受一个二元谓词 p,用于自定义比较逻辑。

std::adjacent_find 的返回值是一个迭代器,指向序列中第一对相邻的重复元素。如果没有找到任何相邻的重复元素,则返回序列的尾迭代器。

以下是一个 std::adjacent_find 的使用示例:

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

int main() {
    // 创建一个序列
    std::vector<int> sequence = {1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 9};

    // 使用 adjacent_find 查找相邻的重复元素
    auto it = std::adjacent_find(sequence.begin(), sequence.end());

    if (it != sequence.end()) {
        // 如果找到了相邻的重复元素,输出它们
        std::cout << "Adjacent elements are: " << *it << " and " << *(std::next(it)) << std::endl;
    } else {
        // 如果没有找到相邻的重复元素,输出消息
        std::cout << "No adjacent elements found." << std::endl;
    }

    return 0;
}

在这个例子中,std::adjacent_find 在 sequence 中查找相邻的重复元素。因为 4 和 4 以及 8 和 8 是相邻的重复元素,所以 it 会指向第一个 4,并且程序会输出:

Adjacent elements are: 4 and 4

注意,std::adjacent_find 只返回第一对找到的相邻重复元素的位置。如果需要查找所有相邻的重复元素对,可以使用一个循环。

std::adjacent_find 的二元谓词版本允许你自定义两个相邻元素之间的比较逻辑。你可以传递一个二元谓词(即一个接受两个参数并返回一个布尔值的对象或函数),以决定何时认为两个元素是“相邻的”。

下面是一个使用 std::adjacent_find 二元谓词版本的例子。在这个例子中,我们将查找相邻的整数,这些整数之间的差小于 3:

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

// 自定义二元谓词,检查两个整数之间的差是否小于 3
struct is_close {
    int threshold;
    is_close(int t) : threshold(t) {}
    bool operator()(int a, int b) const {
        return std::abs(a - b) < threshold;
    }
};

int main() {
    // 创建一个整数序列
    std::vector<int> sequence = {1, 2, 4, 5, 6, 8, 9, 11, 12, 14};

    // 使用自定义的二元谓词查找相邻的元素,这些元素之间的差小于 3
    auto it = std::adjacent_find(sequence.begin(), sequence.end(), is_close(3));

    if (it != sequence.end()) {
        // 如果找到了相邻的元素对,输出它们
        std::cout << "Adjacent elements are: " << *it << " and " << *(std::next(it)) << std::endl;
    } else {
        // 如果没有找到满足条件的相邻元素对,输出消息
        std::cout << "No adjacent elements found with a difference less than 3." << std::endl;
    }

    return 0;
}

在这个例子中,is_close 是一个结构体,它包含一个构造函数来初始化阈值(在这个例子中是 3),以及一个重载的调用操作符 operator(),它接受两个整数并检查它们的差的绝对值是否小于阈值。

std::adjacent_find 使用这个 is_close 谓词来查找序列中相邻的元素,这些元素的差小于 3。在 sequence 中,第一对满足条件的相邻元素是 4 和 5,因为它们的差是 1,小于 3。因此,程序会输出:

Adjacent elements are: 4 and 5

这个二元谓词版本非常灵活,因为它允许你定义什么是“相邻”的,而不仅仅是使用默认的相等比较。

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊猫Devin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值