21- C++ STL 算法-9 (C++)

10.3 算法

10.3.1 排序算法

10.3.1.1 sort() 排序函数

  • sort() 函数是基于快速排序实现的

  • sort() 函数受到底层实现方式的限制,它仅适用于普通数组和部分类型的容器。换句话说,只有普通数组和具备以下条件的容器,才能使用 sort() 函数:

    • 容器支持的迭代器类型必须为随机访问迭代器。这意味着,sort() 只对 vector、deque 这 2个容器提供支持

    • 如果对容器中指定区域的元素做默认升序排序,则元素类型必须支持<小于运算符;同样,如果选用标准库提供的其它排序规则,元素类型也必须支持该规则底层实现所用的比较运算符

    • sort() 函数在实现排序时,需要交换容器中元素的存储位置。这种情况下,如果容器中存储的是自定义的类对象,则该类的内部必须拷贝构造函数和赋值运算符的重载。

    • sort() 排序是不稳定的

#include <iostream>     // std::cout
#include <algorithm>    // std::sort
#include <vector>       // std::vector
using namespace std;
//以普通函数的方式实现自定义排序规则
bool mycomp(int i, int j) {
    return (i < j);
}
//以函数对象的方式实现自定义排序规则
class mycomp2 {
public:
    bool operator() (int i, int j) {
        return (i < j);
    }
};
int main() {
	int a[] = { 32, 71, 12, 45, 26, 80, 53, 33 };
    vector<int> myvector(a, a+8);
    //调用第一种语法格式,对 32、71、12、45 进行排序
    sort(myvector.begin(), myvector.begin() + 4); //(12 32 45 71) 26 80 53 33
    //调用第二种语法格式,利用STL标准库提供的其它比较规则(比如 greater<T>)进行排序
    sort(myvector.begin(), myvector.begin() + 4, greater<int>()); //(71 45 32 12) 26 80 53 33
   
    //调用第二种语法格式,通过自定义比较规则进行排序
    sort(myvector.begin(), myvector.end(), mycomp2());//12 26 32 33 45 53 71 80
    //输出 myvector 容器中的元素
    for (vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it) {
        cout << *it << ' ';
    }
    return 0;
}

10.3.1.2 stable_sort()排序算法

  • stable_sort() 函数是基于归并排序实现的

  • stable_sort() 是稳定的排序算法

  • stable_sort()函数与sort()函数的使用方法相同。

10.3.1.3 partial_sort()排序函数

1、引入

  • 假设这样一种情境,有一个存有 100 万个元素的容器,但我们只想从中提取出值最小的 10 个元素,该如何实现呢?

    • 通过前面的学习,可能会想到使用 sort() 或者 stable_sort() 排序函数,即通过对容器中存储的 100 万个元素进行排序,就可以成功筛选出最小的 10 个元素。但仅仅为了提取 10 个元素,却要先对 100 万个元素进行排序,可想而知这种实现方式的效率是非常低的。

    • 对于解决类似的问题,C++ STL 标准库提供了更高效的解决方案,使用 partial_sort()。

  • partial sort 可直译为“部分排序”,该函数可以从指定区域中提取出部分数据,并对它们进行排序。

2、语法格式

//按照默认的升序排序规则,对 [first, last) 范围的数据进行筛选并排序
void partial_sort (RandomAccessIterator first,
                   RandomAccessIterator middle,
                   RandomAccessIterator last);
//按照 comp 排序规则,对 [first, last) 范围的数据进行筛选并排序
void partial_sort (RandomAccessIterator first,
                   RandomAccessIterator middle,
                   RandomAccessIterator last,
                   Compare comp);
/*
其中,first、middle 和 last 都是随机访问迭代器,comp 参数用于自定义排序规则。
partial_sort() 函数会以交换元素存储位置的方式实现部分排序的。
具体来说,partial_sort() 会将 [first, last) 范围内最小(或最大)的 middle-first 个元素移动到 
[first, middle) 区域中,并对这部分元素做升序(或降序)排序。
*/

需要注意的是,partial_sort() 函数受到底层实现方式的限制,它仅适用于普通数组和部分类型的容器。换句话说,只有普通数组和具备以下条件的容器,才能使用 partial_sort() 函数:

  • partial_sort() 函数只适用于 array、vector、deque 这 3 个容器。

  • 当选用默认的升序排序规则时,容器中存储的元素类型必须支持 <小于运算符;同样,如果选用标准库提供的其它排序规则,元素类型也必须支持该规则底层实现所用的比较运算符;

  • partial_sort() 函数在实现过程中,需要交换某些元素的存储位置。因此,如果容器中存储的是自定义的类对象,则该类的内部必须提供移动构造函数和移动赋值运算符。

