Buch Cover Buch Cover Buch Cover Buch Cover

Web-Code: - Webcode Help

Umgekehrte Polnische Notation (Felder)

Damit zusammengesetzte Ausdrücke auch ohne Klammern geschrieben werden können, hat der polnische Mathematiker Jan Lukasiewicz eine Notation entworfen, welche die Operatoren neben den Zahlen und Variablen (und nicht dazwischen) aufführt.

Die hier verwendete Notation schreibt die Operatoren nach den Zahlen und wird "umgekehrte Polnische Notation" genannt.

Anstelle von "3 + 4" schreibt man hier  "3 4 +". Damit können auch zusammengesetzte Ausdrücke ohne Klammern geschrieben werden. Anstelle von "(3 + 4) * (6 - 2)" schreibt man nun "3 4 + 6 2 - *". Es wird also zuerst 3 + 4 gerechnet, danach wird 6 - 2 bestimmt und am Schluss werden die beiden Faktoren miteinander multipliziert.

Achtung: Eine Änderung in der Reihenfolge der Operatoren hat natürlich auch eine Auswirkung auf die Auswertungsreihenfolge und somit auf das Resultat. Somit wird "3 4 + 6 - 2 *" wie folgt ausgewertet: "((3 + 4)  - 6) * 2" .

Am einfachsten stellt man sich vor, die Zahlen werden der Reihe nach (von links nach rechts) auf Zettel geschrieben und aufeinadergetürmt (Stapel). Kommt nun ein Operator, so werden die beiden obersten Zettel vom Stapel genommen, miteinander verrechtet und am Schluss das Resultat wieder auf dem Stapel (auf einem neuen Zettel) aufgetürmt. (Die beiden verrechneten Zahlen werden nicht mehr auf den Stapel gelegt.)

Schreiben Sie nun ein Programm, welches beliebige Ausdrücke in umgekehrt polnischer Notation berechnen kann. Der Einfachheit halber verwenden wir nur ganze Zahlen und als Operatoren nur die vier Grundrechenarten (+, -, *, /).

 

Zusatzaufgabe (Schwierig): Schreiben Sie auch ein Programm, das die infix-Notation (A + B * C + D) in die postfix-Notation (A B C * + D +) umwandelt. Tipp: Die Lösung könnte iterativ (z. B. shunting-Yard Algorithmus) oder rekursiv geschehen.

3 Kommentare

Bitte melde dich an um einen Kommentar abzugeben

Kommentare (3)

Tobi93 5. September 2012 19:39   reply report
gressly
Tobi93
Interessanter wäre die Umwandlung von Ausdrücken aus der Infix- in die Postfix-Notation.
=> Shunting-yard-Algorithmus

Ja, sicher klar. Ist aber eine neue Aufgabe. Wir mussten dies als Übung an der Uni lösen. Vielleicht passt es auch als Zusatzaufgabe?

Ja, als Zusatzaufgabe passt es.
Ich habe mal meine Python-Lösung abgeändert.
gressly 4. September 2012 19:53   reply report
Tobi93
Interessanter wäre die Umwandlung von Ausdrücken aus der Infix- in die Postfix-Notation.
=> Shunting-yard-Algorithmus

Ja, sicher klar. Ist aber eine neue Aufgabe. Wir mussten dies als Übung an der Uni lösen. Vielleicht passt es auch als Zusatzaufgabe?
Tobi93 1. September 2012 03:41   reply report
Interessanter wäre die Umwandlung von Ausdrücken aus der Infix- in die Postfix-Notation.
=> Shunting-yard-Algorithmus

6 Lösung(en)

package ch.programmieraufgaben.arrays.rpn;

import java.util.Arrays;

/**
 * @author Philipp Gressly (phi AT gressly DOT ch)
 */
public class RPN {
    
