STL的三个关键组件:容器,迭代器,算法
STL容器的类型只要分为3类:序列容器(顺序容器),关联容器,容器适配器
★标准模板库中关于容器的操作
(使用与所有容器)
empty 容器中没有元素时返回true
max_size 返回容器中元素的最大个数
size 返回容器中当前所有元素的个数
operator< 如果第一个容器比第二个小,返回true
operator> (>=,<=,>,=,!=)
swap 交换两个容器中的元素
(适用于第一类容器(序列容器和关联容器))
begin 返回指向容器中第一个元素的iterator或者const_iterator
end 返回指向容器中最后一个元素之后的那个位置的iterator或者const_iterator
rbegin 返回指向容器中最后一个元素的iterator或者const_iterator
rend返回指向容器中第一个元素之前那个位置的iterator或者const_iterator
erase 从容器中删除一个或多个元素
clear 删除容器中所有元素
(适用于序列容器)
front 返回对容器第一个元素的引用
back 返回对容器最后一个元素的引用
push_back 将一个元素插入到容器尾部
pop_back 删除容器中最后一个元素
标准库容器头文件
<vector> <list> <deque>【(双端队列)】 <queue> <stack> <map> <set> <bitset>
迭代器与指针有很多共性,它用于指向第一类容器中的元素,迭代器保存它所操作的特定容器所需要的状态信息。如果迭代器i指向某一元素,++i指向下一个元素,*i为i所指向的元素。同时iterator类型的对象指向一个能修改的容器元素,而const_iterator类型的对象指向一个不能修改的容器元素。
迭代器的类别:
输入迭代器,输出迭代器-à正向迭代器-à双向迭代器-à随机访问迭代器
只有第一类容器支持迭代器,,在第一类迭代器中,只有vector和deque支持随机访问迭代器,其余的只支持双向迭代器。
vector是数组的改进版,可以动态的改变长度,可以相互进行赋值(数组不行,因为数组名其实是常量指针,常量不允许赋值操作)。在vector结尾进行插入操作时很高校的,但是在中间进行插入操作,和数组一样,需要花费很高的代价。因此在头部插入多使用deque类,在尾部插入多使用vector类,在中间插入多使用list类。
1.vector
void main()
{
int a;
vector < int > v;
v.push_back( 1 ); // 从尾部插入操作
v.insert(v.begin() + 1 , 2 );
cout << v.capacity() << endl; // 返回,说明此时容量为
// v.at(2)=3;此时增加的话,必然会导致out_of_range的越界错误,因为at操作执行越界检查
v.push_back( 3 );
cout << v.capacity() << endl; // 此时容量为
v.push_back( 4 );
cout << v.capacity() << endl; // 此时容量为
v.at( 3 ) = 6 ;
// v[5]=4;
vector < int > ::const_iterator v1; // 正向迭代取值
for (v1 = v.begin();v1 != v.end();v1 ++ )
cout <<* v1 << " " ;
cout << endl;
v.pop_back(); // 从尾部删除操作
vector < int > ::const_reverse_iterator v2; // 反向迭代取值
for (v2 = v.rbegin();v2 != v.rend();v2 ++ )
cout <<* v2 << " " ;
cin >> a;
}
注:只有随机访问迭代器支持<,所以最好使用!=与end()来测试是否达到容器尾部
另外,vector还有重载的构造函数
如:int a[6]={1,2,3,4,5,6};
std::vector<int> v(a,a+6);
2.list
list类实际为双向链表,即列表中的每个节点包含了指向列表中前一个节点的指针和指向列表中下一个节点的指针
部分list成员函数:
spice(where,listname) 将第二个参数(容器)中的元素移到第一个参数(迭代器位置)之前
push_front list和dequue专有,vector没有
pop_front
remove(int) 从list中删除int这个值的元素
unique 删除list中的重复值,在此操作之前list应该是排好序的,以便重复值排在一起
values.merge(othervalue) 将othervalue迭代器中的元素以排好的顺序插入到迭代器values中
reverse
sort 递增排序
void print(list < T >& v)
{
cout << endl;
list < T > ::iterator v1;
for (v1 = v.begin();v1 != v.end();v1 ++ )
cout <<* v1 << " " ;
}
void main()
{
int a;
list < int > v;
v.push_front( 1 );
v.push_front( 2 );
v.push_back( 3 );
v.push_back( 4 );
print(v); // v:2 1 3 4
v.sort(); // 排序操作
print(v); // v:1 2 3 4
int b[] = { 5 , 6 , 7 , 8 };
list < int > v2;
v2.insert(v.begin(),b,b + 4 ); // 将v2插入到v.begin()位置
print(v); // v:5 6 7 8 1 2 3 4
v2.splice(v2.begin(),v); // 将v容器中的元素已到v2中去,此时v容器为空
v2.remove( 2 ); // 移除这个元素
v2.push_back( 3 );
v2.sort();
print(v2);
v2.unique(); // 删除重复项
print(v2);
v.merge(v2); // 将v2排好序的元素插入到v
print(v);
v.reverse(); // 容器中元素反转
print(v);
cin >> a;
}
3.deque
deque提供了和vector相同的基本操作,但也增加了成员函数push_front和pop_front,分别在deque头部进行插入和删除操作。
关联容器可以通过“关键字”(查找关键字)来存储和检索元素
4.multiset
multiset允许关键字重复,元素排列的顺序由“比较器函数对象”确定。例如:在整数multiset中,元素能够使用比较器函数对象less<int>排序关键字,以升序进行排列。另外,要使用multiset类必须包含头文件#include <set>.
专有成员函数:find,lower_bound,upper_bound,count
find(value)返回最先出现value的迭代器
lower_bound(value),upper_bound(value)(所有的关联容器都有着两个函数),作用:返回value最早或者最晚出现在multiset的位置之后的那个元素的位置,这两个函数都返回指向相应位置的迭代器,如果找不到,则返回end()
void print(multiset < T,less < T >>& v)
{
multiset < T,less < T >> ::iterator v1;
for (v1 = v.begin();v1 != v.end();v1 ++ )
cout <<* v1 << " " ;
}
void main()
{
int a;
multiset < int ,less < int >> s;
s.insert( 2 );
int b[] = { 1 , 2 , 6 , 4 , 2 };
s.insert(b,b + 5 );
print(s); // 不忽略重复的元素,如果用set则输出2 4 6
s.insert( 5 );
cout << endl;
print(s);
cout << endl << s.count( 2 ); // 2出现的次数
cout << endl <<* ( -- s.find( 6 )); // 返回之前的那个元素
// pair<multiset<int,less<int>>::iterator,multiset<int,less<int>>::iterator> p;
// p=s.equal_range(2);
// cout<<endl<<*(p.first)<<" "<<*(p.second);
cout << endl <<* (s.lower_bound( 2 )) << " " <<* (s.upper_bound( 2 )); // 等价上面3条指令
cin >> a;
}
注:pair类的对象主要用于联系数值对,本例中pair中的对象是两个基于实例multiset的常量迭代器。函数equal_range返回包含下边界lower_bound和上边界upper_bound操作结果的数值对,pair类包含两个public数据成员first和second,分别返回上边界和下边界的迭代器。
5.set
set关联容器用于快速存储和检索单一关键字,所以鼠兔将重复的关键字假如到set中时,会忽略重复值。除了和multiset的关键字不唯一不同以外,他们的实现方法是相同的。
6.multimap
multimap关联容器用于快速存储和检索关键字及其关联值(关键字/值),multiset和set的许多方法同样适用于multimap和map,只是后者中的元素为关键字和值的数值对,而不是单个的值。multimap支持双向迭代器,但是不支持随机迭代器。
要使用multimap类,必须包含头文件#include <map>
{
int a;
typedef multimap < int , double ,less < int >> mmap; // typedef multimap<int,double> mmap;亦可
mmap pairs;
pairs.insert(mmap::value_type( 1 , 1.1 ));
pairs.insert(mmap::value_type( 2 , 2.2 ));
pairs.insert(pairs.begin(),mmap::value_type( 3 , 3.3 ));
for (mmap::const_iterator m = pairs.begin();m != pairs.end();m ++ )
cout << m -> first << " " << m -> second << endl;
mmap::iterator m1 = pairs.find(mmap::key_type( 2 ));
cout << (m1 -> second);
cin >> a;
}
7.map
map:一一映射,用map指定一个关键字可以快速的取得与它关联的值,码盘又称关联数组,在map的下标操作法[]中使用关键字可以定位与该关键字关联的数值,可以在map的任意位置进行插入和删除操作。
容器适配器
适配器不是第一类容器,因为他们不提供实际可以存储元素的数据结构,也不支持迭代器。3类适配器(stack,queue,priority_queue)均提供了push和pop用于在适配器数据结构中进行插入和删除操作。容器适配器的好处在于可以选择合适的底层数据结构。如satck就可以选择任何一种序列容器来实现。
8.satck
默认情况下,satck是通过deque来实现堆栈的,但是也可以通过底层的vector和list容器来实现。使用stack类之前注意包含头文件<stack>
#include " iostream "
#include < stack >
#include < vector >
#include < list >
using namespace std;
template < class T >
void print(T & t)
{
while ( ! t.empty())
{
cout << t.top() << " \t " ;
t.pop();
}
}
void main()
{
int a;
stack < int > inistack; // 默认底层数据结构是deque
stack < int ,vector < int >> vectorstack; // 采用vector容器实现stack
stack < int ,list < int >> liststack; // 采用list容器实现satck
inistack.push( 5 );
inistack.push( 6 );
print(inistack);
vectorstack.push( 3 );
vectorstack.push( 4 );
print(vectorstack);
liststack.push( 1 );
liststack.push( 2 );
print(liststack);
cin >> a;
}
9.queue
queue类适配器主要实现在底层数据结构的尾部进行插入操作,在头部进行删除操作
函数成员:push(通过调用底层数据结构的push_back实现)
pop front(返回第一个元素的引用) back(返回最后一个元素的引用)
empty size
同stack一样,默认情况下是采用deque作为底层的数据结构
10.priority_queue
priority_queue类能够实现将元素有序的插入到底层数据结构中以及在底层数据头部删除元素,可以使用vector和deque作为底层的数据结构,默认情况下是以vector作为底层数据结构实现的。插入元素时,元素时按照优先级排序的,这种始终把优先级最高的(最大值)放在数据结构头部来实现的技术称为“堆排序”。
函数成员:push pop top empty size
#include " iostream "
#include < queue >
using namespace std;
template < class T >
void print(T & t)
{
while ( ! t.empty())
{
cout << t.top() << " \t " ;
t.pop();
}
}
void main()
{
int a;
priority_queue < double > pq;
pq.push( 2.5 ); // 需要进行排序,就是优先级最高的最先弹出
pq.push( 3.5 );
pq.push( 1.5 );
print(pq);
cin >> a;
}
STL算法详解
fill/fill_n/generate/generate_n
#include " iostream "
#include < vector >
#include < algorithm >
using namespace std;
void print(vector < char > & v)
{
vector < char > ::iterator i;
for (i = v.begin();i != v.end();i ++ )
{
cout <<* i;
}
cout << endl;
}
char generateletter()
{
static char l = ' a ' ;
return l ++ ;
}
void main()
{
int a;
vector < char > letter( 10 );
fill(letter.begin(),letter.end(), ' a ' ); // fill为std中库函数,而且第三个参数必须为char,即单字母
print(letter);
fill_n(letter.begin() + 1 , 3 , ' b ' );
print(letter);
generate(letter.begin(),letter.end(),generateletter); // 产生器函数必须返回类型,连续执行产生器函数
print(letter);
generate_n(letter.begin() + 1 , 3 ,generateletter);
print(letter);
cin >> a;
}
equal/mismatch/lexicographical_compare
注意:equal返回bool型
mismatch返回一对迭代器,如果所有元素都匹配,则返回的迭代器就等于两个序列中的最后一个迭代器。否则返回出现不匹配元素的位置
lexicographical_compare返回bool类型,第一个容器和第二个容器进行比较大小,前者大于后者,返回false,否则返回true
#include " iostream "
#include < vector >
#include < algorithm >
using namespace std;
template < class T >
void print(vector < T > & v)
{
vector < T > ::iterator i;
for (i = v.begin();i != v.end();i ++ )
{
cout <<* i << " " ;
}
cout << endl;
}
void main()
{
int a;
int b[ 4 ] = { 65 , 66 , 67 };
char c[ 4 ] = { ' A ' , ' B ' , ' C ' , ' D ' };
vector < int > letter1(b,b + 4 ),letter2(c,c + 4 );
print(letter1);
print(letter2);
bool result = equal(letter1.begin(),letter1.end(),letter2.begin());
if (result)
cout << " letter1 equals letter2 " ;
else
cout << " letter1 not equals letter2 " ;
pair < vector < int > ::iterator,vector < int > ::iterator > pairs;
pairs = mismatch(letter1.begin(),letter1.end(),letter2.begin());
cout << endl << " location: " << pairs.first - letter1.begin() << endl <<* pairs.first << " VS " <<* pairs.second << endl;
bool re = lexicographical_compare(letter1.begin(),letter1.end(),letter2.begin(),letter2.end());
if (re)
cout << " letter1 < letter2 " ;
else
cout << " letter1 >= letter2 " ;
cin >> a;
}
remove/remove_copy/remove_if/remove_copy_if
remove:这个函数并不修改vector的元素个数或者删除元素,而是将所有没有删除的元素移至vector头部,函数返回指向vector中未删除元素中最后一个元素之后那个位置的迭代器。
remove_copy:将容器内除去某特定元素后的所有元素copy至参数指定位置。
remove_if:最后一个参数为bool类型,满足bool类型的被remove
remove_copy_if:最后一个参数是判断函数,该函数必须返回bool类型,除去满足bool类型的,剩下的copy到另一个容器中。
#include " iostream "
#include < vector >
#include < algorithm >
using namespace std;
template < class T >
void print(vector < T > & v)
{
vector < T > ::iterator i;
for (i = v.begin();i != v.end();i ++ )
{
cout <<* i << " " ;
}
cout << endl;
}
bool greater68( int x)
{
return (x > 68 );
}
void main()
{
int a;
int b[ 7 ] = { 65 , 66 , 67 , 68 , 69 , 70 };
vector < int > letter1(b,b + 6 ),letter2(b,b + 1 );
print(letter1);
vector < int > ::iterator v1,n1,n2;
v1 = remove(letter1.begin(),letter1.end(), 66 );
print(letter1); // 其实容器内元素没有发生变化
// n0=remove_copy(letter1.begin(),letter1.end(),letter2.begin(),65);
//
n1 = remove_if(letter1.begin(),letter1.end(),greater68);
vector < int > ::iterator i;
for (i = letter1.begin();i != n1;i ++ )
{
cout <<* i << " " ;
}
// n2=remove_copy_if(letter1.begin(),letter1.end(),letter2.begin(),greater68);
cin >> a;
}
replace/replace_if/replace_copy/replace_if_copy
#include " iostream "
#include < vector >
#include < algorithm >
using namespace std;
template < class T >
void print(vector < T > & v)
{
vector < T > ::iterator i;
for (i = v.begin();i != v.end();i ++ )
{
cout <<* i << " " ;
}
cout << endl;
}
bool greater68( int x)
{
return (x > 68 );
}
void main()
{
int a;
int b[ 7 ] = { 65 , 66 , 67 , 68 , 69 , 70 };
vector < int > letter1(b,b + 6 ),letter2;
print(letter1);
vector < int > ::iterator v1,n1,n2;
// v1=remove(letter1.begin(),letter1.end(),66);
replace(letter1.begin(),letter1.end(), 65 , 650 );
print(letter1); // 其实容器内元素没有发生变化
replace_if(letter1.begin(),letter1.end(),greater68, 0 );
print(letter1);
// replace_copy(letter1.begin(),letter1.end(),letter2.begin(),65,650);
// print(letter2);
cin >> a;
}
random_shuffle/cout/count_if/min_element/accumulate/for_each/transform
random_shuffle 对两个迭代器之间的元素进行随机的排序
cout 计算两个迭代器之间某个元素出现的个数
count_if 计算两个迭代器之间满足最后一个参数为bool的元素个数
min_element 返回最小值元素的输入迭代器
accumulate 累计两个迭代器之间元素的总和,需要包含头文件<numeric>,第3个参数为函数的初始值,当然其重载函数还可以接收地4个参数,为自定义的计算函数
for_each 对两个迭代器之间的元素应用同一个函数进行计算,原容器中的内容不变
transform 将两个迭代器之间的元素应用一个自定义函数后复制到新的容器中,自定义函数必须返回值,不能为空。
find、find_if、sort、binary_serch
binary_search决定参数是否在两个迭代器之间的元素值之间,在这个操作之前,必须按照升序排序序列。
swap、iter_swap、swap_range
iter_swap 带有两个迭代器参数,交换两个迭代器所指的数值
swap_range 带有3个参数,请两个迭代器参数决定交换的原始数据,后一个决定交换的目标数据源,将范围内的数据进行交换
copy_backward、merge、unique、reverse
copy_backward 复制两个迭代器之间的元素,并将它们自后向前复制到另一个迭代器中,返回结果的开头位置的迭代器。
merge 将两个升序序列合并为另一个升序序列,需要5个参数,前两个参数指定一个迭代器的范围,后面两个指定另一个迭代器的范围,最后一个指定目标元素位置的迭代器
unique 删除重复值运算
reverse 翻转运算
inplace_merge、unique_copy、reversr_copy
inplace_merge 三个迭代器参数,将[第一个和第二个迭代器参数之间的元素]和[第二个和第三个迭代器参数之间的元素]合并到一起
unique_copy 不重复复制
includes、set_difference、set_intersection、set_symmetric_difference、set_union(集合操作)
includes 判断一个集合是不是在另一个集合之内,返回bool类型
set_differrence 包含在第一个有序集合中,但不包含第二个有序集合中的元素,这些不同的元素复制到最后一个参数中
set_intersection 同时包含第一个和第二个集合中的元素,这些元素被复制到最后一个参数中
set_symmetric_difference 包含在第一个集合但是不包含在第二个集合中的元素,同时被复制到最后一个参数中
set_union 包含两个集合中所有元素的几个,同时被复制到最后一个集合中。
#include " iostream "
#include < vector >
#include < algorithm >
#include < numeric >
using namespace std;
template < class T >
void print(vector < T > & v)
{
vector < T > ::iterator i;
for (i = v.begin();i != v.end();i ++ )
{
cout <<* i << " " ;
}
cout << endl;
}
bool greater68( int x)
{
return (x > 68 );
}
int squareore( int v)
{
return v + 1 ;
}
void main()
{
int a;
int b[ 7 ] = { 65 , 66 , 67 , 68 , 69 , 70 };
vector < int > letter1(b,b + 6 ),letter2(b,b + 3 );
print(letter1);
vector < int > ::iterator v1,n1,n2;
random_shuffle(letter1.begin(),letter1.end()); // 随机排序
print(letter1);
cout << count(letter1.begin(),letter1.end(), 65 ) << endl;
cout << count_if(letter1.begin(),letter1.end(),greater68) << endl;
cout <<* (min_element(letter1.begin(),letter1.end())) << endl;
cout << accumulate(letter1.begin(),letter1.end(), 1 ) << endl; // 405+1
for_each(letter1.begin(),letter1.end(),squareore);
// transform(letter1.begin(),letter1.end(),letter2.begin(),squareore);
// print(letter2);
cin >> a;
}
find/find_if/sort/binary_serch
binary_search决定参数是否在两个迭代器之间的元素值之间,在这个操作之前,必须按照升序排序序列。
swap/iter_swap/swap_range
iter_swap 带有两个迭代器参数,交换两个迭代器所指的数值
swap_range 带有3个参数,请两个迭代器参数决定交换的原始数据,后一个决定交换的目标数据源,将范围内的数据进行交换
copy_backward/merge/unique/reverse
copy_backward 复制两个迭代器之间的元素,并将它们自后向前复制到另一个迭代器中,返回结果的开头位置的迭代器。
merge 将两个升序序列合并为另一个升序序列,需要5个参数,前两个参数指定一个迭代器的范围,后面两个指定另一个迭代器的范围,最后一个指定目标元素位置的迭代器
unique 删除重复值运算
reverse 翻转运算
inplace_merge/unique_copy/reversr_copy
inplace_merge 三个迭代器参数,将[第一个和第二个迭代器参数之间的元素]和[第二个和第三个迭代器参数之间的元素]合并到一起
unique_copy 不重复复制
includes/set_difference/set_intersection/set_symmetric_difference/set_union(集合操作)
includes 判断一个集合是不是在另一个集合之内,返回bool类型
set_differrence 包含在第一个有序集合中,但不包含第二个有序集合中的元素,这些不同的元素复制到最后一个参数中
set_intersection 同时包含第一个和第二个集合中的元素,这些元素被复制到最后一个参数中
set_symmetric_difference 包含在第一个集合但是不包含在第二个集合中的元素,同时被复制到最后一个参数中
set_union 包含两个集合中所有元素的几个,同时被复制到最后一个集合中。
更多的算法和详解见http://www.cplusplus.com/reference/algorithm/