Programowanie i struktury danych 1 / 19
Dynamiczne struktury danych Dynamiczną strukturą danych nazywamy taka strukturę danych, której rozmiar, a więc liczba przechowywanych w niej danych, może się dowolnie zmieniać w czasie działania programu. Struktury danych umożliwiają dostęp do danych w nich zapisanych. Przykłady liniowych struktur to m.in. listy, stosy, kolejki. Nieliniowe struktury to m.im grafy. Stosowanie struktur danych jest niezbędne w wielu algorytmach. 2 / 19
Lista jednokierunkowa Lista jednokierunkowa składa się z elementów, z których każdy element przechowuje wskaźnik do następnego elementu. Ostatni element ma wskaźnik do następnego ustawiony na NULL (adres pusty). [A=head, D=tail] Najczęściej elementy listy tworzymy używając struktury struct wezel // tu dowolne dane wezel * next ; Pole next jest miejscem, do którego można zapisać adres kolejnej struktury. 3 / 19
Listy jednokierunkowe W przeciwieństwie do tablicy, przechowywane dane listy nie muszą być położone w sąsiednich obszarach. Zalety listy jednokierunkowej: ciąg danych można zapisać w postaci łańcucha identyfikowanego przez pojedynczą zmienną (nie jest potrzebny iterator). 4 / 19
Przykłady listy jednokierunkowej struct osoba string imie ; string nazwisko ; int wiek ; float pensja ; osoba * nastepna ; struct wezel int dana ; wezel * next ; 5 / 19
Tworzenie węzła (dopisywanie na końcu listy) 1 utworzenie zmiennej typu node 2 uzupełnienie danych 3 dopisanie w polu next wartości NULL 4 dołączenie nowego węzła poprzez przypisanie w polu next aktualnie ostatniego węzła wskaźnika na nowy węzeł. struct wezel int dana ; wezel * next ; 6 / 19
Tworzenie węzła (dopisywanie na końcu listy) 1 utworzenie zmiennej typu node 2 uzupełnienie danych 3 dopisanie w polu next wartości NULL 4 dołączenie nowego węzła poprzez przypisanie w polu next aktualnie ostatniego węzła wskaźnika na nowy węzeł. struct wezel int dana ; wezel * next ; 7 / 19
Tworzenie węzła (dopisywanie na końcu listy) 1 utworzenie zmiennej typu node 2 uzupełnienie danych 3 dopisanie w polu next wartości NULL 4 dołączenie nowego węzła poprzez przypisanie w polu next aktualnie ostatniego węzła wskaźnika na nowy węzeł. struct wezel int dana ; wezel * next ; 8 / 19
Tworzenie węzła (dopisywanie na końcu listy) 1 utworzenie zmiennej typu node 2 uzupełnienie danych 3 dopisanie w polu next wartości NULL 4 dołączenie nowego węzła poprzez przypisanie w polu next aktualnie ostatniego węzła wskaźnika na nowy węzeł. struct wezel int dana ; wezel * next ; 9 / 19
Tworzenie węzła (dopisywanie na końcu listy) 1 utworzenie zmiennej typu node 2 uzupełnienie danych 3 dopisanie w polu next wartości NULL 4 dołączenie nowego węzła poprzez przypisanie w polu next aktualnie ostatniego węzła wskaźnika na nowy węzeł. struct wezel int dana ; wezel * next ; 10 / 19
Tworzenie węzła (dopisywanie na końcu listy) 1 utworzenie zmiennej typu node 2 uzupełnienie danych 3 dopisanie w polu next wartości NULL 4 dołączenie nowego węzła poprzez przypisanie w polu next aktualnie ostatniego węzła wskaźnika na nowy węzeł. struct wezel int nr ; wezel * next ; int main () wezel * head ; // deklarujemy glowe head = new wezel ; // rezerwujemy pamiec dla glowy i przypisujemy // adres do zmiennej head head >nr = 0 ; // nadajemy wartosci skladowym wezla glowa head >next = NULL ; // glowa jest ogonem delete head ; return 0 ; 11 / 19
int main () wezel * head ; // deklarujemy glowe head = new wezel ; // rezerwujemy pamiec dla glowy i przypisujemy // adres do zmiennej head head >nr = 0 ; // nadajemy wartosci skladowym wezla glowa head >next = NULL ; // glowa jest ogonem delete head ; return 0 ; 12 / 19
int main () wezel * head ; // deklarujemy glowe head = new wezel ; // rezerwujemy pamiec dla glowy i przypisujemy // adres do zmiennej head head >nr = 0 ; // nadajemy wartosci skladowym wezla glowa head >next = NULL ; // glowa jest ogonem wezel *w1 ; // deklarujemy wezel w1 = new wezel ; // rezerwujemy dla niego pamiec i przypisujemy mu adres w1 >nr = 1 ; // nadajemy wartosci skladowym tego wezla w1 >next = NULL ; // wezel bedzie ogonem head >next = w1 ; // glowa poprzedza wezel ( wezel jest ogonem ) delete w1, head ; return 0 ; 13 / 19
int main () wezel * head ; // deklarujemy glowe head = new wezel ; // rezerwujemy pamiec dla glowy i przypisujemy // adres do zmiennej head head >nr = 0 ; // nadajemy wartosci skladowym wezla glowa head >next = NULL ; // glowa jest ogonem wezel *w1 ; // deklarujemy wezel w1 = new wezel ; // rezerwujemy dla niego pamiec i przypisujemy mu adres w1 >nr = 1 ; // nadajemy wartosci skladowym tego wezla w1 >next = NULL ; // wezel bedzie ogonem head >next = w1 ; // glowa poprzedza wezel ( wezel jest ogonem ) wezel w2 ; // deklarujemy wezel statyczny w2. nr = 2 ; // nadajemy wartosci skladowym tego wezla w2. next = NULL ; // wezel bedzie ogonem w1 >next = & w2 ; // wezel jest ogonem (!) delete w2,w1, head ; return 0 ; 14 / 19
test30.cpp int main () wezel * head ; // deklarujemy glowe head = new wezel ; // rezerwujemy pamiec dla glowy i przypisujemy // adres do zmiennej head head >nr=0 ; // nadajemy wartosci skladowym wezla glowa head >next=null ; // glowa jest ogonem wezel *w1 ; // deklarujemy wezel w1 = new wezel ; // rezerwujemy dla niego pamiec i przypisujemy mu adres w1 >nr=1 ; // nadajemy wartosci skladowym tego wezla w1 >next=null ; // wezel bedzie ogonem head >next = w1 ; // glowa poprzedza wezel ( wezel jest ogonem ) wezel w2 ; // deklarujemy wezel statyczny w2. nr = 2 ; // nadajemy wartosci skladowym tego wezla w2. next = NULL ; // wezel bedzie ogonem w1 >next = & w2 ; // wezel jest ogonem (!) wezel w3 = 3, NULL // deklarujemy wezel ( statyczny!) + // nadajemy wartosci skladowym + wezel bedzie ogonem w2. next = & w3 ; // wezel jest ogonem delete w3,w2,w1, head ; return 0 ; 15 / 19
Lista jednokierunkowa - operacje na listach Bardzo wygodną własnością list jest fakt, że aby operować na liście, wystarczy adres jej pierwszego elementu; mając dostęp do pierwszego elementu, możemy w jego składowej next znaleźć adres następnego itd. 16 / 19
Lista jednokierunkowa - operacje na listach Dla przykładu zdefiniujemy funkcje wypisujące zawartość listy (jest to kontynuacja poprzedniego kodu). test31.cpp struct wezel int nr ; wezel * next ; void drukuj_liste ( const wezel * w) ; // prototyp funkcji int main ()... drukuj_liste (head ) ; delete head,w1,w2,w3 ; return 0 ; void drukuj_liste ( const wezel * w) for ( ; w ; w = w >next ) cout<<( int )w<<endl ; cout<<" ------------------\n" ; cout<<"nr = "<<setw (12)<<w >nr<<" "<<endl ; cout<<" ------------------\n" ; cout<<" next = "<<setw (10)<<( int ) w >next<<" "<<endl ; cout<<" ------------------\n" ; cout<<" \n" ; cout<<" V \n" ; cout<<"null \n" ; 17 / 19
Lista jednokierunkowa - operacje na listach test32.cpp int main ()... drukuj_liste (head ) ; cout<<"null \n" ; cout<<"\na TERAZ ODWROTNIE \n"<<endl ; cout<<"null \n" ; drukuj_liste_odwrotnie (head ) ; delete head,w1,w2,w3 ; return 0 ;... void drukuj_liste_odwrotnie ( const wezel * n) if (n == NULL ) // pusta lista cout<<"null \n" ; return ; if (n >next!= NULL ) ; drukuj_liste_odwrotnie (n >next ) ; cout<<" ^ \n" ; cout<<" \n" ; cout<<" ------------------\n" ; cout<<"nr = "<<setw (12)<<n >nr<<" "<<endl ; cout<<" ------------------\n" ; cout<<" next = "<<setw (10)<<( int ) n >next<<" "<<endl ; cout<<" ------------------\n" ; cout<<( int )n<<endl ; 18 / 19
Dziękuję za uwagę!!! 19 / 19