数据结构--计算表达式完整版(涉及乘方)

思路:

两个栈:数据栈与符号栈。

(在描述优先级时,我们将加减描述为‘I级’,乘除为‘II既’,乘方为‘III级’)

1.在之前的只有加减乘除的计算表达式里:就有了初步思路

当我们要计算的时候:

局部计算函数:数字栈与符号栈,分别在数字栈顶取出两个操作数,再在符号栈里取出对应的符号进行运算。

在只有加减乘除的计算中:我们只需要考虑两种情况来调用局部计算函数,

        一:当存入一个数字压栈时,判断出符号栈顶是优先级的'*'或'/',II级时,直接进入计算函数。

        二:当读到右括号时,进行while的计算函数操作,其目的就是把括号里低级,I级的加减进行计算。

加入乘方后的难点:比如: 2*3^4,如果按上述会产生读到3后判断出前一个为'*',就进行计算函数的操作,而乘方^ 优先级应高于*,导致错误。

解决方法:前文解决乘除的优先级问题时,是通过判断压入数字判符号栈顶元素是否为II级即可。同理,我们可以在判断数字时,顺便判断它后方是否为III级,如果是,则再获取III后方的数字,并且直接通过乘方计算后再压入数字栈;比如: a*b^c,当读入b后,判断出后一位为III,则再往后读数字c,然后压栈时压入的就是(b^c),就转化为了只有加减乘除的问题。顺便判断它后方是否为III级,如果是,但后边有括号如:a^(b+c) 

故以下我们主要讨论:
1.a*b^c

2.(a+b)^c与a^(b+c) 

3.a*b^(c+d)与b^(c+d)*a

我的测试:

a+b                        a+b+c+d                
a*ba*b*c*d

a^b

a^b^c^d
a*b^cb^c*a
(a+b)^ca^(b+c) 
a*b^(c+d)b^(c+d)*a

(方法较为复杂,只是以个人角度解题,在使用不同表达式时修修改改,该程序可能依然有隐藏bug!!!) 

 对于 a*b^c  可以使用上述解决方法,当读入数字是判断后方是否为III并且将III后方数字也同样计算出来再压回栈里:

对于:a^(b+c)则需要避免这种情况:故应该有:&& str[j+1]!='('

