zoukankan      html  css  js  c++  java
  • 算数表达式二叉树

     算数表达式--二叉树

    最早提出遍历问题的是对存储在计算机中的表达式求值。例如:(a+b×(c-d))-e/f。表达式用树形来表示,如图8-11-1所示。运算符在树中放在非终端结点的位置上,操作数放在叶子结点处。                                                                                                                                                        

                          

     

    当我们对此二叉树进行先序、中序和后序遍历后,便可得到表达式的前缀、中缀和后缀书写形式:

    前缀:-+a*b-cd/ef

    中缀:a+b*c-d-e/f

    后缀:abcd-*+ef/-

    其中,中缀形式是算术表达式的通常形式,只是没有括号。在计算机内,使用后缀表达式易于求值。

    例1 输入一个算术表达式,判断该表达式是否合法,若不合法,给出错误信息;若合法,则输出合法表达式的表达式树。

    【算法分析】表达式不合法有三种情况:①左右括号不匹配;②变量名不合法;③运算符两旁无参与运算的变量或数。

    分析表达式树可以看到:表达式的根结点及其子树的根结点为运算符,其在树中的顺序是按运算的先后顺序从后到前,表达树的叶子为参与运算的变量或数。

     
       

    例如,表达式:a+(b-c)/d

    运算顺序:    ③ ① 

     

     

                 

                                      

    表达式树如图8-11-2

    处理时,首先找到运算级别最低的运算符“+”作为根结点,继而确定该根结点的左、右子树结点在表达式串中的范围为a和(b-c)/d,再在对应的范围内寻找运算级别最低的运算符作为子树的根结点,直到范围内无运算符,则剩余的变量或数为表达式树的叶子。

    【算法步骤】

    设数组ex存放表达式串的各字符,lt、rt作为结点的左右指针,变量left、right用于存放每次取字符范围的左、右界。

    设置左界初值为1;右界初值为串长度。

    判断左右括号是否匹配,不匹配则认为输入有错误。

    在表达式的左右界范围内寻找运算级别最低的运算符,同时判断运算符两旁有否参与运算的变量或数。若无,则输入表达式不合法;若有,作为当前子树的根结点,设置左子树指针及其左右界值,设置右子树指针及其左右界值。

    若表达式在左右界范围内无运算符,则为叶子结点,判断变量名或数是否合法。

    转④,直到表达式字符取完为止。

    源程序中的h、d、w用于存放文本画图时结点的坐标位置。

    program exptree;

    uses crt;

    type

      point=^tree;

      tree=record

             data:string;

             lt:point;

             rt:point;

           end;

    var

      n,len,k:integer;

      ex:string;

      letters:set of char;

      root:point;

    procedure error(er:byte);    {出错信息提示}

    begin

      write('Enter error:');

      case er of

        1:writeln('No letter');

        2,3:writeln('No expressint');

        4:writeln('No+,*,-or/');

        5:writeln('No(or)');

      end;

      write('Press<enter>...');readln;halt(1);

    end;

    procedure create(left,right:integer;var p:point);

    var q:point;

        k,n:integer;

    begin     {找运算级别最低的运算符}

      if ex[left]='(' then

        begin

          n:=left+1;k:=0;

          while (n<right) and (k>=0) do

            begin

              if ex[n]='(' then inc(k);

              if ex[n]=')' then dec(k);

              inc(n);

            end;

          if n=right then

            begin

              dec(right);inc(left);

            end;

        end;

      if right<left then error(1);

      n:=right;k:=0;

      repeat

        if ex[n]=')' then inc(k);

        if ex[n]='(' then dec(k);

        dec(n);

      until (((ex[n]='+') or (ex[n]='-')) and (k=0)) or (n<left);

      if n=left then error(3);

      if n>left then

        begin

          with p^ do

            begin

              data:=ex[n];

              new(q);lt:=q;

              new(q);rt:=q;

            end;

          create(left,n-1,p^.lt);

          create(n+1,right,p^.rt);

        end

      else     {not found '+''-'}

        begin

          n:=right;

          repeat

            if ex[n]=')' then inc(k);

            if ex[n]='(' then dec(k);

            dec(n);

          until (((ex[n]='*') or (ex[n]='/')) and (k=0)) or (n<left);

          if n=left then error(3);

          if n>left then

            begin

              with p^ do

                begin

                  data:=ex[n];

                  new(q);rt:=q;

                  new(q);lt:=q;

                end;

              create(left,n-1,p^.lt);

              create(n+1,right,p^.rt);

            end

          else    {only string}

            begin       {求叶子结点的字串}

              for k:=left to right do

                if not(ex[k] in letters) then error(1);

              p^.data:='';

              for k:=left to right do

                p^.data:=p^.data+ex[k];

              p^.lt:=nil;

              p^.rt:=nil;

            end;

        end;

    end;

    procedure pr_tree(w,dep:integer;p:point);    {画出生成的表达式树}

    var h,i,lt,rt:integer;

    begin

      h:=40;for i:=1 to dep do h:=h div 2;

      gotoxy(w-1,dep*3);write('(',p^.data,')');

      if p^.lt=nil then lt:=w

      else begin

             lt:=w-h;pr_tree(lt,dep+1,p^.lt)

           end;

      if p^.rt=nil then rt:=w

      else begin

             rt:=w+h;pr_tree(rt,dep+1,p^.rt);

           end;

      if lt<>rt then

        begin

          gotoxy(w,dep*3+1);write('|');

          gotoxy(lt,3*dep+2);write('|');

          for i:=lt to rt-2 do write('-');write('|');

        end;

    end;

    begin

      clrscr;

      letters:=['A'..'Z','a'..'z','0'..'9'];

      repeat

        write('Enter expression:');readln(ex);

        len:=length(ex)

      until len>0;

      n:=1;

      k:=0;

      while (n<=len) and (k>=0) do   {判断左括号是否匹配}

        begin

          if ex[n]='(' then inc(k);

          if ex[n]=')' then dec(k);

          inc(n);

        end;

      if k<>0 then error(5);

      new(root);create(1,len,root);

      pr_tree(40,1,root);readln

    end.

    注:Pascal语言的程序中,通过在程序的开头使用uses命令,说明所需要使用的单元,其语法为:

    uses  <单元名表>;    {单元名表是指用逗号隔开的1个或多个单元名称}

    crt                   {具有屏幕模式控制、扩展键盘码、颜色、窗口、声音等功能}

    clrscr                 {清楚当前窗口或屏幕,光标返回到左上角}

      什么是Bit-map

      所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省。

  • 相关阅读:
    Min_25 筛 学习笔记
    UOJ#172. 【WC2016】论战捆竹竿 字符串 KMP 动态规划 单调队列 背包
    Codeforces 715B. Complete The Graph 最短路,Dijkstra,构造
    UOJ#407. 【IOI2018】狼人 Kruskal,kruskal重构树,主席树
    UOJ#218. 【UNR #1】火车管理 线段树 主席树
    Codeforces 1045E. Ancient civilizations 构造 计算几何 凸包
    Codeforces 947F. Public Service 构造
    Pop Star 1.2.5
    TopCoder SRM704 Div1 800 构造
    Codeforces 1109E. Sasha and a Very Easy Test 线段树
  • 原文地址:https://www.cnblogs.com/gw811/p/2720777.html
Copyright © 2011-2022 走看看