C++ stack类与queue类

目录

0.前言

1.容器适配器

1.1容器适配器的特点

1.2容器适配器的实现

1.3使用容器适配器的场景

2.stack的介绍与使用

2.1介绍

2.2使用

3.queue的介绍与使用

3.1介绍

3.2使用

4.stack和queue的模拟实现

4.1 stack的模拟实现

4.2 queue的模拟实现

5.结语


(图像由AI生成)

0.前言

在前面的博客中,我们介绍了STL(Standard Template Library)中的stringvectorlist,这些都是作为“容器”而存在的数据结构。它们各有特点和适用场景,并且都属于独立的容器类型。接下来要介绍的stackqueue,则是“容器适配器”。它们并不是独立的容器,而是通过某些容器来实现特定的行为和接口。因此,它们被称为“容器适配器”。接下来,就让我们一探究竟。

1.容器适配器

容器适配器(Container Adapters)是C++标准模板库(STL)中的一种特殊类别。与常规容器(如vectorlistdeque等)不同,容器适配器不直接管理存储元素的内存,而是基于现有的容器提供一种特定的接口和行为。容器适配器通过限制和修改底层容器的操作来实现其功能。

C++中主要的容器适配器有三种:stackqueuepriority_queue。它们分别适用于不同的场景:

  1. stack:实现后进先出(LIFO,Last In First Out)数据结构。
  2. queue:实现先进先出(FIFO,First In First Out)数据结构。
  3. priority_queue:实现元素按优先级排序的队列,允许最高优先级的元素先出队。

1.1容器适配器的特点

  • 基于现有容器:容器适配器是基于已有容器(如dequelistvector)实现的。这意味着它们依赖于这些底层容器的存储和操作机制。
  • 限制接口:容器适配器通过限制底层容器的操作接口来实现特定的数据结构行为。例如,stack只允许访问栈顶元素,不允许随机访问其他元素。
  • 一致性接口:所有容器适配器都提供一致的接口,这使得它们在使用上更加简洁和统一。

1.2容器适配器的实现

容器适配器通过组合现有容器类,并对其进行包装,实现特定的接口。以下是一个自定义的容器适配器MyAdapter的简化实现:

#include <iostream>
#include <deque>

template <typename T, typename Container = std::deque<T>>
class MyAdapter {
private:
    Container c;
public:
    // 类型定义
    typedef typename Container::value_type value_type;
    typedef typename Container::size_type size_type;
    typedef typename Container::reference reference;
    typedef typename Container::const_reference const_reference;

    // 构造函数
    explicit MyAdapter(const Container& cont = Container()) : c(cont) {}

    // 成员函数
    bool isEmpty() const { return c.empty(); }
    size_type getSize() const { return c.size(); }
    reference getFirst() { return c.front(); }
    const_reference getFirst() const { return c.front(); }
    void add(const value_type& value) { c.push_back(value); }
    void removeFirst() { c.pop_front(); }
};

int main() {
    MyAdapter<int> adapter;
    adapter.add(1);
    adapter.add(2);
    adapter.add(3);

    std::cout << "First element: " << adapter.getFirst() << std::endl;
    adapter.removeFirst();
    std::cout << "First element after removal: " << adapter.getFirst() << std::endl;

    return 0;
}

在这个简化的实现中,MyAdapter类是一个模板类,它基于Container(默认为deque)实现。通过限制Container的操作接口,实现了特定的行为:

  • isEmpty():检查容器是否为空。
  • getSize():获取容器中的元素数量。
  • getFirst():访问容器中的第一个元素。
  • add():向容器中添加元素。
  • removeFirst():移除容器中的第一个元素。

1.3使用容器适配器的场景

容器适配器在实际开发中有广泛的应用场景。例如:

  • 递归和回溯算法:在递归和回溯算法中,stack常用于保存临时状态和返回地址。
  • 任务调度queue常用于实现任务调度,按顺序处理任务。
  • 优先级调度priority_queue常用于实现优先级调度,将高优先级任务优先处理。

通过使用容器适配器,可以简化代码的实现,提高开发效率。同时,由于容器适配器基于已有容器实现,性能和稳定性也得到了保证。

2.stack的介绍与使用

2.1介绍

stack是一种后进先出(LIFO,Last In First Out)的数据结构。它的特点是最后添加的元素最先被移除。stack适用于许多计算机科学领域和算法,包括递归、表达式求值、括号匹配、深度优先搜索(DFS)等。C++中的stack是通过容器适配器实现的,通常基于dequevector容器。

stack提供了一组特定的接口,包括:

  • push:将元素添加到栈顶。
  • pop:移除栈顶元素。
  • top:访问栈顶元素,但不移除它。
  • empty:检查栈是否为空。
  • size:获取栈中的元素数量。

