C++ implements calculator

1. Experiment purpose (Objects)

1. Master the operation and application of the stack;

2. Understand the robustness of the algorithm;

2. Experimental content (Contents)

1. Realize the lp, rp and operate functions in the calculator class;

2. Improve the evaluate function of the calculator class, increase the legality check of the input, including filtering out all illegal input and processing the input where the left and right brackets do not match;

3. Create an application to test the calculator;

4. Test with the following expression:

(56-23)/8-4# 期望结果:0.125 
34+p(u89-12.3)k/3# 期望结果:59.5667 
89.5*749+25)# 期望结果:输入有误 
(8*(7-4)# 期望结果:输入有误 
65*(72+98)(70-45)# 期望结果:输入有误 
6*# 期望结果:输入有误 
)5+3(# 期望结果:输入有误

5. Verify the calculation results.

3. Experimental steps (Yourstepsorcodes)

1st. Overall design

The overall design of this experiment is based on two classes (class) as the main framework. One is the Stack class; the other is the Calculator class. Among them, Generic is used for the Stack class. Its overall design is as follows:

/********************************************栈的构建*********************************************/ 
template<typenameT> 
classStack{
    
    //栈模板类的创建与其数据变量 
private:
	T* n;//栈中存储数据的数组; 
	Stac_Int Nlen;//栈当前长度; 
	Stac_Int capacity;//栈的最长长度; 
	Stac_Int top_;//存储当前栈顶元素的下标; 
public:
	Stack();//构造函数 
	~Stack();//析构函数 
	void push(Tx);//栈的 push函数,向栈顶添加元素 
	T top();//栈的 top函数,返回栈顶元素 
	bool isEmpty();//栈的为空判断 
	bool isFull();//栈的为满判断 
	Stac_Int backNlen();//返回栈的长度 
	void pop();//栈的 pop函数,弹出栈顶元素 
	void to_empty();//清空栈 
	};
	//****************************************计算器类的构建*******************************************// 
classCalculator{
    
     
private:
	Stack<char> optr;//运算符栈; 
	Stack<double> opnd;//运算数栈; 
	char* at;//计算器类的运算式字符串的头指针; 
	int n; 
	int lp(chara);//返回字符栈头部字符的优先级命令; 
	int rp(chara);//返回录入读取字符的优先级命令; 
	double char_to_double(char*a,intn);
	//该函数进行字符串的小数转换成 double类型的小数(但只对有一个点 的小数有作用) 
	double operate_double(chara,doublex1,doublex2);//该函数计算两数的四则运算 
public:
	Calculator();//无参构造函数; 
	Calculator(char*a,intnn);//含参构造函数; 
	~Calculator();//析构函数; 
	void operate();对输入的一串算术字符串式的处理(核心处理函数); 
	bool rr(chara)const;//辅助函数; 
	bool evaluate()const;//判断输入的一串算术字符串是否合法; 
	double result();//返回运算结果; 
	};

Regarding the core function definitions of the Stack class and the Calculator class, I will detail them in the column of the algorithm framework.

2nd. Algorithm Framework

1. About the algorithm framework of the core functions of the Stack class:

The core function is:

void push(T x);//栈的 push函数,向栈顶添加元素 
T top();//栈的 top函数,返回栈顶元素 
void pop();//栈的 pop函数,弹出栈顶元素 
void to_empty();//清空栈

1>. About the push function:

//栈的 push函数,向栈顶添加元素 
template<typename T> 
void Stack<T>::push(T x){
    
    
 if(!isFull()){
    
     
 	top_++; 
 	n[top_]=x; 
 	Nlen++; 
 	}
 else
 	printf("堆栈已满;创建失败!\n"); 
 }

When the stack is not empty, let top_, which saves the foot code of the top element of the stack, increase by one first and then let n[top_]=x; at this time, the stack element increases, Nlen++; when the stack is empty, output "the stack is full; Creation failed!".

2>. About the pop function:

//栈的 pop函数,弹出栈顶元素 
template<typename T> 
void Stack<T>::pop(){
    
     
	top_--; 
	Nlen--; 
}

Only top_–;Nlen–; is required.

3>. About the top function:

//栈的 top函数,返回栈顶元素 
template<typename T> 
T Stack<T>::top(){
    
     
	returnn[top_]; 
}

Just return the top element directly.

4>. About the to_empty function:

//清空栈 
template<typename T> 
void Stack<T>::to_empty(){
    
     
	top_=0; 
	Nlen=0; 
}

Just let the footer of the top element of the stack be 0 and the stack length be 0.

2. About the framework of Calculator class core functions:

The core function is:

void operate();对输入的一串算术字符串式的处理(核心处理函数);
double char_to_double(char*a,int n);
//该函数进行字符串的小数转换成 double类型的小数(但只对有一个点的小 数有作用)

The following are helper functions:

 int lp(char a);//返回字符栈头部字符的优先级命令; 
 int rp(char a);//返回录入读取字符的优先级命令; 
 double operate_double(char a,double x1,double x2);//该函数计算两数的四则运算 
 bool rr(char a)const;//辅助函数; 
 bool evaluate()const;//判断输入的一串算术字符串是否合法; 
 double result();//返回运算结果;

For its main definition, see the source code.

1>. Discuss the implementation algorithm of the char_to_double function:

//该函数进行字符串的小数转换成 double类型的小数(但只对有一个点的小数有作用) 
double Calculator::char_to_double(char*a,int n){
    
     
	double su=0; 
	int i; 
	int t1=-1; 
	int t2; 
	for(i=0;i<n;i++){
    
     
		if(a[i]=='.'){
    
     
			t1=i; break; 
			} 
		}
		if(t1!=-1){
    
     
			t2=t1-1; 
			for(i=0;i<t1;i++,t2--){
    
     
				su+=(a[i]-'0')*pow(10,t2); 
				}
			int j=-1; 
			for(i=t1+1;i<n;i++,j--){
    
     
				su+=(a[i]-'0')*pow(10,j); 
				} 
			}
			else {
    
     
				t2=n-1; 
				for(i=0;i<n;i++,t2--) 
					su+=(a[i]-'0')*pow(10,t2); 
					}
				return su; 
		}

In this function, the double type variable of su is used to store the decimal after converting the final string type number into double type. First pass in the number of the string, first judge whether it has a decimal point:

for(i=0;i<n;i++){
    
     
	if(a[i]=='.'){
    
     
		t1=i; 
		break; 
		} 
	}

If so, use t1 to store the subscript of the current array element, and t1 is initially -1 to determine whether the string number has a decimal point. If it is, it is divided into two parts for processing: the integer part and the decimal part.

if(t1!=-1){
    
    
	t2=t1-1; 
	for(i=0;i<t1;i++,t2--){
    
     
		su+=(a[i]-'0')*pow(10,t2);
	}
	int j=-1; 
	for(i=t1+1;i<n;i++,j--){
    
     
		su+=(a[i]-'0')*pow(10,j); 
		} 
	}else {
    
     
		t2=n-1; 
		for(i=0;i<n;i++,t2--) 
			su+=(a[i]-'0')*pow(10,t2); 
}

If not, just deal with the integer part. Finally return to su.
Algorithm complexity analysis: The worst case is that there is no decimal point, then each element must be processed twice, so it is processed 2*n times. That is O(n);

2>. About the implementation of the operate function;

//对输入的一串算术字符串式的处理 
void Calculator::operate(){
    
     
	int i; 
	int k=0; 
	int t=0; 
	char a1; 
	int ii; 
	double tt1,tt2; 
	optr.push('#'); 
	for(i=0;i<n;i++){
    
     
		if(at[i]>='0'&&at[i]<='9'){
    
     
		/*这部分主要是在截取输入的算式字符串中的数字字符串部分, 截取之后需要借助 char_to_double()函数把字符串数字转换成 double类型的值,然后才可以压入 opnd栈中*/ 
		k=i; 
		while((at[i]>='0'&&at[i]<='9')||at[i]=='.'){
    
     
			t++; 
			i++; 
			}
		char u[100]; 
		for(ii=0;ii<t;ii++,k++) 
			u[ii]=at[k]; 
		opnd.push(char_to_double(u,t)); 
		t=0; 
		i--; 
		}
		else if(at[i]=='#'&&optr.top()=='#') /*如果此时读取到'#',则什么都不做, 也意味着结束整体处理*/		else{
    
    /*以下是算符优先级的实现*/ 
			while(1){
    
     
				if(rp(at[i])==-1) /*过滤非算符非数字的字符*/ 
				break; 
				else if(rp(at[i])>lp(optr.top())){
    
     optr.push(at[i]); /*如果传入字符优先级大于 optr栈顶字符优先级 则压入栈顶。*/ 
					break;
	}
	else if(rp(at[i])<lp(optr.top())){
    
     
		a1=optr.top(); 
		optr.pop(); 
		tt1=opnd.top(); 
		opnd.pop(); 
		tt2=opnd.top(); 
		opnd.pop(); 
		opnd.push(operate_double(a1,tt2,tt1)); /*如果传入字符优先级小于 optr栈顶字符优先级 则进行四则运算处理,处理结果,之后压入 opnd栈顶*/ 
		}
	else if(
		rp(at[i])==lp(optr.top())){
    
     
			optr.pop(); /*如果传入字符优先级与 optr栈顶优先级相等 则弹出 optr栈顶字符。*/ 
			break; } } } } }

The main algorithm of this part is the character priority algorithm and the algorithm for intercepting string numbers: As follows: first determine the algorithm idea of ​​operator priority: the
insert image description here
idea of ​​operator priority can be specified as shown in the above figure.
Firstly, the horizontal operator can be called t2 operator, and the vertical operator can be called t1 operator. The figure above shows the priority relationship between operators.
The priority relationship is derived from the four arithmetic rules:
- first multiply and divide, then add and subtract
- first left and then right
- first inside the brackets and then outside the brackets
The following is an algorithmic description of the order of operator operations:
*Set up an operator stack x1 and an operand stack x2. Put the terminator # at the bottom of the x1 stack.
*Scan the expression from left to right, if it is an operand, push it into the x2 stack, and continue scanning; if it is an operator t2, compare it with the top element t1 of the x1 stack: -
If t2t1'#', the operation ends, and the result is on the top of the x2 stack;
- If the priority of t2 is high, t2 enters the x1 stack and continues scanning;
- If the priorities are equal, exit the x1 stack top element '(', continue scanning;
- If the priority of t2 is low, exit t1 from the x1 stack, exit the two operands b and a from the x2 stack, and push the result into the x2 stack after performing the operation at1b. Its implementation is as follows
:

if(at[i]=='#'&&optr.top()=='#') /*如果此时读取到'#',则什么都不做, 也意味着结束整体处理*/ ; 
	else{
    
    /*以下是算符优先级的实现*/ 
		while(1){
    
     
			if(rp(at[i])==-1) /*过滤非算符非数字的字符*/ 
				break; 
			else if(rp(at[i])>lp(optr.top())){
    
     
				optr.push(at[i]); /*如果传入字符优先级大于 optr栈顶字符优先级 则压入栈顶。*/ 
				break; 
			}
			else if(rp(at[i])<lp(optr.top())){
    
     
				a1=optr.top(); 
				optr.pop(); 
				tt1=opnd.top(); 
				opnd.pop(); 
				tt2=opnd.top(); 
				opnd.pop(); 
				opnd.push(operate_double(a1,tt2,tt1)); /*如果传入字符优先级小于 optr栈顶字符优先级 则进行四则运算处理,处理结果,之后压入 opnd栈顶*/ 
				}
			else if(rp(at[i])==lp(optr.top())){
    
     
				optr.pop(); /*如果传入字符优先级与 optr栈顶优先级相等 则弹出 optr栈顶字符。*/ 
				break; 
				} 
	}

Then there is an algorithm for intercepting the string number, and converting it into a double type number and pushing it to the top of the opnd stack:

if(at[i]>='0'&&at[i]<='9'){
    
     /*这部分主要是在截取输入的算式字符串中的数字字符串部分, 截取之后需要借助 char_to_double()函数把字符串数字转换成 double类型的值,然后才可以压入 opnd栈中*/ 
	k=i; 
	while((at[i]>='0'&&at[i]<='9')||at[i]=='.'){
    
     
		t++; 
		i++; 
		}
	char u[100]; 
	for(ii=0;ii<t;ii++,k++) 
		u[ii]=at[k]; 
		opnd.push(char_to_double(u,t)); 
		t=0; 
		i--; 
	}

First use k to store the subscript of the character that is originally a number in the array, and then continue traversing until a certain at[i] is not a number or '.'. Use t to calculate the length of the string's digits. Then save it to a new array at u[100]. Finally, the char_to_double() function is called to convert u[t] into a double type and push the number that can directly perform four arithmetic operations to the top of the opnd stack. Finally initialize t. It is convenient for next use.

Four. Source Program (SourceProgram)

For various reasons, it is not convenient to display the source code here.
If you need the source code, you can private message me.

Guess you like

Origin blog.csdn.net/weixin_42529594/article/details/120455067