   int rpn(String ausdruck[]) {
      int[] stack = new int[ausdruck.length / 2 + 1];
      int   top   = -1;
      
      int readPos  = 0;
      int resultat;
      while(readPos < ausdruck.length) {
          String symbol = ausdruck[readPos];
          if("+".equals(symbol)) {
            resultat = stack[top - 1] + stack[top];
            top = top - 1;
            stack[top] = resultat;
          } else
          if("*".equals(symbol)) {
            resultat = stack[top - 1] * stack[top];
            top = top - 1;
            stack[top] = resultat;
          } else
          if("-".equals(symbol)) {
            resultat = stack[top - 1] - stack[top];
            top = top - 1;
            stack[top] = resultat;
          } else
          if("/".equals(symbol)) {
            resultat = stack[top - 1] / stack[top];
            top = top - 1;
            stack[top] = resultat;
          }
          else { // Kein Opreator
            top = top + 1;
            stack[top] = Integer.parseInt(symbol);
          }
          readPos = readPos + 1;
      }
      
      return stack[0];
   }
   
   public static void main(String[] args) {
    new RPN().tests();
  }
   
  void tests() {
     test(13, new String[] {"11", "2", "+"}); 
     test(22, new String[] {"11", "2", "*"});
     test(77, new String[] {"3", "4", "+", "11", "*"});  
     test( 2, new String[] {"22", "13", "2", "-", "/"});
  }
  
  void test(int erwartet, String[] ausdruck) {
     int ist = rpn(ausdruck);
     System.out.println(Arrays.toString(ausdruck) + " liefert " + ist + " ...");
     if(ist == erwartet) {
         System.out.println(" ... ok.");
     } else {
         System.out.println(" ... FEHLER!");
         
     }
  }
} // end of class RPN
                

