目录
deque
Dequ(double-e nded queue)双端队列,是一种可以在头尾两端进行插入和 删除操作且时间复杂度为O(1)的"连续"空间的数据结构
空间结构:
deque是由一段段等长度的连续空间和一个map中控区(指针数组)所构成的,当空间不足时只需在开一个空间并将他链接到map,与list不同,deque不能保证将其所有元素存储在连续的存储位置.
迭代器:
dequr的迭代器维护起来相对复杂,是由四个指针一起来维护,node指向中控区,first和node分别指向一段空间的开始和结束,cur指向访问到的位置。如果访问的元素不在当前空间,cur就等于下一个空间的first,依次跑下去
deque的优缺点
与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是必vector高的。
与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段
deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到 某段小空间的边界,导致效率低下。
为什么选择deque作为stack和queue的底层默认容器
stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
优先级队列(priority_queue)
优先级队列(priority_queue)是一种容器适配器,优先级队列(priority_queue)其实并不像queue那样满足先进先出,优先级队列中,将具有最高优先级的元素将被首先删除,
仿函数的概念
仿函数又称为函数对象,是一个能行使函数功能的类。
作为仿函数的类,都必须重载 operator() 运算符。因为调用仿函数,实际上就是通过类对象调用重载后的 operator() 运算符。
让我们看两个例子
template<class T>
struct less
{
bool operator()(const T& x1,const T& x2)
{
return x1 < x2;
}
}
template<class T>
struct greater
{
bool operator()(const T& x1,const T& x2)
{
return x1 > x2;
}
}
我们看到 greater 和 less 都只是将 operator()运算符进行重载,只不过返回的真假结果不同。
和queue不同 priority_queue 多了一个仿函数类型的模板参数。且是缺省值,不传参数时,默认使用less将优先级最高的元素弹出。
priority_queue的成员函数:
模拟实现一个简单的priority_queue
模拟实现的priority_queue的成员函数:
1.push() :入队。向队列添加一个元素;
2.pop() :将队列中优先级最高的元素删除(出队)
3.top() :获得队列优先级最高的元素。
4.size() :获得队列大小。
5.empty() :判断队列是否为空
priority_queue的底层就像数据类型中的“堆”一样,将元素从堆顶弹出
不传第三个参数时,默认是用less,会将优先级最高的元素弹出。
当我们第三参数传greater时,会弹出优先级最低的元素。
push()和top()
push的时候每次都将有限级最高(或最低)的元素排在队头,top的时候将队头的数据弹出
template<class T,class Container=vector<T>,class compare=less<T>>
{
public:
//向上调整,将最大(或最小)的元素排到堆顶
void AdjustUp(int child)
{
compate com; //仿函数类型
int parent=(child-1)/2;child的根节点
while(child > 0)
{
//这里的_con()是被operator()重载过得,返回的是一个bool值
if(com(_con[parent],_con[child]))
{
//向上调整,将最大(或最小)的元素排到堆顶
swap(con[child],_con[parent]);
child=parent;
parent=(child-1)/2;
}
else
{
break;
}
}
}
void push(const T& x)
{
_con.push_back(x);
AdjustUp(_con.size() -1);
}
T& top()
{
return _con[0] //将第一个元素弹出
}
private:
container _con;
}
pop()
pop先将第一个元素和最后一个元素交换,将最后一个弹出,但是交换过后存储的数据就乱了,我们还需用向下调整法将数据的一个元素调整为优先级最高的(或最低的),
template<class T,class Container=vector<T>,class compare=less<T>>
{
public:
void AddjustDown()
{
Compare com; 定义一个仿函数类型
int child=rood*2+1; 找到根的孩子
while(child < _con.size())
{
//选出左右孩子中大(或下的)的那一个
if(child+1<con.zize() && com(_con[child],_con[child+1])
{
++child;
}
if(com[_con[child],_con[parent]);
{
swap(_con[child],_con[parent]);
parent=child;
child=parent*2+1;
}
else
{
break;
}
}
}
void push()
{
swap(_con[0],con[con.size()-1);//将我们需要pop的元素交换到尾
_con.pop_back() //弹出队尾元素;
AddjustDown(0)将数据的第一个元素调整为优先级最高的(或最低的)
}
private:
container _con;
}
size()和empty()
template<class T,class Container=vector<T>,class compare=less<T>>
{
public:
size_t size()
{
return _con.size();
}
bool empty()
{
return _con.empty();
}
private:
container _con;
}
测试
void test_priority_queue()
{
//默认大的优先级比较高
priority_queue<int,vector<int>,less<int>> pq;
pq.push(3);
pq.push(1);
pq.push(9);
pq.push(4);
pq.push(2);
pq.pop();
cout<<"pq: ";
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
//默认小的有限级高
priority_queue<int, vector<int>, greater<int>> pq2;
pq2.push(3);
pq2.push(1);
pq2.push(9);
pq2.push(4);
pq2.push(2);
pq2.pop();
cout<<"pq2: ";
while (!pq2.empty())
{
cout << pq2.top() << " ";
pq2.pop();
}
cout << endl;
}
测试结果
本篇就分享到这里,如果本文对您有帮助请点赞支持一下~
文章尚有不足,欢迎大牛指正