程序设计学习笔记(C++、STL)2023.5.1

一、概述

在程序设计中常用的数据结构包含线性结构、树状结构、图结构、散列结构等。针对不同结构常见的操作包括构建、插入、查找、删除等。

二、数据结构以及容器

在线性结构中常用的是数组和字符串,字符串是一种特殊的数组,但是具有一些特殊的使用场景和方法。通用的方法包括查找、删除、插入,字符串包含正则表达式、子串等。

1. 数组

在容器存储的数组中实现折半查找,使用迭代器实现折半查找。

#include
#include

template
bool binary_search(T1 first, T1 last, const T2 value){
    if(first > last){
        return false;
    }
    T1 middle = first + (last - first)/2;
    if(*middle < value){
        return binary_search(middle+1, last, value);
    }else if (value < *middle){
        return binary_search(first, middle-1, value);
    }
    return true;
}

int main(){
    std::vectorarr = {1, 2, 5, 9, 10, 20, 30};
    std::cout<

使用传统的数组实现折半查找。

#include

template
bool binary_search(T* first, T* last, const T& value){
    if(first > last){
        return false;
    }
    T* middle = first + (last - first)/2;
    if(*middle < value){
        return binary_search(middle+1, last, value);
    }else if (value < *middle){
        return binary_search(first, middle-1, value);
    }
    return true;
}

int main(){
    int arr[] = {1, 2, 5, 9, 10, 20, 30};
    std::cout<

2. 字符串

2.1 使用C++ string类

2.1.1 创建字符串

std::string str;

2.1.2 字符串求子串

string substr(size_t pos=0, size_t len=npos) const

2.1.3 字符串延伸

在string类中重载了与string,char*,char的字符串拼接。

2.1.4 任意位置插入字符串

string& insert(size_t pos, const string& str)

2.1.5 字符串查找

size_t find(const string& str, size_t pos=0) const

size_t rfind(const string& str, size_t pos=0) const

size_t find_first_of(const string& str, size_t pos=0) const

2.1.6 示例

#include
#include
#include

int main(){
    std::string str = "test";
    // 获取字符串的长度使用`length()`函数,直接获取实际的字符串长度
    std::cout<

2.2 使用C类型实现

2.2.1 创建字符串

C语言中字符串是以字符数组的形式实现的,每个字符串以'\0'结尾。

创建字符串的方式有两种,一是按照数组的方式对字符数组赋值,第二种是直接将字符串赋值给数组。

char str1[6] = {'H','e','l','l','o','\0'};
char str2[] = "Hello";

2.2.2 字符串长度

字符串长度可以使用size_t strlen(const char* str);

使用已有的函数需要使用string.h库或者在C++中使用ctring

#include
#include

int my_str_len(char* str){
    if(str == nullptr){
        return 0;
    }
    int ret = 0;
    char *p = str;
    while ((*p)!='\0'){
        ret+=1;
        ++p;
    }
    return ret;
    
}

int main(){
    char str[] = "Hello";
    std::cout<

2.2.3 字符串复制

字符串复制可以直接使用char* strcpy(char* str1, const char* str2);

#include
#include
#include

char* my_strcpy(char* str1, const char* str2){
    assert(str1 != nullptr && str2 != nullptr);
    char* ret = str1;
    while ((*str1++ = *str2++)!='\0');
    return ret;
}

int main(){
    char str[] = "Hello";
    char *new_str = new char[strlen(str)+1];
    std::cout<

2.2.4 字符串拼接

字符串的拼接可以直接使用char* strcat(char* str1, const char* str2);

在C语言中无法探测分配空间的大小,应该开发者考虑是否越界。

#include
#include
#include

char* my_strcat(char* str1, const char* str2){
    assert(str1 != nullptr && str2 != nullptr);
    char* ret = str1;
    while (*str1!='\0'){
        ++str1;
    }
    while ((*str1++ = *str2++)!='\0');
    return ret;
}

int main(){
    char str1[30] = "Hello";
    char str2[] = "World!";
    strcat(str1, str2);
    std::cout<

2.2.5 字符串比较

字符串比较使用int strcmp(const char* str1, const char* str2)

#include
#include
#include

int my_str_cmp(const char* str1, const char* str2){
    assert(str1!=nullptr && str2!=nullptr);
    while ((*str1!='\0')&&(*str1++ == *str2++));
    int t = *str1-*str2;
    if (t == 0){
        return 0;
    }else{
        return (t>0)?1:-1;
    }
    
}

int main(){
    char str1[] = "abcde";
    char str2[] = "abcde";
    std::cout<

2.2.6 子串查找

从字符串中查找字符使用直接的查找,直接查找子串的时间复杂度较大,KMP算法。

#include
#include

int find_str(const char* str1, const char* str2){
    if(str1 == nullptr || str2 == nullptr){
        return -1;
    }
    int n = strlen(str1);
    int m = strlen(str2);
    for(int i = 0; i < n - m + 1; ++i){
        int j = 0;
        for(; j < m; ++j){
            if(str1[i+j] != str2[j]){
                break;
            }
        }
        if(j == m){
            return i;
        }
    }
    return -1;
}

int main(){
    char str1[] = "abcdefghijk";
    char str2[] = "efg";
    std::cout<

三、常用容器

在编程中经常遇到对线性结构的组织以及key-value对的组织,并且在一些场景下需要数值进行自动排序。

1. array

array是一个长度固定不变的容器。

2. vector

vector是一个长度可变的序列容器,支持随机访问,在尾部插入或者删除的效率高,当内存不足会重新分配空间并转移数据。

#include
#include
#include

int main(){
    std::vector vec;
    // 增
    for(int i=0; i<10; ++i){
        // vec.push_back(i);
        vec.emplace_back(i);
    }
    for(auto v: vec){
        std::cout<::iterator rm_iter = std::remove(vec.begin(), vec.end(), 3);
    std::cout<<"Remove 3."<::iterator iter = std::find(vec.begin(), vec.end(), 30);
    if(iter!=vec.end()){
        std::cout<<"Find:"<<*iter<

3. deque

deque是双端序列容器,在双端处增删数据效率高。支持数据的随机访问。

4. list

list是一个以双向链表形式组织的容器,在首尾可以高效插入或者删除元素,不支持数据的随机访问。

5. forward_list

forward_list是一个单链表形式组织的容器,因此只能从一个方向进行元素遍历,比list节省空间。

4. pair

pair表示一对数据first-second

#include
#include
#include

int main(){
    std::vector> vec;
    for(int i=0; i<10; ++i){
        vec.emplace_back(std::pair(10-i, i));
    }
    std::sort(vec.begin(), vec.end(), [](std::pair& a, std::pair& b){return a.first

5. map

map是映射容器,提供一对一的映射,内部自动排序。键的值不能重复也不能修改。

#include
#include
#include

int main(){
    std::map my_map;
    // 增
    for(int i=0; i<10;++i){
        std::pair::iterator, bool> tag = my_map.emplace("str_"+std::to_string(9-i), i);
        if (!tag.second){
            tag.first->second += 1;
        }
    }
    // my_map["str_81"]=20;
    for(auto m: my_map){
        std::cout<::iterator, bool> tag = my_map.emplace("str_"+std::to_string(9-i), i);
        if (!tag.second){
            tag.first->second += 1;
        }
    }
    std::cout<<"New map."<::iterator iter = my_map.find("str_81");
    if(iter != my_map.end()){
        my_map.erase(iter);
    }
    std::cout<<"Delete."<first<<" "<second<

6. multimap

multimap多重映射容器,存储键值对,键的值不能修改,可以存储多个键相同的数据。

7. set

set是集合容器,不允许有相同的元素,因此可用于去重。底层实现为红黑树。

在元素之外额外配置一个键值,键值与元素值相同。默认按照从小到大排序。

#include
#include
#include

int main(){
    std::set my_set;
    // 增
    for(int i=0; i<10; ++i){
        my_set.emplace("str_"+std::to_string(10-i));
    }
    for(auto s: my_set){
        std::cout<::iterator iter = my_set.find("str_2");
    if(iter != my_set.end()){
        my_set.erase(iter);
    }
    my_set.erase("str_3");
    for(auto s: my_set){
        std::cout<

8. multiset

multiset是多重集合容器,容器能够对加入的数值或者对象自动排序,可以存在重复值。底层实现为红黑树。

9. unordered_map

unordered_map是一种哈希容器,或者称为无序关联容器。底层采用哈希表的存储结构。

相比map容器的差别在于底层的实现结构不同,并且不会对元素进行排序。

使用迭代器遍历哈希容器,效率不如关联式容器。

在操作unordered_map容器过程(尤其是向容器中添加新键值对)中,一旦当前容器的负载因子超过最大负载因子(默认值为 1.0),该容器就会适当增加桶的数量(通常是翻一倍),并自动执行rehash()成员方法,重新调整各个键值对的存储位置(此过程又称“重哈希”),此过程很可能导致之前创建的迭代器失效。

#include 
#include 

int main()
{
    //创建 umap 容器
    std::unordered_map umap;
    //向 umap 容器添加 50 个键值对
    for (int i = 1; i <= 50; i++) {
        umap.emplace(i, i);
    }
    //获取键为 49 的键值对所在的范围
    auto pair = umap.equal_range(49);
    //输出 pair 范围内的每个键值对的键的值
    for (auto iter = pair.first; iter != pair.second; ++iter) {
        std::cout << iter->first <<" ";
    }
    std::cout << std::endl;
    //手动调整最大负载因子数
    umap.max_load_factor(3.0);
    //手动调用 rehash() 函数重哈希
    umap.rehash(10);
    //重哈希之后,pair 的范围可能会发生变化
    for (auto iter = pair.first; iter != pair.second; ++iter) {
        std::cout << iter->first << " ";
    }
    return 0;
}

10. unordered_multimap

unordered_multimap是哈希多重映射。

11. unordered_set

unordered_set是一个哈希容器,或者叫无序关联容器。

12. unordered_multiset

unordered_multiset是哈希多重集合。

表 1 不同容器的迭代器

容器 对应的迭代器类型
array 随机访问迭代器
vector 随机访问迭代器
deque 随机访问迭代器
list 双向迭代器
set / multiset 双向迭代器
map / multimap 双向迭代器
forward_list 前向迭代器
unordered_map / unordered_multimap 前向迭代器
unordered_set / unordered_multiset 前向迭代器
stack 不支持迭代器
queue 不支持迭代器

表 2 迭代器的 4 种定义方式

迭代器定义方式 具体格式
正向迭代器 容器类名::iterator 迭代器名;
常量正向迭代器 容器类名::const_iterator 迭代器名;
反向迭代器 容器类名::reverse_iterator 迭代器名;
常量反向迭代器 容器类名::const_reverse_iterator 迭代器名;

三、C++算法

1. 排序

对容器中元素的排序是一个常用的操作,对对象的排序需要首先定义对象的大小判断规则,重载operator<或者使用Lambda函数

函数名 用法
sort (first, last) 对容器或普通数组中 [first, last) 范围内的元素进行排序,默认进行升序排序。
stable_sort (first, last) 和 sort() 函数功能相似,不同之处在于,对于 [first, last) 范围内值相同的元素,该函数不会改变它们的相对位置。
partial_sort (first, middle, last) 从 [first,last) 范围内,筛选出 middle-first 个最小的元素并排序存放在 [first,middle) 区间中。
partial_sort_copy (first, last, result_first, result_last) 从 [first, last) 范围内筛选出 result_last-result_first 个元素排序并存储到 [result_first, result_last) 指定的范围中。
is_sorted (first, last) 检测 [first, last) 范围内是否已经排好序,默认检测是否按升序排序。
is_sorted_until (first, last) 和 is_sorted() 函数功能类似,唯一的区别在于,如果 [first, last) 范围的元素没有排好序,则该函数会返回一个指向首个不遵循排序规则的元素的迭代器。
void nth_element (first, nth, last) 找到 [first, last) 范围内按照排序规则(默认按照升序排序)应该位于第 nth 个位置处的元素,并将其放置到此位置。同时使该位置左侧的所有元素都比其存放的元素小,该位置右侧的所有元素都比其存放的元素大。

1.1 sort()

sort()函数使用快速排序实现,要求排序的迭代器为随机访问迭代器,因此支持的容器为arrayvectordeque

在排序中需要交换容器中元素的位置,因此对对象的排序需要对类定义移动构造函数和移动赋值函数。

sort()函数包含在algorithm头文件中。

#include      // std::cout
#include     // std::sort
#include        // 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 myvector{ 32, 71, 12, 45, 26, 80, 53, 33 };
    // 升序
    std::sort(myvector.begin(), myvector.end());
    for (std::vector::iterator it = myvector.begin(); it != myvector.end(); ++it) {
        std::cout << *it << ' ';
    }
    std::cout<());
    for (std::vector::iterator it = myvector.begin(); it != myvector.end(); ++it) {
        std::cout << *it << ' ';
    }
    std::cout<::iterator it = myvector.begin(); it != myvector.end(); ++it) {
        std::cout << *it << ' ';
    }
    std::cout<

1.2 stable_sort()

stable_sort()函数基于归并排序实现,能够保证相等元素的相对位置。

函数的使用方法与sort()函数一致。

1.3 partial_sort()partial_sort_copy()

partial_sort()函数为局部排序,适用于支持随机访问的容器。

partial_sort_copy()函数的功能与partial_sort()函数类似,前者不会在原有容器上改动,二是将元素拷贝到指定的数组或者容器中。

partial_sort_copy()函数还支持对list容器或者forward_list容器中存储的元素进行排序,而partial_sort()函数不行。排序后输出的容器需要支持随机访问。

#include      // std::cout
#include     // std::is_sorted
#include          // std::list

int main() {
    std::list mylist{1,2,3,4,5};
    // 从大到小排序--结果存储到数组中
    int ret[5] = {0};
    std::partial_sort_copy(mylist.begin(), mylist.end(), ret, ret+5,[](int &a, int &b){return a>b;});
    for(int i=0; i<5; ++i){
        std::cout<

1.4 nth_element()

nth_element()函数在所有元素中得到排序第n的元素。

容器需要支持随机访问。

#include 
#include     // std::nth_element
#include        // std::vector
int main() {
    std::vector myvector{2,3,9,1,7,8,10,5,4,6};
    // 升序
    std::nth_element(myvector.begin(), myvector.begin()+2, myvector.end());
    std::cout << "First sort:"<::iterator it = myvector.begin(); it != myvector.end(); ++it) {
        std::cout << *it << ' ';
    }
    std::cout<b;});
    std::cout << "Second sort:"<::iterator it = myvector.begin(); it != myvector.end(); ++it) {
        std::cout << *it << ' ';
    }
    std::cout<

1.5 is_sorted()is_sorted_until()

is_sorted()函数判断元素的排序是否符合指定的排序规则,is_sorted_until()函数不仅能检测出某个序列是否有序,还会返回一个正向迭代器,该迭代器指向的是当前序列中第一个破坏有序状态的元素。

这个函数不要求容器元素的随机访问。

#include      // std::cout
#include     // std::is_sorted
#include          // std::list

int main() {
    std::list mylist{1,2,3,4,5};
    if (!is_sorted(mylist.begin(), mylist.end(),[](int &a, int &b){return ab;})) {
        std::cout << "容器不是从大到小排序。" << std::endl;
    }else{
        std::cout << "容器是从大到小排序。" << std::endl;
    }
    return 0;
}

2. 查找

2.1 find()

find()函数本质上是一个模板函数,用于在指定范围内查找和目标元素值相等的第一个元素。

2.2 find_if()find_if_not()

按条件查找。find_if()函数用于在指定区域内执行查找操作。find()函数需要明确指定要查找的元素的值,find_if()则允许自定义查找规则。

#include      // std::cout
#include     // std::find_if, std::find_if_not
#include        // std::vector

int main() {
    std::vector vec{ 4,2,3,1,5 };
    std::vector::iterator iter = std::find_if(vec.begin(), vec.end(), [](int &a){return a%2==1;});
    if(iter!=vec.end()){
        std::cout << "*iter = " << *iter << std::endl;
    }
    iter = std::find_if_not(vec.begin(), vec.end(), [](int &a){return a%2==1;});
    if(iter!=vec.end()){
        std::cout << "*iter = " << *iter << std::endl;
    }
    return 0;
}

2.3 find_end()

find_end()函数用于在一个序列中查找另一个序列最后一次出现的位置。

#include      // std::cout
#include     // std::find_end
#include        // 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 myvector{ 1,2,3,4,8,12,18,1,2,3 };
    int myarr[] = { 1,2,3 };
    //第一种语法格式
    vector::iterator it = find_end(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 = find_end(myvector.begin(), myvector.end(), myarr2, myarr2 + 3, mycomp2());
    if (it != myvector.end()) {
        cout << "最后一个{2,3,4}的起始位置为:" << it - myvector.begin() << ",*it = " << *it;
    }
    return 0;
}

2.4 find_first_of()

find_first_of()函数用于在一个序列中找到另一个序列的第一个元素。

#include      // std::cout
#include     // std::find_first_of
#include        // std::vector

//自定义二元谓词函数,作为 find_first_of() 函数的匹配规则
bool mycomp(int c1, int c2) {
    return (c2 % c1 == 0);
}
//以函数对象的形式定义一个 find_first_of() 函数的匹配规则
class mycomp2 {
public:
    bool operator()(const int& c1, const int& c2) {
        return (c2 % c1 == 0);
    }
};
int main() {
    std::string str = "AAAaaaBBBbbbCCCccc";
    char ch[] = "aa";
    //调用第一种语法格式,找到str中和 "stl" 任一字符相同的第一个字符
    std::string::iterator it = std::find_first_of(str.begin(), str.end(), ch, ch + 4);

    if (it != str.end()) {
        std::cout << "*it = " << *it << std::endl;
    }

    std::vector vec{ 5,7,3,9 };
    int inter[] = { 4,6,8 };
    //调用第二种语法格式,找到 myvector 容器中和 3、5、7 任一元素有 c2%c1=0 关系的第一个元素
    std::vector::iterator iter = std::find_first_of(vec.begin(), vec.end(), inter, inter + 3, mycomp2());
    if (iter != vec.end()) {
        std::cout << "*iter = " << *iter << std::endl;
    }
    return 0;
}

2.5 adjacent_find()

adjacent_find()函数用于在指定范围内查找两个连续相等的元素。

#include      // std::cout
#include     // std::adjacent_find
#include        // std::vector
using namespace std;
//以创建普通函数的形式定义一个查找规则
bool mycomp1(int i, int j) {
    return (i == j);
}
//以函数对象的形式定义一个查找规则
class mycomp2{
public:
    bool operator()(const int& _Left, const int& _Right){
        return (_Left == _Right);
    }
};
int main() {
    std::vector myvector{ 5,20,5,30,30,20,10,10,20 };
    //调用第一种语法格式
    std::vector::iterator it = adjacent_find(myvector.begin(), myvector.end());

    if (it != myvector.end()) {
        cout << "one : " << *it << '\n';
    }
    //调用第二种格式,也可以使用 mycomp1
    it = adjacent_find(++it, myvector.end(), mycomp2());

    if (it != myvector.end()) {
        cout << "two : " << *it;
    }
    return 0;
}

2.6 search()search_n()

search()函数找到第一个匹配的元素,与find_end()相反。

相比于search()函数,search_n()函数能在调用中指定查找序列的长度count以及val

2.7 lower_bound()upper_bound()equal_range()binary_search()

find()find_if()search()等函数使用顺序查找的方式定位元素,对于有序数据,使用二分查找能够加快查找的效率。

lower_bound()函数用于在指定区域内查找不小于目标值的第一个元素。

upper_bound()函数用于在指定范围内查找大于目标值的第一个元素。

equal_range()函数用于在指定范围内查找等于目标值的所有元素。

binary_search()函数会返回一个 bool 类型值,如果函数在 [first, last) 区域内成功找到和 val 相等的元素,则返回 true;反之则返回 false。

#include      // std::cout
#include     // std::lower_bound
#include        // std::vector

int main() {
    int a[5] = { 1,2,3,4,5 };
    //从 a 数组中找到第一个不小于 3 的元素
    int *p = std::lower_bound(a, a + 5, 3);
    std::cout << "*p = " << *p << std::endl;
    std::vector myvector{ 4,5,3,1,2 };
    //根据 mycomp2 规则,从 myvector 容器中找到第一个违背 mycomp2 规则的元素
    std::vector::iterator iter = std::lower_bound(myvector.begin(), myvector.end(),3,[](const int& i, const int& j){return i>j;});
    // myvector 容器中存储的元素看似是乱序的,但对于元素 3 来说,大于 3 的所有元素都位于其左侧,小于 3 的所有元素都位于其右侧,且查找规则查找的是第一个不大于 3 的元素,因此 lower_bound() 函数是可以成功运行的。
    std::cout << "*iter = " << *iter;
    return 0;
}
#include      // std::cout
#include     // std::equal_range
#include        // std::vector

int main() {
    int a[9] = { 1,2,3,4,4,4,5,6,7};
    //从 a 数组中找到所有的元素 4
    std::pair range = std::equal_range(a, a + 9, 4);
    std::cout << "a[9]: ";
    for (int *p = range.first; p < range.second; ++p) {
        std::cout << *p << " ";
    }

    std::vectormyvector{ 7,8,5,4,3,3,3,3,2,1 };
    std::pair::iterator, std::vector::iterator> range2 = std::equal_range(myvector.begin(), myvector.end(), 3, [](const int& i, const int& j){return i>j;});
    std::cout << "\nmyvector: ";
    for (auto it = range2.first; it != range2.second; ++it) {
        std::cout << *it << " ";
    }
    return 0;
}
#include      // std::cout
#include     // std::binary_search
#include        // std::vector

int main() {
    int a[7] = { 1,2,3,4,5,6,7 };
    // 从 a 数组中查找元素 4
    bool haselem = std::binary_search(a, a + 9, 4);
    std::cout << "haselem: " << haselem << std::endl;

    std::vectormyvector{ 4,5,3,1,2 };
    // 从 myvector 容器查找元素 3
    // 由于 binary_search() 底层实现采用的是二分查找的方式,因此该函数仅适用于“已排好序”的序列。所谓“已排好序”,并不是要求 [first, last) 区域内的数据严格按照某个排序规则进行升序或降序排序,只要满足“所有令 elementj;});
    std::cout << "haselem2: " << haselem2 << std::endl;
    return 0;
}

3. 分组

3.1 partition()stable_partition()

两个函数根据指定的条件对容器中的元素进行分组,并返回指向第二组起始元素的迭代器。两个函数的差别是stable_partition()函数不会改变元素的相对位置。

3.2 partition_copy()

使用partition()stable_partition()这两个函数对容器进行划分会修改原始的数据,使用partition_copy()函数不会对原始数据进行修改。

#include      // std::cout
#include     // std::partition_copy
#include        // std::vector

int main() {
    std::vector myvector{ 1,2,3,4,5,6,7,8,9 };
    int b[10] = { 0 }, c[10] = { 0 };
    std::pair result= partition_copy(myvector.begin(), myvector.end(), b, c, [](const int &a){return a%2==0;});
    std::cout<< "Result: " << result.first - b<<", "<< result.second - c<

3.3 partition_point()

partition()stale_partition()或者partition_copy()函数能够按照指定的规则对数据进行分组,然而在已经分好组的数据中找到分界使用partition_point()函数,返回第一个不符合分组规则的元素迭代器。

#include      // std::cout
#include     // std::partition_point
#include        // std::vector

int main() {
    std::vector myvector{ 2,4,6,8,1,3,5,7,9 };
    //根据 mycomp 规则,为 myvector 容器中的数据找出分界
    std::vector::iterator iter = partition_point(myvector.begin(), myvector.end(),[](const int &a){return a%2==0;});
    //输出第一组的数据
    for (auto it = myvector.begin(); it != iter; ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    //输出第二组的数据
    for (auto it = iter; it != myvector.end(); ++it) {
        std::cout << *it << " ";
    }
    return 0;
}

4. 谓词

4.1 all_of()any_of()none_of()

all_of()算法会返回 true,前提是序列中的所有元素都可以使谓词返回 true。
any_of()算法会返回 true,前提是序列中的任意一个元素都可以使谓词返回 true。
none_of()算法会返回 true,前提是序列中没有元素可以使谓词返回 true。

5. 匹配

5.1 equal()

可以用和比较字符串类似的方式来比较序列。如果两个序列的长度相同,并且对应元素都相等,equal() 算法会返回 true。有 4 个版本的 equal() 算法,其中两个用 == 运算符来比较元素,另外两个用我们提供的作为参数的函数对象来比较元素,所有指定序列的迭代器都必须至少是输入迭代器。

5.2 mimatch()

mismatch()算法也是用于判断两个序列是否匹配,而且如果不匹配,还能返回不匹配的位置。

6. 比较

6.1 lexicographical_compare()

lexicographical_compare()算法可以比较由开始和结束迭代器定义的两个序列。它的前两个参数定义了第一个序列,第 3 和第 4 个参数分别是第二个序列的开始和结束迭代器。默认用 < 运算符来比较元素,但在需要时,也可以提供一个实现小于比较的函数对象作为可选的第 5 个参数。如果第一个序列的字典序小于第二个,这个算法会返回 true,否则返回 false。所以,返回 false 表明第一个序列大于或等于第二个序列。

#include
#include
#include
#include
int main(){
    std::vector phrase1 {"the", "tigers", "of", "wrath"};
    std::vector phrase2 {"the", "horses", "of", "instruction"};
    auto less = std::lexicographical_compare (phrase1.begin(), phrase1.end(), phrase2.begin(), phrase2.end(), [](const std::string& s1, const std::string& s2) { return s1 < s2; });
    std::cout << (less ? "are":"are not") << " less than ";
    return 0;
}

7. 排列组合

7.1 next_permutation()prev_permutation()is_permutaion()

next_permutation()会生成一个序列的重排列,它是所有可能的字典序中的下一个排列,默认使用 < 运算符来做这些事情。
next_permutation()按照字典升序的方式生成的排列。prev_permutation()以降序的方式生成排列时。
is_permutation()算法可以用来检查一个序列是不是另一个序列的排列,如果是,会返回 true。

#include 
#include 
#include 
#include 
#include 

int main()
{
    std::vector words;
    std::string word = "ABC";
    std::string word_copy (word);
    do
    {
        words.push_back(word);
        std::next_permutation(std::begin(word), std::end(word));
    } while(word != word_copy);

    size_t count{}, max{8};
    for(const auto& wrd : words)
        std::cout << wrd << ((++count % max == 0) ? '\n' : ' ');
    std::cout << std::endl;
    words.clear();
    std::string word1 = "ABC";
    std::string word2 = "ACB";
    std::cout<

8. 复制

8.1 copy_n()copy_if()copy_backward()

copy_n()算法可以从源容器复制指定个数的元素到目的容器中。第一个参数是指向第一个源元素的输入迭代器,第二个参数是需要复制的元素的个数,第三个参数是指向目的容器的第一个位置的迭代器。

copy_if()算法可以从源序列复制使谓词返回 true 的元素,所以可以把它看作一个过滤器。前两个参数定义源序列的输入迭代器,第三个参数是指向目的序列的第一个位置的输出迭代器,第 4 个参数是一个谓词。

copy_backward()会复制前两个迭代器参数指定的序列。第三个参数是目的序列的结束迭代器,通过将源序列中的最后一个元素复制到目的序列的结束迭代器之前,源序列会被复制到目的序列中。copy_backward()的 3 个参数都必须是可以自增或自减的双向迭代器,这个算法只能应用到序列容器的序列上。与copy()函数不同的是copy_backward()从后向前复制。

8.2 reverse()reverse_copy()

reverse()算法可以在原地逆序它的两个双向迭代器参数所指定序列的元素。
reverse_copy()算法可以将源序列复制到目的序列中,目的序列中的元素是逆序的。定义源序列的前两个迭代器参数必须是双向迭代器。

9. 合并

9.1 merge()inplace_merge()

merge()函数将两个有序序列合并为一个有序序列,两个有序序列的排序规则相同。如果原始的两个序列无序,则合并后序列也无序。

inplace_merge()函数用于将单个数组或者容器中的两个有序序列合并为一个有序序列。

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

    for (int i = 0; i < 11; i++) {
        cout << first[i] << " ";
    }
    return 0;
}

10. 其他

10.1 unique()

unique()算法可以在序列中原地移除重复的元素,这就要求被处理的序列必须是正向迭代器所指定的。在移除重复元素后,它会返回一个正向迭代器作为新序列的结束迭代器。可以提供一个函数对象作为可选的第三个参数,这个参数会定义一个用来代替==比较元素的方法。

#include 
#include 
#include 

int main()
{
    std::string text {"There's nooo air in spaaaaaace!"};
    auto iter = std::unique(std::begin(text), std::end(text),[](char ch1, char ch2) { return ch1 == ch2; });
    text.erase(iter, text.end());
    std::cout << text << std::endl;
    return 0;
}

10.2 rotate()rotate_copy()

rotate_copy()算法会在新序列中生成一个序列的旋转副本,并保持原序列不变

#include 
#include 
#include 
#include 

int main()
{
    std::vector words { "one", "two", "three", "four", "five","six", "seven", "eight"};
    std::vector words_copy(10);
    std::rotate_copy(words.begin(), words.begin()+3 , words.end(), words_copy.begin());
    for(auto s: words_copy){
        std::cout<< s<< " ";
    }
    std::cout<

10.3 move()

move()算法会将它的前两个输入迭代器参数指定的序列移到第三个参数定义的目的序列的开始位置,第三个参数必须是输出迭代器。这个算法返回的迭代器指向最后一个被移动到目的序列的元素的下一个位置。

10.4 swap_ranges()

swap_ranges()算法来交换两个序列。

10.5 remove()remove_copy()remove_if()remove_copy_if()

remove()可以从它的前两个正向迭代器参数指定的序列中移除和第三个参数相等的对象。基本上每个元素都是通过用它后面的元素覆盖它来实现移除的。它会返回一个指向新的最后一个元素之后的位置的迭代器。

remove_copy()可以将前两个正向迭代器参数指定的序列中的元素复制到第三个参数指定的目的序列中,并忽略和第 4 个参数相等的元素。它返回一个指向最后一个被复制到目的序列的元素的后一个位置的迭代器。序列不能是重叠的。

remove_if()可以从前两个正向迭代器指定的序列中移除能够使作为第三个参数的谓词返回 true 的元素。

remove_copy_if()可以将前两个正向迭代器参数指定的序列中,能够使作为第 4 个参数的谓词返回 true 的元素,复制到第三个参数指定的目的序列中。它返回一个指向最后一个被复制到目的序列的元素的后一个位置的迭代器。序列不能是重叠的。

10.6 fill()fill_n()

fill()fill_n() 算法提供了一种为元素序列填入给定值的简单方式,fill() 会填充整个序列; fill_n() 则以给定的迭代器为起始位置,为指定个数的元素设置值。

10.7 generate()generate_n()

10.8 transform()

transform() 可以将函数应用到序列的元素上,并将这个函数返回的值保存到另一个序列中,它返回的迭代器指向输出序列所保存的最后一个元素的下一个位置。

10.9 replace()

replace() 算法会用新的值来替换和给定值相匹配的元素。

你可能感兴趣的:(c++,学习,笔记)