C++知识点 STL容器1—vector
~vector~
vector可能是与各位选手见面次数最多的STL容器了
这是因为它在图论问题中发挥的特殊而重要的作用
简单来说vector就是一个能根据需求改变自己长度的数组
它有一个空间的初始值,一旦初始值满则向内存申请两倍的空间
同样的,它支持像数组一样使用下标访问,(不是修改)
也像数组一样不能O(1)在任意位置插入元素(链表才有这种性质)
要实现非首尾插入必须将插入位置的后面元素整体后移1才能实现
所以为保证效率,元素的插入与删除应该在数组尾进行
看下代码实现
//如何建一个vector
#include <vector>//每种容器都有单独的头文件
using namespace std;
int main() {
vector <int> a;//直接声明了一个叫做a的可变长一维数组
vector <int> b[233];
//声明了一个第一维长度固定为233,第二位长度可变的二维数组
struct Node{
long long val, tag1, tag2;
Node *rs, *ls;
}vector <Node> c;
//将名为Node的结构体压入一个vector
//结构体同样也可以存放在vector中,这点和数组一样
return 0;
}
建好了vector便可以对它进行操作了
首先是输入
和数组一样一样的操作
伪代码就是
vector <int> a;
for(int i = 1; i <= n; i++)
cin>>a[i];
这里没什么可说的
这里很有必要说一下
vector和数组最大的区别就是不能修改中间元素
必须从队尾使用bush_back函数加入新元素
用pop_back函数删除vector最后一个元素
像上面被删除的伪代码一样操作会直接导致程序崩溃
来看这波代码实现
#include <iostream>
#include <vector>
using namespace std;
vector<int>s;
int main()
{
int n;
cin>>n;
for(int i = 0; i < n; i++)
{
//输入4 1 2 3 1
int x;
cin>>x;
s.push_back(x);
}
for(int j = 0; j < n; j++)
cout<<s[j]<<" ";
return 0;
}
这里要特别注意的是
使用push_back从队尾插入元素时
第一个元素会默认插入a[0]中,而不是a[1]
我们讲完了vector的声明储存和插入
再来看size,empty,和clear函数
size返回的是一个整形,表示该vector中真实存在的元素
empty返回一个布尔,判断该vector是否为空,bool为true则vector为空
clear则可以清空一个vector
看下代码实现
#include <iostream>
#include <vector>
using namespace std;
vector<int>s;
int main()
{
int n;
cin>>n;
for(int i = 0; i < n; i++)
{
//输入4 1 2 3 1
int x;
cin>>x;
s.push_back(x);
}
cout<<"vector s 的大小是"<<s.size()<<endl;
if(!s.empty())
cout<<"s 不为空"<<endl;
else
cout<<"s 为空"<<endl;
s.clear();
if(!s.empty())
cout<<"s 不为空"<<endl;
else
cout<<"s 为空"<<endl;
return 0;
}
输出结果为:
4
s 不为空
s 为空
看完这些对vector空间的操作
我们再来看vector中的迭代器
这些玩意类似于指针
同样可以用*和->操作
首先我们可以通过
vector<int>::iterator it;
声明一个叫做it的int类型的vector迭代器
那我们这时候又不得不学两个函数
一个叫begin,一个叫end
begin返回的是vector的队首迭代器
end返回的则是vector的队尾的后一个元素的迭代器
基本上和指针大差不差
我们看一下代码实现
#include <iostream> #include <vector> using namespace std; vector<int>s; int main() { int n; cin>>n; for(int i = 0; i < n; i++) { //4 1 2 3 1 int x; cin>>x; s.push_back(x); } cout<<*s.begin()<<endl;//*和对指针的意义相同 cout<<*s.end()<<endl;for(vector<int>::iterator it = s.begin(); it != s.end(); it++) cout<<*it<<" "; return 0; }
如果你认为充分理解了这段代码所传达的含义
建议把它粘贴到编译器中运行一下
啊这
第三行我们本来期望输出此时的队尾元素1的
却出现了个诡异的数字
这就说明你还是没理解(大雾
end函数返回的是队尾的后一个元素
此时这个元素是不存在也就是没有被插入的
于是乎就出现了个诡异的数
要想访问队尾元素
我们既可以直接s[n-1]
也可以访问*s.end()--,也就是访问s.end()的前面内个元素(队尾元素
还有个叫back的函数
s.back()等价于*s.end()--
(与back相对的front函数则与*s.begin()或者s[0]等价
由于我们刚才for语句中it != s.end(),
所以当it成为队尾元素迭代器时就停止了,不会触碰下一个没有被插入的节点
vector至此即可告一段落
最后来一波vector的代码总成
希望读者在自己的机器上编译运行一下
看看是什么效果,这些函数的作用都理解了
vector也没有什么难懂的了(算法竞赛领域内
#include <iostream> #include <vector> using namespace std; vector<int>s; int main() { int n; cin>>n; for(int i = 0; i < n; i++) { //输入5 1 2 3 4 5 int x; cin>>x; s.push_back(x); } cout<<s.front()<<endl; cout<<s.back()<<endl; s.pop_back(); cout<<*s.begin()<<endl; cout<<*s.end()<<endl; cout<<*--s.end()<<endl; for(vector<int>::iterator it = s.begin(); it != s.end(); it++) cout<<*it<<" "; cout<<endl; cout<<s.size()<<endl; if(!s.empty()) cout<<"s非空"<<endl; else cout<<"s已空"<<endl; s.clear(); if(!s.empty()) cout<<"s非空"<<endl; else cout<<"s已空"<<endl; return 0; }
~END~