Wróć do informacji o e-podręczniku Wydrukuj Pobierz materiał do PDF Pobierz materiał do EPUB Pobierz materiał do MOBI Zaloguj się, aby dodać do ulubionych Zaloguj się, aby skopiować i edytować materiał Zaloguj się, aby udostępnić materiał Zaloguj się, aby dodać całą stronę do teczki
Problem 1

Napisz program, który wygeneruje i narysuje na standardowym wyjściu fraktale – Zbiór Cantora oraz Dywan Sierpińskiego.

R1I7zM6OYpT6w
Wymyśl pytanie na kartkówkę związane z tematem materiału.
Polecenie 1

Porównaj swoje rozwiązanie z przedstawionym w filmie.

RSMXwVsNT7LTP1
Film nawiązujący do treści materiału: Fraktale w matematyce - zbiór Cantora, dywan Sierpińskiego.

Trójkąt Sierpińskiego w języku C++ generowany rekurencyjnie

Aby napisać algorytm pozwalający narysować na ekranie fraktalfraktalfraktal zwany trójkątem Sierpińskiego, musimy zastanowić się, w jaki sposób chcemy przechowywać tę strukturę w programie. Utworzymy dwuwymiarową tablicę, w której wielokrotnie umieścimy znaki składające się na trójkąty. Wynikiem działania programu będzie wypisanie struktury podobnej do przedstawionej niżej (różniącej się rozmiarem lub użytymi znakami):

Linia 1. kratka. Linia 2. kratka kratka. Linia 3. kratka kratka. Linia 4. kratka kratka kratka kratka. Linia 5. kratka kratka. Linia 6. kratka kratka kratka kratka. Linia 7. kratka kratka kratka kratka. Linia 8. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 9. kratka kratka. Linia 10. kratka kratka kratka kratka. Linia 11. kratka kratka kratka kratka. Linia 12. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 13. kratka kratka kratka kratka. Linia 14. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 15. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 16. kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka.

Struktura taka może zostać utworzona za pomocą globalnej tablicy typu bool, zadeklarowanej w następujący sposób:

Linia 1. const int STOPIEN znak równości 4 średnik. Linia 2. bool trojkat otwórz nawias kwadratowy 1 otwórz nawias ostrokątny otwórz nawias ostrokątny STOPIEN zamknij nawias kwadratowy otwórz nawias kwadratowy 1 otwórz nawias ostrokątny otwórz nawias ostrokątny STOPIEN zamknij nawias kwadratowy średnik.

Wiele osób może zdziwić taka deklaracja, ale za chwilę wszystko się wyjaśni. Operator << oznacza, że dokonujemy przesunięcia bitowegoprzesunięcie bitoweprzesunięcia bitowego. Na potrzeby bieżącego e‑materiału możemy przyjąć, że prawdziwa jest następująca zależność:

a << n = a 2 n

Dzięki zastosowaniu operacji przesunięcia bitowego jesteśmy w stanie obliczyć kolejne potęgi liczby 2 bez potrzeby użycia funkcji. W rezultacie możemy zadeklarować tablicę, której rozmiar zostanie obliczony w momencie kompilacji. Warto zapamiętać powyższą własność, gdyż zostanie ona wykorzystana również w dalszej części programu.

Ciekawostka

Operacja przesunięcia bitowego jest wykonywana znacznie szybciej niż potęgowanie, ponieważ wymaga tylko zmodyfikowania zapisu binarnego liczby (usunięcia n cyfr z przodu, dopisania n zer z tyłu). Potęgowanie wymaga z kolei wielokrotnego wykonywania operacji mnożenia, która jest o wiele bardziej czasochłonna (procesor wykonuje ją dłużej).

Po zadeklarowaniu tablicy globalnie, możemy przejść do realizacji głównej części programu. Napiszmy funkcję, która wypełni tablicę znakami składającymi się na trójkąt Sierpińskiego. Ponieważ chcemy wykorzystać rekurencję, funkcja musi przyjmować odpowiednie parametry. W wypadku fraktala najważniejszy jest jego stopień. Trójkąt Sierpińskiego składa się z trzech mniejszych trójkątów Sierpińskiego oraz z jednego „białego” (pustego) trójkąta w środku; potrzebnymi parametrami będą zatem współrzędne, od których tablica zostanie wypełniona kolejnym trójkątem. Przez współrzędne rozumiemy górny wierzchołek trójkąta, który rysujemy. Deklaracja funkcji może wyglądać następująco:

Linia 1. void utworzTrojkat otwórz nawias okrągły int stopien przecinek int x przecinek int y zamknij nawias okrągły średnik.

W każdej funkcji rekurencyjnej należy określić moment zakończenia jej działania. W rozpatrywanym przypadku będzie to etap, gdy stopień fraktala osiągnie wartość 0. Uzupełnimy wówczas pojedynczy element tablicy (zawierający opis pojedynczego elementu trójkąta) wartością true. Zapiszmy zatem warunek, dzięki któremu zostanie wykryty moment zakończenia rekurencji:

Linia 1. void utworzTrojkat otwórz nawias okrągły int stopien przecinek int x przecinek int y zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. prawy ukośnik prawy ukośnik warunek końcowy. Linia 3. if otwórz nawias okrągły stopien znak równości znak równości 0 zamknij nawias okrągły otwórz nawias klamrowy. Linia 4. trojkat otwórz nawias kwadratowy y zamknij nawias kwadratowy otwórz nawias kwadratowy x zamknij nawias kwadratowy znak równości true średnik. Linia 5. zamknij nawias klamrowy else otwórz nawias klamrowy. Linia 6. prawy ukośnik prawy ukośnik kolejne wywołania rekurencyjne. Linia 7. zamknij nawias klamrowy. Linia 8. zamknij nawias klamrowy.

W tablicach wielowymiarowych w programowaniu zwyczajowo przyjmuje się, że pierwsza współrzędna oznacza wiersz, a druga kolumnę. Jest to sytuacja odwrotna niż w przypadku układu współrzędnych, gdzie współrzędne oznaczamy przez x oraz y. Z tego powodu w powyższym programie przyjmujemy, że y oznacza wiersz, a x kolumnę.

Obecnie funkcję można wywołać tylko z parametrem stopien = 0. W przeciwnym razie nie zostanie wykonana żadna operacja. Zastanówmy się, w jaki sposób należy uruchomić kolejne etapy rekurencji.

Musimy zlecić narysowanie trzech trójkątów Sierpińskiego (których stopień będzie o 1 mniejszy) przy użyciu odpowiednich współrzędnych tablicy, a także narysować „białą” część trójkąta wewnątrz. Współrzędne pierwszego trójkąta są oczywiste, ponieważ musimy narysować go w górnym wierzchołku, czyli w tym samym miejscu, w którym się znajdujemy. Pierwsze wywołanie kolejnej rekurencji będzie wyglądać zatem następująco:

Linia 1. void utworzTrojkat otwórz nawias okrągły int stopien przecinek int x przecinek int y zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. prawy ukośnik prawy ukośnik warunek końcowy. Linia 3. if otwórz nawias okrągły stopien znak równości znak równości 0 zamknij nawias okrągły otwórz nawias klamrowy. Linia 4. trojkat otwórz nawias kwadratowy y zamknij nawias kwadratowy otwórz nawias kwadratowy x zamknij nawias kwadratowy znak równości true średnik. Linia 5. zamknij nawias klamrowy else otwórz nawias klamrowy. Linia 6. prawy ukośnik prawy ukośnik kolejne wywołania rekurencyjne. Linia 7. prawy ukośnik prawy ukośnik pierwszy trójkąt dwukropek. Linia 8. utworzTrojkat otwórz nawias okrągły stopien minus 1 przecinek x przecinek y zamknij nawias okrągły średnik. Linia 9. zamknij nawias klamrowy. Linia 10. zamknij nawias klamrowy.

Chcąc narysować kolejne trójkąty, musimy najpierw obliczyć ich rozmiary. Określą one przesunięcie w kierunku następnych współrzędnych. W tym celu ponownie posłużymy się przesunięciem bitowym. Wówczas możemy zlecić rysowanie kolejnych trójkątów w następujący sposób:

