Odwrotna notacja polska (ONP) jest rodzajem notacji arytmetycznej, w której operator znajduje się za argumentami, czyli w innym miejscu niż w przypadku zapisu infiksowegozapis infiksowyzapisu infiksowego.
Obliczanie wartości wyrażenia zapisanego w odwrotnej notacji polskiej jest dla nas trudniejsze, niż gdy mamy do czynienia z klasyczną notacją arytmetyczną. A jednak dla komputera zapis ten jest o wiele bardziej „zrozumiały”. Algorytm wykorzystywany podczas obliczeń opiera się na strukturze danych zwanej stosem. Każdy nowy wpis jest układany na szczycie stosu – jeżeli chcemy pobrać z niego dane, muszą to być te, które zostały w nim zapisane ostatnio.
Implementacja algorytmu jest prosta: pobieramy kolejne elementy wyrażenia; jeżeli analizowany element jest liczbą, to umieszczamy go na stosie, a jeżeli operatorem – zdejmujemy ze stosu dwa ostatnio ułożone na nim elementy, wykonujemy na nich operację wskazaną przez operatora, a otrzymany wynik umieszczamy na stosie. Gdy zakończymy przetwarzanie elementów, na stosie powinna znajdować się tylko jedna liczba i jest nią wynik wyrażenia.
Przykładowe zadanie maturalne
Zadanie 1
Treść zadania:
Dla przetwarzania przez komputer wygodnym sposobem zapisu wyrażeń arytmetycznych jest tzw. odwrotna notacja polska (ONP). Zapis w ONP wyrażenia W nazywamy postacią ONP i oznaczamy ją ONP(W). W ONP operator (dodawania, odejmowania, mnożenia, dzielenia) umieszczamy za jego argumentami, np. 2 + 5 zapisujemy jako 2 5 +. Dokładniej, postać ONP dla wyrażenia definiujemy rekurencyjnie w następujący sposób:
jeżeli W jest liczbą, to jego postać ONP jest równa W;
jeżeli W ma postać WIndeks dolny 11 op WIndeks dolny 22, gdzie op jest operatorem, a WIndeks dolny 11 i WIndeks dolny 22 wyrażeniami, to
ONP(W) jest równe ONP(WIndeks dolny 11) ONP(WIndeks dolny 22) op.
Postać ONP wyrażeń, choć dla ludzi mało czytelna, ma własności bardzo przydatne dla analizy komputerowej. W ONP nie są potrzebne nawiasy, a do wyznaczania wartości wyrażenia można zastosować prosty algorytm podany poniżej.
Specyfikacja
Dane:
Linia 1. n — liczba całkowita dodatnia przecinek.
Linia 2. X znak równości X otwórz nawias kwadratowy 1 kropka kropka kropka n zamknij nawias kwadratowy — wyrażenie w ONP przecinek gdzie X otwórz nawias kwadratowy i zamknij nawias kwadratowy dla 1 ≤ i ≤ n jest liczbą lub znakiem ze zbioru otwórz nawias klamrowy plus przecinek – przecinek asterysk zamknij nawias klamrowy kropka.
n — liczba całkowita dodatnia,
X = X[1...n] — wyrażenie w ONP, gdzie X[i] dla 1 ≤ i ≤ n jest liczbą lub znakiem ze zbioru {+, –, *}.
Wynik:
Linia 1. wartość wyrażenia X kropka.
wartość wyrażenia X.
Algorytm:
Linia 1. k ← 1.
Linia 2. dla i znak równości 1 przecinek 2 przecinek kropka kropka kropka przecinek n wykonuj.
Linia 3. jeżeli X otwórz nawias kwadratowy i zamknij nawias kwadratowy jest liczbą.
Linia 4. T otwórz nawias kwadratowy k zamknij nawias kwadratowy ← X otwórz nawias kwadratowy i zamknij nawias kwadratowy.
Linia 6. jeżeli X otwórz nawias kwadratowy i zamknij nawias kwadratowy ∈ otwórz nawias klamrowy plus przecinek – przecinek asterysk zamknij nawias klamrowy.
Linia 7. b ← T otwórz nawias kwadratowy k – 1 zamknij nawias kwadratowy.
Linia 8. a ← T otwórz nawias kwadratowy k – 2 zamknij nawias kwadratowy.
Linia 9. k ← k – 2.
Linia 11. jeżeli X otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości apostrof plus apostrof.
Linia 12. T otwórz nawias kwadratowy k zamknij nawias kwadratowy ← a plus b.
Linia 13. jeżeli X otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości apostrof – apostrof.
Linia 14. T otwórz nawias kwadratowy k zamknij nawias kwadratowy ← a – b.
Linia 15. jeżeli X otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości apostrof asterysk apostrof.
Linia 16. T otwórz nawias kwadratowy k zamknij nawias kwadratowy ← a asterysk b.
Linia 18. k ← k plus 1.
Linia 20. zwróć T otwórz nawias kwadratowy 1 zamknij nawias kwadratowy.
k ← 1
dla i = 1, 2, ..., n wykonuj
jeżeli X[i] jest liczbą
T[k] ← X[i]
jeżeli X[i] ∈ {+, –, *}
b ← T[k – 1]
a ← T[k – 2]
k ← k – 2
jeżeli X[i] = '+'
T[k] ← a + b
jeżeli X[i] = '–'
T[k] ← a – b
jeżeli X[i] = '*'
T[k] ← a * b
k ← k + 1
zwróć T[1]
Prześledź działanie podanego algorytmu dla wyrażenia X = 9 7 + 3 * 5 4 - 2 * -, czyli dla n = 11 oraz następujących wartości X[1], ..., X[11]:
i
1
2
3
4
5
6
7
8
9
10
11
X[i]
9
7
+
3
*
5
4
-
2
*
-
Uzupełnij poniższą tabelę:
i
Wartość zmiennej k po i‑tym przebiegu pętli
Zawartość tablicy T[1..k ‑ 1] po i‑tym przebiegu pętli
1
2
9
2
3
9, 7
3
3
16
4
5
6
10
11
Zadanie zostało opracowane przez Centralną Komisję Egzaminacyjną i pojawiło się w zbiorze zadań z informatyki, jako Zadanie 11.2 (wiązka zadań „Odwrotna notacja polska”) . Cały zbiór można znaleźć na oficjalnej stronie internetowej CKE.
Algorytm, który pozwala obliczyć wartość wyrażenia zapisanego w ONP, został już podany. Aby lepiej jednak zrozumieć, jak on działa, spróbujemy napisać swoją wersję tego algorytmu.
Na egzaminie maturalnym z informatyki każdy uczeń ma możliwość wybrania jednego z dostępnych języków programowania. Z tego powodu nie będziemy dokonywać implementacji rozwiązania zadania w konkretnym języku. Zamiast tego przedstawimy je za pomocą pseudokodu.
Przełóż proponowany algorytm na język, w którym programujesz.
Przykładowe rozwiązanie:
Algorytm do znajdowania wartości wyrażenia zapisanego w ONP jest dość prosty. Aby go zaimplementować, będziemy potrzebować stosu. Stos możemy utworzyć, korzystając ze zwykłej tablicy statycznejtablica statycznatablicy statycznej oraz jednej zmiennej.
Tworząc tablicę statyczną, która posłuży nam jako stos, nadajemy jej większy – niż potrzebny – rozmiar, żeby zabezpieczyć się przed brakiem miejsca na działania. Zmienna będzie przechowywać pierwszy wolny indeks w stosie. Inicjowany stos jest pusty, zatem zmienna ta otrzyma na początku wartość 0.
Linia 1. stos otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości tablica o rozmiarze 30.
Linia 2. pierwszyWolnyIndeks znak równości 0.
stos[] = tablica o rozmiarze 30
pierwszyWolnyIndeks = 0
Następnie odczytujemy kolejne elementy wyrażenia. Jeżeli element jest liczbą, umieszczamy go na stosie.
Linia 1. stos otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości tablica o rozmiarze 30.
Linia 2. pierwszyWolnyIndeks znak równości 0.
Linia 4. dla element z wyrażenia wykonuj dwukropek.
Linia 5. jeżeli element jest liczbą wykonaj dwukropek.
Linia 6. stos otwórz nawias kwadratowy pierwszyWolnyIndeks zamknij nawias kwadratowy znak równości element.
Linia 7. pierwszyWolnyIndeks plus znak równości 1.
stos[] = tablica o rozmiarze 30
pierwszyWolnyIndeks = 0
dla element z wyrażenia wykonuj:
jeżeli element jest liczbą wykonaj:
stos[pierwszyWolnyIndeks] = element
pierwszyWolnyIndeks += 1
Jeżeli element jest operatorem, zdejmujemy ze stosu dwa elementy, wykonujemy na nich operację, a jej wynik umieszczamy na stosie.
Linia 1. stos otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości tablica o rozmiarze 30.
Linia 2. pierwszyWolnyIndeks znak równości 0.
Linia 4. dla element z wyrażenia wykonuj dwukropek.
Linia 5. jeżeli element jest liczbą wykonaj dwukropek.
Linia 6. stos otwórz nawias kwadratowy pierwszyWolnyIndeks zamknij nawias kwadratowy znak równości element.
Linia 7. pierwszyWolnyIndeks plus znak równości 1.
Linia 9. jeżeli element jest operatorem wykonaj dwukropek.
Linia 10. wynik znak równości stos otwórz nawias kwadratowy pierwszyWolnyIndeks minus 1 zamknij nawias kwadratowy operator stos otwórz nawias kwadratowy pierwszyWolnyIndeks minus 2 zamknij nawias kwadratowy.
Linia 11. stos otwórz nawias kwadratowy pierwszyWolnyIndeks minus 2 zamknij nawias kwadratowy znak równości wynik.
Linia 12. pierwszyWolnyIndeks minus znak równości 1.
stos[] = tablica o rozmiarze 30
pierwszyWolnyIndeks = 0
dla element z wyrażenia wykonuj:
jeżeli element jest liczbą wykonaj:
stos[pierwszyWolnyIndeks] = element
pierwszyWolnyIndeks += 1
jeżeli element jest operatorem wykonaj:
wynik = stos[pierwszyWolnyIndeks - 1] operator stos[pierwszyWolnyIndeks - 2]
stos[pierwszyWolnyIndeks - 2] = wynik
pierwszyWolnyIndeks -= 1
Po zakończeniu działania jedyny element, jaki pozostanie na stosie, jest wartością wyrażenia.
Linia 1. stos otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości tablica o rozmiarze 30.
Linia 2. pierwszyWolnyIndeks znak równości 0.
Linia 4. dla element z wyrażenia wykonuj dwukropek.
Linia 5. jeżeli element jest liczbą wykonaj dwukropek.
Linia 6. stos otwórz nawias kwadratowy pierwszyWolnyIndeks zamknij nawias kwadratowy znak równości element.
Linia 7. pierwszyWolnyIndeks plus znak równości 1.
Linia 9. jeżeli element jest operatorem wykonaj dwukropek.
Linia 10. wynik znak równości stos otwórz nawias kwadratowy pierwszyWolnyIndeks minus 1 zamknij nawias kwadratowy operator stos otwórz nawias kwadratowy pierwszyWolnyIndeks minus 2 zamknij nawias kwadratowy.
Linia 11. stos otwórz nawias kwadratowy pierwszyWolnyIndeks minus 2 zamknij nawias kwadratowy znak równości wynik.
Linia 12. pierwszyWolnyIndeks minus znak równości 1.
Linia 14. wypisz stos otwórz nawias kwadratowy 0 zamknij nawias kwadratowy.
stos[] = tablica o rozmiarze 30
pierwszyWolnyIndeks = 0
dla element z wyrażenia wykonuj:
jeżeli element jest liczbą wykonaj:
stos[pierwszyWolnyIndeks] = element
pierwszyWolnyIndeks += 1
jeżeli element jest operatorem wykonaj:
wynik = stos[pierwszyWolnyIndeks - 1] operator stos[pierwszyWolnyIndeks - 2]
stos[pierwszyWolnyIndeks - 2] = wynik
pierwszyWolnyIndeks -= 1
wypisz stos[0]
Opierając się na tym algorytmie, zaimplementuj program w wybranym języku programowania, a następnie wypełnij tabelkę z zadania.
Schemat oceniania:
i
Wartość zmiennej k po i‑tym przebiegu pętli
Zawartość tablicy T[1..k ‑ 1] po i‑tym przebiegu pętli
1
2
9
2
3
9, 7
3
3
16
4
2
16, 3
5
3
48
6
3
48, 5
10
3
48, 2
11
2
46
Schemat oceniania pochodzi ze zbioru zadań maturalnych z informatyki opracowanych przez CKE. Cały zbiór można znaleźć na oficjalnej stronie internetowej CKE.
Słownik
ONP
ONP
skrót pojęcia „odwrotna notacja polska”
tablica statyczna
tablica statyczna
tablica, której rozmiar jest określany podczas inicjacji i nie można go zmienić w trakcie działania programu
zapis infiksowy
zapis infiksowy
klasyczny zapis algebraiczny, w którym operator znajduje się między argumentami