四则运算表达式求值の各种心碎

实验三---四则运算表达式求值

一、基本要求:


1 ) 利用二叉树后序遍历来实现表达式的转换,同时可以使用实验三的结果来求解后缀表达式的值。


2) 输入输出格式:

输入格式:在字符界面上输入一个中缀表达式,回车表示结束。

请输入表达式:

输入一个中缀表达式

输出格式:如果该中缀表达式正确,那么在字符界面上输出其后缀表达式,其中后

缀表达式中两相邻操作数之间利用空格隔开;如果不正确,在字符界面上输出表达式错误提示。

逆波兰表达式为:

输出逆波兰表达式

运算结果为:输出运算后的结果

测试数据

输入: 21+23*( 12-6)

输出: 21 23 12 6 -*+

二、基本思路

中缀表达式-》二叉树-》后序遍历-》计算

1.中缀表达式-》二叉树の需要考虑的问题:

  • 保存的二叉树是什么样子的,才能使得后序遍历就能得到后缀表达式

操作符的等级设置

最上面的等级最小

设计函数ToTree来实现此过程:该过程递归

递归的判断:

1.怎样按同类更小问题解决:找到当前字符串中的最小等级操作符给data,左边的表达式给左子树,右边的表达式给右子树,左边和右边分别是一个更短的字符串的分支问题

2.各个递归怎么减小问题规模:左边和右边分别是一个更短的字符串的分支问题

3.什么情况可以当做基例:到叶子节点的情况,也就是说表达式里面没有运算符了,然后data=操作数,左右子树=NULL

4.能否最后达到基例:可以要么我写个P啊

  • 怎么找到当前字符串中的最小等级的操作符?

首先先要把各个字符都赋好等级,我把数字也赋值了,最开始没有,还写了个函数提取了所有操作符,后来发现这样很难把等级数组和算式相对应,又推倒重新写了一次,我心在滴血!,如果把数字都负上就可以对上了,查找最小的时候下标是可以返回的,对应了相应的操作符。

	for(i=0;suanshi[i]!='\0';i++)
	{
		if(suanshi[i]=='(')
		{
			duoshaoji++;//记录第几层括号,几层括号就把里面的运算符的等级提高n*100<img alt="惊讶" src="http://static.blog.csdn.net/xheditor/xheditor_emot/default/ohmy.gif" />?它好聪明!
            dengji[i]=0;
			dengji[i]=0;
		}
		else if(suanshi[i]==')')
		{
			duoshaoji--;
			dengji[i]=0;
		}
		else if(suanshi[i]=='+'||suanshi[i]=='-')
			dengji[i]=1+duoshaoji*100;
		else if(suanshi[i]=='*'||suanshi[i]=='/')
			dengji[i]=2+duoshaoji*100;
		else
			dengji[i]=-1;
	}
  • 怎么处理()的问题

因为在树中我们不需要(),所以()肯定不能到树里,但是我们还需要()来辅助判断运算等级,经过分析发现,只要把最开始进函数的表达式两边的括号去掉就行了,这样就对后面的不影响了。

 if(suanshi[0]=='('&&suanshi[length]==')')
	{
		suanshi++;
		suanshi[length-1]='\0';
	}//去括号的过程,只去那种开头是括号结尾是括号的情况
  • 最后的数字和前面的char型不符合,怎么办?

最开始我设的树节点是一个char,后来用了什么ASII的编码把char-》int的变来变去,还是不成,最后只好托马重写,改成了char数组的形式,这样就随之而来一些问题,在之后的后序遍历赋值里会遇到。

  • 这一段是我闹心的心情札记:接着昨天的唠唠叨叨,心碎,今天被猪脚再次挑出个毛病,算起来又是我之前写的逆波兰的程序的错误,我觉得有时间的话我真的应该把逆波兰的程序在写一遍了,我不会说我上节课改逆波兰改了4次吧,算上这回应该有5、6次了吧,心碎,不过也确实怪我自己考虑问题不全,没有想到数字和操作符的数目可能不相符的情况,又让这个猪脚挑出了猫饼,以后我要叫他猫饼猪脚。这么萌的名字一定配的上他用的可爱的少女心的粉色本本~