Linia 1. void utworzTrojkat otwórz nawias okrągły int stopien przecinek int x przecinek int y zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. prawy ukośnik prawy ukośnik warunek końcowy. Linia 3. if otwórz nawias okrągły stopien znak równości znak równości 0 zamknij nawias okrągły otwórz nawias klamrowy. Linia 4. trojkat otwórz nawias kwadratowy y zamknij nawias kwadratowy otwórz nawias kwadratowy x zamknij nawias kwadratowy znak równości true średnik. Linia 5. zamknij nawias klamrowy else otwórz nawias klamrowy. Linia 6. prawy ukośnik prawy ukośnik kolejne wywołania rekurencyjne. Linia 7. prawy ukośnik prawy ukośnik pierwszy trójkąt dwukropek. Linia 8. utworzTrojkat otwórz nawias okrągły stopien minus 1 przecinek x przecinek y zamknij nawias okrągły średnik. Linia 10. prawy ukośnik prawy ukośnik rozmiar stanowiący przesunięcie. Linia 11. int rozmiar znak równości 1 otwórz nawias ostrokątny otwórz nawias ostrokątny otwórz nawias okrągły stopien minus 1 zamknij nawias okrągły średnik. Linia 13. prawy ukośnik prawy ukośnik kolejne 2 trójkąty dwukropek. Linia 14. utworzTrojkat otwórz nawias okrągły stopien minus 1 przecinek x przecinek y plus rozmiar zamknij nawias okrągły średnik. Linia 15. utworzTrojkat otwórz nawias okrągły stopien minus 1 przecinek x plus rozmiar przecinek y plus rozmiar zamknij nawias okrągły średnik. Linia 16. zamknij nawias klamrowy. Linia 17. zamknij nawias klamrowy.

Teraz pozostaje już tylko wypełnić środkowy „biały” trójkąt. Można to zrobić np. za pomocą dwóch zagnieżdżonych pętli for. Pamiętajmy, że środkowy trójkąt w powstałej strukturze ma mieć rozmiar o 1 mniejszy niż pozostałe trzy trójkąty.

Linia 1. void utworzTrojkat otwórz nawias okrągły int stopien przecinek int x przecinek int y zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. prawy ukośnik prawy ukośnik warunek końcowy. Linia 3. if otwórz nawias okrągły stopien znak równości znak równości 0 zamknij nawias okrągły otwórz nawias klamrowy. Linia 4. trojkat otwórz nawias kwadratowy y zamknij nawias kwadratowy otwórz nawias kwadratowy x zamknij nawias kwadratowy znak równości true średnik. Linia 5. zamknij nawias klamrowy else otwórz nawias klamrowy. Linia 6. prawy ukośnik prawy ukośnik kolejne wywołania rekurencyjne. Linia 7. prawy ukośnik prawy ukośnik pierwszy trójkąt dwukropek. Linia 8. utworzTrojkat otwórz nawias okrągły stopien minus 1 przecinek x przecinek y zamknij nawias okrągły średnik. Linia 10. prawy ukośnik prawy ukośnik rozmiar stanowiący przesunięcie. Linia 11. int rozmiar znak równości 1 otwórz nawias ostrokątny otwórz nawias ostrokątny otwórz nawias okrągły stopien minus 1 zamknij nawias okrągły średnik. Linia 13. prawy ukośnik prawy ukośnik kolejne 2 trójkąty dwukropek. Linia 14. utworzTrojkat otwórz nawias okrągły stopien minus 1 przecinek x przecinek y plus rozmiar zamknij nawias okrągły średnik. Linia 15. utworzTrojkat otwórz nawias okrągły stopien minus 1 przecinek x plus rozmiar przecinek y plus rozmiar zamknij nawias okrągły średnik. Linia 17. prawy ukośnik prawy ukośnik 1 biały trójkąt w środku. Linia 18. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny rozmiar minus 1 średnik plus plus i zamknij nawias okrągły otwórz nawias klamrowy. Linia 19. for otwórz nawias okrągły int j znak równości i średnik j otwórz nawias ostrokątny rozmiar minus 1 średnik plus plus j zamknij nawias okrągły otwórz nawias klamrowy. Linia 20. trojkat otwórz nawias kwadratowy y plus rozmiar plus i zamknij nawias kwadratowy otwórz nawias kwadratowy x plus 1 plus j zamknij nawias kwadratowy znak równości false średnik. Linia 21. zamknij nawias klamrowy. Linia 22. zamknij nawias klamrowy. Linia 23. zamknij nawias klamrowy. Linia 24. zamknij nawias klamrowy.

Należy także przygotować funkcję, która wypisze zawartość utworzonej tablicy. Znowu posłużymy się przesunięciem bitowym oraz dwiema zagnieżdżonymi pętlami for:

