算數表達式--二叉樹


 算數表達式--二叉樹

最早提出遍歷問題的是對存儲在計算機中的表達式求值。例如:(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為單位來存儲數據,因此在存儲空間方面,可以大大節省。

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM