四则运算表达式求值(栈+二叉树,c++版)

合集下载

字符串的四则运算

字符串的四则运算

字符串的四则运算四则运算,最常⽤的当然是逆波兰⽅法,现将表达式由中缀表达式转化为后缀表达式,然后再使⽤栈计算即可。

这两步下来,估计没有三四百⾏代码是实现不了的。

中缀表达式转前缀后缀表达式将中缀表达式转换为后缀表达式的算法思想:数字时,加⼊后缀表达式;运算符:a. 若为 '(',⼊栈;b. 若为 ')',则依次把栈中的的运算符加⼊后缀表达式中,直到出现'(',从栈中删除'(' ;c. 若为除括号外的其他运算符,当其优先级⾼于除'('以外的栈顶运算符时,直接⼊栈。

否则从栈顶开始,依次弹出⽐当前处理的运算符优先级⾼和优先级相等的运算符,直到⼀个⽐它优先级低的或者遇到了⼀个左括号为⽌。

⾼优先级可以压迫低优先级!⼈⼯实现转换这⾥我给出⼀个中缀表达式:a+b*c-(d+e)第⼀步:按照运算符的优先级对所有的运算单位加括号:式⼦变成了:((a+(b*c))-(d+e))第⼆步:转换前缀与后缀表达式前缀:把运算符号移动到对应的括号前⾯,则变成了:-( +(a *(bc)) +(de)) ,把括号去掉:-+a*bc+de 前缀式⼦出现。

后缀:把运算符号移动到对应的括号后⾯,则变成了:((a(bc)* )+ (de)+ )- ,把括号去掉:abc*+de+- 后缀式⼦出现。