Linia 1. void wypiszTrojkat otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny otwórz nawias okrągły 1 otwórz nawias ostrokątny otwórz nawias ostrokątny STOPIEN zamknij nawias okrągły średnik plus plus i zamknij nawias okrągły otwórz nawias klamrowy. Linia 3. for otwórz nawias okrągły int j znak równości 0 średnik j otwórz nawias ostrokątny znak równości i średnik plus plus j zamknij nawias okrągły otwórz nawias klamrowy. Linia 4. std dwukropek dwukropek cout otwórz nawias ostrokątny otwórz nawias ostrokątny otwórz nawias okrągły trojkat otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy znak zapytania cudzysłów kratka cudzysłów dwukropek cudzysłów cudzysłów zamknij nawias okrągły średnik. Linia 5. zamknij nawias klamrowy. Linia 7. std dwukropek dwukropek cout otwórz nawias ostrokątny otwórz nawias ostrokątny std dwukropek dwukropek endl średnik. Linia 8. zamknij nawias klamrowy. Linia 9. zamknij nawias klamrowy.

Po połączeniu wszystkich elementów oraz napisaniu funkcji main() otrzymujemy następujący kod:

Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny. Linia 3. const int STOPIEN znak równości 4 średnik. Linia 4. bool trojkat otwórz nawias kwadratowy 1 otwórz nawias ostrokątny otwórz nawias ostrokątny STOPIEN zamknij nawias kwadratowy otwórz nawias kwadratowy 1 otwórz nawias ostrokątny otwórz nawias ostrokątny STOPIEN zamknij nawias kwadratowy średnik. Linia 6. void utworzTrojkat otwórz nawias okrągły int stopien przecinek int x przecinek int y zamknij nawias okrągły otwórz nawias klamrowy. Linia 7. prawy ukośnik prawy ukośnik warunek końcowy. Linia 8. if otwórz nawias okrągły stopien znak równości znak równości 0 zamknij nawias okrągły otwórz nawias klamrowy. Linia 9. trojkat otwórz nawias kwadratowy y zamknij nawias kwadratowy otwórz nawias kwadratowy x zamknij nawias kwadratowy znak równości true średnik. Linia 10. zamknij nawias klamrowy else otwórz nawias klamrowy. Linia 11. prawy ukośnik prawy ukośnik kolejne wywołania rekurencyjne. Linia 12. prawy ukośnik prawy ukośnik pierwszy trójkąt dwukropek. Linia 13. utworzTrojkat otwórz nawias okrągły stopien minus 1 przecinek x przecinek y zamknij nawias okrągły średnik. Linia 15. prawy ukośnik prawy ukośnik rozmiar stanowiący przesunięcie. Linia 16. int rozmiar znak równości 1 otwórz nawias ostrokątny otwórz nawias ostrokątny otwórz nawias okrągły stopien minus 1 zamknij nawias okrągły średnik. Linia 18. prawy ukośnik prawy ukośnik kolejne 2 trójkąty dwukropek. Linia 19. utworzTrojkat otwórz nawias okrągły stopien minus 1 przecinek x przecinek y plus rozmiar zamknij nawias okrągły średnik. Linia 20. utworzTrojkat otwórz nawias okrągły stopien minus 1 przecinek x plus rozmiar przecinek y plus rozmiar zamknij nawias okrągły średnik. Linia 22. prawy ukośnik prawy ukośnik 1 biały trójkąt w środku. Linia 23. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny rozmiar minus 1 średnik plus plus i zamknij nawias okrągły otwórz nawias klamrowy. Linia 24. for otwórz nawias okrągły int j znak równości i średnik j otwórz nawias ostrokątny rozmiar minus 1 średnik plus plus j zamknij nawias okrągły otwórz nawias klamrowy. Linia 25. trojkat otwórz nawias kwadratowy y plus rozmiar plus i zamknij nawias kwadratowy otwórz nawias kwadratowy x plus 1 plus j zamknij nawias kwadratowy znak równości false średnik. Linia 26. zamknij nawias klamrowy. Linia 27. zamknij nawias klamrowy. Linia 28. zamknij nawias klamrowy. Linia 29. zamknij nawias klamrowy. Linia 31. void wypiszTrojkat otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy. Linia 32. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny otwórz nawias okrągły 1 otwórz nawias ostrokątny otwórz nawias ostrokątny STOPIEN zamknij nawias okrągły średnik plus plus i zamknij nawias okrągły otwórz nawias klamrowy. Linia 33. for otwórz nawias okrągły int j znak równości 0 średnik j otwórz nawias ostrokątny znak równości i średnik plus plus j zamknij nawias okrągły otwórz nawias klamrowy. Linia 34. std dwukropek dwukropek cout otwórz nawias ostrokątny otwórz nawias ostrokątny otwórz nawias okrągły trojkat otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy znak zapytania cudzysłów kratka cudzysłów dwukropek cudzysłów cudzysłów zamknij nawias okrągły średnik. Linia 35. zamknij nawias klamrowy. Linia 37. std dwukropek dwukropek cout otwórz nawias ostrokątny otwórz nawias ostrokątny std dwukropek dwukropek endl średnik. Linia 38. zamknij nawias klamrowy. Linia 39. zamknij nawias klamrowy. Linia 41. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy. Linia 42. utworzTrojkat otwórz nawias okrągły STOPIEN przecinek 0 przecinek 0 zamknij nawias okrągły średnik. Linia 43. wypiszTrojkat otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 44. return 0 średnik. Linia 45. zamknij nawias klamrowy.

