四则运算
写在前面
学过数据结构的同学都知道中缀和后缀算法,但是记不太清楚了。
本文通过建立两个栈的方法,直接从输入端调用进行运算,方便广大未学过数据结构或是对数据结构不熟悉的同学学习交流。
核心算法源自 《软件技术基础》 ——西安电子科技大学出版社
任务目标
通过
栈
方法实现基本的四则运算。一个栈用于存放数值,另一个栈用于放置操作符。
通过四则运算练习链栈的创建、访问、置空,和节点元素的插入、删除等操作,并合理运用C++中的函数重载,实现浮点数和字符的操作。
结构框架
栈结构
核心算法
算法分析
链栈
栈的构建
创建节点结构
typedef struct node
{
int flag; //标记位,1为浮点数,2为字符型
datatype num;
chartype sign;
node* next;
}node;
//栈结构
typedef struct Sqstack
{
node *Top;
}SqStack;
栈的声明
//构造一个空栈
void InitStack(SqStack *& S);
//置空栈
void SetNull(SqStack *S);
//判断栈空
int Empty(SqStack*S);
//函数重载
//出栈 根据格式返回需要的元素
void Pop(SqStack *S,datatype &e);
void Pop(SqStack *S,chartype &e);
//入栈 根据格式返回需要的元素
void Push(SqStack *S,datatype n);
void Push(SqStack *S,chartype s);
//获得栈顶元素 根据格式返回需要的元素
void GetTop(SqStack *S,datatype &e);
void GetTop(SqStack *S,chartype &e);
栈的基本功能
//构造一个空栈
void InitStack(SqStack *& S)
{
S = (SqStack*)malloc(sizeof(SqStack));
S->Top = NULL;
}
//置空栈
void SetNull(SqStack *S)
{
node* p = NULL;
while(S->Top != NULL)
{
p = S->Top;
S->Top = p->next;
free(p);p = NULL;
}
cout<<"置空成功"<<endl;
}
//判断栈空,空返回1
int Empty(SqStack*S)
{
if(S->Top<=0) return 1;
else return 0;
}
//入栈
void Push(SqStack *S,datatype n)
{
node *p = (node*)malloc(sizeof(node));
if(p != NULL)
{
p->flag = 1;
p->num = n;
p->next = S->Top;
S->Top = p;
cout<<"Num入栈成功:"<<p->num<<endl;
}
else
cout<<"Error"<<endl;
}
void Push(SqStack *S,chartype s)
{
node *p = (node*)malloc(sizeof(node));
if(p != NULL)
{
p->flag = 2;
p->sign = s;
p->next = S->Top;
S->Top = p;
cout<<"Sign入栈成功:"<<p->sign<<endl;
}
else
cout<<"Error"<<endl;
}
//出栈
void Pop(SqStack *S,datatype &e)
{
if(S->Top != NULL)
{
node* p = S->Top;
e = p->num;
S->Top = p->next;
free(p);
cout<<"出栈成功: "<<e<<endl;
}
else {}
}
void Pop(SqStack *S,chartype &e)
{
if(S->Top != NULL)
{
node* p = S->Top;
e = p->sign;
S->Top = p->next;
free(p);
cout<<"出栈成功: "<<e<<endl;
}
else {}
}
//获得栈顶元素
void GetTop(SqStack *S,chartype &e)
{
if(S->Top != NULL)
e = S->Top->sign;
else {}
}
void GetTop(SqStack *S,datatype &e)
{
if(S->Top != NULL)
e = S->Top->num;
else {}
}
四则运算
函数声明
//判断是否为字符型,是返回1,否返回0
int CharOrNot(char ch);
//输入表达式保存
void GetExpression(SqStack *&S);
//输入输出对换
void ReturnStack(SqStack *&S);
//四则运算
datatype EvaluateExpression(SqStack *C);
//自带输入的四则运算
datatype EvaluateExpression();
//判断优先级
chartype Precede(chartype a,chartype b);
//对相关运算进行封装,返回运算结果
datatype Operate(datatype a,chartype b,datatype c);
读取算数表达式
//获取表达式
void GetExpression(SqStack *&S)
{
cout<<"请输入运算代数式:";
char ch=0;
ch = getchar();
while (ch !='\n')
{
if(CharOrNot(ch))//为字符
{
Push(S,ch);
ch = getchar();
}
else
{
datatype k=1;
datatype m=datatype(ch)-48;
ch = getchar();
while(ch!='.' && !CharOrNot(ch))
{
m=m*10+int(ch)-48;
ch = getchar();
}
if(ch=='.') ch=getchar();
while(!CharOrNot(ch))
{
k=0.1*k;
m=m+k*(int(ch)-48);
ch = getchar();
}
Push(S,m);
}
}
}
转换算数式顺序-出栈进栈
按照输入顺序输出,方便进行运算
//变换顺序
void ReturnStack(SqStack *&S)
{
SqStack *Q;node *p;
InitStack(Q);
datatype a;chartype b;
while(S->Top!=NULL)
{
p=S->Top;
S->Top = p->next;
p->next = Q->Top;
Q->Top=p;
}
S->Top = Q->Top;
Q->Top = NULL;
free(Q);
cout<<"转变完成"<<endl;
}
判断优先级
//判断优先级
chartype Precede(chartype a,chartype b)
{
int m,n;
switch(a)
{
case '#': m=0;break;
case '-':
case '+': m=2;break;
case '*':
case '/': m=3;break;
case '(': m=1;break;
//default
//case')': m=3;
}
switch(b)
{
case '#': n=0;break;
case '-':
case '+': n=2;break;
case '*':
case '/': n=3;break;
case '(': n=4;break;
case ')': n=1;break;
//default
}
if(m<n)
a='<';
else if(m==n && m == 1)//脱括号
a='=';
else if(m==n &&m != 0 && m!= 1 || m>n)
a='>';
return a;
}
操作符运算
datatype Operate(datatype a,chartype b,datatype c)
{
switch(b)
{
case'+': return a+c;break;
case'-': return c-a;break;
case'*': return a*c;break;
case'/': return c/a;break;
}
}
四则运算函数
datatype EvaluateExpression(SqStack *C)
{
SqStack *S,*Q;node *p;
InitStack(S);InitStack(Q);
Push(Q,'#'); //作为结束判断的标志
chartype b='!';datatype a;datatype c;
//当最后一个和第一个元素都为#时结束
while(p->sign!='#' || b!='#')
{
ifcp->flag == 1)//flag = 1 为数字
{
Push(S,p->num);p=p->next;//进入数字栈
}
else if(p->flag == 2) //为字符
{
GetTop(Q,b);
//通过switch判断需要做的操作
switch(Precede(b,p->sign)){
case'<'://栈顶符号优先级小于当前符号
Push(Q,p->sign);//对当前进行进栈操作
p=p->next;//p指向下一个节点
break;
case'='://脱括号
Pop(Q,b);//出栈
p=p->next;//p指向下一个节点
break;
case'>':// 栈顶符号优先级大于当前符号
Pop(Q,b);//出栈操作符
Pop(S,a);//得到第二个数字
Pop(S,c);//得到第一个数字
Push(S,Operate(a,b,c));//将运算结c果进栈
break;
}
}
GetTop(Q,b);//更新 b 为栈顶元素符号,方便判断
}
GetTop(S,a);//结束循环,返回数字栈结果
SetNull(S);SetNull(Q);//置空
free(S);free(Q);free(p);//释放栈格式
return a;//返回结果
}
附:自带读取功能的四则算法
无需读取算数表达式的操作,可直接调用
本文栈相关操作与之匹配
提供不同的思路方法
//无需读取字符串算法
/*datatype EvaluateExpression()
{
SqStack *S,*Q;
InitStack(S);InitStack(Q);
Push(S,'#');Push(Q,'#');
chartype b; chartype d; datatype a;datatype c;
cout<<"请输入运算代数式:";
chartype ch=getchar();
while(ch!='#' || b!='#')
{
if(!CharOrNot(ch))
{
a=datatype(ch);
Push(S,a-48);
ch=getchar();
}
else
{
d = chartype(ch);GetTop(Q,b);
switch(Precede(b,d)){
case'<':
Push(Q,ch);ch=getchar();break;
case'=':
Pop(Q,b);ch=getchar();break;
case'>':
Pop(Q,b);//操作符
Pop(S,a);//第一个数字
Pop(S,c);//第二个数字
Push(S,Operate(a,b,c));
break;
}
}
GetTop(Q,b);
}
GetTop(S,a);
SetNull(S);SetNull(Q);
free(S);free(Q);
return a;
}
结果分析
基本的四则运算
带括号的运算
小数运算
负数运算
写道这里已经满足了上机需求,并且花费了许多时间用于调试和理解算法。之后有时间会添加上这一部分。
完整代码
main.cpp
#include "func.h"
int main()
{
SqStack *S;
InitStack(S);
GetExpression(S);
ReturnStack(S);
datatype a;
a = EvaluateExpression(S);
cout<<"运算结果: "<<a<<endl;
SetNull(S);
free(S);
return 0;
}
func.h
#include<iostream>
#include <stdlib.h>
using namespace std;
typedef float datatype;
typedef char chartype;
#define MaxSize 30
//定义栈格式
typedef struct node
{
int flag; //标记位,1为浮点数,2为字符型
datatype num;
chartype sign;
node* next;
}node;
typedef struct Sqstack
{
node *Top;
}SqStack;
//构造一个空栈
void InitStack(SqStack *& S);
//置空栈
void SetNull(SqStack *S);
//判断栈空
int Empty(SqStack*S);
//出栈
void Pop(SqStack *S,datatype &e);
void Pop(SqStack *S,chartype &e);
//入栈
void Push(SqStack *S,datatype n);
void Push(SqStack *S,chartype s);
//
void GetTop(SqStack *S,datatype &e);
void GetTop(SqStack *S,chartype &e);
//判断是否为字符型,是返回1,否返回0
int CharOrNot(char ch);
//输入表达式保存
void GetExpression(SqStack *&S);
//输入输出对换
void ReturnStack(SqStack *&S);
//四则运算
datatype EvaluateExpression(SqStack *C);
//自带输入的四则运算
datatype EvaluateExpression();
//判断优先级
chartype Precede(chartype a,chartype b);
//对相关运算进行封装,返回运算结果
datatype Operate(datatype a,chartype b,datatype c);
func.cpp
#include "func.h"
//构造一个空栈
void InitStack(SqStack *& S)
{
S = (SqStack*)malloc(sizeof(SqStack));
S->Top = NULL;
}
//置空栈
void SetNull(SqStack *S)
{
node* p = NULL;
while(S->Top != NULL)
{
p = S->Top;
S->Top = p->next;
free(p);p = NULL;
}
cout<<"置空成功"<<endl;
}
//判断栈空,空返回1
int Empty(SqStack*S)
{
if(S->Top<=0) return 1;
else return 0;
}
//入栈
void Push(SqStack *S,datatype n)
{
node *p = (node*)malloc(sizeof(node));
if(p != NULL)
{
p->flag = 1;
p->num = n;
p->next = S->Top;
S->Top = p;
//cout<<"Num入栈成功:"<<p->num<<endl;
}
else
cout<<"Error"<<endl;
}
//入栈
void Push(SqStack *S,chartype s)
{
node *p = (node*)malloc(sizeof(node));
if(p != NULL)
{
p->flag = 2;
p->sign = s;
p->next = S->Top;
S->Top = p;
//cout<<"Sign入栈成功:"<<p->sign<<endl;
}
else
cout<<"Error"<<endl;
}
//出栈
void Pop(SqStack *S,datatype &e)
{
if(S->Top != NULL)
{
node* p = S->Top;
e = p->num;
S->Top = p->next;
free(p);
//cout<<"出栈成功: "<<e<<endl;
}
else {}
}
void Pop(SqStack *S,chartype &e)
{
if(S->Top != NULL)
{
node* p = S->Top;
e = p->sign;
S->Top = p->next;
free(p);
//cout<<"出栈成功: "<<e<<endl;
}
else {}
}
//获得栈顶元素
void GetTop(SqStack *S,chartype &e)
{
if(S->Top != NULL)
e = S->Top->sign;
else {}
}
void GetTop(SqStack *S,datatype &e)
{
if(S->Top != NULL)
e = S->Top->num;
else {}
}
//判断运算符 为真返回1
int CharOrNot(char ch)
{
if(ch!='+'&&ch!='-'&&ch!='*'&&ch!='/'&&ch!='('&&ch!=')'&&ch!='#')
return 0;
else return 1;
}
//获取表达式
void GetExpression(SqStack *&S)
{
cout<<"请输入运算代数式:";
char ch=0;
ch = getchar();
while (ch !='\n')
{
if(CharOrNot(ch))//为字符
{
Push(S,ch);
ch = getchar();
}
else
{
datatype k=1;
datatype m=datatype(ch)-48;
ch = getchar();
while(ch!='.' && !CharOrNot(ch))
{
m=m*10+int(ch)-48;
ch = getchar();
}
if(ch=='.') ch=getchar();
while(!CharOrNot(ch))
{
k=0.1*k;
m=m+k*(int(ch)-48);
ch = getchar();
}
Push(S,m);
}
}
cout<<"输入完毕"<<endl;
}
//变换顺序
void ReturnStack(SqStack *&S)
{
SqStack *Q;node *p;
InitStack(Q);
datatype a;chartype b;
while(S->Top!=NULL)
{
p=S->Top;
S->Top = p->next;
p->next = Q->Top;
Q->Top=p;
}
S->Top = Q->Top;
Q->Top = NULL;
free(Q);
cout<<"转变完成"<<endl;
}
//输入栈 处理
datatype EvaluateExpression(SqStack *C)
{
SqStack *S,*Q;node *p;
InitStack(S);InitStack(Q);
Push(Q,'#'); //作为结束判断的标志
chartype b='!';datatype a;datatype c;
//当最后一个和第一个元素都为#时结束
while(p->sign!='#' || b!='#')
{
if(p->flag == 1)//flag = 1 为数字
{
Push(S,p->num);p=p->next;//进入数字栈
}
else if(p->flag == 2) //为字符
{
GetTop(Q,b);
//通过switch判断需要做的操作
switch(Precede(b,p->sign)){
case'<'://栈顶符号优先级小于当前符号
Push(Q,p->sign);//对当前进行进栈操作
p=p->next;//p指向下一个节点
break;
case'='://脱括号
Pop(Q,b);//出栈
p=p->next;//p指向下一个节点
break;
case'>':// 栈顶符号优先级大于当前符号
Pop(Q,b);//出栈操作符
Pop(S,a);//得到第二个数字
Pop(S,c);//得到第一个数字
Push(S,Operate(a,b,c));//将运算结果进栈
break;
}
}
GetTop(Q,b);//更新 b 为栈顶元素符号,方便判断
}
GetTop(S,a);//结束循环,返回数字栈结果
SetNull(S);SetNull(Q);//置空
free(S);free(Q);free(p);//释放栈格式
return a;//返回结果
}
//无需读取字符串算法
/*datatype EvaluateExpression()
{
SqStack *S,*Q;
InitStack(S);InitStack(Q);
Push(S,'#');Push(Q,'#');
chartype b; chartype d; datatype a;datatype c;
cout<<"请输入运算代数式:";
chartype ch=getchar();
while(ch!='#' || b!='#')
{
if(!CharOrNot(ch))
{
a=datatype(ch);
Push(S,a-48);
ch=getchar();
}
else
{
d = chartype(ch);GetTop(Q,b);
switch(Precede(b,d)){
case'<':
Push(Q,ch);ch=getchar();break;
case'=':
Pop(Q,b);ch=getchar();break;
case'>':
Pop(Q,b);//操作符
Pop(S,a);//第一个数字
Pop(S,c);//第二个数字
Push(S,Operate(a,b,c));
break;
}
}
GetTop(Q,b);
}
GetTop(S,a);
SetNull(S);SetNull(Q);
free(S);free(Q);
return a;
}
*/
//判断优先级
chartype Precede(chartype a,chartype b)
{
int m,n;
switch(a)
{
case '#': m=0;break;
case '-':
case '+': m=2;break;
case '*':
case '/': m=3;break;
case '(': m=1;break;
//default
//case')': m=3;
}
switch(b)
{
case '#': n=0;break;
case '-':
case '+': n=2;break;
case '*':
case '/': n=3;break;
case '(': n=4;break;
case ')': n=1;break;
//default
}
if(m<n)
a='<';
else if(m==n && m == 1)//脱括号
a='=';
else if(m==n &&m != 0 && m!= 1 || m>n)
a='>';
return a;
}
datatype Operate(datatype a,chartype b,datatype c)
{
switch(b)
{
case'+': return a+c;break;
case'-': return c-a;break;
case'*': return a*c;break;
case'/': return c/a;break;
}
}