实现一个整形栈

代码:

cpp 复制代码
#include <iostream>
#include <stdexcept> // 用于 std::out_of_range

class IntStack {
private:
    int* _data;        // 动态数组指针,指向堆上的内存
    size_t _capacity;  // 栈的总容量(数组大小)
    size_t _top;       // 栈顶索引(指向下一个可插入位置,也代表当前元素个数)

    // 私有辅助函数:扩容
    void resize() {
        size_t new_capacity = _capacity * 2;
        int* new_data = new int[new_capacity]; // 1. 分配新内存

        // 2. 复制旧数据
        for (size_t i = 0; i < _top; ++i) {
            new_data[i] = _data[i];
        }

        // 3. 释放旧内存并更新指针
        delete[] _data;
        _data = new_data;
        _capacity = new_capacity;
    }

public:
    // 1. 构造函数
    explicit IntStack(size_t init_size = 10) 
        : _capacity(init_size), _top(0) {
        if (init_size == 0) {
            _data = nullptr;
        } else {
            _data = new int[_capacity];
        }
    }

    // 2. 析构函数 (三法则之一)
    ~IntStack() {
        delete[] _data; // 释放堆内存
    }

    // 3. 拷贝构造函数 (三法则之一)
    IntStack(const IntStack& other) 
        : _capacity(other._capacity), _top(other._top) {
        if (_capacity == 0) {
            _data = nullptr;
        } else {
            _data = new int[_capacity];
            for (size_t i = 0; i < _top; ++i) {
                _data[i] = other._data[i];
            }
        }
    }

    // 4. 赋值运算符 (三法则之一)
    IntStack& operator=(const IntStack& other) {
        if (this != &other) { // 防止自赋值
            // 1. 申请新资源
            int* new_data = nullptr;
            size_t new_capacity = other._capacity;
            if (new_capacity > 0) {
                new_data = new int[new_capacity];
                for (size_t i = 0; i < other._top; ++i) {
                    new_data[i] = other._data[i];
                }
            }

            // 2. 释放旧资源
            delete[] _data;

            // 3. 更新状态
            _data = new_data;
            _capacity = new_capacity;
            _top = other._top;
        }
        return *this;
    }

    // 5. 元素个数
    size_t size() const {
        return _top;
    }

    // 6. 判空
    bool empty() const {
        return _top == 0;
    }

    // 7. 入栈
    void push(int value) {
        if (_top >= _capacity) {
            resize(); // 自动扩容
        }
        _data[_top++] = value; // 先赋值,再自增
    }

    // 8. 访问栈顶元素 (不删除)
    int& top() {
        if (empty()) {
            throw std::out_of_range("IntStack top() error: stack is empty");
        }
        return _data[_top - 1];
    }

    const int& top() const {
        if (empty()) {
            throw std::out_of_range("IntStack top() error: stack is empty");
        }
        return _data[_top - 1];
    }

    // 9. 出栈 (删除栈顶元素)
    void pop() {
        if (empty()) {
            throw std::out_of_range("IntStack pop() error: stack is empty");
        }
        --_top;
    }
};

该类主要由以下几个核心模块组成,每个模块都有其特定的作用:

1. 私有成员变量 (数据存储)

_data (int*): 这是一个指针,指向堆上分配的连续内存块(动态数组)。它是存储栈中所有元素的物理容器。

_capacity (size_t): 记录 _data 数组的总长度。表示栈最多能存多少个元素而不需要重新申请内存。

_top (size_t): 栈顶指针。这里采用的是"左闭右开"区间逻辑,_top 指向下一个待插入元素的位置 。因此,_top 的值也等于当前栈中元素的个数。

2. 辅助函数 resize()

作用 :当栈满(_top == _capacity)时,自动扩大存储空间。

用处:

  1. 申请一块两倍于当前容量的新内存。
  2. 将旧内存中的所有数据逐个复制到新内存。
  3. 释放旧内存,并让 _data 指向新内存
3. 构造函数 IntStack()

作用:初始化对象。

细节 :使用了 explicit 防止隐式类型转换。默认初始容量为 10。如果初始大小为 0,则将指针置空。

4. 析构函数 ~IntStack()

作用:清理资源。

关键点 :必须使用 delete[] 释放构造函数中 new 出来的数组。这是防止内存泄漏的关键。

5. 拷贝控制 (三法则)

为了管理动态内存,必须手动控制拷贝行为:

拷贝构造函数 :当用一个栈初始化另一个栈时调用。它执行深拷贝,即不仅复制指针,还复制指针指向的数据,确保两个栈互不影响。

赋值运算符:当一个栈被赋值给另一个已存在的栈时调用。它需要先释放自己原有的内存,再申请新内存复制数据,并处理自赋值的情况。

6. 核心接口

push(int): 入栈。先检查是否需要扩容,然后将元素放入 _data[_top] 位置,最后 _top 加 1。

pop(): 出栈。仅将 _top 减 1(逻辑上删除),不实际删除数据。

top(): 访问栈顶。返回 _data[_top - 1] 的引用,允许读写。如果栈空则抛出异常。

empty(): 通过判断 _top 是否为 0 来确定栈是否为空。

size(): 返回 _top 的值。

测试代码:

cpp 复制代码
int main() {
    IntStack s;
    s.push(10);
    s.push(20);
    
    std::cout << "Top: " << s.top() << std::endl; // 输出 20
    s.pop();
    std::cout << "Size: " << s.size() << std::endl; // 输出 1
    
    return 0;
}
相关推荐
努力努力再努力wz1 分钟前
【Lua 入门系列】Lua数据结构:从 Table 出发,一文串联数组、链表、栈、队列、集合、映射与树的实现原理
数据结构·链表·lua
ShineWinsu8 分钟前
对于Qt:QLCDNumber常见属性以及QTimer的解析
服务器·数据库·c++·qt·gui·qtimer·qlcdnumber
xiaoye-duck15 分钟前
《C++ 工具库实战》C++ 解析利器 JsonCpp:从基础使用到封装简易 JSON 工具
c++·json·第三方库
dialect_8 小时前
KMP算法
开发语言·c++·算法
reikocao9 小时前
卡尔曼滤波的动态机制:P如何改变融合权重
算法
漂流瓶jz9 小时前
UVA-1612 猜名次 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·题解·排序·aoapc·算法竞赛入门经典
吞下星星的少年·-·10 小时前
Div.2 CF 1130B题(构造,贪心)
算法·贪心·构造
ShineWinsu10 小时前
对于Qt:QRadioButton常见属性以及QButtonGroup的解析
数据库·c++·qt·microsoft·gui·qradiobutton·qbuttongroup
傲世仙尊11 小时前
多态-虚表才活到运行期符号表早已消失
c++
chenbingjie_c11 小时前
C++ 多态完全指南:从虚函数重写到虚函数表原理
开发语言·c++