ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

javaScript:表达式转二叉树

2022-07-21 16:03:31  阅读:202  来源: 互联网

标签:string javaScript stack item 二叉树 str children 表达式


以前学习数据结构的时候,学过将数学表达式(中缀表达式)转换为二叉树,最近遇到需要将带有逻辑与和逻辑或的表达式转换为树结构的需求,参考了一些博客,最后做出来效果如下:

表达式:

(1 & 2) &3 | 4

树结构:

image

对树结构进行中序遍历就能还原为原表达式。

下面是处理过程:

1、中缀表达式转后缀表达式

主要逻辑:

准备一个栈用来暂存操作数和运算符,准备一个队列用来存储后缀表达式。

从左向右开始读取算术表达式的元素X,分以下情况进行不同的处理:

(1)如果X是操作数,直接入队(即直接放入表达式中)

(2)如果X是运算符:再分以下情况:

​ 1)如果栈为空,直接入栈。

​ 2)如果X==”(“,直接入栈。

​ 3)如果X==”)“,则将栈里的元素逐个出栈并入队,直到遇到”)”。注意:”)“和”(“都出栈但不入队。

​ 4)如果是其他运算符,若X优先级小于栈顶元素,则出栈并入队直到X大于栈顶元素。否则直接入栈。

原文链接:https://blog.csdn.net/DH2442897094/article/details/82760498

本文中的表达式只包含数字以及逻辑与、逻辑或运算符,已知逻辑与的优先级大于逻辑或。

原表达式:(1 & 2) &3 | 4

代码如下:

  const getString = (str) => {
    //去掉表达式中可能出现的空格
    str = str.replace(/\s*/g, "");
    //当表达式只有一个操作数时不做处理
    if (str.length < 2) {
      return;
    }
    let opStack = []; //暂存栈
    let string = ""; //后缀表达式队列
    //对str中的字符逐个读取
    str.split("").forEach((item) => {
      //isNaN方法判断字符是否是非数字,非数字返回true,数字返回false
      if (!isNaN(item)) {
        //若是操作数,直接入队
        string += item;
      } else {
        //遇到"("直接入栈
        if (item === "(") {
          opStack.push(item);
        } else if (item === ")") {
          //遇到")"出栈并入队直到遇到"("
          for (let i = opStack.length - 1; i >= 0; i--) {
            const key = opStack.pop();
            if (key === "(") {
              break;
            }
            //入队在判断"("之前,因为"("不入队
            string += key;
          }
        } else {
          //其他操作符,判断优先级
          let result = checkOp(item, opStack, string);
          opStack = result.stack;
          string = result.string;
        }
      }
    });
    //原表达式读取后若栈中还有元素,则逐个出栈并入队
    opStack.forEach(() => {
      string += opStack.pop();
    });
  };
  //判断优先级
  const checkOp = (op, stack, string) => {
    //若该操作符优先级小于栈顶操作符(只能是|与&相比较的情况)
    if (op === "|" && stack[stack.length - 1] === "&") {
      //出栈并入队
      string += stack.pop();
      //再与栈顶元素判断优先级
      checkOp(op, stack, string);
    } else {
      stack.push(op);
    }
    //返回处理后的栈和表达式
    return { stack: stack, string: string };
  };

处理后得到的string就是目的后缀表达式:12&3&4|

2、对后缀表达式构造树结构

主要逻辑:

准备一个栈用来存放子节点。

对后缀表达式从左往右读取元素i,分以下情况对i做处理:

1、i是数字,直接入栈。

2、i是操作符,取栈顶两个元素作为i的子节点,将i入栈。

后缀表达式读取结束后,栈内还剩一个元素,该元素就是我们要的数组。

代码如下:

  const buildTree = (str) => {
    let children = [];
    //用到前端树控件,需要唯一id,可忽略
    let index = 0;
    str.split("").forEach((item) => {
      //数字直接入栈,用到前端控件需要显示label,不需要的直接push(item)即可
      if (!isNaN(item)) {
        children.push({
          id: index++,
          value: item,
          label: item,
        });
      } else {
        //遇到操作数,取栈顶两个元素作为子节点
        const parent = {
          id: index++,
          value: item,
          label: item,
          children: children.splice(children.length - 2).reverse(),
        };
        //处理后入栈
        children.push(parent);
      }
    });
    console.log(children);
    //控件的绑定值
    setOptions(children);
  };

处理后的children就是我们要的数组,是一个二叉树结构。

这里我用到了MUI的TreeItem控件,前端展示效果为:

image

标签:string,javaScript,stack,item,二叉树,str,children,表达式
来源: https://www.cnblogs.com/xzdx/p/16502219.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有