【问题标题】:If else vs switch with stack logicIf else vs 使用堆栈逻辑切换
【发布时间】:2015-09-10 19:43:00
【问题描述】:

我正在通过编写一个验证括号语法的程序来学习堆栈。如果我输入(Baller) 它应该会给我一个积极的结果。如果我有(Baller(),它应该会给我一个否定的结果。本质上,应用程序检查用户是否正确使用了 ()、{} 和 []。

  • 如果遇到 ( 、 { 或 [ 字符,我会将其添加到 堆栈上的字符。
  • 如果我遇到 ) } ] 符号,我将从堆栈中删除一个字符。
  • 如果文本包含奇数个圆括号或方括号 连续(例如, ( 和 ] 不连续),错误
    消息被打印出来。

所以我在 if else 语句中完成了这一半,但我认为在 switch 语句中应该更容易,并且也是一个很好的学习体验。

所以我在switch语句中所做的是这样的:

public class Input {
    public static void main(String[] args) {
        Stack stack = new Stack();
        String str;
        str = JOptionPane.showInputDialog("Text to parse: ");
        char arr[] = str.toCharArray();
        System.out.print(str);
        System.out.println();
        System.out.println();

        for(char c : arr) {
            switch(c) {

            case '{':
                stack.Push(c);
                System.out.print(stack.firstNode.getData());
                break;
            case '(':
                stack.Push(c);
                System.out.print(stack.firstNode.getData());
                break;
            case '[':
                stack.Push(c);
                System.out.print(stack.firstNode.getData());
                break;

            case '}':
                c = (Character) stack.Peek(); //<-- Edited for @Jimmy
                if( c != '{') {
                    System.out.println("  Syntax ERROR");
                }
            case ']':
                if( c != '[') {
                    System.out.println("  Syntax ERROR");
                }   
            case ')':
                if( c != '(') {
                    System.out.println("  Syntax ERROR");
                }
            }
        }
    }
}

但是现在我遇到了一个问题,如果我只添加一个右侧括号,它就会被删除,因为我有一个弹出窗口。我试图在 if-else 语句中做到这一点,该语句将以这样的 if 语句结束:

if(first == '(' && (current == '}' || current == ']')) {
if first == '{' && (current == ']' || current == ')')) {
//and so on

我怎样才能把它变成一个开关盒?这是一个坏主意吗?

我所知道的是,我的左侧支架并没有真正的问题,但右侧支架确实存在问题。

编辑:代码现在看起来如何

import javax.swing.JOptionPane;



public class Input {
    public static void main(String[] args) {
        Stack stack = new Stack();
        String str;
        str = JOptionPane.showInputDialog("Text to parse: ");
        char arr[] = str.toCharArray();
        System.out.print(str);
        System.out.println();
        System.out.println();


        for(char c : arr) {

            switch(c) {

            case '{':
                stack.Push(c);
                break;
            case '(':
                stack.Push(c);
                break;
            case '[':
                stack.Push(c);
                break;

            case '}':
                if(stack.isEmpty() || (Character) stack.Pop() != '{') {
                    System.out.println("  Syntax ERROR");
                }
                break;
            case ']':
                if(stack.isEmpty() || (Character) stack.Pop() != '[') {
                    System.out.println("  Syntax ERROR");
                }
                break;
            case ')':
                if(stack.isEmpty() || (Character) stack.Pop() != '(') {
                    System.out.println("  Syntax ERROR");
                }
                break;
            }
        } if(!stack.isEmpty()) {
            System.out.println("  Syntax ERROR");
        }
    }
}

【问题讨论】:

  • 您可以使用 peek(),它只会让您看到堆栈的最后内容。如果没有错误,则可以调用 pop() 否则不要调用 pop 并且不会被删除。
  • @Jimmy 你能举例说明它在代码中的工作方式吗?否则你打算在哪里改变?
  • 在您的第一个删除案例中类似这样的事情。即案例'}':c = (Character) stack.Peek(); if( c != '{') { System.out.println(" Syntax ERROR"); }else stack.Pop();
  • @Jimmy Ok 所以我将其更改为 Peek() 并得到相同的结果。我在编辑中进行了更改,以向您显示编辑的位置。
  • 我认为最干净的解决方案是避免失败并在每个 case 中单独弹出。但请注意空堆栈的情况。此外,您应该使用Stack&lt;Character&gt; 来摆脱不安全的演员表。

标签: java if-statement stack switch-statement


【解决方案1】:

好问题!很高兴您已经有了一个可行的解决方案并正在努力改进它。

您仍然可以使用您的 switch 语句,但您首先需要在尝试弹出下一个值之前验证您的堆栈不为空。在我的实现中,我首先通过检查stack.isEmpty() 并使用短路或条件|| 进行检查。短路意味着如果 OR 条件的左侧为真,则甚至不会计算右侧。

这是更新后的 for 循环。我不确定您使用的是哪个 Stack 类,所以我使用的是 java.util.Stack

for(char c : arr) {

    switch(c) {

    case '{':
        stack.push(c);
        System.out.print(stack.peek());
        break;
    case '(':
        stack.push(c);
        System.out.print(stack.peek());
        break;
    case '[':
        stack.push(c);
        System.out.print(stack.peek());
        break;

    case '}':
        if(stack.isEmpty() || (Character) stack.pop() != '{') {
            System.out.println("  Syntax ERROR");
        }
        break;
    case ']':
        if(stack.isEmpty() || (Character) stack.pop() != '[') {
            System.out.println("  Syntax ERROR");
        }
        break;
    case ')':
        if(stack.isEmpty() || (Character) stack.pop() != '(') {
            System.out.println("  Syntax ERROR");
        }
        break;
    }
}

编辑:我添加了缺少的 break; 语句。如果没有这些,系统将执行多个case: 条件,因为它会“失败”到每个条件。

编辑 2:Zong Zheng Li 在他们的回答中提出了一个很好的观点。完成后,您应该验证堆栈上没有任何剩余字符。在你的循环之后,你应该有这样的东西:

if(!stack.isEmpty()) {
    System.out.println("  Syntax ERROR");
}

编辑 3:将 stack.firstElement() 更改为 stack.peek()

【讨论】:

  • 这看起来有点不可思议!不过是的。我创建了一个自己的类,我用自己的 Push、Pop、Peek 和 Count 方法对其进行了初始化。这让我们知道我没有 isEmpty 方法。但我猜它与我的 Count() 方法几乎相同,因为它返回计数中的元素。所以如果我对它做一些改变,它会有所帮助吗?
  • @Thillofit123 是的,如果你愿意,你可以使用你的 Count() 方法,只用零进行相等检查,例如stack.Count() == 0。不过,您应该考虑创建自己的 isEmpty(),因为它会使您的代码更易于阅读(另外,不要重复自己通常是一个好习惯)。
  • public int Count() { 返回计数; } public boolean isEmpty() { if(count == 0) { return true; } 否则 { 返回假; } } } 这样的事情就够了吗?
  • @Thrillofit123 这几乎是完美的!您可以将其简化为:public boolean isEmpty() { return count == 0; }
  • 是的,它成功了!哇哦!真的!我真的很感谢你在这里度过本。 M和其他人也一样!据我所知,它有效。现在我要试着让它更酷,但正如我现在所看到的。一切都变好了!我无话可说!!!!
【解决方案2】:

除了检查特定字符是否匹配之外,还有两种情况需要有关堆栈本身的信息:

  1. 当括号的数量在中间状态下不多时。当您在堆栈为空时尝试弹出时会发生这种情况。

  2. 当字符串末尾有孤立括号时。在这种情况下,堆栈最终是非空的。

要修复1,您应该在弹出之前检查堆栈是否为空:

case '}':
    if (stack.empty()) {
        System.out.println("  Syntax ERROR");
    }
    else {
        c = (Character) stack.Pop();
        if( c != '{') {
            System.out.println("  Syntax ERROR");
        }
    }
    break;

或等价的,

case '}':
    if (stack.empty() || ((Character)stack.Pop()) != '{') {
        System.out.println("  Syntax ERROR");
    }
    break;

要修复 2,在程序结束时,您应该检查堆栈 是否 为空。这会捕获尚未解决的(bal)ler) 案例。

