【C++】STL中的容器适配器 stack queue 和 priority_queue 的模拟实现

简介: 【C++】STL中的容器适配器 stack queue 和 priority_queue 的模拟实现

一、容器适配器

1、什么是容器适配器

适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。

例如我们常见的充电器就是一种适配器,它将我们常用的220V交流电压转化为4,5V (或者其他更高的电压) 的直流电压来给我们的电子设备进行充电。

2、STL标准库中的容器适配器

虽然stackqueuepriority_queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配

器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stackqueue默认使用dequepriority_queue默认使用了vector

二、stack的模拟实现

1、stack的简单介绍

相关文档

stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,但这些容器类应该支持以下操作:

  • empty:判空操作
  • back:获取尾部元素操作
  • push_back:尾部插入元素操作
  • pop_back:尾部删除元素操作

标准容器vectordequelist均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque

2、栈的模拟实现

为了栈的通用性,这里我们使用模板来进行模拟栈,关于栈的底层容器这里我们选择vector来进行模拟实现。

template<class T, class Container = vector<T>>
class stack
{
public:
  //栈的插入
  void push(const T& val)
  {
    //使用底层容器中尾插函数进行插入,栈只能进行栈顶插入和删除
    _con.push_back(val);
  }
  //栈的删除
  void pop()
  {
    //使用底层容器中尾删函数进行插入,栈只能进行栈顶插入和删除
    _con.pop_back();
  }
  //获取栈顶元素
  T& top()
  {
    //返回底层容器中最后一个数据
    return _con.back();
  }
  //const 版本
  const T& top() const
  {
    return _con.back();
  }
  //获取数据个数
  size_t size() const
  {
    //返回底层容器中数据的个数
    return _con.size();
  }
  //判空函数
  bool empty() const
  {
    //对底层容器进行判空
    return _con.empty();
  }
private:
  //成员变量是一个容器创建的对象
  Container _con;
};

三、queue的模拟实现

1、queue的简单介绍

相关文档

queue底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:

  • empty:检测队列是否为空
  • size:返回队列中有效元素的个数
  • front:返回队头元素的引用
  • back:返回队尾元素的引用
  • push_back:在队列尾部入队列
  • pop_front:在队列头部出队列

标准容器类dequelist满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque

2、queue的模拟实现

为了queue的通用性,这里我们使用模板来进行模拟queue,关于queue的底层容器这里我们选择list来进行模拟实现。

template<class T, class Container = list<T>>
class queue
{
public:
  //队列的插入
  void push(const T& val)
  {
    //使用底层容器中尾插函数进行插入,队列只能进行队尾插入
    _com.push_back(val);
  }
  //队列的删除
  void pop()
  {
    //使用底层容器中头删函数进行删除,队列只能进行队头删除
    _com.pop_front();
  }
  //获取队头数据
  T& front()
  {
    //返回底层容器中第一个数据
    return _com.front();
  }
  //const版本
  const T& front() const
  {
    return _com.front();
  }
  //获取队尾数据
  T& back()
  {
    //返回底层容器中最后一个数据
    return _com.back();
  }
  //const版本
  const T& back() const
  {
    return _com.back();
  }
  //获取数据个数
  size_t size() const
  {
    //返回底层容器中数据的个数
    return _com.size();
  }
  //判空函数
  bool empty() const
  {
    //对底层容器进行判空
    return _com.empty();
  }
private:
  //成员变量是一个容器创建的对象
  Container _com;
};

四、priority_queue的模拟实现

1、priority_queue的简单介绍

相关文档

优先队列是一种容器适配器,它其实就是我们数据结构中的,默认情况下priority_queue是大堆。

priority_queue底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:

  • empty:检测容器是否为空
  • size:返回容器中有效元素个数
  • front:返回容器中第一个元素的引用
  • push_back:在容器尾部插入元素
  • pop_back:删除容器尾部元素

标准容器类vectordeque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector

2、priority_queue的模拟实现

与前面的栈与队列一样priority_queue前两个模板参数都类似,但是priority_queue要有第三个模板参数,这个参数表示按照什么方式进行比较,即建立大堆还是小堆。

//第三个参数是比较方式,需要传递一个仿函数来确定比较方式,默认传递的是less<T>,表示建大堆
template<class T, class Container = vector<T>, class Comper = less<T>>
class priority_queue
{
public:
  //获取堆顶数据
  const T& top() const
  {
    //返回底层容器的第一个数据
    return _con.front();
  }
  //获取数据个数
  size_t size() const
  {
    //返回底层容器的数据个数
    return _con.size();
  }
  //判空函数
  bool empty() const
  {
    //判断底层容器是否为空
    return _con.empty();
  }
  //堆的插入
  void push(const T& val)
  {
    //从尾部插入
    _con.push_back(val);
    int child = _con.size() - 1;
    //向上调整重新建堆
    AdjustUp(child);
  }
  //堆的删除
  void pop()
  {
    //检查堆是否为空
    assert(!_con.empty());
    //交换堆顶与最后一个数据
    swap(_con.front(), _con.back());
    //删除最后一个数据
    _con.pop_back();
    //从堆顶进行向下调整,重新建堆
    AdjustDown(0);
  }
private:
  //向上调整算法
  void AdjustUp(int child)
  {
    Comper com;
    int parent = (child - 1) / 2;
    while (child > 0)
    {
      //这里使用了仿函数来判断建立什么堆
      //比较的位置(_con[parent], _con[child])是不能换的!!!
      if (com(_con[parent], _con[child]))
      {
        swap(_con[parent], _con[child]);
        child = parent;
        parent = (child - 1) / 2;
      }
      else
      {
        break;
      }
    }
  }
  //向下调整算法
  void AdjustDown(int parent)
  {
    Comper com;
    //默认左孩子更符合建堆的要求
    int child = parent *2 + 1;
    while (child < _con.size())
    {
      if (child + 1 < _con.size() && Comper()(_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;
      }
    }
  }
  //成员变量是一个容器创建的对象
  Container _con;
};
相关文章
|
4月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
100 2
|
3月前
|
存储 设计模式 C++
【C++】优先级队列(容器适配器)
本文介绍了C++ STL中的线性容器及其适配器,包括栈、队列和优先队列的设计与实现。详细解析了`deque`的特点和存储结构,以及如何利用`deque`实现栈、队列和优先队列。通过自定义命名空间和类模板,展示了如何模拟实现这些容器适配器,重点讲解了优先队列的内部机制,如堆的构建与维护方法。
60 0
|
4月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
90 5
|
4月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
103 2
|
2天前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
1月前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
68 19
|
1月前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
50 13
|
1月前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
50 5
|
1月前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
40 5
|
1月前
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
48 4