不多说了,上代码!!!(批注较为详细,有没批注的见往期博文捏)
这是要求捏
#include"stdio.h"
#include"stdlib.h"
#include"iostream"
#include"math.h"
#include<fstream>
#define MAXSIZE 100
#define OK 1
#define ERROR 0
using namespace std;
typedef char SElemtype;
typedef int Status;
//栈的定义
typedef struct StackNode {
SElemtype data;
struct StackNode* next;
}StackNode,*LinkStack;
typedef struct StackNodeOPND {
int data;
struct StackNodeOPND* next;
}StackNodeOPND, * LinkStackOPND;
//舍弃顺序栈:
/*
//这个是顺序栈,但是因为我删不掉pop的元素,pop操作仅仅只是把指针位置换了然后让原来存了数据的地方“人为地”看成可以“改变内容”的一个单位
typedef struct {
SElemtype* base;//栈底指针
SElemtype* top;//栈顶指针
int stacksize;
}SqStack;
//删不掉我感觉很难受,就不用了
*/
//**************************以下操作均以链栈为操作基础**************************
//值得一提的是,我在第一次做程序功能检查时发现我的程序只能处理单位数参与的运算,这是缺陷,所以接下来函数名带“OPND”的均为补丁
//栈的初始化 InitStack
Status InitStack(LinkStack &S) {
S = NULL;//这是创建了一个空栈顶指针:很明显,如果要后来居上形成一个类似“桶”的栈结构,必须要用前面链表的逆向创建思路,那么此时这个新指针就很明显地地成为了栈顶指针
return OK;
}
Status InitStackOPND(LinkStackOPND & S) {
S = NULL;//这是创建了一个空栈顶指针:很明显,如果要后来居上形成一个类似“桶”的栈结构,必须要用前面链表的逆向创建思路,那么此时这个新指针就很明显地地成为了栈顶指针
return OK;
}
//读取栈顶(检测) GetTop
SElemtype GetTop(LinkStack S) {//类型换为SElemtype是为了在主函数里面用的时候可以直接让栈的某一个节点的data等于GetTop()
if (S != NULL) { //不加&是为了不让操作权限暴露给函数
return S->data;
}
}
int GetTopOPND(LinkStackOPND S) {//类型换为SElemtype是为了在主函数里面用的时候可以直接让栈的某一个节点的data等于GetTop()
if (S != NULL) { //不加&是为了不让操作权限暴露给函数
return S->data;
}
}
//Pop
Status Pop(LinkStack& S, SElemtype &e) {//用e迎接返回值
if (S == NULL)
return ERROR;
else {
e = S->data;
LinkStack p;//临时协助删除操作的指针
p = S;//将当前栈顶元素的地址交给p
S = S->next;//栈顶指针下移
delete p;//删除前栈顶的内容
return OK;
}
}
Status PopOPND(LinkStackOPND& S, int& e) {//用e迎接返回值
if (S == NULL)
return ERROR;
else {
e = S->data;
LinkStackOPND p;//临时协助删除操作的指针
p = S;//将当前栈顶元素的地址交给p
S = S->next;//栈顶指针下移
delete p;//删除前栈顶的内容
return OK;
}
}
//Push
Status Push(LinkStack &S,SElemtype e) {
LinkStack p;//申请一个临时的结点便于将数据打包进栈的单个结构并并入链栈
p = new StackNode;
p->data = e;//打包进节点
p->next = S;//经典将next填充为头指针的NULL型next。但是这里不一样,因为我们最先申请的栈顶指针赋值是NULL,而且他此时没有“next”这个内容,是个指向NULL的“野指针”
S=p;//真正指向“栈顶”:指向栈顶元素而不是像顺序栈那样指向真正“栈顶元素”的上面一个可用空位(为社么顺序表要指向真正元素的上一个空位?这要从top指针的确定之初讲
//起:因为要一次性规定好一个顺序栈所以top指针和base指针都要一起规定出来,但是如果top指针必须指向栈顶元素的话那么就必须一开始有栈顶元素,不然只能等第一个元
//素push进去之后再生成一个top指针;同样地,由于顺序指针是在一个已经规定了大小的数组空间内执行,要判断栈是否满还得用个“if(S.top-S.base==S.stacksize)”,显然
//只有用一个预先就留好的、在操作过程中在栈顶元素之上的top指针才能使这个教材给的规范语句得到正确的结果)
return OK;
}
Status PushOPND(LinkStackOPND& S, int e) {
LinkStackOPND p;
p = new StackNodeOPND;
p->data = e;
p->next = S;
S = p;
return OK;
}
//**************************以上操作均以链栈为操作基础**************************
//运算符比较 Precede
//首先定义一个二维数组用来充当运算符的比较(如下)
/*
* 0 1 2 3 4 5 6 7
* + - * / % ( ) #
*
* 0 + > > < < < < > >
*
* 1 - > > < < < < > >
*
* 2 * > > > > > < > >
*
* 3 / > > > > > < > >
*
* 4 % > > > > > < > >
*
* 5 ( < < < < < < =
*
* 6 ) > > > > > > >
*
* 7 # < < < < < < =
*/
//这个打了我好久捏,像雕花一样
char m_OPTR[8][8] = {'>','>','<','<','<','<','>','>','>','>','<','<','<','<','>','>','>','>','>','>','>','<','>','>','>','>','>','>','>','<','>','>','>','>','>','>','>','<','>','>','<','<','<','<','<','<','=','\ ','>','>','>','>','>','\ ','>','>','<','<','<','<','<','<','\ ','='};
//比较优先级
Status Precede(SElemtype storedtopdata,SElemtype newdata) {
int a=0, b=0;
switch (storedtopdata) {
case '+':a = 0; break;
case '-':a = 1; break;
case '*':a = 2; break;
case '/':a = 3; break;
case '%':a = 4; break;
case '(':a = 5; break;
case ')':a = 6; break;
case '#':a = 7; break;
}
switch (newdata) {
case '+':b = 0; break;
case '-':b = 1; break;
case '*':b = 2; break;
case '/':b = 3; break;
case '%':b = 4; break;
case '(':b = 5; break;
case ')':b = 6; break;
case '#':b = 7; break;
}
return m_OPTR[a][b];
}
//查询输入内容是数字还是运算符 In(Status函数)
Status In(SElemtype newdata) {
if (newdata == '+' || newdata == '-' || newdata == '*' || newdata == '/' || newdata == '%' || newdata == '(' || newdata == ')' || newdata == '#') {
return 1;
}
else
return 0;
}
//进行二元运算处理 Operate
int Operate(int former, char theta, int latter) {
int result=0;
switch (theta) {
case '+':result = former + latter; break;
case '-':result = former - latter; break;
case '*':result = former * latter; break;
case '/':result = former / latter; break;
case '%':result = former % latter; break;
}
return result;
}
//读取文件中的表达式
int Read_and_calculate(LinkStack&OPTR,LinkStackOPND&OPND,char *filename) {
InitStack(OPTR);
InitStackOPND(OPND);
char ch,theta,x,bowlchar;
int bowlint,bowlint2, a, b,final;
ifstream inFile;
inFile.open(filename);
inFile >> ch;//此时ch必为#
Push(OPTR, ch);
inFile >> ch;
while (ch != '#' || GetTop(OPTR) != '#') {
if (!In(ch)) {
bowlint = ch - 48;
PushOPND(OPND, bowlint);
inFile >> ch;
while (!In(ch) == 1) {
PopOPND(OPND, bowlint);
bowlint2 =bowlint*10+(ch - 48);
PushOPND(OPND, bowlint2);
inFile >> ch;
}
}
else {
switch(Precede(GetTop(OPTR),ch)){
case'<':
Push(OPTR, ch);
inFile >> ch;
break;
case'>':
Pop(OPTR, theta);
PopOPND(OPND, b);
PopOPND(OPND, a);
//此处a,b是char型,需要转化为int再参与计算
bowlint=Operate(a, theta, b);
PushOPND(OPND, bowlint);
break;
case'=':
Pop(OPTR, x); //弹出栈顶的'('
//这个x并不重要
inFile >> ch;//读入下一个
break;
}
}
}
inFile.close();
final=GetTopOPND(OPND);
return final;
}
//主函数
void main() {
LinkStack OPTR;
LinkStackOPND OPND;
int result;
char filename[] = "C:\\Users\\Nighfearti\\Desktop\\test.txt";
result=Read_and_calculate(OPTR,OPND,filename);
printf("%d", result);
}