当前位置: 首页 > 编程日记 > 正文

栈 -- 顺序栈、链式栈的实现 及其应用(函数栈,表达式求值,括号匹配)

文章目录

      • 实现
        • 顺序栈实现
        • 链式栈实现
      • 应用
        • 函数栈 的应用
        • 表达式求值中 的应用
        • 括号匹配中 的应用

我们使用浏览器的时候经常会用到前进、后退功能。
依次访问完一串页面 a – b – c之后点击后退功能,则能够依次看到c – b – a的页面。
但是这个过程中,如果后退到了页面b,点击了新的页面d,则再点击前进无法回到页面c。
这个过程的实现就是我们 “栈”数据在其中起作用了。

实现

栈的基本实现有如下两种:

  • 顺序栈 – 基于数组的实现
  • 链式栈 – 基于链表的实现

在这里插入图片描述

顺序栈实现

#include <iostream>
#include <assert.h>using namespace std;class ArrayStack{
private:int size; // stack sizeint count; // stack element countint *arr; // 数组,保存栈中元素public:ArrayStack(int n) {size = n;count = 0;arr = new int[n];}ArrayStack(ArrayStack &obj) = delete;~ArrayStack() {delete []arr;}; //析构掉new出来的数组bool push(int element); // push元素到栈中int pop();  //从栈中弹出元素,并返回弹出到数值bool isEmpty(); //栈是否为空void show();    //打印栈中元素int get_size() { return size;} //获取栈的大小
};bool ArrayStack::push(int element) {assert(count != size );arr[count] = element;count ++;return  true;
}int ArrayStack::pop() {assert(count != 0);int tmp = arr[count];count --;return  tmp;
}bool ArrayStack::isEmpty() {if(count != 0) {return true;}return  false;
}void ArrayStack::show() {if(!this->isEmpty()) {cout << "stack is empty " << endl;}cout << "stack size is: " << count << " element is :";for (int i = 0;i < count; ++i) {cout << arr[i] << " ";}cout << endl;
}typedef  struct Link{int val;struct Link *next;
}list;class ListStack {
private:int size; // stack的大小int count; // stack的长度list *head; // 链表public:};int main() {ArrayStack st(5);int ele;int len = st.get_size();while (len != 0) {cin >> ele;st.push(ele);len --;}st.show();st.pop();st.show();st.pop();st.show();return 0;
}

输出如下:

#输入 
2 3 4  5 6#输出 
stack size is: 5 element is :2 3 4 5 6 
stack size is: 4 element is :2 3 4 5 
stack size is: 3 element is :2 3 4 

链式栈实现

#include <iostream>
#include <assert.h>using namespace std;/*链式栈的功能实现*/
template <class T> //模版类,用来创建任意数据类型的栈
class ListStack {
private:int size; // stack的大小int count; // stack的长度/*链式栈的数据结构*/struct Link{T val;struct Link *next;Link(T x = T()): val(x), next(nullptr){}};Link *head; // 链表public:ListStack(){} //默认构造函数ListStack(int n):size(n),count(0){head = new Link;}~ListStack();bool push(T x); //向栈中push元素T pop(); //pop元素bool isEmpty();void show();int get_size() { return size;}
};template <class T>
ListStack<T>::~ListStack() {Link *p, *tmp;p = head;while(p->next) {tmp = p -> next;p -> next = p -> next -> next;delete tmp;}delete  head;size = 0;count = 0;
}template <class T>
bool ListStack<T>::push(T x) {if(count == size) {return  false;}auto *p = new Link;p ->val = x;p -> next = head -> next;head -> next = p;count ++;return  true;
}template <class T>
T ListStack<T>::pop() {if (count == 0 || head == NULL) {return -1;}auto *p = head -> next;T val = p -> val;head -> next = head -> next -> next;count --; // 栈中元素个数自减delete p; // 需要将pop的元素空间释放return val;
}template <class T>
bool ListStack<T>::isEmpty() {return count == 0;
}template <class T>
void ListStack<T>::show() {if(isEmpty() || head == NULL) {cout << "stack is empty" << endl;}auto *p = head -> next;cout << "stack size is : " << count << " element is :";while(p) {cout << p -> val << " ";p = p -> next;}cout << endl;
}
int main() {ListStack<int> *st = new ListStack<int>(5); //初始化链式栈的大小为5int ele;int len_stack = st -> get_size();cout << "stack length is " << len_stack << endl;while(0 != len_stack) {cin >> ele;st->push(ele);len_stack --;}st->show();st->pop();st->show();st->pop();st->show();return 0;
}