Po uruchomieniu programu na ekranie pojawi się figura:

Linia 1. kratka. Linia 2. kratka kratka. Linia 3. kratka kratka. Linia 4. kratka kratka kratka kratka. Linia 5. kratka kratka. Linia 6. kratka kratka kratka kratka. Linia 7. kratka kratka kratka kratka. Linia 8. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 9. kratka kratka. Linia 10. kratka kratka kratka kratka. Linia 11. kratka kratka kratka kratka. Linia 12. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 13. kratka kratka kratka kratka. Linia 14. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 15. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 16. kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka.

Taką właśnie strukturę chcieliśmy uzyskać. Można jeszcze uzupełnić funkcję wypiszTrojkat() o kolejną pętlę for dopisującą spacje (oraz dodać spacje podczas odczytywania elementów tablicy trojkat). W rezultacie powstanie lustrzane odbicie trójkąta.

Linia 1. void wypiszTrojkat otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny otwórz nawias okrągły 1 otwórz nawias ostrokątny otwórz nawias ostrokątny STOPIEN zamknij nawias okrągły średnik plus plus i zamknij nawias okrągły otwórz nawias klamrowy. Linia 3. for otwórz nawias okrągły int j znak równości 0 średnik j otwórz nawias ostrokątny znak równości otwórz nawias okrągły 1 otwórz nawias ostrokątny otwórz nawias ostrokątny STOPIEN zamknij nawias okrągły minus i minus 2 średnik plus plus j zamknij nawias okrągły otwórz nawias klamrowy. Linia 4. std dwukropek dwukropek cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów cudzysłów średnik. Linia 5. zamknij nawias klamrowy. Linia 7. for otwórz nawias okrągły int j znak równości 0 średnik j otwórz nawias ostrokątny znak równości i średnik plus plus j zamknij nawias okrągły otwórz nawias klamrowy. Linia 8. std dwukropek dwukropek cout otwórz nawias ostrokątny otwórz nawias ostrokątny otwórz nawias okrągły trojkat otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy znak zapytania cudzysłów kratka cudzysłów dwukropek cudzysłów cudzysłów zamknij nawias okrągły średnik. Linia 9. zamknij nawias klamrowy. Linia 11. std dwukropek dwukropek cout otwórz nawias ostrokątny otwórz nawias ostrokątny std dwukropek dwukropek endl średnik. Linia 12. zamknij nawias klamrowy. Linia 13. zamknij nawias klamrowy.

Efekt działania zmodyfikowanego programu będzie następujący:

Linia 1. kratka. Linia 2. kratka kratka. Linia 3. kratka kratka. Linia 4. kratka kratka kratka kratka. Linia 5. kratka kratka. Linia 6. kratka kratka kratka kratka. Linia 7. kratka kratka kratka kratka. Linia 8. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 9. kratka kratka. Linia 10. kratka kratka kratka kratka. Linia 11. kratka kratka kratka kratka. Linia 12. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 13. kratka kratka kratka kratka. Linia 14. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 15. kratka kratka kratka kratka kratka kratka kratka kratka. Linia 16. kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka kratka.
1
Ważne!

Co to znaczy, że figury są podobne? O figurach możemy powiedzieć, że są podobne, jeśli mają takie same kąty i proporcjonalne boki, które przy nich leżą.

Fraktale są samopodobne, co oznacza, że kształt całego zbioru (fraktala) jest podobny do kształtu fragmentu tego zbioru (jednego lub kilku).

Słownik

fraktal
fraktal

obiekt samopodobny (taki, którego poszczególne części są podobne do całości)

przesunięcie bitowe
przesunięcie bitowe

operacja polegająca na przesunięciu cyfr liczby zapisanej binarnie o określoną liczbę pozycji w lewo lub prawo