表达式求值(二叉树方法/C++语言描述)(二)

  表达式二叉树节点的数据可能是运算数或运算符,可以使用一个联合体进行存储;同时还需要一个变量来指示存储的是运算数还是运算符,可以采用和栈方法求值中一样的枚举类型TokenType:

 1 typedef enum
 2 {
 3     BEGIN,
 4     NUMBER,
 5     OPERATOR,
 6     LEFT_BRAC,
 7     RIGHT_BRAC
 8 } TokenType;
 9 
10 class Token
11 {
12 public:
13     TokenType _type;
14     union
15     {
16         char op;
17         double num;
18     } _data;
19 };

  二叉树方法求值的Calculator类公有继承自节点数据数据类型为Token类的BinaryTree类:

 1 class Calculator : public BinaryTree<Token>
 2 {
 3 public:
 4     void parseExpression(string expression) throw(string);
 5     double calculate();
 6 
 7 private:
 8     stack<char> _stkOperators;
 9     stack<BinaryTreeNode<Token> *> _stkNodes;
10     stack<double> _stkNumbers;
11 
12     static int priority(char op);
13     static double calculate(double d1, char op, double d2) throw(string);
14 
15     void postOrder(BinaryTreeNode<Token> * node);
16     void calculateStack() throw(string);
17     void dealWithNumber(char *&pToken) throw(string);
18     void dealWithOperator(char *&pToken) throw(string);
19     void dealWithLeftBrac(char *&pToken) throw(string);
20     void dealWithRightBrac(char *&pToken) throw(string);
21 };

方法parseExpression()用来将表达式转换为二叉树,它需要两个栈,一个用来存储运算符,一个用来存储指向子树的指针;用来存储浮点类型的栈仅在求值时使用。由于parseExpression方法需要访问BinaryTreeNode类的私有成员,因此还要在BinaryTreeNode类中声明Calculator类为友元类。

  转换过程与栈方法求值的运算压栈过程基本相同,当遇到运算数时,生成一个新的节点并将它的指针压入节点指针栈中;遇到运算符时比较当前运算符和运算符栈栈顶运算符的优先级,若运算符栈栈顶运算符的优先级较高,则为它生成一个新的节点,并从节点指针栈中弹出两个节点指针,作为新节点的左子树和右子树,随后将这个新节点的指针压入节点指针栈中,将当前运算符压入运算符栈中,否则只将当前运算符压入运算符栈中。最后反复执行上述过程,直至运算符栈为空,节点指针栈的栈顶元素即为指向树根节点的指针。表达式“1+2*3”和“1*2+3”的转换过程如下图:

 

使用代码描述操作节点指针栈的过程:

 1 void Calculator::calculateStack() throw(string)
 2 {
 3     BinaryTreeNode<Token> * node = new BinaryTreeNode<Token>();
 4     assert(node);
 5     node->_data._type = OPERATOR;
 6     node->_data._data.op = _stkOperators.top();
 7     _stkOperators.pop();
 8     assert(!_stkNodes.empty());
 9     node->_rightChild = _stkNodes.top();
10     _stkNodes.pop();
11     assert(!_stkNodes.empty());
12     node->_leftChild = _stkNodes.top();
13     _stkNodes.pop();
14     _stkNodes.push(node);
15 }

  根据数学规则以及最后清空运算符栈的过程,parseExpression()方法实现如下:

 1 void Calculator::parseExpression(string expression) throw(string)
 2 {
 3     destory();
 4     while (!_stkNodes.empty())
 5     {
 6         _stkNodes.pop();
 7     }
 8     while (!_stkOperators.empty())
 9     {
10         _stkOperators.pop();
11     }
12     TokenType lastToken = BEGIN;
13 
14     char * pToken = &expression[0];
15     while (*pToken)
16     {
17         switch (lastToken)
18         {
19         case BEGIN:
20             if (*pToken == '(')
21             {
22                 // an expression begin with a left bracket
23                 dealWithLeftBrac(pToken);;
24                 lastToken = LEFT_BRAC;
25             }
26             else
27             {
28                 // or a number
29                 dealWithNumber(pToken);
30                 lastToken = NUMBER;
31             }
32             break;
33         case NUMBER:
34             // after a number
35             if (*pToken == ')')
36             {
37                 // it may be a right bracket
38                 dealWithRightBrac(pToken);
39                 lastToken = RIGHT_BRAC;
40             }
41             else
42             {
43                 // it may be an operator
44                 dealWithOperator(pToken);
45                 lastToken = OPERATOR;
46             }
47             break;
48         case OPERATOR:
49         case LEFT_BRAC:
50             // after an operator or a left bracket
51             if (*pToken == '(')
52             {
53                 // it may be a left bracket
54                 dealWithLeftBrac(pToken);
55                 lastToken = LEFT_BRAC;
56             }
57             else
58             {
59                 // it may be a number
60                 dealWithNumber(pToken);
61                 lastToken = NUMBER;
62             }
63             break;
64         case RIGHT_BRAC:
65             // after a right bracket
66             if (*pToken == ')')
67             {
68                 // it may be another right bracket
69                 dealWithRightBrac(pToken);
70                 lastToken = RIGHT_BRAC;
71             }
72             else
73             {
74                 // it may be an perator
75                 dealWithOperator(pToken);
76                 lastToken = OPERATOR;
77             }
78             break;
79         }
80     }
81 
82     while (!_stkOperators.empty())
83     {
84         if (_stkOperators.top() == '(')
85         {
86             throw string("bad token '('");
87         }
88         calculateStack();
89     }
90 
91     assert(!_stkNodes.empty());
92     _root = _stkNodes.top();
93 }

