3-3-2 堆栈 求前缀表达式的值 (25分)

算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。前缀表达式指二元运算符位于两个运算数之前,例如2+3*(7-4)+8/4的前缀表达式是:
++ 2 * 3 - 7 4 / 8 4。请设计程序计算前缀表达式的结果值。

输入格式:

输入在一行内给出不超过30个字符的前缀表达式,只包含+、-、*、/以及运算数,不同对象(运算数、运算符号)之间以空格分隔。

输出格式:

输出前缀表达式的运算结果,保留小数点后1位,或错误信息ERROR。

输入样例:

++ 2 * 3 - 7 4 / 8 4

输出样例:

13.0

  • 下面这个代码还有一个测试点没过
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#define MAXN 100
typedef struct SNode* PtrToSNode;
#define ERROR 1e9
typedef enum{false,true} bool;//vs这个不用加
struct SNode {
	double data;
	PtrToSNode next;
};
typedef PtrToSNode Stack;
//Stack CreateStack();//创造指向链表的头结点
bool IsEmpty(Stack S);//判断表是否为空
bool Push(Stack S, double X);//入栈
double Pop(Stack S);//出栈
double PostfixExp(Stack S, char* str);//计算 
double reverse(int n);//因为是从后忘前读 所以当一串字符串为72 读进去就是27 所以写了一个reverse函数把它再倒过来 但是当字符串是30时 读进去的数就是3 再怎么颠倒也是3
//(这就是那一个测试点出错的问题) 
int main()
{
	Stack S;
	S = (Stack)malloc(sizeof(struct SNode));
	S->next = NULL;
	char str[MAXN];
	double f;//f为计算结果(double型)
	gets_s(str);
	f = PostfixExp(S, str);
	if (f != ERROR)
		printf("%.1f", f);
	else printf("ERROR");
	return 0;
}
//Stack CreateStack()//创造链表 头节点(只指向链表,并不存储数据) 
//{
//	//创建一个堆栈的头节点,返回该结点指针 
//	Stack S;
//	S = (Stack)malloc(sizeof(struct SNode));
//	S->next = NULL;
//	return S;
//}
bool IsEmpty(Stack S)//判断链表是否为空 
{
	return (S->next == NULL);//如果为空返回true,因为当指针为空 S->next指向为空,就是头指针什么都不指向,否则返回false
}
bool Push(Stack S, double X)//入栈函数  从链表头入栈(头插法)(后入再前) 
{
	PtrToSNode TmpCell;
	TmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
	TmpCell->data = X;//头插法 
	TmpCell->next = S->next;
	S->next = TmpCell;
	return true;
}
double Pop(Stack S)//出栈
{
	PtrToSNode FirstCell;//栈顶元素出栈
	double TopElem;
	if (IsEmpty(S))//判断是否为空链表
	{
		return ERROR;
	}
	else
	{
		FirstCell = S->next;
		TopElem = FirstCell->data;
		S->next = FirstCell->next;//S只是一个头指针,它并不含有值,只是指向链表(栈)的头节点
		//当出栈的时候,就是将头结点右移(S->next指向原本s->next的下一个),最后再将原先的头结点释放
		free(FirstCell);
		return TopElem;//出栈并将出栈元素返回 
	}

}
double PostfixExp(Stack S, char* str)
{
	int n = strlen(str);
	n--;
	double Op1, Op2;
	for (; n >= 0; n--)
	{//因为是从字符串尾部输入的,所以如果有小数先输入的试小数点后面的数 
		if (str[n] >= '0' && str[n] <= '9' || str[n] == '.')
		{
			double a = 0;
			int flag = 0;//判断是否含有小数 如果有小数
			//flag=1,a为小数部分,b为整数部分,否则a为整数部分
			int dou = 0;
			while (str[n] >= '0' && str[n] <= '9')
			{
				a = a * 10 + str[n] - '0';
				dou++;
				n--;
			}
			a = reverse((int)a);//刚开始没写reverse 如果字符串是72 读入就是27 错了
			if (str[n] == '.')
			{
				flag = 1;
				n--;
			}
			double b = 0;
			if (flag == 1) {
				while (str[n] >= '0' && str[n] <= '9')
				{
					b = b * 10 + str[n] - '0';
					n--;
				}
				b = reverse((int)b);
			}
			double sum = 0;
			if (flag == 0) sum = a;
			else sum = b + a / pow(10, dou);
			if (str[n] == ' '||n==-1) Push(S, sum);//n==-1这个不能丢 就是只有数字没有正负号和运算符的时候能入栈 丢了的话字符串27入不了栈
			else if (str[n] == '-'||str[n]=='+') {
				if(str[n]=='-') sum = -sum;
				Push(S, sum);
			}
		}
		else if (str[n] == '+' || str[n] == '-' || str[n] == '*' || str[n] == '/')
		{
			if (IsEmpty(S)!=ERROR) Op1 = Pop(S);//前缀从右向左入栈,从左向右出栈
			if (IsEmpty(S)!=ERROR) Op2 = Pop(S);
			double sum = 0;
			switch (str[n])
			{	
			case '+':
				sum = Op1 + Op2;
				Push(S, sum);
				break;
			case '-':
				sum = Op1 - Op2;
				Push(S, sum);
				break;
			case '*':
				sum = Op1 * Op2;
				Push(S, sum);
				break;
			case '/':
				if (Op2 != 0.0)
				{
					sum = Op1 / Op2;
					Push(S,sum);
					break;
				}
				else return ERROR;
			}
		}
	}
	double sum = 0;
	if (!IsEmpty(S))
		sum = Pop(S);
	free(S);
	return sum;
}
double reverse(int n)
{
	double sum = 0;
	while (n)
	{
		sum = sum * 10 + n % 10;
		n = n / 10;
	}
	return sum;
}

在这里插入图片描述
下面这个代码就没问题了:
在计算的那个函数那块修改一下 就是把字符串(倒读)转换成数字这块修改一下

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#define MAXN 100
typedef struct SNode* PtrToSNode;
#define ERROR 1e9
typedef enum{false,true} bool;
struct SNode {
	double data;
	PtrToSNode next;
};
typedef PtrToSNode Stack;
//Stack CreateStack();//创造指向链表的头结点
bool IsEmpty(Stack S);//判断表是否为空
bool Push(Stack S, double X);//入栈
double Pop(Stack S);//出栈
double PostfixExp(Stack S, char* str);//计算 
double reverse(int n);
int main()
{
	Stack S;
	S = (Stack)malloc(sizeof(struct SNode));
	//S= NULL;
	S->next = NULL;
	char str[MAXN];
	double f;//f为计算结果(double型)
	gets(str);
	f = PostfixExp(S, str);
	if (f != ERROR)
		printf("%.1f", f);
	else printf("ERROR");
	return 0;
}
//Stack CreateStack()//创造链表 头节点(只指向链表,并不存储数据) 
//{
//	//创建一个堆栈的头节点,返回该结点指针 
//	Stack S;
//	S = (Stack)malloc(sizeof(struct SNode));
//	S->next = NULL;
//	return S;
//}
bool IsEmpty(Stack S)//判断链表是否为空 
{
	return (S->next == NULL);//如果为空返回true,因为当指针为空 S->next指向为空,就是头指针什么都不指向,否则返回false
}
bool Push(Stack S, double X)//入栈函数  从链表头入栈(头插法)(后入再前) 
{
	PtrToSNode TmpCell;
	TmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
	TmpCell->data = X;//头插法 
	TmpCell->next = S->next;
	S->next = TmpCell;
	return true;
}
double Pop(Stack S)//出栈
{
	PtrToSNode FirstCell;//栈顶元素出栈
	double TopElem;
	if (IsEmpty(S))//判断是否为空链表
	{
		return ERROR;
	}
	else
	{
		FirstCell = S->next;
		TopElem = FirstCell->data;
		S->next = FirstCell->next;//S只是一个头指针,它并不含有值,只是指向链表(栈)的头节点
		//当出栈的时候,就是将头结点右移(S->next指向原本s->next的下一个),最后再将原先的头结点释放
		free(FirstCell);
		return TopElem;//出栈并将出栈元素返回 
	}

}
double PostfixExp(Stack S, char* str)
{
	int n = strlen(str);
	n--;
	double Op1, Op2;
	for (; n >= 0; n--)
	{//因为是从字符串尾部输入的,所以如果有小数先输入的试小数点后面的数 
		if (str[n] >= '0' && str[n] <= '9' || str[n] == '.')
		{
			double a = 0;
			int flag = 0;//判断是否含有小数 如果有小数
			//flag=1,a为小数部分,b为整数部分,否则a为整数部分
			int dou = 0;
			while (str[n] >= '0' && str[n] <= '9')
			{
				a = a + (str[n] - '0') * pow(10, dou);//这块这样写就没问题了
				dou++;
				n--;
			}
			//a = reverse((int)a);
			if (str[n] == '.')
			{
				flag = 1;
				n--;
			}
			double b = 0;
			if (flag == 1) {
				int s = 0;
				while (str[n] >= '0' && str[n] <= '9')
				{
					b = b + (str[n] - '0') * pow(10, s);
					s++;
					n--;
				}
				//b = reverse((int)b);
			}
			double sum = 0;
			if (flag == 0) sum = a;
			else sum = b + a / pow(10, dou);
			if (str[n] == ' ' || n == -1) Push(S, sum);
			else if (str[n] == '-' || str[n] == '+') {
				if (str[n] == '-') sum = -sum;
				Push(S, sum);
			}
		}
		else if (str[n] == '+' || str[n] == '-' || str[n] == '*' || str[n] == '/')
		{
			if (IsEmpty(S) != ERROR) Op1 = Pop(S);//前缀从右向左入栈,从左向右出栈
			//else return ERROR;
			if (IsEmpty(S) != ERROR) Op2 = Pop(S);
			//else return ERROR;
			double sum = 0;
			switch (str[n])
			{
			case '+':
				sum = Op1 + Op2;
				Push(S, sum);
				break;
			case '-':
				sum = Op1 - Op2;
				Push(S, sum);
				break;
			case '*':
				sum = Op1 * Op2;
				Push(S, sum);
				break;
			case '/':
				if (Op2 != 0.0)
				{
					sum = Op1 / Op2;
					Push(S, sum);
					break;
				}
				else return ERROR;
			}
		}
	}
	double sum = 0;
	if (!IsEmpty(S))
		sum = Pop(S);
	free(S);
	return sum;
}
double reverse(int n)
{
	double sum = 0;
	while (n)
	{
		sum = sum * 10 + n % 10;
		n = n / 10;
	}
	return sum;
}

posted on 2021-01-28 12:00  不依法度  阅读(51)  评论(0)    收藏  举报

导航