STL
标准库都应该被封装到std空间中
顺序容器
容器没有足够空间执行push_back()这类添加元素的操作时
重新分配(比预计更多)新内存,移动原元素,释放旧内存
#define cap vector/string/deque
cap.shrink_to_fit(); //裁剪至size()大小,退回多余空间
#define cap vector/string
cap.capacity(); //不重新分配内存的条件下,c可以保存多少元素
cap.reserve(n); //n>capacity()时,重新分配>=n个元素的空间,实现不一样可能翻倍
//n<=capacity()时,不会退回空间,什么也不做
string s1,s2;
s1.append("");
s1.insert(pos,"");
s1.erase(pos,n);
s1.assigned(pos,n); //s1=*pos[0~n-1]赋值
s1.replace(pos,n,""); //pos删n插入""
s1.compare(s2);
s1.compare(pos1,n1,s2,pos2,n2); //字典序比较结果
string s3=to_string(i);
double d=stod(s3);
string s4("-3.14");
d=stod(s4.substr(s4.find_first_of("+-.0123456789")));
适配器adaptor
一个类型(函数)A的适配器接受一种已有类型(函数)B,使B的行为看起来像A
容器、迭代器、函数都有适配器
默认构造函数=空对象
接收的容器,其构造函数会拷贝容器中的元素(要求容器有添加、删除以及访问队尾元素的能力)
deque<int> deq({1,2,3,4,5,6});
stack<int> stk(deq); // <T,C<T>> 默认C<T>为deque
vector<int> vec({1,2,3,4,5,6});
stack<int vector<int>> stk1(vec)
while (!stk.empty())
{
cout << stk.top() << endl; //输出6,5,4,3,2,1,stk从deq[0~6]压入栈
stk.pop();
}
泛型算法
算法接受任何可调用对象(callable object)
1.函数 或 函数指针
2.对调用运算符"()"进行了重载的类
3.lambda表达式(lambda expression)
算法依赖于元素类型的操作,操作依赖于运算符
应该依赖于迭代器操作,不应该具有增删(inserter除外)的能力
#include<algorithm>
auto res=find(vec.cbegin(),vec.cend(),val); //cbegin()、cend()返回const迭代器
if(res==vec.cend())cout<<"没找到"<<endl; //使用迭代器,即任何容器(包括数组)都可以使用
int sum=accumulate(vec.cbegin(),vec.cend(),/*initializer*/);
//initializer决定了accumulate中"+"的重载形式
string sum=accumulate(vec.cbegin(),vec.cend(),string("")); //string有实现"+"重载
string sum=accumulate(vec.cbegin(),vec.cend(),""); 错误//const char*没有"+"的重载
bool equal(v1.cbegin(),v1.cend(),v2.cbegin()); //序列二长于序列一,不会抛异常!!!
//只要能用"==",元素类型不必一样 vector<string> 和 list<const char*>
fill(v.cbegin(),v.cend(),/*val*/);
fill_n(dest,n,val); //注意越界
返回v2队尾 = copy(v1.cbegin(),v1.cend(),v2); //v1拷贝到v2
replace(v1.cbegin(),v2.cend(),/*v1被替换元素*/,/*替换元素*/);
#include<iterator>
back_insert_iterator<_Container> back_inserter(_Container& _Cont);
//使用 back_insert_iterator 能够提供新的空间插入新元素 个人喜欢称为 尾后插入迭代器
//source code
back_insert_iterator& operator=(typename _Container::value_type&& _Val)
{ // push value into container
container->push_back(_STD move(_Val)); //可以看到只能在队尾添加新的元素!!!
return *this;
}
replace(v1.cbegin(),v2.cend(),back_inserter(vec),item1,item2); //替换拷贝存入vec中
sort(v.begin(),v.end());//43212121 -> 11122234
auto end_unique=unique(v.begin(),v.end()); //覆盖相邻的重复元素 1234|2234
erase(end_unique,v.end()); //删除重复的元素
谓词(predicate)
一个可调用表达式,返回条件运算结果
元素类型必须能转化为参数的类型,且只接受一个或两个参数
一元谓词(unary predicate)、二元谓词(binary predicate)
bool isShorter(string &s1,string &s2){
return s1.size()<s2.size();
}
sort(vec.begin(),vec.end(),isShorter);
函数指针!!
typedef int (*funp)(int, int) //funp为指针类型 typedef decltype(fun), *p; //decltype返回函数类型,所以p为指针 int fun(int a,int b){return 1;} funp fp=&fun; //指针 int a = fp(1,2); //可以不用解引用
返回函数指针时比较特殊
using F = int(int, int); //fun为函数类型 的 类型别名 using FP = int(*)(int,int); //FP为指针 FP fun(int, int){return FP();} //返回的是函数的指针,注意不允许返回函数对象 int (*fun(int))(int ,int); //等价,fun接收(int)参数,返回指向int (int, int)函数的指针 auto fun(int) -> int(*)(int, int); //尾置返回类型更清晰
lambda表达式
算法 为了接收比谓词(两个)更多的参数,使用lambda表达式
lambda表达式可以看成一个未命名的内联函数
适合在只会用一两次的地方使用
fun()
{
int a=0;
auto f=[a](){return a>0;} //值传递
auto res=f(); //auto = bool 自动推断
}
[capture list](parameter list)->return_type {function body}
[捕获列表] 传递局部(非static)变量
隐式捕获:=(值)或&(引用) eg:[&,names] //隐式引用捕获,names声明值捕获,反之亦然
(参数列表) 可省 没有默认值
返回类型 默认void 使用尾置返回 或 仅有return语句时auto推测
{函数体}
编译器创建一个与lambda对应的类类型,传递给函数时,实例化一个该类型的对象
值传递 :变量在对象创建时被拷贝 const(需要mutable才能赋值)
引用传递:lambda内外变化相互影响 引用决定是否const
数据成员在创建后可能会多次被调用,尽量避免捕获指针或引用
//-------------------------使用示例-------------------------------
void biggies(vector<string>& w,vector<string>::size_type sz)
{
sort(w.begin(),w.end());//排序
auto unique_end=unique(w.begin(),w.end()); //去重
w.erase(unique_end,w.end());
stable_sort(w.begin(),w.end(), //相等的元素维持原顺序
[](const string &l,const string &r){return l.size()<r.size();})
auto it = find_if(v.begin(),v.end(),[sz]const(string &a){return a.size()>=sz;});
//将sz传递进去才可以在函数体中使用
for_each(it,w.end(),[](const string &s){cout<<s<<" ";});
//按字典序打印所有长度>=sz的元素
cout<<endl;
}
//--------------------实现-----------------
template <class _Pr, class _Ty1, class _Ty2>
constexpr bool _Debug_lt_pred(_Pr&& _Pred,
_Ty1&& _Left,
_Ty2&& _Right)
_NOEXCEPT_COND(noexcept(_Pred(_Left, _Right))&& noexcept(_Pred(_Right, _Left)))
{ // test if _Pred(_Left, _Right) and _Pred is strict weak ordering
const auto _Result = static_cast<bool>(_Pred(_Left, _Right));
//返回值会被强制转换为 bool 类型
if (_Result) {
//可以看到每个algorithm对lambda表大式是有不同要求的,这里要求两元素相比的形式
_STL_VERIFY(!_Pred(_Right, _Left), "invalid comparator");
}
return _Result;
}
#define _DEBUG_LT_PRED(pred, x, y) _Debug_lt_pred(pred, x, y)
//----------------------------可以看到source code使用快速排序------------------
template <class _RanIt, class _Pr>
inline void _Sort_unchecked(
_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _Pr _Pred) {
// order [_First, _Last), using _Pred
_Iter_diff_t<_RanIt> _Count;
while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal) {
// divide and conquer by quicksort
auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred);
// TRANSITION, VSO#433486
_Ideal = (_Ideal >> 1) + (_Ideal >> 2); // allow 1.5 log2(N) divisions
if (_Mid.first - _First < _Last - _Mid.second) { // loop on second half
_Sort_unchecked(_First, _Mid.first, _Ideal, _Pred);
_First = _Mid.second;
} else { // loop on first half
_Sort_unchecked(_Mid.second, _Last, _Ideal, _Pred);
_Last = _Mid.first;
}
}
if (_ISORT_MAX < _Count) { // heap sort if too many divisions
_Make_heap_unchecked(_First, _Last, _Pred);
_Sort_heap_unchecked(_First, _Last, _Pred);
} else if (2 <= _Count) {
_Insertion_sort_unchecked(_First, _Last, _Pred); // small
}
}
参数绑定
bind标准库
关联容器
multi | ||
---|---|---|
map{key-value} / set{key} | multimap / multiset | |
unordered hash_map | unordered_set / unordered_map | unordered_multi_set / unordered_multi_map |
有序容器对“关键字的类”要求能比较(同算法,严格弱序,strict weak ordering,实现<比较)
#include<map>
#include<set>
#include<unordered_map>
#include<unordered_set>
#include<string>
#include<iostream>
using namespace std;
bool com(string &a,string &b) //比大小的函数用于排序
{ return a.size<b.size; }
int main()
{
map<string,int>wl={{"hk",1},{"cb",1},{"kz",1}};
set<string,bool(*)(string&,string&)> ex({"the","or"},&com);
string w;
while(cin>>w)
if(ex.find(w)==ex.end()) //不在set中的单词才进入map,返回在set中的iterator
wl[w]++;
for(const pair<string,int> &w:wl) //Sorce Code就是pair<key,value>实现的
cout<<w.first<<":"<<w.second<<endl;
while(1);
return 0;
}