输出如下:

stack length is 5#输入元素
2 3 4 5 6#输出
stack size is : 5 element is :6 5 4 3 2 
stack size is : 4 element is :5 4 3 2 
stack size is : 3 element is :4 3 2 

应用

函数栈 的应用

操作系统在进程运行的时候会为进程中的每个线程分配独立的内存空间,这块内存被组织成独立的栈的数据结构,用来存储函数调用时的临时变量。每进入一个函数,就会将临时变量作为一个栈帧入栈,当被调用函数执行完成,返回之后,这个函数对应的栈帧就会出栈。
如代码:

int main() {int a = 1;int ret = 0;int res = 0;ret = add(3, 5); res = a + ret; printf("%d", res);return 0;
} 
int add(int x, int y) { int sum = 0;sum = x + y;return sum;
} 

从代码中可以看到main()调用add()函数,获取计算结果,并与临时变量a相加,最后打印res的数值。
栈帧的组织图基本如下:
在这里插入图片描述

表达式求值中 的应用

要求支持带括号的四则元算,可以使用数据栈和符号栈进行实现
过程如下:
在这里插入图片描述
实现过程如下:

#include <iostream>
#include <algorithm>
#include <stack>
#include <map>using namespace std;void print_erro(string s,int line) {cout << s <<" " << line << endl;exit(-1);
}void calculate(stack<int> &num_stak, stack<char> &oper_stack) {int num1;int num2;int result;num1 = num_stak.top();num_stak.pop();num2 = num_stak.top();num_stak.pop();if (oper_stack.top() == '+') {result = num1 + num2;} else if (oper_stack.top() == '-') {result = -(num1 - num2);} else if (oper_stack.top() == '*') {result = num1 * num2;} else if (oper_stack.top() == '/') {if (num1 == 0) {print_erro("divide num is 0 \n", __LINE__);}result = num2 / num1;} else {print_erro("operator failed\n", __LINE__);}oper_stack.pop();num_stak.push(result);
}int state_change(string s) {static const int BEGIN_STATE = 0;static const int NUM_STATE = 1;static const int OPE_STATE = 2;int STATE = BEGIN_STATE;map<char,int> prio;stack<int> num_stack;stack<char> oper_stack;int cacl_flag = -1;int number = 0;prio['+'] = 1;prio['-'] = 1;prio['*'] = 2;prio['/'] = 2;prio['('] = 3;int i;if (s.empty()) {print_erro("string is empty\n",__LINE__);}for(int i = 0;i < s.size(); ++i) {if (s[i] == ' ') {continue;}switch (STATE){case BEGIN_STATE:if (s[i] >= '0' && s[i] <= '9') {STATE = NUM_STATE;} else if(s[i] == ')'){print_erro("string is not leagal\n",__LINE__);} else {STATE = OPE_STATE;}i--;break;case NUM_STATE:if (s[i] >= '0' && s[i] <= '9') {number = number*10 + s[i] - '0';} else {num_stack.push(number);if (cacl_flag == 2) {calculate(num_stack,oper_stack);}STATE = OPE_STATE;number = 0;i--;}break;case OPE_STATE:if(prio[s[i]] == 1) {oper_stack.push(s[i]);cacl_flag = 1;} else if(prio[s[i]] == 2) {oper_stack.push(s[i]);cacl_flag = 2;} else if (prio[s[i]] == 3) {cacl_flag = 3;STATE = NUM_STATE;break;} else if (s[i] == ')') {calculate(num_stack,oper_stack);break;} else if(s[i] >= '0' && s[i] <= '9') {STATE = NUM_STATE;i--;} else {print_erro("string is not leagal \n",__LINE__);}break;default:break;}}if (number != 0) {num_stack.push(number);calculate(num_stack,oper_stack);}if (number == 0 && num_stack.empty()) {return 0;}while(!oper_stack.empty() && num_stack.size() != 1) {calculate(num_stack,oper_stack);}if (!oper_stack.empty()) {print_erro("string is not leagal", __LINE__);}return num_stack.top();
}int main() {string s;cout << "input the string " << endl;cin >> s;int a = state_change(s);cout << "calcute the result is " << a << endl;return 0;
}

