Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Калькулятор на С++ с двусвязным списком

60K
21 июня 2010 года
Anastassija
5 / / 21.06.2010
Всем привет!

Мне нужно сделать на С++ калькультор для консоли, выполняющий 4 действия (сложение, вычитание, умножение, деление).
Программа должна быть основана на принципах объектно-ориентированного программирования. Для промежуточного хранения чисел и знаков, надо использовать двусвязанный список.



1. Калькулятор должен работать как с целыми числами, так и с дробными числами и только в десятичной системе (Должен использоваться тип double).
2. Он должен работать "цепочкой" , т.е. производить действия не только над двумя числами, а например считать 3+8*9/15.
3. Должно учитываться приоритетное выполнение умножения и деления.
4. При делении на ноль должно выдаваться сообщение об ошибке
5. Программа должна быть бесконечным циклом, с возможностью прерывания пользователем (введение какого-либо специального знака).



Я что-то пробывала написать, но получается как-то кусками и мозги в кучку не собираются...... может быть кто-то сможет помочь...

#include <iostream>
#include <list>

using namespace std;

class Liste {
public:
double zahl;
char op;

Liste* next;
Liste* last;
Liste(double, char);
~Liste();

}


#include "Zulassungsaufgabe.h"

double zahl;
char op;

Liste* createList();
Liste* start=new Liste(zahl, op);
Liste* temp=start;
Liste* aftertemp=temp+1;
int main(){
while(op!='s', op!='=')
{
cout<<"Enter number: "<<zahl<<endl;
cin>>zahl;
cout<<"Enter operand: "<<op<<endl;
cin>>op;
Liste* neu= new Liste(zahl, op);
neu->last=temp;
temp=neu;
start->next=neu;
}

while (op=='*') {
temp->zahl=(temp->zahl)*(aftertemp->zahl);
temp->op=aftertemp->op;
temp->next=aftertemp->next;
temp->last=temp;}

while (op=='/') {
if(aftertemp->zahl==0){
cout<<"Fehler";}
else{
temp->zahl=(temp->zahl)/(aftertemp->zahl);
temp->op=aftertemp->op;
temp->next=aftertemp->next;
temp->last=temp;}}
while (op=='+') {
temp->zahl=(temp->zahl)+(aftertemp->zahl);
temp->op=aftertemp->op;
temp->next=aftertemp->next;
temp=temp->last;}
while (op=='-') {
temp->zahl=(temp->zahl)*(aftertemp->zahl);
temp->op=aftertemp->op;
temp->next=aftertemp->next;
temp->last=temp;}
}
87
21 июня 2010 года
Kogrom
2.7K / / 02.02.2008
Вероятно, тут лучше не изобретать велосипед. Можно попытаться поискать решение, используя слова "лексический анализатор калькулятор". И найти например такое:

http://gocha.org/webstart/parser/01/parser.pdf

Особо не вникал, но вроде бы много умных слов, да и код не совсем на C++, так что потребуется какая-то работа, а не чистое копирование. И списки там используются.
60K
21 июня 2010 года
Anastassija
5 / / 21.06.2010
Да вот про много умных слов правильно сказано...я что-то вообще не понимаю, как такое совместить с моей программой...
2.1K
22 июня 2010 года
Norgat
452 / / 12.08.2009
ну... писать код сейчас не очень охота...

но, в общем, я бы сделал примерно так:

бесконечный цикл do{/*тут считываем выражение и разбираем его*/}while(/*проверка условия завершения цикла*/);

1) само выражение, которое нужно подсчитать я бы считывал в строку типа string(примеры использования)

2) после ввода, проверить чтобы в строке присутствовали только символы '0', ..., '9', '+', '-', '*', '/'. (если есть иные символы - выдать ошибку и перезапросить строку)

или входная строка есть завершающая последовательность(например "quit") - перейти к шагу 6.

3) разбить строку на компоненты вида [-]0..9, '+', '-', '*', '/'. компоненты поместить в двусвязный список.
получится последовательность вида: [число]-[мат. оператор]-[число]- ... - [число]

