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