Odwrotna Notacja Polska
-- Sebastian Pawlak, 2003.
Najczęściej spotykane funkcje przekształcania wyrażenia zapisanego
w notacji nawiasowej do wyrażenia zapisanego w Odwrotnej Notacji Polskiej
wykorzystują aglorytm rekurencyjny. W sekcji tej prezentuję inny, bardzo
zgrabny, algorytm z wykorzystaniem stosu.
Algorytm przekształcania wyrażenia zapisanego w notacji nawiasowej do
tożsamego zapisanego w Odwrotnej Notacji Polskiej:
Krok 1
Jeżeli nie ma więcej znaków w ciągu wejściowym, to realizuj krok 6; w przeciwnym razie, przeczytaj następny element (nawias, operator lub argument) i nazwij go x.
Krok 2
Jeżeli x jest argumentem, to zapisz go w ciągu wyjściowym, umieść po nim spację i przejdź do realizacji kroku 1.
Krok 3
Jeżeli x jest nawiasem otwierającym, wpisz go na stos i realizuj krok 1. Jeżeli x jest nawiasem zamykającym, przejdź do realizacji kroku 4, a w przeciwnym razie - kroku 5.
Krok 4
Jeżeli na wierzchu stosu nie ma nawiasu otwierającego, to wycofaj ten obiekt ze stosu wpisując go do ciągu wyjściowego, a zaraz za nim wpisz spację i przejdź do wykonywania kroku 4. Jeżeli na wierzchołku stosu jest nawias otwierający, to wycofaj go ze stosu i przejdź do realizacji kroku 1.
Krok 5
W przypadku, gdy priorytet elementu wierzchołkowego stosu jest większy lub równy priorytetowi x, wycofaj element z wierzchołka stosu, wpisz go do ciągu wyjściowego, a potem wpisz za nim znacznik i powtórz krok 5. W przeciwnym razie, połóż x na wierzchołek stosu i wróć do wykonywania kroku 1.
Krok 6
Opróżnij stos po jednym elemencie, wpisując każdy z nich do ciągu wyjściowego i wstawiając między nimi spację; i to już koniec.
Oto jak zaimplementowałem przedstawiony algorytm:
Kod źródłowy pliku "onp.c":
/* konwerterONP: przeksztalca wyrazenie zapisane w notacji nawiasowej do
* wyrazenia w Odwrotnej Notacji Polskiej;
* obslugiwane operatory: ^ * / + -
* obsluguje liczby zmiennoprzecinkowe
* przyklad: 0.5+3*(2^3)/(2-1) <- wejscie
* 0.5 3 2 3 ^ * 2 1 - / + <- wyjscie
*
* Algorytm przeksztalcania do ONP:
* 1. Jezeli nie ma wiecej znakow w ciagu wejsciowym, to realizuj
* kork 6. W przeciwnym razie, przeczytaj nastepny element
* (nawias, operator lub argument) i nazwij go "x".
* 2. Jezeli "x" jest argumentem, to zapisz go w ciagu wyjsciowym,
* umiesc po nim spacje i przejdz do realizacji kroku 1.
* 3. Jezeli "x" jest nawiasem otwierajacym, wpisz go na stos
* i realizuj krok 1. Jezeli "x" jest nawiasem zamykajacym,
* przejdz do realizacji kroku 4, a w przeciwnym razie kroku 5.
* 4. Jezeli na wierzchu stosu nie ma nawiasu otwierajacego, to
* wycofaj ten obiekt ze stosu wpisujac go do ciagu
* wyjsciowego, a zaraz za nim wpisz spacje i przejdz do
* wykonywania kroku 4. Jezeli na wierzcholku stosu jest
* nawias otwierajacy, to wycofaj go ze stosu i przejdz
* do realizacji kroku 1.
* 5. W przypadku, gdy priorytet elementu wierzcholkowego
* stosu jest wiekszy lub rowny priorytetowi "x", wycofaj
* element z wierzcholka stosu, wpisz go do ciagu wyjsciowego,
* a potem wpisz za nim znacznik i powtorz krok 5. W przeciwnym
* razie, poloz "x" na wierzcholek stosu i wroc do wykonywania
* kroku 1.
* 6. Oproznij stos po jednym elemencie, wpisujac kazdy z nich do
* ciagu wyjsciowego i wstawiajac miedzy nimi spacje.
*/
void konwerterONP(char *wynik, char *s)
{
char x, y;
while (x = *s++) { /* krok 1 */
if (((x >= '0') && (x <= '9')) || (x == '.')) { /* krok 2 */
/* kopiowanie calej liczby z wejscia na wyjscie */
do
*wynik++ = x;
while (x = *s, (((x >= '0') && (x <= '9')) || (x == '.')) && s++);
*wynik++ = ' ';
} else if (x == '(') /* krok 3 */
push((double)'(');
else if (x == ')') /* krok 4 */
while ((y = (char)pop()) != '(')
*wynik++ = y, *wynik++ = ' ';
else { /* krok 5 */
while (y = (char)pop(),
y && ((y == '^') ||
((y == '*') || (y == '/')) && (x != '^') ||
((y == '+') || (y == '-')) && (x != '*') &&
(x != '/') && (x != '^')))
*wynik++ = y, *wynik++ = ' ';
push((double)y);
push((double)x);
}
}
while (x = (char)pop()) /* krok 6 */
*wynik++ = x, *wynik++ = ' ';
*wynik = '\0'; /* zakonczenie lancucha wyjsciowego */
}
Kod źródłowy pliku "stos.h":
/* stos.h: plik naglowkowy biblioteki z implementacja stosu. * Sebastian Pawlak, 2002 */ #ifndef _STOS_H #define _STOS_H void push(double); double pop(void); #endif
Kod źródłowy pliku "stos.c":
/* stos.c: biblioteka z implementacja stosu.
* Sebastian Pawlak, 2002
*/
#include <stdio.h>
#include "stos.h"
#define MAX_STOS 512 /* maksymalny rozmiar stosu */
double stos[MAX_STOS];
int sp = 0; /* wskaznik kolejnego wolnego miejsca na stosie */
/* push: wstawia element na stos */
void push(double element)
{
if (sp < MAX_STOS)
stos[sp++] = element;
else
printf("push: Przepelnienie stosu!\n");
}
/* pop: zdejmuje element ze stosu */
double pop(void)
{
if (sp > 0)
return stos[--sp];
return 0;
}





