C++ STL库的介绍和使用

文章目录

  • C++ STL库的介绍和使用
    • STL六大组件
      • 算法的分类
      • 迭代器
    • 一个简单的例子
    • 容器和自定义类型
    • 容器嵌套容器
    • 常用容器
      • string
      • vector
      • deque
      • stack
      • queue
      • list
      • set/multiset
      • pair
      • map/multimap
    • 容器的使用时机
    • 函数对象(仿函数)
    • 谓词
    • 内建函数对象
    • 适配器
      • bind2nd和bind1st
      • not1 和 not2 mem_fun_ref和ptr_fun
    • 算法
      • 常用的遍历算法
      • 常用的查找算法
      • 其他
      • 算数生成算法
      • 集合算法

C++ STL库的介绍和使用

STL(标准模板库),是惠普实验室开发的一系列软件的统称。现在主要出现在C++中,但是在引入C++之前该技术已经存在了很长时间了。STL从广义上分为:容器(container) 算法(algorithm) 迭代器(iterator),容器和算法之间通过迭代器进行无缝衔接。STL几乎所有的代码都采用了模板类或者是模板函数,这相比于创痛的由函数和类组成的库来说提供了更好的代码重用机会。STL标准模板库,在我们C++标准程序库中隶属于STL的占到了80%以上。

STL六大组件

  • 容器:各种数据结构 vector list deque set map等,存放数据

  • 算法:如sort find copy for_each等,操作数据

  • 迭代器:容器和算法的桥梁

  • 仿函数:为算法提供更多的策略

  • 适配器:为算法提供更多的参数接口

  • 空间配置器:管容器和算法的空间

STL六大组件的交互关系:容器通过空间配置器获取数据存储空间,算法通过迭代器获取存储器的内容,仿函数可以协助算法完成不同的策略变化,适配器可以修饰仿函数。

算法的分类

质变算法:运算过程中会更好区间内的数据,如拷贝、替换、删除等

非质变算法:运算过程中不会更改区间内容,如查找、计数、遍历等

迭代器

迭代器是一种抽象的概念,提供一种方法,使之能够依顺序访问某个容器所含的各个元素,而无需暴露该容器的内部表示方式。

迭代器的设计思维是STL的关键所在,STL中心思想是把容器和算法分开,彼此设计独立。

一个简单的例子

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void print(int it)
{cout << it << " ";
}
void test()
{vector<int> vv;vv.push_back(1);vv.push_back(2);vv.push_back(3);// 开始迭代器,指向开始位置vector<int>::iterator itBegin = vv.begin();// 结束迭代器,指向尾元素的下一个位置vector<int>::iterator itEnd = vv.end();for(auto it = itBegin; it!= itEnd; it++){cout << *it << " ";}cout << endl;// 需要了解,可用vs查看对应的实现源码,可以看到整体实现思路是上面的forfor_each(itBegin, itEnd, print);cout << endl;
}
int main(int argc, char* argv[])
{test();return 0;
}

容器和自定义类型

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Person
{
public:Person(int a, int n): age(a), num(n) {}int age;int num;
};
void print(const Person &it)
{cout << it.age << " " << it.num << endl;
}void test()
{vector<Person> vv;vv.push_back(Person(1,1));vv.push_back(Person(2,2));vv.push_back(Person(3,3));for_each(vv.begin(), vv.end(), print);
}
int main(int argc, char* argv[])
{test();return 0;
}

容器嵌套容器

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void print2(int a)
{cout << a << " " ;
}
void print(const vector<int> &a)
{for_each(a.begin(), a.end(), print2);
}
void test()
{vector<int> a;a.push_back(1);a.push_back(2);a.push_back(3);vector<int> b;b.push_back(4);b.push_back(5);b.push_back(6);vector<int> c;c.push_back(7);c.push_back(8);c.push_back(9);vector<vector<int>> aa;aa.push_back(a);aa.push_back(b);aa.push_back(c);for_each(aa.begin(), aa.end(), print);
}
int main(int argc, char* argv[])
{test();return 0;
}

常用容器

string

C风格的字符串太过复杂,难以掌握,不太适合大程序的开发,所以C++标准库定义了一种string类,定义在头文件中。

string和C风格字符串对比:

  • char是一个指针,string是一个类,string封装了char,管理了这个字符串,是一个char类型的容器。

  • string封装了很多实用的成员方法,查找find、拷贝copy、删除delete、替换replace、插入insert

  • 不用考虑内存的释放和越界,string管理了char*所分配的内存,每一次string的赋值,取值都由string类负责维护,不用担心复制越界和取值越界等算法

