【STL二十】算法——排序操作(sort、stable_sort)_ 集合操作(merge)
- 一、分类
- 二、修改序列的操作
- 三、排序操作
- 1、sort
- 2、stable_sort
- 3、is_sorted、is_sorted_until
- 四、集合操作
- 1、merge
- 2、inplace_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>