在结束了第三章基本的排序算法,下面开始介绍一些常用的数据结构,例如栈,队列,链表等等~
今天介绍的是栈的知识。其实稍微了解一点的同学,用一句话就可以概括栈的特点,就是后入先出,也就是后保存的数据,在需要提取数据时是最先被提取的。现在使用push(x)方法表示向栈中添加数据,pop()表示弹出最新进栈的数据,top表示栈顶的元素,则下面用图片表示进栈入栈时栈中数据的变化情况:
1.top=0,表示栈空,没有数据。当然这里只是为了解释栈运行时的数据变化,在很多数据结构中,其实top一开始是被赋值为负数,例如-1的,并通 top<0判断栈空过 | 2.push(3),top先自加变为1,然后把下标为1的单元内容赋值为3 |
3.push(8),top先自加变为2,然后把下标为2的单元内容赋值为8 | 4.push(1),top先自加变为3,然后把下标为3的单元内容赋值为1 |
5.pop(),先把下标为3的单元内容清空,然后top自减变为2 | 6.pop(),先把下标为2的单元内容清空,然后top自减变为1 |
7.push(5),top先自加变为2,然后把下标为2的单元内容赋值为5 | 。。。。。之后在允许的情况下,即栈不溢出且不取空栈,可以不断push和pop |
对于栈这种数据结构的实现,有多种方式,数组,链表都可以,只要满足后入先出的都是栈~
下面以一个简单例子来巩固下栈的知识,同时也了解下C++中STL库中已经为我们提供好的数据结构-----stack
逆波兰表达式是一种将运算符写在操作数后面的描述程序(算式)的方法。举个例子,我们平常用中缀表达式(1+2)*(5+4),改为逆波兰表达式之后则是1 2 + 5 4 + *.相较于中缀表达式,逆波兰表达法的优点在于不需要写括号。
现输出以逆波兰表达式法输入的算式的计算结果。
输入 在一行中输入一个算式。相邻的符号(操作数或运算符)用一个空格隔开。
输出 在一行之中输出计算结果。
限制 2<=算式中操作数的总数<=100
1<=算式中运算符的总数<=90
运算符仅包括"+","-","*",操作数为10^6以下的正整数。
-1*10^9<=计算过程中的值<=10^9
输入示例 输出示例
1 2 + 3 4 - * -3
对于这题,我们为什么会想到使用栈这种数据结构,首先我们遍历输入,当遇到操作数的时候,就把数据push到栈中,之后遇到操作符,就不断从栈中pop取两个数据,然后根据运算符进行某种运算,之后再把结果push到栈中,供之后的运算使用~,其过程以1 2 + 3 4 - * 为例,即计算(1+2)*(5+4)
1.遇到数字1和2不断push进栈 | 2.遇到操作符+后,不断pop得到操作数1和2,然后根据运算结果1+2=3,将结果3push进栈 |
1.遇到数字3和4不断push进栈 | 3.遇到操作符-后,不断pop得到操作数4和3,然后根据运算结果3-4=-1,将结果-1push进栈,注意这里是3-4而不是4-3 |
5.遇到操作符*后,不断pop得到操作数-1和3,然后根据运算结果-1*3=-3,将结果-3push进栈 | 6.遍历结束,将栈中唯一的元素-3pop出栈,这也就是最终整个表达式的结果 |
经过详细的图文介绍,相信大家对于栈和栈的简单应用肯定也有了认识,接下来附上逆波兰表达式计算的源代码:
#include<iostream>
#include<cstdlib>
#include <stdio.h>
#include<stack>
using namespace std;
int main()
{
stack<int> s;
string str;
char c;
int a,b;
while(cin>>str)
{
char ch=str[0];
if(ch=='+' || ch=='-' || ch=='*')
{
a=s.top();s.pop();
b=s.top();s.pop();
if(ch=='+')
s.push(a+b);
else if(ch=='-')
s.push(b-a);
else
s.push(a*b);
}
else
{
s.push(atoi(str.c_str())); // atoi()函数将字符串转化为整数
}
c=getchar(); //接收每个数字或者符号后面的空格或者回车
if(c=='\n') //如果是回车,输入结束,退出while
break;
}
cout<<s.top()<<endl;
return 0;
}
PS:这里对于逆波兰表达式,只是简单的用来介绍栈这种数据结构,以后有时间会详细进行介绍,包括中缀表达式到后缀表达式的转换和较复杂形式下的后缀表达式的求解~今天画图用了不少时间,不早了,晚安~