⽐如:计算(2 + 1) * (13 + 5)转换后得:((2+1)*(13+5)) -> ((2 1) + (13 5) +) * -> 2 1 + 13 5 + *这⾥把后缀表达式存储到vector<string>中,实现栈的计算,如下:int cal(int num1, int num2, string tag){if ("+" == tag){return num1 + num2;}else if ("-" == tag){return num1 - num2;}else if ("*" == tag){return num1*num2;}else{return num1 / num2;}}int evalRPN(vector<string> &tokens) {int result = 0;stack<int> nums;for (int i = 0; i<tokens.size(); i++){string tag = tokens[i];if (tag != "+"&&tag != "-"&&tag != "*"&&tag != "/"){//这是⼀个数字nums.push(atoi(tag.c_str()));}else{//不是⼀个数字int num2 = nums.top();nums.pop();int num1 = nums.top();nums.pop();result = cal(num1, num2, tag);nums.push(result);}}return result=nums.top();}实际中遇到的笔试题是这样的,有字符串表⽰的⼀个四则运算表达式,要求计算出该表达式的正确数值,⽐如:5+17*8-4/2。

四则运算实验报告

四则运算实验报告

实验3四则运算表达式求值背景在工资管理软件中,不可避免的要用到公式的定义及求值等问题。

对于数学表达式的计算,虽然可以直接对表达式进行扫描并按照优先级逐步计算,但也可以将中缀表达式转换为逆波兰表达式,这样更容易处理。

问题描述四则运算表达式求值,将四则运算表达式用中缀表达式,然后转换为后缀表达式,并计算结果。

基本要求使用二叉树来实现。

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

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

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

选作内容(1)在输入输出方式上要求使用:输入:将中缀表达式存于文本文件中,程序从该文本文件中读出表达式。

输出:如果该中缀表达式正确,则将后缀表达式输出到该文件中原表达式的后面,它们之间用“---”后相连;如果不正确,请在输出表达式错误提示到该文件原表达式的后面,它们之间用“---”相连。

(2) 利用堆栈来实现中缀表达式转换为后缀表达式。

测试用例输入:21+23*(12-6)输出:21 23 12 6 -*+程序代码:#include <iostream>#include <string.h>using namespace std;#define SIZE 100#define STACKINCREMENT 10template<class T>//栈class stack{public:void InitStack() {S.base = (T *)malloc(SIZE * sizeof(T));if(!S.base) exit(0);S.top = S.base;S.stacksize = SIZE;}void DestroyStack(){free(S.base);}void ClearStack(){S.top = S.base;}bool StackEmpty(){if(S.top == S.base) return true;else return false;}int StackLength(){return (S.top - S.base);}bool GetTop(T &t){if(S.top != S.base){t = *(S.top - 1);return true;}else return false;}void Push(T t){if(S.top - S.base >= S.stacksize){S.base = (T *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(T));if(!S.base) exit(0);S.top = S.base + S.stacksize;S.stacksize += STACKINCREMENT;}*S.top = t;S.top++ ;}bool Pop(T &t){if(S.top == S.base) return false;else S.top-- ;t = *S.top ;return true;}private:struct SqStack{T *base;T *top;int stacksize;}S;};class BiTree{private:struct BiTreeNode{char OPT[10];BiTreeNode *lchild,*rchild;};BiTreeNode *T; //T是根结点int index; //index是后缀表达式转换二叉树时的索引int number_of_point ;//销毁一颗树void DestroyTree(BiTreeNode *T){if(T){DestroyTree(T->lchild);DestroyTree(T->rchild);free(T);}}void DestroyTree(){DestroyTree(T);}//1表示栈顶优先级高于待入栈的元素int compare(char a,char b){ //定义了任意两个运算符的优先级if(a == '(' && b == ')') return 0;else if((a == '+' && b == '*') || (a == '+' && b == '/') || (a == '-' && b == '*') || (a == '-' && b == '/')|| (a != ')' && b == '(') || (a == '(' && b != ')'))return -1;else return 1;}//递归构造start,end分别是一个式子开始值和结束值的索引/*递归构造中缀表达式转化为的二叉树(利用栈) */void InorderCreate(BiTreeNode *&T,char str[30][10],int start,int end){ if(start == end) { //递归终止if(!(T = (BiTreeNode *)malloc(sizeof(BiTreeNode)))) exit(0);strcpy(T->OPT,str[start]);T->lchild = NULL;T->rchild = NULL;}else{stack<char> opt;stack<int> num;num.InitStack();opt.InitStack();char last;int index;int a;bool jump = false;for(int i = start;i <= end;i++) { //begin求解优先级最小的一个运算符if(jump) break;number_of_point = 0 ;if(IsNumber(str[i][0]) || str[i][0] == '-' &&IsNumber(str[i][1]) )continue;else{char c = str[i][0];char b;if(i == start && c == '(') {start += 1;continue;}else if(opt.StackEmpty() || (opt.GetTop(b) && compare(b,c) == -1)){opt.Push(c);num.Push(i);}else{if(c != ')'){opt.Pop(b);num.Pop(a);if(!opt.StackEmpty()){opt.GetTop(b);if(compare(b,c) == 1){opt.Pop(b);num.Pop(a);opt.Push(c);num.Push(i);}else{opt.Push(c);num.Push(i);}}else{opt.Push(c);num.Push(i);}}else{for(opt.GetTop(b);compare(b,c) != 0;opt.GetTop(b)){opt.Pop(b);num.Pop(a);if(opt.StackEmpty()){opt.Push(b);num.Push(a);end -= 1;jump =true;break;}}if(compare(b,c) == 0) {opt.Pop(b);num.Pop(a);}}}}} //end,得到的是该步中的根结点字符last及其索引indexopt.Pop(last);num.Pop(index);if(!opt.StackEmpty()){opt.Pop(last);num.Pop(index);}opt.DestroyStack();num.DestroyStack();if(!(T = (BiTreeNode *)malloc(sizeof(BiTreeNode)))) exit(0);T->OPT[0] = last;T->OPT[1] = '\0';InorderCreate(T->rchild,str,start,index-1);InorderCreate(T->lchild,str,index+1,end);}}bool IsNumber(char a){ //判断一个字符是否为数值形式的if( a == '.' && number_of_point == 0 ) {number_of_point ++ ;return true;}else if('0' <= a && a <= '9') return true ;else return false;}//递归求解树表示的表达式的值double Operate(BiTreeNode *T){if(T->lchild==NULL && T->rchild==NULL){double num = atof(T->OPT); //调用系统函数atof()将字符串转换为浮点数return num;}double ld,rd;ld = Operate(T->lchild);rd = Operate(T->rchild);char c = T->OPT[0];switch(c){case '+': return ld+rd;break;case '-': return rd-ld;break;case '*': return ld*rd;break;case '/': return rd/ld;break;default:cout << " you have entered wrong data ! "<< endl ;return 0;break ;}}void display(BiTreeNode *T){if(T == NULL ) return ;display(T->rchild);display(T->lchild);cout << T->OPT << " " ;public:BiTree() {T = NULL ;index = 0 ;number_of_point = 0 ;}/*以下两个函数重载私有成员函数方便计算*/void InorderCreate(){char OPT[30][10];cout << "输入中缀表达式: " << endl;char c = getchar();bool flag = true;int i = 0,j = 0 ;while(c != 10) { //输入的是空格j = 0;if(c == '-' && flag == true) { //flag判断是否是一个负数的值OPT[i][j++] = c;for(c = getchar() ; IsNumber(c) ; c = getchar() )OPT[i][j++] = c;OPT[i++][j] = '\0';flag = false;}else if(IsNumber(c)){OPT[i][j++] = c;for(c = getchar();IsNumber(c);c = getchar())OPT[i][j++] = c;OPT[i++][j] = '\0';flag = false;}else //运算符时的处理{flag = true;OPT[i][j++] = c;OPT[i++][j] = '\0';c = getchar();}}InorderCreate(T,OPT,0,i-1);}double Operate(){return Operate(T);}void display(){display(T) ;}~BiTree() {DestroyTree();};int main(){BiTree tree;tree.InorderCreate();cout << endl << tree.Operate() << endl;tree.display() ;cout << endl ;return 0;}测试结果:。

表达式求值(数据结构-栈的应用)

表达式求值(数据结构-栈的应用)

表达式求值(数据结构-栈的应⽤)⼀.问题描述:限制:只含有‘+’,‘-’,‘*’,‘/ ’和圆括号,正整数。

表⽰:字符数组,栈。

中缀表达式:在程序语⾔中,运算符位于两个运算数中间的表达式称为中缀表达式,例如 1+2*3.中缀表达式运算规则:先乘除,后加减,从左到右,先括号内,后括号外,因此中缀表达式不仅要判断运算符的优先级,⽽且还有处理括号。

后缀表达式:运算符在运算数的后⾯,如1+2*3的后缀表达式:1 2 3*,在后缀表达式中已经考虑了运算符的优先级,没有括号,只有运算数和运算符。

后缀表达式的运算:按照运算符的次序进⾏的。

例如123*+,从左到右扫描时,第⼀个运算符为*,先执⾏2*3=6,第⼆个运算符为‘+’,执⾏1+6=7。

⼆ .表达式求值的过程:将算术表达式转换成后缀表达式,然后对后缀表达式求值。

1.将算术表达式转换为后缀表达式。

(1)从左到右⼀次扫描中缀表达式的每⼀个字符,如果是字符串,直接写⼊后缀表达式。

(2)如果遇到的是' ( ',则压⼊操作符栈,遇到‘(’时,将栈中的元素放到后缀表达式中,直达栈顶元素为'('时,将栈顶元素'('删除,不需要⼊栈。

(3)如果遇到的是操作符,则将操作符和操作符栈顶元素⽐较。

:如果a[i]的运算符的优先级⼩于等于栈顶元素的优先级,退栈运算符并放到后缀表达式中,直到a[i]的运算符优先级⼤于栈顶运算符的优先级:否则⼊栈。

(4)重复上述步骤,知道中缀表达式的结束符标记“#”,转换结束。

我的代码:#include<bits/stdc++.h>using namespace std;stack<char>f;//操作符栈stack<double>s;//操作数栈bool flag;int prior(char ch)//运算符的优先级{switch(ch){case'+':case'-':return 1;case'*':case'%':case'/':return 2;default:return 0;//括号}}string trans(string a){while(!f.empty()) f.pop();f.push('#');string ret="";//保存中缀表达式int len=a.size(),i=0;while(i<len){if(a[i]==' '||a[i]=='=')//??{i++;continue;}else if(a[i]=='(')f.push(a[i++]);else if(a[i]==')'){while(f.top()!='('){ret+=f.top();ret+=' ';f.pop();}f.pop();//(出栈i++;}else if(a[i]=='+'||a[i]=='-'||a[i]=='*'||a[i]=='/'||a[i]=='%'){while(prior(f.top())>=prior(a[i]))//如果a[]的运算符的优先级⼩于等于栈顶元素的优先级,退栈运算符并放到后缀表达式中,直到a[i]的运算符优先级⼤于栈顶运算符的优先级ret+=f.top();ret+=' ';f.pop();}f.push(a[i++]);}else{while((a[i]>='0'&&a[i]<='9')||a[i]=='.'){ret+=a[i++];}ret+=' ';}}while(f.top()!='#'){ret+=f.top();ret+=' ';f.pop();}ret+='=';return ret;}double cal(double a,double b,double ch)//计算{if(ch=='+') return a+b;if(ch=='-') return a-b;if(ch=='*') return a*b;if(ch=='%') return ((int)a%(int)b);if(ch=='/'){if(b!=0)return a/b;flag=true;return 0;}}double solve(string a)//后缀表达式计算{string t=trans(a);while(!s.empty()) s.pop();flag=false;int len=t.length(),i=0;while(i<len){if(t[i]==' '||t[i]=='='){i++;continue;}else if(t[i]=='+'||t[i]=='-'||t[i]=='*'||t[i]=='/'||t[i]=='%') {double num1,num2;num1=s.top();s.pop();num2=s.top();s.pop();s.push(cal(num1,num2,t[i]));i++;}else{double x=0;while(t[i]>='0'&&t[i]<='9'){x=x*10+t[i]-'0';i++;}if(t[i]=='.'){double k=10.0,y=0;i++;while(t[i]>='0'&&t[i]<='9'){y+=((t[i]-'0')/k);i++;k*=10;;}x+=y;}s.push(x);}}return s.top();}int main(){int num;scanf("%d",&num);while(num--){cin>>a;// cout<<e.trans(a)<<endl;//将中缀表达式装换为后缀表达式 cout<<solve(a)<<endl;}return 0;}。

中缀表达式转后缀表达式---栈--二叉树---四则运算

中缀表达式转后缀表达式---栈--二叉树---四则运算

中缀表达式转后缀表达式---栈--⼆叉树---四则运算 我们平常书写的四则运算表达式属于中缀表达式,形式为"9+(3-1)*3+10/2",因为所有的运算符号都在两操作数之间,所以称为中缀表达式。

我们使⽤中缀表达式来计算表达式的值,不过这种形式并不适合计算机求解。

接下来,我们将中缀表达式转化为后缀表达式,所谓的后缀表达式就是操作符位于操作数后⾯的不包含括号的算数表达式,也叫做逆波兰表达式。

1)⾸先介绍⼀种⼈⼯的转化⽅法()。

以"9+(3-1)*3+10/2"为例,按照运算的规则,找出⾸先计算的部分,这部分包含两个操作数和⼀个操作符,将操作符移动到两个操作数右侧,这就完成了第⼀部分的转换,将这部分看作⼀个操作数,按照运算规则,以相同的⽅法转换,转换过程如下:2)还可以利⽤⼆叉树求得后缀表达式,⾸先利⽤中缀表达式构造⼆叉树,数字是叶⼦节点,操作符为根节点。

每次找到“最后计算”的运算符,作为当前根节点,运算符左侧表达式作为左节点,右侧表达式作为右节点,然后递归处理()。

9+(3-1)*3+10/2对应的⼆叉树的构造过程如下图所⽰: 此⼆叉树做后序遍历就得到了后缀表达式。

对应代码:3)还可以利⽤栈来实现中缀表达式转化为后缀表达式。

转化⽅法如下所述:a.从左向右扫描表达式,如果是数字就输出,否则转b。

b.如果当前扫描的字符是")",则栈顶元素出栈并输出⼀直到栈顶元素为"(",然后删除栈顶元素"(",并不输出。

c.如果扫描的字符或者栈顶元素是“(”,扫描的字符直接⼊栈。

即使扫描的字符是")"也不会⼊栈,因为如果是")",会出栈⾄栈顶元素是"("。

d.如果扫描字符是"+"或者"-",则⼀直出栈⾄栈顶元素为"+"或者"-"或者"("。

数据结构——四则运算

数据结构——四则运算

数据结构——四则运算要进⾏⼀个表达式的计算,⼀个关键的就是括号匹配问题,现在使⽤栈进⾏实现计算表达式的值,可以作为实现⼀个简单四则运算计算器核⼼部分。

根据栈的特性(先进后出),所以决定通过把输⼊的表达式转换为后缀表达式,通过后缀表达式进⾏计算。

实现⽅法:1.⾸先定义两个栈,⼀个⽤于存放操作符,⼀个⽤于存放操作数。

1 #include<stdio.h>2 #include<string>3 #include<conio.h>4#define MAXSIZE 1005 typedef float datatype;67 typedef struct8 {9 datatype a[MAXSIZE];10int top;11 }sequence_stack;1213 typedef struct14 {15char b[MAXSIZE];16int top;17 }SeqStack;2.需要两个数组,⼀个⽤于存放输⼊的中缀表达式,⼀个⽤于存放将中缀表达式转换后的后缀表达式。

将中缀表达式转换为后缀表达式的主要代码:1int operation(char op)//判断是否为操作符2 {3switch(op)4 {5case'+':6case'-':7case'*':8case'/':return1;9default:return0;10 }11 }12int priority(char op)//判断操作符的优先级13 {14switch(op)15 {16case'#':return -1;17case'(':return0;18case'+':19case'-':return1;20case'*':21case'/':return2;22default: return -1;23 }24 }25//将中缀表达式转换为后缀表达式26void postfix(char e[],char f[],SeqStack *s,sequence_stack *s1)27 {28int i=0,j=0;29int t;30 push_SeqStack(s,'#');31while(e[i]!='#')32 {33if((e[i]>='0'&&e[i]<='9')||e[i]=='.')34 f[j++]=e[i];35else if(e[i]=='(')36 {37 push_SeqStack(s,e[i]);38 }39else if(e[i]==')')40 {41 t=s->top-1;42while(s->b[t]!='(')43 {44 f[j++]=s->b[--s->top];45 t=s->top-1;46 }47 s->top--;48 }49else if(operation(e[i]))50 {51 f[j++]=' ';52while(priority(s->b[s->top-1])>=priority(e[i]))53 f[j++]=s->b[--s->top];54 push_SeqStack(s,e[i]);55 }56 i++;57 }58while (s->top)f[j++]=s->b[--s->top];59 {}60 evalpost(f,s1);61 }3.把存放后缀表达式的数组传递给计算后表达式的函数;计算后缀表达式的值主要代码:1float readnumber(char f[],int *i)//将数字字符串转变为数2 {3float x=0.0;4int k=0;5while(f[*i]>='0'&&f[*i]<='9')6 {7 x=x*10+(f[*i]-'0');8 (*i)++;9 }10if(f[*i]=='.')11 {12 (*i)++;13while(f[*i]>='0'&&f[*i]<='9')14 {15 x=x*10+(f[*i]-'0');16 (*i)++;17 k++;18 }19 }20while(k!=0)21 {22 x=x/10.0;23 k=k-1;24 }25return (x);26 }27void evalpost(char f[],sequence_stack *s)28 {29int i=0;30float x1,x2;31while(f[i]!='#')32 {33if(f[i]>='0'&&f[i]<='9')34 {35 push_sequence_stack(s,readnumber(f,&i));36 }37else if(f[i]==' ')38 i++;39else if(f[i]=='+')40 {41 x2=s->a[--s->top];42 x1=s->a[--s->top];43 push_sequence_stack(s,x1+x2);44 i++;45 }46else if(f[i]=='-')47 {48 x2=s->a[--s->top];49 x1=s->a[--s->top];50 push_sequence_stack(s,x1-x2);51 i++;52 }53else if(f[i]=='*')54 {55 x2=s->a[--s->top];56 x1=s->a[--s->top];57 push_sequence_stack(s,x1*x2);58 i++;59 }60else if(f[i]=='/')61 {62 x2=s->a[--s->top];63 x1=s->a[--s->top];64 push_sequence_stack(s,x1/x2);65 i++;66 }67 }68 }最后,只要调⽤计算后的结果将存放在操作数栈的第⼀个位置,并将结果传递给需要显⽰的地⽅(可以放到⾃⼰的程序中显⽰结果的地⽅),显⽰出结果就没问题了。

四则运算二叉树版_[文档在线提供]

四则运算二叉树版_[文档在线提供]

数据结构课程设计报告设计题目:十进制四则运算计算器年级班级姓名学号指导教师起止时间2009.5.18-2009.5.212009 年二学期实习目的通过实习,了解并初步掌握设计、实现较大系统的完整过程,包括系统分析、编码设计、系统集成、以及调试分析,熟练掌握数据结构的选择、设计、实现以及操作方法,为进一步的应用开发打好基础。

二.问题描述在以二叉树表示算术表达式的基础上,设计一个十进制的四则运算的计算器。

[设计要求]实现整数浮点数的四则运算。

三.需求分析该程序实现的是实数型的四则运算,并在此运算上又加入了幂”^”运算,该程序用一二叉树表示整个输入的算术表达式:(1)实现对结点的打印,便于结果分析;(2)实现对结点的统计;(3)实现中间结果的显示,可以看打印的结点,验证运算结果的正确与否。

四.概要设计系统用到的抽象数据类型定义:1.ADT node_type{数据对象V:一个集合,该集合中的所有元素具有相同的特性数据关系R:R={VR}VR={<x,y>|P(x,y)^(x,y属于V)}基本操作:(1)node_type(string k);操作结果:对结点进行初始化}ADT node_type2.ADT binary_tree{数据对象D:一个集合,该集合中的所有元素具有相同的特性数据关系R:若D为空,则为空树。

若D中仅含有一个数据元素,则R为空集,否则R={H},H为如下二元关系:(1)在D中存在唯一的称为根的数据元素root,它在关系H中没有前驱(2)除root以外,D中每个结点在关系H下有且仅有一个前驱。

基本操作:(1)print(node_type *r)CopyTimeTree(p,q);操作结果:对结点进行打印(2)evaluate(node_type *prt);操作结果:对一二叉树进行计算(3)counter();操作结果:计算一棵二叉树中的结点个数}ADT binary_tree系统中子程序及功能要求:1.ADT node_type build_node(string x):建立一个结点2.addition(char OperatorA,char OperatorB):判断两操作符是否相等,若相等返回True3.TakesPrecedence(char OperatorA,char OperatorB):判别符号的优先级。

C++四则运算表达式求值算法

C++四则运算表达式求值算法
的字符串。
u 这里定义了两个构造函数,不带参数的默认 m_string 为空,带 string 类型
参数的将参数值赋予成员变量 m_string,此外还定义了赋值运算符“=”,
目 的是将一个表达式字符串 赋予 成员变量 m_string 。 因此 生 成一个 ExpressionType 的对象可以有如下两种形式: ExpressionType expr(“(2.99-4.32)*(90.8-78.66)+78.0/3.14”); 或者 ExpressionType expr; Expr = “(2.99-4.32)*(90.8-78.66)+78.0/3.14”; u DivideExpressionToItem(): 私有成员函数,返回值是一个 string 类型的 队列。其功能是将原始的中缀表达式中的操作数、操作符以及括号按顺序以 字符串的形式分解出来,然后保存在一个队列中(队列的操作规则是先进先 出)。 u ChangeToSuffix(): 私有成员函数,返回值是一个 string 类型的栈。其功 能是将队列中表示原始表达式各项的字符串调整顺序,转换成后缀表达式的 顺序,并处理掉括号,然后保存在一个栈中(栈的操作规则是先进后出)。 u IsWellForm():私有成员函数,返回 bool 值。其功能是判断原始表达式中的 括号是否匹配,如果匹配返回 true,否则返回 false。 u Size():返回原始表达式所包含的字节数。 u Calculate(): 公有成员函数,返回 double 类型的值。其功能是计算转换后 的后缀表达式的值,即原始中缀表达式的值。
abc然后分别按从左到右放入栈中如果碰到操作符就从栈中弹出两个操作数进行运算最后再将运算结果放入栈中依次进行直到表达式放入栈中然后碰到操作符则从栈中弹出的运算并将其结果d假设为放入栈中最后是操作符所以再弹出进行dc运算并将其结果再次放入栈中此时表达式结束则栈中的元素值就是该表达式最后的运算结果

数据结构习题及答案

数据结构习题及答案

习题一1. 简述下列术语:数据、数据元素、数据对象、数据结构、逻辑结构、存储结构、基本运算、运算实现和数据类型。

2. 设有数据结构(D, R),其中D={d1,d2,d3,d4},R={r},r={ (d1, d2 ) , (d2, d3 ) , (d3, d4 ) }. 试按图论中图的画法惯例画出其逻辑结构图。

3. 函数f(M,n)按下式定义(m,n为≥0的整数):f (m,n)=﹛m+n+1 当m*n=0时f(m-1,(m,n-1))当 m*n≠0 时(1)试写出计算该函数的递归过程;(2)写出递归过程转换成非递归过程的转换规则。

4. 把数组 A[1…n]按递减顺序排序,并分析其最坏情况时间复杂性量级。

5. 为了用计算机实现学生档案管理, 需要经过哪些主要步骤?每个步骤的主要工作是什么?试用本章讲到的从“具体到抽象”、再“从抽象到具体”的观点加以分析。

6. 试设定若干n值,比较两函数n2和50nlog2n的增长趋势,并确定n在什么范围内,函数n2值大于50nlog2n 的值。

习题二1.设线性表存于a(1:n)的前elenum个分量中,且递增有序。

试写一算法,将X 插入到线性表的适当位置上,以保持线性表的有序性。

2.写一个逆置线性表的算法。

即由A[1:n]产生B[1:n],使得B[1]=A[n],B[2]=A[n-1] , … B[n]=A[1]。

要求用最少的附加空间。

3.设有编号为 1,2,3,4 的四辆列车,顺序进入一个栈式结构的站台,试写出这四辆列车开出车站的所有可能顺序。

4. 设有六辆火车编号为1,2,3,4,5,6 利用栈,将它们重新编成3,2,5,6,4,1的顺序。

请写出操作序列,设X 表示将一列火车从栈中开出;S 表示将一列火车从输入端开入栈中。

5.假设栈中每个数据项占K 个空间位置,试改写入栈和出栈的算法。

6. 假设有两个栈如图所示共享空间 [1..m]。

试写一个对任一栈作入栈 push(s,x ,i )和出栈pop (s,i )。

数据结构课程设计四则运算表达式求值(C语言版)

数据结构课程设计四则运算表达式求值(C语言版)

数据结构课程设计四则运算表达式求值(C语⾔版) 明⼈不说暗话,直接上,输⼊提取码z3fy即可下载。

⽂件中包含程序,程序运⾏⽂件,设计报告和测试样例,应有尽有,欢迎⼩伙伴们在中下载使⽤。

本课程设计为四则运算表达式求值,⽤于带⼩括号的⼀定范围内正负数的四则运算标准(中缀)表达式的求值。

注意事项:1、请保证输⼊的四则表达式的合法性。

输⼊的中缀表达式中只能含有英⽂符号“+”、“-”、“*”、“/”、“(”、“)”、“=”、数字“0”到“9”以及⼩数点“.”,输⼊“=”表⽰输⼊结束。

例如9+(3-1)*3.567+10/2=,特别是请勿输⼊多余空格和中⽂左右括号。

2、输⼊的中缀表达式默认限定长度是1001,可根据具体情况调整字符串数组的长度。

3、请保证输⼊的操作数在double数据类型范围内,单个数字有效数字长度不可超过15位。

本课程设计中操作数是C语⾔中的双精度浮点数类型。

4、本课程设计中的运算数可以是负数,另外如果是正数可直接省略“+”号(也可带“+”号)。

 下⾯的程序正常运⾏需要在上⾯的百度⽹盘中下载相应⽂件,否则⽆法正常使⽤哦。

1/*本程序为四则运算表达式求值系统,⽤于计算带⼩括号的四则运算表达式求值。

2具体算法:3先将字符串处理成操作单元(操作数或操作符),再利⽤栈根据四则运算4的运算法则进⾏计算,最后得出结果。

*/56 #include<stdio.h>7 #include<ctype.h>8 #include<stdlib.h>9 #include<string.h>10 #include<stdlib.h>11 #include<ctype.h>1213const int Expmax_length = 1001;//表达式最⼤长度,可根据适当情况调整14struct Ope_unit15 {//定义操作单元16int flag;//=1表⽰是操作数 =0表⽰是操作符 -1表⽰符号单元17char oper;//操作符18double real;//操作数,为双精度浮点数19 };2021void Display();//菜单22void Instru(); //使⽤说明23int Check(char Exp_arry[]);24void Evalua(); //先调⽤Conver操作单元化,再调⽤Calculate函数计算结果并输出25int Conver(struct Ope_unit Opeunit_arry[],char Exp_arry[]);//将字符串处理成操作单元26int Isoper(char ch);//判断合法字符(+ - * / ( ) =)27int Ope_Compar(char ope1,char ope2);//操作符运算优先级⽐较28double Calculate(struct Ope_unit Opeunit_arry[],int Opeunit_count,int &flag);//⽤栈计算表达式结果29double Four_arithm(double x,double y,char oper);//四则运算3031int main()32 {33int select;34while(1)35 {36 Display();37 printf("请输⼊欲执⾏功能对应的数字:");38 scanf("%d",&select);39 printf("\n");40switch(select)41 {42case1: Evalua(); break;43case2: Instru(); break;44case0: return0;45default : printf("⽆该数字对应的功能,请重新输⼊\n");46 system("pause");47 }48 }49return0;50 }5152int Check(char Exp_arry[])53 {//检查是否有⾮法字符,返回1表⽰不合法,0表⽰合法54int Explength=strlen(Exp_arry),i;55for(i=0;i<Explength;i++)56 {57if(!Isoper(Exp_arry[i]) && Exp_arry[i] != '.' && !isdigit(Exp_arry[i]))58return1;59if(isdigit(Exp_arry[i]))60 {61int Dig_number=0,Cur_positoin=i+1;62while(isdigit(Exp_arry[Cur_positoin]) || Exp_arry[Cur_positoin]=='.')63 {64 Dig_number++;65 Cur_positoin++;66 }67if(Dig_number >= 16)//最多能够计算15位有效数字68return1;69 }70 }71return0;72 }7374void Evalua()75 {//先调⽤Conver函数将字符串操作单元化,再调⽤Calculate函数计算结果并输出76char Exp_arry[Expmax_length];77int flag=0;//假设刚开始不合法,1表达式合法,0不合法78struct Ope_unit Opeunit_arry[Expmax_length];7980 getchar();//吃掉⼀个换⾏符81 printf("请输⼊四则运算表达式,以=结尾:\n");82 gets(Exp_arry);83 flag=Check(Exp_arry);84if(flag)85 printf("该表达式不合法!\n");86else87 {88int Opeunit_count = Conver(Opeunit_arry,Exp_arry);89double ans = Calculate(Opeunit_arry,Opeunit_count,flag);90if(flag)91 {92 printf("计算结果为:\n");93 printf("%s%lf\n",Exp_arry,ans);94 }95else96 printf("该表达式不合法!\n");97 }98 system("pause");99 }100101int Conver(struct Ope_unit Opeunit_arry[],char Exp_arry[])102 {//将字符串操作单元化103int Explength=strlen(Exp_arry);104int i,Opeunit_count=0;105for(i=0;i<Explength;i++)106 {107if(Isoper(Exp_arry[i]))//是操作符108 {109 Opeunit_arry[Opeunit_count].flag=0;110 Opeunit_arry[Opeunit_count++].oper=Exp_arry[i];111 }112else//是操作数113 {114 Opeunit_arry[Opeunit_count].flag=1;115char temp[Expmax_length];116int k=0;117for(; isdigit(Exp_arry[i]) || Exp_arry[i]=='.' ;i++)118 {119 temp[k++]=Exp_arry[i];120 }121 i--;122 temp[k]='\0';123 Opeunit_arry[Opeunit_count].real=atof(temp);//将字符转化为浮点数124125//负数126if(Opeunit_count == 1 && Opeunit_arry[Opeunit_count-1].flag==0127 && Opeunit_arry[Opeunit_count-1].oper=='-')128 {129 Opeunit_arry[Opeunit_count-1].flag = -1;130 Opeunit_arry[Opeunit_count].real *= -1;131 }// -9132if(Opeunit_count >= 2 && Opeunit_arry[Opeunit_count-1].flag==0133 && Opeunit_arry[Opeunit_count-1].oper=='-' && Opeunit_arry[Opeunit_count-2].flag==0 134 && Opeunit_arry[Opeunit_count-2].oper !=')')135 {136 Opeunit_arry[Opeunit_count-1].flag = -1;137 Opeunit_arry[Opeunit_count].real *= -1;138 }// )-9139140//正数141if(Opeunit_count == 1 && Opeunit_arry[Opeunit_count-1].flag==0142 && Opeunit_arry[Opeunit_count-1].oper=='+')143 {144 Opeunit_arry[Opeunit_count-1].flag = -1;145 }// +9146if(Opeunit_count >= 2 && Opeunit_arry[Opeunit_count-1].flag==0147 && Opeunit_arry[Opeunit_count-1].oper=='+' && Opeunit_arry[Opeunit_count-2].flag==0148 && Opeunit_arry[Opeunit_count-2].oper !=')')149 {150 Opeunit_arry[Opeunit_count-1].flag = -1;151 }// )+9152 Opeunit_count++;153 }154 }155/*for(i=0;i<Opeunit_count;i++)156 {//查看各操作单元是否正确,1是操作数,0是操作符157 if(Opeunit_arry[i].flag == 1)158 printf("该单元是操作数为:%lf\n",Opeunit_arry[i].real);159 else if(Opeunit_arry[i].flag == 0)160 printf("该单元是操作符为:%c\n",Opeunit_arry[i].oper);161 else162 printf("该单元是负号符为:%c\n",Opeunit_arry[i].oper);163 }*/164return Opeunit_count;165 }166167double Calculate(struct Ope_unit Opeunit_arry[],int Opeunit_count,int &flag)168 {//根据运算规则,利⽤栈进⾏计算169int i,dS_pointer=0,oS_pointer=0;//dS_pointer为操作数栈顶指⽰器,oS_pointer为操作符栈顶指⽰器170double Dig_stack[Expmax_length];//操作数栈(顺序存储结构)171char Ope_stack[Expmax_length];//操作符栈172173for(i=0;i<Opeunit_count-1;i++)174 {175if( Opeunit_arry[i].flag != -1 )176 {177if(Opeunit_arry[i].flag)//是操作数178 {179 Dig_stack[dS_pointer++]=Opeunit_arry[i].real;//⼊操作数栈180//printf("%lf\n",Digit[dS_pointer-1]);181 }182else//是操作符 + - * / ( )183 {184//操作符栈为空或者左括号⼊栈185if(oS_pointer==0 || Opeunit_arry[i].oper=='(')186 {187 Ope_stack[oS_pointer++]=Opeunit_arry[i].oper;188//printf("%oS_pointer\Ope_u_count",Operator[oS_pointer-1]);189 }190else191 {192if(Opeunit_arry[i].oper==')')//是右括号将运算符⼀直出栈,直到遇见左括号193 {194 oS_pointer--;//指向栈顶195 dS_pointer--;//指向栈顶196while(Ope_stack[oS_pointer] != '(' && oS_pointer != 0)197 {198 Dig_stack[dS_pointer-1] = Four_arithm(Dig_stack[dS_pointer-1],Dig_stack[dS_pointer], 199 Ope_stack[oS_pointer--]);//oS_pointer--为操作符出栈200201 dS_pointer--;//前⼀个操作数出栈202//printf("操作数栈顶元素等于%lf\n",Digit[dS_pointer]);203 }204 oS_pointer--;//左括号出栈205206 oS_pointer++;//恢复指向栈顶之上207 dS_pointer++;208 }209else if(Ope_Compar(Opeunit_arry[i].oper,Ope_stack[oS_pointer-1]))//和栈顶元素⽐较210 {211 Ope_stack[oS_pointer++]=Opeunit_arry[i].oper;212//printf("%oS_pointer\Ope_u_count",Operator[oS_pointer-1]);213 }214else//运算符出栈,再将该操作符⼊栈215 {216 oS_pointer--;//指向栈顶217 dS_pointer--;//指向栈顶218while(Ope_Compar(Opeunit_arry[i].oper,Ope_stack[oS_pointer])==0 && oS_pointer != -1) 219 {//当前操作符⽐栈顶操作符优先级⾼220 Dig_stack[dS_pointer-1]=Four_arithm(Dig_stack[dS_pointer-1],Dig_stack[dS_pointer], 221 Ope_stack[oS_pointer--]);222 dS_pointer--;223//printf("操作数栈顶元素等于%lf\n",Digit[dS_pointer]);224 }225 oS_pointer++;//恢复指向栈顶之上226 dS_pointer++;227 Ope_stack[oS_pointer++]=Opeunit_arry[i].oper;228 }229 }230 }231 }232 }233/*for(i=0;i<oS_pointer;i++)234 printf("操作符栈%oS_pointer\Ope_u_count",Operator[i]);235 for(i=0;i<dS_pointer;i++)236 printf("操作数栈%lf\n",Digit[i]);*/237 oS_pointer--;//指向栈顶元素238 dS_pointer--;//指向栈顶元素239while(oS_pointer != -1)240 {241 Dig_stack[dS_pointer-1]=Four_arithm(Dig_stack[dS_pointer-1],Dig_stack[dS_pointer], 242 Ope_stack[oS_pointer--]);//oS_pointer--为操作符出栈243 dS_pointer--;//前⼀个操作数出栈244//printf("操作数栈顶元素为%lf\Ope_u_count",Digit[dS_pointer]);245 }246//printf("%dS_pointer,%dS_pointer\n",oS_pointer,dS_pointer);247if(oS_pointer==-1 && dS_pointer==0)248 flag=1;//为1表⽰表达式合法249return Dig_stack[0];250 }251252int Ope_Compar(char ope1,char ope2)253 {//操作符运算优先级⽐较254char list[]={"(+-*/"};255int map[5][5]={//先⾏后列,⾏⽐列的运算级优先级低为0,⾼为1256// ( + - * /257/* ( */1,0,0,0,0,258/* + */1,0,0,0,0,259/* - */1,0,0,0,0,260/* * */1,1,1,0,0,261/* / */1,1,1,0,0 };262int i,j;263for(i=0;i<5;i++)264if(ope1==list[i]) break;265for(j=0;j<5;j++)266if(ope2==list[j]) break;267return map[i][j];268 }269270double Four_arithm(double x,double y,char oper)271 {//四则运算272switch(oper)//保证不含其它运算符273 {274case'+': return x+y;275case'-': return x-y;276case'*': return x*y;277case'/': return x/y;//y不能为0278default : return0;279 }280 }281282int Isoper(char ch)283 {//判断合法字符 + - * / ( ) =284if(ch=='+' || ch=='-' || ch=='*' || ch=='/' || ch=='(' || ch==')' || ch=='=')285return1;286return0;287 }288289void Display()290 {//打印菜单291 system("cls");292 printf("/******************************************************************************/\n");293 printf("\t\t 欢迎使⽤本四则运算表达式求值系统\n");294 printf("\n\t说明:建议请您先阅读使⽤说明,再输⼊相应的数字进⾏操作,谢谢配合!\n"); 295 printf("\n\t\t1 四则运算表达式求值\n");296 printf("\n\t\t2 使⽤说明\n");297 printf("\n\t\t0 退出\n");298 printf("/******************************************************************************/\n");299 }300301void Instru()302 {//打印使⽤说明303 FILE *fp;304char ch;305if( ( fp=fopen("使⽤说明.txt","r") ) == NULL)306 {307 printf("⽂件打开失败!\n");308 exit(0);309 }310for(; (ch = fgetc(fp)) != EOF; )311 putchar(ch);312 fclose(fp);313 printf("\n");314 system("pause");315 }。

四则运算解析及计算

四则运算解析及计算

四则运算解析及计算四则运算是中缀表达式,需要将其转化为后缀表达式。

原因是计算中缀表达式很困难。

明确运算符的优先级:优先级(数字越⼤,优先级越⾼)运算符2+-1*/0()格式化四则表达式输⼊的表达式可能出现⽆⽤的字符,需要去除否则影响下⾯的判断逻辑。

处理⽅法为,遍历整个字符串,删除换⾏、空格和制表符。

后缀表达式转化中缀表达式转化为后缀表达式的基本步骤如下:1.初始化⼀个运算符栈。

2.从输⼊的表达式的字符串中依次从左向右每次读取⼀个字符。

3.如果当前读取的字符是操作数,则直接填写到后缀表达式中 (如果后缀表达式末尾已经有操作数,需要使⽤逗号分隔开)。

4.如果当前字符是“(”左括号,将其压⼊运算符栈。

5.如果当前字符为运算符,则分三种情况:(1)当前运算符栈为空,将其压⼊运算符栈。

(2)当前运算符的优先级⼤于栈顶元素,则将此运算符压⼊运算符栈;否则,弹出栈顶的运算符到后缀表达式,反复弹出,直到该运算符优先级⼤于栈顶元素或者栈为空时,然后将当前运算符压栈。

回到步骤2继续读取。

(3)如果上⼀次读到的也是运算符,则中缀表达式错误直接返回6.如果当前字符是“)”右括号,反复将栈顶元素弹出到后缀表达式,直到栈顶元素是左括号“(”为⽌,并将左括号从栈中弹出丢弃。

如果找不到“(”则中缀表达式错误直接返回7.如果读取还未完成,回到步骤2.8.如果读取完成,则将栈中剩余的运算符依次弹出到后缀表达式。

※如果表达式中出现负数或者⼩数,需对负数和⼩数点采取特殊处理:(1)如果是负数,需要把“-”⼀起存放到后缀表达式中同时还要添加⼀个特殊字符“!”⽤于标记负数。

两种情况下出现“-”可判定为负数。

A.“-”为⾸字符且下⼀个字符为数字;B.“-”为⾮⾸字符且位于“(”之后且后⼀个字符为数字;(2)如果有⼩数,需要记录⼩数点的位数举例:输⼊的四则表达式是 -15. *((-5+.6)*87-(-4.592+3.33)*8)处理后的后缀表达式为:!-15.,!-5,.6,+87,*!-4.592,3.33,+8,*-*后缀表达式求值:从左到右读取1、设置⼀个栈,开始时,栈为空;2、然后从左到右读取后缀表达式,若遇操作数,则进栈;3、若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕;4、最后,栈中仅有⼀个元素,即为运算的结果。

栈的应用——表达式求值

栈的应用——表达式求值

栈的应⽤——表达式求值 表达式求值是程序设计语⾔编译中的⼀个基本问题,它的实现就是对“栈”的典型应⽤。

本⽂针对表达式求值使⽤的是最简单直观的算法“算符优先法”。

本⽂给出两种⽅式来实现表达式求值,⽅式⼀直接利⽤中缀表达式求值,需要⽤到两个栈,操作数栈和操作符栈。

⾸先置操作数栈为空栈,操作符栈仅有“#”⼀个元素。

依次读⼊表达式中的每个字符,若是操作数则进操作数栈,若是操作符则和操作符栈的栈顶运算符⽐较优先权作相应操作,直⾄整个表达式求值完毕。

⽅式⼆⾸先把中缀表达式转换为后缀表达式并存储起来,然后利⽤读出的后缀表达式完成求值,其本质上是⽅式⼀的分解过程。

表达式求值的代码如下:#include <iostream>#include "stack"#include "map"using namespace std;/* 只能求⼀位整数的加减乘除混合运算 */map<char, pair<int, int>> priority; // 存放各个操作符的栈内栈外优先级,first是栈内,second是栈外char infix[50]; // 存放初始的中缀表达式char postfix[50]; // 存放转化的后缀表达式int result;void MakePriority() // 构造运算符优先级表{priority.insert(make_pair('#', make_pair(0, 0))); // isp(#)=0, icp(#)=0priority.insert(make_pair('\n', make_pair(0, 0))); // isp(\n)=0, icp(\n)=0 表达式结尾的'#'⽤'\n'代替,这样可以省略表达式末尾的结束符'#'priority.insert(make_pair('(', make_pair(1, 6))); // isp(()=1, icp(()=6priority.insert(make_pair('*', make_pair(5, 4))); // isp(*)=5, icp(*)=4priority.insert(make_pair('/', make_pair(5, 4))); // isp(/)=5, icp(/)=4priority.insert(make_pair('%', make_pair(5, 4))); // isp(%)=5, icp(%)=4priority.insert(make_pair('+', make_pair(3, 2))); // isp(+)=3, icp(+)=2priority.insert(make_pair('-', make_pair(3, 2))); // isp(-)=3, icp(-)=2priority.insert(make_pair(')', make_pair(6, 1))); // isp())=6, icp())=1}void InfixToPostfix() // 把中缀表达式转换为后缀表达式{int i = 0;stack<char> optrStack; // 操作符栈char optr; // optr为栈顶的操作符optrStack.push('#');while (!optrStack.empty()){if (isdigit(infix[i])) // 是操作数则直接输出(追加到postfix结尾){postfix[strlen(postfix)] = infix[i];postfix[strlen(postfix) + 1] = '\0';i++; // 读⼊中缀表达式的下⼀个字符}else// 是操作符, ⽐较优先级{optr = optrStack.top(); // 取出栈顶操作符if (priority[infix[i]].second > priority[optr].first) // icp(infix[i]) > isp(optr),infix[i]⼊栈{optrStack.push(infix[i]);i++;}else if (priority[infix[i]].second < priority[optr].first)// icp(infix[i]) < isp(optr),optr退栈并输出{postfix[strlen(postfix)] = optr;postfix[strlen(postfix) + 1] = '\0';optrStack.pop();}else// icp(infix[i]) = isp(optr),退栈但不输出,若退出的是'(',则继续读⼊下⼀个字符{optrStack.pop();if (optr == '(')i++;}}}}void CalculateByPostfix() // 通过后缀表达式求值{int i = 0;stack<int> opndStack; // 操作数栈int left, right; // 左右操作数int value; // 中间结果int newOpnd;while (postfix[i] != '#' && i < strlen(postfix)){switch (postfix[i]){case'+':right = opndStack.top(); // 从操作数栈中取出两个操作数opndStack.pop();left = opndStack.top();opndStack.pop();value = left + right;opndStack.push(value); // 中间结果⼊栈break;case'-':right = opndStack.top();opndStack.pop();left = opndStack.top();opndStack.pop();value = left - right;opndStack.push(value);break;case'*':right = opndStack.top();opndStack.pop();left = opndStack.top();opndStack.pop();value = left * right;opndStack.push(value);break;case'/':right = opndStack.top();opndStack.pop();left = opndStack.top();opndStack.pop();if (right == 0){cerr << "Divide by 0!" << endl;}else{value = left / right;opndStack.push(value);}break;default:newOpnd = (int)(postfix[i] - 48); // 操作数直接⼊栈opndStack.push(newOpnd);break;}i++;}result = opndStack.top();}void CalculateByInfix() // 直接利⽤中缀表达式求值{int i = 0;stack<char> optrStack; // 操作符栈stack<int> opndStack; // 操作数栈char optr; // optr为操作符栈顶的操作符int left, right, value; // 左右操作数以及中间结果optrStack.push('#');optr = optrStack.top();while (!optrStack.empty()) // 直到操作符栈为空{if (isdigit(infix[i])) // 是操作数, 进操作数栈{value = (int)(infix[i] - 48);opndStack.push(value);i++;}else// 是操作符, ⽐较优先级{optr = optrStack.top(); // 取出操作符栈顶的操作符if (priority[infix[i]].second > priority[optr].first) // icp(infix[i]) > isp(optr),infix[i]⼊栈 {optrStack.push(infix[i]);i++;}else if (priority[infix[i]].second < priority[optr].first) // icp(infix[i]) < isp(optr),optr退栈并输出{optrStack.pop();right = opndStack.top(); // 从操作数栈中取出两个操作数opndStack.pop();left = opndStack.top();opndStack.pop();switch (optr){case'+':value = left + right;opndStack.push(value); // 中间结果⼊栈break;case'-':value = left - right;opndStack.push(value); // 中间结果⼊栈break;case'*':value = left * right;opndStack.push(value); // 中间结果⼊栈break;case'/':if (right == 0){cerr << "Divide by 0!" << endl;}else{value = left / right;opndStack.push(value);}break;default:break;}}else{optrStack.pop();if (optr == '(')i++;}}}result = opndStack.top();}int main(){MakePriority(); // 构造运算符优先级表cout << "请输⼊中缀表达式:";cin >> infix;cout << "直接利⽤中缀表达式求值为:";CalculateByInfix();cout << result << endl;cout << "转化为后缀表达式:";InfixToPostfix();for (int i = 0;i < strlen(postfix);i++){cout << postfix[i];}cout << endl;cout << "利⽤后缀表达式求值为:";CalculateByPostfix();cout << result << endl;return0;} 为了⽅便起见,本⽂只是简单的设计了⼀个针对⼀位整数的四则运算进⾏求值的算法,对于处理多位整数的四则运算,需要对本⽂接受输⼊的数据类型进⾏“升阶”,把字符数组换成字符串数组,将⼀个整数的多位数字存⼊⼀个字符串进⾏处理。

用栈解决表达式求值问题的c语言代码

用栈解决表达式求值问题的c语言代码

栈是一种常见的数据结构,用于解决许多算法和数据处理问题。

在编程中,栈通常用于处理表达式求值问题。

本篇文章将介绍如何使用栈解决表达式求值问题,并给出对应的C语言代码。

1. 表达式求值问题介绍表达式求值是指计算一个数学表达式的值,通常涉及到四则运算、括号和优先级等概念。

给定一个表达式“3 + 4 * 2”,我们需要得到其计算结果为11。

在编程中,需要将该表达式转换为计算机可识别的形式,并使用算法进行求值。

2. 中缀表达式、前缀表达式和后缀表达式在计算机中常见的表达式有三种形式:中缀表达式、前缀表达式和后缀表达式。

其中,中缀表达式是通常人们在日常生活中使用的表达式形式,如“3 + 4 * 2”。

前缀表达式是运算符位于操作数之前的形式,例如“+ 3 * 4 2”。

后缀表达式则是运算符位于操作数之后的形式,例如“3 4 2 * +”。

3. 使用栈解决表达式求值问题在解决表达式求值问题时,我们可以利用栈的特性来简化计算过程。

具体步骤如下:3.1 将中缀表达式转换为后缀表达式我们需要将中缀表达式转换为后缀表达式,这样可以简化表达式的计算顺序。

具体转换规则如下:- 从左至右扫描中缀表达式的每个数字或符号。

- 如果是操作数,则直接输出。

- 如果是运算符,则弹出栈中所有优先级大于或等于该运算符的运算符,并将其压入栈中,然后压入该运算符。

- 如果是括号,则根据括号的不同情况进行处理。

通过以上规则,我们可以将中缀表达式转换为后缀表达式。

3.2 计算后缀表达式的值得到后缀表达式后,我们可以利用栈来计算其值。

具体步骤如下:- 从左至右扫描后缀表达式的每个数字或符号。

- 如果是操作数,则压入栈中。

- 如果是运算符,则弹出栈中的两个操作数进行相应的运算,并将结果压入栈中。

- 继续扫描直到表达式结束,栈中的值即为所求结果。

通过以上步骤,我们可以使用栈来解决表达式求值问题。

4. C语言代码实现以下是使用C语言实现栈来解决表达式求值问题的代码示例:```c#include <stdio.h>#include <stdlib.h>#include <string.h>typedef struct {int top;int capacity;int* array;} Stack;Stack* createStack(int capacity) {Stack* stack = (Stack*)malloc(sizeof(Stack));stack->capacity = capacity;stack->top = -1;stack->array = (int*)malloc(stack->capacity * sizeof(int)); return stack;}int isFull(Stack* stack) {return stack->top == stack->capacity - 1; }int isEmpty(Stack* stack) {return stack->top == -1;}void push(Stack* stack, int item) {if (isFull(stack)) return;stack->array[++stack->top] = item;}int pop(Stack* stack) {if (isEmpty(stack)) return -1;return stack->array[stack->top--];}int evaluatePostfix(char* exp) {Stack* stack = createStack(strlen(exp)); for (int i = 0; exp[i]; i++) {if (isdigit(exp[i])) {push(stack, exp[i] - '0');} else {int val1 = pop(stack);int val2 = pop(stack);switch (exp[i]) {case '+':push(stack, val2 + val1); break;case '-':push(stack, val2 - val1); break;case '*':push(stack, val2 * val1); break;case '/':push(stack, val2 / val1); break;}}}return pop(stack);}int m本人n() {char exp[] = "34*2+";printf("The value of s is d\n", exp, evaluatePostfix(exp));return 0;}```以上代码实现了栈的基本功能,并利用栈来计算后缀表达式的值。

四则运算表达式求值(栈+二叉树-c++版)

四则运算表达式求值(栈+二叉树-c++版)

HUNAN UNIVERSITY 课程实习报告题目:四则运算表达式求值学生:周华毅学生学号:201308010411专业班级:计科1304 指导老师:吴帆完成日期:2015/5/1一、需求分析a)四则运算表达式求值,将四则运算表达式用中缀表达式表示,然后转换为后缀表达式,并计算结果。

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

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

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

d)测试数据输入:21+23*〔12-6〕输出:21 23 12 6 -*+二、概要设计抽象数据类型为实现上述程序的功能,应以字符串存储用户的输入,以及计算出的结果。

算法的基本思想根据题目要求,利用二叉树后序遍历来实现表达式的转换。

该算法的基本模块包括二叉树的建立以及如何把输入的中缀表达式利用二叉树后序遍历转化为后缀表达式。

1、首先要将输入的中缀表达式〔数字字符〕存入到二叉树中,由于存在两位或者两位以上的数,甚至还有小数,所以考虑用字符型指针存储数字字符和操作符。

2、为了便于将中缀表达式存入二叉树中,在录入中缀表达式后,要进行相应的处理,比方去掉空格符,添加结束标志,如‘=’、‘#’等。

3、中缀表达式存入到二叉树的过程中,要注意处理的顺序,如‘+’、‘-’号的优先级比‘*’、‘/’号的低,当遇到‘*’、‘/’号时,要判断树以上的节点中是否有‘+’、‘-’号,有的话要与其交换位置。

遇到‘〔’时要反复创建二叉树的结点,构建子二叉树,考虑到括号内要处理的步骤可能会较多,可以考虑用递归。

遇到‘〕’时则直接结束此子二叉树的建立。

此外二叉树中叶子结点存储操作数,非叶子结点存储操作码。

4、对创建好的二叉树进行后序遍历,即可得到相应的后缀表达式,实现方法可以用递归的方式,由于后面还要计算表达式的值,故便利的过程中要将结点中得到的数据存入新的字符数组中。

堆栈四则运算

堆栈四则运算

3 依次读入表达式中的每个字符,若是操作数则进OPND栈,若 是运算符θ2 ,则和OPTR栈的栈顶元素θ1比较优先级后进行 如下操作: 若θ1 < θ2 ,θ2 进栈; 若θ1 = θ2 ,θ1 出栈; 若θ1 > θ2 ,θ1 出栈和一对操作数进行求值;
直至整个表达式求值完毕(即OPTR栈的栈顶元素θ1 和当前 读入的字符均为“#”)。
2. 基础知识点
➢ 栈的初始化
Stack InitStack() //初始化栈 {
Stack S; S.pBase=(int*)malloc(STACK_INIT_SIZE*sizeof(int)); if(!S.pBase) exit(-1); else {
S.pTop=S.pBase; S.StackSize=STACK_INIT_SIZE; } return S; }
1.编程思路分析
# exp #
根据中缀表达式的运算规则,在运算的每一步中,任意两个相继出现的算符θ1 和θ2之间的优先关系应是以下三种关系之一:
➢ θ1<θ2 θ1的优先权低于θ2 θ1 θ2 + - * ➢ θ1=θ2 θ1的优先权等于θ2 + > > <
/()# << > >
➢ θ1>θ2 θ1的优先权高于θ2
}
若θ1 = θ2 ,θ1 出栈;
} 用户输入一个包含“+”、“-”、“*”、“/”、正整数和圆括号的合法数学表达式,计算该表达式的运算结果。
Stack InitStack() //初始化栈
2、前缀表示:<运算符><操作数><操作数>
➢ 取栈顶元素 #define STACK_INIT_SIZE 100 //存储空间初始分配量

c语言求解带括号的四则运算表达式

c语言求解带括号的四则运算表达式

c语言求解带括号的四则运算表达式如何用C语言求解带括号的四则运算表达式在C语言中,我们可以使用栈来求解带括号的四则运算表达式。

栈是一种先入后出(Last-In-First-Out)的数据结构,对于表达式中的每一个运算符,我们都可以使用栈来保存其优先级。

下面是一步一步的解决方法。

第一步:定义运算符优先级在处理表达式时,我们需要知道每个运算符的优先级。

在C语言中,可以使用switch语句来定义每个运算符的优先级。

例如:cint getPriority(char op) {switch(op) {case '+':case '-':return 1;case '*':case '/':return 2;case '(':case ')':default:return 0;}}在这个函数中,我们将运算符+和-的优先级定义为1,将运算符*和/的优先级定义为2,而括号的优先级定义为0。

第二步:将表达式转换为后缀表达式后缀表达式是指将运算符放在操作数之后的表达式形式。

为了求解带括号的四则运算表达式,我们首先需要将其转换为后缀表达式。

具体的转换规则如下:1. 从左到右扫描表达式,如果遇到操作数,则直接将其输出。

2. 如果遇到运算符,则将其与栈顶的运算符比较优先级。

如果栈顶的运算符优先级大于等于当前的运算符,则将栈顶的运算符弹出并输出,直到栈顶的运算符优先级小于当前的运算符或者栈为空。

然后将当前的运算符压入栈中。

3. 如果遇到左括号,则直接将其压入栈中。

4. 如果遇到右括号,则将栈顶的运算符弹出并输出,直到遇到左括号为止。

左括号不输出。

例如,对于表达式"3 + 4 * ( 2 - 1 )",其转换为后缀表达式为"3 4 2 1 - * +"。

第三步:求解后缀表达式在将表达式转换为后缀表达式之后,我们可以使用栈来求解后缀表达式。

数据结构实验报告五—四则运算表达式求值

数据结构实验报告五—四则运算表达式求值

问题描述:四则运算表达式求值,将四则运算表达式用中缀表达式,然后转换为后缀表达式,并计算结果。

一、需求分析:1、本程序是利用二叉树后序遍历来实现表达式的转换,同时可以使用实验三的结果来求解后缀表达式的值。

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

请输入表达式:输入一个中缀表达式输出格式:如果该中缀表达式正确,那么在字符界面上输出其后缀表达式,其中后缀表达式中两相邻操作数之间利用空格隔开;如果不正确,在字符界面上输出表达式错误提示。

逆波兰表达式为:输出逆波兰表达式运算结果为:输出运算后的结果3、测试用例输入:21+23*(12-6)输出:21 23 12 6 -*+二、概要设计:抽象数据类型二叉树类BiTree算法的基本思想根据题目要求,利用栈计算,和二叉树存储,来计算表达式该算法的基本思想是:先利用栈进行计算,然后用二叉树进行存储,和实验三算法一样来计算逆波兰表达式的值程序的流程程序由三个模块组成:(1)输入模块:输入一个运算式(2)计算模块:利用栈进行表达式的计算,二叉树来存储。

(3 )输出模块:屏幕上显示出后缀表达式和运算结果。

三、详细设计物理数据类型程序含有两个类,其中栈不再赘述,另一个类为二叉树class BiTree 包含私有成员struct BiTreeNode,根节点BiTreeNode *T;索引index; int number_of_point 优先级比较函数 compare(char a,char b);生成树的函数void InorderCreate(BiTreeNode *&T,char str[30][10],int start,int end);判断数字函数bool IsNumber(char a);求值函数double Operate(BiTreeNode *T);还有显示后缀表达式的函数void display(BiTreeNode *T) ;而公有成员函数则是对私有函数的重载,为方便使用,因为函数中普遍使用了递归的算法。

湖南大学数据结构试验3四则运算表达式求值

湖南大学数据结构试验3四则运算表达式求值

实验四四则运算表达式的求值一、需求分析1. 要求对四则运算表达式求值,将四则运算表达式用中缀表达式表示,然后转换为后缀表达式,并计算结果。

利用二叉树来实现要求,注意浮点数和整形数的转换。

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

2.中缀表达式由键盘输入(输入的字符串长度小于100),对非法表达式做错误判断和说明在Dos界面输出出列的项3.测试数据输入:21+23*(12-6)输出:21 23 12 6 -*+result is 159.00二、概要设计1.输入中缀表达式转换后缀表达式,以及计算出的结果ADT LinkList {数据对象:D是具有相同特性的数据元素的集合。

数据关系:若D为空寂,则称为空树;(1).若D仅含有一个数据元素,则R为空集,否则R={H},H是如下二元关系:在D中仅存在为一的称为根的数据元素root,它在关系H下无前驱;(2).若D-{root}的一个划分D1,D2,…Dm(m>0),对任意j不等于k(1<=j,k<=m)有Dj和Dk的交集为空,且任意的i(1<=i<=m),唯一存在数据元素Xi属于Di,有<root,Xi>属于H;(3).对应于D-{root}的划分,H-{<root,Xi>,…,<root,Xm>}有唯一的一个划分H1,H2,…Hm(m>0),对任意j不等于k(1<=j,k<=m)有Hj和Hk的交集为空,且对任意i(1<=i<=m),Hi是Di上的二元关系,(Di,{Hi})是一棵符合定义的树,称为根root的子树。

基本操作:int CrtNode(stack <BiTree> &PTR, char *c)操作结果:创建二叉树的根节点,并把值保存在根节点。

void CrtSubTree(stack <BiTree> &PTR, char c)初始条件:二叉树根节点存在操作结果:建立二叉树的子树void CrtExptree(BiTree &T, char exp[])初始条件:二叉树存在操作结果:根据字符串exp的内容构建表达式树Tvoid PostOrderTraverse(BiTree &T, char * exp ,int &count)初始条件:二叉树不为空操作结果:后序遍历二叉树,依据T->len的值,把T->data中的字符依次添加到当前exp字符串的尾端} ADT LinkList2.本程序包含三个基本模块(1)主程序模块:其中又包括构建二叉树和后序遍历二叉树及计算后序表达式的值(2)线性表模块:实现线性表的抽象数据类型(3)元素结构单元模块:定义线性表每个元素的结构三、详细设计1.元素类型,二叉树类型typedef struct BiTNode {TElemType data;int len; //data字符串中字符的个数struct BiTNode * lchild, * rchild;}BiTNode, *BiTree;栈类型:c++标准容器stack容器2.根据二叉树和栈的特点,T即为该二叉树的名称,该程序的基本操作具体实二叉树T—>后序遍历二叉树—>计算二叉树的后序表达式的值—>删除中间指针—>结束3.主程序中:四、调试分析1.输入“4**”诸如此类的表达式时,程序运行时不会报出错误,因为该程序不能判别一些不合法公式的输入情况,类似的情况太多,着重点不在这些错误上。

利用二叉树以及栈对算术表达式实现四则运算等计算功能代码

利用二叉树以及栈对算术表达式实现四则运算等计算功能代码

#include <iostream>#include <string>#include <sstream>#include <stack>#include <cmath>using namespace std;bool IsOperator(string mystring) //判断字符串是否是运算符{if(mystring == "-"||mystring == "+"||mystring == "*"||mystring == "/"||mystring == "^"||mystring == "%")return true;elsereturn false;}bool IsOperator(char ops) //判断一个字符是否是运算符{if(ops == '+'||ops== '-'||ops== '*'||ops== '/'||ops== '^'||ops== '%'||ops=='('||ops==')') return true;elsereturn false;}bool IsOperand(char ch) //判断是否是数字{if (((ch>='0')&&(ch<='9'))||(ch=='.'))return true;elsereturn false;}bool isok(string exp) //判断输入是否正确{char check;int error=0,lb=0,rb=0,numofoperand=0,numofoperator=0;for(int m=0;m<exp.size();m++){check=exp[m];if(IsOperand(check)){if(check=='.'){if(!(exp[m-1]>='0'&&exp[m-1]<='9')&&(exp[m+1]>='0'&&exp[m+1]<='9'))error++;cout<<"浮点型数据输入有误!!!"<<endl;}}numofoperand++;}else if(IsOperator(check)){if(check==')'){rb++;if(rb>lb){error++;cout<<"右括号不可能大于左括号!!!"<<endl;}if(IsOperator(exp[m+1])&&(exp[m+1]=='+'||exp[m+1]=='-'||exp[m+1]=='*'||exp[m+1]=='/'||e xp[m+1]=='^'||exp[m+1]==')'||exp[m+1]=='%')){numofoperator++;m++;if(exp[m]==')')rb++;}else if(IsOperator(exp[m+1])||IsOperand(exp[m+1])){error++;cout<<"右括号后不可能直接跟数据或左括号!!!"<<endl;}}else if(check=='('){lb++;if(IsOperator(exp[m+1])&&exp[m+1]=='('){m++;lb++;}else if(IsOperator(exp[m+1])){error++;cout<<"左括号后运算符只能跟左括号!!!"<<endl;}else{numofoperator++;if(IsOperator(exp[m+1])&&exp[m+1]=='('){m++;lb++;}else if(IsOperator(exp[m+1])){error++;cout<<"非括号的运算符不能直接接非括号运算符!!!"<<endl;}}}else{error++;cout<<check<<"为非法字符!!!"<<endl;}}if((error==0)&&(lb==rb)&&(numofoperand!=0)&&(numofoperator!=0))return true;elsereturn false;}bool addition(char OperatorA,char OperatorB) //A=B返回TRUE.{if(OperatorA==OperatorB||(OperatorA=='*'&&OperatorB=='/')||(OperatorA=='/'&&Operator B=='*')||(OperatorA=='+'&&OperatorB=='-')||(OperatorA=='-'&&OperatorB=='+')) return true;elsereturn false;}bool TakesPrecedence(char OperatorA,char OperatorB) //按照优先级用if从最优至最后从上至下排列,从而达到比较A与B的优先级{if(OperatorA=='(')return false;else if(OperatorB=='(')return false;else if(OperatorB==')')return true;else if(addition(OperatorA,OperatorB))return false;else if((OperatorA=='^')&&(OperatorB=='^'))return false;else if(OperatorA=='^')return true;else if(OperatorB=='^')return false;else if((OperatorA=='%')&&(OperatorB=='%'))return false;else if(OperatorA=='%')return true;else if(OperatorB=='%')return false;else if((OperatorA=='*')||(OperatorA=='/'))return true;else if((OperatorB=='*')||(OperatorB=='/'))return false;else if((OperatorA=='+')||(OperatorA=='-'))return true;elsereturn true;}//****************************************************************************//class BinNode{public:string data;BinNode *left_child;BinNode *right_child;BinNode(string k) //构造函数{data=k;left_child=NULL;right_child=NULL;}};class binary_tree{public:BinNode *root; //根节点binary_tree(void){root=NULL;} //构造函数void print(void){print(root);}void print(BinNode *p){if(p!=NULL){print(p->left_child);print(p->right_child);cout<<p->data<<" ";}}void evaluate(void){evaluate(root);}bool evaluate(BinNode *prt) //计算二叉树一个节点{if(IsOperator(prt->data)&&!IsOperator(prt->left_child->data)&&!IsOperator(prt->right_chil d->data)){float num=0;float num1=atof(prt->left_child->data.c_str());float num2=atof(prt->right_child->data.c_str());if(prt->data=="+")num=num1+num2;else if(prt->data=="-")num=num1-num2;else if(prt->data=="*")num=num1*num2;else if(prt->data=="/"){if(num2==0.0){cout<<"除数为零!!!运算出错";return 0;}elsenum=num1/num2;}else if(prt->data=="^")num=pow(num1,num2);else if(prt->data=="%"){if(num2==0.0){cout<<"除数为零!!!运算出错";return 0;}elsenum=(long)num1%(long)num2;}stringstream bob;bob<<num;string suzzy(bob.str());prt->data=suzzy;prt->left_child=NULL;prt->right_child=NULL;}else if(prt->left_child==NULL&&prt->right_child==NULL);else{evaluate(prt->left_child);evaluate(prt->right_child);evaluate(prt);}return 1;}void clear_help(void){clear_help(root);}void clear_help(BinNode *rt){if(rt!=NULL){clear_help(rt->left_child);clear_help(rt->right_child);delete rt;}}};BinNode *build_node(string x){BinNode *new_node;new_node=new BinNode(x);return (new_node);}void copy(BinNode *&r1,BinNode* r2)//请注意这里的*&!!!{if(r2==NULL)r1=NULL;else{r1=build_node(r2->data);copy(r1->left_child,r2->left_child);copy(r1->right_child,r2->right_child);}}/****************************************************************************/int main(){binary_tree etree;stack<binary_tree> NodeStack;stack<char> OpStack;string infix;char choice='y';char c;while(choice=='y'||choice=='Y'){cout<<endl<<"Introduce the Expression:"<<endl;getline(cin,infix);for(int j=0;j<infix.size();j++){if(infix[j]==' '){infix.erase(j,1);j--;}}cout<<" 华丽的分割线"<<endl<<"-----------------------------"<<endl;cout<<"Expression: "<<infix<<endl;if(isok(infix)){for(int i=0;i<infix.size();i++){c=infix[i];if(i==0 && c=='-') //若开始为负,则把零压入运算数栈,把'-'压入运算符栈{binary_tree temp;temp.root=build_node("0");NodeStack.push(temp);OpStack.push('-');}elseif(IsOperand(c)){string tempstring="";tempstring=tempstring+c;while(i+1<infix.size()&&IsOperand(infix[i+1])){tempstring+=infix[++i];}binary_tree temp;temp.root=build_node(tempstring);NodeStack.push(temp);}else if(c=='+'||c=='-'||c=='/'||c=='*'||c=='^'||c=='%'){if(OpStack.empty())OpStack.push(c);else if(OpStack.top()=='(')OpStack.push(c);else if(TakesPrecedence(c,OpStack.top()))OpStack.push(c);else{while(!OpStack.empty()&&(TakesPrecedence(OpStack.top(),c)||addition(OpStack.top(),c))){binary_tree temp_tree;string thisstring="";thisstring=thisstring+OpStack.top();OpStack.pop();etree.root=build_node(thisstring);copy(temp_tree.root,NodeStack.top().root);NodeStack.pop();etree.root->right_child=temp_tree.root;temp_tree.root=NULL;copy(temp_tree.root,NodeStack.top().root);etree.root->left_child=temp_tree.root;NodeStack.pop();temp_tree.root=NULL;copy(temp_tree.root,etree.root);NodeStack.push(temp_tree);etree.root=NULL;}OpStack.push(c);}}if(c=='(') //若中间遇到括号,则判断下一位是否为'-' {OpStack.push(c);if(infix[i+1]=='-'){binary_tree temp;temp.root=build_node("0");NodeStack.push(temp);OpStack.push('-');++i;}}else if(c==')'){while(OpStack.top()!='('){binary_tree temp_tree;string thisstring="";thisstring=thisstring+OpStack.top();OpStack.pop();etree.root=build_node(thisstring);copy(temp_tree.root,NodeStack.top().root);NodeStack.pop();etree.root->right_child=temp_tree.root;temp_tree.root=NULL;copy(temp_tree.root,NodeStack.top().root);etree.root->left_child=temp_tree.root;NodeStack.pop();temp_tree.root=NULL;copy(temp_tree.root,etree.root);NodeStack.push(temp_tree);etree.root=NULL;}OpStack.pop();}}while(!OpStack.empty()){binary_tree temp_tree;string thisstring="";thisstring=thisstring+OpStack.top();OpStack.pop();etree.root=build_node(thisstring);copy(temp_tree.root,NodeStack.top().root);NodeStack.pop();etree.root->right_child=temp_tree.root;temp_tree.root=NULL;copy(temp_tree.root,NodeStack.top().root);etree.root->left_child=temp_tree.root;NodeStack.pop();temp_tree.root=NULL;copy(temp_tree.root,etree.root);NodeStack.push(temp_tree);if(!OpStack.empty())etree.root=NULL;}cout<<"Postfix traversal:";etree.print();cout<<endl;etree.evaluate();cout<<"The result is:"<<etree.root->data<<endl;cout<<"------------------------------------------------"<<endl;cout<<endl<<"Run Program again? Enter<y/n>:";cin>>choice;getchar();}else{cout<<"**************************"<<endl;cout<<"ERROR: Invalid Exprssion"<<endl;cout<<endl<<"Run Program again? Enter<y/n>:";cin>>choice;getchar();}}return 0;}。

四则运算表达式求值

四则运算表达式求值

HUNAN UNIVERSITY背景在工资管理软件中,不可避免的要用到公式的定义及求值等问题。

对于数学表达式的计算,虽然可以直接对表达式进行扫描并按照优先级逐步计算,但也可以将中缀表达式转换为逆波兰表达式,这样更容易处理。

问题描述四则运算表达式求值,将四则运算表达式用中缀表达式,然后转换为后缀表达式,并计算结果。

一.需求分析(1)本程序利用二叉树后序遍历来实现表达式的转换,同时可以使用栈来求解后缀表达式的值。

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

输出:如果该中缀表达式正确,那么在字符界面上输出其后缀表达式和计算结果,其中后缀表达式中两相邻操作数之间利用空格隔开;如果不正确,在字符界面上输出表达式错误提示。

(3)测试用例:输入:21+23*(12-6)+9输出:21 23 12 6 -*+ 9+result is 168二.概要设计(1)抽象数据类型:由于四则运算表达式中运算符可能有多个后继,而运算的对象无后继,可以采用二叉树来实现把中缀表达式转换为后缀表达式。

数据对象:四则运算符及整数数据关系:运算符有多个后继,二运算对象的值无后继基本操作:后序遍历,二叉树的构建和摧毁,插入,删除经过二叉树的后序遍历后的表达式惊醒运算是满足后进先出的原则,采用栈来实现四则运算表达式的求值。

数据对象:运算符(字符)及整数数据关系:后进先出基本操作:入栈,出栈,栈的构建和删除(2)算法基本思想:用二叉树来存储四则表达式,再通过后序遍历把中缀表达式转换为后缀表达式,最后通过栈来计算表达式的值,最后输出后序表达式和表达式的值。

(3)程序的流程:该程序有三个模块组成:1.输入模块:输入一个中缀表达式2.处理模块:把中缀表达式转换为后缀表达式3.计算模块:计算表达式的值4.输出模块:输出后缀表达式及表达式的值三.详细设计(1)物理数据类型:采用指针来实现二叉树,其中分支节点存储运算符,用叶子节点存储操作数,可以减少二叉树的结构性开销。

四则运算c++实现

四则运算c++实现
{
postexp[j]=data[top_p];
j++;
top_p--;
}
top_p++;
data[top_p]=ch;//压入栈中
break;
}
case ' ':break;
default:
{ቤተ መጻሕፍቲ ባይዱ
while(ch>='0'&&ch<='9')
{
postexp[j]=ch;
j++;
ch=exp[i];
i++;
测试数据:
输入:5*(3+2)!
输出:5#3#2#+*
The result is:25
********************************************************************************/
#include<iostream>
using namespace std;
// private:
int *data; //栈顶指针
int maxSize; //栈的容量
int top_p; //栈顶指针
void resize(); //将栈的容量扩大一倍
int trans(char exp[]);//四则运算
};
/*********************************顺序栈类的实现******************************/
case'+':
case'-': while(op.top!=-1&&op.data[op.top]!='(')
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

HUNAN UNIVERSITY 课程实习报告题目:四则运算表达式求值学生姓名:周华毅学生学号:201308010411专业班级:计科1304指导老师:吴帆完成日期:2015/5/1一、需求分析a)四则运算表达式求值,将四则运算表达式用中缀表达式表示,然后转换为后缀表达式,并计算结果。

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

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

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

d)测试数据输入:21+23*(12-6)输出:21 23 12 6 -*+二、概要设计抽象数据类型为实现上述程序的功能,应以字符串存储用户的输入,以及计算出的结果。

