package edu.bsu.cs121.mamurphy;

import java.util.Stack;

public class Checker {

    char openPara = '(';
    char openBracket = '[';
    char openCurly = '{';
    char openArrow = '<';
    char closePara = ')';
    char closeBracket = ']';
    char closeCurly = '}';
    char closeArrow = '>';

    public boolean checkString(String stringToCheck) {
        Stack<Character> stack = new Stack<Character>();

        for (int i = 0; i < stringToCheck.length(); i++) {
            char c = stringToCheck.charAt(i);
            if (c == openPara || c == openBracket || c == openCurly || c == openArrow) {
                stack.push(c);
                System.out.println(stack);
                ;
            }
            if (c == closePara) {
                if (stack.isEmpty()) {
                    System.out.println("Unbalanced");
                    break;
                } else if (stack.peek() == openPara) {
                    stack.pop();
                } else if (stack.size() > 0) {
                    System.out.println("Unbalanced");
                    break;
                }
            }
            if (c == closeBracket) {
                if (stack.isEmpty()) {
                    System.out.println("Unbalanced");
                    break;
                } else if (stack.peek() == openBracket) {
                    stack.pop();
                } else if (stack.size() > 0) {
                    System.out.println("Unbalanced");
                    break;
                }

            }
            if (c == closeCurly) {
                if (stack.isEmpty()) {
                    System.out.println("Unbalanced");
                    break;
                } else if (stack.peek() == openCurly) {
                    stack.pop();
                } else if (stack.size() > 0) {
                    System.out.println("Unbalanced");
                    break;
                }
            }
            if (c == closeArrow) {
                if (stack.isEmpty()) {
                    System.out.println("Unbalanced");
                    break;
                } else if (stack.peek() == openArrow) {
                    stack.pop();
                } else if (stack.size() > 0) {
                    System.out.println("Unbalanced");
                    break;
                }
            }
        }
        return false;
    }

}

В настоящее время я пытаюсь создать программу, в которой я проверяю, сбалансирована ли строка или нет. Строка сбалансирована тогда и только тогда, когда каждый открывающий символ: (, {, [и <имеет соответствующий закрывающий символ:),},] и> соответственно.

Что происходит при проверке строки, если обнаруживается открывающий символ, он помещается в стек и проверяет, есть ли соответствующий закрывающий символ.

Если перед открывающим символом стоит закрывающий символ, это автоматически означает, что строка не сбалансирована. Кроме того, строка автоматически разбалансируется, если после перехода к следующему символу внутри стека что-то еще остается.

Я пытался использовать

else if (stack.size() > 0) {
                    System.out.println("Unbalanced");
                    break;
                }

Как способ узнать, есть ли что-нибудь в стеке, но это все еще не работает для меня. Любой совет, что делать?

