【C++】学习笔记——stack和queue

简介: 【C++】学习笔记——stack和queue

九、stack和queue

1. stack和queue的介绍

stack 就是我们常说的 ,而 queue 就是 队列 。栈就是 后进先出数据结构,队列就是 先进先出 的数据结构。从严格意义上来讲,这里的栈和队列已经不属于 容器 了,而是属于 容器适配器 。什么是 容器适配器 呢,我们待会再说。

2. stack和queue的使用

stackqueue 的使用非常简单。

栈就这么多接口,其中绝大部分接口我们已经非常非常熟悉了。

队列也只有这么点接口,同样我们都非常熟悉了。

我们发现,栈和队列有一个共同点:他们都不支持迭代器 。为什么呢?因为栈和队列有自己的输入和输出规则,栈是 后进先出 ,队列是 先进先出 ,而迭代器可能会打破这个规则,所以他们俩都不支持迭代器。

#include<iostream>
#include<stack>
#include<queue>
using namespace std;
int main()
{
  stack<int> st;
  st.push(1);
  st.push(2);
  st.push(3);
  st.push(4);
  st.push(5);
  while (!st.empty())
  {
    cout << st.top() << " ";
    st.pop();
  }
  cout << endl;
  return 0;
}

3. stack和queue的模拟实现

STL库 里,这俩其实是通过 适配器模式 实现的。适配器是什么意思呢?他就像电源转换器一样,将多少多少伏特电压转换成多少多少伏特电压。具有 转换 的功能。我们一般都是通过循序结构来实现栈和队列的,但是既然我们已经学了 vectorlist ,所以我们就能把 vectorlist 拿过来使用。

#pragma once
#include<vector>
#include<list>
namespace my
{
  template<class T, class Container>
  class stack
  {
  public:
  private:
    Container _con;
  };
}

在这里,如果是数组栈,那我们第二个参数传 vector 即可,如果是链式栈,那第二个参数传 list 即可。

// 数组栈
stack<int, vector<int>>;
// 链式栈
stack<int, list<int>>;

这样实现的栈就是 适配器模式的栈 ,通过容器适配出来的栈。

所以说,我们栈所需要的函数和结果,通过调用其他容器的函数就行。我们来见证一下:首先创建一个 Stack.h 头文件。

// Stack.h
#pragma once
#include<vector>
#include<list>
namespace my
{
  template<class T, class Container>
  class stack
  {
  public:
    void push(const T& x)
    {
      // 栈是栈顶入栈
      _con.push_back(x);
    }
    void pop()
    {
      // 栈顶出栈
      _con.pop_back();
    }
    size_t size()
    {
      return _con.size();
    }
    bool empty()
    {
      return _con.empty();
    }
    const T& top()
    {
      return _con.back();
    }
  private:
    Container _con;
  };
}

是不是很震惊?没错,调用其他容器的函数就能实现栈。我们来测试一下:

// test.cpp
#include<iostream>
#include"Stack.h"
using namespace std;
void test01()
{
  my::stack<int, vector<int>> st;
  st.push(1);
  st.push(2);
  st.push(3);
  st.push(4);
  st.push(5);
  while (!st.empty())
  {
    cout << st.top() << " ";
    st.pop();
  }
  cout << endl;
}
int main()
{
  test01();
  return 0;
}

跟我们想的栈几乎没区别好吧。仅仅只是创建对象的时候需要两个参数而已,但是 STL库 里的栈和队列就没有第二个参数,我们需要将第二个参数给优化掉。怎么优化呢? 缺省参数

// 函数模板给缺省参数就能够解决问题。
template<class T, class Container = vector<T>>
class stack
{
public:
  //
private:
  Container _con;
};

这下若是使用数组栈,就可以只传一个参数了。

#include<iostream>
#include"Stack.h"
#include<queue>
using namespace std;
void test01()
{
  my::stack<int> st;
  st.push(1);
  st.push(2);
  st.push(3);
  st.push(4);
  st.push(5);
  while (!st.empty())
  {
    cout << st.top() << " ";
    st.pop();
  }
  cout << endl;
}
int main()
{
  test01();
  return 0;
}

栈的实现这么简单,队列的实现同样非常简单,这里我直接给代码了:

#pragma once
#include<list>
namespace my2
{
  template<class T, class Container = list<T>>
  class queue
  {
  public:
    void push(const T& x)
    {
      // 尾部入队列
      _con.push_back(x);
    }
    void pop()
    {
      // 头部出队列
      _con.pop_front();
    }
    size_t size()
    {
      return _con.size();
    }
    bool empty()
    {
      return _con.empty();
    }
    const T& back()
    {
      return _con.back();
    }
    const T& front()
    {
      return _con.front();
    }
  private:
    Container _con;
  };
}

测试一下:

#include<iostream>
#include"Queue.h"
using namespace std;
void test02()
{
  my2::queue<int> q;
  q.push(1);
  q.push(2);
  q.push(3);
  q.push(4);
  q.push(5);
  while (!q.empty())
  {
    cout << q.front() << " ";
    q.pop();
  }
  cout << endl;
}
int main()
{
  test02();
  return 0;
}

4. deque的简单了解

deque 是什么?deque双端队列 。但其本质不是队列,它并不要求先进先出。它集合了 vectorlist 的优点。

vector的优缺点

优点:支持下标随机访问。

缺点:头部或者中间插入/删除效率低,扩容有消耗

list的优缺点

优点:支持任意位置插入/删除,效率都不错。

缺点:不支持下标随机访问。

那我们还需要使用 vectorlist 吗?当然要使用,不然我们学他们干什么哈哈。deque 就像是一个链表,每个节点存的都是一个小数组,然后通过一个 中控指针数组 来指向每一个节点的地址,就像 页表 一样。可以快速访问数据。由于 deque 支持头插和尾插,所以 中控指针数组一开始只能在中间头插的时候中控指针数组往左延申,尾插的时候往右延申。当中控指针数组满的时候给其扩容。

由于 deque 的逻辑难度和实现难度都比之前的难不少,这里就不再详细实现,通过看文档了解即可。

deque的优缺点

优点:头插/尾插的效率很好。

缺点:中间插入会非常麻烦,效率一般,[]访问的效率不够极致。

STL库 里的栈和队列当中,默认容器都是 deque ,原因就是 deque的头尾插入删除很优秀 ,而栈和队列也仅仅支持头尾插入删除。


未完待续

目录
相关文章
|
2月前
|
存储 算法 调度
【C++打怪之路Lv11】-- stack、queue和优先级队列
【C++打怪之路Lv11】-- stack、queue和优先级队列
43 1
|
2月前
|
设计模式 存储 C++
C++之stack 和 queue(下)
C++之stack 和 queue(下)
44 1
|
2月前
|
存储 算法 C语言
【C++】C++ STL探索:Priority Queue与仿函数的深入解析(一)
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
|
2月前
|
C++ 容器
C++之stack 和 queue(上)
C++之stack 和 queue(上)
65 0
|
2月前
|
存储 C++ 容器
C++番外篇——stack、queue的实现及deque的介绍
C++番外篇——stack、queue的实现及deque的介绍
32 0
|
2月前
|
存储 算法 C++
C++入门10——stack与queue的使用
C++入门10——stack与queue的使用
48 0
|
2月前
|
C++
【C++】C++ STL探索:Priority Queue与仿函数的深入解析(三)
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
|
2月前
|
编译器 程序员 C++
【C++】C++ STL探索:Priority Queue与仿函数的深入解析(二)
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
|
1月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
51 2
|
1月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
108 5