算法的基本思想根据题目要求,利用二叉树后序遍历来实现表达式的转换。

该算法的基本模块包括二叉树的建立以及如何把输入的中缀表达式利用二叉树后序遍历转化为后缀表达式。

1、首先要将输入的中缀表达式(数字字符)存入到二叉树中,由于存在两位或者两位以上的数,甚至还有小数,所以考虑用字符型指针存储数字字符和操作符。

2、为了便于将中缀表达式存入二叉树中,在录入中缀表达式后,要进行相应的处理,比如去掉空格符,添加结束标志,如‘=’、‘#’等。

3、中缀表达式存入到二叉树的过程中,要注意处理的顺序,如‘+’、‘-’号的优先级比‘*’、‘/’号的低,当遇到‘*’、‘/’号时,要判断树以上的节点中是否有‘+’、‘-’号,有的话要与其交换位置。

遇到‘(’时要反复创建二叉树的结点,构建子二叉树,考虑到括号内要处理的步骤可能会较多,可以考虑用递归。

遇到‘)’时则直接结束此子二叉树的建立。

此外二叉树中叶子结点存储操作数,非叶子结点存储操作码。

4、对创建好的二叉树进行后序遍历,即可得到相应的后缀表达式,实现方法可以用递归的方式,由于后面还要计算表达式的值,故便利的过程中要将结点中得到的数据存入新的字符数组中。

