Решатель инфиксного уравнения c ++ - PullRequest
2 голосов
/ 27 февраля 2012

Я создаю решатель проблем с инфиксами, и он завершается в последнем цикле while, чтобы завершить последнюю часть уравнения.

Я вызываю последний цикл while в main, чтобы решить, что осталось в стеке, и он зависает там, и если я вытолкну последний элемент из стека, он выйдет из цикла и вернет неправильный ответ.

//
//
//
//
//
#include <iostream>
#include<stack>
#include<string>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
using namespace std;
#define size 30
int count=0;
int count2=0;
int total=0;
stack< string > prob;
char equ[size];
char temp[10];
string oper;
string k;
char t[10];
int j=0;
char y;


   int solve(int f,int s, char o)
   {
  cout<<"f="<<f<<endl;
  cout<<"s="<<s<<endl;
  cout<<"o="<<o<<endl;
  int a;
  if (o== '*')//checks the operand stack for operator
  {
    cout << f << "*" << s << endl;
    a= f*s;
  }
  if (o == '/')//checks the operand stack for operator
  {
    cout << f << "/" << s << endl;
    if(s==0)
    {
      cout<<"Cant divide by 0"<<endl;
    }
    else
      a= f/s;
  }
  if (o == '+')//checks the operand stack for operator
  {
    cout << f << "+" << s << endl;
    a= f+s;
  }
  if (o == '-')//checks the operand stack for operator
  {
    cout << f << "-" << s << endl;
    a= f-s;
  }
  return a;
}



int covnum()
{
  int l,c;
  k=prob.top();
  for(int i=0;k[i]!='\n';i++)t[i]=k[i];
  return l=atoi(t);
}


char covchar()
{
  k=prob.top();
  for(int i=0;k[i]!='\n';i++)t[i]=k[i];
  return t[0];
}


void tostring(int a)
{
  stringstream out;
  out << a;
  oper = out.str();
}


void charstack(char op)
{
  oper=op;
  prob.push(oper);
}


void numstack(char n[])
{
  oper=n;
  prob.push(oper);
}

void setprob()
{
  int f,s;
  char o;
  char t;
  int a;
  int i;
  t=covchar();
  if(ispunct(t))
  {
    if(t=='(')
    {
      prob.pop();
    }
    if(t==')')
    {
      prob.pop();
    }
    else if(t=='+'||'-')
    {
      y=t;
      prob.pop();
    }
    else if(t=='/'||'*')
    {
      y=t;
      prob.pop();
    }
  }
  cout<<"y="<<y<<endl;
  i=covnum();
  cout<<"i="<<i<<endl;
  s=i;
  prob.pop();
  t=covchar();
  cout<<"t="<<t<<endl;
  if(ispunct(t))
  {
    o=t;
    prob.pop();
  }
  i=covnum();
  cout<<"i="<<i<<endl;
  f=i;
  prob.pop();
  t=covchar();
  if (t=='('||')')
  {
    prob.pop();
  }
  a=solve(f,s, o);
  tostring(a);
  prob.push(oper);
  cout<<"A="<<prob.top()<<endl;
}


void postfix()
{
  int a=0;
  char k;
  for(int i=0;equ[i]!='\0';i++)
  {
    if(isdigit(equ[i]))//checks array for number
    {
      temp[count]=equ[i];
      count++;
    }
    if(ispunct(equ[i]))//checks array for operator
    {
      if(count>0)//if the int input is done convert it to a string and push to stack
      {
        numstack(temp);
        count=0;//resets the counter
      }
      if(equ[i]==')')//if char equals the ')' then set up and solve that bracket
      {
        setprob();
        i++;//pushes i to the next thing in the array
        total++;
      }
      while(equ[i]==')')//if char equals the ')' then set up and solve that bracket
      {
        i++;
      }
      if(isdigit(equ[i]))//checks array for number
      {
        temp[count]=equ[i];
        count++;
      }
      if(ispunct(equ[i]))
      {
        if(equ[i]==')')//if char equals the ')' then set up and solve that bracket
        {
          i++;
        }
        charstack(equ[i]);
      }
      if(isdigit(equ[i]))//checks array for number
      {
        temp[count]=equ[i];
        count++;
      }
    }
  }
}



int main()
{
  int a=0;
  char o;
  int c=0;

  cout<<"Enter Equation: ";
  cin>>equ;
  postfix();
  while(!prob.empty())
  {
    setprob();
    a=covnum();
    cout<<a<<" <=="<<endl;
    prob.pop();
    cout<<prob.top()<<"<top before c"<<endl;
    c=covnum();
    a=solve(c,a,y);
  }
  cout<<"Final Awnser"<<a<<endl;
  system ("PAUSE");
  return 0;
}

Ответы [ 2 ]

3 голосов
/ 27 февраля 2012

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

Пример:

for(int i=0;k[i]!='\n';i++)

k является примеромстанд :: строка.std :: string не заканчивается нулем.Он отслеживает длину строки, поэтому вы должны сделать что-то вроде этого:

for(int i=0;i<k.size();i++)

