zoukankan      html  css  js  c++  java
  • 四则运算的算法

    代码
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;

    namespace Arithmetic_Demo
    {
    #region 节点对象
    //语法树节点
    interface INode
    {
    Num Compute();
    }
    //数字
    class Num : INode
    {
    public double Number { get; set; }

    public Num(double number)
    {
    this.Number = number;
    }

    public Num Compute()
    {
    return this;
    }
    }
    //运算符
    abstract class Op : INode
    {
    INode _left;
    INode _right;

    public Op(INode left, INode right)
    {
    this._left = left;
    this._right = right;
    }

    public Num Compute()
    {
    return new Num(this.Operate(this._left.Compute().Number, this._right.Compute().Number));
    }

    protected abstract double Operate(double a, double b);
    }

    class Plus_Op : Op
    {
    public Plus_Op(INode left, INode right) : base(left, right) { }
    protected override double Operate(double a, double b)
    {
    return a + b;
    }
    }
    class Sub_Op : Op
    {
    public Sub_Op(INode left, INode right) : base(left, right) { }
    protected override double Operate(double a, double b)
    {
    return a - b;
    }
    }
    class Multi_Op : Op
    {
    public Multi_Op(INode left, INode right) : base(left, right) { }
    protected override double Operate(double a, double b)
    {
    return a * b;
    }
    }
    class Div_Op : Op
    {
    public Div_Op(INode left, INode right) : base(left, right) { }
    protected override double Operate(double a, double b)
    {
    return a / b;
    }
    }
    #endregion

    #region 运算符优先级判定辅助类
    //语义解析辅助类,处理 1 + 2 * 3这种式子的决断作用
    class ParseAssist
    {
    INode _n1;
    //操作数1
    INode _n2; //操作数2
    INode _n3; //操作数3
    string _op1 = null; //运算符1
    string _op2 = null; //运算符2

    //当前是否num op num op num形式了
    public bool CanCompute { get; private set; }
    public void AddNum(string n)
    {
    var tmp
    = new Num(Convert.ToDouble(n));
    this.AddNum(tmp);
    }
    public void AddNum(INode n)
    {
    //判断op1为了处理正数负数情况
    if (this._n1 == null && this._op1 == null)
    this._n1 = n;
    else if (this._n2 == null)
    {
    this._n2 = n;
    //处理正数负数
    if (this._n1 == null)
    {
    this._n1 = this.GetOp(this._op1, new Num(0), this._n2);
    this._op1 = null;
    this._n2 = null;
    }
    }
    else
    {
    this._n3 = n;
    this.CanCompute = true;
    }
    }
    public void AddOp(string op)
    {
    if (this._op1 == null)
    this._op1 = op;
    else
    this._op2 = op;
    }
    //组合出一个节点树
    public INode Combinate()
    {
    INode tmp
    = null;
    //判断优先级
    if (this.Priority(this._op1, this._op2))
    {
    //计算前二个数字
    tmp = GetOp(this._op1, this._n1, this._n2);
    this._n1 = tmp;
    this._n2 = this._n3;
    this._op1 = this._op2;
    }
    else
    {
    //计算后两个数字
    tmp = GetOp(this._op2, this._n2, this._n3);
    this._n2 = tmp;
    this._n3 = null;
    this._op2 = null;
    this.CanCompute = false;
    }
    return tmp;
    }
    //得到Op对象
    private INode GetOp(string op, INode a, INode b)
    {
    if (b == null)
    b
    = new Num(0);
    switch (op)
    {
    case Arithmetic.PLUS:
    return new Plus_Op(a, b);
    case Arithmetic.SUB:
    return new Sub_Op(a, b);
    case Arithmetic.MULTI:
    return new Multi_Op(a, b);
    case Arithmetic.DIV:
    return new Div_Op(a, b);
    default:
    return null;
    }
    }
    //运算符优先级判断
    private bool Priority(string op1, string op2)
    {
    if (op1 == null)
    {
    this._op1 = Arithmetic.PLUS;
    return true;
    }
    if (op1 == Arithmetic.PLUS || op1 == Arithmetic.SUB)
    {
    if (op2 == null || op2 == Arithmetic.PLUS || op2 == Arithmetic.SUB)
    return true;
    else
    return false;
    }
    else
    return true;
    }

    }
    #endregion

    class Arithmetic
    {
    public const string LEFT_BRACKET = "(";
    public const string RIGHT_BRACKET = ")";
    public const string PLUS = "+";
    public const string SUB = "-";
    public const string MULTI = "*";
    public const string DIV = "/";

    public double Eval(string expr)
    {
    List
    <string> wordTree = new List<string>();
    string tmp = "";
    //得到数字
    Action addNum = () =>
    {
    if (tmp.Length > 0)
    {
    wordTree.Add(tmp);
    tmp
    = "";
    }
    };
    #region 词法解析
    foreach (var c in expr)
    {
    if (c == ' ')
    {
    addNum();
    continue;
    }
    else if (c == '(')
    {
    addNum();
    wordTree.Add(LEFT_BRACKET);
    }
    else if (c == ')')
    {
    addNum();
    wordTree.Add(RIGHT_BRACKET);
    }
    else if (c == '+')
    {
    addNum();
    wordTree.Add(PLUS);
    }
    else if (c == '-')
    {
    addNum();
    wordTree.Add(SUB);
    }
    else if (c == '*')
    {
    addNum();
    wordTree.Add(MULTI);
    }
    else if (c == '/')
    {
    addNum();
    wordTree.Add(DIV);
    }
    else
    tmp
    += c;
    }
    #endregion
    addNum();
    var pos
    = 0;
    return Parse(wordTree, ref pos).Compute().Number;
    }
    #region 语义解析
    private INode Parse(List<string> wordTree, ref int pos)
    {
    var assist
    = new ParseAssist();
    //计算中间结果
    Action priority_compute = () =>
    {
    //判断是否达到3数字,2操作符
    if (assist.CanCompute)
    assist.Combinate();
    };
    for (; pos < wordTree.Count; ++pos, priority_compute())
    {
    var word
    = wordTree[pos];
    //遇到左边的小括号进入递归
    if (word == LEFT_BRACKET)
    {
    ++pos;
    assist.AddNum(Parse(wordTree,
    ref pos));
    continue;
    }
    //遇到右边的小括号推出递归
    if (word == RIGHT_BRACKET)
    break;
    if (this.IsOp(word))
    assist.AddOp(word);
    else
    assist.AddNum(word);
    }
    return assist.Combinate();
    }
    #endregion
    private bool IsOp(string op)
    {
    switch (op)
    {
    case PLUS:
    case SUB:
    case MULTI:
    case DIV:
    return true;
    default:
    return false;
    }
    }
    }
    class Program
    {
    static void Main(string[] args)
    {
    var result
    = 1.0;
    Arithmetic a
    = new Arithmetic();
    string expr = "4 * (5 + (8 - 3) * 2) / (1 + 3)";
    string expr1 = "-4 + 3 * 2 / (+1 -7)";
    string expr2 = "44 * (51 + (-8 - 3) * 2) / (1 + 3)";
    Console.WriteLine(a.Eval(expr1));

    Stopwatch sw
    = new Stopwatch();
    sw.Start();
    for (var i = 0; i < 100000; ++i)
    {
    result
    = a.Eval(expr2);
    }
    sw.Stop();
    Console.WriteLine(result);
    Console.WriteLine(sw.ElapsedMilliseconds);
    Console.Read();
    }
    }
    }
  • 相关阅读:
    G1垃圾收集器入门-原创译文
    Dubbo微容器(Cooma)详解
    Dubbo工程结构和Maven打包
    Greys学习笔记(未完待续)
    ES学习笔记
    CSS标准盒子模型和IE怪异盒子模型
    npm install 报错
    安卓手机scrollTop失效问题记录
    npm run dev报错
    severless扫盲
  • 原文地址:https://www.cnblogs.com/yangleiWPF/p/1693602.html
Copyright © 2011-2022 走看看