void ToTree(BiTree &T,char *suanshi)
{
	int duoshaoji=0,i=0,length=suanshilength(suanshi),j=0,min=0,minn=0,k=0;
	char *lsuanshi=NULL,*rsuanshi=NULL,exc=NULL;

    if(suanshi[0]=='('&&suanshi[length]==')')
	{
		suanshi++;
		suanshi[length-1]='\0';
	}//去括号的过程,只去那种开头是括号结尾是括号的情况

	length=suanshilength(suanshi);

	int *dengji;
	dengji=(int *)malloc((length+1)*sizeof(int));
	for(i=0;suanshi[i]!='\0';i++)
	{
		if(suanshi[i]=='(')
		{
			duoshaoji++;
			dengji[i]=0;
		}
		else if(suanshi[i]==')')
		{
			duoshaoji--;
			dengji[i]=0;
		}
		else if(suanshi[i]=='+'||suanshi[i]=='-')
			dengji[i]=1+duoshaoji*100;
		else if(suanshi[i]=='*'||suanshi[i]=='/')
			dengji[i]=2+duoshaoji*100;
		else
			dengji[i]=-1;
	}

	T=(BiTreeNode *)malloc(sizeof(BiTreeNode));
	if(checkfuhao(suanshi))//有符号的情况
	{
		for(j=1;j<length+1;j++)
		{
			if(dengji[j]>0)
			{
				min=dengji[j];
				minn=j;
				break;
			}
		}
		for(j=1;j<length+1;j++)
		{

			if(dengji[j]>0&&min>dengji[j])
			{	

				min=dengji[j];

				minn=j;
			}
		}

		T->data[0]=suanshi[minn];
		T->data[1]='\0';
			//printf("****%c\n",T->data);
		lsuanshi=suanshi;
		lsuanshi[minn]='\0';

		rsuanshi=&suanshi[minn+1];

		ToTree(T->leftChild,lsuanshi);
		ToTree(T->rightChild,rsuanshi);

	}
	else//没有符号的情况
	{

		strcpy(T->data,suanshi);
		T->leftChild=NULL;
		T->rightChild=NULL;
	}

	free(dengji);
}
  • 进行后序遍历时:要注意我们后序遍历输出的同时,主要的操作是把后序遍历的结果给到逆序的字符串里,这个要用到strcat……全都是我的鱼唇的想法,大家有好的思路可以告诉我,我觉得自己做的好蠢
void preorder(BiTree t,char *p)
{
	int k=0,x=0;
	if(t)
	{
		preorder(t->leftChild,p);
        preorder(t->rightChild,p);
		if(t->data[0]=='+'||t->data[0]=='-'||t->data[0]=='/'||t->data[0]=='*')
		{printf("%c ",t->data[0]);
		if(*p!='\0')
		{	strcat(p," ");
			strcat(p,t->data);}
		else
		{
			strcat(p,t->data);}

		}
		else
		{printf("%s ",t->data);
		if(*p!='\0')
		{	strcat(p," ");
			strcat(p,t->data);}
		else
		{
			strcat(p,t->data);}

		}
	}
}
  • 最开始的时候极其鱼唇,居然没有建立树,给树空间,导致后面怎么都不对,后来看了一遍又一遍才知道自己里错了。

其他的是上次的逆波兰~

贴一下所有代码

//

#include "stdafx.h"
#define MAXNUM 100
#define OVERFLOW -2;
#include<iostream>
#include<string>
#include<stdlib.h>
#include<stdio.h>
#include<iomanip>
using namespace std; 

char suan[MAXNUM],*p=suan;

typedef struct node
{
    struct node *leftChild;
    struct node *rightChild;
    char data[15];
}BiTreeNode, *BiTree;

int suanshilength(char *suanshi)
{
	int i=0,k=0;
	for(i=0;suanshi[i]!='\0';i++)
	{
		k++;
	}
	k--;
	return k;
}

bool checkkuohao(char *suanshi)
{
	int i=0,k=0;
	bool flag=1;
	for(i=0;suanshi[i]!='\0';i++)
	{
		if(k<0)
		{flag=0;break;
		}
		if(suanshi[i]=='(')
		k++;
		if(suanshi[i]==')')
			k--;

	}
	if(k!=0)
		flag=0;
	return flag;

} 