Lösung von: Philipp G. Freimann (BBW (Berufsbildungsschule Winterthur) https://www.bbw.ch)

(defun calculate-upn-expression ()
	   "Berechnet ein UPN-Term. Die Eingabe erfolgt im Lisp-Stil,
            also mit Klammern und Leerzeichen. Der Term '1', '2', '+'
            wird also so eingegeben: (1 2 +) ."
	   (upn (read)))

(defun upn (expr)
	   (let ((stack nil))
	     (dolist (e expr)
	       (if (numberp e)
		 (push e stack)
		 (let ((right (pop stack)) (left (pop stack)))
		   (push (funcall e left right) stack))))
	     (car stack)))

                

Lösung von: Stefan Meichtry (Erwachsenenbildung)

// Autor:				Andy Großhennig
// Solution for task:	Umgekehrte Polnische Notation (Felder)

#include <iostream>
#include <deque>
#include <string>

using namespace std;

// Function: Get the math task
void getTask(string *sTask)
{
	printf("Matheaufgabe eingeben. Zahlen zusammenschreiben und einzelne Elemente mit einem Leerzeichen trennen. (X XX + XXX -)\n");
	getline(cin, *sTask);
}

// Function: Calculate the result
void calculate()
{
	string sTask;				//Math task
	string::iterator s_iTask;	//Iterator for math task
	string sNumber;				//Current number from the task
	int iNumber = 0;			//Between earning
	deque<int>d_iNumbers;		//Calculating stack

	getTask(&sTask);

	s_iTask = sTask.begin();

	// Loop: Until the program reached the end of the math task
	while(s_iTask != sTask.end())
	{
		sNumber = "";

		// Switch: Check for number or operator
		switch(*s_iTask)
		{
			case '+':	iNumber = d_iNumbers.at(0) + d_iNumbers.at(1);
						d_iNumbers.pop_front(); d_iNumbers.pop_front();
						d_iNumbers.push_front(iNumber);
						iNumber = 0;
						s_iTask++;
						break;
			case '-':	iNumber = d_iNumbers.at(1) - d_iNumbers.at(0);
						d_iNumbers.pop_front(); d_iNumbers.pop_front();
						d_iNumbers.push_front(iNumber);
						iNumber = 0;
						s_iTask++;
						break;
			case '*':	iNumber = d_iNumbers.at(0) * d_iNumbers.at(1);
						d_iNumbers.pop_front(); d_iNumbers.pop_front();
						d_iNumbers.push_front(iNumber);
						iNumber = 0;
						s_iTask++;
						break;
			case '/':	if(d_iNumbers.at(0) == 0)
						{
							printf("\nDivision durch 0 nicht moeglich");
							return;
						}
						iNumber = d_iNumbers.at(1) / d_iNumbers.at(0);
						d_iNumbers.pop_front(); d_iNumbers.pop_front();
						d_iNumbers.push_front(iNumber);
						iNumber = 0;
						s_iTask++;
						break;
			case ' ':	s_iTask++;
						break;
			default:	if(*(s_iTask + 1) == ' ')
						{
							sNumber = *s_iTask;
						}
						else
						{						
							while(*s_iTask != ' ')
							{
								sNumber += *s_iTask;
								s_iTask++;
							}
							
						}
						d_iNumbers.push_front(atoi(sNumber.c_str()));
						s_iTask++;
						break;
		}
	}

	printf("\n%i", d_iNumbers.at(0)); //Result
}

int main()
{
	calculate();
	
	printf("\n\n");
	system("Pause");
	return 0;
}
                

Lösung von: Andy Großhennig (Bundeswehr)

function calculateRpn(str) {
  str = str.split(" ");
  var stack = [],
      left, right;
  for (var i = 0; i < str.length; i++) {
    if (!isNaN(parseInt(str[i]))) stack.push(str[i]);   // zahl
    else {                                              // operator
      right = stack.pop(); left = stack.pop();
      stack.push(eval(left + str[i] + right));
    }
  }
  return stack.pop();
}

console.log(calculateRpn(prompt("Eingabe:")));
                

Lösung von: Lisa Salander (Heidi-Klum-Gymnasium Bottrop)

// NET 6.x | C# 10.x | VS-2022

var mathProblems = new List<string> { "3 4 + 6 2 - *", "22 13 2 - /", "11 2 +", "11 2 *", "3 4 + 11 *" };
mathProblems.ForEach(x => Console.WriteLine($"{x} = {PostfixNotation(x)}"));

double PostfixNotation(string mathProblem) {
    var split = mathProblem.Split(" ");
    var stack = new Stack<int>();
    for (var i = 0; i < split.Count(); i++) {
        var isNumeric = int.TryParse(split[i], out var val);
        if (isNumeric) stack.Push(val);
        else {
            int first = stack.Pop(), second = stack.Pop();
            stack.Push(split[i] switch {
                "+" => second + first,
                "-" => second - first,
                "*" => second * first,
                "/" => second / first,
                _ => 0
            });
        }
    }
    return stack.Pop();
}
                

Lösung von: Jens Kelm (@JKooP)

// C++ 17
#include <iostream>
#include <sstream>
#include <vector>
#include <stack>
#include <algorithm>
#include <vector>
using is_it = std::istream_iterator<std::string>;


double get_postfix_notation(std::string math_problem) {
	const auto get_split_string{ [](const std::string& s) {std::istringstream iss(s); std::vector<std::string> r((is_it(iss)), is_it()); return r; } };
	const auto is_number{ [](const std::string& s) {return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit); } };
	std::stack<double> stack{};
	const auto split{ get_split_string(math_problem) };
	for (auto it{ split.begin() }; it != split.end(); ++it) {
		if (is_number(*it))
			stack.push(std::stoi(*it));
		else {
			const auto first{ stack.top() }; stack.pop();
			const auto second{ stack.top() }; stack.pop();
			if (*it == "+") stack.push(second + first);
			else if (*it == "-") stack.push(second - first);
			else if (*it == "*") stack.push(second * first);
			else if (*it == "/") stack.push((double)second / first);
			else stack.push(0);
		}
	}
	return stack.top();
}

int main() {
	std::vector<std::string>v{ "3 4 + 6 2 - *", "22 13 2 - /", "11 2 +", "11 2 *", "3 4 + 11 *" };
	for (const auto& i : v)
		std::cout << i << " = " << get_postfix_notation(i) << "\n";
}
                

Lösung von: Jens Kelm (@JKooP)

Verifikation/Checksumme:

"11", "2", "+" liefert 13
"11", "2", "*" liefert 22
"3", "4", "+", "11", "*" liefert  77
"22", "13", "2", "-", "/" liefert 2

Aktionen

Bewertung

Durchschnittliche Bewertung:

Eigene Bewertung:
Bitte zuerst anmelden

Meta

Zeit: 1
Schwierigkeit: Schwer
Webcode: vwsv-wf6p
Autor: Philipp G. Freimann (BBW (Berufsbildungsschule Winterthur) https://www.bbw.ch)

Download PDF

Download ZIP

Zu Aufgabenblatt hinzufügen