栈:装水的杯子(二)括号匹配

  rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">

(二)括号匹配

单元测试成绩下来了,子渊考了98分,其中2分是因为在进行加减乘除的混合运算时,子渊少写了半个括号,老师给扣的分,子渊对此不以为然——不就2分吗?

回到家,爸爸检查试卷,看到试卷上大大的“98”分,爸爸居然没有显示出半点高兴的样子——要知道上次测试子渊才考了个85分,爸爸就已经开心得合不拢嘴了。

“爸爸,我表现还不错吧!”子渊试探着问道。

“嗯,还可以——这次题目挺简单的吧?”

“还好,班上就890分以上的。我考了第一名!”

“这样啊,那表现还不错!。。。。。。只是,你这2分怎么回事?”

“哦,那个啊,是我少写了半个括号,老师看着不顺眼给扣的。”

“不顺眼?只扣了你2分?我看应该6分全扣!”

“啊!没这么严重吧?”子渊有些惊讶。

“不严重?我告诉你,在科学的领域,半点马虎都是来不得的!一颗螺丝钉导致整座大桥倒塌,一块硬化的橡皮环使得“挑战者号”航天飞机坠毁,一个小小的内存溢出使得导弹偏航——所有的这些故事,你又不是没有听说过!”

“这。。。。。。这。。。。。。可是。。。。。。”子渊被爸爸迫得没话说,可心里还是有些不服气。

“可是什么!你想说你的失误没造成什么损失吗?确确实实,这次粗心并未造成严重后果,也没有对你第一名的地位造成威胁。但我想说的是,如果你想成为一名优秀的程序员,就必须养成细心,审慎的习惯,否则今后会因为你一时的粗心,制造出难以察觉的BUG,而浪费你无穷无尽的时间和精力。”爸爸开始转入本行,以计算机程序设计为例子:“要想让计算机听从你的指令,首先要了解计算机,向计算机学习,像计算机一样思考。连少写了括号都不知道——你见过计算机犯类似的低级错误吗?”

“计算机当然不会犯这样的错误啦,我每次少输入了括号,在编译的时候,编译器总是会提示语法错误的。”子渊小心翼翼地回答。

“是啊,编译器能够判断代码中的括号是否正确,我们称之为“括号匹配”,现在我就要你解决“括号匹配问题”,以弥补这次考试的失误——做不出不准吃饭!”爸爸转身走了,留下子渊一个人面对电脑屏幕上的“括号匹配问题”:

在用PASCAL语言所写的程序代码中,经常会出现各种括号,例如‘(’,‘)’,‘[’,‘]’,‘{’,‘}’,‘<’,‘>’等,现在要你帮助编译器做一件重要的事情,判断包含上述括号的代码中是否括号匹配,即左右括号成对出现,并且顺序正确,叫做“括号匹配”。

如输入:{ Separate [n] }PROGRAM Separate(INPUT, OUTPUT);

则显示匹配。

如输入:{ Separate [n] }}PROGRAM Separate(INPUT, OUTPUT);

