用C语言实现四则预算

前段时间学习了栈的基础操作后,想着用栈实现四则运算来巩固以下所学知识。

什么是栈

栈(Stack)是规定只能在表尾进行插入和删除操作的线性表。这一规定决定了栈中数据具有后入先出的特点。

由图可知,可以通过栈顶元素、存储元素、栈的最大空间来一起描述一个栈。对于顺序栈,存在一个定义栈的最大空间的参数使顺序栈具有固定的大小。如果想要一个没有存储元素个数限制的栈,则可以模仿动态链表的思路,让栈中元素包含有一个指向下一个元素地址的指针,从而形成一个链栈,这也正是实现四则运算所需要的。

实现思路

首先是实现要用到的栈的操作,分别是元素入栈、元素出栈、获取栈顶元素

栈的基本定义:

typedef enum Status 
{
    ERROR = 0, 
	SUCCESS = 1
} Status;

typedef struct StackNode
{
	int data;
	struct StackNode *next;
}Node;

typedef struct StackInfo
{
	struct StackNode *top;
	int count;
}Stack;

入栈

1、形成新结点

2、新节结点的直接后继指向当前的栈顶元素

3、栈顶指针指向新结点

Status Push(Stack *s, int e)
{
	if (s == NULL)
	{
		return ERROR;
	}

	Node *p = (Node *)malloc(sizeof(Node));
	if (p == NULL)
	{
		return ERROR;
	}

	p->data = e;
	p->next = s->top;
	s->top = p;
	s->count = s->count + 1;

	return SUCCESS;
}

出栈

1、判断栈顶是否为空

2、p指向栈顶元素,栈顶指针下移一位

3、释放p所指向的空间

Status Pop(Stack *s)
{
	if (s == NULL)
	{
		return ERROR;
	}
	if (s->top == NULL)
	{
		return ERROR;
	}

	int save;
	Node *p = s->top;
	save = s->top->data;
	s->top = p->next;
	free(p);
	p = NULL;
	s->count = s->count - 1;

	return save;

}

得到栈顶元素

Status GetTop(Stack *s)
{
	if (s == NULL)
	{
		return ERROR;
	}
	if (s->top == NULL)
	{
		return ERROR;
	}
	return s->top->data;
}

栈的判空

Status EmptyStack(Stack *s)
{
	if (s == NULL)
	{
		return ERROR;
	}
	if(s->top == NULL)
	{
		return SUCCESS;
	}
	else{
		return ERROR;
	}
}

接下来,先理解以下四则运算的实现原理

观察式子:1+2       = 3

平时我们所用的四则运算表达式都是运算符在两个数字中间的,所以称这种表达式为中缀表达式

后缀表达式定义为运算符在两个数字之后的表达式。例如:

式子「1」:6 + ( 4 - 2 ) × 3 + 9 ÷ 3             = 15

式子「2」:6  4  2  -  3  × + 9  3  ÷ +           =

式子「1」是中缀表达式,式子「2」是后缀表达式

与中缀表达式相比,后缀表达式的优点是不需要考虑括号匹配、运算符优先级和简化运算。

我们利用链栈来表示后缀表达式,从而可以计算出结果。所以首先要将中缀表达式转换为后缀表达式,方法如下:

从头到尾读取中缀表达式的每个对象,对不同对象按不同情况处理。

1 运算数:直接输出

2 左括号:压入堆栈

3 右括号:将栈顶元素弹出直到遇到左括号(出栈,不输出)

4 运算符:

        若优先级大于栈顶元素,将它压栈

        若优先级小于栈顶元素,栈顶元素弹出并输出;再比较新的栈顶元素,直到该运算符大于栈顶运算符优先级为止,然后将该运算符号压栈

5 各对象处理完毕后,把堆栈中存留的运算符一并输出

优先级如代码所示:

int Priority(char ch) /*判断优先级*/
{
	switch(ch)
	{
		case '(':
			return 3;
		case '*':
		case '/':
			return 2;
		case '+':
		case '-':
			return 1;
		default:
			return 0;
	} 
}

接下来是后缀表达式的运算

规则:(用栈来进出运算的数字)

1.从左到右遍历后缀表达式的每一个数字和符号

2.若是数字,则进栈

3.若是符号,则把处于栈顶的两个数字出栈,进行运算

4.运算结果进栈

5.直到获得最终结果

最后附上主函数的完整代码

int main()
{
	int i = 0;
	int num1,num2;
	int tem = 0;         /*用来暂时存储数据*/
	char str[111] = {0}; /*存储输入的运算式*/
	Stack *res,*ope;    /*存储运算式中输出的和不输出的*/
	if(!(InitStack(&res)) || !(InitStack(&ope))){
		printf("初始化失败\n"); 
	}
	printf("请输入您的式子:");
	scanf("%s",str);
	
	while(str[i] != '\0' || ope->count != 0){ /*遍历运算式*/
		if('0'<=str[i] && str[i]<='9'){
			tem = tem*10+str[i]-'0'; /*将字符型转换为整型*/
			i++;
			if('0'>=str[i] || str[i]>='9'){
				Push(res,tem); /*如果数字的下一位不是整型,则将数字存储,否则这是一个多位数*/
				tem = 0; 
			}
		} 
		else{ /*当遇到运算符时*/
		      /*首先是运算符入栈的情况*/
		if (GetTop(ope) == '(' && str[i] ==')')	//直接出栈,不计算,栈顶为'(' ,表达式为')'
			{
				Pop(ope);	//括号直接出栈
				i++;
				continue;	//继续下一次循环
			}
			if((EmptyStack(ope) == SUCCESS) || (Priority(str[i]) > Priority(GetTop(ope))) || (GetTop(ope) == '(' && str[i] != ')')) /*存储运算符的栈为空、优先级*/
			{
				Push(ope,str[i]);
				i++;
				continue;
			}
		/*接下来是运算符输出并且运算的情况*/
			if((Priority(str[i]) <= Priority(GetTop(ope)))|| str[i] == ')'|| (str[i] == '\0' && EmptyStack(ope) != SUCCESS))
			{/*优先级、遇到右括号、运算式结束而存储运算的栈还未结束*/
				int num; 
				num1 = Pop(res);	//数字栈顶出栈
				num2 = Pop(res);	//数字栈第二个数字出栈
				switch (Pop(ope))	//后出的数字在前
				{
					case '+':
						num = num1 + num2;
						Push(res,num); /*运算后在放入栈内*/
						break;
					case '-':
						num = num2 - num1;
						Push(res,num);
						break;
					case '*':
						num = num1 * num2;
						Push(res,num);
						break;
					case '/':
						num = num2 / num1;
						Push(res,num);
						break;
			}
			
			}
		}	
}
printf("result = %d",GetTop(res));
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值