一 vector
Vector通常叫做变长数组或长度根据需要而自动改变的数组。
要使用vector需要添加头文件
#include <vector>
并在头文件下面添加语句
using namespace std;
1 vector的定义
//单独定义一个vector
vector<typename> name;
这其实是定义了一维数组,只不过数组长度可以根据长度变化,节省空间。其中typename可以为任意类型,如Int/double/char/结构体也可以是STL标准容器如vector/set/queue等。如果tyename也是一个STL容器,定义的时候记得在>>符号之间加上空格,避免有的编译器把它看作移位操作,导致编译错误。
//typename为一个容器,其实可以看作二维数组
vector<vector<int> > my_vector;
vector数组的定义(vector数组可以看做2个维数都可变长的二维数组)
vector<typename> arrayname[arraysize];
//举例如下
vector<int> vi[100];
其中vi[0]--vi[99]都是一个vector容器.
这种写法与上面vector<vector<int> > my_vector的写法的区别,这种写法已经固定了一个维度的长度,而另一个不是。
请注意 初始化操作
#include <vector>
using namespace std;
int main()
{
vector<int> vi(5);
for(vector<int>::iterator it=vi.begin();it!=vi.end();it++)
printf("%d ",*it);
printf("\n");
vector<int> vec(5,2);
vector<int> vec2(vec);
vector<int> vec3(vec2.begin(),vec2.begin()+2);
int a[3]={3,6,9};
vector<int> vec4(a,a+3);
for(vector<int>::iterator it2=vec3.begin();it2!=vec3.end();it2++)
printf("%d ",*it2);
printf("\n");
for(vector<int>::iterator it3=vec4.begin();it3!=vec4.end();it3++)
printf("%d ",*it3);
printf("\n");
return 0;
}
详见博客
2 vector容器元素的访问
一般vector有两种访问方式:通过下标访问和通过迭代器访问。
(1)通过下标访问
与访问普通数组元素一样。对于容器
vector<int> apple;
可以直接访问apple[index]即可,当然index的下标是从0到apple.size()-1;访问这个范围之外的元素都会出错。
(2)通过迭代器访问
迭代器看起来像是一个类似指针的东西,它的定义为
vector<typename>::iterator it;
//迭代器可以实现自增自减操作 ++i,i++,--i,i--
//注意,并不是所有的STL容器的迭代器都可以自增或自减
#include <cstdio>
#include <vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i=1;i<=5;i++)
vi.push_back(i);
//Begin()取vi的首元素地址,end()取尾元素地址的下一个地址
vector<int>::iterator it=vi.begin();
//注意 vector不支持it<vi.end()只能用!=代替
for(;it!=vi.end();it++)
printf("%d ",*it);
printf("\n");
//也可以用
it=vi.begin();
for(int i=0;i<5;i++)
printf("%d ",*(it+i));
return 0;
}
注意:在STL容器中。只有vector和string中才允许使用vi.begin()+3这种迭代器加上整数的写法。
3 vector常用函数
(1)push_back()
vector<int> vi;
vi.push_back(x); //在vector后面添加一个元素x,时间复杂度为O(1)
(2) pop_back()
vector<double> hui;
hui.pop_back(); //不带参数,从末尾删除vector的尾元素,时间复杂度为O(1)
(3)size()
vector<float> length;
//size()用来获取vector中元素个数,时间复杂度为O(1),size()的返回类型为unsigned类型,不过一般来说用%d不会出很大问题。
printf("%d",length.size());
(4) clear()
//clear()用来清空vector中所有元素,时间复杂度为O(N),其中N为vector元素个数。
vector<int> number;
number.clear();
(5) insert()
//insert(it,x)用于向vector的任意迭代器it处插入一个元素x,时间复杂度为O(N)
vector<int> numbers;
numbers.insert(numbers.begin()+2,4); //将4插入到numbers[2]的位置
(6) erase()
erase()有2种用法:删除单个元素,删除一个区间内所有元素。时间复杂度均为O(N)
1) 删除单个元素
erase(it)即删除迭代器为it处的元素。
#include <cstdio>
#include <vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i=1;i<=5;i++)
vi.push_back(i);
vector<int>::iterator it=vi.begin();
//注意 vector不支持it<vi.end()只能用!=代替
vi.erase(it+2); //删除vi[2]处的元素,即删除3
for(int j=0;j<vi.size();j++)
{
printf("%d ",vi[j]);
}
return 0;
}
2)删除一个区间中所有元素
erase(first,last)即删除[first,last)内所有元素。
#include <cstdio>
#include <vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i=1;i<=5;i++)
vi.push_back(i);
vi.erase(vi.begin(),vi.end()); //删除所有元素
printf("%d\n",vi.size());
return 0;
}
4 vector的常见用途
(1)存储数据
vector本身可以作为数组使用,而且在一些元素个数不很确定的场合可以很好地节省空间。
(2)用邻接表存储图
此处先留白,后续补实例
二 queue
queue可以看作数据结构中的队列,在STL中主要是一个先进先出的容器。
1 queue的定义
#include <queue>
using namespace std;
queue<typename> vi; //typename可以是任意基本类型或容器
2 queue内容器元素的访问
由于队列本来就是一种先进先出的的限制性数据结构,因此在STL中只可以通过front()来访问队首元素或者通过back()来访问队尾元素。不可以随机访问也不可以使用迭代器。
#include <cstdio>
#include <queue>
using namespace std;
int main()
{
queue<int> q;
for(int i=1;i<=5;i++)
q.push(i); //push是进队操作
printf("%d %d\n",q.front(),q.back());
return 0;
}
3 queue常见函数
(1) push()
push(x) 将x元素入队,时间复杂度为O(1)
(2) front(),back()
分别获得队首元素和队尾元素,时间复杂度为O(1)
(3) pop()
令队首元素出队,时间复杂度为O(1)
#include <cstdio>
#include <queue>
using namespace std;
int main()
{
queue<int> q;
for(int i=1;i<=5;i++)
q.push(i); //push是进队操作
q.pop(); //出队操作
printf("%d\n",q.front());
return 0;
}
(4) empty()
检测队列是否为空,若是,返回True,否则返回false,时间复杂度为O(1)
#include <cstdio>
#include <queue>
using namespace std;
int main()
{
queue<int> q;
for(int i=1;i<=5;i++)
q.push(i); //push是进队操作
q.pop(); //出队操作
if(q.empty()==false)
printf("%d\n",q.front());
else
printf("no element in q\n");
return 0;
}
(5) size()
返回queue中的元素,时间复杂度为O(1).
4 清空队列的操作
queue没有clear()函数
清空可以有3种方式
第一种:直接用空的队列对象赋值
第二种:遍历出队列
第三种:使用swap,这种是最高效的,定义clear,保持STL容器的标准
#include <cstdio>
#include <queue>
using namespace std;
int main()
{
queue<int> q;
for(int i=1;i<=5;i++)
q.push(i); //push是进队操作
printf("%d\n",q.size());
q=queue<int>();
printf("%d \n",q.size());
q.push(3);
printf("%d\n",q.size());
while(!q.empty())
q.pop();
printf("%d\n",q.size());
q.push(4);
printf("%d\n",q.size());
queue<int> empty;
swap(q,empty);
printf("%d\n",q.size());
}
5 queue的常见用途
在实现广度优先遍历的时候,可以用到队列,不妨用STL中queue代替。
在使用pop()或front()函数前,必须用empty()来判断队列是否为空,否则可能出错。
STL中还有2个容器和队列有关,分别是双端队列(deque)和优先队列(priority_queue)。前者是首尾皆可插入和删除的队列,后者是使用堆实现的默认将当前队列的最大元素置于队首的容器。
三 priority_queue
priority_queue又名优先队列,其底层是用堆来实现的,在优先队列中,队首元素一定是当前队列中优先级最高的那一个。当往优先队列中添加元素时,优先队列的底层数据结构堆会随时调整结构,使得每次队首元素都是优先级最大的。
1 priority_queue的定义
#include <queue>
using namespace std;
priority_queue<typename> q;
2 元素的访问
#include <cstdio>
#include <queue>
using namespace std;
int main()
{
priority_queue<int> q;
q.push(3);
q.push(2);
q.push(6);
printf("%d",q.top());
return 0;
}
3 常用函数实例
(1)push()
push(x)将x入队,时间复杂度位O(logN),N位当前优先队列中元素个数。
(2)top()
获得队首元素,时间复杂度位O(1)
(3)pop()
令队首元素出队,时间复杂度位O(logN),N位当前优先队列中元素个数。
(4)empty()
判断当前队列是否为空,返回true为空,时间复杂度位O(1)
(5)size()
返回优先队列中元素个数,时间复杂度位O(1)
4 元素优先级的设置
(1) 基本数据类型的优先级设置
基本数据类型指int,double,char型等可以直接使用的数据类型,优先队列对它们的优先级设置一般是数字大的优先级越高,因此队首元素是优先队列元素最大的那个。对基本类型来说,有两种优先队列的定义。
priority_queue<int> q;
priority_queue<int,vector<int>,less<int> >q;
第二种定义方式多出了2个参数,一个是vector<int>,另一个是less<int>。其中vector<int>指的是承载底层数据结构堆的容器,若第一个参数是double,则第二个参数就相应变为vector<double>。第三个参数less<int>则是对第一个参数的比较类,less<int>表示数字大的优先级越大,而greater<int>表示数字小的优先级越大。
因此,若想让优先队列把最小元素放在队首,只需定义:
priority_queue<int,vector<int>,greater<int>> q;
.如下所示:
#include <cstdio>
#include <queue>
using namespace std;
int main()
{
priority_queue<int,vector<int>,greater<int> > q;
q.push(3);
q.push(2);
q.push(6);
printf("%d",q.top());
return 0;
}
(2)结构体的优先级设置
struct fruit{
string name;
int price;
};
如果希望按照水果价格的高低进行优先级的排序,便需要重载小于号“<”。
struct fruit{
string name;
int price;
friend bool operator < (fruit f1,fruit f2)
{
return f1.price<f2.price;
}
};
结构体中增加了一个友元函数。(只可以重载小于号,重载大于号会发生编译错误,f1>f2等价于f2<f1,f1==f2等价于!(f1<f2)&&!(f2<f1))这里重载小于号还是小于的含义,因此以价格高的水果位优先级高(priority_queue永远把优先级高的元素放在前面)
下面重载小于号是大于的含义,以价格低的水果位优先级高
#include <iostream>
#include <queue>
#include <string>
using namespace std;
struct fruit{
string name;
int price;
friend bool operator < (const fruit &f1,const fruit &f2)
{
return f1.price>f2.price; //把价格低的优先级设为高,即队列中存放的是价格低到价格高的
}
};
int main()
{
priority_queue<fruit> q;
fruit f1,f2,f3;
f1.name="peach";
f1.price=3;
f2.name="apple";
f2.price=4;
f3.name="orange";
f3.price=5;
q.push(f1);
q.push(f2);
q.push(f3);
cout<<q.top().name<<" "<<q.top().price<<endl;
return 0;
}
四 deque
deque容器类与vector类似,支持随机访问和快速插入删除,它在容器中某一位置上的操作所花费的是线性时间。与vector不同的是,deque还支持从开始端插入数据:push_front()。
1 deque的定义
#include <deque>
using namespace std;
deque<int> c;
2 deque中元素的访问
与vector一样,deque也有2中访问方式,随机访问和迭代器访问
(1) 随机访问
c.at(pos)返回索引为pos的位置的元素,会执行边界检查,如果越界抛出out_of_range异常
c.operator[]下标运算符重载
c.front()返回c容器的第一个元素
c.back()返回c容器的最后一个元素
#include <cstdio>
#include <deque>
using namespace std;
int main()
{
deque<int> dq;
for(int i=1;i<=5;i++)
dq.push_back(i);
deque<int>::iterator it=dq.begin();
printf("%d\n",dq.at(2));
printf("%d\n",dq[2]);
printf("%d\n",dq.front());
printf("%d\n",dq.back());
return 0;
}
(2) 迭代器访问
c.begin()返回指向第一个元素的迭代器
c.end()返回指向最后一个元素下一个位置的迭代器
c.rbegin()返回指向反向队列的第一个元素的迭代器(即原队列的最后一个元素)
c.rend()返回指向反向队列的最后一个元素的下一个位置(即原队列的第一个元素的前一个位置)
注意要使用反向迭代器时,必须要重新定义反向迭代器!reverse_iterator
#include <cstdio>
#include <deque>
using namespace std;
int main()
{
deque<int> dq;
for(int i=1;i<=5;i++)
dq.push_back(i);
deque<int>::iterator it=dq.begin();
printf("正序:");
for(;it!=dq.end();it++)
{
printf("%d ",*it);
}
printf("\n");
deque<int>::reverse_iterator id=dq.rbegin();
printf("倒序:");
for(;id!=dq.rend();id++)
{
printf("%d ",*id);
}
return 0;
}
3 deque常见函数
(1) c.size()/c.resize()/c.max_size()
第一个返回deque实际拥有的元素个数 第二个重新定义deque的大小 第三个返回容器可能存放元素的最大数值
#include <cstdio>
#include <deque>
using namespace std;
int main()
{
deque<int> dq;
for(int i=1;i<=5;i++)
dq.push_back(i);
deque<int>::iterator it=dq.begin();
printf("size: %d %d\n",dq.size(),dq.max_size());
dq.resize(dq.size()+5);
printf("resize :%d %d\n",dq.size(),dq.max_size());
dq.resize(15);
printf("reresize :%d %d\n",dq.size(),dq.max_size());
return 0;
}
(2) c.clear()/c.empty
清除容器中所有元素
判断容器是否为空,若是,返回true
(3) c.insert()
c.insert(pos,num)在pos位置插入元素num
c.insert(pos,n,num)在pos位置插入n个元素num
c.insert(pos,beg,end)在pos位置插入区间为[beg,end)的元素
#include <cstdio>
#include <deque>
using namespace std;
int main()
{
deque<int> dq;
for(int i=1;i<=5;i++)
dq.push_back(i);
printf("size: %d %d\n",dq.size(),dq.max_size());
dq.insert(dq.end(),6);
dq.insert(dq.begin(),0);
dq.insert(dq.end(),3,7);
int a[4]={8,9,10,11};
dq.insert(dq.end(),a,a+2);
deque<int>::iterator it=dq.begin();
for(;it!=dq.end();it++)
printf("%d ",*it);
return 0;
}
(4) c.erase()
c.erase(pos)删除pos位置的元素c.erase(beg,end)删除区间为[beg,end)的元素
c.erase(beg,end)删除区间为[beg,end)之间的元素
#include <cstdio>
#include <deque>
using namespace std;
int main()
{
deque<int> dq;
for(int i=1;i<=5;i++)
dq.push_back(i);
dq.erase(dq.begin());
dq.erase(dq.begin(),dq.begin()+2);
deque<int>::iterator it=dq.begin();
for(;it!=dq.end();it++)
printf("%d ",*it);
return 0;
}
(5) c.push_back(num)/c.pop_back()/c.push_front(num)/c.pop_front()
分别为从后端入队,出队,从前端入队,出队
出队前需判断是否队列为空。
(6) c.swap()/swap()
c1.swap(c2)交换容器c1,c2;
swap(c1,c2)同上。
#include <cstdio>
#include <deque>
using namespace std;
int main()
{
deque<int> dq1;
for(int i=1;i<=5;i++)
dq1.push_back(i);
deque<int> dq2;
for(int i=1;i<=5;i++)
dq2.push_back(i*2);
dq1.swap(dq2);
deque<int>::iterator it=dq1.begin();
for(;it!=dq1.end();it++)
printf("%d ",*it);
return 0;
}
可参见博客
五 stack
stack在数据结构中是一种先进后出的数据结构,在STL中是一个先进后出的容器。
1 stack的定义
#include <stack>
using namespace std;
stack<typename> s; //typename可以是任意基本类型或容器
2 stack容器内元素的访问
由于栈本身就是一种后进先出的数据结构,在STL的stack容器中只可以通过top()来访问栈顶元素,不可以随机访问,当然也不可以使用迭代器。
#include <cstdio>
#include <stack>
using namespace std;
int main()
{
stack<int> s;
for(int i=1;i<=5;i++)
{
s.push(i); //压栈处理
}
printf("%d\n",s.top()); //获得栈顶元素
return 0;
}
3 常用函数
(1) push()
push(x)将元素x入栈,时间复杂度为O(1)
(2) top()
top()获得栈顶元素,时间复杂度为O(1)
(3) pop()
pop()弹出栈顶元素,时间复杂度为O(1)
(4) empty()
检验是否为空,为空返回true 否则返回false 时间复杂度为O(1) 在弹出元素之前或取栈顶元素之前要判断是否为空,不然会出错。
(5) size()
返回stack内元素个数,时间复杂度为O(1)
4 stack的常见用途
可以用栈来模拟递归。