Uniwersytet Zielonogórski
Instytut Sterowania i Systemów Informatycznych Ćwiczenie 3 — stos
Laboratorium Metod i Języków Programowania
Celem ćwiczenia jest zapoznanie studentów z najprostszą dynamiczną strukturą danych:
stosem.
1 Przebieg ćwiczenia
Uwaga: Typy danych przechowywanych w dowolnego rodzaju dynamicznych struk- turach danych są oczywiście dowolne (np. liczby całkowite itd. ).
Następujące operacje są wspólne dla większości dynamicznych struktur danych, nie tylko dla stosów:
• Definicja typu rekordowego
• Obecność wskaźnika głównego na element struktury
• Dodawanie nowego elementu do struktury
• Usuwanie elementu ze struktury
1.1 Definicja typu rekordowego
Dynamiczne struktury danych składają się z połączonych ze sobą przy pomocy wskaźników zmiennych dynamicznych. Dodatkowo każda zmienna dynamiczna przechowuje dane (co jest podstawowym przeznaczeniem dynamicznej struktury danych). Z tego powodu każda struktura dynamiczna posiada co najmniej:
• Składową przechowującą dane
• Wskaźnik na (następny) element struktury dynamicznej
W bardziej zaawansowanych strukturach takich wskaźników może być więcej, niż jeden.
Definicja typu rekordowego, służącego do przechowywania liczb typuintegerw najprostszym przypadku ma zatem postać
t y p e
T W s k a z n i k N a S t r u k t u r e = ^ T T y p S t r u k t u r y ; T T y p S t r u k t u r y = r e c o r d
D A N E : i n t e g e r ;
N a s t e p n y : T W s k a z n i k N a S t r u k t u r e ; end ;
1.2 Tworzenie wskaźnika głównego
Przed rozpoczęciem tworzenia konieczne jest określenie sposobu odwoływania się do dynamicz- nej struktury danych. W tym celu najczęściej wykorzystuje się zwykły wskaźnik do struktu- ry (zmienną typu TWskaznikNaStrukture), deklarowany jako zwykła zmienna (niedynamiczna).
Wskaźnik taki jest zwykłym wskaźnikiem na typ TWskaznikNaStrukture, dlatego tworzony jest w następujący sposób:
var W i e r z c h o l e k : T W s k a z n i k N a S t r u k t u r e ;
Należy zauważyć, że wskaźnik ten nie wskazuje na żadne użyteczne dane. Z tego powodu w tym momencie odwołanie się do tego, na co wskazuje ten wskaźnik jest błędne. Zostanie on użyty do utworzenia nowej zmiennej dynamicznej.
Wierzcholek
Śmieci
1.3 Tworzenie elementarnej stuktury:
Każdą tworzoną dynamicznie strukturę należy utworzyć przy pomocy instrukcji
new ( W i e r z c h o l e k );
NastępnyDANE ??
Wierzcholek
Śmieci
Następnie należy przypisać polom nowoutworzonej struktury dynamicznej określone dane (w przykładzie jest to liczba 1).
W i e r z c h o l e k ^. D A N E : = 1 ;
NastępnyDANE 1
Wierzcholek
Śmieci
Dodatkowo można również przypisać wskaźnikowi Wierzcholek^.Nastepny wartość NIL. Stanowi to dodatkowe zabezpieczenie przed popełnieniem błędu przez programistę podczas dalszego tworzenia dynamicznej struktury danych. W przypadku stosu linia ta nie jest jednak konieczna, gdyż w następnym kroku jego tworzenia wskaźnik ten wskaże na następny element stosu.
W i e r z c h o l e k ^. N a s t e p n y := NIL ;
NastępnyDANE 1 NIL
Wierzcholek
Jedną z najprostszych w implementacji dynamicznych struktur danych jest stos.
2 Tworzenie stosu
Stos jest dynamiczną strukturą danych, w której dołączanie i usuwanie elementów zachodzi tylko w jednym miejscu: na wierzchołku . Stos można wyobrazić sobie jako stos książek:
chcąc wyjąć jedną, należy wcześniej wyjąć wszystkie znajdujące się powyżej: Wskaźnik główny (Wierzcholek) ma zawsze wskazywać na wierzchołek stosu.
NastępnyDANE 1 NIL
Wierzcholek
NastępnyDANE 2 NastępnyDANE 3
Dodawanie nowych danych Usuwanie danych
Wskaźnik wskazujący zawsze na wierzchołek stosu
Wartość NIL oznaczająca koniec stosu
Rysunek 1: Gotowy stos
Aby usunąć element o wartości w polu DANE równej 2 należy najpierw usunąć wszystkie elementy znajdujące się przed usuwanym elementem (w przykładzie będzie to element o wartości 3 w polu DANE).
2.1 Tworzenie pierwszego elementu
new ( W i e r z c h o l e k );
W i e r z c h o l e k ^. D A N E := 1;
W i e r z c h o l e k ^. N a s t e p n y := NIL ;
To już jest stos, tyle, że nieco mało użyteczny. . . .
NastępnyDANE 1 NIL
Wierzcholek
2.2 Następne elementy
Od teraz dodawanie każdego nowego elementu będzie przebiegało identycznie:
Najpierw należy utworzyć elementarną ”cegiełkę” — nową zmienną dynamiczną (typu
TTypStruktury), która zostanie dodany do stosu. Aby to uczynić niezbędne jest zadeklarowa- nie pomocniczego wskaźnika Tmp
var Tmp : T W s k a z n i k N a S t r u k t u r e ;
Tmp
Śmieci
Przy pomocy wskaźnika Tmptworzona jest nowa zmienna dynamiczna
new ( Tmp );
Tmp ^. D A N E := 2;
Tmp ^. N a s t e p n y := NIL ; { To p r z y p i s a n i e w z a s a d z i e nie j e s t k o n i e c z n e , g d y ż z a r a z Tmp ^. N a s t e p n y z o s t a n i e z m i e n i o n y }
NIL
Tmp NastępnyDANE 1
Wierzcholek
NastępnyDANE 2 NIL
Następnie można połączyć tę nową ”cegiełkę” z resztą stosu:
Tmp ^. N a s t e p n y := W i e r z c h o l e k ;
NastępnyDANE 1 NIL
Wierzcholek
NastępnyDANE 2
Tmp
Ponieważ w przypadku stosu KONIECZNE jest zapewnienie, aby Wierzchołek wskazywał na rzeczywisty wierzchołek stosu, dlatego należy go przesunąć. Przy tej operacji wystarczy zauważyć, że wskaźnik Tmp wskazuje na wierzchołek stosu.
W i e r z c h o l e k := Tmp ;
NastępnyDANE 1 NIL
Wierzcholek
NastępnyDANE 2
(Gotowy stos; Zmienna Tmpnie jest już potrzebna i można ją wykorzystać do innych celów)
2.3 Dodawanie nowego elementu do stosu o dwóch elementach
Należy zauważyć, że dodawanie danych do stosu o dowolnym rozmiarze (od pustego stosu aż do utworzenia potrzebnej liczby elementów) przebiega zawsze w ten sam, omówiony w poprzednich podpunktach, sposób:
• utworzenie nowej zmiennej dynamicznej
new ( Tmp );
Tmp ^. D A N E := 3;
NastępnyDANE 1 NIL
Tmp
Śmieci
NastępnyDANE 2
NastępnyDANE 3
Wierzcholek
• podpięcie jej na wierzchołek stosu:
Tmp ^. N a s t e p n y := W i e r z c h o l e k ;
NastępnyDANE 1 NIL
Tmp
NastępnyDANE 2 NastępnyDANE 3
Wierzcholek
• przeniesienie wskaźnika Wierzcholek na wierzcholek stosu.
W i e r z c h o l e k := Tmp ;
NastępnyDANE 1 NIL
Tmp
NastępnyDANE 2 NastępnyDANE 3
Wierzcholek
Gotowy stos. ZmiennaTmpnie jest już potrzebna i można ją wykorzystać do innych celów. Aby ułatwić sprawdzanie błędów należy jednak ustawić ten wskaźnik na NIL:
Tmp := NIL ;
Tmp
NIL Dodawanie pozostałych elementów następuje analogicznie.
3 Usuwanie elementów ze stosu
Przy usuwaniu elementu ze stosu również niezbędne będzie użycie pomocniczego wskaźnikaTmp:
var Tmp : T W s k a z n i k N a S t r u k t u r e ;
Tmp
Śmieci
Przed usunięciem elementu należy odczytać przechowywaną przez niego (w polu DANE) wartość
— po usunięciu zmiennej dynamicznej nie będzie to możliwe. Jako przykład wykorzystania wartości w tym polu przyjmijmy jego wypisanie na ekranie:
w r i t e l n ( W i e r z c h o l e k ^. D A N E );
Najczęściej usuwanie danych ze stosu realizowanej jest przy pomocy funkcji zwracającej usunię- ty element. Z tego powodu najczęściej wpisuje się Wierzcholek^.DANE do zmiennej pomocniczej, której wartość używana jest jako wartość zwracana z funkcji:
f u n c t i o n U s u n Z e S t o s u ( var W i e r z c h o l e k : T W s k a z n i k N a S t r u k t u r e ) : I n t e g e r ; var w a r t o s c Z w r a c a n a : I n t e g e r ;
{ . . . }
w a r t o s c Z w r a c a n a := W i e r z c h o l e k ^. D A N E ; { u s u w a n i e e l e m e n t u }
U s u n Z e S t o s u := w a r t o s c Z w r a c a n a ;
Przy pomocy zmiennej tymczasowej Tmpnależy przejść na następny element stosu:
Tmp := W i e r z c h o l e k ^. N a s t ę p n y ;
NastępnyDANE 1 NIL
NastępnyDANE 2 NastępnyDANE 3
Wierzcholek Tmp
Przygotowanie danych do usunięcia.
Zmienna dynamiczna na którą wskazuje wskaźnik Wierzcholek zostanie za chwilę usunięta. Dla ułatwienia sprawdzania błędów można najpierw ustawić wskaźnik Wierzcholek^.Następny (na poniższym rysunku oznaczony kolorem czerwonym) na NIL.
UWAGA: PRZED ”odcięciem” zmiennej dynamicznej, na którą wskazuje wskaźnik Wierzcholek
od reszty stosu KONIECZNE jest zapewnienie, że na resztę struktury wskazuje jakiś inny wskaźnik — tutajTmp. Jeśli tak nie będzie, wtedy NIE MA MOŻLIWOŚCI NAPRAWY TEGO BŁĘDU — STRUKTURA ZOSTANIE NIEODWRACALNIE UTRACONA!!!).
W i e r z c h o l e k ^. N a s t ę p n y := NIL ;
NastępnyDANE 1 NIL
Tmp
NastępnyDANE 2
NastępnyDANE 3
Wierzcholek
NIL
Pojedyncza zmienna dynamiczna, na którą wskazuje wskaźnikWierzchołek została ”odcięta” od reszty stosu. Na pozostałą część stosu wskazuje zmienna Tmp
Teraz można już usunąć element na wierzchołku stosu:
d i s p o s e ( W i e r z c h o l e k ); { U s u n i ę c i e z m i e n n e j d y n a m i c z n e j , na k t ó r ą w s k a z u j e w s k a ź n i k W i e r z c h o l e k . }
Po wykonaniu tej linii, wskaźnikWierzcholekNIE wskazuje na żaden użyteczny obszar pamięci.
Napisanie więc Wierzcholek^.cokolwiek jest BŁĘDNE).
Można jednak oczywiście nadal zmieniać wartość wskaźnika (to, na co ma wskazywać wskaźnik). Poprawne jest więc przypisanie wskaźnikowi Wierzchołek dowolnej wartości (np.
Wierzchołek:=NIL). Po wykonaniu instrukcji dispose(Wierzcholek); wskaźnik Wierzchołek wska- zuje na bezużyteczne dane:
NastępnyDANE 1 NIL
Tmp
NastępnyDANE 2
Wierzcholek
Śmieci
Ponieważ wskaźnik Wierzchołek powinien zawsze wskazywać na wierzchołek stosu, dlatego ko- nieczne jest jego ponowne ustawienie na wierzchołek pozostałej części stosu (na którą aktualnie wskazuje wskaźnikTmp):
W i e r z c h o l e k := Tmp ;
Teraz Wierzcholek znowu wskazuje na użyteczną zmienną dynamiczną - na początek stosu.
Zmienna TMP nie jest już potrzebna i może zostać użyta do innych celów.
NastępnyDANE 1 NIL
Wierzcholek
NastępnyDANE 2
Usuwanie pozostałych elementów realizuje się analogicznie.
4 Zadania
1. Zaimplementować funkcję służącą do dodawania elementów do stosu
2. Zaimplementować funkcję służącą do usuwania elementów stosu. W przypadku próby usunięcia elementu z pustego stosu należy wypisać komunikat o błędzie.
3. Przy pomocy funkcji z p. 1 i 2, dodać do stosu po kolei liczby: 1,2,3,4,5,6,7,8,9,10. Na- stępnie usunąć wszystkie elementy. Po usunięciu każdego z nich wypisać wartość liczby na ekranie.
4. Zaimplementować program służący do wyznaczania wartości wyrażenia arytmetycznego podanego w formie ONP (Odwrotnej Notacji Polskiej). Do wykonania zadania użyć stosu.
Założyć, że wyrażenie jest:
• Podane z klawiatury jako łańcuch znaków
• Wczytywane z pliku tekstowego