【STL二十】算法——排序操作(sort、stable_sort)_集合操作(merge)

一、分类

根据网站https://www.apiref.com/cpp-zh/cpp/header.html显示,头文件<algorithm>提供的算法如下图。

  • 常用的分类
    • 不修改序列的操作
    • 修改序列的操作
    • 排序操作
    • 集合操作

在这里插入图片描述

二、修改序列的操作

  • 排序操作
函数名 用法
sort (first, last) 对容器或普通数组中 [first, last) 范围内的元素进行排序,默认进行升序排序。
stable_sort (first, last) 和 sort() 函数功能相似,不同之处在于,对于 [first, last) 范围内值相同的元素,该函数不会改变它们的相对位置。
is_sorted (first, last) 检测 [first, last) 范围内是否已经排好序,默认检测是否按升序排序。
is_sorted_until() 从序列中查找第一个未排序的元素。
  • 集合操作
项目 Value
merge() 合并两个已排序的序列。
inplace_merge() 合并两个已排序的序列。

三、排序操作

1、sort

sort() 函数有 2 种用法,其语法格式分别为:

//对 [first, last) 区域内的元素做默认的升序排序
void sort (RandomAccessIterator first, RandomAccessIterator last);
//按照指定的 comp 排序规则,对 [first, last) 区域内的元素进行排序
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

其中,first 和 last 都为随机访问迭代器,它们的组合 [first, last) 用来指定要排序的目标区域;另外在第 2 种格式中,comp 可以是 C++ STL 标准库提供的排序规则(比如 std::greater),也可以是自定义的排序规则。-

  • demo
#include <iostream>     // std::cout
#include <algorithm>    // std::sort
#include <vector>       // std::vector
//以普通函数的方式实现自定义排序规则
bool mycomp(int i, int j) {
    
    
    return (i < j);
}
//以函数对象的方式实现自定义排序规则
class mycomp2 {
    
    
public:
    bool operator() (int i, int j) {
    
    
        return (i < j);
    }
};
int main() {
    
    
    std::vector<int> myvector{
    
     10, 1, 3, 5, 7, 9};
    std::cout << "调用第一种语法格式,进行排序:" << std::endl;
    std::sort(myvector.begin(), myvector.begin() + 4); 
    for (auto t : myvector) std::cout << t << ' ';

    std::cout << "\n调用第二种语法格式,利用STL标准库提供的其它比较规则(比如 greater<T>)进行排序:" << std::endl;
    std::sort(myvector.begin(), myvector.begin() + 4, std::greater<int>());
    for (auto t : myvector) std::cout << t << ' ';

    std::cout << "\n调用第二种语法格式,通过自定义比较规则进行排序:" << std::endl;
    std::sort(myvector.begin(), myvector.end(), mycomp2());
    //输出 myvector 容器中的元素
    for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it) {
    
    
        std::cout << *it << ' ';
    }
    return 0;
}

2、stable_sort

  • 已经了解了 sort() 函数的功能和用法。值得一提的是,当指定范围内包含多个相等的元素时,sort() 排序函数无法保证不改变它们的相对位置。那么,如果既要完成排序又要保证相等元素的相对位置,该怎么办呢?可以使用 stable_sort() 函数。

  • stable_sort() 函数完全可以看作是 sort() 函数在功能方面的升级版。换句话说,stable_sort() 和 sort() 具有相同的使用场景,就连语法格式也是相同的(后续会讲),只不过前者在功能上除了可以实现排序,还可以保证不改变相等元素的相对位置。

  • table_sort() 函数的用法也有 2 种,其语法格式和 sort() 函数完全相同(仅函数名不同):

//对 [first, last) 区域内的元素做默认的升序排序
void stable_sort ( RandomAccessIterator first, RandomAccessIterator last );
//按照指定的 comp 排序规则,对 [first, last) 区域内的元素进行排序
void stable_sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );

其中,first 和 last 都为随机访问迭代器,它们的组合 [first, last) 用来指定要排序的目标区域;另外在第 2 种格式中,comp 可以是 C++ STL 标准库提供的排序规则(比如 std::greater),也可以是自定义的排序规则。

  • demo
#include <iostream>     // std::cout
#include <algorithm>    // std::sort
#include <vector>       // std::vector
//以普通函数的方式实现自定义排序规则
bool mycomp(int i, int j) {
    
    
    return (i < j);
}
//以函数对象的方式实现自定义排序规则
class mycomp2 {
    
    
public:
    bool operator() (int i, int j) {
    
    
        return (i < j);
    }
};
int main() {
    
    
    std::vector<int> myvector{
    
     10, 1, 3, 5, 7, 9};
    std::cout << "调用第一种语法格式,进行排序:" << std::endl;
    std::stable_sort(myvector.begin(), myvector.begin() + 4);
    for (auto t : myvector) std::cout << t << ' ';

    std::cout << "\n调用第二种语法格式,利用STL标准库提供的其它比较规则(比如 greater<T>)进行排序:" << std::endl;
    std::stable_sort(myvector.begin(), myvector.begin() + 4, std::greater<int>());
    for (auto t : myvector) std::cout << t << ' ';

    std::cout << "\n调用第二种语法格式,通过自定义比较规则进行排序:" << std::endl;
    std::stable_sort(myvector.begin(), myvector.end(), mycomp2());
    //输出 myvector 容器中的元素
    for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it) {
    
    
        std::cout << *it << ' ';
    }
    return 0;
}

输出