4) пройтись по списку и произвести операции... сделать, очевидно, нужно 2 прохода - в первом произвести умножение и деление, во втором - сложение и вычитание.

одна операция - это 3 элемента списка: 2 числа и оператор между ними
т.е. после вычисления операции в список вместо [число]-[оператор]-[число] нужно будет подставить результат вычисления операции, т.е. [число]

для преобразования строки в число можно использовать atof.

повторять пункт 4. пока в списке не останется 1 элемент, который и будет результатом вычислений

5) вывести результат и вернуться к шагу 1.

6) завершить программу


как то так наверно это всё нужно сделать...


п.с. если условием является использование ООП парадигмы, то пункты 2-4 можно оформить в один класс, который в качестве параметра конструктора будет принимать считанную строку и иметь метод, который будет вычислять результат...


какой-то такой велосипедик у меня в голове получился полвторого ночи)
297
22 июня 2010 года
koodeer
1.2K / / 02.05.2009
Добавлю пару советов-ссылок от себя.
Чтобы ваш калькулятор мог вычислять выражения типа 3+8*9/15, логично реализовать обратную польскую запись: ссылка1, ссылка2.
60K
22 июня 2010 года
Anastassija
5 / / 21.06.2010
Цитата: Norgat


3) разбить строку на компоненты вида [-]0..9, '+', '-', '*', '/'. компоненты поместить в двусвязный список.
получится последовательность вида: [число]-[мат. оператор]-[число]- ... - [число]

4) пройтись по списку и произвести операции... сделать, очевидно, нужно 2 прохода - в первом произвести умножение и деление, во втором - сложение и вычитание.

одна операция - это 3 элемента списка: 2 числа и оператор между ними
т.е. после вычисления операции в список вместо [число]-[оператор]-[число] нужно будет подставить результат вычисления операции, т.е. [число]


п.с. если условием является использование ООП парадигмы, то пункты 2-4 можно оформить в один класс, который в качестве параметра конструктора будет принимать считанную строку и иметь метод, который будет вычислять результат...






Спасибо за совет)))) Как это все примерно должно работать я себе как раз представляю, а вот как это написать, уже проблематично, т.к. я вообще С++ увидела месяц назад и что-то все очень трудно идет....


Я не понимаю, как сделать пункты 3 и 4...это хоть примерно похоже на то, что я написала??

И что такое ООП парадигмы?? Мне в идеале надо сделать класс списка, не в идеале нужен хоть один какой угодно класс....

60K
22 июня 2010 года
Anastassija
5 / / 21.06.2010
Цитата: koodeer
Добавлю пару советов-ссылок от себя.
Чтобы ваш калькулятор мог вычислять выражения типа 3+8*9/15, логично реализовать обратную польскую запись: ссылка1, ссылка2.




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

14K
22 июня 2010 года
artem_kvadro
63 / / 30.07.2007
[QUOTE="Anastassija"]Обратную польскую запись я уже смотрела, но опять же там все сохраняется в стэк и я не представляю как сохранить это все в двусвязанный список[/QUOTE]

Можно использовать приоритетную очередь на основе двусвязного списка:
 
Код:
priority_queue<MyOperation, deque<MyOperation>>
Это Вам и по условию задания должно подходить и еще операции будут отсортированы по приоритетам. Только тогда для каждой операции нужно определить приоритет, а для класса MyOperation нужно будет определить оператор <. Еще класс MyOperation должен иметь информацию о двух своих операндах. Примерно так в двух словах... Кстати, в выражении может встречаться унарный - и + .
2.1K
22 июня 2010 года
Norgat
452 / / 12.08.2009
Цитата: artem_kvadro
Можно использовать приоритетную очередь на основе двусвязного списка...


кстати да, тогда можно сделать будет всего 1 проход... но код это усложнит)

Цитата: artem_kvadro
Кстати, в выражении может встречаться унарный - и + .


про + можно невзначай забыть, а - всегда относить к числу, заменяя его в очереди операций сложением.

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

14K
22 июня 2010 года
artem_kvadro
63 / / 30.07.2007
В студенческие годы в качестве упражнения делал похожую вещь. Только у меня калькулятор был немного сложнее: в выражениях еще допускались скобки и функции. Деталей уже не помню, все было как-то коряво. Возможно, сейчас реализовал бы это покрасивее, но тогда было у меня два контейнера: один с операндами, а другой - с операциями (приоритетная очередь). Операция содержала ссылку на свой левый операнд, т.е. индекс элемента в контейнере с операндами. В первый проход парсер распихивал все по контейнерам. Во втором проходе из очереди доставались операции, выполнялись, а результат записывался опять в контейнер операндов. Вот такой велосипед изобретал :rolleyes:

[QUOTE="Norgat"]про + можно невзначай забыть, а - всегда относить к числу, заменяя его в очереди операций сложением.[/QUOTE]
Да, я просто к тому, что нужно это учитывать хотя бы на уровне парсера. Не помню почему, но я добавлял 0 перед унарной операцией.

З.Ы. Пороюсь сегодня в старых дисках, может и найду этот говнокод :) Тогда выложу, если интересно будет.
2.1K
22 июня 2010 года
Norgat
452 / / 12.08.2009
Цитата: artem_kvadro
В студенческие годы в качестве упражнения делал похожую вещь. Только у меня калькулятор был немного сложнее: в выражениях еще допускались скобки и функции. Деталей уже не помню, все было как-то коряво. Возможно, сейчас реализовал бы это покрасивее, но тогда было у меня два контейнера: один с операндами, а другой - с операциями (приоритетная очередь). Операция содержала ссылку на свой левый операнд, т.е. индекс элемента в контейнере с операндами. В первый проход парсер распихивал все по контейнерам. Во втором проходе из очереди доставались операции, выполнялись, а результат записывался опять в контейнер операндов. Вот такой велосипед изобретал :rolleyes:


что то оно как то не логично делать две очереди)
вроде ж всё можно в одну упихать и хранить в строках, а при проведении операции гонять туда-сюда преобразованиями строка->число и обратно (оно конечно не ахти как круто, но мы тут и не калькуляторы National Instruments делаем:D)


Цитата: artem_kvadro
Да, я просто к тому, что нужно это учитывать хотя бы на уровне парсера. Не помню почему, но я добавлял 0 перед унарной операцией.

З.Ы. Пороюсь сегодня в старых дисках, может и найду этот говнокод :) Тогда выложу, если интересно будет.



ну я вот что то набросал на больную голову... вообщем парсинг строки выражения:

Код:
#include <iostream>
#include <conio.h>
#include <deque>
#include <string>

using namespace std;

class calculator
{
private:
    deque<string> term;
public:
    calculator(string& str)
    {
        string buffer = "";
        if((str[0]!= '*') && (str[0]!= '/') && (str[0]!= '+'))
        {
            buffer += str[0];
            for(int i = 1;i < str.length(); ++i)
            {
                if((str!= '*') && (str!= '/') && (str!= '+') && (str!= '-'))
                    buffer += str;
                else
                    if(str == '-')
                    {
                        if((term.back()[0] == '*') || (term.back()[0] == '+') || (term.back()[0] == '/'))
                            buffer += '-';
                        else
                        {
                            term.push_back(buffer);
                            buffer.clear();
                            term.push_back("+");
                            buffer += '-';
                        }
                    }
                    else
                    {
                        term.push_back(buffer);
                        buffer = str;
                        term.push_back(buffer);
                        buffer.clear();
                    }
            }
            term.push_back(buffer);
        }
        else
            cerr << "Error parsing\n";
    }
    void print_deq()
    {
        deque<string>::iterator I = term.begin();
        while(I!= term.end())
        {
            cout << I->data() << endl;
            ++I;
        }
    }
};

void main()
{
    string str;
    cout << "Enter term: ";
    cin >> str;

    calculator C(str);
    C.print_deq();

    _getch();
}


правда он далеко не идеален:
- пробелы вставлять крайне не рекомендуется;
- нет проверки входной строки на недопустимые символы;


п.с. Итератор
60K
22 июня 2010 года
Anastassija
5 / / 21.06.2010
Спасибо всем! Поняла, что зря спрашивала...
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог