Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Калькулятор, обратная польская запись (http://forum.oszone.net/showthread.php?t=228785)

Hector 26-02-2012 01:21 1866678

Калькулятор, обратная польская запись
 
Собственно есть вот такой фрагмент кода:
PHP код:

public Map<StringIntegerMAIN_MATH_OPERATIONS;

    {
        
MAIN_MATH_OPERATIONS = new HashMap<StringInteger>();
        
MAIN_MATH_OPERATIONS.put("*"1);
        
MAIN_MATH_OPERATIONS.put("/"1);
        
MAIN_MATH_OPERATIONS.put("+"2);
        
MAIN_MATH_OPERATIONS.put("-"2);
    }

public class ExpressionUtils {
         
// из инфиксной нотации в обратную польскую
        
public String sortingStation(String expressionMap<StringIntegeroperationsString leftBracket,
                                            
String rightBracket) {
            if (
expression == null || expression.length() == 0)
                
throw new IllegalStateException("Expression isn't specified.");
            if (
operations == null || operations.isEmpty())
                
throw new IllegalStateException("Operations aren't specified.");
            
// Выходная строка, разбитая на "символы" - операции и операнды..
            
List<Stringout = new ArrayList<String>();
            
// Стек операций.
            
Stack<Stringstack = new Stack<String>();

            
// Удаление пробелов из выражения.
            
expression expression.replace(" """);

            
// Множество "символов", не являющихся операндами (операции и скобки).
            
Set<StringoperationSymbols = new HashSet<String>(operations.keySet());
            
operationSymbols.add(leftBracket);
            
operationSymbols.add(rightBracket);

            
// Индекс, на котором закончился разбор строки на прошлой итерации.
            
int index 0;
            
// Признак необходимости поиска следующего элемента.
            
boolean findNext true;
            while (
findNext) {
                
int nextOperationIndex expression.length();
                
String nextOperation "";
                
// Поиск следующего оператора или скобки.
                
for (String operation operationSymbols) {
                    
int i expression.indexOf(operationindex);
                    if (
>= && nextOperationIndex) {
                        
nextOperation operation;
                        
nextOperationIndex i;
                    }
                }
                
// Оператор не найден.
                
if (nextOperationIndex == expression.length()) {
                    
findNext false;
                } else {
                    
// Если оператору или скобке предшествует операнд, добавляем его в выходную строку.
                    
if (index != nextOperationIndex) {
                        
out.add(expression.substring(indexnextOperationIndex));
                    }
                    
// Обработка операторов и скобок.
                    // Открывающая скобка.
                    
if (nextOperation.equals(leftBracket)) {
                        
stack.push(nextOperation);
                    }
                    
// Закрывающая скобка.
                    
else if (nextOperation.equals(rightBracket)) {
                        while (!
stack.peek().equals(leftBracket)) {
                            
out.add(stack.pop());
                            if (
stack.empty()) {
                                
throw new IllegalArgumentException("Unmatched brackets");
                            }
                        }
                        
stack.pop();
                    }
                    
// Операция.
                    
else {
                        while (!
stack.empty() && !stack.peek().equals(leftBracket) &&
                                (
operations.get(nextOperation) >= operations.get(stack.peek()))) {
                            
out.add(stack.pop());
                        }
                        
stack.push(nextOperation);
                    }
                    
index nextOperationIndex nextOperation.length();
                }
            }
            
// Добавление в выходную строку операндов после последнего операнда.
            
if (index != expression.length()) {
                
out.add(expression.substring(index));
            }
            
// Пробразование выходного списка к выходной строке.
            
while (!stack.empty()) {
                
out.add(stack.pop());
            }
            
StringBuffer result = new StringBuffer();
            if (!
out.isEmpty())
                
result.append(out.remove(0));
            while (!
out.isEmpty())
                
result.append(" ").append(out.remove(0));

            return 
result.toString();
        }

        
public String sortingStation(String expressionMap<StringIntegeroperations) {
            return 
sortingStation(expressionoperations"("")");
        }
        
// вычисление 
        
public String calculateExpression(String expression) {
            
String rpn sortingStation(expressionMAIN_MATH_OPERATIONS);
            
StringTokenizer tokenizer = new StringTokenizer(rpn" ");
            
Stack<BigDecimalstack = new Stack<BigDecimal>();
            while (
tokenizer.hasMoreTokens()) {
                
String token tokenizer.nextToken();
                
// Операнд.
                
if (!MAIN_MATH_OPERATIONS.keySet().contains(token)) {
                    
stack.push(new BigDecimal(token));
                } else {
                    
BigDecimal operand2 stack.pop();
                    
BigDecimal operand1 stack.empty() ? BigDecimal.ZERO stack.pop();
                    if (
token.equals("*")) {
                        
stack.push(operand1.multiply(operand2));
                    } else if (
token.equals("/")) {
                        if (
operand1.compareTo(operand2)==-1)
                            
stack.push(operand1.divide(operand23RoundingMode.HALF_UP));
                        else
                            
stack.push(operand1.divide(operand2));
                    } else if (
token.equals("+")) {
                        
stack.push(operand1.add(operand2));
                    } else if (
token.equals("-")) {
                        
stack.push(operand1.subtract(operand2));
                    }
                }
            }
            if (
stack.size() != 1)
                
throw new IllegalArgumentException("Expression syntax error.");
            return 
stack.pop().toString();
        }

        
/**
         * Закрытый конструктор класса.
         */
        
private ExpressionUtils() {
        }
    } 

это класс из калькулятора написанного под Android, он выполняет преобразование выражения из инфиксной нотации в обратную польскую, а потом вычисляет его. код немного не работает (проблемы с делением на ноль и дробными числами), поэтому надо поправить. Проблема в том, что о Java я не знаю практически ничего.
Интересуют следующие моменты:
Код:

    public Map<String, Integer> MAIN_MATH_OPERATIONS;

    {
        MAIN_MATH_OPERATIONS = new HashMap<String, Integer>();
        MAIN_MATH_OPERATIONS.put("*", 1);
        MAIN_MATH_OPERATIONS.put("/", 1);
        MAIN_MATH_OPERATIONS.put("+", 2);
        MAIN_MATH_OPERATIONS.put("-", 2);
    }

что это за структура данных? где почитать про нее?

List<String> out = new ArrayList<String>() - это коллекции, или я не прав? опять же, где почитать?
Set<String> operationSymbols = new HashSet<String>(operations.keySet()) - даже догадок нету
for (String operation : operationSymbols) - тоже не понятно

lxa85 26-02-2012 07:35 1866751

Hector, Насколько я понял, в классе реализовано однопроходное преобразование выражения в ОПЗ с использованием стека.
Т.е. надо поискать, что это за метод, и "методом научного тыка" сопоставить реализацию с теорией.
С теорией по Java к сожалению не помогу.

ferget 26-02-2012 08:13 1866758

Цитата:

Цитата Hector
проблемы с делением на ноль »

эту проблему можно решить например так
Код:

if(!operand2.equals(new BigDecimal("0")))
stack.push(operand1.divide(operand2));

Цитата:

Цитата Hector
и дробными числами »

а в чем именно выражается эта проблема?
что-то ее не видно

Hector 26-02-2012 11:09 1866815

ferget, если при делении второй операнд больше первого так, что в результате не получается целой части (например 6/9), тогда программа вылетает. я пытался решить это:
Код:

else if (token.equals("/")) {
                        if (operand1.compareTo(operand2)==-1)
                            stack.push(operand1.divide(operand2, 3, RoundingMode.HALF_UP));
                        else
                            stack.push(operand1.divide(operand2));

но в этом случае у всех следующих чисел всегда будет 3 знака после запятой независимо от последующих операций (выглядит так - 5.000)


Время: 18:23.

Время: 18:23.
© OSzone.net 2001-