程序的流程程序由三个模块组成:(1)输入模块:完成一个中缀表达式的输入,存入字符串数组array[Max]中。

(2)计算模块:设计一个建立二叉树的函数,Node* crtTree(Node* root),传入根结点指针,返回根结点指针,该函数的实现还要反复使用另一个函数chargetOp(Node *temp),其将数字字符存入一个结点,并返回数字字符的后一个符号。

void deal()函数功能是对字符数组进行处理。

void output(Node*root); 函数功能是获得处理后的字符串,也就是中缀表达式转化为的后缀表达式。

(3)输出模块:如果该中缀表达式正确,那么在字符界面上输出其后缀表达式和表达式的值;如果不正确,在字符界面上输出表达式错误提示。

三、详细设计物理数据类型题目要求输入的四则运算表达式运算符只有加减乘除,操作数有整数和小数,为了能够存储,采用C语言中的字符串数组。

char ch[Max];算法的时空分析算法的运行时间主要耗费在二叉树的建立过程中。

可以发现,每当遇到一个运算符或操作数时,都要调用一次函数char getOp(Node *temp),来将其存入二叉树的结点中,其中也会遇到递归的情况,但耗时可以忽略。

所以假设输入的字符串中字符个数为N,则算法的时间复杂度为O(N)。

