数据结构实验0

这篇博客介绍了C++实现数据结构中的栈类和一个小组项目的实现,该项目涉及中缀表达式到后缀表达式的转换,并在此过程中计算基本初等函数,如幂、三角函数、对数、取整和绝对值。博主分享了代码实现,并提到了代码可读性的改进方向。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

现在还在学习的初级阶段,可能有些地方很冗余,请各位大佬指教

本人就读于s大学的软件工程大二年级,数据结构老师是y老师,y老师一共给我们布置了1+4+1次实验即1次个人实验、4次小组实验、1次加分实验,为了不把花费好多时间的成果丢进垃圾桶,所以发到csdn给可能会有需要的学弟学妹们进行参考和交流,注意千万不要完全copy,毕竟我们老师要查重的,下面图片就是实验的要求。第一次个人实验Project 0因为比较简单(实际上是搞丢了)就不放在上面。所以从第一次小组实验Project 1来写时间有限,直接放代码,上面有注释

954766eef5394daa83bc6224baa91255.png

#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>
using namespace std;

//自定义结点类
template <class E>
class StackNode {
public:
	E data;//数据域 
	StackNode<E>* next;//指针域 
};

//自定义栈类
template <class E>
class LStack {
private:
	StackNode<E>* baseNode;
	StackNode<E>* topNode;
	int top = 0;
public:
	LStack() {
		topNode = new StackNode<E>;
		topNode->next = NULL;

		baseNode = new StackNode<E>;
		baseNode = topNode;
	}
	void Push(E data);
	E Pop();
	E GetTop();
	void Display();
};


//添加元素到栈顶
template <class E>
void LStack<E>::Push(E data) {
	StackNode<E>* p = new StackNode<E>;
	p->data = data;
	p->next = topNode;
	topNode = p;
	top++;

}


//移除栈顶元素
template <class E>
E LStack<E>::Pop() {
	E value;
	StackNode<E>* p = new StackNode<E>;
	p = topNode;
	//if (topNode == NULL) {
	//	return;
	//}
	value = topNode->data;
	topNode = topNode->next;
	delete p;
	top--;

	return value;
}


//获取栈顶元素
template <class E>
E LStack<E>::GetTop() {
	if (topNode->next != NULL) {
		return topNode->data;
	}

}


//展示栈中元素
template <class E>
void LStack<E>::Display() {
	StackNode<E>* curr = new StackNode<E>;
	curr = topNode;
	int i = 0;
	while (1) {
		if (top == 0) {
			break;
		}
		i++;
		cout << "第" << i << "个元素为(从上至下):" << curr->data << endl;
		curr = curr->next;
		top--;
	}
}

 这个是小组中另外一位同学写的栈的实现。

