essential c++读书笔记3

第三章 泛型编程风格

STL主要由两种组件构成:1、容器:vector、list、set、map等类;2、是用以操作这些容器的所谓泛型算法,包括find(),sort(),replace(),merge()等
vector和list这两种容器是所谓的顺序性容器,会依次维护第一个、第二个等等元素,主要采用迭代操作
map和set这两种容器属于关联容器,关联容器可以让我们快速查找容器中的元素值。 key/value

3.1 指针的算数运算

主要任务:给定一个储存整数的vector,以及一个整数值。如果该值存在于vector内,就返回一个指针指向该值,反之返回0;

int *find(const vector<int> &vec,int value)
{
	for(int ix=0;ix<vec.size();++ix){
 		if(vec[ix]==value)
		 return &vec[ix];
      }
    return 0}

1、实现函数不仅可以处理整数,又可以处理任意类型?
使用模板函数

template <typename elemType>
int *find(const vector<elemType> &vec,const elemType value)
{
	for(int ix=0;ix<vec.size();++ix){
 		if(vec[ix]==value)
		 return &vec[ix];
      }
return 0}

2、怎么实现同一个函数能同时处理vector和array内的任意类型元素?
答:可以使用重载;
怎么编写一个函数,就解决该问题?主要是采用了指针的地址,使用指针地址的运算
分解为两个小问题?1、将array的元素传入find(),而非指明array;2、将vecotr的元素传入find()而不指明该vector。
1、当数组被传给函数,或是由函数中返回,仅有第一个元素的地址会被传递。int main(int *array){…}
可以使用下标的自增来对数组进行操作;
也可以使用地址的移动来操作数组
这样就可以将array替换出

template <typeneme elemtype>
elemType* find(const elemType *first,const elemType *last,const elemType &value)

2、将vecotr的元素传入find()而不指明该vector
可以和处理array方式一样,将一组用来表示“起始位置/结束地址”的参数传入find函数
但vector可以为空,所以得判断vector是否为空。可以定义函数

template <typename T>
inline elemType *begin(const vector<elemType> &vec)
{
	return vec.empty() ? 0 : &vec[0];
}
template <typename T>
inline elemType *end(const vector<elemType> &vec)
{
	return vec.empty() ? 0 : &vec[vec.size()];
}

3、怎么实现支持list类型?
list类是以一组指针相互链接:前向指针指向下一个元素,后向指针指向上一个元素。
实现方法是在底层的行为之上提供一层抽象,取代程序原本的“指针直接操作”。

使用标准容器

3.2泛型指针 iterator

抽象出来,这样不论是面对list还是vector,使用内置的运算符都是iterator内相关inline函数提供,可以实现基本移动功能。
使用标准容器
每一个标准容器都提供一个名为begin()的操作函数,可返回一个iterator(迭代器),指向第一个元素。
提领操作:取得“位于该指针所指内存地址上”的对象,在指针之前使用*号,便可以达到这个目的。

vector<string> svec;
//iterator语法
vector<string>::iterator iter = svec.begin();

此处iter被定义为一个iterator,指向一个vector,后者的元素类型为string。其初始值指向svec的第一个元素。::表示此itertor是位于string vector定义内的嵌套类型。

则改进后的find的泛型算法如下:

template<typename IteratorType, typename elemType>
IteratorType find(IteratorType first, IteratorType last, const elemType &value)
{
	for (; first != last; ++first) {
		if (value == *first) {
			return first;
		}
	}
	return last;
}

3.3 所有容器的共通操作

equality(==)和inequality(!=)运算符,返回true和false。
empty(): 判断容器是否为空
size(): 返回容器的大小
clear(): 删除所有元素
begin(): 返回一个iterator,指向容器的第一个元素
end(): 返回一个iterator,指向容器的最后一个元素的下一个位置
insert(): 将单个或某个范围内的元素插到容器内
erase(): 将容器内的单一元素或某个范围内的元素删除

3.4 使用顺序性容器

用来维护一组排列有序,类型相同的元素,vector和list是两个最主要的顺序容器。
vector以一块连续内存来存放元素,每个元素位置固定,插入操作效率低。适合数列,查询
list是以双向链接而非连续内存存储内容,可以执行前进或后退操作。list中每个元素都包含三个字段:value、back、front指针。适合插入
deque容器:和vector类似,但对于最前端元素的插入和删除,效率更高
定义容器,必须包含相应的头文件
定义容器的五种方式
1、空的容器 list slist; vector ivec;
2、产生特定大小的容器。每个元素都以默认值作为初值。list ilist(1024); vector svec(32);
3、产生特定大小的容器,并为每个元素指定初值 list ilist(10,,1); vector svec(32,“adsadas”);
4、通过一对iterator产生容器。 int ia[8] = {1,2,5,4}; vector fib(ia,ia+8);
5、根据某个容器产生新容器,复制原容器内的元素,作为新容器的初值。 list slist; list slist2(slist); //将slist复制给slist2

