栈在表达式求值中的应用

栈在表达式求值中的应用

栈的基本操作
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;
}

运行演示
在这里插入图片描述
在这里插入图片描述
代码的优化做到不好,请谅解!时间太紧,功课还挺多的!加油加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值