概述
目录
一.指针的算术运算
二.了解Iterator(泛型指针)
三.所有容器的共通操作
四.使用顺序性容器
五.使用泛型算法
六.设计泛型算法
七.map和set
八.使用iostream iterator
一.指针的算术运算
利用指针的算术运算完成find()函数的c++代码:
#include<iostream>
#include<vector>
using namespace std;
template<typename T1,typename T2>
T1* find(const T1* first, const T1* last, const T2 value) //第一和第二个参数用于表示所搜索的容器范围(两个指针表示范围),第三个参数为在容器中搜索的值。
{
if (!first || !last)
{
return 0;
}
for (; first != end; first++) //end指针所指的位置应该是容器最后一个元素的下一个地址,这样才可以保证容器中的所有元素都经过了扫描
{
if (*first == value)
{
return first;
}
}
return 0;
}
int main()
{
int arr1[5] = { 5,3,10,9,6 };
int* p1 = find(arr1, arr1 + 5, 9); //第一个参数是容器的首地址,第二个参数是容器的最后一个元素的下一个地址,即为尾地址
if (p1 != (arr1 + 5))
{
cout << "找到了,地址为:" <<p1<< endl;
}
else
{
cout << "没找到" << endl;
}
system("pause");
return 0;
}
知识点:
1.*(array+i) 与 array[i]的效果相同,下标操作就是将array的起始地址加上索引值,产出某个元素的地址,然后该地址再被提纲以返回元素值。
2.对于数组最后一个元素的下一个地址,只能对此地址进行比较,而不能用来读取和写入。
eg:
int ia[5] = {1,2,3,4,5};
int a1 = *(ia+6);//错误,对最后一个元素的下一个地址不能用来读取和写入
find(ia,ia+5,ia[3]);//正确,对最后一个元素的下一个元素可以用来比较
3.array数组不能为空,但是vector数组可以为空,同时vector类含有函数“ .empty "来判断一个vector数组是否为空。
4.对于list容器,不适用于指针的算术运算,因为指针的算术运算必须首先假设所有元素都存储在连续的空间里,但是list容器不存储在连续的空间里,其每个节点都有三个值:front指向上一个节点,next指向下一个节点,value表示节点的值。
参考文章:C++ list(STL list)容器完全攻略(超级详细) (biancheng.net)
5.list容器适用于存储常需要修改(插入删除操作)而不常读取的数据,而vector和array容器适用于存储常读取而不常修改(插入删除操作)的数据。
二.了解Iterator(泛型指针)
通过iterator指针实现find()函数的C++代码:
#include<iostream>
#include<vector>
#include<list>
#include<iterator>
using namespace std;
const int asize = 5;
template<typename IteratorType,typename elemType>
IteratorType find1(IteratorType first, IteratorType last,const elemType value) //同理,第一个参数是容器的第一个元素的地址,而第二个参数是容器最后一个元素的下一个地址
{
for (; first != last; first++)
{
if (*first == value)
{
return first;
}
}
return last; //此地址只可以用来比较,而不能用来读取和写入
}
int main()
{
int ia[asize] = { 1,5,10,20,95 };
vector<int> ivec(ia, ia + asize);
list<int>ilist(ia, ia + asize);
int* pia = find1(ia, ia + asize, 20);
if (pia != 0)
{
cout << "找到了" << endl;
}
vector<int>::iterator iter1;
iter1 = find1(ivec.begin(), ivec.end(), 100);
if (iter1 != ivec.end())
{
cout << "找到了" << endl;
}
list<int>::iterator iter2;
iter2 = find1(ilist.begin(), ilist.end(), 95);
if (iter2 != ilist.end())
{
cout << "找到了" << endl;
}
system("pause");
return 0;
}
支持两种形式:一对指针或是一对指向某种容器的iterator
知识点:
1.对于不同类型的iterator指针,其运算符进行的操作是根据iterator class内相关的inline函数提供的。
eg:
//first是一个iterator泛型指针
first++;
//如果first是vector的泛型指针,则first++则是将目前的地址加上一个元素的大小。
//如果first是list的泛型指针,则first++则是会沿着list的指针前进到下一个元素。
2.每个标准容器都提供有一个begin()的操作函数,可返回一个iterator指向第一个元素, 也提供一个end()的操作函数指向最后一个元素的下一位置。
3.定义iterator:需要提供两个参数
(1).迭代对象(即为某个容器)的类型,用来决定如果访问下一元素。
(2).iterator所指的元素类型,可以决定iterator提领操作的返回值。
//iterator<vector,string> iter1;
//iterator<list,int> iter2;
//实际语法:
vector<string>::iterator iter1;
list<int>::iterator iter2;
4.const_iterator:只可读而不可进行其他操作
vector<string>::const_iterator iter;
5.通过iterator指针访问容器内的操作:间接访问( -> )
vector<string>::iterator iter;
int size = iter->size();
三.所有容器的共通操作
①." == " 和 "!="运算符,返回true或false。
②."="运算符,将某个容器复制给另一个容器。
③.empty()会在容器无任何元素时返回true,否则返回false。
④.size()返回容器内目前持有的元素个数。
⑤.clear()删除所有元素。
⑥.begin()返回一个iterator指向容器的第一个元素,end()返回一个iterator指向容器的最后一个元素的下一位置。
⑦.insert()将单一或某个范围内的元素插入容器内,erase()将容器内的单一元素或者某个范围内的元素删除。
四.使用顺序性容器
1.顺序容器用来维护一组排列有序、类型相同的元素。
2.顺序性容器种类:
①.vector:以一块连续内存来存放元素,其中的每个元素都被存储在距离起始点的固定偏移位置上,随机访问效率较高,而对于任意位置的插入或删除操作缺乏效率。
②.list:以双向链接而非连续内存来存储内容,对于任意位置的插入或删除操作都颇具效率,但是随机访问操作则效率不高。(存放元素的内存不连续,因此不支持iterator的偏移运算)
③.deque:以连续内存来存放元素,与vector类似,但同时对于最前端和最后端元素的插入、删除操作效率更高。
3.定义顺序性容器方法:
①.产生空容器:
list<string> slist;
vector<string> ivec;
②.产生特定大小的容器,每个元素都以其默认值作为初值。(eg.int和double类型的默认值为0)
vector<int> ivec(10);
list<string> ilist(20);
③.产生特定大小的容器,并为每个元素指定初值。
vector<int> ivec(1024,10);
list<double> ilist(10,5.20);
④.通过一对iterator产生容器。这对iterator用来标示一整组作为初值的元素的范围。
int ia[5] = {1,2,3,4,5};
vector<int> ivec(ia,ia+5);
list<int> ilist(ia,ia+5);
⑤.根据某个容器产出新容器。复制原容器内的元素,作为新容器的初值。
list<string> ilist1;
list<string> ilist2(ilist1);
4.三种顺序性容器都有push_back()和pop_back()函数,但只有list和deque容器拥有push_front()和pop_front()函数。
5.insert函数的变形函数(除push_front()和push_back()外)
①.
iterator insert(ierator position,elemType value);
将value值插入position之前,同时会返回一个iterator指向被插入的元素。
②.
void insert(iterator position,int count,elemType value);
在position前插入count个元素,这些元素的值都和value的相同。
③.
void insert(iterator position,iterator2 first,iterator2 last);
可在position之前插入[first,last)所标示的各个元素。
④.
iterator insert(iterator position);
在position之前插入元素,元素的初值为其所属属性的默认值。
6.erase()函数的变形函数(除pop_front()和pop_back()外)
①.
iterator erase(iterator position);
删除position所指的元素。
②.
iterator erase(iterator first,iterator last);
删除[first,last)范围内的元素。
五.使用泛型算法
1.使用泛型算法需要包含对应的头文件"algorithm";
#include<algorithm>
2.常用泛型搜索算法:
①.find()用于搜索无序集合中是否存在某值。搜索范围由iterator[first,last)标出。如果找到目标, find()会返回一个iterator指向该值,否则返回一个iterator指向last。
iterator find(iterator first, iterator last, elemType value);
②.binary_search()用于有序集合的搜索。如果搜索到目标则返回true,否则返回false。binary_search比find()更有效率。
bool binary_search(containerType<elemType> name, elemType value);
③.count()返回数值相符的元素数目。
④.search()比对某个容器内是否存在某个子序列。例如给定序列{1,3,5,7,2,9},如果搜索子序列{5,7,2},则search()会返回一个iterator指向子序列起始处。如果子序列不存在,就返回一个iterator指向容器末尾。
3.取得数列最大元素值:max_element()。将一对iterator传给max_element(),它会返回该范围内的最大值。
elemType max_element(iterator first,iterator last);
4.复制容器:copy()。将一对iterator传给copy()标示出复制范围,第三个iterator指向复制行为的目的地。
void copy(iterator1 first,iterator1 last,iterator2 begin);
六.设计泛型算法
泛型算法filiter()的C++代码:
#include<iostream>
//#include<fuctional> //使用function objectL less<int>
#include<vector>
#include<algorithm> ///使用泛型算法find_if()
using namespace std;
template<typename InputIterator, typename OutputIterator, typename ElemType, typename comp>
OutputIterator filter(InputIterator first, InputIterator last, OutputIterator at, const ElemType& value, comp pred) //参数分别为传入容器的范围,传入容器的首地址,用于比较的值,比较类型函数
{
while ((first = find_if(first, last, bind2nd(pred, value))) != last)
{
cout << "found value: " << *first << endl;
//将过滤后的数据放到新的容器,同时更新相应位置:
*at++ = *first++;
}
}
int main()
{
const int elem_size = 8;
int is[ elem_size ] = { 12,8,43,0,66,21,3,7 };
vector<int> ivec(elem_size);
cout << "过滤数组中小于8的值:" << endl;
filter(is, is + elem_size, ivec.begin(), elem_size,less<int>());
system("pause");
return 0;
}
知识点:
1.若要使用事先定义的function object,需包含头文件:#inclucde<funcitional>
(visual studio 2022中已无法打开源文件<fuctional>)
其中包括:
①.六个算术运算:plus<type>,minus<type>,multiplies<type>,divides<type>,negate<type>,modules<type>。
②.六个关系运算:less<type>,less_equal<type>,greater<type>,greater_equal<type>,equal_to<type>,not_equal_to<type>。
③.三个逻辑运算,分别对应&&、||、!:logical_and<type>,logical_or<type>,logical_not<type>。
2.适配器adapter:
①.binder adapter:使binary(二元)fuction object转化为unary(一元)fuction object。
(1).bind1st:将指定值绑定至第一操作数。
bind1st(less<int>,val);
//相当于: val<
(2).bind2nd:将指定值绑定至第二操作数。
bind2nd(less<int>,val);
//相当于 <val
②.negator adapter:对function object的真伪值取反。
(1).not1可对unary function object的真伪值取反。
not1(bind2nd(less<int>,value));
//小于取反得到大于或等于
(2).not2可对binary function object的真伪值取反。
③.insertion adapter: 使用需要包含头文件<iterator>
不能在array上使用,因为array不支持元素插入操作
可以对为设置大小的容器进行插入操作,但不能进行赋值操作
(1).back_inserter()会以容器的push_back()函数取代assignment运算符,参数为复制的目标容器。
(2).inserter()会以容器的insert()函数取代assignment运算符,接受两个参数,一个是复制的目标容器,另外一个是iterator指向容器内的插入操作起点。
(3).front_inserter()会以容器的push_front()函数取代assignment运算符,参数为复制的目标容器。同时这个inserter只适用于list和deque。
filter(ivec.begin(),ivec.end(),back_inserter(ivec2),elem_size,greater<int>);
//第三个参数从最初的ivec2变为了back_inserter(ivec2)
//此操作使push_back()函数替代assignment运算符将元素复制到ivec2容器中
七.map和set
1.使用map和set分别需要包含头文件<map>和 <set>。
2.使用map:
(1).map被定义为一对数值:
map<key,value> mapname;
其中的key通常是个字符串,扮演索引的角色,value则是key对应的值。
(2).map有两个member,分别为first指向key,second指向value:
map<string,int> m1;
map<string,int>::const_iterator it = m1.begin();
it->first; //key
it->second; //value
(3).查询某个map内是否存在某个key:
①.把key当作索引使用:
int count = 0 ;
if(!(count = words["vermeer"]));
原理:若map中不存在某个key,则会将此key放到map中并获得默认值0。
②.通过map的find()函数:
map<string,int>::iterator::it = words.find("vermeer");
原理:如果key在map中,则会返回一个iterator指向key/map形成的一个pair,如果key不在map中则会返回end()。
③.通过map的count()函数:
if(words.count("vermeer"));
原理:count()函数返回key项在map内的个数。
3.使用set
(1).set由一群key组合而成:
set<string> iset;
(2).set的insert()函数:
①加入单一元素:使用单一参数的insert():
iset.insert(ival);
②加入某个范围的元素,使用双参数的insert():
iset.insert(vec.begin(),vec.end());
(3).set元素皆依据其所属类型默认的less-than(递增)运算符进行排列。
4.任何一个key在map和set中最多只会有一份,如果需要储存多份相同的key值,则必须使用multimap和multiset。
八.使用iostream iterator
#include<iostream>
#include<iterator> //istream_iterator, ostream_iterator
#include<algorithm> //copy(),sort()
#include<vector>
#include<string>
using namespace std;
int main()
{
istream_iterator<string> is(cin); //first
istream_iterator<string> eof; //end
vector<string> text;
//输入:
cout << "输入:" << endl;
copy(is, eof, back_inserter(text));
sort(text.begin(), text.end());
ostream_iterator<string> os(cout, " ");
//输出:
cout << "输出:" << endl;
copy(text.begin(), text.end(), os);
system("pause");
return 0;
}
知识点:
1.包含头文件<iterator>使用iostream iterator类 -- istream_iterator和ostream_iterator,分别支持单一类型的元素读取和写入。
2.需要提供一对iterator:first和last用来表示元素范围:
指定istream对象即为first
不指定istream对象即为end-of-file
istream_iterator<string> is(cin); --- first; //指定istream对象即为first
istream_iterator<string> eof; --- last; //不指定istream对象即为end-of-file
3.创建ostream_iterator来标示字符串元素的输出位置:
ostream_iterator<string> os(cout," "):
第二个参数可以是C-style字符串,也可以是字符串常量,用来表示各个元素被输出时之间的分隔符。
4.使用copy()来进行输入和输出:
输入:
copy(is,eof,back_inserter(text));
输出:
copy(text.begin(),text.end(),os)
5.使用iostream_iterator完成从文件中读取,写到文件中去:
将istream_iterator绑定至ifstream object,并将ostream_iterator绑定至ofstream object。
ifstream in_file("input_file.txt");
ofstream out_file("output_file.txt");
istream_iterator<string> is(in_file); //first;
istream_iterator<string> eof; // last;
ostream_iterator<string> os(out_file," ");
最后
以上就是强健小蝴蝶为你收集整理的泛型编程风格的全部内容,希望文章能够帮你解决泛型编程风格所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复