Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Разбор математического выражения


Anton_112 ©   (2006-05-14 01:05:00) 

Задача - пользователь вводит выражение, необходимо представить его в памяти в виде двоичного дерева.
Думаю, несложно будет сделать вызывая рекурсивно процедуру добавления узла для каждого действия. В корне дерева должно находиться действие, которое при вычислении будет выполнено последним. Возникла трудность, как найти в выражении это действие. В идеале - его позицию в строке.
например:
28+3*2-(7+14)*12/3+79
при разборе должно указать на последний плюс.
28+3*2-(7+14)*12/3 +79


atruhin   (2006-06-20 05:55:00) [1]

> Соотвественно, какой плюс выполнится последним - зависит
> от алгоритма разбора.

Это преобразование выражения. Алгоритм разбора должен выдавать оригинальный порядок.


TUser   (2006-06-20 03:30:00) [2]

1+2+3 может быть записано как 1 2 + 3 + или как 2 3 + 1 +. Соотвественно, какой плюс выполнится последним - зависит от алгоритма разбора.


Германн   (2006-06-20 02:23:00) [3]


> Не должно, а может - одно и тоже выражение можно записать
> в виде разных обратных польских записей.


Объясни, пожалуйста. Что, как и почему?


TUser   (2006-06-19 12:49:00) [4]


> Возник вопрос - можно смело полагать ,что действие, оказавшееся
> в обратной польской записи последним, и должно выполняться
> последним в выражении?

Не должно, а может - одно и тоже выражение можно записать в виде разных обратных польских записей.


Joker007   (2006-06-19 12:22:00) [5]

Было бы неплохо :-)))


Германн   (2006-06-19 02:16:00) [6]


> Joker007   (18.06.06 23:23) [11]
>
> Если вы еще тут, не могли бы вы рассказать поподробнее о
> работе своей программки – что происходит с выражением после
> того, как пользователь вводит выражение.


А рассказать нужно "с выражением"? :-)


Joker007   (2006-06-18 23:23:00) [7]

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


StymPunk   (2006-05-31 23:54:00) [8]


> Anton_112


Здравствуйте,
Вы не могли бы скинуть мне свою програмку на мыло? :-)


Anton_112   (2006-05-15 15:24:00) [9]

Спасибо, я сам придумал похожий алгоритм, но этот выглядит "элегантнее".
Благодарю.


Жуков Олег   (2006-05-15 02:56:00) [10]


> Anton_112   (15.05.06 02:26) [7]

Там всё просто - идём по строке от последнего символа к первому, как только встречаем знак '-' или '+' вне скобок (это соответсвует BracketCount = 0),  значит всё, что справа - Expression2, а всё что слева - Expression1 (кстати, можно оптимизировать код по скорости, если Expression2 выделять именно в этот момент, а не прибавлять посимвольно на каждом витке цикла). Тогда разбор строки завершается, запоминается действие, и дальнейший разбор поручается дочерним Operand1 и Operand2,. Если же в первом проходе не обнаружено знаков '+' или '-', запускается второй такой-же проход, в котором точно так же ищется уже знак '*' или '/' (PassNumber=2, здесь тоже можно ускорить, если запоминать позицию знака в дополнительную переменную в первом проходе, тогда можно обойтись одним проходом). Ну а дальше дочерние операнды сами разруливают переданные им выражения, и строят дерево вниз. Если в строке не обнаружено знаков '+', '-', '*', '/', то считается, что это просто число. Ещё там можно выкинуть Completed, его проверка заменяется на  FStyle = osExpression.


Anton_112   (2006-05-15 02:26:00) [11]

Увы, реализовал его с использованием стека ,и на одной из простых проверок он выдал неверный результат... Хотелось бы закончить самаому, но время поджимает, поэтому вопрос к Жукову Олегу, не могли бы вы словами хотя бы вкратце рассказть как разделяете строку с выражением на OperandExpression1 и OperandExpression2? Просмотрев исходник я боюсь что не до конца понял ваш подход.
P.S: Извините за настойчивость


Германн   (2006-05-15 01:15:00) [12]