下面的例子列举了一些简单使用:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 字符串赋值
void test()
{string str("5152");string str3;str3 = str;cout << str3 << endl;string str2;str2 = "hello world";cout << str2 << endl;string str1;str1 = 'H';cout << str1 << endl;string str4;str4.assign(str);cout << str4 << endl;
}
// 字符串存取
void test02()
{string str = "hello world";cout << str[1] << endl;cout << str.at(1) << endl;str[1] = 'E';str[7] = 'O';cout << str << endl;try{
//        str[100] = 'H';str.at(100) = 'H';}catch (exception &e){cout << e.what() << endl;}
}
// 字符串拼接
void test03()
{string str1 = "hello ";string str2 = "world";str1+=str2;cout << str1 << endl;string str3 = "hello ";str3+="world";cout << str3 << endl;str3.append(" mmmm");cout << str3 << endl;str3.append(" mmmm", 3);cout << str3 << endl;str3.append(str2, 2, 3);cout << str3 << endl;
}
// 字符串查找和替换
void test04()
{string str1 = "hello world";int a = str1.find('e');cout << a << endl;a = str1.find('e', 3);cout << a << endl;a = str1.find("worl");cout << a << endl;// 表示从0开始替换5个字符,替换成后面的str1.replace(0, 5, "mmmmm");cout << str1 << endl;
}
// 字符串比较和子串的提取
void test05()
{string str1 = "hello world";string str2 = "hello";int a = str1.compare(str2);cout << a << endl;a = str1.compare("oooo");cout << a << endl;a = str1.compare("hello world");cout << a << endl;string str = str1.substr(0, 8);cout << str << endl;string str11 = "asd:asdas:asdasdasd:dadssad:dasdsa";int pos = 0;while(1){int ret = str11.find(":", pos);if(ret < 0){string tmp = str11.substr(pos, str11.size() - pos);cout << tmp << endl;break;}string tmp = str11.substr(pos, ret - pos);cout << tmp << endl;pos = ret + 1;}
}
// 字符串的插入和删除
void test06()
{string str = "hello world";str.insert(5, " hehe");cout << str << endl;str.erase(5, 5);cout << str << endl;str.clear();cout << str << endl;
}
// 字符串和C风格字符串转换
void test07()
{char *aa = "hello world";string str = aa;const char *cc = str.c_str();cout << str << endl;cout << cc << endl;
}
int main(int argc, char* argv[])
{test07();return 0;
}

vector

vector的数据安排以及操作方式与数组相似,两者的唯一差别在于运用的灵活性。数组是静态空间,一旦配置了就不能改变,要更换大一点或者小一点的空间,可以,但是需要自己去做空间分配和数据拷贝,然后释放原先的空间。vector是动态空间,随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。因此vector的运用对于内存的合理利用与利用的灵活性有很大的帮助,我们不必担心空间不足而开辟一块很大的array。

vector的迭代器:随机访问迭代器

随机访问迭代器:迭代器+n可以通过编译器编译,就是随机访问迭代器。

vector的容量(capacity)和大小(size)是有区别的。

  • capacity:是空间能容纳元素的最大个数

  • size:是空间中实际存放的个数

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void print(const vector<int> &aa)
{for(auto it = aa.begin(); it != aa.end(); it++){cout << *it << " ";}cout << endl;fflush(stdout);
}
void test()
{vector<int> v;for(int i = 0; i < 100; ++i){v.push_back(i);}cout << v.size() << endl;cout << v.capacity() << endl;
}
// 另寻空间的次数
void test02()
{int count = 0;vector<int> v;int *p = nullptr;for(int i = 0; i < 1000; ++i){v.push_back(i);if(p!= &v[0]){count++;p = &v[0];}}cout << count << endl;
}
// vector的构造、赋值和交换
void test03()
{vector<int> v(10, 5);print(v);vector<int> v1(v.begin() + 2, v.end() -2);print(v1);vector<int> v2(v);print(v2);vector<int> v3;v3.assign(v.begin() + 1, v.end() - 1);print(v3);vector<int> v4;v4 = v3;print(v4);vector<int> v5;v5.assign(5, 10);print(v5);vector<int> v6(6, 20);print(v6);v5.swap(v6);print(v5);print(v6);
}
// vector大小操作
void test04()
{vector<int> v(10, 5);if(v.empty()){cout << "v is empty" << endl;}else{cout << v.capacity() << endl;cout << v.size() << endl;}print(v);v.resize(16);print(v);v.resize(1024, 5);print(v);v.resize(2);print(v);cout << v.capacity() << endl;cout << v.size() << endl;// 使用swap收缩容量空间,通过交换函数重新申请大小vector<int>(v).swap(v);cout << v.capacity() << endl;cout << v.size() << endl;vector<int> vv(10, 5);cout << "vv:" << vv.capacity() << endl;cout << "vv:" << vv.size() << endl;// 空间预留vv.reserve(50);cout << "vv:" << vv.capacity() << endl;cout << "vv:" << vv.size() << endl;
}
// vector的数据操作
void test05()
{vector<int> v;for(int i = 0; i < 6; i++){v.push_back(i);}cout << v[5] << endl;cout << v.at(5) << endl;cout << v.front() << endl;cout << v.back() << endl;v.insert(v.begin() + 3, 2, 100);print(v);v.pop_back();print(v);v.erase(v.begin()+1,v.begin()+3);print(v);v.erase(v.begin());print(v);v.clear();print(v);
}
int main(int argc, char* argv[])
{test05();return 0;
}

注意: resize只能修改size,不能修改容量。

deque

vector容器时一段连续的内存空间,dequeue则是一种双向开口的联系线性空间。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作。vector也可以在头尾进行插入操作 ,但是vector的头部插入操作效率奇差,不可以被接受。

deque容器是由一段一段的定量连续空间构成的,一旦有必要在deque前端或者是尾端增加新的空间,便配置一段连续定量的空间,串接在deque的头端或者是尾端。deque最大的工作就是维护这些分段连续的空间的整体性的假象,并提供随机访问接口,避免了重新配置空间,复制,释放的轮回,代价就是复杂的迭代器架构。

#include <iostream>
#include <algorithm>
#include <deque>
using namespace std;
void print(const deque<int> &aa)
{for(auto it = aa.begin(); it != aa.end(); it++){cout << *it << " ";}cout << endl;fflush(stdout);
}
// 初始化和赋值
void test()
{deque<int> v(5, 10);print(v);deque<int> v1;v1.assign(v.begin()+1, v.end()-1);print(v1);deque<int> v2 = v;print(v2);v2.swap(v1);print(v1);print(v2);
}
// 插入和存取
void test02()
{deque<int> v(5, 10);v.resize(10,3);print(v);v.resize(3);print(v);v.push_front(6);print(v);v.push_back(6);print(v);v.pop_front();print(v);v.pop_back();print(v);cout << v[1] << endl;cout << v.at(1) << endl;cout << v.size() << endl;cout << v.empty() << endl;v.clear();cout << v.empty() << endl;
}
int main(int argc, char* argv[])
{test02();return 0;
}

stack

stack是一种先进后出的数据结构,它只有一个出口。stack允许新增元素,移除元素,取得栈顶元素,但是除了顶端外,没有任何办法 存取stack元素。换言之,stack不允许有遍历行为。有元素推入栈的操作称为push, 将元素推出栈的操作称为pop。

stack没有迭代器。

#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
void test()
{stack<int> ss;ss.push(1);ss.push(2);ss.push(3);ss.push(4);ss.push(5);cout << ss.top() << endl;ss.pop();cout << ss.top() << endl;ss.pop();cout << ss.top() << endl;ss.pop();cout << ss.top() << endl;ss.pop();cout << ss.top() << endl;ss.pop();
}
int main(int argc, char* argv[])
{test();return 0;
}

queue

队列是一种先进先出的数据结构,他有一个出口一个入口,queue容器允许从一端新增元素,从另外一端移除元素。

队列没有迭代器。

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
void test()
{queue<int> qq;qq.push(1);qq.push(2);qq.push(3);qq.push(4);qq.push(5);cout << qq.size() << endl;cout << qq.empty() << endl;cout << qq.front() << endl;qq.pop();cout << qq.front() << endl;qq.pop();cout << qq.front() << endl;qq.pop();cout << qq.front() << endl;qq.pop();cout << qq.front() << endl;qq.pop();cout << qq.empty() << endl;
}
int main(int argc, char* argv[])
{test();return 0;
}

list

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的。链表由一系列节点组成,节点在运行时动态生成。每个节点包括两个部分:一个是存储数据元素的数据域,一个是存储下一个节点地址的指针域。相较于vector的连续线性空间,list就显得负责许多,它的每次插入或者是删除一个元素,就是配置或者释放一个元素的空间。因此,list对于空间的运用具有绝对的精准,一点也不浪费,而且,对于任何位置的元素插入或者是删除,list永远是常数时间。list和vector是两个最长被使用的容器。list是一个双向链表。

链表采用的是动态存储分配,不会造成内存浪费和溢出,链表执行插入和 删除操作十分方便,修改指针即可,不需要移动大量的元素。俩表灵活但是空间和时间额外耗费比较大。

list的迭代器是 双向访问迭代器

#include <iostream>
#include <algorithm>
#include <list>
#include <vector>
using namespace std;
void print(const list<int> &ll)
{for(auto & a : ll){cout << a << " ";}cout << endl;fflush(stdout);
}
class Person
{
public:Person(int a) : age(a){}bool operator<(const Person &right){return this->age < right.age;}int age;
};
class Compare
{
public:bool operator()(const Person &left, const Person &right){return left.age < right.age;}
};
bool operator==(const Person &left, const Person &right)
{return left.age == right.age;
}
bool compare(const Person &left, const Person &right)
{return left.age > right.age;
}
void print(const list<Person> &ll)
{for(auto & a : ll){cout << a.age << " ";}cout << endl;fflush(stdout);
}
void print(const vector<Person> &ll)
{for(auto & a : ll){cout << a.age << " ";}cout << endl;fflush(stdout);
}
void test()
{list<int> ll;ll.push_back(10);ll.push_back(20);ll.push_back(30);ll.push_back(40);print(ll);auto it = find(ll.begin(), ll.end(), 20);ll.insert(++it, 3 ,100);print(ll);ll.reverse();print(ll);ll.sort();print(ll);
}
void test01()
{list<Person> ll;ll.push_back(10);ll.push_back(20);ll.push_back(30);ll.push_back(40);print(ll);ll.remove(Person(20));print(ll);ll.sort();print(ll);ll.sort(compare);print(ll);
}
void test02()
{vector<Person> ll;ll.push_back(20);ll.push_back(10);ll.push_back(30);ll.push_back(40);sort(ll.begin(), ll.end(), compare);print(ll);sort(ll.begin(), ll.end(), Compare());print(ll);sort(ll.begin(), ll.end(), [&](const Person &left, const Person &right) -> bool {return left.age > right.age;});print(ll);
}
int main(int argc, char* argv[])
{test02();return 0;
}

注意: list删除自定义数据,必须重载==运算符,否则无法匹配是否相等。

set/multiset

set的特性是:所有元素都会根据元素的键值自动排序。set元素不像map那样可以同时拥有键和值,set元素既是键又是值。set不允许两个元素拥有同样的键值。

set不可以通过迭代器修改set的值,set的值也是键,关系到set元素的排序规则。

multiset的特性和用法和set完全相同,唯一不同的是multiset允许键值重复。set和multiset的底层实现是红黑树,红黑书是平衡二叉树的一种。

#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
void print(const set<int> &ll)
{for(auto & a : ll){cout << a << " ";}cout << endl;fflush(stdout);
}
class Compare
{
public:bool operator()(const int& p1,const int& p2) const//一定要定义为常函数,且参数需要限定为const{return p1 > p2;}
};
void print(const set<int, Compare> &ll)
{for(auto & a : ll){cout << a << " ";}cout << endl;fflush(stdout);
}
void test()
{set<int> ss;ss.insert(2);ss.insert(3);ss.insert(45);ss.insert(10);ss.insert(2);print(ss);cout << ss.size() << endl;ss.erase(3);print(ss);cout << ss.count(2) << endl;multiset<int> ss2;ss2.insert(2);ss2.insert(3);ss2.insert(45);ss2.insert(10);ss2.insert(2);ss2.erase(3);cout << ss2.count(2) << endl;auto it = ss.find(5);it != ss.end()? cout << "找到了" << endl : cout << "没有找到" << endl;auto it1 = lower_bound(ss.begin(), ss.end(), 10);auto it2 = upper_bound(ss.begin(), ss.end(), 10);auto mm = ss.equal_range(30);
}
void test01()
{set<int, Compare> ss;ss.insert(2);ss.insert(6);ss.insert(8);print(ss);
}
int main(int argc, char* argv[])
{test01();return 0;
}

注意: set存放自定义数据类型的时候必须指定排序规则。

pair

对组是将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值可以分别用pair的两个公有属性first和second进行访问。

#include <iostream>
#include <algorithm>
using namespace std;
void test()
{pair<int, int> pp(1, 2);cout << pp.first << " " << pp.second << endl;pair<int, int> pp1 = make_pair(1, 2);cout << pp1.first << " " << pp1.second << endl;
}
int main(int argc, char* argv[])
{test();return 0;
}

map/multimap

map的特性是所有元素会根据元素的键值自动排序。map所有的元素都是pair,同时拥有实值和键值,pair的第一个元素是键值,第二个元素被视为实值,map不允许两个元素有相同的键值。

map的键值不可变,实值是可变的。

multimap和map的操作类似,唯一的区别就是multimap键值可重复。map和multimap都是以红黑树为底层实现机制。

#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
void print(const map<int, int> &ll)
{for(auto & a : ll){cout << a.first << " " << a.second << " " << endl;}fflush(stdout);
}
void test()
{int a = 10;int &b = a;a = 20;cout << a << endl;cout << b << endl;
}
int main(int argc, char* argv[])
{test();return 0;
}

容器的使用时机

典型的存储结构可随机存取
vector单端数组
deque双端数组
list双向列表
set/multiset红黑树
map/multimap红黑树否(针对于ke)
元素查询元素插入删除
vector尾部
deque两端
list非常慢任何位置
set/multiset
map/multimap

函数对象(仿函数)

重载函数调用操作符的对象,其对象常称为函数对象,即他们是行为类似于函数的对象,也叫仿函数,其实就是重载了"()"操作符,使得对象可以像函数那样调用。

注意:

  • 函数对象是一个类,不是一个函数。
  • 函数对象重载了"()"操作符,使他可以像函数一样调用。

分类:

  • 如果一个函数重载了"()"且需要一个参数,则称为一元仿函数

  • 如果一个函数重载了"()"且需要两个参数,则称为二元仿函数

总结:

  • 函数对象通常不定义构造函数和析构函数,所以在构造和析构的时候不会发生任何问题,避免了函数调用的运行时问题。
  • 函数对象超出了普通函数的概念,函数对象可以有自己的状态
  • 函数对象可以内联编译,性能好。用函数指针几乎不可能
  • 模板函数对象使得函数对象具有通用性,这就是他的优势之一

谓词

指的是普通函数或者是仿函数的返回值是bool类型的函数对象。

如果operator接受一个参数,则叫一元谓词,如果接受2个参数则称为二元谓词。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool findBigThan10(int a)
{return a > 10;
}
class Find20
{
public:bool operator()(int v){return v > 20;}
};
void test()
{vector<int> vv;vv.push_back(10);vv.push_back(20);vv.push_back(30);vv.push_back(40);vv.push_back(50);vv.push_back(60);auto ret = find_if(vv.begin(), vv.end(), findBigThan10);auto ret1 = find_if(vv.begin(), vv.end(), Find20());cout << *ret << endl;cout << *ret1 << endl;
}
bool compare(int left, int right)
{return left > right;
}
class Compare
{
public:bool operator()(int left, int right){return left < right;}
};
void test02()
{vector<int> vv;vv.push_back(10);vv.push_back(20);vv.push_back(30);vv.push_back(40);vv.push_back(50);vv.push_back(60);sort(vv.begin(), vv.end(), compare);for_each(vv.begin(), vv.end(), [](int val){cout << val << " ";});cout << endl;sort(vv.begin(), vv.end(), Compare());for_each(vv.begin(), vv.end(), [](int val){cout << val << " ";});cout << endl;
}
int main(int argc, char* argv[])
{test02();return 0;
}

内建函数对象

STL内建了一些函数对象,分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。

下面列出一些简单的例子。如果想要查看内建的函数,可以到对应的文件内查看对应的函数原型。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool findBigThan10(int a)
{return a > 10;
}
class Find20
{
public:bool operator()(int v){return v > 20;}
};
void test()
{plus<int> p;cout << p(10, 20) << endl;cout << plus<int>()(50, 20) << endl;minus<int> p1;cout << p1(10, 20) << endl;
}
int main(int argc, char* argv[])
{test();return 0;
}

适配器

bind2nd和bind1st

#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
void print(int a, int b)
{cout << a << " " << b << " " << endl;
}
class Print : public binary_function<int, int, void>
{
public:void operator()(int a, int b) const{cout << a << " " << b << " " << endl;}
};
void test()
{vector<int> vv;vv.push_back(10);vv.push_back(20);vv.push_back(30);vv.push_back(40);for_each(vv.begin(), vv.end(), bind1st(Print(), 5));for_each(vv.begin(), vv.end(), bind2nd(Print(), 5));
}
int main(int argc, char* argv[])
{test();return 0;
}

not1 和 not2 mem_fun_ref和ptr_fun

这里列出标题,不做代码展示

算法

算法主要是由头文件组成,是所有stl头文件中最大的一个,其中常用的功能涉及到比较,交换,查找,遍历,修改,翻转,排序,合并等。体积很小,只包括在几个序列容器上进行的简单运算的模板函数,定义了一些模板类,用以声明函数对象。

常用的遍历算法

  • for_each
  • transform
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
int mvTransform(int a)
{return a;
}
class Print : public binary_function<int, int, void>
{
public:void operator()(int a, int b) const{cout << a << " " << b << " " << endl;}
};
void test()
{vector<int> vv;vv.push_back(10);vv.push_back(20);vv.push_back(30);vv.push_back(40);vector<int> bb;bb.resize(vv.size());transform(vv.begin(), vv.end(), bb.begin(), mvTransform);for_each(bb.begin(), bb.end(), bind2nd(Print(), 5));
}
int main(int argc, char* argv[])
{test();return 0;
}

常用的查找算法

  • find
  • find_if
  • adjacent_find 查找相邻的重复元素
  • binary_find 二分查找,前提是容器必须有序
  • count 统计元素出现次数
  • count_if 按照条件统计次数
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
class Person
{
public:Person(int a) : age(a) {}int age;
};
bool operator==(const Person &left, const Person &right)
{return left.age == right.age;
}
void test()
{vector<int> vv;vv.push_back(10);vv.push_back(10);vv.push_back(20);vv.push_back(30);vv.push_back(30);auto it = adjacent_find(vv.begin(), vv.end());if(it != vv.end()){cout << *it << endl;}vector<Person> vp;vp.push_back(50);vp.push_back(50);auto itP = adjacent_find(vp.begin(), vp.end());if(itP != vp.end()){cout << itP->age << endl;}}
int main(int argc, char* argv[])
{test();return 0;
}

其他

  • merge
  • sort
  • random_shuffle 打乱
  • reverse 反转
  • copy
  • replace
  • replace_if
  • swap 交换函数
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
void test()
{vector<int> vv;vv.push_back(10);vv.push_back(10);vv.push_back(20);vv.push_back(20);vv.push_back(30);vv.push_back(30);vv.push_back(40);vv.push_back(40);vector<int> v2;v2.push_back(10);v2.push_back(30);vector<int> v3;v3.resize(vv.size() + v2.size());merge(vv.begin(), vv.end(), v2.begin(), v2.end(), v3.begin());for_each(v3.begin(), v3.end(), [](int a){cout << a << " ";});
}
int main(int argc, char* argv[])
{test();return 0;
}

算数生成算法

  • accumulate 累加求和
  • fill
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <numeric>
using namespace std;
void test()
{vector<int> vv;vv.push_back(10);vv.push_back(10);int sum = accumulate(vv.begin(), vv.end(), 0);cout << sum << endl;fill(vv.begin(), vv.end(), 20);for_each(vv.begin(), vv.end(), [](int a){ cout << a << endl; });
}
int main(int argc, char* argv[])
{test();return 0;
}

集合算法

  • set_intersection 求交集
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <numeric>
using namespace std;
void test()
{vector<int> vv;vv.push_back(10);vv.push_back(20);vv.push_back(30);vv.push_back(40);vector<int> v2;v2.push_back(30);v2.push_back(40);v2.push_back(50);v2.push_back(60);vector<int> v3;v3.resize(4);auto it = set_intersection(vv.begin(), vv.end(), v2.begin(), v2.end(), v3.begin());int size = 4 - (v3.end() - it);v3.resize(size);for_each(v3.begin(), v3.end(), [](int a){ cout << a << endl;});
}
int main(int argc, char* argv[])
{test();return 0;
}
  • set_union 求交集
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <numeric>
using namespace std;
void test()
{vector<int> vv;vv.push_back(10);vv.push_back(20);vv.push_back(30);vv.push_back(40);vector<int> v2;v2.push_back(30);v2.push_back(40);v2.push_back(50);v2.push_back(60);vector<int> v3;v3.resize(8);auto it = set_union(vv.begin(), vv.end(), v2.begin(), v2.end(), v3.begin());int size = 8 -(v3.end() - it);v3.resize(size);for_each(v3.begin(), v3.end(), [](int a){ cout << a << endl;});
}
int main(int argc, char* argv[])
{test();return 0;
}
  • set_difference 求差集
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <numeric>
using namespace std;
void test()
{vector<int> vv;vv.push_back(10);vv.push_back(20);vv.push_back(30);vv.push_back(40);vector<int> v2;v2.push_back(30);v2.push_back(40);v2.push_back(50);v2.push_back(60);vector<int> v3;v3.resize(4);auto it = set_difference(vv.begin(), vv.end(), v2.begin(), v2.end(), v3.begin());int size = 4 -(v3.end() - it);v3.resize(size);for_each(v3.begin(), v3.end(), [](int a){ cout << a << endl;});
}
int main(int argc, char* argv[])
{test();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/72663.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

洛谷 LGR SCP-J 2023 c++语言模拟试题 10. 以下程序片段的时间复杂度为( )

之前在牛客的一个群中看到有位哥们发的题 好像是洛谷哪次的模拟题&#xff0c;还写着什么 LGR SCP-J 2023 c语言模拟试题 题目 就是给段代码询问时间复杂度 for (int i1; i<n; i){for (int j1; j<n; ji){for (int k1; k<n; k j){}} } 跑代码 一开始想不出怎么解就…

数据结构(C语言版)概念、数据类型、线性表

数据结构&#xff08;C语言&#xff09;基本概念 数据的基本单位 数据的基本单位是位&#xff08;bit&#xff09;和字节&#xff08;byte&#xff09;。位是最小的存储单位&#xff0c;它可以表示一个二进制的0或1。字节由8个位组成&#xff0c;用于表示一个字符或数字。在计…

ElasticSearch第二讲:ES详解 - ElasticSearch基础概念

ElasticSearch第二讲&#xff1a;ES详解 - ElasticSearch基础概念 在学习ElasticSearch之前&#xff0c;先简单了解下ES流行度&#xff0c;使用背景&#xff0c;以及相关概念等。本文是ElasticSearch第二讲&#xff0c;ElasticSearch的基础概念。 文章目录 ElasticSearch第二讲…

将PyCharm中的终端运行前面的PS修改成当前环境

最近使用Pycharm中的Terminal来pip安装一些pakage&#xff0c;发现Terminal运行前面的显示的是PS&#xff0c;然后输入安装指令报错。“python无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。” 解决方法&#xff1a; 只需要在pycharm的设置中修改一些termi…

SpringBoot复习:(61)拦截器(HandlerInterceptor)的用法

一、自定义拦截器&#xff1a; package cn.edu.tju.interceptor;import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRespo…

01JVM_内存结构

一、什么是JVM 1.JVM的定义 Java程序的运行环境&#xff0c;java二进制字节码的运行环境 2.JVM的好处 ①一次编写&#xff0c;到处运行 ②自动内存管理&#xff0c;垃圾回收功能 ③数组下标越界检查 ④多态 3.jvm&#xff0c;jre&#xff0c;jdk的比较 3.常见的JVM 主…

Redis限流实践:实现用户消息推送每天最多通知2次的功能

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

java从入门到起飞(八)——循环和递归

文章目录 Java循环1. 什么是循环&#xff1f;1.1 为什么需要循环&#xff1f;1.2 循环的分类 2. Java中的循环结构2.1 for循环2.2 while循环2.3 do-while循环 3. 循环控制语句3.1 break语句3.2 continue语句 4. 总结 Java递归1. 什么是递归2. 递归的原理3. 递归的实现4. 递归的…

更换 yum 阿里源 - 手把手教你怎么配置,在也不需要求别人了 - 看懂一个就相当于看懂了其他的linux系统

更换阿里源 我的是centos8 当然 centos7 也可以换 后面有更详细的怎么配 &#xff0c;再也不用求别人怎么弄了 最直接的方式 直接复制 执行 centos7 curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo或者 wget -O /etc/yum.repos.…

基于SpringBoot + Vue的项目整合WebSocket的入门教程

1、WebSocket简介 WebSocket是一种网络通信协议&#xff0c;可以在单个TCP连接上进行全双工通信。它于2011年被IETF定为标准RFC 6455&#xff0c;并由RFC7936进行补充规范。在WebSocket API中&#xff0c;浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性…

酷雷曼第二期无人机技能培训圆满举办

第2期无人机技能培训 2023年8月24日-8月25日&#xff0c;第二期酷雷曼无人机技能培训及执照考试在北京圆满举办&#xff0c;来自五湖四海、全国各地的合作商千里相聚&#xff0c;培训现场热闹融洽&#xff0c;再续精彩盛况。 随着《无人驾驶航空器飞行管理暂行条例》正式发布…

Redis内存数据库

Redis内存数据库 NoSQL数据库简介Redis简介Redis应用场景windows下安装和使用Redis在linux下安装redisRedis数据可视化RedisDesktopManagerRedis配置Redis 数据类型Redis 字符串(String)Redis 哈希(Hash)Redis 列表(List)Redis 集合(Set)Redis 有序集合(sorted set)Redis key命…

性能测试 —— Jmeter 命令行详细

我们在启动Jmeter时 会看见&#xff1a;Don’t use GUI mode for load testing !, only for Test creation and Test debugging.For load testing, use CLI Mode (was NON GUI) 这句话的意思就是说&#xff0c;不要使用gui模式进行负载测试&#xff0c;gui模式仅仅是创建脚本…

Mysql JSON

select json_extract(c2, $.a) select c2->"$.a" // json_extract的语法糖 &#xff08;取出的值会保留"双引号" so不适合实战&#xff09; 注&#xff1a;mysql若是引擎Mariadb则不支持json操作符-&#xff1e;&#xff1e;语法糖 select c2->…

深度翻页导出导致慢SQL,mysqlCPU飙升优化方案

慢SQL原因分析&#xff1a; 1.深度翻页 2.多表JOIN 3. 大IN 4. id倒排序 本文针对深度翻页的优化进行探讨 方案1&#xff1a; 将limit offset, pageSize的方式改成 id > xx limit pageSize. 这样能走Id索引&#xff0c;提高速度。 缺点&#xff1a;不能使用多线程…

Java面向对象学习笔记-2

前言 本文介绍了Java中类的定义和对象的创建的基本概念。我们通过示例代码演示了如何定义不同类型的类&#xff0c;包括管理员信息、顾客信息、学校信息和访客信息&#xff0c;并展示了如何创建这些类的对象以及如何访问它们的属性和方法。这些示例有助于理解面向对象编程的基…

扫地僧静态养站王站群:搜狗SEO站群收录养站效果

扫地僧静态养站王站群:Sogou搜狗SEO出站及收录效果,扫地僧静态站群采用了静态生成式的方式&#xff0c;只需要一个后台管理系统即可管理多个网站&#xff0c;大大提高了建站效率。建站大概45天左右&#xff0c;收录率百分之三十至百分之五十左右 如果对购买的域名进行把控&…

游戏思考30(补充版):关于逆水寒铁牢关副本、白石副本和技能的一些注释(2023/0902)

前期介绍 我是一名逆水寒的玩家&#xff0c;做一些游戏的笔记当作攻略记录下来&#xff0c;荣光不朽-帝霸来源视频连接 传送门 一、旧版铁牢关&#xff08;非逆水寒老兵服&#xff09; &#xff08;1&#xff09;老一&#xff1a;巨鹰 1&#xff09;机制一&#xff1a;三阵风…

ubuntu20.04 Supervisor 开机自启动脚本一文配置

前言: 最近发现一种非常好的开机启动服务方式,不光可以开机自启动,而且还可以进行开机节点的进程守护,这样大大确保了线程的稳定情况,这种服务甚至可以守护开机的进程,所以比之前设置 rc.local 开机自启动脚本一文配置节点好出很多,它甚至可以使用网页登录监管我开机自启…

手写RPC框架--4.服务注册

RPC框架-Gitee代码(麻烦点个Starred, 支持一下吧) RPC框架-GitHub代码(麻烦点个Starred, 支持一下吧) 服务注册 服务注册a.添加服务节点和主机节点b.抽象注册中心c.本地服务列表 服务注册 a.添加服务节点和主机节点 主要完成服务注册和发现的功能&#xff0c;其具体流程如下&…