第八章 非变异算法 8.1循环 8.2查询

非变异算法不直接改变其操作的数据结构的元素,其查找数据结构中的元素,检查序列元素是否满足某函数式,计算序列元素满足某条件的个数等。下表是按功能划分的非变异算法

1.循环     for_each           遍历容器元素,对每个元素执行相同的函数操作

2.查询     find                    在单迭代器序列中找出某个值第一次出现的位置

               find_if                在单迭代器序列中找出符合某谓词的第一个元素

               find_first_of       在双迭代器序列中找出子序列中某元素第一次出现的位置

               adjacent_find     在单选代器序列中找出第一次相邻值相等元素的位置

               find_end             在双迭代器序列中找出一子序列最后一次出现的位置

               Search                在双迭代器序列中找出一个子序列第一次出现的位置

               search_n             在单选代器序列中找出一个值连续 n次出现的位置

3.计数     count                 在序列中统计某个值出现的次数

               count_if              在序列中统计与某谓词(表达式)匹配的次数

4.比较     equal                  两个序列中的对应元素都相同时为真

                Mismatch           找出两个序列相异的第一个元豪

8.1 循环

8.1.1 主要函数

for_each():遍历容器元素,对每个元素执行相同的函数操作

Template

Fun For_each(InIt first, InIt last, Fun f);

InIt:可以是数组或输入迭代器  first:表示数组的起始元素的指针或输入迭代器的起始迭代指针  f:可以是全局函数或者是一元函数

该模板需数的含义是[first,last)之间的每个元案,作为函数f的参数传入并执行。

例:打印向量中每个整型元素的立方

使用 vector 容器存储一系列整数,并使用 for_each 算法对容器中的每个元素应用自定义的函数。在本例中,函数 PrintCube 计算每个元素的立方并将结果打印到控制台上

#include

#include

#include

using namespace std;



void PrintCube(int n)

{

    cout << n * n * n << " ";

}

int main()

{

    const int VECTOR_SIZE = 8;

    typedef vector IntVector;

    typedef IntVector::iterator IntVectorIt;



    IntVector Numbers(VECTOR_SIZE);//创建容器并规定大小



    IntVectorIt start, end, it;//定义了 IntVectorIt 类型的迭代器变量



    for (int i = 0; i < VECTOR_SIZE; i++)//整数依次存储到 Numbers 容器中

        Numbers[i] = i + 1;



    start = Numbers.begin();//赋值

    end = Numbers.end();



    cout << "Numbers{";

    for (it = start; it != end; it++)//for 循环打印出 Numbers 容器中的所有元素

        cout << *it << " ";

    cout << "}\n" << endl;

// for_each 算法,对 Numbers 容器中的每个元素应用 PrintCube 函数

    for_each(start, end, PrintCube);

    cout << "\n";



    return 0;

}

第八章 非变异算法 8.1循环 8.2查询_第1张图片

(1)for_each 函数各参数的含义。start,end 表示向量的起始迭代指针、结束迭代指针,不是具体的值,比如for_each(start[0],end,PrintCube)是错误的,因为 start[0]表示的是向量中第一个元素的值 1。但 for_each(&start[0],end,PrintCube)是正确的,因为&start[0]表示的是第一个元素的地址。

(2) PrintCube函数必须有且只有一个参数,且参数类型与向量的模板类型一致。

例 求整数向量的和、最大值、最小值。

第八章 非变异算法 8.1循环 8.2查询_第2张图片

 PrintInfo P = for_each(A, A + N, PrintInfo());

PS:使用 for_each 算法,对数组 A 中的每个元素应用 PrintInfo 类的对象。通过这个操作,我们将数组中的元素依次传递给 PrintInfo 类的函数调用运算符,并在其中进行总和、最大值和最小值的计算。将 for_each 的结果赋值给 PrintInfo 类的对象 P

(1)必须重载PrintInfo的operator()运算符,本例中即 void operator() (int x)在此函数内完成了求和、最大值、最小值的功能。

(2)主程序中 for_each(A,A+N,PrintInfo())

使用 for_each 算法,对数组 A 中的每个元素应用 PrintInfo 类的对象。通过这个操作,我们将数组中的元素依次传递给 PrintInfo 类的函数调用运算符,并在其中进行总和、最大值和最小值的计算。将 for_each 的结果赋值给 PrintInfo 类的对象 P。

运行时,序执行 PrintInfo(),即调用了 PrintInfo 类中不含参数的构造函数,然后数组中的每一项依次调用PrintInfo类中的 void operator()(int x)函数完成相应功能。

(3)对主程序中 PrintInfo P=for_each(A,A十N,PrintInfo())等号左边PrintInfo

template

