码迷,mamicode.com
首页 > Windows程序 > 详细

C# - 二叉树表达式计算

时间:2015-09-27 21:29:03      阅读:439      评论:0      收藏:0      [点我收藏+]

标签:

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

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

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

这样学习印象才深嘛.

我喜欢逆过来贴代码~

这是运行结果:

技术分享

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         }

总结:

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

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

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

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

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

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

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

C# - 二叉树表达式计算

标签:

原文地址:http://www.cnblogs.com/niconico/p/4842670.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!