数据结构之栈(中缀转后缀计算四则运算)
2018-01-26 12:02
465 查看
前面转载了一篇有关栈的基础讲解的文章,所以这篇文章就不再说有关栈的概念性内容了。
这篇文章主要的内容,就是用学到的栈的基础操作,来实现一个输入中缀四则运算表达式(+ - * /),转换成后缀表达式,然后计算结果并输出的小程序。表达式中可以有括号,操作数可以是多位整数(不支持小数,不过要修改也很容易)。
2.栈为空时,遇到运算符,入栈;
3.遇到左括号,将其入栈;
4.遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出;
5.遇到其他运算符’+”-”*”/’时,弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈;
6.最终将栈中的元素依次出栈,输出。
经过上面的步骤,得到的输出既是转换得到的后缀表达式。
举例:a+b*c+(d*e+f)g ———> abc+de*f+g*+具体步骤:
const int maxlen = 100;//栈的最大存储量
template <typename T>
class stack
{
public:
stack(); //构造函数,用于初始化(C++11新特性可以在类的声明中初始化变量)
bool empty(); //判断栈是否为空
bool full(); //判断栈是否为满
T gettop(); //取栈顶元素
bool push(T x); //元素入栈
T pop(); // 弹出栈顶
private:
int count; //元素的计数器
T data[maxlen]; //顺序存储结构
};
template <typename T>
stack<T>::stack()
{
count = 0;
};
template <typename T>
bool stack<T>::empty()
{
if (count == 0)
return true;
return false;
};
template <typename T>
bool stack<T>::full()
{
if (count == maxlen)
return true;
return false;
};
template <typename T>
T stack<T>::gettop()
{
T x;
x = data[count - 1];
return x;
};
template <typename T>
bool stack<T>::push(T x)
{
if (!full())
{
data[count++] = x;
return true;
}
return false;
};
template <typename T>
T stack<T>::pop()
{
T x;
count--;
x = data[count];
return x;
};要自定义栈结构的话,最好也是用C++的模板,因为最少会用到两个类型的栈。
class calculator
{
private:
stack<char> scMidToPost; //用于中缀转后缀
stack<float> sfCalculate; //用于计算后缀表达式
public:
string strInput; //输入的中缀表达式
string strPost; //得到的后缀表达式
void Input(string strTemp); //得到输入的中缀表达式
void Change(); //中缀转后缀
float Calculate(); //计算
};
{
strInput = strTemp; //输入
}
void calculator::Change()
{
int length = strInput.length(); //表达式长度
char cJudge;
for (int i = 0; i < length; i++)
{
char cTemp; //临时变量
cJudge = strInput[i]; //当前字符
switch (cJudge)
{
case '(':
scMidToPost.push(cJudge);
break;
case ')':
while (!scMidToPost.empty())
{
cTemp = scMidToPost.pop(); //相当于查看栈顶
if (cTemp != '(') //把直到左括号位置的全部弹出
strPost = strPost + cTemp;
else
break;
}
break;
case '+':
case '-':
while (!scMidToPost.empty())
{
cTemp = scMidToPost.pop();
if (cTemp == '(') //只有左括号的优先级小于+、-
{
scMidToPost.push(cTemp);
break;
}
else
{
strPost = strPost + cTemp; //其他全是优先级大于等于,全部弹出
}
}
scMidToPost.push(cJudge);
break;
case '*':
case '/':
while (!scMidToPost.empty())
{
cTemp = scMidToPost.pop();
if (cTemp == '+' || cTemp == '-' || cTemp == '(')
{ //*、/除了它们自己,其他的优先级全部小于它们
scMidToPost.push(cTemp);
break;
}
else
{
strPost = strPost + cTemp;
}
}
scMidToPost.push(cJudge);
break;
default:
if (cJudge >= '0'&& cJudge <= '9') //如果是操作数,就在两端加上‘#’
{
strPost = strPost + '#';
while (strInput[i] >= '0'&&strInput[i] <= '9')
{
strPost = strPost + strInput[i];
i++;
}
i--; //要回退一位
strPost = strPost + '#';
}
break;
}
}
while (!scMidToPost.empty())
{
strPost = strPost + scMidToPost.pop();
}
cout << strPost << endl; //输出后缀表达式
}4.计算后缀表达式得到结果
float calculator::Calculate()
{
char cJudge;
int length = strPost.length();
float fResult; //保存结果
float fTemp; //临时变量
for (int i = 0; i < length; i++)
{
cJudge = strPost[i];
if (cJudge == '+' || cJudge == '-' || cJudge == '*' || cJudge == '/')
{ //如果是操作符,那么就进行相应计算
float right = sfCalculate.pop(); //右操作数,后进先出
float left = sfCalculate.pop(); //左操作数,先进后出
switch (cJudge)
{
case '+':
fTemp = right + left;
sfCalculate.push(fTemp);
break;
case '-':
fTemp = left-right;
sfCalculate.push(fTemp);
break;
case '*':
fTemp = left*right;
sfCalculate.push(fTemp);
break;
case '/':
fTemp = left/right;
sfCalculate.push(fTemp);
break;
default:
break;
}
}
else if (cJudge == '#') //遇到'#'号则说明是操作数
{
i++;
fResult = 0;
while (strPost[i] != '#')
{
fTemp = strPost[i] - '0';
fResult = fResult * 10 + fTemp; //把字符形式的操作数变为浮点型
i++;
}
sfCalculate.push(fResult); //操作数入栈
}
}
fResult = sfCalculate.gettop();
return fResult;
}
这篇文章主要的内容,就是用学到的栈的基础操作,来实现一个输入中缀四则运算表达式(+ - * /),转换成后缀表达式,然后计算结果并输出的小程序。表达式中可以有括号,操作数可以是多位整数(不支持小数,不过要修改也很容易)。
中缀转后缀方法:
1.遇到操作数,直接输出;2.栈为空时,遇到运算符,入栈;
3.遇到左括号,将其入栈;
4.遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出;
5.遇到其他运算符’+”-”*”/’时,弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈;
6.最终将栈中的元素依次出栈,输出。
经过上面的步骤,得到的输出既是转换得到的后缀表达式。
举例:a+b*c+(d*e+f)g ———> abc+de*f+g*+
具体步骤:
1.首先自定义一个栈结构
(这里用的是之前第一次写的时候,在网上找的代码,希望作者莫见怪)const int maxlen = 100;//栈的最大存储量
template <typename T>
class stack
{
public:
stack(); //构造函数,用于初始化(C++11新特性可以在类的声明中初始化变量)
bool empty(); //判断栈是否为空
bool full(); //判断栈是否为满
T gettop(); //取栈顶元素
bool push(T x); //元素入栈
T pop(); // 弹出栈顶
private:
int count; //元素的计数器
T data[maxlen]; //顺序存储结构
};
template <typename T>
stack<T>::stack()
{
count = 0;
};
template <typename T>
bool stack<T>::empty()
{
if (count == 0)
return true;
return false;
};
template <typename T>
bool stack<T>::full()
{
if (count == maxlen)
return true;
return false;
};
template <typename T>
T stack<T>::gettop()
{
T x;
x = data[count - 1];
return x;
};
template <typename T>
bool stack<T>::push(T x)
{
if (!full())
{
data[count++] = x;
return true;
}
return false;
};
template <typename T>
T stack<T>::pop()
{
T x;
count--;
x = data[count];
return x;
};要自定义栈结构的话,最好也是用C++的模板,因为最少会用到两个类型的栈。
2.然后是定义一个计算用的类
(类中封装了要使用的栈,以及进行相应的操作函数)class calculator
{
private:
stack<char> scMidToPost; //用于中缀转后缀
stack<float> sfCalculate; //用于计算后缀表达式
public:
string strInput; //输入的中缀表达式
string strPost; //得到的后缀表达式
void Input(string strTemp); //得到输入的中缀表达式
void Change(); //中缀转后缀
float Calculate(); //计算
};
3.输入并实现中缀转后缀
void calculator::Input(string strTemp){
strInput = strTemp; //输入
}
void calculator::Change()
{
int length = strInput.length(); //表达式长度
char cJudge;
for (int i = 0; i < length; i++)
{
char cTemp; //临时变量
cJudge = strInput[i]; //当前字符
switch (cJudge)
{
case '(':
scMidToPost.push(cJudge);
break;
case ')':
while (!scMidToPost.empty())
{
cTemp = scMidToPost.pop(); //相当于查看栈顶
if (cTemp != '(') //把直到左括号位置的全部弹出
strPost = strPost + cTemp;
else
break;
}
break;
case '+':
case '-':
while (!scMidToPost.empty())
{
cTemp = scMidToPost.pop();
if (cTemp == '(') //只有左括号的优先级小于+、-
{
scMidToPost.push(cTemp);
break;
}
else
{
strPost = strPost + cTemp; //其他全是优先级大于等于,全部弹出
}
}
scMidToPost.push(cJudge);
break;
case '*':
case '/':
while (!scMidToPost.empty())
{
cTemp = scMidToPost.pop();
if (cTemp == '+' || cTemp == '-' || cTemp == '(')
{ //*、/除了它们自己,其他的优先级全部小于它们
scMidToPost.push(cTemp);
break;
}
else
{
strPost = strPost + cTemp;
}
}
scMidToPost.push(cJudge);
break;
default:
if (cJudge >= '0'&& cJudge <= '9') //如果是操作数,就在两端加上‘#’
{
strPost = strPost + '#';
while (strInput[i] >= '0'&&strInput[i] <= '9')
{
strPost = strPost + strInput[i];
i++;
}
i--; //要回退一位
strPost = strPost + '#';
}
break;
}
}
while (!scMidToPost.empty())
{
strPost = strPost + scMidToPost.pop();
}
cout << strPost << endl; //输出后缀表达式
}
4.计算后缀表达式得到结果
float calculator::Calculate(){
char cJudge;
int length = strPost.length();
float fResult; //保存结果
float fTemp; //临时变量
for (int i = 0; i < length; i++)
{
cJudge = strPost[i];
if (cJudge == '+' || cJudge == '-' || cJudge == '*' || cJudge == '/')
{ //如果是操作符,那么就进行相应计算
float right = sfCalculate.pop(); //右操作数,后进先出
float left = sfCalculate.pop(); //左操作数,先进后出
switch (cJudge)
{
case '+':
fTemp = right + left;
sfCalculate.push(fTemp);
break;
case '-':
fTemp = left-right;
sfCalculate.push(fTemp);
break;
case '*':
fTemp = left*right;
sfCalculate.push(fTemp);
break;
case '/':
fTemp = left/right;
sfCalculate.push(fTemp);
break;
default:
break;
}
}
else if (cJudge == '#') //遇到'#'号则说明是操作数
{
i++;
fResult = 0;
while (strPost[i] != '#')
{
fTemp = strPost[i] - '0';
fResult = fResult * 10 + fTemp; //把字符形式的操作数变为浮点型
i++;
}
sfCalculate.push(fResult); //操作数入栈
}
}
fResult = sfCalculate.gettop();
return fResult;
}
总结:
栈可以说是最最基础,同时也是最最重要的数据结构了,许多底层的实现都利用了栈结构。个人认为,它的先进后出的特点,可以很方便的实现保存某些数据或者某种状态的效果,就像一个桶一样。可以说是妙用无穷.....相关文章推荐
- 四则运算之中缀表达式转后缀表达式
- 中缀计算四则运算表达式
- 中缀/后缀表达式转换-使用四则混合运算表达式生成树
- 中缀/后缀表达式转换-使用四则混合运算表达式生成树
- 中缀表达式的计算(只包含四则运算与括号)
- 简易四则运算,利用中缀转后缀表达…
- C语言写的秒速计算四则混合运算项目
- Java实现四则运算表达式计算
- 中缀转后缀并计算
- PTA 表达式转换 算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。
- 华为机试:计算日期到天数转换、四则运算
- 中缀试转后缀试及前缀试并计算其结果
- 【原创】Delphi实现数学表达式的计算(逆波兰式法)-四则运算解析
- 从键盘上输入一个后缀表达式,试编写算法计算表达式的值。规定:逆波兰表达式的长度不超过一行,以$符作为输入结束,操作数之间用空格分隔,操作符只可能有+、-、*、/四种运算。例如:234 34+2*$。
- 中缀表达式转化为后缀表达式,并计算结果
- 栈-中缀转后缀及后缀计算
- IDG | 四则运算表达式计算
- 二叉树实现运算符优先级算法,支持表达式前缀,中缀,后缀,层次,广义表输出
- 简易计算中缀表达式 支持+-*/以及()运算
- 表达式计算(中缀转后缀,然后求值)