C++基础知识第十天

cpp软件架构狮 2018-07-23 13:14:59

1.STL六大组件

2.STL三大组件:容器、算法、迭代器

每一个容器都有自己的迭代器,迭代器用来遍历容器中的元素。

遍历:不重复的进行访问每个元素。

3.容器,迭代器,算法的初步使用。

1)先引入所需要的容器头文件和算法头文件

void Myprint( int val )
{
	算法 中 的回 调 函数 需 要自己写
	cout << val << " "; 内容 为 自己所想打印的内容
}


void test()
{
	vector V;
	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)每个容器都有自己的迭代器,由容器自己提供。

3.string 容器:

1)从 const char * 到 string 有隐式转换;反之则没有。

3.下标操作符: [] 和 at()方法。

两个的区别在于:1)[] 越界程序会直接挂掉, 2)at()方法越界程序会提供错误信息。

4.vector 容器:

1)连续的内存空间

2)单口

3)会实现内存空间动态增长(当已有内存占满时);申请更大的空间,原来的空间析构,原来的迭代器会失效。

4)它的内存空间不会随着 clear()方法清除数据而消失的,只有当容器生命周期结束时,它的容量才会释放;

"所以当想在生命周期存在时减少或增大容器内存,可以使用 swap() 方法。"(如下)

void test04()
{
	vector v;
	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)只要容器的容量产生变化,原来的迭代器就会失效。(如删除元素之后,原来的迭代器就不能用了)。

5.迭代器的注意事项:

1)"(当内存由于动态增长,更换地址后,原来的迭代器就失效了,不可以再使用)。"

2)只要能遍历容器中所有元素的,都是容器认可的迭代器。

3)每个容器的迭代器不一样,有自己的独立迭代器。

4) const_iterator 只读

reverse_iterator 逆序迭代器

iterator 最普通的正向迭代器

6.迭代器的种类:5种。

1)每个容器只提供一种

2)都是由对应的容器自己提供的迭代器。(因为每个容器的实现机制不一样)。

3)输入迭代器,输出迭代器,前向迭代器,双向迭代器,随机访问迭代器

6.vector 申请和释放空间的注意:

尽量不要频繁申请和释放空间(太浪费时间);可以先预测一下所用空间的大小,直接用reserve()申请足够大的空间,在逐步初始化。

7.随机迭代器:(vector容器支持随机访问)

8.deque 容器:

1)是一种双向开口,动态以分段连续内存空间组合而成,随时可以增加一块新内存的容量器。

2)可以在首尾两端分别作元素的删除和插入操作。

1.栈容器(stack) :元素先进后出,单口容器

1)不提供迭代器;没有遍历功能

2)以其他的容器作为底层,它相当于提供接口

3)只有栈顶元素才可以被外界取用。所以想遍历容器,只能从栈顶开始,取出一个元素,就删除它,当遍历完后,容器也就没有元素了。

2.队列容器(queue):元素先进先出

1)没有迭代器。不支持随机访问

2)两个出口,一个只进,一个只出。

3)和 stack 栈容器一样,遍历完后,容器的元素也被删除空。

3.( stack 和 queue 容器叫受限的线性表)

3.链表容器(list):双向循环链表

1)采用动态存储分配,不会造成内存浪费和溢出。

2)元素的插入和删除十分方便,修改指针即可。

3)list容器提供自己的排序算法;

4)list容器的排序(重点在回调函数的使用)

5)swap()既可以交换两个链表的数据,也可以动态的伸缩内存。

4.set容器(红黑树,平衡二叉树的一种)

1)它的元素既是键值又是实值,而且所有的元素都会自动排序。

2)不允许两个元素有相同的键值。

3)不允许通过迭代器修改元素的值。

4)与list有某些相同的性质,当对容器中的元素进行插入和删除操作时,操作之前的所有迭代器,在完成操作完成后都是有效的,除了被删除的那个元素的迭代器

5.multiset容器:

1)特性和set一样,唯一区别在于它允许键值重复。

