cpp软件架构狮 2018-07-23 13:14:59
每一个容器都有自己的迭代器,迭代器用来遍历容器中的元素。
遍历:不重复的进行访问每个元素。
3.容器,迭代器,算法的初步使用。
1)先引入所需要的容器头文件和算法头文件
void Myprint( int val ) { 算法 中 的回 调 函数 需 要自己写 cout << val << " "; 内容 为 自己所想打印的内容 } void test() { vectorV; for ( int i = 0; i < 5; i++ ) { V.push_back( i + 10 ); } vector ::iterator pBegin = V.begin(); vector ::iterator pEnd = V.end(); /* 直接使用迭代器进行容器的遍历 */ while ( pBegin != pEnd ) { cout << *pBegin << " "; pBegin++; } cout << endl; /* 模拟算法的最后一个回调函数的使用 */ pBegin = V.begin(); while ( pBegin != pEnd ) { Myprint( *pBegin ); pBegin++; } cout << endl; /* 使用算法遍历容器,并且打印出来。注意:算法的最后一个参数为回调函数,需要自己写(所想要打印的内从容) */ for_each( V.begin(), V.end(), Myprint ); cout << endl; } } ;
2)容器的分类:序列式容器和关联式容器
序列式容器:容器元素在容器中的位置由元素进入容器的时间和地点来决定。如:(vector,deque , list, stack, queue )
关联式容器:容器具有自己的规则,元素在容器中的位置由容器的规则来定。如(树状容器: set/mutilset; map/mutilmap )
3)每个容器都有自己的迭代器,由容器自己提供。
1)从 const char * 到 string 有隐式转换;反之则没有。
3.下标操作符: [] 和 at()方法。
两个的区别在于:1)[] 越界程序会直接挂掉, 2)at()方法越界程序会提供错误信息。
1)连续的内存空间
2)单口
3)会实现内存空间动态增长(当已有内存占满时);申请更大的空间,原来的空间析构,原来的迭代器会失效。
4)它的内存空间不会随着 clear()方法清除数据而消失的,只有当容器生命周期结束时,它的容量才会释放;
"所以当想在生命周期存在时减少或增大容器内存,可以使用 swap() 方法。"(如下)
void test04() { vectorv; for ( int i = 0; i < 100000; i++ ) { v.push_back( i ); } cout << "capacity:" << v.capacity() << endl; cout << "size:" << v.size() << endl; v.resize( 3 ); cout << "capacity:" << v.capacity() << endl; "注意容量与长度不一样," cout << "size:" << v.size() << endl; /* * 收缩内存 * vector (v).swap(v); */ vector ( v ).swap( v ); /* 匿名对象 */ cout << "capacity:" << v.capacity() << endl; cout << "size:" << v.size() << endl; }
5)reserve的使用:"预留空间",在此空间还没有初始化时是不允许访问。可以通过push_back()插入元素后,进行访问。
6)resize的使用:开辟空间并且初始化,它的空间申请完后是可以访问的。
重新指定容器的长度为num,若容器变长,则默认值或指定值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除,"只是长度变短,但是容器的容量没有变化,"。
7)只要容器的容量产生变化,原来的迭代器就会失效。(如删除元素之后,原来的迭代器就不能用了)。
1)"(当内存由于动态增长,更换地址后,原来的迭代器就失效了,不可以再使用)。"
2)只要能遍历容器中所有元素的,都是容器认可的迭代器。
3)每个容器的迭代器不一样,有自己的独立迭代器。
4) const_iterator 只读
reverse_iterator 逆序迭代器
iterator 最普通的正向迭代器
1)每个容器只提供一种
2)都是由对应的容器自己提供的迭代器。(因为每个容器的实现机制不一样)。
3)输入迭代器,输出迭代器,前向迭代器,双向迭代器,随机访问迭代器
尽量不要频繁申请和释放空间(太浪费时间);可以先预测一下所用空间的大小,直接用reserve()申请足够大的空间,在逐步初始化。
1)是一种双向开口,动态以分段连续内存空间组合而成,随时可以增加一块新内存的容量器。
2)可以在首尾两端分别作元素的删除和插入操作。
1)不提供迭代器;没有遍历功能
2)以其他的容器作为底层,它相当于提供接口
3)只有栈顶元素才可以被外界取用。所以想遍历容器,只能从栈顶开始,取出一个元素,就删除它,当遍历完后,容器也就没有元素了。
1)没有迭代器。不支持随机访问
2)两个出口,一个只进,一个只出。
3)和 stack 栈容器一样,遍历完后,容器的元素也被删除空。
3.( stack 和 queue 容器叫受限的线性表)
1)采用动态存储分配,不会造成内存浪费和溢出。
2)元素的插入和删除十分方便,修改指针即可。
3)list容器提供自己的排序算法;
4)list容器的排序(重点在回调函数的使用)
5)swap()既可以交换两个链表的数据,也可以动态的伸缩内存。
1)它的元素既是键值又是实值,而且所有的元素都会自动排序。
2)不允许两个元素有相同的键值。
3)不允许通过迭代器修改元素的值。
4)与list有某些相同的性质,当对容器中的元素进行插入和删除操作时,操作之前的所有迭代器,在完成操作完成后都是有效的,除了被删除的那个元素的迭代器
1)特性和set一样,唯一区别在于它允许键值重复。
都是由小到大;如果想从大到小,就需要自己建立一个回调函数
将一对值组合成一个值,这一对值可以具有不同的数据类型。两个值可以分别用对组的公有属性 first 和 second 访问。
创建对组的两种方式:
1)pair 2)pair 3)pair 8.map 容器:(它的所有元素都是一个对组) 1)键值对;键值不可以相同,实值可以相同。所有的元素都会根据键值自动排序。 2)插入元素的四种方式: map m.insert(pair m.insert(make_pair(2, 2)); m.insert(map m[4] = 4; 3)如果通过[] 访问一个不存在的key值,那么编译器会创建一个,实值为默认值。 4)map的迭代器与普通容器不同。是一个对组迭代器。可以通过迭代器修改实值的值,不可以修改键值的值。 5)map的迭代器与list迭代器有某些相同的性质,对容器元素进行插入和删除时,操作之前的所有迭代器在操作完成之后不会失效,当然那个被删除的元素迭代器除外。 6)指定map 的排序规则:(因为它的元素为对组,所以排序规则需要自己写函数确定) 与map 容器操作类似,唯一不同在于它的键值可以相同。 10.如何判断容器支持随机访问(或提供随机迭代器): 只需要看容器提供的迭代器能否 +2,+3 vector queue 1)此时就涉及到深拷贝和浅拷贝的问题;当由指针存在,而且它指向堆内存时,用容器提供的拷贝只会复制指针的指向,并没有拷贝到指针所指向的数据。 当生命周期结束,进行空间析构时,就会出现同一块内存二次析构,程序挂掉。 2)必须自己重载一个深拷贝函数(和类的函数重载一样;(一般都是:一个拷贝函数和一个重载=号操作函数)。9.multimap容器:
11.STL中,所有的拷贝都是值寓意,所提供的内容必须是可以拷贝的。
12.STL使用的时机
1)仿函数是一个类,不是一个函数。重载了()
2)仿函数重载了()操作符,使得函数对象可以像函数一样使用。
3)重载的operator()需要一个参数的,这样的类对象称为 "一元仿函数"; 依次类推。
1)plus
>4.函数对象与普通函数的区别:
1)函数对象超出了普通函数的概念,可以保存函数的调用状态
2)函数对象可以做参数和返回值
1)普通函数或重载的operator()"返回值为bool 类型"的函数对象(仿函数)。
2)一个参数的叫一元谓词,以此类推。
for_each(v1.begin(), v1.end(), [](int val){ cout<< val<<" "; });
for_each(v1.begin(), v1.end(), [](int val)->void{ cout<< val<<" "; });
template
template
template
template
template
template
1). 让自己编写的函数对象继承基类,如果是一元函数对象需要继承unary_function,
如果是二元函数对象继承binary_function
2). 函数对象operator()函数后增加 const
3). 使用bind2nd bind1st(将一个二元函数对象转变为一元函数对象),
区别为: bind1st: 将参数绑定为函数对象的第一个参数 bind2nd: 将参数绑定为函数的第二个参数。
4)for_each():遍历打印容器内容。返回值为最后一个函数对象的类型。
6)取反适配器
find_if():查找容器中有无所寻找的内容,返回值为查找类型的迭代器。
对一元函数对象、谓词取反用 not1; 对二元函数对象、谓词取反用 not2;
7)给普通函数绑定参数(需要:先把一个普通的函数指针适配成函数对象)
ptr_fun函数指针适配器:把一个普通函数指针适配为函数对象。
void Myprint(int val1, int val2){ cout<< val1 + val2 <<" "; }
void main() { for_each(v1.begin(), v1.end(), bind2nd(ptr_fun(Myprint), 200)); }
8)成员函数适配器(mem_fun_ref:容器中存放的为对象实体。)(mem_fun:容器中存放的为对象指针。)
vector
for_each(v1.begin(), v1.end(), mem_fun_ref(&person::showperosn));
vector
for_each(v1.begin(), v1.end(), mem_fun(&person::showperosn));
遍历算法:
1)for_each算法:第三个参数,接受的函数类型。
2)transform;
查找算法
1)find(查找元素或对象) 与 find_if(查找指针所指向的内容)
2)adjacent_find查找相邻重复元素
3)binary_search(二分查找法),需要查找的容器元素有序排列
4)count 与 count_if (统计容器中元素的个数)
排序算法
1)合并两个有序序列(merge)两个序列必须是有序的。且顺序应该一样(或从小大,或从大到小,两种方式参数有点区别,默认从小到大,从大到小需要额外添加函数对象)
2) sort算法(条件:容器必须支持随机访问)
3)random_shuffle(打乱容器中的顺序)
4)reverse (反转)
拷贝和替换算法
1)copy (拷贝)
2)replace(替换)把所有要替换的值都替换成目标值。
3)replace_if
4) swap
算数生成算法
1)accumulate (累加容器中元素)
2)fill(填充)
3)
集合算法
1)set_intersection (求交集) 注意它的返回值。
2)set_union (求并集)
3)set_difference (差集);