> Возник вопрос - можно смело полагать
> ,что действие, оказавшееся
> в обратной польской записи последним, и должно выполняться
> последним в выражении? Просто этот алгоритм раньше был мне
> неизвестен, и пока что я не смог до конца понять его.


Этот алгоритм - "классика  жанра". Так что можно "смело полагаться на него", но вот на конкретную реализацию полагаться не следует. Её нужно тщательно проверять.


Anton_112   (2006-05-15 00:26:00) [13]

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


TUser   (2006-05-14 07:28:00) [14]

http://algolist.manual.ru/syntax/index.php


Жуков Олег   (2006-05-14 03:40:00) [15]

Показалось интересным, написал - вычисление выражения с помощью двоичного дерева. Причесать, выловить глюки и можно сдавать:
type
 TOperandStyle = (osNumber, osExpression);

 TOperand = class
 private
   FStyle: TOperandStyle;
   FValue: Extended;
   FOperand1: TOperand;
   FOperand2: TOperand;
   FAction: Char;
 protected
   function GetValue(): Extended;
 public
   property Value: Extended read GetValue write FValue;

   constructor Create(Expression: string);
   destructor Destroy(); override;

 end;

{ TOperand }

function TOperand.Getvalue(): Extended;
begin
 if FStyle = osNumber then
   Result := FValue
 else
   case FAction of
     '+': Result := FOperand1.Value + FOperand2.Value;
     '-': Result := FOperand1.Value - FOperand2.Value;
     '*': Result := FOperand1.Value * FOperand2.Value;
     '/': Result := FOperand1.Value / FOperand2.Value;
   else
     raise Exception.Create('Unknown action.');
   end;
end;

constructor TOperand.Create(Expression: string);
var
 Index: Integer;
 BracketCount: Integer;
 OperandExpression1, OperandExpression2: string;
 PassNumber: Integer;
 Completed : Boolean;
begin
 inherited Create();
 FStyle := osNumber;
 Expression := Trim(Expression);
 if Expression[1] = '(' then
   if Pos(')', Expression) = Length(Expression) then
     Expression := Copy(Expression, 2, Length(Expression) - 2);

 Completed := False;
 PassNumber := 1;

 while (PassNumber <= 2) and not Completed do
 begin
   BracketCount := 0;
   OperandExpression1 := '';
   OperandExpression2 := '';
   Index := Length(Expression);
   while (Index > 0) and not Completed do
   begin

     case Expression[Index] of
       ')':
       begin
         Inc(BracketCount);
       end;

       '(':
       begin
         Dec(BracketCount);
       end;

       '+', '-', '*', '/':
       if (BracketCount = 0)
         and ((Expression[Index] in ['+', '-']) or (PassNumber = 2)) then
       begin
         FStyle := osExpression;
         FOperand2 := TOperand.Create(OperandExpression2);
         OperandExpression1 := Copy(Expression, 1, Index - 1);
         FOperand1 := TOperand.Create(OperandExpression1);
         FAction := Expression[Index];
         Completed := True;
       end;

     end;

     OperandExpression2 := Expression[Index] + OperandExpression2;
     Dec(Index);

   end; // while Index < Length(s) do

   Inc(PassNumber);
 end;

 if FStyle = osNumber then
 begin
   FValue := StrToFloat(Expression);
 end;

end;

destructor TOperand.Destroy();
begin
 if Assigned(FOperand1) then
   FOperand1.Destroy();
 if Assigned(FOperand2) then
   FOperand2.Destroy();
 inherited;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 Operand: TOperand;
begin
 Operand := TOperand.Create(Edit1.Text);
 try
   Edit2.Text := FloatToStr(Operand.Value);
 finally
   Operand.Free();
 end;
end;


Anton_112   (2006-05-14 02:08:00) [16]

Спасибо, думаю это мне поможет. Я и начал с google, но не знал как сформулировать запрос :)


Германн   (2006-05-14 01:45:00) [17]

Ищи в гугле или яндексе "обратная польская запись" и да прибудет тебе успех.


Наверх

Титульная страница Поиск, карта сайта Написать письмо