字符串:
头文件
#include<string>
定义
string str;
获取长度
str.length();
重载操作符[],返回下标所在字符。
字符串连接
str = str1+str2;
标准模板库(STL)
顺序容器:vector/deque/list
关联容器:set/map/multiset/multimap
头文件分别为< vector>/< deque>/< list>/< set>/< map>
迭代器
用于遍历容器中的元素
头文件< iterator>
算法
头文件< algorithm>
find() 找到一个给定的键的元素,若被找到,则返回该元素的一个迭代器。否则返回最后一个元素的下一个位置。(即vec.end())
copy()是将容器的内容复制到另一个容器中。
vector
vector作为STL提供的标准容器之一,是经常要使用的,有很重要的地位,并且使用起来也是灰常方便。vector又被称为向量,vector可以形象的描述为长度可以动态改变的数组,功能和数组较为相似。实际上更专业的描述为:vector是一个多功能的,能够操作多种数据结构和算法的模板类和函数库,vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。(注:STL的容器从实现的角度讲可以说是类模板(class teplate)。)
那么vector和数组的主要区别是什么呢??这对于理解vector是很有帮助的~~~~
数组:分配的是静态空间,一般分配了就不可以改变,就像我们熟知的定义了一个数组,那么数组的长度就不可以改变了,我们也不可以进行越界访问,但是编译器不检查越界,这一点在我们编程的时候要尤为注意(很多都可能会烦这样的错误!!)。一般申请的数组长度不能满足我们的要求了,我们要重新申请大一点数组,然后把原数组中数据复制过来。
vector:分配的是动态空间,即:我们发现在声明vector容器的时候也可以不指定容器的大小,vector是随着元素的加入,空间自动扩展的。但是,我们必须要负责任的肯定vector分配的空间是连续的,也就是支持数组中的下标随机访问,实际上vector的实现机制是:预留一部分空间,而且预留空间的大小是按一定比率增长的,如果空间不够用的话,要保证连续,就必须重新new一片空间,然后将原有元素移动到新空间,同时预留新的空间(并且新分配的空间比原来分配的空间),最后将原来的那部分空间释放掉。这样预留空间的好处就是不用每次向vector中加元素都重新分配空间。
创建:
2.1.vector容器的构造函数
vector容器的声明方式主要包括一下几种:
vector v ,创建一个空的vector。
vector v1(v) ,复制一个vector。
vector v(n) ,创建一个vector,含有n个数据,数据均已缺省构造产生。
vector v(n, elem) ,创建一个含有n个elem拷贝的vector。
vector v(beg,end) ,创建一个以[beg;end)区间的vector。
v.~ vector () ,销毁所有数据,释放内存。
注意:注意这种:vector c(beg,end)声明方式,创建一个和[beg;end)区间元素相同的vector,一定要注意是左闭右开区间,同时需要说的是,STL中不论是容器还是算法都是采用的这种左闭右开区间办事的,包括v.end()函数也是返回的vector末端的下位置,相当于int a[n]的a[n],并不能访问。
v.assign(beg,end) , 将[beg; end)区间中的数据赋值给v。
v.assign(n,elem) , 将n个elem的拷贝赋值给v。
v.at(idx) , 传回索引idx所指的数据,如果idx越界,抛出out_of_range。
v.begin() , 传回迭代器中的第一个数据。
v.capacity() , 返回容器中数据个数。
v.clear() , 移除容器中所有数据。
v.empty() , 判断容器是否为空。
v.end() , 指向迭代器中的最后一个数据地址。
v.insert(pos,elem) 在pos位置插入一个elem拷贝,传回新数据位置(位置指传回地址值)。
v.insert(pos,n,elem) 在pos位置插入n个elem数据。无返回值。
v.insert(pos,beg,end) 在pos位置插入在[beg,end)区间的数据。无返回值。
v.erase(pos) 删除pos位置的数据,传回下一个数据的位置。
v.erase(beg,end) 删除[beg,end)区间的数据,传回下一个数据的位置。
v.capacity() 返回容器中数据个数。
v.size() 返回容器中实际数据的个数。
v.reserve() 保留适当的容量。
v.resize(num) 重新指定队列的长度。
v.max_size() 返回容器中最大数据的数量。
c.pop_back() 删除最后一个数据。
c.push_back(elem) 在尾部加入一个数据。
c.front() 传回地一个数据。
c.back() 传回最后一个数据,不检查这个数据是否存在。
c1.swap(c2) 将c1和c2元素互换。
swap(c1,c2) 同上操作。
#include<iostream>
#include<vector>
#include<algorithm>
#include<iterator>
using namespace std;
int main(){
const int sz=6;
int array[sz]={1,2,3,4,5,6};
vector<int> v;//创建空数组
//声明jint型的容器,并用数组赋初值
vector<int> vec(array,array+sz);
cout<<vec[0]<<endl;//下标访问
cout<<vec.front()<<endl;//返回第一个元素
cout<<vec.back()<<endl;//返回最后一个元素
vec[1]=7;//通过下标操作符来修改容器中元素内容
vec.at(2)=10;//用at函数修改,更安全,因为会检查下标是否越界
vec.insert(vec.begin()+1,22);//在第二个元素位置插入22这一元素
vec.push_back(19);//尾部添加19元素
//声明一个迭代器,遍历
vector<int>::iterator iter;
for(iter=vec.begin();iter!=vec.end();iter++)
{
cout<<*iter<<endl;
}
iter = find(vec.begin(),vec.end(),22);//查找22元素的位置,并返回给迭代器
if(iter!=vec.end()){
cout<<"location:"<<(iter-vec.begin())<<endl;
} else{
cout<<"not found"<<endl;
}
cout<<vec.max_size()<<endl;
cout<<vec.capacity()<<endl;
vec.erase(vec.begin());
vec.erase(vec.begin(),vec.end());
cout<<(vec.empty()?"empty":"not empty")<<endl;;
vec.insert(vec.begin(),array,array+sz);
cout<<(vec.empty()?"empty":"not empty")<<endl;;
vec.clear();//清空容器
cout<<(vec.empty()?"empty":"not empty");
return 0;
}
vector<int> ret;//创建
ret.empty();//判空
ret.push_back(111);//尾插
ret.pop_back();//尾删
ret.size();//获取大小
ret.swap();//交换
ret[0];//访问
ret.insert(ret.begin()+i,222);//在第i+1个元素前插入222
ret.erase(ret.begin()+2);//删除第三个元素
ret.erase(ret.begin()+i,ret.begin()+j);//删除[i,j-1]区间的元素
//遍历,或者也可以对下标用for循环去遍历
vector<int>::iterator iter;
for(iter=ret.begin();iter!=ret.end();iter++)
{
cout<<*iter<<endl;
}
//翻转元素
reverse(ret.begin(),ret.end());
//升序排
sort(ret.begin(),ret.end());
//降序排
sort(ret.begin(),ret.end(),cmp);
static bool cmp(int a,int b){
string A=to_string(a)+to_string(b);
string B=to_string(b)+to_string(a);
return A<B;
}
//将arr复制到array中
copy(arr.begin(),arr.end(),array.begin());
list
1、list是一种序列式容器。list容器完成的功能实际上和数据结构中的双向链表是极其相似的,list中的数据元素是通过链表指针串连成逻辑意义上的线性表,也就是list也具有链表的主要优点,即:在链表的任一位置进行元素的插入、删除操作都是快速的。list的实现大概是这样的:list的每个节点有三个域:前驱元素指针域、数据域和后继元素指针域。前驱元素指针域保存了前驱元素的首地址;数据域则是本节点的数据;后继元素指针域则保存了后继元素的首地址。其实,list和循环链表也有相似的地方,即:头节点的前驱元素指针域保存的是链表中尾元素的首地址,list的尾节点的后继元素指针域则保存了头节点的首地址,这样,list实际上就构成了一个双向循环链。由于list元素节点并不要求在一段连续的内存中,显然在list中是不支持快速随机存取的,因此对于迭代器,只能通过“++”或“–”操作将迭代器移动到后继/前驱节点元素处。而不能对迭代器进行+n或-n的操作,这点,是与vector等不同的地方。
#include<iostream>
#include<list>
using namespace std;
int main(){
list<int> lst;
for(int i=0;i<5;++i)
{
lst.push_front(i);//前插
lst.push_back(i);//尾插
}
list<int>::iterator itor=lst.begin();//遍历
while(itor!=lst.end())
{
cout<<*itor++<<" ";//输出 4321001234
}
cout<<endl;
return 0;
}
2.1 list中的构造函数:
list() 声明一个空列表;
list(n) 声明一个有n个元素的列表,每个元素都是由其默认构造函数T()构造出来的
list(n,val) 声明一个由n个元素的列表,每个元素都是由其复制构造函数T(val)得来的
list(n,val) 声明一个和上面一样的列表
list(first,last) 声明一个列表,其元素的初始值来源于由区间所指定的序列中的元素
2.2 begin()和end():通过调用list容器的成员函数begin()得到一个指向容器起始位置的iterator,可以调用list容器的 end() 函数来得到list末端下一位置,相当于:int a[n]中的第n+1个位置a[n],实际上是不存在的,不能访问,经常作为循环结束判断结束条件使用。
2.3 push_back() 和push_front():使用list的成员函数push_back和push_front插入一个元素到list中。其中push_back()从list的末端插入,而 push_front()实现的从list的头部插入。
2.4 empty():利用empty() 判断list是否为空。
2.5 resize(): 如果调用resize(n)将list的长度改为只容纳n个元素,超出的元素将被删除,如果需要扩展那么调用默认构造函数T()将元素加到list末端。如果调用resize(n,val),则扩展元素要调用构造函数T(val)函数进行元素构造,其余部分相同。
2.6 clear(): 清空list中的所有元素。
2.7 front()和back(): 通过front()可以获得list容器中的头部元素,通过back()可以获得list容器的最后一个元素。但是有一点要注意,就是list中元素是空的时候,这时候调用front()和back()会发生什么呢?实际上会发生不能正常读取数据的情况,但是这并不报错,那我们编程序时就要注意了,个人觉得在使用之前最好先调用empty()函数判断list是否为空。
2.8 pop_back和pop_front():通过pop_back删除最后一个元素,通过pop_front()删除第一个元素;序列必须不为空,如果当list为空的时候调用pop_back()和pop_front()会使程序崩掉。
2.9 assign():具体和vector中的操作类似,也是有两种情况,第一种是:l1.assign(n,val)将 l1中元素变为n个T(val)。第二种情况是:l1.assign(l2.begin(),l2.end())将l2中的从l2.begin()到l2.end()之间的数值赋值给l1。
2.10 swap():交换两个链表(两个重载),一个是l1.swap(l2); 另外一个是swap(l1,l2),都可能完成连个链表的交换。
2.11 reverse():通过reverse()完成list的逆置。
2.12 merge():合并两个链表并使之默认升序(也可改),l1.merge(l2,greater()); 调用结束后l2变为空,l1中元素包含原来l1 和 l2中的元素,并且排好序,升序。其实默认是升序,greater()可以省略,另外greater()是可以变的,也可以不按升序排列。
2.13 insert():在指定位置插入一个或多个元素(三个重载):
l1.insert(l1.begin(),100); 在l1的开始位置插入100。
l1.insert(l1.begin(),2,200); 在l1的开始位置插入2个100。
l1.insert(l1.begin(),l2.begin(),l2.end());在l1的开始位置插入l2的从开始到结束的所有位置的元素。
2.14 erase():删除一个元素或一个区域的元素(两个重载)
l1.erase(l1.begin()); 将l1的第一个元素删除。
l1.erase(l1.begin(),l1.end()); 将l1的从begin()到end()之间的元素删除。
set
C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作。vector封装数组,list封装了链表,map和set封装了二叉树等,在封装这些数据结构的时候,STL按照程序员的使用习惯,以成员函数方式提供的常用操作,如:插入、排序、删除、查找等。让用户在STL使用过程中,并不会感到陌生。
关于set,必须说明的是set关联式容器。set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。应该注意的是set中数元素的值不能直接被改变。C++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构。
begin() ,返回set容器的第一个元素
end() ,返回set容器的最后一个元素
clear() ,删除set容器中的所有的元素
empty() ,判断set容器是否为空
max_size() ,返回set容器可能包含的元素最大个数
size() ,返回当前set容器中的元素个数
rbegin ,返回的值和end()相同
rend() ,返回的值和rbegin()相同
#include<iostream>
#include<set>
using namespace std;
int main(){
set<int> st;
st.insert(10);
st.insert(-5);
st.insert(123);
st.insert(10);
set<int>::iterator itor=st.begin();
while(itor!=st.end())
{
cout<<*itor++<<" ";//输出-5 10 123
}
cout<<endl;
int key;
cin>>key;
itor = st.find(key);
if(itor!=st.end())
{
cout<<key<<" is in this set"<<endl;
} else{
cout<<key<<" is not in this set"<<endl;
}
cout<<"set 中 10 出现的次数是 :"<<st.count(10)<<endl;// 1
cout<<"set 中 4 出现的次数是 :"<<st.count(4)<<endl;// 0
return 0;
}
count() 用来查找set中某个某个键值出现的次数。这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。
erase(iterator) ,删除定位器iterator指向的值
erase(first,second),删除定位器first和second之间的值
erase(key_value),删除键值key_value的值
find() ,返回给定值值得定位器,如果没找到则返回end()。
insert(key_value); 将key_value插入到set中 ,返回值是pair<set::iterator,bool>,bool标志着插入是否成功,而iterator代表插入的位置,若key_value已经在set中,则iterator表示的key_value在set中的位置。
inset(first,second);将定位器first到second之间的元素插入到set中,返回值是void.
lower_bound(key_value) ,返回第一个小于等于key_value的定位器
upper_bound(key_value),返回最后一个大于等于key_value的定位器
map
Map是c++的一个标准容器,她提供了很好一对一的关系,在一些程序中建立一个map可以起到事半功倍的效果,总结了一些map基本简单实用的操作!
- map最基本的构造函数;
map<string , int >mapstring;
map<int ,string >mapint;
map<sring, char>mapstring;
map< char ,string>mapchar;
map<char ,int>mapchar;
map<int ,char >mapint; - map添加数据;
map<int ,string> maplive;
1.maplive.insert(pair<int,string>(102,“aclive”));
2.maplive.insert(map<int,string>::value_type(321,“hai”));
3, maplive[112]=“April”;//map中最简单最常用的插入添加!
3,map中元素的查找:
find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。
map<int ,string >::iterator l_it;;
l_it=maplive.find(112);
if(l_it==maplive.end())
cout<<"we do not find 112"<<endl;
else cout<<"wo find 112"<<endl;
4,map中元素的删除:
如果删除112;
map<int ,string >::iterator l_it;;
l_it=maplive.find(112);
if(l_it==maplive.end())
cout<<"we do not find 112"<<endl;
else maplive.erase(l_it); //delete 112;
5,map中 swap的用法:
Map中的swap不是一个容器中的元素交换,而是两个容器交换;
For example:
#include <map>
#include <iostream>
using namespace std;
int main( )
{
map <int, int> m1, m2, m3;
map <int, int>::iterator m1_Iter;
m1.insert ( pair <int, int> ( 1, 10 ) );
m1.insert ( pair <int, int> ( 2, 20 ) );
m1.insert ( pair <int, int> ( 3, 30 ) );
m2.insert ( pair <int, int> ( 10, 100 ) );
m2.insert ( pair <int, int> ( 20, 200 ) );
m3.insert ( pair <int, int> ( 30, 300 ) );
cout << "The original map m1 is:";
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << " " << m1_Iter->second;
cout << "." << endl;
// This is the member function version of swap
//m2 is said to be the argument map; m1 the target map
m1.swap( m2 );
cout << "After swapping with m2, map m1 is:";
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << " " << m1_Iter -> second;
cout << "." << endl;
cout << "After swapping with m2, map m2 is:";
for ( m1_Iter = m2.begin( ); m1_Iter != m2.end( ); m1_Iter++ )
cout << " " << m1_Iter -> second;
cout << "." << endl;
// This is the specialized template version of swap
swap( m1, m3 );
cout << "After swapping with m3, map m1 is:";
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << " " << m1_Iter -> second;
cout << "." << endl;
}
6.map的sort问题:
Map中的元素是自动按key升序排序,所以不能对map用sort函数:
For example:
#include <map>
#include <iostream>
using namespace std;
int main( )
{
map <int, int> m1;
map <int, int>::iterator m1_Iter;
m1.insert ( pair <int, int> ( 1, 20 ) );
m1.insert ( pair <int, int> ( 4, 40 ) );
m1.insert ( pair <int, int> ( 3, 60 ) );
m1.insert ( pair <int, int> ( 2, 50 ) );
m1.insert ( pair <int, int> ( 6, 40 ) );
m1.insert ( pair <int, int> ( 7, 30 ) );
cout << "The original map m1 is:"<<endl;
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << m1_Iter->first<<" "<<m1_Iter->second<<endl;
}
运行结果:
The original map m1 is:
1 20
2 50
3 60
4 40
6 40
7 30
请按任意键继续. . .
7, map的基本操作函数:
C++ Maps是一种关联式容器,包含“关键字/值”对
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比较元素key的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数