一、需求分析1.程序说明:本程序利用二叉树的后序遍历实现表达式的转换,同时可以使用本程序的结果求解后缀表达式的值2.输入输出的形式:输入:21+23*(12-6)输出:21 23 12 6 -*+计算结果为:1593.输入输出范围:程序仅计算int类型的数,输入输出的结果均在int类型的限定范围内4.测试数据第一组:输入:21+23*(12-6)输出:21 23 12 6 -*+计算结果为:159第二组:输入:9+(3-1)*3+10/2输出:9 3 1-3*+ 10 2/+计算结果为:20第三组:输入:( ( 35 + 15 ) * ( 80 – 70 ) ) / 20输出:35 15 + 80 70 - * 20 /计算结果为:25第四组:输入:14×8/7-20×3输出:14 8 × 7 / 20 3 × -计算结果为:-44第五组:输入:10×8+9×6-(6+4)输出:10 8 ×+ 9 6 ×- 6 4 +计算结果为:124二、概要设计抽象数据类型由于中序遍历表达树,将得到中缀表达式;后序遍历表达式树,将得到后缀表达式,而使用栈对后序表达式求取较为方便因此,获取的四则运算表达式使用线性表临时存储,再转存至二叉树中,利用二叉树,得到后缀表达式,通过栈,对后缀表达式求值线性表ADT{数据对象:D={ a i | a i∈ElemSet, i=1,2,...,n, n≥0 }//称 n 为线性表的表长//称 n=0 时的线性表为空表数据关系:R1={ <a i-1 ,a i >|a i-1 ,a i∈D, i=2,...,n }//设线性表为 (a1,a2, . . . ,a i,. . . ,a n),//称 i 为 a i 在线性表中的位序。
基本操作:void clear() = 0; //清空线性表bool append(const Elem&) = 0; //线性表尾添加元素,若添加失败,返回false void setStart() = 0; //将当前位序设置为线性表头bool setPos(int pos) = 0; //设置当前位序,若表空,返回falseElem getValue() = 0; //获取当前元素}//二叉树节点ADT of BinaryTreeNode{数据对象D:D是具有相同特性的数据元素的集合数据关系R:若D为空集,则称为空树。
否则:(1) 在D中存在唯一的称为根的数据元素root;(2) 当n>1时,其余结点可分为不相交的有限集T l、 T r,其中每一个子集本身又是一棵符合本定义的二叉树,称为根root的子树基本操作M:Elem& val() = 0; // Return the node's elementvoid setVal(const Elem&) = 0; // Set the node's elementBinNode* left() const = 0; // Return the node's left childvoid setLeft(BinNode*) = 0; // Set the node's left childBinNode* right() const = 0; // Return the node's right childvoid setRight(BinNode*) = 0; // Set the node's right childbool isLeaf() = 0; // Return true iff the node is a leaf}//栈ADTADT of stack{数据对象D:D={ a i | a i ∈ElemSet, i=1,2,...,n, n≥0 }数据关系R:R1={ <a i-1, a i >| a i-1, a i∈D, i=2,...,n }约定a n端为栈顶,a1 端为栈底基本操作M:// Reinitialize the stackvoid clear() = 0;// Push an element onto the top of the stack.bool push(const Elem&) = 0;// Remove the element at the top of the stack.bool pop(Elem&) = 0;// Get a copy of the top element in the stackbool topValue(Elem&) const = 0;// Return the number of elements in the stack.int length() const = 0;}//二叉树ADTADT of BTree{数据对象D:D是具有相同特性的数据元素的集合数据关系R:若D为空集,则称为空树。
否则:(1) 在D中存在唯一的称为根的数据元素root;(2) 当n>1时,其余结点可分为不相交的有限集T l、 T r,其中每一个子集本身又是一棵符合本定义的二叉树,称为根root的子树基本操作M:Btree( BTNode<Elem>* r = nullptr ); //构造树~Btree(); //析构树void CreatTree(List<char> str); //将表达式以树的形式存储 void PosOrder(List<char> str); //用str返回后缀表达式,}算法的基本思想获取四则运算表达式,将四则运算表达式存储至一颗二叉树,通过二叉树的基本操得到到四则运算表达式的后缀表达式,输出后缀表达式,计算后缀表达式结果并输出程序模块输入模块:获取输入,并将表达式临时存储至线性表存储模块:将表达式序列存储至二叉树中处理模块:得到后缀表达式,计算后缀表达式输出模块:输出后缀表达式以及计算结果三:详细设计由于输入的表达式长度不确定,所以采用链式,实现用于临时存储表达式序列的线性表采用链式,实现二叉树采用链式,实现栈物理数据类型//BTreeNode基本操作实现template <class Elem>class BinNodePtr : public BinNode<Elem>{private:Elem it; // The node's valueBinNodePtr* lc; // Pointer to left childBinNodePtr* rc; // Pointer to right childpublic:BinNodePtr() { lc = rc = NULL; }BinNodePtr(Elem e, BinNodePtr* l =NULL, BinNodePtr* r =NULL){ it = e; lc = l; rc = r; }Elem& val() { return it; }void setVal(const Elem& e) { it = e; }inline BinNode<Elem>* left() const{ return lc; }void setLeft(BinNode<Elem>* b){ lc = (BinNodePtr*)b; }inline BinNode<Elem>* right() const{ return rc; }void setRight(BinNode<Elem>* b){ rc = (BinNodePtr*)b; }bool isLeaf(){ return (lc == NULL) && (rc == NULL); }};核心算法描述1.语言描述:第一步:构造一个空的线性表第二步:从键盘获取表达式序列,通过线性表的append操作将获取的表达序列临时存储至线性表L中第三步:调用二叉树的CreatTree操作,将表达式序列L存储至二叉树中第三步:调用二叉树的PosOrder操作,得到后缀表达式序列L,并输出第四步:构造两个空栈整数栈A,字符栈B,遍历后缀表达式L,如果遍历的当前元素不是运算符,(Ascll值!=40、41、42、43、45、47),将该字符转化为操作数(将字符转化为int整数),并将该整数入栈A否则,将该字符入栈B从B中出栈栈顶元素,得到运算符c,同时从A中两次出栈,得到两个操作数a b,计算a c b(switch), 并将计算结果入栈A,重复2步骤,直到栈B为空A出栈,此时出栈元素即计算结果,并输出出栈元素的值2.伪代码//主程序LList<char> str;char ch;do // 获取输入,并存储至线性表中{cin >> ch;cin.ignore(1024, '\n');str.append(ch);}while(ch != '\n');BTree expression;BTree.generateTree(str); //表达式存储至二叉树中BTree.posOrder(str); //得到后缀表达式while(str.getValue() != '\0') //输出后缀表达式{cout << str.getValue();str.next();}cout << calc(str);//输出结果//calculate functionint calc(LList<char>* str) //计算后缀表达式的伪代码{LStack<int> num;int num1,num2,value;int length = str.length();for(int i=0;i<length;++i){for(int i = 0; i < length; ++i){if(!isOper(str.getValue()))num.push(str.getValue()-48);str.next();}else{if(num.size()<2){cout<<"Error in infix expression!\n";exit(0);}num1=num.top(); num.pop();num2=num.top(); num.pop();if(str[i]=='+') value=num2+num1;if(str[i]=='-') value=num2-num1;if(str[i]=='*') value=num2*num1;if(str[i]=='/'){if(num1==0){cout<<"Can't evaluate the expression !";exit(1);}else value=num2/num1;}num.push(value);}}return num.top();}3.复杂度分析Calculate时间复杂度为○(n)创建二叉树时间复杂度为○(n)得到后缀表达式时间复杂度○(nlgn)程序时间复杂度○(nlgn)四、输入输出格式输入:无错的一串表达式序列( 35 + 15 ) * ( 80 - 70 ) /20输出:四则运算表达式序列对应的后缀表达式形式/ * + 35 15 – 80 70 20表达式对应的结果25。