输入和输出的格式输入本程序可以将输入的四则运算表达式(中缀表达式)转换为后缀表达式//提示请输入四则运算表达式://提示等待输入输出//提示后缀表达式为://输出结果的位置表达式的值为://输出结果的位置四、调试分析本次实验的难点主要是在建立二叉树的问题上。

关于如何把中缀表达式存入二叉树中,我参考了网上的一些方法,成功实现了目标,但是却遇到了一个问题,那就是不能处理小数,甚至两位或两位以上的整数。

因为如果采用字符数组来存储操作数,运算符合一位整数还可以处理,但对于两位数就就会出问题,最后我改进采用字符串数组来存储操作数,成功解决了问题。

另外在处理输入的非法表达式问题中,我也费了很大功夫,但总体问题不大。

五、测试结果六、用户使用说明(可选)1、本程序的运行环境为DOS操作系统2、运行程序时提示输入四则运算表达式本程序可以将中缀表达式转化为后缀表达式,并计算结果请输入四则运算表达式:输出后缀表达式为:表达式的值为:七、附录(可选)程序源代码(c++)1、利用二叉树后序遍历来实现表达式的转换:#include<iostream>#include<string>#include<stack>#include<iomanip>const int Max=100;using namespace std;class Node{public:char ch[Max]; //考虑到数值有时会是两位数,所以使用字符串数组Node* lChild;Node* rChild;Node(){strcpy(ch,"");lChild=rChild=NULL;}~Node(){if(lChild!=NULL)delete lChild;if(rChild!=NULL)delete rChild;}};static int count=0;static char array[Max]; //保存原始的中缀表达式static char str[2*Max]; //保存后序遍历出来的字符串,为表达式求值提供方便static int k=0;char getOp(Node *temp); //temp指针保存每个结点,返回的是运算符Node* crtTree(Node* root); //传入根结点指针,返回根结点指针void output(Node *root); //获得处理后的字符串bool isError(char); //判断字符是否有问题void deal(); //对字符数组进行处理double value(string); // 计算后缀表达式,得到其结果。

