C++ -- 学习系列 std::deque 的原理与使用

一   deque 是什么?

std::deque 是 c++ 一种序列式容器,其与 vector 类似,其底层内存都是连续的,不同的地方在于, vector 是一端开口,在一端放入数据与扩充空间,而 deque 是双端均开口,都可以放入数据与扩充空间。

二  原理

deque中存在两种数组:中控数组与缓存数组,在 deque 初始化时,两种数组均会初始化完成。

1. 缓存数组有多个,缓存数组用于存储真正的元素

2.中控数组用于存放缓存数组的地址,方便快速定位到指定缓存数组,进而快速定位元素的位置

其原理图如下:

其迭代器 Iterator 中需要含有四种信息:

1. 当前元素所在缓存数组的首元素地址

2. 当前元素所在缓存数组的尾元素地址

3. 当前元素在缓存数组中的实际地址

4. 当前元素所在缓存数组在中控数组的地址

三  使用

1. 容器构造

std::deque<T,Allocator>::deque - cppreference.com

函数说明
deque( size_type count,

                const T& value,

                const Allocator& alloc = Allocator() );
定义 count 个值为 value的元素存储到 deque 中             
deque( std::initializer_list<T> init,
       const Allocator& alloc = Allocator() );
通过 list 定义 deque 
#include<iostream>
#include<deque>template<typename T>
void printDeque(std::deque<T>& tmp_deque)
{for(auto iter = tmp_deque.begin(); iter != tmp_deque.end(); iter++){std::cout << *iter <<" ";}std::cout  <<"" << std::endl;
}int main()
{std::deque<int> tmp_deque1(6, 8);printDeque(tmp_deque1);std::deque<int> tmp_deque2;tmp_deque2 = {1, 2 , 3, 4, 5, 6};printDeque(tmp_deque2);return 0;
}

2. 访问元素

https://en.cppreference.com/w/cpp/container/deque

函数说明
at返回指定下标元素的引用
operator[]同上
front返回容器的首元素引用
back返回容器的尾元素引用
#include<iostream>
#include<deque>int main()
{std::deque<int> tmp_deque2 = {1, 2 , 3, 4, 5, 6};// Read Elementstd::cout << tmp_deque2.at(1) << std::endl;std::cout << tmp_deque2[2] << std::endl;std::cout << tmp_deque2.front() << std::endl;std::cout << tmp_deque2.back() << std::endl;// Wirte Elementtmp_deque2.at(1) = 888;tmp_deque2[2] = 888;tmp_deque2.front() = 888;tmp_deque2.back() = 888;std::cout << tmp_deque2.at(1) << std::endl;std::cout << tmp_deque2[2] << std::endl;std::cout << tmp_deque2.front() << std::endl;std::cout << tmp_deque2.back() << std::endl;    return 0;
}

3. 容器空间

函数说明
empty()返回 deque 是否为空
size()返回 deque 实际存储元素的个数
#include<deque>
#include<iostream>int  main()
{std::deque<int> tmp_deque2;tmp_deque2 = {1, 2 , 3, 4, 5, 6};std::deque<int> tmp_deque3;std::cout << tmp_deque3.empty() << std::endl;std::cout << tmp_deque3.size() << std::endl;std::cout << tmp_deque2.empty() << std::endl;std::cout << tmp_deque2.size() << std::endl;return 0;
}

4. 容器修改

std::deque - cppreference.com

