在使用c++容器的时候其底层如何实现  例如  vector 容器  :是一个内存可以二倍扩容的向量容器,使用方便但是对内存要求严格,弊端明显    list  容器  : 双向循环链表    deque  容器 :双端队列

deque容器是C++标准模版库(STL,Standard Template Library)中的部分内容。deque容器类与vector类似,支持随机访问和快速插入删除,它在容器中某一位置上的操作所花费的是线性时间。与vector不同的是,deque还支持从开始端插入数据:push_front()。

实际上双端队列是一个二维数组,但是实际存储数据的部分并不是连续的,一维数组存放指针,指向二维申请出来的空间,如图

首先申请一维空间存放指向二维的指针,例如一维空间长度为int len;则在len/4的位置先申请一块二维空间,指向前的指针*_frist与指向后的指针*_last 位于二维空间的中间,前插数据则*_frist--,后插数据则*_last++;

如果前插到二维的0下标位置,若一维数组上一个位置指向的空间为空,此时会在一维上一个位置申请二维,*_frist指向二维尾部,例如上图,会在*p   0 的位置申请二维,*_frist指向新开辟的二维的尾部,实现继续前插,若上面的所有一维都申请了二维,但是下面还有一维数组还有空,则整体将数据往下挪,把一维0号下标的二维空出来,继续前插,直到所有的一维都申请了二维并且数据放满,此时需要扩容,将一维数组2倍扩大,然后将所有数据移到新的一维数组所指向的二维数组中,满足数据位置为  :(新的一维数组长度/4)的位置。尾插同理  只是向下插方向相反。

下面是数据结构和基本函数

#define QUE_SIZE(T) 4096 / sizeof(T)
#define DEFAULT_QUE 2
class Deque
{
public:
Deque(); //构造函数
~Deque(); // 析构函数
Deque(const Deque &src); // 左值引用参数构造拷贝函数 防止浅拷贝 Deque(Deque &&src); // 右值引用参数拷贝构造函数 防止临时量对空间时间的浪费 Deque& operator=(const Deque &src); // 左值引用参数赋值构造函数 Deque& operator=(Deque &&src); // 带右值引用参数的赋值构造函数 void push_back(int val); // 尾部入队 void pop_back(); // 尾部删除 void push_front(int val); // 前插 void pop_front(); //前删 int front(); //返回队头元素 int back(); // 返回队尾元素 bool empty(); // 是否对空 private:
int **mMapper;
int *mFirst;
int *mLast;
int mMapperSize;
};

具体函数 封装成类