bool checkfuhao(char *suanshi)
{
	int i=0;
	bool flag=0;
	for(i=0;suanshi[i]!='\0';i++)
	{
		if(suanshi[i]=='+'||suanshi[i]=='-'||suanshi[i]=='*'||suanshi[i]=='/')
		{
			flag=1;
		}
	}
	return flag;
}

void ToTree(BiTree &T,char *suanshi)
{
	int duoshaoji=0,i=0,length=suanshilength(suanshi),j=0,min=0,minn=0,k=0;
	char *lsuanshi=NULL,*rsuanshi=NULL,exc=NULL;

    if(suanshi[0]=='('&&suanshi[length]==')')
	{
		suanshi++;
		suanshi[length-1]='\0';
	}//去括号的过程,只去那种开头是括号结尾是括号的情况

	length=suanshilength(suanshi);

	int *dengji;
	dengji=(int *)malloc((length+1)*sizeof(int));
	for(i=0;suanshi[i]!='\0';i++)
	{
		if(suanshi[i]=='(')
		{
			duoshaoji++;
			dengji[i]=0;
		}
		else if(suanshi[i]==')')
		{
			duoshaoji--;
			dengji[i]=0;
		}
		else if(suanshi[i]=='+'||suanshi[i]=='-')
			dengji[i]=1+duoshaoji*100;
		else if(suanshi[i]=='*'||suanshi[i]=='/')
			dengji[i]=2+duoshaoji*100;
		else
			dengji[i]=-1;
	}

	T=(BiTreeNode *)malloc(sizeof(BiTreeNode));
	if(checkfuhao(suanshi))//有符号的情况
	{
		for(j=1;j<length+1;j++)
		{
			if(dengji[j]>0)
			{
				min=dengji[j];
				minn=j;
				break;
			}
		}
		for(j=1;j<length+1;j++)
		{

			if(dengji[j]>0&&min>dengji[j])
			{	

				min=dengji[j];

				minn=j;
			}
		}

		T->data[0]=suanshi[minn];
		T->data[1]='\0';
			//printf("****%c\n",T->data);
		lsuanshi=suanshi;
		lsuanshi[minn]='\0';

		rsuanshi=&suanshi[minn+1];

		ToTree(T->leftChild,lsuanshi);
		ToTree(T->rightChild,rsuanshi);

	}
	else//没有符号的情况
	{

		strcpy(T->data,suanshi);

		T->leftChild=NULL;
		T->rightChild=NULL;
	}

	free(dengji);
} 

void preorder(BiTree t,char *p)
{
	int k=0,x=0;
	if(t)
	{
		preorder(t->leftChild,p);
        preorder(t->rightChild,p);
		if(t->data[0]=='+'||t->data[0]=='-'||t->data[0]=='/'||t->data[0]=='*')
		{printf("%c ",t->data[0]);
		if(*p!='\0')
		{	strcat(p," ");
			strcat(p,t->data);}
		else
		{
			strcat(p,t->data);}
		}
		else
		{printf("%s ",t->data);
		if(*p!='\0')
		{	strcat(p," ");
			strcat(p,t->data);}
		else
		{
			strcat(p,t->data);}

		}
	}
}  

typedef struct nibolanstack //建立栈类
{
	double *base;
	double *top;
	int stacksize;
}nibolans;

bool InitStack(nibolans &S){  //创建一个空栈
    S.base=(double *)malloc(50*sizeof(double));
  //  if(!S.base) exit(OVERFLOW);
    S.top=S.base;
    S.stacksize=50;
    return 1;
}  

bool push(nibolans &S,double e)  //插入元素
 {
   if(S.top-S.base>=S.stacksize)
   {
      S.base=(double *)realloc(S.base,(S.stacksize+20)*sizeof(double));
     if(!S.base)
       exit(-2);
     S.top=S.base+S.stacksize;
     S.stacksize=S.stacksize+20;
   }
   *(S.top)=e;
   S.top++;
   return 1;
 }  

bool pop(nibolans &S,double &e)  //出栈
 {
   if(S.top==S.base)
     return 0;
   S.top--;
   e=*S.top;
  return 1;
 }  

