这是我的实验报告,原封不动地弄上来了,本来是给老师看的呢。
项目名称:实现四则运算:
项目实施方法:建立一个栈,并建立两个对象,用来对操作符和操作数进行操作。从左至右对输入的文本进行扫描,将相应的操作符和操作数进行压入,然后进行相应的运算。
我使用了memcpy函数,起初担心memcpy函数的效率问题,但是网络上是这样回答的。
“最近又听到有人在讲memcpy的效率问题,实在是忍不住了,基本上很多人对memcpy的原理都是一知半解,大部分认为memcpy是一个char到char的拷贝的循环,担心它的效率。
实际上,memcpy是一个效率最高的内存拷贝函数,他不会那么傻,来做一个一个字节的内存拷贝,在地址不对齐的情况下,他是一个字节一个字节的拷,地址对齐以后,就会使用CPU字长来拷(和dma类似),32bit或64bit,还会根据cpu的类型来选择一些优化的指令来进行拷贝。
总的来说,memcpy的实现是和CPU类型、操作系统、cLib相关的。毫无疑问,它是内存拷贝里效率最高的,请放心使用。”
因此在程序设计之初曾经想过两种方案:
副本一、使用memcpy函数,可以采用动态开辟数组来模拟顺序栈的实现;
副本二、不使用memcpy函数,对链表的操作会显得慢些。
最终选择了没有使用memcpy()函数。
压入栈的伪代码:
1将top节点备份给temp;
2开辟一个节点,赋给top指针;
3将temp指针的值赋给top的成员link。
弹出栈的伪代码:
1取出元素;
2删除节点;
3将top指针指向下一个节点;
4返回元素。
处理当前字符的函数(CharProcess()函数)的伪代码:
1若是字符,则直接返回;
2若是数字,则取下一个字符,并循环判断
3在判断中若是字符,则对数字进行压栈操作,并返回。
计算表达式的函数(EnvaluateExpression()函数)的伪代码:
1定义对象,并初始化;
2对存储操作符的栈压入“=”字符;
3在字符不为“=”或者“)”,则运行CharProcess()函数;
4若有括号匹配现象,消去括号;
5运行Precede()函数,并对其产生不同的返回值进行不同的操作;
6若未产生“=”匹配现象,则循环3~6步操作;
7返回栈顶元素。
注意:
1此程序仅表示了核心的代码,若用户误输入了错误的数据,则会产生各种的错误;
2此程序仅支持“+-*/()”四则运算,尚不满足科学计算要求。
程序特点:链式栈、支持四则运算、支持一次性输入两位数及以上、支持浮点型数
程序代码:define.h代码:
- #ifndef_J_DEFINE_H_
- #define_J_DEFINE_H_
- //UsingC++style
- template<typenameCustomType>//可将任意类型应用于此
- structCustomStruct
- {
- CustomStruct():elem(0),link(0){}//默认构造函数
- CustomTypeelem;
- CustomStruct*link;
- };
- template<typenameCustomType>
- classJStack
- {
- public:
- JStack():base(0),top(0),JStackSize(0){}//默认构造函数
- ~JStack(){}//默认析构函数
- boolInitJStack(void);//初始化栈
- CustomTypeGetTop(void);//取出栈顶的元素
- boolPop(void);//将元素从栈中弹出
- boolPush(CustomTypee);//将元素压入栈顶
- private:
- CustomStruct<CustomType>*base;//栈底
- CustomStruct<CustomType>*top;//栈顶
- intJStackSize;//栈的元素个数
- };//栈结构的定义
- //boolIsOperator(charc);
- charCharProcess(JStack<float>&opndStack);
- charPrecede(chartheta1,chartheta2);
- floatEvaluateExpression(void);
- floatGetAnswer(floata,charc,floatb);
- #endif
define.cpp代码:
- #include<iostream>
- #include<string.h>
- #include"define.h"
- usingnamespacestd;
- template<typenameCustomType>
- boolJStack<CustomType>::InitJStack(void)//初始化栈
- {
- base=top=newCustomStruct<CustomType>;
- if(!base)
- returnfalse;
- returntrue;
- }
- template<typenameCustomType>
- boolJStack<CustomType>::Push(CustomTypee)//将元素压入栈顶
- {
- CustomStruct<CustomType>*temp;
- temp=top;
- top=newCustomStruct<CustomType>;
- if(!top)
- returnfalse;
- top->elem=e;
- top->link=temp;
- returntrue;
- }//此方法相当于头插法
- template<typenameCustomType>
- boolJStack<CustomType>::Pop(void)//将元素从栈中弹出
- {
- CustomStruct<CustomType>temp;
- temp.elem=top->elem;
- temp.link=top->link;
- deletetop;
- top=temp.link;
- returntrue;
- }
- template<typenameCustomType>
- CustomTypeJStack<CustomType>::GetTop(void)//取出栈顶的元素
- {
- returntop->elem;
- }
- floatEvaluateExpression(void)
- {//计算表达式的函数
- charc=0,operand;
- floata=0,b=0;//定义计算的操作数
- JStack<float>opndStack;//存储操作数的栈
- JStack<char>operStack;//存储操作符的栈
- opndStack.InitJStack();//初始化
- operStack.InitJStack();//初始化
- operStack.Push('=');
- do
- {
- if(c!='='&&c!=')')//如果当前未到等号位置,则继续处理字符
- c=CharProcess(opndStack);
- if(operStack.GetTop()=='('&&c==')')
- {//消去括号
- operStack.Pop();
- cin.get(c);
- }
- switch(Precede(operStack.GetTop(),c))
- {//对不同的情况进行操作
- case'<'://低优先级
- operStack.Push(c);break;
- case'='://优先级相等
- operStack.Pop();
- break;
- case'>'://高优先级
- b=opndStack.GetTop();//右操作数
- opndStack.Pop();//右操作数弹出
- operand=operStack.GetTop();//操作符
- operStack.Pop();//操作符弹出
- a=opndStack.GetTop();//左操作数
- opndStack.Pop();//左操作数弹出
- opndStack.Push(GetAnswer(a,operand,b));
- if(c!='='&&c!=')')//如果不是等号或者右边括号
- operStack.Push(c);//要将当前操作符入栈
- break;
- case'':
- break;
- }
- }
- while(c!='='||operStack.GetTop()!='=');//若未到等于符号,继续读取
- returnopndStack.GetTop();
- }
- charCharProcess(JStack<float>&opndStack)
- {
- chartemp[16]={0};//定义临时变量,用来存储字符串化的数字
- charc;//定义一个字符
- inti=0;//定义一个自增的变量
- cin.get(c);//读取一个字符
- if(c=='+'||c=='-'||c=='*'||c=='/'||c=='('||c==')')
- returnc;
- while(c>='0'&&c<='9'||c=='.')
- {//若是数字的话,将其放在临时的变量中
- temp[i++]=c;
- cin.get(c);//再取一个字符
- }//剩下的就是操作符了
- opndStack.Push(atof(temp));
- returnc;//返回当前操作符
- }
- charPrecede(chartheta1,chartheta2)
- {//对运算符的优先级进行判断的函数
- if(theta1=='+'||theta1=='-')
- {
- if(theta2=='+'||theta2=='-'||theta2==')'||theta2=='=')
- return'>';
- elsereturn'<';
- }
- if(theta1=='*'||theta1=='/')
- {
- if(theta2=='(')
- return'<';
- elsereturn'>';
- }
- if(theta1=='(')
- {
- if(theta2==')')
- return'=';
- elseif(theta2=='=')
- return'';
- elsereturn'<';
- }
- if(theta1==')')
- {
- if(theta2=='(')
- return'';
- elsereturn'>';
- }
- if(theta1=='=')
- {
- if(theta2=='=')
- return'=';
- elseif(theta2==')')
- return'';
- elsereturn'<';
- }
- return0;//返回错误信息
- }
- floatGetAnswer(floata,charoperand,floatb)
- {
- switch(operand)
- {
- case'+':returna+b;
- case'-':returna-b;
- case'*':returna*b;
- case'/':returna/b;
- }
- return0.0f;
- }
mainframe.cpp代码:
- #include<iostream>
- #include"define.h"
- intmain(intarg,char**argv)
- {
- floatanswer;
- answer=EvaluateExpression();
- std::cout<<"上述式子的结果是:"<<answer<<'/n';
- return0;
- }
程序的运行结果如图所示: