栈的操作和c语言实现算术表达式求值
来源:互联网 发布:tensorflow安装windows 编辑:程序博客网 时间:2024/05/22 00:11
</pre><p><span style="font-size:18px;">栈是一种特殊的线性表,按照“后进先出”的原则处理数据。</span></p><p><span style="font-size:18px;">栈的基本操作有两种:一种是入栈(Push),即把数据保存到栈顶,注意在入栈前应该先检查栈是否已满,如满则不能入栈操作,未满则修改栈顶指针,使其向上移动一个元素的位置,然后将数据保存到栈顶指针所指的位置。 一种是出栈(Pop),即把栈顶数据弹出,注意在出栈之前检查栈是否为空,如果栈为空没有数据则提示不能进行出栈操作,若不空,则修改栈顶指针,使其指向栈中的下一个元素。</span></p><p><span style="font-size:18px;">1.编写操作栈的头文件 </span></p><p><pre name="code" class="cpp">typedef struct stack{DATA data[SIZE+1]; //数据元素 top为o表示栈为空 int top; //定义栈顶 } seqStack;
其中DATA定义栈中元素的数据类型,SIZE表示栈的最大容量,SIZE+1表示栈的数据从下标为1开始,当top为0时,表示栈为空。
2.初始化栈
seqStack *seqStackInit(){seqStack *p;if(p=(seqStack *)malloc(sizeof(seqStack))) //申请内存{p->top=0;return p;} return NULL; //申请内存失败 }
初始化栈需要做两件事,首先按照SIZE指定的大小申请一片内存空间,保存栈中数据,然后设置栈顶指针的值为0,表示空栈。
3.判断栈的状态
int seqStackIsempty(seqStack *s) //栈是否为空{return(s->top==0);} int seqStackIsfull(seqStack *s) //栈是否满{return(s->top==SIZE);}
对栈操作前先判断栈的状态,入栈前栈是否满,出栈前栈是否为空。
4.清空栈 释放栈所占的内存空间
void seqStackClear(seqStack *s){s->top=0; //清空栈 }void seqStackfree(seqStack *s) //释放栈的空间 {if(s) free(s); }
清空栈时,即把栈顶指针top置0,释放栈时,因为栈是用malloc函数分配的,所以不使用时用free函数释放分配的内存空间。
5.入栈操作
int seqStackPush(seqStack *s,DATA data){if((s->top+1)>SIZE) //栈的上一个位置超过最大位置 {printf("栈溢出\n");return 0;}s->data[++s->top]=data; //修改栈顶指针,把元素入栈return 1; }
入栈时,判断若top已经满了(s->top==size),则top+1就超出栈的最大内存空间,提示栈溢出,做出错处理。若没有溢出,则栈顶指针向上移动一位,把数据放入其中,即入栈。
6.出栈操作
int seqStackPop(seqStack *s) //出栈{if(s->top==0){printf("栈为空:\n");exit(0);}return (s->data[s->top--]); //从栈顶弹出元素 }
出栈与入栈相反,从栈顶弹出一个数据元素。先判断top是否为0,若为0,则表示空栈,提示出错,若不为0,修改栈顶指针减一,即往下移动一位,返回此时栈顶指针所指位置,原来栈顶元素弹出,即出栈。
7.获取栈顶元素
DATA seqStackPeek(seqStack *s) //读出栈顶元素{if(s->top==0){printf("栈为空");exit(0);}return (s->data[s->top]); //返回栈顶元素 }
在出栈操作中,是把原来的栈顶元素弹出(抛弃了),即出栈后栈顶元素就不存在了,若只是读取一下栈顶的元素而不删除,就不需要将top指针往下移动,不修改指针位置,这样返回栈顶后栈顶数据元素还在。
以上为栈的基本操作,下面举一个实用例子深入理解栈的相关操作。
栈的实际运用:算术表达式求值
在计算机中输入一个算式如:(2+3)*5 容易知道先计算2+3=5,再将5*5=25,,但计算机在读入算式时的具体过程是怎样的?
计算机先逐步扫描:先是(括号,这时不知道右括号在哪里出现,所以先保存起来,然后是2,也不知道该字符下一位是什么,也先保存,然后是+,这时知道是加上一个数,但不知道加什么,先保存起来,然后是3,这时知道是2+3,直接相加吗?不能,如果3后面是*,或者/的高优先级话就先计算,所以也先保存,然后是),这时括号内的2+3就可以取出运算了,得出结果5后再保存起来(由此可以看出加减的优先级大于()的优先级),然后是*,保存起来,然后是5,保存起来,然后是=号,表示整个算式结束了,将2+3得到的5与5相乘,输出最终结果。
由上分析可知,程序需要保存操作数,保存运算符(+,-,*,/,=,(,)),还需要确定优先级(乘除大于加减,加减大于括号,括号可以改变优先级的顺序,相同优先级从左往右计算)。
为了简化程序,只考虑加减乘除四则运算。
首先调用库函数:
#include<stdio.h>#include<stdlib.h>#include<conio.h>#define SIZE 50typedef int DATA; //定义栈元素类型 #include "biaodashi.h"
第六行引用最开始的栈的基本操作程序为头文件,
具体函数模块分析:
1.每次读取检查字符是否为运算符
int isOperator(char c) //检查字符是否为运算符{switch(c){case '+':case '-':case '*':case '/':case '(':case ')':case '=':return 1;break;default: return 0; break; //字符c是运算符则返回1,,否则返回0 }}
定义isOperator函数,如果字符为+,-,*,/,(,),=,运算符,则返回1,否则返回0,。
2.比较运算符的优先级:
注:在计算表达式时,为了方便判断增设“=”为表达式定界符,即以=表示开始,=表示结束
int PRI(char oper1,char oper2) //判断两个运算符的优先级//如果oper1>oper2返回1 如果oper1<oper2返回-1 如果oper1,,oper2是左右符号返回0{int pri;switch(oper2) //判断优先级{case '+':case '-':if(oper1=='('||oper1=='=') //为左括号 pri=-1; //oper1<oper2else pri=1; //oper1>oper2break;case '*':case '/':if(oper1=='*'||oper1=='/'||oper1==')') pri=1; //oper1>oper2else pri=-1; //oper1<oper2 break;case '(':if(oper1==')') //右括号右侧不能马上出现左括号{printf("语法错误\n");exit(0);} else pri=-1; //oper1<oper2 break;case ')':if(oper1=='(') pri=0;else if(oper1=='='){printf("括号不匹配\n");exit(0);}else pri=1; break;case '=':if(oper1=='('){printf("括号不匹配\n");exit(0);}else if(oper1=='=') pri=0; //等号匹配,返回0 else pri=1; //oper1>oper2 break; }return pri;}
在该函数中对oper1和oper2两个运算符比较,34到40行表示:oper2为+或-号,若oper1为(或=号,oper1<oper2,则pri=-1,否则oper1>oper2,pri=1。41到47行同理。48到55行表示:oper2等于(时,若oper1等于),即)(,这样右括号后直接左括号是不对的,oper2等于(,若oper1不为),则oper1<oper2,pri=1。56到65表示:oper2等于),若oper1等于(,则括号匹配,pri等于0,如果oper1等于=,即:=),括号不匹配。第66到75行表示:oper2为=号,若oper1为(,即:(=,括号不匹配,如果oper1等于=,表示结束算式,如果oper1为其他,则oper1>oper2,pri=1。 最后返回pri。
3.对于优先级高的运算符,需要将运算符两侧的数据进行计算,
int Calc(int a,int oper,int b) //计算两个操作数的结果{switch(oper) //根据运算符计算{case '+':return a+b;case '-':return a-b;case '*':return a*b;case '/':if(b!=0) return a/b;else{printf("除数不能为0!\n");exit(0);}} }
4.写好以上函数部分,就可以开始计算表达式的值:
int CalcExp(char exp[]) //表达式计算函数{seqStack *StackOper,*StackData; //指向两个栈的指针变量,一个操作符,一个运算数int i=0,flag=0; //flag作为标志,用来处理多位数DATA a,b,c,q,x,t,oper;StackOper=seqStackInit();StackData=seqStackInit(); //初始化两个栈q=0; //变量q保存多位数的操作x='=';seqStackPush(StackOper,x); //首先把等号=进入操作栈x=seqStackPeek(StackOper); //获取操作栈的首元素 c=exp[i++]; while(c!='='||x!='=') //循环处理表达式中的每一个字符{if(isOperator(c)) //如果是运算符{if(flag){seqStackPush(StackData,q); //表达式入栈q=0; //操作数清零 flag=0; //标志清零,表示操作数已经入栈 }switch(PRI(x,c)) //判断运算符优先级{case -1:seqStackPush(StackOper,c); //运算符进栈c=exp[i++];break;case 0:c=seqStackPop(StackOper); //运算符括号,等号出栈,被抛弃c=exp[i++]; //取下一个 字符 break; case 1:oper=seqStackPop(StackOper); //运算符出栈b=seqStackPop(StackData);a=seqStackPop(StackData); //两个操作数出栈t=Calc(a,oper,b); //计算结果seqStackPush(StackData,t); //将运算结果入栈 break; } }else if(c>='0'&&c<='9') //如果输出的字符在0到9之间{c-='0'; //把字符转换成数字q=q*10+c; //多位数的进位处理c=exp[i++]; //取出下一位字符 flag=1; //设置标志,表示操作数未入栈} else {printf("输入错误\n");getch();exit(0);}x=seqStackPeek(StackOper); //获取栈顶操作符 } q=seqStackPop(StackData); seqStackfree(StackOper); seqStackfree(StackData); //释放内存占用空间return q; //出栈,返回结果 }
该部分注解:
首先是以一个字符串exp为参数,返回一个整型数(即表达式的结果),一个标志变量flag,作用是处理当操作数是多位数时处理多位数的情况(代码一次只能从表达式中获取一个字符),当操作数是多位数就把每一位获取后再入栈。flag为0表示没有操作数入栈,为1表示有操作数需要入栈。
然后将变量x为“=”,将该符号作为表达式的第一个运算符入栈,然后循环诸葛处理表达式字符串中的每一个字符,直到遇到表达式的结束字符“=”为止。
5.主函数
int main(){int c;char exp[80];printf("请输入需要计算的表达式(以=结束):\n");scanf("%s",exp);printf("%s%d\n",exp,CalcExp(exp));getch();return 0;}
最后编译结果:
- 栈的操作和c语言实现算术表达式求值
- 利用栈实现算术表达式的求值
- 栈和队列-算术表达式的求值
- 算术表达式求值(C语言)
- 利用栈实现算术表达式求值(Java语言描述)
- 利用栈实现算术表达式求值(Java语言描述)
- 栈的算术表达式求值
- C语言实现表达式求值,支持+、-、*、/四则运算,并且支持多级括号,自定义了栈的操作。
- c语言栈实现表达式求值
- 栈实现表达式求值(C语言)
- 栈实现表达式求值(C语言)
- 利用栈实现简单算术表达式求值
- 算术表达式求值(顺序栈实现)
- 算术表达式求值@C/C++
- 栈的应用--算术表达式求值
- 栈的应用之算术表达式求值
- c语言中的操作符和表达式求值
- C语言之第十课:C语言的算术运算符和算术表达式
- Architecture outline
- Maximum Subarray
- hdu 2896——病毒侵袭
- SMT成长日记
- 机房收费系统文档总结(反思篇)
- 栈的操作和c语言实现算术表达式求值
- python 优化指南
- java面试题一
- Maven之——仓库(上)
- iOS 8 获得屏幕高度的适配
- asfasfasf
- 继续ipv6
- OpenCV入门(十九)--直方图用法
- Android图像处理之Bitmap类②