巧妙地用二叉树完成算式计算算法<计算器,二叉树,C++,独辟蹊径>
#01、引言,我们知道算式计算的问题是栈里面一个非常经典的题目。但是用栈来实现是一个非常麻烦的过程,第一要解决算式判断,是否为符合规则的算式,第二要由中最表达式转化为后缀表达式。这两个部分是栈实现计算算式表达式的比较复杂的地方。不仅如此,栈实现里面的各种运算符的优先级,各种条件判断,可以说是麻烦的要命。但是,实际上有一种数据结构比栈更适合解决这类问题。可以说是得天独厚的优势。对,就是二叉树。例如一个表达式:1+2*3-4/5
我们构造这样一个二叉树

#define Maxsize 100
//定义数据元素类型
typedef char elemtype;
//定义二叉树数据变量
typedef union
{
char Operator;
double date;
}perdate;
//定义二叉树链式存储结构
typedef struct node
{
perdate DATE;//用union类型存运算符或操作数
struct node *lchild;
struct node *rchild;
}btnode;
struct op
{
char opration;
int index;//括号层数//当这个index被标记为-1时,就不会再次被查找到
int locate;//op的位置
};
用union定义一个perdate类型,用来分别记录操作数和运算符。op是查找运算符时用,从后往前查找,括号级数最低的作为根节点来创建二叉树。
0x002、实现的函数
//查找op,并填充Aop数组
int Sortop(char str[], op Aop[], int &index);
//将字符串转化为浮点数
double str_to_flaot(char strpoly[], int p,int q);
//判断数组是不是1.2类型,就是只有数据
bool isdate(char str[],int p,int q);//p,q指向str的开始和结尾处
//判断str是否为运算符和括号
bool isoprater(char str[],int p,int q);//p,q指向str的开始和结尾处
//用算数表达式创建二叉树
void Createbtnode(btnode *b, char *str, int p, int q,int tail);//p,q指向str的开始和结尾处;tail是Aop的尾指针
//计算二叉树算式的结果
double Comp(btnode *b);
0x003、main函数,整个算法过程简述
#include"标头.h"
int index = ;//记录最大的括号层数
struct op Aop[Maxsize];
int main()
{
btnode * b;
b = new btnode;
char str[Maxsize];
cout << "算式计算器[张安源]" << endl;
while(true)
{
cout << "[Type \"exit\" to exit]" << endl << "请输入你要求的表达式:" << endl;
cin.getline(str, Maxsize);
if (strcmp("exit", str) == ) break;//如果输入的是exit则退出
else
{
int tail = Sortop(str, Aop, index);//整理得到Aop的结构数组
Createbtnode(b, str, , strlen(str) - , tail);
double result = Comp(b);
cout << result << endl;
}
}
}
一直循环,让用户输入一个表达式,当输入为exit时,退出循环。Sortop函数将表达式的操作符的括号层数和其在表达式的位置经行记录到Aop数组里面,返回值是最大的括号层数。然后由Createbtnode函数创建一个二叉树b。comp求出二叉树表达式的结构,然后输出结果。大致的过程是这样,但是里面却还包含了一些实现的细节,具体代码是怎么实现的就不啰嗦了,看代码比讲解跟方便。
0x004、整个project。
<1>Header.h
#pragma once
#include<iostream>
using namespace std;
#define Maxsize 100
//定义数据元素类型
//*********int check = 0;//作为判断表达式是否正确的标记
typedef char elemtype;
//定义二叉树数据变量
typedef union
{
char Operator;
double date;
}perdate;
//定义二叉树链式存储结构
typedef struct node
{
perdate DATE;//用union类型存运算符或操作数
struct node *lchild;
struct node *rchild;
}btnode;
//定义查找运算符的结构数组
struct op
{
char opration;
int index;//括号层数//当这个index被标记为-1时,就不会再次被查找到
int locate;//op的位置
};
extern int index;
extern struct op Aop[Maxsize];
//******************************************************
//查找op,并填充Aop数组
int Sortop(char str[], op Aop[], int &index);
//将字符串转化为浮点数
double str_to_flaot(char strpoly[], int p,int q);
//判断数组是不是1.2类型,就是只有数据
bool isdate(char str[],int p,int q);//p,q指向str的开始和结尾处
//判断str是否为运算符和括号
bool isoprater(char str[],int p,int q);//p,q指向str的开始和结尾处
//用算数表达式创建二叉树
void Createbtnode(btnode *b, char *str, int p, int q,int tail);//p,q指向str的开始和结尾处;tail是Aop的尾指针
//计算二叉树算式的结果
double Comp(btnode *b);
<2>op.cpp
#include"标头.h"
//查找op,并填充Aop数组
int Sortop(char str[], op Aop[], int &index)
{
int j = ;//记录Aop的top
int i;
int ind = ;//记录括号层数
for (i = ; str[i] != '\0'; i++)
{
if (str[i] == '(')
ind++;
else if (str[i] == ')')
ind--;
else if (str[i] == '+' || str[i] == '-' || str[i] == '*'||str[i]=='/' || str[i] == '^')
{
Aop[j].opration = str[i];
Aop[j].index = ind;
Aop[j].locate = i;
j++;
}
index = (index > ind) ? index : ind;
}
return j;
}
//将字符串转化为浮点数
double str_to_flaot(char strpoly[], int p,int q)
{
if (strpoly[p] == '(')
p++;
if (strpoly[q] == ')')
q--;
//判断小数点前有几位数字
int index = ;
int temp = p;//保存原来的p值
double n = ;//最后的浮点数
for (;( p <= q)&&(strpoly[p]!='.'); p++) index++;
p = temp;
for (; p<=q; p++)
{
if (strpoly[p] == '.') continue;
index--;
n = n + ((double)(strpoly[p] - ''))*(pow(, index)); }
return n;
}
//判断数组是不是1.2类型,就是只有数据//忽略括号
bool isdate(char str[],int p,int q)
{
int i;
int index = ;
for (i = p; i<=q; i++)
{
if (str[i] == '.')
index++;
if (str[i] == '+' || str[i] == '-' || str[i] == '*' ||str[i]=='/' || str[i] == '^')
return false;
}
if (index== || index == )
{
return true;
}
else
abort();
}
//判断str是否为运算符和括号
bool isoprater(char str[],int p,int q)
{
if ((p==q)&&(str[p] == '(' || str[p] == ')' || str[p] == '*'||str[p]=='/' || str[p] == '^' || str[p] == '+' || str[p] == '-'))
return true;
else
return false;
}
//用算数表达式创建二叉树
void Createbtnode(btnode *b, char *str, int p, int q,int tail) //由str串创建二叉链
{ //p,q分别标志Aop的首尾
int i = ;
int j = ;//
int find=;
if (isdate(str,p,q))//str为1.3类型
{
//创建头节点,并将数据位置为str_to_double
b->DATE.date = str_to_flaot(str,p,q);
b->lchild = NULL;
b->rchild = NULL;
}
else if (isoprater(str,p,q))//str为+、—、^、(、)、*
{
abort();
b->DATE.Operator = str[i];
b->lchild = NULL;
b->rchild = NULL;
}
///***************************************************************
else
for (int temp = ; temp <= index; temp++)
{
for (j = tail; j >=; j--)//从后往前找,才符合运算的法则,前面先算后面后算
{
if (Aop[j].index == temp && ((Aop[j].opration == '+')||(Aop[j].opration == '-')) && Aop[j].locate >= p&&Aop[j].locate <= q)
{
find++;
Aop[j].index = -;//标志这个已经被找过了
btnode *lt, *rt;
lt = new btnode;
rt = new btnode;
b->lchild = lt;
b->rchild = rt;
b->DATE.Operator = Aop[j].opration;
Createbtnode(b->lchild, str, p, Aop[j].locate - ,tail);
Createbtnode(b->rchild, str, Aop[j].locate+, q,tail);
}
}
if(find==)
for (j = tail; j >=; j--)
{
if (Aop[j].index == temp && ((Aop[j].opration == '*')||(Aop[j].opration=='/')) && Aop[j].locate >= p&&Aop[j].locate <= q)
{
find++;
Aop[j].index = -;//标志这个已经被找过了
btnode *lt, *rt;
lt = new btnode;
rt = new btnode;
b->lchild = lt;
b->rchild = rt;
b->DATE.Operator = Aop[j].opration;
Createbtnode(b->lchild, str, p, Aop[j].locate - ,tail);
Createbtnode(b->rchild, str, Aop[j].locate+, q,tail);
}
}
if(find==)
for (j = tail; j >=; j--)
{
if (Aop[j].index == temp && (Aop[j].opration == '^') && Aop[j].locate >= p&&Aop[j].locate <= q)
{
Aop[j].index = -;//标志这个已经被找过了
btnode *lt, *rt;
lt = new btnode;
rt = new btnode;
b->lchild = lt;
b->rchild = rt;
b->DATE.Operator = Aop[j].opration;
Createbtnode(b->lchild, str, p, Aop[j].locate - ,tail);
Createbtnode(b->rchild, str, Aop[j].locate+, q,tail);
}
}
}
}
//计算二叉树算式的结果
double Comp(btnode *b)
{
double v1, v2;
if (b == NULL) return ;
if (b->lchild == NULL && b->rchild == NULL)
return b->DATE.date; //叶子节点直接返回节点值
v1 = Comp(b->lchild);
v2 = Comp(b->rchild);
switch (b->DATE.Operator)
{
case '+':
return v1 + v2;
case '-':
return v1 - v2;
case '*':
return v1*v2;
case '/':
if (v2 != )
return v1 / v2;
else
abort();
case '^':
return (pow(v1, v2));
default:
abort();
}
}
<3>main.cpp
#include"标头.h"
int index = ;//记录最大的括号层数
struct op Aop[Maxsize];
int main()
{
btnode * b;
b = new btnode;
char str[Maxsize];
cout << "算式计算器[张安源]" << endl;
while(true)
{
cout << "[Type \"exit\" to exit]" << endl << "请输入你要求的表达式:" << endl;
cin.getline(str, Maxsize);
if (strcmp("exit", str) == ) break;//如果输入的是exit则退出
else
{
int tail = Sortop(str, Aop, index);//整理得到Aop的结构数组
Createbtnode(b, str, , strlen(str) - , tail);
double result = Comp(b);
cout << result << endl;
}
}
}
#04算法测试

