Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
SANTA000
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 74
1

Как преобразовать обычный калькулятор в калькулятор использующий класс стек?

02.06.2018, 13:12. Просмотров 583. Ответов 12
Метки нет (Все метки)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
 
int main(){
    int a = 0;
    int b = 0;
    char operation;
    std::cout << "Enter first number: ";
    std::cin >> a;
    std::cout << "Enter second number: ";
    std::cin >> b;
    std::cout << "Enter operation: ";
    std::cin >> operation;
 
    switch (operation){
    case '-':
        std::cout << "a - b = " << a - b <<'\n';
        break;
    case '+':
        std::cout << "a + b = " << a + b << '\n';
        break;
    case '*':
        std::cout << "a * b = " << a * b << '\n';
        break;
    case '/':
        std::cout << "a / b = " << a / b << '\n';
        break;
    default:
        std::cout << "Error\n";
    }
    return 0;
}
Помогите преобразовать обычный калькулятор в калькулятор использующий шаблон класса stack чтобы учитывал очередность действий скобки и все в этом духе.
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
02.06.2018, 13:12
Ответы с готовыми решениями:

обычный калькулятор
помогите решить задачу на С: Написать программу, работающую как простейший...

Калькулятор и стек
Решил опробовать себя в С++. В Visual Studio C++ решил сделать мини...

Стек: Калькулятор ОБЗ
Написать программу, получающую строку с некоторым выражением, записанным...

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

Написать калькулятор, используя класс
Добрый вечер. Не понимаю я ООП и пока трудно оно мне даётся, задача лабы вот...

12
Praktolock
71 / 71 / 18
Регистрация: 29.11.2011
Сообщений: 345
02.06.2018, 13:25 2
А скобки тоже будут по одной вводиться с клавиатуры?
0
SANTA000
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 74
02.06.2018, 13:41  [ТС] 3
Добавлено через 56 секунд
Цитата Сообщение от Praktolock Посмотреть сообщение
А скобки тоже будут по одной вводиться с клавиатуры?
без разницы
скорее всего это должно выглядеть так записывается выражение допустим "2+4-5*1(1/2)+1^1" и калькулятор все это высчитывает используя приоритетность
0
Praktolock
71 / 71 / 18
Регистрация: 29.11.2011
Сообщений: 345
02.06.2018, 14:17 4
Тогда у тебя даже не близко "обычный калькулятор"
0
SANTA000
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 74
02.06.2018, 14:41  [ТС] 5
Спасибо, что подметили, я просто как пример скинул..
0
Praktolock
71 / 71 / 18
Регистрация: 29.11.2011
Сообщений: 345
02.06.2018, 14:43 6
А тебе прям обязательно стек использовать, или просто нужен рабочий калькулятор?
0
SANTA000
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 74
02.06.2018, 15:00  [ТС] 7
Ну задание звучит: "С помощью шаблона класса стек написать программу калькулятор с операциями сложения, вычитания, деления, умножения, возведения в степень." Так что да, обязательно.
0
Renji
2123 / 1561 / 476
Регистрация: 05.06.2014
Сообщений: 4,524
02.06.2018, 15:26 8
Цитата Сообщение от SANTA000 Посмотреть сообщение
Ну задание звучит: "С помощью шаблона класса стек написать программу калькулятор с операциями сложения, вычитания, деления, умножения, возведения в степень."
"С помощью метода "копипаста" написать задачник, не вникая какую дичь ты несешь".
Если появилось слово "стек", значит спрашивают польскую запись. Если появилось слово "шаблон", значит не понимают что реализация на обычном стеке проста как мычание. И вообще, не понимают что бывают стеки отличные от шаблонов. Ну, короче тебе нужно взять вот такой код и куда-то там воткнуть стек. Куда именно - надо уточнять у ведущих конструкторов велосипедов. Желательно, индусов по национальности.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
 
long polishNotation()
{
    while(std::cin.peek()==' ')
        std::cin.get();
    switch(std::cin.peek())
    {
    case'-':
        std::cin.get();
        return polishNotation()-polishNotation();
    case'+':
        std::cin.get();
        return polishNotation()+polishNotation();
    default:
    {
        long value;
        std::cin>>value;
        return value;
    }
    }
}
 
