四则运算表达式求值(栈+二叉树,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 )。

  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){ // 计算后缀表达式,得到其结果。

相关文档
最新文档