基本概念:
容器被分为:
序列式容器:每个元素均有固定位置
关联式容器:各元素之间没有严格意义上的物理关系,如二叉树
算法被分为:
质变算法、非质变算法 区别在于运算过程是否会改变区间内元素的内容
迭代器:
提供一种方法,能够依序访问某个容器的各个元素,而无需暴露该容器的内部表示方式。
每个容器都是有自己专属的迭代器
迭代器用法类似指针
迭代器分类:
注意区分const_iterator和const iterator的区别
vector:
遍历实例:
void test(){void myPrint(int);vector<int> a = {10,20,30,40};vector<int>::iterator i;for_each(a.begin(), a.end(), myPrint);
}template<typename T>
void myPrint(T i);//模板函数的声明必须在全局、类、命名空间进行void test2() {STL_Person p1 = { 1,"a" };STL_Person p2 = { 2,"b" };STL_Person p3 = { 3,"c" };STL_Person p4 = { 4,"d" };STL_Person p5 = { 5,"e" };vector<STL_Person> a = { p1,p2,p3,p4,p5 };vector<STL_Person>::iterator i = a.begin();while (i != a.end()) {myPrint(*i);i++;}vector<STL_Person*> b = { &p1,&p2,&p3,&p4,&p5 };vector<STL_Person*>::iterator j = b.begin();while (j != b.end()) {myPrint(**j);j++;}
}
template<typename T>
void myPrint(T i) {cout << "template:" << endl;cout << i << endl;
}
void myPrint(int i) {cout << "int:" << endl;cout << i << endl;
}
注意区分容器的类型为指针时具体使用方式(STL_Person类进行了输出运算符重载)
容器嵌套容器别忘了空格┗|`O′|┛ 嗷~~
头部操作的效率伴随数据量的增大而降低
支持随机访问迭代器
存储结构类似数组,是连续的
赋值方式:使用“=”或assign
改变size大小:resize函数,变短时,多余的部分被删除,变长时,多出的部分被赋予默认值(或可以指定)
互换操作:swap函数,本质是交换,但可以帮助重置capacity,节省内存空间
vector<int>(a).swap(a)
匿名变量拷贝初始化,然后和自己交换,capacity会为拷贝容器设置,最后交换到你要节省空间的容器上,最后在这行执行完后被自动释放。
vector会因为size逼近capacity重新找一段更长的连续空间拷贝,导致原先迭代器指向的位置无效
push_back将元素拷贝加入到容器中,注意当目标元素没有实现拷贝构造时默认为浅拷贝,存在重复删除内存空间的危险
预留空间:reverse函数,改变capacity
string:
赋值、初始化操作自己查文档(利用“=”或assign函数)
拼接操作使用append或“+=”
查找、替换操作
比较操作 使用 “>” “<” “==” 或compare函数
存取操作 使用“[]”或at
deque:
vector访问元素比deque快,push_back速度为O(1),push_front为O(n),所以没有提供后者这个操作
deque支持头部插入删除,该操作的速度比vector快
工作原理:使用中控器维护缓冲区中的内容,中控器记录每一块缓冲区的地址,访问数据速度不如vector的原因在于,所有数据的存放位置不是连续的,而是由多块连续的缓冲区组成
真不戮
deque不存在capacity,只能改变size
stack容器:
先进后出,接口较少,只能返回栈顶元素
对于 stack 对象有一个特例化的全局函数 swap() 可以使用
- push(const T& obj):可以将对象副本压入栈顶。这是通过调用底层容器的 push_back() 函数完成的。
- push(T&& obj):以移动对象的方式将对象压入栈顶。这是通过调用底层容器的有右值引用参数的 push_back() 函数完成的。
queue容器:
先进先出,队尾进,队头出,只有队头队尾能被访问,中间元素无法遍历
list容器:
使用链表结构,所以插入删除方便,但是遍历访问慢,多占用了几份指针的空间
STL的链表为双向链表
仅支持前移和后移,不支持随机访问(走多步)
动态存储分配,不会造成内存溢出和浪费
不支持“[]”、at方式访问元素
类似的,不支持迭代器 +1、+2操作,不支持标准sort算法(涉及随机访问)
set和multiset容器:
关联式容器,使用二叉树实现,不支持随机访问迭代器
关联容器需要一个排序基准
只有insert的插入方式,并自动排序,不会插入重复值,multiset可以插入重复值
insert返回pair<iterator,bool>类型
erase函数具有remove作用的重载函数
使用find和count查找和计数指定元素是否存在以及统计指定元素个数
find返回的是迭代器,所以没有找到时返回的是 set.end()
利用仿函数帮助容器处理元素的排序顺序,具体初始化方式为:set<type,func>
pair对组:
创建方式:
pair<int, int> p = { 1,5 };pair<int, int> p1(1, 5);pair<int, int> p3 = pair<int, int>(1, 5);pair<int, int> p2 = make_pair(1, 5);
map和multimap容器:
由pair组成,分别为key和value,map根据键值进行排序,不支持随机访问迭代器
插入必须使用pair,删除根据key(键值)来删
map不允许有相同键值元素在容器中,multimap可以
不建议使用“[]”运算符重载创建,因为该语句会在该键值不存在时自动创建
用法实例
map<string, int> m;m.insert(make_pair("abc", 3));cout << m["abc"] << endl;
emplace:
emplace操作是C++11新特性,新引入的的三个成员emplace_front、emplace 和 emplace_back,这些操作构造而不是拷贝元素到容器中,这些操作分别对应push_front、insert 和push_back,允许我们将元素放在容器头部、一个指定的位置和容器尾部
函数对象(仿函数):
针不戮
一个函数对象是封装在类中, 从而看起来更像是一个对象。 这个类只有一个成员函数, 即重载了() (括号)的运算符。 它没有任何数据。 该类被模板化了, 从而可以应付多种数据类型。
仿函数就是在类中重载“()”运算符
比起普通函数,函数对象可以拥有状态(函数可以写该类的成员,达到记忆效果)
用例:
class Greater {
public:int value;bool operator() (int val) {return val > value;}Greater(int val) :value(val) {}
};
template<typename T>
class between {
public:T max;T min;between(T a, T b):max(b),min(a){}bool operator() (T val) {return less<T>()(val,max) && greater<T>()(val,min);}
};
void test01() {//copy算法void STL_Print(int&);vector<int> a = { 6,5,5,4,3,2,1 };vector<int> b;b.resize(a.size());copy(a.begin(), a.end(), b.begin());for_each(a.begin(), a.end(), STL_Print);
}
void test02() {//replace、replace_if算法void STL_Print(int&);vector<int> a = { 6,5,5,4,3,2,1 };replace(a.begin(), a.end(), 1, 2);for_each(a.begin(), a.end(), STL_Print);cout << endl;replace_if(a.begin(), a.end(), bind(greater<int>(), placeholders::_1, 5), 100);for_each(a.begin(), a.end(), STL_Print);cout << endl;replace_if(a.begin(), a.end(), bind(between<int>(4,100),placeholders::_1), 100);for_each(a.begin(), a.end(), STL_Print);cout << endl;Greater greater(101);replace_if(a.begin(), a.end(), greater, 100);for_each(a.begin(), a.end(), STL_Print);
}
void test() {test02();
}
void STL_Print(int &a) {a++;cout << a << ",";
}
//test02输出
//7, 6, 6, 5, 4, 3, 3,
//101, 101, 101, 6, 5, 4, 4,
//102, 102, 102, 101, 101, 5, 5,
//101, 101, 101, 102, 102, 6, 6,
谓词:
返回bool类型的仿函数称为谓词,根据参数的多少被分为一元谓词和二元谓词
例如:一元谓词配合find_if函数,二元谓词配合sort函数
内建函数:
functional库
被分为算术仿函数(加减乘除取余...)、关系仿函数(大于小于等于...)、逻辑仿函数(与或非,应用较少)
transform操作:
algorithm库
使用transform搬运时需注意目标容器的容量(不会动态开辟更大空间)
查找操作:
find操作查找特定元素
find_if使用一元谓词/普通函数提供筛选条件
adjacent_find查找相邻重复元素
binary_search要求有序序列(通过二元谓词/普通函数告诉容器的排序方式,否则默认升序排列)
void test01() {//adjacent find 查找相邻重复元素 binary_search二分查找bool less(int, int);greater<int> n;vector<int> a = { 6,5,5,4,3,2,1 };auto i = adjacent_find(a.begin(), a.end());cout << *i << endl;cout << binary_search(a.begin(), a.end(), 3, less) << endl;
}
bool less(int a, int b) {return a > b;
}
void test() {test01();
}
count统计容器中相等的元素个数(自定义类型使用运算符重载),count_if同find和find_if的区别
排序操作:algorithm库
sort排序:
支持随机迭代器的容器均支持sort排序,否则使用容器的成员sort函数
可以提供仿函数/普通函数/内建函数,指定结果为true的时候是想要的排序顺序
random_shuffle洗牌:
配合srand生成种子成为真随机
merge合并:
要求被合并的两个序列都是有序的,进行归并
需要指向被合并容器和目标容器的迭代器来规定合并范围和合并起始点
新容器有时需要事先resize(reserve不行)
reverse反转:
没啥
常用拷贝和替换算法:algorithm库
copy算法:
提供被copy的容器的起始位置和最终位置,以及目标容器的位置
replace、replace_if算法:
将区间内所有 指定/符合条件 的旧值替换为指定新值
swap算法:
必须是同类容器
常用算术生成算法:numeric库
accumulate:
求累加值,需要容器的范围及起始值
fill:
容器范围内元素全部替换为指定值
常用集合算法:algorithm库,必须是有序序列(也可以通过仿函数、普通函数告诉容器的排序方法)
set_intersection:将两个容器的交集放在目标容器中
set_union:并集
set_difference:差集
示例:
void test03() {//set_intersection求交集、并集、差集void STL_Print(const int&);vector<int> a = { 6,5,4,3,1 };vector<int> b = { 6,5,4,2 };vector<int> c(a.size()+b.size(),0);auto pos = set_intersection(a.begin(), a.end(), b.begin(), b.end(), c.begin(), [](int a, int b) ->bool {return a > b; });for_each(c.begin(), pos, STL_Print);cout << endl;pos = set_union(a.begin(), a.end(), b.begin(), b.end(), c.begin(), [](int a, int b) ->bool {return a > b; });for_each(c.begin(), pos, STL_Print);cout << endl;pos = set_difference(a.begin(), a.end(), b.begin(), b.end(), c.begin(), [](int a, int b) ->bool {return a > b; });for_each(c.begin(), pos, STL_Print);
}
//6, 5, 4,
//6, 5, 4, 3, 2, 1,
//3, 1,
void test() {test03();
}
void STL_Print(const int &a) {cout << a << ",";
}
void STL_Print(int& a) {a++;cout << a << ",";
}