Serwis Edukacyjny
w I-LO w Tarnowie
obrazek

Materiały dla uczniów liceum

  Wyjście       Spis treści       Wstecz       Dalej  

Autor artykułu: mgr Jerzy Wałaszek

©2026 mgr Jerzy Wałaszek

Drzewa wyrażeń

SPIS TREŚCI
Tematy pomocnicze

Problem

Należy przedstawić symboliczne wyrażenie arytmetyczne jako drzewo wyrażeń.

Rozwiązanie

Drzewo wyrażeń (ang. expression tree) jest drzewem binarnym (ang. binary tree), które przedstawia sobą wyrażenie arytmetyczne. Liście drzewa reprezentują argumenty, a wewnętrzne węzły operacje arytmetyczne. Dla uproszczenia umówmy się, że argumenty będą symbolami jednoliterowymi: a, b, c. Operacje ograniczymy do: +, -, *, / oraz ^ (potęgowanie). W wyrażeniu będą mogły pojawiać się nawiasy ().

Poniżej podajemy przykłady kilku drzew wyrażeń arytmetycznych:

a+b obrazek
(a+b)*(c-d)   obrazek
a^(b+c*d)   obrazek

Tworzenie drzewa wyrażeń wymaga przekształcenia wyrażenia na postać ONP, a następnie wykorzystania stosu oraz drzew binarnych. Zasada jest następująca:

Mamy dane symboliczne wyrażenie arytmetyczne:

( a * b / c ) ^ ( d - e )

Wyrażenie przekształcamy na postać ONP:

a b * c / d e - ^ =

Przygotowujemy pusty stos, na którym będziemy umieszczać wskazania węzłów drzewa. Wyrażenie ONP przeglądamy kolejno po jednym elemencie od strony lewej do prawej. Jeśli napotkamy argument, to tworzymy węzeł drzewa z tym argumentem i umieszczamy jego adres na stosie. Jeśli trafimy na operator, to tworzymy węzeł z tym operatorem, następnie ze stosu zdejmujemy dwa węzły i dołączamy je jako synów do węzła z operatorem, po czym adres tego węzła wędruje na stos. Gdy przeglądniemy całe wyrażenie ONP, na stosie będziemy mieli adres korzenia drzewa wyrażeń. Prześledźmy te działania na naszym przykładzie:

Wyrażenie ONP Opis Stos
 a b * c / d e - ^ 
Elementem jest argument a.
Tworzymy węzeł z tym argumentem
i umieszczamy go stosie (uwaga: przez
umieszczenie węzła na stosie
rozumiemy umieszczenie na stosie
jego wskazania)
.
obrazek
 a b * c / d e - ^ 
Kolejny element wyrażenia jest również
argumentem. Tworzymy dla niego węzeł
umieszczamy go na stosie.
obrazek
 a b * c / d e - ^ 
Teraz napotykamy na operator *.
Tworzymy nowy węzeł dla operatora.
Ze stosu pobieramy dwa węzły (tzn.
adresy tych węzłów)
i tworzymy z nich
lewego i prawego syna węzła z operatorem,
po czym węzeł ten umieszczamy na stosie.
obrazek
 a b * c / d e - ^ 
Argument c.
Tworzymy dla niego węzeł i umieszczamy
na stosie.
obrazek
 a b * c / d e - ^ 
Operator /.
Tworzymy węzeł operatora. Ze stosu
pobieramy dwa węzły (* oraz c)
i dołączamy je do węzła operatora / jako
lewy i prawy syn. Następnie węzeł
operatora / umieszczamy na stosie.
obrazek
 a b * c / d e - ^ 
Argument d.
Tworzymy dla niego węzeł i umieszczamy
na stosie.
obrazek
 a b * c / d e - ^ 
Argument e. Tworzymy dla niego węzeł
i umieszczamy na stosie.
obrazek
 a b * c / d e - 
Operator -. Tworzymy węzeł dla operatora -.
Ze stosu pobieramy węzły d i e i dołączamy
je do węzła operatora jako lewy
i prawy syn. Węzeł operatora umieszczamy
na stosie.
obrazek
 a b * c / d e - ^ 
Operator ^. Tworzymy węzeł operatora,
pobieramy ze stosu dwa węzły
i dołączamy je jako lewy i prawy syn.
Węzeł umieszczamy na stosie.
obrazek
 a b * c / d e - ^ 
Koniec wyrażenia.
Na szczycie stosu mamy adres korzenia
drzewa wyrażeń.
 

Algorytm tworzenia drzewa wyrażeń z wyrażenia ONP

Wejście:

Wyrażenie ONP.

Wyjście:

Na szczycie stosu adres korzenia drzewa wyrażeń.

Elementy pomocnicze:

S : stos przechowujący adresy węzłów.
el : element wyrażenia, znak.
: przechowuje adres węzła.

Lista kroków:

K01: Jeśli koniec wyrażenia, ; sprawdzamy koniec wyrażenia
     to zakończ
K02: Czytaj el ; czytamy element wyrażenia
K03: Utwórz nowy węzeł
K04: v ← adres nowego węzła
K05: vdatael ; w węźle umieszczamy odczytany
     ; element wyrażenia
K06: Jeśli el nie jest argumentem, 
     to idź do kroku K10
K07: vleftnil ; dla argumentów zerujemy synów
K08: vrightnil
K09: Idź do kroku K14
K10: vrightS.top() ; dla operatorów pobieramy
     ; ze stosu dwa węzły
K11: S.pop()
K12: vleftS.top()
K13: S.pop()
K14: S.push(v) ; węzeł umieszczamy na stosie
K15: Idź do kroku K01 ; wracamy na początek pętli

Przykładowe programy

Uwaga:

Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich.

Do programu wprowadzamy symboliczne wyrażenie arytmetyczne. W wyrażeniu można stosować:
  • pojedyncze litery (małe lub duże) jako symbole argumentów,
  • znaki operacji arytmetycznych +, -, *, / oraz ^ dla potęgowania,
  • znaki nawiasów (, ).

Przykładowe wyrażenie:

(a+b^(c-d))/e*f^g
Pascal
// Tworzenie drzewa wyrażeń
// Data: 11.05.2013
// (C)2013 mgr Jerzy Wałaszek
//---------------------------

program e_tree;

// Typ węzłów drzewa
//------------------
type
  PBTnode = ^BTnode;
  BTnode  = record
    left, right : PBTnode;
    Data: char;
  end;

  // rozmiar dla stosów
const S_MAX = 100;

// Zmienne globalne
//-----------------
var
  // łańcuchy do znaków ramek
  cr, cl, cp : string;

// Zwraca priorytet operatora
// dla ONP
//---------------------------
function p(c : char) : integer;
begin
  case c of
   '('      : p := 0;
   '+', '-' : p := 1;
   '*', '/' : p := 2;
   '^'      : p := 3;
   end;
end;

// Funkcja przekształca wyrażenie
// arytmetyczne e na ONP
//-------------------------------
function onp(e : string) : string;
var
  // Stos operatorów
  S  : array [0..S_MAX-1] of char;
  // Wskaźnik stosu
  sp : integer;
  // Wynik pośredni
  t  : string;
  i  : integer;

begin
  // Inicjujemy stos
  sp := 0;
  // Zerujemy wynik
  t  := '';
  for i := 1 to length(e) do
    // Analizujemy znak wyrażenia
    case e[i] of
      // Spację ignorujemy
      ' ' : ;
      // Nawias otwierający zawsze
      // na stos
      '(' : begin
            S[sp] := '(';
            inc(sp);
          end;
      // Nawias zamykający
      ')' : begin
              while S[sp-1] <> '(' do
              begin
                // Ze stosu przesyłamy
                // na wyjście
                dec(sp);
                // wszystkie operatory
                // aż do nawiasu (
                t := t+S[sp];
                // Echo na ekran
                write(S[sp], ' ');
              end;
              // Usuwamy ze stosu
              // nawias otwierający
              dec(sp);
            end;
      // Operator
      '+', '-', '*', '/', '^' :
            begin
              while sp > 0 do
              begin
                if(p(e[i]) = 3) or
                  (p(e[i]) > p(S[sp-1])) then
                  break;
                // Na wyjście przesyłamy
                // ze stosu wszystkie
                dec(sp);
                // operatory o wyższych
                // priorytetach
                t := t+S[sp];
                // Echo na ekran
                write(S[sp], ' ');
              end;
              // Operator umieszczamy
              // na stosie
              S[sp] := e[i];
              inc(sp);
            end;
      else
        begin
          // Inaczej znak przesyłamy
          // na wyjście
          t := t+e[i];
          // Echo na ekran
          write(e[i], ' ');
        end;
      end;

  // Jeśli stos coś zawiera, 
  while sp > 0 do
  begin
    // to na wyjście przesyłamy
    dec(sp);
    // całą zawartość stosu
    t := t+S[sp];
    // Echo na ekran
    write(S[sp], ' ');
  end;

  writeln; writeln;

  ONP := t;
end;

// Funkcja zwraca adres korzenia
// drzewa wyrażeń, które zostaje
// utworzone na podstawie
// wyrażenia e
//------------------------------
function etree(e : string) : PBTnode;
var
  // Stos
  S  : array [0..S_MAX-1] of PBTnode;
  // Wskaźnik stosu
  sp : integer;
  // Adres węzła
  v  : PBTnode;
  // Indeks
  i  : integer;

begin
  // Zerujemy stos
  sp := 0;
  // Przetwarzamy wyrażenie ONP
  for i := 1 to length(e) do
  begin
    // Tworzymy nowy węzeł
    new(v);
    // Umieszczamy w nim
    // element wyrażenia
    v^.Data:= e[i];
    if e[i] in ['+', '-', '*', '/', '^'] then
    // Operator
    begin
      // Pobieramy ze stosu węzły
      // i czynimy je synami węzła
      v^.right := S[sp-1];
      v^.left  := S[sp-2];
      dec(sp, 2);
    end
    else
    // Argument
    begin
      // Liść, nie ma synów
      v^.left  := nil;
      v^.right := nil;
    end;
    // Węzeł umieszczamy na stosie
    S[sp] := v;
    inc(sp);
  end;
  // Zwracamy adres korzenia
  etree := S[sp-1];
end;

// Procedura DFS:postorder
// usuwająca drzewo
//------------------------
procedure dfs_release(v : PBTnode);
begin
  if v <> nil then
  begin
    // usuwamy lewe poddrzewo
    dfs_release(v^.left);
    // usuwamy prawe poddrzewo
    dfs_release(v^.right);
    // usuwamy sam węzeł
    dispose(v);
  end;
end;

// Procedura wypisuje drzewo
//--------------------------
procedure print_bt(sp, sn : string;
                  v : PBTnode);
var
  s : string;
  i : integer;
begin
  if v <> nil then
  begin
    s := sp;
    if sn = cr then
      s[length(s)-1] := ' ';
    print_bt(s+cp, cr, v^.right);

    s := Copy(sp, 1, length(sp)-2);
    for i := 1 to length(s) do
      write(char(ord(s[i])));
    for i := 1 to length(sn) do
      write(char(ord(sn[i])));
    writeln(v^.data);

    s := sp;
    if sn = cl then
      s[length(s)-1] := ' ';
    print_bt(s+cp, cl, v^.left);
  end;
end;

//**********************
//*** PROGRAM GŁÓWNY ***
//**********************

var
  // Wyrażenie
  e : string;
  // Korzeń drzewa
  root : PBTnode;
begin

  // Ustawiamy łańcuchy znakowe, 
  // ponieważ nie wszystkie
  // edytory pozwalają wstawiać
  // znaki konsoli do tworzenia
  // ramek
  // cr = +--
  //      |

  // cl = |
  //      +--

  // cp = |
  //      |

  cr := #218#196;
  cl := #192#196;
  cp := #179#32;

  // Czytamy wyrażenie
  readln(e);
  writeln;
  // Tworzymy drzewo wyrażeń
  root := etree(onp(e));
  // Wyświetlamy drzewo
  print_bt('', '', root);
  // Usuwamy drzewo z pamięci
  dfs_release(root);
end.
C++
// Tworzenie drzewa wyrażeń
// Data: 11.05.2013
// (C)2013 mgr Jerzy Wałaszek
//---------------------------

#include <iostream>
#include <string>

using namespace std;

// Typ węzłów drzewa
//------------------
struct BTnode
{
  BTnode *left, *right;
  char data;
};

// rozmiar dla stosów
const int S_MAX = 100;

// Zmienne globalne
//-----------------

// łańcuchy do znaków ramek
string cr, cl, cp;

// Zwraca priorytet operatora
//---------------------------
int p (char c)
{
  switch (c)
  {
    case '+' :
    case '-' : return 1;
    case '*' :
    case '/' : return 2;
    case '^' : return 3;
  }
  return 0;
}

// Funkcja przekształca wyrażenie
// arytmetyczne e na ONP
//-------------------------------
string ONP (string e)
{
  // Stos operatorów
  char S[S_MAX];
  // Wskaźnik stosu
  int sp;
  // Wynik
  string t;
  unsigned int i;

  // Inicjujemy stos
  sp = 0;
  // Zerujemy wynik
  t  = "";
  for(i = 0; i < e.length(); i++)
    // Analizujemy znak wyrażenia
    switch(e[i])
    {
      // Spację ignorujemy
      case ' ' : break;
      // Nawias otwierający zawsze
      // na stos
      case '(' : {
                   S[sp++] = '(';
                   break;
                 }
      // Nawias zamykający
      case ')' : {
                   // Ze stosu przesyłamy
                   // na wyjście
                   while(S[sp-1] != '(')
                   {
                     t += S[--sp];
                     // wszystkie operatory
                     // aż do nawiasu (
                     // Echo na ekran
                     cout << S[sp] << " ";
                   }
                   // Usuwamy ze stosu
                   // nawias otwierający
                   sp--;
                   break;
                 }
      // Operator
      case '+' :
      case '-' :
      case '*' :
      case '/' :
      case '^' : {
                   while(sp)
                   {
                     if((p(e[i]) == 3) ||
                        (p(e[i]) > p(S[sp-1])))
                       break;
                     // Na wyjście przesyłamy
                     // ze stosu wszystkie
                     // operatory o wyższych
                     // priorytetach
                     t += S[--sp];
                     // Echo na ekran
                     cout << S[sp] << " ";
                   }
                   // Operator umieszczamy
                   // na stosie
                   S[sp++] = e[i];
                   break;
                 }
      default :  {
                   // Inaczej znak przesyłamy
                   // na wyjście
                   t += e[i];
                   // Echo na ekran
                   cout << e[i] << " ";
                   break;
                 }
    }

  // Jeśli stos coś zawiera, 
  // to na wyjście przesyłamy
  while(sp)
  {
    // całą zawartość stosu
    t += S[--sp];
    // Echo na ekran
    cout << S [sp] << " ";
  }
  cout << endl << endl;
  return t;
}

// Funkcja zwraca adres korzenia
// drzewa wyrażeń, które zostaje
// utworzone na podstawie
// wyrażenia e
//-------------------------------
BTnode * etree(string e)
{
  // Stos
  BTnode * S[S_MAX];
  // Wskaźnik stosu
  int sp;
  // Adres węzła
  BTnode * v;
  // Indeks
  unsigned int i;

  // Zerujemy stos
  sp = 0;
  // Przetwarzamy wyrażenie ONP
  for(i = 0; i < e.length(); i++)
  {
    // Tworzymy nowy węzeł
    v = new BTnode;
    // Umieszczamy w nim
    // element wyrażenia
    v->data = e[i];
    switch(e [i])
    {
      // Operator
      case '+' :
      case '-' :
      case '*' :
      case '/' :
      case '^' : {
                   // Pobieramy ze stosu węzły
                   // i czynimy je synami
                   // węzła
                   v->right = S[--sp];
                   v->left  = S[--sp];
                   break;
                 }
      // Argument
      default  : {
                   // Liść, nie ma synów
                   v->left = v->right= NULL;
                   break;
                 }
    }
    // Węzeł umieszczamy na stosie
    S[sp++] = v;
  }
  // Zwracamy adres korzenia
  return S[sp-1];
}

// Procedura DFS:postorder
// usuwająca drzewo
//-----------------------------------------
void dfs_release(BTnode * v)
{
  if(v)
  {
    // usuwamy lewe poddrzewo
    dfs_release(v->left);
    // usuwamy prawe poddrzewo
    dfs_release(v->right);
    // usuwamy sam węzeł
    delete v;
  }
}

// Procedura wypisuje drzewo
//--------------------------
void print_bt(string sp, 
             string sn, 
             BTnode * v)
{
  string s;

  if(v)
  {
    s = sp;
    if(sn == cr)
      s[s.length()-2] = ' ';
    print_bt(s+cp, cr, v->right);

    s = s.substr(0, sp.length()-2);
    cout << s << sn << v->data << endl;

    s = sp;
    if(sn == cl) s[s.length()-2] = ' ';
    print_bt(s+cp, cl, v->left);
  }
}

//**********************
//*** PROGRAM GŁÓWNY ***
//**********************

int main()
{
  // Wyrażenie
  string e;
  // Korzeń drzewa
  BTnode * root;

  // Ustawiamy łańcuchy znakowe, 
  // ponieważ nie wszystkie
  // edytory pozwalają
  // wstawiać znaki konsoli
  // do tworzenia ramek.
  // cr = +--
  //      |

  // cl = |
  //      +--

  // cp = |
  //      |

  cr = cl = cp = "  ";
  cr[0] = 218; cr[1] = 196;
  cl[0] = 192; cl[1] = 196;
  cp[0] = 179;

  // Czytamy wyrażenie
  getline(cin, e);
  cout << endl;
  // Tworzymy drzewo wyrażeń
  root = etree(onp(e));
  // Wyświetlamy drzewo
  print_bt("", "", root);
  // Usuwamy drzewo z pamięci
  dfs_release(root);
  return 0;
}
Basic
' Tworzenie drzewa wyrażeń
' Data: 11.05.2013
' (C)2013 mgr Jerzy Wałaszek
'------------------------------

' Typ węzłów drzewa
'------------------
Type BTnode
  left  As BTnode Ptr
  right As BTnode Ptr
  data  As String * 1
End Type

' rozmiar dla stosów
Const S_MAX = 100

' Zmienne globalne
'-----------------

' łańcuchy do ramek
Dim Shared As String * 2 cr, cl, cp

' Zwraca priorytet operatora
'---------------------------
Function p (c As String) _
              As Integer
  Select Case c
    Case "("
      p = 0
    Case "+", "-"
      p = 1
    Case "*", "/"
      p = 2
    Case "^"
      p = 3
  End Select
End Function

' Funkcja przekształca wyrażenie
' arytmetyczne e na ONP
'-------------------------------
Function ONP (e As string) _
                As String
  ' Stos operatorów
  Dim S(S_MAX) As String * 1
  ' Wskaźnik stosu
  Dim sp As Integer
  ' Wynik
  Dim t As String
  Dim i As Integer

  ' Inicjujemy stos
  sp = 0
  ' Zerujemy wynik
  t  = ""
  For i = 1 To Len(e)
    ' Analizujemy znak
    Select Case Mid(e, i, 1)
      ' Spację ignorujemy
      Case " "
      Case "("
        ' Nawias otwierający
        ' zawsze na stos
        S(sp) = "("
        sp += 1
      Case ")"
    	' Nawias zamykający
        While S(sp-1) <> "("
          ' Ze stosu przesyłamy
          ' na wyjście wszystkie
          ' operatory aż do
          ' nawiasu otwierającego
          sp -= 1
          t += S(sp)
          ' Echo na ekran
          Print S(sp);" ";
        Wend
        ' Usuwamy ze stosu
        ' nawias otwierający
        sp -= 1
      Case "+", "-", "*", "/", "^"
        While sp > 0
          If(p(Mid(e, i, 1)) = 3) OrElse _
            (p(Mid(e, i, 1)) > p(S(sp-1))) _
          Then Exit While
          ' Na wyjście przesyłamy
          ' ze stosu wszystkie
          sp -= 1
          ' operatory o wyższych
          ' priorytetach
          t += S(sp)
          ' Echo na ekran
          Print S(sp);" ";
        Wend
        ' Operator umieszczamy
        ' na stosie
        S(sp) = Mid(e, i, 1)
        sp += 1
      Case Else
        ' Inaczej znak
        ' przesyłamy na wyjście
        t += Mid(e, i, 1)
        ' Echo na ekran
        Print Mid(e, i, 1);" ";
    End Select
  Next
  ' Jeśli stos coś zawiera, 
  While sp > 0
    ' to na wyjście przesyłamy
    sp -= 1
    ' całą zawartość stosu
    t += S(sp)
    ' Echo na ekran
    Print S(sp);" ";
  Wend
  Print: Print
  ONP = t
End Function

' Funkcja zwraca adres korzenia
' drzewa wyrażeń, które zostaje
' utworzone na podstawie wyrażenia e
'-----------------------------------
Function etree(e As String) _
                 As BTnode Ptr
  ' Stos węzłów
  Dim As BTnode Ptr S(S_MAX)
  ' Wskaźnik stosu
  Dim As Integer sp
  ' Adres węzła
  Dim As BTnode Ptr v
  ' Indeks
  Dim As Integer i
  
  ' Zerujemy stos
  sp = 0
  ' Przetwarzamy wyrażenie ONP
  For i = 1 To Len(e)
    ' Tworzymy nowy węzeł
    v = new BTnode
    ' Umieszczamy w nim
    ' element wyrażenia
    v->data = Mid(e, i, 1)

    Select Case Mid(e, i, 1)
      ' Operator
      Case "+", "-", "*", "/", "^"
        ' Pobieramy ze stosu
        ' węzły i czynimy je
        ' synami węzła
        v->right = S(sp-1)
        v->left  = S(sp-2)
        sp -= 2
      ' Argument
      Case Else
        ' Liść, nie ma synów
        v->left  = 0
        v->Right = 0
    End Select
    ' Węzeł umieszczamy na stosie
    S(sp) = v
    sp += 1
  Next
  ' Zwracamy adres korzenia
  etree = S(sp-1)
End Function

' Procedura DFS:postorder
' usuwająca drzewo
'------------------------
Sub dfs_release(v As BTnode Ptr)
  If v Then
    ' usuwamy lewe poddrzewo
    dfs_release(v->left)
    ' usuwamy prawe poddrzewo
    dfs_release(v->right)
    ' usuwamy sam węzeł
    Delete v
  End If
End Sub

' Procedura wypisuje drzewo
'--------------------------
Sub print_bt(sp As String, _
            sn As String, _
            v As BTnode Ptr)
  Dim As String s

  If v Then
    s = sp
    If sn = cr Then _
      Mid(s, Len(s)-1, 1) = " "
    print_bt(s+cp, cr, v->right)
    s = Mid(s, 1, Len(sp)-2)
    Print Using "&&&";s;sn;v->Data
    s = sp
    If sn = cl Then Mid(s, Len(s)-1, 1) = " "
    print_bt(s+cp, cl, v->Left)
  End If
End Sub

'**********************
'*** PROGRAM GŁÓWNY ***
'**********************

' Wyrażenie
Dim As string e
' Korzeń drzewa
Dim As BTnode Ptr root

' Ustawiamy łańcuchy znakowe, 
' ponieważ nie wszystkie
' edytory pozwalają wstawiać
' znaki konsoli do tworzenia
' ramek.

' cr = +--
'      |

' cl = |
'      +--

' cp = |
'      |

cr = Chr(218)+Chr(196)
cl = Chr(192)+Chr(196)
cp = Chr(179)+" "

Open Cons For Input As #1
' Czytamy wyrażenie
Line Input #1, e
Print
' Tworzymy drzewo wyrażeń
root = etree(onp(e))
' Wyświetlamy drzewo
print_bt("", "", root)
' Usuwamy drzewo z pamięci
dfs_release(root)
End
Python (dodatek)
# Tworzenie drzewa wyrażeń
# Data: 23.07.2024
# (C)2024 mgr Jerzy Wałaszek
#------------------------------


# klasa węzłów drzewa
class BTnode:


    def __init__(self):
        self.left  = None
        self.right = None
        self.data  = 0


# zmienne globalne

# rozmiar dla stosów
S_MAX = 100
# łańcuchy do ramek
cr = "┌─"
cl = "└─"
cp = "│ "


# Zwraca priorytet operatora
def p(c):
    r = -1
    match c:
        case "(":
            r = 0
        case "+"|"-":
            r = 1
        case "*"|"/":
            r = 2
        case "^":
            r = 3
    return r


# Funkcja przekształca wyrażenie
# arytmetyczne e na ONP
def onp(e):
    global S_MAX
    # Stos operatorów
    s = [""] * S_MAX
    # Wskaźnik stosu
    sp = 0
    # Wynik
    t = ""
    for i in range(len(e)):
        # Analizujemy znak
        match e[i]:
            # Spację ignorujemy
            case " ":
                sp = sp
            case "(":
                # Nawias otwierający
                # zawsze na stos
                s[sp] = "("
                sp += 1
            case ")":
                # Nawias zamykający
                while s[sp-1] != "(":
                    # Ze stosu przesyłamy
                    # na wyjście wszystkie
                    # operatory aż do
                    # nawiasu otwierającego
                    sp -= 1
                    t += s[sp]
                    # Echo na ekran
                    print(s[sp], end=" ")
                # Usuwamy ze stosu
                # nawias otwierający
                sp -= 1
            case "+"|"-"|"*"|"/"|"^":
                while sp:
                    if ((p(e[i]) == 3) or
                        (p(e[i]) > p(s[sp-1]))):
                        break
                    # Na wyjście przesyłamy
                    # ze stosu wszystkie
                    sp -= 1
                    # operatory o wyższych
                    # priorytetach
                    t += s[sp]
                    # Echo na ekran
                    print(s[sp], end=" ")
                # Operator umieszczamy
                # na stosie
                s[sp] = e[i]
                sp += 1
            case _:
                # Inaczej znak
                # przesyłamy na wyjście
                t += e[i]
                # Echo na ekran
                print(e[i], end=" ")
    # Jeśli stos coś zawiera,
    while sp:
        # to na wyjście przesyłamy
        sp -= 1
        # całą zawartość stosu
        t += s[sp]
        # Echo na ekran
        print(s[sp], end=" ")
    print()
    print()
    return t


# Funkcja zwraca adres korzenia
# drzewa wyrażeń, które zostaje
# utworzone na podstawie wyrażenia e
def etree(e):
    global S_MAX
    # Stos węzłów
    s = [BTnode()] * S_MAX
    # Wskaźnik stosu
    sp = 0
    # Przetwarzamy wyrażenie ONP
    for i in range(len(e)):
        # Tworzymy nowy węzeł
        v = BTnode()
        # Umieszczamy w nim
        # element wyrażenia
        v.data = e[i]
        match e[i]:
            # Operator
            case "+"|"-"|"*"|"/"|"^":
                # Pobieramy ze stosu
                # węzły i czynimy je
                # synami węzła
                v.right = s[sp-1]
                v.left  = s[sp-2]
                sp -= 2
            # Argument
            case _:
                # Liść, nie ma synów
                v.left  = None
                v.Right = None
        # Węzeł umieszczamy na stosie
        s[sp] = v
        sp += 1
    # Zwracamy adres korzenia
    return s[sp-1]


# Procedura DFS:postorder
# usuwająca drzewo
def dfs_release(v):
    if v:
        # usuwamy lewe poddrzewo
        dfs_release(v.left)
        # usuwamy prawe poddrzewo
        dfs_release(v.right)
        # usuwamy odwołania
        v.left = None
        v.right = None


# procedura wypisuje drzewo
def print_bt(sp, sn, v):
    global cr, cl, cp
    if v:
        s = sp
        if sn == cr:
            s = s[:-2]+' '+s[-1]
        print_bt(s+cp, cr, v.right)
        s = s[:-2]
        print(s, sn, v.data, sep="")
        s = sp
        if sn == cl:
            s = s[:-2]+' '+s[-1]
        print_bt(s+cp, cl, v.left)


#**********************
#*** PROGRAM GŁÓWNY ***
#**********************

# Czytamy wyrażenie
e = input()
print()
# Tworzymy drzewo wyrażeń
root = etree(onp(e))
# Wyświetlamy drzewo
print_bt("", "", root)
# Usuwamy drzewo z pamięci
dfs_release(root)
Wynik:
(a+b^(c-d))/e*f^g

a b c d - ^ + e / f g ^ *

  ┌─g
┌─^
│ └─f
*
│ ┌─e
└─/
  │     ┌─d
  │   ┌─-
  │   │ └─c
  │ ┌─^
  │ │ └─b
  └─+
    └─a

do podrozdziału  do strony 

Zespół Przedmiotowy
Chemii-Fizyki-Informatyki

w I Liceum Ogólnokształcącym
im. Kazimierza Brodzińskiego
w Tarnowie
ul. Piłsudskiego 4
©2026 mgr Jerzy Wałaszek

Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.

Informacje dodatkowe.