美文网首页二叉树之下
基于二叉树的算术表达式计算与实现

基于二叉树的算术表达式计算与实现

作者: iDucky131 | 来源:发表于2019-03-14 17:39 被阅读29次

最近做题时遇到一道很有意思的题,当时思考了很久没有思路,最后在借鉴下面这篇文章后做了出来:
基于二叉树的算术表达式计算与实现

题目如下

表达式树是二叉树的一种应用,叶子是操作数,其余结点为操作符。例如,下图表示的表达式树,用中序遍历得到中序表达式 (a+bc)+((de+f)*g)

题目

就是这么一道题,想了好久没想出来(自己太菜了,以后要多多码代码了.jpg),看了上面那篇文章之后,自己参考着写了些,现在总结一下思路:

首先我们看一下题上给的这个中缀表达式,和图片对应后我们可以发现最上面的根节点就是括号外面的那个节点,其中有这么几条规则:
1.如果括号外有有+或者-,那么一定是最后一个+或者-最后运算
例如:(2+5)x3-5/2,这里的减号一定是最后计算的;

2.如果括号外有x或者/而且没有+或者-,那么x或者/一定是最后计算的

所以,我们就可以利用这个来解决中缀表达式转换为对应后缀表达式二叉树的形式

toTree()函数:
-接收到一个字符串
-扫描字符串,寻找括号外面的符号,如果括号外面存在符号,按照上面的两个规则定义根节点,并递归定义左孩子节点和右孩子节点

-如果没有,说明这个算术表达式被括号包起来,那就去掉括号后继续递归
目前实现了以下功能
  • 转换字母形式的中缀表达式,如(a-b)*c
  • 转换多位数和单位整数形式的中缀表达式,如(29-23)*7/(2+3)
  • 转换存在负数的中缀表达式,但是负数必须用()括起来,如:
    (-14x5)/2 必须表示为 ((-14)x5)/2才能够正常转换
PS:以上字母和括号、符号全部在英文输入法下输入终端
代码如下,有注释,应该不难懂:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define Max 200
#define notNumber 0x7fffffff  //最大的int类型,用于最为一个判断标志

struct Tree
{
    int flag; //标志段,0表示数字,1表示字符
    int data; //数据段
    char cha;
    Tree *lchild; //左孩子节点
    Tree *rchild; //右孩子节点
};

int check(char a[], int start, int end)
{ //判断是否只剩下了数字
    int number = 0;
    int flag = 1;  //正数和负数标志
    if (a[start] == '-')
    {
        flag = -1;
        start++;
    }
    for (int i = start; i < end; i++)
    {
        if (!isdigit(a[i]))
            return notNumber;
        number = number * 10 + (a[i] - '0');
    }
    return number * flag;
}

Tree *changeToTree(char a[], int start, int end)
{

    int number = check(a, start, end); //判断当前字符串内是不是只剩下了数字
    if (number != notNumber)
    { //如果字符串只有数字 
        Tree *root = (Tree *)malloc(sizeof(Tree));
        root->flag = 0;
        root->data = number;
        root->lchild = NULL;
        root->rchild = NULL;
        return root;
    }
    if(start==end-1){ //弥补上方的数字格式,用于输出字母表达式
        Tree *root = (Tree *)malloc(sizeof(Tree));
        root->flag = 1;
        root->cha = a[start];
        root->lchild = NULL;
        root->rchild = NULL;
        return root;

    }
    int posAddOrSub = -1; //最后一个+或者-运算符号的位置
    int posMulOrDiv = -1; //最后一个*或者/运算符号的位置
    int flags = 0;        //?????
    for (int i = start; i < end; i++)
    { //遍历字符串,寻找括号外的运算符
        if (a[i] == '(')
            flags++;
        else if (a[i] == ')')
            flags--;
        if (flags == 0)
        { //如果当前符号在括号外
            if (a[i] == '+' || a[i] == '-')
                posAddOrSub = i;
            else if (a[i] == '*' || a[i] == '/')
                posMulOrDiv = i;
        }
    }

    if (posAddOrSub > 0)
    { //存在+或者-,那么最后一个+或-符号就是根节点
        Tree *root = (Tree *)malloc(sizeof(Tree));
        root->flag = 1; //+?-????flag??1
        root->cha = a[posAddOrSub];
        root->lchild = changeToTree(a, start, posAddOrSub);
        root->rchild = changeToTree(a, posAddOrSub + 1, end);
        return root;
    }
    else if (posMulOrDiv > 0)
    { //如果括号外存在*或者/,那么最后一个运算符就是根节点
        Tree *root = (Tree *)malloc(sizeof(Tree));
        root->flag = 1; //*?/???
        root->cha = a[posMulOrDiv];
        root->lchild = changeToTree(a, start, posMulOrDiv);
        root->rchild = changeToTree(a, posMulOrDiv + 1, end);
        return root;
    }

    else if (posAddOrSub == -1 && posMulOrDiv == -1)
    { //如果括号外不存在运算符号,那么说明这个表达式被()包围,去掉括号递归转换
        return changeToTree(a, start + 1, end - 1);
    }
}