#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
#define QUE_SIZE(T) 4096 / sizeof(T)
#define DEFAULT_QUE 2
class Deque
{
public:
Deque()
{
mMapper=new int*[DEFAULT_QUE]();
mMapperSize=DEFAULT_QUE;
mMapper[DEFAULT_QUE/]=new int[QUE_SIZE(int)];
mFirst=mMapper[DEFAULT_QUE/]+QUE_SIZE(int)/;
mLast=mFirst+;
}
~Deque()
{
int i=;
for(;i<mMapperSize;i++)
{
delete []mMapper[i];
mMapper[i]=nullptr;
}
delete []mMapper;
mMapper=nullptr;
} Deque(const Deque &src)
{
mMapper=new int*[src.mMapperSize]();
int mfirst=-;
int mlast=-;
bool sign=;
int i;
for(i=;i<src.mMapperSize;i++)
{
if(src.mMapper[i]==nullptr)
{
continue;
}
if(src.mMapper[i]!=nullptr)
{ if(sign)
{
mfirst=i;
sign=;
} int j;
mMapper[i]=new int[QUE_SIZE(int)];
for(j=;j<QUE_SIZE(int);j++)
{
*(mMapper[i]+j)=*(src.mMapper[i]+j);
}
mlast=i;
} }
mFirst=mMapper[mfirst]+(src.mFirst-src.mMapper[mfirst]);
mLast=mMapper[mlast]+(src.mLast-src.mMapper[mlast]);
mMapperSize=src.mMapperSize;
}
Deque(Deque &&src)
{
mMapper=src.mMapper;
mMapperSize=src.mMapperSize;
mFirst=src.mFirst;
mLast=src.mLast;
src.mMapper=nullptr;
} Deque& operator=(const Deque &src)
{
if(this==&src)
{
return *this;
}
int i=;
for(;i<mMapperSize;i++)
{
delete[]mMapper[i];
}
delete []mMapper;
mMapper=new int*[src.mMapperSize]();
int mfirst=-;
int mlast=-;
bool sign=-;
for(i=;i<src.mMapperSize;i++)
{
if(src.mMapper[i]==nullptr)
{
continue;
}
if(src.mMapper[i]!=nullptr)
{
if(sign)
{
mfirst=i;
sign=;
}
int j;
mMapper[i]=new int[QUE_SIZE(int)];
for(j=;j<QUE_SIZE(int);j++)
{
*(mMapper[i]+j)=*(src.mMapper[i]+j);
}
mlast=i;
}
}
mFirst=mMapper[mfirst]+(src.mFirst-src.mMapper[mfirst]);
mLast=mMapper[mlast]+(src.mLast-src.mMapper[mlast]);
mMapperSize=src.mMapperSize;
return *this;
} Deque& operator=(Deque &&src)
{
int i=;
for(;i<mMapperSize;i++)
{
delete []mMapper[i];
}
delete []mMapper;
mMapper=src.mMapper;
mMapperSize=src.mMapperSize;
mLast=src.mLast;
mFirst=src.mFirst;
src.mMapper=nullptr;
return *this;
}
void push_back(int val) // 尾部入队
{
int index = -;
for (int i = ; i < mMapperSize; ++i)
{
if (mMapper[i] == nullptr)
{
index = i;
continue;
} // 表示last已经指向行的末尾了,需要扩容
if (mMapper[i] + QUE_SIZE(int) == mLast)
{
// 说明下面还有空行,直接分配新的第二维数组
if (i != mMapperSize - )
{
mMapper[i+] = new int[QUE_SIZE(int)];
mLast = mMapper[i + ];
break;
} // 说明last下面已经没有空闲行了
if (index != -)
{
// 说明上面还有空闲行,整体往上挪一行,下面就有一个空闲行了
for (int i = index; i < mMapperSize-; ++i)
{
mMapper[i] = mMapper[i + ];
}
mMapper[mMapperSize-] = new int[QUE_SIZE(int)];
mLast = mMapper[mMapperSize - ];
break;
}
else
{
// 说明上面没有空闲行,一维需要开始扩容了
int **tmpMapper = new int*[* mMapperSize];
int idx = * mMapperSize / ;
for (int i = ; i < mMapperSize; ++i)
{
tmpMapper[idx++] = mMapper[i];
}
delete[]mMapper;
mMapper = tmpMapper;
mMapperSize *= ; mMapper[idx] = new int[QUE_SIZE(int)];
mLast = mMapper[idx];
break;
}
}
}
// 添加元素
*mLast++ = val;
}
void pop_back()
{
int i;
bool sign=;
for(i=;i<mMapperSize;i++)
{
if(mMapper[i]==mLast)
{
mLast=mMapper[i-]+QUE_SIZE(int);
sign=;
break;
}
}
if(sign)
{
mLast--;
}
} void push_front(int val)
{ // 遍历第一维的数组,从下往上遍历 与尾插方法一样
int index = -;
int i=mMapperSize-;
for (; i>=; i--)
{
if (mMapper[i] == nullptr)
{
index = i;
continue;
} // 表示frist已经指向行首,需要扩容
if (mMapper[i] ==mFirst)
{
// 说明上面还有空行,直接分配新的第二维数组
if (i != )
{
mMapper[i-] = new int[QUE_SIZE(int)];
mFirst = mMapper[i-]+QUE_SIZE(int);
break;
} // 说明frist下面已经没有空闲行了
if (index != -) {
// 说明下面还有空闲行,整体往下挪一行,上面就有一个空闲行了
for (i = index; i >; i--)
{
mMapper[i] = mMapper[i-];
}
mMapper[] = new int[QUE_SIZE(int)];
mFirst= mMapper[]+QUE_SIZE(int);
break;
}
else
{
// 说明下面没有空闲行,一维需要开始扩容了
int **tmpMapper = new int*[* mMapperSize];
int idx = * mMapperSize / ;
for (int i = ; i < mMapperSize; ++i)
{
tmpMapper[idx+i] = mMapper[i];
}
delete[]mMapper;
mMapper = tmpMapper;
mMapperSize *= ; mMapper[idx-] = new int[QUE_SIZE(int)];
mFirst = mMapper[idx-]+QUE_SIZE(int);
break;
}
}
}
// 添加元素
*mFirst-- = val;
}
void pop_front()
{
int i;
bool sign=;
for(i=;i<mMapperSize;i++)
{
if(mMapper[i]+QUE_SIZE(int)==mFirst)
{
mFirst=mMapper[i+];
sign=;
break;
}
}
if(sign)
{
mFirst++;
} }
int front()
{
int i;
for(i=;i<mMapperSize;i++)
{
if(mMapper[i]+QUE_SIZE(int)==mFirst)
{
return *mMapper[i+];
}
}
return *(mFirst+); } int back()
{
int i=;
for(;i<mMapperSize;i++)
{
if(mMapper[i]==mLast)
{
return *(mMapper[i-]+QUE_SIZE(int));
}
}
return *(mLast-); } bool empty()
{
return mFirst+==mLast;
} private:
int **mMapper;
int *mFirst;
int *mLast;
int mMapperSize;
};
int main()
{
Deque s1;
Deque s2;
int i=;
for(;i<;i++)
{
s1.push_back(i);
}
s2=s1;
for(i=;i<;i++)
{
cout<<s2.front()<<' ';
s2.pop_front();
}
cout<<endl;
return ;
}

