Page 1 Nazwa przedmiotu: Algorytmy i złoŜoność (Laboratorium

advertisement
Nazwa przedmiotu: Algorytmy i złoŜoność (Laboratorium)
Prowadzący zajęcia: mgr inŜ. Przemysław Pardel
Laboratorium 10
LP
Zakres materiału
Czas
realizacji
Abstrakcyjne struktury danych i ich implementacje: stosy kolejki, listy, drzewa,
grafy, słowniki, haszowanie, kolejki priorytetowe, drzewa poszukiwań binarnych.
7.
9
Czas realizacji zadań: 3 godziny
Teoria:
Lista
Lista - rodzaj kontenera, dynamiczna struktura danych używana w informatyce, składająca
się z podstruktur wskazujących na następniki i/lub poprzedniki.
Najprościej listę moŜna określić jako skończony ciąg elementów naleŜących do pewnego zbioru.
JeŜeli jest to ciąg
e1,e2,…,en
to listę zapisuje się w postaci:
(e1,e2,…,en).
wskaźnik na
pierwszy element
e1
…
e2
en
nil
Elementarny składnik tej struktury składa się z dwóch pól, które moŜna traktować jako odrębne
komórki pamięci. Pierwsze z pól zawiera sam pamiętany element (jego zawartość informacyjną), a
drugie tzw. wskaźnik informujący o połoŜeniu następnego elementu w liście. Wyjątkiem jest ostatni
składnik, którego wskaźnik odwołuje się do elementu pustego (nil). Wskaźnik na pierwszy element
pamiętany jest w specjalnie do tego celu przeznaczonej zmiennej (head).
Struktura taka jest przykładem tzw. listy jednokierunkowej, w której pojedynczy składnik
zawiera wskaźnik tylko na element następny.
Najczęściej listę przedstawia się w postaci bardziej rozbudowanej struktury określanej jako lista
dwukierunkowa.
wskaźnik na
pierwszy element
nil
e1
e2
…
en
nil
Pojedynczy składnik listy dwukierunkowej zawiera pole informacyjne i dwa pola wskaźników: lewy
wskazujący na poprzedni element oraz prawy wskazujący na element następny.
Istnieją dwie popularne implementacje struktury listy: tablicowa i wskaźnikowa.
Implementacja tablicowa
Jak wskazuje nazwa, lista zaimplementowana w ten sposób opiera się na tablicy obiektów (lub
rekordów) danego typu.
Dopisanie elementu do listy to wstawienie elementu do tablicy:
• jeśli ma ono nastąpić na końcu listy, będzie to kolejny element w tablicy;
•
jeśli nowy element ma znaleźć się między innymi elementami, naleŜy przesunąć o jedno
pole w prawo wszystkie elementy o indeksie wyŜszym niŜ pole, na które będzie wstawiany
obiekt; następnie w powstałą lukę wpisuje się nowy element.
Usunięcie elementu znajdującego się pod danym indeksem tablicy to przesunięcie o jedno pole
w lewo wszystkich elementów o indeksie wyŜszym.
Zalety tej implementacji: prosta nawigacja wewnątrz listy, korzystanie z gotowej struktury tablicy,
szybki dostęp do elementu o konkretnym numerze, większa odporność na błędy.
Wady: niska elastyczność, szczególnie dotycząca rozmiaru tablicy, złoŜoność operacji wstawiania i
usuwania.
Implementację tablicową stosuje się tam, gdzie elastyczność nie odgrywa istotnej roli, a wymagana
jest szybka i prosta nawigacja.
Implementacja wskaźnikowa
W tej implementacji kaŜdy obiekt na liście musi (co nie było konieczne w wersji tablicowej)
zawierać dodatkowy element: wskaźnik do innego obiektu tego typu. Wynika to z faktu, Ŝe to
wskaźniki są podstawą nawigacji w tym typie listy, a dostęp do jej elementów jest moŜliwy
wyłącznie przez wskaźnik.
Dopisanie elementu (dla prostej listy jednostronnej):
• jeśli ma ono nastąpić na końcu listy, to wskaźnik wiąŜący w obiekcie ostatnim ustawia się
na nowy obiekt danego typu;
• jeśli ma ono nastąpić wewnątrz listy, to najpierw tworzy się nowy obiekt danego typu i
jego wskaźnik wiąŜący ustawia się na następnik elementu, za którym ma być wstawiany.
Później wskaźnik poprzednika przestawia się na ten nowy obiekt. W tym przypadku bardzo
waŜna jest kolejność, której zachwianie jest częstą przyczyną błędów. Np. moŜna najpierw
przestawić wskaźnik poprzednika na nowy obiekt, co spowoduje bezpowrotną utratę
dostępu do dalszych elementów listy, na które juŜ nie będzie pokazywał Ŝaden wskaźnik.
Ustawienie wskaźnika nowego elementu na następnik nie będzie moŜliwe, bo nie będzie
znany jego adres.
Usunięcie elementu jest odwrotne do wstawiania: w pewnym miejscu zapisuje się wskaźnik do
usuwanego elementu (aby nie "zgubić" jego adresu), następnie wskaźnik wiąŜący poprzednika
przestawia się na następnik, i dopiero w tym momencie zwalnia się pamięć po obiekcie usuwanym
(do tego potrzebny jest ten wskaźnik tymczasowy).
Zalety i wady tej implementacji są komplementarne w stosunku do implementacji tablicowej.
Podstawowe operacje na listach
• Poszukiwanie elementu na liście
• Wstawianie elementu do listy
• Usuwanie elementu z listy
MoŜna wyróŜnić następujące rodzaje list:
• lista jednokierunkowa - w kaŜdym elemencie listy jest przechowywane odniesienie tylko
do jednego sąsiada (następnika lub poprzednika).
•
lista dwukierunkowa - w kaŜdym elemencie listy jest przechowywane odniesienie
zarówno do następnika jak i poprzednika elementu w liście. Taka reprezentacja umoŜliwia
swobodne przemieszczanie się po liście w obie strony.
•
lista cykliczna - następnikiem ostatniego elementu jest pierwszy element, a
poprzednikiem pierwszego ostatni. Po liście moŜna więc przemieszczać się cyklicznie. Nie
ma w takiej liście charakterystycznego ogona (ani głowy), często rozpoznawanego po tym,
Ŝe jego następnik jest pusty (NULL).
•
lista z wartownikiem - lista z wyróŜnionym elementem zwanym wartownikiem. Jest to
specjalnie oznaczony element niewidoczny dla programisty wykorzystującego listę. Pusta
lista zawiera wtedy tylko wartownika. Zastosowanie wartownika znacznie upraszcza
implementację operacji na listach.
Zadania do realizacji:
1. Zaimplementować listę jednokierunkową z wykorzystaniem:
a. tablicy jednowymiarowej,
b. tablicy wielowymiarowej,
c. dwóch tablic.
Zaimplementować do każdego z przypadków podstawowe operacje na listach.
2. Zaimplementować listę dwukierunkową z wykorzystaniem:
a. tablicy jednowymiarowej,
b. tablicy wielowymiarowej,
c. trzech tablic.
Zaimplementować do każdego z przypadków podstawowe operacje na listach.
Bibliografia:
1. Świder K.: Algorytmy i struktury danych
2. Wikipedia, Wolna encyklopedia, http://www.wikipedia.pl
Download