C# - 二叉树表达式计算

很早以前就写过双栈的表达式计算.

这次因为想深入学一下二叉树,网上都是些老掉牙的关于二叉树的基本操作.

感觉如果就学那些概念,没意思也不好记忆.于是动手写了一个表达式计算的应用例子.

这样学习印象才深嘛.

我喜欢逆过来贴代码~

这是运行结果:

cal() 是节点类里的计算方法,从根节点调用,递归所有子节点进行计算.Left,Right分别是左右子节点.

1      public double cal()
2         {
3             if (this.isDig==false)
4             {
5                 return CAL(Fuhao, Left.cal() , Right.cal() );
6             }
7             return value;
8         }

上面的CAL(大写)的是静态的计算方法,根据不同符号进行不同计算.

 1  public static double CAL(int FUHAO, double l, double r)
 2         {
 3             switch (FUHAO)
 4             {
 5                 case ADD:
 6                     return l + r;
 7                 case SUB:
 8                     return l - r;
 9                 case MUL:
10                     return l * r;
11                 case DIV:
12                     return l / r;
13             }
14             return 0;
15         }

看到这,是不是觉得很简单呢?

没错,二叉树在计算表达式时非常简单,但难点在于如何构建这个表达式树.

写程序最重要的就是严谨强大的逻辑思维能力.

在写下面的方法时,我经历了很多次debug.大概修改了10次,才完成..可见我的逻辑能力还是很不足.

下面这个方法包含大量逻辑判断,可能不好理解,也许某些判断可以简化优化,而且我默认第一位是数字,也就是不支持第一位是括号的表达式.

 1     public static BNode CreateTree(List<string> zf)
 2         {
 3             var fh=new List<string>{"+","-","*","/"};
 4             var kh = new List<string> { "(", ")" };
 5            BNode CurN=null;
 6            BNode TempCur = null;
 7             foreach (var a in zf)
 8             {
 9                 if (fh.Contains(a))
10                 {//是符号
11                     int tfuhao=fh.IndexOf(a);       //偷懒写法,取得符号值,0-3分别代表+-*/
12                     int tfhvalue=tfuhao/2;          //符号优先值,+-为0.*/为1,判断符号优先,这里写的很偷懒
13                     if (CurN.Parent != null)
14                     {
15                         if (CurN.Parent.FuhaoValue < tfhvalue)
16                             //当前节点的父节点符号<新节点符号,即新加的符号优先级比较高.
17                         {
18                             var tp = CurN.Parent;
19                             var t = CurN;
20                             CurN = new BNode { Parent=tp,Left=t , isDig = false,  Fuhao = tfuhao,FuhaoValue=tfhvalue };
21                             tp.Right = CurN;
22                             t.Parent = CurN;
23                         }
24                         else if (CurN.Parent.FuhaoValue >= tfhvalue)
25                             //新加的符号优先级不高于当前节点的父节点符号,
26                         {
27                             BNode tp = CurN;
28                             while (tp.isKuoHao || tp.isDig  ||  tp.FuhaoValue != tfhvalue)
29                               //循环取得与新加节点优先级相同的节点.
30                             {
31                                 if (tp.Parent != null)
32                                     tp = tp.Parent;
33                                 else
34                                     break;
35                             }
36                             if (tp.Parent == null)
37                             {
38                                 CurN = new BNode {  Left = tp, isDig = false, Fuhao = tfuhao, FuhaoValue = tfhvalue };
39                                 tp.Parent = CurN;
40                             }
41                             else
42                             {
43                                 var p = tp.Parent;
44                                 CurN = new BNode { Parent = p, Left = tp, isDig = false, Fuhao = tfuhao, FuhaoValue = tfhvalue };
45                                 p.Right = CurN;
46                                 tp.Parent = CurN;
47                             }
48                         }
49                     }
50                     else
51                     {
52                         var t = CurN;
53                         CurN = new BNode { isDig = false, Fuhao = tfuhao, FuhaoValue = tfhvalue, Left = CurN };
54                         t.Parent = CurN;
55                     }
56
57                 }
58                 else if (kh.Contains(a))
59                 {//是括号
60                     if (a == "(")
61                     {
62                         TempCur = CurN;
63                         CurN = null;
64                     }
65                     else if (a == ")")
66                     {
67                        var top= CurN.GetTop();
68                        top.Parent = TempCur;
69                        TempCur.Right = top;
70                        CurN = top;
71                        CurN.isKuoHao = true;
72                     }
73                 }
74                 else
75                 {//是数字
76                     if (CurN == null)
77                         CurN = new BNode { value = double.Parse(a) };
78                     else if (CurN.isDig == false)
79                     {
80                         var t= CurN;
81                         CurN = new BNode { value = double.Parse(a), Parent=t };
82                         t.Right = CurN;
83                     }
84                 }
85             }
86
87             return CurN;
88         }

其实写起来也没什么太大难度,只要把所有情况的处理都考虑到就行.

最后是2个辅助函数.

FenGe:我比较偷懒,事先把字符串里的数字和符号分隔开了,这样就不用一位一位的去取判断是数字或者符号.