push_back()插入和pop_back()删除 末尾操作

insert()有四种变形:
1、iterator insert(iterator position,elemType value) 可将value插入position之前,返回一个iterator,指向被插入的元素。
2、void insert(iterator position,int count,elemType value) 可在position之前插入count个元素,这些元素都和value相同。
3、void insert(iterator position,iterator2 first,iterator2 last) 可在position之前插入first last所标示的各个元素。
4、iterator insert(iterator position) 可在position之前插入元素,初始值为默认值

3.5 泛型算法

头文件 #include
find() 无序集合,搜索范围由iterator[first,last]标出
binary_search() 用于有序集合的搜索。
count() 返回数值相符的元素数目
search() 比对某个容器内是否存在某个子序列。
max_element() 返回该范围的最大值 int max_value = max_element(vec.begin(),vec.end());
copy() 接收两个iterator。标出复制范围。 vector temp(vec.size()); copy(vec.begin(),vec.end(),temp.begin());
sort() 排序 sort(temp.begin(),temp.end());

3.6 设计泛型算法

任务
用户给一个整数,返回一个新vector,其中内含原vector之中小于10的所有数字。就是将小于10的数拿出来。
常用方法:

vector<int>  less_than_10(const vecotr<int> &vec)
{
    vector<int> nvec;
    for(int ix = 0;ix<vec.size();++ix)
	{
             if(vec[ix] < 10)
		nvec.push_back(vec[ix]);
	}
}

如果是小于11:让用户指定某个上限值
vector less_than(const vector &vec,int less_than_val);

允许用户指定不同的比较操作,大于、小于、等于
解法1:以函数调用来取代less_than运算符。

vector<int> filter(const vector<int> &vec,int filter_value,bool (*pred)(int,int));

这样就可以定义许多关系。bool less_than(int v1,int v2){return v1<v2?true:false;}
完整解法

vector<int> big_vec;
int value;
vector<int> it_10 = filse(big_vec,value,less_than);

vector<int> filter_ver1(const vector<int> &vec,int filter_value,bool (*pred)(int,int))
{
	vector<int> nvec;
	
	for(int ix=0;ix<vec.size();++ix)
	{
		if(pred(vec[ix],filter_value))
			nvec.push_back(vec[ix]);	
	}
return nvec;
}

那么怎么去掉for循环呢?
使用泛型算法 find() 查找有几个等于val的值

int count_occurs(const vector<int> &vec,int val)
{
	vector<int>::const_iterator iter = vec.begin();
	int occurs_count = 0;
	while((iter  = find(iter,vec.end(),val)) != vec.end())    //迭代查找vec中等于val的值
	{
		++occurs_count;
		++iter;	
	}
	return occurs_count;
}

function object
是某种class的实例化对象,这类class对function call运算符做了重载操作。主要是为了效率。
标准库实现定义的function obj,分为算数运算、关系运算、逻辑运算
六个算数运算:plus 加、minus 减、negate 非、multiplies 乘、divides 除、modules
六个关系运算:less 小于、 less_equal 小于等于、 greater 大于、 greater_equal 大于等于、 equal_to 等于、 not_equal_to 不等于
三个逻辑运算:logical_and &&、 logical_or || 、 logical_not !

要想使用function object,要包含相关头文件
#include

function object adapter
想要比较某个vector中的数与一个固定数的大小,问题:怎么将参数绑定至用户指定的数值
标准库提供的adapter就可以
所谓binder adapter(绑定适配器)会将function object的参数绑定至某特定值,使biary(二元)function object转化为一元。
提供了两个:bindlst:将指定值绑定至第一操作数;bind2nd:将指定值绑定至第二操作数

vector<int> filter(const vector<int> &vec,int val,less<int> &lt)
{
	vector<int> nvec;
	vector<int>::const_iterator iter = vec.begin();
	//less<int> 会将每个元素拿来和val比较
	while((iter  = find_if(iter,vec.end(),bind2nd(lt,val))) != vec.end())    //迭代查找vec中小于val的值
	{
		nvec.push_back(*iter);
		iter++;	
	}
	return nvec;
}

怎么使函数更泛型
使用template