if (isNumber(temp)) {
	int j = i;
	int sum = 0, power = 1;
	while (isNumber(str[j]) && j < strlen(str)) {      
	sum = sum * 10 + str[j] - '0';
	j++;
	}
	if ( str[j] == '^' && j<strlen(str) 
        && head->dataC[head->topC] != '^' 
        && str[j+1]!='(' && str[j + 1] != ')' )
{
		j++;//2^(2+3)
		while (isNumber(str[j]) && j < strlen(str)) {
		power = power * 10 + str[j] - '0';
		j++;
	}
	sum = pow(sum, power);
	}
    i = j - 1;
	pushI(head, sum);

对于 (a+b)^c:则可以采用乘除的判断方法: 压入了一个数字并且发现此时符号栈顶为'^',则直接计算:

if (head->dataC[head->topC] == '*' || head->dataC[head->topC] == '/') cal_loc(head); 
if(head->dataC[head->topC] == '^') cal_loc(head);

 对于a^(b+c) :通过计算完成括号内数字后,若栈顶为III,则再进行计算a*b^(c+d)与b^(c+d)*a:if (head->dataC[head->topC] == '*' &&str[i+1]!='^') cal_loc(head);这样是为了确保 ^ 始终都先被计算;

case')':
	while(head->dataC[head->topC]!='(') cal_loc(head);
	popC(head);
	if(head->dataC[head->topC] == '^') cal_loc(head);
    if (head->dataC[head->topC] == '*' &&str[i+1]!='^') cal_loc(head);
	break;

局部计算函数:

void cal_loc(stackPtr head) {
	if (head->dataC[head->topC] == '(') return;
	int a = popI(head);
	int b = popI(head);
	char c = popC(head);
	int res = 0;
	switch (c) {
	case'^':
		res = pow(b, a);
		break;
	case'*':
		res = a * b;
		break;
	case'/':
		res = (double)b / a;
		break;
	case'+':
		res = a + b;
		break;
	case'-':
		res = b - a;
		break;
	}
	pushI(head, res);
}

 逻辑判断主函数:

int calculate(stackPtr head,char* str) {
	for (int i = 0; i <= strlen(str);i++ ) {
		PrintC(head);
		putchar('\n');
		PrintI(head);
		putchar('\n');
		char temp;
		if (i < strlen(str)) {
			temp = str[i];
		}
		else {
			temp = ')';
		}
		if (isNumber(temp)) {
			int j = i;
			int sum = 0, power = 0;
			while (isNumber(str[j]) && j < strlen(str)) {      
				sum = sum * 10 + str[j] - '0';
				j++;
				printf("sum1:%d \n", sum);
			}
			if (str[j] == '^' && j<strlen(str) && head->dataC[head->topC] != '^' && str[j+1]!='(' && str[j + 1] != ')') {
				j++;//2^(2+3)
				while (isNumber(str[j]) && j < strlen(str)) {
					power = power * 10 + str[j] - '0';
					j++;
				}
				sum = pow(sum, power);
				printf("sum2:%d \n", sum);
			}
			i = j - 1;
			pushI(head, sum);
			printf("pushed:");
			PrintI_TOP(head);

			if ((head->dataC[head->topC] == '*' || head->dataC[head->topC] == '/') && str[i+1]!='^') cal_loc(head);
			if(head->dataC[head->topC] == '^') cal_loc(head);
		}
		else {
			switch (temp) {
			case'(':
				pushC(head, temp);
				break;
			case')':
				while(head->dataC[head->topC]!='(') cal_loc(head);
				popC(head);
				if (head->dataC[head->topC] == '^') cal_loc(head);
				if (head->dataC[head->topC] == '*' && str[i+1]!='^') cal_loc(head);
				break;
			case '^':
				pushC(head, temp);
				break;
			case '*':
				pushC(head, temp);
				break;
			case '/':
				pushC(head, temp);
				break;
			case'+':
				pushC(head, temp);
				break;
			case'-':
				pushC(head, temp);
				break;
			}
		}
	}
	return popI(head);
}

完整代码:

#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<math.h>

typedef struct {
	char dataC[20];
	int dataI[20];
	int topC,topI;
}*stackPtr, stack;

stackPtr InitStack() {
	stackPtr head = (stackPtr)malloc(sizeof(stack));
	head->topC = -1;
	head->topI = -1;
	return head;
}

void pushC(stackPtr head, char c) {
	if (head->topC >= 18) {
		printf("no space");
		return;
	}
	head->topC++;
	head->dataC[head->topC] = c;
}

char popC(stackPtr head) {
	char tempchar = head->dataC[head->topC];
	head->topC--;
	return tempchar;
}

void pushI(stackPtr head, int c) {
	if (head->topI >= 18) {
		printf("no space");
		return;
	}
	head->topI++;
	head->dataI[head->topI] = c;
}

int popI(stackPtr head) {
	int tempint = head->dataI[head->topI];
	head->topI--;
	return tempint;
}

int isNumber(char c) {
	if (c >= '0' && c <= '9') return 1;
	return 0;
}

void PrintC(stackPtr head) {
	if (head->topC == -1) return;
	for (int i = head->topC; i >= 0; i--) {
		printf("%c ", head->dataC[i]);
	}
}

void PrintI(stackPtr head) {
	if (head->topI == -1) return;
	for (int i = head->topI; i >= 0; i--) {
		printf("%d ", head->dataI[i]);
	}
}

void PrintI_TOP(stackPtr head) {
	if (head->topI == -1) return;
	printf("%d\n", head->dataI[head->topI]);
}

void cal_loc(stackPtr head) {
	if (head->dataC[head->topC] == '(') return;
	int a = popI(head);
	int b = popI(head);
	char c = popC(head);
	int res = 0;
	switch (c) {
	case'^':
		res = pow(b, a);
		break;
	case'*':
		res = a * b;
		break;
	case'/':
		res = (double)b / a;
		break;
	case'+':
		res = a + b;
		break;
	case'-':
		res = b - a;
		break;
	}
	pushI(head, res);
}

int calculate(stackPtr head,char* str) {
	for (int i = 0; i <= strlen(str);i++ ) {
		PrintC(head);
		putchar('\n');
		PrintI(head);
		putchar('\n');
		char temp;
		if (i < strlen(str)) {
			temp = str[i];
		}
		else {
			temp = ')';
		}
		if (isNumber(temp)) {
			int j = i;
			int sum = 0, power = 0;
			while (isNumber(str[j]) && j < strlen(str)) {      
				sum = sum * 10 + str[j] - '0';
				j++;
				printf("sum1:%d \n", sum);
			}
			if (str[j] == '^' && j<strlen(str) && head->dataC[head->topC] != '^' && str[j+1]!='(' && str[j + 1] != ')') {
				j++;//2^(2+3)
				while (isNumber(str[j]) && j < strlen(str)) {
					power = power * 10 + str[j] - '0';
					j++;
				}
				sum = pow(sum, power);
				printf("sum2:%d \n", sum);
			}
			i = j - 1;
			pushI(head, sum);
			printf("pushed:");
			PrintI_TOP(head);

			if ((head->dataC[head->topC] == '*' || head->dataC[head->topC] == '/') && str[i+1]!='^') cal_loc(head);
			if(head->dataC[head->topC] == '^') cal_loc(head);
		}
		else {
			switch (temp) {
			case'(':
				pushC(head, temp);
				break;
			case')':
				while(head->dataC[head->topC]!='(') cal_loc(head);
				popC(head);
				if (head->dataC[head->topC] == '^') cal_loc(head);
				if (head->dataC[head->topC] == '*' && str[i+1]!='^') cal_loc(head);
				break;
			case '^':
				pushC(head, temp);
				break;
			case '*':
				pushC(head, temp);
				break;
			case '/':
				pushC(head, temp);
				break;
			case'+':
				pushC(head, temp);
				break;
			case'-':
				pushC(head, temp);
				break;
			}
		}
	}
	return popI(head);
}

void Test() {
	stackPtr head = InitStack(head);
	pushC(head, '(');

	char* tempExpression = "10+(3+2)^4";
	printf("The result = %d ", calculate(head, tempExpression));
}
int main() {
	Test();
	return 0;
}

ps:提前压入‘(’和末尾压‘)’的原因是:涉及加减的运算在该程序需要读到‘)’才会进行计算,但可能表达式中没有,故人为加入‘)’。

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值