Reverse Polish Notation - elegáns alternatíva matematikai kifejezések kiértékeléséhez
A Reverse Polish Notation (RPN) egy hatékony módszer matematikai kifejezések kiértékelésére, melynek lényege, hogy a műveleti jelek az operandusok után következnek. Ez a megközelítés lehetővé teszi a zárójelek mellőzését, így egyszerűbbé és átláthatóbbá válik a számítási folyamat. Bár elsőre eltérőnek tűnhet, az RPN alkalmazása jelentősen felgyorsítja a műveletek végrehajtását, különösen a számítógépes rendszerek és programozható számológépek terén.

A matematikai kifejezések leírásának számos módja létezik. A leginkább elterjedt az infix notáció, ahol az operátorok a operandusok között helyezkednek el, mint például az A + B
vagy (C * D) - E
. Bár ez a notáció intuitívnak tűnhet számunkra, emberek számára, a számítógépek és számológépek számára nem feltétlenül a legoptimálisabb megoldás. Ebben a cikkben egy kevésbé ismert, de annál elegánsabb alternatívát, a Reverse Polish Notation (RPN), vagy magyarul fordított lengyel notációt, más néven postfix notációt fogunk megvizsgálni.
Mi is az a Reverse Polish Notation?
Az RPN egy olyan matematikai notáció, ahol az operátorok az operandusok után következnek. Ahelyett, hogy A + B
-t írnánk, RPN-ben A B +
-ként jelöljük. Első pillantásra talán szokatlannak tűnhet, de hamar megértjük az előnyeit.
Az RPN koncepciója Jan Łukasiewicz lengyel matematikus nevéhez fűződik, aki az 1920-as években fejlesztette ki a prefix notációt (lengyel notációt), ahol az operátorok az operandusok előtt állnak. A postfix notáció ennek egy variánsa, és Charles Hamblin ausztrál számítógép-tudós fejlesztette tovább az 1950-es években, egyszerűsítve a számítógépes feldolgozást.
Miért jó az RPN?
Az RPN legfőbb előnye a kétértelműség kiküszöbölése és a számítási hatékonyság. Az infix notációban zárójelekre van szükségünk a műveletek sorrendjének egyértelművé tételéhez, és a számítógépeknek bonyolult elemzési algoritmusokra van szükségük a műveleti sorrend (precedencia) helyes kezeléséhez. Az RPN-ben viszont nincs szükség zárójelekre, és a műveletek sorrendje a kifejezés felépítéséből automatikusan adódik.
Ez különösen a korai számítógépek és zsebszámológépek esetében volt kritikus fontosságú, ahol a hardver erőforrások korlátozottak voltak. Az RPN-t alkalmazó számológépek egyszerűbb és gyorsabb számításokat tudtak végezni.
Történelmi érdekesség: Az RPN notációt először a Hewlett-Packard (HP) cég tette népszerűvé az 1960-as és 70-es években. Az HP-9100A asztali számológép (1968) volt az egyik első kereskedelmi forgalomban kapható számológép, amely RPN-t használt. Később a legendás HP-35 (1972), az első tudományos zsebszámológép is az RPN-t alkalmazta, és ez a módszer a HP professzionális számológépeinek védjegyévé vált hosszú időre. Az RPN-t használó számológépek híresek voltak a gyors és pontos számításaikról, és a mérnökök, tudósok és pénzügyi szakemberek körében nagy népszerűségre tettek szert.
Az RPN Működése
Nézzünk egy példát, hogyan működik az RPN. Vegyük az infix kifejezést: (3 + 4) * 2 - 5
.
Először konvertáljuk ezt RPN-be. A konverzióhoz figyelembe kell vennünk a műveletek sorrendjét. Ebben az esetben először az összeadást végezzük el a zárójelben, majd szorzunk kettővel, végül kivonunk ötöt. Az RPN kifejezés a következő lesz: 3 4 + 2 * 5 -
.
Most nézzük meg, hogyan értékeljük ki ezt az RPN kifejezést egy verem (stack) segítségével. A verem egy olyan adatszerkezet, amelybe elemeket helyezhetünk (push) és kivehetünk (pop), mindig a legutoljára behelyezett elemet véve ki először (LIFO - Last-In, First-Out).
Az RPN kifejezés kiértékelése lépésről lépésre:
3
: Olvassuk be a3
-at. Ez egy operandus, helyezzük a verembe. Verem állapota:[3]
4
: Olvassuk be a4
-et. Ez is operandus, helyezzük a verembe. Verem állapota:[3, 4]
+
: Olvassuk be a+
operátort. Vegyünk ki két operandust a veremből (először a4
-et, majd a3
-at). Végezzük el az összeadást:3 + 4 = 7
. Helyezzük az eredményt (7
) vissza a verembe. Verem állapota:[7]
2
: Olvassuk be a2
-t. Operandus, verembe helyezzük. Verem állapota:[7, 2]
*
: Olvassuk be a*
operátort. Vegyünk ki két operandust a veremből (először a2
-t, majd a7
-et). Végezzük el a szorzást:7 * 2 = 14
. Helyezzük az eredményt (14
) vissza a verembe. Verem állapota:[14]
5
: Olvassuk be az5
-öt. Operandus, verembe helyezzük. Verem állapota:[14, 5]
-
: Olvassuk be a-
operátort. Vegyünk ki két operandust a veremből (először az5
-öt, majd a14
-et). Végezzük el a kivonást:14 - 5 = 9
. Helyezzük az eredményt (9
) vissza a verembe. Verem állapota:[9]
Mivel az RPN kifejezés végére értünk, és a veremben csak egy elem maradt, ez az elem a végeredmény. Tehát az (3 + 4) * 2 - 5
kifejezés értéke RPN-ben kiértékelve 9
.
Hogyan konvertáljunk infix kifejezést RPN-é?
A legelterjedtebb algoritmus az infix kifejezések RPN-re történő átalakítására az Shunting-yard algoritmus, amelyet Edsger Dijkstra fejlesztett ki. Ez az algoritmus egy vermet és egy kimeneti sort (ami gyakorlatban lehet egyszerű lista is) használ a konverzióhoz.
Az Shunting-yard algoritmus lépései:
- Tokenizálás: Bontsuk fel az infix kifejezést tokenekre (számok, operátorok, zárójelek).
- Inicializálás: Hozzunk létre egy üres vermet operátorok tárolására és egy üres kimeneti sort az RPN kifejezés építéséhez.
- Tokenek feldolgozása: Iteráljunk végig a tokeneken:
- Szám: Ha a token szám, adjuk hozzá a kimeneti sorhoz.
- Operátor: Ha a token operátor (op1):
- Miközben a verem tetején operátor (op2) van, és:
- op2 precedenciája nagyobb vagy egyenlő, mint op1 precedenciája, ÉS
- op1 balról asszociatív (a mi példánkban minden operátor balról asszociatív),
- Vegyük le op2-t a veremből, és adjuk hozzá a kimeneti sorhoz.
- Toljuk op1-et a verembe.
- Miközben a verem tetején operátor (op2) van, és:
- Bal zárójel
(
: Toljuk a vermbe. - Jobb zárójel
)
:- Miközben a verem tetején nem bal zárójel van:
- Vegyük le az operátort a veremből, és adjuk hozzá a kimeneti sorhoz.
- Ha a verem tetején bal zárójel van, vegyük le a veremből (de ne adjuk hozzá a kimeneti sorhoz - a zárójelek nem kerülnek az RPN kifejezésbe).
- Ha a verem tetején nem bal zárójel van a jobb zárójel feldolgozása után, akkor a zárójelezés hibás.
- Miközben a verem tetején nem bal zárójel van:
- Verem ürítése: Ha már nincsenek több tokenek, vegyük le a veremből az összes operátort, és adjuk hozzá a kimeneti sorhoz.
- Eredmény: A kimeneti sor tartalmazza az RPN kifejezést.
Precedencia és Asszociativitás:
Fontos a műveletek precedenciájának és asszociativitásának ismerete. A szokásos precedencia sorrend (magasabbtól alacsonyabbig):
- Szorzás (
*
), Osztás (/
) - Összeadás (
+
), Kivonás (-
)
Mind a négy alapművelet balról asszociatív, ami azt jelenti, hogy az azonos precedenciájú operátorok balról jobbra értékelődnek ki (pl. a - b - c
= (a - b) - c
).
Példa az infix (3 + 4) * 2 - 5
RPN-re konvertálására Shunting-yard algoritmussal:
Token | Kimeneti sor (Queue) | Verem (Stack) | Megjegyzés |
---|---|---|---|
( |
( |
Bal zárójel a verembe. | |
3 |
3 |
( |
Szám a kimeneti sorhoz. |
+ |
3 |
( , + |
Operátor a verembe. |
4 |
3 , 4 |
( , + |
Szám a kimeneti sorhoz. |
) |
3 , 4 , + |
( |
Jobb zárójel - operátorok a veremből a kimeneti sorba, amíg bal zárójel nem jön. Bal zárójel levétele a veremből. |
* |
3 , 4 , + |
* |
Operátor a verembe (magasabb precedencia). |
2 |
3 , 4 , + , 2 |
* |
Szám a kimeneti sorhoz. |
- |
3 , 4 , + , 2 , * |
- |
Operátor a verembe (alacsonyabb precedencia, de a * precedenciája magasabb, ezért nem kerül levételre a veremből). |
5 |
3 , 4 , + , 2 , * , 5 |
- |
Szám a kimeneti sorhoz. |
Vége | 3 , 4 , + , 2 , * , 5 , - |
Verem ürítése a kimeneti sorhoz. |
Tehát az infix (3 + 4) * 2 - 5
RPN formája: 3 4 + 2 * 5 -
.
Összefoglalás
A Reverse Polish Notation egy elegáns és hatékony módszer matematikai kifejezések leírására és kiértékelésére. Bár az infix notációhoz képest kevésbé intuitívnak tűnhet elsőre, az RPN számos előnnyel rendelkezik, különösen a számítógépes feldolgozás szempontjából. Megszünteti a kétértelműséget, nincs szükség zárójelekre, és hatékonyan kiértékelhető egy egyszerű verem segítségével. Az infix kifejezések RPN-re történő átalakítására az Shunting-yard algoritmus egy széles körben használt és hatékony módszer.
Történelmi jelentősége vitathatatlan, hiszen a korai zsebszámológépekben fontos szerepet játszott, és a mai napig releváns koncepció a számítástechnikában, például a fordítóprogramokban és a virtuális gépekben is alkalmazzák. Bár a mindennapi felhasználásban kevésbé elterjedt, az RPN egy értékes eszköz és gondolkodásmód, amely mélyebb megértést biztosít a matematikai kifejezések és a számítógépes műveletek kapcsolatáról. A cikkben bemutatott Python kód segítségével pedig gyakorlati tapasztalatot is szerezhetünk az RPN működésével és alkalmazásával kapcsolatban.