ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【算法】友谊与雪花的舞动,脚本解析器原理 [打印本页]

作者: 花瓣小跑    时间: 2023-12-16 21:51
标题: 【算法】友谊与雪花的舞动,脚本解析器原理
在11月的下雪天,小悦身处于温暖的办公室中,窗外的雪花在灯光下翩翩起舞。她盯着电脑屏幕,不经意间,一个熟悉的身影从办公室门口处经过,吸引了她的目光。那个人看上去很像是一个女孩,名叫苏菲,是她在大学时期遇到的国外交换生。
小悦的心跳加速,她有些不敢相信自己的眼睛。在她的记忆中,苏菲是一个温柔、聪明且乐于助人的女孩。她们曾经一起上过计算机科学课,苏菲对数学和编程的热爱给小悦留下了深刻的印象。在课程中,苏菲表现出了非凡的编程天赋和扎实的技术功底,她的编程能力让小悦敬佩不已。
小悦忍不住站起来,快步走向那个人。她轻轻地拍了拍她的肩膀,问道:“苏菲?”
那个女孩转过身来,露出了一张熟悉的面孔。她的眼睛闪烁着聪慧的光芒,嘴角挂着一抹微笑。她惊喜地喊道:“小悦?”
两人紧紧地拥抱在一起,重逢的喜悦让她们感到温暖。她们来到楼下的咖啡厅,开始回忆起大学时期的时光,谈论着彼此的生活和工作。
小悦感到非常惊喜,没想到苏菲会来到她的办公楼。苏菲也并不知道小悦在这里工作。或许是命运的安排,让她们再次相遇。小悦心想,一定要好好和苏菲聊聊天,畅谈彼此的近况,重温那段美好的大学时光。
小悦想起了那次计算机科学课的上机考试。她需要实现一个计算器表达式算法。小悦在考试前尝试着自己实现了一个多项式解析式算法,但是效果并不甚理想。这个问题让她感到很困惑,不知道如何着手。就在这时,苏菲主动帮助了她。
苏菲耐心地解释了如何分析问题、拆分令牌、使用逆波兰表达式算法进行计算,以及如何使用栈来处理后缀表达式。她的思路清晰、有条理,让小悦瞬间明白了问题的解决方法。
在苏菲的帮助下,小悦成功地解决了问题,并且在考试中取得了优异的成绩。她一直感激苏菲的帮助和鼓励。
回忆起那段经历,小悦不禁感慨万分。她对苏菲说:“谢谢你,苏菲。你的帮助和支持让我变得更加自信和勇敢。”
苏菲微笑着说:“我们是朋友,小悦。无论何时何地,我都会尽力帮助你。”
她们聊了很久,谈论着过去的点点滴滴和现在的变化。毕业后,苏菲选择继续深造,攻读计算机科学硕博学位。在国外留学期间,她积累了丰富的经验和技能,志向是成为一名计算机科学家。然而,尽管小悦和苏菲在大学时期形影不离,但毕业后两人便各奔东西,相距太远,渐渐失去了联系。她们还计划着再次回到校园,去湖心岛看看那个曾经给她们带来无限回忆的地方。
在分别前,小悦紧紧地拥抱了苏菲一次。她心里默默地想:谢谢你,苏菲,谢谢你陪我度过了那段美好的时光。我会永远珍惜这份友谊。
随着时间的推移,虽然小悦和苏菲的联系越来越少。但是她们的友谊和回忆永远留在彼此的心中。在这个下雪的日子里,小悦重新与苏菲相遇,让她回忆起了那些青葱校园岁月和湖心岛的甜蜜时光。她感到无比幸福和感激,因为她知道这些美好的回忆将永远伴随着她走过人生的旅程。即使未来还有更多的挑战等待着她,小悦也相信自己的能力能够克服一切困难。
当时小悦和苏菲面对的考试题目为:要求计算一个包含数字和运算符的字符串的结果,包括加减乘除和幂运算,还有括号。数字可以是整数或小数,字符串中可以有空格。要求处理字符串中的所有运算符和数字,并计算出最终的结果。
示例:3 * (4 +       (2 / 3) * 6 - 5)=9;
123      -( 4^ (       3 -   1) * 8 - 8      /(     1 + 1 ) *(3 -1) )=3; 
算法实现1:
  1.   1 using System;
  2.   2 using System.Collections.Generic;
  3.   3
  4.   4 public static class Edm {
  5.   5
  6.   6   public static double calculate(string input)
  7.   7     {
  8.   8         // 从输入中移除空格
  9.   9         input = input.Replace(" ", "");
  10. 10
  11. 11         // 将输入转换为令牌列表
  12. 12         List<string> tokens = new List<string>();
  13. 13         string currentToken = "";
  14. 14         foreach (char c in input) {
  15. 15             if (char.IsDigit(c) || c == '.') { // 如果字符是数字或小数点
  16. 16                 currentToken += c; // 将字符添加到当前令牌中
  17. 17             } else {
  18. 18                 if (currentToken != "") { // 如果当前令牌不为空
  19. 19                     tokens.Add(currentToken); // 将当前令牌添加到令牌列表中
  20. 20                     currentToken = ""; // 重置当前令牌
  21. 21                 }
  22. 22                 tokens.Add(c.ToString()); // 将字符转换为字符串并添加到令牌列表中
  23. 23             }
  24. 24         }
  25. 25         if (currentToken != "") { // 如果当前令牌不为空
  26. 26             tokens.Add(currentToken); // 将当前令牌添加到令牌列表中
  27. 27         }
  28. 28
  29. 29         // 使用逆波兰算法评估令牌
  30. 30         Stack<string> operatorStack = new Stack<string>(); // 操作符栈
  31. 31         Queue<string> outputQueue = new Queue<string>(); // 输出队列
  32. 32         foreach (string token in tokens) {
  33. 33             if (double.TryParse(token, out double num)) { // 如果令牌可以转换为双精度浮点数
  34. 34                 outputQueue.Enqueue(num.ToString()); // 将数字转换为字符串并添加到输出队列中
  35. 35             } else if (IsOperator(token)) { // 如果令牌是操作符
  36. 36                 while (operatorStack.Count > 0 && IsOperator(operatorStack.Peek()) && GetPrecedence(token) <= GetPrecedence(operatorStack.Peek())) {
  37. 37                     outputQueue.Enqueue(operatorStack.Pop()); // 将操作符栈中的操作符弹出并添加到输出队列中
  38. 38                 }
  39. 39                 operatorStack.Push(token); // 将操作符添加到操作符栈中
  40. 40             } else if (token == "(") { // 如果令牌是左括号
  41. 41                 operatorStack.Push(token); // 将左括号添加到操作符栈中
  42. 42             } else if (token == ")") { // 如果令牌是右括号
  43. 43                 while (operatorStack.Count > 0 && operatorStack.Peek() != "(") {
  44. 44                     outputQueue.Enqueue(operatorStack.Pop()); // 将操作符栈中的操作符弹出并添加到输出队列中
  45. 45                 }
  46. 46                 if (operatorStack.Count == 0) {
  47. 47                     throw new Exception("Mismatched parentheses"); // 抛出异常,提示括号不匹配
  48. 48                 }
  49. 49                 operatorStack.Pop(); // 弹出左括号
  50. 50             } else {
  51. 51                 throw new Exception("Invalid token: " + token); // 抛出异常,提示令牌无效
  52. 52             }
  53. 53         }
  54. 54         while (operatorStack.Count > 0) {
  55. 55             if (operatorStack.Peek() == "(") {
  56. 56                 throw new Exception("Mismatched parentheses"); // 抛出异常,提示括号不匹配
  57. 57             }
  58. 58             outputQueue.Enqueue(operatorStack.Pop()); // 将操作符栈中的操作符弹出并添加到输出队列中
  59. 59         }
  60. 60
  61. 61         // 评估后缀表达式
  62. 62         Stack<double> operandStack = new Stack<double>(); // 操作数栈
  63. 63         foreach (string token in outputQueue) {
  64. 64             if (double.TryParse(token, out double num)) { // 如果令牌可以转换为双精度浮点数
  65. 65                 operandStack.Push(num); // 将数字添加到操作数栈中
  66. 66             } else if (IsOperator(token)) { // 如果令牌是操作符
  67. 67                 double b = operandStack.Pop();
  68. 68                 double a = operandStack.Pop();
  69. 69                 double result = EvaluateOperator(token, a, b); // 计算操作符对应的结果
  70. 70                 operandStack.Push(result); // 将计算结果压入操作数栈中
  71. 71             } else {
  72. 72                 throw new Exception("Invalid token: " + token); // 抛出异常,提示令牌无效
  73. 73             }
  74. 74         }
  75. 75         if (operandStack.Count != 1) {
  76. 76             throw new Exception("Invalid expression"); // 抛出异常,提示表达式无效
  77. 77         }
  78. 78         return operandStack.Pop(); // 返回操作数栈中唯一的元素作为计算结果
  79. 79     }
  80. 80
  81. 81     static bool IsOperator(string token) {
  82. 82         return token == "+" || token == "-" || token == "*" || token == "/" || token == "^"; // 判断一个字符串是否为操作符(+、-、*、/、^)
  83. 83     }
  84. 84     
  85. 85     static int GetPrecedence(string op) {// 获取操作符优先级
  86. 86         if (op == "^") {
  87. 87             return 3;
  88. 88         } else if (op == "*" || op == "/") {
  89. 89             return 2;
  90. 90         } else if (op == "+" || op == "-") {
  91. 91             return 1;
  92. 92         } else {
  93. 93             return 0;
  94. 94         }
  95. 95     }
  96. 96
  97. 97    // 计算两个操作数和一个操作符的结果
  98. 98     static double EvaluateOperator(string op, double a, double b) {
  99. 99         if (op == "+") {
  100. 100             return a + b;
  101. 101         } else if (op == "-") {
  102. 102             return a - b;
  103. 103         } else if (op == "*") {
  104. 104             return a * b;
  105. 105         } else if (op == "/") {
  106. 106             return a / b;
  107. 107         } else if (op == "^") {
  108. 108             return Math.Pow(a, b);
  109. 109         } else {
  110. 110             throw new Exception("Invalid operator: " + op);
  111. 111         }
  112. 112     }
  113. 113 }