方法实现与栈方法求值的公有方法calculator()基本相同。开始调用的destory()方法继承自BinaryTree类,用于释放已占用的二叉树节点空间,可以防止程序内存溢出。

转载于:https://www.cnblogs.com/lets-blu/p/7289643.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400307.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python连接mysql

1&#xff09; 安装 sudo apt-get install mysql-serversudo apt-get install python-mysqldb 2&#xff09; 使用 import MySQLdbdef get_db_connector():return MySQLdb.connect(hostlocalhost, userroot, passwdchangme, dbdatabaseName)def set_db_close(conn, cur):conn.…

【RK3399Pro学习笔记】五、ROS与USB摄像头

目录usb_cam方法一安装一些要用的包测试usb摄像头方法二下载usb_cam源码编译测试usb摄像头uvc-camera平台&#xff1a;华硕 Thinker Edge R 瑞芯微 RK3399Pro 固件版本&#xff1a;Tinker_Edge_R-Debian-Stretch-V1.0.4-20200615 参考资料&#xff1a; ROS下usb_cam的安装 ——…

这是我们的第一篇博客----偕行软件

欢迎您光临我们的网站&#xff1a;链接 转载于:https://www.cnblogs.com/udsoft/p/3259366.html

wp insert post 插入文章到数据库

在 wordpress 主题目录下的 index.php 文件中&#xff0c;添加如下代码 <?php get_header(); ?><?php// 创建文章对象 $my_post array(post_title > 我的测试文章,post_content > 这是一个测试文章。,post_status > publish,post_author > 1…

Eclipse相关快捷键

Alt左箭头,右箭头 以在编辑窗口切换标签Alt上下箭头, 以自动选择鼠标所在行,并将其上下移动Ctrlf6 可以弹出菜单,上面列出可以切换的编辑窗口,这样不用鼠标也可切换Ctrlf7 可以在视图之间切换 ,如编辑视图,输出视图,工程视图Ctrlf8 可以在不同的观察视图中切换,就是在java视图,…

MFC编程之创建Ribbon样式的应用程序框架

Ribbon界面就是微软从Office2007開始引入的一种为了使应用程序的功能更加易于发现和使用、降低了点击鼠标的次数的新型界面。从实际效果来看&#xff0c;不仅外观美丽&#xff0c;并且功能直观&#xff0c;用户操作简洁方便。 利用MFC向导创建Ribbon样式的单文档应用程序框架的…

【RK3399Pro学习笔记】六、ROS发布者Publisher的编程实现

目录如何实现一个发布者C创建功能包编写程序配置CMakeLists.txt编译并运行发布者python创建并编写脚本运行平台&#xff1a;华硕 Thinker Edge R 瑞芯微 RK3399Pro 固件版本&#xff1a;Tinker_Edge_R-Debian-Stretch-V1.0.4-20200615 记录自【古月居】古月ROS入门21讲 | 一学…

linux下svn命令大全