void showTree(Tree *root)
{
    if (root)
    {
        //后序遍历输出树
        showTree(root->lchild); //输出左孩子
        showTree(root->rchild); //输出右孩子
        if (root->flag == 0)    //输出当前节点
        {
            printf("%d", root->data);
        }
        else
        {
            printf("%c", root->cha);
        }
    }
}

int main()
{
    char a[Max];
    printf("Please enter the value of the arithmetic expression: (negative numbers are enclosed in parentheses):\n");
    scanf("%s", a);
    int start = 0;
    int end = 0;
    Tree *root = (Tree *)malloc(sizeof(Tree));
    while (a[end] != '\0')
    { //记录字符串的长度
        end++;
    }
    root = changeToTree(a, start, end);
    showTree(root);

    printf("\n---------------------------\n");
    printf("---------end---------------\n");
    system("pause");
    return 0;
}


相关文章

  • 基于二叉树的算术表达式计算与实现

    最近做题时遇到一道很有意思的题,当时思考了很久没有思路,最后在借鉴下面这篇文章后做了出来:基于二叉树的算术表达式计...

  • 堆栈计算算术表达式

    双堆栈计算算术表达式

  • 利用栈解析算术表达式

    在编写编译器时经常需要实现对算术表达式的解析,然而对于计算机的算法来说如果直接求解算术表达式的值,还是相当困难的。...

  • 中缀表达式构建二叉树

    在上篇文章栈结构与四则运算中提到了通过算术表达式构造二叉树,比如是一个标准的算术表达式,也叫中缀表达式。在通过中缀...

  • 简单数据结构(一) 树

    了解树在文件系统里的应用 计算算术表达式的值,如中缀表达式等 树是如何实现以O(logN)的平均时间进行查找操作,...

  • 算法之逆波兰计算器的分析与实现

    关于使用栈实现的普通计算器我之前已经实践过了,但是使用的是普通的中缀算术表达式的方式实现的,感兴趣可以看这篇文章:...

  • 实验五——表达式计算

    利用二叉树求解表达式的值,编写程序test5.cpp要求:输入一个算术表达式(以“#”开始,以“#”结束),建立对...

  • mongodb聚合管道运算符

    1.算术表达式运算符 算术表达式对数字执行数学运算。一些算术表达式也可以支持日期算术。 数组表达式运算符 布尔表达...

  • JavaScript数据结构与算法-栈练习

    栈的实现 练习 一. 栈可以用来判断一个算术表达式中的括号是否匹配。编写一个函数,该函数接受一个算术表达式作为参数...

  • Linux Day23:let

    shell中如何进行算术运算: let 算术运算表达式:let C=$A+$B $ [ 算术运算表达式]:C=$[...

网友评论

    本文标题:基于二叉树的算术表达式计算与实现

    本文链接:https://www.haomeiwen.com/subject/djycmqtx.html