STL常用容器
3.3 deque容器
3.3.1 deque容器的基本概念
1. 功能:
双端数组,可以对头端和尾端进行插入删除操作
2. deque与vector区别:
vector对于头部的插入和删除效率低,数据量越大,效率越低。(需要将所有数据后移,将头部位置空出,才可插入数据)
相对而言,deque对头部的插入和删除速度比vector快
vector访问元素的速度比deque快,这和两者内部实现有关。
3. deque内部工作原理:
deque内部有一个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据。中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间。
和 vector 容器采用连续的线性空间不同,deque 容器存储数据的空间是由一段一段等长的连续空间构成,各段空间之间并不一定是连续的,可以位于在内存的不同区域。
为了管理这些连续空间,deque 容器用数组存储着各个连续空间的首地址。也就是说,数组中存储的都是指针,指向那些真正用来存储数据的各个连续空间。
通过建立数组,deque 容器申请的这些分段的连续空间就能实现“整体连续”的效果。换句话说,当 deque 容器需要在头部或尾部增加存储空间时,它会申请一段新的连续空间,同时在数组的开头或结尾添加指向该空间的指针,由此该空间就串接到了 deque 容器的头部或尾部。
deque 容器的分段存储结构,提高了在序列两端添加或删除元素的效率,但访问速度比vector慢,并且也使该容器迭代器的底层实现变得更复杂。
4. deque容器迭代器的底层实现:
由于 deque 容器底层将序列中的元素分别存储到了不同段的连续空间中,因此要想实现迭代器的功能,必须先解决如下两个问题:
①迭代器在遍历 deque 容器时,必须能够确认各个连续空间在数组中的位置;
②迭代器在遍历某个具体的连续空间时,必须能够判断自己是否已经处于空间的边缘位置。如果是,则一旦前进或者后退,就需要跳跃到上一个或者下一个连续空间中。
实现:迭代器内部包含4个指针,它们各自的作用为:
cur:指向当前正在遍历的元素;
first:指向当前连续空间的首地址;
last:指向当前连续空间的末尾地址;
node:它是一个二级指针,用于指向数组中存储的指向当前连续空间的指针。
3.3.2 deque构造函数
函数原型:
(和vector的构造函数基本一样,灵活使用即可。)
deque<T> deqT; // 默认构造
deque(beg,end); // 构造函数将[beg,end)区间中的元素拷贝给本身
deque(n,elem); // n个elem拷贝给本身
deque(const deque &deq); // 拷贝构造函数
示例:
#include<iostream>
using namespace std;
#include<deque>
// 输出接口
void printDeque(const deque<int> &d)
{
for(deque<int>::const_iterator it=d.begin();it!=d.end();it++)
{
// *it = 100; // const的修饰是的容器中的数据不可修改,此时为只读迭代器
cout << *it << " ";
}
cout << endl;
}
void test01()
{
// 四种构造方式
deque<int> d1;
for(int i = 0;i<10;i++)
{
d1.push_back(i);
}
printDeque(d1);
deque<int> d2(d1.begin(),d1.end());
printDeque(d2);
deque<int> d3(10,100);
printDeque(d3);
deque<int> d4(d3);
printDeque(d4);
}
int main()
{
test01();
system("pause");
return 0;
}
输出打印函数中,想要进行只读操作的时候,需要对形参和迭代器同时用const进行修饰
运行结果:
3.3.3 deque赋值操作
函数原型:
deque& operator=(const deque& deq); // 重载等号操作符
assign(beg,end); // 将[beg,end)区间中的数据拷贝赋值给本身
assign(n,elem); // 将n个elem拷贝赋值给本身
示例:
#include<iostream>
using namespace std;
#include<deque>
void printDeque(const deque<int> d)
{
for(deque<int>::const_iterator it = d.begin();it!=d.end();it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
deque<int> d1;
for(int i = 0;i<10;i++)
{
d1.push_back(i);
}
printDeque(d1);
deque<int> d2;
d2 = d1;
printDeque(d2);
deque<int> d3;
d3.assign(d1.begin(),d1.end());
printDeque(d3);
deque<int> d4;
d4.assign(10,100);
printDeque(d4);
}
int main()
{
test01();
system("pause");
return 0;
}
运行结果:
3.3.4 deque大小操作
函数原型:
deque.empty(); // 判断容器是否为空,空返回true,非空返回false
deque.size(); // 返回容器中元素的个数(大小,当前存放数据个数)
deque.resize(int num); // 重新指定容器的长度为num
// 若容器变长,则以默认值0填充新位置;如果变短,则末尾超出容器长度的元素被删除
deque.resize(int num,elem); // 重新指定容器的长度为num
// 若容器变长,则以elem填充新位置;如果变短,则末尾超出容器长度的元素被删除
(deque容器没有容量的概念)
示例:
#include<iostream>
using namespace std;
#include<deque>
void printDeque(const deque<int> &d)
{
for(deque<int>::const_iterator it = d.begin();it!=d.end();it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
deque<int> d1;
for(int i= 0;i<10;i++)
{
d1.push_back(i);
}
printDeque(d1);
if(d1.empty())
cout << "该deque容器为空!" << endl;
else
{
cout << "该容器不为空," << endl;
cout << "容器大小为:" << d1.size() << endl;
}
d1.resize(15);
printDeque(d1);
d1.resize(5);
printDeque(d1);
d1.resize(15,10);
printDeque(d1);
}
int main()
{
test01();
system("pause");
return 0;
}
运行结果:
3.3.5 deque插入和删除
函数原型:
/******** 两端的插入和删除 ********/
push_back(elem); // 在容器尾部添加一个数据
push_front(elem); // 在容器头部插入一个数据
pop_back(); // 删除容器最后一个数据
pop_front(); // 删除容器第一个数据
/******** 指定位置的插入和删除 ********/
insert(pos,elem); // 在pos位置插入一个elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem); // 在pos位置插入n个elem数据,无返回值
insert(pos,beg,end); // 在pos位置插入[beg,end)区间的数据,无返回值
clear(); // 清空容器的所有数据
erase(beg,end); // 删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos); // 删除pos位置的数据,返回下一个数据的位置。
示例:
#include<iostream>
using namespace std;
#include<deque>
void printDeque(const deque<int> d)
{
for(deque<int>::const_iterator it = d.begin();it!=d.end();it++)
cout << *it <<" ";
cout << endl;
}
// 两端操作
void test01()
{
cout << "两端操作" << endl;
cout << "=========" << endl;
deque<int> d1;
//尾插
d1.push_back(10);
d1.push_back(20);
//头插
d1.push_front(100);
d1.push_front(200);
printDeque(d1);
// 尾删
d1.pop_back();
// 头删
d1.pop_front();
printDeque(d1);
}
// 指定位置
void test02()
{
cout << "Insert指定位置操作" << endl;
cout << "=========" << endl;
deque<int> d1;
d1.push_back(10);
d1.push_back(20);
d1.push_front(100);
d1.push_front(200);
printDeque(d1);
// insert
d1.insert(d1.begin(),1000);
printDeque(d1);
d1.insert(d1.begin(),2,100);
printDeque(d1);
// insert --- 区间
deque<int> d2;
for(int i = 1;i<6;i++)
d2.push_back(i);
printDeque(d2);
d1.insert(d1.begin(),d2.begin(),d2.end());
printDeque(d1);
}
// 删除操作
void test03()
{
cout << "删除操作" << endl;
cout << "=========" << endl;
deque<int> d1;
d1.push_back(10);
d1.push_back(20);
d1.push_front(100);
d1.push_front(200);
printDeque(d1);
// 删除
deque<int>:: iterator it = d1.begin();
it ++ ; // 迭代器偏移 删除指定位置的元素
d1.erase(it);
printDeque(d1);
d1.erase(d1.begin(),d1.end());
//d1.clear();
printDeque(d1); // 打印一个换行
}
int main()
{
test01();
test02();
test03();
system("pause");
return 0;
}
执行结果:
3.2.6 deque数据存取
函数原型:
at(int idx); // 返回索引idx所指的数据
operator[]; // 返回索引idx所指的数据
front(); // 返回容器中第一个数据元素
back(); // 返回容器中最后一个数据元素
示例:
#include<iostream>
using namespace std;
#include<deque>
void test01()
{
deque<int> d;
d.push_back(10);
d.push_back(20);
d.push_back(30);
d.push_front(100);
d.push_front(200);
d.push_front(300);
// 通过 [] 访问元素并输出
for(int i=0;i<d.size();i++)
{
cout << d[i]<< " ";
}
cout << endl;
// 通过 at 访问元素并输出
for(int i=0;i<d.size();i++)
{
cout << d.at(i)<< " ";
}
cout << endl;
cout << "第一个元素为:" << d.front() << endl;
cout << "最后一个元素为:" << d.back() << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
运行结果:
3.3.7 deque排序
利用算法实现对deque容器进行排序。
函数原型:
sort(iterator beg,iterator end); //对beg和end区间内元素进行排序
默认的排序规则时从小到大,即升序。
对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序。
示例:
#include<iostream>
using namespace std;
#include<deque>
#include<algorithm> // 包含头文件
void printDeque(const deque<int> &d)
{
for(deque<int>::const_iterator it=d.begin();it!=d.end();it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
deque<int> d;
d.push_back(10);
d.push_back(20);
d.push_back(30);
d.push_front(100);
d.push_front(200);
d.push_front(300);
printDeque(d);
// 排序
sort(d.begin(),d.end());
cout << "排序后:";
printDeque(d);
}
int main()
{
test01();
system("pause");
return 0;
}