Najprostsze dynamiczne struktury danych, jakie poznaliśmy, to stos i kolejka. Obydwie implementować można za pomocą różnych mechanizmów. Jednym z najprostszych rozwiązań, które służy zazwyczaj do wyjaśnienia działania tych struktur, jest użycie statycznej lub dynamicznej tablicy. Jednak nie jest to rozwiązanie w pełni dynamiczne, ponieważ użycie tablic wymaga podania maksymalnej liczby przechowywanych w strukturze elementów. Aby uzyskać w pełni dynamiczne struktury stosu i kolejki, wykorzystuje się listy.
Stos
Przypomnijmy, że stos to liniowa struktura typu LIFO (ang. Last‑In, First‑Out – ostatni na wejściu, pierwszy na wyjściu), która obsługuje dwie podstawowe operacje, tj. dodawanie i usuwanie danych. Dodatkowe działania, jakie wykonuje się na stosie, to odczytywanie wierzchołka stosu, czyli ostatniego odłożonego elementu, bez usuwania go, oraz ewentualnie sprawdzanie rozmiaru stosu, czyli liczby odłożonych elementów.
Biorąc pod uwagę powyższe warunki, do implementacji stosu wystarczy jednokierunkowa lista niecykliczna. Elementami tej listy będą węzły zawierające dane, np. liczby, oraz – w przypadku listy jednokierunkowej – wskaźnikwskaźnikwskaźnik na element następny. Do zdefiniowania węzła możemy użyć strukturystrukturastruktury zawierającej dwa pola:
Linia 1. typedef struct Wezel otwórz nawias klamrowy.
Linia 2. int liczba średnik.
Linia 3. Wezel asterysk nastepny średnik.
Linia 4. zamknij nawias klamrowy Wezel średnik.
typedef struct Wezel {
int liczba;
Wezel *nastepny;
} Wezel;
Stworzenie nowego węzła i przypisanie wartości do jego składowych umożliwiają instrukcje:
Linia 1. Wezel asterysk wezel znak równości new Wezel średnik.
Linia 2. wezel minus zamknij nawias ostrokątny liczba znak równości 1 średnik.
Linia 3. wezel minus zamknij nawias ostrokątny nastepny znak równości nullptr średnik.
W omawianych poniżej implementacjach zakładamy wykorzystanie struktury definiującej węzeł, natomiast w sekcji „Prezentacja multimedialna” posłużymy się klasą.
Stos zaimplementujemy jako klasę, której atrybutem będzie wskaźnik na wierzchołek stosu o nazwie wierzcholek. Klasa będzie zawierała również definicje konstruktora oraz metod wykonujących charakterystyczne dla stosu operacje.
Linia 1. typedef struct Wezel otwórz nawias klamrowy.
Linia 2. int liczba średnik.
Linia 3. Wezel asterysk nastepny średnik.
Linia 4. zamknij nawias klamrowy Wezel średnik.
Linia 6. class Stos otwórz nawias klamrowy.
Linia 7. Wezel asterysk wierzcholek średnik.
Linia 8. public dwukropek.
Linia 9. Stos otwórz nawias okrągły zamknij nawias okrągły dwukropek wierzcholek otwórz nawias okrągły nullptr zamknij nawias okrągły otwórz nawias klamrowy zamknij nawias klamrowy.
Linia 10. bool czyPusty otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 11. void odloz otwórz nawias okrągły int zamknij nawias okrągły średnik.
Linia 12. int zdejmij otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 13. int pobierzWierzcholek otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 14. void wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 15. zamknij nawias klamrowy średnik.
typedef struct Wezel {
int liczba;
Wezel *nastepny;
} Wezel;
class Stos {
Wezel *wierzcholek;
public:
Stos(): wierzcholek(nullptr) {}
bool czyPusty();
void odloz(int);
int zdejmij();
int pobierzWierzcholek();
void wypisz();
};
W konstruktorze Stos(): wierzcholek(nullptr) {} inicjalizujemy pole wierzcholekpustym wskaźnikiemwskaźnikpustym wskaźnikiem.
Metoda czyPusty() będzie zwracała wartość true (prawda), jeżeli stos będzie pusty, czyli w sytuacji, gdy pole wierzcholek będzie pustym wskaźnikiem. W przeciwnym razie metoda zwróci wartość false (fałsz).
Linia 1. bool Stos dwukropek dwukropek czyPusty otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. if otwórz nawias okrągły wykrzyknik wierzcholek zamknij nawias okrągły otwórz nawias klamrowy.
Linia 3. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Stos pusty wykrzyknik cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 4. zamknij nawias klamrowy.
Linia 5. return wykrzyknik wierzcholek średnik.
Linia 6. zamknij nawias klamrowy.
W celu zachowania poprawności działania struktury LIFO, funkcja odloz() będzie dodawała elementy na początku listy, a funkcja zdejmij() będzie usuwała elementy również z początku listy.
Zacznijmy od metody odloz():
Linia 1. void Stos dwukropek dwukropek odloz otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Odkładam dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 3. Wezel asterysk nowy znak równości new Wezel średnik.
Linia 4. nowy minus zamknij nawias ostrokątny liczba znak równości liczba średnik.
Linia 5. nowy minus zamknij nawias ostrokątny nastepny znak równości wierzcholek średnik.
Linia 6. wierzcholek znak równości nowy średnik.
Linia 7. zamknij nawias klamrowy.
W funkcji odloz() tworzymy nowy węzeł i zapisujemy w nim wartość zmiennej liczba przekazaną jako argument. Kluczowymi operacjami są nadal przypisanie do wskaźnika nastepny nowego elementu wierzchołka oraz ustawienie wierzchołka na nowo dodany element.
W metodzie pomijamy sprawdzenie ewentualnego błędu przepełnienia stosuprzepełnienie stosuprzepełnienia stosu, gdyż ze względu na użycie listy jest on mało prawdopodobny.
Usuwanie pierwszego elementu jest możliwe dzięki wskaźnikowi wierzcholek:
Linia 1. int Stos dwukropek dwukropek zdejmij otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. if otwórz nawias okrągły czyPusty otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return INT podkreślnik MIN średnik.
Linia 4. Wezel asterysk pomocniczy znak równości wierzcholek średnik.
Linia 5. int liczba znak równości pomocniczy minus zamknij nawias ostrokątny liczba średnik.
Linia 6. wierzcholek znak równości wierzcholek minus zamknij nawias ostrokątny nastepny średnik.
Linia 7. delete otwórz nawias okrągły pomocniczy zamknij nawias okrągły średnik.
Linia 8. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Zdejmuję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 9. return liczba średnik.
Linia 10. zamknij nawias klamrowy.
int Stos::zdejmij() {
if (czyPusty()) return INT_MIN;
Wezel *pomocniczy = wierzcholek;
int liczba = pomocniczy->liczba;
wierzcholek = wierzcholek->nastepny;
delete(pomocniczy);
cout << "Zdejmuję: " << liczba << endl;
return liczba;
}
Jeżeli stos jest pusty, tzn. zachodzi błąd niedopełnienia stosuniedopełnienie stosuniedopełnienia stosu, zwracamy minimalną wartość zdefiniowaną dla typu całkowitego w stałej INT_MIN.
W przeciwnym razie dotychczasowy pierwszy element oraz zapisaną w nim wartość zapamiętujemy w zmiennych pomocniczych. Następnie ustawiamy wierzchołek na drugi element listy, dotychczasowy pierwszy usuwamy, a zapamiętaną wartość zwracamy.
Metoda pobierzWierzcholek() ma tylko jedno zadanie: jeżeli stos nie jest pusty, zwraca wartość zapisaną w pierwszym (czyli ostatnim dodanym) elemencie listy:
Linia 1. int Stos dwukropek dwukropek pobierzWierzcholek otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. if otwórz nawias okrągły czyPusty otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return INT podkreślnik MIN średnik.
Linia 3. return wierzcholek minus zamknij nawias ostrokątny liczba średnik.
Linia 4. zamknij nawias klamrowy.
int Stos::pobierzWierzcholek() {
if (czyPusty()) return INT_MIN;
return wierzcholek->liczba;
}
Metoda wypisz() posłuży do wypisania wartości odłożonych na stos, czyli zapisanych w kolejnych węzłach listy:
Linia 1. void Stos dwukropek dwukropek wypisz otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. if otwórz nawias okrągły czyPusty otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return średnik.
Linia 4. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Stos zawiera dwukropek cudzysłów średnik.
Linia 5. Wezel asterysk pomocniczy znak równości wierzcholek średnik.
Linia 6. while otwórz nawias okrągły pomocniczy wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 7. cout otwórz nawias ostrokątny otwórz nawias ostrokątny pomocniczy minus zamknij nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów cudzysłów średnik.
Linia 8. pomocniczy znak równości pomocniczy minus zamknij nawias ostrokątny nastepny średnik.
Linia 9. zamknij nawias klamrowy.
Linia 10. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 11. zamknij nawias klamrowy.
Do wypisania wartości używamy pętli przechodzącej po wszystkich elementach stosu zapisywanych w zmiennej pomocniczy. Wskaźnik ten inicjalizujemy wierzchołkiem, a następnie wewnątrz pętli przesuwamy na kolejne węzły wskazywane przez pole nastepny. Pętla będzie działać, dopóki nie dojdziemy do ostatniego węzła, którego wskaźnik nastepny będzie pusty.
Do sprawdzenia działania stosu możemy użyć poniższego kodu:
Linia 1. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. Stos stos znak równości Stos otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 3. stos kropka odloz otwórz nawias okrągły 1 zamknij nawias okrągły średnik.
Linia 4. stos kropka odloz otwórz nawias okrągły 2 zamknij nawias okrągły średnik.
Linia 5. stos kropka odloz otwórz nawias okrągły 3 zamknij nawias okrągły średnik.
Linia 6. stos kropka wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 7. stos kropka zdejmij otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 8. stos kropka zdejmij otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 9. stos kropka zdejmij otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 10. stos kropka zdejmij otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 11. return 0 średnik.
Linia 12. zamknij nawias klamrowy.
Na podstawie całego omówionego powyżej kodu przygotuj program ilustrujący działanie stosu. Przeanalizuj podaną wyżej funkcję główną i odpowiedz, jaki będzie ostatni wypisany przez program komunikat. Uruchom program i sprawdź poprawność swojej odpowiedzi.
R1RUCKPPwTigq
2
2
Zwróć uwagę na to, ile razy w funkcji głównej wywoływana jest metoda zdejmij().
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. kratka include otwórz nawias ostrokątny limits kropka h zamknij nawias ostrokątny.
Linia 4. using namespace std średnik.
Linia 6. typedef struct Wezel otwórz nawias klamrowy.
Linia 7. int liczba średnik.
Linia 8. Wezel asterysk nastepny średnik.
Linia 9. zamknij nawias klamrowy Wezel średnik.
Linia 11. class Stos otwórz nawias klamrowy.
Linia 12. Wezel asterysk wierzcholek średnik.
Linia 13. public dwukropek.
Linia 14. Stos otwórz nawias okrągły zamknij nawias okrągły dwukropek wierzcholek otwórz nawias okrągły nullptr zamknij nawias okrągły otwórz nawias klamrowy zamknij nawias klamrowy.
Linia 15. bool czyPusty otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 16. void odloz otwórz nawias okrągły int zamknij nawias okrągły średnik.
Linia 17. int zdejmij otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 18. int pobierzWierzcholek otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 19. void wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 20. zamknij nawias klamrowy średnik.
Linia 22. bool Stos dwukropek dwukropek czyPusty otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 23. if otwórz nawias okrągły wykrzyknik wierzcholek zamknij nawias okrągły otwórz nawias klamrowy.
Linia 24. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Stos pusty wykrzyknik cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 25. zamknij nawias klamrowy.
Linia 26. return wykrzyknik wierzcholek średnik.
Linia 27. zamknij nawias klamrowy.
Linia 29. void Stos dwukropek dwukropek odloz otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 30. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Odkładam dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 31. Wezel asterysk nowy znak równości new Wezel średnik.
Linia 32. nowy minus zamknij nawias ostrokątny liczba znak równości liczba średnik.
Linia 33. nowy minus zamknij nawias ostrokątny nastepny znak równości wierzcholek średnik.
Linia 34. wierzcholek znak równości nowy średnik.
Linia 35. zamknij nawias klamrowy.
Linia 37. int Stos dwukropek dwukropek zdejmij otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 38. if otwórz nawias okrągły czyPusty otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return INT podkreślnik MIN średnik.
Linia 40. Wezel asterysk pomocniczy znak równości wierzcholek średnik.
Linia 41. int liczba znak równości pomocniczy minus zamknij nawias ostrokątny liczba średnik.
Linia 42. wierzcholek znak równości wierzcholek minus zamknij nawias ostrokątny nastepny średnik.
Linia 43. delete otwórz nawias okrągły pomocniczy zamknij nawias okrągły średnik.
Linia 44. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Zdejmuję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 45. return liczba średnik.
Linia 46. zamknij nawias klamrowy.
Linia 48. int Stos dwukropek dwukropek pobierzWierzcholek otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 49. if otwórz nawias okrągły czyPusty otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return INT podkreślnik MIN średnik.
Linia 50. return wierzcholek minus zamknij nawias ostrokątny liczba średnik.
Linia 51. zamknij nawias klamrowy.
Linia 53. void Stos dwukropek dwukropek wypisz otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 54. if otwórz nawias okrągły czyPusty otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return średnik.
Linia 56. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Stos zawiera dwukropek cudzysłów średnik.
Linia 57. Wezel asterysk pomocniczy znak równości wierzcholek średnik.
Linia 58. while otwórz nawias okrągły pomocniczy wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 59. cout otwórz nawias ostrokątny otwórz nawias ostrokątny pomocniczy minus zamknij nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów cudzysłów średnik.
Linia 60. pomocniczy znak równości pomocniczy minus zamknij nawias ostrokątny nastepny średnik.
Linia 61. zamknij nawias klamrowy.
Linia 62. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 63. zamknij nawias klamrowy.
Linia 65. int main otwórz nawias okrągły int argc przecinek char asterysk argv otwórz nawias kwadratowy zamknij nawias kwadratowy zamknij nawias okrągły otwórz nawias klamrowy.
Linia 66. Stos stos znak równości Stos otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 67. stos kropka odloz otwórz nawias okrągły 1 zamknij nawias okrągły średnik.
Linia 68. stos kropka odloz otwórz nawias okrągły 2 zamknij nawias okrągły średnik.
Linia 69. stos kropka odloz otwórz nawias okrągły 3 zamknij nawias okrągły średnik.
Linia 70. stos kropka wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 71. stos kropka zdejmij otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 72. stos kropka zdejmij otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 73. stos kropka zdejmij otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 74. stos kropka zdejmij otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 75. return 0 średnik.
Linia 76. zamknij nawias klamrowy.
#include <iostream>
#include <limits.h>
using namespace std;
typedef struct Wezel {
int liczba;
Wezel *nastepny;
} Wezel;
class Stos {
Wezel* wierzcholek;
public:
Stos(): wierzcholek(nullptr) {}
bool czyPusty();
void odloz(int);
int zdejmij();
int pobierzWierzcholek();
void wypisz();
};
bool Stos::czyPusty() {
if (!wierzcholek) {
cout << "Stos pusty!" << endl;
}
return !wierzcholek;
}
void Stos::odloz(int liczba) {
cout << "Odkładam: " << liczba << endl;
Wezel *nowy = new Wezel;
nowy->liczba = liczba;
nowy->nastepny = wierzcholek;
wierzcholek = nowy;
}
int Stos::zdejmij() {
if (czyPusty()) return INT_MIN;
Wezel *pomocniczy = wierzcholek;
int liczba = pomocniczy->liczba;
wierzcholek = wierzcholek->nastepny;
delete(pomocniczy);
cout << "Zdejmuję: " << liczba << endl;
return liczba;
}
int Stos::pobierzWierzcholek() {
if (czyPusty()) return INT_MIN;
return wierzcholek->liczba;
}
void Stos::wypisz() {
if (czyPusty()) return;
cout << "Stos zawiera: ";
Wezel *pomocniczy = wierzcholek;
while (pomocniczy != nullptr) {
cout << pomocniczy->liczba << " ";
pomocniczy = pomocniczy->nastepny;
}
cout << endl;
}
int main(int argc, char *argv[]) {
Stos stos = Stos();
stos.odloz(1);
stos.odloz(2);
stos.odloz(3);
stos.wypisz();
stos.zdejmij();
stos.zdejmij();
stos.zdejmij();
stos.zdejmij();
return 0;
}
Wynikiem działania programu będą komunikaty:
Linia 1. Odkładam dwukropek 1.
Linia 2. Odkładam dwukropek 2.
Linia 3. Odkładam dwukropek 3.
Linia 4. Stos zawiera dwukropek 3 2 1.
Linia 5. Zdejmuję dwukropek 3.
Linia 6. Zdejmuję dwukropek 2.
Linia 7. Zdejmuję dwukropek 1.
Linia 8. Stos pusty wykrzyknik.
W funkcji main() na stos odkładane są trzy wartości, natomiast później metoda zdejmij() wywoływana jest cztery razy. Dlatego ostatni komunikat to: „Stos pusty!”.
Kolejka
Kolejka to liniowa struktura danych typu FIFO (ang. First‑In,First‑Out – pierwszy na wejściu, pierwszy na wyjściu), co oznacza, że jej elementy odczytywane są zgodnie z kolejnością dodawania, a zatem odwrotnie niż w przypadku stosu.
W implementacji kolejki również użyjemy listy jednokierunkowej i takiej samej jak w przypadku stosu struktury węzłów. Natomiast klasa Kolejka będzie zawierała dwa pola:
glowa – wskaźnik na pierwszy element kolejki;
ogon – wskaźnik na ostatni element kolejki, który ułatwi dodawanie elementów na końcu listy.
Nazwy pozostałych metod dostosujemy do omawianej struktury.
Linia 1. typedef struct Wezel otwórz nawias klamrowy.
Linia 2. int liczba średnik.
Linia 3. Wezel asterysk nastepny średnik.
Linia 4. zamknij nawias klamrowy Wezel średnik.
Linia 6. class Kolejka otwórz nawias klamrowy.
Linia 7. Wezel asterysk glowa średnik.
Linia 8. Wezel asterysk ogon średnik.
Linia 9. public dwukropek.
Linia 10. Kolejka otwórz nawias okrągły zamknij nawias okrągły dwukropek glowa otwórz nawias okrągły nullptr zamknij nawias okrągły przecinek ogon otwórz nawias okrągły nullptr zamknij nawias okrągły otwórz nawias klamrowy zamknij nawias klamrowy.
Linia 11. bool czyPusta otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 12. void dodaj otwórz nawias okrągły int zamknij nawias okrągły średnik.
Linia 13. int usun otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 14. void wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 15. zamknij nawias klamrowy średnik.
Metoda czyPusta() działa tak samo, jak w przypadku stosu i każdej listy, tzn. jeżeli wskaźnik na pierwszy element jest pusty, to znaczy, że lista jest pusta.
Linia 1. bool Kolejka dwukropek dwukropek czyPusta otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. return wykrzyknik glowa średnik.
Linia 3. zamknij nawias klamrowy.
bool Kolejka::czyPusta() {
return !glowa;
}
Metoda dodaj() będzie dodawała nowe elementy na końcu listy przy użyciu pola ogon.
Linia 1. void Kolejka dwukropek dwukropek dodaj otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Dodaję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 4. Wezel asterysk nowy znak równości new Wezel średnik.
Linia 5. nowy minus zamknij nawias ostrokątny liczba znak równości liczba średnik.
Linia 6. nowy minus zamknij nawias ostrokątny nastepny znak równości nullptr średnik.
Linia 8. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 9. glowa znak równości ogon znak równości nowy średnik.
Linia 10. return średnik.
Linia 11. zamknij nawias klamrowy.
Linia 13. ogon minus zamknij nawias ostrokątny nastepny znak równości nowy średnik.
Linia 14. ogon znak równości nowy średnik.
Linia 15. zamknij nawias klamrowy.
Na początku metody tworzymy nowy węzeł, przypisujemy otrzymaną liczbę do jego pola liczba, a wskaźnik nastepny ustawiamy na wartość pustą. Następnie, jeżeli lista jest pusta, wskaźniki na pierwszy (glowa) i ostatni (ogon) element listy ustawiamy na nowy węzeł.
W przeciwnym razie wskaźnik nastepny dotychczasowego ostatniego elementu ustawiamy na nowy węzeł i aktualizujemy wskaźnik ogon, aby wskazywał nowo dodany element.
Metoda usun() będzie zwracała kolejne elementy z początku listy, czyli działać będzie tak samo, jak metoda zdejmij() w przypadku stosu. Ponieważ jednak elementy będą dodawane na końcu listy, zasada działania kolejki FIFO zostanie zachowana.
Linia 1. int Kolejka dwukropek dwukropek usun otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return INT podkreślnik MIN średnik.
Linia 4. Wezel asterysk pomocniczy znak równości glowa średnik.
Linia 5. int liczba znak równości pomocniczy minus zamknij nawias ostrokątny liczba średnik.
Linia 6. glowa znak równości glowa minus zamknij nawias ostrokątny nastepny średnik.
Linia 7. delete otwórz nawias okrągły pomocniczy zamknij nawias okrągły średnik.
Linia 8. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Usuwam dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 9. return liczba średnik.
Linia 10. zamknij nawias klamrowy.
int Kolejka::usun() {
if (czyPusta()) return INT_MIN;
Wezel* pomocniczy = glowa;
int liczba = pomocniczy->liczba;
glowa = glowa->nastepny;
delete(pomocniczy);
cout << "Usuwam: " << liczba << endl;
return liczba;
}
Ćwiczenie 2
Wykorzystaj omówiony kod i przygotuj program pozwalający sprawdzić działanie kolejki. Dodaj do kolejki trzy liczby, wypisz kolejkę, a następnie wywołaj metodę usuwającą cztery razy.
RpGXwIaEm0Lh3
Metoda wypisz() jest taka sama, jak w przypadku stosu. Trzeba tylko dostosować komunikat oraz nazwę wskaźnika na pierwszy element listy.
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. kratka include otwórz nawias ostrokątny limits kropka h zamknij nawias ostrokątny.
Linia 4. using namespace std średnik.
Linia 6. typedef struct Wezel otwórz nawias klamrowy.
Linia 7. int liczba średnik.
Linia 8. Wezel asterysk nastepny średnik.
Linia 9. zamknij nawias klamrowy Wezel średnik.
Linia 11. class Kolejka otwórz nawias klamrowy.
Linia 12. Wezel asterysk glowa średnik.
Linia 13. Wezel asterysk ogon średnik.
Linia 14. public dwukropek.
Linia 15. Kolejka otwórz nawias okrągły zamknij nawias okrągły dwukropek glowa otwórz nawias okrągły nullptr zamknij nawias okrągły przecinek ogon otwórz nawias okrągły nullptr zamknij nawias okrągły otwórz nawias klamrowy zamknij nawias klamrowy.
Linia 16. bool czyPusta otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 17. void dodaj otwórz nawias okrągły int zamknij nawias okrągły średnik.
Linia 18. int usun otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 19. void wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 20. zamknij nawias klamrowy średnik.
Linia 22. bool Kolejka dwukropek dwukropek czyPusta otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 23. return wykrzyknik glowa średnik.
Linia 24. zamknij nawias klamrowy.
Linia 26. void Kolejka dwukropek dwukropek dodaj otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 27. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Dodaję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 29. Wezel asterysk nowy znak równości new Wezel średnik.
Linia 30. nowy minus zamknij nawias ostrokątny liczba znak równości liczba średnik.
Linia 31. nowy minus zamknij nawias ostrokątny nastepny znak równości nullptr średnik.
Linia 33. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 34. glowa znak równości ogon znak równości nowy średnik.
Linia 35. return średnik.
Linia 36. zamknij nawias klamrowy.
Linia 38. ogon minus zamknij nawias ostrokątny nastepny znak równości nowy średnik.
Linia 39. ogon znak równości nowy średnik.
Linia 40. zamknij nawias klamrowy.
Linia 42. int Kolejka dwukropek dwukropek usun otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 43. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 44. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Kolejka jest pusta wykrzyknik cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 45. return INT podkreślnik MIN średnik.
Linia 46. zamknij nawias klamrowy.
Linia 48. Wezel asterysk pomocniczy znak równości glowa średnik.
Linia 49. int liczba znak równości pomocniczy minus zamknij nawias ostrokątny liczba średnik.
Linia 50. glowa znak równości glowa minus zamknij nawias ostrokątny nastepny średnik.
Linia 51. delete pomocniczy średnik.
Linia 52. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Usuwam dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 53. return liczba średnik.
Linia 54. zamknij nawias klamrowy.
Linia 56. void Kolejka dwukropek dwukropek wypisz otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 57. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 58. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Kolejka jest pusta wykrzyknik cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 59. return średnik.
Linia 60. zamknij nawias klamrowy.
Linia 62. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Kolejka zawiera dwukropek cudzysłów średnik.
Linia 63. Wezel asterysk pomocniczy znak równości glowa średnik.
Linia 64. while otwórz nawias okrągły pomocniczy wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 65. cout otwórz nawias ostrokątny otwórz nawias ostrokątny pomocniczy minus zamknij nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów cudzysłów średnik.
Linia 66. pomocniczy znak równości pomocniczy minus zamknij nawias ostrokątny nastepny średnik.
Linia 67. zamknij nawias klamrowy.
Linia 68. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 69. zamknij nawias klamrowy.
Linia 71. int main otwórz nawias okrągły int argc przecinek char asterysk argv otwórz nawias kwadratowy zamknij nawias kwadratowy zamknij nawias okrągły otwórz nawias klamrowy.
Linia 72. Kolejka kolejka znak równości Kolejka otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 73. kolejka kropka dodaj otwórz nawias okrągły 1 zamknij nawias okrągły średnik.
Linia 74. kolejka kropka dodaj otwórz nawias okrągły 2 zamknij nawias okrągły średnik.
Linia 75. kolejka kropka dodaj otwórz nawias okrągły 3 zamknij nawias okrągły średnik.
Linia 76. kolejka kropka wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 77. kolejka kropka usun otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 78. kolejka kropka usun otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 79. kolejka kropka usun otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 80. kolejka kropka usun otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 81. return 0 średnik.
Linia 82. zamknij nawias klamrowy.
Linia 1. Dodaję dwukropek 1.
Linia 2. Dodaję dwukropek 2.
Linia 3. Dodaję dwukropek 3.
Linia 4. Kolejka zawiera dwukropek 1 2 3.
Linia 5. Usuwam dwukropek 1.
Linia 6. Usuwam dwukropek 2.
Linia 7. Usuwam dwukropek 3.
Linia 8. Kolejka jest pusta wykrzyknik.
Lista – podobnie jak stos i kolejka – jest liniową i dynamiczną strukturą danych. Elementami listy są węzły, z których każdy zawiera dane oraz wskaźnikwskaźnikwskaźnik na element następny (w przypadku listy jednokierunkowej) lub na następny i poprzedni (w przypadku listy dwukierunkowej).
Do implementacji stosu i kolejki użyliśmy listy jednokierunkowej. Jej węzły zdefiniowaliśmy przy użyciu strukturystrukturastruktury zawierającej dwa pola.
Definicja struktury może dodatkowo obejmować konstruktorkonstruktorkonstruktor inicjalizujący jej składowe, np.:
Linia 1. typedef struct Wezel otwórz nawias klamrowy.
Linia 2. int liczba średnik.
Linia 3. Wezel asterysk nastepny średnik.
Linia 4. Wezel otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 5. this minus zamknij nawias ostrokątny liczba znak równości liczba średnik.
Linia 6. this minus zamknij nawias ostrokątny nastepny znak równości nullptr średnik.
Linia 7. zamknij nawias klamrowy.
Linia 8. zamknij nawias klamrowy Wezel średnik.
Wtedy utworzenie nowego węzła jest możliwe dzięki zwięzłej instrukcji:
Linia 1. Wezel asterysk nowy znak równości new Wezel otwórz nawias okrągły 1 zamknij nawias okrągły średnik.
Wezel *nowy = new Wezel(1);
Podobne możliwości definiowania węzła daje użycie klasyklasaklasy:
Linia 1. class Wezel otwórz nawias klamrowy.
Linia 2. public dwukropek.
Linia 3. int liczba średnik.
Linia 4. Wezel asterysk nastepny średnik.
Linia 6. prawy ukośnik prawy ukośnik Konstruktor domyślny.
Linia 7. Wezel otwórz nawias okrągły zamknij nawias okrągły dwukropek liczba otwórz nawias okrągły 0 zamknij nawias okrągły przecinek nastepny otwórz nawias okrągły nullptr zamknij nawias okrągły otwórz nawias klamrowy zamknij nawias klamrowy.
Linia 9. prawy ukośnik prawy ukośnik Konstruktor argumentowy.
Linia 10. Wezel otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 11. this minus zamknij nawias ostrokątny liczba znak równości liczba średnik.
Linia 12. this minus zamknij nawias ostrokątny nastepny znak równości nullptr średnik.
Linia 13. zamknij nawias klamrowy.
Linia 14. zamknij nawias klamrowy średnik.
Pierwszy konstruktor – domyślny – nie wymaga żadnych argumentów i służy do inicjalizowania składowych wartościami domyślnymi podawanymi po dwukropku. Drugi konstruktor wymaga argumentu i pozwala na zainicjowanie pola liczba wartością podaną podczas tworzenia węzła. Oto przykłady:
Linia 1. prawy ukośnik prawy ukośnik Wykorzystanie konstruktora domyślnego.
Linia 2. Wezel asterysk wezel znak równości new Wezel otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 4. prawy ukośnik prawy ukośnik Wykorzystanie konstruktora argumentowego.
Linia 5. Wezel asterysk wezel znak równości new Wezel otwórz nawias okrągły 1 zamknij nawias okrągły średnik.
// Wykorzystanie konstruktora domyślnego
Wezel *wezel = new Wezel();
// Wykorzystanie konstruktora argumentowego
Wezel *wezel = new Wezel(1);
Ważne!
Zakładamy, że w przedstawionych dalej implementacjach list jako definicji węzła używamy struktury z konstruktorem.
Lista jednokierunkowa
Listę jednokierunkową implementujemy jako klasęklasaklasę z jednym polem glowa – wskaźnikiem na pierwszy element listy. Oprócz tego w klasie definiujemy metody umożliwiające dodawanie, usuwanie i wypisywanie elementów listy. W konstruktorze Lista() inicjalizujemy pole glowapustym wskaźnikiemwskaźnikpustym wskaźnikiem.
Linia 1. class Lista otwórz nawias klamrowy.
Linia 2. Wezel asterysk glowa średnik.
Linia 4. public dwukropek.
Linia 5. Lista otwórz nawias okrągły zamknij nawias okrągły dwukropek glowa otwórz nawias okrągły nullptr zamknij nawias okrągły otwórz nawias klamrowy zamknij nawias klamrowy.
Linia 6. bool czyPusta otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 7. void dodaj otwórz nawias okrągły int zamknij nawias okrągły średnik.
Linia 8. void usun otwórz nawias okrągły int zamknij nawias okrągły średnik.
Linia 9. void wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 10. zamknij nawias klamrowy średnik.
class Lista {
Wezel *glowa;
public:
Lista(): glowa(nullptr) {}
bool czyPusta();
void dodaj(int);
void usun(int);
void wypisz();
};
Metody czyPusta() oraz wypisz() działają tak samo jak w przypadku stosu i kolejki. Wyjaśnijmy teraz działanie metod: dodającej węzły na końcu listy oraz usuwającej węzły o podanej pozycji.
Dodawanie węzłów na końcu listy jednokierunkowej
Metoda dodaj() jako argument będzie przyjmowała liczbę całkowitą. Nowy węzeł – inaczej niż w przypadku stosu i kolejki – będzie dodawany na końcu listy.
Linia 1. void Lista dwukropek dwukropek dodaj otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Dodaję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 4. prawy ukośnik prawy ukośnik Tworzymy nowy węzeł.
Linia 5. Wezel asterysk nowy znak równości new Wezel otwórz nawias okrągły liczba zamknij nawias okrągły średnik.
Linia 7. prawy ukośnik prawy ukośnik Jeżeli lista jest pusta.
Linia 8. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 9. glowa znak równości nowy średnik.
Linia 10. return średnik.
Linia 11. zamknij nawias klamrowy.
Linia 13. prawy ukośnik prawy ukośnik W przeciwnym razie przejdź do ostatniego elementu.
Linia 14. Wezel asterysk pomocniczy znak równości glowa średnik.
Linia 15. while otwórz nawias okrągły pomocniczy minus zamknij nawias ostrokątny nastepny wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 16. pomocniczy znak równości pomocniczy minus zamknij nawias ostrokątny nastepny średnik.
Linia 17. zamknij nawias klamrowy.
Linia 19. prawy ukośnik prawy ukośnik Dodajemy nowy węzeł na końcu listy.
Linia 20. pomocniczy minus zamknij nawias ostrokątny nastepny znak równości nowy średnik.
Linia 21. zamknij nawias klamrowy.
void Lista::dodaj(int liczba) {
cout << "Dodaję: " << liczba << endl;
// Tworzymy nowy węzeł
Wezel *nowy = new Wezel(liczba);
// Jeżeli lista jest pusta
if (czyPusta()) {
glowa = nowy;
return;
}
// W przeciwnym razie przejdź do ostatniego elementu
Wezel *pomocniczy = glowa;
while (pomocniczy->nastepny != nullptr) {
pomocniczy = pomocniczy->nastepny;
}
// Dodajemy nowy węzeł na końcu listy
pomocniczy->nastepny = nowy;
}
Na początku metody tworzymy nowy węzeł, przekazując do jego konstruktora otrzymaną liczbę.
Następnie, jeżeli lista jest pusta, nowy węzeł staje się pierwszym elementem listy przypisanym do pola glowa.
W przeciwnym razie za pomocą węzła pomocniczy w pętli przechodzimy listę do ostatniego elementu, którego wskaźnik nastepny będzie pusty. Po zakończeniu pętli wskaźnik nastepny dotychczasowego ostatniego elementu ustawiamy na nowy węzeł. W ten sposób dodajemy węzeł na końcu listy.
R1eSTXiWk4HIn
Ilustracja przedstawia schemat dodawania węzła do końca listy jednokierunkowej. Lista składa się z czterech elementów, gdzie element pierwszy jest głową, trzeci jest pomocniczy, a czwarty jest elementem nowym. Elementy połączone są strzałkami z podpisem następny. Przy czym element NULL znajdujący się po elemencie trzecim został skreślony, a nowy element NULL jest następny po nowym elemencie czwartym.
Schemat dodawania węzła do końca listy jednokierunkowej
Źródło: Contentplus.pl Sp. z o.o., licencja: CC BY-SA 3.0.
Usuwanie węzłów z listy jednokierunkowej
Metoda usuwająca węzły z listy otrzymywać będzie jako argument liczbę całkowitą wskazującą indeks czy też numer węzła, który chcemy usunąć. Przyjmijmy, że indeksy węzłów zaczynają się od 1.
Linia 1. void Lista dwukropek dwukropek usun otwórz nawias okrągły int indeks zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return średnik.
Linia 4. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Usuwam pozycję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny indeks otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 6. Wezel asterysk pomocniczy1 znak równości glowa przecinek asterysk pomocniczy2 znak równości nullptr średnik.
Linia 7. int rozmiar znak równości 0 średnik.
Linia 9. prawy ukośnik prawy ukośnik Zliczamy elementy listy.
Linia 10. while otwórz nawias okrągły pomocniczy1 wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 11. pomocniczy1 znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 12. rozmiar plus plus średnik.
Linia 13. zamknij nawias klamrowy.
Linia 15. prawy ukośnik prawy ukośnik Jeżeli indeks jest większy od rozmiaru listy.
Linia 16. if otwórz nawias okrągły indeks zamknij nawias ostrokątny rozmiar zamknij nawias okrągły otwórz nawias klamrowy.
Linia 17. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Indeks poza zakresem cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 18. return średnik.
Linia 19. zamknij nawias klamrowy.
Linia 21. prawy ukośnik prawy ukośnik Poniżej dodamy kod usuwający elementy.
Linia 23. zamknij nawias klamrowy.
void Lista::usun(int indeks) {
if (czyPusta()) return;
cout << "Usuwam pozycję: " << indeks << endl;
Wezel *pomocniczy1 = glowa, *pomocniczy2 = nullptr;
int rozmiar = 0;
// Zliczamy elementy listy
while (pomocniczy1 != nullptr) {
pomocniczy1 = pomocniczy1->nastepny;
rozmiar++;
}
// Jeżeli indeks jest większy od rozmiaru listy
if (indeks > rozmiar) {
cout << "Indeks poza zakresem" << endl;
return;
}
// Poniżej dodamy kod usuwający elementy
}
Jeżeli lista nie jest pusta, definiujemy zmienne, których używamy w metodzie:
wskaźnik pomocniczy1 ustawiamy na pierwszy element listy;
wskaźnik pomocniczy2 wykorzystamy przy usuwaniu węzłów innych od pierwszego;
zmienna rozmiar posłuży do ustalenia rozmiaru listy.
Następnie zliczamy elementy listy za pomocą pętli while przechodzącej po wszystkich węzłach listy, zaczynając od pierwszego. Po dojściu do ostatniego elementu w zmiennej pomocniczy1 zostanie zapisana wartość nullptr i pętla zakończy swoje działanie.
Ważne!
Warto zapamiętać omówioną przed chwilą pętlę, ponieważ przechodzenie wszystkich elementów listy zaczynając od pierwszego, jest typową operacją wykonywaną na listach.
Następnie, jeżeli podany indeks nie jest większy od obliczonego rozmiaru listy, zaczynamy usuwanie węzła. Zadanie to realizuje kod, który umieszczamy na końcu omawianej metody:
Linia 1. prawy ukośnik prawy ukośnik Usuwanie pierwszego węzła.
Linia 2. pomocniczy1 znak równości glowa średnik.
Linia 3. if otwórz nawias okrągły indeks znak równości znak równości 1 zamknij nawias okrągły otwórz nawias klamrowy.
Linia 4. glowa znak równości glowa minus zamknij nawias ostrokątny nastepny średnik.
Linia 5. delete pomocniczy1 średnik.
Linia 6. return średnik.
Linia 7. zamknij nawias klamrowy.
Linia 9. prawy ukośnik prawy ukośnik Szukanie węzła do usunięcia otwórz nawias okrągły innego niż pierwszy zamknij nawias okrągły.
Linia 10. while otwórz nawias okrągły indeks minus minus zamknij nawias ostrokątny 1 zamknij nawias okrągły otwórz nawias klamrowy.
Linia 11. pomocniczy2 znak równości pomocniczy1 średnik.
Linia 12. pomocniczy1 znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 13. zamknij nawias klamrowy.
Linia 15. prawy ukośnik prawy ukośnik Zmiana wskaźnika nastepny węzła poprzedzającego usuwany.
Linia 16. pomocniczy2 minus zamknij nawias ostrokątny nastepny znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 18. prawy ukośnik prawy ukośnik Usunięcie węzła o podanym indeksie.
Linia 19. delete pomocniczy1 średnik.
// Usuwanie pierwszego węzła
pomocniczy1 = glowa;
if (indeks == 1) {
glowa = glowa->nastepny;
delete pomocniczy1;
return;
}
// Szukanie węzła do usunięcia (innego niż pierwszy)
while (indeks-- > 1) {
pomocniczy2 = pomocniczy1;
pomocniczy1 = pomocniczy1->nastepny;
}
// Zmiana wskaźnika nastepny węzła poprzedzającego usuwany
pomocniczy2->nastepny = pomocniczy1->nastepny;
// Usunięcie węzła o podanym indeksie
delete pomocniczy1;
Jeżeli usuwanym elementem jest pierwszy węzeł (indeks 1), zapamiętujemy go w zmiennej pomocniczy1, wskaźnik glowa ustawiamy na następny węzeł i usuwamy zapamiętany węzeł.
W przeciwnym razie w pętli, która wykonuje się, dopóki indeks jest większy od 1, szukamy węzła do usunięcia. Po każdej iteracji indeks jest zmniejszany o 1 dzięki notacji postfiksowej. Wewnątrz pętli przechodzimy po indeks - 1 elementach listy od jej początku, więc po jej zakończeniu zmienna pomocniczy1 będzie wskazywała węzeł do usunięcia, a zmienna pomocniczy2 węzeł poprzedni.
Po zakończeniu pętli w węźle poprzedzającym węzeł usuwany ustawiamy wskaźnik nastepny na węzeł następny po węźle usuwanym (w przypadku usuwania ostatniego węzła będzie to wartość nullptr).
Na koniec usuwamy węzeł zapamiętany w zmiennej pomocniczy1.
R1DT71fUbiSfA
Ilustracja przedstawia schemat usuwania węzła z listy jednokierunkowej. Lista składa się z czterech elementów, gdzie element pierwszy jest głową, drugi jest elementem pomocniczym dwa a trzeci jest elementem pomocniczym jeden. Element trzeci został przekreślony, wraz ze strzałką pomiędzy elementami pomocniczymi. Z elementu drugiego prowadzi nowa strzałka prosto do elementu czwartego.
Schemat usuwania węzła z listy jednokierunkowej
Źródło: Contentplus.pl Sp. z o.o., licencja: CC BY-SA 3.0.
Ćwiczenie 3
Wykorzystaj omówiony kod i przygotuj program pozwalający sprawdzić działanie listy jednokierunkowej. Dodaj do listy trzy liczby i wypisz listę. Następnie usuń drugi element i wypisz listę. Na końcu jeszcze raz usuń drugi element, dodaj liczbę i wypisz listę.
Rnni2JtdrJIWx
2
2
Implementacja metod czyPusta() i wypisz() jest taka sama jak w przypadku stosu i kolejki, trzeba tylko dostosować wyświetlane komunikaty i nazwy wskaźników.
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 3. using namespace std średnik.
Linia 5. typedef struct Wezel otwórz nawias klamrowy.
Linia 6. int liczba średnik.
Linia 7. Wezel asterysk nastepny średnik.
Linia 8. Wezel otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 9. this minus zamknij nawias ostrokątny liczba znak równości liczba średnik.
Linia 10. this minus zamknij nawias ostrokątny nastepny znak równości nullptr średnik.
Linia 11. zamknij nawias klamrowy.
Linia 12. zamknij nawias klamrowy Wezel średnik.
Linia 14. class Lista otwórz nawias klamrowy.
Linia 15. Wezel asterysk glowa średnik.
Linia 17. public dwukropek.
Linia 18. Lista otwórz nawias okrągły zamknij nawias okrągły dwukropek glowa otwórz nawias okrągły nullptr zamknij nawias okrągły otwórz nawias klamrowy zamknij nawias klamrowy.
Linia 19. bool czyPusta otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 20. void dodaj otwórz nawias okrągły int zamknij nawias okrągły średnik.
Linia 21. void usun otwórz nawias okrągły int zamknij nawias okrągły średnik.
Linia 22. void wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 23. zamknij nawias klamrowy średnik.
Linia 25. bool Lista dwukropek dwukropek czyPusta otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 26. if otwórz nawias okrągły glowa znak równości znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 27. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Lista jest pusta wykrzyknik cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 28. return true średnik.
Linia 29. zamknij nawias klamrowy.
Linia 30. return false średnik.
Linia 31. zamknij nawias klamrowy.
Linia 33. void Lista dwukropek dwukropek dodaj otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 34. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Dodaję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 36. Wezel asterysk nowy znak równości new Wezel otwórz nawias okrągły liczba zamknij nawias okrągły średnik.
Linia 38. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 39. glowa znak równości nowy średnik.
Linia 40. return średnik.
Linia 41. zamknij nawias klamrowy.
Linia 43. Wezel asterysk pomocniczy znak równości glowa średnik.
Linia 44. while otwórz nawias okrągły pomocniczy minus zamknij nawias ostrokątny nastepny wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 45. pomocniczy znak równości pomocniczy minus zamknij nawias ostrokątny nastepny średnik.
Linia 46. zamknij nawias klamrowy.
Linia 48. pomocniczy minus zamknij nawias ostrokątny nastepny znak równości nowy średnik.
Linia 49. zamknij nawias klamrowy.
Linia 51. void Lista dwukropek dwukropek usun otwórz nawias okrągły int indeks zamknij nawias okrągły otwórz nawias klamrowy.
Linia 52. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return średnik.
Linia 54. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Usuwam pozycję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny indeks otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 56. Wezel asterysk pomocniczy1 znak równości glowa przecinek asterysk pomocniczy2 znak równości nullptr średnik.
Linia 57. int rozmiar znak równości 0 średnik.
Linia 59. while otwórz nawias okrągły pomocniczy1 wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 60. pomocniczy1 znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 61. rozmiar plus plus średnik.
Linia 62. zamknij nawias klamrowy.
Linia 64. if otwórz nawias okrągły indeks zamknij nawias ostrokątny rozmiar zamknij nawias okrągły otwórz nawias klamrowy.
Linia 65. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Indeks poza zakresem cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 66. return średnik.
Linia 67. zamknij nawias klamrowy.
Linia 69. pomocniczy1 znak równości glowa średnik.
Linia 70. if otwórz nawias okrągły indeks znak równości znak równości 1 zamknij nawias okrągły otwórz nawias klamrowy.
Linia 71. glowa znak równości glowa minus zamknij nawias ostrokątny nastepny średnik.
Linia 72. delete pomocniczy1 średnik.
Linia 73. return średnik.
Linia 74. zamknij nawias klamrowy.
Linia 76. while otwórz nawias okrągły indeks minus minus zamknij nawias ostrokątny 1 zamknij nawias okrągły otwórz nawias klamrowy.
Linia 77. pomocniczy2 znak równości pomocniczy1 średnik.
Linia 78. pomocniczy1 znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 79. zamknij nawias klamrowy.
Linia 81. pomocniczy2 minus zamknij nawias ostrokątny nastepny znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 82. delete pomocniczy1 średnik.
Linia 84. zamknij nawias klamrowy.
Linia 86. void Lista dwukropek dwukropek wypisz otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 87. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return średnik.
Linia 89. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Lista zawiera dwukropek cudzysłów średnik.
Linia 90. Wezel asterysk pomocniczy znak równości glowa średnik.
Linia 91. while otwórz nawias okrągły pomocniczy wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 92. cout otwórz nawias ostrokątny otwórz nawias ostrokątny pomocniczy minus zamknij nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów cudzysłów średnik.
Linia 93. pomocniczy znak równości pomocniczy minus zamknij nawias ostrokątny nastepny średnik.
Linia 94. zamknij nawias klamrowy.
Linia 95. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 96. zamknij nawias klamrowy.
Linia 98. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 99. Lista lista średnik.
Linia 101. lista kropka dodaj otwórz nawias okrągły 1 zamknij nawias okrągły średnik.
Linia 102. lista kropka dodaj otwórz nawias okrągły 2 zamknij nawias okrągły średnik.
Linia 103. lista kropka dodaj otwórz nawias okrągły 3 zamknij nawias okrągły średnik.
Linia 104. lista kropka wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 106. lista kropka usun otwórz nawias okrągły 2 zamknij nawias okrągły średnik.
Linia 107. lista kropka wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 109. lista kropka usun otwórz nawias okrągły 2 zamknij nawias okrągły średnik.
Linia 110. lista kropka dodaj otwórz nawias okrągły 4 zamknij nawias okrągły średnik.
Linia 111. lista kropka wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 113. return 0 średnik.
Linia 114. zamknij nawias klamrowy.
Linia 1. Dodaję dwukropek 1.
Linia 2. Lista jest pusta wykrzyknik.
Linia 3. Dodaję dwukropek 2.
Linia 4. Dodaję dwukropek 3.
Linia 5. Lista zawiera dwukropek 1 2 3.
Linia 6. Usuwam pozycję dwukropek 2.
Linia 7. Lista zawiera dwukropek 1 3.
Linia 8. Usuwam pozycję dwukropek 2.
Linia 9. Dodaję dwukropek 4.
Linia 10. Lista zawiera dwukropek 1 4.
Dodaję: 1
Lista jest pusta!
Dodaję: 2
Dodaję: 3
Lista zawiera: 1 2 3
Usuwam pozycję: 2
Lista zawiera: 1 3
Usuwam pozycję: 2
Dodaję: 4
Lista zawiera: 1 4
Lista dwukierunkowa
Lista dwukierunkowa od jednokierunkowej różni się tym, że jej węzły oprócz wskaźnika na element następny zawierają także wskaźnik na element poprzedni. Implementację przygotujemy, wykorzystując omówiony wyżej kod listy jednokierunkowej.
Na początku uzupełniamy strukturę Wezel o pole poprzedni oraz uzupełniamy konstruktor tak, aby inicjalizował je wartością pustą. Do klasy Lista dodajemy pole ogon, które będzie wskazywało na ostatni element listy. W konstruktorze klasy pola glowa i ogon ustawiamy na wartości puste.
Linia 1. typedef struct Wezel otwórz nawias klamrowy.
Linia 2. int liczba średnik.
Linia 3. Wezel asterysk nastepny średnik.
Linia 4. Wezel asterysk poprzedni średnik.
Linia 5. Wezel otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 6. this minus zamknij nawias ostrokątny liczba znak równości liczba średnik.
Linia 7. this minus zamknij nawias ostrokątny nastepny znak równości nullptr średnik.
Linia 8. this minus zamknij nawias ostrokątny poprzedni znak równości nullptr średnik.
Linia 9. zamknij nawias klamrowy.
Linia 10. zamknij nawias klamrowy Wezel średnik.
Linia 12. class Lista otwórz nawias klamrowy.
Linia 13. Wezel asterysk glowa średnik.
Linia 14. Wezel asterysk ogon średnik.
Linia 16. public dwukropek.
Linia 17. Lista otwórz nawias okrągły zamknij nawias okrągły dwukropek glowa otwórz nawias okrągły nullptr zamknij nawias okrągły przecinek ogon otwórz nawias okrągły nullptr zamknij nawias okrągły otwórz nawias klamrowy zamknij nawias klamrowy.
Linia 18. kropka kropka kropka.
Linia 19. zamknij nawias klamrowy.
Pole ogon, tj. wskaźnik na ostatni element listy, jest opcjonalne, może występować zarówno w listach jedno-, jak i dwukierunkowych. Używa się go m.in. do szybkiego dodawania elementów na końcu listy bez konieczności przechodzenia po wszystkich jej elementach w celu znalezienia ostatniego.
Dodawanie węzłów na końcu listy dwukierunkowej
Deklaracje metod obsługujących listę pozostają bez zmian. Modyfikacji wymagają tylko implementacje metod dodaj() i usun(). Zacznijmy od metody dodającej nowe węzły:
Linia 1. void Lista dwukropek dwukropek dodaj otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Dodaję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 4. Wezel asterysk nowy znak równości new Wezel otwórz nawias okrągły liczba zamknij nawias okrągły średnik.
Linia 6. prawy ukośnik prawy ukośnik Jeżeli lista jest pusta.
Linia 7. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 8. glowa znak równości ogon znak równości nowy średnik.
Linia 9. return średnik.
Linia 10. zamknij nawias klamrowy.
Linia 12. prawy ukośnik prawy ukośnik Dodanie nowego węzła na końcu listy.
Linia 13. ogon minus zamknij nawias ostrokątny nastepny znak równości nowy średnik.
Linia 14. nowy minus zamknij nawias ostrokątny poprzedni znak równości ogon średnik.
Linia 15. ogon znak równości nowy średnik.
Linia 16. zamknij nawias klamrowy.
void Lista::dodaj(int liczba) {
cout << "Dodaję: " << liczba << endl;
Wezel *nowy = new Wezel(liczba);
// Jeżeli lista jest pusta
if (czyPusta()) {
glowa = ogon = nowy;
return;
}
// Dodanie nowego węzła na końcu listy
ogon->nastepny = nowy;
nowy->poprzedni = ogon;
ogon = nowy;
}
W komentarzach zaznaczyliśmy różnice w porównaniu do implementacji tej metody użytej w przypadku listy jednokierunkowej. Obejmują one:
ustawienia pola ogon na nowy węzeł w przypadku dodawania pierwszego elementu listy;
wykorzystanie pola ogon – zamiast pętli przechodzącej wszystkie elementy listy – do wskazania ostatniego węzła listy;
ustawienie wskaźników nastepny dotychczasowego ostatniego węzła na nowy oraz poprzedni nowego węzła na dotychczasowy ostatni;
ustawienie pola ogon na nowo dodany element.
RlhFi1x6RJLwH
Ilustracja przedstawia schemat dodawania węzła do końca listy dwukierunkowej. Lista składa się z czterech elementów. Pomiędzy elementami są po dwie strzałki, gdyż każdy z nich jest jednocześnie elementem następnym oraz poprzednim. Pierwszy z elementów to głowa. Trzeci element początkowo był ogonem, jednak po dodaniu węzła to nowy element czwarty jest podpisany jako ogon.
Schemat dodawania węzła do końca listy dwukierunkowej
Źródło: Contentplus.pl Sp. z o.o., licencja: CC BY-SA 3.0.
Usuwanie węzłów z listy dwukierunkowej
Metoda usuwająca elementy z podanej pozycji nie wymaga zmian, lecz uzupełnienia. Jeżeli usuwamy element niebędący ani pierwszym, ani ostatnim, musimy odpowiednio ustawić wskaźnik poprzedni węzła występującego po węźle usuwanym. W przeciwnym razie, jeżeli usuwamy ostatni element, musimy zaktualizować pole ogon, aby wskazywało na dotychczasowy węzeł przedostatni. Poniżej znajduje się kod uzupełnionej metody usun(). W komentarzu zaznaczono instrukcję warunkową realizującą omówione operacje.
Linia 1. void Lista dwukropek dwukropek usun otwórz nawias okrągły int indeks zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return średnik.
Linia 4. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Usuwam pozycję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny indeks otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 6. Wezel asterysk pomocniczy1 znak równości glowa przecinek asterysk pomocniczy2 znak równości nullptr średnik średnik.
Linia 7. int rozmiar znak równości 0 średnik.
Linia 9. while otwórz nawias okrągły pomocniczy1 wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 10. pomocniczy1 znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 11. rozmiar plus plus średnik.
Linia 12. zamknij nawias klamrowy.
Linia 14. if otwórz nawias okrągły indeks zamknij nawias ostrokątny rozmiar zamknij nawias okrągły otwórz nawias klamrowy.
Linia 15. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Indeks poza zakresem kropka cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 16. return średnik.
Linia 17. zamknij nawias klamrowy.
Linia 19. pomocniczy1 znak równości glowa średnik.
Linia 20. if otwórz nawias okrągły indeks znak równości znak równości 1 zamknij nawias okrągły otwórz nawias klamrowy.
Linia 21. glowa znak równości glowa minus zamknij nawias ostrokątny nastepny średnik.
Linia 22. delete pomocniczy1 średnik.
Linia 23. return średnik.
Linia 24. zamknij nawias klamrowy.
Linia 26. while otwórz nawias okrągły indeks minus minus zamknij nawias ostrokątny 1 zamknij nawias okrągły otwórz nawias klamrowy.
Linia 27. pomocniczy2 znak równości pomocniczy1 średnik.
Linia 28. pomocniczy1 znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 29. zamknij nawias klamrowy.
Linia 31. prawy ukośnik prawy ukośnik Zmiana wskaźnika nastepny węzła poprzedzającego usuwany.
Linia 32. pomocniczy2 minus zamknij nawias ostrokątny nastepny znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 34. prawy ukośnik prawy ukośnik Kod obsługujący listę dwukierunkową.
Linia 35. if otwórz nawias okrągły pomocniczy1 minus zamknij nawias ostrokątny nastepny wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 36. prawy ukośnik prawy ukośnik Jeżeli usuwany węzeł nie jest ostatni.
Linia 37. pomocniczy1 minus zamknij nawias ostrokątny nastepny minus zamknij nawias ostrokątny poprzedni znak równości pomocniczy2 średnik.
Linia 38. zamknij nawias klamrowy else otwórz nawias klamrowy.
Linia 39. prawy ukośnik prawy ukośnik Jeżeli usuwany element jest ostatni.
Linia 40. ogon znak równości pomocniczy2 średnik.
Linia 41. zamknij nawias klamrowy.
Linia 43. prawy ukośnik prawy ukośnik Usunięcie węzła o podanym indeksie.
Linia 44. delete pomocniczy1 średnik.
Linia 45. zamknij nawias klamrowy.
void Lista::usun(int indeks) {
if (czyPusta()) return;
cout << "Usuwam pozycję: " << indeks << endl;
Wezel *pomocniczy1 = glowa, *pomocniczy2 = nullptr;;
int rozmiar = 0;
while (pomocniczy1 != nullptr) {
pomocniczy1 = pomocniczy1->nastepny;
rozmiar++;
}
if (indeks > rozmiar) {
cout << "Indeks poza zakresem." << endl;
return;
}
pomocniczy1 = glowa;
if (indeks == 1) {
glowa = glowa->nastepny;
delete pomocniczy1;
return;
}
while (indeks-- > 1) {
pomocniczy2 = pomocniczy1;
pomocniczy1 = pomocniczy1->nastepny;
}
// Zmiana wskaźnika nastepny węzła poprzedzającego usuwany
pomocniczy2->nastepny = pomocniczy1->nastepny;
// Kod obsługujący listę dwukierunkową
if (pomocniczy1->nastepny != nullptr) {
// Jeżeli usuwany węzeł nie jest ostatni
pomocniczy1->nastepny->poprzedni = pomocniczy2;
} else {
// Jeżeli usuwany element jest ostatni
ogon = pomocniczy2;
}
// Usunięcie węzła o podanym indeksie
delete pomocniczy1;
}
R50oTO05RitRz
Ilustracja przedstawia schemat usuwania węzła z listy dwukierunkowej. Lista składa się z czterech elementów. Pomiędzy elementami są po dwie strzałki, gdyż każdy z nich jest jednocześnie elementem następnym oraz poprzednim. Pierwszy z elementów to głowa. Element drugi to element pomocniczy dwa. Element trzeci to element pomocniczy jeden. Element czwarty to ogon. Element trzeci został przekreślony wraz ze strzałkami łączącymi go z drugim oraz czwartym elementem. Pomiędzy drugim i czwartym elementem dodane zostały nowe strzałki.
Schemat usuwania węzła z listy dwukierunkowej
Źródło: Contentplus.pl Sp. z o.o., licencja: CC BY-SA 3.0.
Ćwiczenie 4
Wykorzystaj omówiony kod i przygotuj program pozwalający sprawdzić działanie listy dwukierunkowej. Dodaj do listy trzy liczby i wypisz listę. Następnie usuń pierwszy, drugi i trzeci element. Dodaj do listy jeszcze jedną liczbę i wypisz listę.
R1dy1fKVjtGHu
2
2
Implementacja metod czyPusta() i wypisz() jest taka sama jak w przypadku listy jednokierunkowej, trzeba tylko dostosować wyświetlane komunikaty i nazwy wskaźników.
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 3. using namespace std średnik.
Linia 5. typedef struct Wezel otwórz nawias klamrowy.
Linia 6. int liczba średnik.
Linia 7. Wezel asterysk nastepny średnik.
Linia 8. Wezel asterysk poprzedni średnik.
Linia 9. Wezel otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 10. this minus zamknij nawias ostrokątny liczba znak równości liczba średnik.
Linia 11. this minus zamknij nawias ostrokątny nastepny znak równości nullptr średnik.
Linia 12. this minus zamknij nawias ostrokątny poprzedni znak równości nullptr średnik.
Linia 13. zamknij nawias klamrowy.
Linia 14. zamknij nawias klamrowy Wezel średnik.
Linia 16. class Lista otwórz nawias klamrowy.
Linia 17. Wezel asterysk glowa średnik.
Linia 18. Wezel asterysk ogon średnik.
Linia 20. public dwukropek.
Linia 21. Lista otwórz nawias okrągły zamknij nawias okrągły dwukropek glowa otwórz nawias okrągły nullptr zamknij nawias okrągły przecinek ogon otwórz nawias okrągły nullptr zamknij nawias okrągły otwórz nawias klamrowy zamknij nawias klamrowy.
Linia 22. bool czyPusta otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 23. void dodaj otwórz nawias okrągły int zamknij nawias okrągły średnik.
Linia 24. void usun otwórz nawias okrągły int zamknij nawias okrągły średnik.
Linia 25. void wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 26. zamknij nawias klamrowy średnik.
Linia 28. bool Lista dwukropek dwukropek czyPusta otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 29. if otwórz nawias okrągły glowa znak równości znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 30. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Lista jest pusta wykrzyknik cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 31. return true średnik.
Linia 32. zamknij nawias klamrowy.
Linia 33. return false średnik.
Linia 34. zamknij nawias klamrowy.
Linia 36. void Lista dwukropek dwukropek dodaj otwórz nawias okrągły int liczba zamknij nawias okrągły otwórz nawias klamrowy.
Linia 37. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Dodaję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 39. Wezel asterysk nowy znak równości new Wezel otwórz nawias okrągły liczba zamknij nawias okrągły średnik.
Linia 41. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 42. glowa znak równości ogon znak równości nowy średnik.
Linia 43. return średnik.
Linia 44. zamknij nawias klamrowy.
Linia 46. ogon minus zamknij nawias ostrokątny nastepny znak równości nowy średnik.
Linia 47. nowy minus zamknij nawias ostrokątny poprzedni znak równości ogon średnik.
Linia 48. ogon znak równości nowy średnik.
Linia 49. zamknij nawias klamrowy.
Linia 51. void Lista dwukropek dwukropek usun otwórz nawias okrągły int indeks zamknij nawias okrągły otwórz nawias klamrowy.
Linia 52. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return średnik.
Linia 54. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Usuwam pozycję dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny indeks otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 56. Wezel asterysk pomocniczy1 znak równości glowa przecinek asterysk pomocniczy2 znak równości nullptr średnik średnik.
Linia 57. int rozmiar znak równości 0 średnik.
Linia 59. while otwórz nawias okrągły pomocniczy1 wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 60. pomocniczy1 znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 61. rozmiar plus plus średnik.
Linia 62. zamknij nawias klamrowy.
Linia 64. if otwórz nawias okrągły indeks zamknij nawias ostrokątny rozmiar zamknij nawias okrągły otwórz nawias klamrowy.
Linia 65. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Indeks poza zakresem kropka cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 66. return średnik.
Linia 67. zamknij nawias klamrowy.
Linia 69. pomocniczy1 znak równości glowa średnik.
Linia 70. if otwórz nawias okrągły indeks znak równości znak równości 1 zamknij nawias okrągły otwórz nawias klamrowy.
Linia 71. glowa znak równości glowa minus zamknij nawias ostrokątny nastepny średnik.
Linia 72. delete pomocniczy1 średnik.
Linia 73. return średnik.
Linia 74. zamknij nawias klamrowy.
Linia 76. while otwórz nawias okrągły indeks minus minus zamknij nawias ostrokątny 1 zamknij nawias okrągły otwórz nawias klamrowy.
Linia 77. pomocniczy2 znak równości pomocniczy1 średnik.
Linia 78. pomocniczy1 znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 79. zamknij nawias klamrowy.
Linia 81. pomocniczy2 minus zamknij nawias ostrokątny nastepny znak równości pomocniczy1 minus zamknij nawias ostrokątny nastepny średnik.
Linia 83. if otwórz nawias okrągły pomocniczy1 minus zamknij nawias ostrokątny nastepny wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 84. pomocniczy1 minus zamknij nawias ostrokątny nastepny minus zamknij nawias ostrokątny poprzedni znak równości pomocniczy2 średnik.
Linia 85. zamknij nawias klamrowy else otwórz nawias klamrowy.
Linia 86. ogon znak równości pomocniczy2 średnik.
Linia 87. zamknij nawias klamrowy.
Linia 89. delete pomocniczy1 średnik.
Linia 90. zamknij nawias klamrowy.
Linia 92. void Lista dwukropek dwukropek wypisz otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 94. if otwórz nawias okrągły czyPusta otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły return średnik.
Linia 96. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Lista zawiera dwukropek cudzysłów średnik.
Linia 97. Wezel asterysk pomocniczy znak równości glowa średnik.
Linia 98. while otwórz nawias okrągły pomocniczy wykrzyknik znak równości nullptr zamknij nawias okrągły otwórz nawias klamrowy.
Linia 99. cout otwórz nawias ostrokątny otwórz nawias ostrokątny pomocniczy minus zamknij nawias ostrokątny liczba otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów cudzysłów średnik.
Linia 100. pomocniczy znak równości pomocniczy minus zamknij nawias ostrokątny nastepny średnik.
Linia 101. zamknij nawias klamrowy.
Linia 102. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 103. zamknij nawias klamrowy.
Linia 105. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 106. Lista lista średnik.
Linia 108. lista kropka dodaj otwórz nawias okrągły 1 zamknij nawias okrągły średnik.
Linia 109. lista kropka dodaj otwórz nawias okrągły 2 zamknij nawias okrągły średnik.
Linia 110. lista kropka dodaj otwórz nawias okrągły 3 zamknij nawias okrągły średnik.
Linia 111. lista kropka wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 113. lista kropka usun otwórz nawias okrągły 1 zamknij nawias okrągły średnik.
Linia 114. lista kropka usun otwórz nawias okrągły 3 zamknij nawias okrągły średnik.
Linia 115. lista kropka usun otwórz nawias okrągły 2 zamknij nawias okrągły średnik.
Linia 116. lista kropka dodaj otwórz nawias okrągły 4 zamknij nawias okrągły średnik.
Linia 117. lista kropka wypisz otwórz nawias okrągły zamknij nawias okrągły średnik.
Linia 119. return 0 średnik.
Linia 120. zamknij nawias klamrowy.
Linia 1. Dodaję dwukropek 1.
Linia 2. Lista jest pusta wykrzyknik.
Linia 3. Dodaję dwukropek 2.
Linia 4. Dodaję dwukropek 3.
Linia 5. Lista zawiera dwukropek 1 2 3.
Linia 6. Usuwam pozycję dwukropek 1.
Linia 7. Usuwam pozycję dwukropek 3.
Linia 8. Indeks poza zakresem kropka.
Linia 9. Usuwam pozycję dwukropek 2.
Linia 10. Dodaję dwukropek 4.
Linia 11. Lista zawiera dwukropek 2 4.
Dodaję: 1
Lista jest pusta!
Dodaję: 2
Dodaję: 3
Lista zawiera: 1 2 3
Usuwam pozycję: 1
Usuwam pozycję: 3
Indeks poza zakresem.
Usuwam pozycję: 2
Dodaję: 4
Lista zawiera: 2 4
Stos, kolejka i lista w bibliotece standardowej
Dla zainteresowanych
Biblioteka STLSTLSTL zawiera szablony klas przeznaczone do tworzenia omawianych wyżej struktur dynamicznych. Każda z klas udostępnia wiele metod pozwalających wykonywać typowe operacje na takich strukturach. Poniżej skrótowo zaprezentujemy najważniejsze klasy i ich metody.
Klasa stack
Klasa ta służy do tworzenia stosu. Udostępniane w niej metody to m.in.:
push() – zadaniem metody jest odłożenie elementu na szczyt stosu;
pop() – metoda zdejmuje element ze szczytu stosu;
top() – metoda zwraca referencję do wierzchołka stosu bez usuwania go;
Na początku tworzymy obiekt stos do przechowywania wartości typu int (liczby całkowite). Następnie odkładamy na stos trzy liczby (push), po czym wypisujemy rozmiar (size()) i wierzchołek (top()) stosu.
W kolejnych instrukcjach zdejmujemy wierzchołek ze stosu (pop()), po czym wypisujemy rozmiar i nowy wierzchołek.
Na końcu przy użyciu pętli, która wykonuje się, dopóki stos nie jest pusty (empty()), wypisujemy kolejny wierzchołek i zdejmujemy go. Na końcu wypisujemy jeszcze raz aktualny rozmiar stosu.
Wynik działania programu:
Linia 1. Odkładam liczby 5 przecinek 4 przecinek 6.
Linia 2. Rozmiar dwukropek 3 Wierzchołek dwukropek 6.
Linia 3. Zdejmuję wierzchołek kropka.
Linia 4. Rozmiar dwukropek 2 Wierzchołek dwukropek 4.
Linia 5. Stos zawiera dwukropek 4 5.
Linia 6. Rozmiar dwukropek 0.
Na początku tworzymy obiekt kolejka, który posłuży do przechowywania wartości typu int (liczby całkowite). Dodajemy do kolejki trzy liczby (push) po czym wypisujemy rozmiar (size()) oraz pierwszy (front()) i ostatni (back()) element.
Następnie usuwamy pierwszy element (pop()) oraz wypisujemy rozmiar, pierwszy i ostatni element kolejki.
Na końcu przy użyciu pętli, która wykonuje się, dopóki kolejka nie jest pusta (empty()), wypisujemy kolejne pierwsze elementy i usuwamy je. Na końcu wypisujemy jeszcze raz aktualny rozmiar kolejki.
Wynik działania programu:
Linia 1. Dodaję liczby 5 przecinek 4 przecinek 6.
Linia 2. Rozmiar dwukropek 3 Pierwszy dwukropek 5 Ostatni dwukropek 6.
Linia 3. Usuwam pierwszy kropka.
Linia 4. Rozmiar dwukropek 2 Pierwszy dwukropek 4 Ostatni dwukropek 6.
Linia 5. Kolejka zawiera dwukropek 4 6.
Linia 6. Rozmiar dwukropek 0.
Na początku tworzymy obiekt lista, który posłuży do przechowywania wartości typu int (liczby całkowite). Następnie dodajemy na końcu listy dwie liczby (push_back()), następnie jedną na początku (push_front()), po czym wypisujemy rozmiar (size()) oraz pierwszy (front()) i ostatni (back()) element.
Następnie usuwamy ostatni element (pop_back()) oraz wypisujemy rozmiar, pierwszy i ostatni element listy.
Na końcu przy użyciu pętli wykonującej się, dopóki lista nie jest pusta (empty()), wypisujemy kolejne pierwsze elementy i usuwamy je. Na końcu wypisujemy jeszcze raz aktualny rozmiar listy.
Wynik działania programu:
Linia 1. Dodaję liczby 5 przecinek 4 na końcu.
Linia 2. Dodaję liczbę 6 na początku.
Linia 3. Rozmiar dwukropek 3 Pierwszy dwukropek 6 Ostatni dwukropek 4.
Linia 4. Usuwam ostatni kropka.
Linia 5. Rozmiar dwukropek 2 Pierwszy dwukropek 6 Ostatni dwukropek 5.
Linia 6. Lista zawiera dwukropek 6 5.
Linia 7. Rozmiar dwukropek 0.
Dodaję liczby 5, 4 na końcu
Dodaję liczbę 6 na początku
Rozmiar: 3 Pierwszy: 6 Ostatni: 4
Usuwam ostatni.
Rozmiar: 2 Pierwszy: 6 Ostatni: 5
Lista zawiera: 6 5
Rozmiar: 0
Słownik
klasa
klasa
definiowany przez użytkownika złożony typ danych, który pozwala grupować logicznie powiązane dane oraz funkcje wykonujące na nich operacje; składowe klasy nazywamy polami, a funkcje zdefiniowane w klasie – metodami
konstruktor
konstruktor
metoda o takiej samej nazwie jak klasa, która służy do nadawania wartości początkowych jej polom; w języku C++ klasa może mieć wiele konstruktorów dzięki mechanizmowi przeciążania
niedopełnienie stosu
niedopełnienie stosu
(ang. stack underflow) rodzaj błędu, który występuje, kiedy program próbuje zdjąć wartość z pustego stosu
przepełnienie stosu
przepełnienie stosu
(ang. stack overflow) rodzaj błędu polegającego na przekroczeniu rozmiaru pamięci zarezerwowanej dla stosu
STL
STL
(od ang. Standard Template Library) biblioteka dla języka C++ zawierająca cztery komponenty zwane algorytmami, kontenerami, funkcjami i iteratorami; STL posiada zestaw zdefiniowanych szablonów klas, np.: vector, list, set, map, queue, stack i wiele więcej
struktura
struktura
w języku C++ złożony typ danych pozwalający przechowywać wiele logicznie powiązanych danych różnego typu w jednym pojemniku zwanym obiektem lub rekordem; składowe struktury nazywamy polami
wskaźnik
wskaźnik
zmienna przechowująca adres innej zmiennej lub obiektu, pozwalająca na bezpośredni dostęp do pamięci; możliwe jest tworzenie wskaźników pustych, które na nic nie wskazują