晓石头的博客
邮箱:178673693@qq.com
转载请注明出处,原文链接:http://blog.youkuaiyun.com/QIULANZHU/article/details/50520649
一、共同性
1.值的语意
所有容器提供的都是值的语意,而不是引用的语意。
容器执行插入元素的动作,背后实现是拷贝的动作。
STL容器存储的元素必须是能够被拷贝的,故元素需要提高拷贝构造函数
2.构造函数
每个容器都提供了一个默认构造函数和一个默认拷贝构造函数。
vector<int> cecIntA;//默认构造函数
vector<int> vecIntB(vecIntA);//调用拷贝构造函数
3.容器大小
与大小相关的操作方法(c代表容器):
c.size();//放回容器中元素的个数
c.empty();//判断容器是否为空
4.比较操作(c1,c2代表容器)
c1==c2
c1!=c2
二、各个容器的使用时机
1、vector与deque的比较:
①.vector.at()比deque.at()效率高
vector.at(0),开始位置是固定的
deque的开始位置却是不固定的
②.如果有大量释放操作的话,vector花的时间更少,这和二者的内部实现有关。。
③.deque支持头部的快速插入与快速移除,这是deque的优点。
2、list---适合于频繁的不确定位置元素的添加移除操作。
3、set---分数排行榜,自动排序
4、map---有关键字的排序
三、算法(Algorithm)的介绍
1.算法部分主要由头文件<algorithm>,<numeric>和<functional>组成。
<algorithm>是所有STL头文件中最大的一个,其中常用到的功能范围涉及到比较 、交换、查找、遍历、复制、修改、反转、排序、合并等等。
2.<numeric>体积很小,只包含几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。
3.<functional>中则定义了一些模板类,用以声明函数对象。
4.查找算法的选择
首先,选择查找算法时,区间是否排序是一个至关重要的因素,可以按是否需要排序区间分为两组:
A. count,find
B. binary_search,lower_bound,upper_bound,equal_range
A组不需排序区间, B组需要排序区间。
当一个区间被排序,优先选择B组,因为他们提供对数时间的效率。而A则是线性时间。
另外A组B组所依赖的查找判断法则不同,A使用相等性法则(查找对象需要定义operator==), B使用等价性法则(查找对象需要定义operator<,必须在相等时返回false)。
1、常用的查找算法
相邻重复元素查找:
adjacent_find(beg,end);//在[beg,end)区间,查找一对相邻重复元素,找到则范围这对元素中第一个元素的迭代器。否则返回pass-the-end
例:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool greater(int iNum)
{
if(iNum >3)
{
return true;
}
else
{
return false;
}
}
int main()
{
int data[] = {1,2,4,5,6,8,6,11};
vector<int> vecInt(data, data+sizeof(data)/sizeof(int));
int iCount = count_if(vecInt.begin(), vecInt.end(), greater);
cout<<iCount<<endl;
return 0;
}
折半查找:
bianry_search();//在有序序列中查找value,找到则返回true。注意:在无序序列中,不可使用。
例:
int data[] = {1,2,4,5,6,6,8,11};
vector<int> vecInt(data, data+sizeof(data)/sizeof(int));
bool bFind = binary_search(vecInt.begin(), vecInt.end(), 8);
查找指定元素个数:
count();//利用等于操作符,把标志范围内的元素与输入值比较,返回相等的个数。
例:
int data[] = {1,2,4,5,6,8,6,11};
vector<int> vecInt(data, data+sizeof(data)/sizeof(int));
int iCount = count(vecInt.begin(), vecInt.end(), 6);
查找满足条件的元素个数:
count_if:();//利用输入的函数,对标志范围内的元素进行比较操作,返回结果为true的个数。
例:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool greater(int iNum)
{
if(iNum >3)
{
return true;
}
else
{
return false;
}
}
int main()
{
int data[] = {1,2,4,5,6,8,6,11};
vector<int> vecInt(data, data+sizeof(data)/sizeof(int));
int iCount = count_if(vecInt.begin(), vecInt.end(), greater);
cout<<iCount<<endl;
return 0;
}
条件查找
find_if();//查找满足条件的元素位置
例:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool greater(int iNum)
{
if(iNum >3)
{
return true;
}
else
{
return false;
}
}
int main()
{
int data[] = {1,2,4,5,6,3,6,11};
vector<int> vecInt(data, data+sizeof(data)/sizeof(int));
vector<int>::iterator it = find_if(vecInt.begin(), vecInt.end(), greater);
while(it != vecInt.end())
{
cout<<*it<<endl;
it = find_if(it+1, vecInt.end(), greater);
}
return 0;
}
2、常用合并算法
加集:
merge()//合并:合并容器A和B到容器C。
例:
merge(vecIntA.begin(),vecIntA.end(),vecIntB.begin(),vecIntB.end(), vecIntC.begin());
并集:
set_union() //实现求集合A,B的并。
例:
set_union(vecInt1.begin(), vecInt1.end(), vecInt2.begin(), vecInt2.end(), vecInt.begin());
交集:
set_intersection()//实现求集合A,B交集。
例:
set_intersection(vecInt1.begin(), vecInt1.end(), vecInt2.begin(), vecInt2.end(), vecInt.begin());
差集:
set_difference()//实现求集合A,B的差(即A—B)(差集)。
例:
set_difference(vecInt1.begin(), vecInt1.end(), vecInt2.begin(), vecInt2.end(), vecInt.begin());
3、常用其他算法
排序:
sort()//默认升序排序
例:
sort(vec.begin(), vec.end())
自定义排序:
sort(beg,end,compare)//按照自定义的规则排序
例:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <time.h>
using namespace std;
class Student
{
public:
Student(int id, string name):m_id(id),m_name(name){}
public:
int m_id;
string m_name;
};
bool compare(const Student &stuA, const Student &stuB)
{
return stuA.m_id<stuB.m_id ? true : false;
}
int main(int argc, char* argv[])
{
srand(time(0));//随机数发生器的初始化
vector<Student> vecStudent;
vecStudent.push_back(Student(3, "小明3"));
vecStudent.push_back(Student(5, "小明5"));
vecStudent.push_back(Student(2, "小明2"));
vecStudent.push_back(Student(1, "小明1"));
vecStudent.push_back(Student(4, "小明4"));
sort(vecStudent.begin(), vecStudent.end(), compare);
vector<Student>::iterator it;
for(it=vecStudent.begin(); it!=vecStudent.end(); it++)
{
cout<<(*it).m_name<<" "<<endl;
}
return 0;
}
随机洗盘:
random_shuffle();//打乱原有排序
random_shuffle(vec.begin(), vec.end());
颠倒顺序:
reverse();//反转原有排序
reverse(vec.begin(), vec.end());
拷贝:
copy();//拷贝容器A的指定区间到容器B
例:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Student
{
public:
Student(){}
Student(int id, string name):m_id(id),m_name(name){}
public:
int m_id;
string m_name;
};
int main(int argc, char* argv[])
{
vector<Student> vecStudent;
vector<Student> vecStu;
vecStudent.push_back(Student(3, "小明3"));
vecStudent.push_back(Student(5, "小明5"));
vecStudent.push_back(Student(2, "小明2"));
vecStudent.push_back(Student(1, "小明1"));
vecStudent.push_back(Student(4, "小明4"));
vecStu.resize(vecStudent.size());//需要有默认的构造函数Student()
copy(vecStudent.begin(), vecStudent.end(), vecStu.begin());
vector<Student>::iterator it;
for(it=vecStu.begin(); it!=vecStu.end(); it++)
{
cout<<(*it).m_name<<endl;
}
return 0;
}
替换:
replace();//将指定元素替换成给定的元素
replace(vec.begin(), vec.end(), 3, 10);//将容器中所用等于3的元素替换成10
条件替换:
replace_if();//替换满足条件的元素
例:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool greater(int iNum)
{
if(iNum >3)
{
return true;
}
else
{
return false;
}
}
int main()
{
int data[] = {1,2,4,5,6,3,6,11};
vector<int> vecInt(data, data+sizeof(data)/sizeof(int));
replace_if(vecInt.begin(), vecInt.end(), greater, 10);
vector<int>::iterator it;
for(it=vecInt.begin(); it!=vecInt.end(); it++)
{
cout<<*it<<endl;
}
return 0;
}
交换:
swap(vec1,vec2);//交换容器元素
计算和:
accumulate(vec.begin(), vec.end(), 100);//计算从vec.begin()到vec.end()的和再加上最后的100
填充:
fill(vec.begin(), vec.end(), 100);//将vec里的值全部填充成100
遍历:
for_each();//遍历区间元素
例:
for_each(vecInt.begin(), vecInt.end(), show);
转换:
transform();//改变遍历的元素
例:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
void show(const int &item)
{
cout<<item<< " ";
}
int increase(int item)
{
return item + 1;
}
int main()
{
int data1[] = {1,2,3,4,5,6,7,8};
vector<int> vecInt1(data1, data1+sizeof(data1)/sizeof(int));
vector<int> vecInt;
vecInt.resize(vecInt1.size());
transform(vecInt1.begin(), vecInt1.end(), vecInt.begin(), increase);
for_each(vecInt.begin(), vecInt.end(), show);
return 0;
}
四、删除元素的注意点
1. 对于关联容器(如map, set,multimap,multiset)
删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前iterator即可。这是因为map之类的容器,使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响。for (iter = cont.begin(); it != cont.end();)
{
if(shouldDelete(*iter))
{
cont.erase(iter++);
}
else
{
++iter;
}
}
因为iter传给erase方法的是一个副本,iter++会指向下一个元素。
2. 对于序列式容器(如vector,deque)
删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。还好erase方法可以返回下一个有效的iterator。for (iter = cont.begin(); iter != cont.end();)
{
if(shouldDelete(*iter))
{
iter = cont.erase(iter);
}
else
{
++iter;
}
}
3. 对于list来说
它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种方法都可以使用。
后置++的代码:
_Myiter operator++(int)
{ // postincrement
_Myiter _Tmp = *this;
++*this;
return (_Tmp);
}
*this:表示当前迭代器
_Tmp:当前迭代器的副本
++*this;//*this变成下一个迭代器
return (_Tmp);//最后返回的是当前迭代器的副本
前置++的代码:
_Myiter& operator++()
{
++(*(_Mybase *)this);//*this变成下一个迭代器
return (*this);//返回的是下一个迭代器
}