顺序栈Stack——数据结构系列教程(c++版)

梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)


  栈(Stack)是数据结构中经典的后进先出(LIFO, Last In, First Out),也可称为 “先进后出(FILO)”,就像日常生活中的米桶最先进入的大米最后才被拿出来。栈(Stack)是一种线性数据结构,它的存储方式遵循 “有序线性” 的特征(数据元素之间存在一对一的前后逻辑关系),但访问和操作具有严格的限制性。本教程基于数组实现的栈,从核心原理、代码结构到实战使用,全面讲解栈的原理与实现,功能包含入栈、出栈、获取栈顶元素等核心功能。

教程目录导航

一、栈的核心原理

1.1 栈的性质

  1. 后进先出(LIFO):这是栈的核心规则,新元素从栈顶(top)加入(入栈),元素从栈顶(top)取出(出栈),元素只能在栈顶完成操作,不存在中间插入或删除的操作。
  2. 线性结构:栈属于线性数据结构,元素之间存在一对一的前后逻辑关系,不存在分支或层级结构,符合线性表的基本特征(与数组、链表、队列一致)。
  3. 操作限制:栈的操作具有明确的限制性,仅支持一端的操作,不支持随机访问或中间位置的插入 / 删除
    • 只能在栈顶进行 “入栈” 操作(添加元素);
    • 只能在栈顶进行 “出栈” 操作(删除元素);
    • 可以查看栈顶元素,但无法直接访问栈中间的元素。
  4. 栈状态:
    • 空栈:栈中不包含任何有效元素,此时无法执行出栈操作(下溢);
    • 满栈(仅存在于固定容量队列):栈已达到最大存储容量,此时无法执行入栈操作(上溢)。

演示动画

1.2 核心操作

操作名称 功能描述 时间复杂度
入栈 将指定元素添加到栈顶,栈满时抛出异常或返回失败标识 O(1)
出栈 从栈顶移除并返回元素,栈为空时抛出异常或返回失败标识 O(1)
判空 判断栈是否为空,返回布尔值(true = 空,false = 非空) O(1)
判满 判断固定容量队列是否已满,返回布尔值(true = 满,false = 未满)(链式栈无需此操作) O(1)
获取栈顶元素 查看栈顶元素的值,不执行移除操作,栈为空时抛出异常或返回无效值 O(1)

1.3 存储结构

栈可以采用顺序存储和链式存储两种形式:

(1)顺序存储

(1)链式存储

每一个节点有二个域,即data数据域、next下一个节点地址。

二、代码结构解析

2.1 整体架构

提供的代码是模板化的栈实现(支持任意类型),采用C++结构体封装,分为头文件(声明)和源文件(实现)两部分,核心结构如下:

模块 作用 关键结构/函数
栈结构体 封装所有操作 ArrayStack<T>(模板类)

2.2 关键结构体详解

(1)队列结构体(ArrayStack)


template <typename T>
struct ArrayStack
{
    // ------------------------------------------------------------------------------------------------------
    //                                          私有成员
    // 注:私有成员只能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)不能访问调用)
    //------------------------------------------------------------------------------------------------------
    private:

        //---------------声明私有成员变量---------------

        T data[MAXSIZE];     // 存储数据,支持任意类型
        int top;            // 栈顶指针,初始为-1表示空栈

        //---------------声明私有成员函数---------------


    // ------------------------------------------------------------------------------------------------------
    //                                          公共成员
    // 注:公共成员能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)也能访问调用)
    //------------------------------------------------------------------------------------------------------
    public:

        //---------------声明公共成员函数---------------

        // 构造函数:外部通过该结构体定义(实例化)变量(对象)时,自动执行该函数(主要用于初始化成员变量的值)
        ArrayStack() {
            top = -1;
        }

        int isEmpty();                  // 判断栈是否为空
        int isFull();                   // 栈是否已满
        void push(const T& value);      // 入栈操作
        T pop();                        // 出栈操作(返回栈顶元素)
        T getTop();                     // 获取栈顶元素(不弹出)
        void print();                   // 打印栈数据(从栈底到栈顶,不修改top指针)

        // 析构函数:自动销毁栈,避免内存泄漏
        ~ArrayStack() {
        }
};
            

三、核心操作实现详解

3.1 获取栈顶元素(getTop)

template <typename T>
T ArrayStack<T>::getTop() {
    if (isEmpty()) {
        return T();
    }
    return data[top];
}

3.2 入栈(push)

template <typename T>
void ArrayStack<T>::push(const T& value) {
    if (isFull()) {
        printf("栈溢出!\n");
    }
    data[++top] = value;
}

3.3 出栈(pop)

template <typename T>
T ArrayStack<T>::pop() {
    if (isEmpty()) {
        printf("栈为空!\n");
        return T();
    }
    return data[top--];
}

四、实战使用示例