调用第一种语法格式,进行排序:
1 3 5 10 7 9
调用第二种语法格式,利用STL标准库提供的其它比较规则(比如 greater)进行排序:
10 5 3 1 7 9
调用第二种语法格式,通过自定义比较规则进行排序:
1 3 5 7 9 10

3、is_sorted、is_sorted_until

is_sorted() 函数有 2 种语法格式,分别是:

//判断 [first, last) 区域内的数据是否符合 std::less<T> 排序规则,即是否为升序序列
bool is_sorted (ForwardIterator first, ForwardIterator last);
//判断 [first, last) 区域内的数据是否符合 comp 排序规则  
bool is_sorted (ForwardIterator first, ForwardIterator last, Compare comp);

其中,first 和 last 都为正向迭代器(这意味着该函数适用于大部分容器),[first, last) 用于指定要检测的序列;comp 用于指定自定义的排序规则。

#include <iostream> 
#include <algorithm>
#include <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,1,2,4 };
    //调用第 2 种语法格式的 is_sorted() 函数,该判断语句会得到执行
    if (!is_sorted(myvector.begin(), myvector.end(), mycomp2())) {
    
    
        cout << "开始对 myvector 容器排序" << endl;
        //对 myvector 容器做降序排序
        sort(myvector.begin(), myvector.end(), mycomp2());
        //输出 myvector 容器中的元素
        for (auto it = myvector.begin(); it != myvector.end(); ++it) {
    
    
            cout << *it << " ";
        }
    }
    return 0;
}

输出

开始对 myvector 容器排序
4 3 2 1

  • is_sorted_until

is_sorted_until() 函数有以下 2 种语法格式:

//排序规则为默认的升序排序
ForwardIterator is_sorted_until (ForwardIterator first, ForwardIterator last);
//排序规则是自定义的 comp 规则
ForwardIterator is_sorted_until (ForwardIterator first,
                                 ForwardIterator last,
                                 Compare comp);

其中,first 和 last 都为正向迭代器(这意味着该函数适用于大部分容器),[first, last) 用于指定要检测的序列;comp 用于指定自定义的排序规则。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void) {
    
    
    vector<int> v = {
    
     1, 2, 3, 5, 4 };
    auto it = is_sorted_until(v.begin(), v.end());
    cout << "First unsorted element = " << *it << endl;
    v[3] = 4;
    it = is_sorted_until(v.begin(), v.end());
    if (it == end(v))
        cout << "Entire vector is sorted." << endl;
    return 0;
}

输出

First unsorted element = 4
Entire vector is sorted.

四、集合操作

1、merge

merge() 函数用于将 2 个有序序列合并为 1 个有序序列,前提是这 2 个有序序列的排序规则相同(要么都是升序,要么都是降序)。并且最终借助该函数获得的新有序序列,其排序规则也和这 2 个有序序列相同。
C++ STL 标准库的开发人员考虑到用户可能需要自定义排序规则,因此为 merge() 函数设计了以下 2 种语法格式:

//以默认的升序排序作为排序规则
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);

可以看到,first1、last1、first2 以及 last2 都为输入迭代器,[first1, last1) 和 [first2, last2) 各用来指定一个有序序列;result 为输出迭代器,用于为最终生成的新有序序列指定存储位置;comp 用于自定义排序规则。同时,该函数会返回一个输出迭代器,其指向的是新有序序列中最后一个元素之后的位置。

#include <iostream>     // std::cout
#include <algorithm>    // std::merge
#include <vector>       // std::vector
using namespace std;
int main() {
    
    
    //first 和 second 数组中各存有 1 个有序序列
    int first[] = {
    
     1,3,5,7,9 };
    int second[] = {
    
     2,4,6,8,10 };
    //用于存储新的有序序列
    vector<int> myvector(11);
    //将 [first,first+5) 和 [second,second+5) 合并为 1 个有序序列,并存储到 myvector 容器中。
    merge(first, first + 5, second, second + 5, myvector.begin());
    //输出 myvector 容器中存储的元素
    for (vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it) {
    
    
        cout << *it << ' ';
    }
    return 0;
}

2、inplace_merge

当 2 个有序序列存储在同一个数组或容器中时,如果想将它们合并为 1 个有序序列,除了使用 merge() 函数,更推荐使用 inplace_merge() 函数。

和 merge() 函数相比,inplace_merge() 函数的语法格式要简单很多:

//默认采用升序的排序规则
void inplace_merge (BidirectionalIterator first, BidirectionalIterator middle,
                    BidirectionalIterator last);
//采用自定义的 comp 排序规则
void inplace_merge (BidirectionalIterator first, BidirectionalIterator middle,
                    BidirectionalIterator last, Compare comp);

其中,first、middle 和 last 都为双向迭代器,[first, middle) 和 [middle, last) 各表示一个有序序列。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(void) {
    
    
   vector<int> v = {
    
    1, 3, 2, 4, 5};
   inplace_merge(v.begin(), v.begin() + 2, v.end());
   for (auto it = v.begin(); it != v.end(); ++it)
      cout << *it << endl;
   return 0;
}

输出

1
2
3
4
5

原计划接下来两篇会介绍内存分配器和内存池,但是梳理知识时发现,需要把c++的内存模型搞清楚才好讲分配器那些,所以,接下来会临时补充几篇c++内存模型相关的文章。

参考
1、C++ STL 容器库 中文文档
2、STL教程:C++ STL快速入门
3、https://www.apiref.com/cpp-zh/cpp/header.html
4、https://en.cppreference.com/w/cpp/header
5、WIKI教程_C ++标准库_C++ Library - <algorithm>

猜你喜欢

转载自blog.csdn.net/junxuezheng/article/details/130021566
今日推荐