template<typename InputIterator,typename OutputIterator,typename Elemtype,typename Comp>
OutputIterator
filter(InputIterator first,InputIterator last,OutputIterator at,const Elemtype &val,Comp pred)
{
	while((first = find_if(first,last,bind2bd(pred,val))) != last)
		{
			cout <<"found value:" << *first <<endl;
			//执行assign操作
			*at++ = *first++;		
		}
	return at;
}

另外一种adapter是所谓的negator,它会对function object的真伪值取反。 not1 可对unary(一元) function object的真伪取反;not2 对binary(二元)取反

这一节的思路
1、由一个找出在vector内小于10的所有元素出发。 太死板,只能确定的小于10

vector<int>  less_than_10(const vecotr<int> &vec)
{
    vector<int> nvec;
    for(int ix = 0;ix<vec.size();++ix)
	{
             if(vec[ix] < 10)
		nvec.push_back(vec[ix]);
	}
}

2、加入一个val,让用户来指定某个数字。 只能是小于的比较方式*/

vector<int> less_than(const vector<int> &vec,int less_than_val)
{
    vector<int> nvec;
    for(int ix = 0;ix<vec.size();++ix)
	{
             if(vec[ix] < less_than_val)
		nvec.push_back(vec[ix]);
	}
}

3、想要修改比较方式,加一个新参数:一个函数指针,让用户指定比较方式

vector<int> big_vec;
int value;
vector<int> it_10 = filse(big_vec,value,less_than);

vector<int> filter_ver1(const vector<int> &vec,int filter_value,bool (*pred)(int,int))
{
	vector<int> nvec;
	
	for(int ix=0;ix<vec.size();++ix)
	{
		if(pred(vec[ix],filter_value))
			nvec.push_back(vec[ix]);	
	}
return nvec;
}

函数指针定义着各种比较方式

4、引入function object概念,使我们得以将某组行为传给函数,
5、最后将函数以function template的方式重新实现。

template<typename InputIterator,typename OutputIterator,typename Elemtype,typename Comp>
OutputIterator
filter(InputIterator first,InputIterator last,OutputIterator at,const Elemtype &val,Comp pred)
{
	while((first = find_if(first,last,bind2bd(pred,val))) != last)
		{
			cout <<"found value:" << *first <<endl;
			//执行assign操作
			*at++ = *first++;		
		}
	return at;
}

3.7 map使用

map 被定义为 一对数字,key-value

#include <map>
#include <string>
map<string,int> words;

输入key/value的最简单方式: words[“vermeer”] = 1;
**想要查询map是否存在某个key。**有三种方法:
1、把key当成索引使用:

int count = 0;
if(!(count = words["vermeer"]))
//vermeer并不存在于words map中

缺点:假设"vermeer"不在words map中,这样的搜索方式会将它放在map中,而其value将是0。

2、map查询法:利用map的find()函数(不是泛型算法的find()函数),将key传入find()并调用。

words.find("vermeer");

如果key已放入其中,find()会返回一个iterator,指向key/value形成的一个pair,反之返回end();

int count = 0;
map<string,int>::iterator it;

it = words.find("vermeer");
if(it ! words.end())
    count = it -> second;

3、利用map的count()函数,count()函数会返回某特定项在map内的个数

int count = 0;
string search_word("vermeer");

if(! words.count(search_word))
    count = words[search_word];

3.8 set

set是由一群key组成,如果我们想知道某值是否存在与某个集合内,就可以使用set。

#include <set>
#include <string>
set<string> word_exclusion;

比较:word_exclusion.count(tword) 检测tword是否在其中
插入:iset.insert(ival);
插入某一个范围的值:iset.insert(vec.begin(),vec.end());

3.9 使用Iterator Inserter

在3.6中while((first = find_if(first,last,bind2bd(pred,val))) != last)

{
			cout <<"found value:" << *first <<endl;
			//执行assign操作
			*at++ = *first++;		
		}

必须保证目标容器足够大。都是提前定义好大小,不能随意增加
怎么才能避免使用容器的assignment运算符?
1、back_inserter() 会以容器的push_back()函数取代assignment运算符。
2、inserter() 会以容器的insert() 函数取代assignment运算符。接收两个参数,一个容器,一个iterator,指向容器内的插入操作起点。
3、front_inserter() 会以容器push_front()函数取代assignment运算符。只适用于list和deque。

#include <iterator>

3.10 使用iostream Iterator

从标准输入设备读取一串string,将其存在vector内,排序,最后输出。
使用istream_iterator

#include<iterator>

first和last表示元素范围

first:  istream_iterator<string> is(cin);
last :  istream_iterator<string> eof;

传递: copy(is,eof,back_inserter(text));

输出: ostream_iterator<string> os(cout," ");

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值