C++中容器的定义
数据存储上,有一种对象类型,它可以持有其他对象或指向其他对象的指针,这种对象类型叫容器。通俗地说容器就是保存其他对象的对象,这种“对象”还包含了一些处理其他对象的方法,这也体现了容器类的一个好处,“容器类是一种对特定代码重用问题的良好的解决方案”。容器另一个好处就是可以自行扩展,解决问题时通常不知道需要存储多少个对象,数组在这方面也是力不从心。容器可以申请内存、释放内存,并且使用最优的算法来执行命令。
顺序容器
顺序容器是一种各元素之间有顺序关系的线性表,是一种线性结构的可序群集。顺序容器中的每个元素均有固定的位置,除非用删除或插入的操作改变这个位置。顺序容器具有插入速度快但查找操作相对较慢的特征。
C++标准模板库里提供3种顺序容器:vector、list和deque。其中,vector类和deque类是以数组为基础的,list类是以双向链表为基础的。
向量(vector)又可以称作变长数组
vector是一个动态的顺序容器,具有连续内存地址的数据结构,通过下标运算符“[]”直接有效地访问向量的任何元素。相比于数组,vector会消耗更多的内存以有效地动态增长。而相比于其他序列容器(deques,lists),vector能更快地索引元素(就像数组一样),而且能相对高效地在尾部插入和删除元素。如果不是在尾部插入和删除元素,效率就没有这些容器高。vector可以用来以邻接表的方式储存图
注:
当需要使用vector的时候,需要包含头文件:#include < vector >,一般加上“using namespace std;”,如果不加,则在调用时候必须用std::vector<…>这样的形式,即在vector前加上std::,这表示运用的是std命名空间下的vector容器。
1、向量的声明及初始化
vector类包含了多个构造函数,其中包括默认构造函数,因此可以通过多种方式来声明和初始化向量容器。
其中元素类型可以是任何基本类型,如int,double,char,结构体…
2、元素的输入及访问
实例C++代码:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> a(10, 1);
int i;
cout << "初始化变量:";
for(i = 0; i < a.size(); i++)
cout << a[i] << " ";
cout << "\n插入数据:";
cin >> a[2];
cin >> a[5];
cin >> a[8];
for(i = 0; i < a.size(); i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
本例先用vector类创建一个大小为10初值为1的向量容器a,然后遍历出该容器,接着在容器第3、第6和第9个元素的位置插入三个新元素
运行结果如下:
3、修改元素
例如:
所有的容器都包含成员函数begin()和end()。函数begin()返回容器中第1个元素的位置,函数end()返回容器中伪元素地址的下一个地址。这两个函数都没有参数。
4、vector容器内元素的访问
(1)通过下标访问
前面已经用代码展示过了,这里就不详细讲了
(2)通过迭代器访问
样例C++代码如下:
#include<stdio.h>
#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();
for(int i = 0; i < 5; i++)
{
printf("%d ", *(it + i));
}
return 0;
}
运行结果如下:
也可用自加++方法实现上图
#include<stdio.h>
#include<vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i = 1; i <= 5; i++){
vi.push_back(i);
}
for(vector<int>::iterator it = vi.begin(); it != vi.end(); it++)
printf("%d ", *it);
//vector也支持it < vi.end()写法
return 0;
}
运行结果和上图一样
vector类包含了一个typedef iterator,这是一个public成员。通过iterator,可以声明向量容器中的迭代器。例如,声明一个向量容器迭代器:
因为iterator是一个定义在vector类中的typedef,所以必须使用容器名(vector)、容器元素类型和作用域符来使用iterator。
表达式:++it,表示将迭代器it加1,使其指向容器中的下一个元素。
表达式:*it,表示返回当前迭代器位置上的元素。
注意:实际上迭代器就是一个指针,用来存取容器中的数据元素,因此迭代器上的操作和指针上的相应操作是相同的。
5、vector常用函数push_back()
push_back(x)就是在vector后面添加一个元素x,时间复杂度为O(1)
#include<stdio.h>
#include<vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i = 1; i <= 3; i++)
vi.push_back(i);
for(int i = 0; i < vi.size(); i++)
{
printf("%d ", vi[i]);
}
return 0;
}
运行结果如下:
6、vector常用函数pop_back()
pop_back()是用来删除vector的尾元素,时间复杂度为O(1)
#include<stdio.h>
#include<vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i = 1; i <= 3; i++)
vi.push_back(i);
vi.pop_back();
for(int i = 0; i < vi.size(); i++)
printf("%d ", vi[i]);
return 0;
}
运行结果如下:
7、vector常用函数size()
size()就是用来获取vector中元素个数
#include<stdio.h>
#include<vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i = 1; i <= 3; i++)
vi.push_back(i);
printf("%d\n", vi.size());
return 0;
}
运行结果如下:
8、vector常用函数clear()
clear()用来清空vector中所有元素,时间复杂度为O(N)
#include<stdio.h>
#include<vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i = 1; i <= 3; i++)
vi.push_back(i);
vi.clear();
printf("%d\n", vi.size());
return 0;
}
运行结果如下:
9、vector常用函数insert()
insert(it, x)用来向vector的任意迭代器it处插入一个元素x,时间复杂度为O(N)
#include<stdio.h>
#include<vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i = 1; i <= 5; i++)
vi.push_back(i);
vi.insert(vi.begin() + 2, -1);
for(int i = 0; i < vi.size(); i++)
printf("%d ", vi[i]);
return 0;
}
运行结果如下:
10、vector常用函数erase()
(1)删除单个元素
erase(it)为删除迭代器为it处的元素
#include<stdio.h>
#include<vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i = 5; i <= 9; i++)
vi.push_back(i);
vi.erase(vi.begin() + 3);
for(int i = 0; i < vi.size(); i++)
printf("%d ", vi[i]);
return 0;
}
运行结果如下:
(2)删除一个区间内的所有元素
erase(first, last)为删除[first, last)内的所有元素
#include<stdio.h>
#include<vector>
using namespace std;
int main()
{
vector<int> vi;
for(int i = 5; i <= 9; i++)
vi.push_back(i);
vi.erase(vi.begin() + 1, vi.begin() + 4);
for(int i = 0; i < vi.size(); i++)
printf("%d ", vi[i]);
printf("\n");
return 0;
}
运行结果如下:
二维向量
与数组相同,向量也可以增加维数。例如,声明一个m*n大小的二维向量方式可以像如下形式:
vector< vector< int > >name;
vector< typename > Arrayname[arraySize];
以上这两种都表示二维数组,但是后者的一维长度已经固定为arraySize,另一维才是变长的
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector< vector<int> > a(3, vector<int>(4, 0));
cout << "输入:" << endl;
cin >> a[0][1];
cin >> a[1][0];
cin >> a[2][3];
cout << "输出:" << endl;
int m, n;
for(m = 0; m < a.size(); m++)
{
for(n = 0; n < a[m].size(); n++)
{
cout << a[m][n] << " ";
}
cout << '\n';
}
return 0;
}
运行结果如下:
分析:使用vector类声明了一个3行4列的二维向量容器,并且初始化值为0。最后同二维数组类似,为其赋值,并输出
综合案例:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int i = 0;
vector<int> a;
for(i = 0; i < 10; i++)
{
a.push_back(i);
}
cout << "初始化遍历:";
for(int i = 0; i < a.size(); i++)
{
cout << a[i] << " ";
}
cout << "\n迭代遍历:";
vector<int>::iterator it;
for(it = a.begin(); it != a.end(); it++)
{
cout << *it << " ";
}
cout << "\n插入遍历:";
a.insert(a.begin() + 4, 0);
for(unsigned int i = 0; i < a.size(); i++)
{
cout << a[i] << " ";
}
cout << "\n擦除遍历:";
a.erase(a.begin() + 2);
for(unsigned int i = 0; i < a.size(); i++)
{
cout << a[i] << " ";
}
cout << "\n迭代遍历:";
a.erase(a.begin() + 3, a.begin() + 5);
for(vector<int>::iterator it = a.begin(); it != a.end(); it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
运行结果如下: