您的位置:首页 > 编程语言 > C语言/C++

文兄的算法题——算术表达式递归构造二叉树

2017-12-22 12:06 260 查看
正在奋斗天津大学的文兄前两天在做算法的时候遇到了一道棘手的题目。

当然,以文兄的聪明才智都不好解决的,我看着也一脸懵逼。然而有万能的度娘,最后还是找到了解决方案。然而说的不是很详细,这里给出我和文兄对这道题的一点理解。

原题如下



按照我的思路,应该先把算术表达式转换成后缀表达式,

那么(a+b)乘(c+d) 转换成后缀表达式为 ab + cd + 乘(星号markdown出不来)

用栈存储运算符,用队列存储数—–然后看过HTDP

都知道,Lisp就是这么编译计算的,按照计算机顺序计算的特点很简单就生成二叉树。

然后,这明显不符合题意,其中构造二叉树子函数必须是递归函数

而且,这明显是道算法题,和这些应该没什么关系。

递归构造的方法

我们的想法是既然括号里面的先算,那么最后的运算符肯定不在括号里面。

然后找括号外的符号,因为乘除是要先算的,那么最后的符号如果有加减的话,那就一定是加减。然后最后的符号作为根节点。

但是,我们都不知道在哪划分左子树和右子树,以及怎样寻找最后的

经过不懈的努力(努力搜),终于找到了递归的方法。

算法思想是一致的,对于表达式,找到最后一个被使用的运算符作为划分,以此运算符为界,递归计算左边的值,递归计算右边的值,然后以此运算符进行运算,即可得到结果.

对于算术表达式,肯定先算括号里的, 然后算乘除法,最后才算加减法 .

所以,先考虑加减法法,再考虑乘除法. 括号外的算术运算符可能很多,所以确定一个原则,找整个算式中最右边算术符号.

代码

#include <iostream>
#define MAXSIZE 1000

using namespace std;

//二叉树结点结构体定义
typedef struct BtreeNode{
char data;
struct BtreeNode *lchild;
struct BtreeNode *rchild;
}BtreeNode;

//算术表达式转化二叉树
/*
afa为指向表达式字符串的指针
s为要转化的表达式字符串的起始位置
e为要转化的表达式字符串的结束位置的后一个
*/
BtreeNode* afaToBtree(char *afa,int s,int e){
//如果只有一个数那就是叶子结点了
if(e-s==1)
{
BtreeNode* bn=(struct BtreeNode*)malloc(sizeof(struct BtreeNode));
bn->data=afa[s];
bn->lchild=NULL;
bn->rchild=NULL;
return bn;
}
/*
local_r记录当前要转化的表达式生成二叉树的根节点操作符的位置
flag记录是否当前搜索在括号里面
m_m_p记录当前表达式中括号外面最右边的+、-位置
a_s_p记录当前表达式中括号外面最右边的*、/位置
*/
int local_r=0,flag=0;
int m_m_p=0,a_s_p=0;
for(int i=s;i<e;i++)
{
if(afa[i]=='(')flag++;
else if(afa[i]==')')flag--;
if(flag==0){
if(afa[i]=='*'||afa[i]=='/')
m_m_p=i;
else if(afa[i]=='+'||afa[i]=='-')
a_s_p=i;
}
}
if((m_m_p==0)&&(a_s_p==0))
//如果式子整个有括号如(a-b*c+d),即括号外面没有操作符,则去掉括号找二叉树
afaToBtree(afa,s+1,e-1);
else
{
//如果有+或者-,则根节点为最右边的+或-,否则是最右边的*或/
if(a_s_p>0)local_r=a_s_p;
else if(m_m_p>0)local_r=m_m_p;
//确定根节点和根节点的左孩子和右孩子
BtreeNode* b=(struct BtreeNode*)malloc(sizeof(struct BtreeNode));;
b->data=afa[local_r];
b->lchild=afaToBtree(afa,s,local_r);
b->rchild=afaToBtree(afa,local_r+1,e);
return b;
}
}

void main(){

char input[MAXSIZE];
int len=0;
//初始化
memset(input,'\0',sizeof(input));

cin >> input ;

BtreeNode* myBtree=(struct BtreeNode*)malloc(sizeof(struct BtreeNode));

//myBtree就是input算术表达式产生的二叉树的根节点(指针类型)

myBtree=afaToBtree(input,0,strlen(input));
}


由于要找的是括号外的算术运算符, 所以得想办法避免记录括号内的运算符,所以设置了一个标志,初始为零,一旦遇到一个左括号, +1, 这时候说明目前在括号内,不应该记录运算符, 当遇到右括号,-1,标志恢复为0,这时候说明目前已经走出
4000
括号,可以记录运算符 .

扫描完整个表达式的时候,m_m_p记录了最右边的括号外的+-号,a_s_p记录了最右边的括号外的*/号.

把(m_m_p==0)&&(a_s_p==0),说明整个算式被括号包围起来了.

括号外面没有操作符,所以可以递归运算时忽略这对括号。

最后,祝文兄考个好成绩!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息