Algorytmy i struktury danych
Algorytmy i struktury danych
Roman Simiński
roman.siminski@us.edu.pl roman@siminskionline.pl
programowanie.siminskionline.pl
Odwrotna notacja polska
Odwrotna notacja polska
Rozważania implementacyjne
Rozważania implementacyjne
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
2 2
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
2 2
( 2 + 3 ) * 5
( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * =
2 3 + 5 * =
Kierunek analizy wyrażenia
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
3 3
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
3 3
2
Połóż
( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
4 4
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
4 4
2
Połóż
( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =3
Liczba, kładziemy ją na stos
Liczba, kładziemy ją na stos
2
3
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
5 5
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
5 5 ( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =
Stos
Operator, zdejmujemy jego argumenty
Operator, zdejmujemy jego argumenty
3
2
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
6 6
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
6 6 ( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =
Stos
Operator, zdejmujemy jego argumenty
Operator, zdejmujemy jego argumenty
3
2
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
7 7
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
7 7 ( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =
Stos
Operator, wartościujemy wyrażenie Operator, wartościujemy wyrażenie3
2
+5
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
8 8
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
8 8
Połóż
( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =Stos
Operator, wartość wyrażenia na stos
Operator, wartość wyrażenia na stos
3
2
+55
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
9 9
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
9 9
Połóż
( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =Stos
5
Liczba, kładziemy ją na stosLiczba, kładziemy ją na stos5
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
10 10
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
10 10 ( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =
Stos
Operator, zdejmujemy jego argumenty
Operator, zdejmujemy jego argumenty
5
5
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
11 11
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
11 11 ( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =
Stos
5
5
*25
Operator, wartościujemy wyrażenie Operator, wartościujemy wyrażenie25
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
12 12
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
12 12
Połóż
( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =Stos
5
5
*25
Operator, wartość wyrażenia na stos
Operator, wartość wyrażenia na stos
25
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
13 13
Wyznaczanie wartości wyrażenia ONP, koncepcja
Wyznaczanie wartości wyrażenia ONP, koncepcja
13 13 ( 2 + 3 ) * 5 ( 2 + 3 ) * 5 2 3 + 5 * =2 3 + 5 * = 2 3 + 5 * =
Stos
Koniec wyrażenia, Wartość na stosie Koniec wyrażenia, Wartość na stosieW tym algorytmie na stos trafiają argumenty, operatory nie
Wyznaczanie wartości
Wyznaczanie wartości
Wyrażenia ONP
Wyrażenia ONP
Pseudokod
Pseudokod
Wyznaczanie wartości wyrażenia ONP, pseudokod
Wyznaczanie wartości wyrażenia ONP, pseudokod
15 15
StosLiczbRzeczywistych stos; for( ; ; )
{
element = podajKolejnyElementWyrażenia( wyrazenieONP ); if( element == '=' )
break;
if( element jest liczbą ) stos.połóż( element ); else
{
// Element jest operatorem
double druga = stos.pobierz();
double pierwsza = stos.pobierz(); double wynik;
switch( element ) {
case '+' : wynik = pierwsza + druga; break; case '-' : wynik = pierwsza – druga; break; case '*' : wynik = pierwsza * druga; break; case '/' : wynik = pierwsza / druga; break; }
stos.połóż( wynik ); }
}
wypisz( "Wartość wyrażenia: " + stos.pobierz() );
Zakładamy, że wyrażenie jest poprawne
Wyznaczanie wartości
Wyznaczanie wartości
Wyrażenia ONP
Wyrażenia ONP
Przykład 1, C++
Przykład 1, C++
Wyznaczanie wartości wyrażenia ONP, przykład, C++
Wyznaczanie wartości wyrażenia ONP, przykład, C++
17 17 ((2+7)/3+(14-3)*4)/2 2 7 + 3 / 14 3 - 4 * + 2 / = ((2+7)/3+(14-3)*4)/2 2 7 + 3 / 14 3 - 4 * + 2 / =
Założenie:
Program wczytuje z stdin kolejne elementy wyrażenia zapisanego w ONP.
Każda wprowadzona linia zawiera liczbę lub operator.
Nie jest sprawdzana poprawność wyrażenia.
Wyrażenie musi być zakończone znakiem '='.
>2
>7
>+
>3
>/
>14
>3
>->4
>*
>+
>2
>/
>=
Wartosc wyrazenia: 23.5
ONPWyznaczanie wartości wyrażenia ONP, przykład, C++
Wyznaczanie wartości wyrażenia ONP, przykład, C++
18 18
if( sscanf( element, "%lf", &liczba ) == 1 )
Udane wyodrębnienie jednej liczby typu double (czyli long float) z łańcucha element i zapisanie do zmiennej liczba
else
Nieudane wyodrębnienie liczby
Do konwersji łańcuch znaków
→ liczba można wykorzystać funkcję sscanf.
Funkcja sscanf wyodrębnia elementy z łańcucha znaków będącego pierwszym
parametrem wywołania.
Wyodrębnianie odbywa się pod kontrolą parametrów zapisanych w drugim
parametrze.
Wydobyte informacje zapisywane są argumentach przekazywanych poprzez
wskaźniki.
Rezultatem jest liczba poprawnie wyodrębnionych elementów.
Funkcja sscanf ma zmienną liczbę parametrów.
Wyznaczanie wartości wyrażenia ONP, przykład, C++
Wyznaczanie wartości wyrażenia ONP, przykład, C++
19 19
const int MAKS_DL_LINII = 80;
Stack<double> stos; // Stos dla wczytywanych liczb
double liczba;
char linia[ MAKS_DL_LINII ]; for( ; ; )
{
// Wczytanie linii
cout << ">"; cin >> linia;
// Czy wczytano operator kończący wyrażenie
if( linia[ 0 ] == '=' ) break;
Wyznaczanie wartości wyrażenia ONP, przykład, C++
Wyznaczanie wartości wyrażenia ONP, przykład, C++
20 20
// Próba wydobycia z wczytanej linii wartości liczbowej
if( sscanf( linia, "%lf", &liczba ) == 1 ) stos.push( liczba );
else {
// Nie ma liczby, jest operator, zdejmujemy argumenty
double druga = stos.pop(); double pierwsza = stos.pop(); double wynik;
switch( linia[ 0 ] ) {
case '+' : wynik = pierwsza + druga; break;
case '-' : wynik = pierwsza - druga; break;
case '*' : wynik = pierwsza * druga; break;
case '/' : wynik = pierwsza / druga; break; } // Wynik na stos stos.push( wynik ); } }
Krok w stronę wyznaczania
Krok w stronę wyznaczania
wartości wyrażenia ONP
wartości wyrażenia ONP
C++
C++
Wydobycie elementów wyrażenia ONP, przykład C++
Wydobycie elementów wyrażenia ONP, przykład C++
22 22 2 7 + 3 / 14 3 - 4 * + 2 / = 2 7 + 3/ 14 3 -4 * + 2 / = 2 7+ 3 / 14 3 - 4 * + 2 / = 2 7 + 3 / 14 3 - 4 * + 2 / = 2 7 + 3/ 14 3 -4 * + 2 / = 2 7+ 3 / 14 3 - 4 * + 2 / =
Założenie:
Wyrażenie zapisane jest w łańcuchu znaków.
Elementy wyrażenia rozdzielone są separatorami – np. znakiem spacji.
Wyrażenie musi być zakończone znakiem '='.
Wydobycie elementów wyrażenia ONP, przykład C++
Wydobycie elementów wyrażenia ONP, przykład C++
23 23
void parsowanieWyrazeniaONP( char * wyrazenie ) {
// Tablica seperatorów rozdzielających elementy char separatory[] = " ";
// Wskaźnik będzie lokalizował kolejne elementy
char * element;
element = strtok( wyrazenie, separatory ); while( element != 0 )
{
// Przykładowe wykorzystanie znalezionego elementu
cout << endl << *element;
// Poszukiwanie następnego elementu
element = strtok( 0, separatory ); }
}
2 7 + ...
element
\0
Tu można dodać inne znaki separujące elementy
wyrażenia
Tu można dodać inne znaki separujące elementy
void parsowanieWyrazeniaONP( char * wyrazenie ) {
// Tablica seperatorów rozdzielających elementy char separatory[] = " ";
// Wskaźnik będzie lokalizował kolejne elementy
char * element;
element = strtok( wyrazenie, separatory ); while( element != 0 )
{
// Przykładowe wykorzystanie znalezionego elementu
cout << endl << *element;
// Poszukiwanie następnego elementu
element = strtok( 0, separatory ); }
}
Wydobycie elementów wyrażenia ONP, przykład C++
Wydobycie elementów wyrażenia ONP, przykład C++
24 24
2 \0 7 + ...
element
Pozycja startowa następnego wywołania
void parsowanieWyrazeniaONP( char * wyrazenie ) {
// Tablica seperatorów rozdzielających elementy char separatory[] = " ";
// Wskaźnik będzie lokalizował kolejne elementy
char * element;
element = strtok( wyrazenie, separatory ); while( element != 0 )
{
// Przykładowe wykorzystanie znalezionego elementu
cout << endl << *element;
// Poszukiwanie następnego elementu
element = strtok( 0, separatory ); }
}
Wydobycie elementów wyrażenia ONP, przykład C++
Wydobycie elementów wyrażenia ONP, przykład C++
25 25
2 \0 7 + ...
element
Pozycja startowa następnego wywołania
2
void parsowanieWyrazeniaONP( char * wyrazenie ) {
// Tablica seperatorów rozdzielających elementy char separatory[] = " ";
// Wskaźnik będzie lokalizował kolejne elementy
char * element;
element = strtok( wyrazenie, separatory ); while( element != 0 )
{
// Przykładowe wykorzystanie znalezionego elementu
cout << endl << *element;
// Poszukiwanie następnego elementu
element = strtok( 0, separatory ); }
}
Wydobycie elementów wyrażenia ONP, przykład C++
Wydobycie elementów wyrażenia ONP, przykład C++
26 26
2
2 \0 7 \0 + ...
element
Pozycja startowa następnego wywołania
void parsowanieWyrazeniaONP( char * wyrazenie ) {
// Tablica seperatorów rozdzielających elementy char separatory[] = " ";
// Wskaźnik będzie lokalizował kolejne elementy
char * element;
element = strtok( wyrazenie, separatory ); while( element != 0 )
{
// Przykładowe wykorzystanie znalezionego elementu
cout << endl << *element;
// Poszukiwanie następnego elementu
element = strtok( 0, separatory ); }
}
Wydobycie elementów wyrażenia ONP, przykład C++
Wydobycie elementów wyrażenia ONP, przykład C++
27 27
2
7
+
3
/
1
3
-4
*
+
2
/
=
2 \0 7 \0 + ... element \0Wyznaczanie
Wyznaczanie
wartości wyrażenia ONP
wartości wyrażenia ONP
Funkcja C++
Funkcja C++
Wyznaczanie wartości wyrażenia ONP, funkcja, przykład, w C++
Wyznaczanie wartości wyrażenia ONP, funkcja, przykład, w C++
29 29
double wyliczWartoscWyrazeniaONP( char * wyrazenie ) {
Stack<double> stos;
char separatory[] = " "; char * element;
double liczba;
element = strtok( wyrazenie, separatory ); while( element != 0 )
{
if( *element == '=' ) break;
if( sscanf( element, "%lf", &liczba ) == 1 ) stos.push( liczba );
else . . .
std::cout << std::endl << wyliczWartoscWyrazeniaONP( "2 3 + 5 * =" );
Przykład wywołania:
Wyznaczanie wartości wyrażenia ONP, funkcja, przykład, C++
Wyznaczanie wartości wyrażenia ONP, funkcja, przykład, C++
30 30
. . . {
double druga = stos.pop(); double pierwsza = stos.pop(); double wynik;
switch( *element ) {
case '+' : wynik = pierwsza + druga; break;
case '-' : wynik = pierwsza - druga; break;
case '*' : wynik = pierwsza * druga; break;
case '/' : wynik = pierwsza / druga; break;
}
stos.push( wynik ); }
element = strtok( 0, separatory ); }
return stos.pop(); }
Konwersja wyrażenia do
Konwersja wyrażenia do
postaci ONP
postaci ONP
Pseudokod
Pseudokod
Konwersja wyrażenia do postaci ONP, algorytm
Konwersja wyrażenia do postaci ONP, algorytm
32 32
( ( 2 + 7 ) / 3 + ( 14 – 3 ) * 4 ) / 2 =
2 7 + 3 / 14 3 - 4 * + 2 / =
( ( 2 + 7 ) / 3 + ( 14 – 3 ) * 4 ) / 2 =
2 7 + 3 / 14 3 - 4 * + 2 / =
Założenie:
Wyrażenie zapisane jest w łańcuchu znaków.
Elementy wyrażenia rozdzielone są separatorami – np. znakiem spacji.
Wyrażenie musi być zakończone znakiem '='.
Konwersja wyrażenia do postaci ONP, algorytm iteracyjny
Konwersja wyrażenia do postaci ONP, algorytm iteracyjny
33 33
Wejście:
wyrażenie : łańcuch znaków onp : łańcuch znaków
StosOperatorow stos; for( ; ; )
{
element = podajKolejnyElementWyrażenia( wyrażenie ); if( koniec wyrażenia )
{
// Koniec wyrażenia źródłowego, pobierz operatory ze stosu, dopisz // je do wyrażenia ONP i zakończ działanie
while( !stos.empty() ) onp += stos.pop();
break; }
Konwersja wyrażenia do postaci ONP, algorytm iteracyjny
Konwersja wyrażenia do postaci ONP, algorytm iteracyjny
34 34
. . .
switch( element ) {
// Jeżeli odczytanym elementem jest nawias otwierający to należy po // odłożyć na stos
case '(' : stos.push( '(' ); break;
// Jeżeli odczytanym elementem jest nawias zamykający to należy pobrać // ze stosu wszystkie operatory aż do nawiasu otwierającego. Operatory // należy dopisać do wyrażenia ONP, nawias otwierający usunąć ze stosu
case ')' : while( stos.peek() != '(' )
onp += stos.pop(); // Pobranie operatora i dopisanie do ONP
stos.pop(); // Pobranie nawiasu otwierającego
break; . . .
Konwersja wyrażenia do postaci ONP, algorytm iteracyjny
Konwersja wyrażenia do postaci ONP, algorytm iteracyjny
. . .
// Odczytanym elementem jest operator, dopisujemy go do stosu, ale wcześniej // zdejmujemy operatory ze stosu i dopisujemy do wyrażenia ONP dopóki:
// odczytany operator ma łączność lewostronną oraz priorytet niższy // lub równy operatorowi na stosie
// lub
// operator ma łączność prawostronną oraz priorytet niższy od operatora // na stosie
case '+' : case '-' : case '*' :
case '/' : while( !stos.empty() ) {
// Wyskakujemy z iteracji jeżeli priorytet odczytanego operatora // (element) jest wyższy lub równy od operatora ze szczytu stosu
if( priorytet( element ) >= priorytet( stos.peek() ) ) break;
// Zdejmujemy operatory o wyższych priorytetach
onp += stos.pop(); }
stos.push( element ); break;
Konwersja wyrażenia do postaci ONP, algorytm iteracyjny
Konwersja wyrażenia do postaci ONP, algorytm iteracyjny
36 36
. . .
// Odczytanym elementem jest argument, dopisujemy go do wyrażenia ONP
default : onp += element; break;
}//switch
Konwersja wyrażenia do
Konwersja wyrażenia do
Postaci ONP
Postaci ONP
Funkcja w C++
Funkcja w C++
Konwersja wyrażenia do postaci ONP, przykład, C++
Konwersja wyrażenia do postaci ONP, przykład, C++
38 38
char * przeksztalcDoONP( char * wyrazenie, char * onp ) { Stack<char> stos; char separatory[] = " "; char * element; double liczba; char symbol; onp[ 0 ] = '\0';
element = strtok( wyrazenie, separatory ); while( element != 0 )
{
if( *element == '=' ) {
while( !stos.empty() )
dopiszZnak( onp, stos.pop() ); dopiszZnak( onp, '=' );
break; }
. . .
Funkcja pobiera wyrażenie w notacji infiksowej, zapisane w tablicy wyrazenie i buduje wyrażenie ONP, zapisując je do tablicy onp. Rezultatem funkcji jest tablica onp, fukcja akceptuje operatory + - * / = oraz argumenty w postaci liczb. Nie jest kontrolowane przepełnienie tablicy onp. Funkcja zakłada, że elementy wyrażenia źródłowego są rozdzielone znakami spacji.
Funkcja pobiera wyrażenie w notacji infiksowej, zapisane w tablicy wyrazenie i buduje wyrażenie ONP, zapisując je do tablicy onp. Rezultatem funkcji jest tablica onp, fukcja akceptuje operatory + - * / = oraz argumenty w postaci liczb. Nie jest kontrolowane przepełnienie tablicy onp. Funkcja zakłada, że elementy wyrażenia źródłowego są rozdzielone znakami spacji.
Konwersja wyrażenia do postaci ONP, przykład, C++
Konwersja wyrażenia do postaci ONP, przykład, C++
. . .
switch( *element ) {
case '(' : stos.push( '(' ); break;
case ')' : while( ( symbol = stos.pop() ) != '(' ) dopiszZnak( onp, symbol );
break; case '+' :
case '-' : case '*' :
case '/' : while( !stos.empty() ) {
if( priorytet( element ) >= priorytet( stos.peek() ) ) break;
dopiszZnak( onp, stos.pop() ); }
stos.push( *element ); break;
default : if( sscanf( element, "%lf", &liczba ) == 1 ) strcat( strcat( onp, element ), " " ); break;
}
element = strtok( 0, separatory ); // Pobranie następnego elementu wyrażenia
}
return onp; }
Rozważane tutaj operatory + - * / są lewostronnie łączne