material/program/c_cpp/STL/algorithms.md

253 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# STL算法
## 目录
- [非修改性算法](#)
- [find](#find)
- [conut](#conut)
- [二分查找](#binary-search)
- [修改性算法](#)
- [copy](#)
- [replace](#):将指定范围内等于给定值的元素替换为新值
- [reverse](#):翻转序列
- [排序算法](#)
- [sort](#)
- [稳定排序](#stable-sort)
- [第n大数](#nth-element)
- [数值算法](#)
- [accumulate](#):计算指定范围内元素的累积和
- [计算两个序列的内积](#inner-product)
- [集合算法](#)
- [两个有序序列的差集](#set-difference)
- [将两个有序序列合并为一个有序序列](#merge)
- [其他算法](#)
- [去除相邻重复元素](#unique)
- [随机打乱序列](#shuffle)
## 非修改性算法
### find
```
template <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& value);
```
+ InputIterator输入迭代器类型表示要搜索的范围的起始和结束位置。
+ first指向范围的起始位置的迭代器。
+ last指向范围的结束位置的迭代器不包含
+ value要查找的目标值。
+ 返回值:如果找到目标值,返回指向该元素的迭代器;如果没有找到,则返回 last
__注意事项__
1. 返回值的判断
如果未找到目标值,返回值是 last,通常需要通过比较返回值是否等于 last 来判断是否找到目标
2. 自定义对象的比较
如果要在自定义对象中使用 `std::find`,需要重载 `operator==`,以便算法能够比较对象是否相等
3. 性能
是线性查找算法,时间复杂度为 O(n),其中 n 是范围内的元素数量
4. 范围的正确性
确保 first 和 last 指向的范围是有效的,并且 first 不大于 last
### conut
```
template <class InputIterator, class T>
typename iterator_traits<InputIterator>::difference_type count(
InputIterator first,
InputIterator last,
const T& value
);
```
+ InputIterator输入迭代器类型表示要搜索的范围的起始和结束位置。
+ first指向范围的起始位置的迭代器。
+ last指向范围的结束位置的迭代器不包含
+ value要统计的目标值。
+ 返回值:返回等于目标值的元素个数,类型为 `iterator_traits<InputIterator>::difference_type`
__注意事项__
1. 返回值的判断
返回值类型是 `iterator_traits<InputIterator>::difference_type`,通常是与容器相关的整数类型 `int` `size_t`
2. 自定义对象的比较
需要重载 `operator==`,以便算法能够比较对象是否相等
3. 性能
是线性查找算法,时间复杂度为 O(n),其中 n 是范围内的元素数量
4. 范围的正确性
确保 first 和 last 指向的范围是有效的,并且 first 不大于 last
### binary-search
用于在*有序序列*中查找是否存在某个值,基于二分查找的思想,时间复杂度为 O(log n)
只返回布尔值,表示是否找到目标值,如果需要找到目标值的位置,可以结合 `std::lower_bound``std::upper_bound` 使用
```
template <class ForwardIterator, class T>
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value);
```
+ ForwardIterator正向迭代器类型表示要搜索的范围的起始和结束位置。
+ first指向范围的起始位置的迭代器。
+ last指向范围的结束位置的迭代器不包含
+ value要查找的目标值。
+ 返回值:如果找到目标值,返回 true否则返回 false。
__还支持自定义比较函数__
```
template <class ForwardIterator, class T, class Compare>
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp);
```
+ Compare比较函数用于定义元素之间的大小关系。如果未提供会使用默认的 < 比较运算符
## 修改性算法
### copy
用于将一个范围内的元素复制到另一个范围中,是一个线性算法时间复杂度为 O(n)
```
template <class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result);
```
+ InputIterator输入迭代器类型表示要复制的源范围的起始和结束位置
+ first指向源范围的起始位置的迭代器
+ last指向源范围的结束位置的迭代器不包含)。
+ OutputIterator输出迭代器类型表示目标范围的起始位置
+ result指向目标范围的起始位置的迭代器
+ 返回值返回指向目标范围结束位置的迭代器 result + (last - first)
### replace
用于在指定范围内将所有等于某个特定值的元素替换为另一个值
```
template <class ForwardIterator, class T>
void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value);
```
+ ForwardIterator正向迭代器类型表示要操作的范围的起始和结束位置
+ first指向范围的起始位置的迭代器
+ last指向范围的结束位置的迭代器不包含)。
+ `old_value`要被替换的旧值
+ `new_value`用于替换的新值
如果需要更复杂的替换逻辑例如基于条件的替换可以结合 `std::replace_if` 使用后者允许传入一个谓词函数来定义替换条件
### reverse
反转指定范围内的元素顺序,要求输入范围的迭代器是双向迭代器即支持双向遍历
```
template <class BidirectionalIterator>
void reverse(BidirectionalIterator first, BidirectionalIterator last);
```
+ BidirectionalIterator双向迭代器类型表示要反转的范围的起始和结束位置
+ first指向范围的起始位置的迭代器
+ last指向范围的结束位置的迭代器(不包含)
## 排序算法
### sort
指定范围内的元素进行排序,要求输入范围的迭代器是随机访问迭代器是不稳定的排序算法,平均时间复杂度为 O(n log n)
```
template <class RandomAccessIterator>
void sort(RandomAccessIterator first, RandomAccessIterator last);
```
+ RandomAccessIterator随机访问迭代器类型表示要排序的范围的起始和结束位置
+ first指向范围的起始位置的迭代器
+ last指向范围的结束位置的迭代器不包含
此外std::sort 还支持自定义比较函数
```
template <class RandomAccessIterator, class Compare>
void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
```
### stable-sort
是一个稳定排序算法,对指定范围内的元素进行排序同时保证相等元素的相对顺序不变
```
template <class RandomAccessIterator>
void stable_sort(RandomAccessIterator first, RandomAccessIterator last);
template <class RandomAccessIterator, class Compare>
void stable_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
```
+ first last随机访问迭代器分别指向要排序范围的起始位置和结束位置不包含
+ Compare可选的比较函数用于定义排序规则如果未提供默认使用 < 运算符
如果有足够的额外内存`std::stable_sort` 的时间复杂度为 O(n log n),内存不足时间复杂度可能退化为 O(n log² n)
### nth-element
用于部分排序序列使得第 k 小的元素被放置到正确的位置同时保证所有在它之前的元素都不大于它所有在它之后的元素都不小于它,平均时间复杂度O(n),最坏时间复杂度O(n²)
```
template <class RandomIt>
void nth_element(RandomIt first, RandomIt nth, RandomIt last);
template <class RandomIt, class Compare>
void nth_element(RandomIt first, RandomIt nth, RandomIt last, Compare comp);
```
+ first指向序列起始位置的随机访问迭代器
+ nth指向序列中第 k 个位置的迭代器0-based index)。
+ last指向序列结束位置的迭代器
+ comp可选自定义比较函数默认使用 std::less
> 不会完全排序整个序列,它只保证第 k 小的元素在正确的位置上
> 该算法的性能优于完全排序
## 数值算法
### accumulate
用于计算指定范围内元素的累积和,时间复杂度为 O(n)
`std::accumulate` first 开始逐个处理范围内的元素将每个元素与累积结果进行操作默认为加法并将最终结果返回
```
template <class InputIterator, class T>
T accumulate(InputIterator first, InputIterator last, T init);
template <class InputIterator, class T, class BinaryOperation>
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation op);
```
+ InputIterator输入迭代器类型表示要操作的范围的起始和结束位置
+ first指向范围的起始位置的迭代器
+ last指向范围的结束位置的迭代器不包含)。
+ T累积结果的类型
+ init初始值用于开始累积操作
+ BinaryOperation可选二元操作函数用于定义累积操作如果未提供默认使用加法操作 `std::plus<T>` [预定义函数符](./containers.md#)
### inner-product
## 集合算法
### set-difference
### merge
## 其他算法
### unique
用于移除序列中相邻的重复元素,并返回一个指向新序列结束位置的迭代器它不会改变原序列的长度而是将重复元素移动到序列末尾并返回一个指向有效部分结束位置的迭代器因此通常需要结合容器的 erase 方法来真正移除重复元素,O(n)
```
template <class ForwardIterator>
ForwardIterator unique(ForwardIterator first, ForwardIterator last);
template <class ForwardIterator, class BinaryPredicate>
ForwardIterator unique(ForwardIterator first, ForwardIterator last, BinaryPredicate pred);
```
+ ForwardIterator正向迭代器类型表示要操作的序列的起始和结束位置
+ first指向序列起始位置的迭代器
+ last指向序列结束位置的迭代器不包含)。
+ BinaryPredicate可选二元谓词函数用于定义两个元素是否相等如果未提供默认使用 operator==
### shuffle
随机打乱指定范围内元素的顺序
```
template <class RandomAccessIterator, class URNG>
void shuffle(RandomAccessIterator first, RandomAccessIterator last, URNG&& g);
```
+ first last随机访问迭代器分别指向要打乱范围的起始位置和结束位置不包含
+ URNG均匀随机数生成器,例如 `std::mt19937` `std::default_random_enginei`
```
// 使用随机数生成器
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::mt19937 rng(seed);
// 打乱顺序
std::shuffle(vec.begin(), vec.end(), rng);
```