复制代码
这段代码实现了一个表达式计算器,能够接受包含基本数学运算的字符串表达式,并返回计算结果。
 逆波兰表达式算法由荷兰计算机科学家Edsger Dijkstra在1960年代实现,它也是ALGOL60语言的基础算法,因为在ALGOL60上做出原理性贡献,Dijkstra获得了1972年的图灵奖。而该算法的名称来源于其发明者,波兰数学家Jan Łukasiewicz由1929年提出此数学方法。
逆波兰表达式算法的数学原理可以通过栈的数据结构来解释。我们以中缀表达式 "3 + 4 * 2" 为例进行解释。
以中缀表达式 "3 + 4 * 2" 为例,通过上述步骤,我们可以将中缀表达式转换为后缀表达式 "3 4 2 * +"。
中缀表达式转换为后缀表达式的过程是为了更方便地让计算机进行数学表达式的计算。后缀表达式(也称为逆波兰表达式)具有以下优点:
对于后缀表达式 "3 4 2 * +",我们可以按照以下步骤进行计算:
对于后缀表达式 "3 4 2 * +",计算过程如下:
因此,后缀表达式的转换和计算可以使数学表达式在计算机中的处理更加简单和高效。
逆波兰表达式算法之所以受到广泛应用,是因为它能够有效地解决中缀表达式计算的问题。中缀表达式需要使用括号来确定操作符的优先级,而逆波兰表达式则不需要,因为它使用后缀表示法,操作符的优先级可以通过操作符的顺序来确定。
逆波兰表达式算法在计算器、编译器、解释器等领域都有广泛应用。在计算器中,用户输入的数学算式,即中缀表达式通常需要转换为逆波兰表达式才能进行计算。在编译器和sql解释器中,逆波兰表达式算法可以用于计算sql表达式的值,以及将sql表达式转换为可执行代码。
算法实现2:
[code] 1 public static double calculate(string s){ 2      s=s.Replace(" ",""); 3      if (Regex.Match(s,"^[(][\\d\\.\\+\\-\\*/\\^]+[)]$").Success) s=Regex.Replace(s,"^[(]|[)]$",""); 4      if (Regex.Match(s,"^-?[\\d\\.]+$").Success) return double.Parse(s);//检测到单个的正负数字,直接返回值 5      if (Regex.Match(s,"^\\d[\\d+-\\.]+$").Success) return Regex.Matches(s,"-[\\d\\.]+|(?




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4