目录
STL容器种类
容器概念
容器,顾名思义,存储数据的器具。我们可以把它类比为数组。但是容器对象封装的许多对容器操作的方法,使用容器操作数据也更加方便。在c++中,容器类型被认为是一种可以创建具体对象的模板。容器可以被认为是一种对象。容器内的类型应该一致。容器的数据归容器所有:当容器过期时,里面的的数据也过期。(如果容器内是指针,指针指向内容并不一定过期)
容器分类
- 基本容器 不保证元素按照特定顺序存储,也不保证元素顺序不变
- 顺序容器 是对基本容器的改进,要求元素按照严格的顺序排列。即除首元素和尾元素外,每个元素前后都有一个元素。
- 关联容器 是对容器的另一种改进,关联容器要求值与键关联在一起。键,通常意义上说,是一种标识。例如,一个人的姓名通常与年龄和性别相关联。姓名是一种键值。通过姓名查找相关联的年龄和性别等信息。
- 无序关联容器 也是对容器概念的一种改进,与关联容器一样,无序关联容器也与键值相关联,他与关联容器的差别在于无序关联容器的底层实现。关联容器底层使用的是树的结构实现,无序关联容器是基于哈希表实现的。无序关联容器,具有更高效的添加,删除,查找元素的算法效率。
顺序容器
在STL中的顺序容器有以下种:vector、deque、list、forward_list根据顺序容器的特点,这些容器都有一些通用操作。
表达式 | 返回类型 | 说明 |
---|---|---|
X a(n,t); | 声明一个名为a的由n个t值组成的序列 | |
X (n,t); | 创建一个由n个t值组成的无序序列 | |
X a(i,j); | 声明一个名为a的序列,并初始化为区间[i,j)的内容 | |
X (i,j); | 创建一个匿名序列,并初始化为区间[i,j)的内容。 | |
a.insert(p,t); | 迭代器 | 将t插入p前面 |
a.insert(p,n,t); | void | 将n个t插入到p前面 |
a.insert(p,i,j); | void | 将区间[i,j)中元素插入到p前面 |
a.erase(p); | 迭代器 | 删除p指向的内容 |
a.erase(p,q) | 迭代器 | 删除区间[p,q)中的元素 |
a.clear() | void | 删除所有元素 |
说明:X指容器类型,a指代容器对象,n表示整数,p,q,i,j表示迭代器。在这里我们使用vector容器演示上述常用方法。
代码如下:
#include<iostream>
#include<vector>
#include<iterator>
using namespace std;
int main(void)
{
int n = 5;
vector<int> v_one(5, n);//将容器v_one声明为5个5
vector<int>::iterator ip;//声明vector迭代器
for (ip = v_one.begin(); ip != v_one.end(); ip++)//将容器内容输出
{
cout << *ip << " ";
}
cout << endl;
vector<int> v_two(v_one.begin(), v_one.end());//将容器v_two声明为容器v_one[v_one.begin(),v_one.end())内容
for (ip = v_two.begin(); ip != v_two.end(); ip++)
{
cout << *ip << " ";
}
cout << endl;
ip = v_two.begin() + 3;//将迭代器赋值为v_two索引值为3的指针,即第四个元素
v_two.insert(ip, 6);//在第四个5前面插入元素6
for (ip = v_two.begin(); ip != v_two.end(); ip++)
{
cout << *ip << " ";
}
cout << endl;
v_one.insert(v_one.begin() + 1, 3, 3);//在v_one中的第二个元素前插入3个3
for (ip = v_one.begin(); ip != v_one.end(); ip++)
{
cout << *ip << " ";
}
cout << endl;
v_one.insert(v_one.begin(), v_two.begin(), v_two.end());//在容器v_one首元素前插入容器v_two的所有元素
for (ip = v_one.begin(); ip != v_one.end(); ip++)
{
cout << *ip << " ";
}
cout << endl;
v_one.erase(v_one.begin());//删除v_one第一个元素
for (ip = v_one.begin(); ip != v_one.end(); ip++)
{
cout << *ip << " ";
}
cout << endl;
v_one.erase(v_one.begin(), v_one.begin() + 3);//删除容器v_one前三个元素
for (ip = v_one.begin(); ip != v_one.end(); ip++)
{
cout << *ip << " ";
}
cout << endl;
v_one.clear();//删除v_one所有元素
for (ip = v_one.begin(); ip != v_one.end(); ip++)//元素被清空返回空
{
cout << *ip << " ";
}
return 0;
}
-
vector
模板类vector 类似于String类,是一种动态数组,在STL中我们把它称为容器,可以在运行阶段设置vector对象的长度,可以在末尾附加数据,可以在中间插入数据,它是new创建动态数组的替代品,vector使用new和delete管理内存,但是是自动完成的。在头文件vector中声明了vector 的模板。
vector中常用的其他方法
表达式 | 说明 |
a.front() | 索引容器首元素 |
a.back() | 索引容器尾元素 |
a.push_back(t) | 从vector 容器结尾插入t |
a.pop_back(t) | 从vector容器后删除t |
a[n] | 索引下标为n的元素 |
a.at(t) | 索引下标为n的元素 |
示例代码:
#include<iostream>
#include<vector>
using namespace std;
int main(void)
{
int n = 5;
int i;
vector<int> v_one;
v_one.push_back(1);
v_one.push_back(2);
v_one.push_back(3);
v_one.push_back(4);
v_one.push_back(5);//向容器中插入0~5
for (int i = 0; i < n; i++)
{
cout << v_one[i]<<" ";
}
cout << endl;
cout << "v_one.front()=" << v_one.front() << endl;//输出容器首元素
cout << "v_one.back()=" << v_one.back();//输出容器尾元素
v_one.pop_back();
v_one.pop_back();//删除后两个元素
cout << endl;
for (int i = 0; i < n-2; i++)
{
cout << v_one.at(i) << " ";
}
return 0;
}
代码结果:
1 2 3 4 5
v_one.front()=1
v_one.back()=5
1 2 3
2.list
list模板类表示双向链表,定义在头文件list中。除第一个和最后一个元素外,每个元素都与前后的元素相链接。这意味着可以双向遍历容器list,我们知道链表的插入和删除的时间复杂度是O(1),所以list的插入和删除的时间是固定的。而vector 底层实现是一个动态数组,插入和删除的时间是线性的,vector 强调的是快速索引,而list强调快速地插入和删除数据。由于list的底层实现是链表,所以不允许快速访问。下面是list成员函数:
成员函数 | 说明 |
---|---|
void merge(list<T,Alloc>& x) | 将链表x与调用链表合并,且两链表内部已排序,最终链表存在调用链表中。时间复杂度为O(n) |
void remove(const T& val) | 从链表中删除示例元素,时间复杂度为O(n) |
void sort() | 将链表进行排序,时间复杂度为nlogn |
void splice(lierator pos,list<T,Alloc> x) | 将链表x的内容插入到pos前,x将为空。时间复杂度O(1) |
void unique() | 将连续相同的元素压缩为单个元素,时间复杂度为O(n) |
代码示例:
#include<iostream>
#include<list>
using namespace std;
int main(void)
{
list<int> l_one{1,1,3,5,};
list<int> l_two{6,2,4};//声明三个list,并且l_one已排好序
list<int> l_three{1,2};
l_two.sort();//将l_two排序
list<int>::iterator ls;//声明list迭代器
for (ls = l_two.begin(); ls != l_two.end(); ls++)//输出已排序后的l_two
{
cout << *ls << " ";
}
l_two.merge(l_one);//合并list_one和list_two,链表在l_two中
cout << endl;
for (ls = l_two.begin(); ls != l_two.end(); ls++)//输出已合并后的l_two
{
cout << *ls << " ";
}
l_two.splice(l_two.begin() , l_three);//在l_two前插入链表l_three内容
cout << endl;
for (ls = l_two.begin(); ls != l_two.end(); ls++)
{
cout << *ls << " ";
}
cout << endl;
l_two.unique();//压缩连续的元素为单个元素,注意不连续的元素相同无法删除
for (ls = l_two.begin(); ls != l_two.end(); ls++)
{
cout << *ls << " ";
}
l_two.remove(1);//将链表中为1的元素都删除
cout << endl;
for (ls = l_two.begin(); ls != l_two.end(); ls++)
{
cout << *ls << " ";
}
return 0;
}
代码结果:
2 4 6
1 1 2 3 4 5 6
1 2 1 1 2 3 4 5 6
1 2 1 2 3 4 5 6
2 2 3 4 5 6
容器适配器
除顺序容器外,STL定义了三个顺序容器适配器:Stack、queue、和priority_queue.适配器是是标准库的一个通用概念。容器、迭代器、和函数都有适配器。适配器接受已有的容器类型、使其行为看起来像另一种事物。例如Stack容器适配器接受一个容器,进行改造使其看起来像Stack这种结构。
1.queue
queue模板类声明在头文件queue中,根据队列的特点,模板类queue不允许随机访问队列中元素,不允许遍历队列。它的基本操作是添加队尾元素,删除队首元素,查看队首和队尾元素的值,检查队列元素,判断队列元素是否为空等。
方法 | 说明 |
---|---|
bool empty() const | 如果队列为空,返回true,否则,返回falsre |
size_type size()const | 返回队列元素的数目 |
T& front() | 返回指向队首元素的引用 |
T& back() | 返回指向队尾元素的引用 |
void push(const T& x) | 在队尾插入x |
void pop() | 删除队首元素 |
代码示例:
#include<iostream>
#include<queue>
using namespace std;
int main(void)
{
queue<int> q_one;
if (q_one.empty())//判断是否为空队列
{
cout << "queue is empty!" << endl;
q_one.push(1);
q_one.push(2);
q_one.push(3);
q_one.push(4);//从队尾插入数据
cout << "Now q_one has " << q_one.size() << " elements";//检查队列元素个数
cout << endl;
cout << "q_one.front()=" << q_one.front() << endl;
cout << "q_one.back()=" << q_one.back() << endl;
q_one.pop();
cout << "q_one.front()=" << q_one.front();
}
return 0;
}
代码结果:
2.Stack
与queue相似,stack在头文件stack中定义,不允许随机访问和遍历栈。它的操作有压入栈顶元素和弹出栈顶元素,查看栈的值,查看元素数目,测试栈是否为空。
方法 | 说明 |
---|---|
bool empty()const | 如果栈为空,则返回true,否则,返回false |
size_type size() const | 返回栈中元素数目 |
T& top() | 返回指向栈的元素的引用 |
void push(const T& x) | 在栈顶元素插入x |
void pop | 删除栈顶元素 |
示例代码:
#include<iostream>
#include<stack>
using namespace std;
int main(void)
{
stack<int> s_one;
if (s_one.empty())//判断是否为空队列
{
cout << "stack is empty!" << endl;
s_one.push(1);
s_one.push(2);
s_one.push(3);
s_one.push(4);//从队尾插入数据
cout << "Now s_one has " << s_one.size() << " elements";//检查队列元素个数
cout << endl;
cout << "s_one.top()=" << s_one.top() << endl;
s_one.pop();
cout << "s_one.top()=" << s_one.top();
}
return 0;
}
代码结果:
stack is empty!
Now s_one has 4 elements
s_one.top()=4
s_one.top()=3
关于关联容器将在下一篇中分析它们的常用用法,小伙伴们记得一键三连哦!!!