或输入:[PROGRAM Separate(<INPUT, OUTPUT};

则显示不匹配。

设计一个算法来实现该功能,子函数接口为:

FUNCTION BracketMatch(code : string) : BOOLEAN;

其中code是存储了PASCAL代码的字符串,括号匹配返回true,否则返回false

 

子渊拿到题目以后犯了愁:“要我像计算机一样思考,我有它那么笨吗?真是的!可是饭不能不吃,还是好好想想这道题目怎么做吧。”

“左右括号匹配?可以是一个左括号对应一个右括号,也可以是连续多个左括号对应多个右括号。要匹配的话,必须是最后出现的左括号与最早出现的右括号匹配。最后对应最早。。。。。。这不就是栈的特性吗?对了!”

“我依次从字符串里读出字符,遇到左括号存进栈里,遇到右括号就把栈顶元素弹出来,看看是否配对,如果不配对就说明匹配错误啦。呵呵,我真聪明!”

不一会,子渊就写出了代码:

{代码4}

{判断字符串中的括号是否匹配}

PROGRAM TheBracketMatch(INPUT, OUTPUT);

CONST

    MAXCAPACITY = 255; {栈的最大容量}

    BOTTOM = 0;        {栈底标志}

 

TYPE

    ElemType = char;  {栈内元素数据类型}

    Stack    = array [1..MAXCAPACITY] of ElemType; {用数组表示的栈}

 

VAR

    code : string;

    s    : Stack;       {定义s为栈}

    top  : integer;     {栈顶标志}

 

。。。。。。{此处为栈的基本操作函数,不再重复列出}

 

FUNCTION BracketMatch(code : string) : BOOLEAN;

var

    i, len : integer;

    flag   : boolean;

begin

    len := length(code);

    for i:=1 to len do

    begin

        flag := false;

        case code[i] of

          '(', '[', '{', '<' : Push(s, top, code[i]); {左括号入栈}

          ')' : if GetTop(s, top) = '(' then    {右括号出栈或报错}

                    Pop(s, top)

                else

                    flag := true;

          ']' : if GetTop(s, top) = '[' then

                    Pop(s, top)

                else

                    flag := true;

          '}' : if GetTop(s, top) = '{' then

                    Pop(s, top)

                else

                    flag := true;

          '>' : if GetTop(s, top) = '<' then

                    Pop(s, top)

                else

                    flag := true;

        end; {case}

 

        if flag then  {左右括号不匹配}

        begin

            BracketMatch := false;

            exit;

        end; {if}

    end; {for}

 

    BracketMatch := true;

end; {BracketMatch}

注:此处调用有关栈的基本操作调用了代码3中的子函数,不再重复列出,主函数如下:

BEGIN {MAIN}

    top := 0; {栈顶初始化}

 

    writeln('Input code:');

    readln(code);

 

    if BracketMatch(code) then

        writeln('match!')

    else

        writeln('mismatch!');

END.

大功告成的子渊得意洋洋地把代码交给爸爸检查,满以为会得到铺天盖地的表扬,谁知爸爸只是轻轻瞄了一喵,就不客气地给出让子渊心凉了半截的评语:“考虑不周,代码缺乏健壮性;思路狭窄,编码缺乏灵活性!”

见子渊沮丧的样子,爸爸有些不忍心,态度缓和下来,补充道:“能用case语句代替if else说明基本功不错,但是在本例中有更好的方法来代替case语句。提示:将所有的括号存储到数组中。其他的自己再好好想想吧。

看见爸爸充满期盼和鼓励的目光,子渊的信心油然而生,大脑又投入到紧张的思考中:

爸爸说我的代码缺乏健壮性,这说明我有些问题没有考虑到。那是什么问题呢?对了,我只考虑到右括号出错的情况,没有考虑到左括号出错,也就是多写了左括号的情况(对于多写或先写右括号的情况,上述代码会出现栈空错误,从而返回假)。如果左括号有多,那遍历字符串结束时,栈仍不为空,这样括号就不匹配了。

case语句用来单个判断各种括号的匹配情况,代码确实有些繁琐。爸爸说可以将所有的括号存储到数组中,那是不是说在判断各类括号匹配时,可以用一个简单的计算来代替繁琐的条件判断呢?对了,如果各个对应的左右括号在数组中的下标刚好互为相反数,那我不就可以用一个简单的加法运算代替条件表达式了吗?太好了!果然精妙!

改良后的代码如下:

{代码5}

{判断字符串中的括号是否匹配}

PROGRAM TheBracketMatch(INPUT, OUTPUT);

CONST

    MAXCAPACITY = 255; {栈的最大容量}

    BOTTOM = 0;        {栈底标志}

    { 存储了各类括号的字符串数组,注意BRACKET [0]='('在程序中不起作用}

    BRACKET : array [-4..4] of char = ('(', '[', '{', '<', '(', '>', '}', ']', ')');

 

。。。。。。{此处为栈的基本操作函数,不再重复列出}

 

FUNCTION BracketMatch(code : string) : BOOLEAN;

var

    i, j, len : integer;

begin

    len := length(code);

    for i:=1 to len do

    begin

        j := -4;

        while (j < 5) and (code[i] <> BRACKET[j]) do {判断code[i]是否为括号}

            inc(j);

   

        if j < 0 then

            Push(s, top, j) {左括号下标入栈}

        else if (j > 0) and (j < 5) then {判断括号是否匹配}

        begin

            if (not StackEmpty(s, top)) and

               (GetTop(s, top) + j = 0) then {左右括号匹配,右括号出栈}

                Pop(s, top)

            else             {左右括号不匹配}

            begin

                BracketMatch := false;

                exit;

            end;   {else}

        end; {else if}

    end; {for}

 

    if StackEmpty(s, top) then {栈空表示没有多余的左括号}

        BracketMatch := true

    else

        BracketMatch := false;

end; {BracketMatch}

 

“嗯,这次表现不错!快来吃饭吧,有你最爱吃的酸菜鱼。”

听到爸爸的表扬,子渊心里比吃了蜜还甜。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值