#include "stack.h"
#include <sstream>
#include<stdio.h>
#include<cmath>
//支持幂函数、三角函数、以e为底数的对数(可以来表示任意底数的对数函数logx(y)==log(y)/log(x)、取整(向下取整)、绝对值
//实现在中缀转后缀的时候将各种基本初等函数计算出来 
string InfixToSuffix(string str);//将参数str中缀表达式转后缀表达式,在这个阶段同时把所有的函数计算出来
double calculate(string str);
LStack<string>* symbolStack = new LStack<string>;//符号栈
LStack<double>* calStack = new LStack<double>;//通过子字符串的方法来实现功能
int SymbolPriority(string symbolstr) {//给运算符设立优先级
	if (symbolstr.compare("*") == 0 || symbolstr.compare("/") == 0) {
		return 2;
	}
	else if (symbolstr.compare("+") == 0 || symbolstr.compare("-") == 0) {
		return 1;
	}
	else if (symbolstr.compare("(") == 0) {
		return 0;
	}
	else if (symbolstr.compare("#") == 0) {//第一个运算符都进栈
		return -1;
	}
}
double change(char c) {//将字符转化成double在calculate函数和InfixToSuffix函数里面调用来判断是数字 
	char a[1] = { c };
	string s = a;
	return atof(s.c_str());
}
//将string里的浮点数转化为double型 (string只能转化为int型的) 
double changesubstr(string substring) {
	string floatheadstr = "";//浮点数小数点前
	string floattailstr = "";//浮点数小数点后
	int dothead = 0;//小数点前字符串转化为整型数
	int dottail = 0;//小数点后字符串转化为整型数
	bool dotappear = false;//判断小数点是否出现,初始值为false
	bool negative = false;
	int startplace = 0;
	if (substring.at(0) == '-') {
		negative = true;
		startplace = 1;
	}
	for (int i = startplace; i < substring.length(); i++) {//遍历字符串,将字符串分为小数点前和小数点后的两个子字符串 
		if (substring.at(i) == '.') {//判断小数点是否出现 
			if (!dotappear) {
				dotappear = true;
			}
			else if (dotappear) {//如果小数点已经出现又出现一个小数点则出错 
				cout << substring << "输入错误,有多个小数点" << endl;
			}
		}
		else {
			if (!dotappear) {//如果小数点没有出现,那么当前字符属于小数点前的字符串 
				floatheadstr = floatheadstr + substring.substr(i, 1);
			}
			else {//如果小数点出现了,那么当前数据字符属于小数点后的字符串 
				floattailstr = floattailstr + substring.substr(i, 1);
			}
		}
	}
	dothead = stoi(floatheadstr);//将小数点前的字符串转化为int 
	if (dotappear) {//如果小数点出现了那么还要将小数点后的字符串转为整型数 
		dottail = stoi(floattailstr);
	}
	if (negative) {
		if (!dotappear) {//如果小数点没出现,那么只需将整型数转化为double
			return -1.0 * (double)(dothead);
		}

		else {//返回作为参数的数据字符串的double型 
			double dottaildouble;
			dottaildouble = (double)(dottail);
			for (int k = 0; k < floattailstr.length(); k++) {
				dottaildouble = dottaildouble / (10.0);
			}
			return -1.0 * ((double)dothead + dottaildouble);
		}
	}
	else {
		if (!dotappear) {//如果小数点没出现,那么只需将整型数转化为double
			return (double)(dothead);
		}

		else {//返回作为参数的数据字符串的double型 
			double dottaildouble;
			dottaildouble = (double)(dottail);
			for (int k = 0; k < floattailstr.length(); k++) {
				dottaildouble = dottaildouble / (10.0);
			}
			return (double)dothead + dottaildouble;
		}
	}
}
//将幂函数计算出来转化为double型再转化string 
string powertodoubletostr(string substring) {
	bool caretappear = false;//判断^是否出现,初始值为false
	string caretheadstr = "";//^前数字符串
	string carettailstr = "";//^后字符串
	double carethead = 0.0;//^前字符串转化为double
	double carettail = 0.0;//^后字符串转化为double
	double fineresult = 0.0;//计算的数值转化为double
	string fineresultstr = "";//将基本初等函数计算出来转化为string 
	for (int i = 0; i < substring.length(); i++) {//遍历字符串 
		if (substring.at(i) == '^') {
			if (!caretappear) {//如果^出现,将caretappear置为true 
				caretappear = true;
			}
			else if (caretappear) {
				cout << substring << "输入错误,有多个^" << endl;
			}
		}
		else {
			if (!caretappear) {//如果^未出现,那么当前数据字符属于^前的字符串 
				caretheadstr = caretheadstr + substring.substr(i, 1);
			}
			else if (caretappear) {//如果^出现,那么当前数据字符数据属于^后的字符串 
				carettailstr = carettailstr + substring.substr(i, 1);
			}
		}
	}
	if (caretheadstr == "e") {
		caretheadstr = "2.7182818";
	}
	if (carettailstr == "e") {
		carettailstr = "2.7182818";
	}
	carethead = changesubstr(caretheadstr);//调用changesubter来将^前的字符串转化为double型 
	carettail = changesubstr(carettailstr);//调用changesubter来将^后的字符串转化为double型 
	fineresult = pow(carethead, carettail);//将幂函数计算出来 
	fineresultstr = to_string(fineresult);//将计算结果转化为string 
	return fineresultstr;
}
//将三角sin函数计算出来转化为double型再转化string 
string sintodoubletostr(string substring) {
	int startpos = 0;//含参数的字符串起始位置 
	int strlen = 0;//参数的长度 
	bool leftbracket = false;//三角函数括号里面是参数 
	string doublestring = "";//含参数的子字符串 
	double doublestringtodouble = 0.0;//将参数由string转化为double 
	double resultdouble = 0.0;//计算最后的结果 
	string resultdoubletostring = "";//将结果转化为string 
	for (int i = 0; i < substring.length(); i++) {//遍历字符串 
		if (substring.at(i) == '(' && i < (substring.length() - 1)) {//遇到(之后下一个位置是参数的起始位置 
			leftbracket = true;
			startpos = i + 1;
			strlen = 0;
		}
		else if (leftbracket && substring.at(i) != ')') {//遇到(之后)之前都是参数的一部分,每遇到字符一个长度需要加1 
			strlen++;
		}
		else if (substring.at(i) == ')') {
			leftbracket = false;
			break;
		}
		else {
			continue;
		}
	}
	doublestring = substring.substr(startpos, strlen);//含有参数的子字符串 
	doublestringtodouble = changesubstr(doublestring);//将参数转化为double
	resultdouble = sin(doublestringtodouble);//将函数值计算出来 
	resultdoubletostring = to_string(resultdouble);//将计算出的函数值转化为string 
	return resultdoubletostring;
}
//costodoubletostr函数和tantodoubletostr函数同sintodoubletostr函数里面都是将参数由string转化为double,计算出来函数值再转化为string 
string costodoubletostr(string substring) {
	int startpos = 0;//含参数的字符串起始位置 
	int strlen = 0;//参数的长度 
	bool leftbracket = false;//三角函数括号里面是参数 
	string doublestring = "";//含参数的子字符串 
	double doublestringtodouble = 0.0;//将参数由string转化为double 
	double resultdouble = 0.0;//计算最后的结果 
	string resultdoubletostring = "";//将结果转化为string 
	for (int i = 0; i < substring.length(); i++) {//遍历字符串 
		if (substring.at(i) == '(' && i < (substring.length() - 1)) {//遇到(之后下一个位置是参数的起始位置 
			leftbracket = true;
			startpos = i + 1;
			strlen = 0;
		}
		else if (leftbracket && substring.at(i) != ')') {//遇到(之后)之前都是参数的一部分,每遇到字符一个长度需要加1 
			strlen++;
		}
		else if (substring.at(i) == ')') {
			leftbracket = false;
			break;
		}
		else {
			continue;
		}
	}
	doublestring = substring.substr(startpos, strlen);//含有参数的子字符串 
	doublestringtodouble = changesubstr(doublestring);//将参数转化为string 
	resultdouble = cos(doublestringtodouble);//将函数值计算出来 
	resultdoubletostring = to_string(resultdouble);//将计算出的函数值转化为string
	return resultdoubletostring;
}
//tan函数 
string tantodoubletostr(string substring) {
	int startpos = 0;//含参数的字符串起始位置 
	int strlen = 0;//参数的长度 
	bool leftbracket = false;//三角函数括号里面是参数 
	string doublestring = "";//含参数的子字符串 
	double doublestringtodouble = 0.0;//将参数由string转化为double 
	double resultdouble = 0.0;//计算最后的结果 
	string resultdoubletostring = "";//将结果转化为string 
	for (int i = 0; i < substring.length(); i++) {//遍历字符串 
		if (substring.at(i) == '(' && i < (substring.length() - 1)) {//遇到(之后下一个位置是参数的起始位置 
			leftbracket = true;
			startpos = i + 1;
			strlen = 0;
		}
		else if (leftbracket && substring.at(i) != ')') {//遇到(之后)之前都是参数的一部分,每遇到字符一个长度需要加1 
			strlen++;
		}
		else if (substring.at(i) == ')') {
			leftbracket = false;
			break;
		}
		else {
			continue;
		}
	}
	doublestring = substring.substr(startpos, strlen);//含有参数的子字符串 
	doublestringtodouble = changesubstr(doublestring);//将参数转化为string 
	resultdouble = tan(doublestringtodouble);//将函数值计算出来 
	resultdoubletostring = to_string(resultdouble);//将计算出的函数值转化为string 
	return resultdoubletostring;
}
//log函数 
string logtodoubletostr(string substring) {
	int startpos = 0;//含参数的字符串起始位置 
	int strlen = 0;//参数的长度 
	bool leftbracket = false;//三角函数括号里面是参数 
	string doublestring = "";//含参数的子字符串 
	double doublestringtodouble = 0.0;//将参数由string转化为double 
	double resultdouble = 0.0;//计算最后的结果 
	string resultdoubletostring = "";//将结果转化为string 
	for (int i = 0; i < substring.length(); i++) {//遍历字符串 
		if (substring.at(i) == '(' && i < (substring.length() - 1)) {//遇到(之后下一个位置是参数的起始位置 
			leftbracket = true;
			startpos = i + 1;
			strlen = 0;
		}
		else if (leftbracket && substring.at(i) != ')') {//遇到(之后)之前都是参数的一部分,每遇到字符一个长度需要加1 
			strlen++;
		}
		else if (substring.at(i) == ')') {
			leftbracket = false;
			break;
		}
		else {
			continue;
		}
	}
	doublestring = substring.substr(startpos, strlen);//含有参数的子字符串 
	doublestringtodouble = changesubstr(doublestring);//将参数转化为string 
	resultdouble = log(doublestringtodouble);//将函数值计算出来 
	resultdoubletostring = to_string(resultdouble);//将计算出的函数值转化为string 
	return resultdoubletostring;
}
//向下取整函数 
string floortodoubletostr(string substring) {
	int startpos = 0;//参数起始位置 
	int strlen = 0;//参数长度 
	bool leftbracket = false;//判断[是否出现 
	string doublestring = "";//参数的子字符串 
	double doublestringtodouble = 0.0;//参数转化为double类型 
	double resultdouble = 0.0;//计算结果 
	string resultdoubletostring = "";//计算结果转化为string类型 
	for (int i = 0; i < substring.length(); i++) {//遍历字符串 
		if (substring.at(i) == '[' && i < (substring.length() - 1)) {//如果[出现,下一个位置是参数起始范围 
			leftbracket = true;
			startpos = i + 1;
			strlen = 0;
		}
		else if (leftbracket && substring.at(i) != ']') {//[之后]之前字符都属于参数 
			strlen++;
		}
		else if (substring.at(i) == ']') {
			leftbracket = false;
			break;
		}
		else {
			continue;
		}
	}
	doublestring = substring.substr(startpos, strlen);
	doublestringtodouble = changesubstr(doublestring);//将参数转化为double型来计算 
	resultdouble = floor(doublestringtodouble);//计算出来函数值 
	resultdoubletostring = to_string(resultdouble);//函数值转化为string型 
	return resultdoubletostring;
}
//绝对值函数 
string absolutevaluetodoubletostr(string substring) {
	int startpos = 0;//参数起始范围 
	int strlen = 0;//参数范围 
	bool leftbracket = false;//判断|是否出现 
	string doublestring = "";//参数的子字符串 
	double doublestringtodouble = 0.0;//参数转化为double型 
	double resultdouble = 0.0;//计算出来的函数值 
	string resultdoubletostring = "";//将函数值转化为string 
	for (int i = 0; i < substring.length(); i++) {
		if (!leftbracket && substring.at(i) == '|' && i < (substring.length() - 1)) {//|下一个字符位置是参数起始位置 
			leftbracket = true;
			startpos = i + 1;
			strlen = 0;
		}
		else if (leftbracket && substring.at(i) != '|') {//两个|之间字符都是参数 
			strlen++;
		}
		else if (leftbracket && substring.at(i) == '|') {//参数结束 
			leftbracket = false;
			break;
		}
		else {
			continue;
		}
	}
	doublestring = substring.substr(startpos, strlen);
	doublestringtodouble = changesubstr(doublestring);
	resultdouble = fabs(doublestringtodouble);//计算出绝对值 
	resultdoubletostring = to_string(resultdouble);//绝对值转化为字符串 
	return resultdoubletostring;
}
int fab(int n)//阶乘函数的实现
{
	int a;
	if (n > 0)
	{
		a = n * fab(n - 1);
	}
	else
	{
		a = 1;
	}

	return a;
}
int fab2(int n)//双阶乘函数的实现
{
	int a;
	if (n > 0)
	{
		a = n * fab2(n - 2);
	}
	else
	{
		a = 1;
	}

	return a;
}
string fabtointtostring(string substring) {//计算阶乘值(调用阶乘函数)再转化为string型
	string intstring = "";//参数的子字符串 
	int intstringtoint = 0;//参数转化为int类型 
	int resultint = 0;//计算结果 
	string resultinttostring = "";//计算结果转化为string类型
	for (int i = 0; i < substring.length(); i++) {//遍历字符串 
		if (substring.at(i) != '!') {
			intstring = intstring + substring.substr(i, 1);
		}
		else {
			break;
		}
	}
	intstringtoint = stoi(intstring);
	resultint = fab(intstringtoint);//计算出来函数值 
	resultinttostring = to_string(resultint);//函数值转化为string型 
	return resultinttostring;
}
string fab2tointtostring(string substring) {//计算阶乘值(调用阶乘函数)再转化为string型
	string intstring = "";//参数的子字符串 
	int intstringtoint = 0;//参数转化为int类型 
	int resultint = 0;//计算结果 
	string resultinttostring = "";//计算结果转化为string类型
	for (int i = 0; i < substring.length()-1; i++) {//遍历字符串 
		if (substring.at(i) != '!') {
			intstring = intstring + substring.substr(i, 1);
		}
		else {
			break;
		}
	}
	intstringtoint = stoi(intstring);
	resultint = fab2(intstringtoint);//计算出来函数值 
	resultinttostring = to_string(resultint);//函数值转化为string型 
	return resultinttostring;
}
//将后缀表达式计算出结果(不含三角函数等) 
double calculate(string str) {
	double sum = 0.0;//储存计算的结果 
	bool whetherinnum = false;//判断是否在字符串里面,初始
	int startpos;//要截取的子字符串起始位置
	int strlen;//要截取的子字符串长度
	string substring;//含有数据的子字符串(数据不仅一个字符) 
	double doublefromsubstring;//子字符串转化为的浮点数 
	for (int i = 0; i < str.length(); i++) {
		if (str.at(i) == ' ') {//如果当前字符是空格 
			if (whetherinnum) {//当前是空格且前一个字符属于数据,那么数据结束,将string型的数转化为double型的压入数据栈中 
				substring = str.substr(startpos, strlen);
				doublefromsubstring = changesubstr(substring);
				calStack->Push(doublefromsubstring);
				whetherinnum = false;
			}
			continue;
		}
		else if (str.at(i) == '+') {//当前是+号 
			if (whetherinnum) {//当前是+且前一个字符属于数据,那么数据结束,将string型的数转化为double型的压入数据栈中 
				substring = str.substr(startpos, strlen);
				doublefromsubstring = changesubstr(substring);
				calStack->Push(doublefromsubstring);
				whetherinnum = false;
			}
			sum = calStack->Pop() + calStack->Pop();//取数据栈顶的两个数据相加 
			calStack->Push(sum);//将结果值压入栈中 
		}
		else if (str.at(i) == '-') {//当前字符数-号 
			if (whetherinnum) {// 当前字符是-且前一个字符属于数据,那么数据结束,将string型的数转化为double型的压入数据栈中 
				substring = str.substr(startpos, strlen);
				doublefromsubstring = changesubstr(substring);
				calStack->Push(doublefromsubstring);
				whetherinnum = false;
			}//将栈顶的两个元素相减之后的结果压入栈中 
			if (str.at(i + 1) != ' ') {
				whetherinnum = true;
				startpos = i;
				strlen = 1;
			}
			if (str.at(i + 1) == ' ') {
				double sub1;
				double sub2;
				sub2 = calStack->Pop();
				sub1 = calStack->Pop();
				sum = sub1 - sub2;
				calStack->Push(sum);
			}
		}
		else if (str.at(i) == '*') {//当前字符是*号 
			if (whetherinnum) {//当前字符是*且一个字符属于数据,那么数据结束,将string型的数转化为double型的压入数据栈中  
				substring = str.substr(startpos, strlen);
				doublefromsubstring = changesubstr(substring);
				calStack->Push(doublefromsubstring);
				whetherinnum = false;
			}
			//将栈顶的两个元素相乘再压入栈中 
			sum = calStack->Pop() * calStack->Pop();
			calStack->Push(sum);
		}
		else if (str.at(i) == '/') {//当前字符是/号 
			if (whetherinnum) {//当前字符是/且一个字符属于数据,那么数据结束,将string型的数转化为double型的压入数据栈中  
				substring = str.substr(startpos, strlen);
				doublefromsubstring = changesubstr(substring);
				calStack->Push(doublefromsubstring);
				whetherinnum = false;
			}
			//将栈顶的两个元素相乘再压入栈中 
			double div1;
			double div2;
			div2 = 1.0 * calStack->Pop();
			div1 = 1.0 * calStack->Pop();
			sum = div1 / div2;
			calStack->Push(sum);
		}
		//当前字符如果是数字或者小数点那么属于数据的一部分 
		else if ((change(str.at(i)) >= 0 && change(str.at(i)) <= 9) || str.at(i) == '.') {
			if ((!whetherinnum) && change(str.at(i)) >= 0 && change(str.at(i)) <= 9) {//如果之前不在数字里面,说明这是在起始位置
				startpos = i;//要截的字符串起始位置
				whetherinnum = true;
				strlen = 1;
			}
			else if (whetherinnum) {
				strlen++;
			}
		}


	}

	return calStack->GetTop();
}

