Vector 容器是单向开口的连续内存空间,deque 则是一种双向开口的连续线性空 间。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector 容器也可以在头尾两端插入元素,但是在其头部操作效率奇差,无法被接受。
Deque 容器和 vector 容器最大的差异,一在于 deque 允许使用常数项时间对头端进行元素的插入和删除操作。二在于 deque 没有容量的概念,因为它是动态的以分段连续空间组合而成,随时可以增加一段新的空间并链接起来,换句话说,像vector 那样,”旧空间不足而重新配置一块更大空间,然后复制元素,再释放旧空间”这样的事情在 deque 身上是不会发生的。也因此,deque没有必须要提供所谓的空间保留(reserve)功能. 虽然 deque 容器也提供了 Random Access Iterator,但是 它的迭代器并不是普通的指针,其复杂度和 vector 不是一个量级,这当然影响各个运算的层面。因此,除非有必要,我们应该尽可能的使用 vector,而不是 deque。对 deque 进行的排序操作,为了最高效率,可将 deque 先完整的复制到一 个 vector 中,对 vector 容器进行排序,再复制回 deque.
一、deque 容器实现原理
Deque 容器是连续的空间,至少逻辑上看来如此,连续现行空间总是令我们联想到 array 和vector,array 无法成长,vector 虽可成长,却只能向尾端成长,而且其成长其实是一个假象,事实上(1) 申请更大空间 (2)原数据复制新空间 (3)释放原空间三步骤,如果不是 vector 每次配置新的空间时都留有余裕,其成长假象所带来的代价是非常昂贵的。 Deque 是由一段一段的定量的连续空间构成。一旦有必要在 deque 前端或者尾端增加新的空间,便配置一段连续定量的空间,串接在 deque 的头端或者尾端。Deque 最大的工作就是维护这些分段连续的内存空间的整 体性的假象,并提供随机存取的接口,避开了重新配置空间,复制,释放的轮回, 代价就是复杂的迭代器架构。 既然 deque 是分段连续内存空间,那么就必须有中 央控制,维持整体连续的假象,数据结构的设计及迭代器的前进后退操作颇为繁 琐。Deque 代码的实现远比 vector 或 list 都多得多。 Deque 采取一块所谓的 map(注意,不是 STL 的 map 容器)作为主控,这里所谓的 map 是一小块连续的内 存空间,其中每一个元素(此处成为一个结点)都是一个指针,指向另一段连续性内 存空间,称作缓冲区。缓冲区才是 deque 的存储空间的主体。
deque容器和vector容器最大的差异:
a、deque插入和删除 常数项时间(不会因为数据量的大小 改变操作所耗时)
b、deque容器没有容量的概念 以分段连续空间组成。
c、Deque是由一段一段的定量的连续空间构成
二、deque容器的构造和赋值
void test()
{
/*
deque构造函数
deque<T> deqT;//默认构造形式
deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身。
deque(n, elem);//构造函数将n个elem拷贝给本身。
deque(const deque &deq);//拷贝构造函数。
deque赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
deque& operator=(const deque &deq); //重载等号操作符
swap(deq);// 将deq与本身的元素互换
*/
deque<int> d(5, 10);
printDequeInt(d);//10 10 10 10 10
//assign(n, elem);//将n个elem拷贝赋值给本身。
deque<int> d1;
d1.assign(5, 100);
printDequeInt(d1);//100 100 100 100 100
//deque& operator=(const deque &deq); //重载等号操作符
deque<int> d2;
d2 = d1;
printDequeInt(d2);//100 100 100 100 100
//swap(deq);// 将deq与本身的元素互换
deque<int> d3(5, 1);
deque<int> d4(5, 2);
printDequeInt(d3);//1 1 1 1 1
printDequeInt(d4);//2 2 2 2 2
d3.swap(d4);
printDequeInt(d3);//2 2 2 2 2
printDequeInt(d4);//1 1 1 1 1
}
三、deque容器的大小操作、双端插入删除操作、元素访问操作
void test02()
{
/*
deque大小操作
deque.size();//返回容器中元素的个数
deque.empty();//判断容器是否为空
deque.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充
新位置,如果容器变短,则末尾超出容器长度的元素被删除。
deque双端插入和删除操作
push_back(elem);//在容器尾部添加一个数据
push_front(elem);//在容器头部插入一个数据
pop_back();//删除容器最后一个数据
pop_front();//删除容器第一个数据
deque数据存取
at(idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range。
operator[];//返回索引idx所指的数据,如果idx越界,不抛出异常,直接出错。
front();//返回第一个数据。
back();//返回最后一个数据
*/
deque<int> d;
//尾部插入
d.push_back(10);
d.push_back(20);
d.push_back(30);
//10 20 30
//头部插入
d.push_front(40);
d.push_front(50);
d.push_front(60);
printDequeInt(d);//60 50 40 10 20 30
//头部删除
d.pop_front();//50 40 10 20 30
d.pop_back();//50 40 10 20
printDequeInt(d);//50 40 10 20
if (d.empty())
{
cout << "d容器为空" << endl;
}
else
{
cout << "d容器非空" << endl;
cout << "size = " << d.size() << endl;//4
}
//[]访问第二个元素
cout << "d[2] = " << d[2] << endl;//10
cout << "d.at(2) = " << d.at(2) << endl;//10
cout << "头元素 = " << d.front() << endl;//50
cout << "尾元素 = " << d.back() << endl;//20
}
四、容器的插入删除
void test03()
{
/*
deque插入操作
insert(pos,elem);//在pos位置插入一个elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
3.3.3.7 deque删除操作
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除pos位置的数据,返回下一个数据的位置
*/
deque<int> d;
d.insert(d.begin(), 5, 100);
printDequeInt(d);//100 100 100 100 100
d.clear();
cout << "size = " << d.size() << endl;//0
}
五、练习:
有5名选手:选手ABCDE,10个评委分别对每一名选手打分, 去除最高分,去除评委中最低分,取平均分,最后输出每位选手的分数
1. 创建五名选手,放到 vector 中
2. 遍历 vector 容器,取出来每一个选手,执行 for 循环,可以把 10 个评分打 分存到 deque 容器中
3. sort 算法对 deque 容器中分数排序,pop_back pop_front 去除最高和最低 分
4. deque 容器遍历一遍,累加分数,累加分数/d.size()
5. person.score = 平均分
#include<iostream>
#include<vector>
#include<deque>
#include<algorithm>
#include<string>
#include<stdlib.h>
#include<time.h>
#include<numeric>
using namespace std;
class Person
{public:
string m_name;
int m_score;
Person(string name, int score) :m_name(name), m_score(score) {};
};
void createperson(vector<Person> &v)
{
//5名选手是ABCDE
string nameTmp = "ABCDE";
for (int i = 0; i < 5; i++)
{
string name = "选手:";
name += nameTmp[i];
v.push_back(Person(name, 0));
}
}
void getscore(vector<Person> &v)
{
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
srand(time(NULL));
deque<int> d;
for (int i = 0; i < 10; ++i)
{
int score = rand() % 41 + 60;//60~100
d.push_back(score);
}
sort(d.begin(), d.end());
d.pop_back();
d.pop_front();
int sum = accumulate(d.begin(), d.end(), 0);
(*it).m_score = sum / d.size();
}
}
void showgrade(vector<Person> &v)
{
for (vector<Person>::iterator mit = v.begin(); mit != v.end(); mit++)
{
cout << (*mit).m_name << " "<<(*mit).m_score << endl;
}
cout << endl;
}
void test()
{
vector<Person> ob;
createperson(ob);
getscore(ob);
showgrade(ob);
}
int main()
{
test();
return 0;
}
注:srand设置随机种子 rand 产生随机数
int main(int argc, char *argv[])
{
//设置随机数种子time(NULL)获取当前时间
srand(time(NULL));
for (int i = 0; i < 10; i++)
{
//rand()函数的返回值就是随机数
int num = rand();
cout << num << " ";
}
cout << endl;
return 0;
}