2013-03-13 14 views
9

Tło:Modelowanie manewrowaniem-Yard Algorytm

Próbuję zaimplementować wariant Shunting-Yard Algorithm, ale zamiast wyprowadzania wyrażenia w notacji RPN, chciałbym go zaktualizować się jako tokeny są wypychane w tak wyniki mogą być wyświetlane w czasie rzeczywistym (tak jakbyś naciskał przyciski na kalkulatorze i musiał aktualizować wyświetlacz po każdym przycisku).

Oto klasa Manewrowanie stoczni ...

public class ShuntingYard 
{ 
    private Stack<double> _operands; 
    private Stack<Operation> _operations; 

    public ShuntingYard() 
    { 
     this._operands = new Stack<double>(); 
     this._operations = new Stack<double>(); 
    } 
} 

I klasa Operation byłoby coś ...

public abstract class Operation 
{ 
    public abstract void Evaluate(Stack<double> operands, Stack<Operation> operations); 
} 

Funkcja Evaluate() aktualizuje Odpowiednio stosy, a " bieżąca wartość "to _operands.Peek()

Oto niektóre z" Operacji "jakie dotychczas miałem:

public class NullaryOperation : Operation { }
E.g. Pi, e, itp
Wystarczy popycha stała na _operands

public class UnaryOperation : Operation { }
Np SquareRoot, sinus, cosinus, itp
Pops jeden numer off _operands, ocenia, i popycha doprowadzić do _operands

public class BinaryOperation : Operation { }
Np +, -, *, /, itp
Kontrole pierwszeństwa, ocenia, jeśli to konieczne, popycha doprowadzić do _operands


Oto problem:
muszę zdolność do pchania open nawiasów ( i zamkniętej nawiasy ) na stos _operations jako część algorytmu. Co więcej, kiedy dodaję nawias zamknięty, muszę trzymać popping operandy/operacje, dopóki nie napotkam otwartego nawiasu.

chcę uniknąć kontroli tak (rodzaje kontroli Object):

while (operations.Peek().GetType() != typeof(OpenParen)) { ... }

chcę uniknąć dodawania metody takie jak to w Operation:

public abstract bool IsOpenParen();

mogłem zrobić coś takiego ...

public abstract class Operation 
{ 
    public enum OperationType { Nullary, Unary, Binary, OpenParen, CloseParen }; 
    public abstract OperationType GetOperationType() { }; 

    public abstract void Evaluate(Stack<double> operands, Stack<Operation> operations); 
} 

Jednak wymaganie, aby wszystkie podtypy określały ich typ jako wyliczenie, wydaje się złym projektem.


Jak mam to modelować w taki sposób, aby móc śledzić i obsługiwać nawiasy, gdy są wciskane?

Na marginesie: myślenie o nawiasach jako "Operacjach" nie ma dla mnie większego sensu. Jednak algorytm na Wikipedii traktuje je w ten sposób i nie mogę wymyślić żadnego innego sposobu na śledzenie ich pozycji względem innych "prawdziwych" operacji.

Dziękuję.

+1

Każdy powód, dla którego nie chcesz tworzyć parensów do zadań specjalnych w swoim projekcie, gdy wyraźnie potrzebujesz specjalnej obsługi ich w swojej aplikacji? Mam na myśli, jestem pewien, że mógłbyś * wymyślić jakąś abstrakcyjną koncepcję, więc nie jest to już specjalny przypadek, ale brzmi to jak nadmierne prześwietlenie, chyba że wiesz, że jest więcej konstruktów, którymi musisz się posługiwać w podobny sposób. – millimoose

+0

Nawiasy są niepotrzebne w notacji polskiej, zarówno do przodu, jak i do tyłu; są one wymagane tylko w notacji typu infix. –

+1

@PieterGeerkens Algorytm Shunting-Yard analizuje wyrażenie notacji infiksowej. RPN jest tylko jednym z możliwych wyjść. – millimoose

Odpowiedz

1
public class Operand { 
    private ShuntingYard sy; 
    private double d; 
    public Operand(double v) { 
     d=v; 
     sy=null; 
    } 
    public Operand() { 
     d=NaN(); // I'm inept at C#, this should mean "d" is unused 
     sy=new ShuntingYard(); 
    } 
} 
public class ShuntingYard { 
    private Stack<Operand> _operands; 
    private Stack<Operation> _operations; 

    public ShuntingYard() 
    { 
     this._operands = new Stack<Operand>(); 
     this._operations = new Stack<Operation>(); 
    } 
} 

StarPilot daje prawidłowe informacje, stawiając kolejny ShuntingYard na stosie, ale poprawny sposób jest umieścić ShuntingYard jako argumentu, a nie operacji. Teraz, gdy pojawi się zagnieżdżony ShuntingYard, wszystkie kolejne operandy i operacje są do niego przekazywane. Przygotowanie powinno być wykonane, aby ShuntingYard otrzymał operację nawiązywania nawiasu zamykającego, błąd najwyższego poziomu powinien spowodować błąd, a te wewnętrzne powinny same ocenić i zastąpić zawierające Operand wynikiem jego oceny.