编译运行如下:

input the string 
(((1+5)/2+6*9+10)-(2+3)*100)
calcute the result is -433

括号匹配中 的应用

给定一个由括号组成的字符串,判断该字符串是否是一个合法的括号序列
假设给定的字符串中只包含三种括号:花括号{},方括号[],圆括号(),它们可以任意嵌套,如:{[{}]}或则[{()}([])]都为合法括号,{[}()]或则[({)]为不合法括号。

这个时候我们可以使用栈来保存未匹配的左括号,基本实现过程如下:

  • 从左到右依次扫描字符串,当遇到左括号的时候入栈
  • 遇到右括号 则从 栈顶取一个左括号,如果能够和当前右括号匹配(比如"(“和”)“匹配,”[“和”]“匹配,”{“和”}"匹配),则栈顶左括号可以从栈顶弹出。
  • 继续扫描后续字符串,如果遇到不能配对的右括号,或者栈中没有数据,则说明当前括号序列不合法。

实现如下:

bool isValid(string s) {if(s.length() == 0) return true;stack<char> S;for (int i = 0;i < s.length(); ++i) {switch(s[i]) {case ')':{if(!S.empty()) {if(S.top() == '('){S.pop();} else {return false;}}else {return false;}break;}case ']':{if(!S.empty()) {if(S.top() == '['){S.pop();} else {return false;}}else {return false;}break;                    }case '}':{if(!S.empty()) {if(S.top() == '{'){S.pop();} else {return false;}}else {return false;}break;                    }case '(':{S.push(s[i]);break;}case '[':{S.push(s[i]);break;}case '{':{S.push(s[i]);break;}}}if (S.size() != 0) {return false;}return true;
}

相关文章:

OC中的NSArray和NSMutableArray、NSDictionary和NSMutableDictionary用法

一&#xff1a;NSArray 和NSMutableArray1: NSArray&#xff1a;不可变数组NSArray是OC中使用的数组&#xff0c;只能用来存放OC对象&#xff0c;不能存放非OC对象如基本数据类型它使不可变的&#xff0c;一旦初始化完毕&#xff0c;内容不能改变&#xff0c;也不能添加元素。而…

java中ContentArea_java中TextArea怎么加载指定路径的文本内容

展开全部这设计到IO操作&#xff0c;很62616964757a686964616fe58685e5aeb931333332643334久以前练手写的加载文本到文本域的界面。具体代码第一步&#xff1a;得到一个File对象&#xff0c;需要参数文本路径File file new File("C:\\test.txt");第二步&#xff1a;…

文本分类技术基础

分类体系 分类&#xff1a;给定一个对象&#xff0c;从一个事先定义好的分类体系中挑出一个或多个最适合该对象的类别。 文本分类(TC, Text Categorization)&#xff1a;在给定的分类体系下&#xff0c;根据文本内容自动的确定文本关联的类别。从数学角度看&#xff0c;文本分类…

C# 返回值为 listT

public List<T> test<T>(List<T> EntityList) where T : class{return EntityList;} 转载于:https://www.cnblogs.com/enych/p/10497312.html

ceph bluestore 源码分析:ceph-osd内存查看方式及控制源码分析

文章目录内存查看内存控制内存控制源码分析通过gperftools接口获取osd进程实际内存 动态设置cache大小动态调整cache比例trim释放内存本文通过对ceph-osd内存查看跟踪的5种手段以及osd内存控制的方式进行源码层面的说明&#xff0c;并未通过修改相关源码进行控制&#xff08;水…

c语言函数库学习~sscanf~格式化输入

---恢复内容开始--- 今天算是被打击到了吧&#xff0c;由郑轻的acm老师来我学院指导安排了个现场的小比赛&#xff0c;&#xff0c;俺们居然有还是输给一个大一的新手&#xff0c;&#xff0c;哎&#xff0c;情何以堪&#xff0c;&#xff0c;所以还是要重视下基础编程能力的培…

java mobile phone games_j2me100-src Java

文件名大小更新时间codesc.net\[J2SE]应用编程150例\chap01\实例1\BorderLayoutDemo.class8192003-07-07codesc.net\[J2SE]应用编程150例\chap01\实例1\BorderLayoutDemo.java5752003-07-07codesc.net\[J2SE]应用编程150例\chap01\实例1\BoxLayoutFrame.class7262003-07-15code…

***突然断开可能是ADSL猫惹的祸

在我们使用服务器的时候&#xff0c;最讨厌的就是无故的断线了&#xff0c;可能正在和好一起副本&#xff0c;或者正在视频热聊中&#xff0c;还或者youtube视频看的正起劲&#xff0c;突然windows一个对话框弹出 - “连接已经断开”。实在是太影响体验了&#xff0c;断开之后&…

文件中数组的最大值及其对应的最小下标

2019年春季学期第二周作业基础作业请在第一周作业的基础上&#xff0c;继续完成&#xff1a;找出给定的文件中数组的最大值及其对应的最小下标&#xff08;下标从0开始&#xff09;。并将最大值和对应的最小下标数值写入文件。 输入&#xff1a;请建立以自己英文名字命名的txt文…

ceph bluestore源码分析:admin_socket实时获取内存池数据

环境&#xff1a; 版本&#xff1a;ceph 12.2.1 部署完cephfs 使用ceph-fuse挂载&#xff0c;并写入数据 关键参数&#xff1a; debug_mempool true 将该参数置为true即可查看详细的blustore管理的内存池的数据 命令&#xff1a; ceph daemon osd.id dump_mempools该命令为ad…

java clob内存溢出_java - java.sql.SQLException:ORA-01704:字符串文字太长时插入或更新 - 堆栈内存溢出...

通常&#xff0c;当我插入4000个字符限制时&#xff0c;它的工作正常&#xff0c;但当超过4000个字符时&#xff0c;它抛出SQL异常字符串文字太长&#xff0c;即使我的DISCHARGE_TEXT数据类型是CLOB我的JavaScript代码是function saveAsDraftNew(){var admissionNo document.g…

LC并联谐振回路

转载于:https://www.cnblogs.com/prayer521/p/4103091.html

zencart分类页产品页去掉url中的id号

最近公司新上的网站被seo指出要修改url&#xff0c;去掉url中产品id。由于我们用的是zencart框架&#xff0c;装了 Ultimate SEO URLs 插件&#xff0c;所以在网上应该有这方面的资料&#xff0c;本文主要参考资料&#xff1a;原网址&#xff1a;修改seo url中去掉产品id的方法…

hexo博客更新主题后上传Git操作

克隆主题: git clone https://github.com/SuperKieran/TKL.git _config.yml文件中主题改为新增主题 # Extensions ## Plugins: https://hexo.io/plugins/ ## Themes: https://hexo.io/themes/ theme: TKL 进入主题目录,更新git cd theme/TKL git pull 执行更新 hexo clean hex…

ceph bluestore源码分析:非对齐写逻辑

文章目录环境原理说明总结环境 ceph:12.2.1 场景&#xff1a;ec 21 部署cephfs&#xff0c;执行如右写模式:dd if/dev/zero of/xxx/cephfs bs6K count4 oflagdirect 关键配置&#xff1a; bluestore_min_alloc_size_hdd 65536 bluestore分配空间的最小粒度 单位&#xff1a;B…

JVM系列(之ClassLoader)

Class Loader Java运作流程 内部class loader bootstrap class loader --引导类加载器&#xff0c;它负责加载Java的核心类【java.* 】&#xff08;如classpath下面的类库&#xff09;&#xff0c;不是 java.lang.ClassLoader的子类&#xff0c;而是由JVM自身实现的。Code . UR…

java平台类成员访问修饰符_JAVA类的修饰符及访问权限

1.类外部类 class前的修饰符只能有publicfinalabstrct无(默认) &#xff1a;同包可见 (Eclipse中选择package)内部类 class前的修饰符有public、protected、private、默认、final、abstract、static。先看类的访问权限&#xff0c;再看成员的访问权限&#xff0c;类…

ios实例开发精品源码文章推荐

1、IOS代码分享:视图布局&#xff08;View Layout&#xff09;Border View140601bvpw22rir88b9i8i.png(19.97 KB, 下载次数: 0)下载附件保存到相册半小时前 上传http://www.apkbus.com/android-101999-1-14.html2、IOS代码分享&#xff1a;导航条&#xff08;Navigation Bar&am…

Spring BeanDefinitionRegistryPostProcessor BeanPostProcessor作用

写博客&#xff0c;写博客&#xff0c;把自己知道的小知识点全部记录&#xff0c;? BeanDefinitionRegistryPostProcessor 接口属于Beanddefination 装配定义的范畴&#xff0c;此时bean 并没有初始化 BeanPostProcessor属于be an 实例化修改的范畴&#xff0c;be an 已经进行…

关于ceph源码 backtrace 打印函数调用栈

当集中精力看一个问题的时候&#xff0c;时间久了就会有这样一个状态&#xff0c;天空飘来五个字&#xff0c;那都不算事 ceph源码庞大的体量以及复杂的设计让很多人望而却步&#xff0c;尤其是大量的纯虚函数更是让读者迷失在代码的海洋&#xff0c;这个时候函数调用栈是一个救…

泛型java 代码讲解_Java泛型详解

2516326-5475e88a458a09e4.png一&#xff0c;打破砂锅问到底泛型存在的意义&#xff1f;泛型类&#xff0c;泛型接口&#xff0c;泛型方法如何定义&#xff1f;如何限定类型变量&#xff1f;泛型中使用的约束和局限性有哪些&#xff1f;泛型类型的继承规则是什么&#xff1f;泛…

(转)金额转中文大写

public class RMB {//返回转换好的大写形式public static String numberToRMB(String money) {return cleanZero(splitNum(roundString(money)));}// 将小写金额转换成大写金额private static String splitNum(String s) {// 如果传入的是空串则继续返回空串if ("".e…

[IOS]UIWebView实现保存页面和读取服务器端json数据

如何通过viewView保存访问过的页面&#xff1f;和如何获取并解析服务器端发送过来的json数据&#xff1f;通过一个简单的Demo来学习一下吧&#xff01; 操作步骤&#xff1a; 1.创建SingleViewApplication应用&#xff0c;新建VIewController&#xff0c;并在xib试图中添加WebV…

struts2之配置文件struts.xml详解

struts配置文件 struts.xml配置参数详解 struts.xml中很大一部分配置默认配置就好了 但是有些还是需要做了解 以便于理解 和修改 <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Str…

ceph bluestore 源码分析:刷缓存(trim)逻辑

环境 ceph版本&#xff1a;12.2.1 部署模式&#xff1a;ec 21 osd&#xff1a; 3个 且资源池已经有数据 执行命令&#xff1a;ceph daemon osd.0 flush_store_cache 进行刷缓存。即将dump_mempools内存池管理的bluestore cache中的无用数据进行释放 主要参数: bluestore_cac…

php中怎么过滤器_PHP 过滤器(Filter)

过滤多个输入表单通常由多个输入字段组成。为了避免对 filter_var 或 filter_input 重复调用&#xff0c;我们可以使用 filter_var_array 或 the filter_input_array 函数。在本例中&#xff0c;我们使用 filter_input_array() 函数来过滤三个 GET 变量。接收到的 GET 变量是一…

c++ Qt向PHP接口POST文件流

Qt调用PHP写的接口&#xff0c;向其传递图片文件&#xff0c;并保存在服务器。 二进制文件无法直接传递&#xff0c;Qt采用Base64进行编码发送&#xff0c;PHP解码保存为文件。 注意&#xff1a;PHP收到数据之后会将POST过来的数据中的加号()替换为空格&#xff0c;造成接收到的…

在网络通讯中应用Protobuf

Protobuf的设计非常适用于在网络通讯中的数据载体&#xff0c;它序列化出来的数据量少再加上以K-V的方式来存储数据&#xff0c;对消息的版本兼容性非常强&#xff1b;还有一个比较大的优点就是有着很多的语言平台支持。下面讲解一下如何在TCP通讯应用中集成Protobuf. Protobuf…

JS中Math函数的常用方法

Math 是数学函数&#xff0c;但又属于对象数据类型 typeof Math > ‘object’ console.dir(Math) 查看Math的所有函数方法。 1&#xff0c;Math.abs() 获取绝对值 Math.abs(-12) 12 2&#xff0c;Math.ceil() and Math.floor() 向上取整和向下取整 console.log(Math.ceil(1…

C++ 泛型编程 -- 函数模版

文章目录定义声明调用方式函数模版的重载函数模版的特点工作中一个同事写了测试demo&#xff0c;想要自己尝试使用发现调用老出错&#xff0c;请教的时候发现是函数模版&#xff0c;有自己的调用方式&#xff0c;并且发现核心代码中大量的函数模版和类模版。特此做一个函数模版…