栈在表达式求值中的应用
栈的基本操作
1,初始化
2,取栈顶值
3,出栈
4,入栈
我们用这么多操作就能实现表达式求值了
王道的课程之中讲到的后缀表达式的思想是很关键点,在此之前要把中缀表达式转换为后缀表达式然后再求值。
按照他给的思路我把代码给写出来了,遇到了不少问题,debug一下午就没了!菜死我了。
第一大块代码是操作符栈的定义和相关的基本操作。栈是用静态数组实现的应该不难理解。
//Opstact Op;
typedef struct{
char data[Maxsize];
int top;
}Opstact;
char GetOp(Opstact &Op){
if(Op.top==0) return false;
char str=Op.data[Op.top-1];
return str;
}
void initOpstact(Opstact &Op){
Op.top=0;
}
bool EmptyOpstact(Opstact Op){
if(Op.top==0) return true;
else return false;
}
bool PushOp(Opstact &Op,char sign){
if(Op.top==Maxsize) return false;
Op.data[Op.top]=sign;
Op.top++;
return true;
}
bool PopOp(Opstact &Op,char &sign){
if(Op.top==0) return false;
Op.top--;
sign=Op.data[Op.top];
return true;
}
我想把操作数栈也定义为静态数组实现发现入栈操作老是出bug就改成链栈了。代码就跑起来了。
//定义 数据栈
typedef struct Linknode{
int data;
struct Linknode * next;
}Linknode,*Listack;
//初始化栈
bool InitListack(Listack &S){
S = (Linknode *) malloc(sizeof(Linknode));//申请内存
if(S->next==NULL) return false;//申请失败
S->data = 0;//初始化链栈头结点数据域
S->next = NULL;//初始化链栈头结点指针域
return true;
}
//入栈
bool Push(Listack &S,int e){
Linknode *headpoint;//指向新节点的指针
headpoint=(Listack)malloc(sizeof(Linknode));//分配空间
if(headpoint==NULL) return false;//申请空间失败
if(S->next==NULL){
headpoint->data=e;//给节点赋值
headpoint->next=NULL;//链接新节点
S->next=headpoint;
return true;
}else{
headpoint->data=e;//给节点赋值
headpoint->next=S->next;//链接新节点
S->next=headpoint;
return true;
}
}
//出栈
bool Pop(Listack &S,int &e){
Linknode *headpoint=S->next;//指向出栈节点的指针
if(S->next==NULL) return false;//空栈,没有节点可以出栈了
else{
//头结点链接第二个元素节点
e=headpoint->data;
S->next=headpoint->next;
free(headpoint);
return true;
}
}
bool Emptystack(Listack S){
if(S->next==NULL) return true;
else return false;
}
isnumber函数判断当前字符是不是数,是数返回true。
isletter没用到这个,编译原理学过头了。
Numberscan就是一个操作数可能有好几个字符组成。这个函数的任务就是一旦碰到‘0’–‘9’的字符就进入这个处理函数,继续扫描到不是数字了,最后用number带出去。
Calculate是就算表达式值的
pre函数定义了优先级。符号用的比较少;
还有就是使用除法的话有小数会被舍弃,因为数据类型是int的。
bool isnumber(char str){
if(str>='0'&&str<='9') return true;
else return false;
}
bool isletter(char str){
if((str>='a'&&str<='z')||(str>='A'&&str<='Z')) return true;
else true;
}
//数字判断
int Numberscan(char str[],int i,int &number){
int a=0;
int index=i;
while(isnumber(str[index])){
a=a*10+(int)str[index]-48;
index++;
}
number=a;
return index-1;
}
//表达式求值a=a op b;
int Calculate(int a,int b,char op){
if(op=='+') return a=a+b;
else if(op=='-') return a=a-b;
else if(op=='*') return a=a*b;
else if(op=='/') return a=a/b;
}
//符号优先级
int pre(char str){
if(str=='+'||str=='-') return 0;
else if(str=='*'||str=='/') return 1;
else if(str=='('||str==')') return -1;
}
main函数里放了程序的控制流程。先把我贴的图看一下!会有收获的哈!
int main(){
//操作符栈
Opstact Op;
initOpstact(Op);
//操作数栈
Listack S;
InitListack(S);
//定义字符数组接受输入
char str[30]={};
//A左操作数,B右操作数
int A,B;
//temp表示当前扫描到的字符
char temp;
//栈顶字符,用来判断优先级
char Opchar;
//接收字符到操作数的转换
int number;
//表达式的输入
scanf("%s",str);
//输出验证一下
printf("%s\n",str);
for(int i=0;i<30;i++){//一遍臊面就能得到表达式的值。时间复杂度O(n).
if(str[i]==' ') break;//扫描结束
temp=str[i];
if(temp=='+'||temp=='-'||temp=='*'||temp=='/'){
//判断当前符号的优先级和栈顶符号的优先级
//当前符号优先级高的话,入栈,否则出栈
Opchar=GetOp(Op);
if(Op.top==0){
PushOp(Op,temp);
continue;
}
if(Opchar=='('){
PushOp(Op,temp);
continue;
}
if(pre(temp)>pre(Opchar)){
PushOp(Op,temp);
continue;
}
if(pre(temp)<=pre(Opchar)){
PopOp(Op,Opchar);
Pop(S,B);
Pop(S,A);
A=Calculate(A,B,Opchar);//calculate
Push(S,A);
i--;
continue;
}
}
if(temp>='0'&&temp<='9'){
//操作数压栈
i=Numberscan(str,i,number);
Push(S,number);
continue;
}
if(temp=='('){
PushOp(Op,temp);
}
if(temp==')'){
while(1){
PopOp(Op,Opchar);
if(Opchar=='(') break;
Pop(S,B);
Pop(S,A);
A=Calculate(A,B,Opchar);
Push(S,A);
}
}
}
while(Op.top!=0){
PopOp(Op,Opchar);
Pop(S,B);
Pop(S,A);
A=Calculate(A,B,Opchar);
Push(S,A);
}
Pop(S,A);
printf("%d\n",A);
return 0;
}
下面贴一下完整的代码
#include<stdio.h>
#include<stdlib.h>
#define Maxsize 10
//Opstact Op;
typedef struct{
char data[Maxsize];
int top;
}Opstact;
char GetOp(Opstact &Op){
if(Op.top==0) return false;
char str=Op.data[Op.top-1];
return str;
}
void initOpstact(Opstact &Op){
Op.top=0;
}
bool EmptyOpstact(Opstact Op){
if(Op.top==0) return true;
else return false;
}
bool PushOp(Opstact &Op,char sign){
if(Op.top==Maxsize) return false;
Op.data[Op.top]=sign;
Op.top++;
return true;
}
bool PopOp(Opstact &Op,char &sign){
if(Op.top==0) return false;
Op.top--;
sign=Op.data[Op.top];
return true;
}
//定义 数据栈
typedef struct Linknode{
int data;
struct Linknode * next;
}Linknode,*Listack;
//初始化栈
bool InitListack(Listack &S){
S = (Linknode *) malloc(sizeof(Linknode));//申请内存
if(S->next==NULL) return false;//申请失败
S->data = 0;//初始化链栈头结点数据域
S->next = NULL;//初始化链栈头结点指针域
return true;
}
//入栈
bool Push(Listack &S,int e){
Linknode *headpoint;//指向新节点的指针
headpoint=(Listack)malloc(sizeof(Linknode));//分配空间
if(headpoint==NULL) return false;//申请空间失败
if(S->next==NULL){
headpoint->data=e;//给节点赋值
headpoint->next=NULL;//链接新节点
S->next=headpoint;
return true;
}else{
headpoint->data=e;//给节点赋值
headpoint->next=S->next;//链接新节点
S->next=headpoint;
return true;
}
}
//出栈
bool Pop(Listack &S,int &e){
Linknode *headpoint=S->next;//指向出栈节点的指针
if(S->next==NULL) return false;//空栈,没有节点可以出栈了
else{
//头结点链接第二个元素节点
e=headpoint->data;
S->next=headpoint->next;
free(headpoint);
return true;
}
}
bool Emptystack(Listack S){
if(S->next==NULL) return true;
else return false;
}
/*
//Numstact NUM;
typedef struct{
int data[Maxsize];
int top1;
}Numstact;
void initNumstact(Numstact &NUM){
NUM.top1==0;
}
bool EmptyNumstact(Numstact NUM){
if(NUM.top1==0) return true;
else return false;
}
bool PushNum(Numstact &NUM,int x){
if(NUM.top1==Maxsize) return false;
NUM.data[NUM.top1]=x;
NUM.top1++;
return true;
}
bool PopNum(Numstact &NUM,int &x){
if(NUM.top1==0) return false;
NUM.top1--;
x=NUM.data[NUM.top1];
return true;
}
*/
bool isnumber(char str){
if(str>='0'&&str<='9') return true;
else return false;
}
bool isletter(char str){
if((str>='a'&&str<='z')||(str>='A'&&str<='Z')) return true;
else true;
}
//数字判断
int Numberscan(char str[],int i,int &number){
int a=0;
int index=i;
while(isnumber(str[index])){
a=a*10+(int)str[index]-48;
index++;
}
number=a;
return index-1;
}
//表达式求值a=a op b;
int Calculate(int a,int b,char op){
if(op=='+') return a=a+b;
else if(op=='-') return a=a-b;
else if(op=='*') return a=a*b;
else if(op=='/') return a=a/b;
}
//符号优先级
int pre(char str){
if(str=='+'||str=='-') return 0;
else if(str=='*'||str=='/') return 1;
else if(str=='('||str==')') return -1;
}
int main(){
//操作符栈
Opstact Op;
initOpstact(Op);
//操作数栈
Listack S;
InitListack(S);
//定义字符数组接受输入
char str[30]={};
int A,B;
char temp;
char Opchar;
int number;
scanf("%s",str);
printf("%s\n",str);
for(int i=0;i<30;i++){
if(str[i]==' ') break;
temp=str[i];
if(temp=='+'||temp=='-'||temp=='*'||temp=='/'){
//判断当前符号的优先级和栈顶符号的优先级
//当前符号优先级高的话,入栈,否则出栈
Opchar=GetOp(Op);
if(Op.top==0){
PushOp(Op,temp);
continue;
}
if(Opchar=='('){
PushOp(Op,temp);
continue;
}
if(pre(temp)>pre(Opchar)){
PushOp(Op,temp);
continue;
}
if(pre(temp)<=pre(Opchar)){
PopOp(Op,Opchar);
Pop(S,B);
Pop(S,A);
A=Calculate(A,B,Opchar);//calculate
Push(S,A);
i--;
continue;
}
}
if(temp>='0'&&temp<='9'){
//操作数压栈
i=Numberscan(str,i,number);
Push(S,number);
continue;
}
if(temp=='('){
PushOp(Op,temp);
}
if(temp==')'){
while(1){
PopOp(Op,Opchar);
if(Opchar=='(') break;
Pop(S,B);
Pop(S,A);
A=Calculate(A,B,Opchar);
Push(S,A);
}
}
}
while(Op.top!=0){
PopOp(Op,Opchar);
Pop(S,B);
Pop(S,A);
A=Calculate(A,B,Opchar);
Push(S,A);
}
Pop(S,A);
printf("%d\n",A);
return 0;
}
运行演示
代码的优化做到不好,请谅解!时间太紧,功课还挺多的!加油加油!