1、将文件checkout到本地目录 svn checkout path&#xff08;path是服务器上的目录&#xff09; 例如&#xff1a;svn checkout svn://192.168.1.1/pro/domain 简写&#xff1a;svn co 2、往版本库中添加新的文件 svn add file 例如&#xff1a;svn add test.php(添加test.php)…

PHP 从结果集中取得一行作为关联数组:

<?php // 假定数据库用户名&#xff1a;root&#xff0c;密码&#xff1a;123456&#xff0c;数据库&#xff1a;RUNOOB $conmysqli_connect("localhost","root","123456","RUNOOB"); if (mysqli_connect_errno($con)) { echo…

三星:Android之外,技术为王

作为Android阵营的领军代表&#xff0c;三星手机为行业与消费者带来了深远的影响与改变&#xff0c;以至于一提到三星&#xff0c;几乎所有人的第一印象都是三星手机。事实上&#xff0c;在手机之外的众多产品领域中&#xff0c;三星同样有着惊人的成绩与贡献。三星的显示器产品…

ASP.NET Core 源码学习之 Logging[3]:Logger

上一章&#xff0c;我们介绍了日志的配置&#xff0c;在熟悉了配置之后&#xff0c;自然是要了解一下在应用程序中如何使用&#xff0c;而本章则从最基本的使用开始&#xff0c;逐步去了解去源码。 LoggerFactory 我们可以在构造函数中注入 ILoggerFactory&#xff0c;来创建一…

【RK3399Pro学习笔记】七、ROS订阅者Subscriber的编程实现

目录如何实现一个订阅者C编写程序配置CMakeLists.txt编译并运行发布者python创建并编写脚本运行平台&#xff1a;华硕 Thinker Edge R 瑞芯微 RK3399Pro 固件版本&#xff1a;Tinker_Edge_R-Debian-Stretch-V1.0.4-20200615 记录自【古月居】古月ROS入门21讲 | 一学就会的ROS机…

C#操作sql通用类 SQLHelper

Codeusing System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Collections; using System.Data.SqlClient;/// <summary> /// 数据库的通用访问代码 /// 此类为抽象类&#xff0c;不允许实例化&#x…

PHP中变量类型的判断

PHP中变量类型的判断 一、gettype() gettype 会根据 参数类型返回下列值 “boolean”&#xff08;从 PHP 4 起&#xff09; “integer” “double”&#xff08;如果是 float 则返回“double”&#xff0c;而不是“float”&#xff09; “string” “array” “object”…

SqlServer优化:当数据量查询不是特别多,但数据库服务器的CPU资源一直100%时,如何优化?...

最近和同事处理一个小程序&#xff0c;数据量不是特别大&#xff0c;某表的的数据记录&#xff1a;7000W条记录左右&#xff0c;但是从改别执行一次查询时&#xff0c;却发现查询速度也不快&#xff0c;而且最明显的问题就是CPU100%。 sql语句&#xff1a; select gridid,lng,l…

时间比金钱金贵得多

工资是一个非常直观的参数&#xff0c;所有人都会被它的数字所诱惑&#xff0c;但工资的背后&#xff0c;体现的是你劳动的性价比&#xff0c;是万不可用工资去交换。 第一个故事 一个35岁左右的白骨精来找我们&#xff0c;她需要在两个工作里面做选择。一个是年薪30万的制片总…

【RK3399Pro学习笔记】八、ROS话题消息的定义与使用

目录自定义话题消息定义msg文件在package.xml中添加功能包依赖在CMakeLists.txt添加编译选项编译结果使用C编写程序person_publisher.cppperson_subscriber.cpp配置CMakeLists.txt编译并运行python编写程序person_publisher.py运行平台&#xff1a;华硕 Thinker Edge R 瑞芯微 …

ios 打电话结束返回到应用中

在我们做打电话这个功能时&#xff0c;我们常常是调用这个方法&#xff1a; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:"tel://xxxxx"]]; 然而&#xff0c;这样实现了功能后&#xff0c;结束通话后&#xff0c;确不能回到自己的应用中来。最…

php 字符符转整数

intval() $my_month intval($my_format_date[1]);

C语言及程序设计进阶例程-17 认识链表

贺老师教学链接 C语言及程序设计进阶 本课讲解 例 建立并输出一个简单链表 #include <stdio.h> struct Student {int num;float score;struct Student *next; }; int main( ) {struct Student a,b,c,*head,*p;a. num31001;a.score89.5;b. num31003;b.score90;c. num3100…