惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
Stack Overflow Blog
Stack Overflow Blog
月光博客
月光博客
T
Threat Research - Cisco Blogs
小众软件
小众软件
有赞技术团队
有赞技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell
Apple Machine Learning Research
Apple Machine Learning Research
C
Cyber Attacks, Cyber Crime and Cyber Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Tailwind CSS Blog
Cisco Talos Blog
Cisco Talos Blog
V
V2EX
博客园 - 【当耐特】
C
Cybersecurity and Infrastructure Security Agency CISA
Hugging Face - Blog
Hugging Face - Blog
The Cloudflare Blog
The Last Watchdog
The Last Watchdog
Simon Willison's Weblog
Simon Willison's Weblog
T
Threatpost
S
Secure Thoughts
O
OpenAI News
P
Proofpoint News Feed
S
SegmentFault 最新的问题
Forbes - Security
Forbes - Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Application and Cybersecurity Blog
Application and Cybersecurity Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Last Week in AI
Last Week in AI
宝玉的分享
宝玉的分享
Scott Helme
Scott Helme
T
Tenable Blog
A
Arctic Wolf
L
LINUX DO - 热门话题
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
www.infosecurity-magazine.com
www.infosecurity-magazine.com
V
Visual Studio Blog
Hacker News: Ask HN
Hacker News: Ask HN
Hacker News - Newest:
Hacker News - Newest: "LLM"
腾讯CDC
博客园 - Franky
WordPress大学
WordPress大学
Know Your Adversary
Know Your Adversary
博客园_首页
雷峰网
雷峰网
IT之家
IT之家
PCI Perspectives
PCI Perspectives
L
LINUX DO - 最新话题
H
Heimdal Security Blog

博客园 - 空气

没有不可能的事情 迅景如梭,旧游似梦,烟水程何限 [转]一些web开发中常用的、做成cs文件的js代码 MBTI职业性格测试 Which Programming Lanuguage Are You? 如何解释内存中的内容 好久没来了。。。 第七章: 封装 - 空气 - 博客园 C/C++中的内存管理 经典正则表达式 二叉树的显示 软件工厂的考试题目程序 第六章: 字符串 测试-通过Word 2007发布Blog 第五章: 数组 第四章: 从 autoboxing 和 unboxing 认识对象 第三章: 语法入门 1. 让自己习惯C++ 0. 序
数类
空气 · 2007-05-12 · via 博客园 - 空气

需求

实现一个类库来存储数学表达式。

该类主要实现以下功能:

  1. 以某种数据结构存储一个数学表达式。(包含加减乘除,幂,对数等运算符)
  2. 将一个字符串识别为数学表达式。
  3. 将存储的表达式转换为字符串或浮点数值。

要求输入的表达式有如下的形式。

加减乘除幂分别用字符 '+', '-', '*', '/' 来表示,其左右操作数分别放在该字符串的两边。如 1+1, 2^3 等。

对数要将其底数与指数放在括号中,并以逗号分开。 如 Log23 应表示为 Log(2,3)

    以 10 为底的对数应将 10 显示的写出。 如 Log10100 应表示为 Log(10,100)

    另外提供自然对数 Ln。 如 Ln100 可以表示为 Log(2.71828,100) 或者 Ln(100)

上面的操作符均允许嵌套。

设计

要求输入的表达式有如下的形式。

加减乘除幂分别用字符 '+', '-', '*', '/' 类表示

一共设计两个类和一个枚举类型。

如图:

  下面那个是用来测试的控制台程序

枚举 类型OperType用来表示几种操作符;

Operator是操作符类,封装了基本的操作符以及常用的方法;

NumClass是数类,存储表达式并提供表达式的相关操作。

NumClass 类是核心类。

存储数学表达式的数据结构是"树"。对于每个表达式将其按照操作符划分,并以操作符为父节点,左右操作数分别为左右子树。

其主要方法有:

  1. 构造函数 NumClass(String num); 从字符串转化为表达式类
  2. 求值函数 string ToString(); 从存储在类中的表达式向字符串的转化

    double ToDouble(); 对存储的表达式的求值

  3. 化简函数 void Trim(); 在一定程度上化简表达式

实现

上面三个函数的实现思路与算法。具体实现看后面附的程序。

NumClass(String num)

这是一个递归函数。

在字符串中找到适当的位置(要考虑到操作符的优先级)来划分左右子树。把该位置左边递归给左子树,右边递归给右子树,中间的是操作符。

若上面找到的"适当的位置"左边只有一个操作符(或操作数)则执行下面的操作,否则返回。