Fun for_each(InIt first, InIt last,Fun f);

返回值可以是函数对象,因此本例中等号左侧定义了 PrintInfo&P引用对象。当然只有当[first,last)中所有迭代值都执行了f 函数才最终返回函数对象。

例:下面采用模板传参技术,用STL提供的一元函数模板类,让上例只能求整型向量的和最大值最小值

#include

#include

#include

using namespace std;

//两个模板参数 T 和 _outPara

template 

class PrintInfo : public unary_function//定义模板类 PrintInfo

{

private:

    T nSum;

    T nMax;

    T nMin;

    int count;//已处理的元素数量

public:

    PrintInfo() : count(0), nSum(0), nMax(0), nMin(0) {}   

    T GetSum() { return nSum; }

    T GetMax() { return nMax; }

    T GetMin() { return nMin; }

 //类模板定义的 _outPara 类型   

    _outPara operator()(T x)//函数调用运算符的重载,接受一个参数 x

    {

        if (count == 0)//是第一个元素

        {

            nMax = x;

            nMin = x;

        }

        else

        {

            if (nMax < x)

                nMax = x;

            if (nMin > x)

                nMin = x;

        }

        nSum += x;

        count++;

    }

};

int main()

{

    float A[] = {1.5, 4.2, 2.6, 8.9, 5.7, 7.1};

    const int N = sizeof(A) / sizeof(float);//计算数组的大小

//将数组中的元素依次传递给 PrintInfo 类的函数调用运算符

    PrintInfo P = for_each(A, A + N, PrintInfo());

    cout << "总和是: " << P.GetSum() << endl;

    cout << "最大值: " << P.GetMax() << endl;

    cout << "最小值: " << P.GetMin() << endl;

    return 0;

}

第八章 非变异算法 8.1循环 8.2查询_第3张图片

8.2 查询

8.2.1主要函数

查询操作是应用最广的操作,STL 主要提供了以下查询函数

find():在单迭代器序列中找出某个值第一次出现的位置。

find_if():在单迭代器序列中找出符合某谓词的第一个元素。

find_first_of():在双迭代器序列中找出一子序列中某元素第一次出现的位置

adjacent_find();在单迭代器序列中找出第一次相邻值相等元素的位置。

find_end():在双迭代器序列中找出一子序列最后一次出现的位置。

search():在双迭代器序列中找出一子序列第一次出现的位置。

search_n():在单选代器序列中找出一个值连续 n次出现的位置。

各个函数原型如下所示。

find:

原型:

template

InIt find(InIt first, InIt last, const T& val);

参数说明:

InIt:输入选代器,first 表示起始元素的迭代器指针,last 表示结束元素的迭代器指针。

T:模板类型参数。

该函数是查询[first,last)间迭代器对应的元素值是否有等于 val的,若有则返回其迭代器指针;若无则返回 last。可知查询元素的个数范围是 N∈[0,last-first),由于要判定* (first+N)==val,因此板丁对应的类必须重运符“operator==”.

 find_if

原型:

templateInIt find_if(Init first, InIt last, Pred pr);

参数说明:

InIt: 输人选代器,first 表示起始元的选代器指针,last 表示结束元的选代器指针。

Pred:普通全局函数或一元函数对象,返回值是 bool类型。该函数是查询[first,last)间迭代器对应的元素 *(first十i),若 pr( * (first+i))返回true,则返回此时的迭代器指针,表明满足条件的元素已找到;若没有找到则返回 last。

 find_first_of

原型:

template

FwdItl find first of(FwdIt1 first1, FwdItl lastl,FwdIt2 first2, FwdIt2 last2);

template

FwdItl find first_of(FwdItl first1, FwdIt1 lastl,FwdIt2 first2, FwdIt2 last2,Pred pr);

参数说明:

FwdIt1,FwdIt2;前向迭代器,first 表示起始元素的选代器指针,last 表示结束元素的迭代器指针。

Pred;二元全局函数或函数对象。

第一个原型含义是:若第一个前向迭代器[first1,last1)间第 N个元素与第二个前向代器[first2,last2)间某元素相等,且N最小,则返回 first1+N。表明第一个前向选代器wdIt1中有元素与第二个前向迭代器 FwdIt2 中的元素相等,否则返回 last1。

第二个原型与第一个类似,只不过要定义预判定函 pr( * (firstl+N),* (first2+M))

adjacent_find

原型:

template

FwdIt adjacent_find(FwdIt first,FwdIt last);

template

FwdIt adjacent_find(FwdIt first,FwdIt last, Pred pr);

参数说明:

FwdIt:前向选代器,first 表示起始元的选代器指针,last 表示结束元素的选代器指针。

Pred:二元全局函数或函数对象。

