Lista dwukierunkowa - przykład implementacji destruktorów Bogdan Kreczmer ZPCiR IIAiR PWr pokój 307 budynek C3 bogdan.kreczmer@pwr.wroc.pl Copyright c 2006 2008 Bogdan Kreczmer Niniejszy dokument zawiera materiały do wykładu na temat programowania obiektowego. Jest on udostępiony pod warunkiem wykorzystania wyłacznie do własnych prywatnych potrzeb i może on być kopiowany wyłacznie w całości, razem z niniejsza strona tytułowa.
Lista dwukierunkowa 1 class ElementListy // public : ElementListy Poprz; ElementListy Naste; ElementListy( ) Poprz = Naste = NULL; ElementListy( ); ; // void WstawPrzed(ElementListy ElemNast); Klasa ElementListy pozwala na stworzenie struktur danych w postaci listy dwukierunkowej.
Element listy 2 class ElementListy // public : ElementListy Poprz; ElementListy Naste; ElementListy( ) Poprz = Naste = NULL; ElementListy( ); ; // void WstawPrzed(ElementListy ElemNast); ElementListy:: ElementListy( ) if ( Poprz) Poprz > Naste = Naste; if ( Naste) Naste > Poprz = Poprz; Destruktor klasy ElementListy umożliwia zachowanie poprawnej struktury listy po usunięciu dowolnego jej elementu.
Destrukcja elementu 3 ElementListy:: ElementListy( ) if ( Poprz) Poprz > Naste = Naste; if ( Naste) Naste > Poprz = Poprz; Rozważmy przebieg destrukcji środkowego elementu listy.
Destrukcja elementu 4 ElementListy:: ElementListy( ) if ( Poprz) Poprz > Naste = Naste; if ( Naste) Naste > Poprz = Poprz; Sprawdzamy, czy istnieje element poprzedzajacy.
Destrukcja elementu 5 ElementListy:: ElementListy( ) if ( Poprz) Poprz > Naste = Naste; if ( Naste) Naste > Poprz = Poprz; Dostajemy się do pola Naste w elemencie poprzednim.
Destrukcja elementu 6 ElementListy:: ElementListy( ) if ( Poprz) Poprz > Naste = Naste; if ( Naste) Naste > Poprz = Poprz; Zmodyfikowana zostaje zawartość pola Naste w elemencie poprzedzajacym, tak aby pole to zawierało adres elementu znajdujacego się za elementem usuwanym.
Destrukcja elementu 7 ElementListy:: ElementListy( ) if ( Poprz) Poprz > Naste = Naste; if ( Naste) Naste > Poprz = Poprz; Sprawdzamy, czy istnieje element następny.
Destrukcja elementu 8 ElementListy:: ElementListy( ) if ( Poprz) Poprz > Naste = Naste; if ( Naste) Naste > Poprz = Poprz; Dostajemy się do pola Poprz w elemencie następnym.
Destrukcja elementu 9 ElementListy:: ElementListy( ) if ( Poprz) Poprz > Naste = Naste; if ( Naste) Naste > Poprz = Poprz; Zmodyfikowana zostaje zawartość pola Poprz w elemencie następnym, tak aby pole to zawierało adres elementu znajdujacego się przed elementem usuwanym.
Destrukcja elementu 10 ElementListy:: ElementListy( ) if ( Poprz) Poprz > Naste = Naste; if ( Naste) Naste > Poprz = Poprz; Po zakończeniu destrukcji struktura listy pozostaje poprawna.
Element listy 11 class ElementListy // public : ElementListy Poprz; ElementListy Naste; ElementListy() Poprz = Naste = NULL; ElementListy(); ; // void WstawPrzed(ElementListy ElemNast); void ElementListy::WstawPrzed(ElementListy ElemNast) Naste = ElemNast; if (!ElemNast) Poprz = NULL; return ; if (ElemNast > Poprz) ( Poprz = ElemNast > Poprz) > Naste = this ; ElemNast > Poprz = this ; Metoda WstawPrzed pozwala na wstawienie elementu w dowolne jej miejsce przed końcem listy.
Lista z zarzadc a 12 class ZarzadcaListy // public: ElementListy Glowa; ZarzadcaListy( ) Glowa = NULL; ZarzadcaListy( ); ; // void DodajNaPoczatek( ElementListy welem); Wprowadzenie zarzadcy umożliwia lepsze zorganizowanie dostępu do listy oraz operacji realizowanych na liście.
Zarzadca listy 13 class ZarzadcaListy // public: ElementListy Glowa; ZarzadcaListy( ) Glowa = NULL; ZarzadcaListy( ); ; // void DodajNaPoczatek( ElementListy welem); ZarzadcaListy:: ZarzadcaListy( ) if (! Glowa) return ; while ( Glowa > Naste) delete Glowa > Naste; delete Glowa; Destruktor klasy ZarzadcaListy umożliwia usunięcie całej listy, która zarzadza.
Zarzadca listy 14 class ZarzadcaListy // public: ElementListy Glowa; ZarzadcaListy( ) Glowa = NULL; ZarzadcaListy( ); ; // void DodajNaPoczatek( ElementListy welem); void ZarzadcaListy::DodajNaPoczatek( ElementListy welem) if (!welem ) return ; welem > Poprz = welem > Naste = NULL; if (! Glowa ) Glowa = welem; return ; welem >WstawPrzed( Glowa); Glowa = welem; Wykorzystanie metody ElementListy::WstawPrzed pozwala w prosty sposób zaimplementować metodę ZarzadcaListy::DodajNaPoczatek.
Rozszerzony element listy 15 class RozElementListy // public : RozZarzadcaListy Zarzadca; RozElementListy Poprz; RozElementListy Naste; RozElementListy( ) Poprz = Naste = NULL; Zarzadca = NULL; RozElementListy( ); ; // void WstawPrzed(RozElementListy ElemNast); Destruktor klasy RozElementListy umożliwia zachowanie poprawnej struktury listy oraz wskazań zarzadcy po usunięciu dowolnego jej elementu.
Rozszerzony element listy 16 class RozElementListy // public : RozZarzadcaListy Zarzadca; RozElementListy Poprz; RozElementListy Naste; RozElementListy( ) Poprz = Naste = NULL; Zarzadca = NULL; RozElementListy( ); ; // void WstawPrzed(RozElementListy ElemNast); RozElementListy:: RozElementListy( ) if ( Poprz) Poprz > Naste = Naste; else Zarzadca > Glowa = Naste; if ( Naste) Naste > Poprz = Poprz; Destruktor klasy RozElementListy umożliwia zachowanie poprawnej struktury listy oraz wskazań zarzadcy po usunięciu dowolnego jej elementu.
Rozszerzony element listy 17 class RozElementListy // public : RozZarzadcaListy Zarzadca; RozElementListy Poprz; RozElementListy Naste; RozElementListy( ) Poprz = Naste = NULL; Zarzadca = NULL; RozElementListy( ); ; // void WstawPrzed(RozElementListy ElemNast); void RozElementListy::WstawPrzed(RozElementListy ElemNast) Naste = ElemNast; if (!ElemNast) Poprz = NULL; return ; Zarzadca = ElemNast > Zarzadca; if (ElemNast > Poprz) ( Poprz = ElemNast > Poprz) > Naste = this ; else Zarzadca > Glowa = this ; ElemNast > Poprz = this ; Metoda WstawPrzed pozwala na wstawienie elementu w dowolne jej miejsce przed końcem listy. Aktualizuje ona również, o ile zachodzi taka potrzeba, samego zarzadcę.
Rozszerzony zarzadca listy 18 class RozZarzadcaListy // public: RozElementListy Glowa; RozZarzadcaListy( ) Glowa = NULL; RozZarzadcaListy( ); ; // void DodajNaPoczatek( RozElementListy welem); RozZarzadcaListy:: RozZarzadcaListy( ) //.. while ( Glowa) delete Glowa; //.. Rozbudowanie metod w klasie RozElementListy pozwoliło na prostszy zapis metod w klasie RozZarzadcaListy. Zapis destruktora całej listy skrócił się do jednej linii.
Rozszerzony zarzadca listy 19 class RozZarzadcaListy // public: RozElementListy Glowa; RozZarzadcaListy( ) Glowa = NULL; RozZarzadcaListy( ); ; // void DodajNaPoczatek( RozElementListy welem); void RozZarzadcaListy::DodajNaPoczatek( RozElementListy welem) //. if (!welem ) return ; welem > Poprz = welem > Naste = NULL; if (! Glowa ) ( Glowa = welem) > Zarzadca = this ; return ; welem >WstawPrzed( Glowa); //.. Metoda dodawania nowego elementu skróciła się o jedna instrukcję.
20 Pytania i ćwiczenia 1. Czy z poziomu jednego destruktora można powodować uruchomienie destruktorów innych obiektów? 2. Dany jest fragment kodu: RozZarzadcaListy RozElementListy Lst; welem; Lst.DodajNaPoczatek(wElem = new RozElementListy); Lst.DodajNaPoczatek(wElem); Jeżeli następna instrukcja będzie: for (welem = Lst. Glowa; welem; welem = welem > Naste); to ile razy wykona się przedstawiona powyżej pętla? 3. Czy działanie instrukcji: for (welem = Lst. Glowa; welem; welem = welem > Poprz); różnić się będzie od przedstawionej wcześniej? Jeśli tak, to ile razy wykona się ta pętla? 4. Czy po wykonaniu instrukcji przedstawionych w punkcie 2 destrukcja listy przebiegnie poprawnie?