C++ STL库 容器自我小结
Vector容器
-
初始化
(1)构造函数初始化
vector<int> vecname(size,initval);
注:size和initval两个参数都可以省略,缺省值均为0.
vector<int> a;//初始化一个size为0的vector vector<int> aa(10);//初始化了一个size为10且值全为0的vector vector<int> aaa(10,1);//初始化了一个size为10且值全为1的vector
(2)通过同类型vector初始化
vector<int> a(10,2); vector<int> b(a);
(3)通过insert()函数初始化
vector<int> a(6,6); vector<int> b;//首先要声明一个vector容器 b.insert(b.begin(),a.begin(),a.begin()+3); //vec1.insert(insertpos,startpos,endpos); //在vec1的inserpos位置中插入[starpos,endpos)中的值 //注意区间的前开后闭,以及三个pos值都是以迭代器形式给出
vector<int> a(6,6); vector<int> b;//首先要声明一个vector容器 b.insert(b.begin(),5,8); //vec.insert(insertpos,nums,val); //在vec的insertpos位置中插入nums个值为val的元素 //insertpos同样是迭代器类型
(4)二维vector的初始化
①vec.resize()方法
vector<vector<int> > a; a.resize(m);//对外层vector进行大小初始化,也就是有m行 //因为vector容器的特性,vector中的各行大小不一定完全确定,可以在循环中分别初始化 for(int i = 0;i<m;i++) a[i].resize(ni);//ni表示第i行应该具有的元素个数
②初始化函数
vector<vector<int> > aa(m,vector<int>(n,vals)); //这个格式和一维vector初始化有点类似 //aa被初始化为一个mxn的二维数组,初始值为vals
Map容器
-
基本介绍
map是STL的一个关联容器提供关键字和值的一对一数据处理能力。map内部自建一棵红黑树,这棵树具有对数据的自动排序功能,所以在map内部所有的数据都是有序的。
-
初始化、构造与常用方法
map<typename1,typename2> mapname; mapname.size();//数据数目 mapname.empty();//判空 mapname.clear();//清空map中的数据
-
数据插入
(1)使用insert函数插入数据
//插入pair数据 map<int,int> mp; mp.insert(pair<int,int>(1,2));//使用pair构造方法 mp.insert(make_pair(1,2));//使用make_pair构造函数 //插入value_type数据 mp.insert(map<int,int>::value_type(1,2));
用insert函数插入数据时,在数据的插入上涉及到集合的唯一性概念。即:当map中有这个关键字的时候,insert操作就无法再插入这组数据。
(2)用数组方式插入数据
map<int,int> mp; mp[1] = 2;
但是用数组方式进行插入,如果有相同的关键字,后面插入的数据会覆盖该关键字对应的值。
-
数据遍历
map<int,int> mp;//注意后面构造迭代器时类型要一致 //使用前迭代器 for(map<int,int>::iterator it = mp.begin();it!=mp.end();it++){ //遍历操作 } //使用反相迭代器 for(map<int,int>::iterator it = mp.rbegin();it != mp.rend();it++){ //遍历操作 } //使用数组方式 for(int i = 0;i<mp.size();i++){ cout<<mp[i]; }
-
数据的查找
//使用count函数确定某一个关键字是否出现 map<int,int> mp; if(mp.count(1)) cout<<"1是该map中的一个键值"<<endl; //使用find函数定位数据出现的位置 if(mp.find(1)!=mp.end()) cout<<"1是该map中的一个键值"<<endl;
count函数的返回值只可能是0或1,当返回值为1的时候即说明该关键字出现。
find函数返回的是数据所在位置的迭代器,如果map中没有需要查找的数据的话,就返回end函数指向的迭代器。
-
数据删除
//数据的删除使用erase函数,它具有三种重载形式,注意参数 map<int,int> mp; // Type1:使用迭代器进行元素删除 map<int,int>::iterator it = mp.find(1); mp.erase(it);//常借助find函数找到某一元素的迭代器 //Type2:使用关键字进行元素删除 mp.erase(1); //Type3:使用迭代器删除多个元素 mp.erase(mp.begin(),mp.end());//等价于mp.clear() //注意stl的特性,区间表示都是前闭后开
Set容器
-
基本介绍
set用来存储同一数据类型,能针对一个数据集合中进行增、删、查的操作;在set中每个元素的值都唯一,系统可以根据元素的值自动进行排序。
set也是C++ STL中的标准关联容器(还有map,multiset,multimap),其内部采用红黑树的数据结构。
- 因为不需要做内存拷贝和内存移动,所以map和set的插入和删除操作的效率更高。
- 因为内存没有发生改变 ,所以进行insert操作之后set的iterator不会失效,使用find()相关算法时不用担心过期的iterator问题。
- 因为底层是高效的树结构且set采用的是二分查找,所以随着数据元素的增多,set的插入和查找速度仅仅呈现对数级增长。
-
声明与初始化
set<typename> setname;
-
常用函数与属性
set<int> st; //返回set容器的始末元素的迭代器 st.begin(),st.end(); //清空set容器 st.clear(); //判空,返回为真值说明为空 st.empty(); //当前容器内含有的元素个数 st.size(); //声明时设置的可能包含的元素的最大个数 st.max_size(); //反向迭代器的始末位置 st.rbegin(),st.rend(); //某一元素出现的次数,因为set的特性返回值只可能是0或1 st.count(1);//1在st中出现的次数 //查找某一给定值的定位器,未找到则返回end() st.find(1);//常利用st.find(nums)!=st.end()判断nums是否存在
-
插入元素
//使用insert函数,注意不同的重载形式 set<int> st; //插入某一元素值,返回pair<set<int>::iterator,bool> st.insert(1);//将1插入到集合中 //插入定位器start到final之间的元素,无返回值 int a[] = {2,3,4,5}; st.insert(a,a+3); //数组名称可以直接表示地址 vector<int> a(10); st.insert(a.begin(),a.begin()+3); //假设已经对内部元素进行过插入
-
删除元素
//使用earse()函数,同样注意重载形式 set<int> st; //删除某一键值 st.erase(1);//删除元素1 //删除定位器指向的元素 st.erase(st.begin());//删除集合中最小的元素,"自动排序" //删除定位器start到final之间的元素 set<int>::iterator final = st.begin(); final++;//只用string和vector的迭代器可以用it+num的形式 final++; st.erase(st.begin(),final);//删除前两个元素
-
元素定位器
set<int> st;//假设该集合中有1,2,3,4共四个元素 //返回第一个大于等于key_value的定位器 st.lower_bound(2);//第一个≥2的定位器 //返回最后一个大于等于key_value的定位器 st.upper_bound(2);//最后一个≥2的定位器
String 容器
-
声明与初始化
string str;//声明一个空字符串 //用已知的string对象初始化 string s(str); //用已知的string对象的某一位置开始的某个长度的字串初始化 string s(str,str.begin(),str.size()); //初始化为若干个相同的字符 string s(10,'a'); //用已知的string对象从某一下标开始到结束的字串初始化 string s(str,str.begin()); //注意下标从0开始
-
常用方法和属性
//string对象含有的字符个数 string.size(); string.length(); //string对象最多可以包含的字符个数,跟对象封装有关 string.max_size(); //重新分配内存之前,string对象能包含的最大字符数;跟当前内存分配有关 string.capacity(); //正向迭代器 string str; string::iterator it = str.begin();//str.end() //反向迭代器 string str; string::reverse_iterator rit = str.rbegin();//str.rend() //字符串排序,按照字典序排列 string str; sort(str.begin(),str.end());
-
字符的插入
//使用push_back()方法尾插字符 string s1; s1.push_back('a'); s1.push_back('b');//s1:ab //使用insert方法在指定位置插入字符 string s2;//假设s2:ab s2.insert(s2.begin(),'c');//s2:cab
-
字符串的比较
// 1. 使用比较操作符,可以按照字典序直接对两个字符串对象比较 //2. 成员函数compare() /* str1.compare(id1,len1,str2,id2,len2); str1的id1处开始长度为len1的子串与str2的id2开始长度为len2的子串进行比较,id和len的参数缺省则默认是两个字符串str1和Str2进行比较 */ string A("123456"); string B("123dfg"); A.compare(0,3,B,0,3);//“123”和“123”的比较
-
字符串的拼接
// 1. 使用+运算符 string str1("123"); string str2("456"); str1 += str2;//str2:123456 //2. 使用append方法 string str1("123"); str1.append("def");//str1:123def
-
字符串的删除
//字符串的清空 string.clear(); //使用erase()函数,注意重载形式 //1. 清除定位器所指向的字符 string str("123456"); str.erase(str.begin());//str:23456 //2. 清除定位器[start,final)之间的字符,字符串迭代器可以使用it+num的形式 string str("123456"); str.erase(str.begin(),str.begin()+2);//str:3456 //3. 清除字符串从某一pos开始长度为len的子串 string str("123456"); str.erase(0,2);//str:3456
-
字符串的查找
//1. find()函数,p.s. find()与rfind()得到区别在于从前还是从后开始查找 string str("123456123456"); str.find("23");//查找某一字串的首字符在源串的下标 str.find("23",0);//查找从下标0开始找到的第一个“23”子串的下标 //2. 在源串中找某一个子串中的字符 string str("123456"); str.find_first_of("ab3r67");//查返回"ab3r67"中第一个在str中出现的字符的下标 3---返回2
Stack容器
-
基础知识
①堆栈本质上也是一个线性表,只不过操作受到限制——插入和删除操作只在表的一端进行:堆栈是一个后进先出(LIFO)的表格。
②C++ STL中的堆栈泛化是直接通过现有的序列容器来实现的,默认使用双端队列,可以改成其他的线性结构。
③为了严格遵循堆栈中数据的后进先出原则,stack不提供元素的任何迭代器操作——stack容器不会像外部提供可用的前向或反向迭代器类型。
-
声明与初始化
stack<typename> sname;
-
常用方法与属性
//stack容器是对栈的实现,元素满足后进先出的特性 stack<int> st; //将元素压入堆栈的栈底 st.push(1); //将元素从栈顶取出,并不会返回元素的值 st.pop(); //在队列非空时取栈顶的元素 int head = st.top();//栈顶元素 //堆栈元素的总数 int sum = st.size(); //判断堆栈容器是否为空 st.empty();
Queue容器
-
声明与初始化
queue<typename> qname;
-
常用方法与属性
//queue容器是对队列的实现,元素满足先进先出的特性 queue<int> q; //将元素放入队列末尾 q.push(1); //将元素从队列头部取出,并不会返回元素的值 q.pop(); //在队列非空时取队列中队首或者队尾的元素 int head = q.front();//队首元素 int tail = q.back(); //队列元素的总数 int sum = q.size(); //判断队列容器是否为空 q.empty();
-
优先队列(priority_queue)
(1)基本介绍
priority_queue是定义在queue头文件内的一个有用的模板类,队列容器是按照入队的先后顺序出队;但是优先队列是按照队列内的元素的优先权进行出队的(模板的默认值是元素值越大,优先权就越大),也可以指定算子来改变默认的优先顺序。
priority_queue模板类中有三个模板参数——元素类型、容器类型、比较算子。后两个可以省略,在模板的默认值下是vector和less算子。
p.s. 算子决定了元素在优先队列中的排列顺序,也就是less的作用下小元素排列在队列的前面,元素大的则后置。
但是优先队列出队的时候是从队列末尾开始弹出元素——也就是,在less算子的作用下,元素值越大的元素优先权越大(优先弹出队列)
(2)对象声明与定义
priority_queue<int> pq1;//后两项缺省,整型数值越大的元素其优先权越大 priority_queue<pair<int,int> > pq2;//改变元素类型 priority_queue<int,vector<int>,greater<int> > pq3; //显式写出了元素类型和容器类型,以及改写了默认比较算子
(3)自定义比较算子
- 如果是基本的数据类型,可以直接使用模板中提供的greater和less算子
- 若要自定义比较算子,其中一种方法就是重载运算符
//以下自定义一个结构类,并针对这个结构类重载运算符 class node{ public: int x,y,z; node(int a,int b,int c){} }; bool operator<(const node& n1,const node& n2){ return n1.z<n2.z;//按照结构中z分量增序排序,值越大的优先权越大 } //测试程序 int main(void) { priority_queue<T>q; q.push(T(4,4,3)); q.push(T(2,2,5)); q.push(T(1,5,4)); q.push(T(3,3,6)); while(!q.empty()) { T t=q.top(); q.pop(); cout<<t.x<<" "<<t.y<<" "<<t.z<<endl; } system("Pause"); return 1; }
其他小Tips
-
重写比较函数
在使用sort函数还有优先队列重写优先级逻辑的时候会用得到。
struct cmp{ bool operator()(typename ¶1,typename ¶2){ return f(para1) < f(para2); } }; func(){ //函数其他主体内容 sort(iterator1,iterator2,cmp());//sort函数中调用 priority_queue<elemtype,containertype,cmp()>; //优先队列定义的时候使用,优先队列就会按照重写的逻辑进行元素处理 }