函数检查字符串最左边的字符,确定表达式第一个操作数(或者是操作符)是数字,括号,对数还是正负号等。并分别赋予正确的值。这样便完成了一次递归的操作。

由于表达式中有形如 Log Ln 等不规则的字符。故实现起来有很多细节需要注意,具体见程序。

string ToString()

double ToDouble()

也是递归实现。

这两个函数的实现方法比较类似。都是递归的计算左右子树,并把结果和操作符一起返回给上一层的调用。

ToSTring() 方法要注意判断操作的优先级以决定是否要增加括号。

void Trim()

该函数调用一个私有函数 void RecursionTrim()。后者递归调用自身,并通过检查操作符的类型以及左右子树是否是叶子结点来决定是否要化简。

可以化简4类表达式。

  1. 不失精度的操作,包括 '+', '-', '*'。如 (1+1)*4 最后可以化简为 8;
  2. 同底数的对数相加减。如 Log(c,a) + Log(c,b) = Log(c,a*b);
  3. 同底数的幂相乘除。 如 c^a * c^b = c^(a+b)
  4. 同指数的幂相乘除。 如 a^c * b^c = (a*b)^c

测试

新建了一个控制台应用程序来测试上面写好的类库。

列举一部分。具体见代码。

构造函数测试

NumClass num;

num = new NumClass("0");

num = new NumClass("-1");

num = new NumClass("+2");

num = new NumClass("-1*2");

num = new NumClass("-1+2");

num = new NumClass("+2*3");

num = new NumClass("((1+1)*(2+2))");

num = new NumClass("log(10,100)*(2+2)/log(2,4)");

num = new NumClass("log(3+7,10*10)^4/log(4,16)");

num = new NumClass("log(log(3,9),log(10,100))");

num = new NumClass("2+((log(log(3,9),log(10,100))+4*2)^2)");

num = new NumClass("log(2+3,25*5)/log(5*5,625)+log(25,625)-log(5,25)");

num = new NumClass("log(1+5,36^2)/log(1+4*2,729)^2+log(3^2,3^4)");

num = new NumClass("log(log(1+1,4^2),16^3)/log(5,log(2,2^25))");

num = new NumClass(" log(log(1+1,4^2), 16^3) / log(5, log(2,2^25)) ");

num = new NumClass(0);

num = new NumClass(0.3);

num = new NumClass(-2);

num = new NumClass(123456.7890);

Console.WriteLine(num.ToDouble());

Console.WriteLine(num.ToString());

操作符重载测试

NumClass numTest1;

NumClass numTest2;

NumClass numTest3;

numTest1 = new NumClass("1-2");

numTest2 = new NumClass("3+4");

numTest3 = numTest1 + numTest2;

numTest3 = numTest1 + 4;

numTest3 = "3-(2*8)" + numTest2;

numTest1 = new NumClass("1-2");

numTest2 = new NumClass("3+4");

numTest3 = numTest1 ^ numTest2;

numTest3 = numTest1 ^ 4;

numTest3 = "3-(2*8)" ^ numTest2;

Console.WriteLine(numTest3.ToDouble());

Console.WriteLine(numTest3.ToString());

表达式化简测试

NumClass num;

num = new NumClass("0");

num = new NumClass("-1");

num = new NumClass("+2");

num = new NumClass("-1*2");

num = new NumClass("-1+2");

num = new NumClass("+2*3");

num = new NumClass("Log(2,2) + Log(2,3)");

num = new NumClass("Log(2,2^4) + Log(2,10)");

num = new NumClass("Log(4,2*4) - Log(2+2,10*4)");

num = new NumClass("2^3*3^3");

num = new NumClass("2^3/3^3");

num = new NumClass("2^4*2^5");

num = new NumClass("2^4/2^5");

num = new NumClass("Log(2,3)^4*Log(2,3)^4");

num = new NumClass("2^Log(2,3)/2^Log(2,3)");

num = new NumClass("2^Log(2,3)/2^Log(2,3)^3");

Console.WriteLine("Before Trim:");

Console.WriteLine(num.ToDouble());

Console.WriteLine(num.ToString());

Console.WriteLine("After Trim:");

num.Trim();

Console.WriteLine(num.ToDouble());

Console.WriteLine(num.ToString());

缺陷

  1. 测试不够完善,程序中肯定有很多未知的错误。
  2. 对错误的输入格式的检查。程序中遇到不正确的输入时便抛出一个异常,但没有机制接收异常。
  3. 化简机制不够完善。比如类似于 4/3/3/3/3/3/3*3*3*3*3 的表达式不能化简为4。