栈的应用——加减乘除四则运算
栈
栈是特殊的线性表,相较于一般的线性表,在定义结构体时多了栈顶指针这一元素(在链式表中为指针,在顺序表中表现为记录数组最后一个元素的下标的整型变量 int top)。栈的操作也有别于通常的线性表,主要是通过栈顶指针对栈顶元素进行修改,包括了入栈、出栈、取栈顶元素等操作。由于栈通过栈顶指针进行操作,栈中元素表现出“后进先出”的特点,在程序设计时的应用十分广泛,其中加减乘除四则运算就是一个典型的例子。
a[maxsize] | 栈顶指针 |
---|---|
a[maxsize-1] | |
… | |
a[n] | top(栈顶元素的下标) |
… | |
a[2] | |
a[1] | |
a[0] |
#define max1 100
#ifndef __MAX__K__
#define __MAX__K__
typedef struct { //定义一个栈
int a[max1]; //栈内的整数数组
char sym[max1]; //字符数组
int topnum=; //定义栈顶下标
int topchar;
}stack;
#endif
栈的基本操作
入栈
a[maxsize] | 栈顶指针 |
---|---|
a[maxsize-1] | |
… | |
a[n+1] | top |
a[n] | |
… | |
a[2] | |
a[1] | |
a[0] |
void push(stack* p, int num) { //num为输入的数值
if ((p->topnum) < max1-1) { //判断栈是否满
p->topnum++; //未满则最大下标+1
int k = p->topnum;
p->a[k] = num; //赋值
}
else {
printf("error\n"); //栈满则输出error
}
}
出栈
a[maxsize] | 栈顶指针 |
---|---|
a[maxsize-1] | |
… | |
a[n] | |
a[n-1] | top |
… | |
a[2] | |
a[1] | |
a[0] |
int pop(stack* p) { //出栈操作
int i=0;
if ((p->topnum) > -1) {
i = p->a[p->topnum]; //i记录栈顶元素的数值
p->topnum--; //出栈之后下标减一
}
else {
printf("error\n");
}
return i;
其他操作
由于其他操作也是在栈顶指针的基础上实现,这里就不一一叙述了。
加减乘除四则运算的实现
我们要写一段代码,实现加减乘除的运算,其实核心问题在于解决乘除运算的优先级高于加减的问题。利用上文所提到栈后进先出的特点,就可以解决这个问题。我们大致的思路如下:
首先定义两个栈,一个存放数值,一个存放运算符
也就是说,在这个过程中,遇到乘或除会优先处理运算,并将其值入栈,而加减则会依次放入运算符栈中。即最后的结果是符号栈只剩下加减,而且在数值栈除a[0]外,每个数都有一个加或减与之对应。而a[0]在第一次读数时已自带正负,也就是说,剩下只需要进行加减运算即可。
核心问题到此以解决。
基于出、入栈的操作,下面补充运算函数用于计算:
int num_op(int x, char i, int y) {
int j = 0,num=0;
if (i == '+') {
num = x + y;
}
if (i == '-') {
num = x - y;
}
if (i == '*') {
num = x * y;
}
if (i == '/') {
num = x / y;
}
return num;
}
int num_tran(int x, char i) { //数值的转换,若数值对应的运损符
//为-,令其等于其相反数;反之不变
if (i == '-') {
x = -x;
}
return x;
}
以下为主函数(其中 pushchar 与 popchar 分别为运算符入栈、出栈的函数):
char m,n; //m读入符号
int num1,all = 0; //all记录整个式子的值
stack* p = (stack*)malloc(sizeof(stack));
if (p) { //判断p是否正常申请
p->topchar = -1; //初始化栈顶指针下标
p->topnum = -1;
while (1) {
scanf_s("%d", &num1); //读入一个数
push(p, num1); //num1入栈
scanf_s("%c", &m,1); //读入运算符至m
__after_1_:
if (m == '=') { //读入 = 号则循环停止
break;
}
if (m == '*' || m == '/') { //读入*或/则读入下一个数并存至k1
while (m == '*' || m == '/') {
scanf_s("%d", &num1); //读入下一个数
int num2 = pop(p); //取栈顶元素并存入num2
num2 = num_op(num2, m, num1); //num2与num1进行m运算并将运算值存入num2
push(p, num2); //进行乘或除运算后的值入栈
scanf_s("%c", &m, 1); // 继续读入一个运算符至m
}
goto __after_1_; //由于运算过程可能出现连续进行连续进行乘
//或除运算的运算,所以这里要回到__after_1_的位置对m
//的符号进行判断,若为*或/,继续进行
//读数 -> 出栈 -> 运算值入栈 的操作
}
if(m=='+'||m=='-'){
pushchar(p, m); //若m为+或-,输入栈的字符数组
}
}
//进行完以上操作后符号栈只剩下+或-,即待剩下的式子为a[0]至a[topnum]之间的+或-运算
while (p->topnum > 0) { //对a[0]之前的数进行操作
n = popchar(p); //为方便操作,这里同意把运算看成+
all += num_tran(pop(p), n); //通过定义num_tran函数转换。若a[n]对应的运算符为-
//取a[n]为其相反数,即将变为 -a[n]的运算变成
// +(-a[n])
}
}
all += pop(p); //由于a[0]没有相应的运算符与之对应这里单独处理
printf("result = %d", all);
free(p);
return 0;