检查括号订单是否有效
Check if bracket order is valid
我想做的是确定括号的顺序是否正确。例如 ([][[]]<<>>)
是有效的,但 ][]<<(>>)
不是。
我有一个工作版本,但它的效率很糟糕,当它有 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。
您正在将所有数据保存到内存中(甚至几次),然后进行大量检查。我认为您走在正确的轨道上,但您可以遵循更简单的步骤。
- 创建一个整数数组(默认值 = 0),长度为您拥有的括号数(例如 '
( [ /* ($ <! << ' ==> 6
)
- 现在要确保您符合要求。逐行阅读文件并仅考虑前 10000 行。This 可能会有所帮助。
- 每次从第一个数组(例如 leftBrackets)中找到一个元素时,将 +1 添加到步骤 1 的数组对应索引的值。示例如下:
'[' ==> checkArray[1] += 1
- 对 rightBrackets 做同样的事情,但这次检查值是否大于 0。如果是,则以相同的方式减去 1(例如
']' ==> checkArray[1] -= 1
),否则你只是发现无效的括号
希望对您有所帮助,祝您好运。
您从文件中读取了字符。逐字节模式读取文件非常慢。您需要优化读取字符串(缓冲区)的方式,或者先将文件加载到内存中。
下面我提出另一种方法来处理获取的字符串。
首先,我声明常量,它将说明您可能拥有的括号:
const
OBr: array [1 .. 5{6}] of string = ('(', '[', '/*', '<!', '<<'{, 'begin'});
CBr: array [11 .. 15{16}] of string = (')', ']', '*/', '!>', '>>'{, 'end'});
我决定这样做,因为现在您不限于括号表达式的长度 and/or 括号类型的数量。每个右括号和相应的左括号的索引差等于 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) 灵活,因为我们可以更改括号表达式的长度,例如使用和检查begin
/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 <> #[=12=]) 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([=12=]);
pline^ := #0;
inc(LngthPc);
if LngthPc < FileSize(f) then
inc(pc);
end;
until (Ch = Chr($D)) or (Ch = Chr($A)) or (Ch = Chr([=12=])) 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;
我认为以下应该有效,并且顺序为 O(n),其中 n 是字符串的长度。首先构建两个函数。
IsLeft(bra : TBracket)可以判断一个括号是左括号还是右括号,所以IsLeft('<') = TRUE, IsLeft('>> ') = 假。
IsMatchingPair(bra, ket : TBracket)可以判断两个括号是否相同'type',所以IsMatchingPair('(',')') =正确,但 IsMatchingPair('{','>>') = FALSE.
然后用三个函数 procedure Push(bra : TBracket) 和 function Pop 构建一个堆栈 TBracketStack : TBracket 和 function IsEmpty : boolean.
现在下面的算法应该可以工作了(需要一些额外的代码来确保你不会意外地从字符串的末尾掉下来):
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;
我想做的是确定括号的顺序是否正确。例如 ([][[]]<<>>)
是有效的,但 ][]<<(>>)
不是。
我有一个工作版本,但它的效率很糟糕,当它有 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。
您正在将所有数据保存到内存中(甚至几次),然后进行大量检查。我认为您走在正确的轨道上,但您可以遵循更简单的步骤。
- 创建一个整数数组(默认值 = 0),长度为您拥有的括号数(例如 '
( [ /* ($ <! << ' ==> 6
) - 现在要确保您符合要求。逐行阅读文件并仅考虑前 10000 行。This 可能会有所帮助。
- 每次从第一个数组(例如 leftBrackets)中找到一个元素时,将 +1 添加到步骤 1 的数组对应索引的值。示例如下:
'[' ==> checkArray[1] += 1
- 对 rightBrackets 做同样的事情,但这次检查值是否大于 0。如果是,则以相同的方式减去 1(例如
']' ==> checkArray[1] -= 1
),否则你只是发现无效的括号
希望对您有所帮助,祝您好运。
您从文件中读取了字符。逐字节模式读取文件非常慢。您需要优化读取字符串(缓冲区)的方式,或者先将文件加载到内存中。
下面我提出另一种方法来处理获取的字符串。
首先,我声明常量,它将说明您可能拥有的括号:
const
OBr: array [1 .. 5{6}] of string = ('(', '[', '/*', '<!', '<<'{, 'begin'});
CBr: array [11 .. 15{16}] of string = (')', ']', '*/', '!>', '>>'{, 'end'});
我决定这样做,因为现在您不限于括号表达式的长度 and/or 括号类型的数量。每个右括号和相应的左括号的索引差等于 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) 灵活,因为我们可以更改括号表达式的长度,例如使用和检查begin
/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 <> #[=12=]) 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([=12=]);
pline^ := #0;
inc(LngthPc);
if LngthPc < FileSize(f) then
inc(pc);
end;
until (Ch = Chr($D)) or (Ch = Chr($A)) or (Ch = Chr([=12=])) 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;
我认为以下应该有效,并且顺序为 O(n),其中 n 是字符串的长度。首先构建两个函数。
IsLeft(bra : TBracket)可以判断一个括号是左括号还是右括号,所以IsLeft('<') = TRUE, IsLeft('>> ') = 假。
IsMatchingPair(bra, ket : TBracket)可以判断两个括号是否相同'type',所以IsMatchingPair('(',')') =正确,但 IsMatchingPair('{','>>') = FALSE.
然后用三个函数 procedure Push(bra : TBracket) 和 function Pop 构建一个堆栈 TBracketStack : TBracket 和 function IsEmpty : boolean.
现在下面的算法应该可以工作了(需要一些额外的代码来确保你不会意外地从字符串的末尾掉下来):
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;