函数说明
clear()清空 deque 的内容
push_backappend 元素到 deque 的尾端
pop_back将 deque 的尾端元素弹出
push_frontappend 元素到 deque 的前端
pop_front将 deque 的前端元素弹出
#include<deque>
#include<iostream>template<typename T>
void printDeque(std::deque<T>& tmp_deque)
{for(auto iter = tmp_deque.begin(); iter != tmp_deque.end(); iter++){std::cout << *iter <<" ";}std::cout  <<"" << std::endl;
}int main(0
{std::deque<int> tmp_deque2;tmp_deque2 = {1, 2 , 3, 4, 5, 6};printDeque(tmp_deque2);tmp_deque2.push_back(22);tmp_deque2.push_front(33);std::cout << tmp_deque2.front() << std::endl;std::cout << tmp_deque2.back() << std::endl;printDeque(tmp_deque2);tmp_deque2.pop_back();tmp_deque2.pop_front();std::cout << tmp_deque2.front() << std::endl;std::cout << tmp_deque2.back() << std::endl;printDeque(tmp_deque2);tmp_deque2.clear();std::cout << tmp_deque2.empty() << std::endl;return 0;
}

四  简单实现

   1. 参照原理做了简单的实现,实现了几个简单的函数接口:

  

// my_deque.h#ifndef MY_DEQUE_H
#define MY_DEQUE_H#include<vector>
#include<iostream>// 迭代器, T 为 my_deque 的元素类型, buffserSize 为每个缓存区的大小
template<typename T, int bufferSize>
struct my_deque_iterator
{T* M_start; // 当前buffer 的起始位置T* M_finish; // 当前buffer 的结尾位置T* M_curr; // 当前元素的位置T** M_map_node; // 当前 buffer 对应的中控数组的位置my_deque_iterator(T* start = nullptr, T* finish = nullptr, T* curr = nullptr, T** map_node = nullptr):M_start(start), M_finish(finish), M_curr(curr),M_map_node(map_node){}my_deque_iterator(const my_deque_iterator& other):M_start(other.M_start), M_finish(other.M_finish), M_curr(other.M_curr),M_map_node(other.M_map_node){}my_deque_iterator(my_deque_iterator& other):M_start(other.M_start), M_finish(other.M_finish), M_curr(other.M_curr),M_map_node(other.M_map_node){}my_deque_iterator& operator++(){if(M_curr == M_finish){M_map_node += 1;set_M_Node(M_map_node);}else{M_curr++;}return *this;}my_deque_iterator& operator++(int){operator++();return *this;}my_deque_iterator& operator--(){if(M_curr == M_start){M_map_node -= 1;set_M_Node(M_map_node, bufferSize - 1);}else{M_curr--;}return *this;}my_deque_iterator& operator--(int){operator--();return *this;}T&  operator*(){return *(this->M_curr);}my_deque_iterator& operator+=(int offset){if(offset >=0 && M_curr + offset <= M_finish || offset < 0 && M_curr + offset >= M_start){M_curr += offset;}else{int diff =  offset >= 0 ? M_finish - M_curr + 1 : M_curr - M_start + 1;int offsetNode = offset >= 0 ? (offset - diff) / bufferSize + 1: ((offset + diff) / bufferSize - 1);int offsetBuff = offset >= 0 ? (offset - diff) % bufferSize :(diff + offset) % bufferSize;M_map_node += offsetNode;if(offset >= 0){set_M_Node(M_map_node, offsetBuff);}else{set_M_Node(M_map_node, bufferSize - 1 - offsetBuff);}}return *this;}my_deque_iterator& operator-=(int offset){this->operator+=(-offset);return *this;}my_deque_iterator operator+(int offset){my_deque_iterator tmp = *this;tmp += offset;return tmp;}my_deque_iterator& operator-(int offset){this->operator-=(offset);return *this;}void set_M_Node(T** map_node, int offset = 0){M_start = M_map_node[0];M_curr = M_start + offset;M_finish = M_start + bufferSize - 1;}bool operator==(my_deque_iterator& other){return this->M_curr == other.M_curr;}bool operator!=(my_deque_iterator& other){return this->M_curr != other.M_curr;}bool operator==(my_deque_iterator&& other){return this->M_curr == other.M_curr;}bool operator!=(my_deque_iterator&& other){return this->M_curr != other.M_curr;}my_deque_iterator& operator=(my_deque_iterator& other){this->M_start = other.M_start;this->M_curr = other.M_curr;this->M_finish = other.M_finish;this->M_map_node = other.M_map_node;return *this;}my_deque_iterator& operator=(my_deque_iterator&& other){this->M_start = other.M_start;this->M_curr = other.M_curr;this->M_finish = other.M_finish;this->M_map_node = other.M_map_node;return *this;}};template<typename T, int bufferSize>
class my_deque
{
public:typedef my_deque_iterator<T, bufferSize> Iterator;public:my_deque(int map_size = 9):M_map_size(map_size){M_map = new T*[M_map_size];for(int i = 0; i < M_map_size; i++){M_map[i] = new T[bufferSize];for(int j = 0; j < bufferSize; j++){M_map[i][j] = 0;}}}~my_deque(){for(int i = 0; i < M_map_size; i++){delete [] M_map[i];}delete [] M_map;}void push_front(T& val){// 元素存储到了起始位置if(M_start.M_curr == &M_map[0][0]){reAlloc(M_map_size * 2);}if(M_start.M_curr == nullptr){M_map[M_map_size/2][0] = val;M_start = Iterator(&M_map[M_map_size/2][0], &M_map[M_map_size/2][0] + bufferSize - 1, &M_map[M_map_size/2][0], &M_map[M_map_size/2]);M_finish = M_start;}else{M_start--;*M_start.M_curr = val;}}void push_front(T&& val){push_front(val);}void push_back(T& val){// 元素存储到了结尾位置if(M_finish.M_curr == &M_map[M_map_size-1][bufferSize-1]){reAlloc(M_map_size * 2);}if(M_finish.M_curr == nullptr){M_map[M_map_size/2][0] = val;M_finish = Iterator(&M_map[M_map_size/2][0],&M_map[M_map_size/2][0] + bufferSize - 1, &M_map[M_map_size/2][0], &M_map[M_map_size/2]);M_start = M_finish;}else{M_finish++;*M_finish.M_curr = val;}}void push_back(T&& val){push_back(val);}T pop_front(){T tmp = *M_start.M_curr;M_start++;return tmp;}T pop_back(){T tmp = *M_finish.M_curr;M_finish--;return tmp;}Iterator begin(){return M_start;}Iterator end(){return M_finish + 1;}int size(){return bufferSize *(M_finish.M_map_node - M_start.M_map_node - 1) +(M_start.M_finish - M_start.M_curr + 1) + (M_finish.M_curr - M_finish.M_start + 1);}T& front(){return *M_start.M_curr;}T& back(){return *M_finish.M_curr;}void print(){for(int i = 0; i < M_map_size; i++){for(int j = 0; j < bufferSize; j++){std::cout << M_map[i][j] <<" ";}std::cout << "" << std::endl;}}private:void reAlloc(int map_size){T** tmp = new T*[map_size];int ori_mid = M_map_size / 2;int new_mid = map_size / 2;tmp[new_mid] = M_map[ori_mid];// mid to leftint new_index = new_mid - 1;for(int i = ori_mid - 1; i >= 0; i--){M_map[new_index--] = tmp[i];}while (new_index >= 0) {M_map[new_index--] = new T[bufferSize];}// mid to rightnew_index = new_mid + 1;for(int i = ori_mid + 1; i < M_map_size; i++){M_map[new_index++] = tmp[i];}while (new_index < map_size) {M_map[new_index++] = new T[bufferSize];}M_map_size = map_size;T** tmp1 = M_map;M_map = tmp;tmp = tmp1;delete tmp;}private:int  M_map_size; // 中控 数组 的长度T**  M_map = nullptr;  // 中控数组Iterator   M_start; // 起始元素Iterator   M_finish; // 结尾元素
};#endif // MY_DEQUE_H// main.cpp
#include<iostream>
#include<my_deque.h>void testMyDeque()
{my_deque<int, 3> tmp_deque;tmp_deque.push_back(1);
//    std::cout << " --------- " << std::endl;
//    tmp_deque.print();
//    std::cout << " --------- " << std::endl;tmp_deque.push_back(2);//    tmp_deque.print();
//    std::cout << " --------- " << std::endl;tmp_deque.push_back(3);
//    tmp_deque.print();
//    std::cout << " --------- " << std::endl;tmp_deque.push_back(4);
//    tmp_deque.print();
//    std::cout << " --------- " << std::endl;tmp_deque.push_back(5);
//    tmp_deque.print();
//    std::cout << " --------- " << std::endl;tmp_deque.push_front(2);
//    tmp_deque.print();
//    std::cout << " --------- " << std::endl;tmp_deque.push_front(3);
//    tmp_deque.print();
//    std::cout << " --------- " << std::endl;tmp_deque.push_front(4);
//    tmp_deque.print();
//    std::cout << " --------- " << std::endl;tmp_deque.push_front(5);
//    tmp_deque.print();for(my_deque<int, 3>::Iterator iter = tmp_deque.begin(); iter != tmp_deque.end(); iter++){std::cout << *iter << " ";}std::cout << " --------- " << std::endl;auto iter = tmp_deque.begin();std::cout << *iter <<std::endl;//std::cout << *(iter-3) <<std::endl;
//    std::cout << (iter).M_start <<std::endl;
//    std::cout << (iter).M_curr <<std::endl;
//    std::cout << (iter).M_finish <<std::endl;
//    std::cout << (iter).M_map_node <<std::endl;std::cout << " --------- " << std::endl;std::cout << *(iter+3) <<std::endl;
//    std::cout << (iter+3).M_start <<std::endl;
//    std::cout << (iter+3).M_curr <<std::endl;
//    std::cout << (iter+3).M_finish <<std::endl;
//    std::cout << (iter+3).M_map_node <<std::endl;std::cout << " --------- " << std::endl;auto iter2 = iter + 3;std::cout << *(iter2-3) <<std::endl;
//    std::cout << (iter2-3).M_start <<std::endl;
//    std::cout << (iter2-3).M_curr <<std::endl;
//    std::cout << (iter2-3).M_finish <<std::endl;
//    std::cout << (iter2-3).M_map_node <<std::endl;std::cout << " --------- " << std::endl;std::cout << *(iter+5) <<std::endl;
//    std::cout << (iter+5).M_start <<std::endl;
//    std::cout << (iter+5).M_curr <<std::endl;
//    std::cout << (iter+5).M_finish <<std::endl;
//    std::cout << (iter+5).M_map_node <<std::endl;std::cout << "size: " << tmp_deque.size() << std::endl;std::cout << "pop_back: " << tmp_deque.pop_back() << std::endl;std::cout << "size: " << tmp_deque.size() << std::endl;std::cout << "pop_front: " << tmp_deque.pop_front() << std::endl;std::cout << "size: " << tmp_deque.size() << std::endl;std::cout << "empty: " << tmp_deque.empty() << std::endl;
}int main()
{testMyDeque();return 0;
}

输出:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/145605.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

pip version 更新

最近报了一个错&#xff1a; 解决办法&#xff1a; 在cmd输入“conda install pip” conda install pip 完了之后再输入&#xff1a; python -m pip install --upgrade pip ok.

C++ AB组辅导课

C AB组辅导课 蓝桥杯C AB组辅导课 第一讲 递归与递推 Acwing1、整数划分(递归)2、acwing92. 递归实现指数型枚举10凑算式(全排列)11李白打酒(全排列)12、棋牌总数(递归)13、剪邮票(递归)14、1050. 鸣人的影分身 (递归或动态规划(记忆化搜索))15、方格分割 &#xff08;dfs思维&…

Win10自带输入法怎么删除-Win10卸载微软输入法的方法

Win10自带输入法怎么删除&#xff1f;Win10系统自带输入法就是微软输入法&#xff0c;这个输入法满足了很多用户的输入需求。但是&#xff0c;有些用户想要使用其它的输入法&#xff0c;这时候就想删除掉微软输入法。下面小编给大家介绍最简单方便的卸载方法吧。 Win10卸载微软…

Oracle物化视图(Materialized View)

与Oracle普通视图仅存储查询定义不同&#xff0c;物化视图&#xff08;Materialized View&#xff09;会将查询结果"物化"并保存下来&#xff0c;这意味着物化视图会消耗存储空间&#xff0c;物化的数据需要一定的刷新策略才能和基表同步&#xff0c;在使用和管理上比…

【网络安全】网络安全之信息收集和信息收集工具讲解,告诉你黑客是如何信息收集的

一&#xff0c;域名信息收集 1-1 域名信息查询 可以用一些在线网站进行收集&#xff0c;比如站长之家 域名Whois查询 - 站长之家站长之家-站长工具提供whois查询工具&#xff0c;汉化版的域名whois查询工具。https://whois.chinaz.com/ 可以查看一下有没有有用的信息&#xf…

Linux服务器安装Anaconda 配置远程jupyter lab使用虚拟环境

参考的博客&#xff1a; Linux服务器安装Anaconda 并配置远程jupyter lab anaconda配置远程访问jupyter&#xff0c;并创建虚拟环境 理解和创建&#xff1a;Anaconda、Jupyterlab、虚拟环境、Kernel 下边是正文了。 https://www.anaconda.com/download是官网网址&#xff0c;可…

7.网络原理之TCP_IP(上)

文章目录 1.网络基础1.1认识IP地址1.2子网掩码1.3认识MAC地址1.4一跳一跳的网络数据传输1.5总结IP地址和MAC地址1.6网络设备及相关技术1.6.1集线器&#xff1a;转发所有端口1.6.2交换机&#xff1a;MAC地址转换表转发对应端口1.6.3主机&#xff1a;网络分层从上到下封装1.6.4主…

django 实现:闭包表—树状结构

闭包表—树状结构数据的数据库表设计 闭包表模型 闭包表&#xff08;Closure Table&#xff09;是一种通过空间换时间的模型&#xff0c;它是用一个专门的关系表&#xff08;其实这也是我们推荐的归一化方式&#xff09;来记录树上节点之间的层级关系以及距离。 场景 我们 …

网页采集工具-免费的网页采集工具

在当今数字化时代&#xff0c;网页采集已经成为了众多领域的必备工具。无论是市场研究、竞争情报、学术研究还是内容创作&#xff0c;网页采集工具都扮演着不可或缺的角色。对于许多用户来说&#xff0c;寻找一个高效、免费且易于使用的网页采集工具太不容易了。 147SEO工具的强…

Spring Mvc的相关知识

一、初识MVC 1.Spring Mvc 是控制层的Spring框架&#xff0c;替换Servlet&#xff0c;除了它以外&#xff0c;还有 struct1和 struct2 区别&#xff1a; 1.struct1被struct2 取代 2.struct2&#xff1a;采用 prototype多例模式&#xff0c;内存消耗快&#xff0c;经常会出现内存…

C++ 类构造函数 析构函数

类的构造函数 类的构造函数是类的一种特殊的成员函数&#xff0c;它会在每次创建类的新对象时执行。 构造函数的名称与类的名称是完全相同的&#xff0c;并且不会返回任何类型&#xff0c;也不会返回 void。构造函数可用于为某些成员变量设置初始值。 下面的实例有助于更好地…

MySQL架构 InnoDB存储引擎

1. 什么是Mysql&#xff1f; 我们在开发的时候&#xff0c;我们都需要对业务数据进行存储&#xff0c;这个时候&#xff0c;你们就会用到MySQL、Oracal等数据库。 MySQL它是一个关系型数据库&#xff0c;这种关系型数据库就有Oracal、 MySQL&#xff0c;以及最近很火的PgSQL等。…

JSP学习笔记【三】——JQuery

前言 在写项目的时候需要动态对某组件的属性进行调整&#xff0c;我看网上的教程都是使用document.getElementById等&#xff0c;但我在eclipse编写.jsp文件的时候&#xff0c;却提示document cannot be resolved。由于我对jsp没有系统的了解以及无人可咨询&#xff0c;网上也…

Linux开发工具之文本编译器vim

●IDE例子 Linux编辑器-vim使用 vi/vim的区别简单点来说&#xff0c;它们都是多模式编辑器&#xff0c;不同的是vim是vi的升级版本&#xff0c;它不仅兼容vi的所有指令&#xff0c;而且还有一些新的特性在里面。例如语法加亮&#xff0c;可视化操作不仅可以在终端运行&#xff…

金融生产存储亚健康治理:升级亚健康 3.0 ,应对万盘规模的挑战

随着集群规模的不断扩大&#xff0c;硬盘数量指数级上升&#xff0c;信创 CPU 和操作系统、硬盘多年老化、物理搬迁等多种复杂因素叠加&#xff0c;为企业的存储亚健康管理增加了新的挑战。 在亚健康 2.0 的基础上&#xff0c;星辰天合在 XSKY SDS V6.2 实现了亚健康 3.0&#…

渗透测试之打点

请遵守中华人民共和国网络安全法 打点的目的是获取一个服务器的控制权限 1. 企业架构收集 &#xff08;1&#xff09;官网 &#xff08;2&#xff09;网站或下属的子网站&#xff0c;依次往下 天眼查 企查查 2. ICP 备案查询 ICP/IP地址/域名信息备案管理系统 使用网站…

ElasticSearch 10000条查询数量限制

一、前言 我们将库存快照数据导入ES后发现要分页查询10000条以后的记录会报错&#xff0c;这是因为ES通过index.max_result_window这个参数控制能够获取数据总数fromsize最大值&#xff0c;默认限制是10000条&#xff0c;因为ES考虑到数据要从其它节点上报到协调节点如果搜索请…

APACHE NIFI学习之—UpdateAttribute

UpdateAttribute 描述: 通过设置属性表达式来更新属性&#xff0c;也可以基于属性正则匹配来删除属性 标签: attributes, modification, update, delete, Attribute Expression Language, state, 属性, 修改, 更新, 删除, 表达式 参数: 如下列表中&#xff0c;必填参数则…

Leetcode 剑指 Offer II 046. 二叉树的右视图

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底…

react create-react-app v5 从零搭建项目

前言&#xff1a; 好久没用 create-react-app做项目了&#xff0c;这次为了个h5项目&#xff0c;就几个页面&#xff0c;决定自己搭建一个&#xff08;ps:mmp 好久没用&#xff0c;搭建的时候遇到一堆问题&#xff09;。 我之前都是使用 umi 。后台管理系统的项目 使用 antd-…