c++初阶--Stack,Queue和PriorityQueue的实现
今天我们来学习一下c++中的栈和队列,我们之前学过的vector和list是模板容器,而今天我们要学习的是容器适配器,那么什么是容器适配器呢?
目录
1. 容器适配器
1.1 适配器
1.2 Stack和Queue
2. deque的介绍
2.1 deque的原理介绍
2.2 deque的缺陷
2.3 为什么选择deque作为stack和queue的底层默认容器
3. Stack和Queue的实现
3.1 Stack的实现
3.2 Queue的实现
4. Priority Queue优先级队列
4.1 优先级队列的介绍
4.2 仿函数
4.3 优先级队列的实现
1. 容器适配器
1.1 适配器
1.2 Stack和Queue
2. deque的介绍
2.1 deque的原理介绍
2.2 deque的缺陷
2.3 为什么选择deque作为stack和queue的底层默认容器
1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进
行操作。
2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的
元素增长时,deque不仅效率高,而且内存使用率高。
3. Stack和Queue的实现
3.1 Stack的实现
#include<deque>
template<class T,class container= deque<T>>
class Stack {
public:
Stack()
{}
bool empty() const
{
return S.empty();
}
size_t size() const
{
return S.size();
}
void push(const T& x)
{
S.push_back(x);
}
void pop()
{
S.pop_back();
}
T& top()
{
return S.back();
}
private:
container S;
};
3.2 Queue的实现
#include<deque>
template<class T,class container= deque<T>>
class Queue {
public:
Queue()
{}
bool empty() const
{
return Q.empty();
}
size_t size() const
{
return Q.size();
}
void push(const T& x)
{
Q.push_back(x);
}
void pop()
{
Q.pop_front();
}
const T& front() const
{
return Q.front();
}
const T& back() const
{
return Q.back();
}
private:
container Q;
};
4. Priority Queue优先级队列
4.1 优先级队列的介绍
1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。4. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。5. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。
4.2 仿函数
优先级队列就是数据结构中的堆,由于堆只能定义为大堆或者小堆,优先级队列默认是元素大的优先级高,我们在使用的时候不能说要找出最小的元素就去再创建一个新的优先级队列,所以这里要使用仿函数。
仿函数是一个类,可以用class或者struct来定义,类中有一个重载函数operator()(),该函数重载的是()运算符。仿函数没有成员变量,是一个空类,所以仿函数的大小为1。
对于仿函数的对象,可以像函数一样调用,所以仿函数对象也叫函数对象。在实际使用的时候,仿函数作用于函数内部用来修饰条件。
4.3 优先级队列的实现
#include<vector>
template<class T>
class Less {
public:
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template<class T>
class Greater {
public:
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
template<class T, class container = vector<T>, class compare = Less<T>>
class Priority_queue {
public:
Priority_queue()
{}
bool empty() const
{
return con.empty();
}
size_t size() const
{
return con.size();
}
const T& top()
{
return con[0];
}
void push(const T& x)
{
con.push_back(x);
adjust_up(con.size() - 1);
}
void adjust_up(int child)
{
compare com;
int parent = (child - 1) / 2;
while (child > 0)
{
if (com(con[parent], con[child]))
{
swap(con[parent], con[child]);
child = parent;
parent=(child - 1) / 2;
}
else {
break;
}
}
}
void pop()
{
swap(con[0], con[con.size() - 1]);
con.pop_back();
adjust_down(0);
}
void adjust_down(int parent)
{
int child = parent * 2 + 1;
compare com;
while (child < con.size())
{
if ((child + 1 < con.size()) && (com(con[child], con[child + 1])))
{
child++;
}
if (com(con[parent], con[child]))
{
swap(con[parent], con[child]);
parent = child;
child = parent * 2 + 1;
}
else {
break;
}
}
}
private:
container con;
};
其中,Less和Greater两个类就是仿函数,它们作用于堆的向上调整和向下调整两个函数中,当我们使用大堆时,模板参数给定Less仿函数,使用小堆时,只需要将Less改为Greater即可,大大增强了使用的便利。
有关c++的Stack和Queue及Priority Queue三个容器适配器就介绍到这里。