int main()
{
    //вводим +3 5, получаем 8
    std::cout<<polishNotation()<<std::endl;
    return 0;
}
0
SuperKir
434 / 399 / 278
Регистрация: 10.03.2015
Сообщений: 1,698
Завершенные тесты: 1
02.06.2018, 15:36 9
Цитата Сообщение от Renji Посмотреть сообщение
Если появилось слово "шаблон", значит не понимают что реализация на обычном стеке проста как мычание
Если я правильно понял посыл, то мб имеется ввиду не template, а конкретно stl - stack? Типо юзать не самописный стек, а шаблонный.
Про ОПН всё логично, тоже писал "калькулятор" применяя ее.
Цитата Сообщение от Renji Посмотреть сообщение
И вообще, не понимают что бывают стеки отличные от шаблонов
А вот тут, если честно, я вообще не понял, что тут имеется ввиду. Если можете, поясните, пожалуйста.
0
Renji
2123 / 1561 / 476
Регистрация: 05.06.2014
Сообщений: 4,524
02.06.2018, 16:58 10
Цитата Сообщение от SuperKir Посмотреть сообщение
А вот тут, если честно, я вообще не понял, что тут имеется ввиду. Если можете, поясните, пожалуйста.
Имеется ввиду аппаратный стек в котором хранятся автоматические переменные и адрес возврата из функции. Реализация стекового калькулятора через "шаблона класса стек" делает ровно тоже самое что в моем решении, только аппаратный стек меняется на программный велосипед с квадратными колесами.
0
Cortas
44 / 43 / 36
Регистрация: 14.03.2016
Сообщений: 200
Завершенные тесты: 5
02.06.2018, 17:55 11
Вот мой вариант, немного неказистый, однако рабочий и с переменными, но без возможности возведения в степень, это ты сам попробуй, только учти, что эта операция имеет больший приоритет чем * и /.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#include <iostream>
#include <conio.h>
#include <string>
#include <stack>
#include <queue>
 
using namespace std;
 
int end() { cout << "\nEND\n"; _getch(); return 0; }
 
queue<char> to_revpol(const string& in)
{
    stack<char> stk;//создаем стак для хранения временных операция
    queue<char> gen;//создаем очередь, куда все будем пихать
    for(auto i : in)//идем по строке
    {
        if(i == '.')//если это просто точка, т.е. пользователь ввел число по типу 0.2,
            gen.push(i);//то тупо пихаем её внутрь
        else if((i >= '0' && i <= '9') ||//если это число или переменная, то тоже просто запихиваем
                (i >= 'a' && i <= 'z') ||
                (i >= 'A' && i <= 'Z'))
        {
            if(gen.empty() != true &&
               (gen.back() >= '0' && gen.back() <= '9') &&
               !(i >= '0' && i <= '9'))
            { stk.push('*'); gen.push(';'); }//эта хрень нужна чтобы можно было не ставить знак умножения перед переменной при вводе 5x, например
            gen.push(i);
        }
        else if
            (i == '+' || i == '-' ||//если же это операция
             i == '*' || i == '/')
        {
            if(stk.empty() != true && (stk.top() == '*' || stk.top() == '/'))//если у нас что-то есть и последняя оперцаия была * или /, то...
            {
                if(i == '*' || i == '/')//если сейчас умножаем или делим
                {
                    gen.push(stk.top());//то можно выгрузить предыдущую операцию
                    stk.top() = i;//и заменить её
                }
                else if(i == '+' || i == '-')//если же это была оперция меньшего приоритета, т.е. + или -
                {
                    while(stk.empty() != true && stk.top() != '(')//следует выгрузить все до открывающейся скобки, либо пока стек не опустеет
                    {//зачем? А переведите на ОПН такое: a * b + c. Тут роль скобочки играет главное тело.
                        gen.push(stk.top());
                        stk.pop();
                    }
                    stk.push(i);
                }
            }
            else//если же стек пуст или последняя операция была не * или /, то...
            {
                if(gen.empty() != true && (
                    (gen.back() >= '0' && gen.back() <= '9') ||
                    (gen.back() >= 'a' && gen.back() <= 'z') ||
                    (gen.back() >= 'A' && gen.back() <= 'Z')))//если последнее, что было в gen - переменная или цифра, 
                    gen.push(';');//то следует поставить ограничивающий знак
                else if(((stk.empty() != true && stk.top() == '(') || gen.empty() == true) && i == '-')//иначе,
                    gen.push('_');//если стек не пуст и последнее, что в него запили была открывающая скобка, либо у нас вообще пока ничего нет, а i == -, то я вставляю знак _
                    //зачем? Ну, для того чтобы все не ломалось при таком вводе: -5 + 3 или 4 * (-2 + 1)
                if(gen.back() != '_')//если последнее в gen не _, которые мы могли только что записать => это какая-то операция
                    stk.push(i);
            }
        }
        else if(i == '(')//если же у нас не цифра, не переменная и не операция, а откр. скобка, то...
        {
            if(gen.empty() != true && (
                (gen.back() >= '0' && gen.back() <= '9') ||
                (gen.back() >= 'a' && gen.back() <= 'z') ||
                (gen.back() >= 'A' && gen.back() <= 'Z')))//если последнее что было в gen - переменная или цифра, 
            {
                gen.push(';');//ставим ограничивающий знак, а в стек записываем *
                stk.push('*');//Опять же, зачем? А затем, чтобы не ставить его самим при записи типа: 23(13 + 1), например
            }
            stk.push(i);//запихиваем ( в стэк
        }
        else if(i == ')')//если же у нас закрылась скобка, следует выгрущить все операции из stk в gen
        {
            while(stk.empty() != true && stk.top() != '(')//пока стек не пустой (если он опустел значит пользователь ввел неправильное выражение) и до, конечно, открывающийся скобки 
            {
                gen.push(stk.top());
                stk.pop();
            }
            if(stk.empty() != true)
                stk.pop();
            else
                throw "WRONG INPUT! Missing (";//кидаем исключение, если пользователь был не очень внимателен
        }
    }
 
    while(stk.empty() != true)//по окончанию работы со строкой в стеке может что-то остаться, потому
    {//выносим все что осталось.
        gen.push(stk.top());
        stk.pop();
    }
    return gen;//и возвращаем результат
}
 
