算数表达式--二叉树

 算数表达式--二叉树

最早提出遍历问题的是对存储在计算机中的表达式求值。例如:(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为单位来存储数据,因此在存储空间方面,可以大大节省。

 

 

 

 

 

 

 

 

posted @ 2012-10-12 09:16  zero516cn  阅读(29661)  评论(0编辑  收藏  举报