if (!stack.empty()) 
    System.out.println("  Syntax ERROR");
}

【讨论】:

    【解决方案3】:

    您说您想学习如何使用switch 语句。您可以使用一个巧妙的技巧,称为falling through

    switch (c) {
        case '{':
        case '(':
        case '[':
            stack.Push(c);
            System.out.print(stack.firstNode.getData());
            break;
    
        case '}':
        case ']':
        case ')':
            if (stack.isEmpty() || stack.pop() != c) {
                System.out.println("Syntax ERROR");
            }
            break;
    }
    

    您也可以使用预先实现的Stack 类,它也是generic

    【讨论】:

    • 这看起来很不错!我创建了一个自己的类,我用自己的 Push、Pop、Peek 和 Count 方法对其进行了初始化。这让我们知道我没有 isEmpty 方法。但我猜它与我的 Count() 方法几乎相同,因为它返回计数中的元素。所以如果我对它做一些改变,它会有所帮助吗?因为如果我导入 Java 堆栈。因为我已经用 Pop、Push 等创建了自己的类,所以它会给我其他的错误。
    • 使用你自己的Stack 类是完全可以的,除非你打算将你的代码发布为一个库并在它的API 中使用你自己的Stack。您可以通过stack.count() == 0 检查您的堆栈是否为空,因此您无需创建isEmpty() 方法,这完全取决于您。
    • 是的,它成功了!哇哦!真的!我非常感谢您在 Kajacx 和其他所有人的时间!据我所知,它有效。现在我要试着让它更酷,但正如我现在所看到的。一切都变好了!我无话可说!!!!
    猜你喜欢
    • 2017-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    相关资源
    最近更新 更多