//中缀转后缀,同时实现将函数计算成double型进而转化成string
string InfixToSuffix(string str) {
	/**1.从左到右遍历中缀表达式的每个数字和运算符;
	   2.若当前字符是数字,则直接输出成为后缀表达式的一部分;
	   3.若当前字符为运算符,则判断其与栈顶运算符的优先级,若优先级大于栈顶运算符,则进栈;若优先级小于栈顶运算符,退出栈顶运算符成为后缀表达式的一部分,然后将当前运算符放入栈中;
	   4.若当前字符为“(”,进栈;
	   5.若当前字符为“)”,则从栈顶起,依次将栈中运算符出栈成为后缀表达式的一部分,直到碰到“(”。将栈中“(”出栈,不需要成为后缀表达式的一部分,然后继续扫描表达式直到最终输出后缀表达式为止。
	*/
	//两个数据之间以空格为间隔
	symbolStack->Push("#");//保证第一个运算符无条件进栈
	string returnstr = "";//要返回的字符串
	bool whetherinnum = false;//判断是否在小数或者整数字符串里面
	bool whetherinpower = false;//判断是否在幂的字符串里面
	bool whetherinsin = false;//判断是否在sin函数里面
	bool whetherincos = false;//判断是否在cos函数里面
	bool whetherintan = false;//判断是否在tan函数里面
	bool whetherinlog = false;//判断是否在log函数里面
	bool whetherinfloor = false;//判断是否在高斯函数里面
	bool whetherinabsolutevalue = false;//判断是否在绝对值运算里面
	bool whetherinfab = false;//判断是否在阶乘运算里面 
	bool whetherinfab2 = false;//判断是否在双阶乘运算里面
	int startpos = 0;//要截取的子字符串起始位置
	int strlen = 0;//要截取的子字符串长度
	string substring = "";//截取的字符串
	int leftbracket = 0;//左括号数目,初始化为0
	int frompos = 0;
	if (str.at(0) == '-') {//处理单目运算符负号'-' 
		returnstr = "0";
		frompos = 1;
	}
	for (int i = frompos; i < str.length(); i++) {//挨个遍历字符串,将运算量转化为string(基本初等函数先转化为double,再转化为string) 
		//处理左括号 
		if (str.at(i) == '(') {
			if (whetherinnum) {//鲁棒性处理 
				cout << "数字和左括号之间没有运算符" << endl;
				symbolStack->Push(str.substr(i, 1));
				leftbracket++;
			}
			else if (whetherinsin || whetherincos || whetherintan || whetherinlog) {//处理三角函数和log函数,属于函数的一部分所以不加1 
				strlen++;
			}
			else {//处理单目运算符,即在左括号和单目运算符之间加0 
				symbolStack->Push(str.substr(i, 1));
				leftbracket++;
				if (str.at(i + 1) == '-') {
					returnstr = returnstr + " " + "0";
				}
			}
			continue;
		}
		//处理中间的空格 
		else if (str.at(i) == ' ') {
			if (whetherinnum) {//判断数字数据的结束 
				substring = str.substr(startpos, strlen);
				whetherinnum = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else if (whetherinpower) {//判断幂函数数据的结束 
				substring = str.substr(startpos, strlen);
				substring = powertodoubletostr(substring);//将带有函数符号的转化为数
				whetherinpower = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else if (whetherinfab) {//判断阶乘数据的结束 
				substring = str.substr(startpos, strlen);
				substring = fabtointtostring(substring);//将带有函数符号的转化为数
				whetherinfab = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else if (whetherinfab2) {//判断阶乘数据的结束 
				substring = str.substr(startpos, strlen);
				substring = fab2tointtostring(substring);//将带有函数符号的转化为数
				whetherinfab2 = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			if (i < (str.length() - 1))//在主函数中最后一个字符为空格,如果是不是最后一个空格继续遍历 
				continue;
			else if (i == (str.length() - 1)) {//如果是最后一个空格那么将之前的运算符由运算符栈顶写进后缀表达式里面 
				while (symbolStack->GetTop() != "#") {
					returnstr = returnstr + " " + symbolStack->Pop();
				}
			}
		}
		//处理右括号 
		else if (str.at(i) == ')') {
			if (whetherinnum) {
				substring = str.substr(startpos, strlen);
				whetherinnum = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
				while (symbolStack->GetTop() != "(") {
					returnstr = returnstr + " " + symbolStack->Pop();
				}
				symbolStack->Pop();//把(从符号栈中排出来
				leftbracket--;
			}
			else if (whetherinpower) {
				substring = str.substr(startpos, strlen);
				substring = powertodoubletostr(substring);//将带有函数符号的转化为数
				whetherinpower = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
				while (symbolStack->GetTop() != "(") {
					returnstr = returnstr + " " + symbolStack->Pop();
				}
				symbolStack->Pop();//把(从符号栈中排出来
				leftbracket--;
			}
			else if (whetherinfab) {
				substring = str.substr(startpos, strlen);
				substring = fabtointtostring(substring);//将带有函数符号的转化为数
				whetherinfab = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
				while (symbolStack->GetTop() != "(") {
					returnstr = returnstr + " " + symbolStack->Pop();
				}
				symbolStack->Pop();//把(从符号栈中排出来
				leftbracket--;
			}
			else if (whetherinfab2) {
				substring = str.substr(startpos, strlen);
				substring = fab2tointtostring(substring);//将带有函数符号的转化为数
				whetherinfab2 = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
				while (symbolStack->GetTop() != "(") {
					returnstr = returnstr + " " + symbolStack->Pop();
				}
				symbolStack->Pop();//把(从符号栈中排出来
				leftbracket--;
			}
			//如果在sin cos tan log里面属于函数的一部分 是初等函数的终结,所以不减1 
			else if (whetherinsin) {
				strlen++;
				substring = str.substr(startpos, strlen);
				substring = sintodoubletostr(substring);//将带有函数符号的转化为数
				whetherinsin = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else if (whetherincos) {
				strlen++;
				substring = str.substr(startpos, strlen);
				substring = costodoubletostr(substring);//将带有函数符号的转化为数
				whetherincos = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else if (whetherintan) {
				strlen++;
				substring = str.substr(startpos, strlen);
				substring = tantodoubletostr(substring);//将带有函数符号的转化为数
				whetherintan = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else if (whetherinlog) {
				strlen++;
				substring = str.substr(startpos, strlen);
				substring = logtodoubletostr(substring);//将带有函数符号的转化为数
				whetherinlog = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else {//如果不是基本初等函数的一部分,那么将运算符从栈顶依次输出直到( 
				while (symbolStack->GetTop() != "(") {
					returnstr = returnstr + " " + symbolStack->Pop();
				}
				symbolStack->Pop();//把(从符号栈中排出来
				leftbracket--;
			}
		}
		else if (str.at(i) == '+' || str.at(i) == '-' || str.at(i) == '*' || str.at(i) == '/') {
			if (str.at(i) == '-' && (whetherinabsolutevalue || whetherinsin || whetherincos || whetherintan || whetherinfloor)) {
				strlen++;
				continue;
			}
			if (whetherinnum) {//如果是运算符且前一个字符为幂(转化为数据压入栈)或者浮点数结束,压入栈中 
				substring = str.substr(startpos, strlen);
				whetherinnum = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else if (whetherinpower) {
				substring = str.substr(startpos, strlen);
				substring = powertodoubletostr(substring);//将带有函数符号的转化为数
				whetherinpower = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else if (whetherinfab) {
				substring = str.substr(startpos, strlen);
				substring = fabtointtostring(substring);//将带有函数符号的转化为数
				whetherinfab = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else if (whetherinfab2) {
				substring = str.substr(startpos, strlen);
				substring = fab2tointtostring(substring);//将带有函数符号的转化为数
				whetherinfab2 = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			//如果优先级比栈顶运算符高,进栈 
			if (SymbolPriority(str.substr(i, 1)) > SymbolPriority(symbolStack->GetTop())) {
				symbolStack->Push(str.substr(i, 1));
			}//如果运算符优先级低,那么将运算高的依次出栈,最后将该运算符压入栈中 
			else if (SymbolPriority(str.substr(i, 1)) <= SymbolPriority(symbolStack->GetTop())) {
				while (SymbolPriority(str.substr(i, 1)) <= SymbolPriority(symbolStack->GetTop())) {
					returnstr = returnstr + " " + symbolStack->Pop();
				}
				symbolStack->Push(str.substr(i, 1));
			}
		}
		//如果当前是自然指数e转化为数值 
		else if (str.at(i) == 'e' && !whetherinpower) {
			returnstr = returnstr + " " + "2.7182818";
		}
		//如果当前是pi转化为数值
		else if (str.at(i) == 'p') {
			returnstr = returnstr + " " + "3.1415926";
		}
		//如果该字符是浮点数、幂、三角函数、向下取整函数、指数函数的一部分 
		else if (str.at(i) == '.' || str.at(i) == '!' || str.at(i) == '^' || str.at(i) == 't' || str.at(i) == 'a' || str.at(i) == 'n' || str.at(i) == 's' || str.at(i) == 'i' || str.at(i) == 'c' || str.at(i) == 'o' || str.at(i) == '|' || str.at(i) == '[' || str.at(i) == ']' || str.at(i) == 'l' || str.at(i) == 'g' || ((change(str.at(i)) >= 0 && change(str.at(i)) <= 9))) {
			if ((!whetherinnum) && (!whetherinpower) && (!whetherinsin) && (!whetherincos) && (!whetherintan) && (!whetherinlog) && (!whetherinfloor) && (!whetherinabsolutevalue)&&(!whetherinfab)&&(!whetherinfab2) && change(str.at(i)) >= 0 && change(str.at(i)) <= 9 && str.at(i) != '.' && str.at(i) != '!' && str.at(i) != '^' && str.at(i) != 't' && str.at(i) != 'a' && str.at(i) != 'n' && str.at(i) != 's' && str.at(i) != 'i' && str.at(i) != 'c' && str.at(i) != 'o' && str.at(i) != '|' && str.at(i) != '[' && str.at(i) != ']' && str.at(i) != 'l' && str.at(i) != 'g') {//如果之前不在数字里面,说明这是在起始位置
				startpos = i;//要截的字符串起始位置
				whetherinnum = true;
				strlen = 1;
			}
			else if (whetherinnum && str.at(i) == '!')
			{
				whetherinnum = false;
				whetherinfab = true;
				strlen++;
			}
			else if (whetherinfab && str.at(i) == '!')
			{
				whetherinfab = false;
				whetherinfab2 = true;
				strlen++;
			}
			else if (whetherinnum && str.at(i) == '^') {//如果之前是浮点数那么出现^之后该数就是幂,起始位置和长度接着浮点数来计算 
				whetherinnum = false;
				whetherinpower = true;
				strlen++;
			}
			else if (str.at(i) == 's' && (!whetherincos)) {//sin和cos都有s
				whetherinsin = true;
				startpos = i;//要截的字符串起始位置
				strlen = 1;
			}
			else if (str.at(i) == 't') {//tan起始 
				whetherintan = true;
				startpos = i;//要截的字符串起始位置
				strlen = 1;
			}
			else if (str.at(i) == 'c') {//cos起始 
				whetherincos = true;
				startpos = i;//要截的字符串起始位置
				strlen = 1;
			}
			else if (str.at(i) == 'l') {//log起始 
				whetherinlog = true;
				startpos = i;//要截的字符串起始位置
				strlen = 1;
			}
			else if (!whetherinabsolutevalue && str.at(i) == '|') {//绝对值函数起始 
				whetherinabsolutevalue = true;
				startpos = i;//要截的字符串起始位置
				strlen = 1;
			}
			else if (whetherinabsolutevalue && str.at(i) == '|') {//绝对值函数结束 
				strlen++;
				substring = str.substr(startpos, strlen);
				substring = absolutevaluetodoubletostr(substring);//将带有函数符号的转化为数
				whetherinabsolutevalue = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else if (str.at(i) == '[') {//向下取整函数开始 
				whetherinfloor = true;
				startpos = i;//要截的字符串起始位置
				strlen = 1;
			}
			else if (str.at(i) == ']' && whetherinfloor) {//向下取整函数结束 
				strlen++;
				substring = str.substr(startpos, strlen);
				substring = floortodoubletostr(substring);//将带有函数符号的转化为数
				whetherinfloor = false;
				strlen = 0;
				returnstr = returnstr + " " + substring;
			}
			else {
				strlen++;//其他的长度加1,说明在一种数据类型里面 
			}
		}
	}
	return returnstr + " ";
}
int main() {
	int x = 0;
	while (x != 999) {
		string str;
		cout << "请选择输入方式:(1)中缀表达式 (2)后缀表达式" << endl;
		string choice;
		getline(cin, choice);
		cout << "输入:";
		getline(cin, str);//输入计算表达式
		if (choice.at(0) == '1') {
			str = str + " ";//在表达式尾部加上空格,方便后续操作 
			str = InfixToSuffix(str);//中缀转后缀 
		}
		cout << str << endl;
		printf("%.2f", calculate(str));//保留两位小数
		cout << " " << endl;
	}
	return 0;
}

这是我实现的cpp,大家不要学我一样变量名写的这么长,否则会被小组其同学埋怨可读性不好了

具体的算法思想可以在另一位同学的实验报告中看到,对就是上面那位同学。

这是实验报告

一.前言

项目重述:利用图实现对两地最短路径的求取。

算法描述:将输入的算术表达式先转为后缀表达式,再对后缀表达式求值。

 

二.项目技术 

2.1 主要数据结构的设计

本项目主要采用C++面向对象的思想来制作。

 

1.自定义结点类G:数据域(data),指针域(*next)。用于定义链栈的结点。

 

2.自定义栈类LStack:私有:栈顶指针(topNode),栈顶(top);公有:构造函数(LStack()),出栈(Pop()),入栈(Push()),获得栈顶指针(GetTop()),展示栈(Display())。用于定义栈,以及栈内的操作。

 

 

2.2 主要算法

 

1.为运算符设定优先级(SymbolPriority):‘*’ ‘/’优先级为2;‘+’ ‘-’优先级为1;‘(’优先级为1,‘#’优先级为-1(处理单目负)。

 

2.将string转化为double(针对整数)(change):运用atof函数将单个字符转为double。

 

3.将string里的浮点数转化为double型(changesubstr):遍历字符串,首先判断是否存在小数点‘.’,若不存在,则直接将字符串转为double;若存在,则将字符串分为小数点前和小数点后的两个子字符串(若在两个子字符串中又出现一个小数点则提示错误),分别将小数点前后的字符串转为double。

 

4.处理幂函数(powertodoubletostr):遍历字符串,首先判断是否存在‘^’,若不存在,则直接将字符串转为double;若存在,则将字符串分为前和后的两个子字符串,分别将前后的字符串转为double,最后调用pow函数计算出结果。

 

5.处理三角函数(弧度制)和对数函数(sintodoubletostr/costodoubletostr/ tantodoubletostr/logtodoubletostr):遍历字符串,若第一个非数字为s则认为是sin;若为c则认为是cos;若为t则认为是tan;若为l则认为是log(若均不存在则直接将字符串转化为double),分别调用sin函数,cos函数,tan函数,log函数,计算出结果。(log函数默认以e为底,若要计算其他底数,则需转换logx(y)==log(y)/log(x))。

 

6.处理向下取整函数(floortodoubletostr):遍历字符串,若出现‘[’则认为是向下取整函数,取出在‘[’和‘]’之间的字符串,将其转为double,调用floor函数,计算出结果。

 

7.处理绝对值函数(absolutevaluetodoubletostr):遍历字符串,若出现‘|’则认为是向下取整函数,取出在‘|’和‘|’之间的字符串,将其转为double,调用fabs函数,计算出结果。

 

8.处理阶乘函数(fabtointtostring):遍历字符串,若出现‘!’则认为是阶乘函数,将阶乘前的字符串转为double类型,调用自定义的fab函数,计算出结果。

 

9.处理双阶乘函数(fab2tointtostring):遍历字符串,若出现‘!!’则认为是双阶乘函数,将阶乘前的字符串转为double类型,调用自定义的fab2函数,计算出结果。

 

10.中缀转后缀的实现(InfixToSuffix):(在此阶段所有基本初等函数被计算出来)

(1).从左到右遍历中缀表达式的每个数字和运算符;

(2).若当前字符是数字,则直接输出成为后缀表达式的一部分;

(3).若当前字符为运算符,则判断其与栈顶运算符的优先级,若优先级大于栈顶运算符,则进栈;若优先级小于栈顶运算符,退出栈顶运算符成为后缀表达式的一部分,然后将当前运算符放入栈中;

(4).若当前字符为“(”,进栈;

(5).若当前字符为“)”,则从栈顶起,依次将栈中运算符出栈成为后缀表达式的一部分,直到碰到“(”。将栈中“(”出栈,不需要成为后缀表达式的一部分,然后继续扫描表达式直到最终输出后缀表达式为止。

 

11.后缀表达式的计算(calculate):从左到右遍历后缀表达式的每个数字和符号,遇到的是数字就进栈,遇到的是符号,就将栈顶的两个数字依次出栈,进行运算(运算规则:后出栈的数字 符号 先出栈的数字),再将运算结果进栈,直到获得最终结果。

 

三、系统测试

四、分析和总结 

4.1算法复杂度分析

 

时间复杂度

空间复杂度

设定运算符优先级

θ(1)

θ(1)

change函数

θ(1)

θ(1)

changesubstr函数

θ(length)

θ(1)

处理幂函数

θ(length)

θ(1)

处理三角函数和对数函数

θ(length)

θ(1)

处理向下取整函数

θ(length)

θ(1)

处理绝对值函数

θ(length)

θ(1)

处理阶乘函数

θ(length)

θ(1)

处理双阶乘函数

θ(length)

θ(1)

中缀转后缀

θ(length2)

θ(1)

后缀的计算

θ(length2)

θ(1)

 

4.2项目亮点

本项目除了对基本运算符进行了实现,适用于整数,小数的计算,还对一些初等函数进行了实现,包括幂函数,指数函数,对数函数,三角函数,取整函数,绝对值函数,阶乘函数,双阶乘函数,并且实现了两类特殊数字的运算,分别为派π和自然对数e。整个系统泛用性较强,并带有检错处理,从而能用于多种情况。

 

4.3不足之处

项目中对部分函数的命名较为冗长,易读性较低;同时系统的核心功能即中转后缀和后缀的计算设计较为啰嗦,代码不易维护,整个系统的架构不太清晰。部分函数不能进行嵌套处理,只能进行单一运算。

 

4.4改进方向

在未来,我们可以增加更多形式的计算,比如进制的转换,角度制与弧度制的转换,余切函数,反三角函数,向上取整函数等;进一步规范代码,使之易读;简化核心代码。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值