#include <iostream>     // std::cout
#include <algorithm>    // std::partial_sort
#include <vector>       // std::vector
using namespace std;
//以普通函数的方式自定义排序规则
bool mycomp1(int i, int j) {
    return (i > j);
}
//以函数对象的方式自定义排序规则
class mycomp2 {
public:
    bool operator() (int i, int j) {
        return (i > j);
    }
};
int main() {
    vector<int> myvector{ 3,2,5,4,1,6,9,7};
    //以默认的升序排序作为排序规则,将 myvector 中最小的 4 个元素移动到开头位置并排好序
    partial_sort(myvector.begin(), myvector.begin() + 4, myvector.end());
    cout << "第一次排序:\n";
    for (vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
        cout << *it << ' ';
    cout << "\n第二次排序:\n";
    // 以指定的 mycomp2 作为排序规则,将 myvector 中最大的 4 个元素移动到开头位置并排好序
    partial_sort(myvector.begin(), myvector.begin() + 4, myvector.end(), mycomp2());
    for (vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
        cout << *it << ' ';
    return 0;
}

10.3.1.4 merge()函数

功能:将两个已经排好序的序列合并为一个有序的序列

默认排序规则:

//以默认的升序排序作为排序规则
OutputIterator merge (InputIterator1 first1, InputIterator1 last1,
                      InputIterator2 first2, InputIterator2 last2,
                      OutputIterator result);
//以自定义的 comp 规则作为排序规则
OutputIterator merge (InputIterator1 first1, InputIterator1 last1,
                      InputIterator2 first2, InputIterator2 last2,
                      OutputIterator result, Compare comp);
/*
* firs1t为第一个容器的首迭代器,last1为第一个容器的末迭代器;
* first2为第二个容器的首迭代器,last2为容器的末迭代器;
* result为存放结果的容器,comapre为比较函数(可略写,默认为合并为一个升序序列)。
*/

注意:使用的时候result,如果用的vector,必须先使用resize扩容

10.3.1.5 revrese()函数

函数参数:reverse(first,last)

功能:反转容器

注意:

  • string和vector和deque只能使用模板库算法里的反转函数

  • list可以使用算法里的和list类的reverse

  • stack和queue没有迭代器,自然不能使用算法里的reverse,其类也没有提供反转的成员函数

  • set和map的元素是按照键值排序的,不能修改键值,不可反转.

10.3.2 查找算法

10.3.2.1 adjacent_find()

功能:在iterator对标识元素范围内,查找一对相邻重复元素,找到则返回指向这对元素的第一个元素的迭代器。

vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(2);
vecInt.push_back(4);
vecInt.push_back(5);
vecInt.push_back(5);
 
vector<int>::iterator it = adjacent_find(vecInt.begin(), vecInt.end()); //*it == 2

10.3.2.2 binary_search()

功能:二分查找法,在有序序列中查找value,找到则返回true。

set<int> setInt;
setInt.insert(3);
setInt.insert(1);
setInt.insert(7);
setInt.insert(5);
setInt.insert(9);
 
bool bFind = binary_search(setInt.begin(),setInt.end(),5);

10.3.2.3 count()

功能:利用等于操作符,把标志范围内的元素与输入值比较,返回相等的个数。

vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(2);
vecInt.push_back(4);
vecInt.push_back(2);
vecInt.push_back(5);
int iCount = count(vecInt.begin(),vecInt.end(),2); //iCount==3

10.3.2.4 find()

功能:find() 函数用于在指定范围内查找和目标元素值相等的第一个元素。

函数的语法格式:

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

其中,first 和 last 为输入迭代器,[first, last) 用于指定该函数的查找范围;val 为要查找的目标元素

正因为 first 和 last 的类型为输入迭代器,因此该函数适用于所有的序列式容器。

该函数会返回一个输入迭代器,当 find() 函数查找成功时,其指向的是在 [first, last) 区域内查找到的第一个目标元素;如果查找失败,则该迭代器的指向和 last 相同。

find() 函数的底层实现,其实就是用运算符将 val 和 [first, last) 区域内的元素逐个进行比对。这也就意味着,[first, last) 区域内的元素必须支持运算符。

#include <iostream>     // std::cout
#include <algorithm>    // std::find
#include <vector>       // std::vector
using namespace std;
int main() {
    //find() 函数作用于普通数组
    char stl[] ="http://c.biancheng.net/stl/";
    //调用 find() 查找第一个字符 'c'
    char * p = find(stl, stl + strlen(stl), 'c');
    //判断是否查找成功
    if (p != stl + strlen(stl)) {
        cout << p << endl;
    }
    //find() 函数作用于容器
    vector<int> myvector{ 10,20,30,40,50 };
    vector<int>::iterator it;
    it = find(myvector.begin(), myvector.end(), 30);
    if (it != myvector.end())
        cout << "查找成功:" << *it;
    else
        cout << "查找失败";
    return 0;
}

10.3.2.5 find_if()

功能:和 find() 函数相同,find_if() 函数也用于在指定区域内执行查找操作。不同的是,前者需要明确指定要查找的元素的值,而后者则允许自定义查找规则。

#include <iostream>     // std::cout
#include <algorithm>    // std::find_if
#include <vector>       // std::vector
using namespace std;

//以函数对象的形式定义一个 find_if() 函数的查找规则
class mycomp2 {
public:
    bool operator()(const int& i) {
        return ((i % 2) == 1);
    }
};
int main() {
    vector<int> myvector{ 4,2,3,1,5 };
    //调用 find_if() 函数
    vector<int>::iterator it = find_if(myvector.begin(), myvector.end(), mycomp2());
    cout << "*it = " << *it;
    return 0;
}

10.3.2.5 search()

功能:search()函数用于在序列 A 中查找序列 B 第一次出现的位置。

例如,以如下两个序列为例:

可以看到,序列 B 在序列 A 中出现了 2 次,借助 search() 函数,我们可以找到序列 A 中第 1 个 {1,2,3}。

search() 函数提供有以下 2 种语法格式:

//查找 [first1, last1) 范围内第一个 [first2, last2) 子序列
ForwardIterator search (ForwardIterator first1, ForwardIterator last1,
                        ForwardIterator first2, ForwardIterator last2);
//查找 [first1, last1) 范围内,和 [first2, last2) 序列满足 pred 规则的第一个子序列
ForwardIterator search (ForwardIterator first1, ForwardIterator last1,
                        ForwardIterator first2, ForwardIterator last2,
                        BinaryPredicate pred);

其中,各个参数的含义分别为:

  • first1、last1:都为正向迭代器,其组合 [first1, last1) 用于指定查找范围(也就是上面例子中的序列 A);

  • first2、last2:都为正向迭代器,其组合 [first2, last2) 用于指定要查找的序列(也就是上面例子中的序列 B);

  • pred:用于自定义查找规则。该规则实际上是一个包含 2 个参数且返回值类型为 bool 的函数(第一个参数接收 [first1, last1) 范围内的元素,第二个参数接收 [first2, last2) 范围内的元素)。函数定义的形式可以是普通函数,也可以是函数对象。

search() 函数会返回一个正向迭代器,当函数查找成功时,该迭代器指向查找到的子序列中的第一个元素;反之,如果查找失败,则该迭代器的指向和 last1 迭代器相同。

#include <iostream>     // std::cout
#include <algorithm>    // std::search
#include <vector>       // std::vector
using namespace std;
//以普通函数的形式定义一个匹配规则
bool mycomp1(int i, int j) {
    return (i%j == 0);
}
//以函数对象的形式定义一个匹配规则
class mycomp2 {
public:
    bool operator()(const int& i, const int& j) {
        return (i%j == 0);
    }
};
int main() {
    vector<int> myvector{ 1,2,3,4,8,12,18,1,2,3 };
    int myarr[] = { 1,2,3 };
    //调用第一种语法格式
    vector<int>::iterator it = search(myvector.begin(), myvector.end(), 
    myarr, myarr + 3);
    if (it != myvector.end()) {
        cout << "第一个{1,2,3}的起始位置为:" << it - myvector.begin() << ",*it = " << *it << endl;
    }
    int myarr2[] = { 2,4,6 };
    //调用第二种语法格式
    it = search(myvector.begin(), myvector.end(), 
    myarr2, myarr2 + 3, mycomp2());
    if (it != myvector.end()) {
        cout << "第一个{2,3,4}的起始位置为:" << it - myvector.begin() << ",*it = " << *it;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/March_A/article/details/132053290