Podstawy programowania II Zachodniopomorska Szkoła Biznesu Podstawy programowania II Wykład 5: Dynamiczne struktury danych
Podstawy programowania II - Dynamiczne struktury danych Dane - model rzeczywistości Złożoność i wielość danych opisujących dany problem Potrzeba organizacji danych w logiczne całości zwane strukturami danych grupowanie danych w sposób odzwierciedlający rzeczywiste związki pomiędzy danymi opis podobnych obiektów za pomocą jednakowych zestawów danych Korzyści płynące z budowy struktur danych ułatwienie projektowania oprogramowania możliwość automatyzacji przetwarzania danych efektywniejsze zarządzanie pamięcią Podstawy programowania II - Dynamiczne struktury danych
Statyczne struktury danych W przypadku problemów prostych i ograniczonych pod względem liczby przetwarzanych danych stosuje się struktury statyczne, których rozmiary i organizacja są niezależne od samych danych i liczby obiektów Typowe dane statyczne: dane proste tablice statyczne danych prostych rekord tablica statyczna rekordów Podstawy programowania II - Dynamiczne struktury danych
Dynamiczne struktury danych Jeżeli problem jest złożony lub dane bardzo liczne, użycie statycznych struktur powoduje: niemożność efektywnego zarządzania pamięcią niemożność odzwierciedlenia związków pomiędzy poszczególnymi obiektami wśród przetwarzanych danych Rozwiązaniem jest tworzenie dynamicznych struktur danych, których organizacja w pewnym stopniu budowana jest już na etapie wykonania programu. Wymaga to: dynamicznego zarządzania pamięcią organizacji danych w struktury zawierające m.in. powiązania pomiędzy obiektami Pozwala to na odzwierciedlenie związków pomiędzy obiektami, co umożliwia znacznie efektywniejsze przetwarzanie danych (np. wyszukiwanie, sortowanie itp.) Podstawy programowania II - Dynamiczne struktury danych
Tworzenie struktur dynamicznych Elementarną strukturą danych w tym ujęciu jest rekord, który stanowi opis pojedynczego obiektu za pomocą pewnej liczby prostych danych (lub niewielkich struktur statycznych) Element, który jest charakterystyczny dla struktur dynamicznych to wprowadzenie do każdego rekordu jednego lub kilku powiązań z innymi obiektami (podobnego lub innego typu) W przypadku języka C++: rekordy mają postać struktur (lub klas) powiązania mają postać wskaźników poszczególne obiekty tworzone są za pomocą dynamicznej alokacji pamięci Podstawy programowania II - Dynamiczne struktury danych
Typowe struktury dynamiczne Lista jednokierunkowa dwukierunkowa cykliczna Drzewo drzewo binarne Kolejka (zastosowanie listy) FIFO LIFO (Stos) Podstawy programowania II - Dynamiczne struktury danych
Lista jednokierunkowa Model: Deklaracja w C++: struct Rekord { // zestaw danych ma temat jakiegoś obiektu,np. float dana; Rekord *next; // wskaźnik na następny rekord }; Rekord *begin=NULL; // wskaźnik na początek listy // NULL oznacza ostatni rekord // na początku lista jest pusta ... Dane 1 begin Dane 2 Dane n Podstawy programowania II - Dynamiczne struktury danych
Podstawy programowania II - Dynamiczne struktury danych Przeglądanie listy Służy do tego wskaźnik, który początkowo wskazuje na początek listy, a następnie cyklicznie przesuwa się na element następny aż do napotkania wartości NULL; void PokazListe() { if (begin==NULL) cout << "Lista pusta!\n"; else { Rekord *r=begin; while (r!=NULL) { cout << r->dana<< endl; r=r->next; } } } Podstawy programowania II - Dynamiczne struktury danych
Pusta lista i dodawanie obiektów Lista pusta: begin Dodanie elementu do listy: Dane 1 begin Dodanie drugiego elementu (na koniec listy): Dane 1 begin Dane 2 Dodanie trzeciego elementu (na początek listy): Dane 1 begin Dane 2 Dane 3 Dodanie czwartego elementu (w środek listy): Dane 1 begin Dane 2 Dane 3 Dane 4 Podstawy programowania II - Dynamiczne struktury danych
Dodanie obiektu do listy (C++) Dodanie nowego obiektu na koniec listy: Rekord *el=new Rekord; // pominiemy tu kontrolę błędów alokacji cin >> el->dana; el->next=NULL; // nowy obiekt będzie ostatni Rekord *wsk=begin; if (wsk==NULL) // lista jest pusta begin=el; else { while (wsk->next!=NULL) // znalezienie końca wsk=wsk->next; wsk=el; } Dodanie nowego obiektu na początek listy: Rekord *el=new Rekord; cin >> el->dana; el->next=begin; // dawny pierwszy element begin=el; Podstawy programowania II - Dynamiczne struktury danych
Usuwanie obiektu z listy Usunięcie obiektu w środku listy Dane 1 Dane 2 Dane 3 begin Usunięcie obiektu na początku listy Dane 1 Dane 2 Dane 3 begin Usunięcie obiektu na końcu listy Dane 1 Dane 2 Dane 3 begin Podstawy programowania II - Dynamiczne struktury danych
Usuwanie obiektu (C++) Usunięcie pierwszego obiektu listy: if (wsk!=NULL) // lista nie jest pusta { Rekord *pierwszy=begin; begin=begin->next; delete pierwszy; } Usunięcie ostatniego obiektu z listy: if (wsk!=NULL) // lista nie jest pusta { Rekord *rek=begin; while ((rek->next)->next!=NULL) // przedost. rek=rek->next; delete rek->next; rek->next=NULL; } Podstawy programowania II - Dynamiczne struktury danych
Przykład listy jednokierunkowej Program LISTA.CPP Podstawy programowania II - Dynamiczne struktury danych
Wskaźnik na koniec listy Często występuje konieczność wykonania operacji na końcu listy (np. dopisanie nowego rekordu) W takich wypadkach konieczne jest przeglądniecie całej listy po kolei aby dojść do końca Przydatne może być zapamiętanie wskaźnika na ostatni rekord listy (wskaźnik ten będzie się zmieniał przy dodaniu elementu na koniec lub usunięciu ostatniego elementu) Model: ... Dane 1 Dane n begin end Podstawy programowania II - Dynamiczne struktury danych
Lista cykliczna jednokierunkowa Model: Ponieważ nie ma tu elementu ostatniego, podczas przeglądania listy należy pamiętać albo liczbę elementów albo sprawdzać czy adres elementu następnego jest równy begin. Wskaźnik begin może być przestawiony na dowolny z elementów listy (można przestawić jej początek) Zastosowanie: zapamiętywanie danych zawierających cykl, np. dane związane z kolejnymi miesiącami roku. Struktura rekordu identyczna jak dla zwykłej listy jednokierunkowej Dane 1 begin Dane 2 Dane n Podstawy programowania II - Dynamiczne struktury danych
Podstawy programowania II - Dynamiczne struktury danych Lista dwukierunkowa Model: Deklaracja w C++: struct Rekord { float dana; // przykładowe dane właściwe Rekord *prev; // wskaźnik na poprzedni rekord Rekord *next; // wskaźnik na następny rekord }; Rekord *begin=NULL; Rekord *end=NULL; // nie zawsze jest tworzony ... Dane 1 Dane 2 Dane n begin end Podstawy programowania II - Dynamiczne struktury danych
Lista cykliczna dwukierunkowa Model: Ponieważ nie ma tu w zasadzie elementu pierwszego ani ostatniego, podczas przeglądania listy należy pamiętać albo liczbę elementów albo sprawdzać czy adres elementu następnego jest równy begin. Wskaźnik begin może być przestawiony na dowolny z elementów listy (można przestawić jej umowny początek) Zastosowanie: zapamiętywanie danych zawierających cykl, np. dane związane z kolejnymi miesiącami roku. Struktura rekordu identyczna jak dlazwykłej listy dwukierunkowej ... Dane 1 Dane 2 Dane n begin Podstawy programowania II - Dynamiczne struktury danych
Podstawy programowania II - Dynamiczne struktury danych Cechy list Łatwość wstawiania i usuwania elementów Możliwość całkowitej zmiany kolejności elementów (np. sortowanie) Dostęp sekwencyjny do poszczególnych elementów (konieczność przeszukiwania listy w celu dostępu do elementu o określonym numerze) W przypadku listy jednokierunkowej przeszukiwanie odbywa się zawsze od elementu pierwszego w stronę ostatniego Lista dwukierunkowa umożliwia przeszukiwanie elementów w obu kierunkach, a nawet wielokrotną zmianę kierunku przeglądania. Podstawy programowania II - Dynamiczne struktury danych
Podstawy programowania II - Dynamiczne struktury danych Lista z atrapą (1) W wielu rodzajach list tworzy się zawsze jeden rekord zwany atrapą Jedynymi danymi, jakie są wypełnione w atrapie są powiązania (brak danych właściwych ) Celem tworzenia atrapy jest zapewnienie aby lista nigdy nie była pusta, a wskaźniki begin i end nigdy nie miały wartości NULL. Ułatwia to opracowywanie algorytmów przetwarzających listę usunięcie warunku czy lista jest pusta ułatwienie dopisania pierwszego lub ostatniego elementu W przypadku listy dwukierunkowej, atrapa może występować zarówno na początku, jak i na końcu listy Podstawy programowania II - Dynamiczne struktury danych
Podstawy programowania II - Dynamiczne struktury danych Lista z atrapą (2) Atrapa begin Dane n Lista jednokierunkowa z atrapą ... Atrapa Dane n begin end Lista dwukierunkowa z atrapą ... Atrapa begin Dane n Lista cykliczna jednokierunkowa z atrapą ... Lista cykliczna dwukierunkowa z atrapą Atrapa Dane n begin ... Podstawy programowania II - Dynamiczne struktury danych
Kolejka FIFO (First In First Out) Dopuszczalne operacje: dopisanie elementu na początek listy odczyt elementu z końca listy wraz z jego usunięciem Realizacja może opierać się o listę jednokierunkową Przykład realizacji: program FIFO.CPP Podstawy programowania II - Dynamiczne struktury danych
Stos (kolejka LIFO - Last In First Out) Dopuszczalne operacje: dopisanie elementu na początek listy odczyt pierwszego elementu z listy wraz z jego usunięciem Realizacja może opierać się o listę jednokierunkową Przykład realizacji: program LIFO.CPP Podstawy programowania II - Dynamiczne struktury danych
Podstawy programowania II - Dynamiczne struktury danych Drzewa (1) Drzewo to struktura dynamiczna o budowie hierarchicznej Każdy element posiada jednego rodzica i może mieć kilka elementów potomnych Model korzeń Dane 1 Dane 11 Dane 12 węzły Dane 13 Dane 121 Dane 122 Dane 123 Dane 131 Dane 132 Dane 1321 liście Podstawy programowania II - Dynamiczne struktury danych
Podstawy programowania II - Dynamiczne struktury danych Drzewa (2) Drzewo daje możliwość odzwierciedlenia hierarchii obiektów występującej w rzeczywistości przykład: zapis drzewa genealogicznego Inną możliwością zastosowania drzewa jest optymalizacja przeszukiwania dużych zbiorów obiektów. Celem jest umożliwienie dojścia do szukanego obiektu jak najkrótszą drogą Warunkiem jest odpowiednie uporządkowanie obiektów już na etapie ich dodawania do drzewa Algorytm przeglądania drzewa nie jest jednoznaczny, np. przeglądanie poziomami od korzenia do liści przeglądanie od gałęzi lewej do prawej Podstawy programowania II - Dynamiczne struktury danych
Podstawy programowania II - Dynamiczne struktury danych Drzewa binarne Drzewo binarne to drzewo, w którym każdy węzeł posiada dokładnie dwa powiązania z węzłami potomnymi Model: Dane 1 Dane 11 Dane 12 Dane 111 Dane 112 Dane 121 Dane 122 Dane 1121 Dane 1122 Dane 1211 Podstawy programowania II - Dynamiczne struktury danych
Podstawy programowania II - Dynamiczne struktury danych Drzewa binarne (C++) Deklaracja: struct Rekord { float dana; // przykładowe dane właściwe Rekord *child1, *child2; // obiekty potomne }; Rekord *root=NULL; // korzeń Podstawy programowania II - Dynamiczne struktury danych
NULL