c++计算器后续(2)

自娱自乐:

大概是了解了一下前缀、中缀、后缀表示法是啥,并没有去深究,比如考虑实现啊,然后Calculation类里面的计算方法还是选用原来的直接对中缀表达式求值,只是把代码改得规范点,以上。

各表示法:

  • 中缀表示法:

    中缀表示法(或中缀记法)是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4)。与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被电脑解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
    与前缀或后缀记法不同的是,中缀记法中括号是必需的。计算过程中必须用括号将操作符和对应的操作数括起来,用于指示运算的次序。

  • 前缀表示法:

    波兰表示法(Polish notation,或波兰记法),是一种逻辑、算术和代数表示方法,其特点是操作符置于操作数的前面,因此也称做前缀表示法。如果操作符的元数(arity)是固定的,则语法上不需要括号仍然能被无歧义地解析。

  • 后缀表示法:

    逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。

举例说明:

  • '(3 + 4) × 5 - 6' 中缀
  • '- × + 3 4 5 6' 前缀
  • '3 4 + 5 × 6 -' 后缀

我们所习惯的表示法自然是中缀,但是对计算机来说,对后缀和前缀表达式进行计算要比中缀来得容易,因为相比后者带有括号,前面两个的运算优先级要好处理的多(感觉就是按优先级写的)。比如计算后缀表达式,只要从左到右遍历,遇到数字就入栈,遇到运算符就弹出两个数字运算,再把结果入栈,直到表达式末尾。像上面的例子,3、4入栈,遇到加号,弹出4、3相加,再把7入栈,接下来5入栈,遇到乘号,弹出5、7相乘,再把结果35入栈,继续6入栈,遇到减号,弹出6、35,计算35-6(大概要注意哪个减哪个),就得到结果啦。前缀也差不多,就是遍历的顺序啥的是相反的。

转化方法:

将中缀表达式转换为前缀表达式:

遵循以下步骤:

  • (1) 初始化两个栈:运算符栈S1和储存中间结果的栈S2;
  • (2) 从右至左扫描中缀表达式;
  • (3) 遇到操作数时,将其压入S2;
  • (4) 遇到运算符时,比较其与S1栈顶运算符的优先级:
    + (4-1) 如果S1为空,或栈顶运算符为右括号“)”,则直接将此运算符入栈;
    + (4-2) 否则,若优先级比栈顶运算符的较高或相等,也将运算符压入S1;
    + (4-3) 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
  • (5) 遇到括号时:
    + (5-1) 如果是右括号“)”,则直接压入S1;
    + (5-2) 如果是左括号“(”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃;
  • (6) 重复步骤(2)至(5),直到表达式的最左边;
  • (7) 将S1中剩余的运算符依次弹出并压入S2;
  • (8) 依次弹出S2中的元素并输出,结果即为中缀表达式对应的前缀表达式。

大概就是按照中缀的运算的优先级来写的,那些括号啊啥的,反正感觉很麻烦,我是没有去深究,这里也就只贴一个,参考的链接在这:点我

表达式树:

表达式好像还可以用二叉树来表示,比如:a+b*(c-d)-e/f,可以表示为下图的二叉树:

感觉也可以理解,直观上觉得很有道理的样子,然后据说不同的树的遍历方式,就能得到那三种表达式。

树的遍历:

下面以二叉树为例,也适用于其他树。

与那些基本上都有标准遍历方式(通常是按线性顺序)的线性数据结构(如链表、一维数组)所不同的是,树结构有多种不同的遍历方式。从二叉树的根节点出发,节点的遍历分为三个主要步骤:对当前节点进行操作(称为“访问”节点)、遍历左边子节点、遍历右边子节点。这三个步骤的先后顺序也是不同遍历方式的根本区别。

由于从给定的某个节点出发,有多个可以前往的下一个节点(树不是线性数据结构),所以在顺序计算(即非并行计算)的情况下,只能推迟对某些节点的访问——即以某种方式保存起来以便稍后再访问。常见的做法是采用栈(LIFO)或队列(FIFO)。

遍历方式的命名,源于其访问节点的顺序。最简单的划分:是深度优先(先访问子节点,再访问父节点,最后是第二个子节点)?还是广度优先(先访问第一个子节点,再访问第二个子节点,最后访问父节点)?

深度优先可进一步按照根节点相对于左右子节点的访问先后来划分。如果把左节点和右节点的位置固定不动,那么根节点放在左节点的左边,称为前序(pre-order)、根节点放在左节点和右节点的中间,称为中序(in-order)、根节点放在右节点的右边,称为后序(post-order)。对广度优先而言,遍历没有前序中序后序之分:给定一组已排序的子节点,其“广度优先”的遍历只有一种唯一的结果。

深度优先搜索的前序、中序、后序遍历得到的表达式就对应前缀、中缀、后缀表达式,大概,然后上面那么官方的东西自然不是我写的,来自维基百科。

顺便附带:

也去看了看命令行,感觉是个很厉害的东西,但是我还不会用它做什么很厉害的事。大概就是会到各个目录里,创建目录,删除目录之类,还发现了一个比较文件不同的命令,感觉计算器第三步说不定可以用来检验输出文件。这里给出一个感觉不错的教程:链接

posted @ 2016-07-27 16:59  archeroc  阅读(583)  评论(2编辑  收藏  举报