deque
双端数组,可以对头端进行插入删除操作
deque
与vector
区别:
vector
对于头部的插入删除效率低,数据量越大,效率越低deque
相对而言,对头部的插入删除速度回比vector快vector
访问元素时的速度会比deque快,这和两者内部实现有关deque
容器的迭代器也是支持随机访问的
deque
内部工作原理:
deque
内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据- 中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间
构造函数
功能描述:
- deque容器构造(用法与 vector 基本一致)
函数原型:
deque<T>
deqT; //默认构造形式deque(beg, end);
//构造函数将[beg, end)区间中的元素拷贝给本身。deque(n, elem);
//构造函数将n个elem拷贝给本身。deque(const deque &deq);
//拷贝构造函数
#include<iostream>
#include<string>
#include<deque>
using namespace std;
// 打印 deque
template<class T>
void print_deque(const deque<T>& d) {
for (size_t i = 0; i < d.size(); i++) {
cout << d[i] << " ";
}
cout << endl;
}
int main() {
// 无参构造函数
deque<int> d;
// 向容器尾部添加元素
for (int i = 0; i < 10; i++){
d.push_back(i);
}
print_deque(d); // 0 1 2 3 4 5 6 7 8 9
// 拷贝 d 容器中的元素进行构造容器
deque<int> d2(d.begin(), d.end());
print_deque(d2); // 0 1 2 3 4 5 6 7 8 9
// 以 5 个 9 作为容器中的数据元素,进行构造容器
deque<int> d3(5, 9);
print_deque(d3); // 9 9 9 9 9
// 拷贝构造函数
deque<int> d4(d3);
print_deque(d3); // 9 9 9 9 9
return 0;
}
赋值操作
功能描述:
- 给deque容器进行赋值(用法与 vector 基本一致)
函数原型:
-
deque& operator=(const deque &deq);
//重载等号操作符 -
assign(beg, end);
//将[beg, end)区间中的数据拷贝赋值给本身。 -
assign(n, elem);
//将n个elem拷贝赋值给本身。
#include<iostream>
#include<string>
#include<deque>
using namespace std;
// 打印 deque
template<class T>
void print_deque(const deque<T>& d) {
for (size_t i = 0; i < d.size(); i++) {
cout << d[i] << " ";
}
cout << endl;
}
int main() {
// 无参构造函数
deque<int> d;
// 向容器尾部添加元素
for (int i = 0; i < 10; i++) {
d.push_back(i);
}
print_deque(d); // 0 1 2 3 4 5 6 7 8 9
// 直接等号赋值
deque<int> d2;
d2 = d;
print_deque(d2); // 0 1 2 3 4 5 6 7 8 9
// 将 d 容器的 [begin(),end()) 区间内的数据元素赋值给 d3 容器
deque<int> d3;
d3.assign(d.begin(),d.end());
print_deque(d3); // 0 1 2 3 4 5 6 7 8 9
// 将 5 个 9 赋值给容器元素
deque<int> d4;
d4.assign(5, 9);
print_deque(d4); // 9 9 9 9 9
return 0;
}
容量大小
功能描述:
- 对deque容器的大小进行操作(用法与 vector 基本一致)
- 由于内部实现不同,deque 没有容量概念
函数原型:
-
deque.empty();
//判断容器是否为空 -
deque.size();
//返回容器中元素的个数 -
deque.resize(num);
//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。 //如果容器变短,则末尾超出容器长度的元素被删除。
-
deque.resize(num, elem);
//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 //如果容器变短,则末尾超出容器长度的元素被删除。
#include<iostream>
#include<string>
#include<deque>
using namespace std;
// 打印 deque
template<class T>
void print_deque(const deque<T>& d) {
for (size_t i = 0; i < d.size(); i++) {
cout << d[i] << " ";
}
cout << endl;
}
int main() {
// 无参构造函数
deque<int> d;
// 判断容器是否为空
cout << (d.empty() ? "容器为空" : "容器不为空") << endl; // 容器为空
// 获取容器大小
cout << "容器的大小为:" << d.size() << endl; // 容器的大小为:0
// 向容器尾部添加元素
for (int i = 0; i < 10; i++) {
d.push_back(i);
}
print_deque(d); // 0 1 2 3 4 5 6 7 8 9
// 重新指定大小,剩余部分默认以0填充
d.resize(15);
print_deque(d); // 0 1 2 3 4 5 6 7 8 9 0 0 0 0 0
// 重新指定大小,剩余部分默认以1填充
d.resize(20,1);
print_deque(d); // 0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 1 1 1 1 1
// 重新指定大小,若长度变短,超出的元素直接舍弃
d.resize(5);
print_deque(d); // 0 1 2 3 4
return 0;
}
插入删除
功能描述:
- 向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>
#include<string>
#include<deque>
using namespace std;
// 打印 deque
template<class T>
void print_deque(const deque<T>& d) {
for (size_t i = 0; i < d.size(); i++) {
cout << d[i] << " ";
}
cout << endl;
}
int main() {
deque<int> d;
deque<int> d1;
/*从容器两端插入元素*/
d.push_back(1); // 从尾部插入一个元素
d.push_back(2);// 从尾部插入一个元素
d.push_front(3); // 从头部插入一个元素
d.push_front(4); // 从头部插入一个元素
d.push_front(5); // 从头部插入一个元素
print_deque(d); // 5 4 3 1 2
d1.push_back(111);
d1.push_back(222);
d1.push_back(333);
/*从容器两端删除元素*/
d.pop_back(); // 从容器尾部删除一个元素
d.pop_back(); // 从容器尾部删除一个元素
d.pop_front(); // 从容器头部删除一个元素
print_deque(d); // 4 3
/*在迭代器所指位置插入元素*/
d.insert(d.begin(), 999); // 在第一个元素位置处插入 999
print_deque(d); // 999 4 3
d.insert(d.end(), 3, 888); // 在最后一个元素的下一个位置插入3个888
print_deque(d); // 999 4 3 888 888 888
// 获取迭代器
deque<int>::iterator ite = d.begin(); // 迭代器执向第一个位置
ite++; // 迭代器往后移动一个位置
d.insert(ite, 555); // 在当前执向位置插入一个 555
print_deque(d); // 999 555 4 3 888 888 888
d.insert(d.begin(),d1.begin(), d1.end()); // 在d的第一个位置处插入 d1 的[egin(),end()) 区间元素
print_deque(d); // 111 222 333 999 555 4 3 888 888 888
/* 删除迭代器指向区间内的元素 */
deque<int>::iterator ite_1 = d.begin(); // 指向第一个元素位置的迭代器
deque<int>::iterator ite_2 = d.end(); // 指向最后一个元素的下一个位置的迭代器
ite_2-=3; // 迭代器指向 前移3个位置
d.erase(ite_1, ite_2); // 删除指定区间内的元素
print_deque(d); // 888 888 888
/* 清空整个容器 */
d.clear();
d1.clear();
cout << d.size() << endl; // 0
cout << d1.size() << endl; // 0
return 0;
}
数据存取
功能描述:
- 对deque 中的数据的存取操作
函数原型:
at(int idx);
//返回索引idx所指的数据operator[];
//返回索引idx所指的数据front();
//返回容器中第一个数据元素back();
//返回容器中最后一个数据元素
#include<iostream>
#include<string>
#include<deque>
using namespace std;
int main() {
deque<int> d;
d.push_back(1);
d.push_back(2);
d.push_back(3);
// 获取第一个位置的元素
int e1 = d[0];
cout << e1 << endl; // 1
// 获取第一个位置的元素
int e2 = d.at(1); // 2
cout << e2 << endl;
// 设置第三个位置的元素
d[2] = 888;
d.at(1) = 999;
// 遍历容器
for (int i = 0; i < d.size(); i++){
cout << d[i] << " ";
}
cout << endl;
return 0;
}
排序
功能描述:
- 利用算法实现对deque容器进行排序
算法:
sort(iterator beg, iterator end)
//对beg和end区间内元素进行排序- sort 排序算法使用需要导入一头文件
algorithm
#include<iostream>
#include<string>
#include<deque>
#include<algorithm>
using namespace std;
// 打印 deque
template<class T>
void print_deque(const deque<T>& d) {
for (size_t i = 0; i < d.size(); i++) {
cout << d[i] << " ";
}
cout << endl;
}
int main() {
deque<int> d;
d.push_back(2);
d.push_back(4);
d.push_back(1);
d.push_front(3);
d.push_front(7);
d.push_front(5);
d.push_front(6);
print_deque(d); // 6 5 7 3 2 4 1
// 获取迭代器
deque<int>::iterator begin = d.begin(); // 指向第一个元素位置
deque<int>::iterator end = d.end(); // 指向最后一个元素的下一个位置
// 对指定区间内的元素进行排序
sort(begin, end);
print_deque(d); // 1 2 3 4 5 6 7
return 0;
}
案例:给选手评分
需求:有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。
- 创建五名选手,放到vector中
- 遍历vector容器,取出来每一个选手,执行for循环,可以把10个评分打分存到deque容器中
- sort算法对deque容器中分数排序(升序),去除最高(从尾部删除)和去除最低(从头部删除)分
- deque容器遍历一遍,累加总分
- 计算平均分
#include<iostream>
#include<string>
#include<deque>
#include<vector>
#include<algorithm>
using namespace std;
const string NAME_PREFIX = "选手";
const string NAME_SUFFIX = "ABCDE";
// 遍历输出容器
template<class T>
void print_container(const T& container) {
for (int i = 0; i < container.size(); i++){
cout << container[i] << endl;;
}
}
class Player {
friend ostream& operator<<(ostream& out,const Player& p);
private:
string name; // 姓名
int score_avg; // 平均分
public:
Player(string name,int score_avg) {
this->name = name;
this->score_avg = score_avg;
}
void set_score_avg(int score) {
this->score_avg = score;
}
};
ostream& operator<<(ostream& out, const Player& p) {
out << "姓名:" << p.name << ",平均分:" << p.score_avg;
return out;
}
// 把选手装入vector容器
void set_player(vector<Player>& players) {
for (int i = 0; i < 5; i++) {
Player p(NAME_PREFIX + NAME_SUFFIX[i], 0);
players.push_back(p);
}
}
// 循环10次给选手打分,计算出平均分
void set_score(vector<Player>& players) {
deque<int> scores; // 存储分数的容器
int sum_score = 0; // 总分
int avg_score = 0; // 平均分
// 循环给每个选手打分
for (int i = 0; i < players.size(); i++) {
int score = 0; // 分数
// 每个选手有十个得分
for (int j = 0; j < 10; j++) {
// 获取到 [60,100]内的一个随机整数作为评分
score = rand() % (100 - 60 + 1) + 60;
// 将分数放入deque容器
scores.push_back(score);
}
// 分数从小到大排序
sort(scores.begin(), scores.end());
// print_container(scores);
// 去掉最高分
scores.pop_back();
// 去掉最低分
scores.pop_front();
// 计算总分
for (int k = 0; k < scores.size(); k++) {
sum_score += scores[k];
}
// 计算平均分
avg_score = sum_score / scores.size();
players.at(i).set_score_avg(avg_score);
// 清空存储分数的容器
scores.clear();
sum_score = 0;
}
}
void test_rand() {
/*
通过rand() % n的方式,获取到[0, n)的随机数,因为任何一个数除以n得到的余数0到n-1。
那么我们就可以通过改变n的值就可以去指定截止数,再将取到的范围加上一个值就可以改变起始数:
要取得 [a,b) 的随机整数,使用 (rand () % (b-a))+ a;
要取得 [a,b] 的随机整数,使用 (rand () % (b-a+1))+ a;
要取得 (a,b] 的随机整数,使用 (rand () % (b-a))+ a + 1;
*/
// 取得[60-100]直接的随机数
cout << rand() % (100 - 60 + 1) + 60 << endl;
}
int main() {
/*
void srand(unsigned int seed)初始化随机数发生器:随机数种子
unsigned:无符号
表示抛弃数据类型的负数部分,将更多的存储空间用来存放非负数
例如:int类型原本占用4字节空间,即只能存储[-2^16,2^16 - 1]范围内的数据
加unsigned后存储数据的范围就是[0,2^32 - 1]
unsigned int表示[0,2^32 - 1]范围内的整型
使用time()作为随机数种子.时间戳,返回从1970年1月1月零点零分零秒到当前时间的秒数
可以将time返回的时间作为参数传递给srand(),因为程序每一次运行时,我们的时间都是不一样的,即每次运行时的随机数种子都不一样。
*/
srand((unsigned int)time(NULL));
// 存储选手的vector容器
vector<Player> players;
// 选手装进容器
set_player(players);
print_container(players);
// 打分
set_score(players);
print_container(players);
return 0;
}