Это более простой вид ошибок, но я также вижу некоторые ошибки в общей логике.Например, ваш токенайзер (постфиксная функция) не обрабатывает случай, когда последняя часть выражения является операндом.Я не уверен, является ли это разрешенным условием, но это то, что должен решать инфикс-решатель (и я рекомендую переименовать эту функцию во что-то вроде токенизации, поскольку очень сложно иметь функцию с именем 'postfix' для решателя инфиксов).

Прежде всего, я советую вам внести некоторые общие изменения в ваш подход.

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

  2. Не используйте глобальные переменные длярешить эту проблему.Может показаться заманчивым избегать раздачи вещей повсюду, но вы будете усложнять выполнение # 1, а также ограничиваете универсальность своего решения.То небольшое время, которое вы сэкономили, не передавая переменные, легко обойдется вам гораздо дороже, если вы ошибетесь.Вы также можете взглянуть на создание класса, который хранит некоторые из этих вещей как переменные-члены, которые вы можете избежать передачи в методах класса, но особенно для временных состояний, таких как 'equ', которые вам даже не нужны после токенизации, просто передайтеэто в необходимую функцию токенизации и покончить с этим.

  3. инициализируйте ваши переменные, как только сможете (в идеале, когда они будут определены впервые).Я вижу много устаревших практик в стиле C, когда вы объявляете все свои переменные в верхней части области видимости.Постарайтесь ограничить область, в которой вы используете переменные, и это сделает ваш код более безопасным и легче будет исправить.Это связано с избеганием глобальных переменных (# 2).

  4. Предпочитайте альтернативы макросам, когда можете, а когда нет, используйте BIG_UGLY_NAMES, чтобы отличать их от всего остального.Использование #define для создания определения препроцессора для «size» фактически не позволяет приведенному выше коду с помощью строкового метода «size» работать.Это может и должно быть простой интегральной константой, или, что еще лучше, вы можете просто использовать std :: string для 'equ' (кроме того, что это не глобальная область видимости файла).

  5. Предпочитайте стандартные заголовки библиотеки C ++, когда можете.<ctype.h> должно быть <cctype>, <stdlib.h> должно быть <cstdlib>, а <stdio.h> должно быть <stdio>.Смешивание нестандартных заголовков с расширением .h и стандартными заголовками в одном и том же модуле компиляции может вызвать проблемы в некоторых компиляторах, и вы также упустите некоторые важные вещи, такие как определение пространства имен и перегрузка функций.

Наконец, не торопитесь с решением и вложите в него немного заботы и любви.Я понимаю, что это домашнее задание, и вы находитесь в крайнем сроке, но вы столкнетесь с еще более жесткими сроками в реальном мире, где такого рода кодирование просто не будет приемлемым.Назовите ваши идентификаторы правильно, четко отформатируйте код, документируйте, что делают ваши функции (а не только то, как работает каждая строка кода, что вам на самом деле не следует делать намного позже, так как вы лучше понимаете язык).Некоторое кодирование TLC займет у вас долгий путь.Действительно подумайте о том, как спроектировать решения проблемы (если мы применяем процедурный подход, разложите проблему на процедуры как общие единицы работы, а не просто нарезанную версию вашей общей логики).# 2 поможет с этим.

** Пример: вместо функции с именем 'postfix', которая работает с некоторой глобальной входной строкой и манипулирует некоторым глобальным стеком и частично вычисляет выражение, заставляет его принимать входную строку и возвращать * отдельные токены. Теперь это общая функция, которую вы можете повторно использовать где угодно, и вы также сократили ее до гораздо более простой задачи для решения и тестирования. Документируйте это и назовите это так же, сосредотачиваясь на использовании и том, что это принимает и возвращает. Например:

// Tokenize an input string. Returns the individual tokens as
// a collection of strings.
std::vector<std::string> tokenize(const std::string& input);

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

2 голосов
/ 27 февраля 2012

Я вижу ряд вещей, которые, вероятно, способствуют тому, что он не работает:

  • Нет проверки ошибок или границ.Я понимаю, что это домашнее задание и, как таковое, может иметь особые требования / спецификации, которые устраняют необходимость в некоторых проверках, но вам все еще нужны некоторые, чтобы убедиться, что вы правильно анализируете входные данные.Что если вы превысите размер массива equ / tmp / t?Что делать, если ваш стек пуст, когда вы пытаетесь его открыть / сверху?
  • Есть несколько операторов if, которые выглядят как else if (t == '+' || '-'), что, скорее всего, не делает то, что вы от них хотите.Это выражение на самом деле всегда истинно, поскольку '-' не равно нулю и преобразуется в истинное значение.Вы, вероятно, хотите else if (t == '+' || t == '-').
  • Насколько я могу судить, кажется, вы пропускаете синтаксический анализ или добавляете в стек '('), что делает невозможным правильную оценку выражения.
  • У вас есть цикл while в середине postfix(), который пропускает несколько символов ')', но ничего не делает.
  • Ваш код очень сложен для отслеживания.Правильное присвоение имен переменным и функциям и устранение большинства глобальных переменных (в действительности вам не нужно большинство из них) очень помогло бы, как и правильное отступление, и добавило бы несколько пробелов в выражениях.
  • Существуют и другие незначительные проблемыособо не стоит упоминать.Например, функции covchar () и covnum () гораздо более сложны, чем нужно.

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

...