文章目录

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

我们使用浏览器的时候经常会用到前进、后退功能。
依次访问完一串页面 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;
}

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

  1. 复习栈和队列,详解最小栈,栈的弹出压入序列,逆波兰表达式求值

    栈和队列的概念 栈:吃进去吐出来 对列:吃进去拉出来 数据结构中的栈和内存中的区别 数据结构中的栈具有后进先出的特性,而内存中的栈是一个内存空间,只不过这个内存空间具与数据结构的栈具有相同的特性. 栈 ...

  2. (栈的应用5.2.2)POJ 2106 Boolean Expressions(表达式求值)

    /** POJ_2106.cpp** Created on: 2013年10月30日* Author: Administrator*/#include <iostream> #includ ...

  3. 栈实现算术表达式求值

    算术表达式求值 利用栈求解的一个典型的问题是算术表达式求值,例如:"3+4*2-(1+1)#",这样的表达式计算,在计算过程中,不是读到一个运算就立即计算,而是要与后面的运算符进行 ...

  4. 顺序栈实现表达式求值(C语言实现)【栈】

    原理说明 代码实现 原理说明 表达式求值一定会出现表达式中运算符的优先级问题. 运算规则: 先乘除,后加减: 从左算到右: 先括号内,后括号外: 运算符优先表: 上面表格中有一些比较特殊的位置: ① ...

  5. c语言中缀表达式求值_数据结构考研笔记之栈与队列(四)栈与队列应用括号匹配、中缀表达式转前缀后缀问题...

    文字:独木 排版:独木 图片:独木 栈与队列 1.括号匹配问题 栈 例题1 例题2-----不匹配例题1 例题3-----不匹配例题2 2. 表达式求值问题 例题 1.中缀表达式转前缀表达式 2.中缀 ...

  6. 数据结构链表之栈——解决括号匹配问题和逆波兰表达式求值问题——6

    括号匹配问题和逆波兰表达式求值问题 基于上一节已经使用python代码对栈进行了简单的实现,这一节我们在其基础上解决两个常见的问题 案例 括号匹配问题(点我直接到代码实现) 逆波兰表达式求值问题(点我 ...

  7. php表达式求值,PHP实现基于栈的后缀表达式求值功能

    本文实例讲述了PHP实现基于栈的后缀表达式求值功能.分享给大家供大家参考,具体如下: 后缀表达式概述 后缀表达式,指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左 ...

  8. 《Algorithms》—— Dijkstra 的双栈算术表达式求值算法

    想当年学数据结构的时候,一直觉得这个是我一辈子都搞不懂的一个东西.现在看看...还挺简单的... 重点在于如何解析由括号.运算符和数字组成的字符串,并按照正确的顺序完成各种初级算术操作.利用了两个栈( ...

  9. c语言中缀表达式求值_数据结构-第三章:栈和队列(栈的应用、括号匹配、表达式转换)

    第三章:栈和队列 下面讲解栈的应用主要内容有:栈的应用.括号匹配.中 后 前 缀表达式转换 1.栈的应用 1.1括号匹配 我们在数学运算中 [(A+b)*c] - (E-F) 往往都会有[ ] 和 ( ...

最新文章

  1. phar.php error 139,composer.phar 安装出现PHP Fatal error解决办法
  2. 别以为真懂Openstack: 虚拟机创建的50个步骤和100个知识点(5)
  3. VUE -- Mac上解决Chrome浏览器跨域问题
  4. 2019 7.14学习笔记
  5. 三维重建_基于图像的三维模型重建_稠密点云重建
  6. JUC锁框架——重入锁ReentrantLock
  7. jconsole监控tomcat
  8. PS 使用画笔修复工具去除文字
  9. C - Copy (hdu)
  10. matlab中 seek,VBA中的seek与matlab中的fseek的说明 | 学步园
  11. pyqtgraph 案例 002 Basic Plotting
  12. 2021年会议平板十大品牌榜中榜,十大会议平板品牌销量排行榜
  13. sqlserver2000企业版,个人版,开发版,标准版的安装
  14. 公众号markdown排版神器(md转微信html)
  15. 特征值特征向量和奇异值分解精彩片段汇总
  16. 安卓中的hander
  17. 使用DOS的导出Oracle的dmp文件
  18. java创始人现在在哪里直播,三年败光120亿,他曾是某电商巨头创始人,如今却靠直播度日!...
  19. C语言编程>第七周 ⑧ 请编一个函数void fun(int a[M][N],int b[N]),c指向一个M行N列的二维数组,求出二维数组每列中最大元素,并依次放入b所指一维数组中。
  20. 电脑引导那些事(2)--UEFI下win8.1咋改win7,咋装双系统,咋不能激活?

热门文章

  1. 关于HTML代码的转义
  2. linux定时器(crontab)实例
  3. 0709 C语言常见误区----------函数指针问题
  4. Mask_RCNN安装与踩过的坑
  5. java qq协议 c#,C# WebQQ协议群发机器人(三)
  6. python目前的应用领域_专栏G|轻松学Python01:Python环境搭建与运行
  7. 大数据概念思维导图_思维导图|数据化风控(信用评分建模教程)
  8. java.io.file jar_IDEA Maven 打包运行 jar java.io.FileNotFoundException: 问题?
  9. php除去重复数组算法,如何从PHP中的多维数组中删除重复值
  10. as3 android白屏,Android 8.0中一些坑以及对应的解决方法