这些接口使得stack可以方便地用于实现各种需要后进先出行为的算法和数据处理任务。

与直接使用dequevector不同,stack通过限制操作接口,确保了只能通过特定的方式访问和修改数据,从而保证了数据的后进先出顺序。这种封装和接口限制提高了代码的安全性和可读性,避免了不必要的操作干扰stack的逻辑。

2.2使用

stack容器适配器提供了一组简单但强大的操作接口,使得它能够高效地实现后进先出的数据管理。以下是stack的主要功能:

  • push:将元素添加到栈顶。每次调用push,新元素都会被放置在栈的顶部。
  • pop:移除栈顶元素。调用pop会删除位于栈顶的元素。注意,pop操作不会返回被移除的元素。
  • top:访问栈顶元素,但不移除它。top操作返回当前位于栈顶的元素,但不会改变栈的状态。
  • empty:检查栈是否为空。如果栈中没有元素,empty返回true,否则返回false
  • size:获取栈中的元素数量。size操作返回栈中当前元素的个数。

以下是一个使用stack的完整示例代码,展示了这些操作的实际使用:

#include <iostream>
#include <stack>

int main() {
    std::stack<int> s;

    // 将元素添加到栈顶
    s.push(1);
    s.push(2);
    s.push(3);

    // 打印栈的大小
    std::cout << "Stack size: " << s.size() << std::endl;

    // 访问栈顶元素
    std::cout << "Top element: " << s.top() << std::endl;

    // 移除栈顶元素
    s.pop();

    // 再次访问栈顶元素
    std::cout << "Top element after pop: " << s.top() << std::endl;

    // 打印栈是否为空
    std::cout << "Is stack empty? " << (s.empty() ? "Yes" : "No") << std::endl;

    // 再次移除栈顶元素并打印状态
    s.pop();
    s.pop();
    std::cout << "Is stack empty after popping all elements? " << (s.empty() ? "Yes" : "No") << std::endl;

    return 0;
}

下面是以上代码的运行结果:

Stack size: 3
Top element: 3
Top element after pop: 2
Is stack empty? No
Is stack empty after popping all elements? Yes 

3.queue的介绍与使用

3.1介绍

queue是一种先进先出(FIFO,First In First Out)的数据结构。它的特点是最早添加的元素最先被移除。queue在很多应用场景中都非常实用,比如任务调度、缓冲区管理、广度优先搜索(BFS)等。C++中的queue是通过容器适配器实现的,通常基于dequelist容器。

queue提供了一组特定的接口,包括:

  • push:将元素添加到队列的末尾。
  • pop:移除队列的第一个元素。
  • front:访问队列的第一个元素,但不移除它。
  • back:访问队列的最后一个元素,但不移除它。
  • empty:检查队列是否为空。
  • size:获取队列中的元素数量。

这些接口使得queue可以方便地用于实现各种需要先进先出行为的算法和数据处理任务。

与直接使用dequelist不同,queue通过限制操作接口,确保了只能通过特定的方式访问和修改数据,从而保证了数据的先进先出顺序。这种封装和接口限制提高了代码的安全性和可读性,避免了不必要的操作干扰queue的逻辑。

3.2使用

queue容器适配器提供了一组简洁而强大的操作接口,使得它能够高效地实现先进先出的数据管理。以下是queue的主要功能:

  • push:将元素添加到队列的末尾。每次调用push,新元素都会被放置在队列的尾部。
  • pop:移除队列的第一个元素。调用pop会删除位于队列前端的元素。注意,pop操作不会返回被移除的元素。
  • front:访问队列的第一个元素,但不移除它。front操作返回当前位于队列前端的元素,但不会改变队列的状态。
  • back:访问队列的最后一个元素,但不移除它。back操作返回当前位于队列尾部的元素,但不会改变队列的状态。
  • empty:检查队列是否为空。如果队列中没有元素,empty返回true,否则返回false
  • size:获取队列中的元素数量。size操作返回队列中当前元素的个数。

以下是一个使用queue的完整示例代码,展示了这些操作的实际使用:

#include <iostream>
#include <queue>

int main() {
    std::queue<int> q;

    // 将元素添加到队列末尾
    q.push(1);
    q.push(2);
    q.push(3);

    // 打印队列的大小
    std::cout << "Queue size: " << q.size() << std::endl;

    // 访问队列的第一个元素
    std::cout << "Front element: " << q.front() << std::endl;

    // 访问队列的最后一个元素
    std::cout << "Back element: " << q.back() << std::endl;

    // 移除队列的第一个元素
    q.pop();

    // 再次访问队列的第一个元素
    std::cout << "Front element after pop: " << q.front() << std::endl;

    // 打印队列是否为空
    std::cout << "Is queue empty? " << (q.empty() ? "Yes" : "No") << std::endl;

    // 再次移除队列的第一个元素并打印状态
    q.pop();
    q.pop();
    std::cout << "Is queue empty after popping all elements? " << (q.empty() ? "Yes" : "No") << std::endl;

    return 0;
}

 下面是以上代码的运行结果:

Queue size: 3
Front element: 1
Back element: 3
Front element after pop: 2
Is queue empty? No
Is queue empty after popping all elements? Yes

4.stack和queue的模拟实现

4.1 stack的模拟实现

下面是Stack类的模拟实现,它是一个模板类,使用一个底层容器Container(默认为deque)来实现栈的功能。我们将详细介绍其原理,并给出完整的代码和注释。

原理介绍

Stack类是一个容器适配器,它封装了一个底层容器Container,并通过限制其接口实现栈的后进先出(LIFO)行为。该类提供了基本的栈操作,包括pushpoptopsizeempty

  • push:将元素添加到栈顶。调用Containerpush_back方法实现。
  • pop:移除栈顶元素。调用Containerpop_back方法实现。
  • top:返回栈顶元素。调用Containerback方法实现。
  • size:返回栈中元素的数量。调用Containersize方法实现。
  • empty:检查栈是否为空。调用Containerempty方法实现。

以下是Stack类的完整代码和注释:

#pragma once
#include <deque>
#include <list>

using namespace std;

// 模板类Stack,默认使用deque作为底层容器
template<class T, class Container = deque<T>>
class Stack {
private:
    // 底层容器,用于存储栈的元素
    Container con;
public:
    // 默认构造函数
    Stack() {}

    // 将元素添加到栈顶
    void push(const T& val) {
        // 使用底层容器的push_back方法将元素添加到末尾
        con.push_back(val);
    }

    // 移除栈顶元素
    void pop() {
        // 使用底层容器的pop_back方法移除末尾元素
        con.pop_back();
    }

    // 返回栈顶元素
    T& top() {
        // 使用底层容器的back方法返回末尾元素
        return con.back();
    }

    // 返回栈中元素的数量
    size_t size() {
        // 使用底层容器的size方法获取元素数量
        return con.size();
    }

    // 检查栈是否为空
    bool empty() {
        // 使用底层容器的empty方法检查是否为空
        return con.empty();
    }
};

4.2 queue的模拟实现

下面是Queue类的模拟实现,它是一个模板类,使用一个底层容器Container(默认为deque)来实现队列的功能。我们将详细介绍其原理,并给出完整的代码和注释。

原理介绍

Queue类是一个容器适配器,它封装了一个底层容器Container,并通过限制其接口实现队列的先进先出(FIFO)行为。该类提供了基本的队列操作,包括pushpopfrontbacksizeempty

  • push:将元素添加到队列的末尾。调用Containerpush_back方法实现。
  • pop:移除队列的第一个元素。调用Containerpop_front方法实现。
  • front:返回队列的第一个元素。调用Containerfront方法实现。
  • back:返回队列的最后一个元素。调用Containerback方法实现。
  • size:返回队列中元素的数量。调用Containersize方法实现。
  • empty:检查队列是否为空。调用Containerempty方法实现。

以下是Queue类的完整代码和注释:

#pragma once
#include <list>
#include <deque>

using namespace std;

// 模板类Queue,默认使用deque作为底层容器
template<class T, class Container = deque<T>>
class Queue {
private:
    // 底层容器,用于存储队列的元素
    Container con;
public:
    // 默认构造函数
    Queue() {}

    // 将元素添加到队列末尾
    void push(const T& val) {
        // 使用底层容器的push_back方法将元素添加到末尾
        con.push_back(val);
    }

    // 移除队列的第一个元素
    void pop() {
        // 使用底层容器的pop_front方法移除第一个元素
        con.pop_front();
    }

    // 返回队列的第一个元素
    T& front() {
        // 使用底层容器的front方法返回第一个元素
        return con.front();
    }

    // 返回队列的最后一个元素
    T& back() {
        // 使用底层容器的back方法返回最后一个元素
        return con.back();
    }

    // 返回队列中元素的数量
    size_t size() {
        // 使用底层容器的size方法获取元素数量
        return con.size();
    }

    // 检查队列是否为空
    bool empty() {
        // 使用底层容器的empty方法检查是否为空
        return con.empty();
    }
};

5.结语

通过对C++标准模板库中的stackqueue的介绍与使用,我们深入了解了这两种重要的容器适配器。stackqueue在许多计算机科学领域和实际应用中都有广泛的使用场景。我们不仅学习了它们的基本操作和应用,还通过模拟实现进一步理解了其内部机制。掌握这些数据结构和容器适配器,将显著提升我们在算法设计和程序开发中的效率和能力。希望这篇博客能帮助读者更好地理解和应用stackqueue,为大家在编程道路上提供有力的支持。

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值