当输入的表达式符合规则时,返回表达式的值。


当输入的表达式不符合规则时,则调用abort函数。
#05、总结
好的数据结构能事半功倍,要培养善于发现的思维,当有某个思路然后去实现它,另外要积累经验。好好理解数据结构!
巧妙地用二叉树完成算式计算算法<计算器,二叉树,C++,独辟蹊径>的更多相关文章
- 二叉树 ADT接口 遍历算法 常规运算
BTree.h (结构定义, 基本操作, 遍历) #define MS 10 typedef struct BTreeNode{ char data; struct BTreeNode * lef ...
- Scalaz(31)- Free :自由数据结构-算式和算法的关注分离
我们可以通过自由数据结构(Free Structure)实现对程序的算式和算法分离关注(separation of concern).算式(Abstract Syntax Tree, AST)即运算表 ...
- JavaScript--数据结构与算法之二叉树
树是一种非线性的数据结构,以分层的方式存储数据. 二叉树:查找非常快,而且二叉树添加或者删除元素也非常快. 形象的可以描述为组织结构图,用来描述一个组织的结构.树是由边连接的点组成.树的一些基本概念: ...
- php求二叉树的深度(1、二叉树就可以递归,因为结构和子结构太相似)(2、谋而后动,算法想清楚,很好过的)
php求二叉树的深度(1.二叉树就可以递归,因为结构和子结构太相似)(2.谋而后动,算法想清楚,很好过的) 一.总结 1.二叉树就可以递归,因为结构和子结构太相似 2.谋而后动,算法想清楚,很好过的 ...
- 两通道实信号使用一个FFT同时计算算法
前言 在工程的实际应用场景中,往往是需要最省资源量.而DSP资源和BRAM资源对FPGA来说弥足珍贵. 对于同时存在多个通道的实信号需要做FFT而言,常规做法是每个通道用一个FFT IP,FFT IP ...
- 算法:二叉树的层次遍历(递归实现+非递归实现,lua)
二叉树知识参考:深入学习二叉树(一) 二叉树基础 递归实现层次遍历算法参考:[面经]用递归方法对二叉树进行层次遍历 && 二叉树深度 上面第一篇基础写得不错,不了解二叉树的值得一看. ...
- 【数据结构与算法】二叉树的 Morris 遍历(前序、中序、后序)
前置说明 不了解二叉树非递归遍历的可以看我之前的文章[数据结构与算法]二叉树模板及例题 Morris 遍历 概述 Morris 遍历是一种遍历二叉树的方式,并且时间复杂度O(N),额外空间复杂度O(1 ...
- [PHP] 算法-镜像二叉树的PHP实现
操作给定的二叉树,将其变换为源二叉树的镜像. 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ 11 9 7 5 思 ...
- 编程熊讲解LeetCode算法《二叉树》
大家好,我是编程熊. 往期我们一起学习了<线性表>相关知识. 本期我们一起学习二叉树,二叉树的问题,大多以递归为基础,根据题目的要求,在递归过程中记录关键信息,进而解决问题. 如果还未学习 ...
随机推荐
- linux系统下的软连接与硬链接
前几天在linux系统下安装mongoDB,然后运行脚本导入数据的时候遇到了链接库查询不到的情况,如图 1所示.当时是通过创建软连接的方式解决的这个问题.虽然,通过网上的教程解决了这个问题,但是对于软 ...
- 用ARCGIS配出一张DEM专题图
专题图是指突出而尽可能完善.详尽地表达制图区内的一种或几种自然或社会经济要素的地图.专题图的制图领域宽广,凡具有空间属性的信息数据都可以用其来表示.由于DEM描述的是地面高程信息,它在测绘.水文.气象 ...
- iOS中如何切换到发短信、打电话、发邮件
我们在做APP的时候,难免会遇到需要调用短信,电话等程序的时候.如美团. 当然,这些都只是一些简单的方法就可以实现,但是时间久了也会淡忘,所以想写这边博客.一是为了再捡起来复习一下,另一个相当于留个备 ...
- 4、Python:strip(),split()
1.strip()函数 strip()是删除'()'里面的字符,当()为空时,默认删除空白符(包括'\n','\r','\t','') (1)s.strip(rm) 删除s字符串中开头. ...
- nodeJS环境
nodeJS官网:https://nodejs.org/en/, npm官网(node package manager):https://www.npmjs.com/ 进入nodejs官方网站下载软 ...
- VUE 入门基础(1)
一,安装 Vue.js 不支持 IE8 及其以下版本,因为 Vue.js 使用了 IE8 不能模拟的 ECMAScript 5 特性. Vue.js 支持所有兼容 ECMAScript 5 的浏览器. ...
- callback转Promise
环境: nodejs - v6.2.0 const fs = require('fs'); let Promise = require('bluebird'); let readSync = fun ...
- awk的涂鸦
awk太牛了,博大精深,学不透,学了不用,又忘. 所以花了一天,自己总结了基础,以后就当字典查(容易忘).有不对的地方,忘大家指出. [ganzl@cmdb ~]$ more /etc/passwd ...
- 已解决: 已引发: "无法加载 DLL“opencv_core2410”: 找不到指定的模块。
之前是win7 32位系统,程序运行没有问题:换了64位 win7后,系统就找不到opencv相关库了,网上各种查询解决方法,感觉不太可行,或者很麻烦...多次试验后,找到方便关键的解决方案如下: 计 ...
- windows下手动安装和配置xamarin
安装xamarin xamarin官方给出了两种安装方式,自动安装和手动安装. 自动安装比较简单,到http://xamarin.com/download下载xamarininstaller.exe ...