4.1 基础类型(int)使用示例

#include "ArrayStack.h"
#include <iostream>

int main() {
    ArrayStack<int> stacks;

    // 1. 入栈测试
    printf("\n=== 入栈测试 ===\n");
    stacks.push(1);
    stacks.push(2);
    stacks.push(3);
    stacks.push(4);
    stacks.push(5);
    printf("入栈1、2、3、4、5后:\n");
    stacks.print();

    // 2. 出队测试
    printf("\n=== 出栈测试 ===\n");
    printf("出栈3次:");
    printf("%d ",stacks.pop());
    printf("%d ",stacks.pop());
    printf("%d \n",stacks.pop());
    printf("出栈后");
    stacks.print();

    return 0;
}

4.2 输出结果


=== 入栈测试 ===
入栈1、2、3、4、5后:
栈元素(栈底 → 栈顶):1 2 3 4 5
栈状态:栈顶指针=4,元素个数=5

=== 出栈测试 ===
出栈3次:5 4 3
出栈后栈元素(栈底 → 栈顶):1 2
栈状态:栈顶指针=1,元素个数=2
            

五、完整可运行代码

5.1 Entitys.h 头文件


#ifndef ENTITYS_H_INCLUDED
#define ENTITYS_H_INCLUDED

//************************************************************************************************************************************************************************
//                                                                      自定义类型
//************************************************************************************************************************************************************************

//========================================================================================================================================================================
//                                                                    学生结构体(Student)
//========================================================================================================================================================================
struct Student {
    int id;// 学号
    std::string name;// 姓名
    std::string dob;// 出生日期
    std::string sex;// 性别
    std::string gender;// 民族
    std::string address;// 地址
    float score;// 入学总分
    std::string school;// 学校
    std::string team;// 班级
    std::string status;// 状态

    bool operator<(const Student& other) const { return id < other.id; }
    bool operator>(const Student& other) const { return id > other.id; }
    bool operator==(const Student& other) const { return id == other.id; }
    bool operator!=(const Student& other) const { return id != other.id; }

    friend std::ostream& operator<<(std::ostream& os, const Student& s) {
        os << "[" << s.id<< ", " << s.name << ", " << s.dob << ", " << s.sex << ", " << s.gender  << ", " << s.address << ", " << s.score<< ", " << s.school<< ", " << s.team<< ", " << s.status << "]";
        return os;
    }
};

//========================================================================================================================================================================
//
//                                                                    学生索引结构体(Student)
//
//========================================================================================================================================================================
struct StudentIndex {
    int id;// 学号
    int row;// 行号

    bool operator<(const StudentIndex& other) const { return id < other.id; }
    bool operator>(const StudentIndex& other) const { return id > other.id; }
    bool operator==(const StudentIndex& other) const { return id == other.id; }
    bool operator!=(const StudentIndex& other) const { return id != other.id; }

    friend std::ostream& operator<<(std::ostream& os, const StudentIndex& i) {
        os << "[" << i.id << ", " << i.row<< "]";
        return os;
    }
};

//========================================================================================================================================================================
//                                                                    迷宫坐标结构体(Pos)
//========================================================================================================================================================================
struct Pos{
    int x;     //x坐标
    int y;    //y坐标
    int step; //步数
};

//========================================================================================================================================================================
//                                                                    打印任务结构体(PrintTask)
//========================================================================================================================================================================
struct PrintTask{
    int taskId;     // 任务ID
    char content[50]; // 打印内容
};

#endif // ENTITYS_H_INCLUDED
        

5.2 ArrayStack.h 头文件


#ifndef ARRAYSTACK_H_INCLUDED
#define ARRAYSTACK_H_INCLUDED

#include "Entitys.h"

//************************************************************************************************************************************************************************
//
//      类名:数组栈(ArrayStack)
//
//      概述:一个可复用的数组栈,存储结构采用数组实现,支持任意类型数据(模板泛型)。
//
//      说明:默认栈的最大容量为100,入栈出栈时间复杂度为O(1)
//
//************************************************************************************************************************************************************************

#define MAXSIZE 100  // 栈的最大容量

//========================================================================================================================================================================
//
//                                                                 数组栈结构体(ArrayStack)
//
//========================================================================================================================================================================
template <typename T>
struct ArrayStack
{
    // ------------------------------------------------------------------------------------------------------
    //                                          私有成员
    // 注:私有成员只能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)不能访问调用)
    //------------------------------------------------------------------------------------------------------
    private:

        //---------------声明私有成员变量---------------

        T data[MAXSIZE];     // 存储数据,支持任意类型
        int top;            // 栈顶指针,初始为-1表示空栈

        //---------------声明私有成员函数---------------


    // ------------------------------------------------------------------------------------------------------
    //                                          公共成员
    // 注:公共成员能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)也能访问调用)
    //------------------------------------------------------------------------------------------------------
    public:

