• 栈及其简单应用


    ##栈是什么 栈就是一个先进先出的线性表,若能够更加方便地去理解栈,我们可以跟剧具体的图来进行理解. ![栈容器示意图](https://img-blog.csdn.net/20180720165436730?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JvbmFsZG83X1pZQg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 相信这个图十分的生动形象,可以看出栈就像是一个桶,若每一个元素进栈的时候,便会存储在最底下,后来的会在上面;而如果需要取出元素,那么必须从最上面开始取,先放的便只能后来取,后放的便只能先取,因此栈的特点便是:先进后出,后进先出.

    如何模拟并存储栈的操作

    为了方便,我们需要用数组去模拟栈的序列.即:
    栈的模拟
    我们定义数组和变量来表示栈,即:
    Stack表示栈的序列,top代表栈的元素个数,那么自然:
    Stack[1]表示栈的底部,stack[top]表示栈顶.那么,如图(c),a,b,c,d,e分别表示Stack[1,2,3,4,5].


    添加与删除栈内的元素

    添加元素

    我们只需要用在顶端放上元素即可,设需要存储的元素为k,即:

    top++;
    Stack[++top]=k;
    

    删除元素

    去掉栈顶元素,其实只需要将元素个数减去1就可以,并不需要要去掉的元素重新赋值为0,因为若要重新插入元素,那么必然新的值会覆盖原来的值.因此只要一句简单的话就可以完成栈的操作:

    top--;
    

    栈的实际操作与运用

    学习好栈并不只是学会简单的模拟和运用,还要更多地知道一道题为什么需要栈,需要栈来维护什么,这也是需要栈的原因.接下来会有一些实际的例题,可以更好地去理解栈的操作


    火车进站

    有一个车站,每天都会有N辆车进站,进站按从1到N的顺序进站。现在车站的站长想让这些火车按照特定的顺序出站,问可以做到吗?
    当N为5时,出站顺序若为1 2 3 4 5,可以做到,但是顺序若为5 4 1 2 3,则不行。
    火车进站图片
    输入格式
    一个N,在1000之内,下接一些出站序列,当读到一个0时,则这个测试数据结束。
    输出格式
    对每个序列输出一行“Yes”或“No”。
    input
    5
    1 2 3 4 5
    5 4 1 2 3
    0
    output
    Yes
    No
    数据规模与约定
    时间限制:1s
    空间限制:256MB
    这道题目其实难度并非很大,最主要的是模拟,需要用数据结构栈来模拟:
    给定一个数列,和栈进行以此配对,即:用1,2,3,4,5进栈,若栈顶元素等于a[first],first表示未被匹配过的初始序列的开头,若匹配成功,则出栈,而匹配的序列也转移到下一个.最后便只要去判断栈是否为空即可.为空没说明匹配完,否则则说明没有匹配完,即该序列不成立.代码很好实现.
    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int a[1000000]={},st[10000000]={};
    int main()
    {
    	int n,cnt_st,cnt_a;
    	cin>>n;
    	for (;;)
    	{
    		cnt_st=0;cnt_a=1;
    		for (int i=1;i<=n;i++)
    		{
    			cin>>a[i];
    			if (a[i]==0&&i==1) return 0;
    		}
    		for (int i=1;i<=n;i++)
    		{
    			st[++cnt_st]=i;
    			if (st[cnt_st]==a[cnt_a])
    			while (st[cnt_st]==a[cnt_a]&&cnt_st>0)
    			{
    			    cnt_st--;
    				cnt_a++;	
    			}
    		}
    		if (cnt_st==0)cout<<"Yes"<<endl;
    			else cout<<"No"<<endl;
    	}
    	return 0;
    }
    

    计算表达式的值

    题目描述
    小明在你的帮助下,破译了Ferrari设的密码门,正要往前走,突然又出现了一个密码门。
    门上有一个算式,其中只有“(”、“)”、“0-9”、“+”、“-”、“”、“/”、“^”,求出的值就是密码。小明的数学学得不好,还需你帮他的忙。(“/”用整数除法)
    输入格式
    只有一行是一个算式(算式长度<=30)。
    输出格式
    对于每组数据,输出算式的值(所有数据在2^31-1内)。
    样例数据input
    1+(3+2)
    (7^2+6*9)/(2)
    output
    258
    数据规模与约定
    时间限制:1s
    1s
    空间限制:256MB
    256MB

    方法1:
    这是一道大模拟,需要用栈进行维护.一个栈储存数字,一个栈储存符号.
    这道题目有一个难点,那就是优先级的处理,这个时候我们就需要用栈维护,即:
    如果当前符号的优先级大于或等于栈顶,那么直接进栈,否则将栈顶进行计算,以此来处理复杂的优先级的问题,以1+2×4-3为例.我们设数字和字符的栈分别是stc1和stc2,栈顶是top1和top2
    1.数字1进栈 stc1={1}
    2.符号+进栈 stc1={1} stc2={+}
    3.数字2进栈 stc1={1,2} stc2={+}
    4.符号×进栈,stc1={1,2} stc2={+,×}
    5.数字4进栈,stc1={1.2.4} stc2={+,×}
    6.现在我们判断到了-,比符号栈顶×的优先级要小,要进行计算,因此将2,4与符号×进行计算,那么栈的序列为,然后重新入栈:stc1={1,8,3} stc2={+,-}
    因此最后答案是:(1+8)-3=6
    然后最后留下+和-,顺序地做一遍即可.
    处理括号:
    1.左括号:直接进栈.
    2.右括号:强制计算,知道向左计算的时候枚举到了第一个左括号为止
    倒序处理加法或减法的BUG:
    例如在做1-2+1,栈是这样的:
    stc1={1,2,1} stc2={-,+}
    那么下一步,便是:stc1={1,3} stc2={-}
    那么最后的答案是:1-3=-2而显然这个算式的答案是0因此我们需要在最后一步进行顺序的处理
    但是有一个问题就是:最有会留下乘除号怎么办:补0
    即,如果原式是2+5(4+69)^2 那么,我们就可以修改成:2+5(4+69+0)^2+0
    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int stc1[1000],top1=0;
    char stc2[1000];int top2=0;
    inline int Math(int x)
    {
    	if (x=='+'||x=='-') return 1;
    	if (x=='*'||x=='/') return 2;
    	if (x=='^') return 3;
    	return 0;
    }//千万不要忘记加上“int"
    int main()
    {
    	string s,s2;
    	cin>>s2;
    	for (int i=0;i<s2.length();i++)
    	    if (s2[i]==')') s=s+"+0"+s2[i];
    		else s+=s2[i];
    	s+="+0";//补0
    	for (int i=0;i<s.length();i++)
    	{
    		if (s[i]>='0'&&s[i]<='9')
    		{
    			if (i==0) stc1[++top1]=s[i]-'0';
    			else if (s[i-1]<'0'||s[i-1]>'9')stc1[++top1]=s[i]-'0';
    			else if (s[i-1]>='0'&&s[i-1]<='9')stc1[top1]=stc1[top1]*10+s[i]-'0';
    			continue;
    		}//处理数字
    		if (Math(s[i])>0)
    		{
    			int math1=Math(s[i]);
    			int math2=Math(stc2[top2]);
    			if (top2==0)
    			{
    				stc2[++top2]=s[i];
    				continue;
    			}//如果没有存放字母
    			if (math2>0&&math1<math2)
    			{
    				char ch=stc2[top2];
    				if (ch=='+') stc1[top1-1]+=stc1[top1];
    				if (ch=='-') stc1[top1-1]-=stc1[top1];
    				if (ch=='*') stc1[top1-1]*=stc1[top1];
    				if (ch=='/') stc1[top1-1]/=stc1[top1];
    				if (ch=='^') stc1[top1-1]=pow(stc1[top1-1],stc1[top1]);
    		        top1--;stc2[top2]=s[i];
    			}//如果优先级比原来大
    			if (math2>0&&math1>+math2)
    			    stc2[++top2]=s[i];//如果优先级比原来小
    			if (stc2[top2]=='(') 
    				stc2[++top2]=s[i];//如果上一个字符是左括号
    		}
    		if (s[i]=='('||s[i]==')')
    		{
    			if (s[i]==')'&&stc2[top2]=='(')
    			{
    				top2--;
    				continue;
    			}//如果左右括号内只有数子
    			if (s[i]=='(')
    			    stc2[++top2]=s[i];//如果是左括号
    			if (s[i]==')')
    			{
    				while (stc2[top2]!='(')
    				{
    					char ch=stc2[top2];
    					if (ch=='+') stc1[top1-1]+=stc1[top1];
    					if (ch=='-') stc1[top1-1]-=stc1[top1];
    					if (ch=='*') stc1[top1-1]*=stc1[top1];
    					if (ch=='/') stc1[top1-1]/=stc1[top1];
    					if (ch=='^') stc1[top1-1]=pow(stc1[top1-1],stc1[top1]);
    		       	    top1--;top2--;
    				}
    				top2--;
    			}//如果是右括号就进行强制处理
    		}
    	}
    	for (int i=1;i<=top2;i++)
    	{
    		int ch=stc2[i];
    		if (ch=='+') stc1[i+1]=stc1[i]+stc1[i+1];
    		if (ch=='-') stc1[i+1]=stc1[i]-stc1[i+1];
    	}//正序处理结果
    	cout<<stc1[top1];
    	return 0;
    }
    

  • 相关阅读:
    Visual Prolog 的 Web 专家系统 (7)
    spring来源理解-BeanFactory子类XmlBeanFactory创建过程
    Threejs 它可以在建立其内部房间效果可见
    Android AlarmManager报警的实现
    什么是注册表和注册表中的作用
    精致的外观Request
    数据仓库的工作日记_创纪录的(一)
    servlet api.jar是干什么的?
    servlet-api-2.5.jar
    用poi-3.6-20091214.jar 实现java给excel资料加密
  • 原文地址:https://www.cnblogs.com/pigzhouyb/p/10119836.html
Copyright © 2020-2023  润新知