6.算法的默认排序原则

都是由小到大;如果想从大到小,就需要自己建立一个回调函数

7.对组( pair )

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

创建对组的两种方式:

1)pair pair1("xiaobai",20); cout<< pair1.first <

2)pair pair2 = make_pair("xiaohong",23); cout<< pair2.first <

3)pair pair3 = pair2; cout<< pair3.first <

8.map 容器:(它的所有元素都是一个对组)

1)键值对;键值不可以相同,实值可以相同。所有的元素都会根据键值自动排序。

2)插入元素的四种方式:

map m;

m.insert(pair(1, 2));

m.insert(make_pair(2, 2));

m.insert(map::value_type(3, 2));

m[4] = 4;

3)如果通过[] 访问一个不存在的key值,那么编译器会创建一个,实值为默认值。

4)map的迭代器与普通容器不同。是一个对组迭代器。可以通过迭代器修改实值的值,不可以修改键值的值。

5)map的迭代器与list迭代器有某些相同的性质,对容器元素进行插入和删除时,操作之前的所有迭代器在操作完成之后不会失效,当然那个被删除的元素迭代器除外。

6)指定map 的排序规则:(因为它的元素为对组,所以排序规则需要自己写函数确定)

9.multimap容器:

与map 容器操作类似,唯一不同在于它的键值可以相同。

10.如何判断容器支持随机访问(或提供随机迭代器):

只需要看容器提供的迭代器能否 +2,+3

vector::iterator it = v.begin(); it = it+3;(可以,提供随机迭代器)

queue::iterator it = q.begin(); it = it+2;(不可以向后跳跃,不提供随机迭代器)。

11.STL中,所有的拷贝都是值寓意,所提供的内容必须是可以拷贝的。

1)此时就涉及到深拷贝和浅拷贝的问题;当由指针存在,而且它指向堆内存时,用容器提供的拷贝只会复制指针的指向,并没有拷贝到指针所指向的数据。

当生命周期结束,进行空间析构时,就会出现同一块内存二次析构,程序挂掉。

2)必须自己重载一个深拷贝函数(和类的函数重载一样;(一般都是:一个拷贝函数和一个重载=号操作函数)。

12.STL使用的时机

1.容器中的 find()函数默认区分大小写,而且返回值为迭代器.

2.仿函数:重载函数调用操作符的类,其对象成为函数对象,也叫仿函数。

1)仿函数是一个类,不是一个函数。重载了()

2)仿函数重载了()操作符,使得函数对象可以像函数一样使用。

3)重载的operator()需要一个参数的,这样的类对象称为 "一元仿函数"; 依次类推。

3.预定义函数对象:(实现了数据类型与算法的分离。)

1)plus p; 预定义好的函数对象,能实现不同类型数据的 + 运算。

3.函数没有类型,不能定义变量。函数对象有类型,因为他是一个类。

>4.函数对象与普通函数的区别:

1)函数对象超出了普通函数的概念,可以保存函数的调用状态

2)函数对象可以做参数和返回值

5.谓词:

1)普通函数或重载的operator()"返回值为bool 类型"的函数对象(仿函数)。

2)一个参数的叫一元谓词,以此类推。

6.兰博打函数表达式: vector v1;

for_each(v1.begin(), v1.end(), [](int val){ cout<< val<<" "; });

for_each(v1.begin(), v1.end(), [](int val)->void{ cout<< val<<" "; });

7.内建函数对象

template T plus//加法仿函数

template T minus//减法仿函数

template T multiplies//乘法仿函数

template T divides//除法仿函数

template T modulus//取模仿函数

template T negate//取反仿函数

7.函数对象适配器:

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 v1; person p1("aaa", 10); v1.push_back(p1);

for_each(v1.begin(), v1.end(), mem_fun_ref(&person::showperosn));

vector v1; v1.push_back(&p1);

for_each(v1.begin(), v1.end(), mem_fun(&person::showperosn));

8.算法:

遍历算法:

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 (差集);