Performance 检查括号顺序是否有效
我想做的是确定括号的顺序是否正确。例如,Performance 检查括号顺序是否有效,performance,logic,pascal,turbo-pascal,Performance,Logic,Pascal,Turbo Pascal,我想做的是确定括号的顺序是否正确。例如,([][]])是vallid,但][]])不是 我有一个工作版本,但它有可怕的效率,当它得到1000+括号,它只是疯狂缓慢。我希望有人能提出一些可能的改进或其他方法 这是我的密码: program Codex; const C_FNAME = 'zavorky.in'; var TmpChar : char; leftBrackets, rightBrackets : string; bracketPos
([][]])
是vallid,但][]])
不是
我有一个工作版本,但它有可怕的效率,当它得到1000+括号,它只是疯狂缓慢。我希望有人能提出一些可能的改进或其他方法
这是我的密码:
program Codex;
const
C_FNAME = 'zavorky.in';
var TmpChar : char;
leftBrackets, rightBrackets : string;
bracketPos : integer;
i,i2,i3 : integer;
Arr, empty : array [0..10000] of String[2];
tfIn : Text;
result : boolean;
begin
leftBrackets := ' ( [ /* ($ <! << ';
rightBrackets := ' ) ] */ $) !> >> ';
i := 0;
result := true;
Assign(tfIn, C_FNAME);
Reset(tfIn);
{ load data into array }
while not eof(tfIn) do
begin
while not eoln(tfIn) do
begin
read(tfIn, TmpChar);
if (TmpChar <> ' ') then begin
if (TmpChar <> '') then begin
Arr[i] := Arr[i] + TmpChar;
end
end
else
begin
i := i + 1;
end
end;
i2 := -1;
while (i2 < 10000) do begin
i2 := i2 + 1;
{if (i2 = 0) then
writeln('STARTED LOOP!');}
if (Arr[i2] <> '') then begin
bracketPos := Pos(' ' + Arr[i2] + ' ',rightBrackets);
if (bracketPos > 0) then begin
if (i2 > 0) then begin
if(bracketPos = Pos(' ' + Arr[i2-1] + ' ',leftBrackets)) then begin
{write(Arr[i2-1] + ' and ' + Arr[i2] + ' - MATCH ');}
Arr[i2-1] := '';
Arr[i2] := '';
{ reindex our array }
for i3 := i2 to 10000 - 2 do begin
Arr[i3 - 1] := Arr[i3+1];
end;
i2 := -1;
end;
end;
end;
end;
end;
{writeln('RESULT: ');}
For i2:=0 to 10 do begin
if (Arr[i2] <> '') then begin
{write(Arr[i2]);}
result := false;
end;
{else
write('M');}
end;
if (result = true) then begin
writeln('true');
end
else begin
writeln('false');
end;
result := true;
{ move to next row in file }
Arr := empty;
i := 0;
readln(tfIn);
end;
Close(tfIn);
readln;
end.
程序代码;
常数
C_FNAME='zavorky.in';
var-TmpChar:char;
左括号,右括号:字符串;
括号位置:整数;
i、 i2,i3:整数;
Arr,空:字符串[2]的数组[0..10000];
tfIn:文本;
结果:布尔型;
开始
左括号:='([/*($>>);
i:=0;
结果:=真;
分配(tfIn,C_FNAME);
复位(tfIn);
{将数据加载到数组中}
而不是eof(tfIn)做什么
开始
而不是eoln(tfIn)做什么
开始
读取(tfIn、TmpChar);
如果为(TmpChar“”),则开始
如果为(TmpChar“”),则开始
Arr[i]:=Arr[i]+TmpChar;
终止
终止
其他的
开始
i:=i+1;
终止
终止
i2:=-1;
当(i2<10000)开始时
i2:=i2+1;
{如果(i2=0)那么
writeln('STARTED LOOP!');}
如果(Arr[i2]”,则开始
括号位置:=Pos(“”+Arr[i2]+“”,右括号);
如果(括号位置>0),则开始
如果(i2>0),则开始
如果(括号Pos=Pos(''+Arr[i2-1]+'',左括号)),则开始
{write(Arr[i2-1]+'和'+Arr[i2]+'-MATCH');}
Arr[i2-1]:='';
Arr[i2]:='';
{重新索引我们的数组}
对于i3:=i2到10000-2开始
Arr[i3-1]:=Arr[i3+1];
终止
i2:=-1;
终止
终止
终止
终止
终止
{writeln('RESULT:');}
对于i2:=0到10,开始
如果(Arr[i2]”,则开始
{write(Arr[i2]);}
结果:=假;
终止
{其他
写('M');}
终止
如果(结果=真),则开始
书面形式(“真实”);
终止
否则开始
书面形式(“假”);
终止
结果:=真;
{移动到文件中的下一行}
Arr:=空;
i:=0;
readln(tfIn);
终止
关闭(tfIn);
readln;
终止
例如,文件zavorky.in中的输入数据如下所示:
<< $) >> << >> ($ $) [ ] <! ( ) !>
( ) /* << /* [ ] */ >> <! !> */
>($$)[]
( ) /* > */
我为每一行确定它是否有效。一行上的最大括号数为10000。您正在将所有数据保存到内存中(甚至几次),然后进行大量检查。我认为您的方法是正确的,但您可以遵循更简单的步骤
([/*($)从文件中读取字符。逐字节读取文件的速度非常慢。您需要优化读取字符串(缓冲区)的方法,或者先将文件加载到内存中
下面,我提出另一种处理获取字符串的方法
首先,我声明常量,它将说明您可能拥有的括号:
const
OBr: array [1 .. 5{6}] of string = ('(', '[', '/*', '<!', '<<'{, 'begin'});
CBr: array [11 .. 15{16}] of string = (')', ']', '*/', '!>', '>>'{, 'end'});
我认为下面的方法应该有效,并且将是orderO(n),其中n是字符串的长度
IsLeft(bra:TBracket)可以确定括号是左括号还是右括号,因此IsLeft('>')=FALSE
IsMatchingPair(bra,ket:TBracket)可以确定两个括号是否属于相同的“类型”,因此IsMatchingPair(“(”,“)”)=TRUE,但IsMatchingPair(“{”,“>>”)=FALSE
然后构建一个堆栈TBracketStack,其中包含三个函数procedure Push(bra:TBracket),以及函数Pop:TBracket,以及函数IsEmpty:boolean
现在,以下算法应该可以工作了(需要一些额外的代码来确保您不会意外地从字符串的末尾掉下来):
如果我没有弄错的话,在这种情况下,这将失败:[(],这是无效的,但您建议的方式会使其看起来有效。您完全正确。对此我很抱歉。要解决此问题,最简单的方法是实现堆栈。当存在左括号时,推送相应左括号数组的索引,如果存在右括号pop
,并检查变量都是一样的。如果它们不匹配或者堆栈是空的,那么你只会发现无效的括号序列,但问题是,由于一行括号可以长达10.000个括号,我无法在字符串中读取它,因为它不适合。而且将10.000个字符划分为字符串与检查不匹配。@Mykybo实际上,这不是问题。Str在Pascal中调用类似于一个字符数组。声明一个字符数组并从文件中填充。然后使用我在这里给你的想法。如果有必要,你也可以自己重新声明一个函数,如Pos
。但是,请不要读取你的文件字节。它非常慢。@Mykybo我已经添加了答案。请参阅如何创建b锁定文件的读取。
function ExpressionIsValid(const InputStr: string): boolean;
var
BracketsArray: array of byte;
i, Offset, CurrPos: word;
Stack: array of byte;
begin
result := false;
Setlength(BracketsArray, Length(InputStr) + 1);
for i := 0 to High(BracketsArray) do
BracketsArray[i] := 0; // initialize the pos array
for i := Low(OBr) to High(OBr) do
begin
Offset := 1;
Repeat
CurrPos := Pos(OBr[i], InputStr, Offset);
if CurrPos > 0 then
begin
BracketsArray[CurrPos] := i;
Offset := CurrPos + 1;
end;
Until CurrPos = 0;
end; // insert the positions of the opening brackets
for i := Low(CBr) to High(CBr) do
begin
Offset := 1;
Repeat
CurrPos := Pos(CBr[i], InputStr, Offset);
if CurrPos > 0 then
begin
BracketsArray[CurrPos] := i;
Offset := CurrPos + 1;
end;
Until CurrPos = 0;
end; // insert the positions of the closing brackets
Setlength(Stack, 0); // initialize the stack to push/pop the last bracket
for i := 0 to High(BracketsArray) do
case BracketsArray[i] of
Low(OBr) .. High(OBr):
begin
Setlength(Stack, Length(Stack) + 1);
Stack[High(Stack)] := BracketsArray[i];
end; // there is an opening bracket
Low(CBr) .. High(CBr):
begin
if Length(Stack) = 0 then
exit(false); // we can not begin an expression with Closing bracket
if Stack[High(Stack)] <> BracketsArray[i] - 10 then
exit(false) // here we do check if the previous bracket suits the
// closing bracket
else
Setlength(Stack, Length(Stack) - 1); // remove the last opening
// bracket from stack
end;
end;
if Length(Stack) = 0 then
result := true;
end;
procedure BlckRead;
var
f: file;
pc, pline: { PChar } PAnsiChar;
Ch: { Char } AnsiChar;
LngthLine, LngthPc: word;
begin
AssignFile(f, 'b:\br.txt'); //open the file
Reset(f, 1);
GetMem(pc, FileSize(f) + 1); //initialize memory blocks
inc(pc, FileSize(f)); //null terminate the string
pc^ := #0;
dec(pc, FileSize(f)); //return the pointer to the beginning of the block
GetMem(pline, FileSize(f)); //not optimal, but here is just an idea.
pline^ := #0;//set termination => length=0
BlockRead(f, pc^, FileSize(f)); // read the whole file
//you can optimize that if you wish,
//add exception catchers etc.
LngthLine := 0; // current pointers' offsets
LngthPc := 0;
repeat
repeat
Ch := pc^;
if (Ch <> #$D) and (Ch <> #$A) and (Ch <> #$0) then
begin // if the symbol is not string-terminating then we append it to pc
pline^ := Ch;
inc(pline);
inc(pc);
inc(LngthPc);
inc(LngthLine);
end
else
begin //otherwise we terminate pc with Chr($0);
pline^ := #0;
inc(LngthPc);
if LngthPc < FileSize(f) then
inc(pc);
end;
until (Ch = Chr($D)) or (Ch = Chr($A)) or (Ch = Chr($0)) or
(LngthPc = FileSize(f));
dec(pline, LngthLine);
if LngthLine > 0 then //or do other outputs
Showmessage(pline + #13#10 + Booltostr(ExpressionIsValid(pline), true));
pline^ := #0; //actually can be skipped but you know your file structure better
LngthLine := 0;
until LngthPc = FileSize(f);
FreeMem(pline); //free the blocks and close the file
dec(pc, FileSize(f) - 1);
FreeMem(pc);
CloseFile(f);
end;
BracketError := FALSE;
while StillBracketsToProcess(BracketString) and not BracketError do
begin
bra := GetNextBracket(BracketString);
if IsLeft(bra) then
Stack.Push(bra)
else
BracketError := Stack.IsEmpty or not IsMatchingPair(Stack.Pop,bra)
end;