您的位置:首页 > 其它

泛型算法与容器的关系

2016-08-28 10:40 176 查看

1.前言

c++中的容器支持插入删除操作,支持获取第一个元素的迭代器和超过元素末端的下一迭代器操作......但是却不支持获取指定元素操作,比较操作,排序操作......因为这些操作都是和算法有关的,在C++中将它们独立出来,说明算法和具体的容器和具体的数据类型无关,只和自身的元素相关。比如find函数,用于查找指定的值,看下面两段代码:

vector<int> vect;
//往vect添加元素
vector<int>::iterator iter=find(vect.begin(),vect,end(),search_value);

list<int> lis;
//添加元素
list<int>::iterator iter=find(lis.begin(),lis.end(),search_value);

int a[5]={1,2,3,4,5};
int *result=find(a,a+5,search_value);


我们可以对于find函数来说,它对于容器的类型和数据类型都没有要求,即它只与自身的算法实现有关,和容器类型无关。除了迭代器之外,我们可以发现,指针也可以用于find函数的实参。所以对find函数来说只有几个要求:

①、数据类型必须是可以比较的,这样才可以判断是否是所查找的值。

②、必须给定一段范围,必须知道从哪里开始从哪里结束。

③、如果找到该值,就返回指向该值的指针或者迭代器,否则返回第二个参数即最后一个元素的下一个元素的地址。

在C++中提供了泛型算法,它包含在algorithm头文件中,以及一个泛化的算数算法,它包含在numeric头文件中。

2、只读算法

只读算法只会读取范围内的元素,而不对范围内的元素进行任何操作。前面的find函数就是一个例子,另一个就是accumulate函数,定义在numeric头文件中,它使用数据类型的加法操作进行将某段元素范围的元素相加。考虑下面的代码:

vecotr<int> vectInt;
vector<string> vectString;

int sum=accumulate(vectInt.begin(),vectInt.end(),0);

string result=accumulate(vectString.begin(),vectString.end(),string(""));


上述尝试对int和string元素进行相加操作,对于sum的值,它是以0为起始值,并把vectInt标记的元素范围内所有值的相加。对于accumulate来说,它并不知道要添加的元素的类型是什么,因此它是通过第三个参数来判断执行加操作符的意义的。比如result的结果则是,获取了一端拼接起来的字符串。注意这里不能替换为字符串字面值,因为字符串字面值是const char*类型,这样会导致编译错误。

在numeric头文件,还有很多find系列的函数,比如find_fisrt_of();此函数接受四个参数,分别标志两段数据范围,它的作用用于查找在这两段标志的区间里面重合的元素,如果找到了就返回第一段范围内第一个重合元素的迭代器,否则就返回第一段范围内最后一个元素的下一个元素的迭代器。看如下代码:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace::std;

int main()
{

vector<string> vect;
vect.push_back("harden");
vect.push_back("james");
vect.push_back("howard");
vect.push_back("harden");
vect.push_back("wade");

vector<string> vect1(vect);
vect1.erase(--vect1.end());

vector<string>::iterator it = vect.begin();
int count = 0;

while ((it = find_first_of(it, vect.end(), vect1.begin(), vect1.end())) != vect.end())
{
count++;
it++;
}
cout << count << endl;
system("pause");
return 0;
}


上述代码会打印出4,因为在第一段范围内,每次查找到第一个元素就会缩小到下一个元素,这样就把第一段范围内所有的与第二段范围重合的元素查找出来了。

3、利用算法排序元素

C++提供了排序算法,可用于排序容器内的元素,比如sort,此方法有两个版本,一个是接受一对迭代器作为实参(此版本的方法默认是使用<比较符比较对象),另外一个是除了一对迭代器之外,还接受一个函数名称。对该函数是由要求的,比如如果排序的对象是vector<int>型,则该函数的返回值必须是bool,形参必须是两个int型对象的引用。

注意,任何算法都不会删除或修改添加容器元素的元素数据。因此C++还提供了一个unique算法,可以将所有容器中出现多次的内容都排到容器末端,并且返回指向第一个相同元素的迭代器。通过它,我们就可以避免重复对容器中相同的元素进行操作。

看下面的代码:

vector<string> vect;
vect.push_back("harden");
vect.push_back("james");
vect.push_back("howard");
vect.push_back("harden");
vect.push_back("wade");
/*
对容器内元素进行排序
*/
vect.push_back("james");
//sort 元素会对元素内的元素进行<排序
sort(vect.begin(), vect.end());

cout << "输出从小到大排序后的内容:";
for (vector<string>::iterator it = vect.begin(); it < vect.end(); ++it)
{
cout << *it<<" ";
}
cout << endl;

//此函数会将容器内的元素的相同元素都排到容器的末端,然后返回指向第一个相同元素的迭代器。即在此迭代器之前的元素都是唯一的
vector<string>::iterator uniqu_end = unique(vect.begin(), vect.end());
cout<<"输出不包含相同元素的容器内容:";
for (vector<string>::iterator it = vect.begin(); it < uniqu_end; ++it)
{
cout << *it << " ";
}
cout << endl;

//可使用erase将相同元素删掉。
vect.erase(uniqu_end, vect.end());
cout << "输出删除元素后的内容:";
for (vector<string>::iterator it = vect.begin(); it < vect.end(); ++it)
{
cout << *it << " ";
}
cout << endl;

//使用sort的时候,也可以自带排序算法函数
sort(vect.begin(), vect.end(), isLonger);
cout << "输出从大到小排序元素后的内容:";
for (vector<string>::iterator it = vect.begin(); it < vect.end(); ++it)
{
cout << *it << " ";
}
cout << endl;


isLonger函数如下:

bool isLonger(string &one, string &two)
{
return one > two;
}


输出结果:



4.迭代器综述

我们一般接触的迭代器都是正向迭代器,其实C++还提供了正向迭代器,iostream迭代器,插入迭代器。如下:



有关算法是不和容器捆绑的,除了前面提到的算法之外,还有很多不常用的算法,希望读者有兴趣的多去了解。

---------文章写自:HyHarden---------

--------博客地址:http://blog.csdn.net/qq_25722767-----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  泛型算法 容器