Оцените постфикс, используя стек в C ++ - PullRequest
0 голосов
/ 12 апреля 2011
#include <iostream>
#include <sstream>
#include <stack>
#include <limits>
#include <string>
using namespace std;

int main()
{
    string input;
    cout << "Enter a postfix expression: " << endl;
    getline(cin, input);

    int operand1, operand2, result,number;
    stack<char>operation;

    stringstream temp;

    int i=0;
    while (i < input.length())
    {
        if (isdigit(input[i]))
        {
            operation.push(input[i]);
        }
        else
        {
            operand2 = operation.top();
            temp << operation.top();
            operation.pop();

            operand1 = operation.top();
            temp << operation.top();
            operation.pop();

            switch(operand1,operand2)
            {
                case '+': result=operand1 + operand2;
                break;

                case '-': result=operand1 - operand2;
                break;

                case '*': result=operand1 * operand2;
                break;

                case '/': result=operand1 / operand2;
                break;
            }
            operation.push(result);
        }
        i++;
    }
    cout << "The result is: "<<temp.str()<<endl;
    cin.ignore(numeric_limits<streamsize>::max(), '\n');

    return 0;
}

Я изменил код и смог получить значение «pop», но операция не сработала.

Ответы [ 3 ]

2 голосов
/ 12 апреля 2011

Вы, вероятно, имели в виду

switch(input[i])

вместо

switch(operation.top())
1 голос
/ 12 апреля 2011

Обновление ответ на изменения кода


Я могу подтвердить, что вы изменили код, но не в хорошем смысле.

  1. Код в основномимеет все недостатки, которые у него уже были, и еще несколько.
  2. Что хорошего в том, что вы теперь объединяете операнды в поток строк?
  3. Теперь вы включаете (операнд1, операнд2) ...
    • оба неинициализированы
    • (операнд1, операнд2) в этом контексте означает в основном (операнд2) (оператор последовательности )
    • ваши метки ветвления ... операторы (+ - / *)
  4. теперь вы выводите окончательный результат, который является объединением всехцифры на входе (если вы когда-нибудь дойдете до конца программы без сбоев)?

Среди вещей, которые были не правы ранее и должны быть исправлены

  1. ментальная модель стекового калькулятора.
    • числа (целые числа) - операнды (таким образом, 9, 100, 39829 - действительные операнды)
    • + - / * - операторы (operators работают наoperands)
    • стек - это операнд стек, не стек операторов (операторы не нужно запоминать, потому что ониоцениваются сразу)
    • числа состоят из 1 или более digits (0123456789) в строке;поэтому вам нужно прочитать несколько символов, прежде чем вы сможете «нажать» number на operand stack
    • operators + - / * дубль 2 operands,поэтому любая операция со стеком размером <2 является ошибкой (вам необходимо это проверить, иначе программа потерпит крах при попытке доступа к памяти, которая не существует или содержит мусор). </li>

Этого должно быть достаточно, чтобы начать.

Две вещи, которые я считаю положительными :

  1. Вы программируете компиляцию.+1 для того, чтобы вы на самом деле использовали компилятор там:)
  2. Вы вынули повторный operation.push(result) из коммутатора, чтобы он больше не дублировался.+1 за стиль кодирования ...

Я надеюсь, что из этого вы можете понять, что код не очень хорош (мягко говоря), и я действительно думаю, что некоторые базовые упражнения в порядке:1. написать простой цикл for, который печатает числа от 1 до 10, на консоль 1. написать простой цикл while, который печатает слова, введенные пользователем 1. использовать простой цикл для печати всех чисел от 1 до 50, кратных 7 1используйте оператор switch для вывода «yes» всякий раз, когда пользователь вводит одну из букв a, b, k или z 2. создайте простой цикл, который печатает только входной символ для каждого символа, который следует за идентичным (так что «abccdefgghijkllmabcdd»)станет «cgld») 1. использовать тот же цикл, но на этот раз выведите каждое слово , которое следует сразу за идентичным словом (так что «нет, нет, вы не должны выскочить, выскользнуть, но нажать, выскочить» становится"no pop")

Это должно дать вам представление о том, как все действительно работает, без догадок или "магического фактора".

О, и не забывайте, я реализовал все это для вас ниже.Я не предлагаю вам слепо копировать его (это будет довольно очевидно для вашего учителя :)), но вы можете взглянуть на него, если хотите знать, что я имею в виду всеми моими словами выше:)


  1. Вы выдвигаете свободные цифры, а не проанализированные числа

  2. В строке 31 вы можете вытолкнуть, возможно, пустой стек (приводящий к segfault, если тольковы используете флаги режима отладки STL на вашем компиляторе)

Просто для удовольствия:

#include <iostream>
#include <stack>
#include <vector>
#include <limits>
#include <string>
#include <stdexcept>
#include <iterator>
#include <fstream>