Например, если строковый ввод был ()<>{(), тогда программа должна выполняться как обычно, пока не дойдет до единственного {, а затем код должен понять, что строка несбалансирована, и вывести Unbalanced .

По какой-то причине мой код этого не делает.

2
MoeMarmalade 28 Окт 2015 в 00:32

4 ответа

Лучший ответ

Следующая логика ошибочна (выделено мной):

Например, если строковый ввод был ()<>{(), тогда программа должна работать как обычно, пока не дойдет до единственного { , а затем код должен понять, что строка несбалансирована и выход несимметричный.

Фактически, код не может сделать вывод о несбалансированности строки до тех пор, пока он не просканирует всю строку и не установит, что { не имеет соответствия }. Насколько он знает, полный вход может быть ()<>{()} и быть сбалансированным.

Для этого вам нужно добавить проверку, которая гарантирует, что стек будет пуст после обработки всей строки. В вашем примере он все равно будет содержать {, указывающий, что вход не сбалансирован.

2
NPE 27 Окт 2015 в 21:54

Например, если строковый ввод был () <> {(), тогда программа должна выполняться как обычно до тех пор, пока не дойдет до единственного {, а затем код должен понять, что строка несбалансирована и вывести Несбалансированный.

Из вашего примера не ясно, могут ли границы быть вложенными , например ([{}]). Если они могут, эта логика не будет работать, так как вся строка должна быть использована, чтобы быть уверенным, что любые отсутствующие закрывающие символы не находятся в конце, и поэтому строку нельзя надежно считать несбалансированной в указанном вами месте.

Вот мой взгляд на вашу проблему:

Класс BalanceChecker:

package so_q33378870;

import java.util.Stack;

public class BalanceChecker {

    private final char[] opChars = "([{<".toCharArray();
    private final char[] edChars = ")]}>".toCharArray();

    //<editor-fold defaultstate="collapsed" desc="support functions">
    public boolean isOPChar(char c) {
        for (char checkChar : opChars) {
            if (c == checkChar) {
                return true;
            }
        }
        return false;
    }

    public boolean isEDChar(char c) {
        for (char checkChar : edChars) {
            if (c == checkChar) {
                return true;
            }
        }
        return false;
    }

    //NOTE: Unused.
//  public boolean isBoundaryChar(char c) {
//      boolean result;
//      if (result = isOPChar(c) == false) {
//          return isEDChar(c);
//      } else {
//          return result;
//      }
//  }

    public char getOpCharFor(char c) {
        for (int i = 0; i < edChars.length; i++) {
            if (c == edChars[i]) {
                return opChars[i];
            }
        }
        throw new IllegalArgumentException("The character (" + c + ") received is not recognized as a closing boundary character.");
    }
//</editor-fold>

    public boolean isBalanced(char[] charsToCheck) {
        Stack<Character> checkStack = new Stack<>();
        for (int i = 0; i < charsToCheck.length; i++) {
            if (isOPChar(charsToCheck[i])) {
                //beginning char found. Add to top of stack.
                checkStack.push(charsToCheck[i]);
            } else if (isEDChar(charsToCheck[i])) {
                if (checkStack.isEmpty()) {
                    //ending char found without beginning chars on the stack. UNBALANCED.
                    return false;
                } else if (getOpCharFor(charsToCheck[i]) == checkStack.peek()) {
                    //ending char found matches last beginning char on the stack. Pop and continue.
                    checkStack.pop();
                } else {
                    //ending char found, but doesn't match last beginning char on the stack. UNBALANCED.
                    return false;
                }
            }
        }
        //the string is balanced if and only if the stack is empty at the end.
        return checkStack.empty();
    }

    public boolean isBalanced(String stringToCheck) {
        return isBalanced(stringToCheck.toCharArray());
    }
}

Основной класс (используется для тестирования):

package so_q33378870;

public class main {

    private static final String[] tests = {
        //Single - Balanced.
        "()",
        //Single - Unbalanced by missing end.
        "(_",
        //Multiple - Balanced.
        "()[]{}<>",
        //Multiple - Unbalanced by missing beginning.
        "()[]_}<>",
        //Nested - Balanced.
        "([{<>}])",
        //Nested - Unbalanced by missing end.
        "([{<>}_)",
        //Endurance test - Balanced.
        "the_beginning (abcd) divider (a[bc]d) divider (a[b{c}d]e) divider (a[b{c<d>e}f]g) the_end"
    };

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        BalanceChecker checker = new BalanceChecker();
        for (String s : tests) {
            System.out.println("\"" + s + "\" is " + ((checker.isBalanced(s)) ? "BALANCED!" : "UNBALANCED!"));
        }
    }
}
0
XenoRo 28 Окт 2015 в 21:27

Вот альтернативный подход:

    private static final char[] openParens = "[({<".toCharArray();
    private static final char[] closeParens = "])}>".toCharArray();

    public static boolean isBalanced(String expression){
        Deque<Character> stack = new ArrayDeque<>();
        for (char c : expression.toCharArray()){
            for (int i = 0; i < openParens.length; i++){
                if (openParens[i] == c){
                    // This is an open - put it in the stack
                    stack.push(c);
                    break;
                }
                if (closeParens[i] == c){
                    // This is a close - check the open is at the top of the stack
                    if (stack.poll() != openParens[i]){
                        return false;
                    }
                    break;
                }
            }
        }
        return stack.isEmpty();
    }

Это упрощает логику наличия двух соответствующих массивов символов открытия и закрытия. Вы также можете сделать это с четными и нечетными позициями в одном массиве, т.е. "{} <>", например:

    private static final char[] symbols = "[](){}<>".toCharArray();

    public static boolean isBalanced(String expression){
        Deque<Character> stack = new ArrayDeque<>();
        for (char c : expression.toCharArray()){
            for (int i = 0; i < symbols.length; i += 2){
                if (symbols[i] == c){
                    // This is an open - put it in the stack
                    stack.push(c);
                    break;
                }
                if (symbols[i + 1] == c){
                    // This is a close - check the open is at the top of the stack
                    if (stack.poll() != symbols[i]){
                        return false;
                    }
                    break;
                }
            }
        }
        return stack.isEmpty();
    }

Обратите внимание, что опрос возвращает значение null, если стек пуст, поэтому сравнение на равенство не выполняется корректно, если стек закончился.

0
Tim Spears 27 Окт 2015 в 23:08

Я попытался ответить на этот вопрос. Мои решения возвращают истину, если строка сбалансирована и обеспечивает выполнение порядка открытия / закрытия (т.е. ({)} возвращает ложь). Я начал с вашего кода и попытался его уменьшить.

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

public class mamurphy {

  private static final char openPara = '(';
  private static final char openBracket = '[';
  private static final char openCurly = '{';
  private static final char openArrow = '<';
  private static final char closePara = ')';
  private static final char closeBracket = ']';
  private static final char closeCurly = '}';
  private static final char closeArrow = '>';


  public static void main(String... args) {
    System.out.println(checkString("{}[]()90<>"));//true
    System.out.println(checkString("(((((())))"));//false
    System.out.println(checkString("((())))"));//false
    System.out.println(checkString(">"));//false
    System.out.println(checkString("["));//false
    System.out.println(checkString("{[(<>)]}"));//true
    System.out.println(checkString("{[(<>)}]"));//false
    System.out.println(checkString("( a(b) (c) (d(e(f)g)h) I (j<k>l)m)"));//true
  }

  public static boolean checkString(String stringToCheck) {
    final Map<Character, Character> closeToOpenMap = new HashMap<>();
    closeToOpenMap.put(closePara, openPara);
    closeToOpenMap.put(closeBracket, openBracket);
    closeToOpenMap.put(closeCurly, openCurly);
    closeToOpenMap.put(closeArrow, openArrow);
    Stack<Character> stack = new Stack<>();
    final char[] stringAsChars = stringToCheck.toCharArray();
    for (int i = 0; i < stringAsChars.length; i++) {
      final char current = stringAsChars[i];
      if (closeToOpenMap.values().contains(current)) {
        stack.push(current); //found an opening char, push it!
      } else if (closeToOpenMap.containsKey(current)) {
        if (stack.isEmpty() || closeToOpenMap.get(current) != stack.pop()) {
          return false;//found closing char without correct opening char on top of stack
        }
      }
    }
    if (!stack.isEmpty()) {
      return false;//still have opening chars after consuming whole string
    }
    return true;
  }
}
0
Andreas 27 Окт 2015 в 22:10