鍵盤輸入一個含有括弧的四則運算運算式,可能含有多餘的括弧,編程整理該運算式,
去掉所有多餘的括弧,原運算式中所有變數和運算子相對位置保持不變,並保持與原運算式
等價。
例:輸入運算式 應輸出運算式
a+(b+c) a+b+c
(a*b)+c/d a*b+c/d
a+b/(c-d) a+b/(c-d)
注意輸入a+b時不能輸出b+a。
運算式以字串輸入,長度不超過255。輸入不要判錯。
所有變數為單個小寫字母。只是要求去掉所有多餘括弧,不要求對錶達式化簡。
二、演算法分析
四則運算運算式含運算子'+','-','*','/','(',')',其優先順序由低至高為
'+','-' ─→ '*','/' ─→ '(',')'
一個括弧是否作為多餘的括弧剔除,關鍵是分析該括弧內優先順序最低的運算子與左鄰括
號或右鄰括弧的運算子之間的運算優先關係:
設待整理的運算式為(s1 op s2);
op—括弧內優先順序最低的運算子('+','-'或'*','/');
1、若左鄰括弧的運算子為'/',則無論op為何運算子,括弧必須保留,即…… /( s1
op s2)……。因為原式(s1 op s2)作為除數,一旦去除括弧後,僅s1作為除數,不
可能與原式等價;
2、若左鄰括弧的運算子為'*'或'-',而op為'+'或'-',則保留括弧,即……*-(s1+-
s2)。不能去除括弧的原因是:
若左鄰標符為'*',優先順序大於括弧內運算子,因此必須用括弧保證括弧內的'+'或
'-'優先進行;
若左鄰算符為'-',去除括弧後,由於括弧內的'+'、'-'要變號, 結果不與原式等
價;
3、若右鄰括弧的運算子為'*'或'/',而op為'+'或'-',原式中的op運算必須優先進行,
因此括弧不能去除,即(s1+-s2)*/……;
4、除上述情況外,括弧去除,結果與原式等價,即 …s1 op s2…。
我們從最裡層嵌套的括弧開始,依據上述規律逐步向外層進行括弧整理,直至最外層的
括弧保留或去除為止。這個整理過程可以用下述的一個遞迴過程reduce描述:
function reduce(運算式串s,var op):string;
{ 整理運算式s,並返回s串中優先順序最低的運算子op和整理結果 }
begin
if s是變數 then
begin
op=' '; reduce=變數s; exit
end;
if s是(s')形式 then
begin
reduce=reduce(s',op); exit
end;
{ s是's1 op s2' 形式 }
a=reduce(s1,c1);b=reduce(s2,c2);
if (op in ['*','-']) and (c2 in ['+','-']) then s2='(s2)';
if (op in ['*','/']) and (c1 in ['+','-']) then s1='(s1)';
if (op in ['/']) and (c2<>' ') then s2='(s2)';
reduce='s1 op s2'
end;
例如,剔除運算式'((a+b)*f)-(i/j)'中多餘的括弧。依據上述演算法進行整理的過程如下:
'((a+b)*f)-(i/j)','-'
┌────────┴─────────┐
'((a+b)*f)','*' '(i/j)','/'
│ │
'(a+b)*f','*' 'i/j','/'
┌───┴────┐ ┌─┴──┐
'(a+b)','+' 'f',' ' 'i',' ' 'j',' '
│
'a+b','+'
┌┴────┐
'a',' ' 'b',' '
(圖1.1-1)
最後,自底向上得整理結果:(a+b)*f-i/j。
三、程式分析
Program P11;
var
ins : string; { 算術運算式 }
p : char; { 最低級運算子 }
function suitable(s:string;i:byte):byte;
{ s[i]為')',函數suitable輸出與之相對應的'('在s中的位置 }
var
t:byte;
begin
t:=1;
repeat
dec(i);
if s[i]=')'
then inc(t)
else if s[i]='(' then dec(t)
until t=0;
suitable:=i
end; {suitable}
function find(s:string):byte;
{ 輸出運算式s中最低級算符的位置 }
var
i,k:byte;
begin
i:=length(s);k:=0;
while i>0 do
begin
if (s[i]='+') or (s[i]='-')
then begin
find:=i;exit
end; {then}
if (k=0) and ((s[i]='*') or (s[i]='/')) then k:=i;
if s[i]=')' then i:=suitable(s,i);
dec(i)
end; {while}
find:=k
end; {find}
function reduce(s:string;var p:char):string;
{ 整理運算式s並返回優先順序最低的運算子p }
var
a,b:string; { 運算式s的左項和右項整理的結果 }
c1,c2:char; { 運算式s的左項和右項的最低級運算子 }
i:byte; { 運算式s的最低級運算子的位置 }
begin
if length(s)=1 { 若運算式是變數則返回變數 }
then begin
reduce:=s;p:=' ';exit
end; {then}
if (s[length(s)]=')') and (suitable(s,length(s))=1)
{ 若運算式被一對括弧包住,則返回括弧內運算式的整理結果 }
then begin
reduce:=reduce(copy(s,2,length(s)-2),p);
exit
end; {then}
i:=find(s);p:=s[i]; { 找出最低級運算子及其位置 }
a:=reduce(copy(s,1,i-1),c1); { 分別整理左項和右項 }
b:=reduce(copy(s,i+1,length(s)-i),c2);
{ 根據p和c1,c2,決定是否加括弧 }
if (p in ['*','-']) and (c2 in ['+','-']) then b:='('+b+')';
if (p in ['*','-']) and (c1 in ['+','-']) then a:='('+a+')';
if (p='/') and (c2<>' ') then b:='('+b+')';
reduce:=a+p+b { 返回整理結果 }
end; {reduce}
begin
write('Str = ');
readln(ins); { 輸入算術運算式 }
writeln(reduce(ins,p)) { 剔除多餘括弧並列印整理結果 }
end. {main}
//////////////////////////////////////////////////////////////////////////////////////////////////////
例23 剔除多佘的括弧。
鍵盤輸入一個含有括弧的四則運算運算式,可能含有多佘的括弧,編程整理該運算式,去掉所有多佘的括弧,原運算式中所有變數和運算子相對位置保持不變,並保持與原運算式等價。
例如:
輸入運算式 |
應輸出運算式 |
A+b(+c) |
A+b+c |
(a*b)+c/(d*c) |
A*b+a/(d*c) |
A+b/(c-d) |
A+b/(c-d) |
注意輸入工A+b時不能輸出B+a。
運算式以字串輸入,長度不超過255,輸入不需要判錯。
所有變數為單個小寫字母。只是要求去掉所有多佘括弧,不要求對錶達式簡化。
演算法分析
對於四則運算運算式,我們分析一下哪些括弧可以去掉。
設待整理的運算式為(s1 op s2);op為括弧內優先順序最低的運算子(“+”,“-”或“×”,“/”);
①左鄰括弧的運算子為“/”,則括弧必須保留,既…/(s1 op s2)…形式。
②左鄰括弧的預算符為“*”或“-”。而op為“+”或“-”,則保留括弧,既…×(s1+s2)…”、“…-(s1+s2)…”、“…×(s1-s2)…”、“…-(s1-s2)…”。
③右鄰括弧的運算子為“×”或“/”,而op 為“+”或“-”,原式中的op運算必須優先進行,因此括弧不去除,即“(s1+s2)*…”。
除上述情況外,可以把括弧去除,即“…s1 op s2…”等價於“…(s1 op s2)…”。
人們從最裡層嵌套的括弧開始,依據上述規律逐步向外進行括弧整理,直至最外層括弧保留或去除為止。這個整理過程可以用一個遞迴的過程來實現。
【參考程式】
program aa;
var ch:char;
st:string;
function loc(s:string;i:byte):byte;
var q:byte;
begin
q:=1;
repeat
inc(i);
if s[i]='(' then inc(q)
else if s[i]=')' then dec(q);
until q=0;
loc:=i;
end;
function find(s:string):byte;
var i,k:byte;
begin
i:=1;
k:=0;
while i<=length(s) do
begin
if (s[i]='+')or(s[i]='-') then
begin
find:=i; exit;
end;
if(k=0)and((s[i]='*')or(s[i]='/')) then k:=i;
if s[i]='(' then i:=loc(s,i);
inc(i);
end;
find:=k;
end;
function del(s:string;var p:char):string;
var i,j:byte;
ch1,ch2:char;
left,right:string;
begin
i:=0; j:=0;
i:=pos('(',s); j:=pos(')',s);
if (i=0)and(j=0) then
begin del:=s; exit; end;
if (s[1]='(')and(loc(s,1)=length(s)) then
begin
del:=del(copy(s,2,length(s)-2),p);
exit;
end;
i:=find(s);
p:=s[i];
left:=del(copy(s,1,i-1),ch1);
right:=del(copy(s,i+1,length(s)-i),ch2);
if (p in ['*','/'])and(ch1 in ['+','-']) then
left:='('+left+')';
if (p in ['*','/'])and(ch2 in ['+','-'])or(p='/')and(ch2 <>' ') then
right:='('+right+')';
del:=left+p+right;
end;
begin
readln(st);
writeln(del(st,ch));
end.