Задание по C#
| |
gorlumfan | Дата: Четверг, 09 Октября 2014, 01:20 | Сообщение # 1 |
участник
Сейчас нет на сайте
| Перейду сразу к сути вопроса. Есть задание: тебе вводят арифметическое выражение в целых числах со скобками. Ты должен вывести результат.
Например, вводят: 3*(8-(9-3)+2*2)+1 Ты выводишь: 19
тебе вводят произвольное выражение, а ты его разбираешь и выводишь ответ. Вводят с клавиатуры, во время работы программы, через Console.ReadLine. Заранее ты выражение не знаешь, и в код программы подставить не можешь.
Честно говоря мыслей по поводу этой задачи не много. Лично я себе это представляю как. Вводим уравнение, записываем его в массив, в нем разбиваем на элементы. И уже после этого начинаем расчет. Если есть у кого какие либо идеи по этому поводу, буду рад услышать.
|
|
| |
HPlusDiese | Дата: Четверг, 09 Октября 2014, 02:14 | Сообщение # 2 |
участник
Сейчас нет на сайте
| Цитата gorlumfan ( ) Лично я себе это представляю как. Вводим уравнение, записываем его в массив, в нем разбиваем на элементы. И уже после этого начинаем расчет. Почти верно. Тебе нужна либа для парсинга или самому всё сделать нужно?
|
|
| |
Lertmind | Дата: Четверг, 09 Октября 2014, 09:17 | Сообщение # 3 |
заслуженный участник
Сейчас нет на сайте
| Самый простой способ преобразовать в обратную польскую нотацию и посчитать. Она может быть неявно в алгоритме. Почти готовый код на C++ здесь. Ещё можно написать простой калькулятор без скобок, потом внутренние выражения в скобках заменять посчитанными значения, например 3*(8-(9-3)+2*2)+1 => 3*(8-6+2*2)+1 => 3*6 + 1 => 19, но это хреновый способ в плане производительности.
|
|
| |
ZnOFF | Дата: Четверг, 09 Октября 2014, 09:28 | Сообщение # 4 |
частый гость
Сейчас нет на сайте
| Есть ещё способ - "компиляция на лету". Компилятор сам всё это может посчитать. Зачем за него мозг напрягать?
|
|
| |
gorlumfan | Дата: Четверг, 09 Октября 2014, 11:02 | Сообщение # 5 |
участник
Сейчас нет на сайте
| Короче говоря, это точно не парсер. Как объяснил мой учитель, это "Задание чисто на манипулирование строками и данными, которые ты сам создаешь." Ребят не как не пойму как это реализовать, хоть направление дайте в котором капать ) Добавлено (09.10.2014, 11:02) ---------------------------------------------
Цитата ZnOFF ( ) Есть ещё способ - "компиляция на лету". Компилятор сам всё это может посчитать. Зачем за него мозг напрягать? Можно поподробнее про это ?)
|
|
| |
Vinchensoo | Дата: Четверг, 09 Октября 2014, 11:17 | Сообщение # 6 |
Злобный социопат с комплексом Бога
Сейчас нет на сайте
| Цитата gorlumfan ( ) Короче говоря, это точно не парсер. Как объяснил мой учитель, это "Задание чисто на манипулирование строками и данными, которые ты сам создаешь." Ребят не как не пойму как это реализовать, хоть направление дайте в котором капать ) Это и есть парсер. Лол. http://habrahabr.ru/post/199266/
|
|
| |
HPlusDiese | Дата: Четверг, 09 Октября 2014, 11:26 | Сообщение # 7 |
участник
Сейчас нет на сайте
| Цитата gorlumfan ( ) хоть направление дайте в котором капать ) Сначало приводищь выражение к обратной польской записи, потом на простейшей стековой машине считаешь. Научись уже гуглить.
Сообщение отредактировал HPlusDiese - Четверг, 09 Октября 2014, 11:27 |
|
| |
KamiRonin | Дата: Четверг, 09 Октября 2014, 11:48 | Сообщение # 8 |
почти ветеран
Сейчас нет на сайте
| пример на разных языках для ОПН
Мыслю - значит программирую... Конструктивная критика - умных ведет к совершенству... Великие умы обсуждают идеи, средние - обсуждают поступки, а малые - людей.
|
|
| |
gorlumfan | Дата: Пятница, 10 Октября 2014, 08:15 | Сообщение # 9 |
участник
Сейчас нет на сайте
| Всем спасибо за помощь, но как сказал человек давший мне задание. Делаться это должно проще, чем эти 2 метода. Пока копаю дальше, может что пропустил.
|
|
| |
Lertmind | Дата: Пятница, 10 Октября 2014, 12:01 | Сообщение # 10 |
заслуженный участник
Сейчас нет на сайте
| Цитата gorlumfan ( ) но как сказал человек давший мне задание. Делаться это должно проще, чем эти 2 метода. Плохой учитель у тебя, БЕГN. А вообще, раз он знает лучше, пусть тебе лучше и объяснит чего хочет.
|
|
| |
gorlumfan | Дата: Вторник, 04 Ноября 2014, 01:53 | Сообщение # 11 |
участник
Сейчас нет на сайте
| Ребят после продолжительной читалки книжек и сети + советы учителя написал следующий код. Код рабочий все правильно делает. И спасибо кстати за подсказку относительно польской нотации, сразу не разобрал что к чему. Так вот собственно вопрос, программа считывает пример -> преобразует его в ОПН -> затем считает. Но проблема в том, что лишь по 1 символу. Как можно с этим побороться ? Если это поможет то вот мой код Код using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string m = Console.ReadLine(); Console.WriteLine("Эта же запись но в посфиксном виде " + Postfix(m)); Console.WriteLine("Ответ " + Equal(Postfix(m))); Console.ReadLine();//Задержка экрана } // //Функция превращения строки в постфиксную запись static string Postfix(string Input) { var MyStack = new Stack<char>();//Объявлен стек для операций string x = null; int y; //Цикл превращение строки в постфиксную for (int i = 0; i < Input.Length; i++) {
if (Char.IsDigit(Input[i]))//Проверяем входной символ, если число { x += Convert.ToString(Input[i]); } else //Если символ, производим его разбор { y = Prior(Input[i]);// Назначаем приоритет для входящего символа if (MyStack.Count == 0) //Если стек пустой { MyStack.Push(Input[i]);//Закидываем знак в стек } else //Если стек имеет какие либо значения { if (y != Prior(MyStack.Peek()))//Если символы по приоритету не ровны { if (y > Prior(MyStack.Peek()))//Если приоритет входящего символа больше имеющегося { MyStack.Push(Input[i]); } else if (y < Prior(MyStack.Peek())) {
if (y == 2) //Если символ является закрывающей скобкой { if (MyStack.Peek() == '(') //Если на вершине стека находится открывающая скобка { MyStack.Pop(); } else if (MyStack.Peek() != '(') //Если не равен открывающей скобке { while (MyStack.Peek() != '(')//Пока на вершине стека не будет открывающей скобки, { x += MyStack.Pop(); //Выталкиваем в строку символы } MyStack.Pop(); } } else { if (y == 1) //Если равен открывающей скобке { MyStack.Push(Input[i]); } else { x += MyStack.Pop(); MyStack.Push(Input[i]); }
} } } else if (y == Prior(MyStack.Peek()))//Если символы ровны { x += MyStack.Pop();//Из вершины стека выкидываем символ в строку MyStack.Push(Input[i]);//Кладем в стек новый символ }
} }
} while (MyStack.Count > 0)//Выкидываем остаток символов из стека { x += MyStack.Pop(); } return x;//Возвращаем строку в постфиксной записи }
// //Функция подсчета static int Equal(string Input) { var MyStack = new Stack<int>(); int a = 0, b = 0; for (int i = 0; i < Input.Length; i++) { if (Char.IsDigit(Input[i]))//Если число то, { MyStack.Push(CharsToInt(Input[i])); } else //иначе { Console.WriteLine("В стаке кол-во элементов " + MyStack.Count); a = MyStack.Pop();//Выкидываем первое число Console.WriteLine("Первое число " + a); b = MyStack.Pop();//Выкидываем второе число Console.WriteLine("Второе число " + b);
switch (Input[i])//Переключатель для определения действий над числами { //Модуль возведения в степень не работает правильно (работает только с положительными числами) case '^': Console.WriteLine("Знак операции ^"); a = Convert.ToInt32(Math.Pow(a, b)); Console.WriteLine("Значение x " + a); MyStack.Push(a); break; case '*': Console.WriteLine("Знак операции *"); a = b * a; Console.WriteLine("Значение x " + a); MyStack.Push(a); break; case '/': Console.WriteLine("Знак операции /"); if (a == 0) { a = 0; } else { a = b / a; } Console.WriteLine("Значение x " + a); MyStack.Push(a); break; case '+': Console.WriteLine("Знак операции +"); a = b + a; Console.WriteLine("Значение x " + a); MyStack.Push(a); break; case '-': Console.WriteLine("Знак операции -"); a = b - a; Console.WriteLine("Значение x " + a); MyStack.Push(a); break; } } } return a; }
//Функция обработки числа из char в int static int CharsToInt(char Input) { int x = 0, y = 0; //кол-во итераций в данном случае равно a.Length
x = Input - '0'; //Переводит из char в int число справа на левово y = y * 10 + x;
return y; }
// //Функция обработки числа из char[] в int static int CharsArrToInt(char[] Input) { int x = 0, y = 0; //кол-во итераций в данном случае равно a.Length for (int power = 0; power < Input.Length; power++) //Цикл обработки числа из Char в Int { x = (Input[power] - '0'); //Переводит из char в int число справа на левово y = y * 10 + x; } return y; } // //Функция приоритета знаков static int Prior(char Input) { switch (Input) //Получаем на входе символ, и возвращаем его приоритет. { case '^': return 6; case '*': return 5; case '/': return 5; case '+': return 4; case '-': return 4; case '=': return 3; case ')': return 2; case '(': return 1; default: return 0; }
} } }
Сообщение отредактировал gorlumfan - Вторник, 04 Ноября 2014, 01:59 |
|
| |
Lertmind | Дата: Вторник, 04 Ноября 2014, 06:20 | Сообщение # 12 |
заслуженный участник
Сейчас нет на сайте
| В string Postfix(string Input) внутри if (Char.IsDigit(Input[i])) {} записать: Код if (i > 0 && !Char.IsDigit(Input[i - 1])) x += " "; x += Convert.ToString(Input[i]); Тогда в постфиксной записи будут пробелы между числами, например для "(10+1)*23" будет " 10 1+ 23*".
В int Equal(string Input) объявляем переменную string number = ""; и вместо if (Char.IsDigit(Input[i])) {} else { записать: Код if (Char.IsDigit(Input[i]))//Если число то, { number += Input[i]; if (i + 1 == Input.Length || !Char.IsDigit(Input[i + 1])) { MyStack.Push(int.Parse(number)); number = ""; } } else if (Prior(Input[i]) > 0)//иначе { В number будет собираться число. Если следующий символ не цифра или конец строки, то добавляем в стек число (можешь написать свою функцию преобразования из строки в число вместо int.Parse(), хотя ты зачем-то уже написал CharsArrToInt() ). Проверка if (Prior(Input[i]) > 0) нужна, чтобы проходили только символы операций, а всякие пробелы и прочий мусор игнорировались.
Полный код (протестил только для (10+1)*23, должно работать для всего): Код using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string m = Console.ReadLine(); Console.WriteLine("Эта же запись но в посфиксном виде " + Postfix(m)); Console.WriteLine("Ответ " + Equal(Postfix(m))); Console.ReadLine();//Задержка экрана } // //Функция превращения строки в постфиксную запись static string Postfix(string Input) { var MyStack = new Stack<char>();//Объявлен стек для операций string x = null; int y; //Цикл превращение строки в постфиксную for (int i = 0; i < Input.Length; i++) {
if (Char.IsDigit(Input[i]))//Проверяем входной символ, если число { if (i > 0 && !Char.IsDigit(Input[i - 1])) x += " "; x += Convert.ToString(Input[i]); } else //Если символ, производим его разбор { y = Prior(Input[i]);// Назначаем приоритет для входящего символа if (MyStack.Count == 0) //Если стек пустой { MyStack.Push(Input[i]);//Закидываем знак в стек } else //Если стек имеет какие либо значения { if (y != Prior(MyStack.Peek()))//Если символы по приоритету не ровны { if (y > Prior(MyStack.Peek()))//Если приоритет входящего символа больше имеющегося { MyStack.Push(Input[i]); } else if (y < Prior(MyStack.Peek())) {
if (y == 2) //Если символ является закрывающей скобкой { if (MyStack.Peek() == '(') //Если на вершине стека находится открывающая скобка { MyStack.Pop(); } else if (MyStack.Peek() != '(') //Если не равен открывающей скобке { while (MyStack.Peek() != '(')//Пока на вершине стека не будет открывающей скобки, { x += MyStack.Pop(); //Выталкиваем в строку символы } MyStack.Pop(); } } else { if (y == 1) //Если равен открывающей скобке { MyStack.Push(Input[i]); } else { x += MyStack.Pop(); MyStack.Push(Input[i]); }
} } } else if (y == Prior(MyStack.Peek()))//Если символы ровны { x += MyStack.Pop();//Из вершины стека выкидываем символ в строку MyStack.Push(Input[i]);//Кладем в стек новый символ }
} }
} while (MyStack.Count > 0)//Выкидываем остаток символов из стека { x += MyStack.Pop(); } return x;//Возвращаем строку в постфиксной записи }
// //Функция подсчета static int Equal(string Input) { var MyStack = new Stack<int>(); int a = 0, b = 0; string number = ""; for (int i = 0; i < Input.Length; i++) { if (Char.IsDigit(Input[i]))//Если число то, { number += Input[i]; if (i + 1 == Input.Length || !Char.IsDigit(Input[i + 1])) { MyStack.Push(int.Parse(number)); number = ""; } } else if (Prior(Input[i]) > 0)//иначе { Console.WriteLine("В стаке кол-во элементов " + MyStack.Count); a = MyStack.Pop();//Выкидываем первое число Console.WriteLine("Первое число " + a); b = MyStack.Pop();//Выкидываем второе число Console.WriteLine("Второе число " + b);
switch (Input[i])//Переключатель для определения действий над числами { //Модуль возведения в степень не работает правильно (работает только с положительными числами) case '^': Console.WriteLine("Знак операции ^"); a = Convert.ToInt32(Math.Pow(a, b)); Console.WriteLine("Значение x " + a); MyStack.Push(a); break; case '*': Console.WriteLine("Знак операции *"); a = b * a; Console.WriteLine("Значение x " + a); MyStack.Push(a); break; case '/': Console.WriteLine("Знак операции /"); if (a == 0) { a = 0; } else { a = b / a; } Console.WriteLine("Значение x " + a); MyStack.Push(a); break; case '+': Console.WriteLine("Знак операции +"); a = b + a; Console.WriteLine("Значение x " + a); MyStack.Push(a); break; case '-': Console.WriteLine("Знак операции -"); a = b - a; Console.WriteLine("Значение x " + a); MyStack.Push(a); break; } } } return a; }
//Функция обработки числа из char в int static int CharsToInt(char Input) { int x = 0, y = 0; //кол-во итераций в данном случае равно a.Length
x = Input - '0'; //Переводит из char в int число справа на левово y = y * 10 + x;
return y; }
// //Функция обработки числа из char[] в int static int CharsArrToInt(char[] Input) { int x = 0, y = 0; //кол-во итераций в данном случае равно a.Length for (int power = 0; power < Input.Length; power++) //Цикл обработки числа из Char в Int { x = (Input[power] - '0'); //Переводит из char в int число справа на левово y = y * 10 + x; } return y; } // //Функция приоритета знаков static int Prior(char Input) { switch (Input) //Получаем на входе символ, и возвращаем его приоритет. { case '^': return 6; case '*': return 5; case '/': return 5; case '+': return 4; case '-': return 4; case '=': return 3; case ')': return 2; case '(': return 1; default: return 0; }
} } } Добавлено (04.11.2014, 06:20) --------------------------------------------- На самом деле, твой код не работает с унарным минусом ("-1" фейл). Ещё ты неправильно возводишь в степень, во-первых, надо записать a = Convert.ToInt32(Math.Pow(b, a));, во-вторых, возведение в степень правоассоциативная операция и для, например 2^2^3, должно быть 2^(2^3), а не (2^2)^3 как в твоей программе, опять же прочитай внизу здесь. Замечу, что для "0-2^2^3" должен быть результат -256, а для "(0-2)^2^3" уже 256 (если сделаешь унарный минус, то 0 приписывать не надо).
|
|
| |
gorlumfan | Дата: Вторник, 04 Ноября 2014, 13:20 | Сообщение # 13 |
участник
Сейчас нет на сайте
| Lertmind, Спасибо за разъяснение, как будет возможность обязательно попробую переделать )
|
|
| |
|