void check(char s[],nibolans &S)
{
	char *p=s,q[10];
	int i=0,k=0;
	double m,x,y,z;
//	cout<<s<<endl;
	while(*p!='#')
	{

		if(*p==' ')
		{	

		//	cout<<endl;
			m=atof(q);
		//	cout<<m<<endl;
			if(m!=0)
			push(S,m);

			for(int j=0;j<i;j++)
			{
				q[j]='\0';//char型置空
			}
			i=0;

		}
		else
		{
		//	cout<<*p<<" ";
		//	cout<<(*p=='+');
			if((*p=='+')||(*p=='-')||(*p=='*')||(*p=='/'))
			{
				pop(S,x);

				pop(S,y);

				if(*p=='+')
				{
					z=x+y;
					push(S,z);

				}
				if(*p=='-')
				{
					z=y-x;
					push(S,z);

				}
				if(*p=='*')
				{
					z=x*y;
					push(S,z);

				}
				if(*p=='/')
				{
					z=y/x;
					push(S,y/x);

				}

			}
			else
			{

				q[i]=*p;

				i++;

			}

		}

		p++;

	}
//	return z;

}
bool checkk(char s[])
{
	bool flag=0;
	char *p=s;
	char *q=s;
		while(*q!='\0')
	{
		if((*q=='+')||(*q=='-')||(*q=='*')||(*q=='/'))

	{
		flag=1;
	}
	q++;
	}
	while(*p!='\0')
	{
		if((*p!='0')&&(*p!='1')&&(*p!='2')&&(*p!='3')&&(*p!='4')&&(*p!='5')&&(*p!='6')&&(*p!='7')&&(*p!='8')&&(*p!='9')&&(*p!='+')&&(*p!='-')&&(*p!='*')&&(*p!='/')&&(*p!=' ')&&(*p!='#'))

	{
		flag=0;
	}
	p++;
	}

	return flag;

}

int main(int argc, char* argv[])
{
	char suanshi[MAXNUM];
	double jieguo;
	BiTree BT;
	nibolans S;
	InitStack(S);
	printf("请输入中缀表达式:\n");
	gets(suanshi);
	if(checkkuohao(suanshi))
	{
	ToTree(BT,suanshi);
	preorder(BT,p);
	cout<<endl;

	strcat(suan,"#");
		puts(suan);
	if(checkk(suan))
	{
	check(suan,S);

	pop(S,jieguo);
	cout<<fixed<<setprecision(2)<<jieguo;
	}
	else
		cout<<"表达式错误!"<<endl;
	}
	else
		cout<<"表达式错误!"<<endl;

	return 0;

}

接下来是我几个不太熟悉的函数总结一下:

1.复制字符串

strcpy(T->data,suanshi);

把后面的复制到前面的地方。C语言标准库函数strcpy,把从src地址开始且含有‘\0‘结束符的字符串复制到以dest开始的地址空间

2.字符串后追加字符串

strcat(p,t->data)

把p指向的字符串追加到t-》data后面,两者都得有‘、0’

时间: 2024-10-05 05:31:10

四则运算表达式求值の各种心碎的相关文章

四则运算表达式求值 OpenJ_Bailian - 4132

四则运算表达式求值 OpenJ_Bailian - 4132 题意:设计一个计算器,实现+-*/以及()的表达式运算求值. 栈的应用,这学期学数据结构,手写了栈练一下~ 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=10010; //最大表达式长度 4 5 template <typename T> 6 class Stack; 7 8 template <typename T> 9

数据结构(7)----栈与队列之栈的应用四则运算表达式求值

栈与队列之栈的应用四则运算表达式求值 栈在四则运算表达式求值的应用为逆波兰表达式(后缀表达式) 普通算式(中缀表达式):9 + (3 - 1) * 3 + 10 / 2     ---(1) 逆波兰表达式(后缀表达式):9 3 1 - 3 * + 10 2 /         ---(2) 1:逆波兰表达式的计算规则 从左到右遍历表达式的每个数字和符号,遇到数字就进栈,遇到符号,就将处于栈顶的两个数字出栈,进行运算,再把运算结果进栈,一直到最终获得结果.接下来我们以(2)式为例:

