performance - 检查括号顺序是否有效

标签 performance logic pascal turbo-pascal

我想做的是确定括号的顺序是否正确。例如([][[]]<<>>)有效,但是][]<<(>>)不是。

我有一个工作版本,但它的效率很糟糕,当它得到 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.

文件 zavorky.in 中的输入数据如下所示:

<< $) >> << >> ($ $) [ ] <! ( ) !>
( ) /* << /* [ ] */ >> <! !> */

我确定每一行是否有效。一行中括号的最大数量为 10000。

最佳答案

您从文件中读取了字符。以字节方式读取文件非常慢。您需要优化读取字符串(缓冲区)的方式,或者首先将文件加载到内存中。

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

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

const
  OBr: array [1 .. 5{6}]   of string = ('(', '[', '/*', '<!', '<<'{, 'begin'});
  CBr: array [11 .. 15{16}] of string = (')', ']', '*/', '!>', '>>'{, 'end'});

我决定这样做,因为现在您不再受限于括号表达式的长度和/或括号类型的数量。每个右括号和相应的左括号的指数差等于 10。

这是该函数的代码:

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;

也许,我们通过创建字节数组做了额外的工作,但似乎这种方法 i) 更容易理解,ii) 很灵活,因为我们可以更改括号表达式的长度,例如使用和检查 开始/结束括号等

已附加

一旦我发现主要问题在于组织文件的 block 读取,我就会在这里给出如何做到这一点的想法:

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;

关于performance - 检查括号顺序是否有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33849127/

相关文章:

performance - d3.js 我应该在退出/删除时分离事件监听器吗?

c++ - 为什么这个 `__xstat64` 的性能成本如此之高?

sql-server - SQL Server ODBC性能损失?

javascript - JavaScript 中最快的 MD5 实现

haskell - 有没有什么工具可以进行防守分析?

python - 我的 codejam 练习的解决方案或输出方法有什么不正确的地方?

logic - 构建有效的 CTL 或 LTL 表达式(在 NuSMV 中)

delphi - 帕斯卡对象 : how to do a typed forward declaration?

delphi - 是最大的点。两条线?

Delphi while循环导致程序停止响应