using namespace std;

    template <class T>
        static void dumpstack(std::stack<T> s/*byval!*/)
    {
        std::vector<T> vec;

        while (!s.empty())
        {
            vec.push_back(s.top());
            s.pop();
        }

        std::copy(vec.rbegin(), vec.rend(), std::ostream_iterator<int>(std::cout, " "));
    }

    class calc
    {
        private:
            std::stack<int> _stack;
            int _accum;
            bool _pending;

            void store(/*store accumulator if pending*/)
            {
                if (_pending)
                {
                    _stack.push(_accum);
                    _pending = false;
                    _accum = 0;
                }
            }

        public:
            calc() : _accum(0), _pending(false) 
            {
            }

            void handle(char ch)
            {
                switch (ch)
                {
                    case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
                        _pending = true;
                        _accum *= 10;
                        _accum += ch-'0';
                        break;
                    case '+': case '-': case '/': case '*':
                        {
                            store();
                            if (_stack.size()<2)
                                throw std::runtime_error("stack underflow");

                            int op2 = _stack.top(); _stack.pop();
                            int op1 = _stack.top(); _stack.pop();
                            switch (ch)
                            {
                                case '+': _stack.push(op1 + op2); break;
                                case '-': _stack.push(op1 - op2); break;
                                case '/': _stack.push(op1 / op2); break;
                                case '*': _stack.push(op1 * op2); break;
                            }

                            // feedback to console:
                            std::cout << std::endl << "(evaluated: " << op1 << " " << ch << " " << op2 << " == " << _stack.top() << ")" << std::endl;
                            dump();
                        }
                        break;
                    default:
                        store(); // todo: notify of ignored characters in input?
                }
            }

            void dump() const
            {
                dumpstack(_stack);
            }
    };

    int main() 
    {
        cout << "Enter postfix expressions: " << endl;
        calc instance;

        try
        {
            while (std::cin.good())
            {
                char ch = std::cin.get();
                instance.handle(ch);
            }
            std::cout << "Final result: "; 
            instance.dump();

            return 0;
        } catch(const std::exception& e)
        {
            std::cerr << "E: " << e.what() << std::endl;
            return 255;
        }

    }

Тестовый вывод: (обратите внимание, что вы можете продолжить с оставшимися,частично оценивается, укладывается после нажатия возврата каретки)

Enter postfix expressions: 
1 2 3 +4 * - / 1333 *

(evaluated: 2 + 3 == 5)
1 5 
(evaluated: 5 * 4 == 20)
1 20 
(evaluated: 1 - 20 == -19)
-19 E: stack underflow
0 голосов
/ 12 апреля 2011

В коде много ошибок, начиная с разбора входного выражения. Скорее всего, фактический сбой объясняется тем, что если вы введете что-то вроде "12+", вы вставите '1' и '2' в стек (примечание: символы 1 и 2, а не значения 1 и 2 !!!) и затем попытайтесь извлечь два операнда и оператор, который вы никогда не вставляли в стек.

При синтаксическом анализе ввода вы читаете символ за символом, и только с использованием первой цифры синтаксический анализ не может обрабатывать пробелы или любой другой разделитель ... Попробуйте разбить проблему на две части: анализ и обработка. Проблему синтаксического анализа можно решить, не используя фактические прочитанные значения, а просто печатая их (или сохраняя в некоторой форме, а затем печатая все прочитанное выражение), и может быть первым шагом. Убедитесь, что синтаксический анализатор может работать с общими выражениями, такими как «1 2+», «10 20+», «1 2+», «1 2+» (обратите внимание на различные позиции пробелов) надежным способом. И что он не в состоянии изящно разобрать выражения, такие как "+", "1 +", "1 2 ++" ... Вы никогда не можете доверять пользовательскому вводу, они допустят ошибки, и это не должно поставить вашу программу на колени.

Как только вы уверены, что сможете проанализировать ввод, начните с самого алгоритма. Сделайте его устойчивым к недопустимым пользовательским вводам, которые вы, возможно, раньше не могли обработать, например, «10 0 /», и выполняйте фактическую обработку.

Научитесь использовать отладчик, он поможет вам понять, когда дела идут на юг, в чем причины. Отладчику потребуется менее одной секунды, чтобы указать на конкретную проблему в вашем коде выше, он не скажет вам, почему он умер, но покажет вам, как он умер и каково было состояние программы. Если моя догадка верна, то она укажет вам на команду operation.top() как на виновника, и вы увидите, что пытались извлечь больше элементов, чем было вставлено. Выполните часть вашей программы шаг за шагом, чтобы понять, что она на самом деле делает, и вы заметите, что когда вы читаете «12+», вы фактически сохраняете два, казалось бы, не связанных целых числа в стек (значения ASCII '1' и '2' ...

...