c++实现双端队列的更多相关文章

  1. lintcode二叉树的锯齿形层次遍历 (双端队列)

    题目链接: http://www.lintcode.com/zh-cn/problem/binary-tree-zigzag-level-order-traversal/ 二叉树的锯齿形层次遍历 给出 ...

  2. lintcode 滑动窗口的最大值(双端队列)

    题目链接:http://www.lintcode.com/zh-cn/problem/sliding-window-maximum/# 滑动窗口的最大值 给出一个可能包含重复的整数数组,和一个大小为  ...

  3. STL---deque(双端队列)

    Deque是一种优化了的.对序列两端元素进行添加和删除操作的基本序列容器.它允许较为快速地随机访问,但它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结 ...

  4. hdu-5929 Basic Data Structure(双端队列+模拟)

    题目链接: Basic Data Structure Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 65536/65536 K (Ja ...

  5. HDU 4286 Data Handler --双端队列

    题意:有一串数字,两个指针,然后一些添加,删除,反转,以及移动操作,最后输出序列. 解法:可以splay做,但是其实双端队列更简便. 维护三个双端队列LE,MI,RI分别表示[L,R]序列左边,[L, ...

  6. 双端队列(单调队列)poj2823 区间最小值(RMQ也可以)

    Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 41844   Accepted: 12384 ...

  7. Java 集合深入理解(10):Deque 双端队列

    点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 什么是 Deque Deque 是 Double ended queue (双端队列) 的缩写,读音和 deck 一样,蛋 ...

  8. BZOJ2457 BeiJing2011 双端队列

    [问题描述] Sherry现在碰到了一个棘手的问题,有N个整数需要排序.  Sherry手头能用的工具就是若干个双端队列.        她需要依次处理这N个数,对于每个数,Sherry能做以下两件事 ...

  9. Fork/Join框架之双端队列

    简介 ForkJoinPool管理着ForkJoinWorkerThread线程,ForkJoinWorkerThread线程内部有一个双端队列,这个双端队列主要由一个数组queue.数组下标queu ...

  10. 【贪心】Bzoj 2457:[BeiJing2011]双端队列

    2457: [BeiJing2011]双端队列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 209  Solved: 95[Submit][Stat ...

随机推荐

  1. Laravel中的Storage::disk

    Laravel中的Storage::disk 一.总结 一句话总结: Storage的disk的路径和file的路径都是一回事,都是config/filesystems.php配置文件中disks 比 ...

  2. 卷积和池化的区别、图像的上采样(upsampling)与下采样(subsampled)

    1.卷积 当从一个大尺寸图像中随机选取一小块,比如说 8x8 作为样本,并且从这个小块样本中学习到了一些特征,这时我们可以把从这个 8x8 样本中学习到的特征作为探测器,应用到这个图像的任意地方中去. ...

  3. CNS、ENS和PNS的发育过程

    central nervous system (CNS) peripheral nervous system (PNS) enteric nervous system (ENS) 做这部分的科研必须要 ...

  4. 从库延迟增大,MySQL日志出现InnoDB: page_cleaner: 1000ms intended loop took 17915ms.

    今天同事负责的数据库从库出现从库延迟增大,MySQL日志InnoDB: page_cleaner: 1000ms intended loop took 17915ms. 了解原因,keepalived ...

  5. Tosca 添加插件或者是扩展功能,把页面上某块内容识别成table

    #遇到了问题 "ICS table was not found" 是因为编辑case的时候用到了插件的功能, 但是setting里面却没有配置这个插件 #在哪里添加插件 #目的 这 ...

  6. VS Code 通过文件名查询文件并打开

    On Windows press Ctrl+p or Ctrl+e On Mac press Cmd+p on the Linux press also Ctrl+p works Older Mac ...

  7. 峰回路转的提权08r2服务器

    事前日下这个站的时候说实话,略微的蛋疼.其过程就不写了,就讲讲提权吧.可能图片有点暗.看看我写这篇文章的时候就知道了. 这个学校我好多同学在里面读书,就萌生了.日下这个站的想法. 拿到shell,理所 ...

  8. 【转】Python读取PDF文档,输出内容

    Python3读取pdf文档,输出内容(txt) from urllib.request import urlopen from pdfminer.pdfinterp import PDFResour ...

  9. SERVER_ADDR

    $_SERVER["SERVER_ADDR"]  当前运行脚本的服务器的ip地址

  10. 【k8s secret token 删掉自动重建】kubernetes secret 和 serviceaccount

    https://stackoverflow.com/questions/54354243/kubernetes-secret-is-persisting-through-deletes