当前位置: 首页 > news >正文

s4栈学习和链栈的实现

一、核心知识点回顾

  1. 栈(Stack)的特性栈是一种后进先出(LIFO, Last In First Out) 的线性数据结构,仅允许在一端(栈顶)进行插入(push)和删除(pop)操作,常用操作包括:

    • push:在栈顶插入元素
    • pop:移除栈顶元素
    • getTop:获取栈顶元素(不删除)
    • isEmpty:判断栈是否为空
    • getSize:获取栈中元素数量
  2. 链表实现栈的优势栈的实现通常有两种方式:数组和链表。本代码采用链表实现,优势在于:

    • 动态扩容:无需预先指定大小,元素数量可灵活增长
    • 内存高效:仅占用实际存储元素所需的内存,无数组的 “预分配冗余”
    • 操作便捷:栈顶插入 / 删除元素的时间复杂度为O(1)
  3. 模板类(Template)代码使用template <class T>定义模板类,使ListStack能存储任意数据类型(如intstring等),实现了代码的复用性和泛型编程思想。

二、代码逐部分讲解

1. 栈节点结构(StackNode
template <class T>
struct StackNode {T value;          // 存储节点的值StackNode *next;  // 指向后继节点(栈底方向的节点)// 构造函数:初始化值和指针(默认值为T的默认构造,指针为nullptr)StackNode(const T &val = T(), StackNode*n = nullptr) : value(val), next(n) {}
};
  • 每个节点包含两部分:value(存储数据)和next(指向栈的下一个元素,即更靠近栈底的元素)
  • 构造函数支持自定义初始化,简化新节点的创建
2. 栈类(ListStack)的核心成员
template <typename T>
class ListStack {int size;               // 栈中元素的数量StackNode<T> *top;      // 指向栈顶节点的指针(栈的入口)
public:// 构造函数:初始化栈为空(size=0,top=nullptr)ListStack() : size(0), top(nullptr) {}// ... 成员函数 ...
};
  • size:记录元素数量,避免每次需要遍历链表计数(O(1)获取大小)
  • top:栈顶指针,所有插入 / 删除操作都围绕top进行
3. 核心操作实现
(1)入栈(push
void push(const T& val) {// 创建新节点,值为val,next指向当前栈顶(新节点成为新的栈顶)StackNode<T>* newNode = new StackNode<T>(val, top);top = newNode;  // 更新栈顶指针为新节点size++;         // 元素数量+1
}
  • 流程:创建新节点 → 新节点的next指向原栈顶 → 更新top为新节点 → 增大size
  • 时间复杂度:O(1)(仅需修改指针)
(2)出栈(pop
void pop() {if (isEmpty()) {throw std::runtime_error("栈为空,无法执行出栈操作");}StackNode<T>* temp = top;  // 保存当前栈顶节点top = top->next;           // 栈顶指针后移(指向原栈顶的下一个节点)delete temp;               // 释放原栈顶节点的内存(避免内存泄漏)size--;                    // 元素数量-1
}
  • 注意:出栈前必须检查栈是否为空(否则会访问nullptr,导致程序崩溃)
  • 异常处理:栈空时抛出异常,避免错误操作
  • 时间复杂度:O(1)
(3)获取栈顶元素(getTop
T& getTop() {if (isEmpty()) {throw std::runtime_error("栈为空,无法获取栈顶元素");}return top->value;  // 返回栈顶节点的值(引用类型,支持修改)
}
  • 同样需要检查栈是否为空,避免访问空指针
  • 返回引用(T&):允许直接修改栈顶元素的值(如intStack.getTop() = 100;
(4)其他辅助操作
  • isEmpty():通过size == 0判断栈是否为空(O(1)
  • getSize():直接返回sizeO(1)
  • clear():通过循环调用pop()清空所有元素(O(n)n为元素数量)
  • print():从栈顶到栈底遍历链表,打印所有元素(O(n)
4. 主函数(main)测试
int main() {// 测试int类型的栈ListStack<int> intStack;intStack.push(10);intStack.push(20);intStack.push(30);intStack.print();  // 栈顶->栈底:30 20 10(符合LIFO特性)// 测试string类型的栈ListStack<std::string> strStack;strStack.push("Hello");strStack.push("World");strStack.print();  // 栈顶->栈底:World Helloreturn 0;
}
  • 验证了模板类的泛型能力:同一ListStack类可处理intstring等不同类型
  • 输出结果符合栈的 “后进先出” 特性:最后入栈的元素在最前面打印

三、总结

  1. 设计亮点

    • 采用链表实现,动态性好,无固定大小限制
    • 模板类设计实现泛型编程,支持多数据类型
    • 操作安全性高:空栈操作时抛出异常,避免崩溃
    • 内存管理完善:pop()clear()中显式释放内存,防止泄漏
  2. 可优化点

    • 可添加拷贝构造函数和赋值运算符重载,避免浅拷贝问题(默认的拷贝会导致两个栈共用同一份链表,释放时双重删除)
    • 可将print()改为迭代器遍历,更符合 STL 风格
    • 异常处理可改为返回bool值(根据场景选择异常或返回值方式)

这段代码完整实现了栈的核心功能,是链表和栈数据结构结合的典型案例,同时展示了模板编程的灵活性,适合作为数据结构入门的实践代码。

完整代码:

#include <iostream>
using namespace std;
template <class T>
struct StackNode
{T value;StackNode *next;StackNode(const T &val = T(), StackNode*n = nullptr) : value(val), next(n) {}
};
template <typename T>
class ListStack
{int size;StackNode<T> *top;public:ListStack() : size(0), top(nullptr) {}void push(const T& val)//在栈顶插入新元素{StackNode<T>* newNode = new StackNode<T>(val);newNode->next=top;top=newNode;size++;}void pop()//移除栈顶元素{if (isEmpty()) {throw std::runtime_error("栈为空,无法执行出栈操作");}// 保存当前栈顶节点StackNode<T>* temp = top;// 更新栈顶指针top = top->next;// 释放原栈顶节点的内存delete temp;// 栈大小减1size--;}T& getTop()//获取栈顶元素{if (isEmpty()) {throw std::runtime_error("栈为空,无法获取栈顶元素");}return top->value;}bool isEmpty()//判断栈是否为空{return size==0;}int getSize()//获取栈中元素个数{return size;}void clear()//清空栈中所有元素{while(!isEmpty()){pop();}}void print()//打印栈中所有元素{if (isEmpty()) {std::cout << "栈为空" << std::endl;return;}std::cout << "栈元素(栈顶->栈底):";StackNode<T>* current = top;while (current != nullptr) {std::cout << current->value<< " ";current = current->next;}std::cout << std::endl;}
};
int main(){ListStack<int> intStack;// 入栈操作intStack.push(10);intStack.push(20);intStack.push(30);intStack.print();  // 输出:栈元素(栈顶->栈底):30 20 10// 获取栈顶元素std::cout << "栈顶元素:" << intStack.getTop() << std::endl;  // 输出:30// 出栈操作intStack.pop();intStack.print();  // 输出:栈元素(栈顶->栈底):20 10// 查看栈大小std::cout << "栈大小:" << intStack.getSize() << std::endl;  // 输出:2// 创建一个存储字符串的链栈ListStack<std::string> strStack;strStack.push("Hello");strStack.push("World");strStack.print();  // 输出:栈元素(栈顶->栈底):World Helloreturn 0;
}

http://www.dtcms.com/a/487457.html

相关文章:

  • 阿里云建站后台国际新闻最新报道
  • Linux操作系统学习之---进程信号的产生和保存
  • React Hooks 核心原理与开发技巧
  • 海南手机网站建设公司哪家好深圳营销型网站seo
  • 丽江市建设局网站深圳市城乡和建设局网站首页
  • 南昌做公司网站哪家好生物做实验的网站
  • RHCSA 基础练习
  • Learn C the Hardway学习笔记和拓展知识(一)
  • 算法10.0
  • 凡科网做的网站能直接用吗网站换服务器对排名有影响吗
  • 多层超表面革新 | 简化传统光学系统
  • 辽阳专业建设网站公司电话山东住房城乡建设厅网站首页
  • 数据结构2:线性表1-线性表类型及其特点
  • 网站外包如何报价做那种事的网站
  • 张家港做网站的推荐驻马店app和网站开发公司
  • 目标检测(一)
  • 石家庄免费做网站专做药材的网站有哪些
  • 基本功 | 一文讲清多线程和多线程同步
  • 360门户网站怎样做广州百度seo代理
  • C++蓝桥杯之函数与递归
  • Oracle AWR报告分析:诊断RAC Global cache log flush性能故障
  • python - 第四天
  • 领取流量网站药剂学教学网站的建设
  • 端端网站开发网络广告网站怎么做
  • threejs(五)纹理贴图、顶点UV坐标
  • debug - MDK - arm-none-eabi - 将MDK工程编译过程的所有命令行参数找出来
  • 网站怎么维护百度会收录双域名的网站么
  • Oracle数据库基本命令的8个模块
  • Vue3中的计算属性和监视属性【5】
  • Docker部署WordPress及相关配置