第一个原型含义是,若前向代器 Fwdlt 中存在第N个元素,有*(first+N),且N最小,则表明有两个相邻元素是相等的,返回(first+N)否返回last。

第二个原型与第一个类似,只不过要定义预判定函数 pr( * (frst+N),*(first+N+1))。

find_end

原型:

template

FwdItI find_end(FwdItl first1, FwdItl lastl,Fwdit2 first2, Fwdit2 last2),

template

FwdIti find_end(Ewdit1 first1, EwdIt1 last1,wdit2 first2, Fwdit2 last2, Pred pe

参数说明:

FwdIt1,FwdIt2:前向迭代器,first 表示起始元的迭代器指针,last 表示结束元的迭代器指针。

Pred:二元全局函数或函数对象。

第一个原型含义是:若前向迭代器 FwdItl 从第 N 个元开始:* (firstl+N)* (first2+0), * (firstl+N+1) = * (first2+ 1),..., * [firstl十 (last2- first2-1)]*[first2+(last2-first2-1)],且 N 最大,则返回(firstl+N),否则返回 last1。即返回FwdIt1 元素中最后一次完全与 FwdIt2 序列元素匹配的开始位置。

第二个原型与第一个类似,只不过要定义预判定函数 pr( * (first1+N+M),* (first2+N+M))。

 search

原型:

template

FwdIt1 search(FwdIt1 first1, FwdIt1 last1,FwdIt2 first2,FwdIt2 last2);

template

FwdIt1 search(FwdIt1 first1, FwdIt1 last1,FwdIt2 first2, FwdIt2 last2,Pred pr);

参数说明:

FwdIt1,FwdIt2:前向迭代器,first 表示起始元的迭代器指针,last 表示结束元素的迭代器指针。

Pred;二元全局函数或函数对象。

第一个原型含义是:若前向迭代器 FwdIt1从第 N个元素开始:* (first1十N)=* (first2+0), * (firstl+N+1)= * (first2+ 1),..., * [first] 十 (last2 - first2-1)]* [first2+(last2-first2-1)],且N最小,则返回(firstl十N),否则返回 last2。即返回在FwdIt1 元素中首次完全与 FwdIt2 序列元素匹配的开始位置。

第二个原型与第一个类似,只不过要定义预判定函数 pr( * (first1+N+M),* (irst2+M))

Search_n

template

FwdIt search_n(Fwdit first, Fwdit last,Dist n, const T& val);

template

spwdrt seareh n(FwdIt firat, fwdit last,Dist n, const Ts val, Pred pr);

参数说明:。FwdIt:前向选代器,first 表示起始元素的选代器指针,last 表示结束元素的迭代器指针。count:要搜索的连续出现次数,value:要搜索的特定值。n: 整型变量,表示大小。 val:待比较的值。 Pred:二元全局函数或函数对象。

第一个原型含义是:在前向迭代器 FwdIt 中,从第 N 个元开始连续的n个元素满足;* (first+N)=val,* (first+1)= val,...,* (first+N+n)-val,且 N最小,则返回*(first+N),否则返回 last。

第二个原型与第一个类似,只不过要定义预判定函数 pr( * (first1+N+M),val)。

8.2.2示例分析

例: 7个查询函数的简单应用。

#include //STL算法库的头文件

#include 

using namespace std;



bool mygreater(int m) {//自定义的谓词函数

    return m > 4;//查找大于4的元素。该函数接受一个整数参数m

}



bool pr(int* ptr) {

    return (*ptr) % 2 == 0;//是否为偶数

}



