C++ STL和泛型编程(一)

STL:Standard Template Library(标准模板库)
GP:Generic Programming(泛型编程)

STL是GP最成功的作品!!

一、STL六大部件

  • Allocators(分配器)
  • Containers(容器)
  • Algorithms(算法)
  • Iterators(迭代器)
  • Adapters(适配器)
  • Functors(仿函式)

六大部件的关系如图:
在这里插入图片描述

1.首先接触到的是Containers,而容器要数据,数据需要占用内存,
2.所以又涉及到分配内存的问题,所以Allocator就是给容器分配对应存放元素的内存的分配器。
3.而需要对存放容器的里的数据元素进行操作时,虽然容器是一个模板类且有一部分操作是通过容器内的函数进行操作的,但大部分操作都是被独立出来变成一个一个模板函数放在容器外部的即Algorithms。
(注意:在面向对象(OO)这种编程技巧时,在定义类时是鼓励将数据放在类里面,处理数据的函数也放在类内,从而形成一个class;但在STL中,则是鼓励数据放在容器中,处理数据的函数放在算法中,分开的,所以设计方式跟面向对象的不同。)
4.当算法要去处理容器如List中的数据时,则需要通过Iterator(即一种泛化的指针)迭代器这个中间的桥梁去找到这些存放容器里的数据而进行相应的操作处理。
5.Functors用来处理一些类与类之间的操作,实现一些类似函数的操作功能,另外Adapters用来帮助Containers\Iterators\Functors作一些转换。

在这里插入图片描述
首先使用vector容器时 < >表示模板,需要指定对应模板参数 ,第一参数表示需要指定的元素参数类型(不能省略),第二个参数则是允许指定分配器来给容器放置其中的元素分配相应的内存(可省略,不指定则调用默认的)。而vector<int, allocator<int>> vi(ia, ia+6)中的赋值形式,是因为容器类的定义中,对赋值的定义不同方式如vi(ia, ia+6),即将数组的头跟尾当成初值赋值给vector。

接下来便是要对数据进行操作,count_if()便是个算法,对vector里的数据进行操作,在满足给出的条件下计数,而算法又需通过Irerators去找到存放于vector的对应数据元素,所以传入参数迭代器【泛化的指针】vi.begin()和vi.end(),即要操作的数据元素范围在哪到哪;而第三个参数则是对应处理的条件,less<int>(),是一个仿函数表示小于某某对象;而条件是要求找出在这些元素中小于40的,所以需要绑定ess<int>()操作的对象,即用上了Adapter适配器bind2nd()绑定其第二传入参数为40;同理notl()也是一个函数适配器,作用是将内部结果取反,即求得大于等于40的结果。所以notl(bind2nd(less<int>(), 40))对应于if条件。以上便是混合使用六大部件的例子。

二、容器的“前闭后开”区间

所有容器都提供begin()和end()两个函数:
这里注意end()函数指向的是容器里最后一个元素的再下一位,即调用end()函数代表的迭代器(泛型指针)其内存地址是指向容器里最后一位元素的下一个位置,因此是在容器范围外的
所以*(c.begin())是可以的,(c.end())是不正确的*,因为其得到的泛型指针的解引用是得到灰色的那块内容,其是在容器外的而不是容器里的一部分,所以*(c.end())这样取不知道会取到容器外的什么东西。
在这里插入图片描述由上便可知,对于一个容器的清空,可以令c.begin() = c.end(),这样就意味着,容器的第一个起始地址指向容器外的地址,相当于容器长度为0,即容器清空了。

list<string> c;
...
list<string>::iterator ite;  // 一般的迭代器即泛型指针的声明(注明容器的类型即相应的容器模板参数)
ite = ::find(c.begin(), c.end, target);

auto ite1 = ::find(c.begin(), c.end, target); // 新特性的迭代器即泛型指针的声明,用auto关键字让编译器自己推导。

三、容器结构与分类

在这里插入图片描述

- Sequence Containers(序列式容器):

  • Array(新增的):固定大小空间的
  • Vector:大小是动态变化的,由allocator自动以前一次内存大小两倍的形式扩充
  • Deque:双向的
  • List:双向的,且在内存里不是连续的
  • Forward-List:单向的List

- Associative Containers(关联式容器):

特征:由key和value组成的,查找快速!

  • Set:key和value是同一个,且不可出现相同的元素
  • Multiset:里面的元素可以重复出现
  • Map:key和value是分开的,且不可出现相同的元素
  • Multimap:里面的元素可以重复出现

- Unordered Containers(未定序容器):其内部位置会动态发生变化的

  • Unordered Set:key和value是同一个,且不可出现相同的元素
  • Unordered Multiset:里面的元素可以重复出现
  • Unordered Map:key和value是分开的,且不可出现相同的元素
  • Unordered Multimap:里面的元素可以重复出现

其是通过Hash Table 来实现的,每个bucket里面是一条separate chaining,元素的存放是通过一些计算,看挂到哪条链表上的:如容器有20个空间,元素A经过计算放到第3个位置,B经过计算也放到第3个位置,则此时在第3个位置便会形成一条链表,A->B…而当某条链当链上的元素过多即某位置链表过长时,此时则会进行重新分配(因为链表查找元素时,如果链表长度过长会影响链表的查找速度),所以称之为unordered。

四、容器分类与各种测试

测试程序之辅助函数

using std::cin;
using std::cout;
using std::string;

long get_a_target_long(){
   
	long target = 0;
	cout << "target (0~" << RAND_MAX << "): ";
	cin >> target;
	return target;
}

string get_a_target_string(){
   
	long target = 0;
	char buf[10];
	cout << "target (0~" << RAND_MAX <<
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值