double calc(queue<char> in)
{
    stack<double> res;//временное хранилище значений
    bool minus = false, op = false;//флаги на минус, либо на оперцию
    size_t fl = 0;//переменная для правильного ввода значений с плавающей точкой
    double temp;//и просто временная переменная
 
    res.push(0.0);//добавляем одно значение
    while(in.empty() != true)//пока очередь не опустеет
    {
        if(in.front() == '_')//если встретился знак _, значит был ввод типа: -3 + 2 или 5 * (-4 + 3) и т.д.
        {   
            minus = true;//поднимаем флаг минуса 
            in.pop();//убираем эл.
        }
        else if(in.front() >= '0' && in.front() <= '9')//если получили цифру
        {
            if(op == true) { res.push(0.0); op = false; }//если была какая-то операция и сейчас нам нужно записать новое значение, то добавляем память и опускаем флаг
            while(in.empty() != true && in.front() >= '0' && in.front() <= '9')//пока в очереди что-то есть и пока это цифры
            {
                if((in.front() == '0' && res.top() == 0.0) == false)//чтобы не умножать 0 на 10 и не прибавлять (48 - 48)
                {
                    if(fl == 0)//если не встречалось ., т.е. пока у нас обычное, целое число
                    {
                        res.top() = res.top() * 10 + in.front() - 48;
                    }
                    else//иначе
                    {
                        temp = in.front() - 48;//переводим символьное число в обычное
                        for(size_t i = 0; i < fl; i++)//и по счетчику разряда делим на 10
                            temp /= 10;
                        res.top() += temp;//и просто добавляем к текущему
                        fl++;//увеличиваем разряд
                    }
                }
                in.pop();//убираем эл.
                if(in.empty() != true && in.front() == '.')//если встретилась точка и очередь не пуста, то
                {
                    fl = 1;//счетчик разряда ставим в 1
                    in.pop();//и удаляем .
                }
            }
            fl = 0;//после считывания числа, обнуляем счетчик разрядов
        }
        else if((in.front() >= 'a' && in.front() <= 'z') || (in.front() >= 'A' && in.front() <= 'Z'))//если же нам встретилась переменная
            {
                cout << "Please enter the variable \'";//просим пользователя её ввести
                do
                {//выводим название переменной. А выводим в цикле за тем, чтобы можно было писать переменные не в одну букву
                    cout << in.front();
                    in.pop();
                }while(in.empty() != true && (in.front() >= 'a' && in.front() <= 'z') || (in.front() >= 'A' && in.front() <= 'Z'));
                cout << "\': ";
                if(op == true) { res.push(0.0); op = false;}//если до этого была операция, а теперь нам нужно ввести новое значение, то выделяем память
                cin >> res.top();//вводим значение переменной с клавиатуры
            }
            else if(in.front() == ';' ||
                    in.front() == '+' || in.front() == '-' ||
                    in.front() == '*' || in.front() == '/')//если же нам наконец попалась операция
            {
                if(minus == true)//если флаг минуса поднят
                {
                    minus = false;//опускаем флаг
                    res.top() = -res.top();//умножаем текущее значение на -1
                }
                if(in.front() == ';')//если это знак разделитель, значит надо добавить памяти
                {
                    res.push(0.0);//добавляем 
                    in.pop();//убираем знак
                }
                else if(res.size() > 1)//иначе, если у нас уже что-то есть в стеке
                {
                    temp = res.top();//пихаем в temp последнее значение
                    res.pop();//убираем его из стека
                    switch(in.front())//смотрим что это и делаем необходимые операции
                    {
                        case '+':
                            res.top() += temp;
                            break;
                        case '-':
                            res.top() -= temp;
                            break;
                        case '*':
                            res.top() *= temp;
                            break;
                        case '/':
                            res.top() /= temp;
                            break;
                    }
                    op = true;//ставим флаг операции
                    in.pop();//убираем символ операции из очереди
                }
            }
    }
    if(res.size() > 1)//если вдруг в стеке осталось что-то кроме результата, выводим сообщение об ошибке и все, что осталось в стеке
    {
        cout << "something went wrong!";
        while(res.empty() != true)
        {
            cout << res.top() << ' ';
            res.pop();
        }
        return 0.0;
    }
    return res.top();//если же все хорошо, возвращаем результат
}
 