int main() {

    int a[] = {1, 2, 2, 2, 3, 4, 4, 5, 6, 7, 1, 2, 2, 31};

    int nSize = sizeof(a) / sizeof(int);//计算数组a的大小,即元素个数



    cout << "原始数组:" << endl;

    for (int i = 0; i < nSize; i++) {

        cout << a[i] << "\t";

    }

    cout << endl << endl;

//a 结尾的指针 a + nSize

    int* pl = find(a, a + nSize, 3);//find算法在数组a中查找首次出现的值为3的元素

    if (pl != a + nSize) {//指针 pl 相对于数组 a 的偏移量

        cout << "(find) 首次等于 3 的位置:" << pl - a << "\t值:" << *pl << endl;

    }

    int* p2 = find_if(a, a + nSize, mygreater);

    if (p2 != a + nSize) {

        cout << "(find_if) 首次大于 4 的位置:" << p2 - a << "\t值:" << *p2 << endl;

    }



    int b[] = {10, 12, 61};

    int nSize2 = sizeof(b) / sizeof(int);

    int* p3 = find_first_of(a, a + nSize, b, b + nSize2);

    if (p3 != a + nSize) {//数组a中查找首次出现的与数组b中任意元素匹配

        cout << "(find_first_of) 首次在 a 数组中发现 b 数组 [10, 12, 61] 中元素位置:" << p3 - a << "\t值:" << *p3 << endl;

    }



    int* p4 = adjacent_find(a, a + nSize);

    if (p4 != a + nSize) {//在数组a中查找首次出现的相邻元素相同的位置

        cout << "(adjacent_find) 首次相邻元素相同位置:" << p4 - a << "\t值:" << *p4 << endl;

    }



    int c[] = {2, 31};

    int nSize3 = sizeof(c) / sizeof(int);

    int* p5 = find_end(a, a + nSize, c, c + nSize3);

    if (p5 != a + nSize) {//在数组a中查找最后一次出现的与数组c完全匹配的子序列的位置

        cout << "最后一次匹配 c 数组 [2, 31] 位置:" << p5 - a << endl;//12

    }

    int* p6 = search(a, a + nSize, c, c + nSize3);

    if (p6 != a + nSize) {//使用search算法在数组a中查找首次出现的与数组c完全匹配的子序列的位置

        cout << "首次匹配 c 数组 [2, 31] 位置:" << p6 - a << endl;//3

    }

    int* p7 = search_n(a, a + nSize, 3, 2);

    if (p7 != a + nSize) {//在数组a中查找首次出现的连续3个值为2的元素的位置

        cout << "首次出现 3 个 2 的位置:" << p7 - a << endl;//1

    }

    return 0;

}

第八章 非变异算法 8.1循环 8.2查询_第4张图片

find_if 和 find 是C++ STL算法库中的两个函数,用于在容器或者数组中查找元素。它们的区别如下:

1.功能不同:

find 函数用于在范围内查找第一个与指定值相等的元素,并返回指向该元素的迭代器(或指针)。

find_if 函数用于在范围内查找第一个满足指定条件(通过谓词函数)的元素,并返回指向该元素的迭代器(或指针)。

2.查找条件不同:

find 函数通过比较相等运算符(==)来确定元素是否与指定值相等。

find_if 函数通过调用用户自定义的谓词函数(predicate function)来判断元素是否满足特定条件。

3.使用方式不同:

find 函数的调用形式为 find(first, last, value),其中 first 和 last 是表示范围的迭代器(或指针),value 是要查找的特定值。

find_if 函数的调用形式为 find_if(first, last, predicate),其中 first 和 last 是表示范围的迭代(或指针),predicate 是一个谓词函数,用于判断元素是否满足条件。

例 :根据学号询学生信息,且已知学号是关键字

#include 

#include 

#include 

#include 

using namespace std;



class Student {

public:

    int NO;

    string strName;

    Student(int NO, string strName) {

        this->NO = NO;//初始化

        this->strName = strName;

    }

    bool operator==(int NO) {//重载了 operator== 运算符,用于判断学生对象的学号是否与给定的学号相等

        return (this->NO == NO);

    }

};

int main() {

    vector v;

    Student s1(101, "张三");

    Student s2(102, "李四");

    v.push_back(s1);

    v.push_back(s2);



    vector::iterator begin, end, it_find;//声明了三个迭代器it_find存储查找结果的迭代器

    begin = v.begin();

    end = v.end();



    int nFindNO = 102;//表示要查询的学号



    it_find = find(begin, end, nFindNO);//find 函数在向量中查找学号为 nFindNO 的学生



    cout << "查询学号为" << nFindNO << "的信息:" << endl;



    if (it_find != end) {

        cout << "学号:" << it_find->NO << "\t" << "姓名:" << it_find->strName << endl;

    } else {

        cout << "无该学号学生!" << endl;

    }

    return 0;

}

第八章 非变异算法 8.1循环 8.2查询_第5张图片理解 Student类必须重载运算符“==”。当执行 find(begin,end,nFindNO)语句时,[begin,end)间的每一个迭代指针表示的 Student 对象都要与 nFindNO 比较,判断是否相等,因此必须重载 Student类中的“==”运算符。由于 nFindNO 是整型,因此重载的“=="运算符参数必须是整型数。

8.3 习题

1. 下面哪个algorithm定义的函数支持对数据传入自定义的处理算法(  )

   A. for    B. find_if    C. count   D. swap

2. 下面哪个不属于algorithm算法定义的函数(D)

  A. for_each    B. find_if    C. count   D. less<>//属于函数对象functional

3.下面哪个函数实现遍历容器元素,对每个元素执行相同的函数操作()

    A. for   B. for_each   C. count  D. swap

你可能感兴趣的:(C++STL大三上,算法,c++,数据结构,学习)