Cal:使用时唯一需要接触的函数.

 1    public static double Cal(string expresstion)
 2         {
 3            var a= FenGe(expresstion);
 4            var zfs = a.Split("|".ToCharArray() ,StringSplitOptions.RemoveEmptyEntries);
 5           var t= BNode.CreateTree(zfs.ToList());
 6           var root= t.GetTop();
 7           var result = root.cal();
 8             return result;
 9         }
10
11         public static string FenGe(string exp)
12         {
13             var ys = new List<string> { "\\d*\\.?\\d+", "[+\\-\\*/\\(\\)]{1}" };
14             ys.ForEach(a =>
15             {
16                 var r = new Regex(a);
17                exp= r.Replace(exp, b => b.Value + "|", int.MaxValue);
18             });
19             return exp;
20         }
1   public BNode GetTop()
2         {
3             if (Parent != null)
4                 return Parent.GetTop();
5             return this;
6         }

总结:

二叉树计算的优势在于易于扩展,很容易将数字计算扩展成支持函数,参数的表达式计算.

计算时候的逻辑很简单,但是构建二叉树就比较复杂.

基本逻辑:遇到数字,放到左节点,遇到符号(判断是否为根节点,是作为数字的父节点,否的话判断符号优先级,优先级高,就放入低优先级的右节点;优先级低或者等于就

放到前一个符号的父节点.

括号的处理就是:重新创一个节点作为当前节点,当作一个新的表达式进行处理,等遇到右括号的时候,再将括号内的表达式的根节点放入之前最后处理的节点的子节点.

逻辑很多比较复杂,慢慢想应该不难理解.

效率来说:纯数字的计算肯定二栈的方式快.

时间: 2024-08-05 17:49:48

C# - 二叉树表达式计算的相关文章

二叉树表达式计算(2)

/*学号:2014329620069  姓名:张卓鹏 班级:14计科2*/#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<stack>#include<iostream>#include<string>#include<string.h>#include<math.h>#include<sstream>usin

表达式计算

1 #include<iostream> 2 #include<string> 3 #include<cstdlib> 4 #include<cstring> 5 #include<iomanip> 6 #include<stack> 7 using namespace std; 8 9 #define OK 0 10 #define ERROR -1 11 #define OVERFLOW -1 12 #define OPSETSI

Vs2013在Linux开发中的应用(26):表达式计算

快乐虾 http://blog.csdn.net/lights_joy/ 欢迎转载,但请保留作者信息 当VS调试时将鼠标移到一个变量上面的时候,VS将显示这个变量的值,实际上这个时候VS进行了表达式的计算,我们所需要做的,就是把这个过程转换为gdb的命令: Operation Description -enable-pretty-printing enable Python-based pretty-printing -var-create create a variable object -v

HDU 2424-Gary&#39;s Calculator(表达式计算+大数)

Gary's Calculator Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 950    Accepted Submission(s): 209 Problem Description Gary has finally decided to find a calculator to avoid making simple cal

C++实现 逆波兰表达式计算问题

C++实现 逆波兰表达式计算问题 #include <iostream> #include <string> using namespace std; class Stack { private: int size; int top; float *listArray; public: Stack(int sz=20); ~Stack(); bool push(float it);//入栈 bool pop(float& it);//出栈 bool isEmpty();//

爪哇国新游记之二十二----算术表达式计算求值

代码: import java.util.ArrayList; import java.util.List; // 辅助类 class Item{ String value; boolean isNumber; public Item(String value,boolean isNumber){ this.value=value; this.isNumber=isNumber; } public Item(char c,boolean isNumber){ this.value=String.

C#动态表达式计算

应该有不少人开发过程中遇到过这样的需求,我们直接看图说话: 如上图所示,其中Entity为实体类,其中包括五个属性,该五个属性的值分别来自于数据库查询结果: 用户通过可视化界面进行某些条件的配置以及某些算法的配置并自动生成表达式或者生成数学模型: 程序中需要通过生成的表达式以及动态从数据库中获取的数据进行算法映射以及自动计算出结果. 该需求这边可以举出几个应用场景: 1.报表设计器 我们可以通过报表设计器设计数据库的映射关系并配置数据之间的算法关系,然后动态生成报表: 2.某些采集工具 定向采集

蓝桥杯 算法训练 ALGO-156 表达式计算

算法训练 表达式计算 时间限制:1.0s   内存限制:256.0MB 问题描述 输入一个只包含加减乖除和括号的合法表达式,求表达式的值.其中除表示整除. 输入格式 输入一行,包含一个表达式. 输出格式 输出这个表达式的值. 样例输入 1-2+3*(4-5) 样例输出 -4 数据规模和约定 表达式长度不超过100,表达式运算合法且运算过程都在int内进行. 题目解析: 运算优先级: 括号 → 乘除 → 加减 例如 1-2+3*(4-5) (1)计算(4-5),表达式变为  1-2+3*-1 (2

表达式计算系列【未完】

P1040 表达式计算 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 给出一个表达式,其中运算符仅包含+,要求求出表达式的最终值 输入格式 仅一行,即为表达式 输出格式 仅一行,既为表达式算出的结果 测试样例1 输入 1+1 输出 2 备注 表达式总长度<=1500 1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 string ans(1501