4132:四则运算表达式求值(栈)

总时间限制: 1000ms 内存限制:  65536kB 描述 求一个可以带括号的小学算术四则运算表达式的值 输入 一行,一个四则运算表达式.'*'表示乘法,'/'表示除法 输出 一行,该表达式的值,保留小数点后面两位 样例输入 输入样例1: 3.4 输入样例2: 7+8.3 输入样例3: 3+4.5*(7+2)*(3)*((3+4)*(2+3.5)/(4+5))-34*(7-(2+3)) 样例输出 输出样例1: 3.40 输出样例2: 15.30 输出样例3: 454.75  思路:先把中缀表

【栈的应用】四则运算表达式求值

1. 后缀表达式计算结果 (1) 规则 从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶的两个数字出栈,运算结果进栈,一直到最终获得结果. (2) 示例 后缀表达式:9 3 1 - 3 * + 10 2 / + 初始化一个空栈.此栈用来对要运算的数字进出使用: 后缀表达式中前三个都是数字,所以9.3.1依次进栈: 接下来是"-",所以将栈中的1出栈作为减数,3出栈作为背减数,并运算3-1得到2,再将2进栈: 接着是数字3进栈: 后面是"*&quo

从中序表达式到逆序表达式(逆波兰式)(四则运算表达式求值)

本份代码需要两个栈.一个是符号栈,一个是数字栈. 输入中序表达式如9+(3-1)*3+10/2# #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<math.h> #define max 100 char ex[max]; /*存储后序表达式*/ /*函数功能:将中序表达式转化为后序表达式*/ void trans() { char str[max]; /*表达式字符串*/ char stack[max]; /*运

栈的典型应用-表达式求值【转】

本文转载自:http://www.voidcn.com/blog/lub0807/article/p-1510616.html 栈的一个应用是求四则运算表达式的值,这里的表达式包含数字.加减乘除4种运算符,以及小括号. 由于输入是一个字符串,因此解决这个问题需要以下3个步骤: 1.输入字符串转化为中缀表达式: 2.中缀表达式转化为后缀表达式: 3.后缀表达式求值. 现在表达式为:9 + ( 3 - 1 )* 3 + 10 / 2 ,先看一下运行结果: 首先解释一下中缀表达式和后缀表达式的概念.所

表达式求值 - Java实现

本程序用于计算任意四则运算表达式.如 4 * ( 10 + 2 ) + 1 的结果应该为 49. 算法说明: 1. 首先定义运算符优先级.我们用一个 Map<String, Map<String, String>> 来保存优先级表.这样我们就可以通过下面的方式来计算两个运算符的优先级了: /** * 查表得到op1和op2的优先级 * @param op1 运算符1 * @param op2 运算符2 * @return ">", "<&q

11、蛤蟆的数据结构笔记之十一栈的应用之表达式求值实现

11.蛤蟆的数据结构笔记之十一栈的应用之表达式求值实现 本篇名言:"人生不售来回票,一旦动身,绝不能复返." 继续栈应用实现,这次是来看下表达式求值的栈实现. 欢迎转载,转载请标明出处: 1.  表达式求值 表达式求值是设计语言编译中的一个基本问题,它的实现是栈应用的又一个典型例子. 任何一个表达式都是由操作数(Operand).运算符(operator)和界限符(delimiter)组成. 操作数可以是常数也可以是变量或变量的标识符. 运算符可以分为算术运算符.关系运算符和逻辑运算符

一起talk C栗子吧(第二十一回:C语言实例--表达式求值)

各位看官们,大家好,前几回中咱们说了堆栈的原理,并且举了实际的例子进行解说,这一回咱们说的例 子是:表达式求值.表达式求值和上一回中说的括号匹配一样,都使用了堆栈的原理,大家可以从例子中 看出来,所以我们把它们放在一起.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在这里说的表达式为包含加,减,乘除的四则运算表达式.例如:1+2*3-4/5就是一个四则运 算表达式.这个表达式中,运算符在数字中间,所以我们叫它中缀表达式,这也是符合我们思维的一种表 现形式,不过,计算机就不理解中