int main(){Node* root=NULL;cout<<"输入中缀表达式:";cin.getline(array,40);deal();root=crtTree(root);cout<<"输出后缀表达式:";output(root);cout<<str<<endl;cout<<"输出后缀表达式的值:";if(value(str)!=0)cout<<fixed<<setprecision(2)<<value(str)<<endl;elsecout<<"A Wrong Input!"<<endl;return 0;}//将数字字符存入一个结点,并返回数字字符的后一个符号char getOp(Node *temp){int i=0;if( isError(array[count]) )exit(0);while(array[count]<='9'&&array[count]>='0'||array[count]=='.'){ temp->ch[i]=array[count];i++;count++;}temp->ch[i]='\0';count++;return array[count-1];}//传入根结点指针,返回根结点指针Node* crtTree(Node* root) {Node *p,*q;char op;if(root==NULL){root=new Node;p=new Node;}op=getOp(root);while(op!='='){q=new Node;q->ch[0]=op;q->ch[1]='\0';switch(op){case '+':case '-':q->lChild=root;root=q;p=new Node;op=getOp(p);root->rChild=p;break;case '*':case '/':if(root->ch[0]=='+'||root->ch[0]=='-'){p=new Node;strcpy(p->ch,root->ch);p->lChild=root;p->rChild=q;op=getOp(root);root=p;} else {q->lChild=root;root=q;p=new Node;op=getOp(p);root->rChild=p;} break;case '(':p=root;while(p->rChild)p=p->rChild;if(p->lChild==NULL) {p->lChild=crtTree(p->lChild); //递归创建括号里的指针op=array[count];count++;break;} else{p->rChild=crtTree(p->rChild); //递归创建括号里的指针op=array[count];count++;break;}case ')':return root;}}return root;}//传入根结点,后序遍历,赋值给另一个字符数组(主要是为了给后序的计算表达式值提供方便)void output(Node *root){int n;if(root){output(root->lChild);output(root->rChild);n=0;while(root->ch[n]!='\0')str[k++]=root->ch[n++];str[k++]=' ';}}bool isError(char ch){ //判断每个字符是否有错if(ch!='+'&&ch!='-'&&ch!='*'&&ch!='/'&&!(ch<='9'&&ch>='0')&&ch!='.'&&ch!='(' &&ch!=')'){cout << "字符错误!";return true;}return false;}void deal(){ //对字符数组进行处理int i=0,n=0;while(array[i]){if(array[i]==' '||array[i]=='=')i++;array[n++]=array[i++];}array[n++]='=';array[n]='\0';}double value(string s2){ // 计算后缀表达式,得到其结果。

相关文档
最新文档