栈的运用之表达式的运算

最近刚刚学完栈的相关结构,想着写一个小项目(题目的#号没有使用)

设计算法:1小时;代码实现:2小时;调试bug:12小时左右;

设计的算法思想:首先通过一个字符串数组c将操作者的式子全部放进去,之后将字符数组c的全部字符转入栈S1,由于式子中还有括号,所以要有一个式子括号检测是否匹配的问题,检测完毕后,提取栈S1中一个匹配括号的式子放入栈S2,再由一个整型数组a存放所有S2的内容(式子可能存在二位数以上所以要有一个合并数字字符的操作转入S3),通过安排好运算符的优先级就可以在整型数组a里面实现运算了,运算完毕最后的值放在a[0]的位置在传给原本的栈S1。式子内的括号全部运算完都放至栈S1,栈S1就有了完整的式子,之后将栈S1的全部数据转入一个整型数组进行运算(和括号内运算的代码类似)。


代码的内容不好做细分所以就没有一一化区块来展示了,下方是完整的代码:

使用的环境是vs2019;源文件后缀是.cpp

#define _CRT_SECURE_NO_WARNINGS//栈
#include <stdio.h>
#include <malloc.h>
#include<string>


//全局定义特殊变量
#define ok 1
#define OVERFLOW 0
#define MAX 30

//转定义区域
typedef char SElemType;
typedef int status;


typedef struct//定义栈
{
	SElemType* top;
	SElemType* base;
	int Stacksize;

}Sqstack;

status InitStack(Sqstack& S)//栈的初始化函数//功能函数
{
	S.base = (SElemType*)malloc(sizeof(SElemType[MAX]));
	if (!S.base)
	{
		return  OVERFLOW;
	}
	S.top = S.base;
	S.Stacksize = MAX;
	return ok;
}

status check(Sqstack& S, char c[50])//检查括号是否匹配//功能函数
{
	int i, count;
	for (i = 0; c[i] != '\0'; i++)//只录入括号
	{
		if (c[i] == '(')
		{
			*S.top++ = c[i];
		}
		if (c[i] == ')')
		{
			S.top--;
		}
	}
	if (S.top == S.base)
	{
		count = 1;
	}
	else
	{
		count = 0;
	}
	return count;
}

status StackLength(Sqstack S)//输出栈的长度//功能函数
{
	int i = 0;
	SElemType* p;
	p = S.top;
	while (p != S.base)
	{
		--p;
		i++;
	}
	return i;
}

status Clearstack(Sqstack& S)//清空栈
{
	if (S.top = S.base)
	{
		return 1;
	}
	while (S.top != S.base)
	{
		--S.top;
	}
	return 1;
	//printf("栈已清空!");
}
int main()
{
	int count;
	Sqstack S1, S2, S3;
	InitStack(S1);
	InitStack(S2);
	InitStack(S3);
	char c[50];//输入存放的式子
	int a[50];//进行数字运算
	int i, j, e, a1 = 0, F, x, y, len = 0, lens, zhi, mk = 0;
	printf("欢迎使用表达式计算小程序:\n");
	printf("请输入要计算的表达式:(等回车表示输入结束)");
	gets_s(c);//源文件后缀为.c就不用加下划线
	count = check(S1, c);
	if (count == 1)
	{
		for (i = 0; c[i] != '\0'; i++)
		{
			if (c[i] == ')')//计算括号匹配的式子
			{
				while (1)
				{
					if (*--S1.top == '(')
					{
						break;
					}
					*S2.top++ = *S1.top;//通过S2将数字摆正=数组从S2出来后式子的顺序符合我们运算时的顺序
				}
				lens = StackLength(S2);//求得长度来限制数组a的存放次数
				--S2.top;
				if (*S2.top >= '0' && *S2.top < '10')//整合所有的数字
				{

				mark:while (*S2.top >= '0' && *S2.top < '10')
				{
					*S3.top++ = *S2.top;
					--S2.top;
					len++;
				}
				for (F = 1, y = 0, x = 0; S3.top != S3.base; F = F * 10)//若表达式的数字存在二位数及以上的就要合并
				{
					x = *--S3.top - '0';//利用的是ascll码表的规则进行字符到整型的转换
					y = y + x * F;
				}
				a[a1] = y;
				a1++;
				if (*S2.top == '*')//符号直接进入整型数组会自动转化为对应的ascll码值进行保存
				{
					a[a1] = *S2.top--;
					a1++;
					len++;
				}
				if (*S2.top == '/')
				{
					a[a1] = *S2.top--;
					a1++;
					len++;
				}
				if (*S2.top == '+')
				{
					a[a1] = *S2.top--;
					a1++;
					len++;
				}
				if (*S2.top == '-')
				{
					a[a1] = *S2.top--;
					a1++;
					len++;
				}
				if (len != lens)
				{
					goto mark;
				}
				//以上是将栈保存的式子数据保存至整型数组进行运算
				}
				a[a1] = '\0';
				for (e = 0; a[e] != '\0'; e++)//乘法除法运算//运算时涉及到运算符的优先级
				{
					if (a[e] == '*' || a[e] == '/')
					{
						if (a[e] == '*')
						{
							zhi = a[e - 1] * a[e + 1];
						}
						if (a[e] == '/')
						{
							zhi = a[e - 1] / a[e + 1];
						}
						a[e] = '\0'; a[e + 1] = '\0';
						a[e - 1] = zhi;
						for (; a[e + 2] != '\0'; e += 2)
						{
							a[e] = a[e + 2];
							a[e + 2] = '\0';
							a[e + 1] = a[e + 3];
							a[e + 3] = '\0';
							mk++;
						}
						if (mk > 0)//由于上面涉及到数组的移位,之后重新判断式子的时候要考虑到之前的循环条件for (e = 0; a[e] != '\0'; e++)
						{
							e -= 1 + (2 * mk);//进行参数的调整变化
							mk = 0;
						}
					}
				}
				for (e = 0; a[e] != '\0'; e++)//加法减法运算
				{
					if (a[e] == '+' || a[e] == '-')
					{
						if (a[e] == '+')
						{
							zhi = a[e - 1] + a[e + 1];
						}
						if (a[e] == '-')
						{
							zhi = a[e - 1] - a[e + 1];
						}
						a[e] = '\0'; a[e + 1] = '\0';
						a[e - 1] = zhi;
						for (; a[e + 2] != '\0'; e += 2)
						{
							a[e] = a[e + 2];
							a[e + 2] = '\0';
							a[e + 1] = a[e + 3];
							a[e + 3] = '\0';
							mk++;
						}
						if (mk > 0)
						{
							e -= 1 + (2 * mk);
							mk = 0;
						}
					}


				}
				Clearstack(S2);
				while (a[0] != 0)//将括号结果转为字符准备入栈S1
				{
					*S2.top++=(a[0] % 10)+'0';
					a[0] /= 10;
				}
				while (S2.top!=S2.base)
				{
					*S1.top++ = *--S2.top;
				}



			}
			*S1.top++ = c[i];
			if (c[i] == ')')
			{
				--S1.top;//出掉栈里面多余的括号
			}
			a1 = 0;
			len = 0;//以上这两行初始化非常重要,防止数组的越界问题
		}
		while (S1.top != S1.base)
		{
			*S2.top++ = *--S1.top;
		}
		//接下来的代码和之前括号里面的运算是一致的
		lens = StackLength(S2);
		--S2.top;
		Clearstack(S3);
		if (*S2.top >= '0' && *S2.top < '10')//整合所有的数字
		{

		mark1:while (*S2.top >= '0' && *S2.top < '10')
		{
			*S3.top++ = *S2.top;
			--S2.top;
			len++;
		}
		for (F = 1, y = 0, x = 0; S3.top != S3.base; F = F * 10)
		{

			x = *--S3.top - '0';
			y = y + x * F;
			
		}
		a[a1] = y;
		a1++;
		if (*S2.top == '*')
		{
			a[a1] = *S2.top--;
			a1++;
			len++;
		}
		if (*S2.top == '/')
		{
			a[a1] = *S2.top--;
			a1++;
			len++;
		}
		if (*S2.top == '+')
		{
			a[a1] = *S2.top--;
			a1++;
			len++;
		}
		if (*S2.top == '-')
		{
			a[a1] = *S2.top--;
			a1++;
			len++;
		}
		if (len != lens)
		{
			goto mark1;
		}

		}
		a[a1] = '\0';
		for (e = 0; a[e] != '\0'; e++)//乘法除法运算
		{
			if (a[e] == '*' || a[e] == '/')
			{
				if (a[e] == '*')
				{
					zhi = a[e - 1] * a[e + 1];
				}
				if (a[e] == '/')
				{
					zhi = a[e - 1] / a[e + 1];
				}
				a[e] = '\0'; a[e + 1] = '\0';
				a[e - 1] = zhi;
				for (; a[e + 2] != '\0'; e += 2)
				{
					a[e] = a[e + 2];
					a[e + 2] = '\0';
					a[e + 1] = a[e + 3];
					a[e + 3] = '\0';
					mk++;
				}
				if (mk > 0)
				{
					e -= 1 + (2 * mk);
					mk = 0;
				}
			}
		}
		for (e = 0; a[e] != '\0'; e++)//加法减法运算
		{
			if (a[e] == '+' || a[e] == '-')
			{
				if (a[e] == '+')
				{
					zhi = a[e - 1] + a[e + 1];
				}
				if (a[e] == '-')
				{
					zhi = a[e - 1] - a[e + 1];
				}
				a[e] = '\0'; a[e + 1] = '\0';
				a[e - 1] = zhi;
				for (; a[e + 2] != '\0'; e += 2)
				{
					a[e] = a[e + 2];
					a[e + 2] = '\0';
					a[e + 1] = a[e + 3];
					a[e + 3] = '\0';
					mk++;
				}
				if (mk > 0)
				{
					e -= 1 + (2 * mk);
					mk = 0;
				}
			}


		}
		
		printf("式子的结果为:%d",a[0]);
	}
	else
	{
		printf("该式子不符合语法");
	}
	return 0;

}

这个代码最容易出现的就是:某某的内容访问失败-->这个情况讲得首先考虑数组越界!注意做好数据元素的初始化(当初在这个地方一直调试不出来,花了好多时间,这个情况编译器是不会报错的,运行代码时就不行了);

 实现的技术要点:

1.整型转字符,字符转整型(通过ascll码表来做的)

2.括号的检测(通过一个栈来实现的,栈空就是括号匹配)

3.数字的合并(这个花了不少功夫)

4.栈与数组的数据传输

5.“笑着”调试代码(作为初学者有bug很正常,要耐下心来不要急躁)

实施效果:

注意:不能出现:数字后面直接加(),如果要乘以括号里面的式子要:数字*();


目前缺陷:

1.算数的精度不够(由于是整型运算,一涉及到除法的运算就会有偏差,因为只取整)

2.只支持+ 、 - 、* 、/ 的运算

3.可能还有未知的bug(还望大佬们指出)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值