Week7 Notes
容器Containers
Stack
也是一个线性容器,是一种先进后出FILO的数据结构,所以支持的操作有push pop,只能访问顶层元素。
#include
int main(){
std::stacks;
}
底层数据结构是deque为默认的底层结构
templateContainer =
deque
> class stack{
}
可以看做是对deque的封装,修改了deque的接口。因为stack不允许遍历,所以没有iterator。也可以用list作为stack的底层数据结构。
Queue队列
是一种先进先出的数据结构,FIFO,有两个出口,只能访问最前或最后的元素,不允许遍历有push,pop,front和back
#include
的层结构是以dequeue作为默认的底层结构
没有iterator
也可以用list
前面都是序列式容器,除了list之外都是连续的内存分布
map and multimap
set and multiset
关联式的容器
元素和元素之间会有某种联系
map存储的对象是key/value pair
不允许有重复的key
春初的对象必须是具备可排序性的
templatePr
= less
class _Alloc = allocator > >
class map{…}
map的初始化
struct Employee{
Employee()
Employee(conststd::wstring& wszName): Name(wszName) {}
Std::wstringName;
}
struct ReverseId:public std:binaryfunction{
booloperator()(cons tint& key1, cons int& key2) const{
return(key1<=key2)?false:true;
}
}
const int size = 3;
const std::pairitems[size] = {
std::make_pair(1,Employee(L”Tom”)),
std::make_pair(2,Employee(L”Jerry”)),
std::make_pair(3,Employee(L”Alice”)),
};
std::mapmap1(items, items+3);
插入元素
map1.insert(std::make_pair(4, Employee(L”Brown”)));
map1[5] = Employee(L”Fisher”);
删除元素
std::map::iterator it = map1.begin();
map1.erase(it);
operator[]存取元素
Employee& e = map1[2];
e.SetName(L”…”);
Multimap
类似map的容器,但允许key重复
set and multiset
set是一种关联容器,存储的对象本身既是key又是value,不允许有重复的key,存储的对象必须是可排序性
templatePr =
less
, classAlloc = allocator<Kty> > class set{
…
}
默认less定义排序行为,存储对象必须具备operator<行为,可以自定义排序行为,通过仿函数
std::setps1(personArray, personArray+nSize);
插入元素
ps1.insert(Person(L”Bill”, 4));
删除元素
std::set::iterator it = ps1.begin();
std::advance(it, 1);
ps1.erase(it);
关于set的一些算法
set_union把两个set合并在一起
std::setdest;
std::insert_iterator > ii(dest, dest.begin());
std::set_union(ps1.begin(), ps1.end(),ps2.begin(), ps2.end(), ii, PersonIdComparer);
set_union是依照id来排序的,所以person(L“Apple”,0)仍然跑到了最前面。
Set_intersection找出set中相同的元素
Std::setdest;
Std::insert_iterator > ii(dest, dest.begin());
Std::set_intersection(ps1.begin(),ps1.end(), ps3.begin(), ps3.end(0, ii, PersonIdComparer());
Set_difference
包含在(first1, last1)中而不再(first2, last2)中的不同元素
set需要注意的问题
用于排序的成员(真正的key)
除了真正的key其他成员都可以改变
std::set::iterator it = ps1.find(Person(L”Bill”, 4));
if(it != ps1.end())
it->SetName(L”Bill Gates”);
无法通过编译,set的实现方式不允许通过迭代器改变对象成员
std::set::iterator it = ps1.find(Person(L”Bill”, 4));
if(it != ps1.end())
const_cast(*it).SetName(L”BillGates”)
以下方式无法改
Person tempCopy(*it);
tempCopy.SetName(L”Bill Gates”)
STL整体结构仿函数
STL整体结构
仿函数,适配器
STL组件之间的关系,内存分配器allocator迭代器iterators容器containers算法algorithms仿函数functors适配器adapters
仿函数又称为函数对象function object起作用相当于一个函数指针,remove_if(v.begin, v.end(), ContainsString(L”C++”))
要将某种行为作为算法的函数,此处是判断是否存在C++这几个字符,需要将该行为函数指针作为算法的函数。
STL中将这种行为函数指针定义为所谓的仿函数,其实是一个class再以该仿函数产生一个对象作为算法参数。
STL内建仿函数或者用户自定义仿函数
仿函数的类别定义中必须重载函数调用运算子operator()
#include
std::greater g;
std::cout<
std::cout<()(100,300) <
自定义的仿函数必须重载operator()
struct containsstring: publicstd::unary_function
为什么要用仿函数?不用函数指针?
普通函数指针无法满足stl的抽象要求
函数指针无法和STL其他组件交互
仿函数可以作为模板实参用于定义对象的某种默认行为
以某种顺序对元素进行排序的容器,排序规则就是一个模板实参
templatePr =
less
> class set{
…
}
less作为元素的排序行为,如果两个set具有不同的排序规则,那么进行赋值或者==判断会错误
std::set
> set1, set2; //operator<作为排序行为
std::set
std::greater > set3, set4;//iperator >作为排序行为
if(set1 == set2) //
if(set1 == set3) // error
set1 = set2
set1 = set3 //error
仿函数适配器(functor adapters)
目的在于将无法匹配的函数套接成可以匹配的型别
binder1st/binder2nd
mem_fun/mem_fun_ref
template
class binder1st的源码分析
调用find_if的时候模板里的第二个参数是class具体为not_equal_to,传入的参数是迭代器和输入的数的比较,然后返回find_if
binder2nd,mem_fun, mem_fun_ref
实际使用的时候应当使用更简洁的写法。
Bind1st封装了binder1st的调用复杂性
Template
Inline binder1st <_Fn2> bind1st(const_Fn2& _Func, const _Ty& _Left){
TypenameFn2::first_argument _typeVal(Left);
Return (binder1st<_Fn2>(_Func,_Val));
}
类似的还有bind2nd适配器,区别在于_Func操作是作用在左边的值还是右边的值上。
Std::vector::iterator it=
Std::find_if(v.begin(), v.end(),std::bind1st(std::less(), 0));
等价于
std::Vector::iterator it=
std::find_if(v.begin(), v.end(),std::bind2nd(std::greater(), 0));
mem_fun/mem_fun_ref
用来适配对象的成员函数
std::vector v;
std::for_each(v.begin(), v.end(),&Person::Print);//error
有全局函数Print
void PrintPerson(const Person* p){…}
std::for_each(v.begin(), v.end(),&PrintPerson);//OK
可以去调用一个对象
对于函数f以及对象obj,在obj上调用f的形式可以有三种
f(obj)
obj.f()
obj->f()
但在for_each中,只接受第一种形式,mem_fun和mem_fun_ref的存在,是为了obj的成员函数f可以被第一种形式调用
std::for_each(v.begin, v.end(), std::mem_fun(&Person::print));
仿函数适配器
如果vector中存放的不是指针是对象用mem_fun_ref
std::string/std::wstring与vector/vector
单线程情况下对字符串操作用std::string/std::wstring
多线程情况下要考虑是否带引用计数reference count
多线程情况下可以考虑用vector
当new初对象并放入容器时,要在销毁容器之前delete那些对象
std::vector v;
for(vector::iterator it =v.begin(); it != v.end(); it++)
delete (*it);
v.clear;
尽量用算法代替手写循环
通过swap为容器缩水
size和capacity的区别
int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9,10};
std::vector v(array, array+10);
v.reserve(100000);
::_tprintf(TEXT(“vector size:%d\n”),v.size());// size = 10;
v.capacity() //capacity = 100000
std::vector(v).swap(v);
//SIZE = 10
//capacity = 10
std::vector().swap(v);//清楚v并最小化其容量size =0, capacity = 0
再有对象继承的情况下,建立指针的容器而不是对象的容器
STL装入的对象是原始对象的一个拷贝
如果对象很大,需要大量性能开销
由于继承的存在,拷贝回发生slicing,如果以基类对象建立一个容器而插入派生类对象,那么当对此昂通过基类的拷贝构造函数考入容器的时候对象的派生部分会被切割
泛型算法,非变易算法
泛型算法和内存分配器
非变易算法non-mutating algorithms
变易算法mutating algorithms
排序sorting
泛型数值算法generalized numeric algorithms
非变易算法是一系列模板函数,在不改变操作对象的前提下对元素进行处理,如查找,子序列搜索统计匹配
for_each find find_if count count_ifmismatch equal search find_first_of
非变易算法for_each,调用流程之前已经提过
非变易算法find
int elements [] = {1, 2, 3, 23, 423, 587};
std::vector v(elements,elements+6);
std::vector::iterator it = std::find(v.begin(),v.end(), 23);
if(it != v.end()){
//found!
}
非变易算法find_if
int elements[] = {1,2,3,23,423,596};
std::vector v(elements,elements+6);
std::vector::iterator it =std::find_if(v.begin(), v.end(), std::bind2nd(std::greater(), 100));
非变易算法adjacent_find
非变易算法find_first_of
非变易算法count
非变易算法count_if
非变易算法mismatch
查找*i1 != *(_First2 + i1-_First1)
非变易算法search
变易算法,变易算法是指那些改变容器中对象的操作
copy, swap, transform, replace, fill,generate, remove, unique, reserve, rotate, random_shuffle, partition
变易算法copy, copy_n, copy_backward, copy_if,
变易算法swap
变易算法transform
变易算法replace
变易算法fill
变易算法generate
std::vector v(5);
std::generate(v.begin(), v.end(), rand);
变易算法remove
变易算法unique
变易算法reverse
变易算法rotate
template inline
FwdIt rotate(FwdIt _First, _FwdIt _Mid, _FwdIt _Last)
变易算法partition
泛型算法
排序sort,对于排序的元素需要提供operator<
partial_sort
部分排序,有可能从后面排到前面来,所以排序是一种遍历的算法??
Binary_search,搜索前要先排序