        //---------------声明公共成员函数---------------

        // 构造函数:外部通过该结构体定义(实例化)变量(对象)时,自动执行该函数(主要用于初始化成员变量的值)
        ArrayStack() {
            top = -1;
        }

        int isEmpty();                  // 判断栈是否为空
        int isFull();                   // 栈是否已满
        void push(const T& value);      // 入栈操作
        T pop();                        // 出栈操作(返回栈顶元素)
        T getTop();                     // 获取栈顶元素(不弹出)
        void print();                   // 打印栈数据(从栈底到栈顶,不修改top指针)

        // 析构函数:自动销毁栈,避免内存泄漏
        ~ArrayStack() {
        }
};

#endif // ARRAYSTACK_H_INCLUDED
                
                
                

5.3 ArrayStack.cpp 程序代码


#include <iostream>
#include"ArrayStack.h"

//**********************实现公有成员函数**********************

// 判断栈是否为空函数
template <typename T>
int ArrayStack<T>::isEmpty() {
    return top == -1;
}

// 判断栈是否已满函数
template <typename T>
int ArrayStack<T>::isFull() {
    return top == MAXSIZE - 1;
}

// 入栈操作函数
template <typename T>
void ArrayStack<T>::push(const T& value) {
    if (isFull()) {
        printf("栈溢出!\n");
    }
    data[++top] = value;
}

// 出栈操作函数(返回栈顶元素)
template <typename T>
T ArrayStack<T>::pop() {
    if (isEmpty()) {
        printf("栈为空!\n");
        return T();
    }
    return data[top--];
}

// 获取栈顶元素函数(不弹出)
template <typename T>
T ArrayStack<T>::getTop() {
    if (isEmpty()) {
        return T();
    }
    return data[top];
}

// 打印栈数据(从栈底到栈顶,不修改top指针)
template <typename T>
void ArrayStack<T>::print() {
    if (isEmpty()) {
        printf("栈为空,无元素可遍历!\n");
        return;
    }

    // 方式1:从栈底(索引0)到栈顶(索引top)遍历(符合栈的"先进先出"遍历逻辑)
    printf("栈元素(栈底 → 栈顶):");
    for (int i = 0; i <= top; i++) {
        printf("%d ", data[i]);
    }
    printf("\n");

    // 可选:方式2 - 从栈顶到栈底遍历(按需选择)
    // printf("栈元素(栈顶 → 栈底):");
    // for (int i = top; i >= 0; i--) {
    //     printf("%d ", data[i]);
    // }
    // printf("\n");

    // 可选:打印栈状态(便于调试,不修改指针)
    printf("栈状态:栈顶指针=%d,元素个数=%d\n", top, top + 1);
}                   

// 显式实例化常用类型(避免链接错误,可选)
template class ArrayStack<int>;
template class ArrayStack<char>;
template class ArrayStack<float>;
template class ArrayStack<std::string>;
template class ArrayStack<Student>; // 新增:显式实例化Student类型
template class ArrayStack<Pos>; // 新增:显式实例化Pos类型
template class ArrayStack<PrintTask>; // 新增:显式实例化PrintTask类型

5.4 main.cpp 测试代码

#include "ArrayStack.h"
#include <iostream>
#include <string>

int main() {
    ArrayStack<int> stacks;

    // 1. 入栈测试
    printf("\n=== 入栈测试 ===\n");
    stacks.push(1);
    stacks.push(2);
    stacks.push(3);
    stacks.push(4);
    stacks.push(5);
    printf("入栈1、2、3、4、5后:\n");
    stacks.print();

    // 2. 出队测试
    printf("\n=== 出栈测试 ===\n");
    printf("出栈3次:");
    printf("%d ",stacks.pop());
    printf("%d ",stacks.pop());
    printf("%d \n",stacks.pop());
    printf("出栈后");
    stacks.print();
    
    return 0;
}

输出结果


=== 入栈测试 ===
入栈1、2、3、4、5后:
栈元素(栈底 → 栈顶):1 2 3 4 5
栈状态:栈顶指针=4,元素个数=5

=== 出栈测试 ===
出栈3次:5 4 3
出栈后栈元素(栈底 → 栈顶):1 2
栈状态:栈顶指针=1,元素个数=2
    

六、注意事项

模板类型约束

  • 模板类型需支持</>/==运算符(内置类型如int/string默认支持,自定义类型需重载);
  • 自定义类型需重载<<运算符(打印输出时使用)。

显式实例化:代码末尾的template class ArrayStack<int>;等显式实例化,避免链接错误,新增类型需补充显式实例化。

七、应用场景

八、总结

本教程通过代码解析和实战示例,覆盖了栈的核心原理、关键操作实现和实际使用场景。栈作为基础数据结构,掌握栈的实现,是深入学习更复杂数据结构的重要基础。


返回顶部