C++(二)— STL容器的基本用法
1、vector基本操作
关于vector简单的讲就是一个动态增长的数组,里面有一个指针指向一片连续的内存空间,当空间装不下的时候会自动申请一片更大的空间(空间配置器)将原来的数据拷贝到新的空间,然后就会释放旧的空间。当删除的时候空间并不会被释放只是清空了里面的数据。
- 对象初始化,使用 v1 中的数据:vector<int> vec(v1.begin(), v1.begin()+3);
- 末尾添加元素: vec.push_back();
- 末尾删除元素: vec.pop_back();
- 任意位置插入元素: vec.insert();
- 任意位置删除元素: vec.erase();
- 交换两个向量的元素: vec.swap();
- 清空向量元素: vec.clear();
#include<vector> //包含头文件 vector<int> vec_one; //最简单vector实例定义 int nLen = 10; vector<int> vec_fir(nLen); //分配nLen个空间,并且每个空间初始化为0(默认值) int nData1 = vec_fir.front(); //查询vector中第一个元素 int nData2 = vec_fir.back(); //查询vector中最后一个个元素 int nData3 = vec_fir.at(8); //查询vector中索引为8(即第9个)元素 int nData4 = vec_fir[8]; //同上,operator[]运算符重载 vec_fir.assign(10,2); //重新赋值vec_fir实例中数据为10个2 vec_fir.assign(vec_sed.begin(),vec_sed.end()); //重新赋值vec_fir为vec_sed vec_fir.push_back(10) //vector尾部添加一个10数据 vec_fir.pop_back() //删除vector尾部一个数据 vec_fir.erase(vec_fir.begin()); //删除vec_fir第一个数据(索引删除),指定位置删除,返回下一个数据的位置 vec_fir.erase(vec_fir.begin(),vec_fir.begin()+5); //删除vec_fir第一个到第五个间断数据,返回下一个数据的位置
vec_fir.insert(vec_fir.begin(),10086); //开始位置插入一个10086数据 vec_fir.insert(vec_fir.begin(),10,99); //开始位置插入10个初始化为99的数据集 vec_fir.insert(vec_fir.begin(),vec_sed.begin(), vec_sed.begin()+5); //将vec_sed开始的5个数插入在vec_fir开头
vec_fir.size(); //求解vector数据个数 //重新定义空间大小为100个空间,空间增加了则新增空间初始化为0,缩小了就仅保留前100个数据 vec_fir.resize(100); vec_fir.clear(); // 清空vector vec_fir.swap(vec_sed); //交换两个vector中所有数据
(1)vector容器实现迭代器,元素遍历
- 开始指针:vec.begin();
- 末尾指针:vec.end(); //指向最后一个元素的下一个位置
//正向迭代器,输出:1 3 5 7 9 vector<int>::iterator it; for (it = vec.begin(); it != vec.end(); it++) cout << *it << endl; //反向迭代器,输出:9 7 5 3 1 vector<int>::reverse_iterator rit; for (rit = vec.rbegin(); rit != vec.rend(); rit++) cout << *rit << endl; //常规的循环输出,输出:1 3 5 7 9 for (int i = 0; i < vec.size(); ++i) { cout << vec[i] << endl; }
(2)几种重要的操作
头文件要包含:#include<algorithm>
(1)sort(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
(2)reverse(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
(3)copy(a.begin(),a.end(),b.begin()+1); //把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素
(4)find(a.begin(),a.end(),10); //在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
2、list基本操作
list中各个元素之间也存在一个线性的逻辑次序,但是与vector极其不同的是,各单元的物理地址可以任意,无需是连续的空间分配。
这个算是一个技巧的介绍,有时候为了方便程序维护与以后修改,我们可以在程序头类型定义对应的模板类为一个简化名称(一般大写表示),如下。这样的好处就是一旦后面我们想用list<long>
定义我们的变量,只需在此修改list<int>
为list<long>
,从而不需要整个程序中修改了。此外取一个通俗易懂的名称也会增加程序的通读行。
#include<list> typedef list<int> INTLIST; typerdef vector<long> LONGVECTOR; typerdef list<int>::iterator INTLISTITER; INTLIST list_fir; //声明一个list<int>对象
list<int> list_fir; //或者INTLIST list_fir,这里不去简写 list<int> list_sed(10,2); // 申请10个空间,全部初始化为2 list<int> list_thd(list_fir); //拷贝构造 vector<int> vec(10,1); list<int> list_for(vec.begin(),vec.end()); //拷贝vector一段数据初始化
//拼接方法 list_fir.merge(list_sed); // 拼接加在list_fir上,而list_sed变为空 list_fir.splice(list_fir.begin(),list_sed); //在list_fir初始位置拼接上list_sed list_fir.push_back(110); //尾部增加一个110数 list_fir.push_front(1); //首部增加一个1数 list_fir.pop_back(); //尾部删除一个数 list_fir.pop_front(); //首部删除一个数 //访问 int data1 = list_fir.front(); // 第一个数 int data2 = list_fir.back(); // 最后一个数 list<int>::iterator iter; for(iter=list_fir.begin();iter!=list_end();iter++) { cout<<*iter<<endl; //就像指针一样*间接访问每个数 }
size_t = list_fir.size(); // 统计list中数据个数 list_fir.unique(); // 链表中每个连续出现的数仅保留第一次出现的那个 if(!list_fir.empty()) // 判断链表中是否为空 { list_fir.clear(); // 清空链表 } list_fir.swap(list_sed);// 交换两个链表所有数据 list_fir.sort(); // 增序排序整个链表
list_fir.insert(list_fir.front()+3, 100); // 插入元素100,是将第三个元素放到第四个上,依次类推,把100放到第三个元素上
list_fir.erase(beg, end) // 删除区间内的数据,左闭右开,返回下一个数据的位置,比如:0 1 2 3 4 5,beg=0,end=3 ,删除后结果为:3 4 5
list_fir.erase(pos) // 删除该位置的数据,返回下一个数据的位置
list_fir.remove(elem) // 删除容器中 所有与 elem 值相匹配的元素
3、双向队列 — deque
deque双向队列是一种双向开口的连续线性空间,可以高效的在头尾两端插入和删除元素,deque在STL中接口上和vector非常相似,此外它还是STL中queue和stack的底层依赖组件。
deque拥有一个bitmap结构(称之为map,并不是STL中容器map),map中每一个元素指向一块连续的内存块,后者才是真正存储deque元素的地方,因为每个块都是固定大小的,但是每个块之间不要求是连续的,所以扩充空间的时候,就没有vector那样的副作用了,即无需“配置新空间 / 移动旧数据 / 释放旧空间”的一套过程。
#include<deque> deque<string> deq_fir; cout<<deq_fir[2]<<endl; //同样是查询下标为2的元素,即第三个元素 cout<<deq_fir.front()<<endl; //查询第一个元素 cout<<deq_fir.back()<<endl; //查询最后一个元素 deq_fir.erase(deq_fir.begin()+5); //删除第五个元素 deq_fir.erase(deq_fir.begin(),deq_fir.begin()+3); //删除前三个元素
deq_fir.insert(deq_fir.begin(),10,"banana!"); //首部插入10个"banana!"字符串 deq_Fir.insert(deq_fir.end(),"apple!"); //尾部插入一个“apple!”字符串 deq_fir.push_back("hello"); //尾部添加字符串 deq_fir.push_front("world!");//首部添加字符串 deq_fir.pop_back(); //尾部删除一个元素 deq_fir.pop_front(); //首部删除一个元素
if(!deq_fir.empty()) // 判断是否为空deque { deq_fir.clear(); // 清空操作 } if(deq_fir.size() > 10) // 查询空间元素个数 deq_fir.resize(10); // 重新定义deque空间大小到10 deq_fir.swap(deq_sed); // 交换两个deque中所有数据
//正向迭代器,输出:1 3 5 7 9 deque<int>::iterator it; for (it = deq.begin(); it != deq.end(); it++) cout << *it << endl; // 查找数组中 某个元素 的位置下标 it = find(deq.begin(), deq.end(), 5); if (it != deq.end()) { cout << "5数组的下标为:" << distance(deq.begin(), it) << endl; } else { cout << "n没有找到5的元素" << endl; }
4、queue基本操作
它是一种先进先出(First In First Out ,简称FIFO)的线性表。只允许在表的尾端进行入队,而在首端进行出队。
#include<queue> queue<int> que_fir; queue<double> que_sed;
que_fir.push(1); // 放入一个元素1在队列尾部 que_fir.pop(); // 删除队首一个元素 que_fir.back(); // 访问队尾元素 que_fir.front(); // 访问队首元素 if(!que_fir.empty()); // 判断队列是否为空 que_fir.swap(que_sed); // 完全交换两个队列中数据,当然两个队列中保存的必须是一种数据类型 que_fir.size(); // 队列中元素个数
5、stack基本操作
栈只有一个出口,像下面一摞椅子一样,只能在栈顶上增加元素,也只能从栈顶移出元素和访问元素。
#include<stack> stack<int> stk_fir; stack<string> stk_sed; stk_fir.push(10086); // 栈顶入栈元素10086 stk_fir.pop(); // 删除一个栈顶元素 stk_fir.top(); // 访问栈顶一个元素(而queue可以访问队首和队尾,分别是front()和back()方法) stk_fir.size(); // 返回栈中元素个数 stk_fir.swap(stk_thd); // 交换两个相同类型的stack中所有数据 stk_fir.empty(); // 栈中为空则返回true
6、priority_queue基本操作
#include<queue>
priority_queue<int> que1; // 普通构造,默认是大顶堆 priority_queue<int, vector<int>, less<int>> //大顶堆:表示其他都比堆顶小 priority_queue<int, vector<int>, greater<int>> //小顶堆:表示其他都比堆顶大
que1.empty( ); // 判断队列是否为空 que1.pop( ); // 删除队顶元素 que1.push( ); // 加入一个元素 que1.size( ); // 返回优先队列中拥有的元素个数 que1.top( ); // 返回队顶元素,接口和stack名一样。而queue中是front()和back()
7、map(红黑树)
#include<map> map<int,float> map_sed; map_sed.insert(pair<int,float>(100 , 0.1234)); //方法一,当map中有这个关键字就不可以操作 map_sed.insert(map<int,float>::value_type(110,100.86)); //方法二,同方法一 map_sed[120] = 10000; // 方法三,可以重载
当然前两种方式是一样的,都是用insert函数插入数据。但是数据的插入涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是插入数据不了的,但是用operator[]重载的方式就不同了,它可以覆盖以前该关键字对应的值。
map<int,float> map_fir; map_fir.swap(map_sed); // 交换所有数据,需要确保map中元素类型相同 map_fir.clear(); // 清空map_fir map_fir.size(); // 统计map_fir中元素个数 map_fir.empty(); // 判断map中是否为空,如果是空则返回1
参考:https://blog.csdn.net/column/details/16577.html