C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作。vector封装数组,list封装了链表,map和set封装了二叉树等,在封装这些数据结构的时候,STL按照程序员的使用习惯,以成员函数方式提供的常用操作,如:插入、排序、删除、查找等。让用户在STL使用过程中,并不会感到陌生。
STL可分为:
1) 容器(continers)、
2) 迭代器(iterator)、
3) 空间配置器
4) 配接器
5) 算法
6) 仿函数
容器:向量(vector)、双向链表(list)、集合(set)、映射(map)
一 vector:
1.概念:
(1)vector是表示可变大小数组的序列容器。
(2)就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
(3)本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
(4)vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
(5)因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
(6)与其它动态序列容器相比(deques, lists and forward_lists), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起lists和forward_lists统一的迭代器和引用更好。
(7) Vector的大小(size)和容量(capacity)通常是不同的,catacity返回vector实际能容纳的元素数量,如果超过这个数量需要重新配置内部存储器。
2.vector基本操作
向量大小: vec.size(); 向量最大容量: vec.max_size(); 更改向量大小: vec.resize(); 向量真实大小: vec.capacity(); 向量判空: vec.empty(); 减少向量大小到满足元素所占存储空间的大小: 多个元素赋值: vec.assign(); //类似于初始化时用数组进行赋值 末尾添加元素: vec.push_back(); 末尾删除元素: vec.pop_back(); 任意位置插入元素: vec.insert(); 任意位置删除元素: vec.erase(); 交换两个向量的元素: vec.swap(); 清空向量元素: vec.clear(); 开始指针:vec.begin(); 末尾指针:vec.end(); 下标访问: vec[1]; //并不会检查是否越界 at方法访问: vec.at(1); //以上两者的区别就是at会检查是否越界,是则抛出out of range异常 访问第一个元素: vec.front(); 访问最后一个元素: vec.back(); 返回一个指针: int* p = vec.data(); //可行的原因在于vector在内存中就是一个连续存储的数组,所以可以返回一个指针指向这个数组。这是是C++11的特性。
二 deque(双端队列容器),和vector相似,vector一边操作,deque可以2边操作
三 string容器
基本操作:
(1)capacity():返回当前容量 (2)max_size():返回string对象中可存放的最大字符串的长度 (3)size():返回当前字符串的大小 (4)length():返回当前字符串的长度 (5)empty():当前字符串是否为空 (6)resize(int len,char c):把字符串当前大小置为len,多去少补,多出的字符c填充不足的部分 (7)find():查找函数 (8)replace():替换函数 (9)compare()比较函数 (10)substr():字符串截取 (11)insert():插入
四 stack(栈容器)
基本操作:
empty:判断堆栈元素是否为空,true表示栈元素为空;
pop:移除栈顶元素;
push:栈顶添加元素;
top:返回栈顶元素;
size:返回栈中元素数目;
#include<iostream> #include<stack> using namespace std; int main() { stack<int> stackTmp; for (int i = 0; i<10; i++) { stackTmp.push(i); } while (stackTmp.size()>1){ cout << stackTmp.top() << " "; stackTmp.pop(); } cout << stackTmp.top() << endl; system("pause"); return 0; }
五 queue(队列)
基本操作:
push(x); 将x 接到队列的末端。
pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
front(),即最早被压入队列的元素。
back(),即最后被压入队列的元素。
empty(),当队列空时,返回true。
#include<iostream> #include<stack> using namespace std; int main() { queue <int> queueTmp; for (int i = 0; i<10; i++) { queueTmp.push(i); } while (queueTmp.size()>1){ cout << queueTmp.front() << " "; queueTmp.pop(); } cout << queueTmp.front() << endl; system("pause"); return 0; }
注意:就stack和queue没有对应的迭代器,不支持遍历
六 list(链表)
list是一种序列式容器。list容器完成的功能实际上和数据结构中的双向链表是极其相似的,list中的数据元素是通过链表指针串连成逻辑意义上的线性表,list不仅是一个双向链表,而其还是一个环状双向链表。所以它只需要一个指针,便可以完整实现整个链表。list有一个重要性质:插入操作(insert)和合并操作(splice)都不会 造成原有的list迭代器失效。甚至 list的元素删除操作(erase)也只有“指向被删除元素”的那个迭代器失效,其他迭代器不受任何影响。
基本操作:
listTmp.push_back(elem);//容器尾部添加一个元素 listTmp.back(); //删除容器中的最后一个元素 listTmp.push_front(elem); //在容器的开头插入一个元素 listTmp.pop_front();//从容器的开头移除一个元素 listTmp.insert(pos, elem);//在pos位置插入elem元素的拷贝,返回新数据的位置 listTmp.insert(pos, n, elem); //在pos位置插入n个elem数据,无返回值 listTmp.insert(pos, begin, end);//在pos位置插入[begin,end]区间的数据,无返回值 listTmp.clear();//移除pos位置的数据,返回下一个数据的位置 listTmp.erase(pos);//删除pos位置的数据,返回下一个数据的位置 listTmp.remove();//删除容器中所有与elem值匹配的元素
七 set/multiset
关于set,必须说明的是set关联式容器。set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。应该注意的是set中数元素的值不能直接被改变。C++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-BlackTree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构
/
B C
/ /
D E F G
#include <iostream> #include <set> using namespace std; int main() { set<int> s; s.insert(1); s.insert(2); s.insert(3); s.insert(1); cout<<"set 的 size 值为 :"<<s.size()<<endl; cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl; cout<<"set 中的第一个元素是 :"<<*s.begin()<<endl; cout<<"set 中的最后一个元素是:"<<*s.end()<<endl; s.clear(); if(s.empty()) { cout<<"set 为空 !!!"<<endl; } cout<<"set 的 size 值为 :"<<s.size()<<endl; cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl; return 0; }
小结:插入3之后虽然插入了一个1,但是我们发现set中最后一个值仍然是3哈,这就是set 。还要注意begin() 和 end()函数是不检查set是否为空的,使用前最好使用empty()检验一下set是否为空.
count() 用来查找set中某个某个键值出现的次数。这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了
#include <iostream> #include <set> using namespace std; int main() { set<int> s; s.insert(1); s.insert(2); s.insert(3); s.insert(1); cout<<"set 中 1 出现的次数是 :"<<s.count(1)<<endl; cout<<"set 中 4 出现的次数是 :"<<s.count(4)<<endl; return 0; }
equal_range() ,返回一对定位器,分别表示第一个大于或等于给定关键值的元素和 第一个大于给定关键值的元素,这个返回值是一个pair类型,如果这一对定位器中哪个返回失败,就会等于end()的值。
#include <iostream> #include <set> using namespace std; int main() { set<int> s; set<int>::iterator iter; for(int i = 1 ; i <= 5; ++i) { s.insert(i); } for(iter = s.begin() ; iter != s.end() ; ++iter) { cout<<*iter<<" "; } cout<<endl; pair<set<int>::const_iterator,set<int>::const_iterator> pr; pr = s.equal_range(3); cout<<"第一个大于等于 3 的数是 :"<<*pr.first<<endl; cout<<"第一个大于 3的数是 : "<<*pr.second<<endl; return 0; }
erase(iterator) ,删除定位器iterator指向的值
erase(first,second),删除定位器first和second之间的值
erase(key_value),删除键值key_value的值
#include <iostream> #include <set> using namespace std; int main() { set<int> s; set<int>::const_iterator iter; set<int>::iterator first; set<int>::iterator second; for(int i = 1 ; i <= 10 ; ++i) { s.insert(i); } //第一种删除 s.erase(s.begin()); //第二种删除 first = s.begin(); second = s.begin(); second++; second++; s.erase(first,second); //第三种删除 s.erase(8); cout<<"删除后 set 中元素是 :"; for(iter = s.begin() ; iter != s.end() ; ++iter) { cout<<*iter<<" "; } cout<<endl; return 0; }
find() ,返回给定值值得定位器,如果没找到则返回end()。
#include <iostream> #include <set> using namespace std; int main() { set<int> st; st.insert(4); st.insert(5); st.insert(3); st.insert(1); st.insert(2); set<int>::iterator it = st.find(4); //find()返回要查找值的迭代器,如果没有,则返回end() if (it != st.end()) { cout << *it << endl; } else { cout << "没有找到" << endl; } return 0; }
lower_bound(key_value) ,返回第一个大于等于key_value的定位器
upper_bound(key_value),返回最后一个大于等于key_value的定位器
#include <iostream> #include <set> using namespace std; int main() { set<int> s; s.insert(1); s.insert(3); s.insert(4); cout<<*s.lower_bound(2)<<endl; cout<<*s.lower_bound(3)<<endl; cout<<*s.upper_bound(3)<<endl; return 0; }
迭代器:是面向对象版本的指针。
1) 指针可以指向内存中的一个地址,
2) 迭代器可以指向容器中的一个位置,用来便利STL容器的全部或者部分元素。
3) STL的每一个容器类模板中,都定义了一组对应的迭代器类
a)*返回当前位置上的元素值,如果给元素有成员,可以通过迭代器以operator->取用。
b) ++ 将迭代器前进至下一个元素。
c) ==&!= 判断两个迭代器是否指向同一位置。
d)= 为迭代器赋值(将所指元素的位置赋值过去)
1)begin():返回一个迭代器,指向第一个元素。
2)end():返回一个迭代器,指向序列结束。
3)sort(array.begin(),array.end()); 排序