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。

您正在将所有数据保存到内存中(甚至几次),然后进行大量检查。我认为您的方法是正确的,但您可以遵循更简单的步骤


  • 创建一个整数数组(默认值为0),长度为您拥有的括号数(例如,
    ([/*($)从文件中读取字符。逐字节读取文件的速度非常慢。您需要优化读取字符串(缓冲区)的方法,或者先将文件加载到内存中

    下面,我提出另一种处理获取字符串的方法

    首先,我声明常量,它将说明您可能拥有的括号:

    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;