template <class T>
ostream& operator<<(ostream& out, queue<T> cs)
{
    while(cs.empty() != true)
    {
        out << cs.front();
        cs.pop();
    }
    return out;
}
 
int main()
{
    string in;
    queue<char> gen;
    cout << "Enter an expression:\n";
    getline(cin, in);
 
    gen = to_revpol(in);
    cout << "Result of the function to_revpol: " << gen << endl;
    cout << "Final result: " << calc(gen);
    return end();
}
0
Fixer_84
1209 / 754 / 715
Регистрация: 30.04.2016
Сообщений: 2,506
25.07.2018, 22:42 12
SANTA000, здравствуйте! Я делал так (учитываются операции '+', '-', '*', '/' и круглые скобки + приоритет операций):

Пример входных данных:

(2+13)*4-28*(329/(23-17))

Ответ: -1475.33

Код программы:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <bits/stdc++.h>
 
    using namespace std;
 
int prec(char ch) {
    if (ch == '*' || ch == '/') return 2;
    else if (ch == '+' || ch == '-') return 1;
    else return -1;
}
 
string infixToPostfix(string &s) {
    stack<char> st;
    string res;
    s += " ";
    int len = s.size();
    for (int i = 0; i < len; i++) {
        if (isdigit(s[i]) || s[i] == '.')
            res += s[i];
        else if (s[i] == '(') st.push('(');                                
        else if (s[i] == ')') {
            res += " ";
            while (!st.empty() && st.top() != '(') {
                char ch = st.top();
                st.pop();
                res += ch;
                if (ch == '*' || ch == '/') res += " ";
            }
            if (st.top() == '(') {
                char ch = st.top();
                st.pop();
            }
        } else {
            res += " ";
            while (!st.empty() && prec(s[i]) <= prec(st.top())) {
                char ch = st.top();
                st.pop();
                res += ch;
                res += " ";
            }
            st.push(s[i]);
        }
    }
    while (!st.empty()) {
        char ch = st.top();
        st.pop();
        res += ch;
    }
    return res;
}
 
int main() {
    double a, b;
    stack<double> st;
    string s, sign;
    getline(cin, s);
    s = infixToPostfix(s);
    stringstream str(s);
    while (str >> sign) {
        if (!(sign == "-" || sign == "+" || sign == "*" || sign == "/")) st.push(atof(sign.c_str()));
        else {
            if (!st.empty()) {
                b = st.top();
                st.pop();
            }
            if (!st.empty()) {
                a = st.top();
                st.pop();
            }
            switch (sign[0]) {
            case '+':
                st.push(a + b);
                break;
            case '-':
                st.push(a - b);
                break;
            case '*':
                st.push(a * b);
                break;
            case '/':
                st.push(a / b);
                break;
            }
        }
    }
    if (!st.empty()) {
        double ch = st.top();
        st.pop();
        if (st.empty()) {
            cout << ch << "\n";
        }
    }
    system("pause");
    return 0;
}
0
Renji
2123 / 1561 / 476
Регистрация: 05.06.2014
Сообщений: 4,524
25.07.2018, 23:16 13
Цитата Сообщение от Fixer_84 Посмотреть сообщение
SANTA000, здравствуйте! Я делал так (учитываются операции '+', '-', '*', '/' и круглые скобки + приоритет операций):
Тыц. Те же объемы кода, но при этом никаких std::stack. А значит, будет быстрее, ибо динамическую память не дергает.
1
25.07.2018, 23:16
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
25.07.2018, 23:16

Класс Калькулятор, написать комментарии
Доброго всем времени суток! Уважаемые жители форума, у меня к вам есть вот...

Простой калькулятор и калькулятор с парсингом
Ребят я совсем не давно только начал изучать сишку, решил написать простенький...

Как заполнить бинарное дерево, чтобы оно не превратилось в обычный стек
вот допустим написал заполнение данных в виде бинарного дерева, и в слуае если...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru