C++stack模拟实现

前言

作者今天来实现一下stack

stack逻辑上是一个先进后出的栈,底层可以考虑用其它容器来实现

在功能上stack相比于vector做了很多简化,比如少了迭代器的功能

1. 容器与容器适配器

cpp 复制代码
template<class T, class Container = std::deque<T>>
class MyStack
{
public:

C++中stack是一个容器适配器,底层默认使用deque容器

容器适配器是对容器进行的封装,对很多容器的接口进行了限制屏蔽,通过底层容器的接口对底层容器里存的数据进行操作

2. deque的简介

deque是一种双端队列,队列两边都可以做平均O(1)级别的插入或删除

底层是一块一块连续空间,所以支持下标作为索引进行O(1)级别访问

3. 选用deque而不用vector的原因

在stack中,deque比起vector,不需要连续虚拟内存空间,且能进行无用内存的释放

4. stack的top方法返回引用

cpp 复制代码
    T& top() {
        return _con.back();
    }
    const T& top() const {
        return _con.back();
    }

top方法返回左值引用,若MyStack的对象没加const,外部可以直接对top()进行修改

5. const对象调用const或者非const成员方法,是否可行

cpp 复制代码
    void push(const T &x) {
        _con.push_back(x);
    }
    void pop() {
        _con.pop_back();
    }
    T& top() {
        return _con.back();
    }
    const T& top() const {
        return _con.back();
    }
    size_t size() const {
        return _con.size();
    }
    bool empty() const {
        return _con.empty();
    }

若类中两个函数同名,参数相同,返回值相同,区别只是隐藏的this指针是否被const修饰

那么如果对象是const修饰,调用该函数,会自动调用const成员函数

如果对象没有const修饰,会自动调用非const成员函数

此外,如果对象没有const修饰,既可以调用非const成员函数,也可以调用const成员函数

如果对象有const修饰,只能调用调用const成员函数

6. std中swap的两个参数类型

cpp 复制代码
template <class T> void swap ( T& a, T& b )
{
  T c(a); a=b; b=c;
}

std::swap传入的两个参数类型必须是左值,swap的两个形参都是对实参的左值引用

因为交换就意味着对参数的值进行修改了

7. stack的swap实现时,使用Container的swap而不使用stl的swap

cpp 复制代码
void swap(MyStack<T, Container> &st) noexcept(noexcept(_con.swap(st._con))) {
    _con.swap(st._con);
}

template <class T> void swap ( T& a, T& b )
{
  T c(a); a=b; b=c;
}

若是使用std自带的swap,发生一次拷贝,两次赋值,赋值底层可能是对象的深拷贝,效率极低

而使用底层容器的swap,可以尽可能地降低时间复杂度,因为像vector这样的容器,它的swap方法仅将交换三个内置类型(即指针),时间复杂度O(1)

8. noexcept的作用

cpp 复制代码
    void swap(MyStack<T, Container> &st) noexcept(noexcept(_con.swap(st._con))) {
        _con.swap(st._con);
    }

noexcept放在函数的参数列表后面,若是noexcept()括号中的值为true,在生成MyStack类中swap汇编相关代码时,不会生成抛异常的代码,从而节省了二进制程序的体积

函数在编译期间就开始计算noexcept的结果

9. 把stl的swap也做重载

cpp 复制代码
template<class T, class Container = std::deque<T>>
void swap(MyStack<T, Container> &a, MyStack<T, Container> &b) 
    noexcept(noexcept(a.swap(b))) 
{
    a.swap(b);
}

结合第7. 点,为了防止用户调用std的swap产生低效率的交换,对于swap两个MyStack模板类对象进行了函数重载

总体实现

cpp 复制代码
#pragma once
#include <deque>

template<class T, class Container = std::deque<T>>
class MyStack
{
public:
    void push(const T &x) {
        _con.push_back(x);
    }
    void pop() {
        _con.pop_back();
    }
    T& top() {
        return _con.back();
    }
    const T& top() const {
        return _con.back();
    }
    size_t size() const {
        return _con.size();
    }
    bool empty() const {
        return _con.empty();
    }
    void swap(MyStack<T, Container> &st) noexcept(noexcept(_con.swap(st._con))) {
        _con.swap(st._con);
    }
private:
    Container _con;
};


template<class T, class Container = std::deque<T>>
void swap(MyStack<T, Container> &a, MyStack<T, Container> &b) 
    noexcept(noexcept(a.swap(b))) 
{
    a.swap(b);
}

测试代码

cpp 复制代码
#include <iostream>
#include <vector>
#include "MyStack.hpp"  // 你的栈头文件

using namespace std;

int main()
{
    // ==========================
    // 测试 1:基础功能
    // ==========================
    MyStack<int> st1;
    cout << "===== 测试 1:基础功能 =====" << endl;
    cout << "空栈? " << boolalpha << st1.empty() << endl; // true

    st1.push(10);
    st1.push(20);
    st1.push(30);

    cout << "size: " << st1.size() << endl;   // 3
    cout << "栈顶: " << st1.top() << endl;    // 30

    st1.pop();
    cout << "pop 后栈顶: " << st1.top() << endl; // 20
    cout << "空栈? " << st1.empty() << endl;     // false
    cout << endl;

    // ==========================
    // 测试 2:swap 核心功能
    // ==========================
    MyStack<int> st2;
    st2.push(100);
    st2.push(200);

    cout << "===== 测试 2:swap 交换 =====" << endl;
    cout << "交换前:" << endl;
    cout << "st1 顶: " << st1.top() << endl;  // 20
    cout << "st2 顶: " << st2.top() << endl;  // 200

    // 两种 swap 都能跑
    st1.swap(st2);       // 成员 swap
    // swap(st1, st2);   // 非成员 swap(也能跑)

    cout << "交换后:" << endl;
    cout << "st1 顶: " << st1.top() << endl;  // 200
    cout << "st2 顶: " << st2.top() << endl;  // 20
    cout << endl;

    // ==========================
    // 测试 3:const 对象
    // ==========================
    cout << "===== 测试 3:const 栈 =====" << endl;
    MyStack<int> st3;
    st3.push(666);
    const MyStack<int>& st_const = st3;
    cout << "const 栈顶: " << st_const.top() << endl;
    cout << "const size: " << st_const.size() << endl;
    cout << "const empty: " << st_const.empty() << endl;
    cout << endl;

    // ==========================
    // 测试 4:底层容器换成 vector
    // ==========================
    cout << "===== 测试 4:vector 做底层容器 =====" << endl;
    MyStack<int, vector<int>> st_vec;
    st_vec.push(111);
    st_vec.push(222);
    cout << "size: " << st_vec.size() << endl;
    cout << "栈顶: " << st_vec.top() << endl;

    cout << "\n===== 所有测试全部通过!=====" << endl;

    return 0;
}

测试结果

./test

===== 测试 1:基础功能 =====

空栈? true

size: 3

栈顶: 30

pop 后栈顶: 20

空栈? false

===== 测试 2:swap 交换 =====

交换前:

st1 顶: 20

st2 顶: 200

交换后:

st1 顶: 200

st2 顶: 20

===== 测试 3:const 栈 =====

const 栈顶: 666

const size: 1

const empty: false

===== 测试 4:vector 做底层容器 =====

size: 2

栈顶: 222

===== 所有测试全部通过!=====

相关推荐
chao1898444 小时前
基于 SPEA2 的多目标优化算法 MATLAB 实现
开发语言·算法·matlab
沪漂阿龙4 小时前
AI大模型面试题:支持向量机是什么?间隔最大化、软间隔、核函数、LinearSVC 全面拆解
人工智能·算法·支持向量机
赏金术士5 小时前
Kotlin 习题集 · 高级篇
android·开发语言·kotlin
little~钰5 小时前
倍增算法和ST表
算法
原来是猿5 小时前
网络计算器:理解序列化与反序列化(中)
linux·运维·服务器·网络·tcp/ip
楼兰公子6 小时前
buildroot 在编译rust时裁剪平台类型数量的方法
开发语言·后端·rust
知识领航员6 小时前
蘑兔AI音乐深度实测:功能拆解、实测表现与适用场景
java·c语言·c++·人工智能·python·算法·github
薛定e的猫咪6 小时前
因果推理研究方向综述笔记
人工智能·笔记·深度学习·算法
AOwhisky6 小时前
虚拟化技术学习笔记
linux·运维·笔记·学习·虚拟化技术
吴声子夜歌6 小时前
Go——并发编程
开发语言·后端·golang