精华内容
下载资源
问答
  • 2020-04-28 23:05:16

    前缀运算符是从右到左
    后缀运算符是从左到右
    !!!

    如:
    1.*++pt:现将++应用于pt,然后将 * 应用于被递增后的pt

    double x = *++pt;//increment pointer, take the value; i,e., arr[2], or 23.4
    

    2.++* pt
    另一方面,++* pt意味着先取得pt指向的值,然后将这个值加1,即为24.4
    在这种情况下pt仍指向原来的arr[2]。

    3.( *pt ) ++

    (*pt)++;//increment pointed-to value
    

    圆括号首先指出,首先对指针解除引用,得到24.4.然后,运算符++将这个值递增到25.4,pt任指向arr[2]。
    4.*pt++

    x = *pt++;//dereference original location, then increment pointer
    

    后缀运算符++的优先级更高,这意味着将运算符用于pt,而不是* pt,因此对指针递增,然而后缀运算符意味着对原来的地址(&arr[2])而不是递增后的新地址解除引用,因此*pt++的值为arr2[2],即为25.4,但该语句执行完毕后,pt的值为arr[3]的地址。

    更多相关内容
  • 输入一元表达式和自变量,可计算一元表达式的值,算法支持的运算符有+、-、*、/、%、^、ln、sin、cos.
  • 简述前缀运算符后缀运算符

    千次阅读 2016-12-26 20:45:45
    在程序设计时,应该养成使用前缀运算符的习惯,在C++软件工程中,经常会涉及到较大的类类型需要重载运算符,在不产生歧义的情况下,尽量使用前缀运算符能够帮助我们提高程序的执行速度。
    对于初学者,经常纠结的一个问题就是 for 循环中的循环量递增过程中,到底是应该用前缀运算符还是后缀运算符。

    • 逻辑
    首先谈一下前缀运算符和后缀运算符有什么区别:粗略的讲,
      • a++是当前值计算表达式,然后将变量a的值+1;
      • 而++a是先将a的值+1,然后使用新的值来计算表达式。
    (这里涉及到表达式和语句、副作用和顺序点,有点复杂,暂时不在这里阐述。)
    在大多数情况下(一个正常的软件工程规定的程序设计规范和风格,应该是尽量避免那种考题式的容易含糊的语句,应该尽量使用意思明确,即:一条语句实现一个功能)是没有区别的,就逻辑上来说,for 循环中,使用前缀运算符和后缀运算符所得的结果都是一样的,但是这里涉及到一个重要的问题:效率!!!

    • 效率
    我们在设计程序时,应当尽量减少程序的开销,在能够使用较少内存的地方,绝不去占用多的内存,这样可以提高程序的执行速度。
    对于内置类型和当代的编译器而言,这没有多大差别。但是一旦涉及到程序员自定义的类类型时,就会体现出很大差别。(C++允许程序员重定义运算符,称之为 运算符重载),如果把一个占用内存较大的类作为循环量对其使用递增(递减)运算符时,我们就应当使用前缀运算符++a(--a)。
    原因如下:
      • 前缀运算符:(程序员自定义)将值+1,然后返回结果;
      • 后缀运算符:首先复制一个副本,将其值+1,然后将复制的副本返回。
    很明显能看出两者之间的差别吧。

    所以,在程序设计时, 应该养成使用前缀运算符的习惯,在C++软件工程中,经常会涉及到较大的类类型需要重载运算符,在不产生歧义的情况下,尽量使用前缀运算符能够帮助我们提高程序的执行速度。
    展开全文
  • java三目运算符表达式 Java应用程序通过评估表达式来处理数据, 表达式是文字,方法调用,变量名和运算符的组合。 评估表达式通常会产生一个新值,该值可以存储在变量中,用于决策等。 在本教程中,您将学习如何为...

    java三目运算符表达式

    Java应用程序通过评估表达式来处理数据, 表达式是文字,方法调用,变量名和运算符的组合。 评估表达式通常会产生一个新值,该值可以存储在变量中,用于决策等。

    在本教程中,您将学习如何为Java程序编写表达式。 在许多情况下,您将使用运算符来编写Java表达式,并且有很多类型的运算符都知道如何使用。 我将简要介绍Java的运算符类型(包括加性,按位,逻辑,条件,移位和相等类型)及其操作数。 您还将了解重要的概念,例如运算符重载和运算符优先级,并且将看到原始类型转换的演示。 我将以一个小型Java程序结束,您可以使用该Java程序自己进行原始类型的转换。

    下载
    下载本教程中示例应用程序的源代码。 由Jeff Friesen为JavaWorld创建。

    简单表达

    一个简单的表达式是文字,变量名或方法调用。 没有操作员参与。 以下是一些简单表达式的示例:

    52                         // integer literal
    age                        // variable name
    System.out.println("ABC"); // method call
    "Java"                     // string literal
    98.6D                      // double precision floating-point literal
    89L                        // long integer literal

    一个简单的表达式具有type ,它可以是原始类型或引用类型。 在这些示例中, 52是32位整数( int ); System.out.println("ABC"); 为void( void ),因为它不返回任何值; "Java"是一个字符串( String ); 98.6D是64位双精度浮点值( double ); 89L是64位长整数( long )。 我们不知道age的类型。

    试用jshell

    您可以使用jshell轻松尝试这些以及其他简单表达式。 例如,在jshell>提示符下输入52 ,您将收到类似以下输出的内容:

    $1 ==> 52

    $1jshell创建以存储52临时变量的名称。 (只要输入文字,便会创建暂存变量。)执行System.out.println($1) ,您将看到52作为输出。

    您可以使用-v命令行参数( jshell -v )运行jshell来生成详细反馈。 在这种情况下,输入52将导致以下消息,表明暂存变量$1具有int (32位整数)类型:

    |  created scratch variable $1 : int

    接下来,尝试输入age 。 在这种情况下,您可能会收到一条错误消息,指出未找到该符号。 Java Shell假定age是一个变量,但它不知道其类型。 您将必须包括一个类型。 例如,查看如果输入int age会发生什么。

    复合表达式

    复合表达式由一个或多个简单表达式组成,这些简单表达式通过运算符集成到较大的表达式中,该运算符是在源代码中以符号表示的一系列指令。 运算符将其表达式操作数转换为另一个值。 例如,在6 * 5 ,乘法运算符( * )将操作数65转换为30。

    复合表达式可以组合成更大的表达式。 例如, 6 * 5 + 10表示复合表达式6 * 5以及由其乘积,加法运算符+和数字10组成的复合表达式。 评估的顺序(先乘后加)由Java的优先级规则决定,我们稍后将介绍。

    复合表达式也可以很简单

    6 * 5是由两个简单表达式65组成的复合表达式。 但是从+的角度来看, 6 * 5也是一个简单的表达式。 +运算符只能看到其乘积30,这是一个简单的表达式。

    运算符和操作数

    Java的运算符按其操作数进行分类:

    • 元运算符具有一个操作数,例如一元减号 (例如-5 )。
    • 二进制运算符有两个操作数,例如乘法和加法。
    • 三元运算符具有三个操作数; 一个示例是条件运算符?:

    Java的运算符也按位置分类:

    • 前缀运算符是在其操作数(例如-5 )之前的一元运算符。
    • 后缀运算符是跟随其操作数的一元运算符(例如age++; -将age的数值加1)。
    • 前缀运算符是运算符的操作数之间的二进制或三进制运算符(例如age + 5 )。

    另一个jshell示例

    在以下各节中,我将以应用程序的形式介绍示例,以介绍更多运算符。 您也可以使用jshell尝试这些运算符,如下所示:

    jshell> 6 + 2
    $1 ==> 8
    
    jshell> 7 * $1
    $2 ==> 56

    在这种情况下,我们首先输入jshell求值的表达式6 + 2 ,将结果8分配给临时变量$1 。 接下来,我们将$1乘以7 ,将56存储在临时变量$2 。 本示例说明您可以在Java表达式中使用暂存变量。

    重载运算符

    加号(+)运算符是重载运算符的一个示例,该运算符是根据其操作数的类型执行几种运算之一的运算符。 当两个操作数都是整数时,plus运算符执行整数加法,当两个操作数都是浮点值时执行浮点加法,并且当两个操作数都是字符串时执行字符串连接。 负号(-)运算符也重载,执行整数或浮点减法。

    Java中的运算符类型

    加法运算符

    加法运算符通过加法和减法来增加或减少数值。 加法运算符包括加法( + ),减法( - ),后减量( -- ),后增量( ++ ),前减量( -- )和预增量( ++ )。 字符串串联( + )也被认为是可加的。 这是每个运算符的正式定义:

    • 另外 :由于operand1 + operand2 ,其中每个操作数必须是字符或数字型的,添加operand2operand1和返回的总和。 示例: 4 + 6
    • 减法 :由于operand1 - operand2 ,其中每个操作数必须是字符或数字型的,减去operand2operand1和返回的差异。 示例: 4 - 6
    • 后减量 :给定variable -- ,其中variable必须为字符或数字类型,请从variable的值中减去1(将结果存储在variable )并返回原始值。 示例: x--;
    • Postincrement :给定variable ++ ,其中variable必须为字符或数字类型,将1加到variable的值上(将结果存储在variable )并返回原始值。 示例: x++;
    • 预递减 :鉴于-- variable ,其中variable必须是字符或数字型的,从它的值中减去1,结果存储在variable ,并返回新递减的值。 示例:-- --x;
    • 预增量 :给定++ variable ,其中variable必须为字符或数字类型,将其值加1,将结果存储在variable ,然后返回新的增量值。 示例: ++x;
    • 字符串连接 :给定operand1 + operand2 ,其中至少一个操作数是String类型,附加operand2的字符串表示来operand1的字符串表示,并返回结果。 示例: "A" + "B"

    加,减,后减,后加,前减和前加运算符可以生成溢出结果类型限制的值。 例如,将两个大的正的64位正整数相加会产生一个无法用64位表示的值。 Java的加法运算符未检测到或未报告所导致的溢出。

    Java标准类库中的溢出检测

    标准类库的Math类包括用于检测溢出的方法。 例如, int addExact(int x, int y)xy的值相加,返回总和或在溢出时引发异常。

    应用示例:加法运算符

    清单1给出了一个用于与Java的加法运算符一起玩的小应用程序。

    清单1. Java中的加法运算符(AddOp.java)

    class AddOp
    {
       public static void main(String[] args)
       {
          System.out.println(125 + 463);
          System.out.println(2.0 - 6.3);
          int age = 65;
          System.out.println(age);
          System.out.println(age--);
          System.out.println(age++);
          System.out.println(--age);
          System.out.println(++age);
          System.out.println("A" + "B");
       }
    }

    您在上一教程中学习了如何使用JDK的javac工具来编译Java源代码,以及如何使用java工具来运行生成的应用程序。 执行以下命令来编译清单1:

    javac AddOp.java

    假设编译成功,您应该在当前目录中观察一个AddOp.class文件。 执行以下命令以运行它:

    java AddOp

    AddOp通过产生以下输出进行响应:

    588
    -4.3
    65
    65
    64
    64
    65
    AB

    研究此输出可以深入了解后递增,后递减,前递增和前递减运算符。 对于后增/后减, age的当前值在增/减操作之前输出。 对于预增/减,执行操作并将其结果存储在age ,然后输出age的新值。

    用Java运算符迭代

    可加运算符在迭代语句的上下文中特别有用,在该语句中 ,它们用于前进到下一个迭代。 在下一个Java 101教程中,您将学习迭代语句

    数组索引运算符

    数组索引运算符[] )通过提供元素的索引 (位置)来访问数组元素。 该运算符放置在数组变量名称之后,如grades[0] (访问分配给grades的数组中的第一个元素;第一个元素存储在索引0中)。 这是一个正式定义:

    给定variable [ index ] ,其中index必须是整数( int )类型,请从位置index处的variable的存储元素中读取值或将值存储到其中。 示例: temperatures[1]

    传递给index的值是一个32位整数,该值可以是0或正值,其范围比数组长度小1,这可以通过在数组名称后附加.length来表示。 例如, grades.length返回数组中分配给grades的元素数。

    数组变量与数组

    grades不是数组,而是一个变量,它包含对形成数组的内存区域的引用。 所有Java数组都是如此。 但是,通常将grades或任何数组变量称为数组。

    示例应用程序:数组索引运算符

    清单2将源代码提供给示例应用程序,使您可以使用数组索引运算符。

    清单2. Java中的数组索引运算符(ArrayIndexOp.java)

    class ArrayIndexOp
    {
       public static void main(String[] args)
       {
          int[] grades = { 89, 90, 68, 73, 79 };
          System.out.println(grades[1]);
          grades[1] = 91;
          System.out.println(grades[1]);
          int index = 4;
          System.out.println(grades[index]);
          System.out.println(grades['C' - 'A']);
    //      System.out.println(grades[1D]);
       }
    }

    清单2比清单1更加有趣。在创建一个五元素的一维整数数组(通过数组初始化器)并将该数组的引用分配给gradesmain()继续访问各种元素。 有两个特别重要的事项:

    • 数组索引运算符的索引最终必须是32位整数(0或正值)。 您可以将包含索引值的整数变量的名称(例如index )指定为索引。
    • 您可以指定涉及字符文字的计算。 (在本教程的后面,我将介绍类型转换,您将发现为什么'C' - 'A'产生一个整数(2),该整数用作有效索引。)

    最后一个将1D作为索引传递给数组索引运算符的示例被注释掉,因为它不会编译。 如果取消注释该行并尝试编译清单2,您将收到有关不兼容类型的错误消息:“可能从doubleint.有损转换。”

    编译清单2( javac ArrayIndexOp.java )并运行应用程序( java ArrayIndexOp )。 您应该观察以下输出:

    90
    91
    79
    68

    数组索引运算符和多维数组

    您可以将此运算符与多维数组一起使用。 例如,假设一个二维costs数组, costs[0][1]访问分配给第一行(通过[0] )和第二列(通过[1] )的元素。

    赋值运算符

    赋值运算符= )将表达式的值赋给变量(例如i = 6; ),其中包括数组元素(例如x[0] = 15; )。 表达式和变量必须是赋值兼容的 ,这意味着它们的类型必须一致。 例如,您不能将字符串文字分配给整数变量。 当我们讨论类型转换时,我将详细解释。

    复合赋值运算符( +=-=*=/=%=&=|=^=<<=>>=>>>= )评估表达式并将结果分配给变量一步。 每个表达式和变量必须与赋值兼容。 每个运算符都是有用的快捷方式。 例如,代替指定x = x + 3; ,您可以指定较短且等效的x += 3;

    保持简短!

    而不是指定x = x + 1;x = x - 1; ,您可以指定较短的x += 1;x -= 1; 。 通过指定较短的x++;可以节省更多的击键x++;x--;

    按位运算符

    翻译自: https://www.infoworld.com/article/2940467/java-101-evaluate-java-expressions-with-operators.html

    java三目运算符表达式

    展开全文
  • 优雅计算算式:后缀表达式

    千次阅读 多人点赞 2020-11-24 12:44:57
    两种常见表达式是代数表达式(如:3+2)和布尔表达式(如true ^ false)都可以用它表示,这些表达式包含了一元运算符和二元运算符,从而节点的孩子可以是零个、一个或两个。表达式树的叶子节点储存操作数(操作数...

    后缀表达式

    提要

    当用户输入了如同"10 - 2"这样的字符串,如何计算这个算式的算术结果?

    答案似乎非常简单:遇到数字就缓存数字,遇到运算符,用缓存的数字对下一个数字进行操作就能得到结果。

    对于"10 - 2 + 5"这样的序列,只需要做一点点修改:把上次的运算结果也缓存起来,跟上面的操作思路就一致了。

    但是一遍线性扫描解决不了这样的问题:如何计算"10 - 2 * 5"?

    按照运算符的优先级规则,我们必须先计算2*5才行,可是计算机只能线性扫描表达式。为此,我们不得不再扫描多几次:先扫描一遍,找出优先级最大的运算符,接着获取前、后的操作数,然后计算,并用计算结果替换这个运算式。然后再扫描一遍,计算,直到没有运算符为止…听起来就好麻烦。

    这还没完,要是算式加上了括号:“5 * (10 - 2)”,这样减号的优先级就会高于乘号,反而需要先进行运算。我们可以这样实现:优先去括号,遇到括号的时候,增大里面每个运算符的优先级,接着去掉这层括号。然后就可以使用上面那个计算的算法(套路)啦。

    是不是觉得这也太复杂了,一个算式要扫描这么多遍才能拿到结果,就没什么更简单的方法吗?

    人类习以为常的中缀表示法看起来不太适合计算机理解。

    中缀表示法

    中缀表示法是指操作符以中缀形式处于操作数的中间(例:3 + 4)来表示算术或者逻辑公式的方法。既然有中缀,那也就有相应的前缀表示法后缀表示法,它们又称波兰表达式和后缀表达式——也就是本文的主角。

    顾名思义,前缀表达式嘛,运算符就得放前面,中缀的3+4表示为前缀就是+3 4,表示为后缀就是3 4+。

    现实生活中不会拿前缀、后缀表示法来表示算式也许是因为,给你一个无分割的3755+,你根本不知道,它表达的到底是3+755还是37+55。

    复杂一点的式子,表示出来就是这样:

    5*(3+2) -> *5(+32) -> 5(32+)*

    怎么感觉前缀、后缀表达式里的括号多余了?对,就是多余的,前缀、后缀表达式完全不需要括号来表示运算的优先级。(这也是这种表示法被提出的初衷——语法上不需要括号仍然能被无歧义地解析,用于简化命题逻辑)需要用括号来避免误解运算次序的只有中缀表达式。这不就简化了计算机处理括号的过程了吗?!

    来个复杂的例子:5 + (18+3) * 5 - 2

    后缀表示法:5 18 3 + 5 * + 2 -

    前缀表示法: - + 5 * + 18 3 5 2

    我们可以发现,后缀表达式里的运算符在去掉括号后,依然是按照正确的运算顺序排列的。先计算了18和3的+,再往后才是5的*。运算符从中缀转为后缀时已经有序,还顺带把加减/乘除法的优先级问题解决了。

    似乎有点意思,使用不同的表示法之后,我们不知不觉就搞定运算符优先级的问题了!

    三种表示法的内在联系——表达式二叉树

    先看看表达式二叉树枯燥的定义:

    概述

    表达式二叉树(Binary expression tree)是用来表示表达式的一种特殊的二叉树。两种常见表达式是代数表达式(如:3+2)和布尔表达式(如true ^ false)都可以用它表示,这些表达式包含了一元运算符和二元运算符,从而节点的孩子可以是零个、一个或两个。表达式树的叶子节点储存操作数(操作数可以是常量或变量),而内部节点则储存运算符。这种受限制的结构简化了表达式树的处理。

    表达式二叉树生成

    如何从表达式生成一棵二叉树呢?暂时不从算法上进行探讨,而只是形式化地描述生成树的过程。

    先思考最简单的算式:2+4,我们可以发现数字有两个,运算符却只有一个,而且恰好夹在数字中间(废话,这不是中缀表达式的特点吗?),生成的树就像下面这样:

    在这里插入图片描述

    接着我们变换一下式子:2+4-5,这个式子的树该怎么画呢?

    不妨把2+4当作一个整体,作为一个数字来看待,那么很明显,我们可以拿减号来连接2+4这个整体表示的数和另一个数5,就像这样:

    在这里插入图片描述

    使用这种代换思想,稍加思索就可以生成5 + (18 + 3) * 5 - 2的表达式二叉树,确认好优先级最高的式子,生成一棵小树,再以这个为基础逐渐添砖加瓦,生成下面这样的树:

    在这里插入图片描述

    遍历

    让我们以先序中序后序来遍历这颗树吧:

    先序: - + 5 * + 18 3 5 2

    中序:5 + 18 + 3 * 5 - 2

    后序:5 18 3 + 5 * + 2 -

    好巧,正对应了三种表示方式。不过中序遍历因为失去了括号的缘故,与原表达式产生了语义上的分歧,为此在遍历的时候就没办法像先序、后序那般省心,还要做额外的添加括号的判断。

    我们看到了后缀表达式自动确定好运算符表达式的优势(为什么不是前缀?前缀表达式基本跟后缀表达式反着来,计算机需要从头扫描到尾,前缀不太好操作),接下来想要以后缀表达式的思路来计算,就得解决两个问题。

    1. 如何将用户输入的中缀表达式转换成后缀表达式?
    2. 如何计算后缀表达式的值?

    Shunting Yard算法

    接下来隆重介绍 Edsger Dijkstra提出的Shunting Yard(调度场)算法。这个算法进行一次扫描就能把中缀表达式转换为后缀表达式。

    为了完成转换的任务,我们分别要用到一个输出队列和一个运算符缓存栈。

    仍然是这个例子:5 + (18 + 3) * 5 - 2,计算机开始从左到右扫描每一个Character,并按照以下五条规则(完整的算法规则多一些,没关系,只讨论四则运算就能触类旁通)进行操作:

    • 如果这个字符是一个数字,放进输出队列的队尾即可。

    • 如果这个字符是一个左括号,无条件压入栈当中。

    • 如果这个字符是个运算符,我们得把它放到栈中,不过得看情况:

      • 如果栈顶运算符优先级大于等于即将入栈的运算符,那么先把栈顶的运算符请出来,放到输出队列里面,循环进行,直到条件不满足。
      • 否则直接进栈。
    • 如果这个字符是一个右括号,不断弹出栈内的运算符并放到输出队列里面,直到遇到左括号。左括号一样需要弹出,不过不要放在输出队列,抛弃即可。

    • 扫描到尾部之后,如果栈非空,把运算符依次弹出,并放到输出队列里面。

    最后依次取出输出队列的元素我们就可以把算式转换为后缀表达式。

    全过程请看下面动图:

    在这里插入图片描述

    计算后缀表达式

    既然已经把表达式转换成功了,接下来研究怎么计算自然是水到渠成。后缀表达式的计算比较简单,不过仍需要一个栈来缓存一下操作数,我们依次从刚才的队列中取出元素,然后:

    • 如果是操作数,将其入栈。
    • 如果是运算符,依次弹出栈内的两个数,然后就进行相应计算(注意符号是否满足交换律,后出栈的操作数是左操作数,先出栈的是右操作数),得出的计算结果进栈即可。

    这样操作一番,栈内剩下的那个元素,就是你想要的最终结果。

    完整过程如下:

    在这里插入图片描述

    怎么样,虽然还是有亿点点复杂(还没讨论诸如sin这样的函数),不过,至少比起强行让计算机在一遍遍的扫描中去理解中缀表达式更加轻松而优雅吧。

    表达式二叉树的生成——算法浅析

    这一节我们叙述如何用后缀表达式生成一棵表达式二叉树。

    之所以把生成表达式二叉树的具体算法放到这里,是因为这个算法的核心思想与上方计算后缀表达式如出一辙,区别只有一点:我们把处于中间态的子树而不是显式的数值当作运算符的“运算结果”。

    算法简述如下:

    1. 初始化存储二叉树的栈,然后开始从左到右扫描后缀表达式。
    2. 遇到操作数时,初始化为最小的二叉树(单个二叉树结点),然后入栈。
    3. 遇到操作符时,初始化为二叉树结点,然后取出栈内的前两个子树,以该操作符为根结点,先出栈的作为右子树,后出栈的作为左子树,构造一棵新的二叉树,然后入栈。
    4. 表达式扫描完毕后,栈内剩下唯一的一棵二叉树即为所求的表达式二叉树。

    前缀表达式生成表达式二叉树的方法形式化叙述如下,栈内储存的不再是操作数,而是操作符,显得稍微复杂一些:

    1. 初始化存储二叉树的栈,然后开始从左到右扫描前缀表达式。
    2. 遇到运算符时,初始化为最小的二叉树(单个二叉树结点),然后入栈。
    3. 遇到操作数时,初始化为二叉树结点,然后取出栈顶的二叉树,按照两种情况来操作:
      • 二叉树的根节点上没有左子树或者右子树,则将操作数结点放在左子树(如果没有左子树)或者右子树(如果有左子树)上。
      • 二叉树根节点左、右子树均有,则从栈内弹出一棵新的树B,把当前这颗树作为子树,添加到B树上(先左后右,左空优先放左),这之后,按照上一点来考虑操作数结点能不能加入到B树,如果不能,继续执行上述步骤,直到操作数成功进入二叉树内。
    4. 表达式扫描完毕后,栈内剩下唯一的一棵二叉树即为所求的表达式二叉树。

    至于中缀表达式,可以通过调度场算法来将中缀转为后缀来构造表达式二叉树。

    Kotlin实现

    以下给出了Kotlin版本的部分算法实现

    Operator.kt

    /**
     * 运算符的枚举类
     */
    enum class Operator(val value: String, val priority: Int) {
        Plus("+", 1), Minus("-", 1),
        Multiply("*", 2), Divide("/", 2),
        Left("(", 3), Right(")", 3);
    
        override fun toString(): String {
            return value
        }
    
        companion object {
            /**
             * 将字符串映射为某一个确定的运算符
             */
            fun matching(value: String): Operator {
                return when(value) {
                    "+" -> Plus
                    "-" -> Minus
                    "*" -> Multiply
                    "/" -> Divide
                    "(" -> Left
                    ")" -> Right
                    else -> Plus
                }
            }
        }
    }
    

    Utils.kt

    /**
     * 将中缀表达式读入集合中,并以对象的形式储存
     * @param formula 中缀表达式字符串,其中操作数与操作符之间不含空格
     * @return 包含了操作数Int的对象和操作符Operator对象的集合,顺序与原来的中缀表达式一致
     */
    fun getOperand(formula: String): List<Any> {
        val list: MutableList<Any> = mutableListOf()
        var begin = 0
        for (i in formula.indices) {
            val c = formula[i]
            // 如果c是一个运算符
            if (c.toString().matches(Regex("\\+|-|\\*|/|\\(|\\)"))) {
                // 按照缓存(begin)的起始位置到当前位置前,截断字符串,并解析成一个操作数
                val cache = formula.substring(begin, i)
                if (cache.isNotEmpty()) {
                    list.add(cache.toInt())
                }
                // 将当前位置的字符解释为运算符
                list.add(Operator.matching(c.toString()))
                begin = i + 1
            }
        }
        // 解析表达式的最后一个操作数
        val sub = formula.substring(begin)
        if (sub.isNotEmpty()) {
            list.add(sub.toInt())
        }
        return list
    }
    /**
     * 将表示中缀表达式的集合转换为表示后缀表达式的队列,调度场算法
     */
    fun generateReversePolishNotation(list: List<Any>): Queue<Any> {
        val operationStack: Stack<Operator> = Stack()
        val deque: ArrayDeque<Any> = ArrayDeque()
        for (any in list) {
            if (any is Double || any is Int) {
                // 操作数进队列
                deque.offerLast(any)
            } else if (any is Operator) {
                when (any) {
                    Operator.Left -> {
                        // 左括号直接进栈
                        operationStack.push(any)
                    }
                    Operator.Right -> {
                        // 遇到右括号,持续弹出运算符,直到遇到左括号
                        while (operationStack.peek() != Operator.Left) {
                            deque.offerLast(operationStack.pop())
                        }
                        // 弹出左括号
                        operationStack.pop()
                    }
                    else -> {
                        // 如果栈不为空,栈顶不是左括号,栈顶运算符的优先级大于等于当前运算符
                        // 将栈内的运算符弹出到队列,直到不满足前面的条件
                        while (!operationStack.isEmpty() && operationStack.peek() != Operator.Left
                                && any.priority <= operationStack.peek().priority) {
                            deque.offerLast(operationStack.pop())
                        }
                        // 不满足上述条件,将运算符压入栈内
                        operationStack.push(any)
                    }
                }
            }
        }
        // 将剩余的运算符全部弹出
        while (!operationStack.isEmpty()) {
            deque.offerLast(operationStack.pop())
        }
        return deque
    }
    
    /**
     * 根据后缀表达式计算结果。要求序列中所有的数为Int
     */
    fun calculateReversePolishNotation(expressionQueue: Queue<Any>): Int {
        val calculateStack: Stack<Int> = Stack()
        var obj: Any?
        while (expressionQueue.poll().also { obj = it } != null) {
            if (obj is Int) {
                calculateStack.push(obj as Int)
            } else if (obj is Operator) {
                val numberOne = calculateStack.pop()
                val numberTwo = calculateStack.pop()
                calculateStack.push(calculate(numberOne, numberTwo, obj as Operator))
            }
        }
        // 弹出运算结果
        return calculateStack.pop()
    }
    
    /**
     * 根据操作符计算结果
     * @param numberOne 操作数
     * @param numberTwo 被操作数(被除数)
     */
    fun calculate(numberOne: Int,
                  numberTwo: Int, operator: Operator): Int {
        return when(operator) {
            Operator.Plus -> {
                numberTwo + numberOne
            }
            Operator.Minus -> {
                numberTwo - numberOne
            }
            Operator.Multiply -> {
                numberTwo * numberOne
            }
            Operator.Divide -> {
                numberTwo / numberOne
            }
            else -> 1
        }
    }
    
    展开全文
  • 最近因工作需要,用到“计算器”功能:输入一串文本,解析后进行计算。这部分只是作为一个简单的应用模块,而不是单独的程序,所以着重在算法的实现上。实际编码前,想过用栈、...RPN就是逆波兰表达式,即后缀表达式
  • 一、三者的概念(参考维基百科)1.1中缀表达式中缀表达式是符合...1.2前缀表达式(又称波兰表达式)前缀表达式(以及后缀表达式)是符合计算机思维的一种表达方式。将1.1的几个中缀表达式转换成前缀表达式如下:+ 3 4 ...
  • C语言之运算符表达式和语句总结

    千次阅读 2021-12-12 10:39:25
    本文是对一些常用的运算符进行总结,以及表达式和语句的知识点的归纳 一、算术运算符 1.加法运算符:+ 用于加法运算,相加的值可以是变量也可以是常量。如printf("%d",4+20); income = salary + bribes;均是正确...
  • 只有一个运算符是一元运算符,比如-6,+6。 优先级:如果一个式子不含括号。求幂运算最先执行,他们比其他优先级都高。接下来就是乘法和除法,然后是加法和减法。 在中缀表达式中,每个二元运算符出现在两个操作数...
  • 对比三个不同的中缀表达式转换为后缀表达式的结果 可以发现: 1.后缀表达式数字的出现顺序和中缀表达式中是完全一样的。 2.中缀表达式中相邻两个运算符的优先级不一样,其在后缀表达...
  • Java运算符表达式

    千次阅读 多人点赞 2018-07-14 14:56:35
    常用运算符 运算符是一种特殊的符号,用以表示数据的...算术运算符用在数学表达式中,它们的作用和在数学中的作用一样。下表列出了所有的算术运算符。表格中的实例假设整数变量A的值为10,变量B的值为20: 操作符 ...
  • c++运算符表达式

    2020-09-08 23:02:03
    在程序中,运算符是用来操作数据的,这些数据也被称为操作数,使用运算符将操作数连接而成的式子称为:表达式表达式具有如下特点 常量和变量都是表达式 运算符的类型对应表达式的类型 每一个表达式都有自己的值 ...
  • 中缀表达式求值: #include #include #include #include #include using namespace std; int priority(char c)//优先级 { if(c == '=') return 0; if(c == '+') return 1; if(c == '-') return 1; if...
  • C++运算符表达式

    2020-07-28 23:45:41
    运算符表达式算数运算符 运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C++内置了丰富的运算符,并提供了以下类型的运算符: 算数运算符 关系运算符 逻辑运算符运算符 赋值运算符 杂项运算符 在...
  • spe,i): return 2 elif i=="(": return 3 elif i==")": return 4 def Operator_operation_1(self,elem,operator): # 为不同的一元运算符提供相应的运算 if operator=='sin': # print("elem=",elem) # print(print...
  • 4、如果扫描的项目是一个一元运算符,则对栈的最顶上操作数执行该运算。 5、将运算结果重新压入栈。 6、重复步骤2-5,直到后缀表达式扫描完毕,栈中即为结果值。 Talk is cheap,let me show you the code 接下来是...
  • 1、从左而右对算数表达式进行扫描,每次读入一个字符s1[i]; 2、若遇到数字或小数点,则立即写入s2[i],若遇算数运算符,将“”(空格)写入s2[i]; 3、遇到左括号“(”则压栈; 4、若遇算术运算符,如果它们的...
  • Js运算符表达式

    2020-06-12 20:55:38
    表达式时用于JavaScript脚本运行时进行计算的式子,可以包含常量、变量、运算符 2.运算符 1)算术运算符 +、-、*、/、% ++、– 分为前缀和后缀形式,前缀形式先加/减1再执行,后缀先执行再加/减1 tip: ...
  • 表达式运算符和操作数的字符串。可做为操作数的结构有:字面量,常量,变量,方法调用,元素访问器,其它表达式表达式求值是将每个运算符应用到它的操作数的过程,以适当的顺序产生一个值。2. 字面量字面量 ...
  • 《C语言运算符表达式.ppt》由会员分享,可在线阅读,更多相关《C语言运算符表达式.ppt(29页珍藏版)》请在人人文库网上搜索。1、运算符表达式,夏涛,运算符表达式,计算机与运算密不可分。运算是对数据的加工。...
  • 一元运算符只对一个表达式执行操作,该表达式可以是数值数据类型类别中的任何一种数据类型。 “+” 一元加运算符 表示正值 “-” 一元减运算符 表示负值 “++” 自增运算符 将值增加一 下列输出为2 class Test{ ...
  • C++后缀表达式计算器

    千次阅读 2016-11-28 11:27:21
    C++后缀表达式计算器
  • 运算符表达式

    2019-02-21 16:40:14
    1.运算符 (1)一元运算符 接受一个操作数的运算符被称为一元运算符(前缀运算符(operator op)、后缀运算符(op operator)) 例如:++ -- new等 (2)二元运算符 接受两个操作数的运算符被称为二元运算符(op1 ...
  • C语言中的运算符表达式

    千次阅读 2021-05-19 16:36:47
    一、赋值运算符和赋值表达式1、赋值运算符C语言的赋值运算符为等号,表示形式“=”。此外,还有复合赋值运算符,后续陆续介绍。2、赋值表达式“=”的左侧是变量,右侧是常量、变量、表达式、函数等,“=”的含义是将...
  • 转载自:http://www.cnblogs.com/wanghetao/archive/2012/04/23/2466580.html 逆波兰表达式表达式一般由操作数(Operand)、运算符(Operator)组成,例如算术表达式中,通常把运算符放在两个操作数的中间,这称为中缀...
  • C#提供了大量的运算符,按需要操作数的数目来分,有一元运算符(如++)、二元运算符(如+,*)、三元运算符(如? : )。按运算功能来分,基本的运算符可以分为以下几类: ![1631424648343](C:\Users\86172\AppData\...
  • 运算符指定将要进行的操作。 表达式则把变量与常量组合起来生成新的值。 对象的类型决定该对象可取值的集合以及可以对该对象执行的操作。 2.1 变量名 变量名的命名规则: 1.名字只能由字母和数字组成,下划线被看做...
  • 实现+, -两个一元运算符(即正、负号); 操作数可为任意整型值(程序假定整数及运算范围不超过int型表示范围)。 若两个整数相除,结果只保留整数商(余数丢弃);每位同学可选择实现基本要求或者提高要求;程序...
  • 一、基本运算符 C用运算符表示算数原酸。 1、赋值运算符:= 符号 “=” 被称为赋值运算符 i = 100; 读作“把值100赋给变量i”。 左值 = 右值; 可修改的左值(对象定位值)必须是是变量名,用于标识特定数据对象的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,520
精华内容 2,608
关键字:

一元运算符转后缀表达式